parent
							
								
									ed7a4c80a0
								
							
						
					
					
						commit
						4b8d24ae0f
					
				| @ -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; | ||||
| } | ||||
|  | ||||
| @ -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