Upload 2.0.2
[physicsfs] / test / test_physfs.c
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 #include <stdio.h>
10 #include <stdlib.h>
11 #include <errno.h>
12 #include <string.h>
13
14 #if (defined __MWERKS__)
15 #include <SIOUX.h>
16 #endif
17
18 #if (defined PHYSFS_HAVE_READLINE)
19 #include <unistd.h>
20 #include <readline/readline.h>
21 #include <readline/history.h>
22 #endif
23
24 #include <time.h>
25
26 #include "physfs.h"
27
28 #define TEST_VERSION_MAJOR  2
29 #define TEST_VERSION_MINOR  0
30 #define TEST_VERSION_PATCH  2
31
32 static FILE *history_file = NULL;
33 static PHYSFS_uint32 do_buffer_size = 0;
34
35 static void output_versions(void)
36 {
37     PHYSFS_Version compiled;
38     PHYSFS_Version linked;
39
40     PHYSFS_VERSION(&compiled);
41     PHYSFS_getLinkedVersion(&linked);
42
43     printf("test_physfs version %d.%d.%d.\n"
44            " Compiled against PhysicsFS version %d.%d.%d,\n"
45            " and linked against %d.%d.%d.\n\n",
46             TEST_VERSION_MAJOR, TEST_VERSION_MINOR, TEST_VERSION_PATCH,
47             (int) compiled.major, (int) compiled.minor, (int) compiled.patch,
48             (int) linked.major, (int) linked.minor, (int) linked.patch);
49 } /* output_versions */
50
51
52 static void output_archivers(void)
53 {
54     const PHYSFS_ArchiveInfo **rc = PHYSFS_supportedArchiveTypes();
55     const PHYSFS_ArchiveInfo **i;
56
57     printf("Supported archive types:\n");
58     if (*rc == NULL)
59         printf(" * Apparently, NONE!\n");
60     else
61     {
62         for (i = rc; *i != NULL; i++)
63         {
64             printf(" * %s: %s\n    Written by %s.\n    %s\n",
65                     (*i)->extension, (*i)->description,
66                     (*i)->author, (*i)->url);
67         } /* for */
68     } /* else */
69
70     printf("\n");
71 } /* output_archivers */
72
73
74 static int cmd_quit(char *args)
75 {
76     return(0);
77 } /* cmd_quit */
78
79
80 static int cmd_init(char *args)
81 {
82     if (*args == '\"')
83     {
84         args++;
85         args[strlen(args) - 1] = '\0';
86     } /* if */
87
88     if (PHYSFS_init(args))
89         printf("Successful.\n");
90     else
91         printf("Failure. reason: %s.\n", PHYSFS_getLastError());
92
93     return(1);
94 } /* cmd_init */
95
96
97 static int cmd_deinit(char *args)
98 {
99     if (PHYSFS_deinit())
100         printf("Successful.\n");
101     else
102         printf("Failure. reason: %s.\n", PHYSFS_getLastError());
103
104     return(1);
105 } /* cmd_deinit */
106
107
108 static int cmd_addarchive(char *args)
109 {
110     char *ptr = strrchr(args, ' ');
111     int appending = atoi(ptr + 1);
112     *ptr = '\0';
113
114     if (*args == '\"')
115     {
116         args++;
117         *(ptr - 1) = '\0';
118     } /* if */
119
120     /*printf("[%s], [%d]\n", args, appending);*/
121
122     if (PHYSFS_addToSearchPath(args, appending))
123         printf("Successful.\n");
124     else
125         printf("Failure. reason: %s.\n", PHYSFS_getLastError());
126
127     return(1);
128 } /* cmd_addarchive */
129
130
131 static int cmd_mount(char *args)
132 {
133     char *ptr;
134     char *mntpoint = NULL;
135     int appending = 0;
136
137     if (*args == '\"')
138     {
139         args++;
140         ptr = strchr(args, '\"');
141         if (ptr == NULL)
142         {
143             printf("missing string terminator in argument.\n");
144             return(1);
145         } /* if */
146         *(ptr) = '\0';
147     } /* if */
148     else
149     {
150         ptr = strchr(args, ' ');
151         *ptr = '\0';
152     } /* else */
153
154     mntpoint = ptr + 1;
155     if (*mntpoint == '\"')
156     {
157         mntpoint++;
158         ptr = strchr(mntpoint, '\"');
159         if (ptr == NULL)
160         {
161             printf("missing string terminator in argument.\n");
162             return(1);
163         } /* if */
164         *(ptr) = '\0';
165     } /* if */
166     else
167     {
168         ptr = strchr(mntpoint, ' ');
169         *(ptr) = '\0';
170     } /* else */
171     appending = atoi(ptr + 1);
172
173     /*printf("[%s], [%s], [%d]\n", args, mntpoint, appending);*/
174
175     if (PHYSFS_mount(args, mntpoint, appending))
176         printf("Successful.\n");
177     else
178         printf("Failure. reason: %s.\n", PHYSFS_getLastError());
179
180     return(1);
181 } /* cmd_mount */
182
183
184 static int cmd_removearchive(char *args)
185 {
186     if (*args == '\"')
187     {
188         args++;
189         args[strlen(args) - 1] = '\0';
190     } /* if */
191
192     if (PHYSFS_removeFromSearchPath(args))
193         printf("Successful.\n");
194     else
195         printf("Failure. reason: %s.\n", PHYSFS_getLastError());
196
197     return(1);
198 } /* cmd_removearchive */
199
200
201 static int cmd_enumerate(char *args)
202 {
203     char **rc;
204
205     if (*args == '\"')
206     {
207         args++;
208         args[strlen(args) - 1] = '\0';
209     } /* if */
210
211     rc = PHYSFS_enumerateFiles(args);
212
213     if (rc == NULL)
214         printf("Failure. reason: %s.\n", PHYSFS_getLastError());
215     else
216     {
217         int file_count;
218         char **i;
219         for (i = rc, file_count = 0; *i != NULL; i++, file_count++)
220             printf("%s\n", *i);
221
222         printf("\n total (%d) files.\n", file_count);
223         PHYSFS_freeList(rc);
224     } /* else */
225
226     return(1);
227 } /* cmd_enumerate */
228
229
230 static int cmd_getdirsep(char *args)
231 {
232     printf("Directory separator is [%s].\n", PHYSFS_getDirSeparator());
233     return(1);
234 } /* cmd_getdirsep */
235
236
237 static int cmd_getlasterror(char *args)
238 {
239     printf("last error is [%s].\n", PHYSFS_getLastError());
240     return(1);
241 } /* cmd_getlasterror */
242
243
244 static int cmd_getcdromdirs(char *args)
245 {
246     char **rc = PHYSFS_getCdRomDirs();
247
248     if (rc == NULL)
249         printf("Failure. Reason: [%s].\n", PHYSFS_getLastError());
250     else
251     {
252         int dir_count;
253         char **i;
254         for (i = rc, dir_count = 0; *i != NULL; i++, dir_count++)
255             printf("%s\n", *i);
256
257         printf("\n total (%d) drives.\n", dir_count);
258         PHYSFS_freeList(rc);
259     } /* else */
260
261     return(1);
262 } /* cmd_getcdromdirs */
263
264
265 static int cmd_getsearchpath(char *args)
266 {
267     char **rc = PHYSFS_getSearchPath();
268
269     if (rc == NULL)
270         printf("Failure. reason: %s.\n", PHYSFS_getLastError());
271     else
272     {
273         int dir_count;
274         char **i;
275         for (i = rc, dir_count = 0; *i != NULL; i++, dir_count++)
276             printf("%s\n", *i);
277
278         printf("\n total (%d) directories.\n", dir_count);
279         PHYSFS_freeList(rc);
280     } /* else */
281
282     return(1);
283 } /* cmd_getcdromdirs */
284
285
286 static int cmd_getbasedir(char *args)
287 {
288     printf("Base dir is [%s].\n", PHYSFS_getBaseDir());
289     return(1);
290 } /* cmd_getbasedir */
291
292
293 static int cmd_getuserdir(char *args)
294 {
295     printf("User dir is [%s].\n", PHYSFS_getUserDir());
296     return(1);
297 } /* cmd_getuserdir */
298
299
300 static int cmd_getwritedir(char *args)
301 {
302     printf("Write dir is [%s].\n", PHYSFS_getWriteDir());
303     return(1);
304 } /* cmd_getwritedir */
305
306
307 static int cmd_setwritedir(char *args)
308 {
309     if (*args == '\"')
310     {
311         args++;
312         args[strlen(args) - 1] = '\0';
313     } /* if */
314
315     if (PHYSFS_setWriteDir(args))
316         printf("Successful.\n");
317     else
318         printf("Failure. reason: %s.\n", PHYSFS_getLastError());
319
320     return(1);
321 } /* cmd_setwritedir */
322
323
324 static int cmd_permitsyms(char *args)
325 {
326     int num;
327
328     if (*args == '\"')
329     {
330         args++;
331         args[strlen(args) - 1] = '\0';
332     } /* if */
333
334     num = atoi(args);
335     PHYSFS_permitSymbolicLinks(num);
336     printf("Symlinks are now %s.\n", num ? "permitted" : "forbidden");
337     return(1);
338 } /* cmd_permitsyms */
339
340
341 static int cmd_setbuffer(char *args)
342 {
343     if (*args == '\"')
344     {
345         args++;
346         args[strlen(args) - 1] = '\0';
347     } /* if */
348
349     do_buffer_size = (unsigned int) atoi(args);
350     if (do_buffer_size)
351     {
352         printf("Further tests will set a (%lu) size buffer.\n",
353                 (unsigned long) do_buffer_size);
354     } /* if */
355
356     else
357     {
358         printf("Further tests will NOT use a buffer.\n");
359     } /* else */
360
361     return(1);
362 } /* cmd_setbuffer */
363
364
365 static int cmd_stressbuffer(char *args)
366 {
367     int num;
368
369     if (*args == '\"')
370     {
371         args++;
372         args[strlen(args) - 1] = '\0';
373     } /* if */
374
375     num = atoi(args);
376     if (num < 0)
377         printf("buffer must be greater than or equal to zero.\n");
378     else
379     {
380         PHYSFS_File *f;
381         int rndnum;
382
383         printf("Stress testing with (%d) byte buffer...\n", num);
384         f = PHYSFS_openWrite("test.txt");
385         if (f == NULL)
386             printf("Couldn't open test.txt for writing: %s.\n", PHYSFS_getLastError());
387         else
388         {
389             int i, j;
390             char buf[37];
391             char buf2[37];
392
393             if (!PHYSFS_setBuffer(f, num))
394             {
395                 printf("PHYSFS_setBuffer() failed: %s.\n", PHYSFS_getLastError());
396                 PHYSFS_close(f);
397                 PHYSFS_delete("test.txt");
398                 return(1);
399             } /* if */
400
401             strcpy(buf, "abcdefghijklmnopqrstuvwxyz0123456789");
402             srand((unsigned int) time(NULL));
403
404             for (i = 0; i < 10; i++)
405             {
406                 for (j = 0; j < 10000; j++)
407                 {
408                     PHYSFS_uint32 right = 1 + (PHYSFS_uint32) (35.0 * rand() / (RAND_MAX + 1.0));
409                     PHYSFS_uint32 left = 36 - right;
410                     if (PHYSFS_write(f, buf, left, 1) != 1)
411                     {
412                         printf("PHYSFS_write() failed: %s.\n", PHYSFS_getLastError());
413                         PHYSFS_close(f);
414                         return(1);
415                     } /* if */
416
417                     rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
418                     if (rndnum == 42)
419                     {
420                         if (!PHYSFS_flush(f))
421                         {
422                             printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
423                             PHYSFS_close(f);
424                             return(1);
425                         } /* if */
426                     } /* if */
427
428                     if (PHYSFS_write(f, buf + left, 1, right) != right)
429                     {
430                         printf("PHYSFS_write() failed: %s.\n", PHYSFS_getLastError());
431                         PHYSFS_close(f);
432                         return(1);
433                     } /* if */
434
435                     rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
436                     if (rndnum == 42)
437                     {
438                         if (!PHYSFS_flush(f))
439                         {
440                             printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
441                             PHYSFS_close(f);
442                             return(1);
443                         } /* if */
444                     } /* if */
445                 } /* for */
446
447                 if (!PHYSFS_flush(f))
448                 {
449                     printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
450                     PHYSFS_close(f);
451                     return(1);
452                 } /* if */
453
454             } /* for */
455
456             if (!PHYSFS_close(f))
457             {
458                 printf("PHYSFS_close() failed: %s.\n", PHYSFS_getLastError());
459                 return(1);  /* oh well. */
460             } /* if */
461
462             printf(" ... test file written ...\n");
463             f = PHYSFS_openRead("test.txt");
464             if (f == NULL)
465             {
466                 printf("Failed to reopen stress file for reading: %s.\n", PHYSFS_getLastError());
467                 return(1);
468             } /* if */
469
470             if (!PHYSFS_setBuffer(f, num))
471             {
472                 printf("PHYSFS_setBuffer() failed: %s.\n", PHYSFS_getLastError());
473                 PHYSFS_close(f);
474                 return(1);
475             } /* if */
476
477             for (i = 0; i < 10; i++)
478             {
479                 for (j = 0; j < 10000; j++)
480                 {
481                     PHYSFS_uint32 right = 1 + (PHYSFS_uint32) (35.0 * rand() / (RAND_MAX + 1.0));
482                     PHYSFS_uint32 left = 36 - right;
483                     if (PHYSFS_read(f, buf2, left, 1) != 1)
484                     {
485                         printf("PHYSFS_read() failed: %s.\n", PHYSFS_getLastError());
486                         PHYSFS_close(f);
487                         return(1);
488                     } /* if */
489
490                     rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
491                     if (rndnum == 42)
492                     {
493                         if (!PHYSFS_flush(f))
494                         {
495                             printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
496                             PHYSFS_close(f);
497                             return(1);
498                         } /* if */
499                     } /* if */
500
501                     if (PHYSFS_read(f, buf2 + left, 1, right) != right)
502                     {
503                         printf("PHYSFS_read() failed: %s.\n", PHYSFS_getLastError());
504                         PHYSFS_close(f);
505                         return(1);
506                     } /* if */
507
508                     rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
509                     if (rndnum == 42)
510                     {
511                         if (!PHYSFS_flush(f))
512                         {
513                             printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
514                             PHYSFS_close(f);
515                             return(1);
516                         } /* if */
517                     } /* if */
518
519                     if (memcmp(buf, buf2, 36) != 0)
520                     {
521                         printf("readback is mismatched on iterations (%d, %d).\n", i, j);
522                         printf("wanted: [");
523                         for (i = 0; i < 36; i++)
524                             printf("%c", buf[i]);
525                         printf("]\n");
526
527                         printf("   got: [");
528                         for (i = 0; i < 36; i++)
529                             printf("%c", buf2[i]);
530                         printf("]\n");
531                         PHYSFS_close(f);
532                         return(1);
533                     } /* if */
534                 } /* for */
535
536                 if (!PHYSFS_flush(f))
537                 {
538                     printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
539                     PHYSFS_close(f);
540                     return(1);
541                 } /* if */
542
543             } /* for */
544
545             printf(" ... test file read ...\n");
546
547             if (!PHYSFS_eof(f))
548                 printf("PHYSFS_eof() returned true! That's wrong.\n");
549
550             if (!PHYSFS_close(f))
551             {
552                 printf("PHYSFS_close() failed: %s.\n", PHYSFS_getLastError());
553                 return(1);  /* oh well. */
554             } /* if */
555
556             PHYSFS_delete("test.txt");
557             printf("stress test completed successfully.\n");
558         } /* else */
559     } /* else */
560
561     return(1);
562 } /* cmd_stressbuffer */
563
564
565 static int cmd_setsaneconfig(char *args)
566 {
567     char *org;
568     char *appName;
569     char *arcExt;
570     int inclCD;
571     int arcsFirst;
572     char *ptr = args;
573
574         /* ugly. */
575     org = ptr;
576     ptr = strchr(ptr, ' '); *ptr = '\0'; ptr++; appName = ptr;
577     ptr = strchr(ptr, ' '); *ptr = '\0'; ptr++; arcExt = ptr;
578     ptr = strchr(ptr, ' '); *ptr = '\0'; ptr++; inclCD = atoi(arcExt);
579     arcsFirst = atoi(ptr);
580
581     if (strcmp(arcExt, "!") == 0)
582         arcExt = NULL;
583
584     if (PHYSFS_setSaneConfig(org, appName, arcExt, inclCD, arcsFirst))
585         printf("Successful.\n");
586     else
587         printf("Failure. reason: %s.\n", PHYSFS_getLastError());
588
589     return(1);
590 } /* cmd_setsaneconfig */
591
592
593 static int cmd_mkdir(char *args)
594 {
595     if (*args == '\"')
596     {
597         args++;
598         args[strlen(args) - 1] = '\0';
599     } /* if */
600
601     if (PHYSFS_mkdir(args))
602         printf("Successful.\n");
603     else
604         printf("Failure. reason: %s.\n", PHYSFS_getLastError());
605
606     return(1);
607 } /* cmd_mkdir */
608
609
610 static int cmd_delete(char *args)
611 {
612     if (*args == '\"')
613     {
614         args++;
615         args[strlen(args) - 1] = '\0';
616     } /* if */
617
618     if (PHYSFS_delete(args))
619         printf("Successful.\n");
620     else
621         printf("Failure. reason: %s.\n", PHYSFS_getLastError());
622
623     return(1);
624 } /* cmd_delete */
625
626
627 static int cmd_getrealdir(char *args)
628 {
629     const char *rc;
630
631     if (*args == '\"')
632     {
633         args++;
634         args[strlen(args) - 1] = '\0';
635     } /* if */
636
637     rc = PHYSFS_getRealDir(args);
638     if (rc)
639         printf("Found at [%s].\n", rc);
640     else
641         printf("Not found.\n");
642
643     return(1);
644 } /* cmd_getrealdir */
645
646
647 static int cmd_exists(char *args)
648 {
649     int rc;
650
651     if (*args == '\"')
652     {
653         args++;
654         args[strlen(args) - 1] = '\0';
655     } /* if */
656
657     rc = PHYSFS_exists(args);
658     printf("File %sexists.\n", rc ? "" : "does not ");
659     return(1);
660 } /* cmd_exists */
661
662
663 static int cmd_isdir(char *args)
664 {
665     int rc;
666
667     if (*args == '\"')
668     {
669         args++;
670         args[strlen(args) - 1] = '\0';
671     } /* if */
672
673     rc = PHYSFS_isDirectory(args);
674     printf("File %s a directory.\n", rc ? "is" : "is NOT");
675     return(1);
676 } /* cmd_isdir */
677
678
679 static int cmd_issymlink(char *args)
680 {
681     int rc;
682
683     if (*args == '\"')
684     {
685         args++;
686         args[strlen(args) - 1] = '\0';
687     } /* if */
688
689     rc = PHYSFS_isSymbolicLink(args);
690     printf("File %s a symlink.\n", rc ? "is" : "is NOT");
691     return(1);
692 } /* cmd_issymlink */
693
694
695 static int cmd_cat(char *args)
696 {
697     PHYSFS_File *f;
698
699     if (*args == '\"')
700     {
701         args++;
702         args[strlen(args) - 1] = '\0';
703     } /* if */
704
705     f = PHYSFS_openRead(args);
706     if (f == NULL)
707         printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
708     else
709     {
710         if (do_buffer_size)
711         {
712             if (!PHYSFS_setBuffer(f, do_buffer_size))
713             {
714                 printf("failed to set file buffer. Reason: [%s].\n",
715                         PHYSFS_getLastError());
716                 PHYSFS_close(f);
717                 return(1);
718             } /* if */
719         } /* if */
720
721         while (1)
722         {
723             char buffer[128];
724             PHYSFS_sint64 rc;
725             PHYSFS_sint64 i;
726             rc = PHYSFS_read(f, buffer, 1, sizeof (buffer));
727
728             for (i = 0; i < rc; i++)
729                 fputc((int) buffer[i], stdout);
730
731             if (rc < sizeof (buffer))
732             {
733                 printf("\n\n");
734                 if (!PHYSFS_eof(f))
735                 {
736                     printf("\n (Error condition in reading. Reason: [%s])\n\n",
737                            PHYSFS_getLastError());
738                 } /* if */
739                 PHYSFS_close(f);
740                 return(1);
741             } /* if */
742         } /* while */
743     } /* else */
744
745     return(1);
746 } /* cmd_cat */
747
748
749 static int cmd_filelength(char *args)
750 {
751     PHYSFS_File *f;
752
753     if (*args == '\"')
754     {
755         args++;
756         args[strlen(args) - 1] = '\0';
757     } /* if */
758
759     f = PHYSFS_openRead(args);
760     if (f == NULL)
761         printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
762     else
763     {
764         PHYSFS_sint64 len = PHYSFS_fileLength(f);
765         if (len == -1)
766             printf("failed to determine length. Reason: [%s].\n", PHYSFS_getLastError());
767         else
768             printf(" (cast to int) %d bytes.\n", (int) len);
769
770         PHYSFS_close(f);
771     } /* else */
772
773     return(1);
774 } /* cmd_filelength */
775
776
777 #define WRITESTR "The cat sat on the mat.\n\n"
778
779 static int cmd_append(char *args)
780 {
781     PHYSFS_File *f;
782
783     if (*args == '\"')
784     {
785         args++;
786         args[strlen(args) - 1] = '\0';
787     } /* if */
788
789     f = PHYSFS_openAppend(args);
790     if (f == NULL)
791         printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
792     else
793     {
794         size_t bw;
795         PHYSFS_sint64 rc;
796
797         if (do_buffer_size)
798         {
799             if (!PHYSFS_setBuffer(f, do_buffer_size))
800             {
801                 printf("failed to set file buffer. Reason: [%s].\n",
802                         PHYSFS_getLastError());
803                 PHYSFS_close(f);
804                 return(1);
805             } /* if */
806         } /* if */
807
808         bw = strlen(WRITESTR);
809         rc = PHYSFS_write(f, WRITESTR, 1, bw);
810         if (rc != bw)
811         {
812             printf("Wrote (%d) of (%d) bytes. Reason: [%s].\n",
813                    (int) rc, (int) bw, PHYSFS_getLastError());
814         } /* if */
815         else
816         {
817             printf("Successful.\n");
818         } /* else */
819
820         PHYSFS_close(f);
821     } /* else */
822
823     return(1);
824 } /* cmd_append */
825
826
827 static int cmd_write(char *args)
828 {
829     PHYSFS_File *f;
830
831     if (*args == '\"')
832     {
833         args++;
834         args[strlen(args) - 1] = '\0';
835     } /* if */
836
837     f = PHYSFS_openWrite(args);
838     if (f == NULL)
839         printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
840     else
841     {
842         size_t bw;
843         PHYSFS_sint64 rc;
844
845         if (do_buffer_size)
846         {
847             if (!PHYSFS_setBuffer(f, do_buffer_size))
848             {
849                 printf("failed to set file buffer. Reason: [%s].\n",
850                         PHYSFS_getLastError());
851                 PHYSFS_close(f);
852                 return(1);
853             } /* if */
854         } /* if */
855
856         bw = strlen(WRITESTR);
857         rc = PHYSFS_write(f, WRITESTR, 1, bw);
858         if (rc != bw)
859         {
860             printf("Wrote (%d) of (%d) bytes. Reason: [%s].\n",
861                    (int) rc, (int) bw, PHYSFS_getLastError());
862         } /* if */
863         else
864         {
865             printf("Successful.\n");
866         } /* else */
867
868         PHYSFS_close(f);
869     } /* else */
870
871     return(1);
872 } /* cmd_write */
873
874
875 static void modTimeToStr(PHYSFS_sint64 modtime, char *modstr, size_t strsize)
876 {
877     time_t t = (time_t) modtime;
878     char *str = ctime(&t);
879     strncpy(modstr, str, strsize);
880     modstr[strsize-1] = '\0';
881 } /* modTimeToStr */
882
883
884 static int cmd_getlastmodtime(char *args)
885 {
886     PHYSFS_sint64 rc = PHYSFS_getLastModTime(args);
887     if (rc == -1)
888         printf("Failed to determine. Reason: [%s].\n", PHYSFS_getLastError());
889     else
890     {
891         char modstr[64];
892         modTimeToStr(rc, modstr, sizeof (modstr));
893         printf("Last modified: %s (%ld).\n", modstr, (long) rc);
894     } /* else */
895
896     return(1);
897 } /* cmd_getLastModTime */
898
899
900 /* must have spaces trimmed prior to this call. */
901 static int count_args(const char *str)
902 {
903     int retval = 0;
904     int in_quotes = 0;
905
906     if (str != NULL)
907     {
908         for (; *str != '\0'; str++)
909         {
910             if (*str == '\"')
911                 in_quotes = !in_quotes;
912             else if ((*str == ' ') && (!in_quotes))
913                 retval++;
914         } /* for */
915         retval++;
916     } /* if */
917
918     return(retval);
919 } /* count_args */
920
921
922 static int cmd_help(char *args);
923
924 typedef struct
925 {
926     const char *cmd;
927     int (*func)(char *args);
928     int argcount;
929     const char *usage;
930 } command_info;
931
932 static const command_info commands[] =
933 {
934     { "quit",           cmd_quit,           0, NULL                         },
935     { "q",              cmd_quit,           0, NULL                         },
936     { "help",           cmd_help,           0, NULL                         },
937     { "init",           cmd_init,           1, "<argv0>"                    },
938     { "deinit",         cmd_deinit,         0, NULL                         },
939     { "addarchive",     cmd_addarchive,     2, "<archiveLocation> <append>" },
940     { "mount",          cmd_mount,          3, "<archiveLocation> <mntpoint> <append>" },
941     { "removearchive",  cmd_removearchive,  1, "<archiveLocation>"          },
942     { "enumerate",      cmd_enumerate,      1, "<dirToEnumerate>"           },
943     { "ls",             cmd_enumerate,      1, "<dirToEnumerate>"           },
944     { "getlasterror",   cmd_getlasterror,   0, NULL                         },
945     { "getdirsep",      cmd_getdirsep,      0, NULL                         },
946     { "getcdromdirs",   cmd_getcdromdirs,   0, NULL                         },
947     { "getsearchpath",  cmd_getsearchpath,  0, NULL                         },
948     { "getbasedir",     cmd_getbasedir,     0, NULL                         },
949     { "getuserdir",     cmd_getuserdir,     0, NULL                         },
950     { "getwritedir",    cmd_getwritedir,    0, NULL                         },
951     { "setwritedir",    cmd_setwritedir,    1, "<newWriteDir>"              },
952     { "permitsymlinks", cmd_permitsyms,     1, "<1or0>"                     },
953     { "setsaneconfig",  cmd_setsaneconfig,  5, "<org> <appName> <arcExt> <includeCdRoms> <archivesFirst>" },
954     { "mkdir",          cmd_mkdir,          1, "<dirToMk>"                  },
955     { "delete",         cmd_delete,         1, "<dirToDelete>"              },
956     { "getrealdir",     cmd_getrealdir,     1, "<fileToFind>"               },
957     { "exists",         cmd_exists,         1, "<fileToCheck>"              },
958     { "isdir",          cmd_isdir,          1, "<fileToCheck>"              },
959     { "issymlink",      cmd_issymlink,      1, "<fileToCheck>"              },
960     { "cat",            cmd_cat,            1, "<fileToCat>"                },
961     { "filelength",     cmd_filelength,     1, "<fileToCheck>"              },
962     { "append",         cmd_append,         1, "<fileToAppend>"             },
963     { "write",          cmd_write,          1, "<fileToCreateOrTrash>"      },
964     { "getlastmodtime", cmd_getlastmodtime, 1, "<fileToExamine>"            },
965     { "setbuffer",      cmd_setbuffer,      1, "<bufferSize>"               },
966     { "stressbuffer",   cmd_stressbuffer,   1, "<bufferSize>"               },
967     { NULL,             NULL,              -1, NULL                         }
968 };
969
970
971 static void output_usage(const char *intro, const command_info *cmdinfo)
972 {
973     if (cmdinfo->argcount == 0)
974         printf("%s \"%s\" (no arguments)\n", intro, cmdinfo->cmd);
975     else
976         printf("%s \"%s %s\"\n", intro, cmdinfo->cmd, cmdinfo->usage);
977 } /* output_usage */
978
979
980 static int cmd_help(char *args)
981 {
982     const command_info *i;
983
984     printf("Commands:\n");
985     for (i = commands; i->cmd != NULL; i++)
986         output_usage("  -", i);
987
988     return(1);
989 } /* output_cmd_help */
990
991
992 static void trim_command(const char *orig, char *copy)
993 {
994     const char *i;
995     char *writeptr = copy;
996     int spacecount = 0;
997     int have_first = 0;
998
999     for (i = orig; *i != '\0'; i++)
1000     {
1001         if (*i == ' ')
1002         {
1003             if ((*(i + 1) != ' ') && (*(i + 1) != '\0'))
1004             {
1005                 if ((have_first) && (!spacecount))
1006                 {
1007                     spacecount++;
1008                     *writeptr = ' ';
1009                     writeptr++;
1010                 } /* if */
1011             } /* if */
1012         } /* if */
1013         else
1014         {
1015             have_first = 1;
1016             spacecount = 0;
1017             *writeptr = *i;
1018             writeptr++;
1019         } /* else */
1020     } /* for */
1021
1022     *writeptr = '\0';
1023
1024     /*
1025     printf("\n command is [%s].\n", copy);
1026     */
1027 } /* trim_command */
1028
1029
1030 static int process_command(char *complete_cmd)
1031 {
1032     const command_info *i;
1033     char *cmd_copy;
1034     char *args;
1035     int rc = 1;
1036
1037     if (complete_cmd == NULL)  /* can happen if user hits CTRL-D, etc. */
1038     {
1039         printf("\n");
1040         return(0);
1041     } /* if */
1042
1043     cmd_copy = (char *) malloc(strlen(complete_cmd) + 1);
1044     if (cmd_copy == NULL)
1045     {
1046         printf("\n\n\nOUT OF MEMORY!\n\n\n");
1047         return(0);
1048     } /* if */
1049
1050     trim_command(complete_cmd, cmd_copy);
1051     args = strchr(cmd_copy, ' ');
1052     if (args != NULL)
1053     {
1054         *args = '\0';
1055         args++;
1056     } /* else */
1057
1058     if (cmd_copy[0] != '\0')
1059     {
1060         for (i = commands; i->cmd != NULL; i++)
1061         {
1062             if (strcmp(i->cmd, cmd_copy) == 0)
1063             {
1064                 if ((i->argcount >= 0) && (count_args(args) != i->argcount))
1065                     output_usage("usage:", i);
1066                 else
1067                     rc = i->func(args);
1068                 break;
1069             } /* if */
1070         } /* for */
1071
1072         if (i->cmd == NULL)
1073             printf("Unknown command. Enter \"help\" for instructions.\n");
1074
1075 #if (defined PHYSFS_HAVE_READLINE)
1076         add_history(complete_cmd);
1077         if (history_file)
1078         {
1079             fprintf(history_file, "%s\n", complete_cmd);
1080             fflush(history_file);
1081         } /* if */
1082 #endif
1083
1084     } /* if */
1085
1086     free(cmd_copy);
1087     return(rc);
1088 } /* process_command */
1089
1090
1091 static void open_history_file(void)
1092 {
1093 #if (defined PHYSFS_HAVE_READLINE)
1094 #if 0
1095     const char *envr = getenv("TESTPHYSFS_HISTORY");
1096     if (!envr)
1097         return;
1098 #else
1099     char envr[256];
1100     strcpy(envr, PHYSFS_getUserDir());
1101     strcat(envr, ".testphys_history");
1102 #endif
1103
1104     if (access(envr, F_OK) == 0)
1105     {
1106         char buf[512];
1107         FILE *f = fopen(envr, "r");
1108         if (!f)
1109         {
1110             printf("\n\n"
1111                    "Could not open history file [%s] for reading!\n"
1112                    "  Will not have past history available.\n\n",
1113                     envr);
1114             return;
1115         } /* if */
1116
1117         do
1118         {
1119             if (fgets(buf, sizeof (buf), f) == NULL)
1120                 break;
1121
1122             if (buf[strlen(buf) - 1] == '\n')
1123                 buf[strlen(buf) - 1] = '\0';
1124             add_history(buf);
1125         } while (!feof(f));
1126
1127         fclose(f);
1128     } /* if */
1129
1130     history_file = fopen(envr, "ab");
1131     if (!history_file)
1132     {
1133         printf("\n\n"
1134                "Could not open history file [%s] for appending!\n"
1135                "  Will not be able to record this session's history.\n\n",
1136                 envr);
1137     } /* if */
1138 #endif
1139 } /* open_history_file */
1140
1141
1142 int main(int argc, char **argv)
1143 {
1144     char *buf = NULL;
1145     int rc = 0;
1146
1147 #if (defined __MWERKS__)
1148     extern tSIOUXSettings SIOUXSettings;
1149     SIOUXSettings.asktosaveonclose = 0;
1150     SIOUXSettings.autocloseonquit = 1;
1151     SIOUXSettings.rows = 40;
1152     SIOUXSettings.columns = 120;
1153 #endif
1154
1155     printf("\n");
1156
1157     if (!PHYSFS_init(argv[0]))
1158     {
1159         printf("PHYSFS_init() failed!\n  reason: %s.\n", PHYSFS_getLastError());
1160         return(1);
1161     } /* if */
1162
1163     output_versions();
1164     output_archivers();
1165
1166     open_history_file();
1167
1168     printf("Enter commands. Enter \"help\" for instructions.\n");
1169
1170     do
1171     {
1172 #if (defined PHYSFS_HAVE_READLINE)
1173         buf = readline("> ");
1174 #else
1175         int i;
1176         buf = (char *) malloc(512);
1177         memset(buf, '\0', 512);
1178         printf("> ");
1179         for (i = 0; i < 511; i++)
1180         {
1181             int ch = fgetc(stdin);
1182             if (ch == EOF)
1183             {
1184                 strcpy(buf, "quit");
1185                 break;
1186             } /* if */
1187             else if ((ch == '\n') || (ch == '\r'))
1188             {
1189                 buf[i] = '\0';
1190                 break;
1191             } /* else if */
1192             else if (ch == '\b')
1193             {
1194                 if (i > 0)
1195                     i--;
1196             } /* else if */
1197             else
1198             {
1199                 buf[i] = (char) ch;
1200             } /* else */
1201         } /* for */
1202 #endif
1203
1204         rc = process_command(buf);
1205         if (buf != NULL)
1206             free(buf);
1207     } while (rc);
1208
1209     if (!PHYSFS_deinit())
1210         printf("PHYSFS_deinit() failed!\n  reason: %s.\n", PHYSFS_getLastError());
1211
1212     if (history_file)
1213         fclose(history_file);
1214
1215 /*
1216     printf("\n\ntest_physfs written by ryan c. gordon.\n");
1217     printf(" it makes you shoot teh railgun bettar.\n");
1218 */
1219
1220     return(0);
1221 } /* main */
1222
1223 /* end of test_physfs.c ... */
1224