1 /* NetHack 3.6 dlb_main.c $NHDT-Date: 1570258542 2019/10/05 06:55:42 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.13 $ */
2 /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1993. */
3 /* NetHack may be freely redistributed. See license for details. */
5 /* data librarian; only useful if you are making the library version, DLBLIB
10 #if !defined(O_WRONLY) && !defined(MAC) && !defined(AZTEC_C)
13 #if defined(__DJGPP__)
17 static void FDECL(grow_ld, (libdir **, int *, int));
18 static void FDECL(xexit, (int)) NORETURN;
23 #define DLB_DIRECTORY "Directory" /* name of lib directory */
24 #define LIBLISTFILE "dlb.lst" /* default list file */
26 /* library functions (from dlb.c) */
27 extern boolean FDECL(open_library, (const char *, library *));
28 extern void FDECL(close_library, (library *));
30 char *FDECL(eos, (char *)); /* also used by dlb.c */
31 FILE *FDECL(fopen_datafile, (const char *, const char *));
33 static void FDECL(Write, (int, char *, long));
34 static void NDECL(usage) NORETURN;
35 static void NDECL(verbose_help) NORETURN;
36 static void FDECL(write_dlb_directory, (int, int, libdir *, long, long, long));
38 static char default_progname[] = "dlb";
39 static char *progname = default_progname;
41 /* fixed library and list file names - can be overridden if necessary */
42 static const char *library_file = DLBFILE;
43 static const char *list_file = LIBLISTFILE;
46 static char origdir[255] = "";
53 #define DLB_FILES_ALLOC 200 /* initial # of files we'll handle; can grow */
54 #define DLB_VERS 1 /* version of dlb file we will write */
57 * How the file is encoded within the library. Don't use a space
58 * because (at least) the SunOS 4.1.3 C library will eat the white
59 * space instead of preserving it like the man page says it should.
61 #define ENC_NORMAL 'n' /* normal: not compressed in any way */
64 * If you know tar, you have a small clue how to use this (note: - does
65 * NOT mean stdin/stdout).
67 * dlb COMMANDoptions arg... files...
69 * dlb x extract all files
70 * dlb c build the archive
71 * dlb t list the archive
74 * f file specify archive file (default DLBFILE)
75 * I file specify file for list of files (default LIBLISTFILE)
76 * C dir chdir to dir (used ONCE, not like tar's -C)
82 (void) printf("Usage: %s [ctxCIfv] arguments... [files...]\n", progname);
83 (void) printf(" default library is %s\n", library_file);
84 (void) printf(" default list file is %s\n", list_file);
92 static const char *const 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", "",
103 const char *const *str;
105 for (str = long_help; *str; str++)
106 (void) printf("%s\n", *str);
117 #if defined(MSDOS) && !defined(__DJGPP__)
121 printf("%d Length specified for write() too large for 16 bit env.",
125 slen = (unsigned short) len;
126 if (write(out, buf, slen) != slen) {
128 if (write(out, buf, len) != len) {
130 printf("Write Error in '%s'\n", library_file);
144 /* open_library(dlb.c) needs this (which normally comes from src/files.c) */
146 fopen_datafile(filename, mode)
147 const char *filename, *mode;
149 return fopen(filename, mode);
163 int ap = 2; /* argument pointer */
164 int cp; /* command pointer */
165 int iseen = 0, fseen = 0, verbose = 0; /* flags */
169 if (argc > 0 && argv[0] && *argv[0])
172 progname = vms_basename(progname);
180 for (cp = 0; argv[1][cp]; cp++) {
181 switch (argv[1][cp]) {
183 usage(); /* doesn't return */
186 case '-': /* silently ignore */
196 list_file = argv[ap++];
198 printf("Warning: multiple I options. Previous ignored.\n");
204 library_file = argv[ap++];
205 #ifdef VERSION_IN_DLB_FILENAME
206 library_file = build_dlb_filename(library_file);
209 printf("Warning: multiple f options. Previous ignored.\n");
216 if (!getcwd(origdir, sizeof(origdir))) {
217 printf("Can't get current directory.\n");
221 if (chdir(argv[ap++])) {
222 printf("Can't chdir to %s\n", argv[--ap]);
233 printf("Only one of t,x,c may be specified.\n");
236 action = argv[1][cp];
241 if (argv[ap] && iseen) {
242 printf("Too many arguments.\n");
248 printf("Internal error - action.\n");
253 case 't': /* list archive */
254 if (!open_library(library_file, &lib)) {
255 printf("Can't open dlb file\n");
259 for (i = 0; i < lib.nentries; i++) {
261 printf("%-14s %6ld %6ld\n", lib.dir[i].fname,
262 lib.dir[i].foffset, lib.dir[i].fsize);
264 printf("%s\n", lib.dir[i].fname);
268 printf("Revision:%ld File count:%ld String size:%ld\n", lib.rev,
269 lib.nentries, lib.strsize);
272 /* xexit(EXIT_SUCCESS); */
275 case 'x': { /* extract archive contents */
277 long remainder, total_read;
280 if (!open_library(library_file, &lib)) {
281 printf("Can't open dlb file\n");
285 for (i = 0; i < lib.nentries; i++) {
287 /* if files are listed, see if current is wanted */
289 for (c = ap; c < argc; c++)
290 if (!FILENAME_CMP(lib.dir[i].fname, argv[c]))
294 } else if (!FILENAME_CMP(lib.dir[i].fname, DLB_DIRECTORY)) {
296 * Don't extract the directory unless the user
297 * specifically asks for it.
299 * Perhaps we should never extract the directory???
303 fseek(lib.fdata, lib.dir[i].foffset, SEEK_SET);
305 f = open(lib.dir[i].fname,
306 O_WRONLY | O_TRUNC | O_BINARY | O_CREAT, 0640);
308 printf("Can't create '%s'\n", lib.dir[i].fname);
312 /* read chunks from library and write them out */
315 remainder = lib.dir[i].fsize - total_read;
316 if (remainder > (long) sizeof(buf))
317 r = (int) sizeof(buf);
321 n = fread(buf, 1, r, lib.fdata);
323 printf("Read Error in '%s'\n", lib.dir[i].fname);
326 if (write(f, buf, n) != n) {
327 printf("Write Error in '%s'\n", lib.dir[i].fname);
332 } while (total_read != lib.dir[i].fsize);
337 printf("x %s\n", lib.dir[i].fname);
341 /* xexit(EXIT_SUCCESS); */
345 case 'c': /* create archive */
350 int fd, out, nfiles = 0;
351 long dir_size, slen, flen, fsiz;
352 boolean rewrite_directory = FALSE;
355 * Get names from either/both an argv list and a file
356 * list. This does not do any duplicate checking
359 grow_ld(&ld, &ldlimit, DLB_FILES_ALLOC);
361 /* get file name in argv list */
363 for (; ap < argc; ap++, nfiles++) {
364 if (nfiles == ldlimit)
365 grow_ld(&ld, &ldlimit, DLB_FILES_ALLOC / 5);
366 ld[nfiles].fname = (char *) alloc(strlen(argv[ap]) + 1);
367 Strcpy(ld[nfiles].fname, argv[ap]);
372 /* want to do a list file */
373 FILE *list = fopen(list_file, "r");
375 printf("Can't open %s\n", list_file);
379 /* get file names, one per line */
380 for (; fgets(buf, sizeof(buf), list); nfiles++) {
381 if (nfiles == ldlimit)
382 grow_ld(&ld, &ldlimit, DLB_FILES_ALLOC / 5);
383 *(eos(buf) - 1) = '\0'; /* strip newline */
384 ld[nfiles].fname = (char *) alloc(strlen(buf) + 1);
385 Strcpy(ld[nfiles].fname, buf);
391 printf("No files to archive\n");
396 * Get file sizes and name string length. Don't include
397 * the directory information yet.
399 for (i = 0, slen = 0, flen = 0; i < nfiles; i++) {
400 fd = open(ld[i].fname, O_RDONLY | O_BINARY, 0);
402 printf("Can't open %s\n", ld[i].fname);
405 ld[i].fsize = lseek(fd, 0, SEEK_END);
406 ld[i].foffset = flen;
408 slen += strlen(ld[i].fname); /* don't add null (yet) */
413 /* open output file */
414 out = open(library_file,
415 O_RDWR | O_TRUNC | O_BINARY | O_CREAT, FCMASK);
417 printf("Can't open %s for output\n", library_file);
421 /* caculate directory size */
422 dir_size = 40 /* header line (see below) */
423 + ((nfiles + 1) * 11) /* handling+file offset+SP+newline */
424 + slen + strlen(DLB_DIRECTORY); /* file names */
426 /* write directory */
427 write_dlb_directory(out, nfiles, ld, slen, dir_size, flen);
430 /* write each file */
431 for (i = 0; i < nfiles; i++) {
432 fd = open(ld[i].fname, O_RDONLY | O_BINARY, 0);
434 printf("Can't open input file '%s'\n", ld[i].fname);
438 printf("%s\n", ld[i].fname);
441 while ((r = read(fd, buf, sizeof buf)) != 0) {
443 printf("Read Error in '%s'\n", ld[i].fname);
446 if (write(out, buf, r) != r) {
447 printf("Write Error in '%s'\n", ld[i].fname);
453 if (fsiz != ld[i].fsize)
454 rewrite_directory = TRUE;
455 /* in case directory rewrite is needed */
457 ld[i].foffset = flen;
461 if (rewrite_directory) {
463 printf("(rewriting dlb directory info)\n");
464 (void) lseek(out, 0, SEEK_SET); /* rewind */
465 write_dlb_directory(out, nfiles, ld, slen, dir_size, flen);
468 for (i = 0; i < nfiles; i++)
469 free((genericptr_t) ld[i].fname), ld[i].fname = 0;
470 free((genericptr_t) ld), ldlimit = 0;
473 /* xexit(EXIT_SUCCESS); */
489 grow_ld(ld_p, ldlimit_p, alloc_incr)
494 static libdir zerolibdir;
495 int i = 0, newlimit = *ldlimit_p + alloc_incr;
496 libdir *newld = (libdir *) alloc(newlimit * sizeof *newld);
499 for (; i < *ldlimit_p; ++i)
500 newld[i] = (*ld_p)[i];
501 free((genericptr_t) *ld_p);
503 *ld_p = newld, *ldlimit_p = newlimit;
504 for (; i < *ldlimit_p; ++i)
505 (*ld_p)[i] = zerolibdir;
509 write_dlb_directory(out, nfiles, ld, slen, dir_size, flen)
512 long slen, dir_size, flen;
517 sprintf(buf, "%3ld %8ld %8ld %8ld %8ld\n",
518 (long) DLB_VERS, /* version of dlb file */
519 (long) nfiles + 1, /* # of entries (includes directory) */
520 /* string length + room for nulls */
521 (long) slen + (long) strlen(DLB_DIRECTORY) + nfiles + 1,
522 (long) dir_size, /* start of first file */
523 (long) flen + dir_size); /* total file size */
524 Write(out, buf, strlen(buf));
526 /* write each file entry */
527 #define ENTRY_FORMAT "%c%s %8ld\n"
528 sprintf(buf, ENTRY_FORMAT, ENC_NORMAL, DLB_DIRECTORY, (long) 0);
529 Write(out, buf, strlen(buf));
530 for (i = 0; i < nfiles; i++) {
531 sprintf(buf, ENTRY_FORMAT, ENC_NORMAL, /* encoding */
532 ld[i].fname, /* name */
533 ld[i].foffset + dir_size); /* offset */
534 Write(out, buf, strlen(buf));
557 const char amiga_version_string[] = AMIGA_VERSION_STRING;