Couple of extra nethack->anethack
[aNetHack.git] / util / dlb_main.c
blob422b1d83efdeab95f236514b868a3ccf57b5569f
1 /* aNetHack 0.0.1 dlb_main.c $ANH-Date: 1432512785 2015/05/25 00:13:05 $ $ANH-Branch: master $:$ANH-Revision: 1.10 $ */
2 /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1993. */
3 /* aNetHack may be freely redistributed. See license for details. */
5 /* data librarian; only useful if you are making the library version, DLBLIB
6 */
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
17 static void FDECL(grow_ld, (libdir **, int *, int));
18 static void FDECL(xexit, (int));
20 #ifdef DLB
21 #ifdef DLBLIB
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);
35 static void NDECL(verbose_help);
36 static void FDECL(write_dlb_directory,
37 (int, int, libdir *, long, long, long));
39 static char default_progname[] = "dlb";
40 static char *progname = default_progname;
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;
46 #ifdef AMIGA
47 static char origdir[255] = "";
48 #endif
50 #ifndef O_BINARY
51 #define O_BINARY 0
52 #endif
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 */
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.
62 #define ENC_NORMAL 'n' /* normal: not compressed in any way */
65 * If you know tar, you have a small clue how to use this (note: - does
66 * NOT mean stdin/stdout).
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)
80 static void
81 usage()
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);
89 static void
90 verbose_help()
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
103 const char **str;
105 for (str = long_help; *str; str++)
106 (void) printf("%s\n", *str);
107 usage();
110 static void
111 Write(out, buf, len)
112 int out;
113 char *buf;
114 long len;
116 #if defined(MSDOS) && !defined(__DJGPP__)
117 unsigned short slen;
119 if (len > 65534) {
120 printf("%d Length specified for write() too large for 16 bit env.",
121 len);
122 xexit(EXIT_FAILURE);
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);
134 char *
135 eos(s)
136 char *s;
138 while (*s)
139 s++;
140 return s;
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;
148 return fopen(filename, mode);
151 #endif /* DLBLIB */
152 #endif /* DLB */
155 main(argc, argv)
156 int argc;
157 char **argv;
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;
168 if (argc > 0 && argv[0] && *argv[0])
169 progname = argv[0];
170 #ifdef VMS
171 progname = vms_basename(progname);
172 #endif
174 if (argc < 2) {
175 usage();
176 /* doesn't return */
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);
213 #endif
214 if (chdir(argv[ap++])) {
215 printf("Can't chdir to %s\n", argv[--ap]);
216 xexit(EXIT_FAILURE);
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();
229 action = argv[1][cp];
230 break;
234 if (argv[ap] && iseen) {
235 printf("Too many arguments.\n");
236 xexit(EXIT_FAILURE);
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);
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);
258 if (verbose)
259 printf("Revision:%ld File count:%ld String size:%ld\n", lib.rev,
260 lib.nentries, lib.strsize);
262 close_library(&lib);
263 xexit(EXIT_SUCCESS);
265 case 'x': { /* extract archive contents */
266 int f, n;
267 long remainder, total_read;
268 char buf[BUFSIZ];
270 if (!open_library(library_file, &lib)) {
271 printf("Can't open dlb file\n");
272 xexit(EXIT_FAILURE);
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)) {
286 * Don't extract the directory unless the user
287 * specifically asks for it.
289 * Perhaps we should never extract the directory???
291 continue;
293 fseek(lib.fdata, lib.dir[i].foffset, SEEK_SET);
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);
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;
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);
316 if (write(f, buf, n) != n) {
317 printf("Write Error in '%s'\n", lib.dir[i].fname);
318 xexit(EXIT_FAILURE);
321 total_read += n;
322 } while (total_read != lib.dir[i].fsize);
324 (void) close(f);
326 if (verbose)
327 printf("x %s\n", lib.dir[i].fname);
330 close_library(&lib);
331 xexit(EXIT_SUCCESS);
334 case 'c': /* create archive */
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;
344 * Get names from either/both an argv list and a file
345 * list. This does not do any duplicate checking
348 grow_ld(&ld, &ldlimit, DLB_FILES_ALLOC);
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]);
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);
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);
376 fclose(list);
379 if (nfiles == 0) {
380 printf("No files to archive\n");
381 xexit(EXIT_FAILURE);
385 * Get file sizes and name string length. Don't include
386 * the directory information yet.
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);
394 ld[i].fsize = lseek(fd, 0, SEEK_END);
395 ld[i].foffset = flen;
397 slen += strlen(ld[i].fname); /* don't add null (yet) */
398 flen += ld[i].fsize;
399 close(fd);
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);
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 */
415 /* write directory */
416 write_dlb_directory(out, nfiles, ld, slen, dir_size, flen);
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);
426 if (verbose)
427 printf("%s\n", ld[i].fname);
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);
435 if (write(out, buf, r) != r) {
436 printf("Write Error in '%s'\n", ld[i].fname);
437 xexit(EXIT_FAILURE);
439 fsiz += r;
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;
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);
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;
461 (void) close(out);
462 xexit(EXIT_SUCCESS);
465 #endif /* DLBLIB */
466 #endif /* DLB */
468 xexit(EXIT_SUCCESS);
469 /*NOTREACHED*/
470 return 0;
473 #ifdef DLB
474 #ifdef DLBLIB
476 static void
477 grow_ld(ld_p, ldlimit_p, alloc_incr)
478 libdir **ld_p;
479 int *ldlimit_p;
480 int alloc_incr;
482 static libdir zerolibdir;
483 int i = 0, newlimit = *ldlimit_p + alloc_incr;
484 libdir *newld = (libdir *) alloc(newlimit * sizeof *newld);
486 if (*ld_p) {
487 for (; i < *ldlimit_p; ++i)
488 newld[i] = (*ld_p)[i];
489 free((genericptr_t) *ld_p);
491 *ld_p = newld, *ldlimit_p = newlimit;
492 for (; i < *ldlimit_p; ++i)
493 (*ld_p)[i] = zerolibdir;
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;
502 char buf[BUFSIZ];
503 int i;
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 + 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));
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));
526 #endif /* DLBLIB */
527 #endif /* DLB */
529 static void
530 xexit(retcd)
531 int retcd;
533 #ifdef DLB
534 #ifdef AMIGA
535 if (origdir[0])
536 chdir(origdir);
537 #endif
538 #endif
539 exit(retcd);
542 #ifdef AMIGA
543 #include "date.h"
544 const char amiga_version_string[] = AMIGA_VERSION_STRING;
545 #endif
547 /*dlb_main.c*/