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