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. */
5 /* data librarian; only useful if you are making the library version, DLBLIB */
9 #if !defined(O_WRONLY) && !defined(MAC) && !defined(AZTEC_C)
12 #if defined(__DJGPP__)
16 static void FDECL(xexit, (int));
21 #define DLB_DIRECTORY "Directory" /* name of lib directory */
22 #define LIBLISTFILE "dlb.lst" /* default list file */
24 /* library functions (from dlb.c) */
25 extern boolean FDECL(open_library,(const char *,library *));
26 extern void FDECL(close_library,(library *));
28 char *FDECL(eos, (char *)); /* also used by dlb.c */
29 FILE *FDECL(fopen_datafile, (const char *,const char *));
32 extern char *FDECL(vms_basename, (const char *));
33 extern int FDECL(vms_open, (const char *,int,unsigned int));
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));
41 static char default_progname[] = "dlb";
42 static char *progname = default_progname;
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;
49 static char origdir[255]="";
56 #define MAX_DLB_FILES 200 /* max # of files we'll handle */
57 #define DLB_VERS 1 /* version of dlb file we will write */
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.
64 #define ENC_NORMAL 'n' /* normal: not compressed in any way */
68 * If you know tar, you have a small clue how to use this (note: - does
69 * NOT mean stdin/stdout).
71 * dlb COMMANDoptions arg... files...
73 * dlb x extract all files
74 * dlb c build the archive
75 * dlb t list the archive
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)
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);
95 static const char *long_help[] = {
97 "dlb COMMANDoptions args... files...",
99 " dlb ? print this text",
101 " dlb x extract all files",
102 " dlb c create the archive",
103 " dlb t list table of contents",
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",
114 for (str = long_help; *str; str++)
115 (void) printf("%s\n", *str);
125 #if defined(MSDOS) && !defined(__DJGPP__)
129 printf("%d Length specified for write() too large for 16 bit env.",
133 slen = (unsigned short)len;
134 if (write(out,buf,slen) != slen) {
136 if (write(out,buf,len) != len) {
138 printf("Write Error in '%s'\n",library_file);
153 #ifdef VMS /* essential to have punctuation, to avoid logical names */
155 vms_fopen(filename, mode)
156 const char *filename, *mode;
160 if (!index(filename, '.') && !index(filename, ';'))
161 filename = strcat(strcpy(tmp, filename), ";0");
162 return fopen(filename, mode, "mbc=16");
164 #define fopen vms_fopen
167 /* open_library(dlb.c) needs this (which normally comes from src/files.c) */
169 fopen_datafile(filename, mode)
170 const char *filename, *mode;
172 return fopen(filename, mode);
186 int ap=2; /* argument pointer */
187 int cp; /* command pointer */
188 int iseen=0, fseen=0, verbose=0; /* flags */
192 if (argc > 0 && argv[0] && *argv[0]) progname = argv[0];
194 progname = vms_basename(progname);
202 for(cp=0;argv[1][cp];cp++){
205 usage(); /* doesn't return */
206 case '-': /* silently ignore */
213 if (ap == argc) usage();
214 list_file=argv[ap++];
216 printf("Warning: multiple I options. Previous ignored.\n");
220 if (ap == argc) usage();
221 library_file=argv[ap++];
223 printf("Warning: multiple f options. Previous ignored.\n");
227 if (ap == argc) usage();
229 if(!getcwd(origdir,sizeof(origdir))){
230 printf("Can't get current directory.\n");
234 if(chdir(argv[ap++])){
235 printf("Can't chdir to %s\n",argv[--ap]);
246 printf("Only one of t,x,c may be specified.\n");
254 if(argv[ap] && iseen){
255 printf("Too many arguments.\n");
261 printf("Internal error - action.\n");
264 case 't': /* list archive */
265 if (!open_library(library_file, &lib)) {
266 printf("Can't open dlb file\n");
270 for (i = 0; i < lib.nentries; i++) {
272 printf("%-14s %6ld %6ld\n",
273 lib.dir[i].fname, lib.dir[i].foffset, lib.dir[i].fsize);
275 printf("%s\n", lib.dir[i].fname);
279 printf("Revision:%ld File count:%ld String size:%ld\n",
280 lib.rev, lib.nentries, lib.strsize);
285 case 'x': { /* extract archive contents */
287 long remainder, total_read;
290 if (!open_library(library_file, &lib)) {
291 printf("Can't open dlb file\n");
295 for (i = 0; i < lib.nentries; i++) {
297 /* if files are listed, see if current is wanted */
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)) {
304 * Don't extract the directory unless the user
305 * specifically asks for it.
307 * Perhaps we should never extract the directory???
311 fseek(lib.fdata, lib.dir[i].foffset, SEEK_SET);
313 f = open(lib.dir[i].fname, O_WRONLY|O_TRUNC|O_BINARY|O_CREAT, 0640);
315 printf("Can't create '%s'\n", lib.dir[i].fname);
319 /* read chunks from library and write them out */
322 remainder = lib.dir[i].fsize - total_read;
323 if (remainder > (long) sizeof(buf))
324 r = (int) sizeof(buf);
328 n = fread(buf, 1, r, lib.fdata);
330 printf("Read Error in '%s'\n", lib.dir[i].fname);
333 if (write(f, buf, n) != n) {
334 printf("Write Error in '%s'\n", lib.dir[i].fname);
339 } while (total_read != lib.dir[i].fsize);
343 if (verbose) printf("x %s\n", lib.dir[i].fname);
350 case 'c': /* create archive */
352 libdir ld[MAX_DLB_FILES];
354 int fd, out, nfiles = 0;
355 long dir_size, slen, flen, fsiz;
356 boolean rewrite_directory = FALSE;
359 * Get names from either/both an argv list and a file
360 * list. This does not do any duplicate checking
363 /* get file name in argv list */
365 for ( ; ap < argc; ap++, nfiles++) {
366 if (nfiles >= MAX_DLB_FILES) {
367 printf("Too many dlb files! Stopping at %d.\n",
371 ld[nfiles].fname = (char *) alloc(strlen(argv[ap]) + 1);
372 Strcpy(ld[nfiles].fname, argv[ap]);
377 /* want to do a list file */
378 FILE *list = fopen(list_file, "r");
380 printf("Can't open %s\n",list_file);
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",
391 *(eos(buf)-1) = '\0'; /* strip newline */
392 ld[nfiles].fname = (char *) alloc(strlen(buf) + 1);
393 Strcpy(ld[nfiles].fname, buf);
399 printf("No files to archive\n");
405 * Get file sizes and name string length. Don't include
406 * the directory information yet.
408 for (i = 0, slen = 0, flen = 0; i < nfiles; i++) {
409 fd = open(ld[i].fname, O_RDONLY|O_BINARY, 0);
411 printf("Can't open %s\n", ld[i].fname);
414 ld[i].fsize = lseek(fd, 0, SEEK_END);
415 ld[i].foffset = flen;
417 slen += strlen(ld[i].fname); /* don't add null (yet) */
422 /* open output file */
423 out = open(library_file, O_RDWR|O_TRUNC|O_BINARY|O_CREAT, FCMASK);
425 printf("Can't open %s for output\n", library_file);
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 */
434 /* write directory */
435 write_dlb_directory(out, nfiles, ld, slen, dir_size, flen);
438 /* write each file */
439 for (i = 0; i < nfiles; i++) {
440 fd = open(ld[i].fname, O_RDONLY|O_BINARY, 0);
442 printf("Can't open input file '%s'\n", ld[i].fname);
445 if (verbose) printf("%s\n",ld[i].fname);
448 while ((r = read(fd, buf, sizeof buf)) != 0) {
450 printf("Read Error in '%s'\n", ld[i].fname);
453 if (write(out, buf, r) != r) {
454 printf("Write Error in '%s'\n", ld[i].fname);
460 if (fsiz != ld[i].fsize) rewrite_directory = TRUE;
461 /* in case directory rewrite is needed */
463 ld[i].foffset = flen;
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);
473 for (i = 0; i < nfiles; i++)
474 free((genericptr_t) ld[i].fname), ld[i].fname = 0;
492 write_dlb_directory(out, nfiles, ld, slen, dir_size, flen)
495 long slen, dir_size, flen;
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));
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));
531 if (origdir[0]) chdir(origdir);
540 const char amiga_version_string[] = AMIGA_VERSION_STRING;