Source:NetHack 3.4.3/util/dlb main.c

From NetHackWiki
Revision as of 17:10, 3 February 2011 by Paxedbot (talk | contribs) (Uploading src file util/dlb_main.c)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Below is the full text to util/dlb_main.c from NetHack 3.4.3.

/*	SCCS Id: @(#)dlb_main.c 3.4	1998/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*/


This page may need to be updated for the current version of NetHack.

It may contain text specific to NetHack 3.4.3. Information on this page may be out of date.

Editors: After reviewing this page and making necessary edits, please change the {{nethack-343}} tag to the current version's tag or {{noversion}} as appropriate.