diff --git a/mpw/CMakeLists.txt b/mpw/CMakeLists.txt index 7b76865..106fee4 100644 --- a/mpw/CMakeLists.txt +++ b/mpw/CMakeLists.txt @@ -6,6 +6,11 @@ add_definitions(-I ${CMAKE_SOURCE_DIR}/) set(MPW_SRC mpw.cpp mpw_io.cpp mpw_close.cpp mpw_access.cpp mpw_ioctl.cpp environ.cpp) +add_custom_command( + OUTPUT environ.cpp + COMMAND ragel -p -G2 -o environ.cpp "${CMAKE_CURRENT_SOURCE_DIR}/environ.rl" + MAIN_DEPENDENCY environ.rl +) add_library(MPW_LIB ${MPW_SRC}) \ No newline at end of file diff --git a/mpw/environ.cpp b/mpw/environ.cpp deleted file mode 100644 index 36e749d..0000000 --- a/mpw/environ.cpp +++ /dev/null @@ -1,356 +0,0 @@ -/* Generated by re2c 0.13.5 on Sat May 18 16:26:02 2013 */ -#include -#include - -#include - -/* - * #...comment - * var=value - * where value may contain $var and ${var} interpolations. - * - */ - -namespace MPW { -std::string EvalString(std::string &s, std::unordered_map &env) -{ - - std::string rv; - const char *cp = s.c_str(); - const char *marker = NULL; - - while (*cp) - { - const char *begin = cp; - - - { - char yych; - - yych = (char)*cp; - switch (yych) { - case '\n': goto yy5; - case '$': goto yy2; - default: goto yy4; - } -yy2: - yych = (char)*(marker = ++cp); - switch (yych) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': - case 'G': - case 'H': - case 'I': - case 'J': - case 'K': - case 'L': - case 'M': - case 'N': - case 'O': - case 'P': - case 'Q': - case 'R': - case 'S': - case 'T': - case 'U': - case 'V': - case 'W': - case 'X': - case 'Y': - case 'Z': - case '_': - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - case 'g': - case 'h': - case 'i': - case 'j': - case 'k': - case 'l': - case 'm': - case 'n': - case 'o': - case 'p': - case 'q': - case 'r': - case 's': - case 't': - case 'u': - case 'v': - case 'w': - case 'x': - case 'y': - case 'z': goto yy9; - case '{': goto yy7; - default: goto yy3; - } -yy3: - { - rv.push_back(*begin); - continue; - } -yy4: - yych = (char)*++cp; - goto yy3; -yy5: - ++cp; - { - break; - } -yy7: - yych = (char)*++cp; - switch (yych) { - case '}': goto yy8; - default: goto yy13; - } -yy8: - cp = marker; - goto yy3; -yy9: - ++cp; - yych = (char)*cp; - switch (yych) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': - case 'G': - case 'H': - case 'I': - case 'J': - case 'K': - case 'L': - case 'M': - case 'N': - case 'O': - case 'P': - case 'Q': - case 'R': - case 'S': - case 'T': - case 'U': - case 'V': - case 'W': - case 'X': - case 'Y': - case 'Z': - case '_': - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - case 'g': - case 'h': - case 'i': - case 'j': - case 'k': - case 'l': - case 'm': - case 'n': - case 'o': - case 'p': - case 'q': - case 'r': - case 's': - case 't': - case 'u': - case 'v': - case 'w': - case 'x': - case 'y': - case 'z': goto yy9; - default: goto yy11; - } -yy11: - { - std::string tmp(begin + 1, cp); - - // lookup value... - // append to rv. - auto iter = env.find(tmp); - if (iter != env.end()) - { - rv.append(iter->second); - } - continue; - } -yy12: - ++cp; - yych = (char)*cp; -yy13: - switch (yych) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': - case 'G': - case 'H': - case 'I': - case 'J': - case 'K': - case 'L': - case 'M': - case 'N': - case 'O': - case 'P': - case 'Q': - case 'R': - case 'S': - case 'T': - case 'U': - case 'V': - case 'W': - case 'X': - case 'Y': - case 'Z': - case '_': - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - case 'g': - case 'h': - case 'i': - case 'j': - case 'k': - case 'l': - case 'm': - case 'n': - case 'o': - case 'p': - case 'q': - case 'r': - case 's': - case 't': - case 'u': - case 'v': - case 'w': - case 'x': - case 'y': - case 'z': goto yy12; - case '}': goto yy14; - default: goto yy8; - } -yy14: - ++cp; - { - - std::string tmp(begin + 2, cp - 1); - - auto iter = env.find(tmp); - if (iter != env.end()) - { - rv.append(iter->second); - } - continue; - } - } - - - } - - return rv; -} - - -void LoadEnvironment(std::string &envfile, std::unordered_map &env) -{ - - FILE *fp; - - - fp = fopen(envfile.c_str(), "r"); - - if (!fp) return; - - for (;;) - { - char *begin; - char *end; - char *iter; - - size_t length; - - begin = fgetln(fp, &length); - if (!begin) break; // eof or error. - - if (!length) continue; - if (begin[0] == '#') continue; - - while (length && isspace(begin[length - 1])) --length; - if (!length) continue; - - // key=value - - // ehh, this could really check for [A-Za-z0-9_]+ '=' - - end = begin + length; - iter = std::find(begin, end, '='); - - if (iter == end || iter == begin) - { - fprintf(stderr, "Invalid Environment entry: %.*s\n", (int)length, begin); - continue; - } - - std::string key(begin, iter); - std::string value(iter + 1, end); - - value = EvalString(value, env); - - //fprintf(stdout, "%s = %s\n", key.c_str(), value.c_str()); - - // todo -- does this replace an existing value? - env.emplace(key, value); - } - - fclose(fp); -} - -} \ No newline at end of file diff --git a/mpw/environ.rl b/mpw/environ.rl new file mode 100644 index 0000000..f2501f9 --- /dev/null +++ b/mpw/environ.rl @@ -0,0 +1,145 @@ + +%%{ + + machine lexer; + + + ws = [ \t\r\n]; + + word = [A-Za-z0-9_]; + + action emplace { + //printf("emplacing %s\n", name.c_str()); + // trim any whitespace. + while (value.length() && isspace(value.back())) + value.pop_back(); + env[std::move(name)] = std::move(value); + } + + action error { + fprintf(stderr, "Bad environment: %.*s\n", (int)length, line); + } + + value := |* + + '$' word+ => { + std::string name(ts + 1, te); + auto iter = env.find(name); + if (iter != env.end()) + value.append(iter->second); + }; + + '${' word+ '}' => { + std::string name(ts + 2, te - 1); + auto iter = env.find(name); + if (iter != env.end()) + value.append(iter->second); + }; + + '$$' => { + value.push_back('$'); + }; + + any $eof(emplace) => { + value.push_back(fc); + } ; + + *|; + + + # exit w/ cs = lexer_en_comment. + + comment := any* ${ fbreak; }; + + assignment = + word+ ${ name.push_back(fc); } + ws* %eof(error) + '=' + ws* + (any - ws)? ${ fhold; fgoto value; } + %eof(emplace) + ; + + main := ws* ( '#' ${ fgoto comment; } | assignment); + +}%% + +#include +#include +#include +#include + +namespace MPW { + +void LoadEnvironment(std::string &envfile, std::unordered_map &env) +{ + %% write data; + + FILE *fp; + + + fp = fopen(envfile.c_str(), "r"); + + if (!fp) return; + + for(;;) + { + const char *line; + size_t length; + + line = fgetln(fp, &length); + if (!line) break; // eof or error. + + // strip any trailign space. + while (length && isspace(line[length - 1])) + length--; + + std::string name; + std::string value; + + const char *p = line; + const char *pe = line + length; + const char *eof = line + length; + const char *te; + const char *ts; + + int cs, act; + + %%write init; + %%write exec; + + if (cs == lexer_error) + { + fprintf(stderr, "Bad environment: %.*s\n", (int)length, line); + continue; + } + } + + fclose(fp); +} + +} // namespace + +#ifdef TEST + +int main(int argc, char **argv) +{ + + for (int i = 1; i < argc; ++i) + { + std::unordered_map env; + std::string f(argv[i]); + + MPW::LoadEnvironment(f, env); + + for (const auto &kv : env) + { + printf("%s -> %s\n", kv.first.c_str(), kv.second.c_str()); + } + } + + return 0; +} + + +#endif \ No newline at end of file