OSDN Git Service

upgrade to 3.6.1
[jnethack/source.git] / util / dlb_main.c
1 /* NetHack 3.6  dlb_main.c      $NHDT-Date: 1432512785 2015/05/25 00:13:05 $  $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */
2 /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1993. */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 /* data librarian; only useful if you are making the library version, DLBLIB
6  */
7
8 #include "config.h"
9 #include "dlb.h"
10 #if !defined(O_WRONLY) && !defined(MAC) && !defined(AZTEC_C)
11 #include <fcntl.h>
12 #endif
13 #if defined(__DJGPP__)
14 #include <string.h>
15 #endif
16
17 static void FDECL(grow_ld, (libdir **, int *, int));
18 static void FDECL(xexit, (int));
19
20 #ifdef DLB
21 #ifdef DLBLIB
22
23 #define DLB_DIRECTORY "Directory" /* name of lib directory */
24 #define LIBLISTFILE "dlb.lst"     /* default list file */
25
26 /* library functions (from dlb.c) */
27 extern boolean FDECL(open_library, (const char *, library *));
28 extern void FDECL(close_library, (library *));
29
30 char *FDECL(eos, (char *)); /* also used by dlb.c */
31 FILE *FDECL(fopen_datafile, (const char *, const char *));
32
33 static void FDECL(Write, (int, char *, long));
34 static void NDECL(usage);
35 static void NDECL(verbose_help);
36 static void FDECL(write_dlb_directory,
37                   (int, int, libdir *, long, long, long));
38
39 static char default_progname[] = "dlb";
40 static char *progname = default_progname;
41
42 /* fixed library and list file names - can be overridden if necessary */
43 static const char *library_file = DLBFILE;
44 static const char *list_file = LIBLISTFILE;
45
46 #ifdef AMIGA
47 static char origdir[255] = "";
48 #endif
49
50 #ifndef O_BINARY
51 #define O_BINARY 0
52 #endif
53
54 #define DLB_FILES_ALLOC 200 /* initial # of files we'll handle; can grow */
55 #define DLB_VERS 1          /* version of dlb file we will write */
56
57 /*
58  * How the file is encoded within the library.  Don't use a space
59  * because (at least) the  SunOS 4.1.3 C library will eat the white
60  * space instead of preserving it like the man page says it should.
61  */
62 #define ENC_NORMAL 'n' /* normal: not compressed in any way */
63
64 /*
65  * If you know tar, you have a small clue how to use this (note: - does
66  * NOT mean stdin/stdout).
67  *
68  * dlb COMMANDoptions arg... files...
69  * commands:
70  *  dlb x       extract all files
71  *  dlb c       build the archive
72  *  dlb t       list the archive
73  * options:
74  *  v           verbose
75  *  f file      specify archive file (default DLBFILE)
76  *  I file      specify file for list of files (default LIBLISTFILE)
77  *  C dir       chdir to dir (used ONCE, not like tar's -C)
78  */
79
80 static void
81 usage()
82 {
83     (void) printf("Usage: %s [ctxCIfv] arguments... [files...]\n", progname);
84     (void) printf("  default library is %s\n", library_file);
85     (void) printf("  default list file is %s\n", list_file);
86     xexit(EXIT_FAILURE);
87 }
88
89 static void
90 verbose_help()
91 {
92     static const char *long_help[] = {
93         "", "dlb COMMANDoptions args... files...", "  commands:",
94         "    dlb ?   print this text", "    dlb h   ditto",
95         "    dlb x   extract all files", "    dlb c   create the archive",
96         "    dlb t   list table of contents", "  options:",
97         "    v       verbose operation",
98         "    f file  specify archive file name",
99         "    I file  specify file for list of file names",
100         "    C dir   change directory before processing any files", "",
101         (char *) 0
102     };
103     const char **str;
104
105     for (str = long_help; *str; str++)
106         (void) printf("%s\n", *str);
107     usage();
108 }
109
110 static void
111 Write(out, buf, len)
112 int out;
113 char *buf;
114 long len;
115 {
116 #if defined(MSDOS) && !defined(__DJGPP__)
117     unsigned short slen;
118
119     if (len > 65534) {
120         printf("%d Length specified for write() too large for 16 bit env.",
121                len);
122         xexit(EXIT_FAILURE);
123     }
124     slen = (unsigned short) len;
125     if (write(out, buf, slen) != slen) {
126 #else
127     if (write(out, buf, len) != len) {
128 #endif
129         printf("Write Error in '%s'\n", library_file);
130         xexit(EXIT_FAILURE);
131     }
132 }
133
134 char *
135 eos(s)
136 char *s;
137 {
138     while (*s)
139         s++;
140     return s;
141 }
142
143 /* open_library(dlb.c) needs this (which normally comes from src/files.c) */
144 FILE *
145 fopen_datafile(filename, mode)
146 const char *filename, *mode;
147 {
148     return fopen(filename, mode);
149 }
150
151 #endif /* DLBLIB */
152 #endif /* DLB */
153
154 int
155 main(argc, argv)
156 int argc;
157 char **argv;
158 {
159 #ifdef DLB
160 #ifdef DLBLIB
161     int i, r;
162     int ap = 2;                            /* argument pointer */
163     int cp;                                /* command pointer */
164     int iseen = 0, fseen = 0, verbose = 0; /* flags */
165     char action = ' ';
166     library lib;
167
168     if (argc > 0 && argv[0] && *argv[0])
169         progname = argv[0];
170 #ifdef VMS
171     progname = vms_basename(progname);
172 #endif
173
174     if (argc < 2) {
175         usage();
176         /* doesn't return */
177     }
178
179     for (cp = 0; argv[1][cp]; cp++) {
180         switch (argv[1][cp]) {
181         default:
182             usage(); /* doesn't return */
183         case '-':    /* silently ignore */
184             break;
185         case '?':
186         case 'h':
187             verbose_help();
188             break;
189         case 'I':
190             if (ap == argc)
191                 usage();
192             list_file = argv[ap++];
193             if (iseen)
194                 printf("Warning: multiple I options.  Previous ignored.\n");
195             iseen = 1;
196             break;
197         case 'f':
198             if (ap == argc)
199                 usage();
200             library_file = argv[ap++];
201             if (fseen)
202                 printf("Warning: multiple f options.  Previous ignored.\n");
203             fseen = 1;
204             break;
205         case 'C':
206             if (ap == argc)
207                 usage();
208 #ifdef AMIGA
209             if (!getcwd(origdir, sizeof(origdir))) {
210                 printf("Can't get current directory.\n");
211                 xexit(EXIT_FAILURE);
212             }
213 #endif
214             if (chdir(argv[ap++])) {
215                 printf("Can't chdir to %s\n", argv[--ap]);
216                 xexit(EXIT_FAILURE);
217             }
218             break;
219         case 'v':
220             verbose = 1;
221             break;
222         case 't':
223         case 'c':
224         case 'x':
225             if (action != ' ') {
226                 printf("Only one of t,x,c may be specified.\n");
227                 usage();
228             }
229             action = argv[1][cp];
230             break;
231         }
232     }
233
234     if (argv[ap] && iseen) {
235         printf("Too many arguments.\n");
236         xexit(EXIT_FAILURE);
237     }
238
239     switch (action) {
240     default:
241         printf("Internal error - action.\n");
242         xexit(EXIT_FAILURE);
243         break;
244     case 't': /* list archive */
245         if (!open_library(library_file, &lib)) {
246             printf("Can't open dlb file\n");
247             xexit(EXIT_FAILURE);
248         }
249
250         for (i = 0; i < lib.nentries; i++) {
251             if (verbose)
252                 printf("%-14s %6ld %6ld\n", lib.dir[i].fname,
253                        lib.dir[i].foffset, lib.dir[i].fsize);
254             else
255                 printf("%s\n", lib.dir[i].fname);
256         }
257
258         if (verbose)
259             printf("Revision:%ld  File count:%ld  String size:%ld\n", lib.rev,
260                    lib.nentries, lib.strsize);
261
262         close_library(&lib);
263         xexit(EXIT_SUCCESS);
264
265     case 'x': { /* extract archive contents */
266         int f, n;
267         long remainder, total_read;
268         char buf[BUFSIZ];
269
270         if (!open_library(library_file, &lib)) {
271             printf("Can't open dlb file\n");
272             xexit(EXIT_FAILURE);
273         }
274
275         for (i = 0; i < lib.nentries; i++) {
276             if (argv[ap]) {
277                 /* if files are listed, see if current is wanted */
278                 int c;
279                 for (c = ap; c < argc; c++)
280                     if (!FILENAME_CMP(lib.dir[i].fname, argv[c]))
281                         break;
282                 if (c == argc)
283                     continue; /* skip */
284             } else if (!FILENAME_CMP(lib.dir[i].fname, DLB_DIRECTORY)) {
285                 /*
286                  * Don't extract the directory unless the user
287                  * specifically asks for it.
288                  *
289                  * Perhaps we should never extract the directory???
290                  */
291                 continue;
292             }
293             fseek(lib.fdata, lib.dir[i].foffset, SEEK_SET);
294
295             f = open(lib.dir[i].fname,
296                      O_WRONLY | O_TRUNC | O_BINARY | O_CREAT, 0640);
297             if (f < 0) {
298                 printf("Can't create '%s'\n", lib.dir[i].fname);
299                 xexit(EXIT_FAILURE);
300             }
301
302             /* read chunks from library and write them out */
303             total_read = 0;
304             do {
305                 remainder = lib.dir[i].fsize - total_read;
306                 if (remainder > (long) sizeof(buf))
307                     r = (int) sizeof(buf);
308                 else
309                     r = remainder;
310
311                 n = fread(buf, 1, r, lib.fdata);
312                 if (n != r) {
313                     printf("Read Error in '%s'\n", lib.dir[i].fname);
314                     xexit(EXIT_FAILURE);
315                 }
316                 if (write(f, buf, n) != n) {
317                     printf("Write Error in '%s'\n", lib.dir[i].fname);
318                     xexit(EXIT_FAILURE);
319                 }
320
321                 total_read += n;
322             } while (total_read != lib.dir[i].fsize);
323
324             (void) close(f);
325
326             if (verbose)
327                 printf("x %s\n", lib.dir[i].fname);
328         }
329
330         close_library(&lib);
331         xexit(EXIT_SUCCESS);
332     }
333
334     case 'c': /* create archive */
335     {
336         libdir *ld = 0;
337         int ldlimit = 0;
338         char buf[BUFSIZ];
339         int fd, out, nfiles = 0;
340         long dir_size, slen, flen, fsiz;
341         boolean rewrite_directory = FALSE;
342
343         /*
344          * Get names from either/both an argv list and a file
345          * list.  This does not do any duplicate checking
346          */
347
348         grow_ld(&ld, &ldlimit, DLB_FILES_ALLOC);
349
350         /* get file name in argv list */
351         if (argv[ap]) {
352             for (; ap < argc; ap++, nfiles++) {
353                 if (nfiles == ldlimit)
354                     grow_ld(&ld, &ldlimit, DLB_FILES_ALLOC / 5);
355                 ld[nfiles].fname = (char *) alloc(strlen(argv[ap]) + 1);
356                 Strcpy(ld[nfiles].fname, argv[ap]);
357             }
358         }
359
360         if (iseen) {
361             /* want to do a list file */
362             FILE *list = fopen(list_file, "r");
363             if (!list) {
364                 printf("Can't open %s\n", list_file);
365                 xexit(EXIT_FAILURE);
366             }
367
368             /* get file names, one per line */
369             for (; fgets(buf, sizeof(buf), list); nfiles++) {
370                 if (nfiles == ldlimit)
371                     grow_ld(&ld, &ldlimit, DLB_FILES_ALLOC / 5);
372                 *(eos(buf) - 1) = '\0'; /* strip newline */
373                 ld[nfiles].fname = (char *) alloc(strlen(buf) + 1);
374                 Strcpy(ld[nfiles].fname, buf);
375             }
376             fclose(list);
377         }
378
379         if (nfiles == 0) {
380             printf("No files to archive\n");
381             xexit(EXIT_FAILURE);
382         }
383
384         /*
385          * Get file sizes and name string length.  Don't include
386          * the directory information yet.
387          */
388         for (i = 0, slen = 0, flen = 0; i < nfiles; i++) {
389             fd = open(ld[i].fname, O_RDONLY | O_BINARY, 0);
390             if (fd < 0) {
391                 printf("Can't open %s\n", ld[i].fname);
392                 xexit(EXIT_FAILURE);
393             }
394             ld[i].fsize = lseek(fd, 0, SEEK_END);
395             ld[i].foffset = flen;
396
397             slen += strlen(ld[i].fname); /* don't add null (yet) */
398             flen += ld[i].fsize;
399             close(fd);
400         }
401
402         /* open output file */
403         out =
404             open(library_file, O_RDWR | O_TRUNC | O_BINARY | O_CREAT, FCMASK);
405         if (out < 0) {
406             printf("Can't open %s for output\n", library_file);
407             xexit(EXIT_FAILURE);
408         }
409
410         /* caculate directory size */
411         dir_size = 40                    /* header line (see below) */
412                    + ((nfiles + 1) * 11) /* handling+file offset+SP+newline */
413                    + slen + strlen(DLB_DIRECTORY); /* file names */
414
415         /* write directory */
416         write_dlb_directory(out, nfiles, ld, slen, dir_size, flen);
417
418         flen = 0L;
419         /* write each file */
420         for (i = 0; i < nfiles; i++) {
421             fd = open(ld[i].fname, O_RDONLY | O_BINARY, 0);
422             if (fd < 0) {
423                 printf("Can't open input file '%s'\n", ld[i].fname);
424                 xexit(EXIT_FAILURE);
425             }
426             if (verbose)
427                 printf("%s\n", ld[i].fname);
428
429             fsiz = 0L;
430             while ((r = read(fd, buf, sizeof buf)) != 0) {
431                 if (r == -1) {
432                     printf("Read Error in '%s'\n", ld[i].fname);
433                     xexit(EXIT_FAILURE);
434                 }
435                 if (write(out, buf, r) != r) {
436                     printf("Write Error in '%s'\n", ld[i].fname);
437                     xexit(EXIT_FAILURE);
438                 }
439                 fsiz += r;
440             }
441             (void) close(fd);
442             if (fsiz != ld[i].fsize)
443                 rewrite_directory = TRUE;
444             /* in case directory rewrite is needed */
445             ld[i].fsize = fsiz;
446             ld[i].foffset = flen;
447             flen += fsiz;
448         }
449
450         if (rewrite_directory) {
451             if (verbose)
452                 printf("(rewriting dlb directory info)\n");
453             (void) lseek(out, 0, SEEK_SET); /* rewind */
454             write_dlb_directory(out, nfiles, ld, slen, dir_size, flen);
455         }
456
457         for (i = 0; i < nfiles; i++)
458             free((genericptr_t) ld[i].fname), ld[i].fname = 0;
459         free((genericptr_t) ld), ldlimit = 0;
460
461         (void) close(out);
462         xexit(EXIT_SUCCESS);
463     }
464     }
465 #endif /* DLBLIB */
466 #endif /* DLB */
467
468     xexit(EXIT_SUCCESS);
469     /*NOTREACHED*/
470     return 0;
471 }
472
473 #ifdef DLB
474 #ifdef DLBLIB
475
476 static void
477 grow_ld(ld_p, ldlimit_p, alloc_incr)
478 libdir **ld_p;
479 int *ldlimit_p;
480 int alloc_incr;
481 {
482     static libdir zerolibdir;
483     int i = 0, newlimit = *ldlimit_p + alloc_incr;
484     libdir *newld = (libdir *) alloc(newlimit * sizeof *newld);
485
486     if (*ld_p) {
487         for (; i < *ldlimit_p; ++i)
488             newld[i] = (*ld_p)[i];
489         free((genericptr_t) *ld_p);
490     }
491     *ld_p = newld, *ldlimit_p = newlimit;
492     for (; i < *ldlimit_p; ++i)
493         (*ld_p)[i] = zerolibdir;
494 }
495
496 static void
497 write_dlb_directory(out, nfiles, ld, slen, dir_size, flen)
498 int out, nfiles;
499 libdir *ld;
500 long slen, dir_size, flen;
501 {
502     char buf[BUFSIZ];
503     int i;
504
505     sprintf(buf, "%3ld %8ld %8ld %8ld %8ld\n",
506             (long) DLB_VERS,   /* version of dlb file */
507             (long) nfiles + 1, /* # of entries (includes directory) */
508                                /* string length + room for nulls */
509             (long) slen + (long) strlen(DLB_DIRECTORY) + nfiles + 1,
510             (long) dir_size,         /* start of first file */
511             (long) flen + dir_size); /* total file size */
512     Write(out, buf, strlen(buf));
513
514 /* write each file entry */
515 #define ENTRY_FORMAT "%c%s %8ld\n"
516     sprintf(buf, ENTRY_FORMAT, ENC_NORMAL, DLB_DIRECTORY, (long) 0);
517     Write(out, buf, strlen(buf));
518     for (i = 0; i < nfiles; i++) {
519         sprintf(buf, ENTRY_FORMAT, ENC_NORMAL, /* encoding */
520                 ld[i].fname,                   /* name */
521                 ld[i].foffset + dir_size);     /* offset */
522         Write(out, buf, strlen(buf));
523     }
524 }
525
526 #endif /* DLBLIB */
527 #endif /* DLB */
528
529 static void
530 xexit(retcd)
531 int retcd;
532 {
533 #ifdef DLB
534 #ifdef AMIGA
535     if (origdir[0])
536         chdir(origdir);
537 #endif
538 #endif
539     exit(retcd);
540 }
541
542 #ifdef AMIGA
543 #include "date.h"
544 const char amiga_version_string[] = AMIGA_VERSION_STRING;
545 #endif
546
547 /*dlb_main.c*/