Source:Files.c

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