abstract
| - Below is the full text to dlb.c from the source code of SLASH'EM 0.0.7E7F2. To link to a particular line, write [[SLASH'EM 0.0.7E7F2/dlb.c#line123]], for example. The latest source code for vanilla NetHack is at Source code. 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. #ifdef FILE_AREAS 35. extern FILE *FDECL(fopen_datafile_area, (const char *,const char *, 36. const char *,int)); 37. #else 38. /* 39. * If FILE_AREAS is not defined, then fopen_datafile_area 40. * is a macro defined in terms of fopen_datafile. 41. */ 42. extern FILE *FDECL(fopen_datafile, (const char *,const char *,int)); 43. #endif 44. 45. #ifdef DLBLIB 46. /* 47. * Library Implementation: 48. * 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. 55. * 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. 60. */ 61. 62. #define MAX_LIBS 4 63. static library dlb_libs[MAX_LIBS]; 64. 65. static boolean FDECL(readlibdir,(library *lp)); 66. static boolean FDECL(find_file,(const char *name, library **lib, long *startp, 67. long *sizep)); 68. static boolean NDECL(lib_dlb_init); 69. static void NDECL(lib_dlb_cleanup); 70. static boolean FDECL(lib_dlb_fopen,(dlb *, const char *, const char *)); 71. static int FDECL(lib_dlb_fclose,(dlb *)); 72. static int FDECL(lib_dlb_fread,(char *, int, int, dlb *)); 73. static int FDECL(lib_dlb_fseek,(dlb *, long, int)); 74. static char *FDECL(lib_dlb_fgets,(char *, int, dlb *)); 75. static int FDECL(lib_dlb_fgetc,(dlb *)); 76. static long FDECL(lib_dlb_ftell,(dlb *)); 77. 78. /* not static because shared with dlb_main.c */ 79. boolean FDECL(open_library,(const char *lib_area, const char *lib_name, 80. library *lp)); 81. void FDECL(close_library,(library *lp)); 82. 83. /* without extern.h via hack.h, these haven't been declared for us */ 84. extern char *FDECL(eos, (char *)); 85. 86. 87. 88. /* 89. * Read the directory out of the library. Return 1 if successful, 90. * 0 if it failed. 91. * 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. 96. * 97. * Library file structure: 98. * 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 109. * 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 117. * 118. * followed by the contents of the files 119. */ 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 */ 122. 123. /* 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. 127. * 128. * Return TRUE on success, FALSE on failure. 129. */ 130. static boolean 131. readlibdir(lp) 132. library *lp; /* library pointer to fill in */ 133. { 134. int i; 135. char *sp; 136. long liboffset, totalsize; 137. 138. if (fscanf(lp->fdata, "%ld %ld %ld %ld %ld
", 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; 142. 143. lp->dir = (libdir *) alloc(lp->nentries * sizeof(libdir)); 144. lp->sspace = (char *) alloc(lp->strsize); 145. 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
", 150. &lp->dir[i].handling, sp, &lp->dir[i].foffset) != 3) { 151. free((genericptr_t) lp->dir); 152. free((genericptr_t) lp->sspace); 153. lp->dir = (libdir *) 0; 154. lp->sspace = (char *) 0; 155. return FALSE; 156. } 157. sp = eos(sp) + 1; 158. } 159. 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; 166. } 167. 168. (void) fseek(lp->fdata, 0L, SEEK_SET); /* reset back to zero */ 169. lp->fmark = 0; 170. 171. return TRUE; 172. } 173. 174. /* 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. 177. */ 178. static boolean 179. find_file(name, lib, startp, sizep) 180. const char *name; 181. library **lib; 182. long *startp, *sizep; 183. { 184. int i, j; 185. library *lp; 186. 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; 195. } 196. } 197. } 198. *lib = (library *) 0; 199. *startp = *sizep = 0; 200. return FALSE; 201. } 202. 203. /* 204. * Open the library of the given name and fill in the given library 205. * structure. Return TRUE if successful, FALSE otherwise. 206. */ 207. boolean 208. open_library(lib_area, lib_name, lp) 209. const char *lib_area, *lib_name; 210. library *lp; 211. { 212. boolean status = FALSE; 213. 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; 221. } 222. } 223. return status; 224. } 225. 226. void 227. close_library(lp) 228. library *lp; 229. { 230. (void) fclose(lp->fdata); 231. free((genericptr_t) lp->dir); 232. free((genericptr_t) lp->sspace); 233. 234. (void) memset((char *)lp, 0, sizeof(library)); 235. } 236. 237. /* 238. * Open the library file once using stdio. Keep it open, but 239. * keep track of the file position. 240. */ 241. static boolean 242. lib_dlb_init() 243. { 244. /* zero out array */ 245. (void) memset((char *)&dlb_libs[0], 0, sizeof(dlb_libs)); 246. 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; 253. } 254. #endif 255. return TRUE; 256. } 257. 258. static void 259. lib_dlb_cleanup() 260. { 261. int i; 262. 263. /* close the data file(s) */ 264. for (i = 0; i < MAX_LIBS && dlb_libs[i].fdata; i++) 265. close_library(&dlb_libs[i]); 266. } 267. 268. static boolean 269. lib_dlb_fopen(dp, name, mode) 270. dlb *dp; 271. const char *name, *mode; 272. { 273. long start, size; 274. library *lp; 275. 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; 283. } 284. 285. return FALSE; /* failed */ 286. } 287. 288. static int 289. lib_dlb_fclose(dp) 290. dlb *dp; 291. { 292. /* nothing needs to be done */ 293. return 0; 294. } 295. 296. static int 297. lib_dlb_fread(buf, size, quan, dp) 298. char *buf; 299. int size, quan; 300. dlb *dp; 301. { 302. long pos, nread, nbytes; 303. 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; 308. 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; 313. } 314. 315. nread = fread(buf, size, quan, dp->lib->fdata); 316. nbytes = nread * size; 317. dp->mark += nbytes; 318. dp->lib->fmark += nbytes; 319. 320. return nread; 321. } 322. 323. static int 324. lib_dlb_fseek(dp, pos, whence) 325. dlb *dp; 326. long pos; 327. int whence; 328. { 329. long curpos; 330. 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; 335. } 336. if (curpos < 0) curpos = 0; 337. if (curpos > dp->size) curpos = dp->size; 338. 339. dp->mark = curpos; 340. return 0; 341. } 342. 343. static char * 344. lib_dlb_fgets(buf, len, dp) 345. char *buf; 346. int len; 347. dlb *dp; 348. { 349. int i; 350. char *bp, c = 0; 351. 352. if (len <= 0) return buf; /* sanity check */ 353. 354. /* return NULL on EOF */ 355. if (dp->mark >= dp->size) return (char *) 0; 356. 357. len--; /* save room for null */ 358. for (i = 0, bp = buf; 359. i < len && dp->mark < dp->size && c != '
'; i++, bp++) { 360. if (dlb_fread(bp, 1, 1, dp) <= 0) break; /* EOF or error */ 361. c = *bp; 362. } 363. *bp = '\0'; 364. 365. #if defined(MSDOS) || defined(WIN32) 366. if ((bp = index(buf, '')) != 0) { 367. *bp++ = '
'; 368. *bp = '\0'; 369. } 370. #endif 371. 372. return buf; 373. } 374. 375. static int 376. lib_dlb_fgetc(dp) 377. dlb *dp; 378. { 379. char c; 380. 381. if (lib_dlb_fread(&c, 1, 1, dp) != 1) return EOF; 382. return (int) c; 383. } 384. 385. 386. static long 387. lib_dlb_ftell(dp) 388. dlb *dp; 389. { 390. return dp->mark; 391. } 392. 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 403. }; 404. 405. #endif /* DLBLIB */ 406. 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 418. }; 419. #endif 420. 421. /* Global wrapper functions ------------------------------------------------ */ 422. 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) 432. 433. static const dlb_procs_t *dlb_procs; 434. static boolean dlb_initialized = FALSE; 435. 436. boolean 437. dlb_init() 438. { 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 446. 447. if (dlb_procs) 448. dlb_initialized = do_dlb_init(); 449. } 450. 451. return dlb_initialized; 452. } 453. 454. void 455. dlb_cleanup() 456. { 457. if (dlb_initialized) { 458. do_dlb_cleanup(); 459. dlb_initialized = FALSE; 460. } 461. } 462. 463. 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 472. { 473. FILE *fp; 474. dlb *dp; 475. 476. if (!dlb_initialized) return (dlb *) 0; 477. 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((genericptr_t) dp); 490. dp = (dlb *) 0; 491. } 492. 493. return dp; 494. } 495. 496. int 497. dlb_fclose(dp) 498. dlb *dp; 499. { 500. int ret = 0; 501. 502. if (dlb_initialized) { 503. if (dp->fp) ret = fclose(dp->fp); 504. else ret = do_dlb_fclose(dp); 505. 506. free((genericptr_t) dp); 507. } 508. return ret; 509. } 510. 511. int 512. dlb_fread(buf, size, quan, dp) 513. char *buf; 514. int size, quan; 515. dlb *dp; 516. { 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); 520. } 521. 522. int 523. dlb_fseek(dp, pos, whence) 524. dlb *dp; 525. long pos; 526. int whence; 527. { 528. if (!dlb_initialized) return EOF; 529. if (dp->fp) return fseek(dp->fp, pos, whence); 530. return do_dlb_fseek(dp, pos, whence); 531. } 532. 533. char * 534. dlb_fgets(buf, len, dp) 535. char *buf; 536. int len; 537. dlb *dp; 538. { 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); 542. } 543. 544. int 545. dlb_fgetc(dp) 546. dlb *dp; 547. { 548. if (!dlb_initialized) return EOF; 549. if (dp->fp) return fgetc(dp->fp); 550. return do_dlb_fgetc(dp); 551. } 552. 553. long 554. dlb_ftell(dp) 555. dlb *dp; 556. { 557. if (!dlb_initialized) return 0; 558. if (dp->fp) return ftell(dp->fp); 559. return do_dlb_ftell(dp); 560. } 561. 562. #endif /* DLB */ 563. 564. /*dlb.c*/
|