mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
config: Add struct conf_parsing_state.
This commit is contained in:
parent
63e82e68e4
commit
4c64afec26
@ -56,16 +56,31 @@
|
|||||||
* value to an option, but sometimes you may want to first create the option
|
* value to an option, but sometimes you may want to first create the option
|
||||||
* ;). Then this will come handy. */
|
* ;). Then this will come handy. */
|
||||||
|
|
||||||
|
struct conf_parsing_state {
|
||||||
|
/** This part may be copied to a local variable as a bookmark
|
||||||
|
* and restored later. So it must not contain any pointers
|
||||||
|
* that would have to be freed in that situation. */
|
||||||
|
struct conf_parsing_pos {
|
||||||
|
/** Points to the next character to be parsed from the
|
||||||
|
* configuration file. */
|
||||||
|
unsigned char *look;
|
||||||
|
|
||||||
/* Skip comments and whitespace,
|
/** The line number corresponding to #look. This is
|
||||||
* setting *@line to the number of lines skipped. */
|
* shown in error messages. */
|
||||||
static unsigned char *
|
int line;
|
||||||
skip_white(unsigned char *start, int *line)
|
} pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Skip comments and whitespace. */
|
||||||
|
static void
|
||||||
|
skip_white(struct conf_parsing_pos *pos)
|
||||||
{
|
{
|
||||||
|
unsigned char *start = pos->look;
|
||||||
|
|
||||||
while (*start) {
|
while (*start) {
|
||||||
while (isspace(*start)) {
|
while (isspace(*start)) {
|
||||||
if (*start == '\n') {
|
if (*start == '\n') {
|
||||||
(*line)++;
|
pos->line++;
|
||||||
}
|
}
|
||||||
start++;
|
start++;
|
||||||
}
|
}
|
||||||
@ -73,11 +88,12 @@ skip_white(unsigned char *start, int *line)
|
|||||||
if (*start == '#') {
|
if (*start == '#') {
|
||||||
start += strcspn(start, "\n");
|
start += strcspn(start, "\n");
|
||||||
} else {
|
} else {
|
||||||
return start;
|
pos->look = start;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return start;
|
pos->look = start;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse a command. Returns error code. */
|
/* Parse a command. Returns error code. */
|
||||||
@ -87,33 +103,34 @@ skip_white(unsigned char *start, int *line)
|
|||||||
* will only possibly set OPT_WATERMARK flag to the option (if enabled). */
|
* will only possibly set OPT_WATERMARK flag to the option (if enabled). */
|
||||||
|
|
||||||
static enum parse_error
|
static enum parse_error
|
||||||
parse_set(struct option *opt_tree, unsigned char **file, int *line,
|
parse_set(struct option *opt_tree, struct conf_parsing_state *state,
|
||||||
struct string *mirror, int is_system_conf)
|
struct string *mirror, int is_system_conf)
|
||||||
{
|
{
|
||||||
unsigned char *orig_pos = *file;
|
unsigned char *orig_pos = state->pos.look;
|
||||||
unsigned char *optname;
|
unsigned char *optname;
|
||||||
|
|
||||||
*file = skip_white(*file, line);
|
skip_white(&state->pos);
|
||||||
if (!**file) return ERROR_PARSE;
|
if (!*state->pos.look) return ERROR_PARSE;
|
||||||
|
|
||||||
/* Option name */
|
/* Option name */
|
||||||
optname = *file;
|
optname = state->pos.look;
|
||||||
while (isident(**file) || **file == '*' || **file == '.' || **file == '+')
|
while (isident(*state->pos.look) || *state->pos.look == '*'
|
||||||
(*file)++;
|
|| *state->pos.look == '.' || *state->pos.look == '+')
|
||||||
|
state->pos.look++;
|
||||||
|
|
||||||
optname = memacpy(optname, *file - optname);
|
optname = memacpy(optname, state->pos.look - optname);
|
||||||
if (!optname) return ERROR_NOMEM;
|
if (!optname) return ERROR_NOMEM;
|
||||||
|
|
||||||
*file = skip_white(*file, line);
|
skip_white(&state->pos);
|
||||||
|
|
||||||
/* Equal sign */
|
/* Equal sign */
|
||||||
if (**file != '=') { mem_free(optname); return ERROR_PARSE; }
|
if (*state->pos.look != '=') { mem_free(optname); return ERROR_PARSE; }
|
||||||
(*file)++; /* '=' */
|
state->pos.look++; /* '=' */
|
||||||
*file = skip_white(*file, line);
|
skip_white(&state->pos);
|
||||||
if (!**file) { mem_free(optname); return ERROR_VALUE; }
|
if (!*state->pos.look) { mem_free(optname); return ERROR_VALUE; }
|
||||||
|
|
||||||
/* Mirror what we already have */
|
/* Mirror what we already have */
|
||||||
if (mirror) add_bytes_to_string(mirror, orig_pos, *file - orig_pos);
|
if (mirror) add_bytes_to_string(mirror, orig_pos, state->pos.look - orig_pos);
|
||||||
|
|
||||||
/* Option value */
|
/* Option value */
|
||||||
{
|
{
|
||||||
@ -129,7 +146,8 @@ parse_set(struct option *opt_tree, unsigned char **file, int *line,
|
|||||||
if (!option_types[opt->type].read)
|
if (!option_types[opt->type].read)
|
||||||
return ERROR_VALUE;
|
return ERROR_VALUE;
|
||||||
|
|
||||||
val = option_types[opt->type].read(opt, file, line);
|
val = option_types[opt->type].read(opt, &state->pos.look,
|
||||||
|
&state->pos.line);
|
||||||
if (!val) return ERROR_VALUE;
|
if (!val) return ERROR_VALUE;
|
||||||
|
|
||||||
if (mirror) {
|
if (mirror) {
|
||||||
@ -155,28 +173,29 @@ parse_set(struct option *opt_tree, unsigned char **file, int *line,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static enum parse_error
|
static enum parse_error
|
||||||
parse_unset(struct option *opt_tree, unsigned char **file, int *line,
|
parse_unset(struct option *opt_tree, struct conf_parsing_state *state,
|
||||||
struct string *mirror, int is_system_conf)
|
struct string *mirror, int is_system_conf)
|
||||||
{
|
{
|
||||||
unsigned char *orig_pos = *file;
|
unsigned char *orig_pos = state->pos.look;
|
||||||
unsigned char *optname;
|
unsigned char *optname;
|
||||||
|
|
||||||
/* XXX: This does not handle the autorewriting well and is mostly a
|
/* XXX: This does not handle the autorewriting well and is mostly a
|
||||||
* quick hack than anything now. --pasky */
|
* quick hack than anything now. --pasky */
|
||||||
|
|
||||||
*file = skip_white(*file, line);
|
skip_white(&state->pos);
|
||||||
if (!**file) return ERROR_PARSE;
|
if (!*state->pos.look) return ERROR_PARSE;
|
||||||
|
|
||||||
/* Option name */
|
/* Option name */
|
||||||
optname = *file;
|
optname = state->pos.look;
|
||||||
while (isident(**file) || **file == '*' || **file == '.' || **file == '+')
|
while (isident(*state->pos.look) || *state->pos.look == '*'
|
||||||
(*file)++;
|
|| *state->pos.look == '.' || *state->pos.look == '+')
|
||||||
|
state->pos.look++;
|
||||||
|
|
||||||
optname = memacpy(optname, *file - optname);
|
optname = memacpy(optname, state->pos.look - optname);
|
||||||
if (!optname) return ERROR_NOMEM;
|
if (!optname) return ERROR_NOMEM;
|
||||||
|
|
||||||
/* Mirror what we have */
|
/* Mirror what we have */
|
||||||
if (mirror) add_bytes_to_string(mirror, orig_pos, *file - orig_pos);
|
if (mirror) add_bytes_to_string(mirror, orig_pos, state->pos.look - orig_pos);
|
||||||
|
|
||||||
{
|
{
|
||||||
struct option *opt;
|
struct option *opt;
|
||||||
@ -201,47 +220,50 @@ parse_unset(struct option *opt_tree, unsigned char **file, int *line,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static enum parse_error
|
static enum parse_error
|
||||||
parse_bind(struct option *opt_tree, unsigned char **file, int *line,
|
parse_bind(struct option *opt_tree, struct conf_parsing_state *state,
|
||||||
struct string *mirror, int is_system_conf)
|
struct string *mirror, int is_system_conf)
|
||||||
{
|
{
|
||||||
unsigned char *orig_pos = *file, *next_pos;
|
unsigned char *orig_pos = state->pos.look, *next_pos;
|
||||||
unsigned char *keymap, *keystroke, *action;
|
unsigned char *keymap, *keystroke, *action;
|
||||||
enum parse_error err = ERROR_NONE;
|
enum parse_error err = ERROR_NONE;
|
||||||
|
|
||||||
*file = skip_white(*file, line);
|
skip_white(&state->pos);
|
||||||
if (!**file) return ERROR_PARSE;
|
if (!*state->pos.look) return ERROR_PARSE;
|
||||||
|
|
||||||
/* Keymap */
|
/* Keymap */
|
||||||
keymap = option_types[OPT_STRING].read(NULL, file, line);
|
keymap = option_types[OPT_STRING].read(NULL, &state->pos.look,
|
||||||
*file = skip_white(*file, line);
|
&state->pos.line);
|
||||||
if (!keymap || !**file)
|
skip_white(&state->pos);
|
||||||
|
if (!keymap || !*state->pos.look)
|
||||||
return ERROR_OPTION;
|
return ERROR_OPTION;
|
||||||
|
|
||||||
/* Keystroke */
|
/* Keystroke */
|
||||||
keystroke = option_types[OPT_STRING].read(NULL, file, line);
|
keystroke = option_types[OPT_STRING].read(NULL, &state->pos.look,
|
||||||
*file = skip_white(*file, line);
|
&state->pos.line);
|
||||||
if (!keystroke || !**file) {
|
skip_white(&state->pos);
|
||||||
|
if (!keystroke || !*state->pos.look) {
|
||||||
mem_free(keymap); mem_free_if(keystroke);
|
mem_free(keymap); mem_free_if(keystroke);
|
||||||
return ERROR_OPTION;
|
return ERROR_OPTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Equal sign */
|
/* Equal sign */
|
||||||
*file = skip_white(*file, line);
|
skip_white(&state->pos);
|
||||||
if (**file != '=') {
|
if (*state->pos.look != '=') {
|
||||||
mem_free(keymap); mem_free(keystroke);
|
mem_free(keymap); mem_free(keystroke);
|
||||||
return ERROR_PARSE;
|
return ERROR_PARSE;
|
||||||
}
|
}
|
||||||
(*file)++; /* '=' */
|
state->pos.look++; /* '=' */
|
||||||
|
|
||||||
*file = skip_white(*file, line);
|
skip_white(&state->pos);
|
||||||
if (!**file) {
|
if (!*state->pos.look) {
|
||||||
mem_free(keymap); mem_free(keystroke);
|
mem_free(keymap); mem_free(keystroke);
|
||||||
return ERROR_PARSE;
|
return ERROR_PARSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Action */
|
/* Action */
|
||||||
next_pos = *file;
|
next_pos = state->pos.look;
|
||||||
action = option_types[OPT_STRING].read(NULL, file, line);
|
action = option_types[OPT_STRING].read(NULL, &state->pos.look,
|
||||||
|
&state->pos.line);
|
||||||
if (!action) {
|
if (!action) {
|
||||||
mem_free(keymap); mem_free(keystroke);
|
mem_free(keymap); mem_free(keystroke);
|
||||||
return ERROR_VALUE;
|
return ERROR_VALUE;
|
||||||
@ -277,30 +299,32 @@ static int load_config_file(unsigned char *, unsigned char *, struct option *,
|
|||||||
struct string *, int);
|
struct string *, int);
|
||||||
|
|
||||||
static enum parse_error
|
static enum parse_error
|
||||||
parse_include(struct option *opt_tree, unsigned char **file, int *line,
|
parse_include(struct option *opt_tree, struct conf_parsing_state *state,
|
||||||
struct string *mirror, int is_system_conf)
|
struct string *mirror, int is_system_conf)
|
||||||
{
|
{
|
||||||
unsigned char *orig_pos = *file;
|
unsigned char *orig_pos = state->pos.look;
|
||||||
unsigned char *fname;
|
unsigned char *fname;
|
||||||
struct string dumbstring;
|
struct string dumbstring;
|
||||||
|
|
||||||
if (!init_string(&dumbstring)) return ERROR_NOMEM;
|
if (!init_string(&dumbstring)) return ERROR_NOMEM;
|
||||||
|
|
||||||
*file = skip_white(*file, line);
|
skip_white(&state->pos);
|
||||||
if (!**file) {
|
if (!*state->pos.look) {
|
||||||
done_string(&dumbstring);
|
done_string(&dumbstring);
|
||||||
return ERROR_PARSE;
|
return ERROR_PARSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* File name */
|
/* File name */
|
||||||
fname = option_types[OPT_STRING].read(NULL, file, line);
|
fname = option_types[OPT_STRING].read(NULL, &state->pos.look,
|
||||||
|
&state->pos.line);
|
||||||
if (!fname) {
|
if (!fname) {
|
||||||
done_string(&dumbstring);
|
done_string(&dumbstring);
|
||||||
return ERROR_VALUE;
|
return ERROR_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mirror what we already have */
|
/* Mirror what we already have */
|
||||||
if (mirror) add_bytes_to_string(mirror, orig_pos, *file - orig_pos);
|
if (mirror) add_bytes_to_string(mirror, orig_pos,
|
||||||
|
state->pos.look - orig_pos);
|
||||||
|
|
||||||
/* We want load_config_file() to watermark stuff, but not to load
|
/* We want load_config_file() to watermark stuff, but not to load
|
||||||
* anything, polluting our beloved options tree - thus, we will feed it
|
* anything, polluting our beloved options tree - thus, we will feed it
|
||||||
@ -326,7 +350,7 @@ parse_include(struct option *opt_tree, unsigned char **file, int *line,
|
|||||||
struct parse_handler {
|
struct parse_handler {
|
||||||
const unsigned char *command;
|
const unsigned char *command;
|
||||||
enum parse_error (*handler)(struct option *opt_tree,
|
enum parse_error (*handler)(struct option *opt_tree,
|
||||||
unsigned char **file, int *line,
|
struct conf_parsing_state *state,
|
||||||
struct string *mirror, int is_system_conf);
|
struct string *mirror, int is_system_conf);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -340,7 +364,7 @@ static const struct parse_handler parse_handlers[] = {
|
|||||||
|
|
||||||
|
|
||||||
static enum parse_error
|
static enum parse_error
|
||||||
parse_config_command(struct option *options, unsigned char **file, int *line,
|
parse_config_command(struct option *options, struct conf_parsing_state *state,
|
||||||
struct string *mirror, int is_system_conf)
|
struct string *mirror, int is_system_conf)
|
||||||
{
|
{
|
||||||
const struct parse_handler *handler;
|
const struct parse_handler *handler;
|
||||||
@ -349,8 +373,8 @@ parse_config_command(struct option *options, unsigned char **file, int *line,
|
|||||||
handler++) {
|
handler++) {
|
||||||
int cmdlen = strlen(handler->command);
|
int cmdlen = strlen(handler->command);
|
||||||
|
|
||||||
if (!strncmp(*file, handler->command, cmdlen)
|
if (!strncmp(state->pos.look, handler->command, cmdlen)
|
||||||
&& isspace((*file)[cmdlen])) {
|
&& isspace(state->pos.look[cmdlen])) {
|
||||||
enum parse_error err;
|
enum parse_error err;
|
||||||
struct string mirror2 = NULL_STRING;
|
struct string mirror2 = NULL_STRING;
|
||||||
struct string *m2 = NULL;
|
struct string *m2 = NULL;
|
||||||
@ -358,12 +382,12 @@ parse_config_command(struct option *options, unsigned char **file, int *line,
|
|||||||
/* Mirror what we already have */
|
/* Mirror what we already have */
|
||||||
if (mirror && init_string(&mirror2)) {
|
if (mirror && init_string(&mirror2)) {
|
||||||
m2 = &mirror2;
|
m2 = &mirror2;
|
||||||
add_bytes_to_string(m2, *file, cmdlen);
|
add_bytes_to_string(m2, state->pos.look, cmdlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
*file += cmdlen;
|
state->pos.look += cmdlen;
|
||||||
err = handler->handler(options, file, line, m2,
|
err = handler->handler(options, state, m2,
|
||||||
is_system_conf);
|
is_system_conf);
|
||||||
if (!err && mirror && m2) {
|
if (!err && mirror && m2) {
|
||||||
add_string_to_string(mirror, m2);
|
add_string_to_string(mirror, m2);
|
||||||
@ -380,9 +404,12 @@ parse_config_command(struct option *options, unsigned char **file, int *line,
|
|||||||
enum parse_error
|
enum parse_error
|
||||||
parse_config_exmode_command(unsigned char *cmd)
|
parse_config_exmode_command(unsigned char *cmd)
|
||||||
{
|
{
|
||||||
int dummyline = 0;
|
struct conf_parsing_state state = {{ 0 }};
|
||||||
|
|
||||||
return parse_config_command(config_options, &cmd, &dummyline, NULL, 0);
|
state.pos.look = cmd;
|
||||||
|
state.pos.line = 0;
|
||||||
|
|
||||||
|
return parse_config_command(config_options, &state, NULL, 0);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_EXMODE */
|
#endif /* CONFIG_EXMODE */
|
||||||
|
|
||||||
@ -391,7 +418,7 @@ parse_config_file(struct option *options, unsigned char *name,
|
|||||||
unsigned char *file, struct string *mirror,
|
unsigned char *file, struct string *mirror,
|
||||||
int is_system_conf)
|
int is_system_conf)
|
||||||
{
|
{
|
||||||
struct conf_parsing_pos pos = { 0 };
|
struct conf_parsing_state state = {{ 0 }};
|
||||||
int error_occurred = 0;
|
int error_occurred = 0;
|
||||||
enum parse_error err = 0;
|
enum parse_error err = 0;
|
||||||
enum verbose_level verbose = get_cmd_opt_int("verbose");
|
enum verbose_level verbose = get_cmd_opt_int("verbose");
|
||||||
@ -404,31 +431,36 @@ parse_config_file(struct option *options, unsigned char *name,
|
|||||||
"no memory left", /* ERROR_NOMEM */
|
"no memory left", /* ERROR_NOMEM */
|
||||||
};
|
};
|
||||||
|
|
||||||
while (file && *file) {
|
state.pos.look = file;
|
||||||
unsigned char *orig_pos = file;
|
state.pos.line = 1;
|
||||||
|
|
||||||
|
while (state.pos.look && *state.pos.look) {
|
||||||
|
unsigned char *orig_pos = state.pos.look;
|
||||||
|
|
||||||
/* Skip all possible comments and whitespace. */
|
/* Skip all possible comments and whitespace. */
|
||||||
file = skip_white(file, &line);
|
skip_white(&state.pos);
|
||||||
|
|
||||||
/* Mirror what we already have */
|
/* Mirror what we already have */
|
||||||
if (mirror)
|
if (mirror)
|
||||||
add_bytes_to_string(mirror, orig_pos, file - orig_pos);
|
add_bytes_to_string(mirror, orig_pos,
|
||||||
|
state.pos.look - orig_pos);
|
||||||
|
|
||||||
/* Second chance to escape from the hell. */
|
/* Second chance to escape from the hell. */
|
||||||
if (!*file) break;
|
if (!*state.pos.look) break;
|
||||||
|
|
||||||
err = parse_config_command(options, &file, &line, mirror,
|
err = parse_config_command(options, &state, mirror,
|
||||||
is_system_conf);
|
is_system_conf);
|
||||||
|
|
||||||
if (err == ERROR_COMMAND) {
|
if (err == ERROR_COMMAND) {
|
||||||
orig_pos = file;
|
orig_pos = state.pos.look;
|
||||||
/* Jump over this crap we can't understand. */
|
/* Jump over this crap we can't understand. */
|
||||||
while (!isspace(*file) && *file != '#' && *file)
|
while (!isspace(*state.pos.look)
|
||||||
file++;
|
&& *state.pos.look != '#' && *state.pos.look)
|
||||||
|
state.pos.look++;
|
||||||
|
|
||||||
/* Mirror what we already have */
|
/* Mirror what we already have */
|
||||||
if (mirror) add_bytes_to_string(mirror, orig_pos,
|
if (mirror) add_bytes_to_string(mirror, orig_pos,
|
||||||
file - orig_pos);
|
state.pos.look - orig_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mirror && err) {
|
if (!mirror && err) {
|
||||||
@ -437,7 +469,7 @@ parse_config_file(struct option *options, unsigned char *name,
|
|||||||
* anymore now (?). --pasky */
|
* anymore now (?). --pasky */
|
||||||
if (verbose >= VERBOSE_WARNINGS) {
|
if (verbose >= VERBOSE_WARNINGS) {
|
||||||
fprintf(stderr, "%s:%d: %s\n",
|
fprintf(stderr, "%s:%d: %s\n",
|
||||||
name, line, error_msg[err]);
|
name, state.pos.line, error_msg[err]);
|
||||||
error_occurred = 1;
|
error_occurred = 1;
|
||||||
}
|
}
|
||||||
err = 0;
|
err = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user