Source:NetHack 3.2.0/files.c
(Redirected from NetHack 3.2.0/files.c)
Jump to navigation
Jump to search
Below is the full text to files.c from the source code of NetHack 3.2.0.
Warning! This is the source code from an old release. For newer releases, see Source code
The NetHack General Public License applies to screenshots, source code and other content from NetHack.
This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.
1. /* SCCS Id: @(#)files.c 3.2 95/08/04 */ 2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3. /* NetHack may be freely redistributed. See license for details. */ 4. 5. #include "hack.h" 6. #include "dlb.h" 7. 8. #include <ctype.h> 9. 10. #if !defined(MAC) && !defined(O_WRONLY) && !defined(AZTEC_C) 11. #include <fcntl.h> 12. #endif 13. #if defined(UNIX) || defined(VMS) 14. #include <errno.h> 15. # ifndef SKIP_ERRNO 16. extern int errno; 17. # endif 18. #include <signal.h> 19. #endif 20. 21. #if defined(MSDOS) || defined(OS2) || defined(TOS) || defined(WIN32) 22. # ifndef GNUDOS 23. #include <sys\stat.h> 24. # else 25. #include <sys/stat.h> 26. # endif 27. #endif 28. #ifndef O_BINARY /* used for micros, no-op for others */ 29. # define O_BINARY 0 30. #endif 31. 32. #ifdef MFLOPPY 33. char bones[FILENAME]; /* pathname of bones files */ 34. char lock[FILENAME]; /* pathname of level files */ 35. #else 36. # ifdef VMS 37. char bones[] = "bonesnn.xxx;1"; 38. char lock[PL_NSIZ+17] = "1lock"; /* long enough for _uid+name+.99;1 */ 39. # else 40. char bones[] = "bonesnn.xxx"; 41. char lock[PL_NSIZ+14] = "1lock"; /* long enough for uid+name+.99 */ 42. # endif /* VMS */ 43. #endif /* MFLOPPY */ 44. 45. #ifdef UNIX 46. #define SAVESIZE (PL_NSIZ + 13) /* save/99999player.e */ 47. #else 48. # ifdef VMS 49. #define SAVESIZE (PL_NSIZ + 22) /* [.save]<uid>player.e;1 */ 50. # else 51. #define SAVESIZE FILENAME /* from macconf.h or pcconf.h */ 52. # endif 53. #endif 54. 55. char SAVEF[SAVESIZE]; /* holds relative path of save file from playground */ 56. #ifdef MICRO 57. char SAVEP[SAVESIZE]; /* holds path of directory for save file */ 58. #endif 59. 60. #ifdef AMIGA 61. extern char PATH[]; /* see sys/amiga/amidos.c */ 62. extern char bbs_id[]; 63. static int lockptr; 64. # ifdef __SASC_60 65. #include <proto/dos.h> 66. # endif 67. 68. #include <libraries/dos.h> 69. #endif 70. 71. extern int n_dgns; /* from dungeon.c */ 72. 73. static char *FDECL(set_bonesfile_name, (char *,d_level*)); 74. static char *NDECL(set_bonestemp_name); 75. static char *FDECL(make_lockname, (const char *,char *)); 76. static FILE *FDECL(fopen_config_file, (const char *)); 77. static int FDECL(get_uchars, (FILE *,char *,char *,uchar *,int,const char *)); 78. int FDECL(parse_config_line, (FILE *,char *,char *,char *)); 79. 80. 81. /* fopen a file, with OS-dependent bells and whistles */ 82. /* NOTE: a simpler version of this routine also exists in util/dlb_main.c */ 83. FILE * 84. fopen_datafile(filename, mode) 85. const char *filename, *mode; 86. { 87. FILE *fp; 88. #ifdef AMIGA 89. fp = fopenp(filename, mode); 90. #else 91. # ifdef VMS /* essential to have punctuation, to avoid logical names */ 92. char tmp[BUFSIZ]; 93. 94. if (!index(filename, '.') && !index(filename, ';')) 95. filename = strcat(strcpy(tmp, filename), ";0"); 96. fp = fopen(filename, mode, "mbc=16"); 97. # else 98. fp = fopen(filename, mode); 99. # endif 100. #endif 101. return fp; 102. } 103. 104. /* ---------- BEGIN LEVEL FILE HANDLING ----------- */ 105. 106. #ifdef MFLOPPY 107. /* Set names for bones[] and lock[] */ 108. void 109. set_lock_and_bones() 110. { 111. if (!ramdisk) { 112. Strcpy(levels, permbones); 113. Strcpy(bones, permbones); 114. } 115. append_slash(permbones); 116. append_slash(levels); 117. #ifdef AMIGA 118. strncat(levels, bbs_id, PATHLEN); 119. #endif 120. append_slash(bones); 121. Strcat(bones, "bonesnn.*"); 122. Strcpy(lock, levels); 123. Strcat(lock, alllevels); 124. return; 125. } 126. #endif /* MFLOPPY */ 127. 128. 129. /* Construct a file name for a level-type file, which is of the form 130. * something.level (with any old level stripped off). 131. * This assumes there is space on the end of 'file' to append 132. * a two digit number. This is true for 'level' 133. * but be careful if you use it for other things -dgk 134. */ 135. void 136. set_levelfile_name(file, lev) 137. char *file; 138. int lev; 139. { 140. char *tf; 141. 142. tf = rindex(file, '.'); 143. if (!tf) tf = eos(file); 144. Sprintf(tf, ".%d", lev); 145. #ifdef VMS 146. Strcat(tf, ";1"); 147. #endif 148. return; 149. } 150. 151. int 152. create_levelfile(lev) 153. int lev; 154. { 155. int fd; 156. 157. set_levelfile_name(lock, lev); 158. 159. #if defined(MICRO) 160. /* Use O_TRUNC to force the file to be shortened if it already 161. * exists and is currently longer. 162. */ 163. fd = open(lock, O_WRONLY |O_CREAT | O_TRUNC | O_BINARY, FCMASK); 164. #else 165. # ifdef MAC 166. fd = maccreat(lock, LEVL_TYPE); 167. # else 168. fd = creat(lock, FCMASK); 169. # endif 170. #endif /* MICRO */ 171. 172. if (fd >= 0) 173. level_info[lev].flags |= LFILE_EXISTS; 174. 175. return fd; 176. } 177. 178. 179. int 180. open_levelfile(lev) 181. int lev; 182. { 183. int fd; 184. 185. set_levelfile_name(lock, lev); 186. #ifdef MFLOPPY 187. /* If not currently accessible, swap it in. */ 188. if (level_info[lev].where != ACTIVE) 189. swapin_file(lev); 190. #endif 191. #ifdef MAC 192. fd = macopen(lock, O_RDONLY | O_BINARY, LEVL_TYPE); 193. #else 194. fd = open(lock, O_RDONLY | O_BINARY, 0); 195. #endif 196. return fd; 197. } 198. 199. 200. void 201. delete_levelfile(lev) 202. int lev; 203. { 204. /* 205. * Level 0 might be created by port specific code that doesn't 206. * call create_levfile(), so always assume that it exists. 207. */ 208. if (lev == 0 || (level_info[lev].flags & LFILE_EXISTS)) { 209. set_levelfile_name(lock, lev); 210. (void) unlink(lock); 211. level_info[lev].flags &= ~LFILE_EXISTS; 212. } 213. } 214. 215. 216. void 217. clearlocks() 218. { 219. #if defined(MFLOPPY) && !defined(AMIGA) 220. eraseall(levels, alllevels); 221. if (ramdisk) 222. eraseall(permbones, alllevels); 223. #else 224. register int x; 225. 226. # if defined(UNIX) || defined(VMS) 227. (void) signal(SIGHUP, SIG_IGN); 228. # endif 229. /* can't access maxledgerno() before dungeons are created -dlc */ 230. for (x = (n_dgns ? maxledgerno() : 0); x >= 0; x--) 231. delete_levelfile(x); /* not all levels need be present */ 232. #endif 233. } 234. 235. /* ---------- END LEVEL FILE HANDLING ----------- */ 236. 237. 238. /* ---------- BEGIN BONES FILE HANDLING ----------- */ 239. 240. /* set up "file" to be file name for retrieving bones, and return a 241. * bonesid to be read/written in the bones file. 242. */ 243. static char * 244. set_bonesfile_name(file, lev) 245. char *file; 246. d_level *lev; 247. { 248. char *dptr = rindex(file, '.'); 249. s_level *sptr; 250. 251. if (!dptr) dptr = eos(file); 252. *(dptr-2) = dungeons[lev->dnum].boneid; 253. *(dptr-1) = In_quest(lev) ? pl_character[0] : '0'; 254. if ((sptr = Is_special(lev)) != 0) 255. Sprintf(dptr, ".%c", sptr->boneid); 256. else 257. Sprintf(dptr, ".%d", lev->dlevel); 258. #ifdef VMS 259. Strcat(dptr, ";1"); 260. #endif 261. return(dptr-2); 262. } 263. 264. /* set up temporary file name for writing bones, to avoid another game's 265. * trying to read from an uncompleted bones file. we want an uncontentious 266. * name, so use one in the namespace reserved for this game's level files. 267. * (we are not reading or writing level files while writing bones files, so 268. * the same array may be used instead of copying.) 269. */ 270. static char * 271. set_bonestemp_name() 272. { 273. char *tf; 274. 275. tf = rindex(lock, '.'); 276. if (!tf) tf = eos(lock); 277. Sprintf(tf, ".bn"); 278. #ifdef VMS 279. Strcat(tf, ";1"); 280. #endif 281. return lock; 282. } 283. 284. int 285. create_bonesfile(lev, bonesid) 286. d_level *lev; 287. char **bonesid; 288. { 289. char *file; 290. int fd; 291. 292. *bonesid = set_bonesfile_name(bones, lev); 293. file = set_bonestemp_name(); 294. 295. #ifdef MICRO 296. /* Use O_TRUNC to force the file to be shortened if it already 297. * exists and is currently longer. 298. */ 299. fd = open(file, O_WRONLY |O_CREAT | O_TRUNC | O_BINARY, FCMASK); 300. #else 301. # ifdef MAC 302. fd = maccreat(file, BONE_TYPE); 303. # else 304. fd = creat(file, FCMASK); 305. # endif 306. # if defined(VMS) && !defined(SECURE) 307. /* 308. Re-protect bones file with world:read+write+execute+delete access. 309. umask() doesn't seem very reliable; also, vaxcrtl won't let us set 310. delete access without write access, which is what's really wanted. 311. Can't simply create it with the desired protection because creat 312. ANDs the mask with the user's default protection, which usually 313. denies some or all access to world. 314. */ 315. (void) chmod(file, FCMASK | 007); /* allow other users full access */ 316. # endif /* VMS && !SECURE */ 317. #endif /* MICRO */ 318. 319. return fd; 320. } 321. 322. #ifdef MFLOPPY 323. /* remove partial bonesfile in process of creation */ 324. void 325. cancel_bonesfile() 326. { 327. char *tempname; 328. 329. tempname = set_bonestemp_name(); 330. (void) unlink(tempname); 331. } 332. #endif /* MFLOPPY */ 333. 334. /* move completed bones file to proper name */ 335. void 336. commit_bonesfile(lev) 337. d_level *lev; 338. { 339. char *tempname; 340. int ret; 341. 342. (void) set_bonesfile_name(bones, lev); 343. tempname = set_bonestemp_name(); 344. 345. #if (defined(SYSV) && !defined(SVR4)) || defined(GENIX) 346. /* old SYSVs don't have rename. Some SVR3's may, but since they 347. * also have link/unlink, it doesn't matter. :-) 348. */ 349. (void) unlink(bones); 350. ret = link(tempname, bones); 351. ret += unlink(tempname); 352. #else 353. ret = rename(tempname, bones); 354. #endif 355. #ifdef WIZARD 356. if (wizard && ret != 0) 357. pline("couldn't rename %s to %s", tempname, bones); 358. #endif 359. } 360. 361. 362. int 363. open_bonesfile(lev, bonesid) 364. d_level *lev; 365. char **bonesid; 366. { 367. int fd; 368. 369. *bonesid = set_bonesfile_name(bones, lev); 370. uncompress(bones); /* no effect if nonexistent */ 371. #ifdef MAC 372. fd = macopen(bones, O_RDONLY | O_BINARY, BONE_TYPE); 373. #else 374. fd = open(bones, O_RDONLY | O_BINARY, 0); 375. #endif 376. return fd; 377. } 378. 379. 380. int 381. delete_bonesfile(lev) 382. d_level *lev; 383. { 384. (void) set_bonesfile_name(bones, lev); 385. return !(unlink(bones) < 0); 386. } 387. 388. 389. /* assume we're compressing the recently read or created bonesfile, so the 390. * file name is already set properly */ 391. void 392. compress_bonesfile() 393. { 394. compress(bones); 395. } 396. 397. /* ---------- END BONES FILE HANDLING ----------- */ 398. 399. 400. /* ---------- BEGIN SAVE FILE HANDLING ----------- */ 401. 402. /* set savefile name in OS-dependent manner from pre-existing plname, 403. * avoiding troublesome characters */ 404. void 405. set_savefile_name() 406. { 407. #ifdef VMS 408. Sprintf(SAVEF, "[.save]%d%s", getuid(), plname); 409. regularize(SAVEF+7); 410. Strcat(SAVEF, ";1"); 411. #else 412. # ifdef MICRO 413. Strcpy(SAVEF, SAVEP); 414. # ifdef AMIGA 415. strncat(SAVEF, bbs_id, PATHLEN); 416. # endif 417. { 418. int i = strlen(SAVEP); 419. # ifdef AMIGA 420. /* plname has to share space with SAVEP and ".sav" */ 421. (void)strncat(SAVEF, plname, FILENAME - i - 4); 422. # else 423. (void)strncat(SAVEF, plname, 8); 424. # endif 425. regularize(SAVEF+i); 426. } 427. Strcat(SAVEF, ".sav"); 428. # else 429. Sprintf(SAVEF, "save/%d%s", (int)getuid(), plname); 430. regularize(SAVEF+5); /* avoid . or / in name */ 431. # endif /* MICRO */ 432. #endif /* VMS */ 433. } 434. 435. #ifdef INSURANCE 436. void 437. save_savefile_name(fd) 438. int fd; 439. { 440. (void) write(fd, (genericptr_t) SAVEF, sizeof(SAVEF)); 441. } 442. #endif 443. 444. 445. #if defined(WIZARD) && !defined(MICRO) 446. /* change pre-existing savefile name to indicate an error savefile */ 447. void 448. set_error_savefile() 449. { 450. # ifdef VMS 451. { 452. char *semi_colon = rindex(SAVEF, ';'); 453. if (semi_colon) *semi_colon = '\0'; 454. } 455. Strcat(SAVEF, ".e;1"); 456. # else 457. # ifdef MAC 458. Strcat(SAVEF, "-e"); 459. # else 460. Strcat(SAVEF, ".e"); 461. # endif 462. # endif 463. } 464. #endif 465. 466. 467. /* create save file, overwriting one if it already exists */ 468. int 469. create_savefile() 470. { 471. int fd; 472. #ifdef AMIGA 473. fd = ami_wbench_getsave(O_WRONLY | O_CREAT | O_TRUNC); 474. #else 475. # ifdef MICRO 476. fd = open(SAVEF, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK); 477. # else 478. # ifdef MAC 479. fd = maccreat(SAVEF, SAVE_TYPE); 480. # else 481. fd = creat(SAVEF, FCMASK); 482. # endif 483. # if defined(VMS) && !defined(SECURE) 484. /* 485. Make sure the save file is owned by the current process. That's 486. the default for non-privileged users, but for priv'd users the 487. file will be owned by the directory's owner instead of the user. 488. */ 489. # ifdef getuid /*(see vmsunix.c)*/ 490. # undef getuid 491. # endif 492. (void) chown(SAVEF, getuid(), getgid()); 493. # endif /* VMS && !SECURE */ 494. # endif /* MICRO */ 495. #endif /* AMIGA */ 496. 497. return fd; 498. } 499. 500. 501. /* open savefile for reading */ 502. int 503. open_savefile() 504. { 505. int fd; 506. 507. #ifdef AMIGA 508. fd = ami_wbench_getsave(O_RDONLY); 509. #else 510. # ifdef MAC 511. fd = macopen(SAVEF, O_RDONLY | O_BINARY, SAVE_TYPE); 512. # else 513. fd = open(SAVEF, O_RDONLY | O_BINARY, 0); 514. # endif 515. #endif /* AMIGA */ 516. return fd; 517. } 518. 519. 520. /* delete savefile */ 521. int 522. delete_savefile() 523. { 524. #ifdef AMIGA 525. ami_wbench_unlink(SAVEF); 526. #endif 527. (void) unlink(SAVEF); 528. return 0; /* for restore_saved_game() (ex-xxxmain.c) test */ 529. } 530. 531. 532. /* try to open up a save file and prepare to restore it */ 533. int 534. restore_saved_game() 535. { 536. int fd; 537. 538. set_savefile_name(); 539. #ifdef MFLOPPY 540. if ( 541. # ifdef AMIGA 542. !(FromWBench || saveDiskPrompt(1)) 543. # else 544. !saveDiskPrompt(1) 545. # endif 546. ) return -1; 547. #endif /* MFLOPPY */ 548. 549. uncompress(SAVEF); 550. if ((fd = open_savefile()) < 0) return fd; 551. 552. if (!uptodate(fd, SAVEF)) { 553. (void) close(fd), fd = -1; 554. (void) delete_savefile(); 555. } 556. return fd; 557. } 558. 559. /* ---------- END SAVE FILE HANDLING ----------- */ 560. 561. 562. /* ---------- BEGIN FILE COMPRESSION HANDLING ----------- */ 563. 564. #ifdef COMPRESS 565. 566. void 567. redirect(filename, mode, stream, uncomp) 568. char *filename, *mode; 569. FILE *stream; 570. boolean uncomp; 571. { 572. if (freopen(filename, mode, stream) == (FILE *)0) { 573. (void) fprintf(stderr, "freopen of %s for %scompress failed\n", 574. filename, uncomp ? "un" : ""); 575. terminate(EXIT_FAILURE); 576. } 577. } 578. 579. /* 580. * using system() is simpler, but opens up security holes and causes 581. * problems on at least Interactive UNIX 3.0.1 (SVR3.2), where any 582. * setuid is renounced by /bin/sh, so the files cannot be accessed. 583. * 584. * cf. child() in unixunix.c. 585. */ 586. void 587. docompress_file(filename, uncomp) 588. char *filename; 589. boolean uncomp; 590. { 591. char cfn[80]; 592. FILE *cf; 593. const char *args[10]; 594. # ifdef COMPRESS_OPTIONS 595. char opts[80]; 596. # endif 597. int i = 0; 598. int f; 599. 600. Strcpy(cfn, filename); 601. # ifdef COMPRESS_EXTENSION 602. Strcat(cfn, COMPRESS_EXTENSION); 603. # endif 604. /* when compressing, we know the file exists */ 605. if (uncomp) { 606. if ((cf = fopen(cfn, RDBMODE)) == (FILE *)0) 607. return; 608. (void) fclose(cf); 609. } 610. 611. args[0] = COMPRESS; 612. if (uncomp) args[++i] = "-d"; /* uncompress */ 613. # ifdef COMPRESS_OPTIONS 614. { 615. /* we can't guarantee there's only one additional option, sigh */ 616. char *opt; 617. boolean inword = FALSE; 618. 619. Strcpy(opts, COMPRESS_OPTIONS); 620. opt = opts; 621. while (*opt) { 622. if ((*opt == ' ') || (*opt == '\t')) { 623. if (inword) { 624. *opt = '\0'; 625. inword = FALSE; 626. } 627. } else if (!inword) { 628. args[++i] = opt; 629. inword = TRUE; 630. } 631. opt++; 632. } 633. } 634. # endif 635. args[++i] = (char *)0; 636. 637. f = fork(); 638. if (f == 0) { /* child */ 639. /* run compressor without privileges, in case other programs 640. * have surprises along the line of gzip once taking filenames 641. * in GZIP. 642. */ 643. /* assume all compressors will compress stdin to stdout 644. * without explicit filenames. this is true of at least 645. * compress and gzip, those mentioned in config.h. 646. */ 647. if (uncomp) { 648. redirect(cfn, RDBMODE, stdin, uncomp); 649. redirect(filename, WRBMODE, stdout, uncomp); 650. } else { 651. redirect(filename, RDBMODE, stdin, uncomp); 652. redirect(cfn, WRBMODE, stdout, uncomp); 653. } 654. (void) setgid(getgid()); 655. (void) setuid(getuid()); 656. (void) execv(args[0], (char *const *) args); 657. perror((char *)0); 658. (void) fprintf(stderr, "Exec to %scompress %s failed.\n", 659. uncomp ? "un" : "", filename); 660. terminate(EXIT_FAILURE); 661. } else if (f == -1) { 662. perror((char *)0); 663. pline("Fork to %scompress %s failed.", 664. uncomp ? "un" : "", filename); 665. return; 666. } 667. (void) signal(SIGINT, SIG_IGN); 668. (void) signal(SIGQUIT, SIG_IGN); 669. (void) wait((int *)0); 670. (void) signal(SIGINT, (SIG_RET_TYPE) done1); 671. # ifdef WIZARD 672. if (wizard) (void) signal(SIGQUIT, SIG_DFL); 673. # endif 674. /* remove file left behind */ 675. if (uncomp) 676. (void) unlink(cfn); 677. else 678. (void) unlink(filename); 679. } 680. #endif /* COMPRESS */ 681. 682. /* compress file */ 683. void 684. compress(filename) 685. const char *filename; 686. #ifdef applec 687. # pragma unused(filename) 688. #endif 689. { 690. #ifdef COMPRESS 691. docompress_file(filename, FALSE); 692. #endif 693. } 694. 695. 696. /* uncompress file if it exists */ 697. void 698. uncompress(filename) 699. const char *filename; 700. #ifdef applec 701. # pragma unused(filename) 702. #endif 703. { 704. #ifdef COMPRESS 705. docompress_file(filename, TRUE); 706. #endif 707. } 708. 709. /* ---------- END FILE COMPRESSION HANDLING ----------- */ 710. 711. 712. /* ---------- BEGIN FILE LOCKING HANDLING ----------- */ 713. 714. static int nesting = 0; 715. 716. #ifdef NO_FILE_LINKS /* implies UNIX */ 717. static int lockfd; /* for lock_file() to pass to unlock_file() */ 718. #endif 719. 720. #define HUP if (!program_state.done_hup) 721. 722. static char * 723. make_lockname(filename, lockname) 724. const char *filename; 725. char *lockname; 726. { 727. #if defined(UNIX) || defined(VMS) || defined(AMIGA) 728. # ifdef NO_FILE_LINKS 729. Strcpy(lockname, LOCKDIR); 730. Strcat(lockname, "/"); 731. Strcat(lockname, filename); 732. # else 733. Strcpy(lockname, filename); 734. # endif 735. # ifdef VMS 736. { 737. char *semi_colon = rindex(lockname, ';'); 738. if (semi_colon) *semi_colon = '\0'; 739. } 740. Strcat(lockname, ".lock;1"); 741. # else 742. Strcat(lockname, "_lock"); 743. # endif 744. return lockname; 745. #else 746. lockname[0] = '\0'; 747. return (char*)0; 748. #endif /* UNIX || VMS || AMIGA */ 749. } 750. 751. 752. /* lock a file */ 753. boolean 754. lock_file(filename, retryct) 755. const char *filename; 756. int retryct; 757. #ifdef applec 758. # pragma unused(filename, retryct) 759. #endif 760. { 761. char *lockname, locknambuf[BUFSZ]; 762. 763. nesting++; 764. if (nesting > 1) { 765. impossible("TRIED TO NEST LOCKS"); 766. return TRUE; 767. } 768. 769. lockname = make_lockname(filename, locknambuf); 770. 771. #if defined(UNIX) || defined(VMS) 772. # ifdef NO_FILE_LINKS 773. while ((lockfd = open(lockname, O_RDWR|O_CREAT|O_EXCL, 0666)) == -1) { 774. # else 775. while (link(filename, lockname) == -1) { 776. # endif 777. register int errnosv = errno; 778. 779. switch (errnosv) { /* George Barbanis */ 780. case EEXIST: 781. if (retryct--) { 782. HUP raw_printf( 783. "Waiting for access to %s. (%d retries left).", 784. filename, retryct); 785. # if defined(SYSV) || defined(ULTRIX) || defined(VMS) 786. (void) 787. # endif 788. sleep(1); 789. } else { 790. HUP (void) raw_print("I give up. Sorry."); 791. HUP raw_printf("Perhaps there is an old %s around?", 792. lockname); 793. nesting--; 794. return FALSE; 795. } 796. 797. break; 798. case ENOENT: 799. HUP raw_printf("Can't find file %s to lock!", filename); 800. nesting--; 801. return FALSE; 802. case EACCES: 803. HUP raw_printf("No write permission to lock %s!", filename); 804. nesting--; 805. return FALSE; 806. # ifdef VMS /* c__translate(vmsfiles.c) */ 807. case EPERM: 808. /* could be misleading, but usually right */ 809. HUP raw_printf("Can't lock %s due to directory protection.", 810. filename); 811. nesting--; 812. return FALSE; 813. # endif 814. default: 815. HUP perror(lockname); 816. HUP raw_printf( 817. "Cannot lock %s for unknown reason (%d).", 818. filename, errnosv); 819. nesting--; 820. return FALSE; 821. } 822. 823. } 824. #endif /* UNIX || VMS */ 825. 826. #ifdef AMIGA 827. lockptr = 0; 828. while (retryct-- && !lockptr) { 829. (void)DeleteFile(lockname); /* in case dead process was here first */ 830. lockptr = Open(lockname,MODE_NEWFILE); 831. if (!lockptr) { 832. raw_printf("Waiting for access to %s. (%d retries left).", 833. filename, retryct); 834. Delay(50); 835. } 836. } 837. if (!retryct) { 838. raw_printf("I give up. Sorry."); 839. nesting--; 840. return FALSE; 841. } 842. #endif 843. return TRUE; 844. } 845. 846. 847. #ifdef VMS /* for unlock_file, use the unlink() routine in vmsunix.c */ 848. # ifdef unlink 849. # undef unlink 850. # endif 851. # define unlink(foo) vms_unlink(foo) 852. #endif 853. 854. /* unlock file, which must be currently locked by lock_file */ 855. void 856. unlock_file(filename) 857. const char *filename; 858. #if defined(applec) 859. # pragma unused(filename) 860. #endif 861. { 862. char *lockname, locknambuf[BUFSZ]; 863. 864. if (nesting == 1) { 865. lockname = make_lockname(filename, locknambuf); 866. 867. #if defined(UNIX) || defined(VMS) 868. if (unlink(lockname) < 0) 869. HUP raw_printf("Can't unlink %s.", lockname); 870. # ifdef NO_FILE_LINKS 871. (void) close(lockfd); 872. # endif 873. 874. #endif /* UNIX || VMS */ 875. 876. #ifdef AMIGA 877. if (lockptr) Close(lockptr); 878. DeleteFile(lockname); 879. lockptr = 0; 880. #endif /* AMIGA */ 881. } 882. 883. nesting--; 884. } 885. 886. /* ---------- END FILE LOCKING HANDLING ----------- */ 887. 888. 889. /* ---------- BEGIN CONFIG FILE HANDLING ----------- */ 890. 891. const char *configfile = 892. #ifdef UNIX 893. ".nethackrc"; 894. #else 895. # ifdef MAC 896. "NetHack defaults"; 897. # else 898. "NetHack.cnf"; 899. # endif 900. #endif 901. 902. #ifndef MFLOPPY 903. #define fopenp fopen 904. #endif 905. 906. static FILE * 907. fopen_config_file(filename) 908. const char *filename; 909. { 910. FILE *fp; 911. #if defined(UNIX) || defined(VMS) 912. char tmp_config[BUFSZ]; 913. #endif 914. 915. /* "filename" is an environment variable, so it should hang around */ 916. if (filename) { 917. #ifdef UNIX 918. if (access(filename, 4) == -1) { 919. /* 4 is R_OK on newer systems */ 920. /* nasty sneaky attempt to read file through 921. * NetHack's setuid permissions -- this is the only 922. * place a file name may be wholly under the player's 923. * control 924. */ 925. raw_printf("Access to %s denied (%d).", 926. filename, errno); 927. wait_synch(); 928. /* fall through to standard names */ 929. } else 930. #endif 931. if ((fp = fopenp(filename, "r")) != (FILE *)0) { 932. configfile = filename; 933. return(fp); 934. } 935. } 936. 937. #if defined(MICRO) || defined(MAC) 938. if ((fp = fopenp(configfile, "r")) != (FILE *)0) 939. return(fp); 940. #else 941. # ifdef VMS 942. if ((fp = fopenp("nethackini", "r")) != (FILE *)0) { 943. configfile = "nethackini"; 944. return(fp); 945. } 946. if ((fp = fopenp("sys$login:nethack.ini", "r")) != (FILE *)0) { 947. configfile = "nethack.ini"; 948. return(fp); 949. } 950. Sprintf(tmp_config, "%s%s", getenv("HOME"), "NetHack.cnf"); 951. if ((fp = fopenp(tmp_config, "r")) != (FILE *)0) 952. return(fp); 953. # else /* should be only UNIX left */ 954. Sprintf(tmp_config, "%s/%s", getenv("HOME"), ".nethackrc"); 955. if ((fp = fopenp(tmp_config, "r")) != (FILE *)0) 956. return(fp); 957. # endif 958. #endif 959. return (FILE *)0; 960. 961. } 962. 963. 964. /* 965. * Retrieve a list of integers from a file into a uchar array. 966. * 967. * NOTE: This routine is unable to read a value of 0. 968. */ 969. static int 970. get_uchars(fp, buf, bufp, list, size, name) 971. FILE *fp; /* input file pointer */ 972. char *buf; /* read buffer, must be of size BUFSZ */ 973. char *bufp; /* current pointer */ 974. uchar *list; /* return list */ 975. int size; /* return list size */ 976. const char *name; /* name of option for error message */ 977. { 978. unsigned int num = 0; 979. int count = 0; 980. 981. while (1) { 982. switch(*bufp) { 983. case ' ': case '\0': 984. case '\t': case '\n': 985. if (num) { 986. list[count++] = num; 987. num = 0; 988. } 989. if (count == size || !*bufp) return count; 990. bufp++; 991. break; 992. 993. case '0': case '1': case '2': case '3': 994. case '4': case '5': case '6': case '7': 995. case '8': case '9': 996. num = num*10 + (*bufp-'0'); 997. bufp++; 998. break; 999. 1000. case '\\': 1001. if (fp == (FILE *)0) 1002. goto gi_error; 1003. do { 1004. if (!fgets(buf, BUFSZ, fp)) goto gi_error; 1005. } while (buf[0] == '#'); 1006. bufp = buf; 1007. break; 1008. 1009. default: 1010. gi_error: 1011. raw_printf("Syntax error in %s", name); 1012. wait_synch(); 1013. return count; 1014. } 1015. } 1016. /*NOTREACHED*/ 1017. } 1018. 1019. /*ARGSUSED*/ 1020. int 1021. parse_config_line(fp, buf, tmp_ramdisk, tmp_levels) 1022. FILE *fp; 1023. char *buf; 1024. char *tmp_ramdisk; 1025. char *tmp_levels; 1026. #if defined(applec) 1027. # pragma unused(tmp_ramdisk,tmp_levels) 1028. #endif 1029. { 1030. char *bufp, *altp; 1031. uchar translate[MAXPCHARS]; 1032. int len; 1033. 1034. if (*buf == '#') 1035. return 1; 1036. 1037. /* remove trailing whitespace */ 1038. bufp = eos(buf); 1039. while (--bufp > buf && isspace(*bufp)) 1040. continue; 1041. 1042. if (bufp <= buf) 1043. return 1; /* skip all-blank lines */ 1044. else 1045. *(bufp + 1) = '\0'; /* terminate line */ 1046. 1047. /* find the '=' or ':' */ 1048. bufp = index(buf, '='); 1049. altp = index(buf, ':'); 1050. if (!bufp || (altp && altp < bufp)) bufp = altp; 1051. if (!bufp) return 0; 1052. 1053. /* skip whitespace between '=' and value */ 1054. do { ++bufp; } while (isspace(*bufp)); 1055. 1056. /* Go through possible variables */ 1057. if (!strncmpi(buf, "OPTIONS", 4)) { 1058. parseoptions(bufp, TRUE, TRUE); 1059. if (plname[0]) /* If a name was given */ 1060. plnamesuffix(); /* set the character class */ 1061. #ifdef MICRO 1062. } else if (!strncmpi(buf, "HACKDIR", 4)) { 1063. (void) strncpy(hackdir, bufp, PATHLEN); 1064. # ifdef MFLOPPY 1065. } else if (!strncmpi(buf, "RAMDISK", 3)) { 1066. /* The following ifdef is NOT in the wrong 1067. * place. For now, we accept and silently 1068. * ignore RAMDISK */ 1069. # ifndef AMIGA 1070. (void) strncpy(tmp_ramdisk, bufp, PATHLEN); 1071. # endif 1072. # endif 1073. } else if (!strncmpi(buf, "LEVELS", 4)) { 1074. (void) strncpy(tmp_levels, bufp, PATHLEN); 1075. 1076. } else if (!strncmpi(buf, "SAVE", 4)) { 1077. # ifdef MFLOPPY 1078. extern int saveprompt; 1079. #endif 1080. char *ptr; 1081. if (ptr = index(bufp, ';')) { 1082. *ptr = '\0'; 1083. # ifdef MFLOPPY 1084. if (*(ptr+1) == 'n' || *(ptr+1) == 'N') { 1085. saveprompt = FALSE; 1086. } 1087. # endif 1088. } 1089. #ifdef MFLOPPY 1090. else 1091. saveprompt = flags.asksavedisk; 1092. #endif 1093. 1094. (void) strncpy(SAVEP, bufp, PATHLEN); 1095. append_slash(SAVEP); 1096. #endif /* MICRO */ 1097. } else if(!strncmpi(buf, "CHARACTER", 4)) { 1098. (void) strncpy(pl_character, bufp, PL_CSIZ-1); 1099. } else if(!strncmpi(buf, "DOGNAME", 3)) { 1100. (void) strncpy(dogname, bufp, PL_PSIZ-1); 1101. } else if(!strncmpi(buf, "CATNAME", 3)) { 1102. (void) strncpy(catname, bufp, PL_PSIZ-1); 1103. } else if(!strncmpi(buf, "NAME", 4)) { 1104. (void) strncpy(plname, bufp, PL_NSIZ-1); 1105. plnamesuffix(); 1106. 1107. } else if (!strncmpi(buf, "GRAPHICS", 4)) { 1108. len = get_uchars(fp, buf, bufp, translate, MAXPCHARS, "GRAPHICS"); 1109. assign_graphics(translate, len, MAXPCHARS, 0); 1110. } else if (!strncmpi(buf, "DUNGEON", 4)) { 1111. len = get_uchars(fp, buf, bufp, translate, MAXDCHARS, "DUNGEON"); 1112. assign_graphics(translate, len, MAXDCHARS, 0); 1113. } else if (!strncmpi(buf, "TRAPS", 4)) { 1114. len = get_uchars(fp, buf, bufp, translate, MAXTCHARS, "TRAPS"); 1115. assign_graphics(translate, len, MAXTCHARS, MAXDCHARS); 1116. } else if (!strncmpi(buf, "EFFECTS", 4)) { 1117. len = get_uchars(fp, buf, bufp, translate, MAXECHARS, "EFFECTS"); 1118. assign_graphics(translate, len, MAXECHARS, MAXDCHARS+MAXTCHARS); 1119. 1120. } else if (!strncmpi(buf, "OBJECTS", 3)) { 1121. /* oc_syms[0] is the RANDOM object, unused */ 1122. (void) get_uchars(fp, buf, bufp, &(oc_syms[1]), 1123. MAXOCLASSES-1, "OBJECTS"); 1124. } else if (!strncmpi(buf, "MONSTERS", 3)) { 1125. /* monsyms[0] is unused */ 1126. (void) get_uchars(fp, buf, bufp, &(monsyms[1]), 1127. MAXMCLASSES-1, "MONSTERS"); 1128. #ifdef AMIGA 1129. } else if (!strncmpi(buf, "FONT", 4)) { 1130. char *t; 1131. extern void amii_set_text_font( char *, int ); 1132. 1133. if( t = strchr( buf+5, ':' ) ) 1134. { 1135. *t = 0; 1136. amii_set_text_font( buf+5, atoi( t + 1 ) ); 1137. *t = ':'; 1138. } 1139. } else if (!strncmpi(buf, "PATH", 4)) { 1140. (void) strncpy(PATH, bufp, PATHLEN); 1141. #endif 1142. #ifdef AMIGA 1143. } else if (!strncmpi(buf, "DEPTH", 5)) { 1144. extern int amii_numcolors; 1145. int val = atoi( bufp ); 1146. amii_numcolors = 1L << min( DEPTH, val ); 1147. } else if (!strncmpi(buf, "DRIPENS", 7)) { 1148. int i, val; 1149. char *t; 1150. for (i = 0, t = strtok(bufp, ",/"); t != (char *)0; 1151. i < 20 && (t = strtok((char*)0, ",/")), ++i) { 1152. sscanf(t, "%d", &val ); 1153. flags.amii_dripens[i] = val; 1154. } 1155. } else if (!strncmpi(buf, "SCREENMODE", 10 )) { 1156. extern long amii_scrnmode; 1157. if( sscanf(bufp, "%x", &amii_scrnmode) != 1 ) 1158. amii_scrnmode = 0; 1159. } else if (!strncmpi(buf, "MSGPENS", 7)) { 1160. extern int amii_msgAPen, amii_msgBPen; 1161. char *t = strtok(bufp, ",/"); 1162. if( t ) 1163. { 1164. sscanf(t, "%d", &amii_msgAPen); 1165. if( t = strtok((char*)0, ",/") ) 1166. sscanf(t, "%d", &amii_msgBPen); 1167. } 1168. } else if (!strncmpi(buf, "TEXTPENS", 8)) { 1169. extern int amii_textAPen, amii_textBPen; 1170. char *t = strtok(bufp, ",/"); 1171. if( t ) 1172. { 1173. sscanf(t, "%d", &amii_textAPen); 1174. if( t = strtok((char*)0, ",/") ) 1175. sscanf(t, "%d", &amii_textBPen); 1176. } 1177. } else if (!strncmpi(buf, "MENUPENS", 8)) { 1178. extern int amii_menuAPen, amii_menuBPen; 1179. char *t = strtok(bufp, ",/"); 1180. if( t ) 1181. { 1182. sscanf(t, "%d", &amii_menuAPen); 1183. if( t = strtok((char*)0, ",/") ) 1184. sscanf(t, "%d", &amii_menuBPen); 1185. } 1186. } else if (!strncmpi(buf, "STATUSPENS", 10)) { 1187. extern int amii_statAPen, amii_statBPen; 1188. char *t = strtok(bufp, ",/"); 1189. if( t ) 1190. { 1191. sscanf(t, "%d", &amii_statAPen); 1192. if( t = strtok((char*)0, ",/") ) 1193. sscanf(t, "%d", &amii_statBPen); 1194. } 1195. } else if (!strncmpi(buf, "OTHERPENS", 9)) { 1196. extern int amii_otherAPen, amii_otherBPen; 1197. char *t = strtok(bufp, ",/"); 1198. if( t ) 1199. { 1200. sscanf(t, "%d", &amii_otherAPen); 1201. if( t = strtok((char*)0, ",/") ) 1202. sscanf(t, "%d", &amii_otherBPen); 1203. } 1204. } else if (!strncmpi(buf, "PENS", 4)) { 1205. int i; 1206. char *t; 1207. 1208. for (i = 0, t = strtok(bufp, ",/"); t != (char *)0; 1209. t = strtok((char *)0, ",/"), ++i) 1210. { 1211. sscanf(t, "%hx", &flags.amii_curmap[i]); 1212. } 1213. amii_setpens( amii_numcolors = i ); 1214. #endif 1215. } else 1216. return 0; 1217. return 1; 1218. } 1219. 1220. void 1221. read_config_file(filename) 1222. const char *filename; 1223. { 1224. #define tmp_levels (char *)0 1225. #define tmp_ramdisk (char *)0 1226. 1227. #ifdef MICRO 1228. #undef tmp_levels 1229. char tmp_levels[PATHLEN]; 1230. # ifdef MFLOPPY 1231. # ifndef AMIGA 1232. #undef tmp_ramdisk 1233. char tmp_ramdisk[PATHLEN]; 1234. # endif 1235. # endif 1236. #endif 1237. char buf[BUFSZ]; 1238. FILE *fp; 1239. 1240. #ifdef MAC 1241. long nul = 0L ; 1242. Str255 volName ; 1243. /* 1244. * We should try to get this data from a rsrc, in the profile file 1245. * the user double-clicked... This data should be saved with the 1246. * save file in the resource fork, AND be saveable in "stationery" 1247. */ 1248. GetVol ( volName , & theDirs . dataRefNum ) ; 1249. GetWDInfo ( theDirs . dataRefNum , & theDirs . dataRefNum , & theDirs . 1250. dataDirID , & nul ) ; 1251. if ( volName [ 0 ] > 31 ) volName [ 0 ] = 31 ; 1252. for ( nul = 1 ; nul <= volName [ 0 ] ; nul ++ ) { 1253. if ( volName [ nul ] == ':' ) { 1254. volName [ nul ] = 0 ; 1255. volName [ 0 ] = nul - 1 ; 1256. break ; 1257. } 1258. } 1259. BlockMove ( volName , theDirs . dataName , 32L ) ; 1260. #endif /* MAC */ 1261. 1262. if (!(fp = fopen_config_file(filename))) return; 1263. 1264. #ifdef MICRO 1265. # ifdef MFLOPPY 1266. # ifndef AMIGA 1267. tmp_ramdisk[0] = 0; 1268. # endif 1269. # endif 1270. tmp_levels[0] = 0; 1271. #endif 1272. 1273. while (fgets(buf, BUFSZ, fp)) { 1274. if (!parse_config_line(fp, buf, tmp_ramdisk, tmp_levels)) { 1275. raw_printf("Bad option line: \"%s\"", buf); 1276. wait_synch(); 1277. } 1278. } 1279. (void) fclose(fp); 1280. 1281. #ifdef MICRO 1282. # ifdef MFLOPPY 1283. Strcpy(permbones, tmp_levels); 1284. # ifndef AMIGA 1285. if (tmp_ramdisk[0]) { 1286. Strcpy(levels, tmp_ramdisk); 1287. if (strcmp(permbones, levels)) /* if not identical */ 1288. ramdisk = TRUE; 1289. } else 1290. # endif /* AMIGA */ 1291. Strcpy(levels, tmp_levels); 1292. 1293. Strcpy(bones, levels); 1294. # endif /* MFLOPPY */ 1295. #endif /* MICRO */ 1296. return; 1297. } 1298. 1299. /* ---------- END CONFIG FILE HANDLING ----------- */ 1300. 1301. /* ---------- BEGIN SCOREBOARD CREATION ----------- */ 1302. 1303. /* verify that we can write to the scoreboard file; if not, try to create one */ 1304. void 1305. check_recordfile(dir) 1306. const char *dir; 1307. #if defined(applec) 1308. # pragma unused(dir) 1309. #endif 1310. { 1311. #if defined(UNIX) || defined(VMS) 1312. int fd = open(RECORD, O_RDWR, 0); 1313. 1314. if (fd >= 0) { 1315. # ifdef VMS /* must be stream-lf to use UPDATE_RECORD_IN_PLACE */ 1316. if (!file_is_stmlf(fd)) { 1317. raw_printf( /* note: assume VMS dir has trailing punct */ 1318. "Warning: scoreboard file %s%s is not in stream_lf format", 1319. (dir ? dir : "[]"), RECORD); 1320. wait_synch(); 1321. } 1322. # endif 1323. (void) close(fd); /* RECORD is accessible */ 1324. } else if ((fd = open(RECORD, O_CREAT|O_RDWR, FCMASK)) >= 0) { 1325. (void) close(fd); /* RECORD newly created */ 1326. # if defined(VMS) && !defined(SECURE) 1327. /* Re-protect RECORD with world:read+write+execute+delete access. */ 1328. (void) chmod(RECORD, FCMASK | 007); /* allow everyone full access */ 1329. # endif /* VMS && !SECURE */ 1330. } else { 1331. raw_printf("Warning: cannot write scoreboard file %s/%s", 1332. (dir ? dir : "."), RECORD); 1333. wait_synch(); 1334. } 1335. #endif /* !UNIX && !VMS */ 1336. 1337. #ifdef MICRO 1338. int fd; 1339. char tmp[PATHLEN]; 1340. 1341. # ifdef OS2_CODEVIEW /* explicit path on opening for OS/2 */ 1342. Strcpy(tmp, dir); 1343. append_slash(tmp); 1344. Strcat(tmp, RECORD); 1345. # else 1346. Strcpy(tmp, RECORD); 1347. # endif 1348. 1349. if ((fd = open(tmp, O_RDWR)) < 0) { 1350. /* try to create empty record */ 1351. # if defined(AZTEC_C) || defined(_DCC) 1352. /* Aztec doesn't use the third argument */ 1353. /* DICE doesn't like it */ 1354. if ((fd = open(tmp, O_CREAT|O_RDWR)) < 0) { 1355. # else 1356. if ((fd = open(tmp, O_CREAT|O_RDWR, S_IREAD|S_IWRITE)) < 0) { 1357. # endif 1358. raw_printf("Warning: cannot write record %s", tmp); 1359. wait_synch(); 1360. } else 1361. (void) close(fd); 1362. } else /* open succeeded */ 1363. (void) close(fd); 1364. #else /* MICRO */ 1365. 1366. # ifdef MAC 1367. int fd = macopen ( RECORD , O_RDWR | O_CREAT , TEXT_TYPE ) ; 1368. 1369. if ( fd < 0 ) { 1370. raw_printf ( "Warning: cannot write %s" , RECORD ) ; 1371. } else { 1372. close ( fd ) ; 1373. } 1374. # endif /* MAC */ 1375. 1376. #endif /* MICRO */ 1377. } 1378. 1379. /* ---------- END SCOREBOARD CREATION ----------- */ 1380. 1381. /*files.c*/