more DUMPLOG lint
[aNetHack.git] / src / dlb.c
bloba0b675246d289dacf88f6d9a6caf557600c9fa12
1 /* NetHack 3.6 dlb.c $NHDT-Date: 1446975464 2015/11/08 09:37:44 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */
2 /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1993. */
3 /* NetHack may be freely redistributed. See license for details. */
5 #include "config.h"
6 #include "dlb.h"
8 #ifdef __DJGPP__
9 #include <string.h>
10 #endif
12 #define DATAPREFIX 4
14 #if defined(OVERLAY)
15 #define STATIC_DCL extern
16 #define STATIC_OVL
17 #else /* !OVERLAY */
18 #define STATIC_DCL static
19 #define STATIC_OVL static
20 #endif /* OVERLAY */
22 #ifdef DLB
24 * Data librarian. Present a STDIO-like interface to NetHack while
25 * multiplexing on one or more "data libraries". If a file is not found
26 * in a given library, look for it outside the libraries.
29 typedef struct dlb_procs {
30 boolean NDECL((*dlb_init_proc));
31 void NDECL((*dlb_cleanup_proc));
32 boolean FDECL((*dlb_fopen_proc), (DLB_P, const char *, const char *));
33 int FDECL((*dlb_fclose_proc), (DLB_P));
34 int FDECL((*dlb_fread_proc), (char *, int, int, DLB_P));
35 int FDECL((*dlb_fseek_proc), (DLB_P, long, int));
36 char *FDECL((*dlb_fgets_proc), (char *, int, DLB_P));
37 int FDECL((*dlb_fgetc_proc), (DLB_P));
38 long FDECL((*dlb_ftell_proc), (DLB_P));
39 } dlb_procs_t;
41 /* without extern.h via hack.h, these haven't been declared for us */
42 extern FILE *FDECL(fopen_datafile, (const char *, const char *, int));
44 #ifdef DLBLIB
46 * Library Implementation:
48 * When initialized, we open all library files and read in their tables
49 * of contents. The library files stay open all the time. When
50 * a open is requested, the libraries' directories are searched. If
51 * successful, we return a descriptor that contains the library, file
52 * size, and current file mark. This descriptor is used for all
53 * successive calls.
55 * The ability to open more than one library is supported but used
56 * only in the Amiga port (the second library holds the sound files).
57 * For Unix, the idea would be to split the NetHack library
58 * into text and binary parts, where the text version could be shared.
61 #define MAX_LIBS 4
62 static library dlb_libs[MAX_LIBS];
64 STATIC_DCL boolean FDECL(readlibdir, (library * lp));
65 STATIC_DCL boolean FDECL(find_file, (const char *name, library **lib,
66 long *startp, long *sizep));
67 STATIC_DCL boolean NDECL(lib_dlb_init);
68 STATIC_DCL void NDECL(lib_dlb_cleanup);
69 STATIC_DCL boolean FDECL(lib_dlb_fopen, (dlb *, const char *, const char *));
70 STATIC_DCL int FDECL(lib_dlb_fclose, (dlb *));
71 STATIC_DCL int FDECL(lib_dlb_fread, (char *, int, int, dlb *));
72 STATIC_DCL int FDECL(lib_dlb_fseek, (dlb *, long, int));
73 STATIC_DCL char *FDECL(lib_dlb_fgets, (char *, int, dlb *));
74 STATIC_DCL int FDECL(lib_dlb_fgetc, (dlb *));
75 STATIC_DCL long FDECL(lib_dlb_ftell, (dlb *));
77 /* not static because shared with dlb_main.c */
78 boolean FDECL(open_library, (const char *lib_name, library *lp));
79 void FDECL(close_library, (library * lp));
81 /* without extern.h via hack.h, these haven't been declared for us */
82 extern char *FDECL(eos, (char *));
85 * Read the directory out of the library. Return 1 if successful,
86 * 0 if it failed.
88 * NOTE: An improvement of the file structure should be the file
89 * size as part of the directory entry or perhaps in place of the
90 * offset -- the offset can be calculated by a running tally of
91 * the sizes.
93 * Library file structure:
95 * HEADER:
96 * %3ld library FORMAT revision (currently rev 1)
97 * %1c space
98 * %8ld # of files in archive (includes 1 for directory)
99 * %1c space
100 * %8ld size of allocation for string space for directory names
101 * %1c space
102 * %8ld library offset - sanity check - lseek target for start of first file
103 * %1c space
104 * %8ld size - sanity check - byte size of complete archive file
106 * followed by one DIRECTORY entry for each file in the archive, including
107 * the directory itself:
108 * %1c handling information (compression, etc.) Always ' ' in rev 1.
109 * %s file name
110 * %1c space
111 * %8ld offset in archive file of start of this file
112 * %c newline
114 * followed by the contents of the files
116 #define DLB_MIN_VERS 1 /* min library version readable by this code */
117 #define DLB_MAX_VERS 1 /* max library version readable by this code */
120 * Read the directory from the library file. This will allocate and
121 * fill in our globals. The file pointer is reset back to position
122 * zero. If any part fails, leave nothing that needs to be deallocated.
124 * Return TRUE on success, FALSE on failure.
126 STATIC_OVL boolean
127 readlibdir(lp)
128 library *lp; /* library pointer to fill in */
130 int i;
131 char *sp;
132 long liboffset, totalsize;
134 if (fscanf(lp->fdata, "%ld %ld %ld %ld %ld\n", &lp->rev, &lp->nentries,
135 &lp->strsize, &liboffset, &totalsize) != 5)
136 return FALSE;
137 if (lp->rev > DLB_MAX_VERS || lp->rev < DLB_MIN_VERS)
138 return FALSE;
140 lp->dir = (libdir *) alloc(lp->nentries * sizeof(libdir));
141 lp->sspace = (char *) alloc(lp->strsize);
143 /* read in each directory entry */
144 for (i = 0, sp = lp->sspace; i < lp->nentries; i++) {
145 lp->dir[i].fname = sp;
146 if (fscanf(lp->fdata, "%c%s %ld\n", &lp->dir[i].handling, sp,
147 &lp->dir[i].foffset) != 3) {
148 free((genericptr_t) lp->dir);
149 free((genericptr_t) lp->sspace);
150 lp->dir = (libdir *) 0;
151 lp->sspace = (char *) 0;
152 return FALSE;
154 sp = eos(sp) + 1;
157 /* calculate file sizes using offset information */
158 for (i = 0; i < lp->nentries; i++) {
159 if (i == lp->nentries - 1)
160 lp->dir[i].fsize = totalsize - lp->dir[i].foffset;
161 else
162 lp->dir[i].fsize = lp->dir[i + 1].foffset - lp->dir[i].foffset;
165 (void) fseek(lp->fdata, 0L, SEEK_SET); /* reset back to zero */
166 lp->fmark = 0;
168 return TRUE;
172 * Look for the file in our directory structure. Return 1 if successful,
173 * 0 if not found. Fill in the size and starting position.
175 STATIC_OVL boolean
176 find_file(name, lib, startp, sizep)
177 const char *name;
178 library **lib;
179 long *startp, *sizep;
181 int i, j;
182 library *lp;
184 for (i = 0; i < MAX_LIBS && dlb_libs[i].fdata; i++) {
185 lp = &dlb_libs[i];
186 for (j = 0; j < lp->nentries; j++) {
187 if (FILENAME_CMP(name, lp->dir[j].fname) == 0) {
188 *lib = lp;
189 *startp = lp->dir[j].foffset;
190 *sizep = lp->dir[j].fsize;
191 return TRUE;
195 *lib = (library *) 0;
196 *startp = *sizep = 0;
197 return FALSE;
201 * Open the library of the given name and fill in the given library
202 * structure. Return TRUE if successful, FALSE otherwise.
204 boolean
205 open_library(lib_name, lp)
206 const char *lib_name;
207 library *lp;
209 boolean status = FALSE;
211 lp->fdata = fopen_datafile(lib_name, RDBMODE, DATAPREFIX);
212 if (lp->fdata) {
213 if (readlibdir(lp)) {
214 status = TRUE;
215 } else {
216 (void) fclose(lp->fdata);
217 lp->fdata = (FILE *) 0;
220 return status;
223 void
224 close_library(lp)
225 library *lp;
227 (void) fclose(lp->fdata);
228 free((genericptr_t) lp->dir);
229 free((genericptr_t) lp->sspace);
231 (void) memset((char *) lp, 0, sizeof(library));
235 * Open the library file once using stdio. Keep it open, but
236 * keep track of the file position.
238 STATIC_OVL boolean
239 lib_dlb_init(VOID_ARGS)
241 /* zero out array */
242 (void) memset((char *) &dlb_libs[0], 0, sizeof(dlb_libs));
244 /* To open more than one library, add open library calls here. */
245 if (!open_library(DLBFILE, &dlb_libs[0]))
246 return FALSE;
247 #ifdef DLBFILE2
248 if (!open_library(DLBFILE2, &dlb_libs[1])) {
249 close_library(&dlb_libs[0]);
250 return FALSE;
252 #endif
253 return TRUE;
256 STATIC_OVL void
257 lib_dlb_cleanup(VOID_ARGS)
259 int i;
261 /* close the data file(s) */
262 for (i = 0; i < MAX_LIBS && dlb_libs[i].fdata; i++)
263 close_library(&dlb_libs[i]);
266 /*ARGSUSED*/
267 STATIC_OVL boolean
268 lib_dlb_fopen(dp, name, mode)
269 dlb *dp;
270 const char *name;
271 const char *mode UNUSED;
273 long start, size;
274 library *lp;
276 /* look up file in directory */
277 if (find_file(name, &lp, &start, &size)) {
278 dp->lib = lp;
279 dp->start = start;
280 dp->size = size;
281 dp->mark = 0;
282 return TRUE;
285 return FALSE; /* failed */
288 /*ARGUSED*/
289 STATIC_OVL int
290 lib_dlb_fclose(dp)
291 dlb *dp UNUSED;
293 /* nothing needs to be done */
294 return 0;
297 STATIC_OVL int
298 lib_dlb_fread(buf, size, quan, dp)
299 char *buf;
300 int size, quan;
301 dlb *dp;
303 long pos, nread, nbytes;
305 /* make sure we don't read into the next file */
306 if ((dp->size - dp->mark) < (size * quan))
307 quan = (dp->size - dp->mark) / size;
308 if (quan == 0)
309 return 0;
311 pos = dp->start + dp->mark;
312 if (dp->lib->fmark != pos) {
313 fseek(dp->lib->fdata, pos, SEEK_SET); /* check for error??? */
314 dp->lib->fmark = pos;
317 nread = fread(buf, size, quan, dp->lib->fdata);
318 nbytes = nread * size;
319 dp->mark += nbytes;
320 dp->lib->fmark += nbytes;
322 return nread;
325 STATIC_OVL int
326 lib_dlb_fseek(dp, pos, whence)
327 dlb *dp;
328 long pos;
329 int whence;
331 long curpos;
333 switch (whence) {
334 case SEEK_CUR:
335 curpos = dp->mark + pos;
336 break;
337 case SEEK_END:
338 curpos = dp->size - pos;
339 break;
340 default: /* set */
341 curpos = pos;
342 break;
344 if (curpos < 0)
345 curpos = 0;
346 if (curpos > dp->size)
347 curpos = dp->size;
349 dp->mark = curpos;
350 return 0;
353 STATIC_OVL char *
354 lib_dlb_fgets(buf, len, dp)
355 char *buf;
356 int len;
357 dlb *dp;
359 int i;
360 char *bp, c = 0;
362 if (len <= 0)
363 return buf; /* sanity check */
365 /* return NULL on EOF */
366 if (dp->mark >= dp->size)
367 return (char *) 0;
369 len--; /* save room for null */
370 for (i = 0, bp = buf; i < len && dp->mark < dp->size && c != '\n';
371 i++, bp++) {
372 if (dlb_fread(bp, 1, 1, dp) <= 0)
373 break; /* EOF or error */
374 c = *bp;
376 *bp = '\0';
378 #if defined(MSDOS) || defined(WIN32)
379 if ((bp = index(buf, '\r')) != 0) {
380 *bp++ = '\n';
381 *bp = '\0';
383 #endif
385 return buf;
388 STATIC_OVL int
389 lib_dlb_fgetc(dp)
390 dlb *dp;
392 char c;
394 if (lib_dlb_fread(&c, 1, 1, dp) != 1)
395 return EOF;
396 return (int) c;
399 STATIC_OVL long
400 lib_dlb_ftell(dp)
401 dlb *dp;
403 return dp->mark;
406 const dlb_procs_t lib_dlb_procs = { lib_dlb_init, lib_dlb_cleanup,
407 lib_dlb_fopen, lib_dlb_fclose,
408 lib_dlb_fread, lib_dlb_fseek,
409 lib_dlb_fgets, lib_dlb_fgetc,
410 lib_dlb_ftell };
412 #endif /* DLBLIB */
414 #ifdef DLBRSRC
415 const dlb_procs_t rsrc_dlb_procs = { rsrc_dlb_init, rsrc_dlb_cleanup,
416 rsrc_dlb_fopen, rsrc_dlb_fclose,
417 rsrc_dlb_fread, rsrc_dlb_fseek,
418 rsrc_dlb_fgets, rsrc_dlb_fgetc,
419 rsrc_dlb_ftell };
420 #endif
422 /* Global wrapper functions ------------------------------------------------
425 #define do_dlb_init (*dlb_procs->dlb_init_proc)
426 #define do_dlb_cleanup (*dlb_procs->dlb_cleanup_proc)
427 #define do_dlb_fopen (*dlb_procs->dlb_fopen_proc)
428 #define do_dlb_fclose (*dlb_procs->dlb_fclose_proc)
429 #define do_dlb_fread (*dlb_procs->dlb_fread_proc)
430 #define do_dlb_fseek (*dlb_procs->dlb_fseek_proc)
431 #define do_dlb_fgets (*dlb_procs->dlb_fgets_proc)
432 #define do_dlb_fgetc (*dlb_procs->dlb_fgetc_proc)
433 #define do_dlb_ftell (*dlb_procs->dlb_ftell_proc)
435 static const dlb_procs_t *dlb_procs;
436 static boolean dlb_initialized = FALSE;
438 boolean
439 dlb_init()
441 if (!dlb_initialized) {
442 #ifdef DLBLIB
443 dlb_procs = &lib_dlb_procs;
444 #endif
445 #ifdef DLBRSRC
446 dlb_procs = &rsrc_dlb_procs;
447 #endif
449 if (dlb_procs)
450 dlb_initialized = do_dlb_init();
453 return dlb_initialized;
456 void
457 dlb_cleanup()
459 if (dlb_initialized) {
460 do_dlb_cleanup();
461 dlb_initialized = FALSE;
465 dlb *
466 dlb_fopen(name, mode)
467 const char *name, *mode;
469 FILE *fp;
470 dlb *dp;
472 if (!dlb_initialized)
473 return (dlb *) 0;
475 /* only support reading; ignore possible binary flag */
476 if (!mode || mode[0] != 'r')
477 return (dlb *) 0;
479 dp = (dlb *) alloc(sizeof(dlb));
480 if (do_dlb_fopen(dp, name, mode))
481 dp->fp = (FILE *) 0;
482 else if ((fp = fopen_datafile(name, mode, DATAPREFIX)) != 0)
483 dp->fp = fp;
484 else {
485 /* can't find anything */
486 free((genericptr_t) dp);
487 dp = (dlb *) 0;
490 return dp;
494 dlb_fclose(dp)
495 dlb *dp;
497 int ret = 0;
499 if (dlb_initialized) {
500 if (dp->fp)
501 ret = fclose(dp->fp);
502 else
503 ret = do_dlb_fclose(dp);
505 free((genericptr_t) dp);
507 return ret;
511 dlb_fread(buf, size, quan, dp)
512 char *buf;
513 int size, quan;
514 dlb *dp;
516 if (!dlb_initialized || size <= 0 || quan <= 0)
517 return 0;
518 if (dp->fp)
519 return (int) fread(buf, size, quan, dp->fp);
520 return do_dlb_fread(buf, size, quan, dp);
524 dlb_fseek(dp, pos, whence)
525 dlb *dp;
526 long pos;
527 int whence;
529 if (!dlb_initialized)
530 return EOF;
531 if (dp->fp)
532 return fseek(dp->fp, pos, whence);
533 return do_dlb_fseek(dp, pos, whence);
536 char *
537 dlb_fgets(buf, len, dp)
538 char *buf;
539 int len;
540 dlb *dp;
542 if (!dlb_initialized)
543 return (char *) 0;
544 if (dp->fp)
545 return fgets(buf, len, dp->fp);
546 return do_dlb_fgets(buf, len, dp);
550 dlb_fgetc(dp)
551 dlb *dp;
553 if (!dlb_initialized)
554 return EOF;
555 if (dp->fp)
556 return fgetc(dp->fp);
557 return do_dlb_fgetc(dp);
560 long
561 dlb_ftell(dp)
562 dlb *dp;
564 if (!dlb_initialized)
565 return 0;
566 if (dp->fp)
567 return ftell(dp->fp);
568 return do_dlb_ftell(dp);
571 #endif /* DLB */
573 /*dlb.c*/