Source:NetHack 3.4.0/files.c

Below is the full text to files.c from the source code of NetHack 3.4.0. To link to a particular line, write [[NetHack 3.4.0/files.c#line123 ]], for example.

Warning! This is the source code from an old release. For the latest release, see Source code

1.   /*	SCCS Id: @(#)files.c	3.4	2002/02/23	*/ 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.  #if defined(UNIX) || defined(VMS) 18.  #include   19. # ifndef SKIP_ERRNO 20.  extern int errno; 21.  # endif 22.  #include   23. #endif 24.   25.   #if defined(MSDOS) || defined(OS2) || defined(TOS) || defined(WIN32) 26.  # ifndef GNUDOS 27.  #include   28. # else 29.  #include   30. # endif 31.  #endif 32.  #ifndef O_BINARY	/* used for micros, no-op for others */ 33.  # define O_BINARY 0 34.  #endif 35.   36.   #ifdef PREFIXES_IN_USE 37.  #define FQN_NUMBUF 2 38.  static char fqn_filename_buffer[FQN_NUMBUF][FQN_MAX_FILENAME]; 39.  #endif 40.   41.   #if !defined(MFLOPPY) && !defined(VMS) && !defined(WIN32) 42.  char bones[] = "bonesnn.xxx"; 43.  char lock[PL_NSIZ+14] = "1lock"; /* long enough for uid+name+.99 */ 44.  #else 45.  # if defined(MFLOPPY) 46.  char bones[FILENAME];		/* pathname of bones files */ 47.  char lock[FILENAME];		/* pathname of level files */ 48.  # endif 49.  # if defined(VMS) 50.  char bones[] = "bonesnn.xxx;1"; 51.  char lock[PL_NSIZ+17] = "1lock"; /* long enough for _uid+name+.99;1 */ 52.  # endif 53.  # if defined(WIN32) 54.  char bones[] = "bonesnn.xxx"; 55.  char lock[PL_NSIZ+25];		/* long enough for username+-+name+.99 */ 56.  # endif 57.  #endif 58.   59.   #if defined(UNIX) || defined(__BEOS__) 60.  #define SAVESIZE	(PL_NSIZ + 13)	/* save/99999player.e */ 61.  #else 62.  # ifdef VMS 63.  #define SAVESIZE	(PL_NSIZ + 22)	/* [.save] player.e;1 */ 64.  # else 65.  #  if defined(WIN32) 66.  #define SAVESIZE	(PL_NSIZ + 40)	/* username-player.NetHack-saved-game */ 67.  #  else 68.  #define SAVESIZE	FILENAME	/* from macconf.h or pcconf.h */ 69.  #  endif 70.  # endif 71.  #endif 72.   73.   char SAVEF[SAVESIZE];	/* holds relative path of save file from playground */ 74.  #ifdef MICRO 75.  char SAVEP[SAVESIZE];	/* holds path of directory for save file */ 76.  #endif 77.   78.   #ifdef WIZARD 79.  #define WIZKIT_MAX 128 80.  static char wizkit[WIZKIT_MAX]; 81.  STATIC_DCL FILE *NDECL(fopen_wizkit_file); 82.  #endif 83.   84.   #ifdef AMIGA 85.  extern char PATH[];	/* see sys/amiga/amidos.c */ 86.  extern char bbs_id[]; 87.  static int lockptr; 88.  # ifdef __SASC_60 89.  #include   90. # endif 91.   92.   #include   93. extern void FDECL(amii_set_text_font, ( char *, int )); 94.  #endif 95.   96.   #if defined(WIN32) || defined(MSDOS) 97.  static int lockptr; 98.  # ifdef MSDOS 99.  #define Delay(a) msleep(a) 100. # endif 101. #define Close close 102. #define DeleteFile unlink 103. #endif 104.  105.  #ifdef USER_SOUNDS 106. extern char *sounddir; 107. #endif 108.  109.  extern int n_dgns;		/* from dungeon.c */ 110.  111.  STATIC_DCL char *FDECL(set_bonesfile_name, (char *,d_level*)); 112. STATIC_DCL char *NDECL(set_bonestemp_name); 113. #ifdef COMPRESS 114. STATIC_DCL void FDECL(redirect, (const char *,const char *,FILE *,BOOLEAN_P)); 115. STATIC_DCL void FDECL(docompress_file, (const char *,BOOLEAN_P)); 116. #endif 117. STATIC_DCL char *FDECL(make_lockname, (const char *,char *)); 118. STATIC_DCL FILE *FDECL(fopen_config_file, (const char *)); 119. STATIC_DCL int FDECL(get_uchars, (FILE *,char *,char *,uchar *,int,const char *)); 120. int FDECL(parse_config_line, (FILE *,char *,char *,char *)); 121. #ifdef NOCWD_ASSUMPTIONS 122. STATIC_DCL void FDECL(adjust_prefix, (char *, int)); 123. #endif 124.  125.  #ifndef PREFIXES_IN_USE 126. /*ARGSUSED*/ 127. #endif 128. const char * 129. fqname(basename, whichprefix, buffnum) 130. const char *basename; 131. int whichprefix, buffnum; 132. {  133.  #ifndef PREFIXES_IN_USE 134. 	return basename; 135. #else 136. 	if (!basename || whichprefix < 0 || whichprefix >= PREFIX_COUNT) 137. 		return basename; 138. 	if (!fqn_prefix[whichprefix]) 139. 		return basename; 140. 	if (buffnum < 0 || buffnum >= FQN_NUMBUF) { 141. 		impossible("Invalid fqn_filename_buffer specified: %d",  142.  								buffnum); 143. 		buffnum = 0; 144. 	}  145.  	if (strlen(fqn_prefix[whichprefix]) + strlen(basename) >=  146.  						    FQN_MAX_FILENAME) { 147. 		impossible("fqname too long: %s + %s", fqn_prefix[whichprefix],  148.  						basename); 149. 		return basename;	/* XXX */ 150. 	}  151.  	Strcpy(fqn_filename_buffer[buffnum], fqn_prefix[whichprefix]); 152. 	return strcat(fqn_filename_buffer[buffnum], basename); 153. #endif 154. }  155.   156.   157.  /* fopen a file, with OS-dependent bells and whistles */ 158. /* NOTE: a simpler version of this routine also exists in util/dlb_main.c */ 159. FILE * 160. fopen_datafile(filename, mode, use_scoreprefix) 161. const char *filename, *mode; 162. boolean use_scoreprefix; 163. {  164.  	FILE *fp; 165.  166.  	filename = fqname(filename,  167.  				use_scoreprefix ? SCOREPREFIX : DATAPREFIX, 0); 168. #ifdef VMS	/* essential to have punctuation, to avoid logical names */ 169.     {  170.  	char tmp[BUFSIZ]; 171.  172.  	if (!index(filename, '.') && !index(filename, ';')) 173. 		filename = strcat(strcpy(tmp, filename), ";0"); 174. 	fp = fopen(filename, mode, "mbc=16"); 175.     }  176.  #else 177. 	fp = fopen(filename, mode); 178. #endif 179. 	return fp; 180. }  181.   182.  /* --  BEGIN LEVEL FILE HANDLING --- */ 183.  184.  #ifdef MFLOPPY 185. /* Set names for bones[] and lock[] */ 186. void 187. set_lock_and_bones 188. {  189.  	if (!ramdisk) { 190. 		Strcpy(levels, permbones); 191. 		Strcpy(bones, permbones); 192. 	}  193.  	append_slash(permbones); 194. 	append_slash(levels); 195. #ifdef AMIGA 196. 	strncat(levels, bbs_id, PATHLEN); 197. #endif 198. 	append_slash(bones); 199. 	Strcat(bones, "bonesnn.*"); 200. 	Strcpy(lock, levels); 201. #ifndef AMIGA 202. 	Strcat(lock, alllevels); 203. #endif 204. 	return; 205. }  206.  #endif /* MFLOPPY */ 207.  208.   209.  /* Construct a file name for a level-type file, which is of the form 210.  * something.level (with any old level stripped off). 211.  * This assumes there is space on the end of 'file' to append 212.  * a two digit number. This is true for 'level' 213.  * but be careful if you use it for other things -dgk 214.  */  215.  void 216. set_levelfile_name(file, lev) 217. char *file; 218. int lev; 219. {  220.  	char *tf; 221.  222.  	tf = rindex(file, '.'); 223. 	if (!tf) tf = eos(file); 224. 	Sprintf(tf, ".%d", lev); 225. #ifdef VMS 226. 	Strcat(tf, ";1"); 227. #endif 228. 	return; 229. }  230.   231.  int 232. create_levelfile(lev) 233. int lev; 234. {  235.  	int fd; 236. 	const char *fq_lock; 237.  238.  	set_levelfile_name(lock, lev); 239. 	fq_lock = fqname(lock, LEVELPREFIX, 0); 240.  241.  #if defined(MICRO) 242. 	/* Use O_TRUNC to force the file to be shortened if it already 243. 	 * exists and is currently longer. 244. 	 */  245.  	fd = open(fq_lock, O_WRONLY |O_CREAT | O_TRUNC | O_BINARY, FCMASK); 246. #else 247. # ifdef MAC 248. 	fd = maccreat(fq_lock, LEVL_TYPE); 249. # else 250. 	fd = creat(fq_lock, FCMASK); 251. # endif 252. #endif /* MICRO */ 253.  254.  	if (fd >= 0) 255. 	    level_info[lev].flags |= LFILE_EXISTS; 256.  257.  	return fd; 258. }  259.   260.   261.  int 262. open_levelfile(lev) 263. int lev; 264. {  265.  	int fd; 266. 	const char *fq_lock; 267.  268.  	set_levelfile_name(lock, lev); 269. 	fq_lock = fqname(lock, LEVELPREFIX, 0); 270. #ifdef MFLOPPY 271. 	/* If not currently accessible, swap it in. */ 272.  	if (level_info[lev].where != ACTIVE) 273. 		swapin_file(lev); 274. #endif 275. #ifdef MAC 276. 	fd = macopen(fq_lock, O_RDONLY | O_BINARY, LEVL_TYPE); 277. #else 278. 	fd = open(fq_lock, O_RDONLY | O_BINARY, 0); 279. #endif 280. 	return fd; 281. }  282.   283.   284.  void 285. delete_levelfile(lev) 286. int lev; 287. {  288.  	/*  289.  	 * Level 0 might be created by port specific code that doesn't  290. * call create_levfile, so always assume that it exists. 291. 	 */  292.  	if (lev == 0 || (level_info[lev].flags & LFILE_EXISTS)) { 293. 		set_levelfile_name(lock, lev); 294. 		(void) unlink(fqname(lock, LEVELPREFIX, 0)); 295. 		level_info[lev].flags &= ~LFILE_EXISTS; 296. 	}  297.  }  298.   299.   300.  void 301. clearlocks 302. {  303.  #if !defined(PC_LOCKING) && defined(MFLOPPY) && !defined(AMIGA) 304. 	eraseall(levels, alllevels); 305. 	if (ramdisk) 306. 		eraseall(permbones, alllevels); 307. #else 308. 	register int x;  309. 310. # if defined(UNIX) || defined(VMS) 311. 	(void) signal(SIGHUP, SIG_IGN); 312. # endif 313. 	/* can't access maxledgerno before dungeons are created -dlc */ 314. 	for (x = (n_dgns ? maxledgerno : 0); x >= 0; x--) 315. 		delete_levelfile(x);	/* not all levels need be present */ 316. #endif 317. }  318.   319.  /* --  END LEVEL FILE HANDLING --- */ 320.  321.   322.  /* --  BEGIN BONES FILE HANDLING --- */ 323.  324.  /* set up "file" to be file name for retrieving bones, and return a  325. * bonesid to be read/written in the bones file. 326.  */  327.  STATIC_OVL char * 328. set_bonesfile_name(file, lev) 329. char *file; 330. d_level *lev; 331. {  332.  	s_level *sptr; 333. 	char *dptr; 334.  335.  	Sprintf(file, "bon%c%s", dungeons[lev->dnum].boneid,  336.  			In_quest(lev) ? urole.filecode : "0"); 337. 	dptr = eos(file); 338. 	if ((sptr = Is_special(lev)) != 0) 339. 	    Sprintf(dptr, ".%c", sptr->boneid); 340. 	else 341. 	    Sprintf(dptr, ".%d", lev->dlevel); 342. #ifdef VMS 343. 	Strcat(dptr, ";1"); 344. #endif 345. 	return(dptr-2); 346. }  347.   348.  /* set up temporary file name for writing bones, to avoid another game's  349. * trying to read from an uncompleted bones file. we want an uncontentious 350.  * name, so use one in the namespace reserved for this game's level files. 351.  * (we are not reading or writing level files while writing bones files, so  352.   * the same array may be used instead of copying.) 353.  */  354.  STATIC_OVL char * 355. set_bonestemp_name 356. {  357.  	char *tf; 358.  359.  	tf = rindex(lock, '.'); 360. 	if (!tf) tf = eos(lock); 361. 	Sprintf(tf, ".bn"); 362. #ifdef VMS 363. 	Strcat(tf, ";1"); 364. #endif 365. 	return lock; 366. }  367.   368.  int 369. create_bonesfile(lev, bonesid) 370. d_level *lev; 371. char **bonesid; 372. {  373.  	const char *file; 374. 	int fd; 375.  376.  	*bonesid = set_bonesfile_name(bones, lev); 377. 	file = set_bonestemp_name; 378. 	file = fqname(file, BONESPREFIX, 0); 379.  380.  #ifdef MICRO 381. 	/* Use O_TRUNC to force the file to be shortened if it already 382. 	 * exists and is currently longer. 383. 	 */  384.  	fd = open(file, O_WRONLY |O_CREAT | O_TRUNC | O_BINARY, FCMASK); 385. #else 386. # ifdef MAC 387. 	fd = maccreat(file, BONE_TYPE); 388. # else 389. 	fd = creat(file, FCMASK); 390. # endif 391. # if defined(VMS) && !defined(SECURE) 392. 	/*  393.  	   Re-protect bones file with world:read+write+execute+delete access. 394. 	   umask doesn't seem very reliable; also, vaxcrtl won't let us set 395. 	   delete access without write access, which is what's really wanted. 396. 	   Can't simply create it with the desired protection because creat 397. 	   ANDs the mask with the user's default protection, which usually 398. 	   denies some or all access to world. 399. 	 */  400.  	(void) chmod(file, FCMASK | 007);  /* allow other users full access */ 401. # endif /* VMS && !SECURE */ 402. #endif /* MICRO */ 403.  404.  	return fd; 405. }  406.   407.  #ifdef MFLOPPY 408. /* remove partial bonesfile in process of creation */ 409. void 410. cancel_bonesfile 411. {  412.  	const char *tempname; 413.  414.  	tempname = set_bonestemp_name; 415. 	tempname = fqname(tempname, BONESPREFIX, 0); 416. 	(void) unlink(tempname); 417. }  418.  #endif /* MFLOPPY */ 419.  420.  /* move completed bones file to proper name */ 421. void 422. commit_bonesfile(lev) 423. d_level *lev; 424. {  425.  	const char *fq_bones, *tempname; 426. 	int ret; 427.  428.  	(void) set_bonesfile_name(bones, lev); 429. 	fq_bones = fqname(bones, BONESPREFIX, 0); 430. 	tempname = set_bonestemp_name; 431. 	tempname = fqname(tempname, BONESPREFIX, 1); 432.  433.  #if (defined(SYSV) && !defined(SVR4)) || defined(GENIX) 434. 	/* old SYSVs don't have rename. Some SVR3's may, but since they 435. 	 * also have link/unlink, it doesn't matter. :-) 436.  	 */  437.  	(void) unlink(fq_bones);  438.  	ret = link(tempname, fq_bones);  439.  	ret += unlink(tempname);  440.  #else  441.  	ret = rename(tempname, fq_bones);  442.  #endif  443.  #ifdef WIZARD  444.  	if (wizard && ret != 0)  445.  		pline("couldn't rename %s to %s", tempname, fq_bones);  446.  #endif  447.  }  448.   449.   450.  int  451.  open_bonesfile(lev, bonesid)  452.  d_level *lev;  453.  char **bonesid;  454.  {  455.  	const char *fq_bones;  456.  	int fd;  457.   458.  	*bonesid = set_bonesfile_name(bones, lev);  459.  	fq_bones = fqname(bones, BONESPREFIX, 0);  460.  	uncompress(fq_bones);	/* no effect if nonexistent */  461.  #ifdef MAC  462.  	fd = macopen(fq_bones, O_RDONLY | O_BINARY, BONE_TYPE);  463.  #else  464.  	fd = open(fq_bones, O_RDONLY | O_BINARY, 0);  465.  #endif  466.  	return fd;  467.  }  468.   469.   470.  int  471.  delete_bonesfile(lev) 472. d_level *lev; 473. {  474.  	(void) set_bonesfile_name(bones, lev); 475. 	return !(unlink(fqname(bones, BONESPREFIX, 0)) < 0); 476. }  477.   478.   479.  /* assume we're compressing the recently read or created bonesfile, so the 480.  * file name is already set properly */ 481. void 482. compress_bonesfile 483. {  484.  	compress(fqname(bones, BONESPREFIX, 0)); 485. }  486.   487.  /* --  END BONES FILE HANDLING --- */ 488.  489.   490.  /* --  BEGIN SAVE FILE HANDLING --- */ 491.  492.  /* set savefile name in OS-dependent manner from pre-existing plname, 493.  * avoiding troublesome characters */ 494. void 495. set_savefile_name 496. {  497.  #ifdef VMS 498. 	Sprintf(SAVEF, "[.save]%d%s", getuid, plname); 499. 	regularize(SAVEF+7); 500. 	Strcat(SAVEF, ";1"); 501. #else 502. # if defined(MICRO) && !defined(WIN32) 503. 	Strcpy(SAVEF, SAVEP); 504. #  ifdef AMIGA 505. 	strncat(SAVEF, bbs_id, PATHLEN); 506. #  endif 507. 	{  508.  		int i = strlen(SAVEP); 509. #  ifdef AMIGA 510. 		/* plname has to share space with SAVEP and ".sav" */ 511. 		(void)strncat(SAVEF, plname, FILENAME - i - 4); 512. #  else 513. 		(void)strncat(SAVEF, plname, 8); 514. #  endif 515. 		regularize(SAVEF+i); 516. 	}  517.  	Strcat(SAVEF, ".sav"); 518. # else 519. #  if defined(WIN32) 520. 	Sprintf(SAVEF,"%s-%s.NetHack-saved-game",get_username(0), plname); 521. #  else 522. 	Sprintf(SAVEF, "save/%d%s", (int)getuid, plname); 523. 	regularize(SAVEF+5);	/* avoid. or / in name */ 524. #  endif /* WIN32 */ 525. # endif	/* MICRO */ 526. #endif /* VMS   */ 527. }  528.   529.  #ifdef INSURANCE 530. void 531. save_savefile_name(fd) 532. int fd; 533. {  534.  	(void) write(fd, (genericptr_t) SAVEF, sizeof(SAVEF)); 535. }  536.  #endif 537.  538.   539.  #if defined(WIZARD) && !defined(MICRO) 540. /* change pre-existing savefile name to indicate an error savefile */ 541. void 542. set_error_savefile 543. {  544.  # ifdef VMS 545.       {  546.  	char *semi_colon = rindex(SAVEF, ';'); 547. 	if (semi_colon) *semi_colon = '\0'; 548.       }  549.  	Strcat(SAVEF, ".e;1"); 550. # else 551. #  ifdef MAC 552. 	Strcat(SAVEF, "-e"); 553. #  else 554. 	Strcat(SAVEF, ".e"); 555. #  endif 556. # endif 557. }  558.  #endif 559.  560.   561.  /* create save file, overwriting one if it already exists */ 562. int 563. create_savefile 564. {  565.  	const char *fq_save; 566. 	int fd; 567.  568.  	fq_save = fqname(SAVEF, SAVEPREFIX, 0); 569. #ifdef MICRO 570. 	fd = open(fq_save, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK); 571. #else 572. # ifdef MAC 573. 	fd = maccreat(fq_save, SAVE_TYPE); 574. # else 575. 	fd = creat(fq_save, FCMASK); 576. # endif 577. # if defined(VMS) && !defined(SECURE) 578. 	/*  579.  	   Make sure the save file is owned by the current process. That's 580. the default for non-privileged users, but for priv'd users the 581. 	   file will be owned by the directory's owner instead of the user. 582. 	 */  583.  #  ifdef getuid	/*(see vmsunix.c)*/ 584. #   undef getuid 585. #  endif 586. 	(void) chown(fq_save, getuid, getgid); 587. # endif /* VMS && !SECURE */ 588. #endif	/* MICRO */ 589.  590.  	return fd; 591. }  592.   593.   594.  /* open savefile for reading */ 595. int 596. open_savefile 597. {  598.  	const char *fq_save; 599. 	int fd; 600.  601.  	fq_save = fqname(SAVEF, SAVEPREFIX, 0); 602. #ifdef MAC 603. 	fd = macopen(fq_save, O_RDONLY | O_BINARY, SAVE_TYPE); 604. #else 605. 	fd = open(fq_save, O_RDONLY | O_BINARY, 0); 606. #endif 607. 	return fd; 608. }  609.   610.   611.  /* delete savefile */ 612. int 613. delete_savefile 614. {  615.  	(void) unlink(fqname(SAVEF, SAVEPREFIX, 0)); 616. 	return 0;	/* for restore_saved_game (ex-xxxmain.c) test */ 617. }  618.   619.   620.  /* try to open up a save file and prepare to restore it */ 621. int 622. restore_saved_game 623. {  624.  	const char *fq_save; 625. 	int fd; 626.  627.  	set_savefile_name; 628. #ifdef MFLOPPY 629. 	if (!saveDiskPrompt(1)) 630. 	    return -1; 631. #endif /* MFLOPPY */ 632. 	fq_save = fqname(SAVEF, SAVEPREFIX, 0); 633.  634.  	uncompress(fq_save); 635. 	if ((fd = open_savefile) < 0) return fd; 636.  637.  	if (!uptodate(fd, fq_save)) { 638. 	    (void) close(fd),  fd = -1; 639. 	    (void) delete_savefile; 640. 	}  641.  	return fd; 642. }  643.   644.  /* --  END SAVE FILE HANDLING --- */ 645.  646.   647.  /* --  BEGIN FILE COMPRESSION HANDLING --- */ 648.  649.  #ifdef COMPRESS 650.  651.  STATIC_OVL void 652. redirect(filename, mode, stream, uncomp) 653. const char *filename, *mode; 654. FILE *stream; 655. boolean uncomp; 656. {  657.  	if (freopen(filename, mode, stream) == (FILE *)0) { 658. 		(void) fprintf(stderr, "freopen of %s for %scompress failed\n",  659.  			filename, uncomp ? "un" : ""); 660. 		terminate(EXIT_FAILURE); 661. 	}  662.  }  663.   664.  /*  665.   * using system is simpler, but opens up security holes and causes 666.  * problems on at least Interactive UNIX 3.0.1 (SVR3.2), where any 667.  * setuid is renounced by /bin/sh, so the files cannot be accessed. 668.  *  669.   * cf. child in unixunix.c. 670. */ 671.  STATIC_OVL void 672. docompress_file(filename, uncomp) 673. const char *filename; 674. boolean uncomp; 675. {  676.  	char cfn[80]; 677. 	FILE *cf; 678. 	const char *args[10]; 679. # ifdef COMPRESS_OPTIONS 680. 	char opts[80]; 681. # endif 682. 	int i = 0; 683. 	int f;  684. # ifdef TTY_GRAPHICS 685. 	boolean istty = !strncmpi(windowprocs.name, "tty", 3); 686. # endif 687.  688.  	Strcpy(cfn, filename); 689. # ifdef COMPRESS_EXTENSION 690. 	Strcat(cfn, COMPRESS_EXTENSION); 691. # endif 692. 	/* when compressing, we know the file exists */ 693. 	if (uncomp) { 694. 	    if ((cf = fopen(cfn, RDBMODE)) == (FILE *)0) 695. 		    return; 696. 	    (void) fclose(cf); 697. 	}  698.   699.  	args[0] = COMPRESS; 700. 	if (uncomp) args[++i] = "-d";	/* uncompress */ 701. # ifdef COMPRESS_OPTIONS 702. 	{  703.  	    /* we can't guarantee there's only one additional option, sigh */ 704. 	    char *opt; 705. 	    boolean inword = FALSE; 706.  707.  	    Strcpy(opts, COMPRESS_OPTIONS); 708. 	    opt = opts; 709. 	    while (*opt) { 710. 		if ((*opt == ' ') || (*opt == '\t')) { 711. 		    if (inword) { 712. 			*opt = '\0'; 713. 			inword = FALSE; 714. 		    }  715.  		} else if (!inword) { 716. 		    args[++i] = opt; 717. 		    inword = TRUE; 718. 		}  719.  		opt++; 720. 	    }  721.  	}  722.  # endif 723. 	args[++i] = (char *)0; 724.  725.  	f = fork; 726. # ifdef TTY_GRAPHICS 727. 	/* If we don't do this and we are right after a y/n question *and* 728. 	 * there is an error message from the compression, the 'y' or 'n' can 729. 	 * end up being displayed after the error message. 730. 	 */  731.  	if (istty) 732. 	    mark_synch; 733. # endif 734. 	if (f == 0) {	/* child */ 735. # ifdef TTY_GRAPHICS 736. 		/* any error messages from the compression must come out after 737. 		 * the first line, because the more to let the user read 738. 		 * them will have to clear the first line. This should be 739. * invisible if there are no error messages. 740. 		 */  741.  		if (istty) 742. 		    raw_print(""); 743. # endif 744. 		/* run compressor without privileges, in case other programs 745. 		 * have surprises along the line of gzip once taking filenames 746. 		 * in GZIP. 747. 		 */  748.  		/* assume all compressors will compress stdin to stdout 749. 		 * without explicit filenames. this is true of at least 750. 		 * compress and gzip, those mentioned in config.h.  751. */ 752.  		if (uncomp) { 753. 			redirect(cfn, RDBMODE, stdin, uncomp); 754. 			redirect(filename, WRBMODE, stdout, uncomp); 755. 		} else { 756. 			redirect(filename, RDBMODE, stdin, uncomp); 757. 			redirect(cfn, WRBMODE, stdout, uncomp); 758. 		}  759.  		(void) setgid(getgid); 760. 		(void) setuid(getuid); 761. 		(void) execv(args[0], (char *const *) args); 762. 		perror((char *)0); 763. 		(void) fprintf(stderr, "Exec to %scompress %s failed.\n",  764.  			uncomp ? "un" : "", filename); 765. 		terminate(EXIT_FAILURE); 766. 	} else if (f == -1) { 767. 		perror((char *)0); 768. 		pline("Fork to %scompress %s failed.",  769.  			uncomp ? "un" : "", filename); 770. 		return; 771. 	}  772.  	(void) signal(SIGINT, SIG_IGN); 773. 	(void) signal(SIGQUIT, SIG_IGN); 774. 	(void) wait((int *)&i); 775. 	(void) signal(SIGINT, (SIG_RET_TYPE) done1); 776. # ifdef WIZARD 777. 	if (wizard) (void) signal(SIGQUIT, SIG_DFL); 778. # endif 779. 	if (i == 0) { 780. 	    /* (un)compress succeeded: remove file left behind */ 781. 	    if (uncomp) 782. 		(void) unlink(cfn); 783. 	    else 784. 		(void) unlink(filename); 785. 	} else { 786. 	    /* (un)compress failed; remove the new, bad file */ 787. 	    if (uncomp) { 788. 		raw_printf("Unable to uncompress %s", filename); 789. 		(void) unlink(filename); 790. 	    } else { 791. 		/* no message needed for compress case; life will go on */ 792. 		(void) unlink(cfn); 793. 	    }  794.  #ifdef TTY_GRAPHICS 795. 	    /* Give them a chance to read any error messages from the 796. 	     * compression--these would go to stdout or stderr and would get 797. 	     * overwritten only in tty mode. It's still ugly, since the 798. 	     * messages are being written on top of the screen, but at least 799. 	     * the user can read them. 800. 	     */  801.  	    if (istty) 802. 	    {  803.  		clear_nhwindow(WIN_MESSAGE); 804. 		more; 805. 		/* No way to know if this is feasible */ 806. 		/* doredraw; */ 807. 	    }  808.  #endif 809. 	}  810.  }  811.  #endif	/* COMPRESS */ 812.  813.  /* compress file */ 814. void 815. compress(filename) 816. const char *filename; 817. {  818.  #ifndef COMPRESS 819. #if (defined(macintosh) && (defined(__SC__) || defined(__MRC__))) || defined(__MWERKS__) 820. # pragma unused(filename) 821. #endif 822. #else 823. 	docompress_file(filename, FALSE); 824. #endif 825. }  826.   827.   828.  /* uncompress file if it exists */ 829. void 830. uncompress(filename) 831. const char *filename; 832. {  833.  #ifndef COMPRESS 834. #if (defined(macintosh) && (defined(__SC__) || defined(__MRC__))) || defined(__MWERKS__) 835. # pragma unused(filename) 836. #endif 837. #else 838. 	docompress_file(filename, TRUE); 839. #endif 840. }  841.   842.  /* --  END FILE COMPRESSION HANDLING --- */ 843.  844.   845.  /* --  BEGIN FILE LOCKING HANDLING --- */ 846.  847.  static int nesting = 0; 848.  849.  #ifdef NO_FILE_LINKS	/* implies UNIX */ 850. static int lockfd;	/* for lock_file to pass to unlock_file */ 851. #endif 852.  853.  #define HUP	if (!program_state.done_hup) 854.  855.  STATIC_OVL char * 856. make_lockname(filename, lockname) 857. const char *filename; 858. char *lockname; 859. {  860.  #if (defined(macintosh) && (defined(__SC__) || defined(__MRC__))) || defined(__MWERKS__) 861. # pragma unused(filename,lockname) 862. 	return (char*)0; 863. #else 864. # if defined(UNIX) || defined(VMS) || defined(AMIGA) || defined(WIN32) || defined(MSDOS) 865. #  ifdef NO_FILE_LINKS 866. 	Strcpy(lockname, LOCKDIR); 867. 	Strcat(lockname, "/"); 868. 	Strcat(lockname, filename); 869. #  else 870. 	Strcpy(lockname, filename); 871. #  endif 872. #  ifdef VMS 873.       {  874.  	char *semi_colon = rindex(lockname, ';'); 875. 	if (semi_colon) *semi_colon = '\0'; 876.       }  877.  	Strcat(lockname, ".lock;1"); 878. #  else 879. 	Strcat(lockname, "_lock"); 880. #  endif 881. 	return lockname; 882. # else 883. 	lockname[0] = '\0'; 884. 	return (char*)0; 885. # endif  /* UNIX || VMS || AMIGA || WIN32 || MSDOS */ 886. #endif 887. }  888.   889.   890.  /* lock a file */ 891. boolean 892. lock_file(filename, whichprefix, retryct) 893. const char *filename; 894. int whichprefix; 895. int retryct; 896. {  897.  #if (defined(macintosh) && (defined(__SC__) || defined(__MRC__))) || defined(__MWERKS__) 898. # pragma unused(filename, retryct) 899. #endif 900. 	char locknambuf[BUFSZ]; 901. 	const char *lockname; 902.  903.  	nesting++; 904. 	if (nesting > 1) { 905. 	    impossible("TRIED TO NEST LOCKS"); 906. 	    return TRUE; 907. 	}  908.   909.  	lockname = make_lockname(filename, locknambuf); 910. 	filename = fqname(filename, whichprefix, 0); 911. #ifndef NO_FILE_LINKS	/* LOCKDIR should be subsumed by LOCKPREFIX */ 912. 	lockname = fqname(lockname, LOCKPREFIX, 1); 913. #endif 914.  915.  #if defined(UNIX) || defined(VMS) 916. # ifdef NO_FILE_LINKS 917. 	while ((lockfd = open(lockname, O_RDWR|O_CREAT|O_EXCL, 0666)) == -1) { 918. # else 919. 	while (link(filename, lockname) == -1) { 920. # endif 921. 	    register int errnosv = errno; 922.  923.  	    switch (errnosv) {	/* George Barbanis */ 924. 	    case EEXIST: 925. 		if (retryct--) { 926. 		    HUP raw_printf(  927.  			    "Waiting for access to %s.  (%d retries left).",  928.  			    filename, retryct); 929. # if defined(SYSV) || defined(ULTRIX) || defined(VMS) 930. 		    (void) 931. # endif 932. 			sleep(1); 933. 		} else { 934. 		    HUP (void) raw_print("I give up.  Sorry."); 935. 		    HUP raw_printf("Perhaps there is an old %s around?",  936.  					lockname); 937. 		    nesting--; 938. 		    return FALSE; 939. 		}  940.   941.  		break; 942. 	    case ENOENT: 943. 		HUP raw_printf("Can't find file %s to lock!", filename); 944. 		nesting--; 945. 		return FALSE; 946. 	    case EACCES: 947. 		HUP raw_printf("No write permission to lock %s!", filename); 948. 		nesting--; 949. 		return FALSE; 950. # ifdef VMS			/* c__translate(vmsfiles.c) */ 951. 	    case EPERM: 952. 		/* could be misleading, but usually right */ 953. 		HUP raw_printf("Can't lock %s due to directory protection.",  954.  			       filename); 955. 		nesting--; 956. 		return FALSE; 957. # endif 958. 	    default: 959. 		HUP perror(lockname); 960. 		HUP raw_printf(  961.  			     "Cannot lock %s for unknown reason (%d).",  962.  			       filename, errnosv); 963. 		nesting--; 964. 		return FALSE; 965. 	    }  966.   967.  	}  968.  #endif  /* UNIX || VMS */ 969.  970.  #if defined(AMIGA) || defined(WIN32) || defined(MSDOS) 971.     lockptr = 0; 972.     while (retryct-- && !lockptr) { 973. # ifdef AMIGA 974. 	(void)DeleteFile(lockname); /* in case dead process was here first */ 975. 	lockptr = Open(lockname,MODE_NEWFILE); 976. # else 977. 	lockptr = open(lockname, O_RDWR|O_CREAT|O_EXCL, S_IWRITE); 978. # endif 979. 	if (!lockptr) { 980. 	    raw_printf("Waiting for access to %s.  (%d retries left).",  981.  			filename, retryct); 982. 	    Delay(50); 983. 	}  984.      }  985.      if (!retryct) { 986. 	raw_printf("I give up.  Sorry."); 987. 	nesting--; 988. 	return FALSE; 989.     }  990.  #endif /* AMIGA || WIN32 || MSDOS */ 991. 	return TRUE; 992. }  993.   994.   995.  #ifdef VMS	/* for unlock_file, use the unlink routine in vmsunix.c */ 996. # ifdef unlink 997. #  undef unlink 998. # endif 999. # define unlink(foo) vms_unlink(foo) 1000. #endif 1001. 1002. /* unlock file, which must be currently locked by lock_file */ 1003. void 1004. unlock_file(filename) 1005. const char *filename; 1006. #if defined(macintosh) && (defined(__SC__) || defined(__MRC__)) 1007. # pragma unused(filename) 1008. #endif 1009. { 1010. 	char locknambuf[BUFSZ]; 1011. 	const char *lockname; 1012. 1013. 	if (nesting == 1) { 1014. 		lockname = make_lockname(filename, locknambuf); 1015. #ifndef NO_FILE_LINKS	/* LOCKDIR should be subsumed by LOCKPREFIX */ 1016. 		lockname = fqname(lockname, LOCKPREFIX, 1); 1017. #endif 1018. 1019. #if defined(UNIX) || defined(VMS) 1020. 		if (unlink(lockname) < 0) 1021. 			HUP raw_printf("Can't unlink %s.", lockname); 1022. # ifdef NO_FILE_LINKS 1023. 		(void) close(lockfd); 1024. # endif 1025. 1026. #endif  /* UNIX || VMS */ 1027. 1028. #if defined(AMIGA) || defined(WIN32) || defined(MSDOS) 1029. 		if (lockptr) Close(lockptr); 1030. 		DeleteFile(lockname); 1031. 		lockptr = 0; 1032. #endif /* AMIGA || WIN32 || MSDOS */ 1033. 	} 1034.  1035. 	nesting--; 1036. } 1037.  1038. /* --  END FILE LOCKING HANDLING --- */ 1039. 1040.  1041. /* --  BEGIN CONFIG FILE HANDLING --- */ 1042. 1043. const char *configfile = 1044. #ifdef UNIX 1045. 			".nethackrc"; 1046. #else 1047. # if defined(MAC) || defined(__BEOS__) 1048. 			"NetHack Defaults"; 1049. # else 1050. # if defined(MSDOS) || defined(WIN32) 1051. 			"defaults.nh"; 1052. # else 1053. 			"NetHack.cnf"; 1054. # endif 1055. # endif 1056. #endif 1057. 1058.  1059. #ifdef MSDOS 1060. /* conflict with speed-dial under windows 1061. * for XXX.cnf file so support of NetHack.cnf 1062. * is for backward compatibility only. 1063. * Preferred name (and first tried) is now defaults.nh but 1064. * the game will try the old name if there 1065. * is no defaults.nh. 1066. */  1067. const char *backward_compat_configfile = "nethack.cnf"; 1068. #endif 1069. 1070. #ifndef MFLOPPY 1071. #define fopenp fopen 1072. #endif 1073. 1074. STATIC_OVL FILE * 1075. fopen_config_file(filename) 1076. const char *filename; 1077. { 1078. 	FILE *fp; 1079. #if defined(UNIX) || defined(VMS) 1080. 	char	tmp_config[BUFSZ]; 1081. 	char *envp; 1082. #endif 1083. 1084. 	/* "filename" is an environment variable, so it should hang around */ 1085. 	/* if set, it is expected to be a full path name (if relevant) */ 1086. 	if (filename) { 1087. #ifdef UNIX 1088. 		if (access(filename, 4) == -1) { 1089. 			/* 4 is R_OK on newer systems */ 1090. 			/* nasty sneaky attempt to read file through 1091. 			 * NetHack's setuid permissions -- this is the only 1092. 			 * place a file name may be wholly under the player's 1093. * control 1094. 			 */ 1095. 			raw_printf("Access to %s denied (%d).",  1096. 					filename, errno); 1097. 			wait_synch; 1098. 			/* fall through to standard names */ 1099. 		} else 1100. #endif 1101. 		if ((fp = fopenp(filename, "r")) != (FILE *)0) { 1102. 		   configfile = filename; 1103. 		   return(fp); 1104. #if defined(UNIX) || defined(VMS) 1105. 		} else { 1106. 		   /* access above probably caught most problems for UNIX */ 1107. 		   raw_printf("Couldn't open requested config file %s (%d).",  1108. 					filename, errno); 1109. 		   wait_synch; 1110. 		   /* fall through to standard names */ 1111. #endif 1112. 		} 1113. 	}  1114.  1115. #if defined(MICRO) || defined(MAC) || defined(__BEOS__) 1116. 	if ((fp = fopenp(fqname(configfile, CONFIGPREFIX, 0), "r")) 1117. 								!= (FILE *)0) 1118. 		return(fp); 1119. # ifdef MSDOS 1120. 	else if ((fp = fopenp(fqname(backward_compat_configfile, 1121. 					CONFIGPREFIX, 0), "r")) != (FILE *)0) 1122. 		return(fp); 1123. # endif 1124. #else 1125. 	/* constructed full path names don't need fqname */ 1126. # ifdef VMS 1127. 	if ((fp = fopenp(fqname("nethackini", CONFIGPREFIX, 0), "r")) 1128. 								!= (FILE *)0) { 1129. 		configfile = "nethackini"; 1130. 		return(fp); 1131. 	} 1132. 	if ((fp = fopenp("sys$login:nethack.ini", "r")) != (FILE *)0) { 1133. 		configfile = "nethack.ini"; 1134. 		return(fp); 1135. 	} 1136.  1137. 	envp = nh_getenv("HOME"); 1138. 	if (!envp) 1139. 		Strcpy(tmp_config, "NetHack.cnf"); 1140. 	else 1141. 		Sprintf(tmp_config, "%s%s", envp, "NetHack.cnf"); 1142. 	if ((fp = fopenp(tmp_config, "r")) != (FILE *)0) 1143. 		return(fp); 1144. # else	/* should be only UNIX left */ 1145. 	envp = nh_getenv("HOME"); 1146. 	if (!envp) 1147. 		Strcpy(tmp_config, ".nethackrc"); 1148. 	else 1149. 		Sprintf(tmp_config, "%s/%s", envp, ".nethackrc"); 1150. 	if ((fp = fopenp(tmp_config, "r")) != (FILE *)0) 1151. 		return(fp); 1152. 	else if (errno != ENOENT) { 1153. 		/* e.g., problems when setuid NetHack can't search home 1154. 		 * directory restricted to user */ 1155. 		raw_printf("Couldn't open default config file %s (%d).", 1156. 					tmp_config, errno); 1157. 		wait_synch; 1158. 	} 1159. # endif 1160. #endif 1161. 	return (FILE *)0; 1162. 1163. }  1164.  1165.  1166. /*  1167.  * Retrieve a list of integers from a file into a uchar array. 1168. *  1169.  * NOTE:  This routine is unable to read a value of 0. 1170. */  1171. STATIC_OVL int 1172. get_uchars(fp, buf, bufp, list, size, name) 1173.    FILE *fp;		/* input file pointer */ 1174.    char *buf;		/* read buffer, must be of size BUFSZ */ 1175.    char *bufp;		/* current pointer */ 1176.    uchar *list;	/* return list */ 1177.    int  size;		/* return list size */ 1178.    const char *name;		/* name of option for error message */ 1179. { 1180.     unsigned int num = 0; 1181.    int count = 0; 1182. 1183.     while (1) { 1184. 	switch(*bufp) { 1185. 	   case ' ':  case '\0': 1186. 	   case '\t': case '\n': 1187. 		if (num) { 1188. 		   list[count++] =  num; 1189. 		   num = 0; 1190. 		} 1191. 		if (count == size || !*bufp) return count; 1192. 		bufp++; 1193. 		break; 1194. 1195. 	    case '0': case '1': case '2': case '3': 1196. 	   case '4': case '5': case '6': case '7': 1197. 	   case '8': case '9': 1198. 		num = num*10 + (*bufp-'0'); 1199. 		bufp++; 1200. 		break; 1201. 1202. 	    case '\\': 1203. 		if (fp == (FILE *)0) 1204. 		   goto gi_error; 1205. 		do { 1206. 		   if (!fgets(buf, BUFSZ, fp)) goto gi_error; 1207. 		} while (buf[0] == '#'); 1208. 		bufp = buf; 1209. 		break; 1210. 1211. 	    default: 1212. gi_error: 1213. 		raw_printf("Syntax error in %s", name); 1214. 		wait_synch; 1215. 		return count; 1216. 	} 1217.     }  1218.     /*NOTREACHED*/ 1219. } 1220.  1221. #ifdef NOCWD_ASSUMPTIONS 1222. STATIC_OVL void 1223. adjust_prefix(bufp, prefixid) 1224. char *bufp; 1225. int prefixid; 1226. { 1227. 	char *ptr; 1228. 1229. 	if (!bufp) return; 1230. 	/* Backward compatibility, ignore trailing ;n */ 1231. 	if ((ptr = index(bufp, ';')) != 0) *ptr = '\0'; 1232. 	if (strlen(bufp) > 0) { 1233. 		fqn_prefix[prefixid] = (char *)alloc(strlen(bufp)+2); 1234. 		Strcpy(fqn_prefix[prefixid], bufp); 1235. 		append_slash(fqn_prefix[prefixid]); 1236. 	} 1237. }  1238. #endif 1239. 1240. #define match_varname(INP,NAM,LEN) match_optname(INP, NAM, LEN, TRUE) 1241. 1242. /*ARGSUSED*/ 1243. int 1244. parse_config_line(fp, buf, tmp_ramdisk, tmp_levels) 1245. FILE		*fp; 1246. char		*buf; 1247. char		*tmp_ramdisk; 1248. char		*tmp_levels; 1249. { 1250. #if (defined(macintosh) && (defined(__SC__) || defined(__MRC__))) || defined(__MWERKS__) 1251. # pragma unused(tmp_ramdisk,tmp_levels) 1252. #endif 1253. 	char		*bufp, *altp; 1254. 	uchar  translate[MAXPCHARS]; 1255. 	int  len; 1256. 1257. 	if (*buf == '#') 1258. 		return 1; 1259. 1260. 	/* remove trailing whitespace */ 1261. 	bufp = eos(buf); 1262. 	while (--bufp > buf && isspace(*bufp)) 1263. 		continue; 1264. 1265. 	if (bufp <= buf) 1266. 		return 1;		/* skip all-blank lines */ 1267. 	else 1268. 		*(bufp + 1) = '\0';	/* terminate line */ 1269. 1270. 	/* find the '=' or ':' */ 1271. 	bufp = index(buf, '='); 1272. 	altp = index(buf, ':'); 1273. 	if (!bufp || (altp && altp < bufp)) bufp = altp; 1274. 	if (!bufp) return 0; 1275. 1276. 	/* skip  whitespace between '=' and value */ 1277. 	do { ++bufp; } while (isspace(*bufp)); 1278. 1279. 	/* Go through possible variables */ 1280. 	/* some of these (at least LEVELS and SAVE) should now set the 1281. 	 * appropriate fqn_prefix[] rather than specialized variables 1282. 	 */ 1283. 	if (match_varname(buf, "OPTIONS", 4)) { 1284. 		parseoptions(bufp, TRUE, TRUE); 1285. 		if (plname[0])		/* If a name was given */ 1286. 			plnamesuffix;	/* set the character class */ 1287. #ifdef NOCWD_ASSUMPTIONS 1288. 	} else if (match_varname(buf, "HACKDIR", 4)) { 1289. 		adjust_prefix(bufp, HACKPREFIX); 1290. 	} else if (match_varname(buf, "LEVELDIR", 4) || 1291. 		   match_varname(buf, "LEVELS", 4)) { 1292. 		adjust_prefix(bufp, LEVELPREFIX); 1293. 	} else if (match_varname(buf, "SAVE", 4)) { 1294. 		adjust_prefix(bufp, SAVEPREFIX); 1295. 	} else if (match_varname(buf, "BONESDIR", 5)) { 1296. 		adjust_prefix(bufp, BONESPREFIX); 1297. 	} else if (match_varname(buf, "DATADIR", 4)) { 1298. 		adjust_prefix(bufp, DATAPREFIX); 1299. 	} else if (match_varname(buf, "SCOREDIR", 4)) { 1300. 		adjust_prefix(bufp, SCOREPREFIX); 1301. 	} else if (match_varname(buf, "LOCKDIR", 4)) { 1302. 		adjust_prefix(bufp, LOCKPREFIX); 1303. 	} else if (match_varname(buf, "CONFIGDIR", 4)) { 1304. 		adjust_prefix(bufp, CONFIGPREFIX); 1305. #else /*NOCWD_ASSUMPTIONS*/ 1306. # ifdef MICRO 1307. 	} else if (match_varname(buf, "HACKDIR", 4)) { 1308. 		(void) strncpy(hackdir, bufp, PATHLEN-1); 1309. # ifdef MFLOPPY 1310. 	} else if (match_varname(buf, "RAMDISK", 3)) { 1311. 				/* The following ifdef is NOT in the wrong 1312. 				 * place. For now, we accept and silently 1313. 				 * ignore RAMDISK */ 1314. #  ifndef AMIGA 1315. 		(void) strncpy(tmp_ramdisk, bufp, PATHLEN-1); 1316. #  endif 1317. # endif 1318. 	} else if (match_varname(buf, "LEVELS", 4)) { 1319. 		(void) strncpy(tmp_levels, bufp, PATHLEN-1); 1320. 1321. 	} else if (match_varname(buf, "SAVE", 4)) { 1322. # ifdef MFLOPPY 1323. 		extern	int saveprompt; 1324. # endif 1325. 		char *ptr; 1326. 		if ((ptr = index(bufp, ';')) != 0) { 1327. 			*ptr = '\0'; 1328. # ifdef MFLOPPY 1329. 			if (*(ptr+1) == 'n' || *(ptr+1) == 'N') { 1330. 				saveprompt = FALSE; 1331. 			} 1332. #  endif 1333. 		} 1334. # ifdef	MFLOPPY 1335. 		else 1336. 		   saveprompt = flags.asksavedisk; 1337. # endif 1338. 1339. 		(void) strncpy(SAVEP, bufp, SAVESIZE-1); 1340. 		append_slash(SAVEP); 1341. # endif /* MICRO */ 1342. #endif /*NOCWD_ASSUMPTIONS*/ 1343. 1344. 	} else if (match_varname(buf, "NAME", 4)) { 1345. 	   (void) strncpy(plname, bufp, PL_NSIZ-1); 1346. 	   plnamesuffix; 1347. 	} else if (match_varname(buf, "ROLE", 4) || 1348. 		   match_varname(buf, "CHARACTER", 4)) { 1349. 	   if ((len = str2role(bufp)) >= 0) 1350. 	   	flags.initrole = len; 1351. 	} else if (match_varname(buf, "DOGNAME", 3)) { 1352. 	   (void) strncpy(dogname, bufp, PL_PSIZ-1); 1353. 	} else if (match_varname(buf, "CATNAME", 3)) { 1354. 	   (void) strncpy(catname, bufp, PL_PSIZ-1); 1355. 1356. 	} else if (match_varname(buf, "BOULDER", 3)) { 1357. 	   (void) get_uchars(fp, buf, bufp, &iflags.bouldersym, 1, "BOULDER"); 1358. 	} else if (match_varname(buf, "GRAPHICS", 4)) { 1359. 	   len = get_uchars(fp, buf, bufp, translate, MAXPCHARS, "GRAPHICS"); 1360. 	   assign_graphics(translate, len, MAXPCHARS, 0); 1361. 	} else if (match_varname(buf, "DUNGEON", 4)) { 1362. 	   len = get_uchars(fp, buf, bufp, translate, MAXDCHARS, "DUNGEON"); 1363. 	   assign_graphics(translate, len, MAXDCHARS, 0); 1364. 	} else if (match_varname(buf, "TRAPS", 4)) { 1365. 	   len = get_uchars(fp, buf, bufp, translate, MAXTCHARS, "TRAPS"); 1366. 	   assign_graphics(translate, len, MAXTCHARS, MAXDCHARS); 1367. 	} else if (match_varname(buf, "EFFECTS", 4)) { 1368. 	   len = get_uchars(fp, buf, bufp, translate, MAXECHARS, "EFFECTS"); 1369. 	   assign_graphics(translate, len, MAXECHARS, MAXDCHARS+MAXTCHARS); 1370. 1371. 	} else if (match_varname(buf, "OBJECTS", 3)) { 1372. 	   /* oc_syms[0] is the RANDOM object, unused */ 1373. 	   (void) get_uchars(fp, buf, bufp, &(oc_syms[1]),  1374. 					MAXOCLASSES-1, "OBJECTS"); 1375. 	} else if (match_varname(buf, "MONSTERS", 3)) { 1376. 	   /* monsyms[0] is unused */ 1377. 	   (void) get_uchars(fp, buf, bufp, &(monsyms[1]),  1378. 					MAXMCLASSES-1, "MONSTERS"); 1379. 	} else if (match_varname(buf, "WARNINGS", 5)) { 1380. 	   (void) get_uchars(fp, buf, bufp, translate,  1381. 					WARNCOUNT, "WARNINGS"); 1382. 	   assign_warnings(translate); 1383. #ifdef WIZARD 1384. 	} else if (match_varname(buf, "WIZKIT", 6)) { 1385. 	   (void) strncpy(wizkit, bufp, WIZKIT_MAX-1); 1386. #endif 1387. #ifdef AMIGA 1388. 	} else if (match_varname(buf, "FONT", 4)) { 1389. 		char *t; 1390. 1391. 		if( t = strchr( buf+5, ':' ) ) 1392. 		{ 1393. 		    *t = 0; 1394. 		   amii_set_text_font( buf+5, atoi( t + 1 ) ); 1395. 		   *t = ':'; 1396. 		} 1397. 	} else if (match_varname(buf, "PATH", 4)) { 1398. 		(void) strncpy(PATH, bufp, PATHLEN-1); 1399. 	} else if (match_varname(buf, "DEPTH", 5)) { 1400. 		extern int amii_numcolors; 1401. 		int val = atoi( bufp ); 1402. 		amii_numcolors = 1L << min( DEPTH, val ); 1403. 	} else if (match_varname(buf, "DRIPENS", 7)) { 1404. 		int i, val; 1405. 		char *t; 1406. 		for (i = 0, t = strtok(bufp, ",/"); t != (char *)0; 1407. 				i < 20 && (t = strtok((char*)0, ",/")), ++i) { 1408. 			sscanf(t, "%d", &val ); 1409. 			flags.amii_dripens[i] = val; 1410. 		} 1411. 	} else if (match_varname(buf, "SCREENMODE", 10 )) { 1412. 		extern long amii_scrnmode; 1413. 		if (!stricmp(bufp,"req")) 1414. 		   amii_scrnmode = 0xffffffff; /* Requester */ 1415. 		else if( sscanf(bufp, "%x", &amii_scrnmode) != 1 ) 1416. 		   amii_scrnmode = 0; 1417. 	} else if (match_varname(buf, "MSGPENS", 7)) { 1418. 		extern int amii_msgAPen, amii_msgBPen; 1419. 		char *t = strtok(bufp, ",/"); 1420. 		if( t ) 1421. 		{ 1422. 		    sscanf(t, "%d", &amii_msgAPen); 1423. 		   if( t = strtok((char*)0, ",/") ) 1424. 				sscanf(t, "%d", &amii_msgBPen); 1425. 		} 1426. 	} else if (match_varname(buf, "TEXTPENS", 8)) { 1427. 		extern int amii_textAPen, amii_textBPen; 1428. 		char *t = strtok(bufp, ",/"); 1429. 		if( t ) 1430. 		{ 1431. 		    sscanf(t, "%d", &amii_textAPen); 1432. 		   if( t = strtok((char*)0, ",/") ) 1433. 				sscanf(t, "%d", &amii_textBPen); 1434. 		} 1435. 	} else if (match_varname(buf, "MENUPENS", 8)) { 1436. 		extern int amii_menuAPen, amii_menuBPen; 1437. 		char *t = strtok(bufp, ",/"); 1438. 		if( t ) 1439. 		{ 1440. 		    sscanf(t, "%d", &amii_menuAPen); 1441. 		   if( t = strtok((char*)0, ",/") ) 1442. 				sscanf(t, "%d", &amii_menuBPen); 1443. 		} 1444. 	} else if (match_varname(buf, "STATUSPENS", 10)) { 1445. 		extern int amii_statAPen, amii_statBPen; 1446. 		char *t = strtok(bufp, ",/"); 1447. 		if( t ) 1448. 		{ 1449. 		    sscanf(t, "%d", &amii_statAPen); 1450. 		   if( t = strtok((char*)0, ",/") ) 1451. 				sscanf(t, "%d", &amii_statBPen); 1452. 		} 1453. 	} else if (match_varname(buf, "OTHERPENS", 9)) { 1454. 		extern int amii_otherAPen, amii_otherBPen; 1455. 		char *t = strtok(bufp, ",/"); 1456. 		if( t ) 1457. 		{ 1458. 		    sscanf(t, "%d", &amii_otherAPen); 1459. 		   if( t = strtok((char*)0, ",/") ) 1460. 				sscanf(t, "%d", &amii_otherBPen); 1461. 		} 1462. 	} else if (match_varname(buf, "PENS", 4)) { 1463. 		extern unsigned short amii_init_map[ AMII_MAXCOLORS ]; 1464. 		int i; 1465. char *t; 1466. 1467. 		for (i = 0, t = strtok(bufp, ",/");  1468. 			i < AMII_MAXCOLORS && t != (char *)0;  1469. 			t = strtok((char *)0, ",/"), ++i) 1470. 		{ 1471. 			sscanf(t, "%hx", &amii_init_map[i]); 1472. 		} 1473. 		amii_setpens( amii_numcolors = i ); 1474. 	} else if (match_varname(buf, "FGPENS", 6)) { 1475. 		extern int foreg[ AMII_MAXCOLORS ]; 1476. 		int i; 1477. char *t; 1478. 1479. 		for (i = 0, t = strtok(bufp, ",/");  1480. 			i < AMII_MAXCOLORS && t != (char *)0;  1481. 			t = strtok((char *)0, ",/"), ++i) 1482. 		{ 1483. 			sscanf(t, "%d", &foreg[i]); 1484. 		} 1485. 	} else if (match_varname(buf, "BGPENS", 6)) { 1486. 		extern int backg[ AMII_MAXCOLORS ]; 1487. 		int i; 1488. char *t; 1489. 1490. 		for (i = 0, t = strtok(bufp, ",/");  1491. 			i < AMII_MAXCOLORS && t != (char *)0;  1492. 			t = strtok((char *)0, ",/"), ++i) 1493. 		{ 1494. 			sscanf(t, "%d", &backg[i]); 1495. 		} 1496. #endif 1497. #ifdef USER_SOUNDS 1498. 	} else if (match_varname(buf, "SOUNDDIR", 8)) { 1499. 		sounddir = (char *)strdup(bufp); 1500. 	} else if (match_varname(buf, "SOUND", 5)) { 1501. 		add_sound_mapping(bufp); 1502. #endif 1503. #ifdef QT_GRAPHICS 1504. 	} else if (match_varname(buf, "QT_TILEWIDTH", 12)) { 1505. 		extern char *qt_tilewidth; 1506. 		if (qt_tilewidth == NULL) 1507. 			qt_tilewidth=(char *)strdup(bufp); 1508. 	} else if (match_varname(buf, "QT_TILEHEIGHT", 13)) { 1509. 		extern char *qt_tileheight; 1510. 		if (qt_tileheight == NULL) 1511. 			qt_tileheight=(char *)strdup(bufp); 1512. 	} else if (match_varname(buf, "QT_FONTSIZE", 11)) { 1513. 		extern char *qt_fontsize; 1514. 		if (qt_fontsize == NULL) 1515. 			qt_fontsize=(char *)strdup(bufp); 1516. 	} else if (match_varname(buf, "QT_COMPACT", 10)) { 1517. 		extern int qt_compact_mode; 1518. 		qt_compact_mode = atoi(bufp); 1519. #endif 1520. 	} else 1521. 		return 0; 1522. 	return 1; 1523. } 1524.  1525. #ifdef USER_SOUNDS 1526. boolean 1527. can_read_file(filename) 1528. const char *filename; 1529. { 1530. 	return (access(filename, 4) == 0); 1531. } 1532. #endif /* USER_SOUNDS */ 1533. 1534. void 1535. read_config_file(filename) 1536. const char *filename; 1537. { 1538. #define tmp_levels	(char *)0 1539. #define tmp_ramdisk	(char *)0 1540. 1541. #ifdef MICRO 1542. #undef tmp_levels 1543. 	char	tmp_levels[PATHLEN]; 1544. # ifdef MFLOPPY 1545. # ifndef AMIGA 1546. #undef tmp_ramdisk 1547. 	char	tmp_ramdisk[PATHLEN]; 1548. # endif 1549. # endif 1550. #endif 1551. 	char	buf[4*BUFSZ]; 1552. 	FILE	*fp; 1553. 1554. 	if (!(fp = fopen_config_file(filename))) return; 1555. 1556. #ifdef MICRO 1557. # ifdef MFLOPPY 1558. # ifndef AMIGA 1559. 	tmp_ramdisk[0] = 0; 1560. # endif 1561. # endif 1562. 	tmp_levels[0] = 0; 1563. #endif 1564. 	/* begin detection of duplicate configfile options */ 1565. 	set_duplicate_opt_detection(1); 1566. 1567. 	while (fgets(buf, 4*BUFSZ, fp)) { 1568. 		if (!parse_config_line(fp, buf, tmp_ramdisk, tmp_levels)) { 1569. 			raw_printf("Bad option line: \"%.50s\"", buf); 1570. 			wait_synch; 1571. 		} 1572. 	}  1573. 	(void) fclose(fp); 1574. 	 1575. 	/* turn off detection of duplicate configfile options */ 1576. 	set_duplicate_opt_detection(0); 1577. 1578. #if defined(MICRO) && !defined(NOCWD_ASSUMPTIONS) 1579. 	/* should be superseded by fqn_prefix[] */ 1580. # ifdef MFLOPPY 1581. 	Strcpy(permbones, tmp_levels); 1582. # ifndef AMIGA 1583. 	if (tmp_ramdisk[0]) { 1584. 		Strcpy(levels, tmp_ramdisk); 1585. 		if (strcmp(permbones, levels))		/* if not identical */ 1586. 			ramdisk = TRUE; 1587. 	} else 1588. # endif /* AMIGA */ 1589. 		Strcpy(levels, tmp_levels); 1590. 1591. 	Strcpy(bones, levels); 1592. # endif /* MFLOPPY */ 1593. #endif /* MICRO */ 1594. 	return; 1595. } 1596.  1597. #ifdef WIZARD 1598. STATIC_OVL FILE * 1599. fopen_wizkit_file 1600. { 1601. 	FILE *fp; 1602. #if defined(VMS) || defined(UNIX) 1603. 	char	tmp_wizkit[BUFSZ]; 1604. #endif 1605. 	char *envp; 1606. 1607. 	envp = nh_getenv("WIZKIT"); 1608. 	if (envp && *envp) (void) strncpy(wizkit, envp, WIZKIT_MAX - 1); 1609. 	if (!wizkit[0]) return (FILE *)0; 1610. 1611. #ifdef UNIX 1612. 	if (access(wizkit, 4) == -1) { 1613. 		/* 4 is R_OK on newer systems */ 1614. 		/* nasty sneaky attempt to read file through 1615. 		 * NetHack's setuid permissions -- this is a 1616. * place a file name may be wholly under the player's 1617. * control 1618. 		 */ 1619. 		raw_printf("Access to %s denied (%d).",  1620. 				wizkit, errno); 1621. 		wait_synch; 1622. 		/* fall through to standard names */ 1623. 	} else 1624. #endif 1625. 	if ((fp = fopenp(wizkit, "r")) != (FILE *)0) { 1626. 	   return(fp); 1627. #if defined(UNIX) || defined(VMS) 1628. 	} else { 1629. 	   /* access above probably caught most problems for UNIX */ 1630. 	   raw_printf("Couldn't open requested config file %s (%d).",  1631. 				wizkit, errno); 1632. 	   wait_synch; 1633. #endif 1634. 	} 1635.  1636. #if defined(MICRO) || defined(MAC) || defined(__BEOS__) || defined(WIN32) 1637. 	if ((fp = fopenp(fqname(wizkit, CONFIGPREFIX, 0), "r")) 1638. 								!= (FILE *)0) 1639. 		return(fp); 1640. #else 1641. # ifdef VMS 1642. 	envp = nh_getenv("HOME"); 1643. 	if (envp) 1644. 		Sprintf(tmp_wizkit, "%s%s", envp, wizkit); 1645. 	else 1646. 		Sprintf(tmp_wizkit, "%s%s", "sys$login:", wizkit); 1647. 	if ((fp = fopenp(tmp_wizkit, "r")) != (FILE *)0) 1648. 		return(fp); 1649. # else	/* should be only UNIX left */ 1650. 	envp = nh_getenv("HOME"); 1651. 	if (envp) 1652. 		Sprintf(tmp_wizkit, "%s/%s", envp, wizkit); 1653. 	else 	Strcpy(tmp_wizkit, wizkit); 1654. 	if ((fp = fopenp(tmp_wizkit, "r")) != (FILE *)0) 1655. 		return(fp); 1656. 	else if (errno != ENOENT) { 1657. 		/* e.g., problems when setuid NetHack can't search home 1658. 		 * directory restricted to user */ 1659. 		raw_printf("Couldn't open default wizkit file %s (%d).", 1660. 					tmp_wizkit, errno); 1661. 		wait_synch; 1662. 	} 1663. # endif 1664. #endif 1665. 	return (FILE *)0; 1666. } 1667.  1668. void 1669. read_wizkit 1670. { 1671. 	FILE *fp; 1672. 	char *ep, buf[BUFSZ]; 1673. 	struct obj *otmp; 1674. 	if (!wizard || !(fp = fopen_wizkit_file)) return; 1675. 1676. 	while (fgets(buf, 4*BUFSZ, fp)) { 1677. 		if ((ep = index(buf, '\n'))) *ep = '\0'; 1678. 		if (buf[0]) { 1679. 			otmp = readobjnam(buf, (struct obj *)0, FALSE); 1680. 			if (otmp) { 1681. 			   if (otmp != &zeroobj) 1682. 				otmp = addinv(otmp); 1683. 			} else { 1684. 			   raw_printf("Bad wizkit item: \"%.50s\"", buf); 1685. 			   wait_synch; 1686. 			} 1687. 		}  1688. 	}  1689. 	(void) fclose(fp); 1690. 	return; 1691. } 1692.  1693. #endif /*WIZARD*/ 1694. 1695. /* --  END CONFIG FILE HANDLING --- */ 1696. 1697. /* --  BEGIN SCOREBOARD CREATION --- */ 1698. 1699. /* verify that we can write to the scoreboard file; if not, try to create one */ 1700. void 1701. check_recordfile(dir) 1702. const char *dir; 1703. { 1704. #if (defined(macintosh) && (defined(__SC__) || defined(__MRC__))) || defined(__MWERKS__) 1705. # pragma unused(dir) 1706. #endif 1707. 	const char *fq_record; 1708. 	int fd; 1709. 1710. #if defined(UNIX) || defined(VMS) 1711. 	fq_record = fqname(RECORD, SCOREPREFIX, 0); 1712. 	fd = open(fq_record, O_RDWR, 0); 1713. 	if (fd >= 0) { 1714. # ifdef VMS	/* must be stream-lf to use UPDATE_RECORD_IN_PLACE */ 1715. 		if (!file_is_stmlf(fd)) { 1716. 		   raw_printf(  1717. 		  "Warning: scoreboard file %s is not in stream_lf format",  1718. 				fq_record); 1719. 		   wait_synch; 1720. 		} 1721. # endif 1722. 	   (void) close(fd);	/* RECORD is accessible */ 1723. 	} else if ((fd = open(fq_record, O_CREAT|O_RDWR, FCMASK)) >= 0) { 1724. 	   (void) close(fd);	/* RECORD newly created */ 1725. # if defined(VMS) && !defined(SECURE) 1726. 	   /* Re-protect RECORD with world:read+write+execute+delete access. */ 1727. 	    (void) chmod(fq_record, FCMASK | 007); 1728. # endif /* VMS && !SECURE */ 1729. 	} else { 1730. 	   raw_printf("Warning: cannot write scoreboard file %s", fq_record); 1731. 	   wait_synch; 1732. 	} 1733. #endif  /* !UNIX && !VMS */ 1734. #ifdef MICRO 1735. 	char tmp[PATHLEN]; 1736. 1737. # ifdef OS2_CODEVIEW   /* explicit path on opening for OS/2 */ 1738. 	/* how does this work when there isn't an explicit path or fopenp 1739. 	 * for later access to the file via fopen_datafile? ? */ 1740. 	(void) strncpy(tmp, dir, PATHLEN - 1); 1741. 	tmp[PATHLEN-1] = '\0'; 1742. 	if ((strlen(tmp) + 1 + strlen(RECORD)) < (PATHLEN - 1)) { 1743. 		append_slash(tmp); 1744. 		Strcat(tmp, RECORD); 1745. 	} 1746. 	fq_record = tmp; 1747. # else 1748. 	Strcpy(tmp, RECORD); 1749. 	fq_record = fqname(RECORD, SCOREPREFIX, 0); 1750. # endif 1751. 1752. 	if ((fd = open(fq_record, O_RDWR)) < 0) { 1753. 	   /* try to create empty record */ 1754. # if defined(AZTEC_C) || defined(_DCC) || (defined(__GNUC__) && defined(__AMIGA__)) 1755. 	   /* Aztec doesn't use the third argument */ 1756. 	   /* DICE doesn't like it */ 1757. 	   if ((fd = open(fq_record, O_CREAT|O_RDWR)) < 0) { 1758. # else 1759. 	   if ((fd = open(fq_record, O_CREAT|O_RDWR, S_IREAD|S_IWRITE)) < 0) { 1760. # endif 1761. 	raw_printf("Warning: cannot write record %s", tmp); 1762. 		wait_synch; 1763. 	   } else 1764. 		(void) close(fd); 1765. 	} else		/* open succeeded */ 1766. 	   (void) close(fd); 1767. #else /* MICRO */ 1768. 1769. # ifdef MAC 1770. 	/* Create the "record" file, if necessary */ 1771. 	fq_record = fqname(RECORD, SCOREPREFIX, 0); 1772. 	fd = macopen (fq_record, O_RDWR | O_CREAT, TEXT_TYPE); 1773. 	if (fd != -1) macclose (fd); 1774. # endif /* MAC */ 1775. 1776. #endif /* MICRO */ 1777. } 1778.  1779. /* --  END SCOREBOARD CREATION --- */ 1780. 1781. /*files.c*/