Set up environment from $MPW:Environment

This commit is contained in:
Kelvin Sherlock 2013-05-18 17:24:25 -04:00
parent 722aa2e18a
commit 386dc18ad1
5 changed files with 534 additions and 167 deletions

29
Environment Normal file
View File

@ -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:

View File

@ -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)

356
mpw/environ.cpp Normal file
View File

@ -0,0 +1,356 @@
/* Generated by re2c 0.13.5 on Sat May 18 16:26:02 2013 */
#include <string>
#include <unordered_map>
#include <cstdio>
/*
* #...comment
* var=value
* where value may contain $var and ${var} interpolations.
*
*/
namespace MPW {
std::string EvalString(std::string &s, std::unordered_map<std::string, std::string> &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<std::string, std::string> &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);
}
}

127
mpw/environ.re.cpp Normal file
View File

@ -0,0 +1,127 @@
#include <string>
#include <unordered_map>
#include <cstdio>
/*
* #...comment
* var=value
* where value may contain $var and ${var} interpolations.
*
*/
namespace MPW {
std::string EvalString(std::string &s, std::unordered_map<std::string, std::string> &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<std::string, std::string> &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);
}
}

View File

@ -5,6 +5,7 @@
#include <vector>
#include <string>
#include <deque>
#include <unordered_map>
#include <cstdint>
#include <cstdio>
@ -191,188 +192,44 @@ namespace MPW
// environment,
// just use $MPW and synthesize the other ones.
{
std::deque<std::string> 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<std::string, std::string> 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<std::string, std::string> &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<std::string> 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
{