parent
ed7a4c80a0
commit
4b8d24ae0f
@ -1,526 +1,134 @@ |
|||||||
|
|
||||||
/* #line 1 "ini_parser.rl" */ |
|
||||||
|
|
||||||
/* Ragel constants block */ |
|
||||||
#include "ini_parser.h" |
#include "ini_parser.h" |
||||||
|
|
||||||
// Ragel setup
|
enum nini_state { |
||||||
|
NINI_IDLE, |
||||||
/* #line 10 "ini_parser.c" */ |
NINI_SECTION, |
||||||
static const char _ini_actions[] = { |
NINI_KEY, |
||||||
0, 1, 1, 1, 2, 1, 3, 1,
|
NINI_VALUE, |
||||||
4, 1, 5, 1, 6, 1, 7, 1,
|
NINI_COMMENT, |
||||||
8, 1, 9, 1, 10, 1, 11, 1,
|
|
||||||
13, 2, 0, 4, 2, 12, 4 |
|
||||||
}; |
|
||||||
|
|
||||||
static const char _ini_eof_actions[] = { |
|
||||||
0, 23, 5, 5, 15, 15, 15, 15,
|
|
||||||
19, 19, 0, 0, 0, 0, 0, 0,
|
|
||||||
0 |
|
||||||
}; |
}; |
||||||
|
|
||||||
static const int ini_start = 1; |
static struct { |
||||||
static const int ini_first_final = 12; |
uint8_t section_i; |
||||||
static const int ini_error = 0; |
char section[INI_KEY_MAX]; |
||||||
|
|
||||||
static const int ini_en_section = 2; |
|
||||||
static const int ini_en_keyvalue = 4; |
|
||||||
static const int ini_en_comment = 8; |
|
||||||
static const int ini_en_discard2eol = 10; |
|
||||||
static const int ini_en_main = 1; |
|
||||||
|
|
||||||
|
|
||||||
/* #line 10 "ini_parser.rl" */ |
|
||||||
|
|
||||||
|
|
||||||
// Persistent state
|
|
||||||
static int8_t cs = -1; //!< Ragel's Current State variable
|
|
||||||
static uint32_t buff_i = 0; //!< Write pointer for the buffers
|
|
||||||
static char value_quote = 0; //!< Quote character of the currently collected value
|
|
||||||
static bool value_nextesc = false; //!< Next character is escaped, trated specially, and if quote, as literal quote character
|
|
||||||
static IniParserCallback keyCallback = NULL; //!< Currently assigned callback
|
|
||||||
static void *userdata = NULL; //!< Currently assigned user data for the callback
|
|
||||||
|
|
||||||
// Buffers
|
|
||||||
static char keybuf[INI_KEY_MAX]; |
|
||||||
static char secbuf[INI_KEY_MAX+10]; |
|
||||||
static char valbuf[INI_VALUE_MAX]; |
|
||||||
|
|
||||||
// See header for doxygen!
|
|
||||||
|
|
||||||
void |
|
||||||
ini_parse_reset_partial(void) |
|
||||||
{ |
|
||||||
buff_i = 0; |
|
||||||
value_quote = 0; |
|
||||||
value_nextesc = false; |
|
||||||
} |
|
||||||
|
|
||||||
void |
|
||||||
ini_parse_reset(void) |
|
||||||
{ |
|
||||||
ini_parse_reset_partial(); |
|
||||||
keybuf[0] = secbuf[0] = valbuf[0] = 0; |
|
||||||
|
|
||||||
/* #line 67 "ini_parser.c" */ |
|
||||||
{ |
|
||||||
cs = ini_start; |
|
||||||
} |
|
||||||
|
|
||||||
/* #line 41 "ini_parser.rl" */ |
uint8_t key_i; |
||||||
} |
char key[INI_KEY_MAX]; |
||||||
|
|
||||||
void |
uint8_t value_i; |
||||||
ini_parser_error(const char* msg) |
char value[INI_VALUE_MAX]; |
||||||
{ |
bool val_last_space; |
||||||
ini_error("Parser error: %s", msg); |
|
||||||
ini_parse_reset_partial(); |
|
||||||
} |
|
||||||
|
|
||||||
|
IniParserCallback cb; |
||||||
|
void *userdata; |
||||||
|
enum nini_state state; |
||||||
|
} nini; |
||||||
|
|
||||||
void |
void ini_parse_begin(IniParserCallback callback, void *userData) |
||||||
ini_parse_begin(IniParserCallback callback, void *userData) |
|
||||||
{ |
{ |
||||||
keyCallback = callback; |
|
||||||
userdata = userData; |
|
||||||
ini_parse_reset(); |
ini_parse_reset(); |
||||||
|
nini.cb = callback; |
||||||
|
nini.userdata = userData; |
||||||
} |
} |
||||||
|
|
||||||
|
void ini_parse(const char *data, size_t len) |
||||||
void |
|
||||||
*ini_parse_end(void) |
|
||||||
{ |
{ |
||||||
ini_parse("\n", 1); |
for (; len > 0; len--) { |
||||||
if (keyCallback) { |
char c = *data++; |
||||||
keyCallback = NULL; |
if (c == ' ' || c == '\t' || c == '\r' || c == '\n') { |
||||||
|
if (nini.state != NINI_VALUE && nini.state != NINI_COMMENT) |
||||||
|
continue; |
||||||
} |
} |
||||||
|
|
||||||
void *ud = userdata; |
switch (nini.state) { |
||||||
userdata = NULL; |
case NINI_IDLE: |
||||||
return ud; |
if (c == '[') { |
||||||
|
nini.state = NINI_SECTION; |
||||||
|
nini.section_i = 0; |
||||||
} |
} |
||||||
|
else if (c == '#') { |
||||||
|
nini.state = NINI_COMMENT; |
||||||
void |
|
||||||
ini_parse_file(const char *text, size_t len, IniParserCallback callback, void *userData) |
|
||||||
{ |
|
||||||
ini_parse_begin(callback, userData); |
|
||||||
ini_parse(text, len); |
|
||||||
ini_parse_end(); |
|
||||||
} |
} |
||||||
|
else { |
||||||
static void |
nini.state = NINI_KEY; |
||||||
rtrim_buf(char *buf, int32_t end) |
nini.key_i = 0; |
||||||
{ |
nini.value_i = 0; |
||||||
if (end > 0) { |
nini.val_last_space = false; |
||||||
while ((uint8_t)buf[--end] < 33); |
nini.key[nini.key_i++] = c; |
||||||
end++; // go past the last character
|
|
||||||
} |
|
||||||
|
|
||||||
buf[end] = 0; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
void |
|
||||||
ini_parse(const char *newstr, size_t len) |
|
||||||
{ |
|
||||||
int32_t i; |
|
||||||
char c; |
|
||||||
bool isnl; |
|
||||||
bool isquot; |
|
||||||
|
|
||||||
// Load new data to Ragel vars
|
|
||||||
const uint8_t *p; |
|
||||||
const uint8_t *eof; |
|
||||||
const uint8_t *pe; |
|
||||||
|
|
||||||
if (len == 0) while(newstr[++len] != 0); // alternative to strlen
|
|
||||||
|
|
||||||
p = (const uint8_t *) newstr; |
|
||||||
eof = NULL; |
|
||||||
pe = (const uint8_t *) (newstr + len); |
|
||||||
|
|
||||||
// Init Ragel on the first run
|
|
||||||
if (cs == -1) { |
|
||||||
ini_parse_reset(); |
|
||||||
} |
|
||||||
|
|
||||||
// The parser
|
|
||||||
|
|
||||||
/* #line 152 "ini_parser.c" */ |
|
||||||
{ |
|
||||||
const char *_acts; |
|
||||||
unsigned int _nacts; |
|
||||||
|
|
||||||
if ( p == pe ) |
|
||||||
goto _test_eof; |
|
||||||
if ( cs == 0 ) |
|
||||||
goto _out; |
|
||||||
_resume: |
|
||||||
switch ( cs ) { |
|
||||||
case 1: |
|
||||||
switch( (*p) ) { |
|
||||||
case 32u: goto tr1; |
|
||||||
case 35u: goto tr3; |
|
||||||
case 58u: goto tr0; |
|
||||||
case 59u: goto tr3; |
|
||||||
case 61u: goto tr0; |
|
||||||
case 91u: goto tr4; |
|
||||||
} |
|
||||||
if ( (*p) < 9u ) { |
|
||||||
if ( (*p) <= 8u ) |
|
||||||
goto tr0; |
|
||||||
} else if ( (*p) > 13u ) { |
|
||||||
if ( 14u <= (*p) && (*p) <= 31u ) |
|
||||||
goto tr0; |
|
||||||
} else |
|
||||||
goto tr1; |
|
||||||
goto tr2; |
|
||||||
case 0: |
|
||||||
goto _out; |
|
||||||
case 12: |
|
||||||
goto tr0; |
|
||||||
case 2: |
|
||||||
switch( (*p) ) { |
|
||||||
case 9u: goto tr6; |
|
||||||
case 32u: goto tr6; |
|
||||||
case 93u: goto tr5; |
|
||||||
} |
|
||||||
if ( (*p) <= 31u ) |
|
||||||
goto tr5; |
|
||||||
goto tr7; |
|
||||||
case 3: |
|
||||||
if ( (*p) == 93u ) |
|
||||||
goto tr8; |
|
||||||
if ( (*p) > 8u ) { |
|
||||||
if ( 10u <= (*p) && (*p) <= 31u ) |
|
||||||
goto tr5; |
|
||||||
} else |
|
||||||
goto tr5; |
|
||||||
goto tr7; |
|
||||||
case 13: |
|
||||||
goto tr5; |
|
||||||
case 4: |
|
||||||
switch( (*p) ) { |
|
||||||
case 10u: goto tr10; |
|
||||||
case 58u: goto tr11; |
|
||||||
case 61u: goto tr11; |
|
||||||
} |
|
||||||
goto tr9; |
|
||||||
case 5: |
|
||||||
switch( (*p) ) { |
|
||||||
case 9u: goto tr13; |
|
||||||
case 10u: goto tr14; |
|
||||||
case 13u: goto tr15; |
|
||||||
case 32u: goto tr13; |
|
||||||
} |
|
||||||
goto tr12; |
|
||||||
case 6: |
|
||||||
switch( (*p) ) { |
|
||||||
case 10u: goto tr14; |
|
||||||
case 13u: goto tr15; |
|
||||||
} |
|
||||||
goto tr12; |
|
||||||
case 14: |
|
||||||
goto tr10; |
|
||||||
case 7: |
|
||||||
if ( (*p) == 10u ) |
|
||||||
goto tr14; |
|
||||||
goto tr10; |
|
||||||
case 8: |
|
||||||
switch( (*p) ) { |
|
||||||
case 10u: goto tr17; |
|
||||||
case 13u: goto tr18; |
|
||||||
} |
|
||||||
goto tr16; |
|
||||||
case 15: |
|
||||||
goto tr19; |
|
||||||
case 9: |
|
||||||
if ( (*p) == 10u ) |
|
||||||
goto tr17; |
|
||||||
goto tr19; |
|
||||||
case 10: |
|
||||||
switch( (*p) ) { |
|
||||||
case 10u: goto tr21; |
|
||||||
case 13u: goto tr22; |
|
||||||
} |
|
||||||
goto tr20; |
|
||||||
case 16: |
|
||||||
goto tr23; |
|
||||||
case 11: |
|
||||||
if ( (*p) == 10u ) |
|
||||||
goto tr21; |
|
||||||
goto tr23; |
|
||||||
} |
|
||||||
|
|
||||||
tr23: cs = 0; goto _again; |
|
||||||
tr0: cs = 0; goto f0; |
|
||||||
tr5: cs = 0; goto f4; |
|
||||||
tr10: cs = 0; goto f7; |
|
||||||
tr19: cs = 0; goto f11; |
|
||||||
tr1: cs = 1; goto _again; |
|
||||||
tr6: cs = 2; goto _again; |
|
||||||
tr7: cs = 3; goto f5; |
|
||||||
tr9: cs = 4; goto f8; |
|
||||||
tr13: cs = 5; goto _again; |
|
||||||
tr11: cs = 5; goto f9; |
|
||||||
tr12: cs = 6; goto f10; |
|
||||||
tr15: cs = 7; goto _again; |
|
||||||
tr16: cs = 8; goto _again; |
|
||||||
tr18: cs = 9; goto _again; |
|
||||||
tr20: cs = 10; goto _again; |
|
||||||
tr22: cs = 11; goto _again; |
|
||||||
tr2: cs = 12; goto f1; |
|
||||||
tr3: cs = 12; goto f2; |
|
||||||
tr4: cs = 12; goto f3; |
|
||||||
tr8: cs = 13; goto f6; |
|
||||||
tr14: cs = 14; goto f10; |
|
||||||
tr17: cs = 15; goto f12; |
|
||||||
tr21: cs = 16; goto f13; |
|
||||||
|
|
||||||
f5: _acts = _ini_actions + 1; goto execFuncs; |
|
||||||
f6: _acts = _ini_actions + 3; goto execFuncs; |
|
||||||
f4: _acts = _ini_actions + 5; goto execFuncs; |
|
||||||
f1: _acts = _ini_actions + 7; goto execFuncs; |
|
||||||
f8: _acts = _ini_actions + 9; goto execFuncs; |
|
||||||
f9: _acts = _ini_actions + 11; goto execFuncs; |
|
||||||
f10: _acts = _ini_actions + 13; goto execFuncs; |
|
||||||
f7: _acts = _ini_actions + 15; goto execFuncs; |
|
||||||
f12: _acts = _ini_actions + 17; goto execFuncs; |
|
||||||
f11: _acts = _ini_actions + 19; goto execFuncs; |
|
||||||
f13: _acts = _ini_actions + 21; goto execFuncs; |
|
||||||
f0: _acts = _ini_actions + 23; goto execFuncs; |
|
||||||
f3: _acts = _ini_actions + 25; goto execFuncs; |
|
||||||
f2: _acts = _ini_actions + 28; goto execFuncs; |
|
||||||
|
|
||||||
execFuncs: |
|
||||||
_nacts = *_acts++; |
|
||||||
while ( _nacts-- > 0 ) { |
|
||||||
switch ( *_acts++ ) { |
|
||||||
case 0: |
|
||||||
/* #line 130 "ini_parser.rl" */ |
|
||||||
{ |
|
||||||
buff_i = 0; |
|
||||||
{cs = 2;goto _again;} |
|
||||||
} |
} |
||||||
break; |
break; |
||||||
case 1: |
|
||||||
/* #line 135 "ini_parser.rl" */ |
case NINI_COMMENT: |
||||||
{ |
if (c == '\n' || c == '\r') { |
||||||
if (buff_i >= INI_KEY_MAX) { |
nini.state = NINI_IDLE; |
||||||
ini_parser_error("Section name too long"); |
|
||||||
{cs = 10;goto _again;} |
|
||||||
} |
|
||||||
keybuf[buff_i++] = (*p); |
|
||||||
} |
} |
||||||
break; |
break; |
||||||
case 2: |
|
||||||
/* #line 143 "ini_parser.rl" */ |
case NINI_SECTION: |
||||||
{ |
if (c == ']') { |
||||||
// we need a separate buffer for the result, otherwise a failed
|
nini.section[nini.section_i] = 0; |
||||||
// partial parse would corrupt the section string
|
nini.state = NINI_COMMENT; // discard to EOL
|
||||||
rtrim_buf(keybuf, buff_i); |
|
||||||
for (i = 0; (c = keybuf[i]) != 0; i++) secbuf[i] = c; |
|
||||||
secbuf[i] = 0; |
|
||||||
{cs = 1;goto _again;} |
|
||||||
} |
|
||||||
break; |
break; |
||||||
case 3: |
|
||||||
/* #line 155 "ini_parser.rl" */ |
|
||||||
{ |
|
||||||
ini_parser_error("Syntax error in [section]"); |
|
||||||
if((*p) == '\n') {cs = 1;goto _again;} else {cs = 10;goto _again;} |
|
||||||
} |
} |
||||||
break; |
else if (nini.section_i < INI_KEY_MAX - 1) { |
||||||
case 4: |
nini.section[nini.section_i++] = c; |
||||||
/* #line 162 "ini_parser.rl" */ |
|
||||||
{ |
|
||||||
buff_i = 0; |
|
||||||
keybuf[buff_i++] = (*p); // add the first char
|
|
||||||
{cs = 4;goto _again;} |
|
||||||
} |
} |
||||||
break; |
break; |
||||||
case 5: |
|
||||||
/* #line 168 "ini_parser.rl" */ |
case NINI_KEY: |
||||||
{ |
if (c == '=') { |
||||||
if (buff_i >= INI_KEY_MAX) { |
nini.key[nini.key_i] = 0; |
||||||
ini_parser_error("Key too long"); |
nini.state = NINI_VALUE; |
||||||
{cs = 10;goto _again;} |
|
||||||
} |
} |
||||||
keybuf[buff_i++] = (*p); |
else if (nini.key_i < INI_KEY_MAX - 1) { |
||||||
|
nini.key[nini.key_i++] = c; |
||||||
} |
} |
||||||
break; |
break; |
||||||
case 6: |
|
||||||
/* #line 176 "ini_parser.rl" */ |
|
||||||
{ |
|
||||||
rtrim_buf(keybuf, buff_i); |
|
||||||
|
|
||||||
// --- Value begin ---
|
case NINI_VALUE: |
||||||
buff_i = 0; |
switch (c) { |
||||||
value_quote = 0; |
case ' ': |
||||||
value_nextesc = false; |
case '\t': |
||||||
} |
if (nini.value_i) nini.val_last_space = true; |
||||||
break; |
break; |
||||||
case 7: |
case '\r': |
||||||
/* #line 185 "ini_parser.rl" */ |
case '\n': |
||||||
{ |
nini.value[nini.value_i] = 0; |
||||||
isnl = ((*p) == '\r' || (*p) == '\n'); |
nini.state = NINI_IDLE; |
||||||
isquot = ((*p) == '\'' || (*p) == '"'); |
nini.cb(nini.section, nini.key, nini.value, nini.userdata); |
||||||
|
break; |
||||||
// detect our starting quote
|
default: |
||||||
if (isquot && !value_nextesc && buff_i == 0 && value_quote == 0) { |
if (nini.val_last_space && nini.value_i < INI_VALUE_MAX - 1) { |
||||||
value_quote = (*p); |
nini.value[nini.value_i++] = ' '; |
||||||
goto valueCharDone; |
|
||||||
} |
} |
||||||
|
|
||||||
if (buff_i >= INI_VALUE_MAX) { |
if (nini.value_i < INI_VALUE_MAX - 1) { |
||||||
ini_parser_error("Value too long"); |
nini.value[nini.value_i++] = c; |
||||||
{cs = 10;goto _again;} |
|
||||||
} |
} |
||||||
|
|
||||||
// end of string - clean up and report
|
|
||||||
if ((!value_nextesc && (*p) == value_quote) || isnl) { |
|
||||||
if (isnl && value_quote) { |
|
||||||
ini_parser_error("Unterminated string"); |
|
||||||
{cs = 1;goto _again;} |
|
||||||
} |
} |
||||||
|
|
||||||
// unquoted: trim from the end
|
|
||||||
if (!value_quote) { |
|
||||||
rtrim_buf(valbuf, buff_i); |
|
||||||
} else { |
|
||||||
valbuf[buff_i] = 0; |
|
||||||
} |
} |
||||||
|
|
||||||
if (keyCallback) { |
|
||||||
keyCallback(secbuf, keybuf, valbuf, userdata); |
|
||||||
} |
} |
||||||
|
|
||||||
// we don't want to discard to eol if the string was terminated by eol
|
|
||||||
// - would delete the next line
|
|
||||||
|
|
||||||
if (isnl) {cs = 1;goto _again;} else {cs = 10;goto _again;} |
|
||||||
} |
} |
||||||
|
|
||||||
c = (*p); |
void *ini_parse_end(void) |
||||||
// escape...
|
{ |
||||||
if (value_nextesc) { |
if (nini.state == NINI_VALUE) { |
||||||
if ((*p) == 'n') c = '\n'; |
nini.value[nini.value_i] = 0; |
||||||
else if ((*p) == 'r') c = '\r'; |
nini.state = NINI_IDLE; |
||||||
else if ((*p) == 't') c = '\t'; |
nini.cb(nini.section, nini.key, nini.value, nini.userdata); |
||||||
else if ((*p) == 'e') c = '\033'; |
|
||||||
} |
} |
||||||
|
|
||||||
// collecting characters...
|
return nini.userdata; |
||||||
if (value_nextesc || (*p) != '\\') { // is quoted, or is not a quoting backslash - literal character
|
|
||||||
valbuf[buff_i++] = c; |
|
||||||
} |
} |
||||||
|
|
||||||
value_nextesc = (!value_nextesc && (*p) == '\\'); |
void ini_parse_file(const char *text, size_t len, IniParserCallback callback, void *userData) |
||||||
valueCharDone:; |
|
||||||
} |
|
||||||
break; |
|
||||||
case 8: |
|
||||||
/* #line 247 "ini_parser.rl" */ |
|
||||||
{ |
{ |
||||||
ini_parser_error("Syntax error in key=value"); |
ini_parse_begin(callback, userData); |
||||||
if((*p) == '\n') {cs = 1;goto _again;} else {cs = 10;goto _again;} |
ini_parse(text, len); |
||||||
} |
ini_parse_end(); |
||||||
break; |
|
||||||
case 9: |
|
||||||
/* #line 257 "ini_parser.rl" */ |
|
||||||
{ {cs = 1;goto _again;} } |
|
||||||
break; |
|
||||||
case 10: |
|
||||||
/* #line 258 "ini_parser.rl" */ |
|
||||||
{ |
|
||||||
ini_parser_error("Syntax error in comment"); |
|
||||||
if((*p) == '\n') {cs = 1;goto _again;} else {cs = 10;goto _again;} |
|
||||||
} |
|
||||||
break; |
|
||||||
case 11: |
|
||||||
/* #line 265 "ini_parser.rl" */ |
|
||||||
{ {cs = 1;goto _again;} } |
|
||||||
break; |
|
||||||
case 12: |
|
||||||
/* #line 273 "ini_parser.rl" */ |
|
||||||
{ {cs = 8;goto _again;} } |
|
||||||
break; |
|
||||||
case 13: |
|
||||||
/* #line 276 "ini_parser.rl" */ |
|
||||||
{ |
|
||||||
ini_parser_error("Syntax error in root"); |
|
||||||
{cs = 10;goto _again;} |
|
||||||
} |
|
||||||
break; |
|
||||||
/* #line 458 "ini_parser.c" */ |
|
||||||
} |
|
||||||
} |
} |
||||||
goto _again; |
|
||||||
|
|
||||||
_again: |
void ini_parse_reset(void) |
||||||
if ( cs == 0 ) |
|
||||||
goto _out; |
|
||||||
if ( ++p != pe ) |
|
||||||
goto _resume; |
|
||||||
_test_eof: {} |
|
||||||
if ( p == eof ) |
|
||||||
{ |
{ |
||||||
const char *__acts = _ini_actions + _ini_eof_actions[cs]; |
nini.state = NINI_IDLE; |
||||||
unsigned int __nacts = (unsigned int) *__acts++; |
|
||||||
while ( __nacts-- > 0 ) { |
|
||||||
switch ( *__acts++ ) { |
|
||||||
case 3: |
|
||||||
/* #line 155 "ini_parser.rl" */ |
|
||||||
{ |
|
||||||
ini_parser_error("Syntax error in [section]"); |
|
||||||
if((*p) == '\n') {cs = 1; if ( p == pe ) |
|
||||||
goto _test_eof; |
|
||||||
goto _again;} else {cs = 10; if ( p == pe ) |
|
||||||
goto _test_eof; |
|
||||||
goto _again;} |
|
||||||
} |
|
||||||
break; |
|
||||||
case 8: |
|
||||||
/* #line 247 "ini_parser.rl" */ |
|
||||||
{ |
|
||||||
ini_parser_error("Syntax error in key=value"); |
|
||||||
if((*p) == '\n') {cs = 1; if ( p == pe ) |
|
||||||
goto _test_eof; |
|
||||||
goto _again;} else {cs = 10; if ( p == pe ) |
|
||||||
goto _test_eof; |
|
||||||
goto _again;} |
|
||||||
} |
|
||||||
break; |
|
||||||
case 10: |
|
||||||
/* #line 258 "ini_parser.rl" */ |
|
||||||
{ |
|
||||||
ini_parser_error("Syntax error in comment"); |
|
||||||
if((*p) == '\n') {cs = 1; if ( p == pe ) |
|
||||||
goto _test_eof; |
|
||||||
goto _again;} else {cs = 10; if ( p == pe ) |
|
||||||
goto _test_eof; |
|
||||||
goto _again;} |
|
||||||
} |
|
||||||
break; |
|
||||||
case 13: |
|
||||||
/* #line 276 "ini_parser.rl" */ |
|
||||||
{ |
|
||||||
ini_parser_error("Syntax error in root"); |
|
||||||
{cs = 10; if ( p == pe ) |
|
||||||
goto _test_eof; |
|
||||||
goto _again;} |
|
||||||
} |
|
||||||
break; |
|
||||||
/* #line 517 "ini_parser.c" */ |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
_out: {} |
|
||||||
} |
|
||||||
|
|
||||||
/* #line 283 "ini_parser.rl" */ |
|
||||||
|
|
||||||
} |
} |
||||||
|
@ -1,284 +0,0 @@ |
|||||||
|
|
||||||
/* Ragel constants block */ |
|
||||||
#include "ini_parser.h" |
|
||||||
|
|
||||||
// Ragel setup |
|
||||||
%%{ |
|
||||||
machine ini; |
|
||||||
write data; |
|
||||||
alphtype unsigned char; |
|
||||||
}%% |
|
||||||
|
|
||||||
// Persistent state |
|
||||||
static int8_t cs = -1; //!< Ragel's Current State variable |
|
||||||
static uint32_t buff_i = 0; //!< Write pointer for the buffers |
|
||||||
static char value_quote = 0; //!< Quote character of the currently collected value |
|
||||||
static bool value_nextesc = false; //!< Next character is escaped, trated specially, and if quote, as literal quote character |
|
||||||
static IniParserCallback keyCallback = NULL; //!< Currently assigned callback |
|
||||||
static void *userdata = NULL; //!< Currently assigned user data for the callback |
|
||||||
|
|
||||||
// Buffers |
|
||||||
static char keybuf[INI_KEY_MAX]; |
|
||||||
static char secbuf[INI_KEY_MAX]; |
|
||||||
static char valbuf[INI_VALUE_MAX]; |
|
||||||
|
|
||||||
// See header for doxygen! |
|
||||||
|
|
||||||
void |
|
||||||
ini_parse_reset_partial(void) |
|
||||||
{ |
|
||||||
buff_i = 0; |
|
||||||
value_quote = 0; |
|
||||||
value_nextesc = false; |
|
||||||
} |
|
||||||
|
|
||||||
void |
|
||||||
ini_parse_reset(void) |
|
||||||
{ |
|
||||||
ini_parse_reset_partial(); |
|
||||||
keybuf[0] = secbuf[0] = valbuf[0] = 0; |
|
||||||
%% write init; |
|
||||||
} |
|
||||||
|
|
||||||
void |
|
||||||
ini_parser_error(const char* msg) |
|
||||||
{ |
|
||||||
ini_error("Parser error: %s", msg); |
|
||||||
ini_parse_reset_partial(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
void |
|
||||||
ini_parse_begin(IniParserCallback callback, void *userData) |
|
||||||
{ |
|
||||||
keyCallback = callback; |
|
||||||
userdata = userData; |
|
||||||
ini_parse_reset(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
void |
|
||||||
*ini_parse_end(void) |
|
||||||
{ |
|
||||||
ini_parse("\n", 1); |
|
||||||
if (keyCallback) { |
|
||||||
keyCallback = NULL; |
|
||||||
} |
|
||||||
|
|
||||||
void *ud = userdata; |
|
||||||
userdata = NULL; |
|
||||||
return ud; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
void |
|
||||||
ini_parse_file(const char *text, size_t len, IniParserCallback callback, void *userData) |
|
||||||
{ |
|
||||||
ini_parse_begin(callback, userData); |
|
||||||
ini_parse(text, len); |
|
||||||
ini_parse_end(); |
|
||||||
} |
|
||||||
|
|
||||||
static void |
|
||||||
rtrim_buf(char *buf, int32_t end) |
|
||||||
{ |
|
||||||
if (end > 0) { |
|
||||||
while ((uint8_t)buf[--end] < 33); |
|
||||||
end++; // go past the last character |
|
||||||
} |
|
||||||
|
|
||||||
buf[end] = 0; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
void |
|
||||||
ini_parse(const char *newstr, size_t len) |
|
||||||
{ |
|
||||||
int32_t i; |
|
||||||
char c; |
|
||||||
bool isnl; |
|
||||||
bool isquot; |
|
||||||
|
|
||||||
// Load new data to Ragel vars |
|
||||||
const uint8_t *p; |
|
||||||
const uint8_t *eof; |
|
||||||
const uint8_t *pe; |
|
||||||
|
|
||||||
if (len == 0) while(newstr[++len] != 0); // alternative to strlen |
|
||||||
|
|
||||||
p = (const uint8_t *) newstr; |
|
||||||
eof = NULL; |
|
||||||
pe = (const uint8_t *) (newstr + len); |
|
||||||
|
|
||||||
// Init Ragel on the first run |
|
||||||
if (cs == -1) { |
|
||||||
ini_parse_reset(); |
|
||||||
} |
|
||||||
|
|
||||||
// The parser |
|
||||||
%%{ |
|
||||||
#/ * |
|
||||||
ispace = [ \t]; # inline space |
|
||||||
wchar = any - 0..8 - 10..31; |
|
||||||
#apos = '\''; |
|
||||||
#quot = '\"'; |
|
||||||
nonl = [^\r\n]; |
|
||||||
nl = '\r'? '\n'; |
|
||||||
|
|
||||||
# ---- [SECTION] ---- |
|
||||||
|
|
||||||
action sectionStart { |
|
||||||
buff_i = 0; |
|
||||||
fgoto section; |
|
||||||
} |
|
||||||
|
|
||||||
action sectionChar { |
|
||||||
if (buff_i >= INI_KEY_MAX) { |
|
||||||
ini_parser_error("Section name too long"); |
|
||||||
fgoto discard2eol; |
|
||||||
} |
|
||||||
keybuf[buff_i++] = fc; |
|
||||||
} |
|
||||||
|
|
||||||
action sectionEnd { |
|
||||||
// we need a separate buffer for the result, otherwise a failed |
|
||||||
// partial parse would corrupt the section string |
|
||||||
rtrim_buf(keybuf, buff_i); |
|
||||||
for (i = 0; (c = keybuf[i]) != 0; i++) secbuf[i] = c; |
|
||||||
secbuf[i] = 0; |
|
||||||
fgoto main; |
|
||||||
} |
|
||||||
|
|
||||||
section := |
|
||||||
( |
|
||||||
ispace* <: ((wchar - ']')+ @sectionChar) ']' @sectionEnd |
|
||||||
) $!{ |
|
||||||
ini_parser_error("Syntax error in [section]"); |
|
||||||
if(fc == '\n') fgoto main; else fgoto discard2eol; |
|
||||||
}; |
|
||||||
|
|
||||||
# ---- KEY=VALUE ---- |
|
||||||
|
|
||||||
action keyStart { |
|
||||||
buff_i = 0; |
|
||||||
keybuf[buff_i++] = fc; // add the first char |
|
||||||
fgoto keyvalue; |
|
||||||
} |
|
||||||
|
|
||||||
action keyChar { |
|
||||||
if (buff_i >= INI_KEY_MAX) { |
|
||||||
ini_parser_error("Key too long"); |
|
||||||
fgoto discard2eol; |
|
||||||
} |
|
||||||
keybuf[buff_i++] = fc; |
|
||||||
} |
|
||||||
|
|
||||||
action keyEnd { |
|
||||||
rtrim_buf(keybuf, buff_i); |
|
||||||
|
|
||||||
// --- Value begin --- |
|
||||||
buff_i = 0; |
|
||||||
value_quote = 0; |
|
||||||
value_nextesc = false; |
|
||||||
} |
|
||||||
|
|
||||||
action valueChar { |
|
||||||
isnl = (fc == '\r' || fc == '\n'); |
|
||||||
isquot = (fc == '\'' || fc == '"'); |
|
||||||
|
|
||||||
// detect our starting quote |
|
||||||
if (isquot && !value_nextesc && buff_i == 0 && value_quote == 0) { |
|
||||||
value_quote = fc; |
|
||||||
goto valueCharDone; |
|
||||||
} |
|
||||||
|
|
||||||
if (buff_i >= INI_VALUE_MAX) { |
|
||||||
ini_parser_error("Value too long"); |
|
||||||
fgoto discard2eol; |
|
||||||
} |
|
||||||
|
|
||||||
// end of string - clean up and report |
|
||||||
if ((!value_nextesc && fc == value_quote) || isnl) { |
|
||||||
if (isnl && value_quote) { |
|
||||||
ini_parser_error("Unterminated string"); |
|
||||||
fgoto main; |
|
||||||
} |
|
||||||
|
|
||||||
// unquoted: trim from the end |
|
||||||
if (!value_quote) { |
|
||||||
rtrim_buf(valbuf, buff_i); |
|
||||||
} else { |
|
||||||
valbuf[buff_i] = 0; |
|
||||||
} |
|
||||||
|
|
||||||
if (keyCallback) { |
|
||||||
keyCallback(secbuf, keybuf, valbuf, userdata); |
|
||||||
} |
|
||||||
|
|
||||||
// we don't want to discard to eol if the string was terminated by eol |
|
||||||
// - would delete the next line |
|
||||||
|
|
||||||
if (isnl) fgoto main; else fgoto discard2eol; |
|
||||||
} |
|
||||||
|
|
||||||
c = fc; |
|
||||||
// escape... |
|
||||||
if (value_nextesc) { |
|
||||||
if (fc == 'n') c = '\n'; |
|
||||||
else if (fc == 'r') c = '\r'; |
|
||||||
else if (fc == 't') c = '\t'; |
|
||||||
else if (fc == 'e') c = '\033'; |
|
||||||
} |
|
||||||
|
|
||||||
// collecting characters... |
|
||||||
if (value_nextesc || fc != '\\') { // is quoted, or is not a quoting backslash - literal character |
|
||||||
valbuf[buff_i++] = c; |
|
||||||
} |
|
||||||
|
|
||||||
value_nextesc = (!value_nextesc && fc == '\\'); |
|
||||||
valueCharDone:; |
|
||||||
} |
|
||||||
|
|
||||||
# use * for key, first char is already consumed. |
|
||||||
keyvalue := |
|
||||||
( |
|
||||||
([^\n=:]* @keyChar %keyEnd) |
|
||||||
[=:] ispace* <: nonl* @valueChar nl @valueChar |
|
||||||
) $!{ |
|
||||||
ini_parser_error("Syntax error in key=value"); |
|
||||||
if(fc == '\n') fgoto main; else fgoto discard2eol; |
|
||||||
}; |
|
||||||
|
|
||||||
# ---- COMMENT ---- |
|
||||||
|
|
||||||
comment := |
|
||||||
( |
|
||||||
nonl* nl |
|
||||||
@{ fgoto main; } |
|
||||||
) $!{ |
|
||||||
ini_parser_error("Syntax error in comment"); |
|
||||||
if(fc == '\n') fgoto main; else fgoto discard2eol; |
|
||||||
}; |
|
||||||
|
|
||||||
# ---- CLEANUP ---- |
|
||||||
|
|
||||||
discard2eol := nonl* nl @{ fgoto main; }; |
|
||||||
|
|
||||||
# ---- ROOT ---- |
|
||||||
|
|
||||||
main := |
|
||||||
(space* |
|
||||||
( |
|
||||||
'[' @sectionStart | |
|
||||||
[#;] @{ fgoto comment; } | |
|
||||||
(wchar - [\t =:]) @keyStart |
|
||||||
) |
|
||||||
) $!{ |
|
||||||
ini_parser_error("Syntax error in root"); |
|
||||||
fgoto discard2eol; |
|
||||||
}; |
|
||||||
|
|
||||||
write exec; |
|
||||||
#*/ |
|
||||||
}%% |
|
||||||
} |
|
Loading…
Reference in new issue