Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /**
  2.  * Test program for PhysicsFS. May only work on Unix.
  3.  *
  4.  * Please see the file LICENSE.txt in the source's root directory.
  5.  *
  6.  *  This file written by Ryan C. Gordon.
  7.  */
  8.  
  9. #define _CRT_SECURE_NO_WARNINGS 1
  10.  
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <errno.h>
  14. #include <string.h>
  15.  
  16. #if (defined __MWERKS__)
  17. #include <SIOUX.h>
  18. #endif
  19.  
  20. #if (defined PHYSFS_HAVE_READLINE)
  21. #include <unistd.h>
  22. #include <readline/readline.h>
  23. #include <readline/history.h>
  24. #endif
  25.  
  26. #include <time.h>
  27.  
  28. /* Define this, so the compiler doesn't complain about using old APIs. */
  29. #define PHYSFS_DEPRECATED
  30.  
  31. #include "physfs.h"
  32.  
  33. #define TEST_VERSION_MAJOR  3
  34. #define TEST_VERSION_MINOR  0
  35. #define TEST_VERSION_PATCH  2
  36.  
  37. static FILE *history_file = NULL;
  38. static PHYSFS_uint32 do_buffer_size = 0;
  39.  
  40. static void output_versions(void)
  41. {
  42.     PHYSFS_Version compiled;
  43.     PHYSFS_Version linked;
  44.  
  45.     PHYSFS_VERSION(&compiled);
  46.     PHYSFS_getLinkedVersion(&linked);
  47.  
  48.     printf("test_physfs version %d.%d.%d.\n"
  49.            " Compiled against PhysicsFS version %d.%d.%d,\n"
  50.            " and linked against %d.%d.%d.\n\n",
  51.             TEST_VERSION_MAJOR, TEST_VERSION_MINOR, TEST_VERSION_PATCH,
  52.             (int) compiled.major, (int) compiled.minor, (int) compiled.patch,
  53.             (int) linked.major, (int) linked.minor, (int) linked.patch);
  54. } /* output_versions */
  55.  
  56.  
  57. static void output_archivers(void)
  58. {
  59.     const PHYSFS_ArchiveInfo **rc = PHYSFS_supportedArchiveTypes();
  60.     const PHYSFS_ArchiveInfo **i;
  61.  
  62.     printf("Supported archive types:\n");
  63.     if (*rc == NULL)
  64.         printf(" * Apparently, NONE!\n");
  65.     else
  66.     {
  67.         for (i = rc; *i != NULL; i++)
  68.         {
  69.             printf(" * %s: %s\n    Written by %s.\n    %s\n",
  70.                     (*i)->extension, (*i)->description,
  71.                     (*i)->author, (*i)->url);
  72.             printf("    %s symbolic links.\n",
  73.                     (*i)->supportsSymlinks ? "Supports" : "Does not support");
  74.         } /* for */
  75.     } /* else */
  76.  
  77.     printf("\n");
  78. } /* output_archivers */
  79.  
  80.  
  81. static int cmd_quit(char *args)
  82. {
  83.     return 0;
  84. } /* cmd_quit */
  85.  
  86.  
  87. static int cmd_init(char *args)
  88. {
  89.     if (*args == '\"')
  90.     {
  91.         args++;
  92.         args[strlen(args) - 1] = '\0';
  93.     } /* if */
  94.  
  95.     if (PHYSFS_init(args))
  96.         printf("Successful.\n");
  97.     else
  98.         printf("Failure. reason: %s.\n", PHYSFS_getLastError());
  99.  
  100.     return 1;
  101. } /* cmd_init */
  102.  
  103.  
  104. static int cmd_deinit(char *args)
  105. {
  106.     if (PHYSFS_deinit())
  107.         printf("Successful.\n");
  108.     else
  109.         printf("Failure. reason: %s.\n", PHYSFS_getLastError());
  110.  
  111.     return 1;
  112. } /* cmd_deinit */
  113.  
  114.  
  115. static int cmd_addarchive(char *args)
  116. {
  117.     char *ptr = strrchr(args, ' ');
  118.     int appending = atoi(ptr + 1);
  119.     *ptr = '\0';
  120.  
  121.     if (*args == '\"')
  122.     {
  123.         args++;
  124.         *(ptr - 1) = '\0';
  125.     } /* if */
  126.  
  127.     /*printf("[%s], [%d]\n", args, appending);*/
  128.  
  129.     if (PHYSFS_mount(args, NULL, appending))
  130.         printf("Successful.\n");
  131.     else
  132.         printf("Failure. reason: %s.\n", PHYSFS_getLastError());
  133.  
  134.     return 1;
  135. } /* cmd_addarchive */
  136.  
  137.  
  138. /* wrap free() to avoid calling convention wankery. */
  139. static void freeBuf(void *buf)
  140. {
  141.     free(buf);
  142. } /* freeBuf */
  143.  
  144. typedef enum
  145. {
  146.     MNTTYPE_PATH,
  147.     MNTTYPE_MEMORY,
  148.     MNTTYPE_HANDLE
  149. } MountType;
  150.  
  151. static int cmd_mount_internal(char *args, const MountType mnttype)
  152. {
  153.     char *ptr;
  154.     char *mntpoint = NULL;
  155.     int appending = 0;
  156.     int rc = 0;
  157.  
  158.     if (*args == '\"')
  159.     {
  160.         args++;
  161.         ptr = strchr(args, '\"');
  162.         if (ptr == NULL)
  163.         {
  164.             printf("missing string terminator in argument.\n");
  165.             return 1;
  166.         } /* if */
  167.         *(ptr) = '\0';
  168.     } /* if */
  169.     else
  170.     {
  171.         ptr = strchr(args, ' ');
  172.         *ptr = '\0';
  173.     } /* else */
  174.  
  175.     mntpoint = ptr + 1;
  176.     if (*mntpoint == '\"')
  177.     {
  178.         mntpoint++;
  179.         ptr = strchr(mntpoint, '\"');
  180.         if (ptr == NULL)
  181.         {
  182.             printf("missing string terminator in argument.\n");
  183.             return 1;
  184.         } /* if */
  185.         *(ptr) = '\0';
  186.     } /* if */
  187.     else
  188.     {
  189.         ptr = strchr(mntpoint, ' ');
  190.         *(ptr) = '\0';
  191.     } /* else */
  192.     appending = atoi(ptr + 1);
  193.  
  194.     /*printf("[%s], [%s], [%d]\n", args, mntpoint, appending);*/
  195.  
  196.     if (mnttype == MNTTYPE_PATH)
  197.         rc = PHYSFS_mount(args, mntpoint, appending);
  198.  
  199.     else if (mnttype == MNTTYPE_HANDLE)
  200.     {
  201.         PHYSFS_File *f = PHYSFS_openRead(args);
  202.         if (f == NULL)
  203.         {
  204.             printf("PHYSFS_openRead('%s') failed. reason: %s.\n", args, PHYSFS_getLastError());
  205.             return 1;
  206.         } /* if */
  207.  
  208.         rc = PHYSFS_mountHandle(f, args, mntpoint, appending);
  209.         if (!rc)
  210.             PHYSFS_close(f);
  211.     } /* else if */
  212.  
  213.     else if (mnttype == MNTTYPE_MEMORY)
  214.     {
  215.         FILE *in = fopen(args, "rb");
  216.         void *buf = NULL;
  217.         long len = 0;
  218.  
  219.         if (in == NULL)
  220.         {
  221.             printf("Failed to open %s to read into memory: %s.\n", args, strerror(errno));
  222.             return 1;
  223.         } /* if */
  224.  
  225.         if ( (fseek(in, 0, SEEK_END) != 0) || ((len = ftell(in)) < 0) )
  226.         {
  227.             printf("Failed to find size of %s to read into memory: %s.\n", args, strerror(errno));
  228.             fclose(in);
  229.             return 1;
  230.         } /* if */
  231.  
  232.         buf = malloc(len);
  233.         if (buf == NULL)
  234.         {
  235.             printf("Failed to allocate space to read %s into memory: %s.\n", args, strerror(errno));
  236.             fclose(in);
  237.             return 1;
  238.         } /* if */
  239.  
  240.         if ((fseek(in, 0, SEEK_SET) != 0) || (fread(buf, len, 1, in) != 1))
  241.         {
  242.             printf("Failed to read %s into memory: %s.\n", args, strerror(errno));
  243.             fclose(in);
  244.             free(buf);
  245.             return 1;
  246.         } /* if */
  247.  
  248.         fclose(in);
  249.  
  250.         rc = PHYSFS_mountMemory(buf, len, freeBuf, args, mntpoint, appending);
  251.     } /* else */
  252.  
  253.     if (rc)
  254.         printf("Successful.\n");
  255.     else
  256.         printf("Failure. reason: %s.\n", PHYSFS_getLastError());
  257.  
  258.     return 1;
  259. } /* cmd_mount_internal */
  260.  
  261.  
  262. static int cmd_mount(char *args)
  263. {
  264.     return cmd_mount_internal(args, MNTTYPE_PATH);
  265. } /* cmd_mount */
  266.  
  267.  
  268. static int cmd_mount_mem(char *args)
  269. {
  270.     return cmd_mount_internal(args, MNTTYPE_MEMORY);
  271. } /* cmd_mount_mem */
  272.  
  273.  
  274. static int cmd_mount_handle(char *args)
  275. {
  276.     return cmd_mount_internal(args, MNTTYPE_HANDLE);
  277. } /* cmd_mount_handle */
  278.  
  279. static int cmd_getmountpoint(char *args)
  280. {
  281.     if (*args == '\"')
  282.     {
  283.         args++;
  284.         args[strlen(args) - 1] = '\0';
  285.     } /* if */
  286.  
  287.     printf("Dir [%s] is mounted at [%s].\n", args, PHYSFS_getMountPoint(args));
  288.     return 1;
  289. } /* cmd_getmountpoint */
  290.  
  291. static int cmd_removearchive(char *args)
  292. {
  293.     if (*args == '\"')
  294.     {
  295.         args++;
  296.         args[strlen(args) - 1] = '\0';
  297.     } /* if */
  298.  
  299.     if (PHYSFS_unmount(args))
  300.         printf("Successful.\n");
  301.     else
  302.         printf("Failure. reason: %s.\n", PHYSFS_getLastError());
  303.  
  304.     return 1;
  305. } /* cmd_removearchive */
  306.  
  307.  
  308. static int cmd_enumerate(char *args)
  309. {
  310.     char **rc;
  311.  
  312.     if (*args == '\"')
  313.     {
  314.         args++;
  315.         args[strlen(args) - 1] = '\0';
  316.     } /* if */
  317.  
  318.     rc = PHYSFS_enumerateFiles(args);
  319.  
  320.     if (rc == NULL)
  321.         printf("Failure. reason: %s.\n", PHYSFS_getLastError());
  322.     else
  323.     {
  324.         int file_count;
  325.         char **i;
  326.         for (i = rc, file_count = 0; *i != NULL; i++, file_count++)
  327.             printf("%s\n", *i);
  328.  
  329.         printf("\n total (%d) files.\n", file_count);
  330.         PHYSFS_freeList(rc);
  331.     } /* else */
  332.  
  333.     return 1;
  334. } /* cmd_enumerate */
  335.  
  336.  
  337. static int cmd_getdirsep(char *args)
  338. {
  339.     printf("Directory separator is [%s].\n", PHYSFS_getDirSeparator());
  340.     return 1;
  341. } /* cmd_getdirsep */
  342.  
  343.  
  344. static int cmd_getlasterror(char *args)
  345. {
  346.     printf("last error is [%s].\n", PHYSFS_getLastError());
  347.     return 1;
  348. } /* cmd_getlasterror */
  349.  
  350.  
  351. static int cmd_getcdromdirs(char *args)
  352. {
  353.     char **rc = PHYSFS_getCdRomDirs();
  354.  
  355.     if (rc == NULL)
  356.         printf("Failure. Reason: [%s].\n", PHYSFS_getLastError());
  357.     else
  358.     {
  359.         int dir_count;
  360.         char **i;
  361.         for (i = rc, dir_count = 0; *i != NULL; i++, dir_count++)
  362.             printf("%s\n", *i);
  363.  
  364.         printf("\n total (%d) drives.\n", dir_count);
  365.         PHYSFS_freeList(rc);
  366.     } /* else */
  367.  
  368.     return 1;
  369. } /* cmd_getcdromdirs */
  370.  
  371.  
  372. static int cmd_getsearchpath(char *args)
  373. {
  374.     char **rc = PHYSFS_getSearchPath();
  375.  
  376.     if (rc == NULL)
  377.         printf("Failure. reason: %s.\n", PHYSFS_getLastError());
  378.     else
  379.     {
  380.         int dir_count;
  381.         char **i;
  382.         for (i = rc, dir_count = 0; *i != NULL; i++, dir_count++)
  383.             printf("%s\n", *i);
  384.  
  385.         printf("\n total (%d) directories.\n", dir_count);
  386.         PHYSFS_freeList(rc);
  387.     } /* else */
  388.  
  389.     return 1;
  390. } /* cmd_getcdromdirs */
  391.  
  392.  
  393. static int cmd_getbasedir(char *args)
  394. {
  395.     printf("Base dir is [%s].\n", PHYSFS_getBaseDir());
  396.     return 1;
  397. } /* cmd_getbasedir */
  398.  
  399.  
  400. static int cmd_getuserdir(char *args)
  401. {
  402.     printf("User dir is [%s].\n", PHYSFS_getUserDir());
  403.     return 1;
  404. } /* cmd_getuserdir */
  405.  
  406.  
  407. static int cmd_getprefdir(char *args)
  408. {
  409.     char *org;
  410.     char *appName;
  411.     char *ptr = args;
  412.  
  413.     org = ptr;
  414.     ptr = strchr(ptr, ' '); *ptr = '\0'; ptr++; appName = ptr;
  415.     printf("Pref dir is [%s].\n", PHYSFS_getPrefDir(org, appName));
  416.     return 1;
  417. } /* cmd_getprefdir */
  418.  
  419.  
  420. static int cmd_getwritedir(char *args)
  421. {
  422.     printf("Write dir is [%s].\n", PHYSFS_getWriteDir());
  423.     return 1;
  424. } /* cmd_getwritedir */
  425.  
  426.  
  427. static int cmd_setwritedir(char *args)
  428. {
  429.     if (*args == '\"')
  430.     {
  431.         args++;
  432.         args[strlen(args) - 1] = '\0';
  433.     } /* if */
  434.  
  435.     if (PHYSFS_setWriteDir(args))
  436.         printf("Successful.\n");
  437.     else
  438.         printf("Failure. reason: %s.\n", PHYSFS_getLastError());
  439.  
  440.     return 1;
  441. } /* cmd_setwritedir */
  442.  
  443.  
  444. static int cmd_permitsyms(char *args)
  445. {
  446.     int num;
  447.  
  448.     if (*args == '\"')
  449.     {
  450.         args++;
  451.         args[strlen(args) - 1] = '\0';
  452.     } /* if */
  453.  
  454.     num = atoi(args);
  455.     PHYSFS_permitSymbolicLinks(num);
  456.     printf("Symlinks are now %s.\n", num ? "permitted" : "forbidden");
  457.     return 1;
  458. } /* cmd_permitsyms */
  459.  
  460.  
  461. static int cmd_setbuffer(char *args)
  462. {
  463.     if (*args == '\"')
  464.     {
  465.         args++;
  466.         args[strlen(args) - 1] = '\0';
  467.     } /* if */
  468.  
  469.     do_buffer_size = (unsigned int) atoi(args);
  470.     if (do_buffer_size)
  471.     {
  472.         printf("Further tests will set a (%lu) size buffer.\n",
  473.                 (unsigned long) do_buffer_size);
  474.     } /* if */
  475.  
  476.     else
  477.     {
  478.         printf("Further tests will NOT use a buffer.\n");
  479.     } /* else */
  480.  
  481.     return 1;
  482. } /* cmd_setbuffer */
  483.  
  484.  
  485. static int cmd_stressbuffer(char *args)
  486. {
  487.     int num;
  488.  
  489.     if (*args == '\"')
  490.     {
  491.         args++;
  492.         args[strlen(args) - 1] = '\0';
  493.     } /* if */
  494.  
  495.     num = atoi(args);
  496.     if (num < 0)
  497.         printf("buffer must be greater than or equal to zero.\n");
  498.     else
  499.     {
  500.         PHYSFS_File *f;
  501.         int rndnum;
  502.  
  503.         printf("Stress testing with (%d) byte buffer...\n", num);
  504.         f = PHYSFS_openWrite("test.txt");
  505.         if (f == NULL)
  506.             printf("Couldn't open test.txt for writing: %s.\n", PHYSFS_getLastError());
  507.         else
  508.         {
  509.             int i, j;
  510.             char buf[37];
  511.             char buf2[37];
  512.  
  513.             if (!PHYSFS_setBuffer(f, num))
  514.             {
  515.                 printf("PHYSFS_setBuffer() failed: %s.\n", PHYSFS_getLastError());
  516.                 PHYSFS_close(f);
  517.                 PHYSFS_delete("test.txt");
  518.                 return 1;
  519.             } /* if */
  520.  
  521.             strcpy(buf, "abcdefghijklmnopqrstuvwxyz0123456789");
  522.             srand((unsigned int) time(NULL));
  523.  
  524.             for (i = 0; i < 10; i++)
  525.             {
  526.                 for (j = 0; j < 10000; j++)
  527.                 {
  528.                     PHYSFS_uint32 right = 1 + (PHYSFS_uint32) (35.0 * rand() / (RAND_MAX + 1.0));
  529.                     PHYSFS_uint32 left = 36 - right;
  530.                     if (PHYSFS_writeBytes(f, buf, left) != left)
  531.                     {
  532.                         printf("PHYSFS_writeBytes() failed: %s.\n", PHYSFS_getLastError());
  533.                         PHYSFS_close(f);
  534.                         return 1;
  535.                     } /* if */
  536.  
  537.                     rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
  538.                     if (rndnum == 42)
  539.                     {
  540.                         if (!PHYSFS_flush(f))
  541.                         {
  542.                             printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
  543.                             PHYSFS_close(f);
  544.                             return 1;
  545.                         } /* if */
  546.                     } /* if */
  547.  
  548.                     if (PHYSFS_writeBytes(f, buf + left, right) != right)
  549.                     {
  550.                         printf("PHYSFS_writeBytes() failed: %s.\n", PHYSFS_getLastError());
  551.                         PHYSFS_close(f);
  552.                         return 1;
  553.                     } /* if */
  554.  
  555.                     rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
  556.                     if (rndnum == 42)
  557.                     {
  558.                         if (!PHYSFS_flush(f))
  559.                         {
  560.                             printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
  561.                             PHYSFS_close(f);
  562.                             return 1;
  563.                         } /* if */
  564.                     } /* if */
  565.                 } /* for */
  566.  
  567.                 if (!PHYSFS_flush(f))
  568.                 {
  569.                     printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
  570.                     PHYSFS_close(f);
  571.                     return 1;
  572.                 } /* if */
  573.  
  574.             } /* for */
  575.  
  576.             if (!PHYSFS_close(f))
  577.             {
  578.                 printf("PHYSFS_close() failed: %s.\n", PHYSFS_getLastError());
  579.                 return 1;  /* oh well. */
  580.             } /* if */
  581.  
  582.             printf(" ... test file written ...\n");
  583.             f = PHYSFS_openRead("test.txt");
  584.             if (f == NULL)
  585.             {
  586.                 printf("Failed to reopen stress file for reading: %s.\n", PHYSFS_getLastError());
  587.                 return 1;
  588.             } /* if */
  589.  
  590.             if (!PHYSFS_setBuffer(f, num))
  591.             {
  592.                 printf("PHYSFS_setBuffer() failed: %s.\n", PHYSFS_getLastError());
  593.                 PHYSFS_close(f);
  594.                 return 1;
  595.             } /* if */
  596.  
  597.             for (i = 0; i < 10; i++)
  598.             {
  599.                 for (j = 0; j < 10000; j++)
  600.                 {
  601.                     PHYSFS_uint32 right = 1 + (PHYSFS_uint32) (35.0 * rand() / (RAND_MAX + 1.0));
  602.                     PHYSFS_uint32 left = 36 - right;
  603.                     if (PHYSFS_readBytes(f, buf2, left) != left)
  604.                     {
  605.                         printf("PHYSFS_readBytes() failed: %s.\n", PHYSFS_getLastError());
  606.                         PHYSFS_close(f);
  607.                         return 1;
  608.                     } /* if */
  609.  
  610.                     rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
  611.                     if (rndnum == 42)
  612.                     {
  613.                         if (!PHYSFS_flush(f))
  614.                         {
  615.                             printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
  616.                             PHYSFS_close(f);
  617.                             return 1;
  618.                         } /* if */
  619.                     } /* if */
  620.  
  621.                     if (PHYSFS_readBytes(f, buf2 + left, right) != right)
  622.                     {
  623.                         printf("PHYSFS_readBytes() failed: %s.\n", PHYSFS_getLastError());
  624.                         PHYSFS_close(f);
  625.                         return 1;
  626.                     } /* if */
  627.  
  628.                     rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
  629.                     if (rndnum == 42)
  630.                     {
  631.                         if (!PHYSFS_flush(f))
  632.                         {
  633.                             printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
  634.                             PHYSFS_close(f);
  635.                             return 1;
  636.                         } /* if */
  637.                     } /* if */
  638.  
  639.                     if (memcmp(buf, buf2, 36) != 0)
  640.                     {
  641.                         printf("readback is mismatched on iterations (%d, %d).\n", i, j);
  642.                         printf("wanted: [");
  643.                         for (i = 0; i < 36; i++)
  644.                             printf("%c", buf[i]);
  645.                         printf("]\n");
  646.  
  647.                         printf("   got: [");
  648.                         for (i = 0; i < 36; i++)
  649.                             printf("%c", buf2[i]);
  650.                         printf("]\n");
  651.                         PHYSFS_close(f);
  652.                         return 1;
  653.                     } /* if */
  654.                 } /* for */
  655.  
  656.                 if (!PHYSFS_flush(f))
  657.                 {
  658.                     printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
  659.                     PHYSFS_close(f);
  660.                     return 1;
  661.                 } /* if */
  662.  
  663.             } /* for */
  664.  
  665.             printf(" ... test file read ...\n");
  666.  
  667.             if (!PHYSFS_eof(f))
  668.                 printf("PHYSFS_eof() returned true! That's wrong.\n");
  669.  
  670.             if (!PHYSFS_close(f))
  671.             {
  672.                 printf("PHYSFS_close() failed: %s.\n", PHYSFS_getLastError());
  673.                 return 1;  /* oh well. */
  674.             } /* if */
  675.  
  676.             PHYSFS_delete("test.txt");
  677.             printf("stress test completed successfully.\n");
  678.         } /* else */
  679.     } /* else */
  680.  
  681.     return 1;
  682. } /* cmd_stressbuffer */
  683.  
  684.  
  685. static int cmd_setsaneconfig(char *args)
  686. {
  687.     char *org;
  688.     char *appName;
  689.     char *arcExt;
  690.     int inclCD;
  691.     int arcsFirst;
  692.     char *ptr = args;
  693.  
  694.         /* ugly. */
  695.     org = ptr;
  696.     ptr = strchr(ptr, ' '); *ptr = '\0'; ptr++; appName = ptr;
  697.     ptr = strchr(ptr, ' '); *ptr = '\0'; ptr++; arcExt = ptr;
  698.     ptr = strchr(ptr, ' '); *ptr = '\0'; ptr++; inclCD = atoi(arcExt);
  699.     arcsFirst = atoi(ptr);
  700.  
  701.     if (strcmp(arcExt, "!") == 0)
  702.         arcExt = NULL;
  703.  
  704.     if (PHYSFS_setSaneConfig(org, appName, arcExt, inclCD, arcsFirst))
  705.         printf("Successful.\n");
  706.     else
  707.         printf("Failure. reason: %s.\n", PHYSFS_getLastError());
  708.  
  709.     return 1;
  710. } /* cmd_setsaneconfig */
  711.  
  712.  
  713. static int cmd_mkdir(char *args)
  714. {
  715.     if (*args == '\"')
  716.     {
  717.         args++;
  718.         args[strlen(args) - 1] = '\0';
  719.     } /* if */
  720.  
  721.     if (PHYSFS_mkdir(args))
  722.         printf("Successful.\n");
  723.     else
  724.         printf("Failure. reason: %s.\n", PHYSFS_getLastError());
  725.  
  726.     return 1;
  727. } /* cmd_mkdir */
  728.  
  729.  
  730. static int cmd_delete(char *args)
  731. {
  732.     if (*args == '\"')
  733.     {
  734.         args++;
  735.         args[strlen(args) - 1] = '\0';
  736.     } /* if */
  737.  
  738.     if (PHYSFS_delete(args))
  739.         printf("Successful.\n");
  740.     else
  741.         printf("Failure. reason: %s.\n", PHYSFS_getLastError());
  742.  
  743.     return 1;
  744. } /* cmd_delete */
  745.  
  746.  
  747. static int cmd_getrealdir(char *args)
  748. {
  749.     const char *rc;
  750.  
  751.     if (*args == '\"')
  752.     {
  753.         args++;
  754.         args[strlen(args) - 1] = '\0';
  755.     } /* if */
  756.  
  757.     rc = PHYSFS_getRealDir(args);
  758.     if (rc)
  759.         printf("Found at [%s].\n", rc);
  760.     else
  761.         printf("Not found.\n");
  762.  
  763.     return 1;
  764. } /* cmd_getrealdir */
  765.  
  766.  
  767. static int cmd_exists(char *args)
  768. {
  769.     int rc;
  770.  
  771.     if (*args == '\"')
  772.     {
  773.         args++;
  774.         args[strlen(args) - 1] = '\0';
  775.     } /* if */
  776.  
  777.     rc = PHYSFS_exists(args);
  778.     printf("File %sexists.\n", rc ? "" : "does not ");
  779.     return 1;
  780. } /* cmd_exists */
  781.  
  782.  
  783. static int cmd_isdir(char *args)
  784. {
  785.     PHYSFS_Stat statbuf;
  786.     int rc;
  787.  
  788.     if (*args == '\"')
  789.     {
  790.         args++;
  791.         args[strlen(args) - 1] = '\0';
  792.     } /* if */
  793.  
  794.     rc = PHYSFS_stat(args, &statbuf);
  795.     if (rc)
  796.         rc = (statbuf.filetype == PHYSFS_FILETYPE_DIRECTORY);
  797.     printf("File %s a directory.\n", rc ? "is" : "is NOT");
  798.     return 1;
  799. } /* cmd_isdir */
  800.  
  801.  
  802. static int cmd_issymlink(char *args)
  803. {
  804.     PHYSFS_Stat statbuf;
  805.     int rc;
  806.  
  807.     if (*args == '\"')
  808.     {
  809.         args++;
  810.         args[strlen(args) - 1] = '\0';
  811.     } /* if */
  812.  
  813.     rc = PHYSFS_stat(args, &statbuf);
  814.     if (rc)
  815.         rc = (statbuf.filetype == PHYSFS_FILETYPE_SYMLINK);
  816.     printf("File %s a symlink.\n", rc ? "is" : "is NOT");
  817.     return 1;
  818. } /* cmd_issymlink */
  819.  
  820.  
  821. static int cmd_cat(char *args)
  822. {
  823.     PHYSFS_File *f;
  824.  
  825.     if (*args == '\"')
  826.     {
  827.         args++;
  828.         args[strlen(args) - 1] = '\0';
  829.     } /* if */
  830.  
  831.     f = PHYSFS_openRead(args);
  832.     if (f == NULL)
  833.         printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
  834.     else
  835.     {
  836.         if (do_buffer_size)
  837.         {
  838.             if (!PHYSFS_setBuffer(f, do_buffer_size))
  839.             {
  840.                 printf("failed to set file buffer. Reason: [%s].\n",
  841.                         PHYSFS_getLastError());
  842.                 PHYSFS_close(f);
  843.                 return 1;
  844.             } /* if */
  845.         } /* if */
  846.  
  847.         while (1)
  848.         {
  849.             char buffer[128];
  850.             PHYSFS_sint64 rc;
  851.             PHYSFS_sint64 i;
  852.             rc = PHYSFS_readBytes(f, buffer, sizeof (buffer));
  853.  
  854.             for (i = 0; i < rc; i++)
  855.                 fputc((int) buffer[i], stdout);
  856.  
  857.             if (rc < sizeof (buffer))
  858.             {
  859.                 printf("\n\n");
  860.                 if (!PHYSFS_eof(f))
  861.                 {
  862.                     printf("\n (Error condition in reading. Reason: [%s])\n\n",
  863.                            PHYSFS_getLastError());
  864.                 } /* if */
  865.                 PHYSFS_close(f);
  866.                 return 1;
  867.             } /* if */
  868.         } /* while */
  869.     } /* else */
  870.  
  871.     return 1;
  872. } /* cmd_cat */
  873.  
  874. static int cmd_cat2(char *args)
  875. {
  876.     PHYSFS_File *f1 = NULL;
  877.     PHYSFS_File *f2 = NULL;
  878.     char *fname1;
  879.     char *fname2;
  880.     char *ptr;
  881.  
  882.     fname1 = args;
  883.     if (*fname1 == '\"')
  884.     {
  885.         fname1++;
  886.         ptr = strchr(fname1, '\"');
  887.         if (ptr == NULL)
  888.         {
  889.             printf("missing string terminator in argument.\n");
  890.             return 1;
  891.         } /* if */
  892.         *(ptr) = '\0';
  893.     } /* if */
  894.     else
  895.     {
  896.         ptr = strchr(fname1, ' ');
  897.         *ptr = '\0';
  898.     } /* else */
  899.  
  900.     fname2 = ptr + 1;
  901.     if (*fname2 == '\"')
  902.     {
  903.         fname2++;
  904.         ptr = strchr(fname2, '\"');
  905.         if (ptr == NULL)
  906.         {
  907.             printf("missing string terminator in argument.\n");
  908.             return 1;
  909.         } /* if */
  910.         *(ptr) = '\0';
  911.     } /* if */
  912.  
  913.     if ((f1 = PHYSFS_openRead(fname1)) == NULL)
  914.         printf("failed to open '%s'. Reason: [%s].\n", fname1, PHYSFS_getLastError());
  915.     else if ((f2 = PHYSFS_openRead(fname2)) == NULL)
  916.         printf("failed to open '%s'. Reason: [%s].\n", fname2, PHYSFS_getLastError());
  917.     else
  918.     {
  919.         char *buffer1 = NULL;
  920.         size_t buffer1len = 0;
  921.         char *buffer2 = NULL;
  922.         size_t buffer2len = 0;
  923.         char *ptr = NULL;
  924.         size_t i;
  925.  
  926.         if (do_buffer_size)
  927.         {
  928.             if (!PHYSFS_setBuffer(f1, do_buffer_size))
  929.             {
  930.                 printf("failed to set file buffer for '%s'. Reason: [%s].\n",
  931.                         fname1, PHYSFS_getLastError());
  932.                 PHYSFS_close(f1);
  933.                 PHYSFS_close(f2);
  934.                 return 1;
  935.             } /* if */
  936.             else if (!PHYSFS_setBuffer(f2, do_buffer_size))
  937.             {
  938.                 printf("failed to set file buffer for '%s'. Reason: [%s].\n",
  939.                         fname2, PHYSFS_getLastError());
  940.                 PHYSFS_close(f1);
  941.                 PHYSFS_close(f2);
  942.                 return 1;
  943.             } /* if */
  944.         } /* if */
  945.  
  946.  
  947.         do
  948.         {
  949.             int readlen = 128;
  950.             PHYSFS_sint64 rc;
  951.  
  952.             ptr = realloc(buffer1, buffer1len + readlen);
  953.             if (!ptr)
  954.             {
  955.                 printf("(Out of memory.)\n\n");
  956.                 free(buffer1);
  957.                 free(buffer2);
  958.                 PHYSFS_close(f1);
  959.                 PHYSFS_close(f2);
  960.                 return 1;
  961.             } /* if */
  962.  
  963.             buffer1 = ptr;
  964.             rc = PHYSFS_readBytes(f1, buffer1 + buffer1len, readlen);
  965.             if (rc < 0)
  966.             {
  967.                 printf("(Error condition in reading '%s'. Reason: [%s])\n\n",
  968.                        fname1, PHYSFS_getLastError());
  969.                 free(buffer1);
  970.                 free(buffer2);
  971.                 PHYSFS_close(f1);
  972.                 PHYSFS_close(f2);
  973.                 return 1;
  974.             } /* if */
  975.             buffer1len += (size_t) rc;
  976.  
  977.             ptr = realloc(buffer2, buffer2len + readlen);
  978.             if (!ptr)
  979.             {
  980.                 printf("(Out of memory.)\n\n");
  981.                 free(buffer1);
  982.                 free(buffer2);
  983.                 PHYSFS_close(f1);
  984.                 PHYSFS_close(f2);
  985.                 return 1;
  986.             } /* if */
  987.  
  988.             buffer2 = ptr;
  989.             rc = PHYSFS_readBytes(f2, buffer2 + buffer2len, readlen);
  990.             if (rc < 0)
  991.             {
  992.                 printf("(Error condition in reading '%s'. Reason: [%s])\n\n",
  993.                        fname2, PHYSFS_getLastError());
  994.                 free(buffer1);
  995.                 free(buffer2);
  996.                 PHYSFS_close(f1);
  997.                 PHYSFS_close(f2);
  998.                 return 1;
  999.             } /* if */
  1000.             buffer2len += (size_t) rc;
  1001.         } while (!PHYSFS_eof(f1) || !PHYSFS_eof(f2));
  1002.  
  1003.         printf("file '%s' ...\n\n", fname1);
  1004.         for (i = 0; i < buffer1len; i++)
  1005.             fputc((int) buffer1[i], stdout);
  1006.         free(buffer1);
  1007.  
  1008.         printf("\n\nfile '%s' ...\n\n", fname2);
  1009.         for (i = 0; i < buffer2len; i++)
  1010.             fputc((int) buffer2[i], stdout);
  1011.         free(buffer2);
  1012.  
  1013.         printf("\n\n");
  1014.     } /* else */
  1015.  
  1016.     if (f1)
  1017.         PHYSFS_close(f1);
  1018.  
  1019.     if (f2)
  1020.         PHYSFS_close(f2);
  1021.  
  1022.     return 1;
  1023. } /* cmd_cat2 */
  1024.  
  1025.  
  1026. #define CRC32_BUFFERSIZE 512
  1027. static int cmd_crc32(char *args)
  1028. {
  1029.     PHYSFS_File *f;
  1030.  
  1031.     if (*args == '\"')
  1032.     {
  1033.         args++;
  1034.         args[strlen(args) - 1] = '\0';
  1035.     } /* if */
  1036.  
  1037.     f = PHYSFS_openRead(args);
  1038.     if (f == NULL)
  1039.         printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
  1040.     else
  1041.     {
  1042.         PHYSFS_uint8 buffer[CRC32_BUFFERSIZE];
  1043.         PHYSFS_uint32 crc = -1;
  1044.         PHYSFS_sint64 bytesread;
  1045.  
  1046.         while ((bytesread = PHYSFS_readBytes(f, buffer, CRC32_BUFFERSIZE)) > 0)
  1047.         {
  1048.             PHYSFS_uint32 i, bit;
  1049.             for (i = 0; i < bytesread; i++)
  1050.             {
  1051.                 for (bit = 0; bit < 8; bit++, buffer[i] >>= 1)
  1052.                     crc = (crc >> 1) ^ (((crc ^ buffer[i]) & 1) ? 0xEDB88320 : 0);
  1053.             } /* for */
  1054.         } /* while */
  1055.  
  1056.         if (bytesread < 0)
  1057.         {
  1058.             printf("error while reading. Reason: [%s].\n",
  1059.                    PHYSFS_getLastError());
  1060.             return 1;
  1061.         } /* if */
  1062.  
  1063.         PHYSFS_close(f);
  1064.  
  1065.         crc ^= -1;
  1066.         printf("CRC32 for %s: 0x%08X\n", args, crc);
  1067.     } /* else */
  1068.  
  1069.     return 1;
  1070. } /* cmd_crc32 */
  1071.  
  1072.  
  1073. static int cmd_filelength(char *args)
  1074. {
  1075.     PHYSFS_File *f;
  1076.  
  1077.     if (*args == '\"')
  1078.     {
  1079.         args++;
  1080.         args[strlen(args) - 1] = '\0';
  1081.     } /* if */
  1082.  
  1083.     f = PHYSFS_openRead(args);
  1084.     if (f == NULL)
  1085.         printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
  1086.     else
  1087.     {
  1088.         PHYSFS_sint64 len = PHYSFS_fileLength(f);
  1089.         if (len == -1)
  1090.             printf("failed to determine length. Reason: [%s].\n", PHYSFS_getLastError());
  1091.         else
  1092.             printf(" (cast to int) %d bytes.\n", (int) len);
  1093.  
  1094.         PHYSFS_close(f);
  1095.     } /* else */
  1096.  
  1097.     return 1;
  1098. } /* cmd_filelength */
  1099.  
  1100. #define WRITESTR "The cat sat on the mat.\n\n"
  1101.  
  1102. static int cmd_append(char *args)
  1103. {
  1104.     PHYSFS_File *f;
  1105.  
  1106.     if (*args == '\"')
  1107.     {
  1108.         args++;
  1109.         args[strlen(args) - 1] = '\0';
  1110.     } /* if */
  1111.  
  1112.     f = PHYSFS_openAppend(args);
  1113.     if (f == NULL)
  1114.         printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
  1115.     else
  1116.     {
  1117.         size_t bw;
  1118.         PHYSFS_sint64 rc;
  1119.  
  1120.         if (do_buffer_size)
  1121.         {
  1122.             if (!PHYSFS_setBuffer(f, do_buffer_size))
  1123.             {
  1124.                 printf("failed to set file buffer. Reason: [%s].\n",
  1125.                         PHYSFS_getLastError());
  1126.                 PHYSFS_close(f);
  1127.                 return 1;
  1128.             } /* if */
  1129.         } /* if */
  1130.  
  1131.         bw = strlen(WRITESTR);
  1132.         rc = PHYSFS_writeBytes(f, WRITESTR, bw);
  1133.         if (rc != bw)
  1134.         {
  1135.             printf("Wrote (%d) of (%d) bytes. Reason: [%s].\n",
  1136.                    (int) rc, (int) bw, PHYSFS_getLastError());
  1137.         } /* if */
  1138.         else
  1139.         {
  1140.             printf("Successful.\n");
  1141.         } /* else */
  1142.  
  1143.         PHYSFS_close(f);
  1144.     } /* else */
  1145.  
  1146.     return 1;
  1147. } /* cmd_append */
  1148.  
  1149.  
  1150. static int cmd_write(char *args)
  1151. {
  1152.     PHYSFS_File *f;
  1153.  
  1154.     if (*args == '\"')
  1155.     {
  1156.         args++;
  1157.         args[strlen(args) - 1] = '\0';
  1158.     } /* if */
  1159.  
  1160.     f = PHYSFS_openWrite(args);
  1161.     if (f == NULL)
  1162.         printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
  1163.     else
  1164.     {
  1165.         size_t bw;
  1166.         PHYSFS_sint64 rc;
  1167.  
  1168.         if (do_buffer_size)
  1169.         {
  1170.             if (!PHYSFS_setBuffer(f, do_buffer_size))
  1171.             {
  1172.                 printf("failed to set file buffer. Reason: [%s].\n",
  1173.                         PHYSFS_getLastError());
  1174.                 PHYSFS_close(f);
  1175.                 return 1;
  1176.             } /* if */
  1177.         } /* if */
  1178.  
  1179.         bw = strlen(WRITESTR);
  1180.         rc = PHYSFS_writeBytes(f, WRITESTR, bw);
  1181.         if (rc != bw)
  1182.         {
  1183.             printf("Wrote (%d) of (%d) bytes. Reason: [%s].\n",
  1184.                    (int) rc, (int) bw, PHYSFS_getLastError());
  1185.         } /* if */
  1186.         else
  1187.         {
  1188.             printf("Successful.\n");
  1189.         } /* else */
  1190.  
  1191.         PHYSFS_close(f);
  1192.     } /* else */
  1193.  
  1194.     return 1;
  1195. } /* cmd_write */
  1196.  
  1197.  
  1198. static char* modTimeToStr(PHYSFS_sint64 modtime, char *modstr, size_t strsize)
  1199. {
  1200.     if (modtime < 0)
  1201.         strncpy(modstr, "Unknown\n", strsize);
  1202.     else
  1203.     {
  1204.         time_t t = (time_t) modtime;
  1205.         char *str = ctime(&t);
  1206.         strncpy(modstr, str, strsize);
  1207.     } /* else */
  1208.  
  1209.     modstr[strsize-1] = '\0';
  1210.     return modstr;
  1211. } /* modTimeToStr */
  1212.  
  1213.  
  1214. static int cmd_getlastmodtime(char *args)
  1215. {
  1216.     PHYSFS_Stat statbuf;
  1217.     if (!PHYSFS_stat(args, &statbuf))
  1218.         printf("Failed to determine. Reason: [%s].\n", PHYSFS_getLastError());
  1219.     else
  1220.     {
  1221.         char modstr[64];
  1222.         modTimeToStr(statbuf.modtime, modstr, sizeof (modstr));
  1223.         printf("Last modified: %s (%ld).\n", modstr, (long) statbuf.modtime);
  1224.     } /* else */
  1225.  
  1226.     return 1;
  1227. } /* cmd_getLastModTime */
  1228.  
  1229. static int cmd_stat(char *args)
  1230. {
  1231.     PHYSFS_Stat stat;
  1232.     char timestring[65];
  1233.  
  1234.     if (*args == '\"')
  1235.     {
  1236.         args++;
  1237.         args[strlen(args) - 1] = '\0';
  1238.     } /* if */
  1239.  
  1240.     if(!PHYSFS_stat(args, &stat))
  1241.     {
  1242.         printf("failed to stat. Reason [%s].\n", PHYSFS_getLastError());
  1243.         return 1;
  1244.     } /* if */
  1245.  
  1246.     printf("Filename: %s\n", args);
  1247.     printf("Size %d\n",(int) stat.filesize);
  1248.  
  1249.     if(stat.filetype == PHYSFS_FILETYPE_REGULAR)
  1250.         printf("Type: File\n");
  1251.     else if(stat.filetype == PHYSFS_FILETYPE_DIRECTORY)
  1252.         printf("Type: Directory\n");
  1253.     else if(stat.filetype == PHYSFS_FILETYPE_SYMLINK)
  1254.         printf("Type: Symlink\n");
  1255.     else
  1256.         printf("Type: Unknown\n");
  1257.  
  1258.     printf("Created at: %s", modTimeToStr(stat.createtime, timestring, 64));
  1259.     printf("Last modified at: %s", modTimeToStr(stat.modtime, timestring, 64));
  1260.     printf("Last accessed at: %s", modTimeToStr(stat.accesstime, timestring, 64));
  1261.     printf("Readonly: %s\n", stat.readonly ? "true" : "false");
  1262.  
  1263.     return 1;
  1264. } /* cmd_filelength */
  1265.  
  1266.  
  1267.  
  1268. /* must have spaces trimmed prior to this call. */
  1269. static int count_args(const char *str)
  1270. {
  1271.     int retval = 0;
  1272.     int in_quotes = 0;
  1273.  
  1274.     if (str != NULL)
  1275.     {
  1276.         for (; *str != '\0'; str++)
  1277.         {
  1278.             if (*str == '\"')
  1279.                 in_quotes = !in_quotes;
  1280.             else if ((*str == ' ') && (!in_quotes))
  1281.                 retval++;
  1282.         } /* for */
  1283.         retval++;
  1284.     } /* if */
  1285.  
  1286.     return retval;
  1287. } /* count_args */
  1288.  
  1289.  
  1290. static int cmd_help(char *args);
  1291.  
  1292. typedef struct
  1293. {
  1294.     const char *cmd;
  1295.     int (*func)(char *args);
  1296.     int argcount;
  1297.     const char *usage;
  1298. } command_info;
  1299.  
  1300. static const command_info commands[] =
  1301. {
  1302.     { "quit",           cmd_quit,           0, NULL                         },
  1303.     { "q",              cmd_quit,           0, NULL                         },
  1304.     { "help",           cmd_help,           0, NULL                         },
  1305.     { "init",           cmd_init,           1, "<argv0>"                    },
  1306.     { "deinit",         cmd_deinit,         0, NULL                         },
  1307.     { "addarchive",     cmd_addarchive,     2, "<archiveLocation> <append>" },
  1308.     { "mount",          cmd_mount,          3, "<archiveLocation> <mntpoint> <append>" },
  1309.     { "mountmem",       cmd_mount_mem,      3, "<archiveLocation> <mntpoint> <append>" },
  1310.     { "mounthandle",    cmd_mount_handle,   3, "<archiveLocation> <mntpoint> <append>" },
  1311.     { "removearchive",  cmd_removearchive,  1, "<archiveLocation>"          },
  1312.     { "unmount",        cmd_removearchive,  1, "<archiveLocation>"          },
  1313.     { "enumerate",      cmd_enumerate,      1, "<dirToEnumerate>"           },
  1314.     { "ls",             cmd_enumerate,      1, "<dirToEnumerate>"           },
  1315.     { "getlasterror",   cmd_getlasterror,   0, NULL                         },
  1316.     { "getdirsep",      cmd_getdirsep,      0, NULL                         },
  1317.     { "getcdromdirs",   cmd_getcdromdirs,   0, NULL                         },
  1318.     { "getsearchpath",  cmd_getsearchpath,  0, NULL                         },
  1319.     { "getbasedir",     cmd_getbasedir,     0, NULL                         },
  1320.     { "getuserdir",     cmd_getuserdir,     0, NULL                         },
  1321.     { "getprefdir",     cmd_getprefdir,     2, "<org> <app>"                },
  1322.     { "getwritedir",    cmd_getwritedir,    0, NULL                         },
  1323.     { "setwritedir",    cmd_setwritedir,    1, "<newWriteDir>"              },
  1324.     { "permitsymlinks", cmd_permitsyms,     1, "<1or0>"                     },
  1325.     { "setsaneconfig",  cmd_setsaneconfig,  5, "<org> <appName> <arcExt> <includeCdRoms> <archivesFirst>" },
  1326.     { "mkdir",          cmd_mkdir,          1, "<dirToMk>"                  },
  1327.     { "delete",         cmd_delete,         1, "<dirToDelete>"              },
  1328.     { "getrealdir",     cmd_getrealdir,     1, "<fileToFind>"               },
  1329.     { "exists",         cmd_exists,         1, "<fileToCheck>"              },
  1330.     { "isdir",          cmd_isdir,          1, "<fileToCheck>"              },
  1331.     { "issymlink",      cmd_issymlink,      1, "<fileToCheck>"              },
  1332.     { "cat",            cmd_cat,            1, "<fileToCat>"                },
  1333.     { "cat2",           cmd_cat2,           2, "<fileToCat1> <fileToCat2>"  },
  1334.     { "filelength",     cmd_filelength,     1, "<fileToCheck>"              },
  1335.     { "stat",           cmd_stat,           1, "<fileToStat>"               },
  1336.     { "append",         cmd_append,         1, "<fileToAppend>"             },
  1337.     { "write",          cmd_write,          1, "<fileToCreateOrTrash>"      },
  1338.     { "getlastmodtime", cmd_getlastmodtime, 1, "<fileToExamine>"            },
  1339.     { "setbuffer",      cmd_setbuffer,      1, "<bufferSize>"               },
  1340.     { "stressbuffer",   cmd_stressbuffer,   1, "<bufferSize>"               },
  1341.     { "crc32",          cmd_crc32,          1, "<fileToHash>"               },
  1342.     { "getmountpoint",  cmd_getmountpoint,  1, "<dir>"                      },
  1343.     { NULL,             NULL,              -1, NULL                         }
  1344. };
  1345.  
  1346.  
  1347. static void output_usage(const char *intro, const command_info *cmdinfo)
  1348. {
  1349.     if (cmdinfo->argcount == 0)
  1350.         printf("%s \"%s\" (no arguments)\n", intro, cmdinfo->cmd);
  1351.     else
  1352.         printf("%s \"%s %s\"\n", intro, cmdinfo->cmd, cmdinfo->usage);
  1353. } /* output_usage */
  1354.  
  1355.  
  1356. static int cmd_help(char *args)
  1357. {
  1358.     const command_info *i;
  1359.  
  1360.     printf("Commands:\n");
  1361.     for (i = commands; i->cmd != NULL; i++)
  1362.         output_usage("  -", i);
  1363.  
  1364.     return 1;
  1365. } /* output_cmd_help */
  1366.  
  1367.  
  1368. static void trim_command(const char *orig, char *copy)
  1369. {
  1370.     const char *i;
  1371.     char *writeptr = copy;
  1372.     int spacecount = 0;
  1373.     int have_first = 0;
  1374.  
  1375.     for (i = orig; *i != '\0'; i++)
  1376.     {
  1377.         if (*i == ' ')
  1378.         {
  1379.             if ((*(i + 1) != ' ') && (*(i + 1) != '\0'))
  1380.             {
  1381.                 if ((have_first) && (!spacecount))
  1382.                 {
  1383.                     spacecount++;
  1384.                     *writeptr = ' ';
  1385.                     writeptr++;
  1386.                 } /* if */
  1387.             } /* if */
  1388.         } /* if */
  1389.         else
  1390.         {
  1391.             have_first = 1;
  1392.             spacecount = 0;
  1393.             *writeptr = *i;
  1394.             writeptr++;
  1395.         } /* else */
  1396.     } /* for */
  1397.  
  1398.     *writeptr = '\0';
  1399.  
  1400.     /*
  1401.     printf("\n command is [%s].\n", copy);
  1402.     */
  1403. } /* trim_command */
  1404.  
  1405.  
  1406. static int process_command(char *complete_cmd)
  1407. {
  1408.     const command_info *i;
  1409.     char *cmd_copy;
  1410.     char *args;
  1411.     int rc = 1;
  1412.  
  1413.     if (complete_cmd == NULL)  /* can happen if user hits CTRL-D, etc. */
  1414.     {
  1415.         printf("\n");
  1416.         return 0;
  1417.     } /* if */
  1418.  
  1419.     cmd_copy = (char *) malloc(strlen(complete_cmd) + 1);
  1420.     if (cmd_copy == NULL)
  1421.     {
  1422.         printf("\n\n\nOUT OF MEMORY!\n\n\n");
  1423.         return 0;
  1424.     } /* if */
  1425.  
  1426.     trim_command(complete_cmd, cmd_copy);
  1427.     args = strchr(cmd_copy, ' ');
  1428.     if (args != NULL)
  1429.     {
  1430.         *args = '\0';
  1431.         args++;
  1432.     } /* else */
  1433.  
  1434.     if (cmd_copy[0] != '\0')
  1435.     {
  1436.         for (i = commands; i->cmd != NULL; i++)
  1437.         {
  1438.             if (strcmp(i->cmd, cmd_copy) == 0)
  1439.             {
  1440.                 if ((i->argcount >= 0) && (count_args(args) != i->argcount))
  1441.                     output_usage("usage:", i);
  1442.                 else
  1443.                     rc = i->func(args);
  1444.                 break;
  1445.             } /* if */
  1446.         } /* for */
  1447.  
  1448.         if (i->cmd == NULL)
  1449.             printf("Unknown command. Enter \"help\" for instructions.\n");
  1450.  
  1451. #if (defined PHYSFS_HAVE_READLINE)
  1452.         add_history(complete_cmd);
  1453.         if (history_file)
  1454.         {
  1455.             fprintf(history_file, "%s\n", complete_cmd);
  1456.             fflush(history_file);
  1457.         } /* if */
  1458. #endif
  1459.  
  1460.     } /* if */
  1461.  
  1462.     free(cmd_copy);
  1463.     return rc;
  1464. } /* process_command */
  1465.  
  1466.  
  1467. static void open_history_file(void)
  1468. {
  1469. #if (defined PHYSFS_HAVE_READLINE)
  1470. #if 0
  1471.     const char *envr = getenv("TESTPHYSFS_HISTORY");
  1472.     if (!envr)
  1473.         return;
  1474. #else
  1475.     char envr[256];
  1476.     strcpy(envr, PHYSFS_getUserDir());
  1477.     strcat(envr, ".testphys_history");
  1478. #endif
  1479.  
  1480.     if (access(envr, F_OK) == 0)
  1481.     {
  1482.         char buf[512];
  1483.         FILE *f = fopen(envr, "r");
  1484.         if (!f)
  1485.         {
  1486.             printf("\n\n"
  1487.                    "Could not open history file [%s] for reading!\n"
  1488.                    "  Will not have past history available.\n\n",
  1489.                     envr);
  1490.             return;
  1491.         } /* if */
  1492.  
  1493.         do
  1494.         {
  1495.             if (fgets(buf, sizeof (buf), f) == NULL)
  1496.                 break;
  1497.  
  1498.             if (buf[strlen(buf) - 1] == '\n')
  1499.                 buf[strlen(buf) - 1] = '\0';
  1500.             add_history(buf);
  1501.         } while (!feof(f));
  1502.  
  1503.         fclose(f);
  1504.     } /* if */
  1505.  
  1506.     history_file = fopen(envr, "ab");
  1507.     if (!history_file)
  1508.     {
  1509.         printf("\n\n"
  1510.                "Could not open history file [%s] for appending!\n"
  1511.                "  Will not be able to record this session's history.\n\n",
  1512.                 envr);
  1513.     } /* if */
  1514. #endif
  1515. } /* open_history_file */
  1516.  
  1517.  
  1518. int main(int argc, char **argv)
  1519. {
  1520.     char *buf = NULL;
  1521.     int rc = 0;
  1522.  
  1523. #if (defined __MWERKS__)
  1524.     extern tSIOUXSettings SIOUXSettings;
  1525.     SIOUXSettings.asktosaveonclose = 0;
  1526.     SIOUXSettings.autocloseonquit = 1;
  1527.     SIOUXSettings.rows = 40;
  1528.     SIOUXSettings.columns = 120;
  1529. #endif
  1530.  
  1531.     printf("\n");
  1532.  
  1533.     if (!PHYSFS_init(argv[0]))
  1534.     {
  1535.         printf("PHYSFS_init() failed!\n  reason: %s.\n", PHYSFS_getLastError());
  1536.         return 1;
  1537.     } /* if */
  1538.  
  1539.     output_versions();
  1540.     output_archivers();
  1541.  
  1542.     open_history_file();
  1543.  
  1544.     printf("Enter commands. Enter \"help\" for instructions.\n");
  1545.     fflush(stdout);
  1546.  
  1547.     do
  1548.     {
  1549. #if (defined PHYSFS_HAVE_READLINE)
  1550.         buf = readline("> ");
  1551. #else
  1552.         int i;
  1553.         buf = (char *) malloc(512);
  1554.         memset(buf, '\0', 512);
  1555.         printf("> ");
  1556.         fflush(stdout);
  1557.         for (i = 0; i < 511; i++)
  1558.         {
  1559.             int ch = fgetc(stdin);
  1560.             if (ch == EOF)
  1561.             {
  1562.                 strcpy(buf, "quit");
  1563.                 break;
  1564.             } /* if */
  1565.             else if ((ch == '\n') || (ch == '\r'))
  1566.             {
  1567.                 buf[i] = '\0';
  1568.                 break;
  1569.             } /* else if */
  1570.             else if (ch == '\b')
  1571.             {
  1572.                 if (i > 0)
  1573.                     i--;
  1574.             } /* else if */
  1575.             else
  1576.             {
  1577.                 buf[i] = (char) ch;
  1578.             } /* else */
  1579.         } /* for */
  1580. #endif
  1581.  
  1582.         rc = process_command(buf);
  1583.         fflush(stdout);
  1584.         if (buf != NULL)
  1585.             free(buf);
  1586.     } while (rc);
  1587.  
  1588.     if (!PHYSFS_deinit())
  1589.         printf("PHYSFS_deinit() failed!\n  reason: %s.\n", PHYSFS_getLastError());
  1590.  
  1591.     if (history_file)
  1592.         fclose(history_file);
  1593.  
  1594. /*
  1595.     printf("\n\ntest_physfs written by ryan c. gordon.\n");
  1596.     printf(" it makes you shoot teh railgun bettar.\n");
  1597. */
  1598.  
  1599.     return 0;
  1600. } /* main */
  1601.  
  1602. /* end of test_physfs.c ... */
  1603.  
  1604.