-
Notifications
You must be signed in to change notification settings - Fork 105
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Sergey Lvov
committed
May 6, 2016
1 parent
3ead0ba
commit 04afd51
Showing
2 changed files
with
75 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -67,7 +67,7 @@ | |
* - Improve efficiency: too many memory allocations and data copying. | ||
* | ||
* Copyright (C) 2014 NatSys Lab. ([email protected]). | ||
* Copyright (C) 2015 Tempesta Technologies, Inc. | ||
* Copyright (C) 2015-2016 Tempesta Technologies, Inc. | ||
* | ||
* This program is free software; you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License as published by | ||
|
@@ -110,6 +110,50 @@ | |
* but they have to be NULL-terminated, so we have to allocate space and copy | ||
* them. Helpers below facilitate that. | ||
*/ | ||
typedef enum { | ||
TOKEN_NA = 0, | ||
TOKEN_LBRACE, | ||
TOKEN_RBRACE, | ||
TOKEN_EQSIGN, | ||
TOKEN_SEMICOLON, | ||
TOKEN_LITERAL, | ||
_TOKEN_COUNT, | ||
} token_t; | ||
|
||
typedef struct { | ||
const char *in; /* The whole input buffer. */ | ||
const char *pos; /* Current position in the @in buffer. */ | ||
int line; /* Current line. */ | ||
|
||
/* Current FSM state is saved to here. */ | ||
const void *fsm_s; /* Pointer to label (GCC extension). */ | ||
const char *fsm_ss; /* Label name as string (for debugging). */ | ||
|
||
/* Currently/previously processed character. */ | ||
char c; | ||
char prev_c; | ||
|
||
/* Currently/previously processed token. | ||
* The language is context-sensitive, so we need to store all these | ||
* previous tokens and literals to parse it without peek()'ing. */ | ||
token_t t; | ||
token_t prev_t; | ||
|
||
/* Literal value (not NULL only when @t == TOKEN_LITERAL). */ | ||
const char *lit; | ||
const char *prev_lit; | ||
|
||
/* Length of @lit (the @lit is not terminated). */ | ||
int lit_len; | ||
int prev_lit_len; | ||
|
||
int err; /* The latest error code. */ | ||
|
||
/* Currently parsed entry. Accumulates literals as values/attributes. | ||
* When current entry is done, a TfwCfgSpec->handler is called and a new | ||
* entry is started. */ | ||
TfwCfgEntry e; | ||
} TfwCfgParserState; | ||
|
||
static const char * | ||
alloc_and_copy_literal(const char *src, size_t len) | ||
|
@@ -125,8 +169,7 @@ alloc_and_copy_literal(const char *src, size_t len) | |
TFW_ERR("can't allocate memory\n"); | ||
return NULL; | ||
} | ||
|
||
/* Copy the string eating escaping backslashes. */ | ||
/* Copy the string eating escaping backslashes. */ | ||
/* FIXME: the logic looks like a tiny FSM, | ||
* so perhaps it should be included to the TFSM. */ | ||
src_end = src + len; | ||
|
@@ -145,10 +188,17 @@ alloc_and_copy_literal(const char *src, size_t len) | |
++src_pos; | ||
} | ||
*dst_pos = '\0'; | ||
|
||
return dst; | ||
} | ||
|
||
static inline void | ||
print_parse_error(const TfwCfgParserState *ps) | ||
{ | ||
|
||
TFW_ERR("configuration parsing error str:%d;w:%s\n", ps->e.line + 1 , ps->e.name); | ||
} | ||
|
||
|
||
/** | ||
* Check name of an attribute or name | ||
* | ||
|
@@ -304,49 +354,7 @@ entry_add_attr(TfwCfgEntry *e, const char *key_src, size_t key_len, | |
* characters respectively). | ||
*/ | ||
|
||
typedef enum { | ||
TOKEN_NA = 0, | ||
TOKEN_LBRACE, | ||
TOKEN_RBRACE, | ||
TOKEN_EQSIGN, | ||
TOKEN_SEMICOLON, | ||
TOKEN_LITERAL, | ||
_TOKEN_COUNT, | ||
} token_t; | ||
|
||
typedef struct { | ||
const char *in; /* The whole input buffer. */ | ||
const char *pos; /* Current position in the @in buffer. */ | ||
|
||
/* Current FSM state is saved to here. */ | ||
const void *fsm_s; /* Pointer to label (GCC extension). */ | ||
const char *fsm_ss; /* Label name as string (for debugging). */ | ||
|
||
/* Currently/previously processed character. */ | ||
char c; | ||
char prev_c; | ||
|
||
/* Currently/previously processed token. | ||
* The language is context-sensitive, so we need to store all these | ||
* previous tokens and literals to parse it without peek()'ing. */ | ||
token_t t; | ||
token_t prev_t; | ||
|
||
/* Literal value (not NULL only when @t == TOKEN_LITERAL). */ | ||
const char *lit; | ||
const char *prev_lit; | ||
|
||
/* Length of @lit (the @lit is not terminated). */ | ||
int lit_len; | ||
int prev_lit_len; | ||
|
||
int err; /* The latest error code. */ | ||
|
||
/* Currently parsed entry. Accumulates literals as values/attributes. | ||
* When current entry is done, a TfwCfgSpec->handler is called and a new | ||
* entry is started. */ | ||
TfwCfgEntry e; | ||
} TfwCfgParserState; | ||
|
||
/* Macros common for both TFSM and PFSM. */ | ||
|
||
|
@@ -374,11 +382,14 @@ do { \ | |
|
||
/* Macros specific to TFSM. */ | ||
|
||
#define TFSM_MOVE(to_state) \ | ||
do { \ | ||
ps->prev_c = ps->c; \ | ||
ps->c = *(++ps->pos); \ | ||
#define TFSM_MOVE(to_state) \ | ||
do { \ | ||
ps->prev_c = ps->c; \ | ||
ps->c = *(++ps->pos); \ | ||
TFW_DBG3("tfsm move: '%c' -> '%c'\n", ps->prev_c, ps->c); \ | ||
if (ps->prev_c == '\n') { \ | ||
++ps->line; \ | ||
} \ | ||
FSM_JMP(to_state); \ | ||
} while (0) | ||
|
||
|
@@ -600,6 +611,7 @@ parse_cfg_entry(TfwCfgParserState *ps) | |
TFW_DBG3("set name: %.*s\n", ps->lit_len, ps->lit); | ||
|
||
ps->err = entry_set_name(&ps->e, ps->lit, ps->lit_len); | ||
ps->e.line = ps->line; | ||
FSM_COND_JMP(ps->err, PS_EXIT); | ||
|
||
PFSM_MOVE(PS_VAL_OR_ATTR); | ||
|
@@ -1107,13 +1119,13 @@ tfw_cfg_handle_children(TfwCfgSpec *cs, TfwCfgEntry *e) | |
while (ps->t && (ps->t != TOKEN_RBRACE)) { | ||
parse_cfg_entry(ps); | ||
if (ps->err) { | ||
TFW_ERR("parser error\n"); | ||
print_parse_error(ps); | ||
return ps->err; | ||
} | ||
|
||
matching_spec = spec_find(nested_specs, ps->e.name); | ||
if (!matching_spec) { | ||
TFW_ERR("don't know how to handle: %s\n", ps->e.name); | ||
print_parse_error(ps); | ||
return -EINVAL; | ||
} | ||
|
||
|
@@ -1365,17 +1377,6 @@ mod_stop(TfwCfgMod *mod) | |
mod->stop(); | ||
} | ||
|
||
static void | ||
print_parse_error(const TfwCfgParserState *ps) | ||
{ | ||
const char *start = max((ps->pos - 80), ps->in); | ||
int len = ps->pos - start; | ||
|
||
TFW_ERR("configuration parsing error:\n" | ||
"%.*s\n" | ||
"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", | ||
len, start); | ||
} | ||
|
||
/* | ||
* Find configuration option specs by option name. | ||
|
@@ -1413,9 +1414,9 @@ tfw_cfg_parse_mods_cfg(const char *cfg_text, struct list_head *mod_list) | |
|
||
do { | ||
parse_cfg_entry(&ps); | ||
if (ps.err) { | ||
TFW_ERR("syntax error\n"); | ||
goto err; | ||
if (ps.err){ | ||
print_parse_error(&ps); | ||
return -EINVAL; | ||
} | ||
if (!ps.e.name) | ||
break; /* EOF - nothing is parsed and no error. */ | ||
|
@@ -1426,25 +1427,23 @@ tfw_cfg_parse_mods_cfg(const char *cfg_text, struct list_head *mod_list) | |
break; | ||
} | ||
if (!matching_spec) { | ||
TFW_ERR("don't know how to handle: '%s'\n", ps.e.name); | ||
goto err; | ||
print_parse_error(&ps); | ||
return -EINVAL; | ||
} | ||
|
||
r = spec_handle_entry(matching_spec, &ps.e); | ||
if (r) | ||
goto err; | ||
print_parse_error(&ps); | ||
|
||
} while (ps.t); | ||
|
||
MOD_FOR_EACH(mod, mod_list) { | ||
r = spec_finish_handling(mod->specs); | ||
if (r) | ||
goto err; | ||
} | ||
print_parse_error(&ps); | ||
|
||
} | ||
return 0; | ||
err: | ||
print_parse_error(&ps); | ||
return -EINVAL; | ||
} | ||
EXPORT_SYMBOL(tfw_cfg_parse_mods_cfg); | ||
|
||
|
@@ -1466,7 +1465,7 @@ tfw_cfg_start_mods(const char *cfg_text, struct list_head *mod_list) | |
TFW_DBG2("parsing configuration and pushing it to modules...\n"); | ||
ret = tfw_cfg_parse_mods_cfg(cfg_text, mod_list); | ||
if (ret) { | ||
TFW_ERR("can't parse configuration data\n"); | ||
TFW_ERR("can't parse configuration data, %d\n", ret); | ||
goto err_recover_cleanup; | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters