diff --git a/Environment b/Environment new file mode 100644 index 0000000..50d44b9 --- /dev/null +++ b/Environment @@ -0,0 +1,29 @@ +# MPW Environment file +# ${var} or $var substitution supported +# $MPW and $Command are pre-defined +# $MPW uses MacOS : paths. + +ShellDirectory=$MPW +SysTempFolder=/tmp/ +TempFolder=/tmp/ + +AIIGSIncludes=$MPW:Interfaces:AIIGSIncludes: +RIIGSIncludes=$MPW:Interfaces:RIIGSIncludes: +CIIGSIncludes=$MPW:Interfaces:CIIGSIncludes: +CIIGSLibraries=$MPW:Libraries:CIIGSLibraries: +PIIGSIncludes=$MPW:Interfaces:PIIGSIncludes: +PIIGSLibraries=$MPW:Libraries:PIIGSLibraries: + +# MPW IIgs v 1.0 compatibility +AIIGSInclude=$MPW:Interfaces:AIIGSIncludes: +RIIGSInclude=$MPW:Interfaces:RIIGSIncludes: +CIIGSinclude=$MPW:Interfaces:CIIGSIncludes: +CIIGSLibrary=$MPW:Libraries:CIIGSIncludes: + +# MPW Macintosh compilers +SCIncludes=$MPW:Interfaces:CIncludes: +CIncludes=$MPW:Interfaces:CIncludes: +AIncludes=$MPW:Interfaces:AIncludes: +RIncludes=$MPW:Interfaces:RIncludes: +PInterfaces=$MPW:Interfaces:PInterfaces: + diff --git a/mpw/CMakeLists.txt b/mpw/CMakeLists.txt index 120633d..7b76865 100644 --- a/mpw/CMakeLists.txt +++ b/mpw/CMakeLists.txt @@ -4,7 +4,7 @@ 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) +set(MPW_SRC mpw.cpp mpw_io.cpp mpw_close.cpp mpw_access.cpp mpw_ioctl.cpp environ.cpp) diff --git a/mpw/environ.cpp b/mpw/environ.cpp new file mode 100644 index 0000000..a541b2d --- /dev/null +++ b/mpw/environ.cpp @@ -0,0 +1,356 @@ +/* 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", 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.re.cpp b/mpw/environ.re.cpp new file mode 100644 index 0000000..072e264 --- /dev/null +++ b/mpw/environ.re.cpp @@ -0,0 +1,127 @@ +#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; + + /*!re2c + re2c:define:YYCTYPE = "char"; + re2c:define:YYCURSOR = cp; + re2c:define:YYMARKER = marker; + re2c:yyfill:enable = 0; + re2c:yych:conversion = 1; + re2c:indent:top = 1; + + '$' [A-Za-z0-9_]+ { + 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; + } + + '${' [A-Za-z0-9_]+ '}' { + + std::string tmp(begin + 2, cp - 1); + + auto iter = env.find(tmp); + if (iter != env.end()) + { + rv.append(iter->second); + } + continue; + } + + . { + rv.push_back(*begin); + continue; + } + [^] { + break; + } + */ + + } + + 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/mpw.cpp b/mpw/mpw.cpp index d396243..74bc03e 100644 --- a/mpw/mpw.cpp +++ b/mpw/mpw.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -191,188 +192,44 @@ namespace MPW // environment, // just use $MPW and synthesize the other ones. { - - std::deque e; - - { - // command name (includes path) - // asm iigs stores error text in the data fork, - // using {Command} to access it. - std::string tmp; - tmp.append("Command"); - tmp.push_back(0); - tmp.append(command); - - e.emplace_back(std::move(tmp)); - - } + std::unordered_map env; const char *mpw = getenv("MPW"); if (mpw && *mpw) { - std::string tmp; - std::string root(mpw); - - root = ToolBox::UnixToMac(root); - //std::replace(root.begin(), root.end(), '/', ':'); - if (root.back() != ':') root.push_back(':'); - - tmp = "MPW"; - tmp.push_back(0); - tmp.append(root); - e.emplace_back(std::move(tmp)); - - - // SysErrs.err - tmp = "ShellDirectory"; - tmp.push_back(0); - tmp.append(root); - e.emplace_back(std::move(tmp)); - - tmp = "AIIGSIncludes"; - tmp.push_back(0); - tmp.append(root); - tmp.append("Interfaces:AIIGSIncludes:"); - e.emplace_back(std::move(tmp)); - - // 1.0 compatibility - tmp = "AIIGSInclude"; - tmp.push_back(0); - tmp.append(root); - tmp.append("Interfaces:AIIGSIncludes:"); - e.emplace_back(std::move(tmp)); - - tmp = "RIIGSIncludes"; - tmp.push_back(0); - tmp.append(root); - tmp.append("Interfaces:RIIGSIncludes:"); - e.emplace_back(std::move(tmp)); - - // 1.0 compatibility - tmp = "RIIGSInclude"; - tmp.push_back(0); - tmp.append(root); - tmp.append("Interfaces:RIIGSIncludes:"); - e.emplace_back(std::move(tmp)); - - tmp = "CIIGSIncludes"; - tmp.push_back(0); - tmp.append(root); - tmp.append("Interfaces:CIIGSIncludes:"); - e.emplace_back(std::move(tmp)); - - // 1.0 compatibility - tmp = "CIIGSinclude"; // lowercase include [??] - tmp.push_back(0); - tmp.append(root); - tmp.append("Interfaces:CIIGSIncludes:"); - e.emplace_back(std::move(tmp)); - - tmp = "CIIGSLibraries"; - tmp.push_back(0); - tmp.append(root); - tmp.append("Libraries:CIIGSIncludes:"); - e.emplace_back(std::move(tmp)); - - // 1.0 compatibility - tmp = "CIIGSLibrary"; - tmp.push_back(0); - tmp.append(root); - tmp.append("Libraries:CIIGSIncludes:"); - e.emplace_back(std::move(tmp)); - - tmp = "PIIGSIncludes"; - tmp.push_back(0); - tmp.append(root); - tmp.append("Interfaces:PIIGSIncludes:"); - e.emplace_back(std::move(tmp)); - - tmp = "PIIGSLibraries"; - tmp.push_back(0); - tmp.append(root); - tmp.append("Libraries:PIIGSIncludes:"); - e.emplace_back(std::move(tmp)); - + std::string m(mpw); + m = ToolBox::UnixToMac(m); + if (m.back() != ':') m.push_back(':'); + env.emplace(std::string("MPW"), m); } + env.emplace(std::string("Command"), command); - uint32_t size = 0; - for(const std::string &s : e) + if (mpw && *mpw) { - int l = s.length() + 1; - if (l & 0x01) l++; - size = size + l + 4; + std::string m(mpw); + + void LoadEnvironment(std::string &envfile, std::unordered_map &env); + + if (m.back() != '/') m.push_back('/'); + m.append("Environment"); + + LoadEnvironment(m, env); } - size += 4; // space for null terminator. - - error = MM::Native::NewPtr(size, true, envptr); - if (error) return error; - - - uint8_t *xptr = memoryPointer(envptr); - uint32_t offset = 0; - - offset = 4 * (e.size() + 1); - unsigned i = 0; - for (const std::string &s : e) - { - // ptr - memoryWriteLong(envptr + offset, envptr + i * 4); - - int l = s.length() + 1; - - std::memcpy(xptr + offset, s.c_str(), l); - - if (l & 0x01) l++; - offset += l; - ++i; - } - - - // null-terminate it. - memoryWriteLong(0, envptr + 4 * e.size()); - } - -#if 0 - // do the same for envp. - // mpw_* variables in the native environment are imported. - // values are stored as key\0value\0, not key=value\0 - { - std::deque e; - uint32_t size = 0; + for (const auto &iter : env) { - // command name (includes path) - // asm iigs stores error text in the data fork, - // using {Command} to access it. std::string tmp; - tmp.append("Command"); + tmp.append(iter.first); tmp.push_back(0); - tmp.append(command); - - e.emplace_back(std::move(tmp)); - - } - - for (unsigned i = 0 ; environ[i]; ++i) - { - int pos; - - char *cp = environ[i]; - if (std::strncmp("mpw_", cp, 4)) continue; - - std::string tmp = cp + 4; - - pos = tmp.find('='); - if (pos == tmp.npos) continue; - tmp[pos] = 0; - + tmp.append(iter.second); e.emplace_back(std::move(tmp)); } - size = 0; + + uint32_t size = 0; for(const std::string &s : e) { int l = s.length() + 1; @@ -409,8 +266,6 @@ namespace MPW // null-terminate it. memoryWriteLong(0, envptr + 4 * e.size()); } -#endif - // ftable {