Upload 2.0.2
[physicsfs] / test / test_physfs.c
diff --git a/test/test_physfs.c b/test/test_physfs.c
new file mode 100644 (file)
index 0000000..2b2f446
--- /dev/null
@@ -0,0 +1,1224 @@
+/**
+ * Test program for PhysicsFS. May only work on Unix.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#if (defined __MWERKS__)
+#include <SIOUX.h>
+#endif
+
+#if (defined PHYSFS_HAVE_READLINE)
+#include <unistd.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+#endif
+
+#include <time.h>
+
+#include "physfs.h"
+
+#define TEST_VERSION_MAJOR  2
+#define TEST_VERSION_MINOR  0
+#define TEST_VERSION_PATCH  2
+
+static FILE *history_file = NULL;
+static PHYSFS_uint32 do_buffer_size = 0;
+
+static void output_versions(void)
+{
+    PHYSFS_Version compiled;
+    PHYSFS_Version linked;
+
+    PHYSFS_VERSION(&compiled);
+    PHYSFS_getLinkedVersion(&linked);
+
+    printf("test_physfs version %d.%d.%d.\n"
+           " Compiled against PhysicsFS version %d.%d.%d,\n"
+           " and linked against %d.%d.%d.\n\n",
+            TEST_VERSION_MAJOR, TEST_VERSION_MINOR, TEST_VERSION_PATCH,
+            (int) compiled.major, (int) compiled.minor, (int) compiled.patch,
+            (int) linked.major, (int) linked.minor, (int) linked.patch);
+} /* output_versions */
+
+
+static void output_archivers(void)
+{
+    const PHYSFS_ArchiveInfo **rc = PHYSFS_supportedArchiveTypes();
+    const PHYSFS_ArchiveInfo **i;
+
+    printf("Supported archive types:\n");
+    if (*rc == NULL)
+        printf(" * Apparently, NONE!\n");
+    else
+    {
+        for (i = rc; *i != NULL; i++)
+        {
+            printf(" * %s: %s\n    Written by %s.\n    %s\n",
+                    (*i)->extension, (*i)->description,
+                    (*i)->author, (*i)->url);
+        } /* for */
+    } /* else */
+
+    printf("\n");
+} /* output_archivers */
+
+
+static int cmd_quit(char *args)
+{
+    return(0);
+} /* cmd_quit */
+
+
+static int cmd_init(char *args)
+{
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    if (PHYSFS_init(args))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_init */
+
+
+static int cmd_deinit(char *args)
+{
+    if (PHYSFS_deinit())
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_deinit */
+
+
+static int cmd_addarchive(char *args)
+{
+    char *ptr = strrchr(args, ' ');
+    int appending = atoi(ptr + 1);
+    *ptr = '\0';
+
+    if (*args == '\"')
+    {
+        args++;
+        *(ptr - 1) = '\0';
+    } /* if */
+
+    /*printf("[%s], [%d]\n", args, appending);*/
+
+    if (PHYSFS_addToSearchPath(args, appending))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_addarchive */
+
+
+static int cmd_mount(char *args)
+{
+    char *ptr;
+    char *mntpoint = NULL;
+    int appending = 0;
+
+    if (*args == '\"')
+    {
+        args++;
+        ptr = strchr(args, '\"');
+        if (ptr == NULL)
+        {
+            printf("missing string terminator in argument.\n");
+            return(1);
+        } /* if */
+        *(ptr) = '\0';
+    } /* if */
+    else
+    {
+        ptr = strchr(args, ' ');
+        *ptr = '\0';
+    } /* else */
+
+    mntpoint = ptr + 1;
+    if (*mntpoint == '\"')
+    {
+        mntpoint++;
+        ptr = strchr(mntpoint, '\"');
+        if (ptr == NULL)
+        {
+            printf("missing string terminator in argument.\n");
+            return(1);
+        } /* if */
+        *(ptr) = '\0';
+    } /* if */
+    else
+    {
+        ptr = strchr(mntpoint, ' ');
+        *(ptr) = '\0';
+    } /* else */
+    appending = atoi(ptr + 1);
+
+    /*printf("[%s], [%s], [%d]\n", args, mntpoint, appending);*/
+
+    if (PHYSFS_mount(args, mntpoint, appending))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_mount */
+
+
+static int cmd_removearchive(char *args)
+{
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    if (PHYSFS_removeFromSearchPath(args))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_removearchive */
+
+
+static int cmd_enumerate(char *args)
+{
+    char **rc;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    rc = PHYSFS_enumerateFiles(args);
+
+    if (rc == NULL)
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+    else
+    {
+        int file_count;
+        char **i;
+        for (i = rc, file_count = 0; *i != NULL; i++, file_count++)
+            printf("%s\n", *i);
+
+        printf("\n total (%d) files.\n", file_count);
+        PHYSFS_freeList(rc);
+    } /* else */
+
+    return(1);
+} /* cmd_enumerate */
+
+
+static int cmd_getdirsep(char *args)
+{
+    printf("Directory separator is [%s].\n", PHYSFS_getDirSeparator());
+    return(1);
+} /* cmd_getdirsep */
+
+
+static int cmd_getlasterror(char *args)
+{
+    printf("last error is [%s].\n", PHYSFS_getLastError());
+    return(1);
+} /* cmd_getlasterror */
+
+
+static int cmd_getcdromdirs(char *args)
+{
+    char **rc = PHYSFS_getCdRomDirs();
+
+    if (rc == NULL)
+        printf("Failure. Reason: [%s].\n", PHYSFS_getLastError());
+    else
+    {
+        int dir_count;
+        char **i;
+        for (i = rc, dir_count = 0; *i != NULL; i++, dir_count++)
+            printf("%s\n", *i);
+
+        printf("\n total (%d) drives.\n", dir_count);
+        PHYSFS_freeList(rc);
+    } /* else */
+
+    return(1);
+} /* cmd_getcdromdirs */
+
+
+static int cmd_getsearchpath(char *args)
+{
+    char **rc = PHYSFS_getSearchPath();
+
+    if (rc == NULL)
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+    else
+    {
+        int dir_count;
+        char **i;
+        for (i = rc, dir_count = 0; *i != NULL; i++, dir_count++)
+            printf("%s\n", *i);
+
+        printf("\n total (%d) directories.\n", dir_count);
+        PHYSFS_freeList(rc);
+    } /* else */
+
+    return(1);
+} /* cmd_getcdromdirs */
+
+
+static int cmd_getbasedir(char *args)
+{
+    printf("Base dir is [%s].\n", PHYSFS_getBaseDir());
+    return(1);
+} /* cmd_getbasedir */
+
+
+static int cmd_getuserdir(char *args)
+{
+    printf("User dir is [%s].\n", PHYSFS_getUserDir());
+    return(1);
+} /* cmd_getuserdir */
+
+
+static int cmd_getwritedir(char *args)
+{
+    printf("Write dir is [%s].\n", PHYSFS_getWriteDir());
+    return(1);
+} /* cmd_getwritedir */
+
+
+static int cmd_setwritedir(char *args)
+{
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    if (PHYSFS_setWriteDir(args))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_setwritedir */
+
+
+static int cmd_permitsyms(char *args)
+{
+    int num;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    num = atoi(args);
+    PHYSFS_permitSymbolicLinks(num);
+    printf("Symlinks are now %s.\n", num ? "permitted" : "forbidden");
+    return(1);
+} /* cmd_permitsyms */
+
+
+static int cmd_setbuffer(char *args)
+{
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    do_buffer_size = (unsigned int) atoi(args);
+    if (do_buffer_size)
+    {
+        printf("Further tests will set a (%lu) size buffer.\n",
+                (unsigned long) do_buffer_size);
+    } /* if */
+
+    else
+    {
+        printf("Further tests will NOT use a buffer.\n");
+    } /* else */
+
+    return(1);
+} /* cmd_setbuffer */
+
+
+static int cmd_stressbuffer(char *args)
+{
+    int num;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    num = atoi(args);
+    if (num < 0)
+        printf("buffer must be greater than or equal to zero.\n");
+    else
+    {
+        PHYSFS_File *f;
+        int rndnum;
+
+        printf("Stress testing with (%d) byte buffer...\n", num);
+        f = PHYSFS_openWrite("test.txt");
+        if (f == NULL)
+            printf("Couldn't open test.txt for writing: %s.\n", PHYSFS_getLastError());
+        else
+        {
+            int i, j;
+            char buf[37];
+            char buf2[37];
+
+            if (!PHYSFS_setBuffer(f, num))
+            {
+                printf("PHYSFS_setBuffer() failed: %s.\n", PHYSFS_getLastError());
+                PHYSFS_close(f);
+                PHYSFS_delete("test.txt");
+                return(1);
+            } /* if */
+
+            strcpy(buf, "abcdefghijklmnopqrstuvwxyz0123456789");
+            srand((unsigned int) time(NULL));
+
+            for (i = 0; i < 10; i++)
+            {
+                for (j = 0; j < 10000; j++)
+                {
+                    PHYSFS_uint32 right = 1 + (PHYSFS_uint32) (35.0 * rand() / (RAND_MAX + 1.0));
+                    PHYSFS_uint32 left = 36 - right;
+                    if (PHYSFS_write(f, buf, left, 1) != 1)
+                    {
+                        printf("PHYSFS_write() failed: %s.\n", PHYSFS_getLastError());
+                        PHYSFS_close(f);
+                        return(1);
+                    } /* if */
+
+                    rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
+                    if (rndnum == 42)
+                    {
+                        if (!PHYSFS_flush(f))
+                        {
+                            printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
+                            PHYSFS_close(f);
+                            return(1);
+                        } /* if */
+                    } /* if */
+
+                    if (PHYSFS_write(f, buf + left, 1, right) != right)
+                    {
+                        printf("PHYSFS_write() failed: %s.\n", PHYSFS_getLastError());
+                        PHYSFS_close(f);
+                        return(1);
+                    } /* if */
+
+                    rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
+                    if (rndnum == 42)
+                    {
+                        if (!PHYSFS_flush(f))
+                        {
+                            printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
+                            PHYSFS_close(f);
+                            return(1);
+                        } /* if */
+                    } /* if */
+                } /* for */
+
+                if (!PHYSFS_flush(f))
+                {
+                    printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
+                    PHYSFS_close(f);
+                    return(1);
+                } /* if */
+
+            } /* for */
+
+            if (!PHYSFS_close(f))
+            {
+                printf("PHYSFS_close() failed: %s.\n", PHYSFS_getLastError());
+                return(1);  /* oh well. */
+            } /* if */
+
+            printf(" ... test file written ...\n");
+            f = PHYSFS_openRead("test.txt");
+            if (f == NULL)
+            {
+                printf("Failed to reopen stress file for reading: %s.\n", PHYSFS_getLastError());
+                return(1);
+            } /* if */
+
+            if (!PHYSFS_setBuffer(f, num))
+            {
+                printf("PHYSFS_setBuffer() failed: %s.\n", PHYSFS_getLastError());
+                PHYSFS_close(f);
+                return(1);
+            } /* if */
+
+            for (i = 0; i < 10; i++)
+            {
+                for (j = 0; j < 10000; j++)
+                {
+                    PHYSFS_uint32 right = 1 + (PHYSFS_uint32) (35.0 * rand() / (RAND_MAX + 1.0));
+                    PHYSFS_uint32 left = 36 - right;
+                    if (PHYSFS_read(f, buf2, left, 1) != 1)
+                    {
+                        printf("PHYSFS_read() failed: %s.\n", PHYSFS_getLastError());
+                        PHYSFS_close(f);
+                        return(1);
+                    } /* if */
+
+                    rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
+                    if (rndnum == 42)
+                    {
+                        if (!PHYSFS_flush(f))
+                        {
+                            printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
+                            PHYSFS_close(f);
+                            return(1);
+                        } /* if */
+                    } /* if */
+
+                    if (PHYSFS_read(f, buf2 + left, 1, right) != right)
+                    {
+                        printf("PHYSFS_read() failed: %s.\n", PHYSFS_getLastError());
+                        PHYSFS_close(f);
+                        return(1);
+                    } /* if */
+
+                    rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
+                    if (rndnum == 42)
+                    {
+                        if (!PHYSFS_flush(f))
+                        {
+                            printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
+                            PHYSFS_close(f);
+                            return(1);
+                        } /* if */
+                    } /* if */
+
+                    if (memcmp(buf, buf2, 36) != 0)
+                    {
+                        printf("readback is mismatched on iterations (%d, %d).\n", i, j);
+                        printf("wanted: [");
+                        for (i = 0; i < 36; i++)
+                            printf("%c", buf[i]);
+                        printf("]\n");
+
+                        printf("   got: [");
+                        for (i = 0; i < 36; i++)
+                            printf("%c", buf2[i]);
+                        printf("]\n");
+                        PHYSFS_close(f);
+                        return(1);
+                    } /* if */
+                } /* for */
+
+                if (!PHYSFS_flush(f))
+                {
+                    printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
+                    PHYSFS_close(f);
+                    return(1);
+                } /* if */
+
+            } /* for */
+
+            printf(" ... test file read ...\n");
+
+            if (!PHYSFS_eof(f))
+                printf("PHYSFS_eof() returned true! That's wrong.\n");
+
+            if (!PHYSFS_close(f))
+            {
+                printf("PHYSFS_close() failed: %s.\n", PHYSFS_getLastError());
+                return(1);  /* oh well. */
+            } /* if */
+
+            PHYSFS_delete("test.txt");
+            printf("stress test completed successfully.\n");
+        } /* else */
+    } /* else */
+
+    return(1);
+} /* cmd_stressbuffer */
+
+
+static int cmd_setsaneconfig(char *args)
+{
+    char *org;
+    char *appName;
+    char *arcExt;
+    int inclCD;
+    int arcsFirst;
+    char *ptr = args;
+
+        /* ugly. */
+    org = ptr;
+    ptr = strchr(ptr, ' '); *ptr = '\0'; ptr++; appName = ptr;
+    ptr = strchr(ptr, ' '); *ptr = '\0'; ptr++; arcExt = ptr;
+    ptr = strchr(ptr, ' '); *ptr = '\0'; ptr++; inclCD = atoi(arcExt);
+    arcsFirst = atoi(ptr);
+
+    if (strcmp(arcExt, "!") == 0)
+        arcExt = NULL;
+
+    if (PHYSFS_setSaneConfig(org, appName, arcExt, inclCD, arcsFirst))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_setsaneconfig */
+
+
+static int cmd_mkdir(char *args)
+{
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    if (PHYSFS_mkdir(args))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_mkdir */
+
+
+static int cmd_delete(char *args)
+{
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    if (PHYSFS_delete(args))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_delete */
+
+
+static int cmd_getrealdir(char *args)
+{
+    const char *rc;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    rc = PHYSFS_getRealDir(args);
+    if (rc)
+        printf("Found at [%s].\n", rc);
+    else
+        printf("Not found.\n");
+
+    return(1);
+} /* cmd_getrealdir */
+
+
+static int cmd_exists(char *args)
+{
+    int rc;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    rc = PHYSFS_exists(args);
+    printf("File %sexists.\n", rc ? "" : "does not ");
+    return(1);
+} /* cmd_exists */
+
+
+static int cmd_isdir(char *args)
+{
+    int rc;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    rc = PHYSFS_isDirectory(args);
+    printf("File %s a directory.\n", rc ? "is" : "is NOT");
+    return(1);
+} /* cmd_isdir */
+
+
+static int cmd_issymlink(char *args)
+{
+    int rc;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    rc = PHYSFS_isSymbolicLink(args);
+    printf("File %s a symlink.\n", rc ? "is" : "is NOT");
+    return(1);
+} /* cmd_issymlink */
+
+
+static int cmd_cat(char *args)
+{
+    PHYSFS_File *f;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    f = PHYSFS_openRead(args);
+    if (f == NULL)
+        printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
+    else
+    {
+        if (do_buffer_size)
+        {
+            if (!PHYSFS_setBuffer(f, do_buffer_size))
+            {
+                printf("failed to set file buffer. Reason: [%s].\n",
+                        PHYSFS_getLastError());
+                PHYSFS_close(f);
+                return(1);
+            } /* if */
+        } /* if */
+
+        while (1)
+        {
+            char buffer[128];
+            PHYSFS_sint64 rc;
+            PHYSFS_sint64 i;
+            rc = PHYSFS_read(f, buffer, 1, sizeof (buffer));
+
+            for (i = 0; i < rc; i++)
+                fputc((int) buffer[i], stdout);
+
+            if (rc < sizeof (buffer))
+            {
+                printf("\n\n");
+                if (!PHYSFS_eof(f))
+                {
+                    printf("\n (Error condition in reading. Reason: [%s])\n\n",
+                           PHYSFS_getLastError());
+                } /* if */
+                PHYSFS_close(f);
+                return(1);
+            } /* if */
+        } /* while */
+    } /* else */
+
+    return(1);
+} /* cmd_cat */
+
+
+static int cmd_filelength(char *args)
+{
+    PHYSFS_File *f;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    f = PHYSFS_openRead(args);
+    if (f == NULL)
+        printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
+    else
+    {
+        PHYSFS_sint64 len = PHYSFS_fileLength(f);
+        if (len == -1)
+            printf("failed to determine length. Reason: [%s].\n", PHYSFS_getLastError());
+        else
+            printf(" (cast to int) %d bytes.\n", (int) len);
+
+        PHYSFS_close(f);
+    } /* else */
+
+    return(1);
+} /* cmd_filelength */
+
+
+#define WRITESTR "The cat sat on the mat.\n\n"
+
+static int cmd_append(char *args)
+{
+    PHYSFS_File *f;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    f = PHYSFS_openAppend(args);
+    if (f == NULL)
+        printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
+    else
+    {
+        size_t bw;
+        PHYSFS_sint64 rc;
+
+        if (do_buffer_size)
+        {
+            if (!PHYSFS_setBuffer(f, do_buffer_size))
+            {
+                printf("failed to set file buffer. Reason: [%s].\n",
+                        PHYSFS_getLastError());
+                PHYSFS_close(f);
+                return(1);
+            } /* if */
+        } /* if */
+
+        bw = strlen(WRITESTR);
+        rc = PHYSFS_write(f, WRITESTR, 1, bw);
+        if (rc != bw)
+        {
+            printf("Wrote (%d) of (%d) bytes. Reason: [%s].\n",
+                   (int) rc, (int) bw, PHYSFS_getLastError());
+        } /* if */
+        else
+        {
+            printf("Successful.\n");
+        } /* else */
+
+        PHYSFS_close(f);
+    } /* else */
+
+    return(1);
+} /* cmd_append */
+
+
+static int cmd_write(char *args)
+{
+    PHYSFS_File *f;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    f = PHYSFS_openWrite(args);
+    if (f == NULL)
+        printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
+    else
+    {
+        size_t bw;
+        PHYSFS_sint64 rc;
+
+        if (do_buffer_size)
+        {
+            if (!PHYSFS_setBuffer(f, do_buffer_size))
+            {
+                printf("failed to set file buffer. Reason: [%s].\n",
+                        PHYSFS_getLastError());
+                PHYSFS_close(f);
+                return(1);
+            } /* if */
+        } /* if */
+
+        bw = strlen(WRITESTR);
+        rc = PHYSFS_write(f, WRITESTR, 1, bw);
+        if (rc != bw)
+        {
+            printf("Wrote (%d) of (%d) bytes. Reason: [%s].\n",
+                   (int) rc, (int) bw, PHYSFS_getLastError());
+        } /* if */
+        else
+        {
+            printf("Successful.\n");
+        } /* else */
+
+        PHYSFS_close(f);
+    } /* else */
+
+    return(1);
+} /* cmd_write */
+
+
+static void modTimeToStr(PHYSFS_sint64 modtime, char *modstr, size_t strsize)
+{
+    time_t t = (time_t) modtime;
+    char *str = ctime(&t);
+    strncpy(modstr, str, strsize);
+    modstr[strsize-1] = '\0';
+} /* modTimeToStr */
+
+
+static int cmd_getlastmodtime(char *args)
+{
+    PHYSFS_sint64 rc = PHYSFS_getLastModTime(args);
+    if (rc == -1)
+        printf("Failed to determine. Reason: [%s].\n", PHYSFS_getLastError());
+    else
+    {
+        char modstr[64];
+        modTimeToStr(rc, modstr, sizeof (modstr));
+        printf("Last modified: %s (%ld).\n", modstr, (long) rc);
+    } /* else */
+
+    return(1);
+} /* cmd_getLastModTime */
+
+
+/* must have spaces trimmed prior to this call. */
+static int count_args(const char *str)
+{
+    int retval = 0;
+    int in_quotes = 0;
+
+    if (str != NULL)
+    {
+        for (; *str != '\0'; str++)
+        {
+            if (*str == '\"')
+                in_quotes = !in_quotes;
+            else if ((*str == ' ') && (!in_quotes))
+                retval++;
+        } /* for */
+        retval++;
+    } /* if */
+
+    return(retval);
+} /* count_args */
+
+
+static int cmd_help(char *args);
+
+typedef struct
+{
+    const char *cmd;
+    int (*func)(char *args);
+    int argcount;
+    const char *usage;
+} command_info;
+
+static const command_info commands[] =
+{
+    { "quit",           cmd_quit,           0, NULL                         },
+    { "q",              cmd_quit,           0, NULL                         },
+    { "help",           cmd_help,           0, NULL                         },
+    { "init",           cmd_init,           1, "<argv0>"                    },
+    { "deinit",         cmd_deinit,         0, NULL                         },
+    { "addarchive",     cmd_addarchive,     2, "<archiveLocation> <append>" },
+    { "mount",          cmd_mount,          3, "<archiveLocation> <mntpoint> <append>" },
+    { "removearchive",  cmd_removearchive,  1, "<archiveLocation>"          },
+    { "enumerate",      cmd_enumerate,      1, "<dirToEnumerate>"           },
+    { "ls",             cmd_enumerate,      1, "<dirToEnumerate>"           },
+    { "getlasterror",   cmd_getlasterror,   0, NULL                         },
+    { "getdirsep",      cmd_getdirsep,      0, NULL                         },
+    { "getcdromdirs",   cmd_getcdromdirs,   0, NULL                         },
+    { "getsearchpath",  cmd_getsearchpath,  0, NULL                         },
+    { "getbasedir",     cmd_getbasedir,     0, NULL                         },
+    { "getuserdir",     cmd_getuserdir,     0, NULL                         },
+    { "getwritedir",    cmd_getwritedir,    0, NULL                         },
+    { "setwritedir",    cmd_setwritedir,    1, "<newWriteDir>"              },
+    { "permitsymlinks", cmd_permitsyms,     1, "<1or0>"                     },
+    { "setsaneconfig",  cmd_setsaneconfig,  5, "<org> <appName> <arcExt> <includeCdRoms> <archivesFirst>" },
+    { "mkdir",          cmd_mkdir,          1, "<dirToMk>"                  },
+    { "delete",         cmd_delete,         1, "<dirToDelete>"              },
+    { "getrealdir",     cmd_getrealdir,     1, "<fileToFind>"               },
+    { "exists",         cmd_exists,         1, "<fileToCheck>"              },
+    { "isdir",          cmd_isdir,          1, "<fileToCheck>"              },
+    { "issymlink",      cmd_issymlink,      1, "<fileToCheck>"              },
+    { "cat",            cmd_cat,            1, "<fileToCat>"                },
+    { "filelength",     cmd_filelength,     1, "<fileToCheck>"              },
+    { "append",         cmd_append,         1, "<fileToAppend>"             },
+    { "write",          cmd_write,          1, "<fileToCreateOrTrash>"      },
+    { "getlastmodtime", cmd_getlastmodtime, 1, "<fileToExamine>"            },
+    { "setbuffer",      cmd_setbuffer,      1, "<bufferSize>"               },
+    { "stressbuffer",   cmd_stressbuffer,   1, "<bufferSize>"               },
+    { NULL,             NULL,              -1, NULL                         }
+};
+
+
+static void output_usage(const char *intro, const command_info *cmdinfo)
+{
+    if (cmdinfo->argcount == 0)
+        printf("%s \"%s\" (no arguments)\n", intro, cmdinfo->cmd);
+    else
+        printf("%s \"%s %s\"\n", intro, cmdinfo->cmd, cmdinfo->usage);
+} /* output_usage */
+
+
+static int cmd_help(char *args)
+{
+    const command_info *i;
+
+    printf("Commands:\n");
+    for (i = commands; i->cmd != NULL; i++)
+        output_usage("  -", i);
+
+    return(1);
+} /* output_cmd_help */
+
+
+static void trim_command(const char *orig, char *copy)
+{
+    const char *i;
+    char *writeptr = copy;
+    int spacecount = 0;
+    int have_first = 0;
+
+    for (i = orig; *i != '\0'; i++)
+    {
+        if (*i == ' ')
+        {
+            if ((*(i + 1) != ' ') && (*(i + 1) != '\0'))
+            {
+                if ((have_first) && (!spacecount))
+                {
+                    spacecount++;
+                    *writeptr = ' ';
+                    writeptr++;
+                } /* if */
+            } /* if */
+        } /* if */
+        else
+        {
+            have_first = 1;
+            spacecount = 0;
+            *writeptr = *i;
+            writeptr++;
+        } /* else */
+    } /* for */
+
+    *writeptr = '\0';
+
+    /*
+    printf("\n command is [%s].\n", copy);
+    */
+} /* trim_command */
+
+
+static int process_command(char *complete_cmd)
+{
+    const command_info *i;
+    char *cmd_copy;
+    char *args;
+    int rc = 1;
+
+    if (complete_cmd == NULL)  /* can happen if user hits CTRL-D, etc. */
+    {
+        printf("\n");
+        return(0);
+    } /* if */
+
+    cmd_copy = (char *) malloc(strlen(complete_cmd) + 1);
+    if (cmd_copy == NULL)
+    {
+        printf("\n\n\nOUT OF MEMORY!\n\n\n");
+        return(0);
+    } /* if */
+
+    trim_command(complete_cmd, cmd_copy);
+    args = strchr(cmd_copy, ' ');
+    if (args != NULL)
+    {
+        *args = '\0';
+        args++;
+    } /* else */
+
+    if (cmd_copy[0] != '\0')
+    {
+        for (i = commands; i->cmd != NULL; i++)
+        {
+            if (strcmp(i->cmd, cmd_copy) == 0)
+            {
+                if ((i->argcount >= 0) && (count_args(args) != i->argcount))
+                    output_usage("usage:", i);
+                else
+                    rc = i->func(args);
+                break;
+            } /* if */
+        } /* for */
+
+        if (i->cmd == NULL)
+            printf("Unknown command. Enter \"help\" for instructions.\n");
+
+#if (defined PHYSFS_HAVE_READLINE)
+        add_history(complete_cmd);
+        if (history_file)
+        {
+            fprintf(history_file, "%s\n", complete_cmd);
+            fflush(history_file);
+        } /* if */
+#endif
+
+    } /* if */
+
+    free(cmd_copy);
+    return(rc);
+} /* process_command */
+
+
+static void open_history_file(void)
+{
+#if (defined PHYSFS_HAVE_READLINE)
+#if 0
+    const char *envr = getenv("TESTPHYSFS_HISTORY");
+    if (!envr)
+        return;
+#else
+    char envr[256];
+    strcpy(envr, PHYSFS_getUserDir());
+    strcat(envr, ".testphys_history");
+#endif
+
+    if (access(envr, F_OK) == 0)
+    {
+        char buf[512];
+        FILE *f = fopen(envr, "r");
+        if (!f)
+        {
+            printf("\n\n"
+                   "Could not open history file [%s] for reading!\n"
+                   "  Will not have past history available.\n\n",
+                    envr);
+            return;
+        } /* if */
+
+        do
+        {
+            if (fgets(buf, sizeof (buf), f) == NULL)
+                break;
+
+            if (buf[strlen(buf) - 1] == '\n')
+                buf[strlen(buf) - 1] = '\0';
+            add_history(buf);
+        } while (!feof(f));
+
+        fclose(f);
+    } /* if */
+
+    history_file = fopen(envr, "ab");
+    if (!history_file)
+    {
+        printf("\n\n"
+               "Could not open history file [%s] for appending!\n"
+               "  Will not be able to record this session's history.\n\n",
+                envr);
+    } /* if */
+#endif
+} /* open_history_file */
+
+
+int main(int argc, char **argv)
+{
+    char *buf = NULL;
+    int rc = 0;
+
+#if (defined __MWERKS__)
+    extern tSIOUXSettings SIOUXSettings;
+    SIOUXSettings.asktosaveonclose = 0;
+    SIOUXSettings.autocloseonquit = 1;
+    SIOUXSettings.rows = 40;
+    SIOUXSettings.columns = 120;
+#endif
+
+    printf("\n");
+
+    if (!PHYSFS_init(argv[0]))
+    {
+        printf("PHYSFS_init() failed!\n  reason: %s.\n", PHYSFS_getLastError());
+        return(1);
+    } /* if */
+
+    output_versions();
+    output_archivers();
+
+    open_history_file();
+
+    printf("Enter commands. Enter \"help\" for instructions.\n");
+
+    do
+    {
+#if (defined PHYSFS_HAVE_READLINE)
+        buf = readline("> ");
+#else
+        int i;
+        buf = (char *) malloc(512);
+        memset(buf, '\0', 512);
+        printf("> ");
+        for (i = 0; i < 511; i++)
+        {
+            int ch = fgetc(stdin);
+            if (ch == EOF)
+            {
+                strcpy(buf, "quit");
+                break;
+            } /* if */
+            else if ((ch == '\n') || (ch == '\r'))
+            {
+                buf[i] = '\0';
+                break;
+            } /* else if */
+            else if (ch == '\b')
+            {
+                if (i > 0)
+                    i--;
+            } /* else if */
+            else
+            {
+                buf[i] = (char) ch;
+            } /* else */
+        } /* for */
+#endif
+
+        rc = process_command(buf);
+        if (buf != NULL)
+            free(buf);
+    } while (rc);
+
+    if (!PHYSFS_deinit())
+        printf("PHYSFS_deinit() failed!\n  reason: %s.\n", PHYSFS_getLastError());
+
+    if (history_file)
+        fclose(history_file);
+
+/*
+    printf("\n\ntest_physfs written by ryan c. gordon.\n");
+    printf(" it makes you shoot teh railgun bettar.\n");
+*/
+
+    return(0);
+} /* main */
+
+/* end of test_physfs.c ... */
+