Source:NetHack 3.6.1/src/files.c

From NetHackWiki
(Redirected from Source:Ref/fqname)
Jump to: navigation, search

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

Top of file

  1.  /* NetHack 3.6	files.c	$NHDT-Date: 1524413723 2018/04/22 16:15:23 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.235 $ */
  2.  /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3.  /*-Copyright (c) Derek S. Ray, 2015. */
  4.  /* NetHack may be freely redistributed.  See license for details. */

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

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

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

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.  
  57.  #ifdef PREFIXES_IN_USE
  58.  #define UNUSED_if_not_PREFIXES_IN_USE /*empty*/
  59.  #else
  60.  #define UNUSED_if_not_PREFIXES_IN_USE UNUSED
  61.  #endif
  62.  
  63.  /*ARGSUSED*/

fqname

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

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.  
  15.  /* ----------  BEGIN LEVEL FILE HANDLING ----------- */
  16.  
  17.  #ifdef MFLOPPY

set_lock_and_bones

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

set_levelfile_name

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

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.  
  29.  #if defined(SELECTSAVED)

strcmp_wrap

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

open_levelfile_exclusively

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

really_close

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

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 /* !HOLD_LOCKFILE_OPEN */
  14.  

nhclose

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

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.      /*
  13.       * "bonD0.nn"   = bones for level nn in the main dungeon;
  14.       * "bonM0.T"    = bones for Minetown;
  15.       * "bonQBar.n"  = bones for level n in the Barbarian quest;
  16.       * "bon3D0.nn"  = \
  17.       * "bon3M0.T"   =  > same as above, but for bones pool #3.
  18.       * "bon3QBar.n" = /
  19.       *
  20.       * Return value for content validation skips "bon" and the
  21.       * pool number (if present), making it feasible for the admin
  22.       * to manually move a bones file from one pool to another by
  23.       * renaming it.
  24.       */
  25.      Strcpy(file, "bon");
  26.  #ifdef SYSCF
  27.      if (sysopt.bones_pools > 1) {
  28.          unsigned poolnum = min((unsigned) sysopt.bones_pools, 10);
  29.  
  30.          poolnum = (unsigned) ubirthday % poolnum; /* 0..9 */
  31.          Sprintf(eos(file), "%u", poolnum);
  32.      }
  33.  #endif
  34.      dptr = eos(file); /* this used to be after the following Sprintf()
  35.                           and the return value was (dptr - 2) */
  36.      /* when this naming scheme was adopted, 'filecode' was one letter;
  37.         3.3.0 turned it into a three letter string (via roles[] in role.c);
  38.         from that version through 3.6.0, 'dptr' pointed past the filecode
  39.         and the return value of (dptr - 2)  was wrong for bones produced
  40.         in the quest branch, skipping the boneid character 'Q' and the
  41.         first letter of the role's filecode; bones loading still worked
  42.         because the bonesid used for validation had the same error */
  43.      Sprintf(dptr, "%c%s", dungeons[lev->dnum].boneid,
  44.              In_quest(lev) ? urole.filecode : "0");
  45.      if ((sptr = Is_special(lev)) != 0)
  46.          Sprintf(eos(dptr), ".%c", sptr->boneid);
  47.      else
  48.          Sprintf(eos(dptr), ".%d", lev->dlevel);
  49.  #ifdef VMS
  50.      Strcat(dptr, ";1");
  51.  #endif
  52.      return dptr;
  53.  }
  54.  

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.  
  47.  #ifdef MFLOPPY

cancel_bonesfile

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

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.  
  11.  /* ----------  BEGIN SAVE FILE HANDLING ----------- */
  12.  

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.  
  55.  #ifdef INSURANCE

save_savefile_name

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

set_error_savefile

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

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.  
  27.  #if defined(SELECTSAVED)

plname_from_file

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

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.  
  16.  /* ----------  BEGIN FILE COMPRESSION HANDLING ----------- */
  17.  
  18.  #ifdef COMPRESS
  19.  

redirect

  1.  STATIC_OVL void
  2.  redirect(filename, mode, stream, uncomp)
  3.  const char *filename, *mode;
  4.  FILE *stream;
  5.  boolean uncomp;
  6.  {
  7.      if (freopen(filename, mode, stream) == (FILE *) 0) {
  8.          (void) fprintf(stderr, "freopen of %s for %scompress failed\n",
  9.                         filename, uncomp ? "un" : "");
  10.          nh_terminate(EXIT_FAILURE);
  11.      }
  12.  }
  13.  
  14.  /*
  15.   * using system() is simpler, but opens up security holes and causes
  16.   * problems on at least Interactive UNIX 3.0.1 (SVR3.2), where any
  17.   * setuid is renounced by /bin/sh, so the files cannot be accessed.
  18.   *
  19.   * cf. child() in unixunix.c.
  20.   */

docompress_file

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

nh_compress

  1.  /* compress file */
  2.  void
  3.  nh_compress(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, FALSE);
  12.  #endif
  13.  }
  14.  

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.  
  15.  #ifdef ZLIB_COMP /* RLC 09 Mar 1999: Support internal ZLIB */

make_compressed_name

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

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.  
  129.  /* ----------  BEGIN FILE LOCKING HANDLING ----------- */
  130.  
  131.  static int nesting = 0;
  132.  
  133.  #if defined(NO_FILE_LINKS) || defined(USE_FCNTL) /* implies UNIX */
  134.  static int lockfd; /* for lock_file() to pass to unlock_file() */
  135.  #endif
  136.  #ifdef USE_FCNTL
  137.  struct flock sflock; /* for unlocking, same as above */
  138.  #endif
  139.  
  140.  #define HUP if (!program_state.done_hup)
  141.  
  142.  #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 */
  35.  

lock_file

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

unlock_file

  1.  /* unlock file, which must be currently locked by lock_file */
  2.  void
  3.  unlock_file(filename)
  4.  const char *filename;
  5.  {
  6.  #ifndef USE_FCNTL
  7.      char locknambuf[BUFSZ];
  8.      const char *lockname;
  9.  #endif
  10.  
  11.      if (nesting == 1) {
  12.  #ifdef USE_FCNTL
  13.          sflock.l_type = F_UNLCK;
  14.          if (fcntl(lockfd, F_SETLK, &sflock) == -1) {
  15.              HUP raw_printf("Can't remove fcntl lock on %s.", filename);
  16.              (void) close(lockfd);
  17.          }
  18.  #else
  19.          lockname = make_lockname(filename, locknambuf);
  20.  #ifndef NO_FILE_LINKS /* LOCKDIR should be subsumed by LOCKPREFIX */
  21.          lockname = fqname(lockname, LOCKPREFIX, 2);
  22.  #endif
  23.  
  24.  #if defined(UNIX) || defined(VMS)
  25.          if (unlink(lockname) < 0)
  26.              HUP raw_printf("Can't unlink %s.", lockname);
  27.  #ifdef NO_FILE_LINKS
  28.          (void) nhclose(lockfd);
  29.  #endif
  30.  
  31.  #endif /* UNIX || VMS */
  32.  
  33.  #if defined(AMIGA) || defined(WIN32) || defined(MSDOS)
  34.          if (lockptr)
  35.              Close(lockptr);
  36.          DeleteFile(lockname);
  37.          lockptr = 0;
  38.  #endif /* AMIGA || WIN32 || MSDOS */
  39.  #endif /* USE_FCNTL */
  40.      }
  41.  
  42.      nesting--;
  43.  }
  44.  
  45.  /* ----------  END FILE LOCKING HANDLING ----------- */
  46.  
  47.  /* ----------  BEGIN CONFIG FILE HANDLING ----------- */
  48.  
  49.  const char *default_configfile =
  50.  #ifdef UNIX
  51.      ".nethackrc";
  52.  #else
  53.  #if defined(MAC) || defined(__BEOS__)
  54.      "NetHack Defaults";
  55.  #else
  56.  #if defined(MSDOS) || defined(WIN32)
  57.      "defaults.nh";
  58.  #else
  59.      "NetHack.cnf";
  60.  #endif
  61.  #endif
  62.  #endif
  63.  
  64.  /* used for messaging */
  65.  char configfile[BUFSZ];
  66.  
  67.  #ifdef MSDOS
  68.  /* conflict with speed-dial under windows
  69.   * for XXX.cnf file so support of NetHack.cnf
  70.   * is for backward compatibility only.
  71.   * Preferred name (and first tried) is now defaults.nh but
  72.   * the game will try the old name if there
  73.   * is no defaults.nh.
  74.   */
  75.  const char *backward_compat_configfile = "nethack.cnf";
  76.  #endif
  77.  

set_configfile_name

  1.  /* remember the name of the file we're accessing;
  2.     if may be used in option reject messages */
  3.  STATIC_OVL void
  4.  set_configfile_name(fname)
  5.  const char *fname;
  6.  {
  7.      (void) strncpy(configfile, fname, sizeof configfile - 1);
  8.      configfile[sizeof configfile - 1] = '\0';
  9.  }
  10.  
  11.  #ifndef MFLOPPY
  12.  #define fopenp fopen
  13.  #endif
  14.  

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

get_uchars

  1.  /*
  2.   * Retrieve a list of integers from buf 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(bufp, list, modlist, size, name)
  9.  char *bufp;       /* current pointer */
  10.  uchar *list;      /* return list */
  11.  boolean modlist;  /* TRUE: list is being modified in place */
  12.  int size;         /* return list size */
  13.  const char *name; /* name of option for error message */
  14.  {
  15.      unsigned int num = 0;
  16.      int count = 0;
  17.      boolean havenum = FALSE;
  18.  
  19.      while (1) {
  20.          switch (*bufp) {
  21.          case ' ':
  22.          case '\0':
  23.          case '\t':
  24.          case '\n':
  25.              if (havenum) {
  26.                  /* if modifying in place, don't insert zeros */
  27.                  if (num || !modlist)
  28.                      list[count] = num;
  29.                  count++;
  30.                  num = 0;
  31.                  havenum = FALSE;
  32.              }
  33.              if (count == size || !*bufp)
  34.                  return count;
  35.              bufp++;
  36.              break;
  37.  
  38.          case '0':
  39.          case '1':
  40.          case '2':
  41.          case '3':
  42.          case '4':
  43.          case '5':
  44.          case '6':
  45.          case '7':
  46.          case '8':
  47.          case '9':
  48.              havenum = TRUE;
  49.              num = num * 10 + (*bufp - '0');
  50.              bufp++;
  51.              break;
  52.  
  53.          case '\\':
  54.              goto gi_error;
  55.              break;
  56.  
  57.          default:
  58.          gi_error:
  59.              raw_printf("Syntax error in %s", name);
  60.              wait_synch();
  61.              return count;
  62.          }
  63.      }
  64.      /*NOTREACHED*/
  65.  }
  66.  
  67.  #ifdef NOCWD_ASSUMPTIONS

adjust_prefix

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

choose_random_part

  1.  /* Choose at random one of the sep separated parts from str. Mangles str. */
  2.  STATIC_OVL char *
  3.  choose_random_part(str,sep)
  4.  char *str;
  5.  char sep;
  6.  {
  7.      int nsep = 1;
  8.      int csep;
  9.      int len = 0;
  10.      char *begin = str;
  11.  
  12.      if (!str)
  13.          return (char *) 0;
  14.  
  15.      while (*str) {
  16.  	if (*str == sep) nsep++;
  17.  	str++;
  18.      }
  19.      csep = rn2(nsep);
  20.      str = begin;
  21.      while ((csep > 0) && *str) {
  22.  	str++;
  23.  	if (*str == sep) csep--;
  24.      }
  25.      if (*str) {
  26.  	if (*str == sep) str++;
  27.  	begin = str;
  28.  	while (*str && *str != sep) {
  29.  	    str++;
  30.  	    len++;
  31.  	}
  32.  	*str = '\0';
  33.  	if (len)
  34.              return begin;
  35.      }
  36.      return (char *) 0;
  37.  }
  38.  

free_config_sections

  1.  STATIC_OVL void
  2.  free_config_sections()
  3.  {
  4.      if (config_section_chosen) {
  5.          free(config_section_chosen);
  6.          config_section_chosen = NULL;
  7.      }
  8.      if (config_section_current) {
  9.          free(config_section_current);
  10.          config_section_current = NULL;
  11.      }
  12.  }
  13.  

is_config_section

  1.  STATIC_OVL boolean
  2.  is_config_section(str)
  3.  const char *str;
  4.  {
  5.      const char *a = rindex(str, ']');
  6.  
  7.      return (a && *str == '[' && *(a+1) == '\0' && (int)(a - str) > 0);
  8.  }
  9.  

handle_config_section

  1.  STATIC_OVL boolean
  2.  handle_config_section(buf)
  3.  char *buf;
  4.  {
  5.      if (is_config_section(buf)) {
  6.          char *send;
  7.          if (config_section_current) {
  8.              free(config_section_current);
  9.          }
  10.          config_section_current = dupstr(&buf[1]);
  11.          send = rindex(config_section_current, ']');
  12.          *send = '\0';
  13.          debugpline1("set config section: '%s'", config_section_current);
  14.          return TRUE;
  15.      }
  16.  
  17.      if (config_section_current) {
  18.          if (!config_section_chosen)
  19.              return TRUE;
  20.          if (strcmp(config_section_current, config_section_chosen))
  21.              return TRUE;
  22.      }
  23.      return FALSE;
  24.  }
  25.  
  26.  #define match_varname(INP, NAM, LEN) match_optname(INP, NAM, LEN, TRUE)
  27.  

find_optparam

  1.  /* find the '=' or ':' */
  2.  char *
  3.  find_optparam(buf)
  4.  const char *buf;
  5.  {
  6.      char *bufp, *altp;
  7.  
  8.      bufp = index(buf, '=');
  9.      altp = index(buf, ':');
  10.      if (!bufp || (altp && altp < bufp))
  11.          bufp = altp;
  12.  
  13.      return bufp;
  14.  }
  15.  

parse_config_line

  1.  boolean
  2.  parse_config_line(origbuf)
  3.  char *origbuf;
  4.  {
  5.  #if defined(MICRO) && !defined(NOCWD_ASSUMPTIONS)
  6.      static boolean ramdisk_specified = FALSE;
  7.  #endif
  8.  #ifdef SYSCF
  9.      int n;
  10.  #endif
  11.      char *bufp, buf[4 * BUFSZ];
  12.      uchar translate[MAXPCHARS];
  13.      int len;
  14.      boolean retval = TRUE;
  15.      int src = iflags.parse_config_file_src;
  16.  
  17.      /* convert any tab to space, condense consecutive spaces into one,
  18.         remove leading and trailing spaces (exception: if there is nothing
  19.         but spaces, one of them will be kept even though it leads/trails) */
  20.      mungspaces(strcpy(buf, origbuf));
  21.  
  22.      /* find the '=' or ':' */
  23.      bufp = find_optparam(buf);
  24.      if (!bufp) {
  25.          config_error_add("Not a config statement, missing '='");
  26.          return FALSE;
  27.      }
  28.      /* skip past '=', then space between it and value, if any */
  29.      ++bufp;
  30.      if (*bufp == ' ')
  31.          ++bufp;
  32.  
  33.      /* Go through possible variables */
  34.      /* some of these (at least LEVELS and SAVE) should now set the
  35.       * appropriate fqn_prefix[] rather than specialized variables
  36.       */
  37.      if (match_varname(buf, "OPTIONS", 4)) {
  38.          /* hack: un-mungspaces to allow consecutive spaces in
  39.             general options until we verify that this is unnecessary;
  40.             '=' or ':' is guaranteed to be present */
  41.          bufp = find_optparam(origbuf);
  42.          ++bufp; /* skip '='; parseoptions() handles spaces */
  43.  
  44.          if (!parseoptions(bufp, TRUE, TRUE))
  45.              retval = FALSE;
  46.      } else if (match_varname(buf, "AUTOPICKUP_EXCEPTION", 5)) {
  47.          add_autopickup_exception(bufp);
  48.      } else if (match_varname(buf, "BINDINGS", 4)) {
  49.          if (!parsebindings(bufp))
  50.              retval = FALSE;
  51.      } else if (match_varname(buf, "AUTOCOMPLETE", 5)) {
  52.          parseautocomplete(bufp, TRUE);
  53.      } else if (match_varname(buf, "MSGTYPE", 7)) {
  54.          if (!msgtype_parse_add(bufp))
  55.              retval = FALSE;
  56.  #ifdef NOCWD_ASSUMPTIONS
  57.      } else if (match_varname(buf, "HACKDIR", 4)) {
  58.          adjust_prefix(bufp, HACKPREFIX);
  59.      } else if (match_varname(buf, "LEVELDIR", 4)
  60.                 || match_varname(buf, "LEVELS", 4)) {
  61.          adjust_prefix(bufp, LEVELPREFIX);
  62.      } else if (match_varname(buf, "SAVEDIR", 4)) {
  63.          adjust_prefix(bufp, SAVEPREFIX);
  64.      } else if (match_varname(buf, "BONESDIR", 5)) {
  65.          adjust_prefix(bufp, BONESPREFIX);
  66.      } else if (match_varname(buf, "DATADIR", 4)) {
  67.          adjust_prefix(bufp, DATAPREFIX);
  68.      } else if (match_varname(buf, "SCOREDIR", 4)) {
  69.          adjust_prefix(bufp, SCOREPREFIX);
  70.      } else if (match_varname(buf, "LOCKDIR", 4)) {
  71.          adjust_prefix(bufp, LOCKPREFIX);
  72.      } else if (match_varname(buf, "CONFIGDIR", 4)) {
  73.          adjust_prefix(bufp, CONFIGPREFIX);
  74.      } else if (match_varname(buf, "TROUBLEDIR", 4)) {
  75.          adjust_prefix(bufp, TROUBLEPREFIX);
  76.  #else /*NOCWD_ASSUMPTIONS*/
  77.  #ifdef MICRO
  78.      } else if (match_varname(buf, "HACKDIR", 4)) {
  79.          (void) strncpy(hackdir, bufp, PATHLEN - 1);
  80.  #ifdef MFLOPPY
  81.      } else if (match_varname(buf, "RAMDISK", 3)) {
  82.  /* The following ifdef is NOT in the wrong
  83.   * place.  For now, we accept and silently
  84.   * ignore RAMDISK */
  85.  #ifndef AMIGA
  86.          if (strlen(bufp) >= PATHLEN)
  87.              bufp[PATHLEN - 1] = '\0';
  88.          Strcpy(levels, bufp);
  89.          ramdisk = (strcmp(permbones, levels) != 0);
  90.          ramdisk_specified = TRUE;
  91.  #endif
  92.  #endif
  93.      } else if (match_varname(buf, "LEVELS", 4)) {
  94.          if (strlen(bufp) >= PATHLEN)
  95.              bufp[PATHLEN - 1] = '\0';
  96.          Strcpy(permbones, bufp);
  97.          if (!ramdisk_specified || !*levels)
  98.              Strcpy(levels, bufp);
  99.          ramdisk = (strcmp(permbones, levels) != 0);
  100.      } else if (match_varname(buf, "SAVE", 4)) {
  101.  #ifdef MFLOPPY
  102.          extern int saveprompt;
  103.  #endif
  104.          char *ptr;
  105.  
  106.          if ((ptr = index(bufp, ';')) != 0) {
  107.              *ptr = '\0';
  108.  #ifdef MFLOPPY
  109.              if (*(ptr + 1) == 'n' || *(ptr + 1) == 'N') {
  110.                  saveprompt = FALSE;
  111.              }
  112.  #endif
  113.          }
  114.  #if defined(SYSFLAGS) && defined(MFLOPPY)
  115.          else
  116.              saveprompt = sysflags.asksavedisk;
  117.  #endif
  118.  
  119.          (void) strncpy(SAVEP, bufp, SAVESIZE - 1);
  120.          append_slash(SAVEP);
  121.  #endif /* MICRO */
  122.  #endif /*NOCWD_ASSUMPTIONS*/
  123.  
  124.      } else if (match_varname(buf, "NAME", 4)) {
  125.          (void) strncpy(plname, bufp, PL_NSIZ - 1);
  126.      } else if (match_varname(buf, "ROLE", 4)
  127.                 || match_varname(buf, "CHARACTER", 4)) {
  128.          if ((len = str2role(bufp)) >= 0)
  129.              flags.initrole = len;
  130.      } else if (match_varname(buf, "DOGNAME", 3)) {
  131.          (void) strncpy(dogname, bufp, PL_PSIZ - 1);
  132.      } else if (match_varname(buf, "CATNAME", 3)) {
  133.          (void) strncpy(catname, bufp, PL_PSIZ - 1);
  134.  
  135.  #ifdef SYSCF
  136.      } else if (src == SET_IN_SYS && match_varname(buf, "WIZARDS", 7)) {
  137.          if (sysopt.wizards)
  138.              free((genericptr_t) sysopt.wizards);
  139.          sysopt.wizards = dupstr(bufp);
  140.          if (strlen(sysopt.wizards) && strcmp(sysopt.wizards, "*")) {
  141.              /* pre-format WIZARDS list now; it's displayed during a panic
  142.                 and since that panic might be due to running out of memory,
  143.                 we don't want to risk attempting to allocate any memory then */
  144.              if (sysopt.fmtd_wizard_list)
  145.                  free((genericptr_t) sysopt.fmtd_wizard_list);
  146.              sysopt.fmtd_wizard_list = build_english_list(sysopt.wizards);
  147.          }
  148.      } else if (src == SET_IN_SYS && match_varname(buf, "SHELLERS", 8)) {
  149.          if (sysopt.shellers)
  150.              free((genericptr_t) sysopt.shellers);
  151.          sysopt.shellers = dupstr(bufp);
  152.      } else if (src == SET_IN_SYS && match_varname(buf, "EXPLORERS", 7)) {
  153.          if (sysopt.explorers)
  154.              free((genericptr_t) sysopt.explorers);
  155.          sysopt.explorers = dupstr(bufp);
  156.      } else if (src == SET_IN_SYS && match_varname(buf, "DEBUGFILES", 5)) {
  157.          /* if showdebug() has already been called (perhaps we've added
  158.             some debugpline() calls to option processing) and has found
  159.             a value for getenv("DEBUGFILES"), don't override that */
  160.          if (sysopt.env_dbgfl <= 0) {
  161.              if (sysopt.debugfiles)
  162.                  free((genericptr_t) sysopt.debugfiles);
  163.              sysopt.debugfiles = dupstr(bufp);
  164.          }
  165.      } else if (src == SET_IN_SYS && match_varname(buf, "DUMPLOGFILE", 7)) {
  166.  #ifdef DUMPLOG
  167.          if (sysopt.dumplogfile)
  168.              free((genericptr_t) sysopt.dumplogfile);
  169.          sysopt.dumplogfile = dupstr(bufp);
  170.  #endif
  171.      } else if (src == SET_IN_SYS && match_varname(buf, "GENERICUSERS", 12)) {
  172.          if (sysopt.genericusers)
  173.              free((genericptr_t) sysopt.genericusers);
  174.          sysopt.genericusers = dupstr(bufp);
  175.      } else if (src == SET_IN_SYS && match_varname(buf, "BONES_POOLS", 10)) {
  176.          /* max value of 10 guarantees (N % bones.pools) will be one digit
  177.             so we don't lose control of the length of bones file names */
  178.          n = atoi(bufp);
  179.          sysopt.bones_pools = (n <= 0) ? 0 : min(n, 10);
  180.          /* note: right now bones_pools==0 is the same as bones_pools==1,
  181.             but we could change that and make bones_pools==0 become an
  182.             indicator to suppress bones usage altogether */
  183.      } else if (src == SET_IN_SYS && match_varname(buf, "SUPPORT", 7)) {
  184.          if (sysopt.support)
  185.              free((genericptr_t) sysopt.support);
  186.          sysopt.support = dupstr(bufp);
  187.      } else if (src == SET_IN_SYS && match_varname(buf, "RECOVER", 7)) {
  188.          if (sysopt.recover)
  189.              free((genericptr_t) sysopt.recover);
  190.          sysopt.recover = dupstr(bufp);
  191.      } else if (src == SET_IN_SYS
  192.                 && match_varname(buf, "CHECK_SAVE_UID", 14)) {
  193.          n = atoi(bufp);
  194.          sysopt.check_save_uid = n;
  195.      } else if (src == SET_IN_SYS
  196.                 && match_varname(buf, "CHECK_PLNAME", 12)) {
  197.          n = atoi(bufp);
  198.          sysopt.check_plname = n;
  199.      } else if (match_varname(buf, "SEDUCE", 6)) {
  200.          n = !!atoi(bufp); /* XXX this could be tighter */
  201.          /* allow anyone to turn it off, but only sysconf to turn it on*/
  202.          if (src != SET_IN_SYS && n != 0) {
  203.              config_error_add("Illegal value in SEDUCE");
  204.              return FALSE;
  205.          }
  206.          sysopt.seduce = n;
  207.          sysopt_seduce_set(sysopt.seduce);
  208.      } else if (src == SET_IN_SYS && match_varname(buf, "MAXPLAYERS", 10)) {
  209.          n = atoi(bufp);
  210.          /* XXX to get more than 25, need to rewrite all lock code */
  211.          if (n < 0 || n > 25) {
  212.              config_error_add("Illegal value in MAXPLAYERS (maximum is 25).");
  213.              return FALSE;
  214.          }
  215.          sysopt.maxplayers = n;
  216.      } else if (src == SET_IN_SYS && match_varname(buf, "PERSMAX", 7)) {
  217.          n = atoi(bufp);
  218.          if (n < 1) {
  219.              config_error_add("Illegal value in PERSMAX (minimum is 1).");
  220.              return FALSE;
  221.          }
  222.          sysopt.persmax = n;
  223.      } else if (src == SET_IN_SYS && match_varname(buf, "PERS_IS_UID", 11)) {
  224.          n = atoi(bufp);
  225.          if (n != 0 && n != 1) {
  226.              config_error_add("Illegal value in PERS_IS_UID (must be 0 or 1).");
  227.              return FALSE;
  228.          }
  229.          sysopt.pers_is_uid = n;
  230.      } else if (src == SET_IN_SYS && match_varname(buf, "ENTRYMAX", 8)) {
  231.          n = atoi(bufp);
  232.          if (n < 10) {
  233.              config_error_add("Illegal value in ENTRYMAX (minimum is 10).");
  234.              return FALSE;
  235.          }
  236.          sysopt.entrymax = n;
  237.      } else if ((src == SET_IN_SYS) && match_varname(buf, "POINTSMIN", 9)) {
  238.          n = atoi(bufp);
  239.          if (n < 1) {
  240.              config_error_add("Illegal value in POINTSMIN (minimum is 1).");
  241.              return FALSE;
  242.          }
  243.          sysopt.pointsmin = n;
  244.      } else if (src == SET_IN_SYS
  245.                 && match_varname(buf, "MAX_STATUENAME_RANK", 10)) {
  246.          n = atoi(bufp);
  247.          if (n < 1) {
  248.              config_error_add(
  249.                  "Illegal value in MAX_STATUENAME_RANK (minimum is 1).");
  250.              return FALSE;
  251.          }
  252.          sysopt.tt_oname_maxrank = n;
  253.  
  254.      /* SYSCF PANICTRACE options */
  255.      } else if (src == SET_IN_SYS
  256.                 && match_varname(buf, "PANICTRACE_LIBC", 15)) {
  257.          n = atoi(bufp);
  258.  #if defined(PANICTRACE) && defined(PANICTRACE_LIBC)
  259.          if (n < 0 || n > 2) {
  260.              config_error_add("Illegal value in PANICTRACE_LIBC (not 0,1,2).");
  261.              return FALSE;
  262.          }
  263.  #endif
  264.          sysopt.panictrace_libc = n;
  265.      } else if (src == SET_IN_SYS
  266.                 && match_varname(buf, "PANICTRACE_GDB", 14)) {
  267.          n = atoi(bufp);
  268.  #if defined(PANICTRACE)
  269.          if (n < 0 || n > 2) {
  270.              config_error_add("Illegal value in PANICTRACE_GDB (not 0,1,2).");
  271.              return FALSE;
  272.          }
  273.  #endif
  274.          sysopt.panictrace_gdb = n;
  275.      } else if (src == SET_IN_SYS && match_varname(buf, "GDBPATH", 7)) {
  276.  #if defined(PANICTRACE) && !defined(VMS)
  277.          if (!file_exists(bufp)) {
  278.              config_error_add("File specified in GDBPATH does not exist.");
  279.              return FALSE;
  280.          }
  281.  #endif
  282.          if (sysopt.gdbpath)
  283.              free((genericptr_t) sysopt.gdbpath);
  284.          sysopt.gdbpath = dupstr(bufp);
  285.      } else if (src == SET_IN_SYS && match_varname(buf, "GREPPATH", 7)) {
  286.  #if defined(PANICTRACE) && !defined(VMS)
  287.          if (!file_exists(bufp)) {
  288.              config_error_add("File specified in GREPPATH does not exist.");
  289.              return FALSE;
  290.          }
  291.  #endif
  292.          if (sysopt.greppath)
  293.              free((genericptr_t) sysopt.greppath);
  294.          sysopt.greppath = dupstr(bufp);
  295.  #endif /* SYSCF */
  296.  
  297.      } else if (match_varname(buf, "BOULDER", 3)) {
  298.          (void) get_uchars(bufp, &iflags.bouldersym, TRUE, 1,
  299.                            "BOULDER");
  300.      } else if (match_varname(buf, "MENUCOLOR", 9)) {
  301.          if (!add_menu_coloring(bufp))
  302.              retval = FALSE;
  303.      } else if (match_varname(buf, "HILITE_STATUS", 6)) {
  304.  #ifdef STATUS_HILITES
  305.          if (!parse_status_hl1(bufp, TRUE))
  306.              retval = FALSE;
  307.  #endif
  308.      } else if (match_varname(buf, "WARNINGS", 5)) {
  309.          (void) get_uchars(bufp, translate, FALSE, WARNCOUNT,
  310.                            "WARNINGS");
  311.          assign_warnings(translate);
  312.      } else if (match_varname(buf, "SYMBOLS", 4)) {
  313.          if (!parsesymbols(bufp)) {
  314.              config_error_add("Error in SYMBOLS definition '%s'", bufp);
  315.              retval = FALSE;
  316.          }
  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.      } else if (match_varname(buf, "QT_TILEWIDTH", 12)) {
  438.  #ifdef QT_GRAPHICS
  439.          extern char *qt_tilewidth;
  440.  
  441.          if (qt_tilewidth == NULL)
  442.              qt_tilewidth = dupstr(bufp);
  443.  #endif
  444.      } else if (match_varname(buf, "QT_TILEHEIGHT", 13)) {
  445.  #ifdef QT_GRAPHICS
  446.          extern char *qt_tileheight;
  447.  
  448.          if (qt_tileheight == NULL)
  449.              qt_tileheight = dupstr(bufp);
  450.  #endif
  451.      } else if (match_varname(buf, "QT_FONTSIZE", 11)) {
  452.  #ifdef QT_GRAPHICS
  453.          extern char *qt_fontsize;
  454.  
  455.          if (qt_fontsize == NULL)
  456.              qt_fontsize = dupstr(bufp);
  457.  #endif
  458.      } else if (match_varname(buf, "QT_COMPACT", 10)) {
  459.  #ifdef QT_GRAPHICS
  460.          extern int qt_compact_mode;
  461.  
  462.          qt_compact_mode = atoi(bufp);
  463.  #endif
  464.      } else {
  465.          config_error_add("Unknown config statement");
  466.          return FALSE;
  467.      }
  468.      return retval;
  469.  }
  470.  
  471.  #ifdef USER_SOUNDS

can_read_file

  1.  boolean
  2.  can_read_file(filename)
  3.  const char *filename;
  4.  {
  5.      return (boolean) (access(filename, 4) == 0);
  6.  }
  7.  #endif /* USER_SOUNDS */
  8.  
  9.  struct _config_error_frame {
  10.      int line_num;
  11.      int num_errors;
  12.      boolean origline_shown;
  13.      boolean fromfile;
  14.      boolean secure;
  15.      char origline[4 * BUFSZ];
  16.      char source[BUFSZ];
  17.      struct _config_error_frame *next;
  18.  };
  19.  
  20.  struct _config_error_frame *config_error_data = (struct _config_error_frame *)0;
  21.  

config_error_init

  1.  void
  2.  config_error_init(from_file, sourcename, secure)
  3.  boolean from_file;
  4.  const char *sourcename;
  5.  boolean secure;
  6.  {
  7.      struct _config_error_frame *tmp = (struct _config_error_frame *)
  8.          alloc(sizeof(struct _config_error_frame));
  9.  
  10.      tmp->line_num = 0;
  11.      tmp->num_errors = 0;
  12.      tmp->origline_shown = FALSE;
  13.      tmp->fromfile = from_file;
  14.      tmp->secure = secure;
  15.      tmp->origline[0] = '\0';
  16.      if (sourcename && sourcename[0]) {
  17.          (void) strncpy(tmp->source, sourcename, sizeof(tmp->source)-1);
  18.          tmp->source[sizeof(tmp->source)-1] = '\0';
  19.      } else
  20.          tmp->source[0] = '\0';
  21.  
  22.      tmp->next = config_error_data;
  23.      config_error_data = tmp;
  24.  }
  25.  

config_error_nextline

  1.  STATIC_OVL boolean
  2.  config_error_nextline(line)
  3.  const char *line;
  4.  {
  5.      struct _config_error_frame *ced = config_error_data;
  6.  
  7.      if (!ced)
  8.          return FALSE;
  9.  
  10.      if (ced->num_errors && ced->secure)
  11.          return FALSE;
  12.  
  13.      ced->line_num++;
  14.      ced->origline_shown = FALSE;
  15.      if (line && line[0]) {
  16.          (void) strncpy(ced->origline, line, sizeof(ced->origline)-1);
  17.          ced->origline[sizeof(ced->origline)-1] = '\0';
  18.      } else
  19.          ced->origline[0] = '\0';
  20.  
  21.      return TRUE;
  22.  }
  23.  
  24.  /*VARARGS1*/

VA_DECL

  1.  void config_error_add
  2.  VA_DECL(const char *, str)
  3.  {
  4.      char buf[BUFSZ];
  5.      char lineno[QBUFSZ];
  6.  
  7.      VA_START(str);
  8.      VA_INIT(str, char *);
  9.  
  10.      Vsprintf(buf, str, VA_ARGS);
  11.  
  12.      if (!config_error_data) {
  13.          pline("%s.", *buf ? buf : "Unknown error");
  14.          wait_synch();
  15.          return;
  16.      }
  17.  
  18.      config_error_data->num_errors++;
  19.      if (!config_error_data->origline_shown
  20.          && !config_error_data->secure) {
  21.          pline("\n%s", config_error_data->origline);
  22.          config_error_data->origline_shown = TRUE;
  23.      }
  24.      if (config_error_data->line_num > 0
  25.          && !config_error_data->secure) {
  26.          Sprintf(lineno, "Line %i: ", config_error_data->line_num);
  27.      } else
  28.          lineno[0] = '\0';
  29.      pline("%s %s%s.",
  30.            config_error_data->secure ? "Error:" : " *",
  31.            lineno,
  32.            *buf ? buf : "Unknown error");
  33.  
  34.      VA_END();
  35.  }
  36.  

config_error_done

  1.  int
  2.  config_error_done()
  3.  {
  4.      int n;
  5.      struct _config_error_frame *tmp = config_error_data;
  6.  
  7.      if (!config_error_data)
  8.          return 0;
  9.      n = config_error_data->num_errors;
  10.      if (n) {
  11.          pline("\n%i error%s in %s.\n", n,
  12.                     (n > 1) ? "s" : "",
  13.                     *config_error_data->source
  14.                ? config_error_data->source : configfile);
  15.          wait_synch();
  16.      }
  17.  
  18.      config_error_data = tmp->next;
  19.  
  20.      free(tmp);
  21.  
  22.      return n;
  23.  }
  24.  

read_config_file

  1.  boolean
  2.  read_config_file(filename, src)
  3.  const char *filename;
  4.  int src;
  5.  {
  6.      FILE *fp;
  7.      boolean rv = TRUE;
  8.  
  9.      if (!(fp = fopen_config_file(filename, src)))
  10.          return FALSE;
  11.  
  12.      /* begin detection of duplicate configfile options */
  13.      set_duplicate_opt_detection(1);
  14.      free_config_sections();
  15.      iflags.parse_config_file_src = src;
  16.  
  17.      rv = parse_conf_file(fp, parse_config_line);
  18.      (void) fclose(fp);
  19.  
  20.      free_config_sections();
  21.      /* turn off detection of duplicate configfile options */
  22.      set_duplicate_opt_detection(0);
  23.      return rv;
  24.  }
  25.  

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.  
  28.  

proc_wizkit_line

  1.  boolean
  2.  proc_wizkit_line(buf)
  3.  char *buf;
  4.  {
  5.      struct obj *otmp = readobjnam(buf, (struct obj *) 0);
  6.  
  7.      if (otmp) {
  8.          if (otmp != &zeroobj)
  9.              wizkit_addinv(otmp);
  10.      } else {
  11.          /* .60 limits output line width to 79 chars */
  12.          config_error_add("Bad wizkit item: \"%.60s\"", buf);
  13.          return FALSE;
  14.      }
  15.      return TRUE;
  16.  }
  17.  

read_wizkit

  1.  void
  2.  read_wizkit()
  3.  {
  4.      FILE *fp;
  5.  
  6.      if (!wizard || !(fp = fopen_wizkit_file()))
  7.          return;
  8.  
  9.      program_state.wizkit_wishing = 1;
  10.      config_error_init(TRUE, "WIZKIT", FALSE);
  11.  
  12.      parse_conf_file(fp, proc_wizkit_line);
  13.      (void) fclose(fp);
  14.  
  15.      config_error_done();
  16.      program_state.wizkit_wishing = 0;
  17.  
  18.      return;
  19.  }
  20.  

parse_conf_file

  1.  /* parse_conf_file
  2.   *
  3.   * Read from file fp, handling comments, empty lines, config sections,
  4.   * CHOOSE, and line continuation, calling proc for every valid line.
  5.   *
  6.   * Continued lines are merged together with one space in between.
  7.   */
  8.  STATIC_OVL boolean
  9.  parse_conf_file(fp, proc)
  10.  FILE *fp;
  11.  boolean FDECL((*proc), (char *));
  12.  {
  13.      char inbuf[4 * BUFSZ];
  14.      boolean rv = TRUE; /* assume successful parse */
  15.      char *ep;
  16.      boolean skip = FALSE, morelines = FALSE;
  17.      char *buf = (char *) 0;
  18.  
  19.      free_config_sections();
  20.  
  21.      while (fgets(inbuf, (int) (sizeof inbuf), fp)) {
  22.          ep = index(inbuf, '\n');
  23.          if (skip) { /* in case previous line was too long */
  24.              if (ep)
  25.                  skip = FALSE; /* found newline; next line is normal */
  26.          } else {
  27.              if (!ep) {
  28.                  config_error_add("Line too long, skipping");
  29.                  skip = TRUE; /* newline missing; discard next fgets */
  30.              } else {
  31.                  char *tmpbuf = (char *) 0;
  32.                  int len;
  33.                  boolean ignoreline = FALSE;
  34.                  boolean oldline = FALSE;
  35.  
  36.                  *ep = '\0'; /* remove newline */
  37.  
  38.                  /* line continuation (trailing '\') */
  39.                  morelines = (--ep >= inbuf && *ep == '\\');
  40.                  if (morelines)
  41.                      *ep = '\0';
  42.  
  43.                  /* trim off spaces at end of line */
  44.                  while (--ep >= inbuf && (*ep == ' ' || *ep == '\t' || *ep == '\r'))
  45.                      *ep = '\0';
  46.  
  47.                  if (!config_error_nextline(inbuf)) {
  48.                      rv = FALSE;
  49.                      if (buf)
  50.                          free(buf), buf = (char *) 0;
  51.                      break;
  52.                  }
  53.  
  54.                  ep = inbuf;
  55.                  while (*ep == ' ' || *ep == '\t') ep++;
  56.  
  57.                  /* lines beginning with '#' are comments. ignore empty lines. */
  58.                  if (!*ep || *ep == '#')
  59.                      ignoreline = TRUE;
  60.  
  61.                  if (buf)
  62.                      oldline = TRUE;
  63.  
  64.                  /* merge now read line with previous ones, if necessary */
  65.                  if (!ignoreline) {
  66.                      len = strlen(inbuf) + 1;
  67.                      if (buf)
  68.                          len += strlen(buf);
  69.                      tmpbuf = (char *) alloc(len);
  70.                      if (buf) {
  71.                          Sprintf(tmpbuf, "%s %s", buf, inbuf);
  72.                          free(buf);
  73.                      } else
  74.                          Strcpy(tmpbuf, inbuf);
  75.                      buf = tmpbuf;
  76.                  }
  77.  
  78.                  if (morelines || (ignoreline && !oldline))
  79.                      continue;
  80.  
  81.                  if (handle_config_section(ep)) {
  82.                      free(buf);
  83.                      buf = (char *) 0;
  84.                      continue;
  85.                  }
  86.  
  87.                  /* from here onwards, we'll handle buf only */
  88.  
  89.                  if (match_varname(buf, "CHOOSE", 6)) {
  90.                      char *section;
  91.                      char *bufp = find_optparam(buf);
  92.                      if (!bufp) {
  93.                          config_error_add("Format is CHOOSE=section1,section2,...");
  94.                          rv = FALSE;
  95.                          free(buf);
  96.                          buf = (char *) 0;
  97.                          continue;
  98.                      }
  99.                      bufp++;
  100.                      if (config_section_chosen)
  101.                          free(config_section_chosen);
  102.                      section = choose_random_part(bufp, ',');
  103.                      if (section)
  104.                          config_section_chosen = dupstr(section);
  105.                      else {
  106.                          config_error_add("No config section to choose");
  107.                          rv = FALSE;
  108.                      }
  109.                      free(buf);
  110.                      buf = (char *) 0;
  111.                      continue;
  112.                  }
  113.  
  114.                  if (!proc(buf))
  115.                      rv = FALSE;
  116.  
  117.                  free(buf);
  118.                  buf = (char *) 0;
  119.              }
  120.          }
  121.      }
  122.  
  123.      if (buf)
  124.          free(buf);
  125.  
  126.      free_config_sections();
  127.      return rv;
  128.  }
  129.  
  130.  extern struct symsetentry *symset_list;  /* options.c */
  131.  extern struct symparse loadsyms[];       /* drawing.c */
  132.  extern const char *known_handling[];     /* drawing.c */
  133.  extern const char *known_restrictions[]; /* drawing.c */
  134.  static int symset_count = 0;             /* for pick-list building only */
  135.  static boolean chosen_symset_start = FALSE, chosen_symset_end = FALSE;
  136.  static int symset_which_set = 0;
  137.  

fopen_sym_file

  1.  STATIC_OVL
  2.  FILE *
  3.  fopen_sym_file()
  4.  {
  5.      FILE *fp;
  6.  
  7.      fp = fopen_datafile(SYMBOLS, "r", HACKPREFIX);
  8.      return fp;
  9.  }
  10.  

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.      FILE *fp;
  10.  
  11.      if (!(fp = fopen_sym_file()))
  12.          return 0;
  13.  
  14.      symset_count = 0;
  15.      chosen_symset_start = chosen_symset_end = FALSE;
  16.      symset_which_set = which_set;
  17.  
  18.      config_error_init(TRUE, "symbols", FALSE);
  19.  
  20.      parse_conf_file(fp, proc_symset_line);
  21.      (void) fclose(fp);
  22.  
  23.      if (!chosen_symset_start && !chosen_symset_end) {
  24.          /* name caller put in symset[which_set].name was not found;
  25.             if it looks like "Default symbols", null it out and return
  26.             success to use the default; otherwise, return failure */
  27.          if (symset[which_set].name
  28.              && (fuzzymatch(symset[which_set].name, "Default symbols",
  29.                             " -_", TRUE)
  30.                  || !strcmpi(symset[which_set].name, "default")))
  31.              clear_symsetentry(which_set, TRUE);
  32.          config_error_done();
  33.          return (symset[which_set].name == 0) ? 1 : 0;
  34.      }
  35.      if (!chosen_symset_end)
  36.          config_error_add("Missing finish for symset \"%s\"",
  37.                     symset[which_set].name ? symset[which_set].name
  38.                                            : "unknown");
  39.  
  40.      config_error_done();
  41.  
  42.      return 1;
  43.  }
  44.  

proc_symset_line

  1.  boolean
  2.  proc_symset_line(buf)
  3.  char *buf;
  4.  {
  5.      return !((boolean) parse_sym_line(buf, symset_which_set));
  6.  }
  7.  

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

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.  
  20.  /* ----------  BEGIN SCOREBOARD CREATION ----------- */
  21.  
  22.  #ifdef OS2_CODEVIEW
  23.  #define UNUSED_if_not_OS2_CODEVIEW /*empty*/
  24.  #else
  25.  #define UNUSED_if_not_OS2_CODEVIEW UNUSED
  26.  #endif
  27.  

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.  #ifdef WIN32
  55.      /* If dir is NULL it indicates create but
  56.         only if it doesn't already exist */
  57.      if (!dir) {
  58.          char buf[BUFSZ];
  59.  
  60.          buf[0] = '\0';
  61.          fd = open(fq_record, O_RDWR);
  62.          if (!(fd == -1 && errno == ENOENT)) {
  63.              if (fd >= 0) {
  64.                  (void) nhclose(fd);
  65.              } else {
  66.                  /* explanation for failure other than missing file */
  67.                  Sprintf(buf, "error   \"%s\", (errno %d).",
  68.                          fq_record, errno);
  69.                  paniclog("scorefile", buf);
  70.              }
  71.              return;
  72.          }
  73.          Sprintf(buf, "missing \"%s\", creating new scorefile.",
  74.                  fq_record);
  75.          paniclog("scorefile", buf);
  76.      }
  77.  #endif
  78.  
  79.      if ((fd = open(fq_record, O_RDWR)) < 0) {
  80.          /* try to create empty 'record' */
  81.  #if defined(AZTEC_C) || defined(_DCC) \
  82.      || (defined(__GNUC__) && defined(__AMIGA__))
  83.          /* Aztec doesn't use the third argument */
  84.          /* DICE doesn't like it */
  85.          fd = open(fq_record, O_CREAT | O_RDWR);
  86.  #else
  87.          fd = open(fq_record, O_CREAT | O_RDWR, S_IREAD | S_IWRITE);
  88.  #endif
  89.          if (fd <= 0) {
  90.              raw_printf("Warning: cannot write record '%s'", tmp);
  91.              wait_synch();
  92.          } else {
  93.              (void) nhclose(fd);
  94.          }
  95.      } else {
  96.          /* open succeeded => 'record' exists */
  97.          (void) nhclose(fd);
  98.      }
  99.  #else /* MICRO || WIN32*/
  100.  
  101.  #ifdef MAC
  102.      /* Create the "record" file, if necessary */
  103.      fq_record = fqname(RECORD, SCOREPREFIX, 0);
  104.      fd = macopen(fq_record, O_RDWR | O_CREAT, TEXT_TYPE);
  105.      if (fd != -1)
  106.          macclose(fd);
  107.  #endif /* MAC */
  108.  
  109.  #endif /* MICRO || WIN32*/
  110.  }
  111.  
  112.  /* ----------  END SCOREBOARD CREATION ----------- */
  113.  
  114.  /* ----------  BEGIN PANIC/IMPOSSIBLE LOG ----------- */
  115.  
  116.  /*ARGSUSED*/

paniclog

  1.  void
  2.  paniclog(type, reason)
  3.  const char *type;   /* panic, impossible, trickery */
  4.  const char *reason; /* explanation */
  5.  {
  6.  #ifdef PANICLOG
  7.      FILE *lfile;
  8.      char buf[BUFSZ];
  9.  
  10.      if (!program_state.in_paniclog) {
  11.          program_state.in_paniclog = 1;
  12.          lfile = fopen_datafile(PANICLOG, "a", TROUBLEPREFIX);
  13.          if (lfile) {
  14.  #ifdef PANICLOG_FMT2
  15.              (void) fprintf(lfile, "%ld %s: %s %s\n",
  16.                             ubirthday, (plname ? plname : "(none)"),
  17.                             type, reason);
  18.  #else
  19.              time_t now = getnow();
  20.              int uid = getuid();
  21.              char playmode = wizard ? 'D' : discover ? 'X' : '-';
  22.  
  23.              (void) fprintf(lfile, "%s %08ld %06ld %d %c: %s %s\n",
  24.                             version_string(buf), yyyymmdd(now), hhmmss(now),
  25.                             uid, playmode, type, reason);
  26.  #endif /* !PANICLOG_FMT2 */
  27.              (void) fclose(lfile);
  28.          }
  29.          program_state.in_paniclog = 0;
  30.      }
  31.  #endif /* PANICLOG */
  32.      return;
  33.  }
  34.  
  35.  /* ----------  END PANIC/IMPOSSIBLE LOG ----------- */
  36.  
  37.  #ifdef SELF_RECOVER
  38.  
  39.  /* ----------  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.          (void) nhclose(lfd);
  88.          delete_savefile();
  89.          return FALSE;
  90.      }
  91.  
  92.      if (write(sfd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi) {
  93.          raw_printf("\nError writing %s; recovery failed (savefile_info).\n",
  94.                     SAVEF);
  95.          (void) nhclose(gfd);
  96.          (void) nhclose(sfd);
  97.          (void) nhclose(lfd);
  98.          delete_savefile();
  99.          return FALSE;
  100.      }
  101.  
  102.      if (write(sfd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz)
  103.          != sizeof pltmpsiz) {
  104.          raw_printf("Error writing %s; recovery failed (player name size).\n",
  105.                     SAVEF);
  106.          (void) nhclose(gfd);
  107.          (void) nhclose(sfd);
  108.          (void) nhclose(lfd);
  109.          delete_savefile();
  110.          return FALSE;
  111.      }
  112.  
  113.      if (write(sfd, (genericptr_t) &tmpplbuf, pltmpsiz) != pltmpsiz) {
  114.          raw_printf("Error writing %s; recovery failed (player name).\n",
  115.                     SAVEF);
  116.          (void) nhclose(gfd);
  117.          (void) nhclose(sfd);
  118.          (void) nhclose(lfd);
  119.          delete_savefile();
  120.          return FALSE;
  121.      }
  122.  
  123.      if (!copy_bytes(lfd, sfd)) {
  124.          (void) nhclose(gfd);
  125.          (void) nhclose(sfd);
  126.          (void) nhclose(lfd);
  127.          delete_savefile();
  128.          return FALSE;
  129.      }
  130.      (void) nhclose(lfd);
  131.      processed[savelev] = 1;
  132.  
  133.      if (!copy_bytes(gfd, sfd)) {
  134.          (void) nhclose(gfd);
  135.          (void) nhclose(sfd);
  136.          delete_savefile();
  137.          return FALSE;
  138.      }
  139.      (void) nhclose(gfd);
  140.      processed[0] = 1;
  141.  
  142.      for (lev = 1; lev < 256; lev++) {
  143.          /* level numbers are kept in xchars in save.c, so the
  144.           * maximum level number (for the endlevel) must be < 256
  145.           */
  146.          if (lev != savelev) {
  147.              lfd = open_levelfile(lev, (char *) 0);
  148.              if (lfd >= 0) {
  149.                  /* any or all of these may not exist */
  150.                  levc = (xchar) lev;
  151.                  write(sfd, (genericptr_t) &levc, sizeof(levc));
  152.                  if (!copy_bytes(lfd, sfd)) {
  153.                      (void) nhclose(lfd);
  154.                      (void) nhclose(sfd);
  155.                      delete_savefile();
  156.                      return FALSE;
  157.                  }
  158.                  (void) nhclose(lfd);
  159.                  processed[lev] = 1;
  160.              }
  161.          }
  162.      }
  163.      (void) nhclose(sfd);
  164.  
  165.  #ifdef HOLD_LOCKFILE_OPEN
  166.      really_close();
  167.  #endif
  168.      /*
  169.       * We have a successful savefile!
  170.       * Only now do we erase the level files.
  171.       */
  172.      for (lev = 0; lev < 256; lev++) {
  173.          if (processed[lev]) {
  174.              const char *fq_lock;
  175.  
  176.              set_levelfile_name(lock, lev);
  177.              fq_lock = fqname(lock, LEVELPREFIX, 3);
  178.              (void) unlink(fq_lock);
  179.          }
  180.      }
  181.      return TRUE;
  182.  }
  183.  

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.  
  20.  /* ----------  OTHER ----------- */
  21.  
  22.  #ifdef SYSCF
  23.  #ifdef SYSCF_FILE

assure_syscf_file

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

debugcore

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

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 */
  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.  
  13.      /* if a different book or we've used up all the passages already,
  14.         reset in order to have all 'passagecnt' passages available */
  15.      if (oid != context.novel.id || context.novel.count == 0) {
  16.          int i, range = passagecnt, limit = MAXPASSAGES;
  17.  
  18.          context.novel.id = oid;
  19.          if (range <= limit) {
  20.              /* collect all of the N indices */
  21.              context.novel.count = passagecnt;
  22.              for (idx = 0; idx < MAXPASSAGES; idx++)
  23.                  context.novel.pasg[idx] = (xchar) ((idx < passagecnt)
  24.                                                     ? idx + 1 : 0);
  25.          } else {
  26.              /* collect MAXPASSAGES of the N indices */
  27.              context.novel.count = MAXPASSAGES;
  28.              for (idx = i = 0; i < passagecnt; ++i, --range)
  29.                  if (range > 0 && rn2(range) < limit) {
  30.                      context.novel.pasg[idx++] = (xchar) (i + 1);
  31.                      --limit;
  32.                  }
  33.          }
  34.      }
  35.  
  36.      idx = rn2(context.novel.count);
  37.      res = (int) context.novel.pasg[idx];
  38.      /* move the last slot's passage index into the slot just used
  39.         and reduce the number of passages available */
  40.      context.novel.pasg[idx] = context.novel.pasg[--context.novel.count];
  41.      return res;
  42.  }
  43.  

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

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