--- /dev/null
+/* SCCS Id: @(#)dlb_main.c 3.3 98/08/16 */
+/* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1993. */
+/* NetHack may be freely redistributed. See license for details. */
+
+/* data librarian; only useful if you are making the library version, DLBLIB */
+
+#include "config.h"
+#include "dlb.h"
+#if !defined(O_WRONLY) && !defined(MAC) && !defined(AZTEC_C)
+#include <fcntl.h>
+#endif
+#if defined(__DJGPP__)
+#include <string.h>
+#endif
+
+static void FDECL(xexit, (int));
+
+#ifdef DLB
+#ifdef DLBLIB
+
+#define DLB_DIRECTORY "Directory" /* name of lib directory */
+#define LIBLISTFILE "dlb.lst" /* default list file */
+
+/* library functions (from dlb.c) */
+extern boolean FDECL(open_library,(const char *,library *));
+extern void FDECL(close_library,(library *));
+
+char *FDECL(eos, (char *)); /* also used by dlb.c */
+FILE *FDECL(fopen_datafile, (const char *,const char *));
+
+#ifdef VMS
+extern char *FDECL(vms_basename, (const char *));
+extern int FDECL(vms_open, (const char *,int,unsigned int));
+#endif
+
+static void FDECL(Write, (int,char *,long));
+static void NDECL(usage);
+static void NDECL(verbose_help);
+static void FDECL(write_dlb_directory, (int,int,libdir *,long,long,long));
+
+static char default_progname[] = "dlb";
+static char *progname = default_progname;
+
+/* fixed library and list file names - can be overridden if necessary */
+static const char *library_file = DLBFILE;
+static const char *list_file = LIBLISTFILE;
+
+#ifdef AMIGA
+static char origdir[255]="";
+#endif
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#define MAX_DLB_FILES 200 /* max # of files we'll handle */
+#define DLB_VERS 1 /* version of dlb file we will write */
+
+/*
+ * How the file is encoded within the library. Don't use a space
+ * because (at least) the SunOS 4.1.3 C library will eat the white
+ * space instead of preserving it like the man page says it should.
+ */
+#define ENC_NORMAL 'n' /* normal: not compressed in any way */
+
+
+/*
+ * If you know tar, you have a small clue how to use this (note: - does
+ * NOT mean stdin/stdout).
+ *
+ * dlb COMMANDoptions arg... files...
+ * commands:
+ * dlb x extract all files
+ * dlb c build the archive
+ * dlb t list the archive
+ * options:
+ * v verbose
+ * f file specify archive file (default DLBFILE)
+ * I file specify file for list of files (default LIBLISTFILE)
+ * C dir chdir to dir (used ONCE, not like tar's -C)
+ */
+
+static void
+usage()
+{
+ (void) printf("Usage: %s [ctxCIfv] arguments... [files...]\n", progname);
+ (void) printf(" default library is %s\n", library_file);
+ (void) printf(" default list file is %s\n", list_file);
+ xexit(EXIT_FAILURE);
+}
+
+static void
+verbose_help()
+{
+ static const char *long_help[] = {
+ "",
+ "dlb COMMANDoptions args... files...",
+ " commands:",
+ " dlb ? print this text",
+ " dlb h ditto",
+ " dlb x extract all files",
+ " dlb c create the archive",
+ " dlb t list table of contents",
+ " options:",
+ " v verbose operation",
+ " f file specify archive file name",
+ " I file specify file for list of file names",
+ " C dir change directory before processing any files",
+ "",
+ (char *)0
+ };
+ const char **str;
+
+ for (str = long_help; *str; str++)
+ (void) printf("%s\n", *str);
+ usage();
+}
+
+static void
+Write(out,buf,len)
+ int out;
+ char *buf;
+ long len;
+{
+#if defined(MSDOS) && !defined(__DJGPP__)
+ unsigned short slen;
+
+ if (len > 65534) {
+ printf("%d Length specified for write() too large for 16 bit env.",
+ len);
+ xexit(EXIT_FAILURE);
+ }
+ slen = (unsigned short)len;
+ if (write(out,buf,slen) != slen) {
+#else
+ if (write(out,buf,len) != len) {
+#endif
+ printf("Write Error in '%s'\n",library_file);
+ xexit(EXIT_FAILURE);
+ }
+}
+
+
+char *
+eos(s)
+ char *s;
+{
+ while (*s) s++;
+ return s;
+}
+
+
+#ifdef VMS /* essential to have punctuation, to avoid logical names */
+static FILE *
+vms_fopen(filename, mode)
+const char *filename, *mode;
+{
+ char tmp[BUFSIZ];
+
+ if (!index(filename, '.') && !index(filename, ';'))
+ filename = strcat(strcpy(tmp, filename), ";0");
+ return fopen(filename, mode, "mbc=16");
+}
+#define fopen vms_fopen
+#endif /* VMS */
+
+/* open_library(dlb.c) needs this (which normally comes from src/files.c) */
+FILE *
+fopen_datafile(filename, mode)
+const char *filename, *mode;
+{
+ return fopen(filename, mode);
+}
+
+#endif /* DLBLIB */
+#endif /* DLB */
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+#ifdef DLB
+#ifdef DLBLIB
+ int i, r;
+ int ap=2; /* argument pointer */
+ int cp; /* command pointer */
+ int iseen=0, fseen=0, verbose=0; /* flags */
+ char action=' ';
+ library lib;
+
+ if (argc > 0 && argv[0] && *argv[0]) progname = argv[0];
+#ifdef VMS
+ progname = vms_basename(progname);
+#endif
+
+ if (argc<2) {
+ usage();
+ /* doesn't return */
+ }
+
+ for(cp=0;argv[1][cp];cp++){
+ switch(argv[1][cp]){
+ default:
+ usage(); /* doesn't return */
+ case '-': /* silently ignore */
+ break;
+ case '?':
+ case 'h':
+ verbose_help();
+ break;
+ case 'I':
+ if (ap == argc) usage();
+ list_file=argv[ap++];
+ if(iseen)
+ printf("Warning: multiple I options. Previous ignored.\n");
+ iseen=1;
+ break;
+ case 'f':
+ if (ap == argc) usage();
+ library_file=argv[ap++];
+ if(fseen)
+ printf("Warning: multiple f options. Previous ignored.\n");
+ fseen=1;
+ break;
+ case 'C':
+ if (ap == argc) usage();
+#ifdef AMIGA
+ if(!getcwd(origdir,sizeof(origdir))){
+ printf("Can't get current directory.\n");
+ xexit(EXIT_FAILURE);
+ }
+#endif
+ if(chdir(argv[ap++])){
+ printf("Can't chdir to %s\n",argv[--ap]);
+ xexit(EXIT_FAILURE);
+ }
+ break;
+ case 'v':
+ verbose=1;
+ break;
+ case 't':
+ case 'c':
+ case 'x':
+ if(action != ' '){
+ printf("Only one of t,x,c may be specified.\n");
+ usage();
+ }
+ action=argv[1][cp];
+ break;
+ }
+ }
+
+ if(argv[ap] && iseen){
+ printf("Too many arguments.\n");
+ xexit(EXIT_FAILURE);
+ }
+
+ switch(action){
+ default:
+ printf("Internal error - action.\n");
+ xexit(EXIT_FAILURE);
+ break;
+ case 't': /* list archive */
+ if (!open_library(library_file, &lib)) {
+ printf("Can't open dlb file\n");
+ xexit(EXIT_FAILURE);
+ }
+
+ for (i = 0; i < lib.nentries; i++) {
+ if (verbose)
+ printf("%-14s %6ld %6ld\n",
+ lib.dir[i].fname, lib.dir[i].foffset, lib.dir[i].fsize);
+ else
+ printf("%s\n", lib.dir[i].fname);
+ }
+
+ if (verbose)
+ printf("Revision:%ld File count:%ld String size:%ld\n",
+ lib.rev, lib.nentries, lib.strsize);
+
+ close_library(&lib);
+ xexit(EXIT_SUCCESS);
+
+ case 'x': { /* extract archive contents */
+ int f, n;
+ long remainder, total_read;
+ char buf[BUFSIZ];
+
+ if (!open_library(library_file, &lib)) {
+ printf("Can't open dlb file\n");
+ xexit(EXIT_FAILURE);
+ }
+
+ for (i = 0; i < lib.nentries; i++) {
+ if (argv[ap]) {
+ /* if files are listed, see if current is wanted */
+ int c;
+ for (c = ap; c < argc; c++)
+ if (!FILENAME_CMP(lib.dir[i].fname, argv[c])) break;
+ if (c == argc) continue; /* skip */
+ } else if (!FILENAME_CMP(lib.dir[i].fname, DLB_DIRECTORY)) {
+ /*
+ * Don't extract the directory unless the user
+ * specifically asks for it.
+ *
+ * Perhaps we should never extract the directory???
+ */
+ continue;
+ }
+ fseek(lib.fdata, lib.dir[i].foffset, SEEK_SET);
+
+ f = open(lib.dir[i].fname, O_WRONLY|O_TRUNC|O_BINARY|O_CREAT, 0640);
+ if (f < 0) {
+ printf("Can't create '%s'\n", lib.dir[i].fname);
+ xexit(EXIT_FAILURE);
+ }
+
+ /* read chunks from library and write them out */
+ total_read = 0;
+ do {
+ remainder = lib.dir[i].fsize - total_read;
+ if (remainder > (long) sizeof(buf))
+ r = (int) sizeof(buf);
+ else
+ r = remainder;
+
+ n = fread(buf, 1, r, lib.fdata);
+ if (n != r) {
+ printf("Read Error in '%s'\n", lib.dir[i].fname);
+ xexit(EXIT_FAILURE);
+ }
+ if (write(f, buf, n) != n) {
+ printf("Write Error in '%s'\n", lib.dir[i].fname);
+ xexit(EXIT_FAILURE);
+ }
+
+ total_read += n;
+ } while (total_read != lib.dir[i].fsize);
+
+ (void) close(f);
+
+ if (verbose) printf("x %s\n", lib.dir[i].fname);
+ }
+
+ close_library(&lib);
+ xexit(EXIT_SUCCESS);
+ }
+
+ case 'c': /* create archive */
+ {
+ libdir ld[MAX_DLB_FILES];
+ char buf[BUFSIZ];
+ int fd, out, nfiles = 0;
+ long dir_size, slen, flen, fsiz;
+ boolean rewrite_directory = FALSE;
+
+ /*
+ * Get names from either/both an argv list and a file
+ * list. This does not do any duplicate checking
+ */
+
+ /* get file name in argv list */
+ if (argv[ap]) {
+ for ( ; ap < argc; ap++, nfiles++) {
+ if (nfiles >= MAX_DLB_FILES) {
+ printf("Too many dlb files! Stopping at %d.\n",
+ MAX_DLB_FILES);
+ break;
+ }
+ ld[nfiles].fname = (char *) alloc(strlen(argv[ap]) + 1);
+ Strcpy(ld[nfiles].fname, argv[ap]);
+ }
+ }
+
+ if (iseen) {
+ /* want to do a list file */
+ FILE *list = fopen(list_file, "r");
+ if (!list) {
+ printf("Can't open %s\n",list_file);
+ xexit(EXIT_FAILURE);
+ }
+
+ /* get file names, one per line */
+ for ( ; fgets(buf, sizeof(buf), list); nfiles++) {
+ if (nfiles >= MAX_DLB_FILES) {
+ printf("Too many dlb files! Stopping at %d.\n",
+ MAX_DLB_FILES);
+ break;
+ }
+ *(eos(buf)-1) = '\0'; /* strip newline */
+ ld[nfiles].fname = (char *) alloc(strlen(buf) + 1);
+ Strcpy(ld[nfiles].fname, buf);
+ }
+ fclose(list);
+ }
+
+ if (nfiles == 0) {
+ printf("No files to archive\n");
+ xexit(EXIT_FAILURE);
+ }
+
+
+ /*
+ * Get file sizes and name string length. Don't include
+ * the directory information yet.
+ */
+ for (i = 0, slen = 0, flen = 0; i < nfiles; i++) {
+ fd = open(ld[i].fname, O_RDONLY|O_BINARY, 0);
+ if (fd < 0) {
+ printf("Can't open %s\n", ld[i].fname);
+ xexit(EXIT_FAILURE);
+ }
+ ld[i].fsize = lseek(fd, 0, SEEK_END);
+ ld[i].foffset = flen;
+
+ slen += strlen(ld[i].fname); /* don't add null (yet) */
+ flen += ld[i].fsize;
+ close(fd);
+ }
+
+ /* open output file */
+ out = open(library_file, O_RDWR|O_TRUNC|O_BINARY|O_CREAT, FCMASK);
+ if (out < 0) {
+ printf("Can't open %s for output\n", library_file);
+ xexit(EXIT_FAILURE);
+ }
+
+ /* caculate directory size */
+ dir_size = 40 /* header line (see below) */
+ + ((nfiles+1)*11) /* handling+file offset+SP+newline */
+ + slen+strlen(DLB_DIRECTORY); /* file names */
+
+ /* write directory */
+ write_dlb_directory(out, nfiles, ld, slen, dir_size, flen);
+
+ flen = 0L;
+ /* write each file */
+ for (i = 0; i < nfiles; i++) {
+ fd = open(ld[i].fname, O_RDONLY|O_BINARY, 0);
+ if (fd < 0) {
+ printf("Can't open input file '%s'\n", ld[i].fname);
+ xexit(EXIT_FAILURE);
+ }
+ if (verbose) printf("%s\n",ld[i].fname);
+
+ fsiz = 0L;
+ while ((r = read(fd, buf, sizeof buf)) != 0) {
+ if (r == -1) {
+ printf("Read Error in '%s'\n", ld[i].fname);
+ xexit(EXIT_FAILURE);
+ }
+ if (write(out, buf, r) != r) {
+ printf("Write Error in '%s'\n", ld[i].fname);
+ xexit(EXIT_FAILURE);
+ }
+ fsiz += r;
+ }
+ (void) close(fd);
+ if (fsiz != ld[i].fsize) rewrite_directory = TRUE;
+ /* in case directory rewrite is needed */
+ ld[i].fsize = fsiz;
+ ld[i].foffset = flen;
+ flen += fsiz;
+ }
+
+ if (rewrite_directory) {
+ if (verbose) printf("(rewriting dlb directory info)\n");
+ (void) lseek(out, 0, SEEK_SET); /* rewind */
+ write_dlb_directory(out, nfiles, ld, slen, dir_size, flen);
+ }
+
+ for (i = 0; i < nfiles; i++)
+ free((genericptr_t) ld[i].fname), ld[i].fname = 0;
+
+ (void) close(out);
+ xexit(EXIT_SUCCESS);
+ }
+ }
+#endif /* DLBLIB */
+#endif /* DLB */
+
+ xexit(EXIT_SUCCESS);
+ /*NOTREACHED*/
+ return 0;
+}
+
+#ifdef DLB
+#ifdef DLBLIB
+
+static void
+write_dlb_directory(out, nfiles, ld, slen, dir_size, flen)
+int out, nfiles;
+libdir *ld;
+long slen, dir_size, flen;
+{
+ char buf[BUFSIZ];
+ int i;
+
+ sprintf(buf,"%3ld %8ld %8ld %8ld %8ld\n",
+ (long) DLB_VERS, /* version of dlb file */
+ (long) nfiles+1, /* # of entries (includes directory) */
+ /* string length + room for nulls */
+ (long) slen+strlen(DLB_DIRECTORY)+nfiles+1,
+ (long) dir_size, /* start of first file */
+ (long) flen+dir_size); /* total file size */
+ Write(out, buf, strlen(buf));
+
+ /* write each file entry */
+#define ENTRY_FORMAT "%c%s %8ld\n"
+ sprintf(buf, ENTRY_FORMAT, ENC_NORMAL, DLB_DIRECTORY, (long) 0);
+ Write(out, buf, strlen(buf));
+ for (i = 0; i < nfiles; i++) {
+ sprintf(buf, ENTRY_FORMAT,
+ ENC_NORMAL, /* encoding */
+ ld[i].fname, /* name */
+ ld[i].foffset + dir_size); /* offset */
+ Write(out, buf, strlen(buf));
+ }
+}
+
+#endif /* DLBLIB */
+#endif /* DLB */
+
+static void
+xexit(retcd)
+ int retcd;
+{
+#ifdef DLB
+#ifdef AMIGA
+ if (origdir[0]) chdir(origdir);
+#endif
+#endif
+ exit(retcd);
+}
+
+
+#ifdef AMIGA
+#include "date.h"
+const char amiga_version_string[] = AMIGA_VERSION_STRING;
+#endif
+
+/*dlb_main.c*/