diff --git a/include/decl.h b/include/decl.h index b201816f3..db9042445 100644 --- a/include/decl.h +++ b/include/decl.h @@ -258,7 +258,7 @@ struct instance_globals_c { /* symbols.c */ int currentgraphics; - /* files.c */ + /* files.c, cfgfiles.c */ char *cmdline_rcfile; /* set in unixmain.c, used in options.c */ char *config_section_chosen; char *config_section_current; diff --git a/include/extern.h b/include/extern.h index 5886eb0c0..d4f1e549d 100644 --- a/include/extern.h +++ b/include/extern.h @@ -310,6 +310,28 @@ extern boolean friday_13th(void); extern int night(void); extern int midnight(void); +/* ### cfgfiles.c ### */ + +#if !defined(CROSSCOMPILE) || defined(CROSSCOMPILE_TARGET) +extern int l_get_config_errors(lua_State *) NONNULLARG1; +#endif +extern int do_write_config_file(void); +extern boolean parse_config_line(char *) NONNULLARG1; +#ifdef USER_SOUNDS +extern boolean can_read_file(const char *) NONNULLARG1; +#endif +extern void config_error_init(boolean, const char *, boolean); +extern void config_erradd(const char *); +extern int config_error_done(void); +/* arg1 of read_config_file can be NULL to pass through + * to fopen_config_file() to mean 'use the default config file name' */ +extern boolean read_config_file(const char *, int); +extern boolean parse_conf_str(const char *str, boolean (*proc)(char *)); +extern boolean parse_conf_file(FILE *fp, boolean (*proc)(char *arg)); +extern void set_configfile_name(const char *); +extern char *get_configfile(void); +extern const char *get_default_configfile(void); + /* ### coloratt.c ### */ extern char *color_attr_to_str(color_attr *); @@ -1009,9 +1031,6 @@ extern void makerogueghost(void); /* ### files.c ### */ extern const char *nh_basename(const char *, boolean) NONNULLARG1; -#if !defined(CROSSCOMPILE) || defined(CROSSCOMPILE_TARGET) -extern int l_get_config_errors(lua_State *) NONNULLARG1; -#endif extern char *fname_encode(const char *, char, char *, char *, int) NONNULLPTRS; extern char *fname_decode(char, char *, char *, int) NONNULLPTRS; @@ -1051,20 +1070,8 @@ extern void nh_compress(const char *); extern void nh_uncompress(const char *); extern boolean lock_file(const char *, int, int) NONNULLARG1; extern void unlock_file(const char *) NONNULLARG1; -extern int do_write_config_file(void); -extern boolean parse_config_line(char *) NONNULLARG1; -#ifdef USER_SOUNDS -extern boolean can_read_file(const char *) NONNULLARG1; -#endif -extern void config_error_init(boolean, const char *, boolean); -extern void config_erradd(const char *); -extern int config_error_done(void); -/* arg1 of read_config_file can be NULL to pass through - * to fopen_config_file() to mean 'use the default config file name' */ -extern boolean read_config_file(const char *, int); extern void check_recordfile(const char *); extern void read_wizkit(void); -extern boolean parse_conf_str(const char *str, boolean (*proc)(char *)); extern int read_sym_file(int); extern void paniclog(const char *, const char *) NONNULLPTRS; extern void testinglog(const char *, const char *, const char *); diff --git a/src/cfgfiles.c b/src/cfgfiles.c new file mode 100644 index 000000000..bf48bf9f6 --- /dev/null +++ b/src/cfgfiles.c @@ -0,0 +1,1859 @@ +/* NetHack 3.7 cfgfiles.c $NHDT-Date: 1740532826 2025/02/25 17:20:26 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.417 $ */ +/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ +/*-Copyright (c) Derek S. Ray, 2015. */ +/* NetHack may be freely redistributed. See license for details. */ + +#define NEED_VARARGS + +#include "hack.h" +#include "dlb.h" +#include + +#ifdef USER_SOUNDS +extern char *sounddir; /* defined in sounds.c */ +#endif + +staticfn FILE *fopen_config_file(const char *, int); +staticfn int get_uchars(char *, uchar *, boolean, int, const char *); +#ifdef NOCWD_ASSUMPTIONS +staticfn void adjust_prefix(char *, int); +#endif +staticfn char *choose_random_part(char *, char); +staticfn boolean config_error_nextline(const char *); +staticfn void free_config_sections(void); +staticfn char *is_config_section(char *); +staticfn boolean handle_config_section(char *); +boolean parse_config_line(char *); +staticfn char *find_optparam(const char *); +staticfn boolean cnf_line_OPTIONS(char *); +staticfn boolean cnf_line_AUTOPICKUP_EXCEPTION(char *); +staticfn boolean cnf_line_BINDINGS(char *); +staticfn boolean cnf_line_AUTOCOMPLETE(char *); +staticfn boolean cnf_line_MSGTYPE(char *); +staticfn boolean cnf_line_HACKDIR(char *); +staticfn boolean cnf_line_LEVELDIR(char *); +staticfn boolean cnf_line_SAVEDIR(char *); +staticfn boolean cnf_line_BONESDIR(char *); +staticfn boolean cnf_line_DATADIR(char *); +staticfn boolean cnf_line_SCOREDIR(char *); +staticfn boolean cnf_line_LOCKDIR(char *); +staticfn boolean cnf_line_CONFIGDIR(char *); +staticfn boolean cnf_line_TROUBLEDIR(char *); +staticfn boolean cnf_line_NAME(char *); +staticfn boolean cnf_line_ROLE(char *); +staticfn boolean cnf_line_dogname(char *); +staticfn boolean cnf_line_catname(char *); +#ifdef SYSCF +staticfn boolean cnf_line_WIZARDS(char *); +staticfn boolean cnf_line_SHELLERS(char *); +staticfn boolean cnf_line_MSGHANDLER(char *); +staticfn boolean cnf_line_EXPLORERS(char *); +staticfn boolean cnf_line_DEBUGFILES(char *); +staticfn boolean cnf_line_DUMPLOGFILE(char *); +staticfn boolean cnf_line_GENERICUSERS(char *); +staticfn boolean cnf_line_BONES_POOLS(char *); +staticfn boolean cnf_line_SUPPORT(char *); +staticfn boolean cnf_line_RECOVER(char *); +staticfn boolean cnf_line_CHECK_SAVE_UID(char *); +staticfn boolean cnf_line_CHECK_PLNAME(char *); +staticfn boolean cnf_line_SEDUCE(char *); +staticfn boolean cnf_line_HIDEUSAGE(char *); +staticfn boolean cnf_line_MAXPLAYERS(char *); +staticfn boolean cnf_line_PERSMAX(char *); +staticfn boolean cnf_line_PERS_IS_UID(char *); +staticfn boolean cnf_line_ENTRYMAX(char *); +staticfn boolean cnf_line_POINTSMIN(char *); +staticfn boolean cnf_line_MAX_STATUENAME_RANK(char *); +staticfn boolean cnf_line_LIVELOG(char *); +staticfn boolean cnf_line_PANICTRACE_LIBC(char *); +staticfn boolean cnf_line_PANICTRACE_GDB(char *); +staticfn boolean cnf_line_GDBPATH(char *); +staticfn boolean cnf_line_GREPPATH(char *); +staticfn boolean cnf_line_CRASHREPORTURL(char *); +staticfn boolean cnf_line_SAVEFORMAT(char *); +staticfn boolean cnf_line_BONESFORMAT(char *); +staticfn boolean cnf_line_ACCESSIBILITY(char *); +staticfn boolean cnf_line_PORTABLE_DEVICE_PATHS(char *); +staticfn void parseformat(int *, char *); +#endif /* SYSCF */ +staticfn boolean cnf_line_BOULDER(char *); +staticfn boolean cnf_line_MENUCOLOR(char *); +staticfn boolean cnf_line_HILITE_STATUS(char *); +staticfn boolean cnf_line_WARNINGS(char *); +staticfn boolean cnf_line_ROGUESYMBOLS(char *); +staticfn boolean cnf_line_SYMBOLS(char *); +staticfn boolean cnf_line_WIZKIT(char *); +#ifdef USER_SOUNDS +staticfn boolean cnf_line_SOUNDDIR(char *); +staticfn boolean cnf_line_SOUND(char *); +#endif +staticfn boolean cnf_line_QT_TILEWIDTH(char *); +staticfn boolean cnf_line_QT_TILEHEIGHT(char *); +staticfn boolean cnf_line_QT_FONTSIZE(char *); +staticfn boolean cnf_line_QT_COMPACT(char *); +struct _cnf_parser_state; /* defined below (far below...) */ +staticfn void cnf_parser_init(struct _cnf_parser_state *parser); +staticfn void cnf_parser_done(struct _cnf_parser_state *parser); +staticfn void parse_conf_buf(struct _cnf_parser_state *parser, + boolean (*proc)(char *arg)); +/* next one is in extern.h; why here too? */ +boolean parse_conf_str(const char *str, boolean (*proc)(char *arg)); + +/* ---------- BEGIN CONFIG FILE HANDLING ----------- */ + +/* used for messaging. Also used in options.c */ +static const char *default_configfile = +#ifdef UNIX + ".nethackrc"; +#else +#if defined(MAC) || defined(__BEOS__) + "NetHack Defaults"; +#else +#if defined(MSDOS) || defined(WIN32) + CONFIG_FILE; +#else + "NetHack.cnf"; +#endif +#endif +#endif +static char configfile[BUFSZ]; + +char * +get_configfile(void) +{ + return configfile; +} + +const char * +get_default_configfile(void) +{ + return default_configfile; +} + +#ifdef MSDOS +/* conflict with speed-dial under windows + * for XXX.cnf file so support of NetHack.cnf + * is for backward compatibility only. + * Preferred name (and first tried) is now defaults.nh but + * the game will try the old name if there + * is no defaults.nh. + */ +const char *backward_compat_configfile = "nethack.cnf"; +#endif + +/* #saveoptions - save config options into file */ +int +do_write_config_file(void) +{ + FILE *fp; + char tmp[BUFSZ]; + + if (!configfile[0]) { + pline("Strange, could not figure out config file name."); + return ECMD_OK; + } + if (flags.suppress_alert < FEATURE_NOTICE_VER(3,7,0)) { + pline("Warning: saveoptions is highly experimental!"); + wait_synch(); + pline("Some settings are not saved!"); + wait_synch(); + pline("All manual customization and comments are removed" + " from the file!"); + wait_synch(); + } +#define overwrite_prompt "Overwrite config file %.*s?" + Sprintf(tmp, overwrite_prompt, + (int) (BUFSZ - sizeof overwrite_prompt - 2), configfile); +#undef overwrite_prompt + if (!paranoid_query(TRUE, tmp)) + return ECMD_OK; + + fp = fopen(configfile, "w"); + if (fp) { + size_t len, wrote; + strbuf_t buf; + + strbuf_init(&buf); + all_options_strbuf(&buf); + len = strlen(buf.str); + wrote = fwrite(buf.str, 1, len, fp); + fclose(fp); + strbuf_empty(&buf); + if (wrote != len) + pline("An error occurred, wrote only partial data (%zu/%zu).", + wrote, len); + } + return ECMD_OK; +} + +/* remember the name of the file we're accessing; + if may be used in option reject messages */ +void +set_configfile_name(const char *fname) +{ + (void) strncpy(configfile, fname, sizeof configfile - 1); + configfile[sizeof configfile - 1] = '\0'; +} + +staticfn FILE * +fopen_config_file(const char *filename, int src) +{ + FILE *fp; +#if defined(UNIX) || defined(VMS) + char tmp_config[BUFSZ]; + char *envp; +#endif + + if (src == set_in_sysconf) { + /* SYSCF_FILE; if we can't open it, caller will bail */ + if (filename && *filename) { + set_configfile_name(fqname(filename, SYSCONFPREFIX, 0)); + fp = fopen(configfile, "r"); + } else + fp = (FILE *) 0; + return fp; + } + /* If src != set_in_sysconf, "filename" is an environment variable, so it + * should hang around. If set, it is expected to be a full path name + * (if relevant) + */ + if (filename && *filename) { + set_configfile_name(filename); +#ifdef UNIX + if (access(configfile, 4) == -1) { /* 4 is R_OK on newer systems */ + /* nasty sneaky attempt to read file through + * NetHack's setuid permissions -- this is the only + * place a file name may be wholly under the player's + * control (but SYSCF_FILE is not under the player's + * control so it's OK). + */ + raw_printf("Access to %s denied (%d).", configfile, errno); + wait_synch(); + /* fall through to standard names */ + } else +#endif + if ((fp = fopen(configfile, "r")) != (FILE *) 0) { + return fp; +#if defined(UNIX) || defined(VMS) + } else { + /* access() above probably caught most problems for UNIX */ + raw_printf("Couldn't open requested config file %s (%d).", + configfile, errno); + wait_synch(); +#endif + } + } + /* fall through to standard names */ + +#if defined(MICRO) || defined(MAC) || defined(__BEOS__) || defined(WIN32) + set_configfile_name(fqname(default_configfile, CONFIGPREFIX, 0)); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) { + return fp; + } else if (strcmp(default_configfile, configfile)) { + set_configfile_name(default_configfile); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) + return fp; + } +#ifdef MSDOS + set_configfile_name(fqname(backward_compat_configfile, CONFIGPREFIX, 0)); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) { + return fp; + } else if (strcmp(backward_compat_configfile, configfile)) { + set_configfile_name(backward_compat_configfile); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) + return fp; + } +#endif +#else +/* constructed full path names don't need fqname() */ +#ifdef VMS + /* no punctuation, so might be a logical name */ + set_configfile_name("nethackini"); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) + return fp; + set_configfile_name("sys$login:nethack.ini"); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) + return fp; + + envp = nh_getenv("HOME"); + if (!envp || !*envp) + Strcpy(tmp_config, "NetHack.cnf"); + else + Sprintf(tmp_config, "%s%s%s", envp, + !strchr(":]>/", envp[strlen(envp) - 1]) ? "/" : "", + "NetHack.cnf"); + set_configfile_name(tmp_config); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) + return fp; +#else /* should be only UNIX left */ + envp = nh_getenv("HOME"); + if (!envp) + Strcpy(tmp_config, ".nethackrc"); + else + Sprintf(tmp_config, "%s/%s", envp, ".nethackrc"); + + set_configfile_name(tmp_config); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) + return fp; +#if defined(__APPLE__) /* UNIX+__APPLE__ => OSX || MacOS */ + /* try an alternative */ + if (envp) { + /* keep 'tmp_config' intact here; if alternates fail, use it to + restore configfile[] to its preferred setting (".nethackrc") */ + char alt_config[sizeof tmp_config]; + + /* OSX-style configuration settings */ + Snprintf(alt_config, sizeof alt_config, "%s/%s", envp, + "Library/Preferences/NetHack Defaults"); + set_configfile_name(alt_config); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) + return fp; + /* may be easier for user to edit if filename has '.txt' suffix */ + Snprintf(alt_config, sizeof alt_config, "%s/%s", envp, + "Library/Preferences/NetHack Defaults.txt"); + set_configfile_name(alt_config); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) + return fp; + /* couldn't open either of the alternate names; for use in + messages, put 'configfile' back to the normal value rather than + leaving it set to last alternate; retry open() to reset 'errno' */ + set_configfile_name(tmp_config); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) + return fp; + } +#endif /*__APPLE__*/ + if (errno != ENOENT) { + const char *details; + + /* e.g., problems when setuid NetHack can't search home + directory restricted to user */ +#if defined(NHSTDC) && !defined(NOTSTDC) + if ((details = strerror(errno)) == 0) +#endif + details = ""; + raw_printf("Couldn't open default config file %s %s(%d).", + configfile, details, errno); + wait_synch(); + } +#endif /* !VMS => Unix */ +#endif /* !(MICRO || MAC || __BEOS__ || WIN32) */ + return (FILE *) 0; +} + +/* + * Retrieve a list of integers from buf into a uchar array. + * + * NOTE: zeros are inserted unless modlist is TRUE, in which case the list + * location is unchanged. Callers must handle zeros if modlist is FALSE. + */ +staticfn int +get_uchars(char *bufp, /* current pointer */ + uchar *list, /* return list */ + boolean modlist, /* TRUE: list is being modified in place */ + int size, /* return list size */ + const char *name) /* name of option for error message */ +{ + unsigned int num = 0; + int count = 0; + boolean havenum = FALSE; + + while (1) { + switch (*bufp) { + case ' ': + case '\0': + case '\t': + case '\n': + if (havenum) { + /* if modifying in place, don't insert zeros */ + if (num || !modlist) + list[count] = num; + count++; + num = 0; + havenum = FALSE; + } + if (count == size || !*bufp) + return count; + bufp++; + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + havenum = TRUE; + num = num * 10 + (*bufp - '0'); + bufp++; + break; + + case '\\': + goto gi_error; + break; + + default: + gi_error: + raw_printf("Syntax error in %s", name); + wait_synch(); + return count; + } + } + /*NOTREACHED*/ +} + +#ifdef NOCWD_ASSUMPTIONS +staticfn void +adjust_prefix(char *bufp, int prefixid) +{ + char *ptr; + + if (!bufp) + return; +#ifdef WIN32 + if (fqn_prefix_locked[prefixid]) + return; +#endif + /* Backward compatibility, ignore trailing ;n */ + if ((ptr = strchr(bufp, ';')) != 0) + *ptr = '\0'; + if (strlen(bufp) > 0) { + gf.fqn_prefix[prefixid] = (char *) alloc(strlen(bufp) + 2); + Strcpy(gf.fqn_prefix[prefixid], bufp); + append_slash(gf.fqn_prefix[prefixid]); + } +} +#endif + +/* Choose at random one of the sep separated parts from str. Mangles str. */ +staticfn char * +choose_random_part(char *str, char sep) +{ + int nsep = 1; + int csep; + int len = 0; + char *begin = str; + + if (!str) + return (char *) 0; + + while (*str) { + if (*str == sep) + nsep++; + str++; + } + csep = rn2(nsep); + str = begin; + while ((csep > 0) && *str) { + str++; + if (*str == sep) + csep--; + } + if (*str) { + if (*str == sep) + str++; + begin = str; + while (*str && *str != sep) { + str++; + len++; + } + *str = '\0'; + if (len) + return begin; + } + return (char *) 0; +} + +staticfn void +free_config_sections(void) +{ + if (gc.config_section_chosen) { + free(gc.config_section_chosen); + gc.config_section_chosen = NULL; + } + if (gc.config_section_current) { + free(gc.config_section_current); + gc.config_section_current = NULL; + } +} + +/* check for " [ anything-except-bracket-or-empty ] # arbitrary-comment" + with spaces optional; returns pointer to "anything-except..." (with + trailing " ] #..." stripped) if ok, otherwise Null */ +staticfn char * +is_config_section( + char *str) /* trailing spaces are stripped, ']' too iff result is good */ +{ + char *a, *c, *z; + + /* remove any spaces at start and end; won't significantly interfere + with echoing the string in a config error message, if warranted */ + a = trimspaces(str); + /* first character should be open square bracket; set pointer past it */ + if (*a++ != '[') + return (char *) 0; + /* last character should be close bracket, ignoring any comment */ + z = strchr(a, ']'); + if (!z) + return (char *) 0; + /* comment, if present, can be preceded by spaces */ + for (c = z + 1; *c == ' '; ++c) + continue; + if (*c && *c != '#') + return (char *) 0; + /* we now know that result is good; there won't be a config error + message so we can modify the input string */ + *z = '\0'; + /* 'a' points past '[' and the string ends where ']' was; remove any + spaces between '[' and choice-start and between choice-end and ']' */ + return trimspaces(a); +} + +staticfn boolean +handle_config_section(char *buf) +{ + char *sect = is_config_section(buf); + + if (sect) { + if (gc.config_section_current) + free(gc.config_section_current), gc.config_section_current = 0; + /* is_config_section() removed brackets from 'sect' */ + if (!gc.config_section_chosen) { + config_error_add("Section \"[%s]\" without CHOOSE", sect); + return TRUE; + } + if (*sect) { /* got a section name */ + gc.config_section_current = dupstr(sect); + debugpline1("set config section: '%s'", + gc.config_section_current); + } else { /* empty section name => end of sections */ + free_config_sections(); + debugpline0("unset config section"); + } + return TRUE; + } + + if (gc.config_section_current) { + if (!gc.config_section_chosen) + return TRUE; + if (strcmp(gc.config_section_current, gc.config_section_chosen)) + return TRUE; + } + return FALSE; +} + +#define match_varname(INP, NAM, LEN) match_optname(INP, NAM, LEN, TRUE) + +/* find the '=' or ':' */ +staticfn char * +find_optparam(const char *buf) +{ + char *bufp, *altp; + + bufp = strchr(buf, '='); + altp = strchr(buf, ':'); + if (!bufp || (altp && altp < bufp)) + bufp = altp; + + return bufp; +} + +staticfn boolean +cnf_line_OPTIONS(char *origbuf) +{ + char *bufp = find_optparam(origbuf); + + ++bufp; /* skip '='; parseoptions() handles spaces */ + return parseoptions(bufp, TRUE, TRUE); +} + +staticfn boolean +cnf_line_AUTOPICKUP_EXCEPTION(char *bufp) +{ + add_autopickup_exception(bufp); + return TRUE; +} + +staticfn boolean +cnf_line_BINDINGS(char *bufp) +{ + return parsebindings(bufp); +} + +staticfn boolean +cnf_line_AUTOCOMPLETE(char *bufp) +{ + parseautocomplete(bufp, TRUE); + return TRUE; +} + +staticfn boolean +cnf_line_MSGTYPE(char *bufp) +{ + return msgtype_parse_add(bufp); +} + +staticfn boolean +cnf_line_HACKDIR(char *bufp) +{ +#ifdef NOCWD_ASSUMPTIONS + adjust_prefix(bufp, HACKPREFIX); +#else /*NOCWD_ASSUMPTIONS*/ +#ifdef MICRO + (void) strncpy(gh.hackdir, bufp, PATHLEN - 1); +#else /* MICRO */ + nhUse(bufp); +#endif /* MICRO */ +#endif /*NOCWD_ASSUMPTIONS*/ + return TRUE; +} + +staticfn boolean +cnf_line_LEVELDIR(char *bufp) +{ +#ifdef NOCWD_ASSUMPTIONS + adjust_prefix(bufp, LEVELPREFIX); +#else /*NOCWD_ASSUMPTIONS*/ +#ifdef MICRO + if (strlen(bufp) >= PATHLEN) + bufp[PATHLEN - 1] = '\0'; + Strcpy(g.permbones, bufp); + if (!ramdisk_specified || !*levels) + Strcpy(levels, bufp); + gr.ramdisk = (strcmp(g.permbones, levels) != 0); +#else /* MICRO */ + nhUse(bufp); +#endif /* MICRO */ +#endif /*NOCWD_ASSUMPTIONS*/ + return TRUE; +} + +staticfn boolean +cnf_line_SAVEDIR(char *bufp) +{ +#ifdef NOCWD_ASSUMPTIONS + adjust_prefix(bufp, SAVEPREFIX); +#else /*NOCWD_ASSUMPTIONS*/ +#ifdef MICRO + char *ptr; + + if ((ptr = strchr(bufp, ';')) != 0) { + *ptr = '\0'; + } + + (void) strncpy(gs.SAVEP, bufp, SAVESIZE - 1); + append_slash(gs.SAVEP); +#else /* MICRO */ + nhUse(bufp); +#endif /* MICRO */ +#endif /*NOCWD_ASSUMPTIONS*/ + return TRUE; +} + +staticfn boolean +cnf_line_BONESDIR(char *bufp) +{ +#ifdef NOCWD_ASSUMPTIONS + adjust_prefix(bufp, BONESPREFIX); +#else + nhUse(bufp); +#endif + return TRUE; +} + +staticfn boolean +cnf_line_DATADIR(char *bufp) +{ +#ifdef NOCWD_ASSUMPTIONS + adjust_prefix(bufp, DATAPREFIX); +#else + nhUse(bufp); +#endif + return TRUE; +} + +staticfn boolean +cnf_line_SCOREDIR(char *bufp) +{ +#ifdef NOCWD_ASSUMPTIONS + adjust_prefix(bufp, SCOREPREFIX); +#else + nhUse(bufp); +#endif + return TRUE; +} + +staticfn boolean +cnf_line_LOCKDIR(char *bufp) +{ +#ifdef NOCWD_ASSUMPTIONS + adjust_prefix(bufp, LOCKPREFIX); +#else + nhUse(bufp); +#endif + return TRUE; +} + +staticfn boolean +cnf_line_CONFIGDIR(char *bufp) +{ +#ifdef NOCWD_ASSUMPTIONS + adjust_prefix(bufp, CONFIGPREFIX); +#else + nhUse(bufp); +#endif + return TRUE; +} + +staticfn boolean +cnf_line_TROUBLEDIR(char *bufp) +{ +#ifdef NOCWD_ASSUMPTIONS + adjust_prefix(bufp, TROUBLEPREFIX); +#else + nhUse(bufp); +#endif + return TRUE; +} + +staticfn boolean +cnf_line_NAME(char *bufp) +{ + (void) strncpy(svp.plname, bufp, PL_NSIZ - 1); + return TRUE; +} + +staticfn boolean +cnf_line_ROLE(char *bufp) +{ + int len; + + if ((len = str2role(bufp)) >= 0) + flags.initrole = len; + return TRUE; +} + +staticfn boolean +cnf_line_dogname(char *bufp) +{ + (void) strncpy(gd.dogname, bufp, PL_PSIZ - 1); + return TRUE; +} + +staticfn boolean +cnf_line_catname(char *bufp) +{ + (void) strncpy(gc.catname, bufp, PL_PSIZ - 1); + return TRUE; +} + +#ifdef SYSCF + +staticfn boolean +cnf_line_WIZARDS(char *bufp) +{ + if (sysopt.wizards) + free((genericptr_t) sysopt.wizards); + sysopt.wizards = dupstr(bufp); + if (strlen(sysopt.wizards) && strcmp(sysopt.wizards, "*")) { + /* pre-format WIZARDS list now; it's displayed during a panic + and since that panic might be due to running out of memory, + we don't want to risk attempting to allocate any memory then */ + if (sysopt.fmtd_wizard_list) + free((genericptr_t) sysopt.fmtd_wizard_list); + sysopt.fmtd_wizard_list = build_english_list(sysopt.wizards); + } + return TRUE; +} + +staticfn boolean +cnf_line_SHELLERS(char *bufp) +{ + if (sysopt.shellers) + free((genericptr_t) sysopt.shellers); + sysopt.shellers = dupstr(bufp); + return TRUE; +} + +staticfn boolean +cnf_line_MSGHANDLER(char *bufp) +{ + if (sysopt.msghandler) + free((genericptr_t) sysopt.msghandler); + sysopt.msghandler = dupstr(bufp); + return TRUE; +} + +staticfn boolean +cnf_line_EXPLORERS(char *bufp) +{ + if (sysopt.explorers) + free((genericptr_t) sysopt.explorers); + sysopt.explorers = dupstr(bufp); + return TRUE; +} + +staticfn boolean +cnf_line_DEBUGFILES(char *bufp) +{ + /* might already have a vaule from getenv("DEBUGFILES"); + if so, ignore this value from SYSCF */ + if (!sysopt.env_dbgfl) { + if (sysopt.debugfiles) + free((genericptr_t) sysopt.debugfiles); + sysopt.debugfiles = dupstr(bufp); + } + return TRUE; +} + +staticfn boolean +cnf_line_DUMPLOGFILE(char *bufp) +{ +#ifdef DUMPLOG + if (sysopt.dumplogfile) + free((genericptr_t) sysopt.dumplogfile); + sysopt.dumplogfile = dupstr(bufp); +#else + nhUse(bufp); +#endif /*DUMPLOG*/ + return TRUE; +} + +staticfn boolean +cnf_line_GENERICUSERS(char *bufp) +{ + if (sysopt.genericusers) + free((genericptr_t) sysopt.genericusers); + sysopt.genericusers = dupstr(bufp); + return TRUE; +} + +staticfn boolean +cnf_line_BONES_POOLS(char *bufp) +{ + /* max value of 10 guarantees (N % bones.pools) will be one digit + so we don't lose control of the length of bones file names */ + int n = atoi(bufp); + + sysopt.bones_pools = (n <= 0) ? 0 : min(n, 10); + /* note: right now bones_pools==0 is the same as bones_pools==1, + but we could change that and make bones_pools==0 become an + indicator to suppress bones usage altogether */ + return TRUE; +} + +staticfn boolean +cnf_line_SUPPORT(char *bufp) +{ + if (sysopt.support) + free((genericptr_t) sysopt.support); + sysopt.support = dupstr(bufp); + return TRUE; +} + +staticfn boolean +cnf_line_RECOVER(char *bufp) +{ + if (sysopt.recover) + free((genericptr_t) sysopt.recover); + sysopt.recover = dupstr(bufp); + return TRUE; +} + +staticfn boolean +cnf_line_CHECK_SAVE_UID(char *bufp) +{ + int n = atoi(bufp); + + sysopt.check_save_uid = n; + return TRUE; +} + +staticfn boolean +cnf_line_CHECK_PLNAME(char *bufp) +{ + int n = atoi(bufp); + + sysopt.check_plname = n; + return TRUE; +} + +staticfn boolean +cnf_line_SEDUCE(char *bufp) +{ + int n = !!atoi(bufp); /* XXX this could be tighter */ +#ifdef SYSCF + int src = iflags.parse_config_file_src; + boolean in_sysconf = (src == set_in_sysconf); +#else + boolean in_sysconf = FALSE; +#endif + + /* allow anyone to disable it but can only enable it in sysconf + or as a no-op for the user when sysconf hasn't disabled it */ + if (!in_sysconf && !sysopt.seduce && n != 0) { + config_error_add("Illegal value in SEDUCE"); + n = 0; + } + sysopt.seduce = n; + sysopt_seduce_set(sysopt.seduce); + return TRUE; +} + +staticfn boolean +cnf_line_HIDEUSAGE(char *bufp) +{ + int n = !!atoi(bufp); + + sysopt.hideusage = n; + return TRUE; +} + +staticfn boolean +cnf_line_MAXPLAYERS(char *bufp) +{ + int n = atoi(bufp); + + /* XXX to get more than 25, need to rewrite all lock code */ + if (n < 0 || n > 25) { + config_error_add("Illegal value in MAXPLAYERS (maximum is 25)"); + n = 5; + } + sysopt.maxplayers = n; + return TRUE; +} + +staticfn boolean +cnf_line_PERSMAX(char *bufp) +{ + int n = atoi(bufp); + + if (n < 1) { + config_error_add("Illegal value in PERSMAX (minimum is 1)"); + n = 0; + } + sysopt.persmax = n; + return TRUE; +} + +staticfn boolean +cnf_line_PERS_IS_UID(char *bufp) +{ + int n = atoi(bufp); + + if (n != 0 && n != 1) { + config_error_add("Illegal value in PERS_IS_UID (must be 0 or 1)"); + n = 0; + } + sysopt.pers_is_uid = n; + return TRUE; +} + +staticfn boolean +cnf_line_ENTRYMAX(char *bufp) +{ + int n = atoi(bufp); + + if (n < 10) { + config_error_add("Illegal value in ENTRYMAX (minimum is 10)"); + n = 10; + } + sysopt.entrymax = n; + return TRUE; +} + +staticfn boolean +cnf_line_POINTSMIN(char *bufp) +{ + int n = atoi(bufp); + + if (n < 1) { + config_error_add("Illegal value in POINTSMIN (minimum is 1)"); + n = 100; + } + sysopt.pointsmin = n; + return TRUE; +} + +staticfn boolean +cnf_line_MAX_STATUENAME_RANK(char *bufp) +{ + int n = atoi(bufp); + + if (n < 1) { + config_error_add("Illegal value in MAX_STATUENAME_RANK" + " (minimum is 1)"); + n = 10; + } + sysopt.tt_oname_maxrank = n; + return TRUE; +} + +staticfn boolean +cnf_line_LIVELOG(char *bufp) +{ + /* using 0 for base accepts "dddd" as decimal provided that first 'd' + isn't '0', "0xhhhh" as hexadecimal, and "0oooo" as octal; ignores + any trailing junk, including '8' or '9' for leading '0' octal */ + long L = strtol(bufp, NULL, 0); + + if (L < 0L || L > 0xffffL) { + config_error_add("Illegal value for LIVELOG" + " (must be between 0 and 0xFFFF)."); + return 0; + } + sysopt.livelog = L; + return TRUE; +} + +staticfn boolean +cnf_line_PANICTRACE_LIBC(char *bufp) +{ + int n = atoi(bufp); + +#if defined(PANICTRACE) && defined(PANICTRACE_LIBC) + if (n < 0 || n > 2) { + config_error_add("Illegal value in PANICTRACE_LIBC (not 0,1,2)"); + n = 0; + } +#endif + sysopt.panictrace_libc = n; + return TRUE; +} + +staticfn boolean +cnf_line_PANICTRACE_GDB(char *bufp) +{ + int n = atoi(bufp); + +#if defined(PANICTRACE) + if (n < 0 || n > 2) { + config_error_add("Illegal value in PANICTRACE_GDB (not 0,1,2)"); + n = 0; + } +#endif + sysopt.panictrace_gdb = n; + return TRUE; +} + +staticfn boolean +cnf_line_GDBPATH(char *bufp) +{ +#if defined(PANICTRACE) && !defined(VMS) + if (!file_exists(bufp)) { + config_error_add("File specified in GDBPATH does not exist"); + return FALSE; + } +#endif + if (sysopt.gdbpath) + free((genericptr_t) sysopt.gdbpath); + sysopt.gdbpath = dupstr(bufp); + return TRUE; +} + +staticfn boolean +cnf_line_GREPPATH(char *bufp) +{ +#if defined(PANICTRACE) && !defined(VMS) + if (!file_exists(bufp)) { + config_error_add("File specified in GREPPATH does not exist"); + return FALSE; + } +#endif + if (sysopt.greppath) + free((genericptr_t) sysopt.greppath); + sysopt.greppath = dupstr(bufp); + return TRUE; +} + +staticfn boolean +cnf_line_CRASHREPORTURL(char *bufp) +{ + if (sysopt.crashreporturl) + free((genericptr_t) sysopt.crashreporturl); + sysopt.crashreporturl = dupstr(bufp); + return TRUE; +} + +staticfn boolean +cnf_line_SAVEFORMAT(char *bufp) +{ + parseformat(sysopt.saveformat, bufp); + return TRUE; +} + +staticfn boolean +cnf_line_BONESFORMAT(char *bufp) +{ + parseformat(sysopt.bonesformat, bufp); + return TRUE; +} + +staticfn boolean +cnf_line_ACCESSIBILITY(char *bufp) +{ + int n = atoi(bufp); + + if (n < 0 || n > 1) { + config_error_add("Illegal value in ACCESSIBILITY (not 0,1)"); + n = 0; + } + sysopt.accessibility = n; + return TRUE; +} + +staticfn boolean +cnf_line_PORTABLE_DEVICE_PATHS(char *bufp) +{ +#ifdef WIN32 + int n = atoi(bufp); + + if (n < 0 || n > 1) { + config_error_add("Illegal value in PORTABLE_DEVICE_PATHS" + " (not 0 or 1)"); + n = 0; + } + sysopt.portable_device_paths = n; +#else /* Windows-only directive encountered by non-Windows config */ + nhUse(bufp); + config_error_add("PORTABLE_DEVICE_PATHS is not supported"); +#endif + return TRUE; +} + +#endif /* SYSCF */ + +staticfn boolean +cnf_line_BOULDER(char *bufp) +{ + (void) get_uchars(bufp, &go.ov_primary_syms[SYM_BOULDER + SYM_OFF_X], + TRUE, 1, "BOULDER"); + return TRUE; +} + +staticfn boolean +cnf_line_MENUCOLOR(char *bufp) +{ + return add_menu_coloring(bufp); +} + +staticfn boolean +cnf_line_HILITE_STATUS(char *bufp) +{ +#ifdef STATUS_HILITES + return parse_status_hl1(bufp, TRUE); +#else + nhUse(bufp); + return TRUE; +#endif +} + +staticfn boolean +cnf_line_WARNINGS(char *bufp) +{ + uchar translate[MAXPCHARS]; + + (void) get_uchars(bufp, translate, FALSE, WARNCOUNT, "WARNINGS"); + assign_warnings(translate); + return TRUE; +} + +staticfn boolean +cnf_line_ROGUESYMBOLS(char *bufp) +{ + if (parsesymbols(bufp, ROGUESET)) { + switch_symbols(TRUE); + return TRUE; + } + config_error_add("Error in ROGUESYMBOLS definition '%s'", bufp); + return FALSE; +} + +staticfn boolean +cnf_line_SYMBOLS(char *bufp) +{ + if (parsesymbols(bufp, PRIMARYSET)) { + switch_symbols(TRUE); + return TRUE; + } + config_error_add("Error in SYMBOLS definition '%s'", bufp); + return FALSE; +} + +staticfn boolean +cnf_line_WIZKIT(char *bufp) +{ + (void) strncpy(gw.wizkit, bufp, WIZKIT_MAX - 1); + return TRUE; +} + +#ifdef USER_SOUNDS +staticfn boolean +cnf_line_SOUNDDIR(char *bufp) +{ + if (sounddir) + free((genericptr_t) sounddir); + sounddir = dupstr(bufp); + return TRUE; +} + +staticfn boolean +cnf_line_SOUND(char *bufp) +{ + add_sound_mapping(bufp); + return TRUE; +} +#endif /*USER_SOUNDS*/ + +staticfn boolean +cnf_line_QT_TILEWIDTH(char *bufp) +{ +#ifdef QT_GRAPHICS + extern char *qt_tilewidth; + + if (qt_tilewidth == NULL) + qt_tilewidth = dupstr(bufp); +#else + nhUse(bufp); +#endif + return TRUE; +} + +staticfn boolean +cnf_line_QT_TILEHEIGHT(char *bufp) +{ +#ifdef QT_GRAPHICS + extern char *qt_tileheight; + + if (qt_tileheight == NULL) + qt_tileheight = dupstr(bufp); +#else + nhUse(bufp); +#endif + return TRUE; +} + +staticfn boolean +cnf_line_QT_FONTSIZE(char *bufp) +{ +#ifdef QT_GRAPHICS + extern char *qt_fontsize; + + if (qt_fontsize == NULL) + qt_fontsize = dupstr(bufp); +#else + nhUse(bufp); +#endif + return TRUE; +} + +staticfn boolean +cnf_line_QT_COMPACT(char *bufp) +{ +#ifdef QT_GRAPHICS + extern int qt_compact_mode; + + qt_compact_mode = atoi(bufp); +#else + nhUse(bufp); +#endif + return TRUE; +} + +typedef boolean (*config_line_stmt_func)(char *); + +/* normal */ +#define CNFL_N(n, l) { #n, l, FALSE, FALSE, cnf_line_##n } +/* normal, alias */ +#define CNFL_NA(n, l, f) { #n, l, FALSE, FALSE, cnf_line_##f } +/* sysconf only */ +#define CNFL_S(n, l) { #n, l, TRUE, FALSE, cnf_line_##n } + +static const struct match_config_line_stmt { + const char *name; + int len; + boolean syscnf_only; + boolean origbuf; + config_line_stmt_func fn; +} config_line_stmt[] = { + /* OPTIONS handled separately */ + { "OPTIONS", 4, FALSE, TRUE, cnf_line_OPTIONS }, + CNFL_N(AUTOPICKUP_EXCEPTION, 5), + CNFL_N(BINDINGS, 4), + CNFL_N(AUTOCOMPLETE, 5), + CNFL_N(MSGTYPE, 7), + CNFL_N(HACKDIR, 4), + CNFL_N(LEVELDIR, 4), + CNFL_NA(LEVELS, 4, LEVELDIR), + CNFL_N(SAVEDIR, 4), + CNFL_N(BONESDIR, 5), + CNFL_N(DATADIR, 4), + CNFL_N(SCOREDIR, 4), + CNFL_N(LOCKDIR, 4), + CNFL_N(CONFIGDIR, 4), + CNFL_N(TROUBLEDIR, 4), + CNFL_N(NAME, 4), + CNFL_N(ROLE, 4), + CNFL_NA(CHARACTER, 4, ROLE), + CNFL_N(dogname, 3), + CNFL_N(catname, 3), +#ifdef SYSCF + CNFL_S(WIZARDS, 7), + CNFL_S(SHELLERS, 8), + CNFL_S(MSGHANDLER, 9), + CNFL_S(EXPLORERS, 7), + CNFL_S(DEBUGFILES, 5), + CNFL_S(DUMPLOGFILE, 7), + CNFL_S(GENERICUSERS, 12), + CNFL_S(BONES_POOLS, 10), + CNFL_S(SUPPORT, 7), + CNFL_S(RECOVER, 7), + CNFL_S(CHECK_SAVE_UID, 14), + CNFL_S(CHECK_PLNAME, 12), + CNFL_S(SEDUCE, 6), + CNFL_S(HIDEUSAGE, 9), + CNFL_S(MAXPLAYERS, 10), + CNFL_S(PERSMAX, 7), + CNFL_S(PERS_IS_UID, 11), + CNFL_S(ENTRYMAX, 8), + CNFL_S(POINTSMIN, 9), + CNFL_S(MAX_STATUENAME_RANK, 10), + CNFL_S(LIVELOG, 7), + CNFL_S(PANICTRACE_LIBC, 15), + CNFL_S(PANICTRACE_GDB, 14), + CNFL_S(CRASHREPORTURL, 13), + CNFL_S(GDBPATH, 7), + CNFL_S(GREPPATH, 7), + CNFL_S(SAVEFORMAT, 10), + CNFL_S(BONESFORMAT, 11), + CNFL_S(ACCESSIBILITY, 13), + CNFL_S(PORTABLE_DEVICE_PATHS, 8), +#endif /*SYSCF*/ + CNFL_N(BOULDER, 3), + CNFL_N(MENUCOLOR, 9), + CNFL_N(HILITE_STATUS, 6), + CNFL_N(WARNINGS, 5), + CNFL_N(ROGUESYMBOLS, 4), + CNFL_N(SYMBOLS, 4), + CNFL_N(WIZKIT, 6), +#ifdef USER_SOUNDS + CNFL_N(SOUNDDIR, 8), + CNFL_N(SOUND, 5), +#endif /*USER_SOUNDS*/ + CNFL_N(QT_TILEWIDTH, 12), + CNFL_N(QT_TILEHEIGHT, 13), + CNFL_N(QT_FONTSIZE, 11), + CNFL_N(QT_COMPACT, 10) +}; + +#undef CNFL_N +#undef CNFL_NA +#undef CNFL_S + +boolean +parse_config_line(char *origbuf) +{ +#if defined(MICRO) && !defined(NOCWD_ASSUMPTIONS) + static boolean ramdisk_specified = FALSE; +#endif +#ifdef SYSCF + int src = iflags.parse_config_file_src; + boolean in_sysconf = (src == set_in_sysconf); +#endif + char *bufp, buf[4 * BUFSZ]; + int i; + + while (*origbuf == ' ' || *origbuf == '\t') /* skip leading whitespace */ + ++origbuf; /* (caller probably already did this) */ + (void) strncpy(buf, origbuf, sizeof buf - 1); + buf[sizeof buf - 1] = '\0'; /* strncpy not guaranteed to NUL terminate */ + /* convert any tab to space, condense consecutive spaces into one, + remove leading and trailing spaces (exception: if there is nothing + but spaces, one of them will be kept even though it leads/trails) */ + mungspaces(buf); + + /* find the '=' or ':' */ + bufp = find_optparam(buf); + if (!bufp) { + config_error_add("Not a config statement, missing '='"); + return FALSE; + } + /* skip past '=', then space between it and value, if any */ + ++bufp; + if (*bufp == ' ') + ++bufp; + + for (i = 0; i < SIZE(config_line_stmt); i++) { +#ifdef SYSCF + if (config_line_stmt[i].syscnf_only && !in_sysconf) + continue; +#endif + if (match_varname(buf, config_line_stmt[i].name, + config_line_stmt[i].len)) { + char *parm = config_line_stmt[i].origbuf ? origbuf : bufp; + + return config_line_stmt[i].fn(parm); + } + } + + config_error_add("Unknown config statement"); + return FALSE; +} + +#ifdef USER_SOUNDS +boolean +can_read_file(const char *filename) +{ + return (boolean) (access(filename, 4) == 0); +} +#endif /* USER_SOUNDS */ + +struct _config_error_errmsg { + int line_num; + char *errormsg; + struct _config_error_errmsg *next; +}; + +struct _config_error_frame { + int line_num; + int num_errors; + boolean origline_shown; + boolean fromfile; + boolean secure; + char origline[4 * BUFSZ]; + char source[BUFSZ]; + struct _config_error_frame *next; +}; + +static struct _config_error_frame *config_error_data = 0; +static struct _config_error_errmsg *config_error_msg = 0; + +void +config_error_init(boolean from_file, const char *sourcename, boolean secure) +{ + struct _config_error_frame *tmp = (struct _config_error_frame *) + alloc(sizeof *tmp); + + tmp->line_num = 0; + tmp->num_errors = 0; + tmp->origline_shown = FALSE; + tmp->fromfile = from_file; + tmp->secure = secure; + tmp->origline[0] = '\0'; + if (sourcename && sourcename[0]) { + (void) strncpy(tmp->source, sourcename, sizeof (tmp->source) - 1); + tmp->source[sizeof (tmp->source) - 1] = '\0'; + } else + tmp->source[0] = '\0'; + + tmp->next = config_error_data; + config_error_data = tmp; + program_state.config_error_ready = TRUE; +} + +staticfn boolean +config_error_nextline(const char *line) +{ + struct _config_error_frame *ced = config_error_data; + + if (!ced) + return FALSE; + + if (ced->num_errors && ced->secure) + return FALSE; + + ced->line_num++; + ced->origline_shown = FALSE; + if (line && line[0]) { + (void) strncpy(ced->origline, line, sizeof (ced->origline) - 1); + ced->origline[sizeof (ced->origline) - 1] = '\0'; + } else + ced->origline[0] = '\0'; + + return TRUE; +} + +int +l_get_config_errors(lua_State *L) +{ + struct _config_error_errmsg *dat = config_error_msg; + struct _config_error_errmsg *tmp; + int idx = 1; + + lua_newtable(L); + + while (dat) { + lua_pushinteger(L, idx++); + lua_newtable(L); + nhl_add_table_entry_int(L, "line", dat->line_num); + nhl_add_table_entry_str(L, "error", dat->errormsg); + lua_settable(L, -3); + tmp = dat->next; + free(dat->errormsg); + dat->errormsg = (char *) 0; + free(dat); + dat = tmp; + } + config_error_msg = (struct _config_error_errmsg *) 0; + + return 1; +} + +/* varargs 'config_error_add()' moved to pline.c */ +void +config_erradd(const char *buf) +{ + char lineno[QBUFSZ]; + const char *punct; + + if (!buf || !*buf) + buf = "Unknown error"; + + /* if buf[] doesn't end in a period, exclamation point, or question mark, + we'll include a period (in the message, not appended to buf[]) */ + punct = c_eos((char *) buf) - 1; /* eos(buf)-1 is valid */ + punct = strchr(".!?", *punct) ? "" : "."; + + if (!program_state.config_error_ready) { + /* either very early, where pline() will use raw_print(), or + player gave bad value when prompted by interactive 'O' command */ + pline("%s%s%s", !iflags.window_inited ? "config_error_add: " : "", + buf, punct); + wait_synch(); + return; + } + + if (iflags.in_lua) { + struct _config_error_errmsg *dat + = (struct _config_error_errmsg *) alloc(sizeof *dat); + + dat->next = config_error_msg; + dat->line_num = config_error_data->line_num; + dat->errormsg = dupstr(buf); + config_error_msg = dat; + return; + } + + config_error_data->num_errors++; + if (!config_error_data->origline_shown && !config_error_data->secure) { + pline("\n%s", config_error_data->origline); + config_error_data->origline_shown = TRUE; + } + if (config_error_data->line_num > 0 && !config_error_data->secure) { + Sprintf(lineno, "Line %d: ", config_error_data->line_num); + } else + lineno[0] = '\0'; + + pline("%s %s%s%s", config_error_data->secure ? "Error:" : " *", + lineno, buf, punct); +} + +int +config_error_done(void) +{ + int n; + struct _config_error_frame *tmp = config_error_data; + + if (!config_error_data) + return 0; + n = config_error_data->num_errors; +#ifndef USER_SOUNDS + if (gn.no_sound_notified > 0) { + /* no USER_SOUNDS; config_error_add() was called once for first + SOUND or SOUNDDIR entry seen, then skipped for any others; + include those skipped ones in the total error count */ + n += (gn.no_sound_notified - 1); + gn.no_sound_notified = 0; + } +#endif + if (n) { + boolean cmdline = !strcmp(config_error_data->source, "command line"); + + pline("\n%d error%s %s %s.\n", n, plur(n), cmdline ? "on" : "in", + *config_error_data->source ? config_error_data->source + : configfile); + wait_synch(); + } + config_error_data = tmp->next; + free(tmp); + program_state.config_error_ready = (config_error_data != 0); + return n; +} + +boolean +read_config_file(const char *filename, int src) +{ + FILE *fp; + boolean rv = TRUE; + + if (!(fp = fopen_config_file(filename, src))) + return FALSE; + + /* begin detection of duplicate configfile options */ + reset_duplicate_opt_detection(); + free_config_sections(); + iflags.parse_config_file_src = src; + + rv = parse_conf_file(fp, parse_config_line); + (void) fclose(fp); + + free_config_sections(); + /* turn off detection of duplicate configfile options */ + reset_duplicate_opt_detection(); + return rv; +} + +struct _cnf_parser_state { + char *inbuf; + unsigned inbufsz; + int rv; + char *ep; + char *buf; + boolean skip, morelines; + boolean cont; + boolean pbreak; +}; + +/* Initialize config parser data */ +staticfn void +cnf_parser_init(struct _cnf_parser_state *parser) +{ + parser->rv = TRUE; /* assume successful parse */ + parser->ep = parser->buf = (char *) 0; + parser->skip = FALSE; + parser->morelines = FALSE; + parser->inbufsz = 4 * BUFSZ; + parser->inbuf = (char *) alloc(parser->inbufsz); + parser->cont = FALSE; + parser->pbreak = FALSE; + memset(parser->inbuf, 0, parser->inbufsz); +} + +/* caller has finished with 'parser' (except for 'rv' so leave that intact) */ +staticfn void +cnf_parser_done(struct _cnf_parser_state *parser) +{ + parser->ep = 0; /* points into parser->inbuf, so becoming stale */ + if (parser->inbuf) + free(parser->inbuf), parser->inbuf = 0; + if (parser->buf) + free(parser->buf), parser->buf = 0; +} + +/* + * Parse config buffer, handling comments, empty lines, config sections, + * CHOOSE, and line continuation, calling proc for every valid line. + * + * Continued lines are merged together with one space in between. + */ +staticfn void +parse_conf_buf(struct _cnf_parser_state *p, boolean (*proc)(char *arg)) +{ + p->cont = FALSE; + p->pbreak = FALSE; + p->ep = strchr(p->inbuf, '\n'); + if (p->skip) { /* in case previous line was too long */ + if (p->ep) + p->skip = FALSE; /* found newline; next line is normal */ + } else { + if (!p->ep) { /* newline missing */ + if (strlen(p->inbuf) < (p->inbufsz - 2)) { + /* likely the last line of file is just + missing a newline; process it anyway */ + p->ep = eos(p->inbuf); + } else { + config_error_add("Line too long, skipping"); + p->skip = TRUE; /* discard next fgets */ + } + } else { + *p->ep = '\0'; /* remove newline */ + } + if (p->ep) { + char *tmpbuf = (char *) 0; + int len; + boolean ignoreline = FALSE; + boolean oldline = FALSE; + + /* line continuation (trailing '\') */ + p->morelines = (--p->ep >= p->inbuf && *p->ep == '\\'); + if (p->morelines) + *p->ep = '\0'; + + /* trim off spaces at end of line */ + while (p->ep >= p->inbuf + && (*p->ep == ' ' || *p->ep == '\t' || *p->ep == '\r')) + *p->ep-- = '\0'; + + if (!config_error_nextline(p->inbuf)) { + p->rv = FALSE; + if (p->buf) + free(p->buf), p->buf = (char *) 0; + p->pbreak = TRUE; + return; + } + + p->ep = p->inbuf; + while (*p->ep == ' ' || *p->ep == '\t') + ++p->ep; + + /* ignore empty lines and full-line comment lines */ + if (!*p->ep || *p->ep == '#') + ignoreline = TRUE; + + if (p->buf) + oldline = TRUE; + + /* merge now read line with previous ones, if necessary */ + if (!ignoreline) { + len = (int) strlen(p->ep) + 1; /* +1: final '\0' */ + if (p->buf) + len += (int) strlen(p->buf) + 1; /* +1: space */ + tmpbuf = (char *) alloc(len); + *tmpbuf = '\0'; + if (p->buf) { + Strcat(strcpy(tmpbuf, p->buf), " "); + free(p->buf), p->buf = 0; + } + p->buf = strcat(tmpbuf, p->ep); + if (strlen(p->buf) >= p->inbufsz) + p->buf[p->inbufsz - 1] = '\0'; + } + + if (p->morelines || (ignoreline && !oldline)) + return; + + if (handle_config_section(p->buf)) { + free(p->buf), p->buf = (char *) 0; + return; + } + + /* from here onwards, we'll handle buf only */ + + if (match_varname(p->buf, "CHOOSE", 6)) { + char *section; + char *bufp = find_optparam(p->buf); + + if (!bufp) { + config_error_add("Format is CHOOSE=section1" + ",section2,..."); + p->rv = FALSE; + free(p->buf), p->buf = (char *) 0; + return; + } + bufp++; + if (gc.config_section_chosen) + free(gc.config_section_chosen), + gc.config_section_chosen = 0; + section = choose_random_part(bufp, ','); + if (section) { + gc.config_section_chosen = dupstr(section); + } else { + config_error_add("No config section to choose"); + p->rv = FALSE; + } + free(p->buf), p->buf = (char *) 0; + return; + } + + if (!(*proc)(p->buf)) + p->rv = FALSE; + + free(p->buf), p->buf = (char *) 0; + } + } +} + +boolean +parse_conf_str(const char *str, boolean (*proc)(char *arg)) +{ + size_t len; + struct _cnf_parser_state parser; + + cnf_parser_init(&parser); + free_config_sections(); + config_error_init(FALSE, "parse_conf_str", FALSE); + while (str && *str) { + len = 0; + while (*str && len < (parser.inbufsz-1)) { + parser.inbuf[len] = *str; + len++; + str++; + if (parser.inbuf[len-1] == '\n') + break; + } + parser.inbuf[len] = '\0'; + parse_conf_buf(&parser, proc); + if (parser.pbreak) + break; + } + cnf_parser_done(&parser); + + free_config_sections(); + config_error_done(); + return parser.rv; +} + +/* parse_conf_file + * + * Read from file fp, calling parse_conf_buf for each line. + */ +boolean +parse_conf_file(FILE *fp, boolean (*proc)(char *arg)) +{ + struct _cnf_parser_state parser; + + cnf_parser_init(&parser); + free_config_sections(); + + while (fgets(parser.inbuf, parser.inbufsz, fp)) { + parse_conf_buf(&parser, proc); + if (parser.pbreak) + break; + } + cnf_parser_done(&parser); + + free_config_sections(); + return parser.rv; +} + +#ifdef SYSCF +staticfn void +parseformat(int *arr, char *str) +{ + const char *legal[] = { "historical", "lendian", "ascii" }; + int i, kwi = 0, words = 0; + char *p = str, *keywords[2]; + + while (*p) { + while (*p && isspace((uchar) *p)) { + *p = '\0'; + p++; + } + if (*p) { + words++; + if (kwi < 2) + keywords[kwi++] = p; + } + while (*p && !isspace((uchar) *p)) + p++; + } + if (!words) { + impossible("missing format list"); + return; + } + while (--kwi >= 0) + if (kwi < 2) { + for (i = 0; i < SIZE(legal); ++i) { + if (!strcmpi(keywords[kwi], legal[i])) + arr[kwi] = i + 1; + } + } +} +#endif /* SYSCF */ + +/* ---------- END CONFIG FILE HANDLING ----------- */ + +/*cfgfiles.c*/ diff --git a/src/files.c b/src/files.c index 8e7d214a9..cd8ea9815 100644 --- a/src/files.c +++ b/src/files.c @@ -114,10 +114,6 @@ extern char *translate_path_variables(const char *, char *); #define PRAGMA_UNUSED #endif -#ifdef USER_SOUNDS -extern char *sounddir; /* defined in sounds.c */ -#endif - staticfn NHFILE *new_nhfile(void); staticfn void free_nhfile(NHFILE *); #ifdef SELECTSAVED @@ -137,93 +133,7 @@ staticfn boolean make_compressed_name(const char *, char *); #ifndef USE_FCNTL staticfn char *make_lockname(const char *, char *); #endif -staticfn void set_configfile_name(const char *); -staticfn FILE *fopen_config_file(const char *, int); -staticfn int get_uchars(char *, uchar *, boolean, int, const char *); -#ifdef NOCWD_ASSUMPTIONS -staticfn void adjust_prefix(char *, int); -#endif -staticfn char *choose_random_part(char *, char); -staticfn boolean config_error_nextline(const char *); -staticfn void free_config_sections(void); -staticfn char *is_config_section(char *); -staticfn boolean handle_config_section(char *); -boolean parse_config_line(char *); -staticfn char *find_optparam(const char *); -staticfn boolean cnf_line_OPTIONS(char *); -staticfn boolean cnf_line_AUTOPICKUP_EXCEPTION(char *); -staticfn boolean cnf_line_BINDINGS(char *); -staticfn boolean cnf_line_AUTOCOMPLETE(char *); -staticfn boolean cnf_line_MSGTYPE(char *); -staticfn boolean cnf_line_HACKDIR(char *); -staticfn boolean cnf_line_LEVELDIR(char *); -staticfn boolean cnf_line_SAVEDIR(char *); -staticfn boolean cnf_line_BONESDIR(char *); -staticfn boolean cnf_line_DATADIR(char *); -staticfn boolean cnf_line_SCOREDIR(char *); -staticfn boolean cnf_line_LOCKDIR(char *); -staticfn boolean cnf_line_CONFIGDIR(char *); -staticfn boolean cnf_line_TROUBLEDIR(char *); -staticfn boolean cnf_line_NAME(char *); -staticfn boolean cnf_line_ROLE(char *); -staticfn boolean cnf_line_dogname(char *); -staticfn boolean cnf_line_catname(char *); -#ifdef SYSCF -staticfn boolean cnf_line_WIZARDS(char *); -staticfn boolean cnf_line_SHELLERS(char *); -staticfn boolean cnf_line_MSGHANDLER(char *); -staticfn boolean cnf_line_EXPLORERS(char *); -staticfn boolean cnf_line_DEBUGFILES(char *); -staticfn boolean cnf_line_DUMPLOGFILE(char *); -staticfn boolean cnf_line_GENERICUSERS(char *); -staticfn boolean cnf_line_BONES_POOLS(char *); -staticfn boolean cnf_line_SUPPORT(char *); -staticfn boolean cnf_line_RECOVER(char *); -staticfn boolean cnf_line_CHECK_SAVE_UID(char *); -staticfn boolean cnf_line_CHECK_PLNAME(char *); -staticfn boolean cnf_line_SEDUCE(char *); -staticfn boolean cnf_line_HIDEUSAGE(char *); -staticfn boolean cnf_line_MAXPLAYERS(char *); -staticfn boolean cnf_line_PERSMAX(char *); -staticfn boolean cnf_line_PERS_IS_UID(char *); -staticfn boolean cnf_line_ENTRYMAX(char *); -staticfn boolean cnf_line_POINTSMIN(char *); -staticfn boolean cnf_line_MAX_STATUENAME_RANK(char *); -staticfn boolean cnf_line_LIVELOG(char *); -staticfn boolean cnf_line_PANICTRACE_LIBC(char *); -staticfn boolean cnf_line_PANICTRACE_GDB(char *); -staticfn boolean cnf_line_GDBPATH(char *); -staticfn boolean cnf_line_GREPPATH(char *); -staticfn boolean cnf_line_CRASHREPORTURL(char *); -staticfn boolean cnf_line_SAVEFORMAT(char *); -staticfn boolean cnf_line_BONESFORMAT(char *); -staticfn boolean cnf_line_ACCESSIBILITY(char *); -staticfn boolean cnf_line_PORTABLE_DEVICE_PATHS(char *); -staticfn void parseformat(int *, char *); -#endif /* SYSCF */ -staticfn boolean cnf_line_BOULDER(char *); -staticfn boolean cnf_line_MENUCOLOR(char *); -staticfn boolean cnf_line_HILITE_STATUS(char *); -staticfn boolean cnf_line_WARNINGS(char *); -staticfn boolean cnf_line_ROGUESYMBOLS(char *); -staticfn boolean cnf_line_SYMBOLS(char *); -staticfn boolean cnf_line_WIZKIT(char *); -#ifdef USER_SOUNDS -staticfn boolean cnf_line_SOUNDDIR(char *); -staticfn boolean cnf_line_SOUND(char *); -#endif -staticfn boolean cnf_line_QT_TILEWIDTH(char *); -staticfn boolean cnf_line_QT_TILEHEIGHT(char *); -staticfn boolean cnf_line_QT_FONTSIZE(char *); -staticfn boolean cnf_line_QT_COMPACT(char *); -struct _cnf_parser_state; /* defined below (far below...) */ -staticfn void cnf_parser_init(struct _cnf_parser_state *parser); -staticfn void cnf_parser_done(struct _cnf_parser_state *parser); -staticfn void parse_conf_buf(struct _cnf_parser_state *parser, - boolean (*proc)(char *arg)); -/* next one is in extern.h; why here too? */ -boolean parse_conf_str(const char *str, boolean (*proc)(char *arg)); -staticfn boolean parse_conf_file(FILE *fp, boolean (*proc)(char *arg)); + staticfn FILE *fopen_wizkit_file(void); staticfn void wizkit_addinv(struct obj *); boolean proc_wizkit_line(char *buf); @@ -2106,1752 +2016,6 @@ unlock_file(const char *filename) /* ---------- END FILE LOCKING HANDLING ----------- */ -/* ---------- BEGIN CONFIG FILE HANDLING ----------- */ - -static const char *default_configfile = -#ifdef UNIX - ".nethackrc"; -#else -#if defined(MAC) || defined(__BEOS__) - "NetHack Defaults"; -#else -#if defined(MSDOS) || defined(WIN32) - CONFIG_FILE; -#else - "NetHack.cnf"; -#endif -#endif -#endif - -/* used for messaging. Also used in options.c */ -char configfile[BUFSZ]; - -#ifdef MSDOS -/* conflict with speed-dial under windows - * for XXX.cnf file so support of NetHack.cnf - * is for backward compatibility only. - * Preferred name (and first tried) is now defaults.nh but - * the game will try the old name if there - * is no defaults.nh. - */ -const char *backward_compat_configfile = "nethack.cnf"; -#endif - -/* #saveoptions - save config options into file */ -int -do_write_config_file(void) -{ - FILE *fp; - char tmp[BUFSZ]; - - if (!configfile[0]) { - pline("Strange, could not figure out config file name."); - return ECMD_OK; - } - if (flags.suppress_alert < FEATURE_NOTICE_VER(3,7,0)) { - pline("Warning: saveoptions is highly experimental!"); - wait_synch(); - pline("Some settings are not saved!"); - wait_synch(); - pline("All manual customization and comments are removed" - " from the file!"); - wait_synch(); - } -#define overwrite_prompt "Overwrite config file %.*s?" - Sprintf(tmp, overwrite_prompt, - (int) (BUFSZ - sizeof overwrite_prompt - 2), configfile); -#undef overwrite_prompt - if (!paranoid_query(TRUE, tmp)) - return ECMD_OK; - - fp = fopen(configfile, "w"); - if (fp) { - size_t len, wrote; - strbuf_t buf; - - strbuf_init(&buf); - all_options_strbuf(&buf); - len = strlen(buf.str); - wrote = fwrite(buf.str, 1, len, fp); - fclose(fp); - strbuf_empty(&buf); - if (wrote != len) - pline("An error occurred, wrote only partial data (%zu/%zu).", - wrote, len); - } - return ECMD_OK; -} - -/* remember the name of the file we're accessing; - if may be used in option reject messages */ -staticfn void -set_configfile_name(const char *fname) -{ - (void) strncpy(configfile, fname, sizeof configfile - 1); - configfile[sizeof configfile - 1] = '\0'; -} - -staticfn FILE * -fopen_config_file(const char *filename, int src) -{ - FILE *fp; -#if defined(UNIX) || defined(VMS) - char tmp_config[BUFSZ]; - char *envp; -#endif - - if (src == set_in_sysconf) { - /* SYSCF_FILE; if we can't open it, caller will bail */ - if (filename && *filename) { - set_configfile_name(fqname(filename, SYSCONFPREFIX, 0)); - fp = fopen(configfile, "r"); - } else - fp = (FILE *) 0; - return fp; - } - /* If src != set_in_sysconf, "filename" is an environment variable, so it - * should hang around. If set, it is expected to be a full path name - * (if relevant) - */ - if (filename && *filename) { - set_configfile_name(filename); -#ifdef UNIX - if (access(configfile, 4) == -1) { /* 4 is R_OK on newer systems */ - /* nasty sneaky attempt to read file through - * NetHack's setuid permissions -- this is the only - * place a file name may be wholly under the player's - * control (but SYSCF_FILE is not under the player's - * control so it's OK). - */ - raw_printf("Access to %s denied (%d).", configfile, errno); - wait_synch(); - /* fall through to standard names */ - } else -#endif - if ((fp = fopen(configfile, "r")) != (FILE *) 0) { - return fp; -#if defined(UNIX) || defined(VMS) - } else { - /* access() above probably caught most problems for UNIX */ - raw_printf("Couldn't open requested config file %s (%d).", - configfile, errno); - wait_synch(); -#endif - } - } - /* fall through to standard names */ - -#if defined(MICRO) || defined(MAC) || defined(__BEOS__) || defined(WIN32) - set_configfile_name(fqname(default_configfile, CONFIGPREFIX, 0)); - if ((fp = fopen(configfile, "r")) != (FILE *) 0) { - return fp; - } else if (strcmp(default_configfile, configfile)) { - set_configfile_name(default_configfile); - if ((fp = fopen(configfile, "r")) != (FILE *) 0) - return fp; - } -#ifdef MSDOS - set_configfile_name(fqname(backward_compat_configfile, CONFIGPREFIX, 0)); - if ((fp = fopen(configfile, "r")) != (FILE *) 0) { - return fp; - } else if (strcmp(backward_compat_configfile, configfile)) { - set_configfile_name(backward_compat_configfile); - if ((fp = fopen(configfile, "r")) != (FILE *) 0) - return fp; - } -#endif -#else -/* constructed full path names don't need fqname() */ -#ifdef VMS - /* no punctuation, so might be a logical name */ - set_configfile_name("nethackini"); - if ((fp = fopen(configfile, "r")) != (FILE *) 0) - return fp; - set_configfile_name("sys$login:nethack.ini"); - if ((fp = fopen(configfile, "r")) != (FILE *) 0) - return fp; - - envp = nh_getenv("HOME"); - if (!envp || !*envp) - Strcpy(tmp_config, "NetHack.cnf"); - else - Sprintf(tmp_config, "%s%s%s", envp, - !strchr(":]>/", envp[strlen(envp) - 1]) ? "/" : "", - "NetHack.cnf"); - set_configfile_name(tmp_config); - if ((fp = fopen(configfile, "r")) != (FILE *) 0) - return fp; -#else /* should be only UNIX left */ - envp = nh_getenv("HOME"); - if (!envp) - Strcpy(tmp_config, ".nethackrc"); - else - Sprintf(tmp_config, "%s/%s", envp, ".nethackrc"); - - set_configfile_name(tmp_config); - if ((fp = fopen(configfile, "r")) != (FILE *) 0) - return fp; -#if defined(__APPLE__) /* UNIX+__APPLE__ => OSX || MacOS */ - /* try an alternative */ - if (envp) { - /* keep 'tmp_config' intact here; if alternates fail, use it to - restore configfile[] to its preferred setting (".nethackrc") */ - char alt_config[sizeof tmp_config]; - - /* OSX-style configuration settings */ - Snprintf(alt_config, sizeof alt_config, "%s/%s", envp, - "Library/Preferences/NetHack Defaults"); - set_configfile_name(alt_config); - if ((fp = fopen(configfile, "r")) != (FILE *) 0) - return fp; - /* may be easier for user to edit if filename has '.txt' suffix */ - Snprintf(alt_config, sizeof alt_config, "%s/%s", envp, - "Library/Preferences/NetHack Defaults.txt"); - set_configfile_name(alt_config); - if ((fp = fopen(configfile, "r")) != (FILE *) 0) - return fp; - /* couldn't open either of the alternate names; for use in - messages, put 'configfile' back to the normal value rather than - leaving it set to last alternate; retry open() to reset 'errno' */ - set_configfile_name(tmp_config); - if ((fp = fopen(configfile, "r")) != (FILE *) 0) - return fp; - } -#endif /*__APPLE__*/ - if (errno != ENOENT) { - const char *details; - - /* e.g., problems when setuid NetHack can't search home - directory restricted to user */ -#if defined(NHSTDC) && !defined(NOTSTDC) - if ((details = strerror(errno)) == 0) -#endif - details = ""; - raw_printf("Couldn't open default config file %s %s(%d).", - configfile, details, errno); - wait_synch(); - } -#endif /* !VMS => Unix */ -#endif /* !(MICRO || MAC || __BEOS__ || WIN32) */ - return (FILE *) 0; -} - -/* - * Retrieve a list of integers from buf into a uchar array. - * - * NOTE: zeros are inserted unless modlist is TRUE, in which case the list - * location is unchanged. Callers must handle zeros if modlist is FALSE. - */ -staticfn int -get_uchars(char *bufp, /* current pointer */ - uchar *list, /* return list */ - boolean modlist, /* TRUE: list is being modified in place */ - int size, /* return list size */ - const char *name) /* name of option for error message */ -{ - unsigned int num = 0; - int count = 0; - boolean havenum = FALSE; - - while (1) { - switch (*bufp) { - case ' ': - case '\0': - case '\t': - case '\n': - if (havenum) { - /* if modifying in place, don't insert zeros */ - if (num || !modlist) - list[count] = num; - count++; - num = 0; - havenum = FALSE; - } - if (count == size || !*bufp) - return count; - bufp++; - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - havenum = TRUE; - num = num * 10 + (*bufp - '0'); - bufp++; - break; - - case '\\': - goto gi_error; - break; - - default: - gi_error: - raw_printf("Syntax error in %s", name); - wait_synch(); - return count; - } - } - /*NOTREACHED*/ -} - -#ifdef NOCWD_ASSUMPTIONS -staticfn void -adjust_prefix(char *bufp, int prefixid) -{ - char *ptr; - - if (!bufp) - return; -#ifdef WIN32 - if (fqn_prefix_locked[prefixid]) - return; -#endif - /* Backward compatibility, ignore trailing ;n */ - if ((ptr = strchr(bufp, ';')) != 0) - *ptr = '\0'; - if (strlen(bufp) > 0) { - gf.fqn_prefix[prefixid] = (char *) alloc(strlen(bufp) + 2); - Strcpy(gf.fqn_prefix[prefixid], bufp); - append_slash(gf.fqn_prefix[prefixid]); - } -} -#endif - -/* Choose at random one of the sep separated parts from str. Mangles str. */ -staticfn char * -choose_random_part(char *str, char sep) -{ - int nsep = 1; - int csep; - int len = 0; - char *begin = str; - - if (!str) - return (char *) 0; - - while (*str) { - if (*str == sep) - nsep++; - str++; - } - csep = rn2(nsep); - str = begin; - while ((csep > 0) && *str) { - str++; - if (*str == sep) - csep--; - } - if (*str) { - if (*str == sep) - str++; - begin = str; - while (*str && *str != sep) { - str++; - len++; - } - *str = '\0'; - if (len) - return begin; - } - return (char *) 0; -} - -staticfn void -free_config_sections(void) -{ - if (gc.config_section_chosen) { - free(gc.config_section_chosen); - gc.config_section_chosen = NULL; - } - if (gc.config_section_current) { - free(gc.config_section_current); - gc.config_section_current = NULL; - } -} - -/* check for " [ anything-except-bracket-or-empty ] # arbitrary-comment" - with spaces optional; returns pointer to "anything-except..." (with - trailing " ] #..." stripped) if ok, otherwise Null */ -staticfn char * -is_config_section( - char *str) /* trailing spaces are stripped, ']' too iff result is good */ -{ - char *a, *c, *z; - - /* remove any spaces at start and end; won't significantly interfere - with echoing the string in a config error message, if warranted */ - a = trimspaces(str); - /* first character should be open square bracket; set pointer past it */ - if (*a++ != '[') - return (char *) 0; - /* last character should be close bracket, ignoring any comment */ - z = strchr(a, ']'); - if (!z) - return (char *) 0; - /* comment, if present, can be preceded by spaces */ - for (c = z + 1; *c == ' '; ++c) - continue; - if (*c && *c != '#') - return (char *) 0; - /* we now know that result is good; there won't be a config error - message so we can modify the input string */ - *z = '\0'; - /* 'a' points past '[' and the string ends where ']' was; remove any - spaces between '[' and choice-start and between choice-end and ']' */ - return trimspaces(a); -} - -staticfn boolean -handle_config_section(char *buf) -{ - char *sect = is_config_section(buf); - - if (sect) { - if (gc.config_section_current) - free(gc.config_section_current), gc.config_section_current = 0; - /* is_config_section() removed brackets from 'sect' */ - if (!gc.config_section_chosen) { - config_error_add("Section \"[%s]\" without CHOOSE", sect); - return TRUE; - } - if (*sect) { /* got a section name */ - gc.config_section_current = dupstr(sect); - debugpline1("set config section: '%s'", - gc.config_section_current); - } else { /* empty section name => end of sections */ - free_config_sections(); - debugpline0("unset config section"); - } - return TRUE; - } - - if (gc.config_section_current) { - if (!gc.config_section_chosen) - return TRUE; - if (strcmp(gc.config_section_current, gc.config_section_chosen)) - return TRUE; - } - return FALSE; -} - -#define match_varname(INP, NAM, LEN) match_optname(INP, NAM, LEN, TRUE) - -/* find the '=' or ':' */ -staticfn char * -find_optparam(const char *buf) -{ - char *bufp, *altp; - - bufp = strchr(buf, '='); - altp = strchr(buf, ':'); - if (!bufp || (altp && altp < bufp)) - bufp = altp; - - return bufp; -} - -staticfn boolean -cnf_line_OPTIONS(char *origbuf) -{ - char *bufp = find_optparam(origbuf); - - ++bufp; /* skip '='; parseoptions() handles spaces */ - return parseoptions(bufp, TRUE, TRUE); -} - -staticfn boolean -cnf_line_AUTOPICKUP_EXCEPTION(char *bufp) -{ - add_autopickup_exception(bufp); - return TRUE; -} - -staticfn boolean -cnf_line_BINDINGS(char *bufp) -{ - return parsebindings(bufp); -} - -staticfn boolean -cnf_line_AUTOCOMPLETE(char *bufp) -{ - parseautocomplete(bufp, TRUE); - return TRUE; -} - -staticfn boolean -cnf_line_MSGTYPE(char *bufp) -{ - return msgtype_parse_add(bufp); -} - -staticfn boolean -cnf_line_HACKDIR(char *bufp) -{ -#ifdef NOCWD_ASSUMPTIONS - adjust_prefix(bufp, HACKPREFIX); -#else /*NOCWD_ASSUMPTIONS*/ -#ifdef MICRO - (void) strncpy(gh.hackdir, bufp, PATHLEN - 1); -#else /* MICRO */ - nhUse(bufp); -#endif /* MICRO */ -#endif /*NOCWD_ASSUMPTIONS*/ - return TRUE; -} - -staticfn boolean -cnf_line_LEVELDIR(char *bufp) -{ -#ifdef NOCWD_ASSUMPTIONS - adjust_prefix(bufp, LEVELPREFIX); -#else /*NOCWD_ASSUMPTIONS*/ -#ifdef MICRO - if (strlen(bufp) >= PATHLEN) - bufp[PATHLEN - 1] = '\0'; - Strcpy(g.permbones, bufp); - if (!ramdisk_specified || !*levels) - Strcpy(levels, bufp); - gr.ramdisk = (strcmp(g.permbones, levels) != 0); -#else /* MICRO */ - nhUse(bufp); -#endif /* MICRO */ -#endif /*NOCWD_ASSUMPTIONS*/ - return TRUE; -} - -staticfn boolean -cnf_line_SAVEDIR(char *bufp) -{ -#ifdef NOCWD_ASSUMPTIONS - adjust_prefix(bufp, SAVEPREFIX); -#else /*NOCWD_ASSUMPTIONS*/ -#ifdef MICRO - char *ptr; - - if ((ptr = strchr(bufp, ';')) != 0) { - *ptr = '\0'; - } - - (void) strncpy(gs.SAVEP, bufp, SAVESIZE - 1); - append_slash(gs.SAVEP); -#else /* MICRO */ - nhUse(bufp); -#endif /* MICRO */ -#endif /*NOCWD_ASSUMPTIONS*/ - return TRUE; -} - -staticfn boolean -cnf_line_BONESDIR(char *bufp) -{ -#ifdef NOCWD_ASSUMPTIONS - adjust_prefix(bufp, BONESPREFIX); -#else - nhUse(bufp); -#endif - return TRUE; -} - -staticfn boolean -cnf_line_DATADIR(char *bufp) -{ -#ifdef NOCWD_ASSUMPTIONS - adjust_prefix(bufp, DATAPREFIX); -#else - nhUse(bufp); -#endif - return TRUE; -} - -staticfn boolean -cnf_line_SCOREDIR(char *bufp) -{ -#ifdef NOCWD_ASSUMPTIONS - adjust_prefix(bufp, SCOREPREFIX); -#else - nhUse(bufp); -#endif - return TRUE; -} - -staticfn boolean -cnf_line_LOCKDIR(char *bufp) -{ -#ifdef NOCWD_ASSUMPTIONS - adjust_prefix(bufp, LOCKPREFIX); -#else - nhUse(bufp); -#endif - return TRUE; -} - -staticfn boolean -cnf_line_CONFIGDIR(char *bufp) -{ -#ifdef NOCWD_ASSUMPTIONS - adjust_prefix(bufp, CONFIGPREFIX); -#else - nhUse(bufp); -#endif - return TRUE; -} - -staticfn boolean -cnf_line_TROUBLEDIR(char *bufp) -{ -#ifdef NOCWD_ASSUMPTIONS - adjust_prefix(bufp, TROUBLEPREFIX); -#else - nhUse(bufp); -#endif - return TRUE; -} - -staticfn boolean -cnf_line_NAME(char *bufp) -{ - (void) strncpy(svp.plname, bufp, PL_NSIZ - 1); - return TRUE; -} - -staticfn boolean -cnf_line_ROLE(char *bufp) -{ - int len; - - if ((len = str2role(bufp)) >= 0) - flags.initrole = len; - return TRUE; -} - -staticfn boolean -cnf_line_dogname(char *bufp) -{ - (void) strncpy(gd.dogname, bufp, PL_PSIZ - 1); - return TRUE; -} - -staticfn boolean -cnf_line_catname(char *bufp) -{ - (void) strncpy(gc.catname, bufp, PL_PSIZ - 1); - return TRUE; -} - -#ifdef SYSCF - -staticfn boolean -cnf_line_WIZARDS(char *bufp) -{ - if (sysopt.wizards) - free((genericptr_t) sysopt.wizards); - sysopt.wizards = dupstr(bufp); - if (strlen(sysopt.wizards) && strcmp(sysopt.wizards, "*")) { - /* pre-format WIZARDS list now; it's displayed during a panic - and since that panic might be due to running out of memory, - we don't want to risk attempting to allocate any memory then */ - if (sysopt.fmtd_wizard_list) - free((genericptr_t) sysopt.fmtd_wizard_list); - sysopt.fmtd_wizard_list = build_english_list(sysopt.wizards); - } - return TRUE; -} - -staticfn boolean -cnf_line_SHELLERS(char *bufp) -{ - if (sysopt.shellers) - free((genericptr_t) sysopt.shellers); - sysopt.shellers = dupstr(bufp); - return TRUE; -} - -staticfn boolean -cnf_line_MSGHANDLER(char *bufp) -{ - if (sysopt.msghandler) - free((genericptr_t) sysopt.msghandler); - sysopt.msghandler = dupstr(bufp); - return TRUE; -} - -staticfn boolean -cnf_line_EXPLORERS(char *bufp) -{ - if (sysopt.explorers) - free((genericptr_t) sysopt.explorers); - sysopt.explorers = dupstr(bufp); - return TRUE; -} - -staticfn boolean -cnf_line_DEBUGFILES(char *bufp) -{ - /* might already have a vaule from getenv("DEBUGFILES"); - if so, ignore this value from SYSCF */ - if (!sysopt.env_dbgfl) { - if (sysopt.debugfiles) - free((genericptr_t) sysopt.debugfiles); - sysopt.debugfiles = dupstr(bufp); - } - return TRUE; -} - -staticfn boolean -cnf_line_DUMPLOGFILE(char *bufp) -{ -#ifdef DUMPLOG - if (sysopt.dumplogfile) - free((genericptr_t) sysopt.dumplogfile); - sysopt.dumplogfile = dupstr(bufp); -#else - nhUse(bufp); -#endif /*DUMPLOG*/ - return TRUE; -} - -staticfn boolean -cnf_line_GENERICUSERS(char *bufp) -{ - if (sysopt.genericusers) - free((genericptr_t) sysopt.genericusers); - sysopt.genericusers = dupstr(bufp); - return TRUE; -} - -staticfn boolean -cnf_line_BONES_POOLS(char *bufp) -{ - /* max value of 10 guarantees (N % bones.pools) will be one digit - so we don't lose control of the length of bones file names */ - int n = atoi(bufp); - - sysopt.bones_pools = (n <= 0) ? 0 : min(n, 10); - /* note: right now bones_pools==0 is the same as bones_pools==1, - but we could change that and make bones_pools==0 become an - indicator to suppress bones usage altogether */ - return TRUE; -} - -staticfn boolean -cnf_line_SUPPORT(char *bufp) -{ - if (sysopt.support) - free((genericptr_t) sysopt.support); - sysopt.support = dupstr(bufp); - return TRUE; -} - -staticfn boolean -cnf_line_RECOVER(char *bufp) -{ - if (sysopt.recover) - free((genericptr_t) sysopt.recover); - sysopt.recover = dupstr(bufp); - return TRUE; -} - -staticfn boolean -cnf_line_CHECK_SAVE_UID(char *bufp) -{ - int n = atoi(bufp); - - sysopt.check_save_uid = n; - return TRUE; -} - -staticfn boolean -cnf_line_CHECK_PLNAME(char *bufp) -{ - int n = atoi(bufp); - - sysopt.check_plname = n; - return TRUE; -} - -staticfn boolean -cnf_line_SEDUCE(char *bufp) -{ - int n = !!atoi(bufp); /* XXX this could be tighter */ -#ifdef SYSCF - int src = iflags.parse_config_file_src; - boolean in_sysconf = (src == set_in_sysconf); -#else - boolean in_sysconf = FALSE; -#endif - - /* allow anyone to disable it but can only enable it in sysconf - or as a no-op for the user when sysconf hasn't disabled it */ - if (!in_sysconf && !sysopt.seduce && n != 0) { - config_error_add("Illegal value in SEDUCE"); - n = 0; - } - sysopt.seduce = n; - sysopt_seduce_set(sysopt.seduce); - return TRUE; -} - -staticfn boolean -cnf_line_HIDEUSAGE(char *bufp) -{ - int n = !!atoi(bufp); - - sysopt.hideusage = n; - return TRUE; -} - -staticfn boolean -cnf_line_MAXPLAYERS(char *bufp) -{ - int n = atoi(bufp); - - /* XXX to get more than 25, need to rewrite all lock code */ - if (n < 0 || n > 25) { - config_error_add("Illegal value in MAXPLAYERS (maximum is 25)"); - n = 5; - } - sysopt.maxplayers = n; - return TRUE; -} - -staticfn boolean -cnf_line_PERSMAX(char *bufp) -{ - int n = atoi(bufp); - - if (n < 1) { - config_error_add("Illegal value in PERSMAX (minimum is 1)"); - n = 0; - } - sysopt.persmax = n; - return TRUE; -} - -staticfn boolean -cnf_line_PERS_IS_UID(char *bufp) -{ - int n = atoi(bufp); - - if (n != 0 && n != 1) { - config_error_add("Illegal value in PERS_IS_UID (must be 0 or 1)"); - n = 0; - } - sysopt.pers_is_uid = n; - return TRUE; -} - -staticfn boolean -cnf_line_ENTRYMAX(char *bufp) -{ - int n = atoi(bufp); - - if (n < 10) { - config_error_add("Illegal value in ENTRYMAX (minimum is 10)"); - n = 10; - } - sysopt.entrymax = n; - return TRUE; -} - -staticfn boolean -cnf_line_POINTSMIN(char *bufp) -{ - int n = atoi(bufp); - - if (n < 1) { - config_error_add("Illegal value in POINTSMIN (minimum is 1)"); - n = 100; - } - sysopt.pointsmin = n; - return TRUE; -} - -staticfn boolean -cnf_line_MAX_STATUENAME_RANK(char *bufp) -{ - int n = atoi(bufp); - - if (n < 1) { - config_error_add("Illegal value in MAX_STATUENAME_RANK" - " (minimum is 1)"); - n = 10; - } - sysopt.tt_oname_maxrank = n; - return TRUE; -} - -staticfn boolean -cnf_line_LIVELOG(char *bufp) -{ - /* using 0 for base accepts "dddd" as decimal provided that first 'd' - isn't '0', "0xhhhh" as hexadecimal, and "0oooo" as octal; ignores - any trailing junk, including '8' or '9' for leading '0' octal */ - long L = strtol(bufp, NULL, 0); - - if (L < 0L || L > 0xffffL) { - config_error_add("Illegal value for LIVELOG" - " (must be between 0 and 0xFFFF)."); - return 0; - } - sysopt.livelog = L; - return TRUE; -} - -staticfn boolean -cnf_line_PANICTRACE_LIBC(char *bufp) -{ - int n = atoi(bufp); - -#if defined(PANICTRACE) && defined(PANICTRACE_LIBC) - if (n < 0 || n > 2) { - config_error_add("Illegal value in PANICTRACE_LIBC (not 0,1,2)"); - n = 0; - } -#endif - sysopt.panictrace_libc = n; - return TRUE; -} - -staticfn boolean -cnf_line_PANICTRACE_GDB(char *bufp) -{ - int n = atoi(bufp); - -#if defined(PANICTRACE) - if (n < 0 || n > 2) { - config_error_add("Illegal value in PANICTRACE_GDB (not 0,1,2)"); - n = 0; - } -#endif - sysopt.panictrace_gdb = n; - return TRUE; -} - -staticfn boolean -cnf_line_GDBPATH(char *bufp) -{ -#if defined(PANICTRACE) && !defined(VMS) - if (!file_exists(bufp)) { - config_error_add("File specified in GDBPATH does not exist"); - return FALSE; - } -#endif - if (sysopt.gdbpath) - free((genericptr_t) sysopt.gdbpath); - sysopt.gdbpath = dupstr(bufp); - return TRUE; -} - -staticfn boolean -cnf_line_GREPPATH(char *bufp) -{ -#if defined(PANICTRACE) && !defined(VMS) - if (!file_exists(bufp)) { - config_error_add("File specified in GREPPATH does not exist"); - return FALSE; - } -#endif - if (sysopt.greppath) - free((genericptr_t) sysopt.greppath); - sysopt.greppath = dupstr(bufp); - return TRUE; -} - -staticfn boolean -cnf_line_CRASHREPORTURL(char *bufp) -{ - if (sysopt.crashreporturl) - free((genericptr_t) sysopt.crashreporturl); - sysopt.crashreporturl = dupstr(bufp); - return TRUE; -} - -staticfn boolean -cnf_line_SAVEFORMAT(char *bufp) -{ - parseformat(sysopt.saveformat, bufp); - return TRUE; -} - -staticfn boolean -cnf_line_BONESFORMAT(char *bufp) -{ - parseformat(sysopt.bonesformat, bufp); - return TRUE; -} - -staticfn boolean -cnf_line_ACCESSIBILITY(char *bufp) -{ - int n = atoi(bufp); - - if (n < 0 || n > 1) { - config_error_add("Illegal value in ACCESSIBILITY (not 0,1)"); - n = 0; - } - sysopt.accessibility = n; - return TRUE; -} - -staticfn boolean -cnf_line_PORTABLE_DEVICE_PATHS(char *bufp) -{ -#ifdef WIN32 - int n = atoi(bufp); - - if (n < 0 || n > 1) { - config_error_add("Illegal value in PORTABLE_DEVICE_PATHS" - " (not 0 or 1)"); - n = 0; - } - sysopt.portable_device_paths = n; -#else /* Windows-only directive encountered by non-Windows config */ - nhUse(bufp); - config_error_add("PORTABLE_DEVICE_PATHS is not supported"); -#endif - return TRUE; -} - -#endif /* SYSCF */ - -staticfn boolean -cnf_line_BOULDER(char *bufp) -{ - (void) get_uchars(bufp, &go.ov_primary_syms[SYM_BOULDER + SYM_OFF_X], - TRUE, 1, "BOULDER"); - return TRUE; -} - -staticfn boolean -cnf_line_MENUCOLOR(char *bufp) -{ - return add_menu_coloring(bufp); -} - -staticfn boolean -cnf_line_HILITE_STATUS(char *bufp) -{ -#ifdef STATUS_HILITES - return parse_status_hl1(bufp, TRUE); -#else - nhUse(bufp); - return TRUE; -#endif -} - -staticfn boolean -cnf_line_WARNINGS(char *bufp) -{ - uchar translate[MAXPCHARS]; - - (void) get_uchars(bufp, translate, FALSE, WARNCOUNT, "WARNINGS"); - assign_warnings(translate); - return TRUE; -} - -staticfn boolean -cnf_line_ROGUESYMBOLS(char *bufp) -{ - if (parsesymbols(bufp, ROGUESET)) { - switch_symbols(TRUE); - return TRUE; - } - config_error_add("Error in ROGUESYMBOLS definition '%s'", bufp); - return FALSE; -} - -staticfn boolean -cnf_line_SYMBOLS(char *bufp) -{ - if (parsesymbols(bufp, PRIMARYSET)) { - switch_symbols(TRUE); - return TRUE; - } - config_error_add("Error in SYMBOLS definition '%s'", bufp); - return FALSE; -} - -staticfn boolean -cnf_line_WIZKIT(char *bufp) -{ - (void) strncpy(gw.wizkit, bufp, WIZKIT_MAX - 1); - return TRUE; -} - -#ifdef USER_SOUNDS -staticfn boolean -cnf_line_SOUNDDIR(char *bufp) -{ - if (sounddir) - free((genericptr_t) sounddir); - sounddir = dupstr(bufp); - return TRUE; -} - -staticfn boolean -cnf_line_SOUND(char *bufp) -{ - add_sound_mapping(bufp); - return TRUE; -} -#endif /*USER_SOUNDS*/ - -staticfn boolean -cnf_line_QT_TILEWIDTH(char *bufp) -{ -#ifdef QT_GRAPHICS - extern char *qt_tilewidth; - - if (qt_tilewidth == NULL) - qt_tilewidth = dupstr(bufp); -#else - nhUse(bufp); -#endif - return TRUE; -} - -staticfn boolean -cnf_line_QT_TILEHEIGHT(char *bufp) -{ -#ifdef QT_GRAPHICS - extern char *qt_tileheight; - - if (qt_tileheight == NULL) - qt_tileheight = dupstr(bufp); -#else - nhUse(bufp); -#endif - return TRUE; -} - -staticfn boolean -cnf_line_QT_FONTSIZE(char *bufp) -{ -#ifdef QT_GRAPHICS - extern char *qt_fontsize; - - if (qt_fontsize == NULL) - qt_fontsize = dupstr(bufp); -#else - nhUse(bufp); -#endif - return TRUE; -} - -staticfn boolean -cnf_line_QT_COMPACT(char *bufp) -{ -#ifdef QT_GRAPHICS - extern int qt_compact_mode; - - qt_compact_mode = atoi(bufp); -#else - nhUse(bufp); -#endif - return TRUE; -} - -typedef boolean (*config_line_stmt_func)(char *); - -/* normal */ -#define CNFL_N(n, l) { #n, l, FALSE, FALSE, cnf_line_##n } -/* normal, alias */ -#define CNFL_NA(n, l, f) { #n, l, FALSE, FALSE, cnf_line_##f } -/* sysconf only */ -#define CNFL_S(n, l) { #n, l, TRUE, FALSE, cnf_line_##n } - -static const struct match_config_line_stmt { - const char *name; - int len; - boolean syscnf_only; - boolean origbuf; - config_line_stmt_func fn; -} config_line_stmt[] = { - /* OPTIONS handled separately */ - { "OPTIONS", 4, FALSE, TRUE, cnf_line_OPTIONS }, - CNFL_N(AUTOPICKUP_EXCEPTION, 5), - CNFL_N(BINDINGS, 4), - CNFL_N(AUTOCOMPLETE, 5), - CNFL_N(MSGTYPE, 7), - CNFL_N(HACKDIR, 4), - CNFL_N(LEVELDIR, 4), - CNFL_NA(LEVELS, 4, LEVELDIR), - CNFL_N(SAVEDIR, 4), - CNFL_N(BONESDIR, 5), - CNFL_N(DATADIR, 4), - CNFL_N(SCOREDIR, 4), - CNFL_N(LOCKDIR, 4), - CNFL_N(CONFIGDIR, 4), - CNFL_N(TROUBLEDIR, 4), - CNFL_N(NAME, 4), - CNFL_N(ROLE, 4), - CNFL_NA(CHARACTER, 4, ROLE), - CNFL_N(dogname, 3), - CNFL_N(catname, 3), -#ifdef SYSCF - CNFL_S(WIZARDS, 7), - CNFL_S(SHELLERS, 8), - CNFL_S(MSGHANDLER, 9), - CNFL_S(EXPLORERS, 7), - CNFL_S(DEBUGFILES, 5), - CNFL_S(DUMPLOGFILE, 7), - CNFL_S(GENERICUSERS, 12), - CNFL_S(BONES_POOLS, 10), - CNFL_S(SUPPORT, 7), - CNFL_S(RECOVER, 7), - CNFL_S(CHECK_SAVE_UID, 14), - CNFL_S(CHECK_PLNAME, 12), - CNFL_S(SEDUCE, 6), - CNFL_S(HIDEUSAGE, 9), - CNFL_S(MAXPLAYERS, 10), - CNFL_S(PERSMAX, 7), - CNFL_S(PERS_IS_UID, 11), - CNFL_S(ENTRYMAX, 8), - CNFL_S(POINTSMIN, 9), - CNFL_S(MAX_STATUENAME_RANK, 10), - CNFL_S(LIVELOG, 7), - CNFL_S(PANICTRACE_LIBC, 15), - CNFL_S(PANICTRACE_GDB, 14), - CNFL_S(CRASHREPORTURL, 13), - CNFL_S(GDBPATH, 7), - CNFL_S(GREPPATH, 7), - CNFL_S(SAVEFORMAT, 10), - CNFL_S(BONESFORMAT, 11), - CNFL_S(ACCESSIBILITY, 13), - CNFL_S(PORTABLE_DEVICE_PATHS, 8), -#endif /*SYSCF*/ - CNFL_N(BOULDER, 3), - CNFL_N(MENUCOLOR, 9), - CNFL_N(HILITE_STATUS, 6), - CNFL_N(WARNINGS, 5), - CNFL_N(ROGUESYMBOLS, 4), - CNFL_N(SYMBOLS, 4), - CNFL_N(WIZKIT, 6), -#ifdef USER_SOUNDS - CNFL_N(SOUNDDIR, 8), - CNFL_N(SOUND, 5), -#endif /*USER_SOUNDS*/ - CNFL_N(QT_TILEWIDTH, 12), - CNFL_N(QT_TILEHEIGHT, 13), - CNFL_N(QT_FONTSIZE, 11), - CNFL_N(QT_COMPACT, 10) -}; - -#undef CNFL_N -#undef CNFL_NA -#undef CNFL_S - -boolean -parse_config_line(char *origbuf) -{ -#if defined(MICRO) && !defined(NOCWD_ASSUMPTIONS) - static boolean ramdisk_specified = FALSE; -#endif -#ifdef SYSCF - int src = iflags.parse_config_file_src; - boolean in_sysconf = (src == set_in_sysconf); -#endif - char *bufp, buf[4 * BUFSZ]; - int i; - - while (*origbuf == ' ' || *origbuf == '\t') /* skip leading whitespace */ - ++origbuf; /* (caller probably already did this) */ - (void) strncpy(buf, origbuf, sizeof buf - 1); - buf[sizeof buf - 1] = '\0'; /* strncpy not guaranteed to NUL terminate */ - /* convert any tab to space, condense consecutive spaces into one, - remove leading and trailing spaces (exception: if there is nothing - but spaces, one of them will be kept even though it leads/trails) */ - mungspaces(buf); - - /* find the '=' or ':' */ - bufp = find_optparam(buf); - if (!bufp) { - config_error_add("Not a config statement, missing '='"); - return FALSE; - } - /* skip past '=', then space between it and value, if any */ - ++bufp; - if (*bufp == ' ') - ++bufp; - - for (i = 0; i < SIZE(config_line_stmt); i++) { -#ifdef SYSCF - if (config_line_stmt[i].syscnf_only && !in_sysconf) - continue; -#endif - if (match_varname(buf, config_line_stmt[i].name, - config_line_stmt[i].len)) { - char *parm = config_line_stmt[i].origbuf ? origbuf : bufp; - - return config_line_stmt[i].fn(parm); - } - } - - config_error_add("Unknown config statement"); - return FALSE; -} - -#ifdef USER_SOUNDS -boolean -can_read_file(const char *filename) -{ - return (boolean) (access(filename, 4) == 0); -} -#endif /* USER_SOUNDS */ - -struct _config_error_errmsg { - int line_num; - char *errormsg; - struct _config_error_errmsg *next; -}; - -struct _config_error_frame { - int line_num; - int num_errors; - boolean origline_shown; - boolean fromfile; - boolean secure; - char origline[4 * BUFSZ]; - char source[BUFSZ]; - struct _config_error_frame *next; -}; - -static struct _config_error_frame *config_error_data = 0; -static struct _config_error_errmsg *config_error_msg = 0; - -void -config_error_init(boolean from_file, const char *sourcename, boolean secure) -{ - struct _config_error_frame *tmp = (struct _config_error_frame *) - alloc(sizeof *tmp); - - tmp->line_num = 0; - tmp->num_errors = 0; - tmp->origline_shown = FALSE; - tmp->fromfile = from_file; - tmp->secure = secure; - tmp->origline[0] = '\0'; - if (sourcename && sourcename[0]) { - (void) strncpy(tmp->source, sourcename, sizeof (tmp->source) - 1); - tmp->source[sizeof (tmp->source) - 1] = '\0'; - } else - tmp->source[0] = '\0'; - - tmp->next = config_error_data; - config_error_data = tmp; - program_state.config_error_ready = TRUE; -} - -staticfn boolean -config_error_nextline(const char *line) -{ - struct _config_error_frame *ced = config_error_data; - - if (!ced) - return FALSE; - - if (ced->num_errors && ced->secure) - return FALSE; - - ced->line_num++; - ced->origline_shown = FALSE; - if (line && line[0]) { - (void) strncpy(ced->origline, line, sizeof (ced->origline) - 1); - ced->origline[sizeof (ced->origline) - 1] = '\0'; - } else - ced->origline[0] = '\0'; - - return TRUE; -} - -int -l_get_config_errors(lua_State *L) -{ - struct _config_error_errmsg *dat = config_error_msg; - struct _config_error_errmsg *tmp; - int idx = 1; - - lua_newtable(L); - - while (dat) { - lua_pushinteger(L, idx++); - lua_newtable(L); - nhl_add_table_entry_int(L, "line", dat->line_num); - nhl_add_table_entry_str(L, "error", dat->errormsg); - lua_settable(L, -3); - tmp = dat->next; - free(dat->errormsg); - dat->errormsg = (char *) 0; - free(dat); - dat = tmp; - } - config_error_msg = (struct _config_error_errmsg *) 0; - - return 1; -} - -/* varargs 'config_error_add()' moved to pline.c */ -void -config_erradd(const char *buf) -{ - char lineno[QBUFSZ]; - const char *punct; - - if (!buf || !*buf) - buf = "Unknown error"; - - /* if buf[] doesn't end in a period, exclamation point, or question mark, - we'll include a period (in the message, not appended to buf[]) */ - punct = c_eos((char *) buf) - 1; /* eos(buf)-1 is valid */ - punct = strchr(".!?", *punct) ? "" : "."; - - if (!program_state.config_error_ready) { - /* either very early, where pline() will use raw_print(), or - player gave bad value when prompted by interactive 'O' command */ - pline("%s%s%s", !iflags.window_inited ? "config_error_add: " : "", - buf, punct); - wait_synch(); - return; - } - - if (iflags.in_lua) { - struct _config_error_errmsg *dat - = (struct _config_error_errmsg *) alloc(sizeof *dat); - - dat->next = config_error_msg; - dat->line_num = config_error_data->line_num; - dat->errormsg = dupstr(buf); - config_error_msg = dat; - return; - } - - config_error_data->num_errors++; - if (!config_error_data->origline_shown && !config_error_data->secure) { - pline("\n%s", config_error_data->origline); - config_error_data->origline_shown = TRUE; - } - if (config_error_data->line_num > 0 && !config_error_data->secure) { - Sprintf(lineno, "Line %d: ", config_error_data->line_num); - } else - lineno[0] = '\0'; - - pline("%s %s%s%s", config_error_data->secure ? "Error:" : " *", - lineno, buf, punct); -} - -int -config_error_done(void) -{ - int n; - struct _config_error_frame *tmp = config_error_data; - - if (!config_error_data) - return 0; - n = config_error_data->num_errors; -#ifndef USER_SOUNDS - if (gn.no_sound_notified > 0) { - /* no USER_SOUNDS; config_error_add() was called once for first - SOUND or SOUNDDIR entry seen, then skipped for any others; - include those skipped ones in the total error count */ - n += (gn.no_sound_notified - 1); - gn.no_sound_notified = 0; - } -#endif - if (n) { - boolean cmdline = !strcmp(config_error_data->source, "command line"); - - pline("\n%d error%s %s %s.\n", n, plur(n), cmdline ? "on" : "in", - *config_error_data->source ? config_error_data->source - : configfile); - wait_synch(); - } - config_error_data = tmp->next; - free(tmp); - program_state.config_error_ready = (config_error_data != 0); - return n; -} - -boolean -read_config_file(const char *filename, int src) -{ - FILE *fp; - boolean rv = TRUE; - - if (!(fp = fopen_config_file(filename, src))) - return FALSE; - - /* begin detection of duplicate configfile options */ - reset_duplicate_opt_detection(); - free_config_sections(); - iflags.parse_config_file_src = src; - - rv = parse_conf_file(fp, parse_config_line); - (void) fclose(fp); - - free_config_sections(); - /* turn off detection of duplicate configfile options */ - reset_duplicate_opt_detection(); - return rv; -} - -struct _cnf_parser_state { - char *inbuf; - unsigned inbufsz; - int rv; - char *ep; - char *buf; - boolean skip, morelines; - boolean cont; - boolean pbreak; -}; - -/* Initialize config parser data */ -staticfn void -cnf_parser_init(struct _cnf_parser_state *parser) -{ - parser->rv = TRUE; /* assume successful parse */ - parser->ep = parser->buf = (char *) 0; - parser->skip = FALSE; - parser->morelines = FALSE; - parser->inbufsz = 4 * BUFSZ; - parser->inbuf = (char *) alloc(parser->inbufsz); - parser->cont = FALSE; - parser->pbreak = FALSE; - memset(parser->inbuf, 0, parser->inbufsz); -} - -/* caller has finished with 'parser' (except for 'rv' so leave that intact) */ -staticfn void -cnf_parser_done(struct _cnf_parser_state *parser) -{ - parser->ep = 0; /* points into parser->inbuf, so becoming stale */ - if (parser->inbuf) - free(parser->inbuf), parser->inbuf = 0; - if (parser->buf) - free(parser->buf), parser->buf = 0; -} - -/* - * Parse config buffer, handling comments, empty lines, config sections, - * CHOOSE, and line continuation, calling proc for every valid line. - * - * Continued lines are merged together with one space in between. - */ -staticfn void -parse_conf_buf(struct _cnf_parser_state *p, boolean (*proc)(char *arg)) -{ - p->cont = FALSE; - p->pbreak = FALSE; - p->ep = strchr(p->inbuf, '\n'); - if (p->skip) { /* in case previous line was too long */ - if (p->ep) - p->skip = FALSE; /* found newline; next line is normal */ - } else { - if (!p->ep) { /* newline missing */ - if (strlen(p->inbuf) < (p->inbufsz - 2)) { - /* likely the last line of file is just - missing a newline; process it anyway */ - p->ep = eos(p->inbuf); - } else { - config_error_add("Line too long, skipping"); - p->skip = TRUE; /* discard next fgets */ - } - } else { - *p->ep = '\0'; /* remove newline */ - } - if (p->ep) { - char *tmpbuf = (char *) 0; - int len; - boolean ignoreline = FALSE; - boolean oldline = FALSE; - - /* line continuation (trailing '\') */ - p->morelines = (--p->ep >= p->inbuf && *p->ep == '\\'); - if (p->morelines) - *p->ep = '\0'; - - /* trim off spaces at end of line */ - while (p->ep >= p->inbuf - && (*p->ep == ' ' || *p->ep == '\t' || *p->ep == '\r')) - *p->ep-- = '\0'; - - if (!config_error_nextline(p->inbuf)) { - p->rv = FALSE; - if (p->buf) - free(p->buf), p->buf = (char *) 0; - p->pbreak = TRUE; - return; - } - - p->ep = p->inbuf; - while (*p->ep == ' ' || *p->ep == '\t') - ++p->ep; - - /* ignore empty lines and full-line comment lines */ - if (!*p->ep || *p->ep == '#') - ignoreline = TRUE; - - if (p->buf) - oldline = TRUE; - - /* merge now read line with previous ones, if necessary */ - if (!ignoreline) { - len = (int) strlen(p->ep) + 1; /* +1: final '\0' */ - if (p->buf) - len += (int) strlen(p->buf) + 1; /* +1: space */ - tmpbuf = (char *) alloc(len); - *tmpbuf = '\0'; - if (p->buf) { - Strcat(strcpy(tmpbuf, p->buf), " "); - free(p->buf), p->buf = 0; - } - p->buf = strcat(tmpbuf, p->ep); - if (strlen(p->buf) >= p->inbufsz) - p->buf[p->inbufsz - 1] = '\0'; - } - - if (p->morelines || (ignoreline && !oldline)) - return; - - if (handle_config_section(p->buf)) { - free(p->buf), p->buf = (char *) 0; - return; - } - - /* from here onwards, we'll handle buf only */ - - if (match_varname(p->buf, "CHOOSE", 6)) { - char *section; - char *bufp = find_optparam(p->buf); - - if (!bufp) { - config_error_add("Format is CHOOSE=section1" - ",section2,..."); - p->rv = FALSE; - free(p->buf), p->buf = (char *) 0; - return; - } - bufp++; - if (gc.config_section_chosen) - free(gc.config_section_chosen), - gc.config_section_chosen = 0; - section = choose_random_part(bufp, ','); - if (section) { - gc.config_section_chosen = dupstr(section); - } else { - config_error_add("No config section to choose"); - p->rv = FALSE; - } - free(p->buf), p->buf = (char *) 0; - return; - } - - if (!(*proc)(p->buf)) - p->rv = FALSE; - - free(p->buf), p->buf = (char *) 0; - } - } -} - -boolean -parse_conf_str(const char *str, boolean (*proc)(char *arg)) -{ - size_t len; - struct _cnf_parser_state parser; - - cnf_parser_init(&parser); - free_config_sections(); - config_error_init(FALSE, "parse_conf_str", FALSE); - while (str && *str) { - len = 0; - while (*str && len < (parser.inbufsz-1)) { - parser.inbuf[len] = *str; - len++; - str++; - if (parser.inbuf[len-1] == '\n') - break; - } - parser.inbuf[len] = '\0'; - parse_conf_buf(&parser, proc); - if (parser.pbreak) - break; - } - cnf_parser_done(&parser); - - free_config_sections(); - config_error_done(); - return parser.rv; -} - -/* parse_conf_file - * - * Read from file fp, calling parse_conf_buf for each line. - */ -staticfn boolean -parse_conf_file(FILE *fp, boolean (*proc)(char *arg)) -{ - struct _cnf_parser_state parser; - - cnf_parser_init(&parser); - free_config_sections(); - - while (fgets(parser.inbuf, parser.inbufsz, fp)) { - parse_conf_buf(&parser, proc); - if (parser.pbreak) - break; - } - cnf_parser_done(&parser); - - free_config_sections(); - return parser.rv; -} - -#ifdef SYSCF -staticfn void -parseformat(int *arr, char *str) -{ - const char *legal[] = { "historical", "lendian", "ascii" }; - int i, kwi = 0, words = 0; - char *p = str, *keywords[2]; - - while (*p) { - while (*p && isspace((uchar) *p)) { - *p = '\0'; - p++; - } - if (*p) { - words++; - if (kwi < 2) - keywords[kwi++] = p; - } - while (*p && !isspace((uchar) *p)) - p++; - } - if (!words) { - impossible("missing format list"); - return; - } - while (--kwi >= 0) - if (kwi < 2) { - for (i = 0; i < SIZE(legal); ++i) { - if (!strcmpi(keywords[kwi], legal[i])) - arr[kwi] = i + 1; - } - } -} -#endif /* SYSCF */ - -/* ---------- END CONFIG FILE HANDLING ----------- */ - /* ---------- BEGIN WIZKIT FILE HANDLING ----------- */ staticfn FILE * @@ -4621,7 +2785,7 @@ reveal_paths(int code) fqn = fqname(filep, SYSCONFPREFIX, 0); if (fqn) { set_configfile_name(fqn); - filep = configfile; + filep = get_configfile(); } raw_printf(" \"%s\"", filep); if (code == 1) { @@ -4765,7 +2929,7 @@ reveal_paths(int code) Strcat(buf, "/"); } endp = eos(buf); - copynchars(endp, default_configfile, + copynchars(endp, get_default_configfile(), (int) (sizeof buf - 1 - strlen(buf))); #if defined(__APPLE__) /* UNIX+__APPLE__ => MacOSX aka OSX aka macOS */ if (envp) { @@ -4783,7 +2947,7 @@ reveal_paths(int code) if (access(buf, 4) == -1) { /* second alternate failed too, so revert to the original default ("$HOME/.nethackrc") for message */ - copynchars(endp, default_configfile, + copynchars(endp, get_default_configfile(), (int) (sizeof buf - 1 - strlen(buf))); } } @@ -4794,9 +2958,9 @@ reveal_paths(int code) #else /* !UNIX */ fqn = (const char *) 0; #ifdef PREFIXES_IN_USE - fqn = fqname(default_configfile, CONFIGPREFIX, 2); + fqn = fqname(get_default_configfile(), CONFIGPREFIX, 2); #endif - raw_printf(" \"%s\"", fqn ? fqn : default_configfile); + raw_printf(" \"%s\"", fqn ? fqn : get_default_configfile()); #endif /* ?UNIX */ raw_print(""); diff --git a/src/options.c b/src/options.c index 704351790..82e1bafbb 100644 --- a/src/options.c +++ b/src/options.c @@ -111,7 +111,7 @@ static struct allopt_t allopt[SIZE(allopt_init)]; /* use rest of file */ -extern char configfile[]; /* for messages; files.c */ +/* extern char configfile[]; */ /* for messages; files.c */ extern const struct symparse loadsyms[]; #if defined(TOS) extern boolean colors_changed; /* in tos.c */ @@ -457,8 +457,8 @@ ask_do_tutorial(void) boolean norc; int n, pass = 0; - rc = nh_basename(configfile, TRUE); - norc = !strcmp(configfile, "/dev/null"); + rc = nh_basename(get_configfile(), TRUE); + norc = !strcmp(get_configfile(), "/dev/null"); Snprintf(buf, sizeof buf, "Put \"OPTIONS=!tutorial\" in %s to skip this query.", (rc && *rc && !norc) ? rc : "your configuration file"); @@ -6799,10 +6799,10 @@ staticfn void rejectoption(const char *optname) { #ifdef MICRO - pline("\"%s\" settable only from %s.", optname, configfile); + pline("\"%s\" settable only from %s.", optname, get_configfile()); #else pline("%s can be set only from NETHACKOPTIONS or %s.", optname, - configfile); + get_configfile()); #endif } @@ -9474,7 +9474,7 @@ option_help(void) datawin = create_nhwindow(NHW_TEXT); Snprintf(buf, sizeof buf, - "Set options as OPTIONS= in %s", configfile); + "Set options as OPTIONS= in %s", get_configfile()); opt_intro[CONFIG_SLOT] = (const char *) buf; for (i = 0; opt_intro[i]; i++) putstr(datawin, 0, opt_intro[i]); diff --git a/sys/msdos/Makefile.GCC b/sys/msdos/Makefile.GCC index 2828b60f3..069b2679a 100644 --- a/sys/msdos/Makefile.GCC +++ b/sys/msdos/Makefile.GCC @@ -272,31 +272,31 @@ DLBOBJ = $(O)dlb.o VOBJ01 = $(O)allmain.o $(O)alloc.o $(O)apply.o $(O)artifact.o $(O)attrib.o -VOBJ02 = $(O)ball.o $(O)bones.o $(O)botl.o $(O)calendar.o $(O)cmd.o -VOBJ03 = $(O)coloratt.o $(O)date.o $(O)dbridge.o $(O)decl.o $(O)detect.o -VOBJ04 = $(O)dig.o $(O)display.o $(O)do.o $(O)do_name.o $(O)do_wear.o -VOBJ05 = $(O)dog.o $(O)dogmove.o $(O)dokick.o $(O)dothrow.o $(O)drawing.o -VOBJ06 = $(O)dungeon.o $(O)eat.o $(O)end.o $(O)engrave.o $(O)exper.o -VOBJ07 = $(O)explode.o $(O)extralev.o $(O)files.o $(O)fountain.o $(O)getpos.o -VOBJ08 = $(O)glyphs.o $(O)getline.o $(O)hack.o $(O)hacklib.o $(O)insight.o -VOBJ09 = $(O)invent.o $(O)isaac64.o $(O)lock.o $(O)mail.o $(O)main.o -VOBJ10 = $(O)makemon.o $(O)mcastu.o $(O)mdlib.o $(O)mhitm.o $(O)mhitu.o -VOBJ11 = $(O)minion.o $(O)mkmap.o $(O)mklev.o $(O)mkmaze.o $(O)mkobj.o -VOBJ12 = $(O)mkroom.o $(O)mon.o $(O)mondata.o $(O)monmove.o $(O)monst.o -VOBJ13 = $(O)mplayer.o $(O)mthrowu.o $(O)muse.o $(O)music.o $(O)o_init.o -VOBJ14 = $(O)objects.o $(O)objnam.o $(O)options.o $(O)pickup.o $(O)pline.o -VOBJ15 = $(O)polyself.o $(O)potion.o $(O)quest.o $(O)questpgr.o $(O)pager.o -VOBJ16 = $(O)pray.o $(O)priest.o $(O)read.o $(O)rect.o $(O)region.o -VOBJ17 = $(O)report.o $(O)restore.o $(O)rip.o $(O)rnd.o $(O)role.o -VOBJ18 = $(O)rumors.o $(O)save.o $(O)selvar.o $(O)sfstruct.o $(O)shk.o -VOBJ19 = $(O)shknam.o $(O)sit.o $(O)sounds.o $(O)sp_lev.o $(O)spell.o -VOBJ20 = $(O)stairs.o $(O)steal.o $(O)steed.o $(O)symbols.o $(O)sys.o -VOBJ21 = $(O)teleport.o $(O)strutil.o $(O)termcap.o $(O)timeout.o $(O)topl.o -VOBJ22 = $(O)topten.o $(O)trap.o $(O)u_init.o $(O)uhitm.o $(O)utf8map.o -VOBJ23 = $(O)vault.o $(O)track.o $(O)vision.o $(O)weapon.o $(O)were.o -VOBJ24 = $(O)wield.o $(O)windows.o $(O)wintty.o $(O)wizard.o $(O)wizcmds.o -VOBJ25 = $(O)worm.o $(O)worn.o $(O)write.o $(O)zap.o $(O)light.o -VOBJ26 = $(O)dlb.o $(REGEX) +VOBJ02 = $(O)ball.o $(O)bones.o $(O)botl.o $(O)calendar.o $(O)cfgfiles.o +VOBJ03 = $(O)cmd.o $(O)coloratt.o $(O)date.o $(O)dbridge.o $(O)decl.o +VOBJ04 = $(O)detect.o $(O)dig.o $(O)display.o $(O)do.o $(O)do_name.o +VOBJ05 = $(O)do_wear.o $(O)dog.o $(O)dogmove.o $(O)dokick.o $(O)dothrow.o +VOBJ06 = $(O)drawing.o $(O)dungeon.o $(O)eat.o $(O)end.o $(O)engrave.o +VOBJ07 = $(O)exper.o $(O)explode.o $(O)extralev.o $(O)files.o $(O)fountain.o +VOBJ08 = $(O)getpos.o $(O)glyphs.o $(O)getline.o $(O)hack.o $(O)hacklib.o +VOBJ09 = $(O)insight.o $(O)invent.o $(O)isaac64.o $(O)lock.o $(O)mail.o +VOBJ10 = $(O)main.o $(O)makemon.o $(O)mcastu.o $(O)mdlib.o $(O)mhitm.o +VOBJ11 = $(O)mhitu.o $(O)minion.o $(O)mkmap.o $(O)mklev.o $(O)mkmaze.o +VOBJ12 = $(O)mkobj.o $(O)mkroom.o $(O)mon.o $(O)mondata.o $(O)monmove.o +VOBJ13 = $(O)monst.o $(O)mplayer.o $(O)mthrowu.o $(O)muse.o $(O)music.o +VOBJ14 = $(O)o_init.o $(O)objects.o $(O)objnam.o $(O)options.o $(O)pickup.o +VOBJ15 = $(O)pline.o $(O)polyself.o $(O)potion.o $(O)quest.o $(O)questpgr.o +VOBJ16 = $(O)pager.o $(O)pray.o $(O)priest.o $(O)read.o $(O)rect.o +VOBJ17 = $(O)region.o $(O)report.o $(O)restore.o $(O)rip.o $(O)rnd.o +VOBJ18 = $(O)role.o $(O)rumors.o $(O)save.o $(O)selvar.o $(O)sfstruct.o +VOBJ19 = $(O)shk.o $(O)shknam.o $(O)sit.o $(O)sounds.o $(O)sp_lev.o +VOBJ20 = $(O)spell.o $(O)stairs.o $(O)steal.o $(O)steed.o $(O)symbols.o +VOBJ21 = $(O)sys.o $(O)teleport.o $(O)strutil.o $(O)termcap.o $(O)timeout.o +VOBJ22 = $(O)topl.o $(O)topten.o $(O)trap.o $(O)u_init.o $(O)uhitm.o +VOBJ23 = $(O)utf8map.o $(O)vault.o $(O)track.o $(O)vision.o $(O)weapon.o +VOBJ24 = $(O)were.o $(O)wield.o $(O)windows.o $(O)wintty.o $(O)wizard.o +VOBJ25 = $(O)wizcmds.o $(O)worm.o $(O)worn.o $(O)write.o $(O)zap.o +VOBJ26 = $(O)light.o $(O)dlb.o $(REGEX) SOBJ = $(O)msdos.o $(O)pcsys.o $(O)tty.o $(O)unix.o \ $(O)video.o $(O)vidtxt.o $(O)pckeys.o diff --git a/sys/unix/Makefile.src b/sys/unix/Makefile.src index d8283a03f..d2e3c8e91 100644 --- a/sys/unix/Makefile.src +++ b/sys/unix/Makefile.src @@ -582,7 +582,7 @@ HOSTOBJ = $(FIRSTOBJ) alloc.o drawing.o HOBJ = $(TARGETPFX)allmain.o $(TARGETPFX)alloc.o \ $(TARGETPFX)apply.o $(TARGETPFX)artifact.o $(TARGETPFX)attrib.o \ $(TARGETPFX)ball.o $(TARGETPFX)bones.o $(TARGETPFX)botl.o \ - $(TARGETPFX)calendar.o $(TARGETPFX)cmd.o \ + $(TARGETPFX)calendar.o $(TARGETPFX)cfgfiles.o $(TARGETPFX)cmd.o \ $(TARGETPFX)coloratt.o $(TARGETPFX)dbridge.o $(TARGETPFX)decl.o \ $(TARGETPFX)detect.o $(TARGETPFX)dig.o $(TARGETPFX)display.o \ $(TARGETPFX)dlb.o $(TARGETPFX)do.o $(TARGETPFX)do_name.o \ @@ -1127,6 +1127,7 @@ $(TARGETPFX)ball.o: ball.c $(HACK_H) $(TARGETPFX)bones.o: bones.c $(HACK_H) $(TARGETPFX)botl.o: botl.c $(HACK_H) $(TARGETPFX)calendar.o: calendar.c $(HACK_H) +$(TARGETPFX)cfgfiles.o: cfgfiles.c $(HACK_H) $(TARGETPFX)cmd.o: cmd.c $(HACK_H) ../include/func_tab.h $(TARGETPFX)coloratt.o: coloratt.c $(HACK_H) $(TARGETPFX)dbridge.o: dbridge.c $(HACK_H) diff --git a/sys/unix/NetHack.xcodeproj/project.pbxproj b/sys/unix/NetHack.xcodeproj/project.pbxproj index 762be72de..f42f2a312 100644 --- a/sys/unix/NetHack.xcodeproj/project.pbxproj +++ b/sys/unix/NetHack.xcodeproj/project.pbxproj @@ -165,6 +165,7 @@ 5493735A277AAE830031FE02 /* alloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 31B8A36521A238040055BD01 /* alloc.c */; }; 54A3D3EC282C55A900143F8C /* utf8map.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A3D3EB282C55A900143F8C /* utf8map.c */; }; 54BD340D2D8B70350073C484 /* hacklib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31B8A36421A238040055BD01 /* hacklib.c */; }; + 54EBA6D32DDED3F100CD20EC /* cfgfiles.c in Sources */ = {isa = PBXBuildFile; fileRef = 54EBA6D22DDED3F100CD20EC /* cfgfiles.c */; }; 54FB2B4B246310A600397C0E /* symbols.c in Sources */ = {isa = PBXBuildFile; fileRef = 54FB2B4A246310A600397C0E /* symbols.c */; }; 54FCE8292223261F00F393C8 /* isaac64.c in Sources */ = {isa = PBXBuildFile; fileRef = 54FCE8282223261F00F393C8 /* isaac64.c */; }; BAB57DB527C1C3E200FCF150 /* libnhlua.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BAE8010A27B97760002B3786 /* libnhlua.a */; }; @@ -545,6 +546,7 @@ 54BD34102D8B711E0073C484 /* selvar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = selvar.h; path = ../../include/selvar.h; sourceTree = ""; }; 54BD34112D8B711E0073C484 /* stairs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = stairs.h; path = ../../include/stairs.h; sourceTree = ""; }; 54BD34122D8B711E0073C484 /* weight.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = weight.h; path = ../../include/weight.h; sourceTree = ""; }; + 54EBA6D22DDED3F100CD20EC /* cfgfiles.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = cfgfiles.c; path = /Users/mikeallison/Documents/git/NHsource/src/cfgfiles.c; sourceTree = ""; }; 54FB2B4A246310A600397C0E /* symbols.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = symbols.c; path = ../../src/symbols.c; sourceTree = ""; }; 54FCE8282223261F00F393C8 /* isaac64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = isaac64.c; path = ../../src/isaac64.c; sourceTree = ""; }; BAE8010A27B97760002B3786 /* libnhlua.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libnhlua.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -657,6 +659,7 @@ 3189578C21A1FF8200FB2ABE /* src */ = { isa = PBXGroup; children = ( + 54EBA6D22DDED3F100CD20EC /* cfgfiles.c */, 056E43BB2C810EE800FD1F52 /* calendar.c */, 056E43BC2C810EE800FD1F52 /* coloratt.c */, 056E43BD2C810EE800FD1F52 /* getpos.c */, @@ -1790,6 +1793,7 @@ 31B8A3D121A238060055BD01 /* do.c in Sources */, 31B8A39021A238060055BD01 /* objnam.c in Sources */, 31B8A3B621A238060055BD01 /* bones.c in Sources */, + 54EBA6D32DDED3F100CD20EC /* cfgfiles.c in Sources */, 31B8A3C521A238060055BD01 /* timeout.c in Sources */, 31B8A3AD21A238060055BD01 /* uhitm.c in Sources */, 31B8A3B321A238060055BD01 /* track.c in Sources */, diff --git a/sys/vms/Makefile.src b/sys/vms/Makefile.src index 14b75a3da..f2efc62bb 100644 --- a/sys/vms/Makefile.src +++ b/sys/vms/Makefile.src @@ -147,8 +147,8 @@ HACK_H = $(SRC)hack.h-t # all .c that are part of the main NetHack program and are not operating- or # windowing-system specific HACKCSRC = allmain.c alloc.c apply.c artifact.c attrib.c ball.c bones.c \ - botl.c calendar.c cmd.c coloratt.c dbridge.c decl.c detect.c dig.c \ - display.c dlb.c do.c do_name.c do_wear.c dog.c dogmove.c dokick.c \ + botl.c calendar.c cfgfiles.c cmd.c coloratt.c dbridge.c decl.c detect.c \ + dig.c display.c dlb.c do.c do_name.c do_wear.c dog.c dogmove.c dokick.c \ dothrow.c drawing.c dungeon.c eat.c end.c engrave.c exper.c \ explode.c extralev.c files.c fountain.c getpos.c glyphs.c hack.c \ hacklib.c insight.c invent.c light.c lock.c \ @@ -191,9 +191,9 @@ FIRSTOBJ = vmsmisc.obj,vmsfiles.obj,monst.obj,objects.obj # split up long list so that we can write pieces of it into nethack.opt HOBJ1 = allmain.obj,alloc.obj,apply.obj,artifact.obj,attrib.obj, \ - ball.obj,bones.obj,botl.obj,calendar.obj,cmd.obj,coloratt.obj, \ - dbridge.obj,decl.obj,detect.obj,dig.obj,display.obj,dlb.obj, \ - do.obj,do_name.obj,do_wear.obj + ball.obj,bones.obj,botl.obj,calendar.obj,cfgfiles.obj,cmd.obj, \ + coloratt.obj,dbridge.obj,decl.obj,detect.obj,dig.obj,display.obj, \ + dlb.obj,do.obj,do_name.obj,do_wear.obj HOBJ2 = dog.obj,dogmove.obj,dokick.obj,dothrow.obj,drawing.obj, \ dungeon.obj,eat.obj,end.obj,engrave.obj,exper.obj,explode.obj, \ extralev.obj,files.obj,fountain.obj,getpos.obj,glyphs.obj,hack.obj, \ @@ -500,6 +500,7 @@ ball.obj : ball.c $(HACK_H) bones.obj : bones.c $(HACK_H) botl.obj : botl.c $(HACK_H) cmd.obj : cmd.c $(HACK_H) $(INC)func_tab.h +cfgfiles.obj : cfgfiles.c $(HACK_H) dbridge.obj : dbridge.c $(HACK_H) decl.obj : decl.c $(HACK_H) detect.obj : detect.c $(HACK_H) $(INC)artifact.h diff --git a/sys/vms/Makefile_src.vms b/sys/vms/Makefile_src.vms index dd46aafad..5123dfe4c 100644 --- a/sys/vms/Makefile_src.vms +++ b/sys/vms/Makefile_src.vms @@ -701,6 +701,7 @@ $(TARGETPFX)ball.obj: ball.c $(HACK_H) $(TARGETPFX)bones.obj: bones.c $(HACK_H) $(TARGETPFX)botl.obj: botl.c $(HACK_H) $(TARGETPFX)calendar.obj: calendar.c $(HACK_H) +$(TARGETPFX)cfgfiles.obj: cfgfiles.c $(HACK_H) $(TARGETPFX)cmd.obj: cmd.c $(HACK_H) $(INCL)func_tab.h $(TARGETPFX)coloratt.obj: coloratt.c $(HACK_H) $(TARGETPFX)dbridge.obj: dbridge.c $(HACK_H) diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index e16bdb31e..0698ae200 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -1000,7 +1000,7 @@ endif # HAVE_SOUNDLIB # nethackw #========================================== COREOBJS = $(addsuffix .o, allmain alloc apply artifact attrib ball bones botl \ - calendar cmd coloratt cppregex \ + calendar cfgfiles cmd coloratt cppregex \ dbridge decl detect dig display dlb do do_name do_wear \ dog dogmove dokick dothrow drawing dungeon \ eat end engrave exper explode extralev files fountain \ diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index e19d067d7..a0b8387e9 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -846,34 +846,34 @@ TTYOBJTTY = $(OTTY)topl.o $(OTTY)getline.o $(OTTY)wintty.o COREOBJTTY = \ $(OTTY)allmain.o $(OTTY)alloc.o $(OTTY)apply.o $(OTTY)artifact.o \ $(OTTY)attrib.o $(OTTY)ball.o $(OTTY)bones.o $(OTTY)botl.o \ - $(OTTY)calendar.o $(OTTY)cmd.o $(OTTY)coloratt.o $(OTTY)dbridge.o \ - $(OTTY)decl.o $(OTTY)detect.o $(OTTY)dig.o $(OTTY)display.o \ - $(OTTY)do.o $(OTTY)do_name.o $(OTTY)do_wear.o $(OTTY)dog.o \ - $(OTTY)dogmove.o $(OTTY)dokick.o $(OTTY)dothrow.o $(OTTY)drawing.o \ - $(OTTY)dungeon.o $(OTTY)eat.o $(OTTY)end.o $(OTTY)engrave.o \ - $(OTTY)exper.o $(OTTY)explode.o $(OTTY)extralev.o $(OTTY)files.o \ - $(OTTY)fountain.o $(OTTY)getpos.o $(OTTY)glyphs.o $(OTTY)hack.o \ - $(OTTY)insight.o $(OTTY)invent.o $(OTTY)isaac64.o $(OTTY)light.o \ - $(OTTY)lock.o $(OTTY)mail.o $(OTTY)makemon.o $(OTTY)mcastu.o \ - $(OTTY)mhitm.o $(OTTY)mhitu.o $(OTTY)minion.o $(OTTY)mklev.o \ - $(OTTY)mkmap.o $(OTTY)mkmaze.o $(OTTY)mkobj.o $(OTTY)mkroom.o \ - $(OTTY)mon.o $(OTTY)mondata.o $(OTTY)monmove.o $(OTTY)monst.o \ - $(OTTY)mplayer.o $(OTTY)mthrowu.o $(OTTY)muse.o $(OTTY)music.o \ - $(OTTY)o_init.o $(OTTY)objects.o $(OTTY)objnam.o $(OTTY)options.o \ - $(OTTY)pager.o $(OTTY)pickup.o $(OTTY)pline.o $(OTTY)polyself.o \ - $(OTTY)potion.o $(OTTY)pray.o $(OTTY)priest.o $(OTTY)quest.o \ - $(OTTY)questpgr.o $(OTTY)read.o $(OTTY)rect.o $(OTTY)region.o \ - $(OTTY)report.o $(OTTY)restore.o $(OTTY)rip.o $(OTTY)rnd.o \ - $(OTTY)role.o $(OTTY)rumors.o $(OTTY)save.o $(OTTY)selvar.o \ - $(OTTY)sfstruct.o $(OTTY)shk.o $(OTTY)shknam.o $(OTTY)sit.o \ - $(OTTY)sounds.o $(OTTY)sp_lev.o $(OTTY)spell.o $(OTTY)stairs.o \ - $(OTTY)steal.o $(OTTY)steed.o $(OTTY)strutil.o $(OTTY)symbols.o \ - $(OTTY)sys.o $(OTTY)teleport.o $(OTTY)timeout.o $(OTTY)topten.o \ - $(OTTY)track.o $(OTTY)trap.o $(OTTY)u_init.o $(OTTY)uhitm.o \ - $(OTTY)utf8map.o $(OTTY)vault.o $(OTTY)vision.o $(OTTY)weapon.o \ - $(OTTY)were.o $(OTTY)wield.o $(OTTY)windows.o $(OTTY)wizard.o \ - $(OTTY)wizcmds.o $(OTTY)worm.o $(OTTY)worn.o $(OTTY)write.o \ - $(OTTY)zap.o + $(OTTY)calendar.o $(OTTY)cfgfiles.o $(OTTY)cmd.o $(OTTY)coloratt.o \ + $(OTTY)dbridge.o $(OTTY)decl.o $(OTTY)detect.o $(OTTY)dig.o \ + $(OTTY)display.o $(OTTY)do.o $(OTTY)do_name.o $(OTTY)do_wear.o \ + $(OTTY)dog.o $(OTTY)dogmove.o $(OTTY)dokick.o $(OTTY)dothrow.o \ + $(OTTY)drawing.o $(OTTY)dungeon.o $(OTTY)eat.o $(OTTY)end.o \ + $(OTTY)engrave.o $(OTTY)exper.o $(OTTY)explode.o $(OTTY)extralev.o \ + $(OTTY)files.o $(OTTY)fountain.o $(OTTY)getpos.o $(OTTY)glyphs.o \ + $(OTTY)hack.o $(OTTY)insight.o $(OTTY)invent.o $(OTTY)isaac64.o \ + $(OTTY)light.o $(OTTY)lock.o $(OTTY)mail.o $(OTTY)makemon.o \ + $(OTTY)mcastu.o $(OTTY)mhitm.o $(OTTY)mhitu.o $(OTTY)minion.o \ + $(OTTY)mklev.o $(OTTY)mkmap.o $(OTTY)mkmaze.o $(OTTY)mkobj.o \ + $(OTTY)mkroom.o $(OTTY)mon.o $(OTTY)mondata.o $(OTTY)monmove.o \ + $(OTTY)monst.o $(OTTY)mplayer.o $(OTTY)mthrowu.o $(OTTY)muse.o \ + $(OTTY)music.o $(OTTY)o_init.o $(OTTY)objects.o $(OTTY)objnam.o \ + $(OTTY)options.o $(OTTY)pager.o $(OTTY)pickup.o $(OTTY)pline.o \ + $(OTTY)polyself.o $(OTTY)potion.o $(OTTY)pray.o $(OTTY)priest.o \ + $(OTTY)quest.o $(OTTY)questpgr.o $(OTTY)read.o $(OTTY)rect.o \ + $(OTTY)region.o $(OTTY)report.o $(OTTY)restore.o $(OTTY)rip.o \ + $(OTTY)rnd.o $(OTTY)role.o $(OTTY)rumors.o $(OTTY)save.o \ + $(OTTY)selvar.o $(OTTY)sfstruct.o $(OTTY)shk.o $(OTTY)shknam.o \ + $(OTTY)sit.o $(OTTY)sounds.o $(OTTY)sp_lev.o $(OTTY)spell.o \ + $(OTTY)stairs.o $(OTTY)steal.o $(OTTY)steed.o $(OTTY)strutil.o \ + $(OTTY)symbols.o $(OTTY)sys.o $(OTTY)teleport.o $(OTTY)timeout.o \ + $(OTTY)topten.o $(OTTY)track.o $(OTTY)trap.o $(OTTY)u_init.o \ + $(OTTY)uhitm.o $(OTTY)utf8map.o $(OTTY)vault.o $(OTTY)vision.o \ + $(OTTY)weapon.o $(OTTY)were.o $(OTTY)wield.o $(OTTY)windows.o \ + $(OTTY)wizard.o $(OTTY)wizcmds.o $(OTTY)worm.o $(OTTY)worn.o \ + $(OTTY)write.o $(OTTY)zap.o OBJSTTY = $(MDLIBTTY) $(COREOBJTTY) $(REGEXTTY) $(RANDOMTTY) @@ -909,34 +909,34 @@ GUIOBJ = $(OGUI)mhaskyn.o $(OGUI)mhdlg.o \ COREOBJGUI = \ $(OGUI)allmain.o $(OGUI)alloc.o $(OGUI)apply.o $(OGUI)artifact.o \ $(OGUI)attrib.o $(OGUI)ball.o $(OGUI)bones.o $(OGUI)botl.o \ - $(OGUI)calendar.o $(OGUI)cmd.o $(OGUI)coloratt.o $(OGUI)dbridge.o \ - $(OGUI)decl.o $(OGUI)detect.o $(OGUI)dig.o $(OGUI)display.o \ - $(OGUI)do.o $(OGUI)do_name.o $(OGUI)do_wear.o $(OGUI)dog.o \ - $(OGUI)dogmove.o $(OGUI)dokick.o $(OGUI)dothrow.o $(OGUI)drawing.o \ - $(OGUI)dungeon.o $(OGUI)eat.o $(OGUI)end.o $(OGUI)engrave.o \ - $(OGUI)exper.o $(OGUI)explode.o $(OGUI)extralev.o $(OGUI)files.o \ - $(OGUI)fountain.o $(OGUI)getpos.o $(OGUI)glyphs.o $(OGUI)hack.o \ - $(OGUI)insight.o $(OGUI)invent.o $(OGUI)isaac64.o $(OGUI)light.o \ - $(OGUI)lock.o $(OGUI)mail.o $(OGUI)makemon.o $(OGUI)mcastu.o \ - $(OGUI)mhitm.o $(OGUI)mhitu.o $(OGUI)minion.o $(OGUI)mklev.o \ - $(OGUI)mkmap.o $(OGUI)mkmaze.o $(OGUI)mkobj.o $(OGUI)mkroom.o \ - $(OGUI)mon.o $(OGUI)mondata.o $(OGUI)monmove.o $(OGUI)monst.o \ - $(OGUI)mplayer.o $(OGUI)mthrowu.o $(OGUI)muse.o $(OGUI)music.o \ - $(OGUI)o_init.o $(OGUI)objects.o $(OGUI)objnam.o $(OGUI)options.o \ - $(OGUI)pager.o $(OGUI)pickup.o $(OGUI)pline.o $(OGUI)polyself.o \ - $(OGUI)potion.o $(OGUI)pray.o $(OGUI)priest.o $(OGUI)quest.o \ - $(OGUI)questpgr.o $(OGUI)read.o $(OGUI)rect.o $(OGUI)region.o \ - $(OGUI)report.o $(OGUI)restore.o $(OGUI)rip.o $(OGUI)rnd.o \ - $(OGUI)role.o $(OGUI)rumors.o $(OGUI)save.o $(OGUI)selvar.o \ - $(OGUI)sfstruct.o $(OGUI)shk.o $(OGUI)shknam.o $(OGUI)sit.o \ - $(OGUI)sounds.o $(OGUI)sp_lev.o $(OGUI)spell.o $(OGUI)stairs.o \ - $(OGUI)steal.o $(OGUI)steed.o $(OGUI)strutil.o $(OGUI)symbols.o \ - $(OGUI)sys.o $(OGUI)teleport.o $(OGUI)timeout.o $(OGUI)topten.o \ - $(OGUI)track.o $(OGUI)trap.o $(OGUI)u_init.o $(OGUI)uhitm.o \ - $(OGUI)utf8map.o $(OGUI)vault.o $(OGUI)vision.o $(OGUI)weapon.o \ - $(OGUI)were.o $(OGUI)wield.o $(OGUI)windows.o $(OGUI)wizard.o \ - $(OGUI)wizcmds.o $(OGUI)worm.o $(OGUI)worn.o $(OGUI)write.o \ - $(OGUI)zap.o + $(OGUI)calendar.o $(OGUI)cfgfiles.o $(OGUI)cmd.o $(OGUI)coloratt.o \ + $(OGUI)dbridge.o $(OGUI)decl.o $(OGUI)detect.o $(OGUI)dig.o \ + $(OGUI)display.o $(OGUI)do.o $(OGUI)do_name.o $(OGUI)do_wear.o \ + $(OGUI)dog.o $(OGUI)dogmove.o $(OGUI)dokick.o $(OGUI)dothrow.o \ + $(OGUI)drawing.o $(OGUI)dungeon.o $(OGUI)eat.o $(OGUI)end.o \ + $(OGUI)engrave.o $(OGUI)exper.o $(OGUI)explode.o $(OGUI)extralev.o \ + $(OGUI)files.o $(OGUI)fountain.o $(OGUI)getpos.o $(OGUI)glyphs.o \ + $(OGUI)hack.o $(OGUI)insight.o $(OGUI)invent.o $(OGUI)isaac64.o \ + $(OGUI)light.o $(OGUI)lock.o $(OGUI)mail.o $(OGUI)makemon.o \ + $(OGUI)mcastu.o $(OGUI)mhitm.o $(OGUI)mhitu.o $(OGUI)minion.o \ + $(OGUI)mklev.o $(OGUI)mkmap.o $(OGUI)mkmaze.o $(OGUI)mkobj.o \ + $(OGUI)mkroom.o $(OGUI)mon.o $(OGUI)mondata.o $(OGUI)monmove.o \ + $(OGUI)monst.o $(OGUI)mplayer.o $(OGUI)mthrowu.o $(OGUI)muse.o \ + $(OGUI)music.o $(OGUI)o_init.o $(OGUI)objects.o $(OGUI)objnam.o \ + $(OGUI)options.o $(OGUI)pager.o $(OGUI)pickup.o $(OGUI)pline.o \ + $(OGUI)polyself.o $(OGUI)potion.o $(OGUI)pray.o $(OGUI)priest.o \ + $(OGUI)quest.o $(OGUI)questpgr.o $(OGUI)read.o $(OGUI)rect.o \ + $(OGUI)region.o $(OGUI)report.o $(OGUI)restore.o $(OGUI)rip.o \ + $(OGUI)rnd.o $(OGUI)role.o $(OGUI)rumors.o $(OGUI)save.o \ + $(OGUI)selvar.o $(OGUI)sfstruct.o $(OGUI)shk.o $(OGUI)shknam.o \ + $(OGUI)sit.o $(OGUI)sounds.o $(OGUI)sp_lev.o $(OGUI)spell.o \ + $(OGUI)stairs.o $(OGUI)steal.o $(OGUI)steed.o $(OGUI)strutil.o \ + $(OGUI)symbols.o $(OGUI)sys.o $(OGUI)teleport.o $(OGUI)timeout.o \ + $(OGUI)topten.o $(OGUI)track.o $(OGUI)trap.o $(OGUI)u_init.o \ + $(OGUI)uhitm.o $(OGUI)utf8map.o $(OGUI)vault.o $(OGUI)vision.o \ + $(OGUI)weapon.o $(OGUI)were.o $(OGUI)wield.o $(OGUI)windows.o \ + $(OGUI)wizard.o $(OGUI)wizcmds.o $(OGUI)worm.o $(OGUI)worn.o \ + $(OGUI)write.o $(OGUI)zap.o OBJSGUI = $(MDLIBGUI) $(COREOBJGUI) $(REGEXGUI) $(RANDOMGUI) @@ -2962,6 +2962,7 @@ $(OTTY)ball.o: ball.c $(HACK_H) $(OTTY)bones.o: bones.c $(HACK_H) $(OTTY)botl.o: botl.c $(HACK_H) $(OTTY)calendar.o: calendar.c $(HACK_H) +$(OTTY)cfgfiles.o: cfgfiles.c $(HACK_H) $(OTTY)cmd.o: cmd.c $(HACK_H) $(INCL)func_tab.h $(OTTY)coloratt.o: coloratt.c $(HACK_H) $(OTTY)dbridge.o: dbridge.c $(HACK_H) @@ -3338,6 +3339,7 @@ $(OGUI)ball.o: ball.c $(HACK_H) $(OGUI)bones.o: bones.c $(HACK_H) $(OGUI)botl.o: botl.c $(HACK_H) $(OGUI)calendar.o: calendar.c $(HACK_H) +$(OGUI)cfgfiles.o: cfgfiles.c $(HACK_H) $(OGUI)cmd.o: cmd.c $(HACK_H) $(INCL)func_tab.h $(OGUI)coloratt.o: coloratt.c $(HACK_H) $(OGUI)dbridge.o: dbridge.c $(HACK_H) diff --git a/sys/windows/vs/NetHack/NetHack.vcxproj b/sys/windows/vs/NetHack/NetHack.vcxproj index da501d2fb..9da54976c 100644 --- a/sys/windows/vs/NetHack/NetHack.vcxproj +++ b/sys/windows/vs/NetHack/NetHack.vcxproj @@ -82,6 +82,7 @@ + diff --git a/sys/windows/vs/NetHackW/NetHackW.vcxproj b/sys/windows/vs/NetHackW/NetHackW.vcxproj index c5562205e..6c0360d49 100644 --- a/sys/windows/vs/NetHackW/NetHackW.vcxproj +++ b/sys/windows/vs/NetHackW/NetHackW.vcxproj @@ -90,6 +90,7 @@ +