// helper functions to test the parsing of config files and/or metaknobs // void testparse(int lineno, MACRO_SET & set, MACRO_EVAL_CONTEXT &ctx, MACRO_SOURCE & source, bool verbose, const char * tag, const char * params, const char * expected) { int ret = Parse_config_string(source, 0, params, set, ctx); const char * hashout = NULL; if (ret < 0) { fprintf(stderr, "Failed %5d: test '%s' local=%s subsys=%s parse error %d\n", lineno, tag, ctx.localname ? ctx.localname : "", ctx.subsys ? ctx.subsys : "", ret); gmstr.clear(); hashout = NULL; } else { dump_macro_set(set, gmstr, "\t"); hashout = gmstr.c_str(); if (gmstr != expected) { fprintf(stderr, "Failed %5d: test '%s' local=%s subsys=%s resulting hashtable does not match expected\n", lineno, tag, ctx.localname ? ctx.localname : "", ctx.subsys ? ctx.subsys : ""); ret = -1; } else if (verbose) { fprintf(stdout, " OK %5d: test '%s' local=%s subsys=%s\n", lineno, tag, ctx.localname ? ctx.localname : "", ctx.subsys ? ctx.subsys : ""); ret = 0; } } if (verbose || ret) { fprintf(ret ? stderr : stdout, "\t---- parse input %d ----\n%s", lineno, params); if (hashout) fprintf(ret ? stderr : stdout, "\t---- resulting hash %d ----\n%s", lineno, hashout); if (ret) fprintf(stderr, "\t---- expected hash %d ----\n%s", lineno, expected); fprintf(ret ? stderr : stdout, "\t---- end %d ----\n\n", lineno); } clear_macro_set(set); }
tst_t *Parse_config_string(bstring content) { Token *temp = NULL; void *parser = ParseAlloc(malloc); check_mem(parser); ParserState state = {.settings = NULL, .error = 0, .line_number = 1}; char *p = bdata(content); char *pe = bdataofs(content, blength(content) - 1); char *eof = pe; int cs = -1; int act = -1; char *ts = NULL; char *te = NULL; #line 114 "src/lexer.c" { cs = m2sh_lexer_start; ts = 0; te = 0; act = 0; } #line 135 "src/lexer.rl" #line 124 "src/lexer.c" { if ( p == pe ) goto _test_eof; switch ( cs ) { tr1: #line 77 "src/lexer.rl" {te = p+1;{ TKSTR(QSTRING) }} goto st6; tr4: #line 91 "src/lexer.rl" {te = p+1;} goto st6; tr7: #line 89 "src/lexer.rl" {te = p+1;} goto st6; tr9: #line 88 "src/lexer.rl" {te = p+1;{ state.line_number++; }} goto st6; tr10: #line 83 "src/lexer.rl" {te = p+1;{ TK(LPAREN) }} goto st6; tr11: #line 84 "src/lexer.rl" {te = p+1;{ TK(RPAREN) }} goto st6; tr12: #line 85 "src/lexer.rl" {te = p+1;{ TK(COMMA) }} goto st6; tr14: #line 86 "src/lexer.rl" {te = p+1;{ TK(COLON) }} goto st6; tr15: #line 78 "src/lexer.rl" {te = p+1;{ TK(EQ) }} goto st6; tr17: #line 81 "src/lexer.rl" {te = p+1;{ TK(LBRACE) }} goto st6; tr18: #line 82 "src/lexer.rl" {te = p+1;{ TK(RBRACE) }} goto st6; tr20: #line 79 "src/lexer.rl" {te = p+1;{ TK(LBRACKET) }} goto st6; tr21: #line 80 "src/lexer.rl" {te = p+1;{ TK(RBRACKET) }} goto st6; tr22: #line 93 "src/lexer.rl" {te = p;p--;{ TK(NUMBER) }} goto st6; tr23: #line 1 "NONE" { switch( act ) { case 15: {{p = ((te))-1;} TK(CLASS) } break; case 16: {{p = ((te))-1;} TK(IDENT) } break; } } goto st6; tr25: #line 95 "src/lexer.rl" {te = p;p--;{ TK(IDENT) }} goto st6; st6: #line 1 "NONE" {ts = 0;} if ( ++p == pe ) goto _test_eof6; case 6: #line 1 "NONE" {ts = p;} #line 210 "src/lexer.c" switch( (*p) ) { case 10: goto tr9; case 32: goto tr7; case 34: goto st1; case 35: goto st3; case 39: goto st4; case 40: goto tr10; case 41: goto tr11; case 44: goto tr12; case 58: goto tr14; case 61: goto tr15; case 91: goto tr17; case 93: goto tr18; case 95: goto st9; case 123: goto tr20; case 125: goto tr21; } if ( (*p) < 48 ) { if ( 9 <= (*p) && (*p) <= 13 ) goto tr7; } else if ( (*p) > 57 ) { if ( (*p) > 90 ) { if ( 97 <= (*p) && (*p) <= 122 ) goto st9; } else if ( (*p) >= 65 ) goto tr16; } else goto st7; goto st0; st0: cs = 0; goto _out; st1: if ( ++p == pe ) goto _test_eof1; case 1: switch( (*p) ) { case 34: goto tr1; case 92: goto st2; } goto st1; st2: if ( ++p == pe ) goto _test_eof2; case 2: goto st1; st3: if ( ++p == pe ) goto _test_eof3; case 3: if ( (*p) == 10 ) goto tr4; goto st3; st4: if ( ++p == pe ) goto _test_eof4; case 4: switch( (*p) ) { case 39: goto tr1; case 92: goto st5; } goto st4; st5: if ( ++p == pe ) goto _test_eof5; case 5: goto st4; st7: if ( ++p == pe ) goto _test_eof7; case 7: if ( 48 <= (*p) && (*p) <= 57 ) goto st7; goto tr22; tr16: #line 1 "NONE" {te = p+1;} #line 95 "src/lexer.rl" {act = 16;} goto st8; tr24: #line 1 "NONE" {te = p+1;} #line 94 "src/lexer.rl" {act = 15;} goto st8; st8: if ( ++p == pe ) goto _test_eof8; case 8: #line 301 "src/lexer.c" if ( (*p) == 95 ) goto st9; if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) goto st9; } else if ( (*p) > 90 ) { if ( 97 <= (*p) && (*p) <= 122 ) goto tr24; } else goto tr24; goto tr23; st9: if ( ++p == pe ) goto _test_eof9; case 9: if ( (*p) == 95 ) goto st9; if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) goto st9; } else if ( (*p) > 90 ) { if ( 97 <= (*p) && (*p) <= 122 ) goto st9; } else goto st9; goto tr25; } _test_eof6: cs = 6; goto _test_eof; _test_eof1: cs = 1; goto _test_eof; _test_eof2: cs = 2; goto _test_eof; _test_eof3: cs = 3; goto _test_eof; _test_eof4: cs = 4; goto _test_eof; _test_eof5: cs = 5; goto _test_eof; _test_eof7: cs = 7; goto _test_eof; _test_eof8: cs = 8; goto _test_eof; _test_eof9: cs = 9; goto _test_eof; _test_eof: {} if ( p == eof ) { switch ( cs ) { case 7: goto tr22; case 8: goto tr23; case 9: goto tr25; } } _out: {} } #line 136 "src/lexer.rl" if(state.error) { Parse_print_error("SYNTAX ERROR", content, (int)(ts - bdata(content)), ++state.line_number); } else if( cs == #line 359 "src/lexer.c" 0 #line 141 "src/lexer.rl" ) { Parse_print_error("INVALID CHARACTER", content, (int)(ts - bdata(content)), ++state.line_number); } else if( cs >= #line 366 "src/lexer.c" 6 #line 144 "src/lexer.rl" ) { Parse(parser, TKEOF, NULL, &state); } else { log_err("INCOMPLETE CONFIG FILE. There needs to be more to this."); } Parse(parser, 0, 0, &state); ParseFree(parser, free); return state.settings; error: if(state.error) { Parse_print_error("SYNTAX ERROR", content, (int)(ts - bdata(content)), ++state.line_number); } ParseFree(parser, free); return NULL; } tst_t *Parse_config_file(const char *path) { FILE *script; bstring buffer = NULL; tst_t *settings = NULL; script = fopen(path, "r"); check(script, "Failed to open file: %s", path); buffer = bread((bNread)fread, script); check_mem(buffer); fclose(script); script = NULL; // make sure there's a \n at the end bconchar(buffer, '\n'); settings = Parse_config_string(buffer); check(settings != NULL, "Failed to parse file: %s", path); bdestroy(buffer); buffer = NULL; return settings; error: bdestroy(buffer); if(script) fclose(script); return NULL; }