diff --git a/utils/ini_parser.c b/utils/ini_parser.c index 96acdbd..02a9791 100644 --- a/utils/ini_parser.c +++ b/utils/ini_parser.c @@ -1,526 +1,134 @@ - -/* #line 1 "ini_parser.rl" */ - -/* Ragel constants block */ #include "ini_parser.h" -// Ragel setup - -/* #line 10 "ini_parser.c" */ -static const char _ini_actions[] = { - 0, 1, 1, 1, 2, 1, 3, 1, - 4, 1, 5, 1, 6, 1, 7, 1, - 8, 1, 9, 1, 10, 1, 11, 1, - 13, 2, 0, 4, 2, 12, 4 +enum nini_state { + NINI_IDLE, + NINI_SECTION, + NINI_KEY, + NINI_VALUE, + NINI_COMMENT, }; -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 const int ini_first_final = 12; -static const int ini_error = 0; - -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! +static struct { + uint8_t section_i; + char section[INI_KEY_MAX]; -void -ini_parse_reset_partial(void) -{ - buff_i = 0; - value_quote = 0; - value_nextesc = false; -} + uint8_t key_i; + char key[INI_KEY_MAX]; -void -ini_parse_reset(void) -{ - ini_parse_reset_partial(); - keybuf[0] = secbuf[0] = valbuf[0] = 0; - -/* #line 67 "ini_parser.c" */ - { - cs = ini_start; - } + uint8_t value_i; + char value[INI_VALUE_MAX]; + bool val_last_space; -/* #line 41 "ini_parser.rl" */ -} + IniParserCallback cb; + void *userdata; + enum nini_state state; +} nini; -void -ini_parser_error(const char* msg) +void ini_parse_begin(IniParserCallback callback, void *userData) { - ini_error("Parser error: %s", msg); - ini_parse_reset_partial(); + ini_parse_reset(); + nini.cb = callback; + nini.userdata = userData; } - -void -ini_parse_begin(IniParserCallback callback, void *userData) +void ini_parse(const char *data, size_t len) { - keyCallback = callback; - userdata = userData; - ini_parse_reset(); + for (; len > 0; len--) { + char c = *data++; + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') { + if (nini.state != NINI_VALUE && nini.state != NINI_COMMENT) + continue; + } + + switch (nini.state) { + case NINI_IDLE: + if (c == '[') { + nini.state = NINI_SECTION; + nini.section_i = 0; + } + else if (c == '#') { + nini.state = NINI_COMMENT; + } + else { + nini.state = NINI_KEY; + nini.key_i = 0; + nini.value_i = 0; + nini.val_last_space = false; + nini.key[nini.key_i++] = c; + } + break; + + case NINI_COMMENT: + if (c == '\n' || c == '\r') { + nini.state = NINI_IDLE; + } + break; + + case NINI_SECTION: + if (c == ']') { + nini.section[nini.section_i] = 0; + nini.state = NINI_COMMENT; // discard to EOL + break; + } + else if (nini.section_i < INI_KEY_MAX - 1) { + nini.section[nini.section_i++] = c; + } + break; + + case NINI_KEY: + if (c == '=') { + nini.key[nini.key_i] = 0; + nini.state = NINI_VALUE; + } + else if (nini.key_i < INI_KEY_MAX - 1) { + nini.key[nini.key_i++] = c; + } + break; + + case NINI_VALUE: + switch (c) { + case ' ': + case '\t': + if (nini.value_i) nini.val_last_space = true; + break; + case '\r': + case '\n': + nini.value[nini.value_i] = 0; + nini.state = NINI_IDLE; + nini.cb(nini.section, nini.key, nini.value, nini.userdata); + break; + default: + if (nini.val_last_space && nini.value_i < INI_VALUE_MAX - 1) { + nini.value[nini.value_i++] = ' '; + } + + if (nini.value_i < INI_VALUE_MAX - 1) { + nini.value[nini.value_i++] = c; + } + } + } + } } - -void -*ini_parse_end(void) +void *ini_parse_end(void) { - ini_parse("\n", 1); - if (keyCallback) { - keyCallback = NULL; - } + if (nini.state == NINI_VALUE) { + nini.value[nini.value_i] = 0; + nini.state = NINI_IDLE; + nini.cb(nini.section, nini.key, nini.value, nini.userdata); + } - void *ud = userdata; - userdata = NULL; - return ud; + return nini.userdata; } - -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) +void ini_parse_file(const char *text, size_t len, IniParserCallback callback, void *userData) { - if (end > 0) { - while ((uint8_t)buf[--end] < 33); - end++; // go past the last character - } - - buf[end] = 0; + ini_parse_begin(callback, userData); + ini_parse(text, len); + ini_parse_end(); } - -void -ini_parse(const char *newstr, size_t len) +void ini_parse_reset(void) { - 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; - case 1: -/* #line 135 "ini_parser.rl" */ - { - if (buff_i >= INI_KEY_MAX) { - ini_parser_error("Section name too long"); - {cs = 10;goto _again;} - } - keybuf[buff_i++] = (*p); - } - break; - case 2: -/* #line 143 "ini_parser.rl" */ - { - // 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; - {cs = 1;goto _again;} - } - 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; - case 4: -/* #line 162 "ini_parser.rl" */ - { - buff_i = 0; - keybuf[buff_i++] = (*p); // add the first char - {cs = 4;goto _again;} - } - break; - case 5: -/* #line 168 "ini_parser.rl" */ - { - if (buff_i >= INI_KEY_MAX) { - ini_parser_error("Key too long"); - {cs = 10;goto _again;} - } - keybuf[buff_i++] = (*p); - } - break; - case 6: -/* #line 176 "ini_parser.rl" */ - { - rtrim_buf(keybuf, buff_i); - - // --- Value begin --- - buff_i = 0; - value_quote = 0; - value_nextesc = false; - } - break; - case 7: -/* #line 185 "ini_parser.rl" */ - { - isnl = ((*p) == '\r' || (*p) == '\n'); - isquot = ((*p) == '\'' || (*p) == '"'); - - // detect our starting quote - if (isquot && !value_nextesc && buff_i == 0 && value_quote == 0) { - value_quote = (*p); - goto valueCharDone; - } - - if (buff_i >= INI_VALUE_MAX) { - ini_parser_error("Value too long"); - {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); - // escape... - if (value_nextesc) { - if ((*p) == 'n') c = '\n'; - else if ((*p) == 'r') c = '\r'; - else if ((*p) == 't') c = '\t'; - else if ((*p) == 'e') c = '\033'; - } - - // collecting characters... - if (value_nextesc || (*p) != '\\') { // is quoted, or is not a quoting backslash - literal character - valbuf[buff_i++] = c; - } - - value_nextesc = (!value_nextesc && (*p) == '\\'); -valueCharDone:; - } - break; - case 8: -/* #line 247 "ini_parser.rl" */ - { - ini_parser_error("Syntax error in key=value"); - if((*p) == '\n') {cs = 1;goto _again;} else {cs = 10;goto _again;} - } - 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: - if ( cs == 0 ) - goto _out; - if ( ++p != pe ) - goto _resume; - _test_eof: {} - if ( p == eof ) - { - const char *__acts = _ini_actions + _ini_eof_actions[cs]; - 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" */ - + nini.state = NINI_IDLE; } diff --git a/utils/ini_parser.h b/utils/ini_parser.h index 52b36ac..995e9ff 100644 --- a/utils/ini_parser.h +++ b/utils/ini_parser.h @@ -8,12 +8,12 @@ #include "platform.h" -// toggleable logging func -#ifdef DEBUG_INI -#define ini_error(fmt, ...) dbg("! INI err: "#fmt, ##__VA_ARGS__) -#else -#define ini_error(fmt, ...) -#endif +//// toggleable logging func +//#ifdef DEBUG_INI +//#define ini_error(fmt, ...) dbg("! INI err: "#fmt, ##__VA_ARGS__) +//#else +//#define ini_error(fmt, ...) +//#endif // buffer sizes //#define INI_KEY_MAX 20 diff --git a/utils/ini_parser.rl b/utils/ini_parser.rl deleted file mode 100644 index 42f6a3c..0000000 --- a/utils/ini_parser.rl +++ /dev/null @@ -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; -#*/ - }%% -}