Lua: set and get config options
Still needs more work, especially the error handling.
This commit is contained in:
@@ -70,6 +70,16 @@ Example:
|
|||||||
local loc = nh.getmap(x,y);
|
local loc = nh.getmap(x,y);
|
||||||
nh.pline("Map location at (" .. x .. "," .. y .. ) is " .. (loc.lit ? "lit" : "unlit") );
|
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
|
=== gettrap
|
||||||
|
|
||||||
Get trap info at x,y
|
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"} } );
|
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
|
=== pline
|
||||||
|
|
||||||
Show the text in the message area.
|
Show the text in the message area.
|
||||||
|
|||||||
@@ -775,6 +775,7 @@ extern void nh_compress(const char *);
|
|||||||
extern void nh_uncompress(const char *);
|
extern void nh_uncompress(const char *);
|
||||||
extern boolean lock_file(const char *, int, int);
|
extern boolean lock_file(const char *, int, int);
|
||||||
extern void unlock_file(const char *);
|
extern void unlock_file(const char *);
|
||||||
|
extern boolean parse_config_line(char *);
|
||||||
#ifdef USER_SOUNDS
|
#ifdef USER_SOUNDS
|
||||||
extern boolean can_read_file(const char *);
|
extern boolean can_read_file(const char *);
|
||||||
#endif
|
#endif
|
||||||
@@ -784,6 +785,7 @@ extern int config_error_done(void);
|
|||||||
extern boolean read_config_file(const char *, int);
|
extern boolean read_config_file(const char *, int);
|
||||||
extern void check_recordfile(const char *);
|
extern void check_recordfile(const char *);
|
||||||
extern void read_wizkit(void);
|
extern void read_wizkit(void);
|
||||||
|
extern boolean parse_conf_str(const char *str, boolean (*proc)(char *));
|
||||||
extern int read_sym_file(int);
|
extern int read_sym_file(int);
|
||||||
extern int parse_sym_line(char *, int);
|
extern int parse_sym_line(char *, int);
|
||||||
extern void paniclog(const char *, const char *);
|
extern void paniclog(const char *, const char *);
|
||||||
@@ -1782,6 +1784,7 @@ extern void initoptions(void);
|
|||||||
extern void initoptions_init(void);
|
extern void initoptions_init(void);
|
||||||
extern void initoptions_finish(void);
|
extern void initoptions_finish(void);
|
||||||
extern boolean parseoptions(char *, boolean, boolean);
|
extern boolean parseoptions(char *, boolean, boolean);
|
||||||
|
extern char *get_option_value(const char *);
|
||||||
extern int doset(void);
|
extern int doset(void);
|
||||||
extern int dotogglepickup(void);
|
extern int dotogglepickup(void);
|
||||||
extern void option_help(void);
|
extern void option_help(void);
|
||||||
|
|||||||
+194
-126
@@ -3064,146 +3064,214 @@ read_wizkit(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parse_conf_file
|
struct _cnf_parser_state {
|
||||||
*
|
char *inbuf;
|
||||||
* Read from file fp, handling comments, empty lines, config sections,
|
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.
|
* CHOOSE, and line continuation, calling proc for every valid line.
|
||||||
*
|
*
|
||||||
* Continued lines are merged together with one space in between.
|
* Continued lines are merged together with one space in between.
|
||||||
*/
|
*/
|
||||||
|
static void
|
||||||
|
parse_conf_buf(struct _cnf_parser_state *p, boolean (*proc)(char *))
|
||||||
|
{
|
||||||
|
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 {
|
||||||
|
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 = 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 (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)(p->buf))
|
||||||
|
p->rv = FALSE;
|
||||||
|
|
||||||
|
free(p->buf);
|
||||||
|
p->buf = (char *) 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
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
|
static boolean
|
||||||
parse_conf_file(FILE *fp, boolean (*proc)(char *))
|
parse_conf_file(FILE *fp, boolean (*proc)(char *))
|
||||||
{
|
{
|
||||||
char inbuf[4 * BUFSZ];
|
struct _cnf_parser_state parser;
|
||||||
boolean rv = TRUE; /* assume successful parse */
|
|
||||||
char *ep;
|
cnf_parser_init(&parser);
|
||||||
boolean skip = FALSE, morelines = FALSE;
|
|
||||||
char *buf = (char *) 0;
|
|
||||||
size_t inbufsz = sizeof inbuf;
|
|
||||||
|
|
||||||
free_config_sections();
|
free_config_sections();
|
||||||
|
|
||||||
while (fgets(inbuf, (int) inbufsz, fp)) {
|
while (fgets(parser.inbuf, parser.inbufsz, fp)) {
|
||||||
ep = index(inbuf, '\n');
|
parse_conf_buf(&parser, proc);
|
||||||
if (skip) { /* in case previous line was too long */
|
if (parser.pbreak)
|
||||||
if (ep)
|
break;
|
||||||
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 */
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
*ep = '\0'; /* remove newline */
|
|
||||||
}
|
|
||||||
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';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (morelines || (ignoreline && !oldline))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (handle_config_section(buf)) {
|
|
||||||
free(buf);
|
|
||||||
buf = (char *) 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* from here onwards, we'll handle buf only */
|
|
||||||
|
|
||||||
if (match_varname(buf, "CHOOSE", 6)) {
|
|
||||||
char *section;
|
|
||||||
char *bufp = find_optparam(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 (!(*proc)(buf))
|
|
||||||
rv = FALSE;
|
|
||||||
|
|
||||||
free(buf);
|
|
||||||
buf = (char *) 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf)
|
if (parser.buf)
|
||||||
free(buf);
|
free(parser.buf);
|
||||||
|
|
||||||
free_config_sections();
|
free_config_sections();
|
||||||
return rv;
|
return parser.rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern const char *known_handling[]; /* drawing.c */
|
extern const char *known_handling[]; /* drawing.c */
|
||||||
|
|||||||
+32
@@ -25,6 +25,7 @@ static int nhl_setmap(lua_State *);
|
|||||||
#endif
|
#endif
|
||||||
static int nhl_pline(lua_State *);
|
static int nhl_pline(lua_State *);
|
||||||
static int nhl_verbalize(lua_State *);
|
static int nhl_verbalize(lua_State *);
|
||||||
|
static int nhl_parse_config(lua_State *);
|
||||||
static int nhl_menu(lua_State *);
|
static int nhl_menu(lua_State *);
|
||||||
static int nhl_getlin(lua_State *);
|
static int nhl_getlin(lua_State *);
|
||||||
static int nhl_makeplural(lua_State *);
|
static int nhl_makeplural(lua_State *);
|
||||||
@@ -412,6 +413,35 @@ nhl_verbalize(lua_State *L)
|
|||||||
return 0;
|
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?");
|
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},
|
{"rn2", nhl_rn2},
|
||||||
{"random", nhl_random},
|
{"random", nhl_random},
|
||||||
{"level_difficulty", nhl_level_difficulty},
|
{"level_difficulty", nhl_level_difficulty},
|
||||||
|
{"parse_config", nhl_parse_config},
|
||||||
|
{"get_config", nhl_get_config},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7102,6 +7102,34 @@ optfn_o_status_hilites(int optidx UNUSED, int req, boolean negated UNUSED,
|
|||||||
}
|
}
|
||||||
#endif /*STATUS_HILITES*/
|
#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 */
|
/* the 'O' command */
|
||||||
int
|
int
|
||||||
doset(void) /* changing options via menu by Per Liboriussen */
|
doset(void) /* changing options via menu by Per Liboriussen */
|
||||||
|
|||||||
Reference in New Issue
Block a user