Source:NetHack 3.4.0/files.c

From NetHackWiki
Revision as of 07:48, 11 August 2010 by Bhaak (talk | contribs) (Undo revision 51764 by 71.141.104.170 (talk))
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

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

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

1.    /*	SCCS Id: @(#)files.c	3.4	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 <ctype.h>
13.   
14.   #if !defined(MAC) && !defined(O_WRONLY) && !defined(AZTEC_C)
15.   #include <fcntl.h>
16.   #endif
17.   #if defined(UNIX) || defined(VMS)
18.   #include <errno.h>
19.   # ifndef SKIP_ERRNO
20.   extern int errno;
21.   # endif
22.   #include <signal.h>
23.   #endif
24.   
25.   #if defined(MSDOS) || defined(OS2) || defined(TOS) || defined(WIN32)
26.   # ifndef GNUDOS
27.   #include <sys\stat.h>
28.   # else
29.   #include <sys/stat.h>
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]<uid>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 <proto/dos.h>
90.   # endif
91.   
92.   #include <libraries/dos.h>
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*/