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