Source:Dlb.c

Below is the full text to src/dlb.c from NetHack 3.4.3. To link to a particular line, write [[dlb.c#line123 ]], for example. 1.   /*	SCCS Id: @(#)dlb.c	3.4	1997/07/29	*/ 2.   /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1993. */ 3.    /* NetHack may be freely redistributed. See license for details. */ 4.

5.   #include "config.h"  6.    #include "dlb.h"  7. 8.   #ifdef __DJGPP__ 9.   #include   10. #endif 11.   12.   #define DATAPREFIX 4 13.   14.   #ifdef DLB 15.  /*  16.    * Data librarian. Present a STDIO-like interface to NetHack while 17.   * multiplexing on one or more "data libraries". If a file is not found 18.   * in a given library, look for it outside the libraries. 19.   */  20.    21.   typedef struct dlb_procs { 22.      boolean NDECL((*dlb_init_proc)); 23.      void NDECL((*dlb_cleanup_proc)); 24.      boolean FDECL((*dlb_fopen_proc), (DLB_P,const char *,const char *)); 25.      int FDECL((*dlb_fclose_proc), (DLB_P)); 26.      int FDECL((*dlb_fread_proc), (char *,int,int,DLB_P)); 27.      int FDECL((*dlb_fseek_proc), (DLB_P,long,int)); 28.      char *FDECL((*dlb_fgets_proc), (char *,int,DLB_P)); 29.      int FDECL((*dlb_fgetc_proc), (DLB_P)); 30.      long FDECL((*dlb_ftell_proc), (DLB_P)); 31.  } dlb_procs_t; 32.   33.   /* without extern.h via hack.h, these haven't been declared for us */ 34.  extern FILE *FDECL(fopen_datafile, (const char *,const char *,int)); 35.   36.   #ifdef DLBLIB 37.  /*  38.    * Library Implementation: 39.   *  40.    * When initialized, we open all library files and read in their tables 41.   * of contents. The library files stay open all the time. When 42.   * a open is requested, the libraries' directories are searched. If 43. * successful, we return a descriptor that contains the library, file 44.   * size, and current file mark. This descriptor is used for all 45.   * successive calls. 46.   *  47.    * The ability to open more than one library is supported but used 48.   * only in the Amiga port (the second library holds the sound files). 49.   * For Unix, the idea would be to split the NetHack library 50.   * into text and binary parts, where the text version could be shared. 51.   */  52.    53.   #define MAX_LIBS 4 54.  static library dlb_libs[MAX_LIBS]; 55.   56.   static boolean FDECL(readlibdir,(library *lp)); 57.  static boolean FDECL(find_file,(const char *name, library **lib, long *startp, 58.  								long *sizep)); 59.  static boolean NDECL(lib_dlb_init); 60.  static void NDECL(lib_dlb_cleanup); 61.  static boolean FDECL(lib_dlb_fopen,(dlb *, const char *, const char *)); 62.  static int FDECL(lib_dlb_fclose,(dlb *)); 63.  static int FDECL(lib_dlb_fread,(char *, int, int, dlb *)); 64.  static int FDECL(lib_dlb_fseek,(dlb *, long, int)); 65.  static char *FDECL(lib_dlb_fgets,(char *, int, dlb *)); 66.  static int FDECL(lib_dlb_fgetc,(dlb *)); 67.  static long FDECL(lib_dlb_ftell,(dlb *)); 68.   69.   /* not static because shared with dlb_main.c */ 70.  boolean FDECL(open_library,(const char *lib_name, library *lp)); 71.  void FDECL(close_library,(library *lp)); 72.   73.   /* without extern.h via hack.h, these haven't been declared for us */ 74.  extern char *FDECL(eos, (char *)); 75.   76.    77.    78.   /*  79.    * Read the directory out of the library. Return 1 if successful, 80.   * 0 if it failed. 81.   *  82.    * NOTE: An improvement of the file structure should be the file 83.   * size as part of the directory entry or perhaps in place of the 84.   * offset -- the offset can be calculated by a running tally of  85. * the sizes. 86.   *  87.    * Library file structure: 88.   *  89.    * HEADER: 90.   * %3ld	library FORMAT revision (currently rev 1) 91.   * %1c	space 92.   * %8ld	# of files in archive (includes 1 for directory) 93.   * %1c	space 94.   * %8ld	size of allocation for string space for directory names 95.   * %1c	space 96.   * %8ld	library offset - sanity check - lseek target for start of first file 97.   * %1c	space 98.   * %8ld	size - sanity check - byte size of complete archive file 99.   *  100.   * followed by one DIRECTORY entry for each file in the archive, including 101.  *  the directory itself: 102.  * %1c	handling information (compression, etc.)  Always ' ' in rev 1. 103.  * %s	file name 104.  * %1c	space 105.  * %8ld	offset in archive file of start of this file 106.  * %c	newline 107.  *  108.   * followed by the contents of the files 109.  */  110.  #define DLB_MIN_VERS  1	/* min library version readable by this code */ 111. #define DLB_MAX_VERS  1	/* max library version readable by this code */ 112.  113.  /*  114.   * Read the directory from the library file. This will allocate and 115.  * fill in our globals. The file pointer is reset back to position 116.  * zero. If any part fails, leave nothing that needs to be deallocated. 117.  *  118.   * Return TRUE on success, FALSE on failure. 119.  */  120.  static boolean 121. readlibdir(lp) 122.     library *lp;	/* library pointer to fill in */ 123. {  124.      int i;  125. char *sp; 126.     long liboffset, totalsize; 127.  128.      if (fscanf(lp->fdata, "%ld %ld %ld %ld %ld\n", 129. 	    &lp->rev,&lp->nentries,&lp->strsize,&liboffset,&totalsize) != 5) 130. 	return FALSE; 131.     if (lp->rev > DLB_MAX_VERS || lp->rev < DLB_MIN_VERS) return FALSE; 132.  133.      lp->dir = (libdir *) alloc(lp->nentries * sizeof(libdir)); 134.     lp->sspace = (char *) alloc(lp->strsize); 135.  136.      /* read in each directory entry */ 137.     for (i = 0, sp = lp->sspace; i < lp->nentries; i++) { 138. 	lp->dir[i].fname = sp; 139. 	if (fscanf(lp->fdata, "%c%s %ld\n", 140. 			&lp->dir[i].handling, sp, &lp->dir[i].foffset) != 3) { 141. 	    free((genericptr_t) lp->dir); 142. 	    free((genericptr_t) lp->sspace); 143. 	    lp->dir = (libdir *) 0; 144. 	    lp->sspace = (char *) 0; 145. 	    return FALSE; 146. 	}  147.  	sp = eos(sp) + 1; 148.     }  149.   150.      /* calculate file sizes using offset information */ 151.     for (i = 0; i < lp->nentries; i++) { 152. 	if (i == lp->nentries - 1) 153. 	    lp->dir[i].fsize = totalsize - lp->dir[i].foffset; 154. 	else 155. 	    lp->dir[i].fsize = lp->dir[i+1].foffset - lp->dir[i].foffset; 156.     }  157.   158.      (void) fseek(lp->fdata, 0L, SEEK_SET);	/* reset back to zero */ 159.     lp->fmark = 0; 160.  161.      return TRUE; 162. }  163.   164.  /*  165.   * Look for the file in our directory structure. Return 1 if successful, 166.  * 0 if not found. Fill in the size and starting position. 167.  */  168.  static boolean 169. find_file(name, lib, startp, sizep) 170.     const char *name; 171.     library **lib; 172.     long *startp, *sizep; 173. {  174.      int i, j;  175. library *lp; 176.  177.      for (i = 0; i < MAX_LIBS && dlb_libs[i].fdata; i++) { 178. 	lp = &dlb_libs[i]; 179. 	for (j = 0; j < lp->nentries; j++) { 180. 	    if (FILENAME_CMP(name, lp->dir[j].fname) == 0) { 181. 		*lib = lp; 182. 		*startp = lp->dir[j].foffset; 183. 		*sizep = lp->dir[j].fsize; 184. 		return TRUE; 185. 	    }  186.  	}  187.      }  188.      *lib = (library *) 0; 189.     *startp = *sizep = 0; 190.     return FALSE; 191. }  192.   193.  /*  194.   * Open the library of the given name and fill in the given library 195.  * structure. Return TRUE if successful, FALSE otherwise. 196.  */  197.  boolean 198. open_library(lib_name, lp) 199.     const char *lib_name; 200.     library *lp; 201. {  202.      boolean status = FALSE; 203.  204.      lp->fdata = fopen_datafile(lib_name, RDBMODE, DATAPREFIX); 205.     if (lp->fdata) { 206. 	if (readlibdir(lp)) { 207. 	    status = TRUE; 208. 	} else { 209. 	    (void) fclose(lp->fdata); 210. 	    lp->fdata = (FILE *) 0; 211. 	}  212.      }  213.      return status; 214. }  215.   216.  void 217. close_library(lp) 218.     library *lp; 219. {  220.      (void) fclose(lp->fdata); 221.     free((genericptr_t) lp->dir); 222.     free((genericptr_t) lp->sspace); 223.  224.      (void) memset((char *)lp, 0, sizeof(library)); 225. }  226.   227.  /*  228.   * Open the library file once using stdio. Keep it open, but 229.  * keep track of the file position. 230.  */  231.  static boolean 232. lib_dlb_init 233. {  234.      /* zero out array */ 235.     (void) memset((char *)&dlb_libs[0], 0, sizeof(dlb_libs)); 236.  237.      /* To open more than one library, add open library calls here. */ 238.      if (!open_library(DLBFILE, &dlb_libs[0])) return FALSE; 239. #ifdef DLBFILE2 240.     if (!open_library(DLBFILE2, &dlb_libs[1]))  { 241. 	close_library(&dlb_libs[0]); 242. 	return FALSE; 243.     }  244.  #endif 245.     return TRUE; 246. }  247.   248.  static void 249. lib_dlb_cleanup 250. {  251.      int i;  252. 253.     /* close the data file(s) */ 254.     for (i = 0; i < MAX_LIBS && dlb_libs[i].fdata; i++) 255. 	close_library(&dlb_libs[i]); 256. }  257.   258.  static boolean 259. lib_dlb_fopen(dp, name, mode) 260.     dlb *dp; 261.     const char *name, *mode; 262. {  263.      long start, size; 264.     library *lp; 265.  266.      /* look up file in directory */ 267.     if (find_file(name, &lp, &start, &size)) { 268. 	dp->lib = lp; 269. 	dp->start = start; 270. 	dp->size = size; 271. 	dp->mark = 0; 272. 	return TRUE; 273. 	}  274.   275.      return FALSE;	/* failed */ 276. }  277.   278.  static int 279. lib_dlb_fclose(dp) 280.     dlb *dp; 281. {  282.      /* nothing needs to be done */ 283.     return 0; 284. }  285.   286.  static int 287. lib_dlb_fread(buf, size, quan, dp) 288.     char *buf; 289.     int size, quan; 290.     dlb *dp; 291. {  292.      long pos, nread, nbytes; 293.  294.      /* make sure we don't read into the next file */ 295.     if ((dp->size - dp->mark) < (size * quan)) 296. 	quan = (dp->size - dp->mark) / size; 297.     if (quan == 0) return 0; 298.  299.      pos = dp->start + dp->mark; 300.     if (dp->lib->fmark != pos) { 301. 	fseek(dp->lib->fdata, pos, SEEK_SET);	/* check for error??? */ 302.  	dp->lib->fmark = pos; 303.     }  304.   305.      nread = fread(buf, size, quan, dp->lib->fdata); 306.     nbytes = nread * size; 307.     dp->mark += nbytes; 308.     dp->lib->fmark += nbytes; 309.  310.      return nread; 311. }  312.   313.  static int 314. lib_dlb_fseek(dp, pos, whence) 315.     dlb *dp; 316.     long pos; 317.     int whence; 318. {  319.      long curpos; 320.  321.      switch (whence) { 322. 	case SEEK_CUR:	   curpos = dp->mark + pos;	break; 323. 	case SEEK_END:	   curpos = dp->size - pos;	break; 324. 	default: /* set */ curpos = pos;		break; 325.     }  326.      if (curpos < 0) curpos = 0; 327.     if (curpos > dp->size) curpos = dp->size; 328.  329.      dp->mark = curpos; 330.     return 0; 331. }  332.   333.  static char * 334. lib_dlb_fgets(buf, len, dp) 335.     char *buf; 336.     int len; 337.     dlb *dp; 338. {  339.      int i;  340. char *bp, c = 0; 341.  342.      if (len <= 0) return buf;	/* sanity check */ 343.  344.      /* return NULL on EOF */ 345.     if (dp->mark >= dp->size) return (char *) 0; 346.  347.      len--;	/* save room for null */ 348.     for (i = 0, bp = buf;  349.  		i < len && dp->mark < dp->size && c != '\n'; i++, bp++) { 350. 	if (dlb_fread(bp, 1, 1, dp) <= 0) break;	/* EOF or error */ 351. 	c = *bp; 352.     }  353.      *bp = '\0'; 354.  355.  #if defined(MSDOS) || defined(WIN32) 356.     if ((bp = index(buf, '\r')) != 0) { 357. 	*bp++ = '\n'; 358. 	*bp = '\0'; 359.     }  360.  #endif 361.  362.      return buf; 363. }  364.   365.  static int 366. lib_dlb_fgetc(dp) 367.     dlb *dp; 368. {  369.      char c;  370. 371.     if (lib_dlb_fread(&c, 1, 1, dp) != 1) return EOF; 372.     return (int) c;  373. } 374.   375.   376.  static long 377. lib_dlb_ftell(dp) 378.     dlb *dp; 379. {  380.      return dp->mark; 381. }  382.   383.  const dlb_procs_t lib_dlb_procs = { 384.     lib_dlb_init, 385.     lib_dlb_cleanup, 386.     lib_dlb_fopen, 387.     lib_dlb_fclose, 388.     lib_dlb_fread, 389.     lib_dlb_fseek, 390.     lib_dlb_fgets, 391.     lib_dlb_fgetc, 392.     lib_dlb_ftell 393. };  394.   395.  #endif /* DLBLIB */ 396.  397.  #ifdef DLBRSRC 398. const dlb_procs_t rsrc_dlb_procs = { 399.     rsrc_dlb_init, 400.     rsrc_dlb_cleanup, 401.     rsrc_dlb_fopen, 402.     rsrc_dlb_fclose, 403.     rsrc_dlb_fread, 404.     rsrc_dlb_fseek, 405.     rsrc_dlb_fgets, 406.     rsrc_dlb_fgetc, 407.     rsrc_dlb_ftell 408. };  409.  #endif 410.  411.  /* Global wrapper functions  */ 412.  413.  #define do_dlb_init (*dlb_procs->dlb_init_proc) 414. #define do_dlb_cleanup (*dlb_procs->dlb_cleanup_proc) 415. #define do_dlb_fopen (*dlb_procs->dlb_fopen_proc) 416. #define do_dlb_fclose (*dlb_procs->dlb_fclose_proc) 417. #define do_dlb_fread (*dlb_procs->dlb_fread_proc) 418. #define do_dlb_fseek (*dlb_procs->dlb_fseek_proc) 419. #define do_dlb_fgets (*dlb_procs->dlb_fgets_proc) 420. #define do_dlb_fgetc (*dlb_procs->dlb_fgetc_proc) 421. #define do_dlb_ftell (*dlb_procs->dlb_ftell_proc) 422.  423.  static const dlb_procs_t *dlb_procs; 424. static boolean dlb_initialized = FALSE; 425.  426.  boolean 427. dlb_init 428. {  429.      if (!dlb_initialized) { 430. #ifdef DLBLIB 431. 	dlb_procs = &lib_dlb_procs; 432. #endif 433. #ifdef DLBRSRC 434. 	dlb_procs = &rsrc_dlb_procs; 435. #endif 436.  437.  	if (dlb_procs) 438. 	    dlb_initialized = do_dlb_init; 439.     }  440.   441.      return dlb_initialized; 442. }  443.   444.  void 445. dlb_cleanup 446. {  447.      if (dlb_initialized) { 448. 	do_dlb_cleanup; 449. 	dlb_initialized = FALSE; 450.     }  451.  }  452.   453.  dlb * 454. dlb_fopen(name, mode) 455.     const char *name, *mode; 456. {  457.      FILE *fp; 458.     dlb *dp; 459.  460.      if (!dlb_initialized) return (dlb *) 0; 461.  462.      dp = (dlb *) alloc(sizeof(dlb)); 463.     if (do_dlb_fopen(dp, name, mode)) 464.     	dp->fp = (FILE *) 0; 465.     else if ((fp = fopen_datafile(name, mode, DATAPREFIX)) != 0) 466. 	dp->fp = fp; 467.     else { 468. 	/* can't find anything */ 469. 	free((genericptr_t) dp); 470. 	dp = (dlb *) 0; 471. 	}  472.   473.      return dp; 474. }  475.   476.  int 477. dlb_fclose(dp) 478.     dlb *dp; 479. {  480.  	int ret = 0; 481.  482.      if (dlb_initialized) { 483. 	if (dp->fp) ret = fclose(dp->fp); 484. 	else ret = do_dlb_fclose(dp); 485.  486.  	free((genericptr_t) dp); 487.     }  488.      return ret; 489. }  490.   491.  int 492. dlb_fread(buf, size, quan, dp) 493.     char *buf; 494.     int size, quan; 495.     dlb *dp; 496. {  497.      if (!dlb_initialized || size <= 0 || quan <= 0) return 0; 498.     if (dp->fp) return (int) fread(buf, size, quan, dp->fp); 499.     return do_dlb_fread(buf, size, quan, dp); 500. }  501.   502.  int 503. dlb_fseek(dp, pos, whence) 504.     dlb *dp; 505.     long pos; 506.     int whence; 507. {  508.      if (!dlb_initialized) return EOF; 509.     if (dp->fp) return fseek(dp->fp, pos, whence); 510.     return do_dlb_fseek(dp, pos, whence); 511. }  512.   513.  char * 514. dlb_fgets(buf, len, dp) 515.     char *buf; 516.     int len; 517.     dlb *dp; 518. {  519.      if (!dlb_initialized) return (char *) 0; 520.     if (dp->fp) return fgets(buf, len, dp->fp); 521.     return do_dlb_fgets(buf, len, dp); 522. }  523.   524.  int 525. dlb_fgetc(dp) 526.     dlb *dp; 527. {  528.      if (!dlb_initialized) return EOF; 529.     if (dp->fp) return fgetc(dp->fp); 530.     return do_dlb_fgetc(dp); 531. }  532.   533.  long 534. dlb_ftell(dp) 535.     dlb *dp; 536. {  537.      if (!dlb_initialized) return 0; 538.     if (dp->fp) return ftell(dp->fp); 539.     return do_dlb_ftell(dp); 540. }  541.   542.  #endif /* DLB */ 543.  544.  /*dlb.c*/