Source:SLASH'EM 0.0.7E7F2/files.c
Revision as of 19:07, 7 March 2008 by Kernigh bot (talk | contribs) (SLASH'EM 0.0.7E7F2/files.c moved to Source:SLASH'EM 0.0.7E7F2/files.c: Robot: moved page)
Below is the full text to files.c from the source code of SLASH'EM 0.0.7E7F2. To link to a particular line, write [[SLASH'EM 0.0.7E7F2/files.c#line123]], for example.
The latest source code for vanilla NetHack is at 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.4 2003/11/14 */ 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. /* WAC for config file */ 9. #include "filename.h" 10. /* needs to be after hack.h. Caused .slashemrc to never be read on UNIX */ 11. 12. #ifdef TTY_GRAPHICS 13. #include "wintty.h" /* more() */ 14. #endif 15. 16. #if defined(GL_GRAPHICS) || defined(SDL_GRAPHICS) 17. #include "winGL.h" /* Sdlgl_parse_options */ 18. #endif 19. 20. #ifdef PROXY_GRAPHICS 21. #include "winproxy.h" /* proxy_config_open() */ 22. #endif 23. 24. #include <ctype.h> 25. 26. #if !defined(MAC) && !defined(O_WRONLY) && !defined(AZTEC_C) 27. #include <fcntl.h> 28. #endif 29. 30. #include <errno.h> 31. #ifdef _MSC_VER /* MSC 6.0 defines errno quite differently */ 32. # if (_MSC_VER >= 600) 33. # define SKIP_ERRNO 34. # endif 35. #else 36. # ifdef NHSTDC 37. # define SKIP_ERRNO 38. # endif 39. #endif 40. #ifndef SKIP_ERRNO 41. # ifdef _DCC 42. const 43. # endif 44. extern int errno; 45. #endif 46. 47. #if defined(UNIX) && defined(QT_GRAPHICS) 48. #include <dirent.h> 49. #endif 50. 51. #if defined(UNIX) || defined(VMS) 52. #include <signal.h> 53. #endif 54. 55. #ifndef NO_SIGNAL 56. #include <signal.h> 57. #endif 58. 59. /* WAC moved to below 60. #include <sys\stat.h> 61. */ 62. 63. /* ALI: For compatibility */ 64. #ifndef FILE_AREAS 65. #define compress(file) compress_area(NULL, file) 66. #define uncompress(file) uncompress_area(NULL, file) 67. #endif 68. 69. #if defined(MSDOS) || defined(OS2) || defined(TOS) || defined(WIN32) 70. # ifndef GNUDOS 71. #include <sys\stat.h> 72. # else 73. #include <sys/stat.h> 74. # endif 75. #endif 76. #ifndef O_BINARY /* used for micros, no-op for others */ 77. # define O_BINARY 0 78. #endif 79. 80. #ifdef PREFIXES_IN_USE 81. #define FQN_NUMBUF 4 82. static char fqn_filename_buffer[FQN_NUMBUF][FQN_MAX_FILENAME]; 83. #endif 84. 85. #if !defined(MFLOPPY) && !defined(VMS) && !defined(WIN32) 86. char bones[] = "bonesnn.xxx"; 87. char lock[PL_NSIZ+14] = "1lock"; /* long enough for uid+name+.99 */ 88. #else 89. # if defined(MFLOPPY) 90. char bones[FILENAMELEN]; /* pathname of bones files */ 91. char lock[FILENAMELEN]; /* pathname of level files */ 92. # endif 93. # if defined(VMS) 94. char bones[] = "bonesnn.xxx;1"; 95. char lock[PL_NSIZ+17] = "1lock"; /* long enough for _uid+name+.99;1 */ 96. # endif 97. # if defined(WIN32) 98. char bones[] = "bonesnn.xxx"; 99. char lock[PL_NSIZ+25]; /* long enough for username+-+name+.99 */ 100. # endif 101. #endif 102. 103. #if defined(UNIX) || defined(__BEOS__) 104. #define SAVESIZE (PL_NSIZ + 13) /* save/99999player.e */ 105. #else 106. # ifdef VMS 107. #define SAVESIZE (PL_NSIZ + 22) /* [.save]<uid>player.e;1 */ 108. # else 109. # if defined(WIN32) 110. #define SAVESIZE (PL_NSIZ + 40) /* username-player.NetHack-saved-game */ 111. # else 112. #define SAVESIZE FILENAMELEN /* from macconf.h or pcconf.h */ 113. # endif 114. # endif 115. #endif 116. 117. char SAVEF[SAVESIZE]; /* holds relative path of save file from playground */ 118. #ifdef MICRO 119. char SAVEP[SAVESIZE]; /* holds path of directory for save file */ 120. #endif 121. 122. #ifdef HOLD_LOCKFILE_OPEN 123. struct level_ftrack { 124. int init; 125. int fd; /* file descriptor for level file */ 126. int oflag; /* open flags */ 127. boolean nethack_thinks_it_is_open; /* Does NetHack think it's open? */ 128. } lftrack; 129. # if defined(WIN32) 130. #include <share.h> 131. # endif 132. #endif /*HOLD_LOCKFILE_OPEN*/ 133. 134. #ifdef WIZARD 135. #define WIZKIT_MAX 128 136. static char wizkit[WIZKIT_MAX]; 137. STATIC_DCL FILE *NDECL(fopen_wizkit_file); 138. #endif 139. 140. #ifdef AMIGA 141. extern char PATH[]; /* see sys/amiga/amidos.c */ 142. extern char bbs_id[]; 143. static int lockptr; 144. # ifdef __SASC_60 145. #include <proto/dos.h> 146. # endif 147. 148. #include <libraries/dos.h> 149. extern void FDECL(amii_set_text_font, ( char *, int )); 150. #endif 151. 152. #if defined(WIN32) || defined(MSDOS) 153. static int lockptr; 154. # ifdef MSDOS 155. #define Delay(a) msleep(a) 156. # endif 157. #define Close close 158. #ifndef WIN_CE 159. #define DeleteFile unlink 160. #endif 161. #endif 162. 163. #ifdef MAC 164. # define unlink macunlink 165. #endif 166. 167. #ifdef USER_SOUNDS 168. extern char *sounddir; 169. #endif 170. 171. extern int n_dgns; /* from dungeon.c */ 172. 173. STATIC_DCL char *FDECL(set_bonesfile_name, (char *,d_level*)); 174. STATIC_DCL char *NDECL(set_bonestemp_name); 175. #ifdef COMPRESS 176. STATIC_DCL void FDECL(redirect, (const char *,const char *,const char *, 177. FILE *,BOOLEAN_P)); 178. STATIC_DCL void FDECL(docompress_file, (const char *,const char *,BOOLEAN_P)); 179. #endif 180. #ifndef FILE_AREAS 181. STATIC_DCL char *FDECL(make_lockname, (const char *,char *)); 182. #endif 183. STATIC_DCL FILE *FDECL(fopen_config_file, (const char *)); 184. STATIC_DCL int FDECL(get_uchars, (FILE *,char *,char *,uchar *,BOOLEAN_P,int,const char *)); 185. int FDECL(parse_config_line, (FILE *,char *,char *,char *)); 186. #ifdef NOCWD_ASSUMPTIONS 187. STATIC_DCL void FDECL(adjust_prefix, (char *, int)); 188. #endif 189. #ifdef SELF_RECOVER 190. STATIC_DCL boolean FDECL(copy_bytes, (int, int)); 191. #endif 192. #ifdef HOLD_LOCKFILE_OPEN 193. STATIC_DCL int FDECL(open_levelfile_exclusively, (const char *, int, int)); 194. #endif 195. 196. /* 197. * fname_encode() 198. * 199. * Args: 200. * legal zero-terminated list of acceptable file name characters 201. * quotechar lead-in character used to quote illegal characters as hex digits 202. * s string to encode 203. * callerbuf buffer to house result 204. * bufsz size of callerbuf 205. * 206. * Notes: 207. * The hex digits 0-9 and A-F are always part of the legal set due to 208. * their use in the encoding scheme, even if not explicitly included in 'legal'. 209. * 210. * Sample: 211. * The following call: 212. * (void)fname_encode("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 213. * '%', "This is a % test!", buf, 512); 214. * results in this encoding: 215. * "This%20is%20a%20%25%20test%21" 216. */ 217. char * 218. fname_encode(legal, quotechar, s, callerbuf, bufsz) 219. const char *legal; 220. char quotechar; 221. char *s, *callerbuf; 222. int bufsz; 223. { 224. char *sp, *op; 225. int cnt = 0; 226. static char hexdigits[] = "0123456789ABCDEF"; 227. 228. sp = s; 229. op = callerbuf; 230. *op = '\0'; 231. 232. while (*sp) { 233. /* Do we have room for one more character or encoding? */ 234. if ((bufsz - cnt) <= 4) return callerbuf; 235. 236. if (*sp == quotechar) { 237. (void)sprintf(op, "%c%02X", quotechar, *sp); 238. op += 3; 239. cnt += 3; 240. } else if ((index(legal, *sp) != 0) || (index(hexdigits, *sp) != 0)) { 241. *op++ = *sp; 242. *op = '\0'; 243. cnt++; 244. } else { 245. (void)sprintf(op,"%c%02X", quotechar, *sp); 246. op += 3; 247. cnt += 3; 248. } 249. sp++; 250. } 251. return callerbuf; 252. } 253. 254. /* 255. * fname_decode() 256. * 257. * Args: 258. * quotechar lead-in character used to quote illegal characters as hex digits 259. * s string to decode 260. * callerbuf buffer to house result 261. * bufsz size of callerbuf 262. */ 263. char * 264. fname_decode(quotechar, s, callerbuf, bufsz) 265. char quotechar; 266. char *s, *callerbuf; 267. int bufsz; 268. { 269. char *sp, *op; 270. int k,calc,cnt = 0; 271. static char hexdigits[] = "0123456789ABCDEF"; 272. 273. sp = s; 274. op = callerbuf; 275. *op = '\0'; 276. calc = 0; 277. 278. while (*sp) { 279. /* Do we have room for one more character? */ 280. if ((bufsz - cnt) <= 2) return callerbuf; 281. if (*sp == quotechar) { 282. sp++; 283. for (k=0; k < 16; ++k) if (*sp == hexdigits[k]) break; 284. if (k >= 16) return callerbuf; /* impossible, so bail */ 285. calc = k << 4; 286. sp++; 287. for (k=0; k < 16; ++k) if (*sp == hexdigits[k]) break; 288. if (k >= 16) return callerbuf; /* impossible, so bail */ 289. calc += k; 290. sp++; 291. *op++ = calc; 292. *op = '\0'; 293. } else { 294. *op++ = *sp++; 295. *op = '\0'; 296. } 297. cnt++; 298. } 299. return callerbuf; 300. } 301. 302. #ifndef PREFIXES_IN_USE 303. /*ARGSUSED*/ 304. #endif 305. const char * 306. fqname(basename, whichprefix, buffnum) 307. const char *basename; 308. int whichprefix, buffnum; 309. { 310. #ifndef PREFIXES_IN_USE 311. return basename; 312. #else 313. if (!basename || whichprefix < 0 || whichprefix >= PREFIX_COUNT) 314. return basename; 315. if (!fqn_prefix[whichprefix]) 316. return basename; 317. if (buffnum < 0 || buffnum >= FQN_NUMBUF) { 318. impossible("Invalid fqn_filename_buffer specified: %d", 319. buffnum); 320. buffnum = 0; 321. } 322. if (strlen(fqn_prefix[whichprefix]) + strlen(basename) >= 323. FQN_MAX_FILENAME) { 324. impossible("fqname too long: %s + %s", fqn_prefix[whichprefix], 325. basename); 326. return basename; /* XXX */ 327. } 328. Strcpy(fqn_filename_buffer[buffnum], fqn_prefix[whichprefix]); 329. return strcat(fqn_filename_buffer[buffnum], basename); 330. #endif 331. } 332. 333. /* reasonbuf must be at least BUFSZ, supplied by caller */ 334. /*ARGSUSED*/ 335. int 336. validate_prefix_locations(reasonbuf) 337. char *reasonbuf; 338. { 339. #if defined(NOCWD_ASSUMPTIONS) 340. FILE *fp; 341. const char *filename; 342. int prefcnt, failcount = 0; 343. char panicbuf1[BUFSZ], panicbuf2[BUFSZ], *details; 344. 345. if (reasonbuf) reasonbuf[0] = '\0'; 346. for (prefcnt = 1; prefcnt < PREFIX_COUNT; prefcnt++) { 347. /* don't test writing to configdir or datadir; they're readonly */ 348. if (prefcnt == CONFIGPREFIX || prefcnt == DATAPREFIX) continue; 349. filename = fqname("validate", prefcnt, 3); 350. if ((fp = fopen(filename, "w"))) { 351. fclose(fp); 352. (void) unlink(filename); 353. } else { 354. if (reasonbuf) { 355. if (failcount) Strcat(reasonbuf,", "); 356. Strcat(reasonbuf, fqn_prefix_names[prefcnt]); 357. } 358. /* the paniclog entry gets the value of errno as well */ 359. Sprintf(panicbuf1,"Invalid %s", fqn_prefix_names[prefcnt]); 360. #if defined (NHSTDC) && !defined(NOTSTDC) 361. if (!(details = strerror(errno))) 362. #endif 363. details = ""; 364. Sprintf(panicbuf2,"\"%s\", (%d) %s", 365. fqn_prefix[prefcnt], errno, details); 366. paniclog(panicbuf1, panicbuf2); 367. failcount++; 368. } 369. } 370. if (failcount) 371. return 0; 372. else 373. #endif 374. return 1; 375. } 376. 377. /* 378. * When file areas are in use, fopen_datafile_area is used instead. 379. */ 380. 381. #ifndef FILE_AREA 382. /* fopen a file, with OS-dependent bells and whistles */ 383. /* NOTE: a simpler version of this routine also exists in util/dlb_main.c */ 384. FILE * 385. fopen_datafile(filename, mode, prefix) 386. const char *filename, *mode; 387. int prefix; 388. { 389. FILE *fp; 390. 391. filename = fqname(filename, prefix, prefix == TROUBLEPREFIX ? 3 : 0); 392. #ifdef VMS /* essential to have punctuation, to avoid logical names */ 393. { 394. char tmp[BUFSIZ]; 395. 396. if (!index(filename, '.') && !index(filename, ';')) 397. filename = strcat(strcpy(tmp, filename), ";0"); 398. fp = fopen(filename, mode, "mbc=16"); 399. } 400. #else 401. fp = fopen(filename, mode); 402. #endif 403. return fp; 404. } 405. #endif /* FILE_AREA */ 406. 407. /* ---------- BEGIN LEVEL FILE HANDLING ----------- */ 408. 409. #ifdef MFLOPPY 410. /* Set names for bones[] and lock[] */ 411. void 412. set_lock_and_bones() 413. { 414. if (!ramdisk) { 415. Strcpy(levels, permbones); 416. Strcpy(bones, permbones); 417. } 418. append_slash(permbones); 419. append_slash(levels); 420. #ifdef AMIGA 421. strncat(levels, bbs_id, PATHLEN); 422. #endif 423. append_slash(bones); 424. Strcat(bones, "bonesnn.*"); 425. Strcpy(lock, levels); 426. #ifndef AMIGA 427. Strcat(lock, alllevels); 428. #endif 429. return; 430. } 431. #endif /* MFLOPPY */ 432. 433. 434. /* Construct a file name for a level-type file, which is of the form 435. * something.level (with any old level stripped off). 436. * This assumes there is space on the end of 'file' to append 437. * a two digit number. This is true for 'level' 438. * but be careful if you use it for other things -dgk 439. */ 440. void 441. set_levelfile_name(file, lev) 442. char *file; 443. int lev; 444. { 445. char *tf; 446. 447. tf = rindex(file, '.'); 448. if (!tf) tf = eos(file); 449. Sprintf(tf, ".%d", lev); 450. #ifdef VMS 451. Strcat(tf, ";1"); 452. #endif 453. return; 454. } 455. 456. int 457. create_levelfile(lev, errbuf) 458. int lev; 459. char errbuf[]; 460. { 461. int fd; 462. #ifndef FILE_AREAS 463. const char *fq_lock; 464. #endif 465. 466. if (errbuf) *errbuf = '\0'; 467. set_levelfile_name(lock, lev); 468. #ifndef FILE_AREAS 469. fq_lock = fqname(lock, LEVELPREFIX, 0); 470. #endif 471. 472. #if defined(MICRO) || defined(WIN32) 473. /* Use O_TRUNC to force the file to be shortened if it already 474. * exists and is currently longer. 475. */ 476. # ifdef FILE_AREAS 477. fd = open_area(FILE_AREA_LEVL, lock, 478. O_WRONLY |O_CREAT | O_TRUNC | O_BINARY, FCMASK); 479. # else 480. # ifdef HOLD_LOCKFILE_OPEN 481. if (lev == 0) 482. fd = open_levelfile_exclusively(fq_lock, lev, 483. O_WRONLY |O_CREAT | O_TRUNC | O_BINARY); 484. else 485. # endif 486. fd = open(fq_lock, O_WRONLY |O_CREAT | O_TRUNC | O_BINARY, FCMASK); 487. # endif 488. #else /* MICRO */ 489. # ifdef FILE_AREAS 490. fd = creat_area(FILE_AREA_LEVL, lock, FCMASK); 491. # else 492. # ifdef MAC 493. fd = maccreat(fq_lock, LEVL_TYPE); 494. # else 495. fd = creat(fq_lock, FCMASK); 496. # endif 497. # endif /* FILE_AREAS */ 498. #endif /* MICRO || WIN32 */ 499. 500. if (fd >= 0) 501. level_info[lev].flags |= LFILE_EXISTS; 502. else if (errbuf) /* failure explanation */ 503. Sprintf(errbuf, 504. "Cannot create file \"%s\" for level %d (errno %d).", 505. lock, lev, errno); 506. 507. return fd; 508. } 509. 510. 511. int 512. open_levelfile(lev, errbuf) 513. int lev; 514. char errbuf[]; 515. { 516. int fd; 517. #ifndef FILE_AREAS 518. const char *fq_lock; 519. #endif 520. 521. if (errbuf) *errbuf = '\0'; 522. set_levelfile_name(lock, lev); 523. #ifndef FILE_AREAS 524. fq_lock = fqname(lock, LEVELPREFIX, 0); 525. #endif 526. #ifdef MFLOPPY 527. /* If not currently accessible, swap it in. */ 528. if (level_info[lev].where != ACTIVE) 529. swapin_file(lev); 530. #endif 531. #ifdef FILE_AREAS 532. fd = open_area(FILE_AREA_LEVL, lock, O_RDONLY | O_BINARY, 0); 533. #else 534. # ifdef MAC 535. fd = macopen(fq_lock, O_RDONLY | O_BINARY, LEVL_TYPE); 536. # else 537. # ifdef HOLD_LOCKFILE_OPEN 538. if (lev == 0) 539. fd = open_levelfile_exclusively(fq_lock, lev, O_RDONLY | O_BINARY ); 540. else 541. # endif 542. fd = open(fq_lock, O_RDONLY | O_BINARY, 0); 543. # endif 544. #endif /* FILE_AREAS */ 545. 546. /* for failure, return an explanation that our caller can use; 547. settle for `lock' instead of `fq_lock' because the latter 548. might end up being too big for nethack's BUFSZ */ 549. if (fd < 0 && errbuf) 550. Sprintf(errbuf, 551. "Cannot open file \"%s\" for level %d (errno %d).", 552. lock, lev, errno); 553. 554. return fd; 555. } 556. 557. 558. void 559. delete_levelfile(lev) 560. int lev; 561. { 562. /* 563. * Level 0 might be created by port specific code that doesn't 564. * call create_levfile(), so always assume that it exists. 565. */ 566. if (lev == 0 || (level_info[lev].flags & LFILE_EXISTS)) { 567. set_levelfile_name(lock, lev); 568. #ifdef FILE_AREAS 569. (void) remove_area(FILE_AREA_LEVL, lock, 0); 570. #else 571. # ifdef HOLD_LOCKFILE_OPEN 572. if (lev == 0) really_close(); 573. # endif 574. (void) unlink(fqname(lock, LEVELPREFIX, 0)); 575. #endif 576. level_info[lev].flags &= ~LFILE_EXISTS; 577. } 578. } 579. 580. 581. void 582. clearlocks() 583. { 584. /* [Tom] Watcom..... 585. #if !defined(PC_LOCKING) && defined(MFLOPPY) && !defined(AMIGA) 586. eraseall(levels, alllevels); 587. if (ramdisk) 588. eraseall(permbones, alllevels); 589. #else 590. register int x; 591. 592. # if defined(UNIX) || defined(VMS) 593. (void) signal(SIGHUP, SIG_IGN); 594. # endif */ 595. /* can't access maxledgerno() before dungeons are created -dlc */ 596. int x; 597. for (x = (n_dgns ? maxledgerno() : 0); x >= 0; x--) 598. delete_levelfile(x); /* not all levels need be present */ 599. /* #endif*/ 600. } 601. 602. #ifdef HOLD_LOCKFILE_OPEN 603. STATIC_OVL int 604. open_levelfile_exclusively(name, lev, oflag) 605. const char *name; 606. int lev, oflag; 607. { 608. int reslt, fd; 609. if (!lftrack.init) { 610. lftrack.init = 1; 611. lftrack.fd = -1; 612. } 613. if (lftrack.fd >= 0) { 614. /* check for compatible access */ 615. if (lftrack.oflag == oflag) { 616. fd = lftrack.fd; 617. reslt = lseek(fd, 0L, SEEK_SET); 618. if (reslt == -1L) 619. panic("open_levelfile_exclusively: lseek failed %d", errno); 620. lftrack.nethack_thinks_it_is_open = TRUE; 621. } else { 622. really_close(); 623. fd = sopen(name, oflag,SH_DENYRW, FCMASK); 624. lftrack.fd = fd; 625. lftrack.oflag = oflag; 626. lftrack.nethack_thinks_it_is_open = TRUE; 627. } 628. } else { 629. fd = sopen(name, oflag,SH_DENYRW, FCMASK); 630. lftrack.fd = fd; 631. lftrack.oflag = oflag; 632. if (fd >= 0) 633. lftrack.nethack_thinks_it_is_open = TRUE; 634. } 635. return fd; 636. } 637. 638. void 639. really_close() 640. { 641. int fd = lftrack.fd; 642. lftrack.nethack_thinks_it_is_open = FALSE; 643. lftrack.fd = -1; 644. lftrack.oflag = 0; 645. (void)_close(fd); 646. return; 647. } 648. 649. int 650. close(fd) 651. int fd; 652. { 653. if (lftrack.fd == fd) { 654. really_close(); /* close it, but reopen it to hold it */ 655. fd = open_levelfile(0, (char *)0); 656. lftrack.nethack_thinks_it_is_open = FALSE; 657. return 0; 658. } 659. return _close(fd); 660. } 661. #endif 662. 663. /* ---------- END LEVEL FILE HANDLING ----------- */ 664. 665. 666. /* ---------- BEGIN BONES FILE HANDLING ----------- */ 667. 668. /* set up "file" to be file name for retrieving bones, and return a 669. * bonesid to be read/written in the bones file. 670. */ 671. STATIC_OVL char * 672. set_bonesfile_name(file, lev) 673. char *file; 674. d_level *lev; 675. { 676. s_level *sptr; 677. char *dptr; 678. 679. Sprintf(file, "bon%c%s", dungeons[lev->dnum].boneid, 680. In_quest(lev) ? urole.filecode : "0"); 681. dptr = eos(file); 682. if ((sptr = Is_special(lev)) != 0) 683. Sprintf(dptr, ".%c", sptr->boneid); 684. else 685. Sprintf(dptr, ".%d", lev->dlevel); 686. #ifdef VMS 687. Strcat(dptr, ";1"); 688. #endif 689. return(dptr-2); 690. } 691. 692. /* set up temporary file name for writing bones, to avoid another game's 693. * trying to read from an uncompleted bones file. we want an uncontentious 694. * name, so use one in the namespace reserved for this game's level files. 695. * (we are not reading or writing level files while writing bones files, so 696. * the same array may be used instead of copying.) 697. */ 698. STATIC_OVL char * 699. set_bonestemp_name() 700. { 701. char *tf; 702. 703. tf = rindex(lock, '.'); 704. if (!tf) tf = eos(lock); 705. Sprintf(tf, ".bn"); 706. #ifdef VMS 707. Strcat(tf, ";1"); 708. #endif 709. return lock; 710. } 711. 712. int 713. create_bonesfile(lev, bonesid, errbuf) 714. d_level *lev; 715. char **bonesid; 716. char errbuf[]; 717. { 718. const char *file; 719. int fd; 720. 721. if (errbuf) *errbuf = '\0'; 722. *bonesid = set_bonesfile_name(bones, lev); 723. file = set_bonestemp_name(); 724. #ifndef FILE_AREAS 725. file = fqname(file, BONESPREFIX, 0); 726. #endif 727. 728. #if defined(MICRO) || defined(WIN32) 729. /* Use O_TRUNC to force the file to be shortened if it already 730. * exists and is currently longer. 731. */ 732. # ifdef FILE_AREAS 733. fd = open_area(FILE_AREA_BONES, file, 734. O_WRONLY |O_CREAT | O_TRUNC | O_BINARY, FCMASK); 735. # else 736. fd = open(file, O_WRONLY |O_CREAT | O_TRUNC | O_BINARY, FCMASK); 737. # endif 738. #else 739. # ifdef FILE_AREAS 740. fd = creat_area(FILE_AREA_BONES, file, FCMASK); 741. # else 742. # ifdef MAC 743. fd = maccreat(file, BONE_TYPE); 744. # else 745. fd = creat(file, FCMASK); 746. # endif 747. # endif /* FILE_AREAS */ 748. #endif 749. if (fd < 0 && errbuf) /* failure explanation */ 750. Sprintf(errbuf, 751. "Cannot create bones \"%s\", id %s (errno %d).", 752. lock, *bonesid, errno); 753. 754. # if defined(VMS) && !defined(SECURE) 755. /* 756. Re-protect bones file with world:read+write+execute+delete access. 757. umask() doesn't seem very reliable; also, vaxcrtl won't let us set 758. delete access without write access, which is what's really wanted. 759. Can't simply create it with the desired protection because creat 760. ANDs the mask with the user's default protection, which usually 761. denies some or all access to world. 762. */ 763. # ifndef FILE_AREAS 764. (void) chmod(file, FCMASK | 007); /* allow other users full access */ 765. # else 766. (void) chmod_area(FILE_AREA_BONES, file, FCMASK | 007); 767. # endif 768. # endif /* VMS && !SECURE */ 769. 770. return fd; 771. } 772. 773. #ifdef MFLOPPY 774. /* remove partial bonesfile in process of creation */ 775. void 776. cancel_bonesfile() 777. { 778. const char *tempname; 779. 780. tempname = set_bonestemp_name(); 781. # ifdef FILE_AREAS 782. (void) remove_area(FILE_AREA_BONES, tempname); 783. # else 784. tempname = fqname(tempname, BONESPREFIX, 0); 785. (void) unlink(tempname); 786. # endif 787. } 788. #endif /* MFLOPPY */ 789. 790. /* move completed bones file to proper name */ 791. void 792. commit_bonesfile(lev) 793. d_level *lev; 794. { 795. const char *fq_bones, *tempname; 796. int ret; 797. 798. (void) set_bonesfile_name(bones, lev); 799. #ifndef FILE_AREAS 800. fq_bones = fqname(bones, BONESPREFIX, 0); 801. #endif 802. tempname = set_bonestemp_name(); 803. #ifndef FILE_AREAS 804. tempname = fqname(tempname, BONESPREFIX, 1); 805. #endif 806. 807. #ifdef FILE_AREAS 808. ret = rename_area(FILE_AREA_BONES, tempname, bones); 809. #else 810. # if (defined(SYSV) && !defined(SVR4)) || defined(GENIX) 811. /* old SYSVs don't have rename. Some SVR3's may, but since they 812. * also have link/unlink, it doesn't matter. :-) 813. */ 814. (void) unlink(fq_bones); 815. ret = link(tempname, fq_bones); 816. ret += unlink(tempname); 817. # else 818. ret = rename(tempname, fq_bones); 819. # endif 820. #endif /* FILE_AREAS */ 821. #ifdef WIZARD 822. if (wizard && ret != 0) 823. #ifdef FILE_AREAS 824. pline("couldn't rename %s to %s.", tempname, bones); 825. #else 826. pline("couldn't rename %s to %s.", tempname, fq_bones); 827. #endif 828. #endif 829. } 830. 831. 832. int 833. open_bonesfile(lev, bonesid) 834. d_level *lev; 835. char **bonesid; 836. { 837. const char *fq_bones; 838. int fd; 839. 840. *bonesid = set_bonesfile_name(bones, lev); 841. #ifdef FILE_AREAS 842. uncompress_area(FILE_AREA_BONES, bones); /* no effect if nonexistent */ 843. fd = open_area(FILE_AREA_BONES, bones, O_RDONLY | O_BINARY, 0); 844. #else 845. fq_bones = fqname(bones, BONESPREFIX, 0); 846. uncompress(fq_bones); /* no effect if nonexistent */ 847. # ifdef MAC 848. fd = macopen(fq_bones, O_RDONLY | O_BINARY, BONE_TYPE); 849. # else 850. fd = open(fq_bones, O_RDONLY | O_BINARY, 0); 851. # endif 852. #endif /* FILE_AREAS */ 853. return fd; 854. } 855. 856. 857. int 858. delete_bonesfile(lev) 859. d_level *lev; 860. { 861. (void) set_bonesfile_name(bones, lev); 862. #ifdef FILE_AREAS 863. return !(remove_area(FILE_AREA_BONES, bones) < 0); 864. #else 865. return !(unlink(fqname(bones, BONESPREFIX, 0)) < 0); 866. #endif 867. } 868. 869. 870. /* assume we're compressing the recently read or created bonesfile, so the 871. * file name is already set properly */ 872. void 873. compress_bonesfile() 874. { 875. #ifdef FILE_AREAS 876. compress_area(FILE_AREA_BONES, bones); 877. #else 878. compress(fqname(bones, BONESPREFIX, 0)); 879. #endif 880. } 881. 882. /* ---------- END BONES FILE HANDLING ----------- */ 883. 884. 885. /* ---------- BEGIN SAVE FILE HANDLING ----------- */ 886. 887. /* set savefile name in OS-dependent manner from pre-existing plname, 888. * avoiding troublesome characters */ 889. void 890. set_savefile_name() 891. { 892. #if defined(WIN32) 893. char fnamebuf[BUFSZ], encodedfnamebuf[BUFSZ]; 894. #endif 895. #ifdef VMS 896. #ifndef FILE_AREAS 897. Sprintf(SAVEF, "[.save]%d%s", getuid(), plname); 898. regularize(SAVEF+7); 899. #else 900. Sprintf(SAVEF, "%d%s", getuid(), plname); 901. regularize(SAVEF); 902. #endif 903. Strcat(SAVEF, ";1"); 904. #else 905. # if defined(MICRO) 906. Strcpy(SAVEF, SAVEP); 907. # ifdef AMIGA 908. strncat(SAVEF, bbs_id, PATHLEN); 909. # endif 910. { 911. int i = strlen(SAVEP); 912. # ifdef AMIGA 913. /* plname has to share space with SAVEP and ".sav" */ 914. (void)strncat(SAVEF, plname, FILENAME - i - 4); 915. # else 916. (void)strncat(SAVEF, plname, 8); 917. # endif 918. regularize(SAVEF+i); 919. } 920. Strcat(SAVEF, ".sav"); 921. # else 922. # ifndef FILE_AREAS 923. # if defined(WIN32) 924. /* Obtain the name of the logged on user and incorporate 925. * it into the name. */ 926. Sprintf(fnamebuf, "%s-%s", get_username(0), plname); 927. (void)fname_encode("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-.", 928. '%', fnamebuf, encodedfnamebuf, BUFSZ); 929. Sprintf(SAVEF, "%s.NetHack-saved-game", encodedfnamebuf); 930. # else 931. Sprintf(SAVEF, "save/%d%s", (int)getuid(), plname); 932. regularize(SAVEF+5); /* avoid . or / in name */ 933. # endif /* WIN32 */ 934. # else 935. Sprintf(SAVEF, "%d%s", (int)getuid(), plname); 936. regularize(SAVEF); /* avoid . or / in name */ 937. # endif 938. # endif /* MICRO */ 939. #endif /* VMS */ 940. } 941. 942. #ifdef INSURANCE 943. void 944. save_savefile_name(fd) 945. int fd; 946. { 947. (void) write(fd, (genericptr_t) SAVEF, sizeof(SAVEF)); 948. } 949. #endif 950. 951. 952. #if defined(WIZARD) && !defined(MICRO) 953. /* change pre-existing savefile name to indicate an error savefile */ 954. void 955. set_error_savefile() 956. { 957. # ifdef VMS 958. { 959. char *semi_colon = rindex(SAVEF, ';'); 960. if (semi_colon) *semi_colon = '\0'; 961. } 962. Strcat(SAVEF, ".e;1"); 963. # else 964. # ifdef MAC 965. Strcat(SAVEF, "-e"); 966. # else 967. Strcat(SAVEF, ".e"); 968. # endif 969. # endif 970. } 971. #endif 972. 973. 974. /* create save file, overwriting one if it already exists */ 975. int 976. create_savefile() 977. { 978. #ifndef FILE_AREAS 979. const char *fq_save; 980. #endif 981. int fd; 982. 983. #ifdef FILE_AREAS 984. # ifdef MICRO 985. fd = open_area(FILE_AREA_SAVE, SAVEF, 986. O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK); 987. # else 988. fd = creat_area(FILE_AREA_SAVE, SAVEF, FCMASK); 989. # endif 990. #else /* FILE_AREAS */ 991. fq_save = fqname(SAVEF, SAVEPREFIX, 0); 992. # if defined(MICRO) || defined(WIN32) 993. fd = open(fq_save, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK); 994. # else 995. # ifdef MAC 996. fd = maccreat(fq_save, SAVE_TYPE); 997. # else 998. fd = creat(fq_save, FCMASK); 999. # endif 1000. # endif /* MICRO */ 1001. #endif /* FILE_AREAS */ 1002. 1003. #if defined(VMS) && !defined(SECURE) 1004. /* 1005. Make sure the save file is owned by the current process. That's 1006. the default for non-privileged users, but for priv'd users the 1007. file will be owned by the directory's owner instead of the user. 1008. */ 1009. # ifdef getuid /*(see vmsunix.c)*/ 1010. # undef getuid 1011. # endif 1012. # ifdef FILE_AREAS 1013. (void) chown_area(FILE_AREA_SAVE, SAVEF, getuid(), getgid()); 1014. # else 1015. (void) chown(fq_save, getuid(), getgid()); 1016. # endif 1017. #endif /* VMS && !SECURE */ 1018. 1019. return fd; 1020. } 1021. 1022. 1023. /* open savefile for reading */ 1024. int 1025. open_savefile() 1026. { 1027. int fd; 1028. 1029. #ifdef FILE_AREAS 1030. fd = open_area(FILE_AREA_SAVE, SAVEF, O_RDONLY | O_BINARY, 0); 1031. #else 1032. const char *fq_save; 1033. fq_save = fqname(SAVEF, SAVEPREFIX, 0); 1034. # ifdef MAC 1035. fd = macopen(fq_save, O_RDONLY | O_BINARY, SAVE_TYPE); 1036. # else 1037. fd = open(fq_save, O_RDONLY | O_BINARY, 0); 1038. # endif 1039. #endif /* FILE_AREAS */ 1040. return fd; 1041. } 1042. 1043. 1044. /* delete savefile */ 1045. int 1046. delete_savefile() 1047. { 1048. /*WAC OK...this is probably a contreversial addition. It's an option tho*/ 1049. #ifdef KEEP_SAVE 1050. /* Wizard mode already has prompt*/ 1051. if (flags.keep_savefile && !wizard) { 1052. # ifdef AMIGA /*WAC If Amiga is ever supported*/ 1053. preserve_icon(); 1054. # endif 1055. return 1; /*Should this return 0?*/ 1056. } 1057. #endif 1058. 1059. #ifdef FILE_AREAS 1060. (void) remove_area(FILE_AREA_SAVE, SAVEF); 1061. #else 1062. (void) unlink(fqname(SAVEF, SAVEPREFIX, 0)); 1063. #endif 1064. return 0; /* for restore_saved_game() (ex-xxxmain.c) test */ 1065. } 1066. 1067. 1068. /* try to open up a save file and prepare to restore it */ 1069. int 1070. restore_saved_game() 1071. { 1072. #ifndef FILE_AREAS 1073. const char *fq_save; 1074. #endif 1075. int fd; 1076. 1077. set_savefile_name(); 1078. #ifdef MFLOPPY 1079. if (!saveDiskPrompt(1)) 1080. return -1; 1081. #endif /* MFLOPPY */ 1082. #ifndef FILE_AREAS 1083. fq_save = fqname(SAVEF, SAVEPREFIX, 0); 1084. 1085. uncompress(fq_save); 1086. #else 1087. uncompress_area(FILE_AREA_SAVE, SAVEF); 1088. #endif 1089. if ((fd = open_savefile()) < 0) return fd; 1090. 1091. #ifndef FILE_AREAS 1092. if (!uptodate(fd, fq_save)) { 1093. #else 1094. if (!uptodate(fd, SAVEF)) { 1095. #endif 1096. (void) close(fd), fd = -1; 1097. (void) delete_savefile(); 1098. } 1099. return fd; 1100. } 1101. 1102. #if defined(UNIX) && defined(QT_GRAPHICS) 1103. /*ARGSUSED*/ 1104. static char* 1105. plname_from_file(filename) 1106. const char* filename; 1107. { 1108. #ifdef STORE_PLNAME_IN_FILE 1109. int fd; 1110. char* result = 0; 1111. 1112. Strcpy(SAVEF,filename); 1113. #ifdef COMPRESS_EXTENSION 1114. SAVEF[strlen(SAVEF)-strlen(COMPRESS_EXTENSION)] = '\0'; 1115. #endif 1116. uncompress(SAVEF); 1117. if ((fd = open_savefile()) >= 0) { 1118. if (uptodate(fd, filename)) { 1119. char tplname[PL_NSIZ]; 1120. mread(fd, (genericptr_t) tplname, PL_NSIZ); 1121. result = strdup(tplname); 1122. } 1123. (void) close(fd); 1124. } 1125. compress(SAVEF); 1126. 1127. return result; 1128. #else 1129. # if defined(UNIX) && defined(QT_GRAPHICS) 1130. /* Name not stored in save file, so we have to extract it from 1131. the filename, which loses information 1132. (eg. "/", "_", and "." characters are lost. */ 1133. int k; 1134. int uid; 1135. char name[64]; /* more than PL_NSIZ */ 1136. #ifdef COMPRESS_EXTENSION 1137. #define EXTSTR COMPRESS_EXTENSION 1138. #else 1139. #define EXTSTR "" 1140. #endif 1141. if ( sscanf( filename, "%*[^/]/%d%63[^.]" EXTSTR, &uid, name ) == 2 ) { 1142. #undef EXTSTR 1143. /* "_" most likely means " ", which certainly looks nicer */ 1144. for (k=0; name[k]; k++) 1145. if ( name[k]=='_' ) 1146. name[k]=' '; 1147. return strdup(name); 1148. } else 1149. # endif 1150. { 1151. return 0; 1152. } 1153. #endif 1154. } 1155. #endif /* defined(UNIX) && defined(QT_GRAPHICS) */ 1156. 1157. char** 1158. get_saved_games() 1159. { 1160. #if defined(UNIX) && defined(QT_GRAPHICS) 1161. int myuid=getuid(); 1162. struct dirent **namelist; 1163. int n = scandir("save", &namelist, 0, alphasort);; 1164. if ( n > 0 ) { 1165. int i,j=0; 1166. char** result = (char**)alloc((n+1)*sizeof(char*)); /* at most */ 1167. for (i=0; i<n; i++) { 1168. int uid; 1169. char name[64]; /* more than PL_NSIZ */ 1170. if ( sscanf( namelist[i]->d_name, "%d%63s", &uid, name ) == 2 ) { 1171. if ( uid == myuid ) { 1172. char filename[BUFSZ]; 1173. char* r; 1174. Sprintf(filename,"save/%d%s",uid,name); 1175. r = plname_from_file(filename); 1176. if ( r ) 1177. result[j++] = r; 1178. } 1179. } 1180. } 1181. result[j++] = 0; 1182. return result; 1183. } else 1184. #endif 1185. { 1186. return 0; 1187. } 1188. } 1189. 1190. void 1191. free_saved_games(saved) 1192. char** saved; 1193. { 1194. if ( saved ) { 1195. int i=0; 1196. while (saved[i]) free((genericptr_t)saved[i++]); 1197. free((genericptr_t)saved); 1198. } 1199. } 1200. 1201. 1202. /* ---------- END SAVE FILE HANDLING ----------- */ 1203. 1204. 1205. /* ---------- BEGIN FILE COMPRESSION HANDLING ----------- */ 1206. 1207. #ifdef COMPRESS 1208. 1209. STATIC_OVL void 1210. redirect(filearea, filename, mode, stream, uncomp) 1211. const char *filearea, *filename, *mode; 1212. FILE *stream; 1213. boolean uncomp; 1214. { 1215. #ifndef FILE_AREAS 1216. if (freopen(filename, mode, stream) == (FILE *)0) { 1217. #else 1218. if (freopen_area(filearea, filename, mode, stream) == (FILE *)0) { 1219. #endif 1220. (void) fprintf(stderr, "redirect of %s for %scompress failed\n", 1221. filename, uncomp ? "un" : ""); 1222. terminate(EXIT_FAILURE); 1223. } 1224. } 1225. 1226. /* 1227. * using system() is simpler, but opens up security holes and causes 1228. * problems on at least Interactive UNIX 3.0.1 (SVR3.2), where any 1229. * setuid is renounced by /bin/sh, so the files cannot be accessed. 1230. * 1231. * cf. child() in unixunix.c. 1232. */ 1233. STATIC_OVL void 1234. docompress_file(filearea, filename, uncomp) 1235. const char *filearea, *filename; 1236. boolean uncomp; 1237. { 1238. char cfn[80]; 1239. FILE *cf; 1240. const char *args[10]; 1241. # ifdef COMPRESS_OPTIONS 1242. char opts[80]; 1243. # endif 1244. int i = 0; 1245. int f; 1246. # ifdef TTY_GRAPHICS 1247. boolean istty = !strncmpi(windowprocs.name, "tty", 3); 1248. # endif 1249. 1250. Strcpy(cfn, filename); 1251. # ifdef COMPRESS_EXTENSION 1252. Strcat(cfn, COMPRESS_EXTENSION); 1253. # endif 1254. /* when compressing, we know the file exists */ 1255. if (uncomp) { 1256. if ((cf = fopen_datafile_area(filearea, cfn, RDBMODE, FALSE)) == 1257. (FILE *)0) 1258. return; 1259. (void) fclose(cf); 1260. } 1261. 1262. args[0] = COMPRESS; 1263. if (uncomp) args[++i] = "-d"; /* uncompress */ 1264. # ifdef COMPRESS_OPTIONS 1265. { 1266. /* we can't guarantee there's only one additional option, sigh */ 1267. char *opt; 1268. boolean inword = FALSE; 1269. 1270. Strcpy(opts, COMPRESS_OPTIONS); 1271. opt = opts; 1272. while (*opt) { 1273. if ((*opt == ' ') || (*opt == '\t')) { 1274. if (inword) { 1275. *opt = '\0'; 1276. inword = FALSE; 1277. } 1278. } else if (!inword) { 1279. args[++i] = opt; 1280. inword = TRUE; 1281. } 1282. opt++; 1283. } 1284. } 1285. # endif 1286. args[++i] = (char *)0; 1287. 1288. # ifdef TTY_GRAPHICS 1289. /* If we don't do this and we are right after a y/n question *and* 1290. * there is an error message from the compression, the 'y' or 'n' can 1291. * end up being displayed after the error message. 1292. */ 1293. if (istty) 1294. mark_synch(); 1295. # endif 1296. f = fork(); 1297. if (f == 0) { /* child */ 1298. # ifdef TTY_GRAPHICS 1299. /* any error messages from the compression must come out after 1300. * the first line, because the more() to let the user read 1301. * them will have to clear the first line. This should be 1302. * invisible if there are no error messages. 1303. */ 1304. if (istty) 1305. raw_print(""); 1306. # endif 1307. /* run compressor without privileges, in case other programs 1308. * have surprises along the line of gzip once taking filenames 1309. * in GZIP. 1310. */ 1311. /* assume all compressors will compress stdin to stdout 1312. * without explicit filenames. this is true of at least 1313. * compress and gzip, those mentioned in config.h. 1314. */ 1315. if (uncomp) { 1316. redirect(filearea, cfn, RDBMODE, stdin, uncomp); 1317. redirect(filearea, filename, WRBMODE, stdout, uncomp); 1318. } else { 1319. redirect(filearea, filename, RDBMODE, stdin, uncomp); 1320. redirect(filearea, cfn, WRBMODE, stdout, uncomp); 1321. } 1322. (void) setgid(getgid()); 1323. (void) setuid(getuid()); 1324. (void) execv(args[0], (char *const *) args); 1325. perror((char *)0); 1326. (void) fprintf(stderr, "Exec to %scompress %s failed.\n", 1327. uncomp ? "un" : "", filename); 1328. terminate(EXIT_FAILURE); 1329. } else if (f == -1) { 1330. perror((char *)0); 1331. pline("Fork to %scompress %s failed.", 1332. uncomp ? "un" : "", filename); 1333. return; 1334. } 1335. # ifndef NO_SIGNAL 1336. (void) signal(SIGINT, SIG_IGN); 1337. (void) signal(SIGQUIT, SIG_IGN); 1338. # endif 1339. (void) wait((int *)&i); 1340. # ifndef NO_SIGNAL 1341. (void) signal(SIGINT, (SIG_RET_TYPE) done1); 1342. # endif 1343. # ifdef WIZARD 1344. if (wizard) (void) signal(SIGQUIT, SIG_DFL); 1345. # endif 1346. if (i == 0) { 1347. /* (un)compress succeeded: remove file left behind */ 1348. if (uncomp) 1349. #ifndef FILE_AREAS 1350. (void) unlink(cfn); 1351. #else 1352. (void) remove_area(filearea, cfn); 1353. #endif 1354. else 1355. #ifndef FILE_AREAS 1356. (void) unlink(filename); 1357. #else 1358. (void) remove_area(filearea, filename); 1359. #endif 1360. } else { 1361. /* (un)compress failed; remove the new, bad file */ 1362. if (uncomp) { 1363. raw_printf("Unable to uncompress %s", filename); 1364. (void) unlink(filename); 1365. } else { 1366. /* no message needed for compress case; life will go on */ 1367. (void) unlink(cfn); 1368. } 1369. #ifdef TTY_GRAPHICS 1370. /* Give them a chance to read any error messages from the 1371. * compression--these would go to stdout or stderr and would get 1372. * overwritten only in tty mode. It's still ugly, since the 1373. * messages are being written on top of the screen, but at least 1374. * the user can read them. 1375. */ 1376. if (istty) 1377. { 1378. clear_nhwindow(WIN_MESSAGE); 1379. more(); 1380. /* No way to know if this is feasible */ 1381. /* doredraw(); */ 1382. } 1383. #endif 1384. } 1385. } 1386. #endif /* COMPRESS */ 1387. 1388. /* compress file */ 1389. void 1390. compress_area(filearea, filename) 1391. const char *filearea, *filename; 1392. { 1393. #ifndef COMPRESS 1394. #if defined(MAC_MPW) || defined(__MWERKS__) 1395. # pragma unused(filename) 1396. #endif 1397. #else 1398. docompress_file(filearea, filename, FALSE); 1399. #endif 1400. } 1401. 1402. 1403. /* uncompress file if it exists */ 1404. void 1405. uncompress_area(filearea, filename) 1406. const char *filearea, *filename; 1407. { 1408. #ifndef COMPRESS 1409. #if defined(MAC_MPW) || defined(__MWERKS__) 1410. # pragma unused(filename) 1411. #endif 1412. #else 1413. docompress_file(filearea, filename, TRUE); 1414. #endif 1415. } 1416. 1417. /* ---------- END FILE COMPRESSION HANDLING ----------- */ 1418. 1419. 1420. /* 1421. * When file areas are in use, (un)lock_file_area are used instead. 1422. */ 1423. 1424. #ifndef FILE_AREAS 1425. 1426. /* ---------- BEGIN FILE LOCKING HANDLING ----------- */ 1427. 1428. static int nesting = 0; 1429. 1430. #ifdef NO_FILE_LINKS /* implies UNIX */ 1431. static int lockfd; /* for lock_file() to pass to unlock_file() */ 1432. #endif 1433. 1434. #define HUP if (!program_state.done_hup) 1435. 1436. STATIC_OVL char * 1437. make_lockname(filename, lockname) 1438. const char *filename; 1439. char *lockname; 1440. { 1441. #if defined(MAC_MPW) || defined(__MWERKS__) 1442. # pragma unused(filename,lockname) 1443. return (char*)0; 1444. #else 1445. # if defined(UNIX) || defined(VMS) || defined(AMIGA) || defined(WIN32) || defined(MSDOS) 1446. # ifdef NO_FILE_LINKS 1447. Strcpy(lockname, LOCKDIR); 1448. Strcat(lockname, "/"); 1449. Strcat(lockname, filename); 1450. # else 1451. Strcpy(lockname, filename); 1452. # endif 1453. # ifdef VMS 1454. { 1455. char *semi_colon = rindex(lockname, ';'); 1456. if (semi_colon) *semi_colon = '\0'; 1457. } 1458. Strcat(lockname, ".lock;1"); 1459. # else 1460. Strcat(lockname, "_lock"); 1461. # endif 1462. return lockname; 1463. # else 1464. lockname[0] = '\0'; 1465. return (char*)0; 1466. # endif /* UNIX || VMS || AMIGA || WIN32 || MSDOS */ 1467. #endif 1468. } 1469. 1470. 1471. /* lock a file */ 1472. boolean 1473. lock_file(filename, whichprefix, retryct) 1474. const char *filename; 1475. int whichprefix; 1476. int retryct; 1477. { 1478. #if defined(MAC_MPW) || defined(__MWERKS__) 1479. # pragma unused(filename, retryct) 1480. #endif 1481. char locknambuf[BUFSZ]; 1482. const char *lockname; 1483. 1484. nesting++; 1485. if (nesting > 1) { 1486. impossible("TRIED TO NEST LOCKS"); 1487. return TRUE; 1488. } 1489. 1490. lockname = make_lockname(filename, locknambuf); 1491. filename = fqname(filename, whichprefix, 0); 1492. #ifndef NO_FILE_LINKS /* LOCKDIR should be subsumed by LOCKPREFIX */ 1493. lockname = fqname(lockname, LOCKPREFIX, 2); 1494. #endif 1495. 1496. #if defined(UNIX) || defined(VMS) 1497. # ifdef NO_FILE_LINKS 1498. while ((lockfd = open(lockname, O_RDWR|O_CREAT|O_EXCL, 0666)) == -1) { 1499. # else 1500. while (link(filename, lockname) == -1) { 1501. # endif 1502. register int errnosv = errno; 1503. 1504. switch (errnosv) { /* George Barbanis */ 1505. case EEXIST: 1506. if (retryct--) { 1507. HUP raw_printf( 1508. "Waiting for access to %s. (%d retries left).", 1509. filename, retryct); 1510. # if defined(SYSV) || defined(ULTRIX) || defined(VMS) 1511. (void) 1512. # endif 1513. sleep(1); 1514. } else { 1515. HUP (void) raw_print("I give up. Sorry."); 1516. HUP raw_printf("Perhaps there is an old %s around?", 1517. lockname); 1518. nesting--; 1519. return FALSE; 1520. } 1521. 1522. break; 1523. case ENOENT: 1524. HUP raw_printf("Can't find file %s to lock!", filename); 1525. nesting--; 1526. return FALSE; 1527. case EACCES: 1528. HUP raw_printf("No write permission to lock %s!", filename); 1529. nesting--; 1530. return FALSE; 1531. # ifdef VMS /* c__translate(vmsfiles.c) */ 1532. case EPERM: 1533. /* could be misleading, but usually right */ 1534. HUP raw_printf("Can't lock %s due to directory protection.", 1535. filename); 1536. nesting--; 1537. return FALSE; 1538. # endif 1539. default: 1540. HUP perror(lockname); 1541. HUP raw_printf( 1542. "Cannot lock %s for unknown reason (%d).", 1543. filename, errnosv); 1544. nesting--; 1545. return FALSE; 1546. } 1547. 1548. } 1549. #endif /* UNIX || VMS */ 1550. 1551. #if defined(AMIGA) || defined(WIN32) || defined(MSDOS) 1552. # ifdef AMIGA 1553. #define OPENFAILURE(fd) (!fd) 1554. lockptr = 0; 1555. # else 1556. #define OPENFAILURE(fd) (fd < 0) 1557. lockptr = -1; 1558. # endif 1559. while (--retryct && OPENFAILURE(lockptr)) { 1560. # if defined(WIN32) && !defined(WIN_CE) 1561. lockptr = sopen(lockname, O_RDWR|O_CREAT, SH_DENYRW, S_IWRITE); 1562. # else 1563. (void)DeleteFile(lockname); /* in case dead process was here first */ 1564. # ifdef AMIGA 1565. lockptr = Open(lockname,MODE_NEWFILE); 1566. # else 1567. lockptr = open(lockname, O_RDWR|O_CREAT|O_EXCL, S_IWRITE); 1568. # endif 1569. # endif 1570. if (OPENFAILURE(lockptr)) { 1571. raw_printf("Waiting for access to %s. (%d retries left).", 1572. filename, retryct); 1573. Delay(50); 1574. } 1575. } 1576. if (!retryct) { 1577. raw_printf("I give up. Sorry."); 1578. nesting--; 1579. return FALSE; 1580. } 1581. #endif /* AMIGA || WIN32 || MSDOS */ 1582. return TRUE; 1583. } 1584. 1585. 1586. #ifdef VMS /* for unlock_file, use the unlink() routine in vmsunix.c */ 1587. # ifdef unlink 1588. # undef unlink 1589. # endif 1590. # define unlink(foo) vms_unlink(foo) 1591. #endif 1592. 1593. /* unlock file, which must be currently locked by lock_file */ 1594. void 1595. unlock_file(filename) 1596. const char *filename; 1597. { 1598. char locknambuf[BUFSZ]; 1599. const char *lockname; 1600. 1601. if (nesting == 1) { 1602. lockname = make_lockname(filename, locknambuf); 1603. #ifndef NO_FILE_LINKS /* LOCKDIR should be subsumed by LOCKPREFIX */ 1604. lockname = fqname(lockname, LOCKPREFIX, 2); 1605. #endif 1606. 1607. #if defined(UNIX) || defined(VMS) 1608. if (unlink(lockname) < 0) 1609. HUP raw_printf("Can't unlink %s.", lockname); 1610. # ifdef NO_FILE_LINKS 1611. (void) close(lockfd); 1612. # endif 1613. 1614. #endif /* UNIX || VMS */ 1615. 1616. #if defined(AMIGA) || defined(WIN32) || defined(MSDOS) 1617. if (lockptr) Close(lockptr); 1618. DeleteFile(lockname); 1619. lockptr = 0; 1620. #endif /* AMIGA || WIN32 || MSDOS */ 1621. } 1622. 1623. nesting--; 1624. } 1625. 1626. /* ---------- END FILE LOCKING HANDLING ----------- */ 1627. 1628. #endif /* FILE_AREAS */ 1629. 1630. /* ---------- BEGIN CONFIG FILE HANDLING ----------- */ 1631. 1632. const char *configfile = 1633. NH_CONFIG_FILE; 1634. /* WAC This stuff is in filename.h now 1635. #ifdef UNIX 1636. ".nethackrc"; 1637. #else 1638. # if defined(MAC) || defined(__BEOS__) 1639. "NetHack Defaults"; 1640. # if defined(MSDOS) || defined(WIN32) 1641. "defaults.nh"; 1642. # else 1643. "NetHack.cnf"; 1644. # endif 1645. # endif 1646. #endif 1647. */ 1648. 1649. 1650. #ifdef MSDOS 1651. /* conflict with speed-dial under windows 1652. * for XXX.cnf file so support of NetHack.cnf 1653. * is for backward compatibility only. 1654. * Preferred name (and first tried) is now defaults.nh but 1655. * the game will try the old name if there 1656. * is no defaults.nh. 1657. */ 1658. const char *backward_compat_configfile = "nethack.cnf"; 1659. #endif 1660. 1661. #ifndef MFLOPPY 1662. #define fopenp fopen 1663. #endif 1664. 1665. STATIC_OVL FILE * 1666. fopen_config_file(filename) 1667. const char *filename; 1668. { 1669. FILE *fp; 1670. #if defined(UNIX) || defined(VMS) 1671. char tmp_config[BUFSZ]; 1672. char *envp; 1673. #endif 1674. 1675. /* "filename" is an environment variable, so it should hang around */ 1676. /* if set, it is expected to be a full path name (if relevant) */ 1677. if (filename) { 1678. #ifdef UNIX 1679. if (access(filename, 4) == -1) { 1680. /* 4 is R_OK on newer systems */ 1681. /* nasty sneaky attempt to read file through 1682. * NetHack's setuid permissions -- this is the only 1683. * place a file name may be wholly under the player's 1684. * control 1685. */ 1686. raw_printf("Access to %s denied (%d).", 1687. filename, errno); 1688. wait_synch(); 1689. /* fall through to standard names */ 1690. } else 1691. #endif 1692. if ((fp = fopenp(filename, "r")) != (FILE *)0) { 1693. configfile = filename; 1694. return(fp); 1695. #if defined(UNIX) || defined(VMS) 1696. } else { 1697. /* access() above probably caught most problems for UNIX */ 1698. raw_printf("Couldn't open requested config file %s (%d).", 1699. filename, errno); 1700. wait_synch(); 1701. /* fall through to standard names */ 1702. #endif 1703. } 1704. } 1705. 1706. #if defined(MICRO) || defined(MAC) || defined(__BEOS__) || defined(WIN32) 1707. if ((fp = fopenp(fqname(configfile, CONFIGPREFIX, 0), "r")) 1708. != (FILE *)0) 1709. return(fp); 1710. # ifdef MSDOS 1711. else if ((fp = fopenp(fqname(backward_compat_configfile, 1712. CONFIGPREFIX, 0), "r")) != (FILE *)0) 1713. return(fp); 1714. # endif 1715. #else 1716. /* constructed full path names don't need fqname() */ 1717. # ifdef VMS 1718. if ((fp = fopenp(fqname(NH_CONFIG_FILE, CONFIGPREFIX, 0), "r")) 1719. != (FILE *)0) { 1720. configfile = NH_CONFIG_FILE; 1721. return(fp); 1722. } 1723. if ((fp = fopenp(NH_CONFIG_FILE2, "r")) != (FILE *)0) { 1724. configfile = index(NH_CONFIG_FILE2, ':'); 1725. if (configfile) 1726. configfile++; 1727. else 1728. configfile = NH_CONFIG_FILE2; 1729. return(fp); 1730. } 1731. 1732. envp = nh_getenv("HOME"); 1733. if (!envp) 1734. Strcpy(tmp_config, NH_CONFIG_FILE3); 1735. else 1736. Sprintf(tmp_config, "%s%s", envp, NH_CONFIG_FILE3); 1737. if ((fp = fopenp(tmp_config, "r")) != (FILE *)0) 1738. return(fp); 1739. # else /* should be only UNIX left */ 1740. envp = nh_getenv("HOME"); 1741. if (!envp) 1742. Strcpy(tmp_config, configfile); 1743. else 1744. Sprintf(tmp_config, "%s/%s", envp, configfile); 1745. if ((fp = fopenp(tmp_config, "r")) != (FILE *)0) 1746. return(fp); 1747. # if defined(__APPLE__) 1748. /* try an alternative */ 1749. if (envp) { 1750. Sprintf(tmp_config, "%s/%s", envp, "Library/Preferences/NetHack Defaults"); 1751. if ((fp = fopenp(tmp_config, "r")) != (FILE *)0) 1752. return(fp); 1753. Sprintf(tmp_config, "%s/%s", envp, "Library/Preferences/NetHack Defaults.txt"); 1754. if ((fp = fopenp(tmp_config, "r")) != (FILE *)0) 1755. return(fp); 1756. } 1757. # endif 1758. if (errno != ENOENT) { 1759. char *details; 1760. 1761. /* e.g., problems when setuid NetHack can't search home 1762. * directory restricted to user */ 1763. 1764. #if defined (NHSTDC) && !defined(NOTSTDC) 1765. if ((details = strerror(errno)) == 0) 1766. #endif 1767. details = ""; 1768. raw_printf("Couldn't open default config file %s %s(%d).", 1769. tmp_config, details, errno); 1770. wait_synch(); 1771. } 1772. else if (!strncmp(windowprocs.name, "proxy/", 6)) { 1773. fp = fopenp("/etc/slashem/proxy.slashemrc", "r"); 1774. if (fp != (FILE *)0) 1775. return(fp); 1776. else if (errno != ENOENT) { 1777. raw_printf("Couldn't open /etc/slashem/proxy.slashemrc (%d).", 1778. errno); 1779. wait_synch(); 1780. } 1781. } 1782. # endif 1783. #endif 1784. return (FILE *)0; 1785. 1786. } 1787. 1788. 1789. /* 1790. * Retrieve a list of integers from a file into a uchar array. 1791. * 1792. * NOTE: zeros are inserted unless modlist is TRUE, in which case the list 1793. * location is unchanged. Callers must handle zeros if modlist is FALSE. 1794. */ 1795. STATIC_OVL int 1796. get_uchars(fp, buf, bufp, list, modlist, size, name) 1797. FILE *fp; /* input file pointer */ 1798. char *buf; /* read buffer, must be of size BUFSZ */ 1799. char *bufp; /* current pointer */ 1800. uchar *list; /* return list */ 1801. boolean modlist; /* TRUE: list is being modified in place */ 1802. int size; /* return list size */ 1803. const char *name; /* name of option for error message */ 1804. { 1805. unsigned int num = 0; 1806. int count = 0; 1807. boolean havenum = FALSE; 1808. 1809. while (1) { 1810. switch(*bufp) { 1811. case ' ': case '\0': 1812. case '\t': case '\n': 1813. if (havenum) { 1814. /* if modifying in place, don't insert zeros */ 1815. if (num || !modlist) list[count] = num; 1816. count++; 1817. num = 0; 1818. havenum = FALSE; 1819. } 1820. if (count == size || !*bufp) return count; 1821. bufp++; 1822. break; 1823. 1824. case '0': case '1': case '2': case '3': 1825. case '4': case '5': case '6': case '7': 1826. case '8': case '9': 1827. havenum = TRUE; 1828. num = num*10 + (*bufp-'0'); 1829. bufp++; 1830. break; 1831. 1832. case '\\': 1833. if (fp == (FILE *)0) 1834. goto gi_error; 1835. do { 1836. if (!fgets(buf, BUFSZ, fp)) goto gi_error; 1837. } while (buf[0] == '#'); 1838. bufp = buf; 1839. break; 1840. 1841. default: 1842. gi_error: 1843. raw_printf("Syntax error in %s", name); 1844. wait_synch(); 1845. return count; 1846. } 1847. } 1848. /*NOTREACHED*/ 1849. } 1850. 1851. #ifdef NOCWD_ASSUMPTIONS 1852. STATIC_OVL void 1853. adjust_prefix(bufp, prefixid) 1854. char *bufp; 1855. int prefixid; 1856. { 1857. char *ptr; 1858. 1859. if (!bufp) return; 1860. /* Backward compatibility, ignore trailing ;n */ 1861. if ((ptr = index(bufp, ';')) != 0) *ptr = '\0'; 1862. if (strlen(bufp) > 0) { 1863. fqn_prefix[prefixid] = (char *)alloc(strlen(bufp)+2); 1864. Strcpy(fqn_prefix[prefixid], bufp); 1865. append_slash(fqn_prefix[prefixid]); 1866. } 1867. } 1868. #endif 1869. 1870. #define match_varname(INP,NAM,LEN) match_optname(INP, NAM, LEN, TRUE) 1871. 1872. /*ARGSUSED*/ 1873. int 1874. parse_config_line(fp, buf, tmp_ramdisk, tmp_levels) 1875. FILE *fp; 1876. char *buf; 1877. char *tmp_ramdisk; 1878. char *tmp_levels; 1879. { 1880. #if defined(MAC_MPW) || defined(__MWERKS__) 1881. # pragma unused(tmp_ramdisk,tmp_levels) 1882. #endif 1883. char *bufp, *altp; 1884. uchar translate[MAXPCHARS]; 1885. int len; 1886. 1887. if (*buf == '#') 1888. return 1; 1889. 1890. /* remove trailing whitespace */ 1891. bufp = eos(buf); 1892. while (--bufp > buf && isspace((int)*bufp)) 1893. continue; 1894. 1895. if (bufp <= buf) 1896. return 1; /* skip all-blank lines */ 1897. else 1898. *(bufp + 1) = '\0'; /* terminate line */ 1899. 1900. /* find the '=' or ':' */ 1901. bufp = index(buf, '='); 1902. altp = index(buf, ':'); 1903. if (!bufp || (altp && altp < bufp)) bufp = altp; 1904. if (!bufp) return 0; 1905. 1906. /* skip whitespace between '=' and value */ 1907. do { ++bufp; } while (isspace((int)*bufp)); 1908. 1909. /* Go through possible variables */ 1910. /* some of these (at least LEVELS and SAVE) should now set the 1911. * appropriate fqn_prefix[] rather than specialized variables 1912. */ 1913. if (match_varname(buf, "OPTIONS", 4)) { 1914. parseoptions(bufp, TRUE, TRUE); 1915. if (plname[0]) /* If a name was given */ 1916. plnamesuffix(); /* set the character class */ 1917. } else if (match_varname(buf, "TILESETS", 7)) { 1918. parsetileset(bufp); 1919. #ifdef AUTOPICKUP_EXCEPTIONS 1920. } else if (match_varname(buf, "AUTOPICKUP_EXCEPTION", 5)) { 1921. add_autopickup_exception(bufp); 1922. #endif 1923. #ifdef NOCWD_ASSUMPTIONS 1924. } else if (match_varname(buf, "HACKDIR", 4)) { 1925. adjust_prefix(bufp, HACKPREFIX); 1926. } else if (match_varname(buf, "LEVELDIR", 4) || 1927. match_varname(buf, "LEVELS", 4)) { 1928. adjust_prefix(bufp, LEVELPREFIX); 1929. } else if (match_varname(buf, "SAVEDIR", 4)) { 1930. adjust_prefix(bufp, SAVEPREFIX); 1931. } else if (match_varname(buf, "BONESDIR", 5)) { 1932. adjust_prefix(bufp, BONESPREFIX); 1933. } else if (match_varname(buf, "DATADIR", 4)) { 1934. adjust_prefix(bufp, DATAPREFIX); 1935. } else if (match_varname(buf, "SCOREDIR", 4)) { 1936. adjust_prefix(bufp, SCOREPREFIX); 1937. } else if (match_varname(buf, "LOCKDIR", 4)) { 1938. adjust_prefix(bufp, LOCKPREFIX); 1939. } else if (match_varname(buf, "CONFIGDIR", 4)) { 1940. adjust_prefix(bufp, CONFIGPREFIX); 1941. } else if (match_varname(buf, "TROUBLEDIR", 4)) { 1942. adjust_prefix(bufp, TROUBLEPREFIX); 1943. #else /*NOCWD_ASSUMPTIONS*/ 1944. # ifdef MICRO 1945. } else if (match_varname(buf, "HACKDIR", 4)) { 1946. (void) strncpy(hackdir, bufp, PATHLEN-1); 1947. # ifdef MFLOPPY 1948. } else if (match_varname(buf, "RAMDISK", 3)) { 1949. /* The following ifdef is NOT in the wrong 1950. * place. For now, we accept and silently 1951. * ignore RAMDISK */ 1952. # ifndef AMIGA 1953. (void) strncpy(tmp_ramdisk, bufp, PATHLEN-1); 1954. # endif 1955. # endif 1956. } else if (match_varname(buf, "LEVELS", 4)) { 1957. (void) strncpy(tmp_levels, bufp, PATHLEN-1); 1958. 1959. } else if (match_varname(buf, "SAVE", 4)) { 1960. # ifdef MFLOPPY 1961. extern int saveprompt; 1962. # endif 1963. char *ptr; 1964. if ((ptr = index(bufp, ';')) != 0) { 1965. *ptr = '\0'; 1966. # ifdef MFLOPPY 1967. if (*(ptr+1) == 'n' || *(ptr+1) == 'N') { 1968. saveprompt = FALSE; 1969. } 1970. # endif 1971. } 1972. # ifdef MFLOPPY 1973. else 1974. saveprompt = flags.asksavedisk; 1975. # endif 1976. 1977. (void) strncpy(SAVEP, bufp, SAVESIZE-1); 1978. append_slash(SAVEP); 1979. # endif /* MICRO */ 1980. #endif /*NOCWD_ASSUMPTIONS*/ 1981. 1982. } else if (match_varname(buf, "NAME", 4)) { 1983. (void) strncpy(plname, bufp, PL_NSIZ-1); 1984. plnamesuffix(); 1985. } else if (match_varname(buf, "ROLE", 4) || 1986. match_varname(buf, "CHARACTER", 4)) { 1987. if ((len = str2role(bufp)) >= 0) 1988. flags.initrole = len; 1989. } else if (match_varname(buf, "DOGNAME", 3)) { 1990. (void) strncpy(dogname, bufp, PL_PSIZ-1); 1991. } else if (match_varname(buf, "CATNAME", 3)) { 1992. (void) strncpy(catname, bufp, PL_PSIZ-1); 1993. } else if (match_varname(buf, "WOLFNAME", 3)) { 1994. (void) strncpy(wolfname, bufp, PL_PSIZ-1); 1995. } else if (match_varname(buf, "GHOULNAME", 3)) { 1996. (void) strncpy(ghoulname, bufp, PL_PSIZ-1); 1997. #if 0 1998. } else if (match_varname(buf, "BATNAME", 3)) { 1999. (void) strncpy(batname, bufp, PL_PSIZ-1); 2000. } else if (match_varname(buf, "SNAKENAME", 3)) { 2001. (void) strncpy(batname, bufp, PL_PSIZ-1); 2002. } else if (match_varname(buf, "RATNAME", 3)) { 2003. (void) strncpy(batname, bufp, PL_PSIZ-1); 2004. } else if (match_varname(buf, "BADGERNAME", 3)) { 2005. (void) strncpy(batname, bufp, PL_PSIZ-1); 2006. } else if (match_varname(buf, "REDDRAGONNAME", 3)) { 2007. (void) strncpy(batname, bufp, PL_PSIZ-1); 2008. } else if (match_varname(buf, "WHITEDRAGONNAME", 3)) { 2009. (void) strncpy(batname, bufp, PL_PSIZ-1); 2010. #endif 2011. 2012. } else if (match_varname(buf, "BOULDER", 3)) { 2013. (void) get_uchars(fp, buf, bufp, &iflags.bouldersym, TRUE, 2014. 1, "BOULDER"); 2015. } else if (match_varname(buf, "MENUCOLOR", 9)) { 2016. #ifdef MENU_COLOR 2017. add_menu_coloring(bufp); 2018. #endif 2019. } else if (match_varname(buf, "GRAPHICS", 4)) { 2020. len = get_uchars(fp, buf, bufp, translate, FALSE, 2021. MAXPCHARS, "GRAPHICS"); 2022. assign_graphics(translate, len, MAXPCHARS, 0); 2023. } else if (match_varname(buf, "DUNGEON", 4)) { 2024. len = get_uchars(fp, buf, bufp, translate, FALSE, 2025. MAXDCHARS, "DUNGEON"); 2026. assign_graphics(translate, len, MAXDCHARS, 0); 2027. } else if (match_varname(buf, "TRAPS", 4)) { 2028. len = get_uchars(fp, buf, bufp, translate, FALSE, 2029. MAXTCHARS, "TRAPS"); 2030. assign_graphics(translate, len, MAXTCHARS, MAXDCHARS); 2031. } else if (match_varname(buf, "EFFECTS", 4)) { 2032. len = get_uchars(fp, buf, bufp, translate, FALSE, 2033. MAXECHARS, "EFFECTS"); 2034. assign_graphics(translate, len, MAXECHARS, MAXDCHARS+MAXTCHARS); 2035. 2036. } else if (match_varname(buf, "OBJECTS", 3)) { 2037. /* oc_syms[0] is the RANDOM object, unused */ 2038. (void) get_uchars(fp, buf, bufp, &(oc_syms[1]), TRUE, 2039. MAXOCLASSES-1, "OBJECTS"); 2040. } else if (match_varname(buf, "MONSTERS", 3)) { 2041. /* monsyms[0] is unused */ 2042. (void) get_uchars(fp, buf, bufp, &(monsyms[1]), TRUE, 2043. MAXMCLASSES-1, "MONSTERS"); 2044. } else if (match_varname(buf, "WARNINGS", 5)) { 2045. (void) get_uchars(fp, buf, bufp, translate, TRUE, 2046. WARNCOUNT, "WARNINGS"); 2047. assign_warnings(translate); 2048. #ifdef WIZARD 2049. } else if (match_varname(buf, "WIZKIT", 6)) { 2050. (void) strncpy(wizkit, bufp, WIZKIT_MAX-1); 2051. #endif 2052. #ifdef AMIGA 2053. } else if (match_varname(buf, "FONT", 4)) { 2054. char *t; 2055. 2056. if( t = strchr( buf+5, ':' ) ) 2057. { 2058. *t = 0; 2059. amii_set_text_font( buf+5, atoi( t + 1 ) ); 2060. *t = ':'; 2061. } 2062. } else if (match_varname(buf, "PATH", 4)) { 2063. (void) strncpy(PATH, bufp, PATHLEN-1); 2064. } else if (match_varname(buf, "DEPTH", 5)) { 2065. extern int amii_numcolors; 2066. int val = atoi( bufp ); 2067. amii_numcolors = 1L << min( DEPTH, val ); 2068. } else if (match_varname(buf, "DRIPENS", 7)) { 2069. int i, val; 2070. char *t; 2071. for (i = 0, t = strtok(bufp, ",/"); t != (char *)0; 2072. i < 20 && (t = strtok((char*)0, ",/")), ++i) { 2073. sscanf(t, "%d", &val ); 2074. flags.amii_dripens[i] = val; 2075. } 2076. } else if (match_varname(buf, "SCREENMODE", 10 )) { 2077. extern long amii_scrnmode; 2078. if (!stricmp(bufp,"req")) 2079. amii_scrnmode = 0xffffffff; /* Requester */ 2080. else if( sscanf(bufp, "%x", &amii_scrnmode) != 1 ) 2081. amii_scrnmode = 0; 2082. } else if (match_varname(buf, "MSGPENS", 7)) { 2083. extern int amii_msgAPen, amii_msgBPen; 2084. char *t = strtok(bufp, ",/"); 2085. if( t ) 2086. { 2087. sscanf(t, "%d", &amii_msgAPen); 2088. if( t = strtok((char*)0, ",/") ) 2089. sscanf(t, "%d", &amii_msgBPen); 2090. } 2091. } else if (match_varname(buf, "TEXTPENS", 8)) { 2092. extern int amii_textAPen, amii_textBPen; 2093. char *t = strtok(bufp, ",/"); 2094. if( t ) 2095. { 2096. sscanf(t, "%d", &amii_textAPen); 2097. if( t = strtok((char*)0, ",/") ) 2098. sscanf(t, "%d", &amii_textBPen); 2099. } 2100. } else if (match_varname(buf, "MENUPENS", 8)) { 2101. extern int amii_menuAPen, amii_menuBPen; 2102. char *t = strtok(bufp, ",/"); 2103. if( t ) 2104. { 2105. sscanf(t, "%d", &amii_menuAPen); 2106. if( t = strtok((char*)0, ",/") ) 2107. sscanf(t, "%d", &amii_menuBPen); 2108. } 2109. } else if (match_varname(buf, "STATUSPENS", 10)) { 2110. extern int amii_statAPen, amii_statBPen; 2111. char *t = strtok(bufp, ",/"); 2112. if( t ) 2113. { 2114. sscanf(t, "%d", &amii_statAPen); 2115. if( t = strtok((char*)0, ",/") ) 2116. sscanf(t, "%d", &amii_statBPen); 2117. } 2118. } else if (match_varname(buf, "OTHERPENS", 9)) { 2119. extern int amii_otherAPen, amii_otherBPen; 2120. char *t = strtok(bufp, ",/"); 2121. if( t ) 2122. { 2123. sscanf(t, "%d", &amii_otherAPen); 2124. if( t = strtok((char*)0, ",/") ) 2125. sscanf(t, "%d", &amii_otherBPen); 2126. } 2127. } else if (match_varname(buf, "PENS", 4)) { 2128. extern unsigned short amii_init_map[ AMII_MAXCOLORS ]; 2129. int i; 2130. char *t; 2131. 2132. for (i = 0, t = strtok(bufp, ",/"); 2133. i < AMII_MAXCOLORS && t != (char *)0; 2134. t = strtok((char *)0, ",/"), ++i) 2135. { 2136. sscanf(t, "%hx", &amii_init_map[i]); 2137. } 2138. amii_setpens( amii_numcolors = i ); 2139. } else if (match_varname(buf, "FGPENS", 6)) { 2140. extern int foreg[ AMII_MAXCOLORS ]; 2141. int i; 2142. char *t; 2143. 2144. for (i = 0, t = strtok(bufp, ",/"); 2145. i < AMII_MAXCOLORS && t != (char *)0; 2146. t = strtok((char *)0, ",/"), ++i) 2147. { 2148. sscanf(t, "%d", &foreg[i]); 2149. } 2150. } else if (match_varname(buf, "BGPENS", 6)) { 2151. extern int backg[ AMII_MAXCOLORS ]; 2152. int i; 2153. char *t; 2154. 2155. for (i = 0, t = strtok(bufp, ",/"); 2156. i < AMII_MAXCOLORS && t != (char *)0; 2157. t = strtok((char *)0, ",/"), ++i) 2158. { 2159. sscanf(t, "%d", &backg[i]); 2160. } 2161. #endif 2162. #ifdef USER_SOUNDS 2163. } else if (match_varname(buf, "SOUNDDIR", 8)) { 2164. sounddir = (char *)strdup(bufp); 2165. } else if (match_varname(buf, "SOUND", 5)) { 2166. add_sound_mapping(bufp); 2167. #endif 2168. #ifdef QT_GRAPHICS 2169. /* These should move to wc_ options */ 2170. } else if (match_varname(buf, "QT_TILEWIDTH", 12)) { 2171. extern char *qt_tilewidth; 2172. if (qt_tilewidth == NULL) 2173. qt_tilewidth=(char *)strdup(bufp); 2174. } else if (match_varname(buf, "QT_TILEHEIGHT", 13)) { 2175. extern char *qt_tileheight; 2176. if (qt_tileheight == NULL) 2177. qt_tileheight=(char *)strdup(bufp); 2178. } else if (match_varname(buf, "QT_FONTSIZE", 11)) { 2179. extern char *qt_fontsize; 2180. if (qt_fontsize == NULL) 2181. qt_fontsize=(char *)strdup(bufp); 2182. } else if (match_varname(buf, "QT_COMPACT", 10)) { 2183. extern int qt_compact_mode; 2184. qt_compact_mode = atoi(bufp); 2185. #endif 2186. #if defined(GL_GRAPHICS) || defined(SDL_GRAPHICS) 2187. } else if (match_varname(buf, "GL_OPTIONS", 10)) { 2188. Sdlgl_parse_options(bufp, TRUE, TRUE); 2189. #endif 2190. } else 2191. return 0; 2192. return 1; 2193. } 2194. 2195. #ifdef USER_SOUNDS 2196. boolean 2197. can_read_file(filename) 2198. const char *filename; 2199. { 2200. return (access(filename, 4) == 0); 2201. } 2202. #endif /* USER_SOUNDS */ 2203. 2204. void 2205. read_config_file(filename) 2206. const char *filename; 2207. { 2208. #define tmp_levels (char *)0 2209. #define tmp_ramdisk (char *)0 2210. 2211. #if defined(MICRO) || defined(WIN32) 2212. #undef tmp_levels 2213. char tmp_levels[PATHLEN]; 2214. # ifdef MFLOPPY 2215. # ifndef AMIGA 2216. #undef tmp_ramdisk 2217. char tmp_ramdisk[PATHLEN]; 2218. # endif 2219. # endif 2220. #endif 2221. char buf[4*BUFSZ]; 2222. FILE *fp; 2223. int i; 2224. #ifdef PROXY_GRAPHICS 2225. int found = FALSE; 2226. 2227. if (!(fp = fopen_config_file(filename))) 2228. goto clnt_process; 2229. else 2230. found = TRUE; 2231. #else 2232. if (!(fp = fopen_config_file(filename))) goto post_process; 2233. #endif 2234. 2235. #if defined(MICRO) || defined(WIN32) 2236. # ifdef MFLOPPY 2237. # ifndef AMIGA 2238. tmp_ramdisk[0] = 0; 2239. # endif 2240. # endif 2241. tmp_levels[0] = 0; 2242. #endif 2243. /* begin detection of duplicate configfile options */ 2244. set_duplicate_opt_detection(1); 2245. 2246. while (fgets(buf, 4*BUFSZ, fp)) { 2247. if (!parse_config_line(fp, buf, tmp_ramdisk, tmp_levels)) { 2248. raw_printf("Bad option line: \"%.50s\"", buf); 2249. wait_synch(); 2250. } 2251. } 2252. (void) fclose(fp); 2253. 2254. /* turn off detection of duplicate configfile options */ 2255. set_duplicate_opt_detection(0); 2256. 2257. #ifdef PROXY_GRAPHICS 2258. clnt_process: 2259. /* 2260. * When acting as a proxy server, allow the client to provide 2261. * its own config file which overrides values in our config file. 2262. * Note: We don't want to warn of values being present in both 2263. * files, but we do want to warn of duplicates within each file. 2264. */ 2265. if (!strncmp(windowprocs.name, "proxy/", 6) && 2266. (fp = proxy_config_file_open())) { 2267. found = TRUE; 2268. set_duplicate_opt_detection(1); 2269. while (fgets(buf, 4*BUFSZ, fp)) { 2270. if (match_varname(buf, "TILESETS", 7) || 2271. match_varname(buf, "HACKDIR", 4) || 2272. match_varname(buf, "LEVELDIR", 4) || 2273. match_varname(buf, "LEVELS", 4) || 2274. match_varname(buf, "SAVEDIR", 4) || 2275. match_varname(buf, "BONESDIR", 5) || 2276. match_varname(buf, "DATADIR", 4) || 2277. match_varname(buf, "SCOREDIR", 4) || 2278. match_varname(buf, "LOCKDIR", 4) || 2279. match_varname(buf, "CONFIGDIR", 4) || 2280. match_varname(buf, "TROUBLEDIR", 4) || 2281. match_varname(buf, "SOUNDDIR", 8) || 2282. match_varname(buf, "SOUND", 5)) { 2283. /* Quietly ignore many commands. There's no sense in 2284. * the client configuring these and some introduce 2285. * potential security breachs. 2286. */ 2287. continue; 2288. } 2289. if (!parse_config_line(fp, buf, tmp_ramdisk, tmp_levels)) { 2290. pline("Bad option line: \"%.50s\"", buf); 2291. wait_synch(); 2292. } 2293. } 2294. proxy_config_file_close(fp); 2295. set_duplicate_opt_detection(0); 2296. } 2297. 2298. if (!found) goto post_process; 2299. #endif 2300. 2301. #if defined(MICRO) && !defined(NOCWD_ASSUMPTIONS) 2302. /* should be superseded by fqn_prefix[] */ 2303. # ifdef MFLOPPY 2304. Strcpy(permbones, tmp_levels); 2305. # ifndef AMIGA 2306. if (tmp_ramdisk[0]) { 2307. Strcpy(levels, tmp_ramdisk); 2308. if (strcmp(permbones, levels)) /* if not identical */ 2309. ramdisk = TRUE; 2310. } else 2311. # endif /* AMIGA */ 2312. Strcpy(levels, tmp_levels); 2313. 2314. Strcpy(bones, levels); 2315. # endif /* MFLOPPY */ 2316. #endif /* MICRO */ 2317. post_process: 2318. if (!no_tilesets) { 2319. for(i = 0; strlen(def_tilesets[i].name); i++) { 2320. strcpy(tilesets[i].name, def_tilesets[i].name); 2321. strcpy(tilesets[i].file, def_tilesets[i].file); 2322. tilesets[i].flags = def_tilesets[i].flags; 2323. } 2324. no_tilesets = i; 2325. } 2326. if (tileset[0] != '\0') { 2327. unsigned int len = strlen(tileset); 2328. for(i = 0; i < no_tilesets; i++) 2329. if (len == strlen(tilesets[i].name) && 2330. !strncmpi(tilesets[i].name, tileset, len)) 2331. break; 2332. if (i == no_tilesets) { 2333. pline("Tileset %s not defined.", tileset); 2334. tileset[0] = '\0'; 2335. } 2336. else 2337. strcpy(tileset, tilesets[i].name); 2338. } 2339. return; 2340. } 2341. 2342. #ifdef WIZARD 2343. STATIC_OVL FILE * 2344. fopen_wizkit_file() 2345. { 2346. FILE *fp; 2347. #if defined(VMS) || defined(UNIX) 2348. char tmp_wizkit[BUFSZ]; 2349. #endif 2350. char *envp; 2351. 2352. envp = nh_getenv("WIZKIT"); 2353. if (envp && *envp) (void) strncpy(wizkit, envp, WIZKIT_MAX - 1); 2354. if (!wizkit[0]) return (FILE *)0; 2355. 2356. #ifdef UNIX 2357. if (access(wizkit, 4) == -1) { 2358. /* 4 is R_OK on newer systems */ 2359. /* nasty sneaky attempt to read file through 2360. * NetHack's setuid permissions -- this is a 2361. * place a file name may be wholly under the player's 2362. * control 2363. */ 2364. raw_printf("Access to %s denied (%d).", 2365. wizkit, errno); 2366. wait_synch(); 2367. /* fall through to standard names */ 2368. } else 2369. #endif 2370. if ((fp = fopenp(wizkit, "r")) != (FILE *)0) { 2371. return(fp); 2372. #if defined(UNIX) || defined(VMS) 2373. } else { 2374. /* access() above probably caught most problems for UNIX */ 2375. raw_printf("Couldn't open requested config file %s (%d).", 2376. wizkit, errno); 2377. wait_synch(); 2378. #endif 2379. } 2380. 2381. #if defined(MICRO) || defined(MAC) || defined(__BEOS__) || defined(WIN32) 2382. if ((fp = fopenp(fqname(wizkit, CONFIGPREFIX, 0), "r")) 2383. != (FILE *)0) 2384. return(fp); 2385. #else 2386. # ifdef VMS 2387. envp = nh_getenv("HOME"); 2388. if (envp) 2389. Sprintf(tmp_wizkit, "%s%s", envp, wizkit); 2390. else 2391. Sprintf(tmp_wizkit, "%s%s", "sys$login:", wizkit); 2392. if ((fp = fopenp(tmp_wizkit, "r")) != (FILE *)0) 2393. return(fp); 2394. # else /* should be only UNIX left */ 2395. envp = nh_getenv("HOME"); 2396. if (envp) 2397. Sprintf(tmp_wizkit, "%s/%s", envp, wizkit); 2398. else Strcpy(tmp_wizkit, wizkit); 2399. if ((fp = fopenp(tmp_wizkit, "r")) != (FILE *)0) 2400. return(fp); 2401. else if (errno != ENOENT) { 2402. /* e.g., problems when setuid NetHack can't search home 2403. * directory restricted to user */ 2404. raw_printf("Couldn't open default wizkit file %s (%d).", 2405. tmp_wizkit, errno); 2406. wait_synch(); 2407. } 2408. # endif 2409. #endif 2410. return (FILE *)0; 2411. } 2412. 2413. void 2414. read_wizkit() 2415. { 2416. FILE *fp; 2417. char *ep, buf[BUFSZ]; 2418. struct obj *otmp; 2419. boolean bad_items = FALSE, skip = FALSE; 2420. 2421. if (!wizard || !(fp = fopen_wizkit_file())) return; 2422. 2423. while (fgets(buf, (int)(sizeof buf), fp)) { 2424. ep = index(buf, '\n'); 2425. if (skip) { /* in case previous line was too long */ 2426. if (ep) skip = FALSE; /* found newline; next line is normal */ 2427. } else { 2428. if (!ep) skip = TRUE; /* newline missing; discard next fgets */ 2429. else *ep = '\0'; /* remove newline */ 2430. 2431. if (buf[0]) { 2432. otmp = readobjnam(buf, (struct obj *)0, FALSE); 2433. if (otmp) { 2434. if (otmp != &zeroobj) 2435. otmp = addinv(otmp); 2436. } else { 2437. /* .60 limits output line width to 79 chars */ 2438. raw_printf("Bad wizkit item: \"%.60s\"", buf); 2439. bad_items = TRUE; 2440. } 2441. } 2442. } 2443. } 2444. if (bad_items) 2445. wait_synch(); 2446. (void) fclose(fp); 2447. return; 2448. } 2449. 2450. #endif /*WIZARD*/ 2451. 2452. /* ---------- END CONFIG FILE HANDLING ----------- */ 2453. 2454. /* ---------- BEGIN SCOREBOARD CREATION ----------- */ 2455. 2456. /* verify that we can write to the scoreboard file; if not, try to create one */ 2457. void 2458. check_recordfile(dir) 2459. const char *dir; 2460. { 2461. #if defined(MAC_MPW) || defined(__MWERKS__) 2462. # pragma unused(dir) 2463. #endif 2464. int fd; 2465. #ifndef FILE_AREAS 2466. const char *fq_record; 2467. #endif 2468. 2469. #if defined(UNIX) || defined(VMS) 2470. # ifdef FILE_AREAS 2471. fd = open_area(NH_RECORD_AREA, NH_RECORD, O_RDWR, 0); 2472. # else 2473. fq_record = fqname(NH_RECORD, SCOREPREFIX, 0); 2474. fd = open(fq_record, O_RDWR, 0); 2475. # endif 2476. 2477. if (fd >= 0) { 2478. # ifdef VMS /* must be stream-lf to use UPDATE_RECORD_IN_PLACE */ 2479. if (!file_is_stmlf(fd)) { 2480. raw_printf( 2481. "Warning: scoreboard file %s is not in stream_lf format", 2482. fq_record); 2483. wait_synch(); 2484. } 2485. # endif 2486. (void) close(fd); /* NH_RECORD is accessible */ 2487. # ifdef FILE_AREAS 2488. } else if ((fd = open_area(NH_RECORD_AREA, NH_RECORD, O_CREAT|O_RDWR, FCMASK)) >= 0) { 2489. # else 2490. } else if ((fd = open(fq_record, O_CREAT|O_RDWR, FCMASK)) >= 0) { 2491. # endif 2492. (void) close(fd); /* NH_RECORD newly created */ 2493. # if defined(VMS) && !defined(SECURE) 2494. /* Re-protect NH_RECORD with world:read+write+execute+delete access. */ 2495. # ifdef FILE_AREAS 2496. (void) chmod_area(NH_RECORD_AREA, NH_RECORD, FCMASK | 007); 2497. # else 2498. (void) chmod(fq_record, FCMASK | 007); 2499. # endif 2500. # endif /* VMS && !SECURE */ 2501. } else { 2502. # ifdef FILE_AREAS 2503. raw_printf("Warning: cannot write scoreboard file %s", NH_RECORD); 2504. # else 2505. raw_printf("Warning: cannot write scoreboard file %s", fq_record); 2506. # endif 2507. wait_synch(); 2508. } 2509. #endif /* !UNIX && !VMS */ 2510. #if defined(MICRO) || defined(WIN32) 2511. char tmp[PATHLEN]; 2512. 2513. # ifdef OS2_CODEVIEW /* explicit path on opening for OS/2 */ 2514. /* how does this work when there isn't an explicit path or fopenp 2515. * for later access to the file via fopen_datafile? ? */ 2516. (void) strncpy(tmp, dir, PATHLEN - 1); 2517. tmp[PATHLEN-1] = '\0'; 2518. if ((strlen(tmp) + 1 + strlen(NH_RECORD)) < (PATHLEN - 1)) { 2519. append_slash(tmp); 2520. Strcat(tmp, NH_RECORD); 2521. } 2522. # ifndef FILE_AREAS 2523. fq_record = tmp; 2524. # endif 2525. # else 2526. Strcpy(tmp, NH_RECORD); 2527. # ifndef FILE_AREAS 2528. fq_record = fqname(NH_RECORD, SCOREPREFIX, 0); 2529. # endif 2530. # endif 2531. 2532. # ifdef FILE_AREAS 2533. if ((fd = open_area(NH_RECORD_AREA, tmp, O_RDWR)) < 0) { 2534. # else 2535. if ((fd = open(fq_record, O_RDWR)) < 0) { 2536. # endif 2537. /* try to create empty record */ 2538. # if defined(FILE_AREAS) 2539. if ((fd = open_area(NH_RECORD_AREA, tmp, O_CREAT|O_RDWR, 2540. S_IREAD|S_IWRITE)) < 0) { 2541. # elif defined(AZTEC_C) || defined(_DCC) || (defined(__GNUC__) && defined(__AMIGA__)) 2542. /* Aztec doesn't use the third argument */ 2543. /* DICE doesn't like it */ 2544. if ((fd = open(fq_record, O_CREAT|O_RDWR)) < 0) { 2545. # else 2546. if ((fd = open(fq_record, O_CREAT|O_RDWR, S_IREAD|S_IWRITE)) < 0) { 2547. # endif 2548. raw_printf("Warning: cannot write record %s", tmp); 2549. wait_synch(); 2550. } else /* create succeeded */ 2551. (void) close(fd); 2552. } else /* open succeeded */ 2553. (void) close(fd); 2554. #else /* MICRO || WIN32*/ 2555. 2556. # ifdef MAC 2557. /* Create the record file, if necessary */ 2558. fq_record = fqname(NH_RECORD, SCOREPREFIX, 0); 2559. fd = macopen (fq_record, O_RDWR | O_CREAT, LOGF_TYPE); 2560. if (fd != -1) macclose (fd); 2561. 2562. /* Create the logfile, if necessary */ 2563. fq_record = fqname(LOGFILE, SCOREPREFIX, 0); 2564. fd = macopen (fq_record, O_RDWR | O_CREAT, LOGF_TYPE); 2565. if (fd != -1) macclose (fd); 2566. # endif /* MAC */ 2567. 2568. #endif /* MICRO || WIN32*/ 2569. } 2570. 2571. /* ---------- END SCOREBOARD CREATION ----------- */ 2572. 2573. /* ---------- BEGIN PANIC/IMPOSSIBLE LOG ----------- */ 2574. 2575. /*ARGSUSED*/ 2576. void 2577. paniclog(type, reason) 2578. const char *type; /* panic, impossible, trickery */ 2579. const char *reason; /* explanation */ 2580. { 2581. #ifdef PANICLOG 2582. FILE *lfile; 2583. char buf[BUFSZ]; 2584. 2585. if (!program_state.in_paniclog) { 2586. program_state.in_paniclog = 1; 2587. lfile = fopen_datafile(PANICLOG, "a", TROUBLEPREFIX); 2588. if (lfile) { 2589. (void) fprintf(lfile, "%s %08ld: %s %s\n", 2590. version_string(buf), yyyymmdd((time_t)0L), 2591. type, reason); 2592. (void) fclose(lfile); 2593. } 2594. program_state.in_paniclog = 0; 2595. } 2596. #endif /* PANICLOG */ 2597. return; 2598. } 2599. 2600. /* ---------- END PANIC/IMPOSSIBLE LOG ----------- */ 2601. 2602. #ifdef SELF_RECOVER 2603. 2604. /* ---------- BEGIN INTERNAL RECOVER ----------- */ 2605. boolean 2606. recover_savefile() 2607. { 2608. int gfd, lfd, sfd; 2609. int lev, savelev, hpid; 2610. xchar levc; 2611. struct version_info version_data; 2612. int processed[256]; 2613. char savename[SAVESIZE], errbuf[BUFSZ]; 2614. 2615. for (lev = 0; lev < 256; lev++) 2616. processed[lev] = 0; 2617. 2618. /* level 0 file contains: 2619. * pid of creating process (ignored here) 2620. * level number for current level of save file 2621. * name of save file nethack would have created 2622. * and game state 2623. */ 2624. gfd = open_levelfile(0, errbuf); 2625. if (gfd < 0) { 2626. raw_printf("%s\n", errbuf); 2627. return FALSE; 2628. } 2629. if (read(gfd, (genericptr_t) &hpid, sizeof hpid) != sizeof hpid) { 2630. raw_printf( 2631. "\nCheckpoint data incompletely written or subsequently clobbered. Recovery impossible."); 2632. (void)close(gfd); 2633. return FALSE; 2634. } 2635. if (read(gfd, (genericptr_t) &savelev, sizeof(savelev)) 2636. != sizeof(savelev)) { 2637. raw_printf("\nCheckpointing was not in effect for %s -- recovery impossible.\n", 2638. lock); 2639. (void)close(gfd); 2640. return FALSE; 2641. } 2642. if ((read(gfd, (genericptr_t) savename, sizeof savename) 2643. != sizeof savename) || 2644. (read(gfd, (genericptr_t) &version_data, sizeof version_data) 2645. != sizeof version_data)) { 2646. raw_printf("\nError reading %s -- can't recover.\n", lock); 2647. (void)close(gfd); 2648. return FALSE; 2649. } 2650. 2651. /* save file should contain: 2652. * version info 2653. * current level (including pets) 2654. * (non-level-based) game state 2655. * other levels 2656. */ 2657. set_savefile_name(); 2658. sfd = create_savefile(); 2659. if (sfd < 0) { 2660. raw_printf("\nCannot recover savefile %s.\n", SAVEF); 2661. (void)close(gfd); 2662. return FALSE; 2663. } 2664. 2665. lfd = open_levelfile(savelev, errbuf); 2666. if (lfd < 0) { 2667. raw_printf("\n%s\n", errbuf); 2668. (void)close(gfd); 2669. (void)close(sfd); 2670. delete_savefile(); 2671. return FALSE; 2672. } 2673. 2674. if (write(sfd, (genericptr_t) &version_data, sizeof version_data) 2675. != sizeof version_data) { 2676. raw_printf("\nError writing %s; recovery failed.", SAVEF); 2677. (void)close(gfd); 2678. (void)close(sfd); 2679. delete_savefile(); 2680. return FALSE; 2681. } 2682. 2683. if (!copy_bytes(lfd, sfd)) { 2684. (void) close(lfd); 2685. (void) close(sfd); 2686. delete_savefile(); 2687. return FALSE; 2688. } 2689. (void)close(lfd); 2690. processed[savelev] = 1; 2691. 2692. if (!copy_bytes(gfd, sfd)) { 2693. (void) close(lfd); 2694. (void) close(sfd); 2695. delete_savefile(); 2696. return FALSE; 2697. } 2698. (void)close(gfd); 2699. processed[0] = 1; 2700. 2701. for (lev = 1; lev < 256; lev++) { 2702. /* level numbers are kept in xchars in save.c, so the 2703. * maximum level number (for the endlevel) must be < 256 2704. */ 2705. if (lev != savelev) { 2706. lfd = open_levelfile(lev, (char *)0); 2707. if (lfd >= 0) { 2708. /* any or all of these may not exist */ 2709. levc = (xchar) lev; 2710. write(sfd, (genericptr_t) &levc, sizeof(levc)); 2711. if (!copy_bytes(lfd, sfd)) { 2712. (void) close(lfd); 2713. (void) close(sfd); 2714. delete_savefile(); 2715. return FALSE; 2716. } 2717. (void)close(lfd); 2718. processed[lev] = 1; 2719. } 2720. } 2721. } 2722. (void)close(sfd); 2723. 2724. #ifdef HOLD_LOCKFILE_OPEN 2725. really_close(); 2726. #endif 2727. /* 2728. * We have a successful savefile! 2729. * Only now do we erase the level files. 2730. */ 2731. for (lev = 0; lev < 256; lev++) { 2732. if (processed[lev]) { 2733. const char *fq_lock; 2734. set_levelfile_name(lock, lev); 2735. fq_lock = fqname(lock, LEVELPREFIX, 3); 2736. (void) unlink(fq_lock); 2737. } 2738. } 2739. return TRUE; 2740. } 2741. 2742. boolean 2743. copy_bytes(ifd, ofd) 2744. int ifd, ofd; 2745. { 2746. char buf[BUFSIZ]; 2747. int nfrom, nto; 2748. 2749. do { 2750. nfrom = read(ifd, buf, BUFSIZ); 2751. nto = write(ofd, buf, nfrom); 2752. if (nto != nfrom) return FALSE; 2753. } while (nfrom == BUFSIZ); 2754. return TRUE; 2755. } 2756. 2757. /* ---------- END INTERNAL RECOVER ----------- */ 2758. #endif /*SELF_RECOVER*/ 2759. 2760. /*files.c*/