OSDN Git Service

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