]> granicus.if.org Git - nethack/commitdiff
Lua: set and get config options
authorPasi Kallinen <paxed@alt.org>
Sat, 6 Feb 2021 16:57:41 +0000 (18:57 +0200)
committerPasi Kallinen <paxed@alt.org>
Sat, 6 Feb 2021 17:02:25 +0000 (19:02 +0200)
Still needs more work, especially the error handling.

doc/lua.adoc
include/extern.h
src/files.c
src/nhlua.c
src/options.c

index b19186003d42b26bc1bd716687863d584095f493..fe650d45ac2e970847f381f25be956b81708bc1c 100644 (file)
@@ -70,6 +70,16 @@ Example:
  local loc = nh.getmap(x,y);
  nh.pline("Map location at (" .. x .. "," .. y .. ) is " .. (loc.lit ? "lit" : "unlit") );
 
+
+=== get_config
+
+Get current value of a boolean or a compound configuration option.
+
+Example:
+
+ local wt = nh.get_config("windowtype");
+
+
 === gettrap
 
 Get trap info at x,y
@@ -158,6 +168,15 @@ Example:
  local selected = nh.menu("prompt", default, pickX, { {key:"a", text:"option a"}, {key:"b", text:"option b"} } );
 
 
+=== parse_config
+
+Parse string as if it was read from a config file.
+
+Example:
+
+ nh.parse_config("OPTIONS=color");
+
+
 === pline
 
 Show the text in the message area.
index 290eedf7ea234f436442cc0b4b5c53d9e54de8a1..a6302da2c25482a72e0bdb7a5d6f404b0d9c2344 100644 (file)
@@ -775,6 +775,7 @@ extern void nh_compress(const char *);
 extern void nh_uncompress(const char *);
 extern boolean lock_file(const char *, int, int);
 extern void unlock_file(const char *);
+extern boolean parse_config_line(char *);
 #ifdef USER_SOUNDS
 extern boolean can_read_file(const char *);
 #endif
@@ -784,6 +785,7 @@ extern int config_error_done(void);
 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 int parse_sym_line(char *, int);
 extern void paniclog(const char *, const char *);
@@ -1782,6 +1784,7 @@ extern void initoptions(void);
 extern void initoptions_init(void);
 extern void initoptions_finish(void);
 extern boolean parseoptions(char *, boolean, boolean);
+extern char *get_option_value(const char *);
 extern int doset(void);
 extern int dotogglepickup(void);
 extern void option_help(void);
index 771f6d74f32b1cc3fbaf9379e73db2f3af42d4ad..d094ca6d415ee5ca4fc029a9fe88ee4385711151 100644 (file)
@@ -3064,146 +3064,214 @@ read_wizkit(void)
     return;
 }
 
-/* parse_conf_file
- *
- * Read from file fp, handling comments, empty lines, config sections,
+struct _cnf_parser_state {
+    char *inbuf;
+    size_t inbufsz;
+    int rv;
+    char *ep;
+    char *buf;
+    boolean skip, morelines;
+    boolean cont;
+    boolean pbreak;
+};
+
+/* Initialize config parser data */
+static 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);
+}
+
+/*
+ * 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.
  */
-static boolean
-parse_conf_file(FILE *fp, boolean (*proc)(char *))
+static void
+parse_conf_buf(struct _cnf_parser_state *p, boolean (*proc)(char *))
 {
-    char inbuf[4 * BUFSZ];
-    boolean rv = TRUE; /* assume successful parse */
-    char *ep;
-    boolean skip = FALSE, morelines = FALSE;
-    char *buf = (char *) 0;
-    size_t inbufsz = sizeof inbuf;
-
-    free_config_sections();
-
-    while (fgets(inbuf, (int) inbufsz, fp)) {
-        ep = index(inbuf, '\n');
-        if (skip) { /* in case previous line was too long */
-            if (ep)
-                skip = FALSE; /* found newline; next line is normal */
-        } else {
-            if (!ep) {  /* newline missing */
-                if (strlen(inbuf) < (inbufsz - 2)) {
-                    /* likely the last line of file is just
-                       missing a newline; process it anyway  */
-                    ep = eos(inbuf);
-                } else {
-                    config_error_add("Line too long, skipping");
-                    skip = TRUE; /* discard next fgets */
-                }
+    p->cont = FALSE;
+    p->pbreak = FALSE;
+    p->ep = index(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 {
-                *ep = '\0'; /* remove newline */
+                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;
             }
-            if (ep) {
-                char *tmpbuf = (char *) 0;
-                int len;
-                boolean ignoreline = FALSE;
-                boolean oldline = FALSE;
-
-                /* line continuation (trailing '\') */
-                morelines = (--ep >= inbuf && *ep == '\\');
-                if (morelines)
-                    *ep = '\0';
-
-                /* trim off spaces at end of line */
-                while (ep >= inbuf
-                       && (*ep == ' ' || *ep == '\t' || *ep == '\r'))
-                    *ep-- = '\0';
-
-                if (!config_error_nextline(inbuf)) {
-                    rv = FALSE;
-                    if (buf)
-                        free(buf), buf = (char *) 0;
-                    break;
-                }
 
-                ep = inbuf;
-                while (*ep == ' ' || *ep == '\t')
-                    ++ep;
-
-                /* ignore empty lines and full-line comment lines */
-                if (!*ep || *ep == '#')
-                    ignoreline = TRUE;
-
-                if (buf)
-                    oldline = TRUE;
-
-                /* merge now read line with previous ones, if necessary */
-                if (!ignoreline) {
-                    len = (int) strlen(ep) + 1; /* +1: final '\0' */
-                    if (buf)
-                        len += (int) strlen(buf) + 1; /* +1: space */
-                    tmpbuf = (char *) alloc(len);
-                    *tmpbuf = '\0';
-                    if (buf) {
-                        Strcat(strcpy(tmpbuf, buf), " ");
-                        free(buf);
-                    }
-                    buf = strcat(tmpbuf, ep);
-                    if (strlen(buf) >= sizeof inbuf)
-                        buf[sizeof inbuf - 1] = '\0';
+            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 = strcat(tmpbuf, p->ep);
+                if (strlen(p->buf) >= p->inbufsz)
+                    p->buf[p->inbufsz - 1] = '\0';
+            }
 
-                if (morelines || (ignoreline && !oldline))
-                    continue;
+            if (p->morelines || (ignoreline && !oldline))
+                return;
 
-                if (handle_config_section(buf)) {
-                    free(buf);
-                    buf = (char *) 0;
-                    continue;
-                }
+            if (handle_config_section(p->buf)) {
+                free(p->buf);
+                p->buf = (char *) 0;
+                return;
+            }
 
-                /* from here onwards, we'll handle buf only */
+            /* from here onwards, we'll handle buf only */
 
-                if (match_varname(buf, "CHOOSE", 6)) {
-                    char *section;
-                    char *bufp = find_optparam(buf);
+            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,...");
-                        rv = FALSE;
-                        free(buf);
-                        buf = (char *) 0;
-                        continue;
-                    }
-                    bufp++;
-                    if (g.config_section_chosen)
-                        free(g.config_section_chosen),
-                            g.config_section_chosen = 0;
-                    section = choose_random_part(bufp, ',');
-                    if (section) {
-                        g.config_section_chosen = dupstr(section);
-                    } else {
-                        config_error_add("No config section to choose");
-                        rv = FALSE;
-                    }
-                    free(buf);
-                    buf = (char *) 0;
-                    continue;
+                if (!bufp) {
+                    config_error_add("Format is CHOOSE=section1,section2,...");
+                    p->rv = FALSE;
+                    free(p->buf);
+                    p->buf = (char *) 0;
+                    return;
                 }
+                bufp++;
+                if (g.config_section_chosen)
+                    free(g.config_section_chosen),
+                        g.config_section_chosen = 0;
+                section = choose_random_part(bufp, ',');
+                if (section) {
+                    g.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)(buf))
-                    rv = FALSE;
+            if (!(*proc)(p->buf))
+                p->rv = FALSE;
 
-                free(buf);
-                buf = (char *) 0;
-            }
+            free(p->buf);
+            p->buf = (char *) 0;
         }
     }
+}
 
-    if (buf)
-        free(buf);
+boolean
+parse_conf_str(const char *str, boolean (*proc)(char *))
+{
+    size_t len;
+    struct _cnf_parser_state parser;
 
+    cnf_parser_init(&parser);
     free_config_sections();
-    return rv;
+    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;
+    }
+
+    if (parser.buf)
+        free(parser.buf);
+
+    free_config_sections();
+    config_error_done();
+    return parser.rv;
+}
+
+/* parse_conf_file
+ *
+ * Read from file fp, calling parse_conf_buf for each line.
+ */
+static boolean
+parse_conf_file(FILE *fp, boolean (*proc)(char *))
+{
+    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;
+    }
+
+    if (parser.buf)
+        free(parser.buf);
+
+    free_config_sections();
+    return parser.rv;
 }
 
 extern const char *known_handling[];     /* drawing.c */
index 99165b1a5d48e37520db0ee70b2db28ed4ce1fda..1e25fc7f46efd27c757f9f4a79e7b078fb384dd9 100644 (file)
@@ -25,6 +25,7 @@ static int nhl_setmap(lua_State *);
 #endif
 static int nhl_pline(lua_State *);
 static int nhl_verbalize(lua_State *);
+static int nhl_parse_config(lua_State *);
 static int nhl_menu(lua_State *);
 static int nhl_getlin(lua_State *);
 static int nhl_makeplural(lua_State *);
@@ -412,6 +413,35 @@ nhl_verbalize(lua_State *L)
     return 0;
 }
 
+/* parse_config("OPTIONS=!color") */
+static int
+nhl_parse_config(lua_State *L)
+{
+    int argc = lua_gettop(L);
+
+    if (argc == 1)
+        parse_conf_str(luaL_checkstring(L, 1), parse_config_line);
+    else
+        nhl_error(L, "Wrong args");
+
+    return 0;
+}
+
+/* local windowtype = get_config("windowtype"); */
+static int
+nhl_get_config(lua_State *L)
+{
+    int argc = lua_gettop(L);
+
+    if (argc == 1) {
+        lua_pushstring(L, get_option_value(luaL_checkstring(L, 1)));
+        return 1;
+    } else
+        nhl_error(L, "Wrong args");
+
+    return 0;
+}
+
 /*
   str = getlin("What do you want to call this dungeon level?");
  */
@@ -798,6 +828,8 @@ static const struct luaL_Reg nhl_functions[] = {
     {"rn2", nhl_rn2},
     {"random", nhl_random},
     {"level_difficulty", nhl_level_difficulty},
+    {"parse_config", nhl_parse_config},
+    {"get_config", nhl_get_config},
     {NULL, NULL}
 };
 
index bd27dd1666f3c251003ea44f7ed34f44a64a105f..3698929b7d5e67183dc414c50ea89c7db8b1712a 100644 (file)
@@ -7102,6 +7102,34 @@ optfn_o_status_hilites(int optidx UNUSED, int req, boolean negated UNUSED,
 }
 #endif /*STATUS_HILITES*/
 
+/* Get string value of configuration option.
+ * Currently handles only boolean and compound options.
+ */
+char *
+get_option_value(const char *optname)
+{
+    static char retbuf[BUFSZ];
+    boolean *bool_p;
+    int i;
+
+    for (i = 0; allopt[i].name != 0; i++)
+        if (!strcmp(optname, allopt[i].name)) {
+            if (allopt[i].opttyp == BoolOpt && (bool_p = allopt[i].addr) != 0) {
+                Sprintf(retbuf, "%s", *bool_p ? "true" : "false");
+                return retbuf;
+            } else if (allopt[i].opttyp == CompOpt && allopt[i].optfn) {
+                int reslt = optn_err;
+
+                reslt = (*allopt[i].optfn)(allopt[i].idx, get_val,
+                                           FALSE, retbuf, empty_optstr);
+                if (reslt == optn_ok && retbuf[0])
+                    return retbuf;
+                return (char *) 0;
+            }
+        }
+    return (char *) 0;
+}
+
 /* the 'O' command */
 int
 doset(void) /* changing options via menu by Per Liboriussen */