Lua: set and get config options
Still needs more work, especially the error handling.
This commit is contained in:
19
doc/lua.adoc
19
doc/lua.adoc
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
320
src/files.c
320
src/files.c
@@ -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 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
|
||||
parse_conf_file(FILE *fp, 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;
|
||||
struct _cnf_parser_state parser;
|
||||
|
||||
cnf_parser_init(&parser);
|
||||
|
||||
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 */
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
while (fgets(parser.inbuf, parser.inbufsz, fp)) {
|
||||
parse_conf_buf(&parser, proc);
|
||||
if (parser.pbreak)
|
||||
break;
|
||||
}
|
||||
|
||||
if (buf)
|
||||
free(buf);
|
||||
if (parser.buf)
|
||||
free(parser.buf);
|
||||
|
||||
free_config_sections();
|
||||
return rv;
|
||||
return parser.rv;
|
||||
}
|
||||
|
||||
extern const char *known_handling[]; /* drawing.c */
|
||||
|
||||
32
src/nhlua.c
32
src/nhlua.c
@@ -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}
|
||||
};
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user