Wikihack
Advertisement

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.

Top of file[]

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.    
The NetHack General Public License applies to screenshots, source code and other content from NetHack.
5.    #include "hack.h"
6.    #include "dlb.h"
7.    
8.    #ifdef TTY_GRAPHICS
9.    #include "wintty.h" /* more() */
10.   #endif
11.   
12.   #include <ctype.h>
13.   
14.   #if !defined(MAC) && !defined(O_WRONLY) && !defined(AZTEC_C)
15.   #include <fcntl.h>
16.   #endif
17.   
18.   #include <errno.h>
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 <dirent.h>
37.   #endif
38.   
39.   #if defined(UNIX) || defined(VMS)
40.   #include <signal.h>
41.   #endif
42.   
43.   #if defined(MSDOS) || defined(OS2) || defined(TOS) || defined(WIN32)
44.   # ifndef GNUDOS
45.   #include <sys\stat.h>
46.   # else
47.   #include <sys/stat.h>
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]<uid>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 <share.h>
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 <proto/dos.h>
120.  # endif
121.  
122.  #include <libraries/dos.h>
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.  

fname_encode[]

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.  

fname_decode[]

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.  

fqname[]

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.  

validate_prefix_locations[]

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.  

fopen_datafile[]

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.  

Level file handling[]

372.  /* ----------  BEGIN LEVEL FILE HANDLING ----------- */
373.  

set_lock_and_bones[]

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.  

set_levelfile_name[]

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.  

create_levelfile[]

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.  

open_levelfile[]

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.  

delete_levelfile[]

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.  

clearlocks[]

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.  

open_levelfile_exclusively[]

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.  

really_close[]

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.  

close[]

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.  

Bones file handling[]

604.  /* ----------  BEGIN BONES FILE HANDLING ----------- */
605.  

set_bonesfile_name[]

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.  

set_bonestemp_name[]

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.  

create_bonesfile[]

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.  

cancel_bonesfile[]

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.  

commit_bonesfile[]

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.  

open_bonesfile[]

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.  

delete_bonesfile[]

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.  

compress_bonesfile[]

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.  

Save file handling[]

779.  /* ----------  BEGIN SAVE FILE HANDLING ----------- */
780.  

set_savefile_name[]

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.  

save_savefile_name[]

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.  

set_error_savefile[]

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.  

create_savefile[]

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.  

open_savefile[]

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.  

delete_savefile[]

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.  

restore_saved_game[]

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.  

plname_from_file[]

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.  

get_saved_games[]

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; i<n; i++) {
1007. 	    int uid;
1008. 	    char name[64]; /* more than PL_NSIZ */
1009. 	    if ( sscanf( namelist[i]->d_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. 

free_saved_games[]

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. 

File compression handling[]

1044. /* ----------  BEGIN FILE COMPRESSION HANDLING ----------- */
1045. 

redirect[]

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. 

docompress_file[]

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. 

compress[]

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. 

uncompress[]

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. 

File locking handling[]

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. 

make_lockname[]

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. 

lock_file[]

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. 

unlock_file[]

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. 

Config file handling[]

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. 

fopen_config_file[]

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. 

get_uchars[]

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. 

adjust_prefix[]

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. 

parse_config_line[]

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. 

can_read_file[]

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. 

read_config_file[]

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. 

fopen_wizkit_file[]

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. 

read_wizkit[]

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. 

Scoreboard creation[]

2153. /* ----------  BEGIN SCOREBOARD CREATION ----------- */
2154. 

check_recordfile[]

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. 

Panic/possible log[]

2237. /* ----------  BEGIN PANIC/IMPOSSIBLE LOG ----------- */
2238. 

paniclog[]

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. 

Internal recover[]

2266. #ifdef SELF_RECOVER
2267. 
2268. /* ----------  BEGIN INTERNAL RECOVER ----------- */

recover_savefile[]

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. 

copy_bytes[]

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*/
Advertisement