Source:NetHack 3.6.0/src/files.c

From NetHackWiki
Jump to: navigation, search

Below is the full text to files.c from the source code of NetHack 3.6.0. To link to a particular line, write [[Source:NetHack 3.6.0/src/files.c#line123]], for example.

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

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

Contents

Top of file

  1.  /* NetHack 3.6	files.c	$NHDT-Date: 1449296293 2015/12/05 06:18:13 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.192 $ */
  2.  /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3.  /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5.  #include "hack.h"
  6.  #include "dlb.h"
  7.  
  8.  #ifdef TTY_GRAPHICS
  9.  #include "wintty.h" /* more() */
  10.  #endif
  11.  
  12.  #if (!defined(MAC) && !defined(O_WRONLY) && !defined(AZTEC_C)) \
  13.      || defined(USE_FCNTL)
  14.  #include <fcntl.h>
  15.  #endif
  16.  
  17.  #include <errno.h>
  18.  #ifdef _MSC_VER /* MSC 6.0 defines errno quite differently */
  19.  #if (_MSC_VER >= 600)
  20.  #define SKIP_ERRNO
  21.  #endif
  22.  #else
  23.  #ifdef NHSTDC
  24.  #define SKIP_ERRNO
  25.  #endif
  26.  #endif
  27.  #ifndef SKIP_ERRNO
  28.  #ifdef _DCC
  29.  const
  30.  #endif
  31.      extern int errno;
  32.  #endif
  33.  
  34.  #ifdef ZLIB_COMP /* RLC 09 Mar 1999: Support internal ZLIB */
  35.  #include "zlib.h"
  36.  #ifndef COMPRESS_EXTENSION
  37.  #define COMPRESS_EXTENSION ".gz"
  38.  #endif
  39.  #endif
  40.  
  41.  #if defined(UNIX) && defined(QT_GRAPHICS)
  42.  #include <sys/types.h>
  43.  #include <dirent.h>
  44.  #include <stdlib.h>
  45.  #endif
  46.  
  47.  #if defined(UNIX) || defined(VMS) || !defined(NO_SIGNAL)
  48.  #include <signal.h>
  49.  #endif
  50.  
  51.  #if defined(MSDOS) || defined(OS2) || defined(TOS) || defined(WIN32)
  52.  #ifndef GNUDOS
  53.  #include <sys\stat.h>
  54.  #else
  55.  #include <sys/stat.h>
  56.  #endif
  57.  #endif
  58.  #ifndef O_BINARY /* used for micros, no-op for others */
  59.  #define O_BINARY 0
  60.  #endif
  61.  
  62.  #ifdef PREFIXES_IN_USE
  63.  #define FQN_NUMBUF 4
  64.  static char fqn_filename_buffer[FQN_NUMBUF][FQN_MAX_FILENAME];
  65.  #endif
  66.  
  67.  #if !defined(MFLOPPY) && !defined(VMS) && !defined(WIN32)
  68.  char bones[] = "bonesnn.xxx";
  69.  char lock[PL_NSIZ + 14] = "1lock"; /* long enough for uid+name+.99 */
  70.  #else
  71.  #if defined(MFLOPPY)
  72.  char bones[FILENAME]; /* pathname of bones files */
  73.  char lock[FILENAME];  /* pathname of level files */
  74.  #endif
  75.  #if defined(VMS)
  76.  char bones[] = "bonesnn.xxx;1";
  77.  char lock[PL_NSIZ + 17] = "1lock"; /* long enough for _uid+name+.99;1 */
  78.  #endif
  79.  #if defined(WIN32)
  80.  char bones[] = "bonesnn.xxx";
  81.  char lock[PL_NSIZ + 25]; /* long enough for username+-+name+.99 */
  82.  #endif
  83.  #endif
  84.  
  85.  #if defined(UNIX) || defined(__BEOS__)
  86.  #define SAVESIZE (PL_NSIZ + 13) /* save/99999player.e */
  87.  #else
  88.  #ifdef VMS
  89.  #define SAVESIZE (PL_NSIZ + 22) /* [.save]<uid>player.e;1 */
  90.  #else
  91.  #if defined(WIN32)
  92.  #define SAVESIZE (PL_NSIZ + 40) /* username-player.NetHack-saved-game */
  93.  #else
  94.  #define SAVESIZE FILENAME /* from macconf.h or pcconf.h */
  95.  #endif
  96.  #endif
  97.  #endif
  98.  
  99.  #if !defined(SAVE_EXTENSION)
  100.  #ifdef MICRO
  101.  #define SAVE_EXTENSION ".sav"
  102.  #endif
  103.  #ifdef WIN32
  104.  #define SAVE_EXTENSION ".NetHack-saved-game"
  105.  #endif
  106.  #endif
  107.  
  108.  char SAVEF[SAVESIZE]; /* holds relative path of save file from playground */
  109.  #ifdef MICRO
  110.  char SAVEP[SAVESIZE]; /* holds path of directory for save file */
  111.  #endif
  112.  
  113.  #ifdef HOLD_LOCKFILE_OPEN
  114.  struct level_ftrack {
  115.      int init;
  116.      int fd;    /* file descriptor for level file     */
  117.      int oflag; /* open flags                         */
  118.      boolean nethack_thinks_it_is_open; /* Does NetHack think it's open? */
  119.  } lftrack;
  120.  #if defined(WIN32)
  121.  #include <share.h>
  122.  #endif
  123.  #endif /*HOLD_LOCKFILE_OPEN*/
  124.  
  125.  #define WIZKIT_MAX 128
  126.  static char wizkit[WIZKIT_MAX];
  127.  STATIC_DCL FILE *NDECL(fopen_wizkit_file);
  128.  STATIC_DCL void FDECL(wizkit_addinv, (struct obj *));
  129.  
  130.  #ifdef AMIGA
  131.  extern char PATH[]; /* see sys/amiga/amidos.c */
  132.  extern char bbs_id[];
  133.  static int lockptr;
  134.  #ifdef __SASC_60
  135.  #include <proto/dos.h>
  136.  #endif
  137.  
  138.  #include <libraries/dos.h>
  139.  extern void FDECL(amii_set_text_font, (char *, int));
  140.  #endif
  141.  
  142.  #if defined(WIN32) || defined(MSDOS)
  143.  static int lockptr;
  144.  #ifdef MSDOS
  145.  #define Delay(a) msleep(a)
  146.  #endif
  147.  #define Close close
  148.  #ifndef WIN_CE
  149.  #define DeleteFile unlink
  150.  #endif
  151.  #endif
  152.  
  153.  #ifdef MAC
  154.  #undef unlink
  155.  #define unlink macunlink
  156.  #endif
  157.  
  158.  #if (defined(macintosh) && (defined(__SC__) || defined(__MRC__))) \
  159.      || defined(__MWERKS__)
  160.  #define PRAGMA_UNUSED
  161.  #endif
  162.  
  163.  #ifdef USER_SOUNDS
  164.  extern char *sounddir;
  165.  #endif
  166.  
  167.  extern int n_dgns; /* from dungeon.c */
  168.  
  169.  #if defined(UNIX) && defined(QT_GRAPHICS)
  170.  #define SELECTSAVED
  171.  #endif
  172.  
  173.  #ifdef SELECTSAVED
  174.  STATIC_PTR int FDECL(CFDECLSPEC strcmp_wrap, (const void *, const void *));
  175.  #endif
  176.  STATIC_DCL char *FDECL(set_bonesfile_name, (char *, d_level *));
  177.  STATIC_DCL char *NDECL(set_bonestemp_name);
  178.  #ifdef COMPRESS
  179.  STATIC_DCL void FDECL(redirect, (const char *, const char *, FILE *,
  180.                                   BOOLEAN_P));
  181.  #endif
  182.  #if defined(COMPRESS) || defined(ZLIB_COMP)
  183.  STATIC_DCL void FDECL(docompress_file, (const char *, BOOLEAN_P));
  184.  #endif
  185.  #if defined(ZLIB_COMP)
  186.  STATIC_DCL boolean FDECL(make_compressed_name, (const char *, char *));
  187.  #endif
  188.  #ifndef USE_FCNTL
  189.  STATIC_DCL char *FDECL(make_lockname, (const char *, char *));
  190.  #endif
  191.  STATIC_DCL FILE *FDECL(fopen_config_file, (const char *, int));
  192.  STATIC_DCL int FDECL(get_uchars, (FILE *, char *, char *, uchar *, BOOLEAN_P,
  193.                                    int, const char *));
  194.  int FDECL(parse_config_line, (FILE *, char *, int));
  195.  STATIC_DCL FILE *NDECL(fopen_sym_file);
  196.  STATIC_DCL void FDECL(set_symhandling, (char *, int));
  197.  #ifdef NOCWD_ASSUMPTIONS
  198.  STATIC_DCL void FDECL(adjust_prefix, (char *, int));
  199.  #endif
  200.  #ifdef SELF_RECOVER
  201.  STATIC_DCL boolean FDECL(copy_bytes, (int, int));
  202.  #endif
  203.  #ifdef HOLD_LOCKFILE_OPEN
  204.  STATIC_DCL int FDECL(open_levelfile_exclusively, (const char *, int, int));
  205.  #endif
  206.  

File access handling

fname_encode

  1.  /*
  2.   * fname_encode()
  3.   *
  4.   *   Args:
  5.   *      legal       zero-terminated list of acceptable file name characters
  6.   *      quotechar   lead-in character used to quote illegal characters as
  7.   *                  hex digits
  8.   *      s           string to encode
  9.   *      callerbuf   buffer to house result
  10.   *      bufsz       size of callerbuf
  11.   *
  12.   *   Notes:
  13.   *      The hex digits 0-9 and A-F are always part of the legal set due to
  14.   *      their use in the encoding scheme, even if not explicitly included in
  15.   *      'legal'.
  16.   *
  17.   *   Sample:
  18.   *      The following call:
  19.   *  (void)fname_encode("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
  20.   *                     '%', "This is a % test!", buf, 512);
  21.   *      results in this encoding:
  22.   *          "This%20is%20a%20%25%20test%21"
  23.   */
  24.  char *
  25.  fname_encode(legal, quotechar, s, callerbuf, bufsz)
  26.  const char *legal;
  27.  char quotechar;
  28.  char *s, *callerbuf;
  29.  int bufsz;
  30.  {
  31.      char *sp, *op;
  32.      int cnt = 0;
  33.      static char hexdigits[] = "0123456789ABCDEF";
  34.  
  35.      sp = s;
  36.      op = callerbuf;
  37.      *op = '\0';
  38.  
  39.      while (*sp) {
  40.          /* Do we have room for one more character or encoding? */
  41.          if ((bufsz - cnt) <= 4)
  42.              return callerbuf;
  43.  
  44.          if (*sp == quotechar) {
  45.              (void) sprintf(op, "%c%02X", quotechar, *sp);
  46.              op += 3;
  47.              cnt += 3;
  48.          } else if ((index(legal, *sp) != 0) || (index(hexdigits, *sp) != 0)) {
  49.              *op++ = *sp;
  50.              *op = '\0';
  51.              cnt++;
  52.          } else {
  53.              (void) sprintf(op, "%c%02X", quotechar, *sp);
  54.              op += 3;
  55.              cnt += 3;
  56.          }
  57.          sp++;
  58.      }
  59.      return callerbuf;
  60.  }
  61.  

fname_decode

  1.  /*
  2.   * fname_decode()
  3.   *
  4.   *   Args:
  5.   *      quotechar   lead-in character used to quote illegal characters as
  6.   *                  hex digits
  7.   *      s           string to decode
  8.   *      callerbuf   buffer to house result
  9.   *      bufsz       size of callerbuf
  10.   */
  11.  char *
  12.  fname_decode(quotechar, s, callerbuf, bufsz)
  13.  char quotechar;
  14.  char *s, *callerbuf;
  15.  int bufsz;
  16.  {
  17.      char *sp, *op;
  18.      int k, calc, cnt = 0;
  19.      static char hexdigits[] = "0123456789ABCDEF";
  20.  
  21.      sp = s;
  22.      op = callerbuf;
  23.      *op = '\0';
  24.      calc = 0;
  25.  
  26.      while (*sp) {
  27.          /* Do we have room for one more character? */
  28.          if ((bufsz - cnt) <= 2)
  29.              return callerbuf;
  30.          if (*sp == quotechar) {
  31.              sp++;
  32.              for (k = 0; k < 16; ++k)
  33.                  if (*sp == hexdigits[k])
  34.                      break;
  35.              if (k >= 16)
  36.                  return callerbuf; /* impossible, so bail */
  37.              calc = k << 4;
  38.              sp++;
  39.              for (k = 0; k < 16; ++k)
  40.                  if (*sp == hexdigits[k])
  41.                      break;
  42.              if (k >= 16)
  43.                  return callerbuf; /* impossible, so bail */
  44.              calc += k;
  45.              sp++;
  46.              *op++ = calc;
  47.              *op = '\0';
  48.          } else {
  49.              *op++ = *sp++;
  50.              *op = '\0';
  51.          }
  52.          cnt++;
  53.      }
  54.      return callerbuf;
  55.  }
  56.  

fqname

  1.  #ifdef PREFIXES_IN_USE
  2.  #define UNUSED_if_not_PREFIXES_IN_USE /*empty*/
  3.  #else
  4.  #define UNUSED_if_not_PREFIXES_IN_USE UNUSED
  5.  #endif
  6.  
  7.  /*ARGSUSED*/
  8.  const char *
  9.  fqname(basenam, whichprefix, buffnum)
  10.  const char *basenam;
  11.  int whichprefix UNUSED_if_not_PREFIXES_IN_USE;
  12.  int buffnum UNUSED_if_not_PREFIXES_IN_USE;
  13.  {
  14.  #ifndef PREFIXES_IN_USE
  15.      return basenam;
  16.  #else
  17.      if (!basenam || whichprefix < 0 || whichprefix >= PREFIX_COUNT)
  18.          return basenam;
  19.      if (!fqn_prefix[whichprefix])
  20.          return basenam;
  21.      if (buffnum < 0 || buffnum >= FQN_NUMBUF) {
  22.          impossible("Invalid fqn_filename_buffer specified: %d", buffnum);
  23.          buffnum = 0;
  24.      }
  25.      if (strlen(fqn_prefix[whichprefix]) + strlen(basenam)
  26.          >= FQN_MAX_FILENAME) {
  27.          impossible("fqname too long: %s + %s", fqn_prefix[whichprefix],
  28.                     basenam);
  29.          return basenam; /* XXX */
  30.      }
  31.      Strcpy(fqn_filename_buffer[buffnum], fqn_prefix[whichprefix]);
  32.      return strcat(fqn_filename_buffer[buffnum], basenam);
  33.  #endif
  34.  }
  35.  

validate_prefix_locations

  1.  int
  2.  validate_prefix_locations(reasonbuf)
  3.  char *reasonbuf; /* reasonbuf must be at least BUFSZ, supplied by caller */
  4.  {
  5.  #if defined(NOCWD_ASSUMPTIONS)
  6.      FILE *fp;
  7.      const char *filename;
  8.      int prefcnt, failcount = 0;
  9.      char panicbuf1[BUFSZ], panicbuf2[BUFSZ];
  10.      const char *details;
  11.  #endif
  12.  
  13.      if (reasonbuf)
  14.          reasonbuf[0] = '\0';
  15.  #if defined(NOCWD_ASSUMPTIONS)
  16.      for (prefcnt = 1; prefcnt < PREFIX_COUNT; prefcnt++) {
  17.          /* don't test writing to configdir or datadir; they're readonly */
  18.          if (prefcnt == SYSCONFPREFIX || prefcnt == CONFIGPREFIX
  19.              || prefcnt == DATAPREFIX)
  20.              continue;
  21.          filename = fqname("validate", prefcnt, 3);
  22.          if ((fp = fopen(filename, "w"))) {
  23.              fclose(fp);
  24.              (void) unlink(filename);
  25.          } else {
  26.              if (reasonbuf) {
  27.                  if (failcount)
  28.                      Strcat(reasonbuf, ", ");
  29.                  Strcat(reasonbuf, fqn_prefix_names[prefcnt]);
  30.              }
  31.              /* the paniclog entry gets the value of errno as well */
  32.              Sprintf(panicbuf1, "Invalid %s", fqn_prefix_names[prefcnt]);
  33.  #if defined(NHSTDC) && !defined(NOTSTDC)
  34.              if (!(details = strerror(errno)))
  35.  #endif
  36.                  details = "";
  37.              Sprintf(panicbuf2, "\"%s\", (%d) %s", fqn_prefix[prefcnt], errno,
  38.                      details);
  39.              paniclog(panicbuf1, panicbuf2);
  40.              failcount++;
  41.          }
  42.      }
  43.      if (failcount)
  44.          return 0;
  45.      else
  46.  #endif
  47.          return 1;
  48.  }
  49.  

fopen_datafile

  1.  /* fopen a file, with OS-dependent bells and whistles */
  2.  /* NOTE: a simpler version of this routine also exists in util/dlb_main.c */
  3.  FILE *
  4.  fopen_datafile(filename, mode, prefix)
  5.  const char *filename, *mode;
  6.  int prefix;
  7.  {
  8.      FILE *fp;
  9.  
  10.      filename = fqname(filename, prefix, prefix == TROUBLEPREFIX ? 3 : 0);
  11.      fp = fopen(filename, mode);
  12.      return fp;
  13.  }
  14.  

Level file handling

  1.  /* ----------  BEGIN LEVEL FILE HANDLING ----------- */
  2.  

set_lock_and_bones

  1.  #ifdef MFLOPPY
  2.  /* Set names for bones[] and lock[] */
  3.  void
  4.  set_lock_and_bones()
  5.  {
  6.      if (!ramdisk) {
  7.          Strcpy(levels, permbones);
  8.          Strcpy(bones, permbones);
  9.      }
  10.      append_slash(permbones);
  11.      append_slash(levels);
  12.  #ifdef AMIGA
  13.      strncat(levels, bbs_id, PATHLEN);
  14.  #endif
  15.      append_slash(bones);
  16.      Strcat(bones, "bonesnn.*");
  17.      Strcpy(lock, levels);
  18.  #ifndef AMIGA
  19.      Strcat(lock, alllevels);
  20.  #endif
  21.      return;
  22.  }
  23.  #endif /* MFLOPPY */

set_levelfile_name

  1.  
  2.  /* Construct a file name for a level-type file, which is of the form
  3.   * something.level (with any old level stripped off).
  4.   * This assumes there is space on the end of 'file' to append
  5.   * a two digit number.  This is true for 'level'
  6.   * but be careful if you use it for other things -dgk
  7.   */
  8.  void
  9.  set_levelfile_name(file, lev)
  10.  char *file;
  11.  int lev;
  12.  {
  13.      char *tf;
  14.  
  15.      tf = rindex(file, '.');
  16.      if (!tf)
  17.          tf = eos(file);
  18.      Sprintf(tf, ".%d", lev);
  19.  #ifdef VMS
  20.      Strcat(tf, ";1");
  21.  #endif
  22.      return;
  23.  }
  24.  

create_levelfile

  1.  int
  2.  create_levelfile(lev, errbuf)
  3.  int lev;
  4.  char errbuf[];
  5.  {
  6.      int fd;
  7.      const char *fq_lock;
  8.  
  9.      if (errbuf)
  10.          *errbuf = '\0';
  11.      set_levelfile_name(lock, lev);
  12.      fq_lock = fqname(lock, LEVELPREFIX, 0);
  13.  
  14.  #if defined(MICRO) || defined(WIN32)
  15.  /* Use O_TRUNC to force the file to be shortened if it already
  16.   * exists and is currently longer.
  17.   */
  18.  #ifdef HOLD_LOCKFILE_OPEN
  19.      if (lev == 0)
  20.          fd = open_levelfile_exclusively(
  21.              fq_lock, lev, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
  22.      else
  23.  #endif
  24.          fd = open(fq_lock, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, FCMASK);
  25.  #else
  26.  #ifdef MAC
  27.      fd = maccreat(fq_lock, LEVL_TYPE);
  28.  #else
  29.      fd = creat(fq_lock, FCMASK);
  30.  #endif
  31.  #endif /* MICRO || WIN32 */
  32.  
  33.      if (fd >= 0)
  34.          level_info[lev].flags |= LFILE_EXISTS;
  35.      else if (errbuf) /* failure explanation */
  36.          Sprintf(errbuf, "Cannot create file \"%s\" for level %d (errno %d).",
  37.                  lock, lev, errno);
  38.  
  39.      return fd;
  40.  }
  41.  

open_levelfile

  1.  int
  2.  open_levelfile(lev, errbuf)
  3.  int lev;
  4.  char errbuf[];
  5.  {
  6.      int fd;
  7.      const char *fq_lock;
  8.  
  9.      if (errbuf)
  10.          *errbuf = '\0';
  11.      set_levelfile_name(lock, lev);
  12.      fq_lock = fqname(lock, LEVELPREFIX, 0);
  13.  #ifdef MFLOPPY
  14.      /* If not currently accessible, swap it in. */
  15.      if (level_info[lev].where != ACTIVE)
  16.          swapin_file(lev);
  17.  #endif
  18.  #ifdef MAC
  19.      fd = macopen(fq_lock, O_RDONLY | O_BINARY, LEVL_TYPE);
  20.  #else
  21.  #ifdef HOLD_LOCKFILE_OPEN
  22.      if (lev == 0)
  23.          fd = open_levelfile_exclusively(fq_lock, lev, O_RDONLY | O_BINARY);
  24.      else
  25.  #endif
  26.          fd = open(fq_lock, O_RDONLY | O_BINARY, 0);
  27.  #endif
  28.  
  29.      /* for failure, return an explanation that our caller can use;
  30.         settle for `lock' instead of `fq_lock' because the latter
  31.         might end up being too big for nethack's BUFSZ */
  32.      if (fd < 0 && errbuf)
  33.          Sprintf(errbuf, "Cannot open file \"%s\" for level %d (errno %d).",
  34.                  lock, lev, errno);
  35.  
  36.      return fd;
  37.  }
  38.  

delete_levelfile

  1.  void
  2.  delete_levelfile(lev)
  3.  int lev;
  4.  {
  5.      /*
  6.       * Level 0 might be created by port specific code that doesn't
  7.       * call create_levfile(), so always assume that it exists.
  8.       */
  9.      if (lev == 0 || (level_info[lev].flags & LFILE_EXISTS)) {
  10.          set_levelfile_name(lock, lev);
  11.  #ifdef HOLD_LOCKFILE_OPEN
  12.          if (lev == 0)
  13.              really_close();
  14.  #endif
  15.          (void) unlink(fqname(lock, LEVELPREFIX, 0));
  16.          level_info[lev].flags &= ~LFILE_EXISTS;
  17.      }
  18.  }
  19.  

clearlocks

  1.  void
  2.  clearlocks()
  3.  {
  4.  #ifdef HANGUPHANDLING
  5.      if (program_state.preserve_locks)
  6.          return;
  7.  #endif
  8.  #if !defined(PC_LOCKING) && defined(MFLOPPY) && !defined(AMIGA)
  9.      eraseall(levels, alllevels);
  10.      if (ramdisk)
  11.          eraseall(permbones, alllevels);
  12.  #else
  13.      {
  14.          register int x;
  15.  
  16.  #ifndef NO_SIGNAL
  17.          (void) signal(SIGINT, SIG_IGN);
  18.  #endif
  19.  #if defined(UNIX) || defined(VMS)
  20.          sethanguphandler((void FDECL((*), (int) )) SIG_IGN);
  21.  #endif
  22.          /* can't access maxledgerno() before dungeons are created -dlc */
  23.          for (x = (n_dgns ? maxledgerno() : 0); x >= 0; x--)
  24.              delete_levelfile(x); /* not all levels need be present */
  25.      }
  26.  #endif /* ?PC_LOCKING,&c */
  27.  }
  28.  

strcmp_wrap

  1.  #if defined(SELECTSAVED)
  2.  /* qsort comparison routine */
  3.  STATIC_OVL int CFDECLSPEC
  4.  strcmp_wrap(p, q)
  5.  const void *p;
  6.  const void *q;
  7.  {
  8.  #if defined(UNIX) && defined(QT_GRAPHICS)
  9.      return strncasecmp(*(char **) p, *(char **) q, 16);
  10.  #else
  11.      return strncmpi(*(char **) p, *(char **) q, 16);
  12.  #endif
  13.  }
  14.  #endif

open_levelfile_exclusively

  1.  
  2.  #ifdef HOLD_LOCKFILE_OPEN
  3.  STATIC_OVL int
  4.  open_levelfile_exclusively(name, lev, oflag)
  5.  const char *name;
  6.  int lev, oflag;
  7.  {
  8.      int reslt, fd;
  9.      if (!lftrack.init) {
  10.          lftrack.init = 1;
  11.          lftrack.fd = -1;
  12.      }
  13.      if (lftrack.fd >= 0) {
  14.          /* check for compatible access */
  15.          if (lftrack.oflag == oflag) {
  16.              fd = lftrack.fd;
  17.              reslt = lseek(fd, 0L, SEEK_SET);
  18.              if (reslt == -1L)
  19.                  panic("open_levelfile_exclusively: lseek failed %d", errno);
  20.              lftrack.nethack_thinks_it_is_open = TRUE;
  21.          } else {
  22.              really_close();
  23.              fd = sopen(name, oflag, SH_DENYRW, FCMASK);
  24.              lftrack.fd = fd;
  25.              lftrack.oflag = oflag;
  26.              lftrack.nethack_thinks_it_is_open = TRUE;
  27.          }
  28.      } else {
  29.          fd = sopen(name, oflag, SH_DENYRW, FCMASK);
  30.          lftrack.fd = fd;
  31.          lftrack.oflag = oflag;
  32.          if (fd >= 0)
  33.              lftrack.nethack_thinks_it_is_open = TRUE;
  34.      }
  35.      return fd;
  36.  }
  37.  

really_close

  1.  void
  2.  really_close()
  3.  {
  4.      int fd = lftrack.fd;
  5.  
  6.      lftrack.nethack_thinks_it_is_open = FALSE;
  7.      lftrack.fd = -1;
  8.      lftrack.oflag = 0;
  9.      if (fd != -1)
  10.          (void) close(fd);
  11.      return;
  12.  }
  13.  

nhclose

  1.  int
  2.  nhclose(fd)
  3.  int fd;
  4.  {
  5.      if (lftrack.fd == fd) {
  6.          really_close(); /* close it, but reopen it to hold it */
  7.          fd = open_levelfile(0, (char *) 0);
  8.          lftrack.nethack_thinks_it_is_open = FALSE;
  9.          return 0;
  10.      }
  11.      return close(fd);
  12.  }
  13.  #else

nhclose

  1.  
  2.  int
  3.  nhclose(fd)
  4.  int fd;
  5.  {
  6.      return close(fd);
  7.  }
  8.  #endif
  9.  
  10.  /* ----------  END LEVEL FILE HANDLING ----------- */
  11.  

Bones file handling

  1.  /* ----------  BEGIN BONES FILE HANDLING ----------- */
  2.  

set_bonesfile_name

  1.  /* set up "file" to be file name for retrieving bones, and return a
  2.   * bonesid to be read/written in the bones file.
  3.   */
  4.  STATIC_OVL char *
  5.  set_bonesfile_name(file, lev)
  6.  char *file;
  7.  d_level *lev;
  8.  {
  9.      s_level *sptr;
  10.      char *dptr;
  11.  
  12.      Sprintf(file, "bon%c%s", dungeons[lev->dnum].boneid,
  13.              In_quest(lev) ? urole.filecode : "0");
  14.      dptr = eos(file);
  15.      if ((sptr = Is_special(lev)) != 0)
  16.          Sprintf(dptr, ".%c", sptr->boneid);
  17.      else
  18.          Sprintf(dptr, ".%d", lev->dlevel);
  19.  #ifdef VMS
  20.      Strcat(dptr, ";1");
  21.  #endif
  22.      return (dptr - 2);
  23.  }
  24.  

set_bonestemp_name

  1.  /* set up temporary file name for writing bones, to avoid another game's
  2.   * trying to read from an uncompleted bones file.  we want an uncontentious
  3.   * name, so use one in the namespace reserved for this game's level files.
  4.   * (we are not reading or writing level files while writing bones files, so
  5.   * the same array may be used instead of copying.)
  6.   */
  7.  STATIC_OVL char *
  8.  set_bonestemp_name()
  9.  {
  10.      char *tf;
  11.  
  12.      tf = rindex(lock, '.');
  13.      if (!tf)
  14.          tf = eos(lock);
  15.      Sprintf(tf, ".bn");
  16.  #ifdef VMS
  17.      Strcat(tf, ";1");
  18.  #endif
  19.      return lock;
  20.  }
  21.  

create_bonesfile

  1.  int
  2.  create_bonesfile(lev, bonesid, errbuf)
  3.  d_level *lev;
  4.  char **bonesid;
  5.  char errbuf[];
  6.  {
  7.      const char *file;
  8.      int fd;
  9.  
  10.      if (errbuf)
  11.          *errbuf = '\0';
  12.      *bonesid = set_bonesfile_name(bones, lev);
  13.      file = set_bonestemp_name();
  14.      file = fqname(file, BONESPREFIX, 0);
  15.  
  16.  #if defined(MICRO) || defined(WIN32)
  17.      /* Use O_TRUNC to force the file to be shortened if it already
  18.       * exists and is currently longer.
  19.       */
  20.      fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, FCMASK);
  21.  #else
  22.  #ifdef MAC
  23.      fd = maccreat(file, BONE_TYPE);
  24.  #else
  25.      fd = creat(file, FCMASK);
  26.  #endif
  27.  #endif
  28.      if (fd < 0 && errbuf) /* failure explanation */
  29.          Sprintf(errbuf, "Cannot create bones \"%s\", id %s (errno %d).", lock,
  30.                  *bonesid, errno);
  31.  
  32.  #if defined(VMS) && !defined(SECURE)
  33.      /*
  34.         Re-protect bones file with world:read+write+execute+delete access.
  35.         umask() doesn't seem very reliable; also, vaxcrtl won't let us set
  36.         delete access without write access, which is what's really wanted.
  37.         Can't simply create it with the desired protection because creat
  38.         ANDs the mask with the user's default protection, which usually
  39.         denies some or all access to world.
  40.       */
  41.      (void) chmod(file, FCMASK | 007); /* allow other users full access */
  42.  #endif /* VMS && !SECURE */
  43.  
  44.      return fd;
  45.  }
  46.  

cancel_bonesfile

  1.  #ifdef MFLOPPY
  2.  /* remove partial bonesfile in process of creation */
  3.  void
  4.  cancel_bonesfile()
  5.  {
  6.      const char *tempname;
  7.  
  8.      tempname = set_bonestemp_name();
  9.      tempname = fqname(tempname, BONESPREFIX, 0);
  10.      (void) unlink(tempname);
  11.  }
  12.  #endif /* MFLOPPY */
  13.  

commit_bonesfile

  1.  /* move completed bones file to proper name */
  2.  void
  3.  commit_bonesfile(lev)
  4.  d_level *lev;
  5.  {
  6.      const char *fq_bones, *tempname;
  7.      int ret;
  8.  
  9.      (void) set_bonesfile_name(bones, lev);
  10.      fq_bones = fqname(bones, BONESPREFIX, 0);
  11.      tempname = set_bonestemp_name();
  12.      tempname = fqname(tempname, BONESPREFIX, 1);
  13.  
  14.  #if (defined(SYSV) && !defined(SVR4)) || defined(GENIX)
  15.      /* old SYSVs don't have rename.  Some SVR3's may, but since they
  16.       * also have link/unlink, it doesn't matter. :-)
  17.       */
  18.      (void) unlink(fq_bones);
  19.      ret = link(tempname, fq_bones);
  20.      ret += unlink(tempname);
  21.  #else
  22.      ret = rename(tempname, fq_bones);
  23.  #endif
  24.      if (wizard && ret != 0)
  25.          pline("couldn't rename %s to %s.", tempname, fq_bones);
  26.  }
  27.  

open_bonesfile

  1.  int
  2.  open_bonesfile(lev, bonesid)
  3.  d_level *lev;
  4.  char **bonesid;
  5.  {
  6.      const char *fq_bones;
  7.      int fd;
  8.  
  9.      *bonesid = set_bonesfile_name(bones, lev);
  10.      fq_bones = fqname(bones, BONESPREFIX, 0);
  11.      nh_uncompress(fq_bones); /* no effect if nonexistent */
  12.  #ifdef MAC
  13.      fd = macopen(fq_bones, O_RDONLY | O_BINARY, BONE_TYPE);
  14.  #else
  15.      fd = open(fq_bones, O_RDONLY | O_BINARY, 0);
  16.  #endif
  17.      return fd;
  18.  }
  19.  

delete_bonesfile

  1.  int
  2.  delete_bonesfile(lev)
  3.  d_level *lev;
  4.  {
  5.      (void) set_bonesfile_name(bones, lev);
  6.      return !(unlink(fqname(bones, BONESPREFIX, 0)) < 0);
  7.  }
  8.  

compress_bonesfile

  1.  /* assume we're compressing the recently read or created bonesfile, so the
  2.   * file name is already set properly */
  3.  void
  4.  compress_bonesfile()
  5.  {
  6.      nh_compress(fqname(bones, BONESPREFIX, 0));
  7.  }
  8.  
  9.  /* ----------  END BONES FILE HANDLING ----------- */
  10.  

Save file handling

  1.  /* ----------  BEGIN SAVE FILE HANDLING ----------- */
  2.  

set_savefile_name

  1.  /* set savefile name in OS-dependent manner from pre-existing plname,
  2.   * avoiding troublesome characters */
  3.  void
  4.  set_savefile_name(regularize_it)
  5.  boolean regularize_it;
  6.  {
  7.  #ifdef VMS
  8.      Sprintf(SAVEF, "[.save]%d%s", getuid(), plname);
  9.      if (regularize_it)
  10.          regularize(SAVEF + 7);
  11.      Strcat(SAVEF, ";1");
  12.  #else
  13.  #if defined(MICRO)
  14.      Strcpy(SAVEF, SAVEP);
  15.  #ifdef AMIGA
  16.      strncat(SAVEF, bbs_id, PATHLEN);
  17.  #endif
  18.      {
  19.          int i = strlen(SAVEP);
  20.  #ifdef AMIGA
  21.          /* plname has to share space with SAVEP and ".sav" */
  22.          (void) strncat(SAVEF, plname, FILENAME - i - 4);
  23.  #else
  24.          (void) strncat(SAVEF, plname, 8);
  25.  #endif
  26.          if (regularize_it)
  27.              regularize(SAVEF + i);
  28.      }
  29.      Strcat(SAVEF, SAVE_EXTENSION);
  30.  #else
  31.  #if defined(WIN32)
  32.      {
  33.          static const char okchars[] =
  34.              "*ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-.";
  35.          const char *legal = okchars;
  36.          char fnamebuf[BUFSZ], encodedfnamebuf[BUFSZ];
  37.  
  38.          /* Obtain the name of the logged on user and incorporate
  39.           * it into the name. */
  40.          Sprintf(fnamebuf, "%s-%s", get_username(0), plname);
  41.          if (regularize_it)
  42.              ++legal; /* skip '*' wildcard character */
  43.          (void) fname_encode(legal, '%', fnamebuf, encodedfnamebuf, BUFSZ);
  44.          Sprintf(SAVEF, "%s%s", encodedfnamebuf, SAVE_EXTENSION);
  45.      }
  46.  #else  /* not VMS or MICRO or WIN32 */
  47.      Sprintf(SAVEF, "save/%d%s", (int) getuid(), plname);
  48.      if (regularize_it)
  49.          regularize(SAVEF + 5); /* avoid . or / in name */
  50.  #endif /* WIN32 */
  51.  #endif /* MICRO */
  52.  #endif /* VMS   */
  53.  }
  54.  

save_savefile_name

  1.  #ifdef INSURANCE
  2.  void
  3.  save_savefile_name(fd)
  4.  int fd;
  5.  {
  6.      (void) write(fd, (genericptr_t) SAVEF, sizeof(SAVEF));
  7.  }
  8.  #endif
  9.  

set_error_savefile

  1.  #ifndef MICRO
  2.  /* change pre-existing savefile name to indicate an error savefile */
  3.  void
  4.  set_error_savefile()
  5.  {
  6.  #ifdef VMS
  7.      {
  8.          char *semi_colon = rindex(SAVEF, ';');
  9.  
  10.          if (semi_colon)
  11.              *semi_colon = '\0';
  12.      }
  13.      Strcat(SAVEF, ".e;1");
  14.  #else
  15.  #ifdef MAC
  16.      Strcat(SAVEF, "-e");
  17.  #else
  18.      Strcat(SAVEF, ".e");
  19.  #endif
  20.  #endif
  21.  }
  22.  #endif
  23.  

create_savefile

  1.  /* create save file, overwriting one if it already exists */
  2.  int
  3.  create_savefile()
  4.  {
  5.      const char *fq_save;
  6.      int fd;
  7.  
  8.      fq_save = fqname(SAVEF, SAVEPREFIX, 0);
  9.  #if defined(MICRO) || defined(WIN32)
  10.      fd = open(fq_save, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK);
  11.  #else
  12.  #ifdef MAC
  13.      fd = maccreat(fq_save, SAVE_TYPE);
  14.  #else
  15.      fd = creat(fq_save, FCMASK);
  16.  #endif
  17.  #if defined(VMS) && !defined(SECURE)
  18.      /*
  19.         Make sure the save file is owned by the current process.  That's
  20.         the default for non-privileged users, but for priv'd users the
  21.         file will be owned by the directory's owner instead of the user.
  22.      */
  23.  #undef getuid
  24.      (void) chown(fq_save, getuid(), getgid());
  25.  #define getuid() vms_getuid()
  26.  #endif /* VMS && !SECURE */
  27.  #endif /* MICRO */
  28.  
  29.      return fd;
  30.  }
  31.  

open_savefile

  1.  /* open savefile for reading */
  2.  int
  3.  open_savefile()
  4.  {
  5.      const char *fq_save;
  6.      int fd;
  7.  
  8.      fq_save = fqname(SAVEF, SAVEPREFIX, 0);
  9.  #ifdef MAC
  10.      fd = macopen(fq_save, O_RDONLY | O_BINARY, SAVE_TYPE);
  11.  #else
  12.      fd = open(fq_save, O_RDONLY | O_BINARY, 0);
  13.  #endif
  14.      return fd;
  15.  }
  16.  

delete_savefile

  1.  /* delete savefile */
  2.  int
  3.  delete_savefile()
  4.  {
  5.      (void) unlink(fqname(SAVEF, SAVEPREFIX, 0));
  6.      return 0; /* for restore_saved_game() (ex-xxxmain.c) test */
  7.  }
  8.  

restore_saved_game

  1.  /* try to open up a save file and prepare to restore it */
  2.  int
  3.  restore_saved_game()
  4.  {
  5.      const char *fq_save;
  6.      int fd;
  7.  
  8.      reset_restpref();
  9.      set_savefile_name(TRUE);
  10.  #ifdef MFLOPPY
  11.      if (!saveDiskPrompt(1))
  12.          return -1;
  13.  #endif /* MFLOPPY */
  14.      fq_save = fqname(SAVEF, SAVEPREFIX, 0);
  15.  
  16.      nh_uncompress(fq_save);
  17.      if ((fd = open_savefile()) < 0)
  18.          return fd;
  19.  
  20.      if (validate(fd, fq_save) != 0) {
  21.          (void) nhclose(fd), fd = -1;
  22.          (void) delete_savefile();
  23.      }
  24.      return fd;
  25.  }
  26.  

plname_from_file

  1.  #if defined(SELECTSAVED)
  2.  char *
  3.  plname_from_file(filename)
  4.  const char *filename;
  5.  {
  6.      int fd;
  7.      char *result = 0;
  8.  
  9.      Strcpy(SAVEF, filename);
  10.  #ifdef COMPRESS_EXTENSION
  11.      SAVEF[strlen(SAVEF) - strlen(COMPRESS_EXTENSION)] = '\0';
  12.  #endif
  13.      nh_uncompress(SAVEF);
  14.      if ((fd = open_savefile()) >= 0) {
  15.          if (validate(fd, filename) == 0) {
  16.              char tplname[PL_NSIZ];
  17.              get_plname_from_file(fd, tplname);
  18.              result = dupstr(tplname);
  19.          }
  20.          (void) nhclose(fd);
  21.      }
  22.      nh_compress(SAVEF);
  23.  
  24.      return result;
  25.  #if 0
  26.  /* --------- obsolete - used to be ifndef STORE_PLNAME_IN_FILE ----*/
  27.  #if defined(UNIX) && defined(QT_GRAPHICS)
  28.      /* Name not stored in save file, so we have to extract it from
  29.         the filename, which loses information
  30.         (eg. "/", "_", and "." characters are lost. */
  31.      int k;
  32.      int uid;
  33.      char name[64]; /* more than PL_NSIZ */
  34.  #ifdef COMPRESS_EXTENSION
  35.  #define EXTSTR COMPRESS_EXTENSION
  36.  #else
  37.  #define EXTSTR ""
  38.  #endif
  39.  
  40.      if ( sscanf( filename, "%*[^/]/%d%63[^.]" EXTSTR, &uid, name ) == 2 ) {
  41.  #undef EXTSTR
  42.          /* "_" most likely means " ", which certainly looks nicer */
  43.          for (k=0; name[k]; k++)
  44.              if ( name[k] == '_' )
  45.                  name[k] = ' ';
  46.          return dupstr(name);
  47.      } else
  48.  #endif /* UNIX && QT_GRAPHICS */
  49.      {
  50.          return 0;
  51.      }
  52.  /* --------- end of obsolete code ----*/
  53.  #endif /* 0 - WAS STORE_PLNAME_IN_FILE*/
  54.  }
  55.  #endif /* defined(SELECTSAVED) */
  56.  

get_saved_games

  1.  char **
  2.  get_saved_games()
  3.  {
  4.  #if defined(SELECTSAVED)
  5.      int n, j = 0;
  6.      char **result = 0;
  7.  #ifdef WIN32
  8.      {
  9.          char *foundfile;
  10.          const char *fq_save;
  11.  
  12.          Strcpy(plname, "*");
  13.          set_savefile_name(FALSE);
  14.  #if defined(ZLIB_COMP)
  15.          Strcat(SAVEF, COMPRESS_EXTENSION);
  16.  #endif
  17.          fq_save = fqname(SAVEF, SAVEPREFIX, 0);
  18.  
  19.          n = 0;
  20.          foundfile = foundfile_buffer();
  21.          if (findfirst((char *) fq_save)) {
  22.              do {
  23.                  ++n;
  24.              } while (findnext());
  25.          }
  26.          if (n > 0) {
  27.              result = (char **) alloc((n + 1) * sizeof(char *)); /* at most */
  28.              (void) memset((genericptr_t) result, 0, (n + 1) * sizeof(char *));
  29.              if (findfirst((char *) fq_save)) {
  30.                  j = n = 0;
  31.                  do {
  32.                      char *r;
  33.                      r = plname_from_file(foundfile);
  34.                      if (r)
  35.                          result[j++] = r;
  36.                      ++n;
  37.                  } while (findnext());
  38.              }
  39.          }
  40.      }
  41.  #endif
  42.  #if defined(UNIX) && defined(QT_GRAPHICS)
  43.      /* posixly correct version */
  44.      int myuid = getuid();
  45.      DIR *dir;
  46.  
  47.      if ((dir = opendir(fqname("save", SAVEPREFIX, 0)))) {
  48.          for (n = 0; readdir(dir); n++)
  49.              ;
  50.          closedir(dir);
  51.          if (n > 0) {
  52.              int i;
  53.  
  54.              if (!(dir = opendir(fqname("save", SAVEPREFIX, 0))))
  55.                  return 0;
  56.              result = (char **) alloc((n + 1) * sizeof(char *)); /* at most */
  57.              (void) memset((genericptr_t) result, 0, (n + 1) * sizeof(char *));
  58.              for (i = 0, j = 0; i < n; i++) {
  59.                  int uid;
  60.                  char name[64]; /* more than PL_NSIZ */
  61.                  struct dirent *entry = readdir(dir);
  62.  
  63.                  if (!entry)
  64.                      break;
  65.                  if (sscanf(entry->d_name, "%d%63s", &uid, name) == 2) {
  66.                      if (uid == myuid) {
  67.                          char filename[BUFSZ];
  68.                          char *r;
  69.  
  70.                          Sprintf(filename, "save/%d%s", uid, name);
  71.                          r = plname_from_file(filename);
  72.                          if (r)
  73.                              result[j++] = r;
  74.                      }
  75.                  }
  76.              }
  77.              closedir(dir);
  78.          }
  79.      }
  80.  #endif
  81.  #ifdef VMS
  82.      Strcpy(plname, "*");
  83.      set_savefile_name(FALSE);
  84.      j = vms_get_saved_games(SAVEF, &result);
  85.  #endif /* VMS */
  86.  
  87.      if (j > 0) {
  88.          if (j > 1)
  89.              qsort(result, j, sizeof (char *), strcmp_wrap);
  90.          result[j] = 0;
  91.          return result;
  92.      } else if (result) { /* could happen if save files are obsolete */
  93.          free_saved_games(result);
  94.      }
  95.  #endif /* SELECTSAVED */
  96.      return 0;
  97.  }
  98.  

free_saved_games

  1.  void
  2.  free_saved_games(saved)
  3.  char **saved;
  4.  {
  5.      if (saved) {
  6.          int i = 0;
  7.  
  8.          while (saved[i])
  9.              free((genericptr_t) saved[i++]);
  10.          free((genericptr_t) saved);
  11.      }
  12.  }
  13.  
  14.  /* ----------  END SAVE FILE HANDLING ----------- */
  15.  

File compression handling

  1.  /* ----------  BEGIN FILE COMPRESSION HANDLING ----------- */
  2.  

redirect

  1.  #ifdef COMPRESS
  2.  
  3.  STATIC_OVL void
  4.  redirect(filename, mode, stream, uncomp)
  5.  const char *filename, *mode;
  6.  FILE *stream;
  7.  boolean uncomp;
  8.  {
  9.      if (freopen(filename, mode, stream) == (FILE *) 0) {
  10.          (void) fprintf(stderr, "freopen of %s for %scompress failed\n",
  11.                         filename, uncomp ? "un" : "");
  12.          terminate(EXIT_FAILURE);
  13.      }
  14.  }
  15.  

docompress_file

  1.  /*
  2.   * using system() is simpler, but opens up security holes and causes
  3.   * problems on at least Interactive UNIX 3.0.1 (SVR3.2), where any
  4.   * setuid is renounced by /bin/sh, so the files cannot be accessed.
  5.   *
  6.   * cf. child() in unixunix.c.
  7.   */
  8.  STATIC_OVL void
  9.  docompress_file(filename, uncomp)
  10.  const char *filename;
  11.  boolean uncomp;
  12.  {
  13.      char cfn[80];
  14.      FILE *cf;
  15.      const char *args[10];
  16.  #ifdef COMPRESS_OPTIONS
  17.      char opts[80];
  18.  #endif
  19.      int i = 0;
  20.      int f;
  21.  #ifdef TTY_GRAPHICS
  22.      boolean istty = !strncmpi(windowprocs.name, "tty", 3);
  23.  #endif
  24.  
  25.      Strcpy(cfn, filename);
  26.  #ifdef COMPRESS_EXTENSION
  27.      Strcat(cfn, COMPRESS_EXTENSION);
  28.  #endif
  29.      /* when compressing, we know the file exists */
  30.      if (uncomp) {
  31.          if ((cf = fopen(cfn, RDBMODE)) == (FILE *) 0)
  32.              return;
  33.          (void) fclose(cf);
  34.      }
  35.  
  36.      args[0] = COMPRESS;
  37.      if (uncomp)
  38.          args[++i] = "-d"; /* uncompress */
  39.  #ifdef COMPRESS_OPTIONS
  40.      {
  41.          /* we can't guarantee there's only one additional option, sigh */
  42.          char *opt;
  43.          boolean inword = FALSE;
  44.  
  45.          Strcpy(opts, COMPRESS_OPTIONS);
  46.          opt = opts;
  47.          while (*opt) {
  48.              if ((*opt == ' ') || (*opt == '\t')) {
  49.                  if (inword) {
  50.                      *opt = '\0';
  51.                      inword = FALSE;
  52.                  }
  53.              } else if (!inword) {
  54.                  args[++i] = opt;
  55.                  inword = TRUE;
  56.              }
  57.              opt++;
  58.          }
  59.      }
  60.  #endif
  61.      args[++i] = (char *) 0;
  62.  
  63.  #ifdef TTY_GRAPHICS
  64.      /* If we don't do this and we are right after a y/n question *and*
  65.       * there is an error message from the compression, the 'y' or 'n' can
  66.       * end up being displayed after the error message.
  67.       */
  68.      if (istty)
  69.          mark_synch();
  70.  #endif
  71.      f = fork();
  72.      if (f == 0) { /* child */
  73.  #ifdef TTY_GRAPHICS
  74.          /* any error messages from the compression must come out after
  75.           * the first line, because the more() to let the user read
  76.           * them will have to clear the first line.  This should be
  77.           * invisible if there are no error messages.
  78.           */
  79.          if (istty)
  80.              raw_print("");
  81.  #endif
  82.          /* run compressor without privileges, in case other programs
  83.           * have surprises along the line of gzip once taking filenames
  84.           * in GZIP.
  85.           */
  86.          /* assume all compressors will compress stdin to stdout
  87.           * without explicit filenames.  this is true of at least
  88.           * compress and gzip, those mentioned in config.h.
  89.           */
  90.          if (uncomp) {
  91.              redirect(cfn, RDBMODE, stdin, uncomp);
  92.              redirect(filename, WRBMODE, stdout, uncomp);
  93.          } else {
  94.              redirect(filename, RDBMODE, stdin, uncomp);
  95.              redirect(cfn, WRBMODE, stdout, uncomp);
  96.          }
  97.          (void) setgid(getgid());
  98.          (void) setuid(getuid());
  99.          (void) execv(args[0], (char *const *) args);
  100.          perror((char *) 0);
  101.          (void) fprintf(stderr, "Exec to %scompress %s failed.\n",
  102.                         uncomp ? "un" : "", filename);
  103.          terminate(EXIT_FAILURE);
  104.      } else if (f == -1) {
  105.          perror((char *) 0);
  106.          pline("Fork to %scompress %s failed.", uncomp ? "un" : "", filename);
  107.          return;
  108.      }
  109.  #ifndef NO_SIGNAL
  110.      (void) signal(SIGINT, SIG_IGN);
  111.      (void) signal(SIGQUIT, SIG_IGN);
  112.      (void) wait((int *) &i);
  113.      (void) signal(SIGINT, (SIG_RET_TYPE) done1);
  114.      if (wizard)
  115.          (void) signal(SIGQUIT, SIG_DFL);
  116.  #else
  117.      /* I don't think we can really cope with external compression
  118.       * without signals, so we'll declare that compress failed and
  119.       * go on.  (We could do a better job by forcing off external
  120.       * compression if there are no signals, but we want this for
  121.       * testing with FailSafeC
  122.       */
  123.      i = 1;
  124.  #endif
  125.      if (i == 0) {
  126.          /* (un)compress succeeded: remove file left behind */
  127.          if (uncomp)
  128.              (void) unlink(cfn);
  129.          else
  130.              (void) unlink(filename);
  131.      } else {
  132.          /* (un)compress failed; remove the new, bad file */
  133.          if (uncomp) {
  134.              raw_printf("Unable to uncompress %s", filename);
  135.              (void) unlink(filename);
  136.          } else {
  137.              /* no message needed for compress case; life will go on */
  138.              (void) unlink(cfn);
  139.          }
  140.  #ifdef TTY_GRAPHICS
  141.          /* Give them a chance to read any error messages from the
  142.           * compression--these would go to stdout or stderr and would get
  143.           * overwritten only in tty mode.  It's still ugly, since the
  144.           * messages are being written on top of the screen, but at least
  145.           * the user can read them.
  146.           */
  147.          if (istty && iflags.window_inited) {
  148.              clear_nhwindow(WIN_MESSAGE);
  149.              more();
  150.              /* No way to know if this is feasible */
  151.              /* doredraw(); */
  152.          }
  153.  #endif
  154.      }
  155.  }
  156.  #endif /* COMPRESS */
  157.  

nh_compress

  1.  #if defined(COMPRESS) || defined(ZLIB_COMP)
  2.  #define UNUSED_if_not_COMPRESS /*empty*/
  3.  #else
  4.  #define UNUSED_if_not_COMPRESS UNUSED
  5.  #endif
  6.  
  7.  /* compress file */
  8.  void
  9.  nh_compress(filename)
  10.  const char *filename UNUSED_if_not_COMPRESS;
  11.  {
  12.  #if !defined(COMPRESS) && !defined(ZLIB_COMP)
  13.  #ifdef PRAGMA_UNUSED
  14.  #pragma unused(filename)
  15.  #endif
  16.  #else
  17.      docompress_file(filename, FALSE);
  18.  #endif
  19.  }
  20.  

nh_uncompress

  1.  /* uncompress file if it exists */
  2.  void
  3.  nh_uncompress(filename)
  4.  const char *filename UNUSED_if_not_COMPRESS;
  5.  {
  6.  #if !defined(COMPRESS) && !defined(ZLIB_COMP)
  7.  #ifdef PRAGMA_UNUSED
  8.  #pragma unused(filename)
  9.  #endif
  10.  #else
  11.      docompress_file(filename, TRUE);
  12.  #endif
  13.  }
  14.  

make_compressed_name

  1.  #ifdef ZLIB_COMP /* RLC 09 Mar 1999: Support internal ZLIB */
  2.  STATIC_OVL boolean
  3.  make_compressed_name(filename, cfn)
  4.  const char *filename;
  5.  char *cfn;
  6.  {
  7.  #ifndef SHORT_FILENAMES
  8.      /* Assume free-form filename with no 8.3 restrictions */
  9.      strcpy(cfn, filename);
  10.      strcat(cfn, COMPRESS_EXTENSION);
  11.      return TRUE;
  12.  #else
  13.  #ifdef SAVE_EXTENSION
  14.      char *bp = (char *) 0;
  15.  
  16.      strcpy(cfn, filename);
  17.      if ((bp = strstri(cfn, SAVE_EXTENSION))) {
  18.          strsubst(bp, SAVE_EXTENSION, ".saz");
  19.          return TRUE;
  20.      } else {
  21.          /* find last occurrence of bon */
  22.          bp = eos(cfn);
  23.          while (bp-- > cfn) {
  24.              if (strstri(bp, "bon")) {
  25.                  strsubst(bp, "bon", "boz");
  26.                  return TRUE;
  27.              }
  28.          }
  29.      }
  30.  #endif /* SAVE_EXTENSION */
  31.      return FALSE;
  32.  #endif /* SHORT_FILENAMES */
  33.  }
  34.  

docompress_file

  1.  STATIC_OVL void
  2.  docompress_file(filename, uncomp)
  3.  const char *filename;
  4.  boolean uncomp;
  5.  {
  6.      gzFile compressedfile;
  7.      FILE *uncompressedfile;
  8.      char cfn[256];
  9.      char buf[1024];
  10.      unsigned len, len2;
  11.  
  12.      if (!make_compressed_name(filename, cfn))
  13.          return;
  14.  
  15.      if (!uncomp) {
  16.          /* Open the input and output files */
  17.          /* Note that gzopen takes "wb" as its mode, even on systems where
  18.             fopen takes "r" and "w" */
  19.  
  20.          uncompressedfile = fopen(filename, RDBMODE);
  21.          if (!uncompressedfile) {
  22.              pline("Error in zlib docompress_file %s", filename);
  23.              return;
  24.          }
  25.          compressedfile = gzopen(cfn, "wb");
  26.          if (compressedfile == NULL) {
  27.              if (errno == 0) {
  28.                  pline("zlib failed to allocate memory");
  29.              } else {
  30.                  panic("Error in docompress_file %d", errno);
  31.              }
  32.              fclose(uncompressedfile);
  33.              return;
  34.          }
  35.  
  36.          /* Copy from the uncompressed to the compressed file */
  37.  
  38.          while (1) {
  39.              len = fread(buf, 1, sizeof(buf), uncompressedfile);
  40.              if (ferror(uncompressedfile)) {
  41.                  pline("Failure reading uncompressed file");
  42.                  pline("Can't compress %s.", filename);
  43.                  fclose(uncompressedfile);
  44.                  gzclose(compressedfile);
  45.                  (void) unlink(cfn);
  46.                  return;
  47.              }
  48.              if (len == 0)
  49.                  break; /* End of file */
  50.  
  51.              len2 = gzwrite(compressedfile, buf, len);
  52.              if (len2 == 0) {
  53.                  pline("Failure writing compressed file");
  54.                  pline("Can't compress %s.", filename);
  55.                  fclose(uncompressedfile);
  56.                  gzclose(compressedfile);
  57.                  (void) unlink(cfn);
  58.                  return;
  59.              }
  60.          }
  61.  
  62.          fclose(uncompressedfile);
  63.          gzclose(compressedfile);
  64.  
  65.          /* Delete the file left behind */
  66.  
  67.          (void) unlink(filename);
  68.  
  69.      } else { /* uncomp */
  70.  
  71.          /* Open the input and output files */
  72.          /* Note that gzopen takes "rb" as its mode, even on systems where
  73.             fopen takes "r" and "w" */
  74.  
  75.          compressedfile = gzopen(cfn, "rb");
  76.          if (compressedfile == NULL) {
  77.              if (errno == 0) {
  78.                  pline("zlib failed to allocate memory");
  79.              } else if (errno != ENOENT) {
  80.                  panic("Error in zlib docompress_file %s, %d", filename,
  81.                        errno);
  82.              }
  83.              return;
  84.          }
  85.          uncompressedfile = fopen(filename, WRBMODE);
  86.          if (!uncompressedfile) {
  87.              pline("Error in zlib docompress file uncompress %s", filename);
  88.              gzclose(compressedfile);
  89.              return;
  90.          }
  91.  
  92.          /* Copy from the compressed to the uncompressed file */
  93.  
  94.          while (1) {
  95.              len = gzread(compressedfile, buf, sizeof(buf));
  96.              if (len == (unsigned) -1) {
  97.                  pline("Failure reading compressed file");
  98.                  pline("Can't uncompress %s.", filename);
  99.                  fclose(uncompressedfile);
  100.                  gzclose(compressedfile);
  101.                  (void) unlink(filename);
  102.                  return;
  103.              }
  104.              if (len == 0)
  105.                  break; /* End of file */
  106.  
  107.              fwrite(buf, 1, len, uncompressedfile);
  108.              if (ferror(uncompressedfile)) {
  109.                  pline("Failure writing uncompressed file");
  110.                  pline("Can't uncompress %s.", filename);
  111.                  fclose(uncompressedfile);
  112.                  gzclose(compressedfile);
  113.                  (void) unlink(filename);
  114.                  return;
  115.              }
  116.          }
  117.  
  118.          fclose(uncompressedfile);
  119.          gzclose(compressedfile);
  120.  
  121.          /* Delete the file left behind */
  122.          (void) unlink(cfn);
  123.      }
  124.  }
  125.  #endif /* RLC 09 Mar 1999: End ZLIB patch */
  126.  
  127.  /* ----------  END FILE COMPRESSION HANDLING ----------- */
  128.  

File locking handling

  1.  /* ----------  BEGIN FILE LOCKING HANDLING ----------- */
  2.  
  3.  static int nesting = 0;
  4.  
  5.  #if defined(NO_FILE_LINKS) || defined(USE_FCNTL) /* implies UNIX */
  6.  static int lockfd; /* for lock_file() to pass to unlock_file() */
  7.  #endif
  8.  #ifdef USE_FCNTL
  9.  struct flock sflock; /* for unlocking, same as above */
  10.  #endif
  11.  
  12.  #define HUP if (!program_state.done_hup)
  13.  
  14.  #ifndef USE_FCNTL

make_lockname

  1.  STATIC_OVL char *
  2.  make_lockname(filename, lockname)
  3.  const char *filename;
  4.  char *lockname;
  5.  {
  6.  #if defined(UNIX) || defined(VMS) || defined(AMIGA) || defined(WIN32) \
  7.      || defined(MSDOS)
  8.  #ifdef NO_FILE_LINKS
  9.      Strcpy(lockname, LOCKDIR);
  10.      Strcat(lockname, "/");
  11.      Strcat(lockname, filename);
  12.  #else
  13.      Strcpy(lockname, filename);
  14.  #endif
  15.  #ifdef VMS
  16.      {
  17.          char *semi_colon = rindex(lockname, ';');
  18.          if (semi_colon)
  19.              *semi_colon = '\0';
  20.      }
  21.      Strcat(lockname, ".lock;1");
  22.  #else
  23.      Strcat(lockname, "_lock");
  24.  #endif
  25.      return lockname;
  26.  #else /* !(UNIX || VMS || AMIGA || WIN32 || MSDOS) */
  27.  #ifdef PRAGMA_UNUSED
  28.  #pragma unused(filename)
  29.  #endif
  30.      lockname[0] = '\0';
  31.      return (char *) 0;
  32.  #endif
  33.  }
  34.  #endif /* !USE_FCNTL */

lock_file

  1.  
  2.  /* lock a file */
  3.  boolean
  4.  lock_file(filename, whichprefix, retryct)
  5.  const char *filename;
  6.  int whichprefix;
  7.  int retryct;
  8.  {
  9.  #if defined(PRAGMA_UNUSED) && !(defined(UNIX) || defined(VMS)) \
  10.      && !(defined(AMIGA) || defined(WIN32) || defined(MSDOS))
  11.  #pragma unused(retryct)
  12.  #endif
  13.  #ifndef USE_FCNTL
  14.      char locknambuf[BUFSZ];
  15.      const char *lockname;
  16.  #endif
  17.  
  18.      nesting++;
  19.      if (nesting > 1) {
  20.          impossible("TRIED TO NEST LOCKS");
  21.          return TRUE;
  22.      }
  23.  
  24.  #ifndef USE_FCNTL
  25.      lockname = make_lockname(filename, locknambuf);
  26.  #ifndef NO_FILE_LINKS /* LOCKDIR should be subsumed by LOCKPREFIX */
  27.      lockname = fqname(lockname, LOCKPREFIX, 2);
  28.  #endif
  29.  #endif
  30.      filename = fqname(filename, whichprefix, 0);
  31.  #ifdef USE_FCNTL
  32.      lockfd = open(filename, O_RDWR);
  33.      if (lockfd == -1) {
  34.          HUP raw_printf("Cannot open file %s. This is a program bug.",
  35.                         filename);
  36.      }
  37.      sflock.l_type = F_WRLCK;
  38.      sflock.l_whence = SEEK_SET;
  39.      sflock.l_start = 0;
  40.      sflock.l_len = 0;
  41.  #endif
  42.  
  43.  #if defined(UNIX) || defined(VMS)
  44.  #ifdef USE_FCNTL
  45.      while (fcntl(lockfd, F_SETLK, &sflock) == -1) {
  46.  #else
  47.  #ifdef NO_FILE_LINKS
  48.      while ((lockfd = open(lockname, O_RDWR | O_CREAT | O_EXCL, 0666)) == -1) {
  49.  #else
  50.      while (link(filename, lockname) == -1) {
  51.  #endif
  52.  #endif
  53.  
  54.  #ifdef USE_FCNTL
  55.          if (retryct--) {
  56.              HUP raw_printf(
  57.                  "Waiting for release of fcntl lock on %s. (%d retries left).",
  58.                  filename, retryct);
  59.              sleep(1);
  60.          } else {
  61.              HUP(void) raw_print("I give up.  Sorry.");
  62.              HUP raw_printf("Some other process has an unnatural grip on %s.",
  63.                             filename);
  64.              nesting--;
  65.              return FALSE;
  66.          }
  67.  #else
  68.          register int errnosv = errno;
  69.  
  70.          switch (errnosv) { /* George Barbanis */
  71.          case EEXIST:
  72.              if (retryct--) {
  73.                  HUP raw_printf(
  74.                      "Waiting for access to %s.  (%d retries left).", filename,
  75.                      retryct);
  76.  #if defined(SYSV) || defined(ULTRIX) || defined(VMS)
  77.                  (void)
  78.  #endif
  79.                      sleep(1);
  80.              } else {
  81.                  HUP(void) raw_print("I give up.  Sorry.");
  82.                  HUP raw_printf("Perhaps there is an old %s around?",
  83.                                 lockname);
  84.                  nesting--;
  85.                  return FALSE;
  86.              }
  87.  
  88.              break;
  89.          case ENOENT:
  90.              HUP raw_printf("Can't find file %s to lock!", filename);
  91.              nesting--;
  92.              return FALSE;
  93.          case EACCES:
  94.              HUP raw_printf("No write permission to lock %s!", filename);
  95.              nesting--;
  96.              return FALSE;
  97.  #ifdef VMS /* c__translate(vmsfiles.c) */
  98.          case EPERM:
  99.              /* could be misleading, but usually right */
  100.              HUP raw_printf("Can't lock %s due to directory protection.",
  101.                             filename);
  102.              nesting--;
  103.              return FALSE;
  104.  #endif
  105.          case EROFS:
  106.              /* take a wild guess at the underlying cause */
  107.              HUP perror(lockname);
  108.              HUP raw_printf("Cannot lock %s.", filename);
  109.              HUP raw_printf(
  110.    "(Perhaps you are running NetHack from inside the distribution package?).");
  111.              nesting--;
  112.              return FALSE;
  113.          default:
  114.              HUP perror(lockname);
  115.              HUP raw_printf("Cannot lock %s for unknown reason (%d).",
  116.                             filename, errnosv);
  117.              nesting--;
  118.              return FALSE;
  119.          }
  120.  #endif /* USE_FCNTL */
  121.      }
  122.  #endif /* UNIX || VMS */
  123.  
  124.  #if (defined(AMIGA) || defined(WIN32) || defined(MSDOS)) \
  125.      && !defined(USE_FCNTL)
  126.  #ifdef AMIGA
  127.  #define OPENFAILURE(fd) (!fd)
  128.      lockptr = 0;
  129.  #else
  130.  #define OPENFAILURE(fd) (fd < 0)
  131.      lockptr = -1;
  132.  #endif
  133.      while (--retryct && OPENFAILURE(lockptr)) {
  134.  #if defined(WIN32) && !defined(WIN_CE)
  135.          lockptr = sopen(lockname, O_RDWR | O_CREAT, SH_DENYRW, S_IWRITE);
  136.  #else
  137.          (void) DeleteFile(lockname); /* in case dead process was here first */
  138.  #ifdef AMIGA
  139.          lockptr = Open(lockname, MODE_NEWFILE);
  140.  #else
  141.          lockptr = open(lockname, O_RDWR | O_CREAT | O_EXCL, S_IWRITE);
  142.  #endif
  143.  #endif
  144.          if (OPENFAILURE(lockptr)) {
  145.              raw_printf("Waiting for access to %s.  (%d retries left).",
  146.                         filename, retryct);
  147.              Delay(50);
  148.          }
  149.      }
  150.      if (!retryct) {
  151.          raw_printf("I give up.  Sorry.");
  152.          nesting--;
  153.          return FALSE;
  154.      }
  155.  #endif /* AMIGA || WIN32 || MSDOS */
  156.      return TRUE;
  157.  }
  158.  

unlock_file

  1.  #ifdef VMS /* for unlock_file, use the unlink() routine in vmsunix.c */
  2.  #ifdef unlink
  3.  #undef unlink
  4.  #endif
  5.  #define unlink(foo) vms_unlink(foo)
  6.  #endif
  7.  
  8.  /* unlock file, which must be currently locked by lock_file */
  9.  void
  10.  unlock_file(filename)
  11.  const char *filename;
  12.  {
  13.  #ifndef USE_FCNTL
  14.      char locknambuf[BUFSZ];
  15.      const char *lockname;
  16.  #endif
  17.  
  18.      if (nesting == 1) {
  19.  #ifdef USE_FCNTL
  20.          sflock.l_type = F_UNLCK;
  21.          if (fcntl(lockfd, F_SETLK, &sflock) == -1) {
  22.              HUP raw_printf("Can't remove fcntl lock on %s.", filename);
  23.              (void) close(lockfd);
  24.          }
  25.  #else
  26.          lockname = make_lockname(filename, locknambuf);
  27.  #ifndef NO_FILE_LINKS /* LOCKDIR should be subsumed by LOCKPREFIX */
  28.          lockname = fqname(lockname, LOCKPREFIX, 2);
  29.  #endif
  30.  
  31.  #if defined(UNIX) || defined(VMS)
  32.          if (unlink(lockname) < 0)
  33.              HUP raw_printf("Can't unlink %s.", lockname);
  34.  #ifdef NO_FILE_LINKS
  35.          (void) nhclose(lockfd);
  36.  #endif
  37.  
  38.  #endif /* UNIX || VMS */
  39.  
  40.  #if defined(AMIGA) || defined(WIN32) || defined(MSDOS)
  41.          if (lockptr)
  42.              Close(lockptr);
  43.          DeleteFile(lockname);
  44.          lockptr = 0;
  45.  #endif /* AMIGA || WIN32 || MSDOS */
  46.  #endif /* USE_FCNTL */
  47.      }
  48.  
  49.      nesting--;
  50.  }
  51.  
  52.  /* ----------  END FILE LOCKING HANDLING ----------- */
  53.  

Config file handling

  1.  /* ----------  BEGIN CONFIG FILE HANDLING ----------- */
  2.  
  3.  const char *configfile =
  4.  #ifdef UNIX
  5.      ".nethackrc";
  6.  #else
  7.  #if defined(MAC) || defined(__BEOS__)
  8.      "NetHack Defaults";
  9.  #else
  10.  #if defined(MSDOS) || defined(WIN32)
  11.      "defaults.nh";
  12.  #else
  13.      "NetHack.cnf";
  14.  #endif
  15.  #endif
  16.  #endif
  17.  
  18.  /* used for messaging */
  19.  char lastconfigfile[BUFSZ];
  20.  
  21.  #ifdef MSDOS
  22.  /* conflict with speed-dial under windows
  23.   * for XXX.cnf file so support of NetHack.cnf
  24.   * is for backward compatibility only.
  25.   * Preferred name (and first tried) is now defaults.nh but
  26.   * the game will try the old name if there
  27.   * is no defaults.nh.
  28.   */
  29.  const char *backward_compat_configfile = "nethack.cnf";
  30.  #endif
  31.  
  32.  #ifndef MFLOPPY
  33.  #define fopenp fopen
  34.  #endif
  35.  

fopen_config_file

  1.  STATIC_OVL FILE *
  2.  fopen_config_file(filename, src)
  3.  const char *filename;
  4.  int src;
  5.  {
  6.      FILE *fp;
  7.  #if defined(UNIX) || defined(VMS)
  8.      char tmp_config[BUFSZ];
  9.      char *envp;
  10.  #endif
  11.  
  12.      /* If src != SET_IN_SYS, "filename" is an environment variable, so it
  13.       * should hang around. If set, it is expected to be a full path name
  14.       * (if relevant) */
  15.      if (filename) {
  16.  #ifdef UNIX
  17.          if ((src != SET_IN_SYS) && access(filename, 4) == -1) {
  18.              /* 4 is R_OK on newer systems */
  19.              /* nasty sneaky attempt to read file through
  20.               * NetHack's setuid permissions -- this is the only
  21.               * place a file name may be wholly under the player's
  22.               * control (but SYSCF_FILE is not under the player's
  23.               * control so it's OK).
  24.               */
  25.              raw_printf("Access to %s denied (%d).", filename, errno);
  26.              wait_synch();
  27.              /* fall through to standard names */
  28.          } else
  29.  #endif
  30.  #ifdef PREFIXES_IN_USE
  31.              if (src == SET_IN_SYS) {
  32.              (void) strncpy(lastconfigfile, fqname(filename, SYSCONFPREFIX, 0),
  33.                             BUFSZ - 1);
  34.          } else
  35.  #endif
  36.              /* always honor sysconf first before anything else */
  37.              (void) strncpy(lastconfigfile, filename, BUFSZ - 1);
  38.          lastconfigfile[BUFSZ - 1] = '\0';
  39.          if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0)
  40.              return  fp;
  41.          if ((fp = fopenp(filename, "r")) != (FILE *) 0) {
  42.              return  fp;
  43.  #if defined(UNIX) || defined(VMS)
  44.          } else {
  45.              /* access() above probably caught most problems for UNIX */
  46.              raw_printf("Couldn't open requested config file %s (%d).",
  47.                         filename, errno);
  48.              wait_synch();
  49.  /* fall through to standard names */
  50.  #endif
  51.          }
  52.      }
  53.  
  54.  #if defined(MICRO) || defined(MAC) || defined(__BEOS__) || defined(WIN32)
  55.      if ((fp = fopenp(fqname(configfile, CONFIGPREFIX, 0), "r")) != (FILE *) 0)
  56.          return fp;
  57.      if ((fp = fopenp(configfile, "r")) != (FILE *) 0)
  58.          return fp;
  59.  #ifdef MSDOS
  60.      if ((fp = fopenp(fqname(backward_compat_configfile, CONFIGPREFIX, 0),
  61.                       "r")) != (FILE *) 0)
  62.          return fp;
  63.      if ((fp = fopenp(backward_compat_configfile, "r")) != (FILE *) 0)
  64.          return fp;
  65.  #endif
  66.  #else
  67.  /* constructed full path names don't need fqname() */
  68.  #ifdef VMS
  69.      (void) strncpy(lastconfigfile, fqname("nethackini", CONFIGPREFIX, 0),
  70.                     BUFSZ - 1);
  71.      lastconfigfile[BUFSZ - 1] = '\0';
  72.      if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0) {
  73.          return fp;
  74.      }
  75.      (void) strncpy(lastconfigfile, "sys$login:nethack.ini", BUFSZ - 1);
  76.      lastconfigfile[BUFSZ - 1] = '\0';
  77.      if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0) {
  78.          return fp;
  79.      }
  80.  
  81.      envp = nh_getenv("HOME");
  82.      if (!envp)
  83.          Strcpy(tmp_config, "NetHack.cnf");
  84.      else
  85.          Sprintf(tmp_config, "%s%s", envp, "NetHack.cnf");
  86.  
  87.      (void) strncpy(lastconfigfile, tmp_config, BUFSZ - 1);
  88.      lastconfigfile[BUFSZ - 1] = '\0';
  89.      if ((fp = fopenp(tmp_config, "r")) != (FILE *) 0)
  90.          return fp;
  91.  #else /* should be only UNIX left */
  92.      envp = nh_getenv("HOME");
  93.      if (!envp)
  94.          Strcpy(tmp_config, ".nethackrc");
  95.      else
  96.          Sprintf(tmp_config, "%s/%s", envp, ".nethackrc");
  97.  
  98.      (void) strncpy(lastconfigfile, tmp_config, BUFSZ - 1);
  99.      lastconfigfile[BUFSZ - 1] = '\0';
  100.      if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0)
  101.          return fp;
  102.  #if defined(__APPLE__)
  103.      /* try an alternative */
  104.      if (envp) {
  105.          Sprintf(tmp_config, "%s/%s", envp,
  106.                  "Library/Preferences/NetHack Defaults");
  107.          (void) strncpy(lastconfigfile, tmp_config, BUFSZ - 1);
  108.          lastconfigfile[BUFSZ - 1] = '\0';
  109.          if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0)
  110.              return fp;
  111.          Sprintf(tmp_config, "%s/%s", envp,
  112.                  "Library/Preferences/NetHack Defaults.txt");
  113.          (void) strncpy(lastconfigfile, tmp_config, BUFSZ - 1);
  114.          lastconfigfile[BUFSZ - 1] = '\0';
  115.          if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0)
  116.              return fp;
  117.      }
  118.  #endif
  119.      if (errno != ENOENT) {
  120.          const char *details;
  121.  
  122.  /* e.g., problems when setuid NetHack can't search home
  123.   * directory restricted to user */
  124.  
  125.  #if defined(NHSTDC) && !defined(NOTSTDC)
  126.          if ((details = strerror(errno)) == 0)
  127.  #endif
  128.              details = "";
  129.          raw_printf("Couldn't open default config file %s %s(%d).",
  130.                     lastconfigfile, details, errno);
  131.          wait_synch();
  132.      }
  133.  #endif /* Unix */
  134.  #endif
  135.      return (FILE *) 0;
  136.  }
  137.  

get_uchars

  1.  /*
  2.   * Retrieve a list of integers from a file into a uchar array.
  3.   *
  4.   * NOTE: zeros are inserted unless modlist is TRUE, in which case the list
  5.   *  location is unchanged.  Callers must handle zeros if modlist is FALSE.
  6.   */
  7.  STATIC_OVL int
  8.  get_uchars(fp, buf, bufp, list, modlist, size, name)
  9.  FILE *fp;         /* input file pointer */
  10.  char *buf;        /* read buffer, must be of size BUFSZ */
  11.  char *bufp;       /* current pointer */
  12.  uchar *list;      /* return list */
  13.  boolean modlist;  /* TRUE: list is being modified in place */
  14.  int size;         /* return list size */
  15.  const char *name; /* name of option for error message */
  16.  {
  17.      unsigned int num = 0;
  18.      int count = 0;
  19.      boolean havenum = FALSE;
  20.  
  21.      while (1) {
  22.          switch (*bufp) {
  23.          case ' ':
  24.          case '\0':
  25.          case '\t':
  26.          case '\n':
  27.              if (havenum) {
  28.                  /* if modifying in place, don't insert zeros */
  29.                  if (num || !modlist)
  30.                      list[count] = num;
  31.                  count++;
  32.                  num = 0;
  33.                  havenum = FALSE;
  34.              }
  35.              if (count == size || !*bufp)
  36.                  return count;
  37.              bufp++;
  38.              break;
  39.  
  40.          case '0':
  41.          case '1':
  42.          case '2':
  43.          case '3':
  44.          case '4':
  45.          case '5':
  46.          case '6':
  47.          case '7':
  48.          case '8':
  49.          case '9':
  50.              havenum = TRUE;
  51.              num = num * 10 + (*bufp - '0');
  52.              bufp++;
  53.              break;
  54.  
  55.          case '\\':
  56.              if (fp == (FILE *) 0)
  57.                  goto gi_error;
  58.              do {
  59.                  if (!fgets(buf, BUFSZ, fp))
  60.                      goto gi_error;
  61.              } while (buf[0] == '#');
  62.              bufp = buf;
  63.              break;
  64.  
  65.          default:
  66.          gi_error:
  67.              raw_printf("Syntax error in %s", name);
  68.              wait_synch();
  69.              return count;
  70.          }
  71.      }
  72.      /*NOTREACHED*/
  73.  }
  74.  

adjust_prefix

  1.  #ifdef NOCWD_ASSUMPTIONS
  2.  STATIC_OVL void
  3.  adjust_prefix(bufp, prefixid)
  4.  char *bufp;
  5.  int prefixid;
  6.  {
  7.      char *ptr;
  8.  
  9.      if (!bufp)
  10.          return;
  11.      /* Backward compatibility, ignore trailing ;n */
  12.      if ((ptr = index(bufp, ';')) != 0)
  13.          *ptr = '\0';
  14.      if (strlen(bufp) > 0) {
  15.          fqn_prefix[prefixid] = (char *) alloc(strlen(bufp) + 2);
  16.          Strcpy(fqn_prefix[prefixid], bufp);
  17.          append_slash(fqn_prefix[prefixid]);
  18.      }
  19.  }
  20.  #endif
  21.  

parse_config_line

  1.  #define match_varname(INP, NAM, LEN) match_optname(INP, NAM, LEN, TRUE)
  2.  
  3.  int
  4.  parse_config_line(fp, origbuf, src)
  5.  FILE *fp;
  6.  char *origbuf;
  7.  int src;
  8.  {
  9.  #if defined(MICRO) && !defined(NOCWD_ASSUMPTIONS)
  10.      static boolean ramdisk_specified = FALSE;
  11.  #endif
  12.  #ifdef SYSCF
  13.      int n;
  14.  #endif
  15.      char *bufp, *altp, buf[BUFSZ];
  16.      uchar translate[MAXPCHARS];
  17.      int len;
  18.  
  19.      /* convert any tab to space, condense consecutive spaces into one,
  20.         remove leading and trailing spaces (exception: if there is nothing
  21.         but spaces, one of them will be kept even though it leads/trails) */
  22.      mungspaces(strcpy(buf, origbuf));
  23.      /* lines beginning with '#' are comments; accept empty lines too */
  24.      if (!*buf || *buf == '#' || !strcmp(buf, " "))
  25.          return 1;
  26.  
  27.      /* find the '=' or ':' */
  28.      bufp = index(buf, '=');
  29.      altp = index(buf, ':');
  30.      if (!bufp || (altp && altp < bufp))
  31.          bufp = altp;
  32.      if (!bufp)
  33.          return 0;
  34.      /* skip past '=', then space between it and value, if any */
  35.      ++bufp;
  36.      if (*bufp == ' ')
  37.          ++bufp;
  38.  
  39.      /* Go through possible variables */
  40.      /* some of these (at least LEVELS and SAVE) should now set the
  41.       * appropriate fqn_prefix[] rather than specialized variables
  42.       */
  43.      if (match_varname(buf, "OPTIONS", 4)) {
  44.          /* hack: un-mungspaces to allow consecutive spaces in
  45.             general options until we verify that this is unnecessary;
  46.             '=' or ':' is guaranteed to be present */
  47.          bufp = index(origbuf, '=');
  48.          altp = index(origbuf, ':');
  49.          if (!bufp || (altp && altp < bufp))
  50.              bufp = altp;
  51.          ++bufp; /* skip '='; parseoptions() handles spaces */
  52.  
  53.          parseoptions(bufp, TRUE, TRUE);
  54.          if (plname[0])      /* If a name was given */
  55.              plnamesuffix(); /* set the character class */
  56.      } else if (match_varname(buf, "AUTOPICKUP_EXCEPTION", 5)) {
  57.          add_autopickup_exception(bufp);
  58.      } else if (match_varname(buf, "MSGTYPE", 7)) {
  59.          (void) msgtype_parse_add(bufp);
  60.  #ifdef NOCWD_ASSUMPTIONS
  61.      } else if (match_varname(buf, "HACKDIR", 4)) {
  62.          adjust_prefix(bufp, HACKPREFIX);
  63.      } else if (match_varname(buf, "LEVELDIR", 4)
  64.                 || match_varname(buf, "LEVELS", 4)) {
  65.          adjust_prefix(bufp, LEVELPREFIX);
  66.      } else if (match_varname(buf, "SAVEDIR", 4)) {
  67.          adjust_prefix(bufp, SAVEPREFIX);
  68.      } else if (match_varname(buf, "BONESDIR", 5)) {
  69.          adjust_prefix(bufp, BONESPREFIX);
  70.      } else if (match_varname(buf, "DATADIR", 4)) {
  71.          adjust_prefix(bufp, DATAPREFIX);
  72.      } else if (match_varname(buf, "SCOREDIR", 4)) {
  73.          adjust_prefix(bufp, SCOREPREFIX);
  74.      } else if (match_varname(buf, "LOCKDIR", 4)) {
  75.          adjust_prefix(bufp, LOCKPREFIX);
  76.      } else if (match_varname(buf, "CONFIGDIR", 4)) {
  77.          adjust_prefix(bufp, CONFIGPREFIX);
  78.      } else if (match_varname(buf, "TROUBLEDIR", 4)) {
  79.          adjust_prefix(bufp, TROUBLEPREFIX);
  80.  #else /*NOCWD_ASSUMPTIONS*/
  81.  #ifdef MICRO
  82.      } else if (match_varname(buf, "HACKDIR", 4)) {
  83.          (void) strncpy(hackdir, bufp, PATHLEN - 1);
  84.  #ifdef MFLOPPY
  85.      } else if (match_varname(buf, "RAMDISK", 3)) {
  86.  /* The following ifdef is NOT in the wrong
  87.   * place.  For now, we accept and silently
  88.   * ignore RAMDISK */
  89.  #ifndef AMIGA
  90.          if (strlen(bufp) >= PATHLEN)
  91.              bufp[PATHLEN - 1] = '\0';
  92.          Strcpy(levels, bufp);
  93.          ramdisk = (strcmp(permbones, levels) != 0);
  94.          ramdisk_specified = TRUE;
  95.  #endif
  96.  #endif
  97.      } else if (match_varname(buf, "LEVELS", 4)) {
  98.          if (strlen(bufp) >= PATHLEN)
  99.              bufp[PATHLEN - 1] = '\0';
  100.          Strcpy(permbones, bufp);
  101.          if (!ramdisk_specified || !*levels)
  102.              Strcpy(levels, bufp);
  103.          ramdisk = (strcmp(permbones, levels) != 0);
  104.      } else if (match_varname(buf, "SAVE", 4)) {
  105.  #ifdef MFLOPPY
  106.          extern int saveprompt;
  107.  #endif
  108.          char *ptr;
  109.  
  110.          if ((ptr = index(bufp, ';')) != 0) {
  111.              *ptr = '\0';
  112.  #ifdef MFLOPPY
  113.              if (*(ptr + 1) == 'n' || *(ptr + 1) == 'N') {
  114.                  saveprompt = FALSE;
  115.              }
  116.  #endif
  117.          }
  118.  #if defined(SYSFLAGS) && defined(MFLOPPY)
  119.          else
  120.              saveprompt = sysflags.asksavedisk;
  121.  #endif
  122.  
  123.          (void) strncpy(SAVEP, bufp, SAVESIZE - 1);
  124.          append_slash(SAVEP);
  125.  #endif /* MICRO */
  126.  #endif /*NOCWD_ASSUMPTIONS*/
  127.  
  128.      } else if (match_varname(buf, "NAME", 4)) {
  129.          (void) strncpy(plname, bufp, PL_NSIZ - 1);
  130.          plnamesuffix();
  131.      } else if (match_varname(buf, "ROLE", 4)
  132.                 || match_varname(buf, "CHARACTER", 4)) {
  133.          if ((len = str2role(bufp)) >= 0)
  134.              flags.initrole = len;
  135.      } else if (match_varname(buf, "DOGNAME", 3)) {
  136.          (void) strncpy(dogname, bufp, PL_PSIZ - 1);
  137.      } else if (match_varname(buf, "CATNAME", 3)) {
  138.          (void) strncpy(catname, bufp, PL_PSIZ - 1);
  139.  
  140.  #ifdef SYSCF
  141.      } else if (src == SET_IN_SYS && match_varname(buf, "WIZARDS", 7)) {
  142.          if (sysopt.wizards)
  143.              free((genericptr_t) sysopt.wizards);
  144.          sysopt.wizards = dupstr(bufp);
  145.          if (strlen(sysopt.wizards) && strcmp(sysopt.wizards, "*")) {
  146.              /* pre-format WIZARDS list now; it's displayed during a panic
  147.                 and since that panic might be due to running out of memory,
  148.                 we don't want to risk attempting to allocate any memory then */
  149.              if (sysopt.fmtd_wizard_list)
  150.                  free((genericptr_t) sysopt.fmtd_wizard_list);
  151.              sysopt.fmtd_wizard_list = build_english_list(sysopt.wizards);
  152.          }
  153.      } else if (src == SET_IN_SYS && match_varname(buf, "SHELLERS", 8)) {
  154.          if (sysopt.shellers)
  155.              free((genericptr_t) sysopt.shellers);
  156.          sysopt.shellers = dupstr(bufp);
  157.      } else if (src == SET_IN_SYS && match_varname(buf, "EXPLORERS", 7)) {
  158.          if (sysopt.explorers)
  159.              free((genericptr_t) sysopt.explorers);
  160.          sysopt.explorers = dupstr(bufp);
  161.      } else if (src == SET_IN_SYS && match_varname(buf, "DEBUGFILES", 5)) {
  162.          /* if showdebug() has already been called (perhaps we've added
  163.             some debugpline() calls to option processing) and has found
  164.             a value for getenv("DEBUGFILES"), don't override that */
  165.          if (sysopt.env_dbgfl <= 0) {
  166.              if (sysopt.debugfiles)
  167.                  free((genericptr_t) sysopt.debugfiles);
  168.              sysopt.debugfiles = dupstr(bufp);
  169.          }
  170.      } else if (src == SET_IN_SYS && match_varname(buf, "SUPPORT", 7)) {
  171.          if (sysopt.support)
  172.              free((genericptr_t) sysopt.support);
  173.          sysopt.support = dupstr(bufp);
  174.      } else if (src == SET_IN_SYS && match_varname(buf, "RECOVER", 7)) {
  175.          if (sysopt.recover)
  176.              free((genericptr_t) sysopt.recover);
  177.          sysopt.recover = dupstr(bufp);
  178.      } else if (src == SET_IN_SYS
  179.                 && match_varname(buf, "CHECK_SAVE_UID", 14)) {
  180.          n = atoi(bufp);
  181.          sysopt.check_save_uid = n;
  182.      } else if (match_varname(buf, "SEDUCE", 6)) {
  183.          n = !!atoi(bufp); /* XXX this could be tighter */
  184.          /* allow anyone to turn it off, but only sysconf to turn it on*/
  185.          if (src != SET_IN_SYS && n != 0) {
  186.              raw_printf("Illegal value in SEDUCE");
  187.              return 0;
  188.          }
  189.          sysopt.seduce = n;
  190.          sysopt_seduce_set(sysopt.seduce);
  191.      } else if (src == SET_IN_SYS && match_varname(buf, "MAXPLAYERS", 10)) {
  192.          n = atoi(bufp);
  193.          /* XXX to get more than 25, need to rewrite all lock code */
  194.          if (n < 1 || n > 25) {
  195.              raw_printf("Illegal value in MAXPLAYERS (maximum is 25).");
  196.              return 0;
  197.          }
  198.          sysopt.maxplayers = n;
  199.      } else if (src == SET_IN_SYS && match_varname(buf, "PERSMAX", 7)) {
  200.          n = atoi(bufp);
  201.          if (n < 1) {
  202.              raw_printf("Illegal value in PERSMAX (minimum is 1).");
  203.              return 0;
  204.          }
  205.          sysopt.persmax = n;
  206.      } else if (src == SET_IN_SYS && match_varname(buf, "PERS_IS_UID", 11)) {
  207.          n = atoi(bufp);
  208.          if (n != 0 && n != 1) {
  209.              raw_printf("Illegal value in PERS_IS_UID (must be 0 or 1).");
  210.              return 0;
  211.          }
  212.          sysopt.pers_is_uid = n;
  213.      } else if (src == SET_IN_SYS && match_varname(buf, "ENTRYMAX", 8)) {
  214.          n = atoi(bufp);
  215.          if (n < 10) {
  216.              raw_printf("Illegal value in ENTRYMAX (minimum is 10).");
  217.              return 0;
  218.          }
  219.          sysopt.entrymax = n;
  220.      } else if ((src == SET_IN_SYS) && match_varname(buf, "POINTSMIN", 9)) {
  221.          n = atoi(bufp);
  222.          if (n < 1) {
  223.              raw_printf("Illegal value in POINTSMIN (minimum is 1).");
  224.              return 0;
  225.          }
  226.          sysopt.pointsmin = n;
  227.      } else if (src == SET_IN_SYS
  228.                 && match_varname(buf, "MAX_STATUENAME_RANK", 10)) {
  229.          n = atoi(bufp);
  230.          if (n < 1) {
  231.              raw_printf(
  232.                  "Illegal value in MAX_STATUENAME_RANK (minimum is 1).");
  233.              return 0;
  234.          }
  235.          sysopt.tt_oname_maxrank = n;
  236.  
  237.      /* SYSCF PANICTRACE options */
  238.      } else if (src == SET_IN_SYS
  239.                 && match_varname(buf, "PANICTRACE_LIBC", 15)) {
  240.          n = atoi(bufp);
  241.  #if defined(PANICTRACE) && defined(PANICTRACE_LIBC)
  242.          if (n < 0 || n > 2) {
  243.              raw_printf("Illegal value in PANICTRACE_LIBC (not 0,1,2).");
  244.              return 0;
  245.          }
  246.  #endif
  247.          sysopt.panictrace_libc = n;
  248.      } else if (src == SET_IN_SYS
  249.                 && match_varname(buf, "PANICTRACE_GDB", 14)) {
  250.          n = atoi(bufp);
  251.  #if defined(PANICTRACE)
  252.          if (n < 0 || n > 2) {
  253.              raw_printf("Illegal value in PANICTRACE_GDB (not 0,1,2).");
  254.              return 0;
  255.          }
  256.  #endif
  257.          sysopt.panictrace_gdb = n;
  258.      } else if (src == SET_IN_SYS && match_varname(buf, "GDBPATH", 7)) {
  259.  #if defined(PANICTRACE) && !defined(VMS)
  260.          if (!file_exists(bufp)) {
  261.              raw_printf("File specified in GDBPATH does not exist.");
  262.              return 0;
  263.          }
  264.  #endif
  265.          if (sysopt.gdbpath)
  266.              free((genericptr_t) sysopt.gdbpath);
  267.          sysopt.gdbpath = dupstr(bufp);
  268.      } else if (src == SET_IN_SYS && match_varname(buf, "GREPPATH", 7)) {
  269.  #if defined(PANICTRACE) && !defined(VMS)
  270.          if (!file_exists(bufp)) {
  271.              raw_printf("File specified in GREPPATH does not exist.");
  272.              return 0;
  273.          }
  274.  #endif
  275.          if (sysopt.greppath)
  276.              free((genericptr_t) sysopt.greppath);
  277.          sysopt.greppath = dupstr(bufp);
  278.  #endif /* SYSCF */
  279.  
  280.      } else if (match_varname(buf, "BOULDER", 3)) {
  281.          (void) get_uchars(fp, buf, bufp, &iflags.bouldersym, TRUE, 1,
  282.                            "BOULDER");
  283.      } else if (match_varname(buf, "MENUCOLOR", 9)) {
  284.          (void) add_menu_coloring(bufp);
  285.      } else if (match_varname(buf, "WARNINGS", 5)) {
  286.          (void) get_uchars(fp, buf, bufp, translate, FALSE, WARNCOUNT,
  287.                            "WARNINGS");
  288.          assign_warnings(translate);
  289.      } else if (match_varname(buf, "SYMBOLS", 4)) {
  290.          char *op, symbuf[BUFSZ];
  291.          boolean morelines;
  292.  
  293.          do {
  294.              /* check for line continuation (trailing '\') */
  295.              op = eos(bufp);
  296.              morelines = (--op >= bufp && *op == '\\');
  297.              if (morelines) {
  298.                  *op = '\0';
  299.                  /* strip trailing space now that '\' is gone */
  300.                  if (--op >= bufp && *op == ' ')
  301.                      *op = '\0';
  302.              }
  303.              /* parse here */
  304.              parsesymbols(bufp);
  305.              if (morelines) {
  306.                  do {
  307.                      *symbuf = '\0';
  308.                      if (!fgets(symbuf, BUFSZ, fp)) {
  309.                          morelines = FALSE;
  310.                          break;
  311.                      }
  312.                      mungspaces(symbuf);
  313.                      bufp = symbuf;
  314.                  } while (*bufp == '#');
  315.              }
  316.          } while (morelines);
  317.          switch_symbols(TRUE);
  318.      } else if (match_varname(buf, "WIZKIT", 6)) {
  319.          (void) strncpy(wizkit, bufp, WIZKIT_MAX - 1);
  320.  #ifdef AMIGA
  321.      } else if (match_varname(buf, "FONT", 4)) {
  322.          char *t;
  323.  
  324.          if (t = strchr(buf + 5, ':')) {
  325.              *t = 0;
  326.              amii_set_text_font(buf + 5, atoi(t + 1));
  327.              *t = ':';
  328.          }
  329.      } else if (match_varname(buf, "PATH", 4)) {
  330.          (void) strncpy(PATH, bufp, PATHLEN - 1);
  331.      } else if (match_varname(buf, "DEPTH", 5)) {
  332.          extern int amii_numcolors;
  333.          int val = atoi(bufp);
  334.  
  335.          amii_numcolors = 1L << min(DEPTH, val);
  336.  #ifdef SYSFLAGS
  337.      } else if (match_varname(buf, "DRIPENS", 7)) {
  338.          int i, val;
  339.          char *t;
  340.  
  341.          for (i = 0, t = strtok(bufp, ",/"); t != (char *) 0;
  342.               i < 20 && (t = strtok((char *) 0, ",/")), ++i) {
  343.              sscanf(t, "%d", &val);
  344.              sysflags.amii_dripens[i] = val;
  345.          }
  346.  #endif
  347.      } else if (match_varname(buf, "SCREENMODE", 10)) {
  348.          extern long amii_scrnmode;
  349.  
  350.          if (!stricmp(bufp, "req"))
  351.              amii_scrnmode = 0xffffffff; /* Requester */
  352.          else if (sscanf(bufp, "%x", &amii_scrnmode) != 1)
  353.              amii_scrnmode = 0;
  354.      } else if (match_varname(buf, "MSGPENS", 7)) {
  355.          extern int amii_msgAPen, amii_msgBPen;
  356.          char *t = strtok(bufp, ",/");
  357.  
  358.          if (t) {
  359.              sscanf(t, "%d", &amii_msgAPen);
  360.              if (t = strtok((char *) 0, ",/"))
  361.                  sscanf(t, "%d", &amii_msgBPen);
  362.          }
  363.      } else if (match_varname(buf, "TEXTPENS", 8)) {
  364.          extern int amii_textAPen, amii_textBPen;
  365.          char *t = strtok(bufp, ",/");
  366.  
  367.          if (t) {
  368.              sscanf(t, "%d", &amii_textAPen);
  369.              if (t = strtok((char *) 0, ",/"))
  370.                  sscanf(t, "%d", &amii_textBPen);
  371.          }
  372.      } else if (match_varname(buf, "MENUPENS", 8)) {
  373.          extern int amii_menuAPen, amii_menuBPen;
  374.          char *t = strtok(bufp, ",/");
  375.  
  376.          if (t) {
  377.              sscanf(t, "%d", &amii_menuAPen);
  378.              if (t = strtok((char *) 0, ",/"))
  379.                  sscanf(t, "%d", &amii_menuBPen);
  380.          }
  381.      } else if (match_varname(buf, "STATUSPENS", 10)) {
  382.          extern int amii_statAPen, amii_statBPen;
  383.          char *t = strtok(bufp, ",/");
  384.  
  385.          if (t) {
  386.              sscanf(t, "%d", &amii_statAPen);
  387.              if (t = strtok((char *) 0, ",/"))
  388.                  sscanf(t, "%d", &amii_statBPen);
  389.          }
  390.      } else if (match_varname(buf, "OTHERPENS", 9)) {
  391.          extern int amii_otherAPen, amii_otherBPen;
  392.          char *t = strtok(bufp, ",/");
  393.  
  394.          if (t) {
  395.              sscanf(t, "%d", &amii_otherAPen);
  396.              if (t = strtok((char *) 0, ",/"))
  397.                  sscanf(t, "%d", &amii_otherBPen);
  398.          }
  399.      } else if (match_varname(buf, "PENS", 4)) {
  400.          extern unsigned short amii_init_map[AMII_MAXCOLORS];
  401.          int i;
  402.          char *t;
  403.  
  404.          for (i = 0, t = strtok(bufp, ",/");
  405.               i < AMII_MAXCOLORS && t != (char *) 0;
  406.               t = strtok((char *) 0, ",/"), ++i) {
  407.              sscanf(t, "%hx", &amii_init_map[i]);
  408.          }
  409.          amii_setpens(amii_numcolors = i);
  410.      } else if (match_varname(buf, "FGPENS", 6)) {
  411.          extern int foreg[AMII_MAXCOLORS];
  412.          int i;
  413.          char *t;
  414.  
  415.          for (i = 0, t = strtok(bufp, ",/");
  416.               i < AMII_MAXCOLORS && t != (char *) 0;
  417.               t = strtok((char *) 0, ",/"), ++i) {
  418.              sscanf(t, "%d", &foreg[i]);
  419.          }
  420.      } else if (match_varname(buf, "BGPENS", 6)) {
  421.          extern int backg[AMII_MAXCOLORS];
  422.          int i;
  423.          char *t;
  424.  
  425.          for (i = 0, t = strtok(bufp, ",/");
  426.               i < AMII_MAXCOLORS && t != (char *) 0;
  427.               t = strtok((char *) 0, ",/"), ++i) {
  428.              sscanf(t, "%d", &backg[i]);
  429.          }
  430.  #endif /*AMIGA*/
  431.  #ifdef USER_SOUNDS
  432.      } else if (match_varname(buf, "SOUNDDIR", 8)) {
  433.          sounddir = dupstr(bufp);
  434.      } else if (match_varname(buf, "SOUND", 5)) {
  435.          add_sound_mapping(bufp);
  436.  #endif
  437.  #ifdef QT_GRAPHICS
  438.          /* These should move to wc_ options */
  439.      } else if (match_varname(buf, "QT_TILEWIDTH", 12)) {
  440.          extern char *qt_tilewidth;
  441.  
  442.          if (qt_tilewidth == NULL)
  443.              qt_tilewidth = dupstr(bufp);
  444.      } else if (match_varname(buf, "QT_TILEHEIGHT", 13)) {
  445.          extern char *qt_tileheight;
  446.  
  447.          if (qt_tileheight == NULL)
  448.              qt_tileheight = dupstr(bufp);
  449.      } else if (match_varname(buf, "QT_FONTSIZE", 11)) {
  450.          extern char *qt_fontsize;
  451.  
  452.          if (qt_fontsize == NULL)
  453.              qt_fontsize = dupstr(bufp);
  454.      } else if (match_varname(buf, "QT_COMPACT", 10)) {
  455.          extern int qt_compact_mode;
  456.  
  457.          qt_compact_mode = atoi(bufp);
  458.  #endif
  459.      } else
  460.          return 0;
  461.      return 1;
  462.  }
  463.  

can_read_file

  1.  #ifdef USER_SOUNDS
  2.  boolean
  3.  can_read_file(filename)
  4.  const char *filename;
  5.  {
  6.      return (boolean) (access(filename, 4) == 0);
  7.  }
  8.  #endif /* USER_SOUNDS */
  9.  

read_config_file

  1.  boolean
  2.  read_config_file(filename, src)
  3.  const char *filename;
  4.  int src;
  5.  {
  6.      char buf[4 * BUFSZ], *p;
  7.      FILE *fp;
  8.      boolean rv = TRUE; /* assume successful parse */
  9.  
  10.      if (!(fp = fopen_config_file(filename, src)))
  11.          return FALSE;
  12.  
  13.      /* begin detection of duplicate configfile options */
  14.      set_duplicate_opt_detection(1);
  15.  
  16.      while (fgets(buf, sizeof buf, fp)) {
  17.  #ifdef notyet
  18.  /*
  19.  XXX Don't call read() in parse_config_line, read as callback or reassemble
  20.  line at this level.
  21.  OR: Forbid multiline stuff for alternate config sources.
  22.  */
  23.  #endif
  24.          if ((p = index(buf, '\n')) != 0)
  25.              *p = '\0';
  26.          if (!parse_config_line(fp, buf, src)) {
  27.              static const char badoptionline[] = "Bad option line: \"%s\"";
  28.  
  29.              /* truncate buffer if it's long; this is actually conservative */
  30.              if (strlen(buf) > BUFSZ - sizeof badoptionline)
  31.                  buf[BUFSZ - sizeof badoptionline] = '\0';
  32.  
  33.              raw_printf(badoptionline, buf);
  34.              wait_synch();
  35.              rv = FALSE;
  36.          }
  37.      }
  38.      (void) fclose(fp);
  39.  
  40.      /* turn off detection of duplicate configfile options */
  41.      set_duplicate_opt_detection(0);
  42.      return rv;
  43.  }
  44.  

fopen_wizkit_file

  1.  STATIC_OVL FILE *
  2.  fopen_wizkit_file()
  3.  {
  4.      FILE *fp;
  5.  #if defined(VMS) || defined(UNIX)
  6.      char tmp_wizkit[BUFSZ];
  7.  #endif
  8.      char *envp;
  9.  
  10.      envp = nh_getenv("WIZKIT");
  11.      if (envp && *envp)
  12.          (void) strncpy(wizkit, envp, WIZKIT_MAX - 1);
  13.      if (!wizkit[0])
  14.          return (FILE *) 0;
  15.  
  16.  #ifdef UNIX
  17.      if (access(wizkit, 4) == -1) {
  18.          /* 4 is R_OK on newer systems */
  19.          /* nasty sneaky attempt to read file through
  20.           * NetHack's setuid permissions -- this is a
  21.           * place a file name may be wholly under the player's
  22.           * control
  23.           */
  24.          raw_printf("Access to %s denied (%d).", wizkit, errno);
  25.          wait_synch();
  26.          /* fall through to standard names */
  27.      } else
  28.  #endif
  29.          if ((fp = fopenp(wizkit, "r")) != (FILE *) 0) {
  30.          return fp;
  31.  #if defined(UNIX) || defined(VMS)
  32.      } else {
  33.          /* access() above probably caught most problems for UNIX */
  34.          raw_printf("Couldn't open requested config file %s (%d).", wizkit,
  35.                     errno);
  36.          wait_synch();
  37.  #endif
  38.      }
  39.  
  40.  #if defined(MICRO) || defined(MAC) || defined(__BEOS__) || defined(WIN32)
  41.      if ((fp = fopenp(fqname(wizkit, CONFIGPREFIX, 0), "r")) != (FILE *) 0)
  42.          return fp;
  43.  #else
  44.  #ifdef VMS
  45.      envp = nh_getenv("HOME");
  46.      if (envp)
  47.          Sprintf(tmp_wizkit, "%s%s", envp, wizkit);
  48.      else
  49.          Sprintf(tmp_wizkit, "%s%s", "sys$login:", wizkit);
  50.      if ((fp = fopenp(tmp_wizkit, "r")) != (FILE *) 0)
  51.          return fp;
  52.  #else /* should be only UNIX left */
  53.      envp = nh_getenv("HOME");
  54.      if (envp)
  55.          Sprintf(tmp_wizkit, "%s/%s", envp, wizkit);
  56.      else
  57.          Strcpy(tmp_wizkit, wizkit);
  58.      if ((fp = fopenp(tmp_wizkit, "r")) != (FILE *) 0)
  59.          return fp;
  60.      else if (errno != ENOENT) {
  61.          /* e.g., problems when setuid NetHack can't search home
  62.           * directory restricted to user */
  63.          raw_printf("Couldn't open default wizkit file %s (%d).", tmp_wizkit,
  64.                     errno);
  65.          wait_synch();
  66.      }
  67.  #endif
  68.  #endif
  69.      return (FILE *) 0;
  70.  }
  71.  

wizkit_addinv

  1.  /* add to hero's inventory if there's room, otherwise put item on floor */
  2.  STATIC_DCL void
  3.  wizkit_addinv(obj)
  4.  struct obj *obj;
  5.  {
  6.      if (!obj || obj == &zeroobj)
  7.          return;
  8.  
  9.      /* subset of starting inventory pre-ID */
  10.      obj->dknown = 1;
  11.      if (Role_if(PM_PRIEST))
  12.          obj->bknown = 1;
  13.      /* same criteria as lift_object()'s check for available inventory slot */
  14.      if (obj->oclass != COIN_CLASS && inv_cnt(FALSE) >= 52
  15.          && !merge_choice(invent, obj)) {
  16.          /* inventory overflow; can't just place & stack object since
  17.             hero isn't in position yet, so schedule for arrival later */
  18.          add_to_migration(obj);
  19.          obj->ox = 0; /* index of main dungeon */
  20.          obj->oy = 1; /* starting level number */
  21.          obj->owornmask =
  22.              (long) (MIGR_WITH_HERO | MIGR_NOBREAK | MIGR_NOSCATTER);
  23.      } else {
  24.          (void) addinv(obj);
  25.      }
  26.  }
  27.  

read_wizkit

  1.  void
  2.  read_wizkit()
  3.  {
  4.      FILE *fp;
  5.      char *ep, buf[BUFSZ];
  6.      struct obj *otmp;
  7.      boolean bad_items = FALSE, skip = FALSE;
  8.  
  9.      if (!wizard || !(fp = fopen_wizkit_file()))
  10.          return;
  11.  
  12.      program_state.wizkit_wishing = 1;
  13.      while (fgets(buf, (int) (sizeof buf), fp)) {
  14.          ep = index(buf, '\n');
  15.          if (skip) { /* in case previous line was too long */
  16.              if (ep)
  17.                  skip = FALSE; /* found newline; next line is normal */
  18.          } else {
  19.              if (!ep)
  20.                  skip = TRUE; /* newline missing; discard next fgets */
  21.              else
  22.                  *ep = '\0'; /* remove newline */
  23.  
  24.              if (buf[0]) {
  25.                  otmp = readobjnam(buf, (struct obj *) 0);
  26.                  if (otmp) {
  27.                      if (otmp != &zeroobj)
  28.                          wizkit_addinv(otmp);
  29.                  } else {
  30.                      /* .60 limits output line width to 79 chars */
  31.                      raw_printf("Bad wizkit item: \"%.60s\"", buf);
  32.                      bad_items = TRUE;
  33.                  }
  34.              }
  35.          }
  36.      }
  37.      program_state.wizkit_wishing = 0;
  38.      if (bad_items)
  39.          wait_synch();
  40.      (void) fclose(fp);
  41.      return;
  42.  }
  43.  

fopen_sym_file

  1.  extern struct symsetentry *symset_list;  /* options.c */
  2.  extern struct symparse loadsyms[];       /* drawing.c */
  3.  extern const char *known_handling[];     /* drawing.c */
  4.  extern const char *known_restrictions[]; /* drawing.c */
  5.  static int symset_count = 0;             /* for pick-list building only */
  6.  static boolean chosen_symset_start = FALSE, chosen_symset_end = FALSE;
  7.  
  8.  STATIC_OVL
  9.  FILE *
  10.  fopen_sym_file()
  11.  {
  12.      FILE *fp;
  13.  
  14.      fp = fopen_datafile(SYMBOLS, "r", HACKPREFIX);
  15.      return fp;
  16.  }
  17.  

read_sym_file

  1.  /*
  2.   * Returns 1 if the chose symset was found and loaded.
  3.   *         0 if it wasn't found in the sym file or other problem.
  4.   */
  5.  int
  6.  read_sym_file(which_set)
  7.  int which_set;
  8.  {
  9.      char buf[4 * BUFSZ];
  10.      FILE *fp;
  11.  
  12.      if (!(fp = fopen_sym_file()))
  13.          return 0;
  14.  
  15.      symset_count = 0;
  16.      chosen_symset_start = chosen_symset_end = FALSE;
  17.      while (fgets(buf, 4 * BUFSZ, fp)) {
  18.          if (!parse_sym_line(buf, which_set)) {
  19.              raw_printf("Bad symbol line:  \"%.50s\"", buf);
  20.              wait_synch();
  21.          }
  22.      }
  23.      (void) fclose(fp);
  24.      if (!chosen_symset_end && !chosen_symset_start)
  25.          return (symset[which_set].name == 0) ? 1 : 0;
  26.      if (!chosen_symset_end) {
  27.          raw_printf("Missing finish for symset \"%s\"",
  28.                     symset[which_set].name ? symset[which_set].name
  29.                                            : "unknown");
  30.          wait_synch();
  31.      }
  32.      return 1;
  33.  }
  34.  

parse_sym_line

  1.  /* returns 0 on error */
  2.  int
  3.  parse_sym_line(buf, which_set)
  4.  char *buf;
  5.  int which_set;
  6.  {
  7.      int val, i;
  8.      struct symparse *symp = (struct symparse *) 0;
  9.      char *bufp, *commentp, *altp;
  10.  
  11.      /* convert each instance of whitespace (tabs, consecutive spaces)
  12.         into a single space; leading and trailing spaces are stripped */
  13.      mungspaces(buf);
  14.      if (!*buf || *buf == '#' || !strcmp(buf, " "))
  15.          return 1;
  16.      /* remove trailing comment, if any */
  17.      if ((commentp = rindex(buf, '#')) != 0) {
  18.          *commentp = '\0';
  19.          /* remove space preceding the stripped comment, if any;
  20.             we know 'commentp > buf' because *buf=='#' was caught above */
  21.          if (commentp[-1] == ' ')
  22.              *--commentp = '\0';
  23.      }
  24.  
  25.      /* find the '=' or ':' */
  26.      bufp = index(buf, '=');
  27.      altp = index(buf, ':');
  28.      if (!bufp || (altp && altp < bufp))
  29.          bufp = altp;
  30.      if (!bufp) {
  31.          if (strncmpi(buf, "finish", 6) == 0) {
  32.              /* end current graphics set */
  33.              if (chosen_symset_start)
  34.                  chosen_symset_end = TRUE;
  35.              chosen_symset_start = FALSE;
  36.              return 1;
  37.          }
  38.          return 0;
  39.      }
  40.      /* skip '=' and space which follows, if any */
  41.      ++bufp;
  42.      if (*bufp == ' ')
  43.          ++bufp;
  44.  
  45.      symp = match_sym(buf);
  46.      if (!symp)
  47.          return 0;
  48.  
  49.      if (!symset[which_set].name) {
  50.          /* A null symset name indicates that we're just
  51.             building a pick-list of possible symset
  52.             values from the file, so only do that */
  53.          if (symp->range == SYM_CONTROL) {
  54.              struct symsetentry *tmpsp;
  55.  
  56.              switch (symp->idx) {
  57.              case 0:
  58.                  tmpsp =
  59.                      (struct symsetentry *) alloc(sizeof (struct symsetentry));
  60.                  tmpsp->next = (struct symsetentry *) 0;
  61.                  if (!symset_list) {
  62.                      symset_list = tmpsp;
  63.                      symset_count = 0;
  64.                  } else {
  65.                      symset_count++;
  66.                      tmpsp->next = symset_list;
  67.                      symset_list = tmpsp;
  68.                  }
  69.                  tmpsp->idx = symset_count;
  70.                  tmpsp->name = dupstr(bufp);
  71.                  tmpsp->desc = (char *) 0;
  72.                  tmpsp->nocolor = 0;
  73.                  /* initialize restriction bits */
  74.                  tmpsp->primary = 0;
  75.                  tmpsp->rogue = 0;
  76.                  break;
  77.              case 2:
  78.                  /* handler type identified */
  79.                  tmpsp = symset_list; /* most recent symset */
  80.                  tmpsp->handling = H_UNK;
  81.                  i = 0;
  82.                  while (known_handling[i]) {
  83.                      if (!strcmpi(known_handling[i], bufp)) {
  84.                          tmpsp->handling = i;
  85.                          break; /* while loop */
  86.                      }
  87.                      i++;
  88.                  }
  89.                  break;
  90.              case 3:                  /* description:something */
  91.                  tmpsp = symset_list; /* most recent symset */
  92.                  if (tmpsp && !tmpsp->desc)
  93.                      tmpsp->desc = dupstr(bufp);
  94.                  break;
  95.              case 5:
  96.                  /* restrictions: xxxx*/
  97.                  tmpsp = symset_list; /* most recent symset */
  98.                  for (i = 0; known_restrictions[i]; ++i) {
  99.                      if (!strcmpi(known_restrictions[i], bufp)) {
  100.                          switch (i) {
  101.                          case 0:
  102.                              tmpsp->primary = 1;
  103.                              break;
  104.                          case 1:
  105.                              tmpsp->rogue = 1;
  106.                              break;
  107.                          }
  108.                          break; /* while loop */
  109.                      }
  110.                  }
  111.                  break;
  112.              }
  113.          }
  114.          return 1;
  115.      }
  116.      if (symp->range) {
  117.          if (symp->range == SYM_CONTROL) {
  118.              switch (symp->idx) {
  119.              case 0:
  120.                  /* start of symset */
  121.                  if (!strcmpi(bufp, symset[which_set].name)) {
  122.                      /* matches desired one */
  123.                      chosen_symset_start = TRUE;
  124.                      /* these init_*() functions clear symset fields too */
  125.                      if (which_set == ROGUESET)
  126.                          init_r_symbols();
  127.                      else if (which_set == PRIMARY)
  128.                          init_l_symbols();
  129.                  }
  130.                  break;
  131.              case 1:
  132.                  /* finish symset */
  133.                  if (chosen_symset_start)
  134.                      chosen_symset_end = TRUE;
  135.                  chosen_symset_start = FALSE;
  136.                  break;
  137.              case 2:
  138.                  /* handler type identified */
  139.                  if (chosen_symset_start)
  140.                      set_symhandling(bufp, which_set);
  141.                  break;
  142.              /* case 3: (description) is ignored here */
  143.              case 4: /* color:off */
  144.                  if (chosen_symset_start) {
  145.                      if (bufp) {
  146.                          if (!strcmpi(bufp, "true") || !strcmpi(bufp, "yes")
  147.                              || !strcmpi(bufp, "on"))
  148.                              symset[which_set].nocolor = 0;
  149.                          else if (!strcmpi(bufp, "false")
  150.                                   || !strcmpi(bufp, "no")
  151.                                   || !strcmpi(bufp, "off"))
  152.                              symset[which_set].nocolor = 1;
  153.                      }
  154.                  }
  155.                  break;
  156.              case 5: /* restrictions: xxxx*/
  157.                  if (chosen_symset_start) {
  158.                      int n = 0;
  159.  
  160.                      while (known_restrictions[n]) {
  161.                          if (!strcmpi(known_restrictions[n], bufp)) {
  162.                              switch (n) {
  163.                              case 0:
  164.                                  symset[which_set].primary = 1;
  165.                                  break;
  166.                              case 1:
  167.                                  symset[which_set].rogue = 1;
  168.                                  break;
  169.                              }
  170.                              break; /* while loop */
  171.                          }
  172.                          n++;
  173.                      }
  174.                  }
  175.                  break;
  176.              }
  177.          } else { /* !SYM_CONTROL */
  178.              val = sym_val(bufp);
  179.              if (chosen_symset_start) {
  180.                  if (which_set == PRIMARY) {
  181.                      update_l_symset(symp, val);
  182.                  } else if (which_set == ROGUESET) {
  183.                      update_r_symset(symp, val);
  184.                  }
  185.              }
  186.          }
  187.      }
  188.      return 1;
  189.  }
  190.  

set_symhandling

  1.  STATIC_OVL void
  2.  set_symhandling(handling, which_set)
  3.  char *handling;
  4.  int which_set;
  5.  {
  6.      int i = 0;
  7.  
  8.      symset[which_set].handling = H_UNK;
  9.      while (known_handling[i]) {
  10.          if (!strcmpi(known_handling[i], handling)) {
  11.              symset[which_set].handling = i;
  12.              return;
  13.          }
  14.          i++;
  15.      }
  16.  }
  17.  
  18.  /* ----------  END CONFIG FILE HANDLING ----------- */
  19.  

Scoreboard creation

  1.  /* ----------  BEGIN SCOREBOARD CREATION ----------- */
  2.  
  3.  #ifdef OS2_CODEVIEW
  4.  #define UNUSED_if_not_OS2_CODEVIEW /*empty*/
  5.  #else
  6.  #define UNUSED_if_not_OS2_CODEVIEW UNUSED
  7.  #endif
  8.  

check_recordfile

  1.  /* verify that we can write to scoreboard file; if not, try to create one */
  2.  /*ARGUSED*/
  3.  void
  4.  check_recordfile(dir)
  5.  const char *dir UNUSED_if_not_OS2_CODEVIEW;
  6.  {
  7.  #if defined(PRAGMA_UNUSED) && !defined(OS2_CODEVIEW)
  8.  #pragma unused(dir)
  9.  #endif
  10.      const char *fq_record;
  11.      int fd;
  12.  
  13.  #if defined(UNIX) || defined(VMS)
  14.      fq_record = fqname(RECORD, SCOREPREFIX, 0);
  15.      fd = open(fq_record, O_RDWR, 0);
  16.      if (fd >= 0) {
  17.  #ifdef VMS /* must be stream-lf to use UPDATE_RECORD_IN_PLACE */
  18.          if (!file_is_stmlf(fd)) {
  19.              raw_printf(
  20.                  "Warning: scoreboard file %s is not in stream_lf format",
  21.                  fq_record);
  22.              wait_synch();
  23.          }
  24.  #endif
  25.          (void) nhclose(fd); /* RECORD is accessible */
  26.      } else if ((fd = open(fq_record, O_CREAT | O_RDWR, FCMASK)) >= 0) {
  27.          (void) nhclose(fd); /* RECORD newly created */
  28.  #if defined(VMS) && !defined(SECURE)
  29.          /* Re-protect RECORD with world:read+write+execute+delete access. */
  30.          (void) chmod(fq_record, FCMASK | 007);
  31.  #endif /* VMS && !SECURE */
  32.      } else {
  33.          raw_printf("Warning: cannot write scoreboard file %s", fq_record);
  34.          wait_synch();
  35.      }
  36.  #endif /* !UNIX && !VMS */
  37.  #if defined(MICRO) || defined(WIN32)
  38.      char tmp[PATHLEN];
  39.  
  40.  #ifdef OS2_CODEVIEW /* explicit path on opening for OS/2 */
  41.      /* how does this work when there isn't an explicit path or fopenp
  42.       * for later access to the file via fopen_datafile? ? */
  43.      (void) strncpy(tmp, dir, PATHLEN - 1);
  44.      tmp[PATHLEN - 1] = '\0';
  45.      if ((strlen(tmp) + 1 + strlen(RECORD)) < (PATHLEN - 1)) {
  46.          append_slash(tmp);
  47.          Strcat(tmp, RECORD);
  48.      }
  49.      fq_record = tmp;
  50.  #else
  51.      Strcpy(tmp, RECORD);
  52.      fq_record = fqname(RECORD, SCOREPREFIX, 0);
  53.  #endif
  54.  
  55.      if ((fd = open(fq_record, O_RDWR)) < 0) {
  56.  /* try to create empty record */
  57.  #if defined(AZTEC_C) || defined(_DCC) \
  58.      || (defined(__GNUC__) && defined(__AMIGA__))
  59.          /* Aztec doesn't use the third argument */
  60.          /* DICE doesn't like it */
  61.          if ((fd = open(fq_record, O_CREAT | O_RDWR)) < 0) {
  62.  #else
  63.          if ((fd = open(fq_record, O_CREAT | O_RDWR, S_IREAD | S_IWRITE))
  64.              < 0) {
  65.  #endif
  66.              raw_printf("Warning: cannot write record %s", tmp);
  67.              wait_synch();
  68.          } else
  69.              (void) nhclose(fd);
  70.      } else /* open succeeded */
  71.          (void) nhclose(fd);
  72.  #else /* MICRO || WIN32*/
  73.  
  74.  #ifdef MAC
  75.      /* Create the "record" file, if necessary */
  76.      fq_record = fqname(RECORD, SCOREPREFIX, 0);
  77.      fd = macopen(fq_record, O_RDWR | O_CREAT, TEXT_TYPE);
  78.      if (fd != -1)
  79.          macclose(fd);
  80.  #endif /* MAC */
  81.  
  82.  #endif /* MICRO || WIN32*/
  83.  }
  84.  
  85.  /* ----------  END SCOREBOARD CREATION ----------- */
  86.  

Panic/Impossible log

  1.  /* ----------  BEGIN PANIC/IMPOSSIBLE LOG ----------- */
  2.  

paniclog

  1.  /*ARGSUSED*/
  2.  void
  3.  paniclog(type, reason)
  4.  const char *type;   /* panic, impossible, trickery */
  5.  const char *reason; /* explanation */
  6.  {
  7.  #ifdef PANICLOG
  8.      FILE *lfile;
  9.      char buf[BUFSZ];
  10.  
  11.      if (!program_state.in_paniclog) {
  12.          program_state.in_paniclog = 1;
  13.          lfile = fopen_datafile(PANICLOG, "a", TROUBLEPREFIX);
  14.          if (lfile) {
  15.              time_t now = getnow();
  16.              int uid = getuid();
  17.              char playmode = wizard ? 'D' : discover ? 'X' : '-';
  18.  
  19.              (void) fprintf(lfile, "%s %08ld %06ld %d %c: %s %s\n",
  20.                             version_string(buf), yyyymmdd(now), hhmmss(now),
  21.                             uid, playmode, type, reason);
  22.              (void) fclose(lfile);
  23.          }
  24.          program_state.in_paniclog = 0;
  25.      }
  26.  #endif /* PANICLOG */
  27.      return;
  28.  }
  29.  
  30.  /* ----------  END PANIC/IMPOSSIBLE LOG ----------- */
  31.  

Internal recover

  1.  #ifdef SELF_RECOVER
  2.  
  3.  /* ----------  BEGIN INTERNAL RECOVER ----------- */

recover_savefile

  1.  boolean
  2.  recover_savefile()
  3.  {
  4.      int gfd, lfd, sfd;
  5.      int lev, savelev, hpid, pltmpsiz;
  6.      xchar levc;
  7.      struct version_info version_data;
  8.      int processed[256];
  9.      char savename[SAVESIZE], errbuf[BUFSZ];
  10.      struct savefile_info sfi;
  11.      char tmpplbuf[PL_NSIZ];
  12.  
  13.      for (lev = 0; lev < 256; lev++)
  14.          processed[lev] = 0;
  15.  
  16.      /* level 0 file contains:
  17.       *  pid of creating process (ignored here)
  18.       *  level number for current level of save file
  19.       *  name of save file nethack would have created
  20.       *  savefile info
  21.       *  player name
  22.       *  and game state
  23.       */
  24.      gfd = open_levelfile(0, errbuf);
  25.      if (gfd < 0) {
  26.          raw_printf("%s\n", errbuf);
  27.          return FALSE;
  28.      }
  29.      if (read(gfd, (genericptr_t) &hpid, sizeof hpid) != sizeof hpid) {
  30.          raw_printf("\n%s\n%s\n",
  31.              "Checkpoint data incompletely written or subsequently clobbered.",
  32.                     "Recovery impossible.");
  33.          (void) nhclose(gfd);
  34.          return FALSE;
  35.      }
  36.      if (read(gfd, (genericptr_t) &savelev, sizeof(savelev))
  37.          != sizeof(savelev)) {
  38.          raw_printf(
  39.           "\nCheckpointing was not in effect for %s -- recovery impossible.\n",
  40.                     lock);
  41.          (void) nhclose(gfd);
  42.          return FALSE;
  43.      }
  44.      if ((read(gfd, (genericptr_t) savename, sizeof savename)
  45.           != sizeof savename)
  46.          || (read(gfd, (genericptr_t) &version_data, sizeof version_data)
  47.              != sizeof version_data)
  48.          || (read(gfd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi)
  49.          || (read(gfd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz)
  50.              != sizeof pltmpsiz) || (pltmpsiz > PL_NSIZ)
  51.          || (read(gfd, (genericptr_t) &tmpplbuf, pltmpsiz) != pltmpsiz)) {
  52.          raw_printf("\nError reading %s -- can't recover.\n", lock);
  53.          (void) nhclose(gfd);
  54.          return FALSE;
  55.      }
  56.  
  57.      /* save file should contain:
  58.       *  version info
  59.       *  savefile info
  60.       *  player name
  61.       *  current level (including pets)
  62.       *  (non-level-based) game state
  63.       *  other levels
  64.       */
  65.      set_savefile_name(TRUE);
  66.      sfd = create_savefile();
  67.      if (sfd < 0) {
  68.          raw_printf("\nCannot recover savefile %s.\n", SAVEF);
  69.          (void) nhclose(gfd);
  70.          return FALSE;
  71.      }
  72.  
  73.      lfd = open_levelfile(savelev, errbuf);
  74.      if (lfd < 0) {
  75.          raw_printf("\n%s\n", errbuf);
  76.          (void) nhclose(gfd);
  77.          (void) nhclose(sfd);
  78.          delete_savefile();
  79.          return FALSE;
  80.      }
  81.  
  82.      if (write(sfd, (genericptr_t) &version_data, sizeof version_data)
  83.          != sizeof version_data) {
  84.          raw_printf("\nError writing %s; recovery failed.", SAVEF);
  85.          (void) nhclose(gfd);
  86.          (void) nhclose(sfd);
  87.          delete_savefile();
  88.          return FALSE;
  89.      }
  90.  
  91.      if (write(sfd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi) {
  92.          raw_printf("\nError writing %s; recovery failed (savefile_info).\n",
  93.                     SAVEF);
  94.          (void) nhclose(gfd);
  95.          (void) nhclose(sfd);
  96.          delete_savefile();
  97.          return FALSE;
  98.      }
  99.  
  100.      if (write(sfd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz)
  101.          != sizeof pltmpsiz) {
  102.          raw_printf("Error writing %s; recovery failed (player name size).\n",
  103.                     SAVEF);
  104.          (void) nhclose(gfd);
  105.          (void) nhclose(sfd);
  106.          delete_savefile();
  107.          return FALSE;
  108.      }
  109.  
  110.      if (write(sfd, (genericptr_t) &tmpplbuf, pltmpsiz) != pltmpsiz) {
  111.          raw_printf("Error writing %s; recovery failed (player name).\n",
  112.                     SAVEF);
  113.          (void) nhclose(gfd);
  114.          (void) nhclose(sfd);
  115.          delete_savefile();
  116.          return FALSE;
  117.      }
  118.  
  119.      if (!copy_bytes(lfd, sfd)) {
  120.          (void) nhclose(lfd);
  121.          (void) nhclose(sfd);
  122.          delete_savefile();
  123.          return FALSE;
  124.      }
  125.      (void) nhclose(lfd);
  126.      processed[savelev] = 1;
  127.  
  128.      if (!copy_bytes(gfd, sfd)) {
  129.          (void) nhclose(lfd);
  130.          (void) nhclose(sfd);
  131.          delete_savefile();
  132.          return FALSE;
  133.      }
  134.      (void) nhclose(gfd);
  135.      processed[0] = 1;
  136.  
  137.      for (lev = 1; lev < 256; lev++) {
  138.          /* level numbers are kept in xchars in save.c, so the
  139.           * maximum level number (for the endlevel) must be < 256
  140.           */
  141.          if (lev != savelev) {
  142.              lfd = open_levelfile(lev, (char *) 0);
  143.              if (lfd >= 0) {
  144.                  /* any or all of these may not exist */
  145.                  levc = (xchar) lev;
  146.                  write(sfd, (genericptr_t) &levc, sizeof(levc));
  147.                  if (!copy_bytes(lfd, sfd)) {
  148.                      (void) nhclose(lfd);
  149.                      (void) nhclose(sfd);
  150.                      delete_savefile();
  151.                      return FALSE;
  152.                  }
  153.                  (void) nhclose(lfd);
  154.                  processed[lev] = 1;
  155.              }
  156.          }
  157.      }
  158.      (void) nhclose(sfd);
  159.  
  160.  #ifdef HOLD_LOCKFILE_OPEN
  161.      really_close();
  162.  #endif
  163.      /*
  164.       * We have a successful savefile!
  165.       * Only now do we erase the level files.
  166.       */
  167.      for (lev = 0; lev < 256; lev++) {
  168.          if (processed[lev]) {
  169.              const char *fq_lock;
  170.              set_levelfile_name(lock, lev);
  171.              fq_lock = fqname(lock, LEVELPREFIX, 3);
  172.              (void) unlink(fq_lock);
  173.          }
  174.      }
  175.      return TRUE;
  176.  }
  177.  

copy_bytes

  1.  boolean
  2.  copy_bytes(ifd, ofd)
  3.  int ifd, ofd;
  4.  {
  5.      char buf[BUFSIZ];
  6.      int nfrom, nto;
  7.  
  8.      do {
  9.          nfrom = read(ifd, buf, BUFSIZ);
  10.          nto = write(ofd, buf, nfrom);
  11.          if (nto != nfrom)
  12.              return FALSE;
  13.      } while (nfrom == BUFSIZ);
  14.      return TRUE;
  15.  }
  16.  
  17.  /* ----------  END INTERNAL RECOVER ----------- */
  18.  #endif /*SELF_RECOVER*/
  19.  

Other

  1.  /* ----------  OTHER ----------- */
  2.  

assure_syscf_file

  1.  #ifdef SYSCF
  2.  #ifdef SYSCF_FILE
  3.  void
  4.  assure_syscf_file()
  5.  {
  6.      int fd;
  7.  
  8.      /*
  9.       * All we really care about is the end result - can we read the file?
  10.       * So just check that directly.
  11.       *
  12.       * Not tested on most of the old platforms (which don't attempt
  13.       * to implement SYSCF).
  14.       * Some ports don't like open()'s optional third argument;
  15.       * VMS overrides open() usage with a macro which requires it.
  16.       */
  17.  #ifndef VMS
  18.      fd = open(SYSCF_FILE, O_RDONLY);
  19.  #else
  20.      fd = open(SYSCF_FILE, O_RDONLY, 0);
  21.  #endif
  22.      if (fd >= 0) {
  23.          /* readable */
  24.          close(fd);
  25.          return;
  26.      }
  27.      raw_printf("Unable to open SYSCF_FILE.\n");
  28.      exit(EXIT_FAILURE);
  29.  }
  30.  
  31.  #endif /* SYSCF_FILE */
  32.  #endif /* SYSCF */
  33.  

debugcore

  1.  #ifdef DEBUG
  2.  /* used by debugpline() to decide whether to issue a message
  3.   * from a particular source file; caller passes __FILE__ and we check
  4.   * whether it is in the source file list supplied by SYSCF's DEBUGFILES
  5.   *
  6.   * pass FALSE to override wildcard matching; useful for files
  7.   * like dungeon.c and questpgr.c, which generate a ridiculous amount of
  8.   * output if DEBUG is defined and effectively block the use of a wildcard */
  9.  boolean
  10.  debugcore(filename, wildcards)
  11.  const char *filename;
  12.  boolean wildcards;
  13.  {
  14.      const char *debugfiles, *p;
  15.  
  16.      if (!filename || !*filename)
  17.          return FALSE; /* sanity precaution */
  18.  
  19.      if (sysopt.env_dbgfl == 0) {
  20.          /* check once for DEBUGFILES in the environment;
  21.             if found, it supersedes the sysconf value
  22.             [note: getenv() rather than nh_getenv() since a long value
  23.             is valid and doesn't pose any sort of overflow risk here] */
  24.          if ((p = getenv("DEBUGFILES")) != 0) {
  25.              if (sysopt.debugfiles)
  26.                  free((genericptr_t) sysopt.debugfiles);
  27.              sysopt.debugfiles = dupstr(p);
  28.              sysopt.env_dbgfl = 1;
  29.          } else
  30.              sysopt.env_dbgfl = -1;
  31.      }
  32.  
  33.      debugfiles = sysopt.debugfiles;
  34.      /* usual case: sysopt.debugfiles will be empty */
  35.      if (!debugfiles || !*debugfiles)
  36.          return FALSE;
  37.  
  38.  /* strip filename's path if present */
  39.  #ifdef UNIX
  40.      if ((p = rindex(filename, '/')) != 0)
  41.          filename = p + 1;
  42.  #endif
  43.  #ifdef VMS
  44.      filename = vms_basename(filename);
  45.      /* vms_basename strips off 'type' suffix as well as path and version;
  46.         we want to put suffix back (".c" assumed); since it always returns
  47.         a pointer to a static buffer, we can safely modify its result */
  48.      Strcat((char *) filename, ".c");
  49.  #endif
  50.  
  51.      /*
  52.       * Wildcard match will only work if there's a single pattern (which
  53.       * might be a single file name without any wildcarding) rather than
  54.       * a space-separated list.
  55.       * [to NOT do: We could step through the space-separated list and
  56.       * attempt a wildcard match against each element, but that would be
  57.       * overkill for the intended usage.]
  58.       */
  59.      if (wildcards && pmatch(debugfiles, filename))
  60.          return TRUE;
  61.  
  62.      /* check whether filename is an element of the list */
  63.      if ((p = strstr(debugfiles, filename)) != 0) {
  64.          int l = (int) strlen(filename);
  65.  
  66.          if ((p == debugfiles || p[-1] == ' ' || p[-1] == '/')
  67.              && (p[l] == ' ' || p[l] == '\0'))
  68.              return TRUE;
  69.      }
  70.      return FALSE;
  71.  }
  72.  
  73.  #endif /*DEBUG*/
  74.  

Tribute

  1.  /* ----------  BEGIN TRIBUTE ----------- */
  2.  
  3.  /* 3.6 tribute code
  4.   */
  5.  
  6.  #define SECTIONSCOPE 1
  7.  #define TITLESCOPE 2
  8.  #define PASSAGESCOPE 3
  9.  
  10.  #define MAXPASSAGES SIZE(context.novel.pasg) /* 30 */
  11.  
  12.  static int FDECL(choose_passage, (int, unsigned));
  13.  

choose_passage

  1.  /* choose a random passage that hasn't been chosen yet; once all have
  2.     been chosen, reset the tracking to make all passages available again */
  3.  static int
  4.  choose_passage(passagecnt, oid)
  5.  int passagecnt; /* total of available passages, 1..MAXPASSAGES */
  6.  unsigned oid; /* book.o_id, used to determine whether re-reading same book */
  7.  {
  8.      int idx, res;
  9.  
  10.      if (passagecnt < 1)
  11.          return 0;
  12.      if (passagecnt > MAXPASSAGES)
  13.          passagecnt = MAXPASSAGES;
  14.  
  15.      /* if a different book or we've used up all the passages already,
  16.         reset in order to have all 'passagecnt' passages available */
  17.      if (oid != context.novel.id || context.novel.count == 0) {
  18.          context.novel.id = oid;
  19.          context.novel.count = passagecnt;
  20.          for (idx = 0; idx < MAXPASSAGES; idx++)
  21.              context.novel.pasg[idx] = (xchar) ((idx < passagecnt) ? idx + 1
  22.                                                                    : 0);
  23.      }
  24.  
  25.      idx = rn2(context.novel.count);
  26.      res = (int) context.novel.pasg[idx];
  27.      /* move the last slot's passage index into the slot just used
  28.         and reduce the number of passages available */
  29.      context.novel.pasg[idx] = context.novel.pasg[--context.novel.count];
  30.      return res;
  31.  }
  32.  

read_tribute

  1.  /* Returns True if you were able to read something. */
  2.  boolean
  3.  read_tribute(tribsection, tribtitle, tribpassage, nowin_buf, bufsz, oid)
  4.  const char *tribsection, *tribtitle;
  5.  int tribpassage, bufsz;
  6.  char *nowin_buf;
  7.  unsigned oid; /* book identifier */
  8.  {
  9.      dlb *fp;
  10.      char *endp;
  11.      char line[BUFSZ], lastline[BUFSZ];
  12.  
  13.      int scope = 0;
  14.      int linect = 0, passagecnt = 0, targetpassage = 0;
  15.      const char *badtranslation = "an incomprehensible foreign translation";
  16.      boolean matchedsection = FALSE, matchedtitle = FALSE;
  17.      winid tribwin = WIN_ERR;
  18.      boolean grasped = FALSE;
  19.      boolean foundpassage = FALSE;
  20.  
  21.      /* check for mandatories */
  22.      if (!tribsection || !tribtitle) {
  23.          if (!nowin_buf)
  24.              pline("It's %s of \"%s\"!", badtranslation, tribtitle);
  25.          return grasped;
  26.      }
  27.  
  28.      debugpline3("read_tribute %s, %s, %d.", tribsection, tribtitle,
  29.                  tribpassage);
  30.  
  31.      fp = dlb_fopen(TRIBUTEFILE, "r");
  32.      if (!fp) {
  33.          /* this is actually an error - cannot open tribute file! */
  34.          if (!nowin_buf)
  35.              pline("You feel too overwhelmed to continue!");
  36.          return grasped;
  37.      }
  38.  
  39.      /*
  40.       * Syntax (not case-sensitive):
  41.       *  %section books
  42.       *
  43.       * In the books section:
  44.       *    %title booktitle (n)
  45.       *          where booktitle=book title without quotes
  46.       *          (n)= total number of passages present for this title
  47.       *    %passage k
  48.       *          where k=sequential passage number
  49.       *
  50.       * %e ends the passage/book/section
  51.       *    If in a passage, it marks the end of that passage.
  52.       *    If in a book, it marks the end of that book.
  53.       *    If in a section, it marks the end of that section.
  54.       *
  55.       *  %section death
  56.       */
  57.  
  58.      *line = *lastline = '\0';
  59.      while (dlb_fgets(line, sizeof line, fp) != 0) {
  60.          linect++;
  61.          if ((endp = index(line, '\n')) != 0)
  62.              *endp = 0;
  63.          switch (line[0]) {
  64.          case '%':
  65.              if (!strncmpi(&line[1], "section ", sizeof("section ") - 1)) {
  66.                  char *st = &line[9]; /* 9 from "%section " */
  67.  
  68.                  scope = SECTIONSCOPE;
  69.                  if (!strcmpi(st, tribsection))
  70.                      matchedsection = TRUE;
  71.                  else
  72.                      matchedsection = FALSE;
  73.              } else if (!strncmpi(&line[1], "title ", sizeof("title ") - 1)) {
  74.                  char *st = &line[7]; /* 7 from "%title " */
  75.                  char *p1, *p2;
  76.  
  77.                  if ((p1 = index(st, '(')) != 0) {
  78.                      *p1++ = '\0';
  79.                      (void) mungspaces(st);
  80.                      if ((p2 = index(p1, ')')) != 0) {
  81.                          *p2 = '\0';
  82.                          passagecnt = atoi(p1);
  83.                          if (passagecnt > MAXPASSAGES)
  84.                              passagecnt = MAXPASSAGES;
  85.                          scope = TITLESCOPE;
  86.                          if (matchedsection && !strcmpi(st, tribtitle)) {
  87.                              matchedtitle = TRUE;
  88.                              targetpassage = !tribpassage
  89.                                               ? choose_passage(passagecnt, oid)
  90.                                               : (tribpassage <= passagecnt)
  91.                                                  ? tribpassage : 0;
  92.                          } else {
  93.                              matchedtitle = FALSE;
  94.                          }
  95.                      }
  96.                  }
  97.              } else if (!strncmpi(&line[1], "passage ",
  98.                                   sizeof("passage ") - 1)) {
  99.                  int passagenum = 0;
  100.                  char *st = &line[9]; /* 9 from "%passage " */
  101.  
  102.                  while (*st == ' ' || *st == '\t')
  103.                      st++;
  104.                  if (*st && digit(*st) && (strlen(st) < 3))
  105.                      passagenum = atoi(st);
  106.                  if (passagenum && (passagenum <= passagecnt)) {
  107.                      scope = PASSAGESCOPE;
  108.                      if (matchedtitle && (passagenum == targetpassage)) {
  109.                          if (!nowin_buf)
  110.                              tribwin = create_nhwindow(NHW_MENU);
  111.                          else
  112.                              foundpassage = TRUE;
  113.                      }
  114.                  }
  115.              } else if (!strncmpi(&line[1], "e ", sizeof("e ") - 1)) {
  116.                  if (matchedtitle && scope == PASSAGESCOPE
  117.                      && ((!nowin_buf && tribwin != WIN_ERR)
  118.                          || (nowin_buf && foundpassage)))
  119.                      goto cleanup;
  120.                  if (scope == TITLESCOPE)
  121.                      matchedtitle = FALSE;
  122.                  if (scope == SECTIONSCOPE)
  123.                      matchedsection = FALSE;
  124.                  if (scope)
  125.                      --scope;
  126.              } else {
  127.                  debugpline1("tribute file error: bad %% command, line %d.",
  128.                              linect);
  129.              }
  130.              break;
  131.          case '#':
  132.              /* comment only, next! */
  133.              break;
  134.          default:
  135.              if (matchedtitle && scope == PASSAGESCOPE) {
  136.                  if (!nowin_buf && tribwin != WIN_ERR) {
  137.                      putstr(tribwin, 0, line);
  138.                      Strcpy(lastline, line);
  139.                  } else if (nowin_buf) {
  140.                      if ((int) strlen(line) < bufsz - 1)
  141.                          Strcpy(nowin_buf, line);
  142.                  }
  143.              }
  144.          }
  145.      }
  146.  
  147.  cleanup:
  148.      (void) dlb_fclose(fp);
  149.      if (!nowin_buf && tribwin != WIN_ERR) {
  150.          if (matchedtitle && scope == PASSAGESCOPE) {
  151.              display_nhwindow(tribwin, FALSE);
  152.              /* put the final attribution line into message history,
  153.                 analogous to the summary line from long quest messages */
  154.              if (index(lastline, '['))
  155.                  mungspaces(lastline); /* to remove leading spaces */
  156.              else /* construct one if necessary */
  157.                  Sprintf(lastline, "[%s, by Terry Pratchett]", tribtitle);
  158.              putmsghistory(lastline, FALSE);
  159.          }
  160.          destroy_nhwindow(tribwin);
  161.          tribwin = WIN_ERR;
  162.          grasped = TRUE;
  163.      } else {
  164.          if (!nowin_buf)
  165.              pline("It seems to be %s of \"%s\"!", badtranslation, tribtitle);
  166.          else
  167.              if (foundpassage)
  168.                  grasped = TRUE;
  169.      }
  170.      return grasped;
  171.  }
  172.  

Death_quote

  1.  boolean
  2.  Death_quote(buf, bufsz)
  3.  char *buf;
  4.  int bufsz;
  5.  {
  6.      unsigned death_oid = 1; /* chance of oid #1 being a novel is negligible */
  7.  
  8.      return read_tribute("Death", "Death Quotes", 0, buf, bufsz, death_oid);
  9.  }
  10.  
  11.  /* ----------  END TRIBUTE ----------- */
  12.  
  13.  /*files.c*/