Source:NetHack 3.2.0/files.c

From NetHackWiki
Jump to navigation Jump to search

Below is the full text to files.c from the source code of NetHack 3.2.0. To link to a particular line, write [[NetHack 3.2.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.2	95/08/04	*/
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.    #include <ctype.h>
9.    
10.   #if !defined(MAC) && !defined(O_WRONLY) && !defined(AZTEC_C)
11.   #include <fcntl.h>
12.   #endif
13.   #if defined(UNIX) || defined(VMS)
14.   #include <errno.h>
15.   # ifndef SKIP_ERRNO
16.   extern int errno;
17.   # endif
18.   #include <signal.h>
19.   #endif
20.   
21.   #if defined(MSDOS) || defined(OS2) || defined(TOS) || defined(WIN32)
22.   # ifndef GNUDOS
23.   #include <sys\stat.h>
24.   # else
25.   #include <sys/stat.h>
26.   # endif
27.   #endif
28.   #ifndef O_BINARY	/* used for micros, no-op for others */
29.   # define O_BINARY 0
30.   #endif
31.   
32.   #ifdef MFLOPPY
33.   char bones[FILENAME];		/* pathname of bones files */
34.   char lock[FILENAME];		/* pathname of level files */
35.   #else
36.   # ifdef VMS
37.   char bones[] = "bonesnn.xxx;1";
38.   char lock[PL_NSIZ+17] = "1lock"; /* long enough for _uid+name+.99;1 */
39.   # else
40.   char bones[] = "bonesnn.xxx";
41.   char lock[PL_NSIZ+14] = "1lock"; /* long enough for uid+name+.99 */
42.   # endif	/* VMS */
43.   #endif	/* MFLOPPY */
44.   
45.   #ifdef UNIX
46.   #define SAVESIZE	(PL_NSIZ + 13)	/* save/99999player.e */
47.   #else
48.   # ifdef VMS
49.   #define SAVESIZE	(PL_NSIZ + 22)	/* [.save]<uid>player.e;1 */
50.   # else
51.   #define SAVESIZE	FILENAME	/* from macconf.h or pcconf.h */
52.   # endif
53.   #endif
54.   
55.   char SAVEF[SAVESIZE];	/* holds relative path of save file from playground */
56.   #ifdef MICRO
57.   char SAVEP[SAVESIZE];	/* holds path of directory for save file */
58.   #endif
59.   
60.   #ifdef AMIGA
61.   extern char PATH[];	/* see sys/amiga/amidos.c */
62.   extern char bbs_id[];
63.   static int lockptr;
64.   # ifdef __SASC_60
65.   #include <proto/dos.h>
66.   # endif
67.   
68.   #include <libraries/dos.h>
69.   #endif
70.   
71.   extern int n_dgns;		/* from dungeon.c */
72.   
73.   static char *FDECL(set_bonesfile_name, (char *,d_level*));
74.   static char *NDECL(set_bonestemp_name);
75.   static char *FDECL(make_lockname, (const char *,char *));
76.   static FILE *FDECL(fopen_config_file, (const char *));
77.   static int FDECL(get_uchars, (FILE *,char *,char *,uchar *,int,const char *));
78.   int FDECL(parse_config_line, (FILE *,char *,char *,char *));
79.   
80.   
81.   /* fopen a file, with OS-dependent bells and whistles */
82.   /* NOTE: a simpler version of this routine also exists in util/dlb_main.c */
83.   FILE *
84.   fopen_datafile(filename, mode)
85.   const char *filename, *mode;
86.   {
87.   	FILE *fp;
88.   #ifdef AMIGA
89.   	fp = fopenp(filename, mode);
90.   #else
91.   # ifdef VMS	/* essential to have punctuation, to avoid logical names */
92.   	char tmp[BUFSIZ];
93.   
94.   	if (!index(filename, '.') && !index(filename, ';'))
95.   		filename = strcat(strcpy(tmp, filename), ";0");
96.   	fp = fopen(filename, mode, "mbc=16");
97.   # else
98.   	fp = fopen(filename, mode);
99.   # endif
100.  #endif
101.  	return fp;
102.  }
103.  
104.  /* ----------  BEGIN LEVEL FILE HANDLING ----------- */
105.  
106.  #ifdef MFLOPPY
107.  /* Set names for bones[] and lock[] */
108.  void
109.  set_lock_and_bones()
110.  {
111.  	if (!ramdisk) {
112.  		Strcpy(levels, permbones);
113.  		Strcpy(bones, permbones);
114.  	}
115.  	append_slash(permbones);
116.  	append_slash(levels);
117.  #ifdef AMIGA
118.  	strncat(levels, bbs_id, PATHLEN);
119.  #endif
120.  	append_slash(bones);
121.  	Strcat(bones, "bonesnn.*");
122.  	Strcpy(lock, levels);
123.  	Strcat(lock, alllevels);
124.  	return;
125.  }
126.  #endif /* MFLOPPY */
127.  
128.  
129.  /* Construct a file name for a level-type file, which is of the form
130.   * something.level (with any old level stripped off).
131.   * This assumes there is space on the end of 'file' to append
132.   * a two digit number.  This is true for 'level'
133.   * but be careful if you use it for other things -dgk
134.   */
135.  void
136.  set_levelfile_name(file, lev)
137.  char *file;
138.  int lev;
139.  {
140.  	char *tf;
141.  
142.  	tf = rindex(file, '.');
143.  	if (!tf) tf = eos(file);
144.  	Sprintf(tf, ".%d", lev);
145.  #ifdef VMS
146.  	Strcat(tf, ";1");
147.  #endif
148.  	return;
149.  }
150.  
151.  int
152.  create_levelfile(lev)
153.  int lev;
154.  {
155.  	int fd;
156.  
157.  	set_levelfile_name(lock, lev);
158.  
159.  #if defined(MICRO)
160.  	/* Use O_TRUNC to force the file to be shortened if it already
161.  	 * exists and is currently longer.
162.  	 */
163.  	fd = open(lock, O_WRONLY |O_CREAT | O_TRUNC | O_BINARY, FCMASK);
164.  #else
165.  # ifdef MAC
166.  	fd = maccreat(lock, LEVL_TYPE);
167.  # else
168.  	fd = creat(lock, FCMASK);
169.  # endif
170.  #endif /* MICRO */
171.  
172.  	if (fd >= 0)
173.  	    level_info[lev].flags |= LFILE_EXISTS;
174.  
175.  	return fd;
176.  }
177.  
178.  
179.  int
180.  open_levelfile(lev)
181.  int lev;
182.  {
183.  	int fd;
184.  
185.  	set_levelfile_name(lock, lev);
186.  #ifdef MFLOPPY
187.  	/* If not currently accessible, swap it in. */
188.  	if (level_info[lev].where != ACTIVE)
189.  		swapin_file(lev);
190.  #endif
191.  #ifdef MAC
192.  	fd = macopen(lock, O_RDONLY | O_BINARY, LEVL_TYPE);
193.  #else
194.  	fd = open(lock, O_RDONLY | O_BINARY, 0);
195.  #endif
196.  	return fd;
197.  }
198.  
199.  
200.  void
201.  delete_levelfile(lev)
202.  int lev;
203.  {
204.  	/*
205.  	 * Level 0 might be created by port specific code that doesn't
206.  	 * call create_levfile(), so always assume that it exists.
207.  	 */
208.  	if (lev == 0 || (level_info[lev].flags & LFILE_EXISTS)) {
209.  		set_levelfile_name(lock, lev);
210.  		(void) unlink(lock);
211.  		level_info[lev].flags &= ~LFILE_EXISTS;
212.  	}
213.  }
214.  
215.  
216.  void
217.  clearlocks()
218.  {
219.  #if defined(MFLOPPY) && !defined(AMIGA)
220.  	eraseall(levels, alllevels);
221.  	if (ramdisk)
222.  		eraseall(permbones, alllevels);
223.  #else
224.  	register int x;
225.  
226.  # if defined(UNIX) || defined(VMS)
227.  	(void) signal(SIGHUP, SIG_IGN);
228.  # endif
229.  	/* can't access maxledgerno() before dungeons are created -dlc */
230.  	for (x = (n_dgns ? maxledgerno() : 0); x >= 0; x--)
231.  		delete_levelfile(x);	/* not all levels need be present */
232.  #endif
233.  }
234.  
235.  /* ----------  END LEVEL FILE HANDLING ----------- */
236.  
237.  
238.  /* ----------  BEGIN BONES FILE HANDLING ----------- */
239.  
240.  /* set up "file" to be file name for retrieving bones, and return a
241.   * bonesid to be read/written in the bones file.
242.   */
243.  static char *
244.  set_bonesfile_name(file, lev)
245.  char *file;
246.  d_level *lev;
247.  {
248.  	char *dptr = rindex(file, '.');
249.  	s_level *sptr;
250.  
251.  	if (!dptr) dptr = eos(file);
252.  	*(dptr-2) = dungeons[lev->dnum].boneid;
253.  	*(dptr-1) = In_quest(lev) ? pl_character[0] : '0';
254.  	if ((sptr = Is_special(lev)) != 0)
255.  	    Sprintf(dptr, ".%c", sptr->boneid);
256.  	else
257.  	    Sprintf(dptr, ".%d", lev->dlevel);
258.  #ifdef VMS
259.  	Strcat(dptr, ";1");
260.  #endif
261.  	return(dptr-2);
262.  }
263.  
264.  /* set up temporary file name for writing bones, to avoid another game's
265.   * trying to read from an uncompleted bones file.  we want an uncontentious
266.   * name, so use one in the namespace reserved for this game's level files.
267.   * (we are not reading or writing level files while writing bones files, so
268.   * the same array may be used instead of copying.)
269.   */
270.  static char *
271.  set_bonestemp_name()
272.  {
273.  	char *tf;
274.  
275.  	tf = rindex(lock, '.');
276.  	if (!tf) tf = eos(lock);
277.  	Sprintf(tf, ".bn");
278.  #ifdef VMS
279.  	Strcat(tf, ";1");
280.  #endif
281.  	return lock;
282.  }
283.  
284.  int
285.  create_bonesfile(lev, bonesid)
286.  d_level *lev;
287.  char **bonesid;
288.  {
289.  	char *file;
290.  	int fd;
291.  
292.  	*bonesid = set_bonesfile_name(bones, lev);
293.  	file = set_bonestemp_name();
294.  
295.  #ifdef MICRO
296.  	/* Use O_TRUNC to force the file to be shortened if it already
297.  	 * exists and is currently longer.
298.  	 */
299.  	fd = open(file, O_WRONLY |O_CREAT | O_TRUNC | O_BINARY, FCMASK);
300.  #else
301.  # ifdef MAC
302.  	fd = maccreat(file, BONE_TYPE);
303.  # else
304.  	fd = creat(file, FCMASK);
305.  # endif
306.  # if defined(VMS) && !defined(SECURE)
307.  	/*
308.  	   Re-protect bones file with world:read+write+execute+delete access.
309.  	   umask() doesn't seem very reliable; also, vaxcrtl won't let us set
310.  	   delete access without write access, which is what's really wanted.
311.  	   Can't simply create it with the desired protection because creat
312.  	   ANDs the mask with the user's default protection, which usually
313.  	   denies some or all access to world.
314.  	 */
315.  	(void) chmod(file, FCMASK | 007);  /* allow other users full access */
316.  # endif /* VMS && !SECURE */
317.  #endif /* MICRO */
318.  
319.  	return fd;
320.  }
321.  
322.  #ifdef MFLOPPY
323.  /* remove partial bonesfile in process of creation */
324.  void
325.  cancel_bonesfile()
326.  {
327.  	char *tempname;
328.  
329.  	tempname = set_bonestemp_name();
330.  	(void) unlink(tempname);
331.  }
332.  #endif /* MFLOPPY */
333.  
334.  /* move completed bones file to proper name */
335.  void
336.  commit_bonesfile(lev)
337.  d_level *lev;
338.  {
339.  	char *tempname;
340.  	int ret;
341.  
342.  	(void) set_bonesfile_name(bones, lev);
343.  	tempname = set_bonestemp_name();
344.  
345.  #if (defined(SYSV) && !defined(SVR4)) || defined(GENIX)
346.  	/* old SYSVs don't have rename.  Some SVR3's may, but since they
347.  	 * also have link/unlink, it doesn't matter. :-)
348.  	 */
349.  	(void) unlink(bones);
350.  	ret = link(tempname, bones);
351.  	ret += unlink(tempname);
352.  #else
353.  	ret = rename(tempname, bones);
354.  #endif
355.  #ifdef WIZARD
356.  	if (wizard && ret != 0)
357.  		pline("couldn't rename %s to %s", tempname, bones);
358.  #endif
359.  }
360.  
361.  
362.  int
363.  open_bonesfile(lev, bonesid)
364.  d_level *lev;
365.  char **bonesid;
366.  {
367.  	int fd;
368.  
369.  	*bonesid = set_bonesfile_name(bones, lev);
370.  	uncompress(bones);	/* no effect if nonexistent */
371.  #ifdef MAC
372.  	fd = macopen(bones, O_RDONLY | O_BINARY, BONE_TYPE);
373.  #else
374.  	fd = open(bones, O_RDONLY | O_BINARY, 0);
375.  #endif
376.  	return fd;
377.  }
378.  
379.  
380.  int
381.  delete_bonesfile(lev)
382.  d_level *lev;
383.  {
384.  	(void) set_bonesfile_name(bones, lev);
385.  	return !(unlink(bones) < 0);
386.  }
387.  
388.  
389.  /* assume we're compressing the recently read or created bonesfile, so the
390.   * file name is already set properly */
391.  void
392.  compress_bonesfile()
393.  {
394.  	compress(bones);
395.  }
396.  
397.  /* ----------  END BONES FILE HANDLING ----------- */
398.  
399.  
400.  /* ----------  BEGIN SAVE FILE HANDLING ----------- */
401.  
402.  /* set savefile name in OS-dependent manner from pre-existing plname,
403.   * avoiding troublesome characters */
404.  void
405.  set_savefile_name()
406.  {
407.  #ifdef VMS
408.  	Sprintf(SAVEF, "[.save]%d%s", getuid(), plname);
409.  	regularize(SAVEF+7);
410.  	Strcat(SAVEF, ";1");
411.  #else
412.  # ifdef MICRO
413.  	Strcpy(SAVEF, SAVEP);
414.  #  ifdef AMIGA
415.  	strncat(SAVEF, bbs_id, PATHLEN);
416.  #  endif
417.  	{
418.  		int i = strlen(SAVEP);
419.  #  ifdef AMIGA
420.  		/* plname has to share space with SAVEP and ".sav" */
421.  		(void)strncat(SAVEF, plname, FILENAME - i - 4);
422.  #  else
423.  		(void)strncat(SAVEF, plname, 8);
424.  #  endif
425.  		regularize(SAVEF+i);
426.  	}
427.  	Strcat(SAVEF, ".sav");
428.  # else
429.  	Sprintf(SAVEF, "save/%d%s", (int)getuid(), plname);
430.  	regularize(SAVEF+5);	/* avoid . or / in name */
431.  # endif	/* MICRO */
432.  #endif	/* VMS */
433.  }
434.  
435.  #ifdef INSURANCE
436.  void
437.  save_savefile_name(fd)
438.  int fd;
439.  {
440.  	(void) write(fd, (genericptr_t) SAVEF, sizeof(SAVEF));
441.  }
442.  #endif
443.  
444.  
445.  #if defined(WIZARD) && !defined(MICRO)
446.  /* change pre-existing savefile name to indicate an error savefile */
447.  void
448.  set_error_savefile()
449.  {
450.  # ifdef VMS
451.        {
452.  	char *semi_colon = rindex(SAVEF, ';');
453.  	if (semi_colon) *semi_colon = '\0';
454.        }
455.  	Strcat(SAVEF, ".e;1");
456.  # else
457.  #  ifdef MAC
458.  	Strcat(SAVEF, "-e");
459.  #  else
460.  	Strcat(SAVEF, ".e");
461.  #  endif
462.  # endif
463.  }
464.  #endif
465.  
466.  
467.  /* create save file, overwriting one if it already exists */
468.  int
469.  create_savefile()
470.  {
471.  	int fd;
472.  #ifdef AMIGA
473.  	fd = ami_wbench_getsave(O_WRONLY | O_CREAT | O_TRUNC);
474.  #else
475.  # ifdef MICRO
476.  	fd = open(SAVEF, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK);
477.  # else
478.  #  ifdef MAC
479.  	fd = maccreat(SAVEF, SAVE_TYPE);
480.  #  else
481.  	fd = creat(SAVEF, FCMASK);
482.  #  endif
483.  #  if defined(VMS) && !defined(SECURE)
484.  	/*
485.  	   Make sure the save file is owned by the current process.  That's
486.  	   the default for non-privileged users, but for priv'd users the
487.  	   file will be owned by the directory's owner instead of the user.
488.  	 */
489.  #   ifdef getuid	/*(see vmsunix.c)*/
490.  #    undef getuid
491.  #   endif
492.  	(void) chown(SAVEF, getuid(), getgid());
493.  #  endif /* VMS && !SECURE */
494.  # endif	/* MICRO */
495.  #endif	/* AMIGA */
496.  
497.  	return fd;
498.  }
499.  
500.  
501.  /* open savefile for reading */
502.  int
503.  open_savefile()
504.  {
505.  	int fd;
506.  
507.  #ifdef AMIGA
508.  	fd = ami_wbench_getsave(O_RDONLY);
509.  #else
510.  # ifdef MAC
511.  	fd = macopen(SAVEF, O_RDONLY | O_BINARY, SAVE_TYPE);
512.  # else
513.  	fd = open(SAVEF, O_RDONLY | O_BINARY, 0);
514.  # endif
515.  #endif /* AMIGA */
516.  	return fd;
517.  }
518.  
519.  
520.  /* delete savefile */
521.  int
522.  delete_savefile()
523.  {
524.  #ifdef AMIGA
525.  	ami_wbench_unlink(SAVEF);
526.  #endif
527.  	(void) unlink(SAVEF);
528.  	return 0;	/* for restore_saved_game() (ex-xxxmain.c) test */
529.  }
530.  
531.  
532.  /* try to open up a save file and prepare to restore it */
533.  int
534.  restore_saved_game()
535.  {
536.  	int fd;
537.  
538.  	set_savefile_name();
539.  #ifdef MFLOPPY
540.  	if (
541.  # ifdef AMIGA
542.  	    !(FromWBench || saveDiskPrompt(1))
543.  # else
544.  	    !saveDiskPrompt(1)
545.  # endif
546.  	  ) return -1;
547.  #endif /* MFLOPPY */
548.  
549.  	uncompress(SAVEF);
550.  	if ((fd = open_savefile()) < 0) return fd;
551.  
552.  	if (!uptodate(fd, SAVEF)) {
553.  	    (void) close(fd),  fd = -1;
554.  	    (void) delete_savefile();
555.  	}
556.  	return fd;
557.  }
558.  
559.  /* ----------  END SAVE FILE HANDLING ----------- */
560.  
561.  
562.  /* ----------  BEGIN FILE COMPRESSION HANDLING ----------- */
563.  
564.  #ifdef COMPRESS
565.  
566.  void
567.  redirect(filename, mode, stream, uncomp)
568.  char *filename, *mode;
569.  FILE *stream;
570.  boolean uncomp;
571.  {
572.  	if (freopen(filename, mode, stream) == (FILE *)0) {
573.  		(void) fprintf(stderr, "freopen of %s for %scompress failed\n",
574.  			filename, uncomp ? "un" : "");
575.  		terminate(EXIT_FAILURE);
576.  	}
577.  }
578.  
579.  /*
580.   * using system() is simpler, but opens up security holes and causes
581.   * problems on at least Interactive UNIX 3.0.1 (SVR3.2), where any
582.   * setuid is renounced by /bin/sh, so the files cannot be accessed.
583.   *
584.   * cf. child() in unixunix.c.
585.   */
586.  void
587.  docompress_file(filename, uncomp)
588.  char *filename;
589.  boolean uncomp;
590.  {
591.  	char cfn[80];
592.  	FILE *cf;
593.  	const char *args[10];
594.  # ifdef COMPRESS_OPTIONS
595.  	char opts[80];
596.  # endif
597.  	int i = 0;
598.  	int f;
599.  
600.  	Strcpy(cfn, filename);
601.  # ifdef COMPRESS_EXTENSION
602.  	Strcat(cfn, COMPRESS_EXTENSION);
603.  # endif
604.  	/* when compressing, we know the file exists */
605.  	if (uncomp) {
606.  	    if ((cf = fopen(cfn, RDBMODE)) == (FILE *)0)
607.  		    return;
608.  	    (void) fclose(cf);
609.  	}
610.  
611.  	args[0] = COMPRESS;
612.  	if (uncomp) args[++i] = "-d";	/* uncompress */
613.  # ifdef COMPRESS_OPTIONS
614.  	{
615.  	    /* we can't guarantee there's only one additional option, sigh */
616.  	    char *opt;
617.  	    boolean inword = FALSE;
618.  
619.  	    Strcpy(opts, COMPRESS_OPTIONS);
620.  	    opt = opts;
621.  	    while (*opt) {
622.  		if ((*opt == ' ') || (*opt == '\t')) {
623.  		    if (inword) {
624.  			*opt = '\0';
625.  			inword = FALSE;
626.  		    }
627.  		} else if (!inword) {
628.  		    args[++i] = opt;
629.  		    inword = TRUE;
630.  		}
631.  		opt++;
632.  	    }
633.  	}
634.  # endif
635.  	args[++i] = (char *)0;
636.  
637.  	f = fork();
638.  	if (f == 0) {	/* child */
639.  		/* run compressor without privileges, in case other programs
640.  		 * have surprises along the line of gzip once taking filenames
641.  		 * in GZIP.
642.  		 */
643.  		/* assume all compressors will compress stdin to stdout
644.  		 * without explicit filenames.  this is true of at least
645.  		 * compress and gzip, those mentioned in config.h.
646.  		 */
647.  		if (uncomp) {
648.  			redirect(cfn, RDBMODE, stdin, uncomp);
649.  			redirect(filename, WRBMODE, stdout, uncomp);
650.  		} else {
651.  			redirect(filename, RDBMODE, stdin, uncomp);
652.  			redirect(cfn, WRBMODE, stdout, uncomp);
653.  		}
654.  		(void) setgid(getgid());
655.  		(void) setuid(getuid());
656.  		(void) execv(args[0], (char *const *) args);
657.  		perror((char *)0);
658.  		(void) fprintf(stderr, "Exec to %scompress %s failed.\n",
659.  			uncomp ? "un" : "", filename);
660.  		terminate(EXIT_FAILURE);
661.  	} else if (f == -1) {
662.  		perror((char *)0);
663.  		pline("Fork to %scompress %s failed.",
664.  			uncomp ? "un" : "", filename);
665.  		return;
666.  	}
667.  	(void) signal(SIGINT, SIG_IGN);
668.  	(void) signal(SIGQUIT, SIG_IGN);
669.  	(void) wait((int *)0);
670.  	(void) signal(SIGINT, (SIG_RET_TYPE) done1);
671.  # ifdef WIZARD
672.  	if (wizard) (void) signal(SIGQUIT, SIG_DFL);
673.  # endif
674.  	/* remove file left behind */
675.  	if (uncomp)
676.  		(void) unlink(cfn);
677.  	else
678.  		(void) unlink(filename);
679.  }
680.  #endif	/* COMPRESS */
681.  
682.  /* compress file */
683.  void
684.  compress(filename)
685.  const char *filename;
686.  #ifdef applec
687.  # pragma unused(filename)
688.  #endif
689.  {
690.  #ifdef COMPRESS
691.  	docompress_file(filename, FALSE);
692.  #endif
693.  }
694.  
695.  
696.  /* uncompress file if it exists */
697.  void
698.  uncompress(filename)
699.  const char *filename;
700.  #ifdef applec
701.  # pragma unused(filename)
702.  #endif
703.  {
704.  #ifdef COMPRESS
705.  	docompress_file(filename, TRUE);
706.  #endif
707.  }
708.  
709.  /* ----------  END FILE COMPRESSION HANDLING ----------- */
710.  
711.  
712.  /* ----------  BEGIN FILE LOCKING HANDLING ----------- */
713.  
714.  static int nesting = 0;
715.  
716.  #ifdef NO_FILE_LINKS	/* implies UNIX */
717.  static int lockfd;	/* for lock_file() to pass to unlock_file() */
718.  #endif
719.  
720.  #define HUP	if (!program_state.done_hup)
721.  
722.  static char *
723.  make_lockname(filename, lockname)
724.  const char *filename;
725.  char *lockname;
726.  {
727.  #if defined(UNIX) || defined(VMS) || defined(AMIGA)
728.  # ifdef NO_FILE_LINKS
729.  	Strcpy(lockname, LOCKDIR);
730.  	Strcat(lockname, "/");
731.  	Strcat(lockname, filename);
732.  # else
733.  	Strcpy(lockname, filename);
734.  # endif
735.  # ifdef VMS
736.        {
737.  	char *semi_colon = rindex(lockname, ';');
738.  	if (semi_colon) *semi_colon = '\0';
739.        }
740.  	Strcat(lockname, ".lock;1");
741.  # else
742.  	Strcat(lockname, "_lock");
743.  # endif
744.  	return lockname;
745.  #else
746.  	lockname[0] = '\0';
747.  	return (char*)0;
748.  #endif  /* UNIX || VMS || AMIGA */
749.  }
750.  
751.  
752.  /* lock a file */
753.  boolean
754.  lock_file(filename, retryct)
755.  const char *filename;
756.  int retryct;
757.  #ifdef applec
758.  # pragma unused(filename, retryct)
759.  #endif
760.  {
761.  	char *lockname, locknambuf[BUFSZ];
762.  
763.  	nesting++;
764.  	if (nesting > 1) {
765.  	    impossible("TRIED TO NEST LOCKS");
766.  	    return TRUE;
767.  	}
768.  
769.  	lockname = make_lockname(filename, locknambuf);
770.  
771.  #if defined(UNIX) || defined(VMS)
772.  # ifdef NO_FILE_LINKS
773.  	while ((lockfd = open(lockname, O_RDWR|O_CREAT|O_EXCL, 0666)) == -1) {
774.  # else
775.  	while (link(filename, lockname) == -1) {
776.  # endif
777.  	    register int errnosv = errno;
778.  
779.  	    switch (errnosv) {	/* George Barbanis */
780.  	    case EEXIST:
781.  		if (retryct--) {
782.  		    HUP raw_printf(
783.  			    "Waiting for access to %s.  (%d retries left).",
784.  			    filename, retryct);
785.  # if defined(SYSV) || defined(ULTRIX) || defined(VMS)
786.  		    (void)
787.  # endif
788.  			sleep(1);
789.  		} else {
790.  		    HUP (void) raw_print("I give up.  Sorry.");
791.  		    HUP raw_printf("Perhaps there is an old %s around?",
792.  					lockname);
793.  		    nesting--;
794.  		    return FALSE;
795.  		}
796.  
797.  		break;
798.  	    case ENOENT:
799.  		HUP raw_printf("Can't find file %s to lock!", filename);
800.  		nesting--;
801.  		return FALSE;
802.  	    case EACCES:
803.  		HUP raw_printf("No write permission to lock %s!", filename);
804.  		nesting--;
805.  		return FALSE;
806.  # ifdef VMS			/* c__translate(vmsfiles.c) */
807.  	    case EPERM:
808.  		/* could be misleading, but usually right */
809.  		HUP raw_printf("Can't lock %s due to directory protection.",
810.  			       filename);
811.  		nesting--;
812.  		return FALSE;
813.  # endif
814.  	    default:
815.  		HUP perror(lockname);
816.  		HUP raw_printf(
817.  			     "Cannot lock %s for unknown reason (%d).",
818.  			       filename, errnosv);
819.  		nesting--;
820.  		return FALSE;
821.  	    }
822.  
823.  	}
824.  #endif  /* UNIX || VMS */
825.  
826.  #ifdef AMIGA
827.      lockptr = 0;
828.      while (retryct-- && !lockptr) {
829.  	(void)DeleteFile(lockname); /* in case dead process was here first */
830.  	lockptr = Open(lockname,MODE_NEWFILE);
831.  	if (!lockptr) {
832.  	    raw_printf("Waiting for access to %s.  (%d retries left).",
833.  			filename, retryct);
834.  	    Delay(50);
835.  	}
836.      }
837.      if (!retryct) {
838.  	raw_printf("I give up.  Sorry.");
839.  	nesting--;
840.  	return FALSE;
841.      }
842.  #endif
843.  	return TRUE;
844.  }
845.  
846.  
847.  #ifdef VMS	/* for unlock_file, use the unlink() routine in vmsunix.c */
848.  # ifdef unlink
849.  #  undef unlink
850.  # endif
851.  # define unlink(foo) vms_unlink(foo)
852.  #endif
853.  
854.  /* unlock file, which must be currently locked by lock_file */
855.  void
856.  unlock_file(filename)
857.  const char *filename;
858.  #if defined(applec)
859.  # pragma unused(filename)
860.  #endif
861.  {
862.  	char *lockname, locknambuf[BUFSZ];
863.  
864.  	if (nesting == 1) {
865.  		lockname = make_lockname(filename, locknambuf);
866.  
867.  #if defined(UNIX) || defined(VMS)
868.  		if (unlink(lockname) < 0)
869.  			HUP raw_printf("Can't unlink %s.", lockname);
870.  # ifdef NO_FILE_LINKS
871.  		(void) close(lockfd);
872.  # endif
873.  
874.  #endif  /* UNIX || VMS */
875.  
876.  #ifdef AMIGA
877.  		if (lockptr) Close(lockptr);
878.  		DeleteFile(lockname);
879.  		lockptr = 0;
880.  #endif /* AMIGA */
881.  	}
882.  
883.  	nesting--;
884.  }
885.  
886.  /* ----------  END FILE LOCKING HANDLING ----------- */
887.  
888.  
889.  /* ----------  BEGIN CONFIG FILE HANDLING ----------- */
890.  
891.  const char *configfile =
892.  #ifdef UNIX
893.  			".nethackrc";
894.  #else
895.  # ifdef MAC
896.  			"NetHack defaults";
897.  # else
898.  			"NetHack.cnf";
899.  # endif
900.  #endif
901.  
902.  #ifndef MFLOPPY
903.  #define fopenp fopen
904.  #endif
905.  
906.  static FILE *
907.  fopen_config_file(filename)
908.  const char *filename;
909.  {
910.  	FILE *fp;
911.  #if defined(UNIX) || defined(VMS)
912.  	char	tmp_config[BUFSZ];
913.  #endif
914.  
915.  	/* "filename" is an environment variable, so it should hang around */
916.  	if (filename) {
917.  #ifdef UNIX
918.  		if (access(filename, 4) == -1) {
919.  			/* 4 is R_OK on newer systems */
920.  			/* nasty sneaky attempt to read file through
921.  			 * NetHack's setuid permissions -- this is the only
922.  			 * place a file name may be wholly under the player's
923.  			 * control
924.  			 */
925.  			raw_printf("Access to %s denied (%d).",
926.  					filename, errno);
927.  			wait_synch();
928.  			/* fall through to standard names */
929.  		} else
930.  #endif
931.  		if ((fp = fopenp(filename, "r")) != (FILE *)0) {
932.  			configfile = filename;
933.  			return(fp);
934.  		}
935.  	}
936.  
937.  #if defined(MICRO) || defined(MAC)
938.  	if ((fp = fopenp(configfile, "r")) != (FILE *)0)
939.  		return(fp);
940.  #else
941.  # ifdef VMS
942.  	if ((fp = fopenp("nethackini", "r")) != (FILE *)0) {
943.  		configfile = "nethackini";
944.  		return(fp);
945.  	}
946.  	if ((fp = fopenp("sys$login:nethack.ini", "r")) != (FILE *)0) {
947.  		configfile = "nethack.ini";
948.  		return(fp);
949.  	}
950.  	Sprintf(tmp_config, "%s%s", getenv("HOME"), "NetHack.cnf");
951.  	if ((fp = fopenp(tmp_config, "r")) != (FILE *)0)
952.  		return(fp);
953.  # else	/* should be only UNIX left */
954.  	Sprintf(tmp_config, "%s/%s", getenv("HOME"), ".nethackrc");
955.  	if ((fp = fopenp(tmp_config, "r")) != (FILE *)0)
956.  		return(fp);
957.  # endif
958.  #endif
959.  	return (FILE *)0;
960.  
961.  }
962.  
963.  
964.  /*
965.   * Retrieve a list of integers from a file into a uchar array.
966.   *
967.   * NOTE:  This routine is unable to read a value of 0.
968.   */
969.  static int
970.  get_uchars(fp, buf, bufp, list, size, name)
971.      FILE *fp;		/* input file pointer */
972.      char *buf;		/* read buffer, must be of size BUFSZ */
973.      char *bufp;		/* current pointer */
974.      uchar *list;	/* return list */
975.      int  size;		/* return list size */
976.      const char *name;		/* name of option for error message */
977.  {
978.      unsigned int num = 0;
979.      int count = 0;
980.  
981.      while (1) {
982.  	switch(*bufp) {
983.  	    case ' ':  case '\0':
984.  	    case '\t': case '\n':
985.  		if (num) {
986.  		    list[count++] =  num;
987.  		    num = 0;
988.  		}
989.  		if (count == size || !*bufp) return count;
990.  		bufp++;
991.  		break;
992.  
993.  	    case '0': case '1': case '2': case '3':
994.  	    case '4': case '5': case '6': case '7':
995.  	    case '8': case '9':
996.  		num = num*10 + (*bufp-'0');
997.  		bufp++;
998.  		break;
999.  
1000. 	    case '\\':
1001. 		if (fp == (FILE *)0)
1002. 		    goto gi_error;
1003. 		do  {
1004. 		    if (!fgets(buf, BUFSZ, fp)) goto gi_error;
1005. 		} while (buf[0] == '#');
1006. 		bufp = buf;
1007. 		break;
1008. 
1009. 	    default:
1010. gi_error:
1011. 		raw_printf("Syntax error in %s", name);
1012. 		wait_synch();
1013. 		return count;
1014. 	}
1015.     }
1016.     /*NOTREACHED*/
1017. }
1018. 
1019. /*ARGSUSED*/
1020. int
1021. parse_config_line(fp, buf, tmp_ramdisk, tmp_levels)
1022. FILE		*fp;
1023. char		*buf;
1024. char		*tmp_ramdisk;
1025. char		*tmp_levels;
1026. #if defined(applec)
1027. # pragma unused(tmp_ramdisk,tmp_levels)
1028. #endif
1029. {
1030. 	char		*bufp, *altp;
1031. 	uchar   translate[MAXPCHARS];
1032. 	int   len;
1033. 
1034. 	if (*buf == '#')
1035. 		return 1;
1036. 
1037. 	/* remove trailing whitespace */
1038. 	bufp = eos(buf);
1039. 	while (--bufp > buf && isspace(*bufp))
1040. 		continue;
1041. 
1042. 	if (bufp <= buf)
1043. 		return 1;		/* skip all-blank lines */
1044. 	else
1045. 		*(bufp + 1) = '\0';	/* terminate line */
1046. 
1047. 	/* find the '=' or ':' */
1048. 	bufp = index(buf, '=');
1049. 	altp = index(buf, ':');
1050. 	if (!bufp || (altp && altp < bufp)) bufp = altp;
1051. 	if (!bufp) return 0;
1052. 
1053. 	/* skip  whitespace between '=' and value */
1054. 	do { ++bufp; } while (isspace(*bufp));
1055. 
1056. 	/* Go through possible variables */
1057. 	if (!strncmpi(buf, "OPTIONS", 4)) {
1058. 		parseoptions(bufp, TRUE, TRUE);
1059. 		if (plname[0])		/* If a name was given */
1060. 			plnamesuffix();	/* set the character class */
1061. #ifdef MICRO
1062. 	} else if (!strncmpi(buf, "HACKDIR", 4)) {
1063. 		(void) strncpy(hackdir, bufp, PATHLEN);
1064. # ifdef MFLOPPY
1065. 	} else if (!strncmpi(buf, "RAMDISK", 3)) {
1066. 				/* The following ifdef is NOT in the wrong
1067. 				 * place.  For now, we accept and silently
1068. 				 * ignore RAMDISK */
1069. #  ifndef AMIGA
1070. 		(void) strncpy(tmp_ramdisk, bufp, PATHLEN);
1071. #  endif
1072. # endif
1073. 	} else if (!strncmpi(buf, "LEVELS", 4)) {
1074. 		(void) strncpy(tmp_levels, bufp, PATHLEN);
1075. 
1076. 	} else if (!strncmpi(buf, "SAVE", 4)) {
1077. # ifdef MFLOPPY
1078. 		extern	int saveprompt;
1079. #endif
1080. 		char *ptr;
1081. 		if (ptr = index(bufp, ';')) {
1082. 			*ptr = '\0';
1083. # ifdef MFLOPPY
1084. 			if (*(ptr+1) == 'n' || *(ptr+1) == 'N') {
1085. 				saveprompt = FALSE;
1086. 			}
1087. # endif
1088. 		}
1089. #ifdef	MFLOPPY
1090. 		else
1091. 		    saveprompt = flags.asksavedisk;
1092. #endif
1093. 
1094. 		(void) strncpy(SAVEP, bufp, PATHLEN);
1095. 		append_slash(SAVEP);
1096. #endif /* MICRO */
1097. 	} else if(!strncmpi(buf, "CHARACTER", 4)) {
1098. 	    (void) strncpy(pl_character, bufp, PL_CSIZ-1);
1099. 	} else if(!strncmpi(buf, "DOGNAME", 3)) {
1100. 	    (void) strncpy(dogname, bufp, PL_PSIZ-1);
1101. 	} else if(!strncmpi(buf, "CATNAME", 3)) {
1102. 	    (void) strncpy(catname, bufp, PL_PSIZ-1);
1103. 	} else if(!strncmpi(buf, "NAME", 4)) {
1104. 	    (void) strncpy(plname, bufp, PL_NSIZ-1);
1105. 	    plnamesuffix();
1106. 
1107. 	} else if (!strncmpi(buf, "GRAPHICS", 4)) {
1108. 	    len = get_uchars(fp, buf, bufp, translate, MAXPCHARS, "GRAPHICS");
1109. 	    assign_graphics(translate, len, MAXPCHARS, 0);
1110. 	} else if (!strncmpi(buf, "DUNGEON", 4)) {
1111. 	    len = get_uchars(fp, buf, bufp, translate, MAXDCHARS, "DUNGEON");
1112. 	    assign_graphics(translate, len, MAXDCHARS, 0);
1113. 	} else if (!strncmpi(buf, "TRAPS", 4)) {
1114. 	    len = get_uchars(fp, buf, bufp, translate, MAXTCHARS, "TRAPS");
1115. 	    assign_graphics(translate, len, MAXTCHARS, MAXDCHARS);
1116. 	} else if (!strncmpi(buf, "EFFECTS", 4)) {
1117. 	    len = get_uchars(fp, buf, bufp, translate, MAXECHARS, "EFFECTS");
1118. 	    assign_graphics(translate, len, MAXECHARS, MAXDCHARS+MAXTCHARS);
1119. 
1120. 	} else if (!strncmpi(buf, "OBJECTS", 3)) {
1121. 	    /* oc_syms[0] is the RANDOM object, unused */
1122. 	    (void) get_uchars(fp, buf, bufp, &(oc_syms[1]),
1123. 					MAXOCLASSES-1, "OBJECTS");
1124. 	} else if (!strncmpi(buf, "MONSTERS", 3)) {
1125. 	    /* monsyms[0] is unused */
1126. 	    (void) get_uchars(fp, buf, bufp, &(monsyms[1]),
1127. 					MAXMCLASSES-1, "MONSTERS");
1128. #ifdef AMIGA
1129. 	} else if (!strncmpi(buf, "FONT", 4)) {
1130. 		char *t;
1131. 		extern void amii_set_text_font( char *, int );
1132. 
1133. 		if( t = strchr( buf+5, ':' ) )
1134. 		{
1135. 		    *t = 0;
1136. 		    amii_set_text_font( buf+5, atoi( t + 1 ) );
1137. 		    *t = ':';
1138. 		}
1139. 	} else if (!strncmpi(buf, "PATH", 4)) {
1140. 		(void) strncpy(PATH, bufp, PATHLEN);
1141. #endif
1142. #ifdef AMIGA
1143. 	} else if (!strncmpi(buf, "DEPTH", 5)) {
1144. 		extern int amii_numcolors;
1145. 		int val = atoi( bufp );
1146. 		amii_numcolors = 1L << min( DEPTH, val );
1147. 	} else if (!strncmpi(buf, "DRIPENS", 7)) {
1148. 		int i, val;
1149. 		char *t;
1150. 		for (i = 0, t = strtok(bufp, ",/"); t != (char *)0;
1151. 				i < 20 && (t = strtok((char*)0, ",/")), ++i) {
1152. 			sscanf(t, "%d", &val );
1153. 			flags.amii_dripens[i] = val;
1154. 		}
1155. 	} else if (!strncmpi(buf, "SCREENMODE", 10 )) {
1156. 		extern long amii_scrnmode;
1157. 		if( sscanf(bufp, "%x", &amii_scrnmode) != 1 )
1158. 			amii_scrnmode = 0;
1159. 	} else if (!strncmpi(buf, "MSGPENS", 7)) {
1160. 		extern int amii_msgAPen, amii_msgBPen;
1161. 		char *t = strtok(bufp, ",/");
1162. 		if( t )
1163. 		{
1164. 		    sscanf(t, "%d", &amii_msgAPen);
1165. 		    if( t = strtok((char*)0, ",/") )
1166. 				sscanf(t, "%d", &amii_msgBPen);
1167. 		}
1168. 	} else if (!strncmpi(buf, "TEXTPENS", 8)) {
1169. 		extern int amii_textAPen, amii_textBPen;
1170. 		char *t = strtok(bufp, ",/");
1171. 		if( t )
1172. 		{
1173. 		    sscanf(t, "%d", &amii_textAPen);
1174. 		    if( t = strtok((char*)0, ",/") )
1175. 				sscanf(t, "%d", &amii_textBPen);
1176. 		}
1177. 	} else if (!strncmpi(buf, "MENUPENS", 8)) {
1178. 		extern int amii_menuAPen, amii_menuBPen;
1179. 		char *t = strtok(bufp, ",/");
1180. 		if( t )
1181. 		{
1182. 		    sscanf(t, "%d", &amii_menuAPen);
1183. 		    if( t = strtok((char*)0, ",/") )
1184. 				sscanf(t, "%d", &amii_menuBPen);
1185. 		}
1186. 	} else if (!strncmpi(buf, "STATUSPENS", 10)) {
1187. 		extern int amii_statAPen, amii_statBPen;
1188. 		char *t = strtok(bufp, ",/");
1189. 		if( t )
1190. 		{
1191. 		    sscanf(t, "%d", &amii_statAPen);
1192. 		    if( t = strtok((char*)0, ",/") )
1193. 				sscanf(t, "%d", &amii_statBPen);
1194. 		}
1195. 	} else if (!strncmpi(buf, "OTHERPENS", 9)) {
1196. 		extern int amii_otherAPen, amii_otherBPen;
1197. 		char *t = strtok(bufp, ",/");
1198. 		if( t )
1199. 		{
1200. 		    sscanf(t, "%d", &amii_otherAPen);
1201. 		    if( t = strtok((char*)0, ",/") )
1202. 				sscanf(t, "%d", &amii_otherBPen);
1203. 		}
1204. 	} else if (!strncmpi(buf, "PENS", 4)) {
1205. 		int i;
1206. 		char *t;
1207. 
1208. 		for (i = 0, t = strtok(bufp, ",/"); t != (char *)0;
1209. 				    t = strtok((char *)0, ",/"), ++i)
1210. 		{
1211. 			sscanf(t, "%hx", &flags.amii_curmap[i]);
1212. 		}
1213. 		amii_setpens( amii_numcolors = i );
1214. #endif
1215. 	} else
1216. 		return 0;
1217. 	return 1;
1218. }
1219. 
1220. void
1221. read_config_file(filename)
1222. const char *filename;
1223. {
1224. #define tmp_levels	(char *)0
1225. #define tmp_ramdisk	(char *)0
1226. 
1227. #ifdef MICRO
1228. #undef tmp_levels
1229. 	char	tmp_levels[PATHLEN];
1230. # ifdef MFLOPPY
1231. #  ifndef AMIGA
1232. #undef tmp_ramdisk
1233. 	char	tmp_ramdisk[PATHLEN];
1234. #  endif
1235. # endif
1236. #endif
1237. 	char	buf[BUFSZ];
1238. 	FILE	*fp;
1239. 
1240. #ifdef MAC
1241. 	long nul = 0L ;
1242. 	Str255 volName ;
1243. 	/*
1244. 	 * We should try to get this data from a rsrc, in the profile file
1245. 	 * the user double-clicked...  This data should be saved with the
1246. 	 * save file in the resource fork, AND be saveable in "stationery"
1247. 	 */
1248. 	GetVol ( volName , & theDirs . dataRefNum ) ;
1249. 	GetWDInfo ( theDirs . dataRefNum , & theDirs . dataRefNum , & theDirs .
1250. 		dataDirID , & nul ) ;
1251. 	if ( volName [ 0 ] > 31 ) volName [ 0 ] = 31 ;
1252. 	for ( nul = 1 ; nul <= volName [ 0 ] ; nul ++ ) {
1253. 		if ( volName [ nul ] == ':' ) {
1254. 			volName [ nul ] = 0 ;
1255. 			volName [ 0 ] = nul - 1 ;
1256. 			break ;
1257. 		}
1258. 	}
1259. 	BlockMove ( volName , theDirs . dataName , 32L ) ;
1260. #endif /* MAC */
1261. 
1262. 	if (!(fp = fopen_config_file(filename))) return;
1263. 
1264. #ifdef MICRO
1265. # ifdef MFLOPPY
1266. #  ifndef AMIGA
1267. 	tmp_ramdisk[0] = 0;
1268. #  endif
1269. # endif
1270. 	tmp_levels[0] = 0;
1271. #endif
1272. 
1273. 	while (fgets(buf, BUFSZ, fp)) {
1274. 		if (!parse_config_line(fp, buf, tmp_ramdisk, tmp_levels)) {
1275. 			raw_printf("Bad option line:  \"%s\"", buf);
1276. 			wait_synch();
1277. 		}
1278. 	}
1279. 	(void) fclose(fp);
1280. 
1281. #ifdef MICRO
1282. # ifdef MFLOPPY
1283. 	Strcpy(permbones, tmp_levels);
1284. #  ifndef AMIGA
1285. 	if (tmp_ramdisk[0]) {
1286. 		Strcpy(levels, tmp_ramdisk);
1287. 		if (strcmp(permbones, levels))		/* if not identical */
1288. 			ramdisk = TRUE;
1289. 	} else
1290. #  endif /* AMIGA */
1291. 		Strcpy(levels, tmp_levels);
1292. 
1293. 	Strcpy(bones, levels);
1294. # endif /* MFLOPPY */
1295. #endif /* MICRO */
1296. 	return;
1297. }
1298. 
1299. /* ----------  END CONFIG FILE HANDLING ----------- */
1300. 
1301. /* ----------  BEGIN SCOREBOARD CREATION ----------- */
1302. 
1303. /* verify that we can write to the scoreboard file; if not, try to create one */
1304. void
1305. check_recordfile(dir)
1306. const char *dir;
1307. #if defined(applec)
1308. # pragma unused(dir)
1309. #endif
1310. {
1311. #if defined(UNIX) || defined(VMS)
1312. 	int fd = open(RECORD, O_RDWR, 0);
1313. 
1314. 	if (fd >= 0) {
1315. # ifdef VMS	/* must be stream-lf to use UPDATE_RECORD_IN_PLACE */
1316. 		if (!file_is_stmlf(fd)) {
1317. 		    raw_printf(	/* note: assume VMS dir has trailing punct */
1318. 		  "Warning: scoreboard file %s%s is not in stream_lf format",
1319. 				(dir ? dir : "[]"), RECORD);
1320. 		    wait_synch();
1321. 		}
1322. # endif
1323. 	    (void) close(fd);	/* RECORD is accessible */
1324. 	} else if ((fd = open(RECORD, O_CREAT|O_RDWR, FCMASK)) >= 0) {
1325. 	    (void) close(fd);	/* RECORD newly created */
1326. # if defined(VMS) && !defined(SECURE)
1327. 	    /* Re-protect RECORD with world:read+write+execute+delete access. */
1328. 	    (void) chmod(RECORD, FCMASK | 007); /* allow everyone full access */
1329. # endif /* VMS && !SECURE */
1330. 	} else {
1331. 	    raw_printf("Warning: cannot write scoreboard file %s/%s",
1332. 			(dir ? dir : "."), RECORD);
1333. 	    wait_synch();
1334. 	}
1335. #endif  /* !UNIX && !VMS */
1336. 
1337. #ifdef MICRO
1338. 	int fd;
1339. 	char tmp[PATHLEN];
1340. 
1341. # ifdef OS2_CODEVIEW   /* explicit path on opening for OS/2 */
1342. 	Strcpy(tmp, dir);
1343. 	append_slash(tmp);
1344. 	Strcat(tmp, RECORD);
1345. # else
1346. 	Strcpy(tmp, RECORD);
1347. # endif
1348. 
1349. 	if ((fd = open(tmp, O_RDWR)) < 0) {
1350. 	    /* try to create empty record */
1351. # if defined(AZTEC_C) || defined(_DCC)
1352. 	    /* Aztec doesn't use the third argument */
1353. 	    /* DICE doesn't like it */
1354. 	    if ((fd = open(tmp, O_CREAT|O_RDWR)) < 0) {
1355. # else
1356. 	    if ((fd = open(tmp, O_CREAT|O_RDWR, S_IREAD|S_IWRITE)) < 0) {
1357. # endif
1358. 	raw_printf("Warning: cannot write record %s", tmp);
1359. 		wait_synch();
1360. 	    } else
1361. 		(void) close(fd);
1362. 	} else		/* open succeeded */
1363. 	    (void) close(fd);
1364. #else /* MICRO */
1365. 
1366. # ifdef MAC
1367. 	int fd = macopen ( RECORD , O_RDWR | O_CREAT , TEXT_TYPE ) ;
1368. 
1369. 	if ( fd < 0 ) {
1370. 		raw_printf ( "Warning: cannot write %s" , RECORD ) ;
1371. 	} else {
1372. 		close ( fd ) ;
1373. 	}
1374. # endif /* MAC */
1375. 
1376. #endif /* MICRO */
1377. }
1378. 
1379. /* ----------  END SCOREBOARD CREATION ----------- */
1380. 
1381. /*files.c*/