Blindfold removal fix
[slashemextended.git] / src / dlb.c
blob438ee9640b51e41b1f3e360db2911594bf269060
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. */
5 #include "config.h"
6 #include "dlb.h"
8 #ifdef __DJGPP__
9 #include <string.h>
10 #endif
12 #define DATAPREFIX 4
14 #ifdef DLB
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.
21 typedef struct dlb_procs {
22 boolean (*dlb_init_proc)(void);
23 void (*dlb_cleanup_proc)(void);
24 boolean (*dlb_fopen_proc)(DLB_P,const char *,const char *);
25 int (*dlb_fclose_proc)(DLB_P);
26 int (*dlb_fread_proc)(char *,int,int,DLB_P);
27 int (*dlb_fseek_proc)(DLB_P,long,int);
28 char *(*dlb_fgets_proc)(char *,int,DLB_P);
29 int (*dlb_fgetc_proc)(DLB_P);
30 long (*dlb_ftell_proc)(DLB_P);
31 } dlb_procs_t;
33 /* without extern.h via hack.h, these haven't been declared for us */
34 #ifdef FILE_AREAS
35 extern FILE *fopen_datafile_area(const char *,const char *,
36 const char *,int);
37 #else
39 * If FILE_AREAS is not defined, then fopen_datafile_area
40 * is a macro defined in terms of fopen_datafile.
42 extern FILE *fopen_datafile(const char *,const char *,int);
43 #endif
45 #ifdef DLBLIB
47 * Library Implementation:
49 * When initialized, we open all library files and read in their tables
50 * of contents. The library files stay open all the time. When
51 * a open is requested, the libraries' directories are searched. If
52 * successful, we return a descriptor that contains the library, file
53 * size, and current file mark. This descriptor is used for all
54 * successive calls.
56 * The ability to open more than one library is supported but used
57 * only in the Amiga port (the second library holds the sound files).
58 * For Unix, the idea would be to split the NetHack library
59 * into text and binary parts, where the text version could be shared.
62 #define MAX_LIBS 4
63 static library dlb_libs[MAX_LIBS];
65 static boolean readlibdir(library *lp);
66 static boolean find_file(const char *name, library **lib, long *startp,
67 long *sizep);
68 static boolean lib_dlb_init(void);
69 static void lib_dlb_cleanup(void);
70 static boolean lib_dlb_fopen(dlb *, const char *, const char *);
71 static int lib_dlb_fclose(dlb *);
72 static int lib_dlb_fread(char *, int, int, dlb *);
73 static int lib_dlb_fseek(dlb *, long, int);
74 static char *lib_dlb_fgets(char *, int, dlb *);
75 static int lib_dlb_fgetc(dlb *);
76 static long lib_dlb_ftell(dlb *);
78 /* not static because shared with dlb_main.c */
79 boolean open_library(const char *lib_area, const char *lib_name,
80 library *lp);
81 void close_library(library *lp);
83 /* without extern.h via hack.h, these haven't been declared for us */
84 extern char *eos(char *);
89 * Read the directory out of the library. Return 1 if successful,
90 * 0 if it failed.
92 * NOTE: An improvement of the file structure should be the file
93 * size as part of the directory entry or perhaps in place of the
94 * offset -- the offset can be calculated by a running tally of
95 * the sizes.
97 * Library file structure:
99 * HEADER:
100 * %3ld library FORMAT revision (currently rev 1)
101 * %1c space
102 * %8ld # of files in archive (includes 1 for directory)
103 * %1c space
104 * %8ld size of allocation for string space for directory names
105 * %1c space
106 * %8ld library offset - sanity check - lseek target for start of first file
107 * %1c space
108 * %8ld size - sanity check - byte size of complete archive file
110 * followed by one DIRECTORY entry for each file in the archive, including
111 * the directory itself:
112 * %1c handling information (compression, etc.) Always ' ' in rev 1.
113 * %s file name
114 * %1c space
115 * %8ld offset in archive file of start of this file
116 * %c newline
118 * followed by the contents of the files
120 #define DLB_MIN_VERS 1 /* min library version readable by this code */
121 #define DLB_MAX_VERS 1 /* max library version readable by this code */
124 * Read the directory from the library file. This will allocate and
125 * fill in our globals. The file pointer is reset back to position
126 * zero. If any part fails, leave nothing that needs to be deallocated.
128 * Return TRUE on success, FALSE on failure.
130 static boolean
131 readlibdir(lp)
132 library *lp; /* library pointer to fill in */
134 int i;
135 char *sp;
136 long liboffset, totalsize;
138 if (fscanf(lp->fdata, "%ld %ld %ld %ld %ld\n",
139 &lp->rev,&lp->nentries,&lp->strsize,&liboffset,&totalsize) != 5)
140 return FALSE;
141 if (lp->rev > DLB_MAX_VERS || lp->rev < DLB_MIN_VERS) return FALSE;
143 lp->dir = (libdir *) alloc(lp->nentries * sizeof(libdir));
144 lp->sspace = (char *) alloc(lp->strsize);
146 /* read in each directory entry */
147 for (i = 0, sp = lp->sspace; i < lp->nentries; i++) {
148 lp->dir[i].fname = sp;
149 if (fscanf(lp->fdata, "%c%s %ld\n",
150 &lp->dir[i].handling, sp, &lp->dir[i].foffset) != 3) {
151 free((void *) lp->dir);
152 free((void *) lp->sspace);
153 lp->dir = (libdir *) 0;
154 lp->sspace = (char *) 0;
155 return FALSE;
157 sp = eos(sp) + 1;
160 /* calculate file sizes using offset information */
161 for (i = 0; i < lp->nentries; i++) {
162 if (i == lp->nentries - 1)
163 lp->dir[i].fsize = totalsize - lp->dir[i].foffset;
164 else
165 lp->dir[i].fsize = lp->dir[i+1].foffset - lp->dir[i].foffset;
168 (void) fseek(lp->fdata, 0L, SEEK_SET); /* reset back to zero */
169 lp->fmark = 0;
171 return TRUE;
175 * Look for the file in our directory structure. Return 1 if successful,
176 * 0 if not found. Fill in the size and starting position.
178 static boolean
179 find_file(name, lib, startp, sizep)
180 const char *name;
181 library **lib;
182 long *startp, *sizep;
184 int i, j;
185 library *lp;
187 for (i = 0; i < MAX_LIBS && dlb_libs[i].fdata; i++) {
188 lp = &dlb_libs[i];
189 for (j = 0; j < lp->nentries; j++) {
190 if (FILENAME_CMP(name, lp->dir[j].fname) == 0) {
191 *lib = lp;
192 *startp = lp->dir[j].foffset;
193 *sizep = lp->dir[j].fsize;
194 return TRUE;
198 *lib = (library *) 0;
199 *startp = *sizep = 0;
200 return FALSE;
204 * Open the library of the given name and fill in the given library
205 * structure. Return TRUE if successful, FALSE otherwise.
207 boolean
208 open_library(lib_area, lib_name, lp)
209 const char *lib_area, *lib_name;
210 library *lp;
212 boolean status = FALSE;
214 lp->fdata = fopen_datafile_area(lib_area, lib_name, RDBMODE, DATAPREFIX);
215 if (lp->fdata) {
216 if (readlibdir(lp)) {
217 status = TRUE;
218 } else {
219 (void) fclose(lp->fdata);
220 lp->fdata = (FILE *) 0;
223 return status;
226 void
227 close_library(lp)
228 library *lp;
230 (void) fclose(lp->fdata);
231 free((void *) lp->dir);
232 free((void *) lp->sspace);
234 (void) memset((char *)lp, 0, sizeof(library));
238 * Open the library file once using stdio. Keep it open, but
239 * keep track of the file position.
241 static boolean
242 lib_dlb_init()
244 /* zero out array */
245 (void) memset((char *)&dlb_libs[0], 0, sizeof(dlb_libs));
247 /* To open more than one library, add open library calls here. */
248 if (!open_library(DLBAREA, DLBFILE, &dlb_libs[0])) return FALSE;
249 #ifdef DLBFILE2
250 if (!open_library(DLBAREA2, DLBFILE2, &dlb_libs[1])) {
251 close_library(&dlb_libs[0]);
252 return FALSE;
254 #endif
255 return TRUE;
258 static void
259 lib_dlb_cleanup()
261 int i;
263 /* close the data file(s) */
264 for (i = 0; i < MAX_LIBS && dlb_libs[i].fdata; i++)
265 close_library(&dlb_libs[i]);
268 static boolean
269 lib_dlb_fopen(dp, name, mode)
270 dlb *dp;
271 const char *name, *mode;
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 static int
289 lib_dlb_fclose(dp)
290 dlb *dp;
292 /* nothing needs to be done */
293 return 0;
296 static int
297 lib_dlb_fread(buf, size, quan, dp)
298 char *buf;
299 int size, quan;
300 dlb *dp;
302 long pos, nread, nbytes;
304 /* make sure we don't read into the next file */
305 if ((dp->size - dp->mark) < (size * quan))
306 quan = (dp->size - dp->mark) / size;
307 if (quan == 0) return 0;
309 pos = dp->start + dp->mark;
310 if (dp->lib->fmark != pos) {
311 fseek(dp->lib->fdata, pos, SEEK_SET); /* check for error??? */
312 dp->lib->fmark = pos;
315 nread = fread(buf, size, quan, dp->lib->fdata);
316 nbytes = nread * size;
317 dp->mark += nbytes;
318 dp->lib->fmark += nbytes;
320 return nread;
323 static int
324 lib_dlb_fseek(dp, pos, whence)
325 dlb *dp;
326 long pos;
327 int whence;
329 long curpos;
331 switch (whence) {
332 case SEEK_CUR: curpos = dp->mark + pos; break;
333 case SEEK_END: curpos = dp->size - pos; break;
334 default: /* set */ curpos = pos; break;
336 if (curpos < 0) curpos = 0;
337 if (curpos > dp->size) curpos = dp->size;
339 dp->mark = curpos;
340 return 0;
343 static char *
344 lib_dlb_fgets(buf, len, dp)
345 char *buf;
346 int len;
347 dlb *dp;
349 int i;
350 char *bp, c = 0;
352 if (len <= 0) return buf; /* sanity check */
354 /* return NULL on EOF */
355 if (dp->mark >= dp->size) return (char *) 0;
357 len--; /* save room for null */
358 for (i = 0, bp = buf;
359 i < len && dp->mark < dp->size && c != '\n'; i++, bp++) {
360 if (dlb_fread(bp, 1, 1, dp) <= 0) break; /* EOF or error */
361 c = *bp;
363 *bp = '\0';
365 #if defined(MSDOS) || defined(WIN32)
366 if ((bp = index(buf, '\r')) != 0) {
367 *bp++ = '\n';
368 *bp = '\0';
370 #endif
372 return buf;
375 static int
376 lib_dlb_fgetc(dp)
377 dlb *dp;
379 char c;
381 if (lib_dlb_fread(&c, 1, 1, dp) != 1) return EOF;
382 return (int) c;
386 static long
387 lib_dlb_ftell(dp)
388 dlb *dp;
390 return dp->mark;
393 const dlb_procs_t lib_dlb_procs = {
394 lib_dlb_init,
395 lib_dlb_cleanup,
396 lib_dlb_fopen,
397 lib_dlb_fclose,
398 lib_dlb_fread,
399 lib_dlb_fseek,
400 lib_dlb_fgets,
401 lib_dlb_fgetc,
402 lib_dlb_ftell
405 #endif /* DLBLIB */
407 #ifdef DLBRSRC
408 const dlb_procs_t rsrc_dlb_procs = {
409 rsrc_dlb_init,
410 rsrc_dlb_cleanup,
411 rsrc_dlb_fopen,
412 rsrc_dlb_fclose,
413 rsrc_dlb_fread,
414 rsrc_dlb_fseek,
415 rsrc_dlb_fgets,
416 rsrc_dlb_fgetc,
417 rsrc_dlb_ftell
419 #endif
421 /* Global wrapper functions ------------------------------------------------ */
423 #define do_dlb_init (*dlb_procs->dlb_init_proc)
424 #define do_dlb_cleanup (*dlb_procs->dlb_cleanup_proc)
425 #define do_dlb_fopen (*dlb_procs->dlb_fopen_proc)
426 #define do_dlb_fclose (*dlb_procs->dlb_fclose_proc)
427 #define do_dlb_fread (*dlb_procs->dlb_fread_proc)
428 #define do_dlb_fseek (*dlb_procs->dlb_fseek_proc)
429 #define do_dlb_fgets (*dlb_procs->dlb_fgets_proc)
430 #define do_dlb_fgetc (*dlb_procs->dlb_fgetc_proc)
431 #define do_dlb_ftell (*dlb_procs->dlb_ftell_proc)
433 static const dlb_procs_t *dlb_procs;
434 static boolean dlb_initialized = FALSE;
436 boolean
437 dlb_init()
439 if (!dlb_initialized) {
440 #ifdef DLBLIB
441 dlb_procs = &lib_dlb_procs;
442 #endif
443 #ifdef DLBRSRC
444 dlb_procs = &rsrc_dlb_procs;
445 #endif
447 if (dlb_procs)
448 dlb_initialized = do_dlb_init();
451 return dlb_initialized;
454 void
455 dlb_cleanup()
457 if (dlb_initialized) {
458 do_dlb_cleanup();
459 dlb_initialized = FALSE;
464 dlb *
465 #ifndef FILE_AREAS
466 dlb_fopen(name, mode)
467 const char *name, *mode;
468 #else
469 dlb_fopen_area(area, name, mode)
470 const char *area, *name, *mode;
471 #endif
473 FILE *fp;
474 dlb *dp;
476 if (!dlb_initialized) return (dlb *) 0;
478 dp = (dlb *) alloc(sizeof(dlb));
479 if (do_dlb_fopen(dp, name, mode))
480 dp->fp = (FILE *) 0;
481 #ifndef FILE_AREAS
482 else if ((fp = fopen_datafile(name, mode, DATAPREFIX)) != 0)
483 #else
484 else if ((fp = fopen_datafile_area(area, name, mode, DATAPREFIX)) != 0)
485 #endif
486 dp->fp = fp;
487 else {
488 /* can't find anything */
489 free((void *) dp);
490 dp = (dlb *) 0;
493 return dp;
497 dlb_fclose(dp)
498 dlb *dp;
500 int ret = 0;
502 if (dlb_initialized) {
503 if (dp->fp) ret = fclose(dp->fp);
504 else ret = do_dlb_fclose(dp);
506 free((void *) dp);
508 return ret;
512 dlb_fread(buf, size, quan, dp)
513 char *buf;
514 int size, quan;
515 dlb *dp;
517 if (!dlb_initialized || size <= 0 || quan <= 0) return 0;
518 if (dp->fp) return (int) fread(buf, size, quan, dp->fp);
519 return do_dlb_fread(buf, size, quan, dp);
523 dlb_fseek(dp, pos, whence)
524 dlb *dp;
525 long pos;
526 int whence;
528 if (!dlb_initialized) return EOF;
529 if (dp->fp) return fseek(dp->fp, pos, whence);
530 return do_dlb_fseek(dp, pos, whence);
533 char *
534 dlb_fgets(buf, len, dp)
535 char *buf;
536 int len;
537 dlb *dp;
539 if (!dlb_initialized) return (char *) 0;
540 if (dp->fp) return fgets(buf, len, dp->fp);
541 return do_dlb_fgets(buf, len, dp);
545 dlb_fgetc(dp)
546 dlb *dp;
548 if (!dlb_initialized) return EOF;
549 if (dp->fp) return fgetc(dp->fp);
550 return do_dlb_fgetc(dp);
553 long
554 dlb_ftell(dp)
555 dlb *dp;
557 if (!dlb_initialized) return 0;
558 if (dp->fp) return ftell(dp->fp);
559 return do_dlb_ftell(dp);
562 #endif /* DLB */
564 /*dlb.c*/