diff --git a/bin/loader.cpp b/bin/loader.cpp index 1d9603e..5aef04c 100644 --- a/bin/loader.cpp +++ b/bin/loader.cpp @@ -538,6 +538,8 @@ bool file_exists(const std::string & name) std::string find_exe(const std::string &name) { + // TODO -- use the environment variable for directories. + if (file_exists(name)) return name; // if name is a path, then it doesn't exist. @@ -652,8 +654,10 @@ int main(int argc, char **argv) //auto start_time = std::chrono::high_resolution_clock::now(); + std::vector defines; + int c; - while ((c = getopt_long(argc, argv, "+hVm:r:s:", LongOpts, NULL)) != -1) + while ((c = getopt_long(argc, argv, "+hVm:r:s:D:", LongOpts, NULL)) != -1) { switch(c) { @@ -700,6 +704,10 @@ int main(int argc, char **argv) exit(EX_CONFIG); break; + case 'D': + defines.push_back(optarg); + break; + case ':': case '?': help(); @@ -768,7 +776,7 @@ int main(int argc, char **argv) MM::Init(Memory, MemorySize, kGlobalSize); OS::Init(); - MPW::Init(argc, argv); + MPW::Init(argc, argv, defines); cpuStartup(); diff --git a/mpw/CMakeLists.txt b/mpw/CMakeLists.txt index 2b8855e..2f59d5b 100644 --- a/mpw/CMakeLists.txt +++ b/mpw/CMakeLists.txt @@ -5,33 +5,39 @@ set(CMAKE_CXX_FLAGS "-std=c++11 -stdlib=libc++ -Wall -g") 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 epv.cpp ep.cpp) + environment.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_custom_command( - OUTPUT environ.cpp - COMMAND ragel -p -G2 -o environ.cpp "${CMAKE_CURRENT_SOURCE_DIR}/environ.rl" - MAIN_DEPENDENCY environ.rl + OUTPUT environment.cpp + COMMAND ragel -p -G2 -o environment.cpp "${CMAKE_CURRENT_SOURCE_DIR}/environment.rl" + MAIN_DEPENDENCY environment.rl ) -add_custom_command( - OUTPUT epv.cpp - COMMAND ragel -p -G2 -o epv.cpp "${CMAKE_CURRENT_SOURCE_DIR}/epv.rl" - MAIN_DEPENDENCY epv.rl -) +# add_custom_command( +# OUTPUT epv.cpp +# COMMAND ragel -p -G2 -o epv.cpp "${CMAKE_CURRENT_SOURCE_DIR}/epv.rl" +# MAIN_DEPENDENCY epv.rl +# ) -add_custom_command( - OUTPUT ep.cpp - COMMAND ragel -p -G2 -o ep.cpp "${CMAKE_CURRENT_SOURCE_DIR}/ep.rl" - MAIN_DEPENDENCY ep.rl -) +# add_custom_command( +# OUTPUT ep.cpp +# COMMAND ragel -p -G2 -o ep.cpp "${CMAKE_CURRENT_SOURCE_DIR}/ep.rl" +# MAIN_DEPENDENCY ep.rl +# ) set_source_files_properties( - environ.cpp ep.cpp epv.cpp + environment.cpp # environ.cpp ep.cpp epv.cpp PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-variable" diff --git a/mpw/environment.rl b/mpw/environment.rl new file mode 100644 index 0000000..9eb1201 --- /dev/null +++ b/mpw/environment.rl @@ -0,0 +1,326 @@ + +#include +#include +#include +#include + + +namespace MPW +{ + extern std::unordered_map Environment; + + std::string ExpandVariables(const std::string &s); +} + +namespace { + + + %%{ + machine name; + + main := + + [A-Za-z0-9_]+ @{ + name.push_back(fc); + } + ; + + write data; + }%% + + %%{ + machine assign; + + ws = [ \t\r\n]; + main := + + ws* + ( + '=' @{ + op = 1; + } + | + '+=' @{ + op = 2; + } + | + '?=' @{ + op = 3; + } + ) + ws* + ; + + write data; + }%% + + %%{ + machine variables; + + main := |* + + '{' [A-Za-z0-9_]+ '}' { + + std::string name(ts + 1, te - 1); + auto iter = Environment.find(name); + if (iter != Environment.end()) + rv.append(iter->second); + }; + + # backwards compatibility. + '${' [A-Za-z0-9_]+ '}' { + + std::string name(ts + 2, te - 1); + auto iter = Environment.find(name); + if (iter != Environment.end()) + rv.append(iter->second); + }; + + # backwards compatibility. + '$' [A-Za-z0-9_]+ { + std::string name(ts + 1, te); + auto iter = Environment.find(name); + if (iter != Environment.end()) + rv.append(iter->second); + }; + + any { + rv.push_back(*ts); + }; + *|; + + write data; + }%% + + // split out since goto names conflict. + const char* GetName(const char *p, const char *pe, std::string &name) + { + const char *eof = pe; + int cs; + + %%{ + machine name; + write init; + write exec; + }%% + + return p; + } + + const char *GetAssignment(const char *p, const char *pe, unsigned &op) + { + const char *eof = pe; + int cs; + + %%{ + machine assign; + write init; + write exec; + }%% + + return p; + } + + bool ParseLine(const char *p, const char *pe) + { + /* + * name = value + * name += value + * name ?= value + */ + + std::string name; + unsigned op = 0; + + const char *begin = p; + + // 1. get the name + p = GetName(p, pe, name); + if (!name.length()) + { + #ifdef TESTING + fprintf(stderr, "No Name\n"); + #endif + return false; + } + + // 2. get the op + p = GetAssignment(p, pe, op); + if (!op) + { + fprintf(stderr, "No assignment\n"); + return false; + } + + std::string value(p, pe); + value = MPW::ExpandVariables(value); + + auto iter = MPW::Environment.find(name); + if (iter == MPW::Environment.end()) + { + MPW::Environment.emplace(std::move(name), std::move(value)); + } + else + { + switch(op) + { + case 1: // = + iter->second = std::move(value); + break; + case 2: // += + iter->second += value; + break; + case 3: // ?= + break; + + } + } + return true; + } + +} + +namespace MPW { + + + std::string GetEnv(const std::string &key) + { + auto iter = Environment.find(key); + if (iter == Environment.end()) return ""; + return iter->second; + } + + std::string ExpandVariables(const std::string &s) + { + if (s.find_first_of("{$") == s.npos) return s; + + std::string rv; + const char *p = s.c_str(); + const char *pe = p + s.length(); + const char *eof = pe; + const char *te; + const char *ts; + + int cs; + int act; + + %%{ + machine variables; + + write init; + write exec; + }%% + + return rv; + } + + void EnvLoadArray(const std::vector &data) + { + for (const auto &s : data) + { + const char *begin = s.c_str(); + const char *end = begin + s.length(); + if (!s.length()) continue; + if (!ParseLine(begin, end)) + { + fprintf(stderr, "Error in variable: %s\n", s.c_str()); + } + } + } + + + void EnvLoadFile(const std::string &envfile) + { + + FILE *fp; + + + fp = fopen(envfile.c_str(), "r"); + + if (!fp) return; + + + /* + * getline(3) is 2008 posix. it allocates (and resizes as appropriate) + * the buffer. + * + */ + char *lineBuffer = NULL; + size_t lineSize = 0; + + for(;;) + { + char *line; + ssize_t length; + + length = getline(&lineBuffer, &lineSize, fp); + if (!length) continue; //? + if (length < 0) break; // eof or error. + + line = lineBuffer; + + // skip any leading space. + while (length && isspace(*line)) + { + ++line; + --length; + } + if (!length) continue; + + // comments + if (*line == '#') continue; + + + // strip any trailing space. + // (will be \n terminated unless there was no \n) + while (length && isspace(line[length - 1])) + { + line[--length] = 0; + } + if (!length) continue; + + if (!ParseLine(line, line + length)) + { + fprintf(stderr, "Error in variable: %s\n", line); + } + } + + fclose(fp); + } + +} // namespace + +#ifdef TESTING + +namespace MPW +{ + std::unordered_map Environment; +} + + +int main(int argc, char **argv) +{ + + + for (int i = 1; i < argc; ++i) + { + char *cp = argv[i]; + int len = strlen(cp); + + if (!ParseLine(cp, cp + len)) + { + fprintf(stderr, "Error: %s\n", cp); + } + } + + MPW::EnvLoadFile("/Users/kelvin/mpw/Environment.text"); + + for (auto kv : MPW::Environment) + { + printf("%s --> %s\n", kv.first.c_str(), kv.second.c_str()); + } + + return 0; +} + +#endif diff --git a/mpw/mpw.cpp b/mpw/mpw.cpp index 054c194..7670252 100644 --- a/mpw/mpw.cpp +++ b/mpw/mpw.cpp @@ -56,7 +56,7 @@ extern char **environ; -namespace MPW { namespace Internal { +namespace MPW { // for dup counts, etc. //std::vector FDTable; @@ -65,12 +65,11 @@ namespace MPW { namespace Internal { std::unordered_map Environment; -} } +} namespace MPW { - using namespace Internal; bool Trace = false; @@ -222,19 +221,7 @@ namespace MPW return path; // unknown. } - - std::string GetEnv(const std::string &name) - { - static std::string empty; - - auto iter = Environment.find(name); - if (iter == Environment.end()) return empty; - return iter->second; - } - - - - uint16_t Init(int argc, char **argv) + uint16_t Init(int argc, char **argv, const std::vector &defines) { /* FDTable.resize(16); @@ -335,6 +322,8 @@ namespace MPW // environment, // just use $MPW and synthesize the other ones. { + void EnvLoadFile(const std::string &envfile); + void EnvLoadArray(const std::vector &data); std::string m(RootDir()); if (!m.empty()) @@ -346,13 +335,15 @@ namespace MPW } Environment.emplace(std::string("Command"), command); + + if (defines.size()) + EnvLoadArray(defines); + if (!m.empty()) { - void LoadEnvironment(std::string &envfile, std::unordered_map &env); - std::string path(RootDirPathForFile("Environment.text")); - LoadEnvironment(path, Environment); + EnvLoadFile(path); } std::deque e; @@ -368,7 +359,7 @@ namespace MPW uint32_t size = 0; - for(const std::string &s : e) + for (const std::string &s : e) { int l = s.length() + 1; if (l & 0x01) l++; diff --git a/mpw/mpw.h b/mpw/mpw.h index c64c719..55364cf 100644 --- a/mpw/mpw.h +++ b/mpw/mpw.h @@ -3,6 +3,7 @@ #include #include +#include namespace MPW { @@ -99,7 +100,7 @@ namespace MPW { // should add argc/argv/envp... - uint16_t Init(int argc, char **argv); + uint16_t Init(int argc, char **argv, const std::vector &defines); uint32_t ExitStatus();