diff --git a/bin/mpw-make-parse.rl b/bin/mpw-make-parse.rl index f64a465..fd303b5 100644 --- a/bin/mpw-make-parse.rl +++ b/bin/mpw-make-parse.rl @@ -47,10 +47,10 @@ LinkIIGS TheHeader.aii.obj IRModule.p.obj ? '\n' => { // terminate the command. if (!token.empty()) { - argv.push_back(strdup(token.c_str())); + argv.push_back(std::move(token)); token.clear(); } - if (argv.size() > 1) { + if (!argv.empty()) { int ok = launch_command(argv); if (ok != 0) { fprintf(stderr, "command failed with exit code %d\n", ok); @@ -58,21 +58,20 @@ LinkIIGS TheHeader.aii.obj IRModule.p.obj ? } } - for (auto cp : argv) { free(cp); } argv.clear(); - argv.push_back(strdup("mpw")); }; [ \t]+ => { // token separator. if (!token.empty()) { - argv.push_back(strdup(token.c_str())); + argv.push_back(std::move(token)); token.clear(); } }; '"{' [A-Za-z][A-Za-z0-9]* '}"' => { // environment variable. remove quotes. + // also expand if possible. token.append(ts + 1, te - 1); }; @@ -104,12 +103,13 @@ namespace { } -extern int launch_command(std::vector &argv); +//extern int launch_command(std::vector &argv); +extern int launch_command(const std::vector &argv); int parse_makefile(int fd) { std::string token; - std::vector argv; + std::vector argv; unsigned char buffer[4096]; @@ -126,9 +126,6 @@ int parse_makefile(int fd) { %% write init; - // strdup so it can be free() later. - argv.push_back(strdup("mpw")); - bool done = false; while (!done) { @@ -174,7 +171,7 @@ int parse_makefile(int fd) { } // any remaining argv? - if (argv.size() > 1) { + if (!argv.empty()) { fprintf(stderr, "warning: unterminated line\n"); int ok = launch_command(argv); @@ -184,8 +181,5 @@ int parse_makefile(int fd) { } } - for (auto cp : argv) { free(cp); } - argv.clear(); - return 0; } diff --git a/bin/mpw-make.cpp b/bin/mpw-make.cpp index d2d7ec7..6802214 100644 --- a/bin/mpw-make.cpp +++ b/bin/mpw-make.cpp @@ -9,13 +9,18 @@ #include #include #include +#include + #include +#include +#include +#include +#include + #include #include -#include -#include #include #include #include @@ -24,7 +29,10 @@ int parse_makefile(int fd); void help(void); void launch_make(std::vector &argv); -void print_command(const std::vector &argv); +void print_command(const std::vector &argv, bool active); +void print_command(const std::vector &argv, bool active); + +int launch_command(const std::vector &argv); int launch_command(std::vector &argv); bool dry_run = false; @@ -56,6 +64,175 @@ void help(void) { } +std::string &lowercase(std::string &s) { + std::transform(std::begin(s), std::end(s), std::begin(s), std::tolower); + return s; +} + +std::unordered_map environment; +std::unordered_map &)>> builtins; + +/* + * 0 = active + * 1+ = nesting level. + */ +unsigned if_status = 0; + +/* true/false if true condition encountered at this level */ + +std::vector if_stack; + +int builtin_set(const std::vector &argv) { + // Set name value + + bool active = if_status == 0; + print_command(argv, active); + + if (!active) return 0; + + if (argv.size() != 3) return 1; + std::string key = argv[1]; + std::string value = argv[2]; + + // lower-case key... + lowercase(key); + + // c++17 has insert_or_assign + environment[std::move(key)] = std::move(value); + + + return 0; +} + +bool evaluate(const std::vector &v) +{ + return false; +} + + + +int builtin_if(const std::vector &argv) { + /* + * if expression + * ... + * [else if expression] + * [else] + * end + */ + + bool active = (if_status == 0); + + print_command(argv, active); + + + if (if_status) { + if_stack.push_back(false); + ++if_status; + return 0; + } + // todo... actually evaluate expression. + + bool ok = evaluate(argv); + if_stack.push_back(ok); + if (!ok) ++if_status; + + return 0; +} + + +int builtin_else(const std::vector &argv) { + + // else + // else if .... + + print_command(argv, if_status < 2); + + if (if_stack.empty()) { + fprintf(stderr, "ELSE without IF\n"); + return -1; + } + + unsigned &processed = if_stack.back(); + + + + // best case -- entire if/else/end stmt is inactive. + + if (if_status > 1) { + return 0; + } + + // second best case -- a true condition has already been found. + if (processed) { + if_status = 1; + return 0; + } + + // third case -- evalute a naked else + if (argv.size() == 1) { + processed = true; + if_status = 0; + return 0; + } + + // fourth case -- evaluate and else if + bool ok = evaluate(argv); + if (ok) { + processed = true; + if_status = 0; + return 0; + } else { + if_status = 1; + return 0; + } + +} + +int builtin_end(const std::vector &argv) { + + print_command(argv, if_status < 2); + + if (if_stack.empty()) { + fprintf(stderr, "END without IF\n"); + return 1; + } + + + if_stack.pop_back(); + + if (if_status) { + --if_status; + } + + return 0; +} + +int builtin_echo(const std::vector &argv) { + // echo [-n] ... + + bool active = (if_status == 0); + + print_command(argv, active); + if (!active) return 0; + if (dry_run) return 0; + + bool n = false; + bool printed = false; + + for (auto iter = argv.begin() + 1; iter != argv.end(); ++iter) { + const std::string &s = *iter; + if (s.length() == 2 && s == "-n") { + n = true; + continue; + } + if (printed) fputs(" ", stdout); + fputs(s.c_str(), stdout); + printed = true; + } + if (!n) fputs("\n", stdout); + return 0; +} + void launch_make(std::vector &argv) { int ok; @@ -67,14 +244,26 @@ void launch_make(std::vector &argv) { exit(EX_OSERR); } -void print_command(const std::vector &argv) { +void print_command(const std::vector &argv, bool active) { + if (!active) printf("# "); for (auto cp : argv) { if (cp) printf("%s ", cp); } printf("\n"); } +void print_command(const std::vector &argv, bool active) { + + if (!active) printf("# "); + for (const auto &cp : argv) { + printf("%s ", cp.c_str()); + } + printf("\n"); +} + + + int launch_command(std::vector &argv) { int pid; @@ -84,10 +273,11 @@ int launch_command(std::vector &argv) { // wait for a return status. //puts(cmd.c_str()); - if (argv.empty() || argv.back() != nullptr) - argv.push_back(nullptr); + bool active = (if_status == 0); - print_command(argv); + print_command(argv, active); + + if (!active) return 0; if (dry_run) { printf("\n"); return 0; @@ -124,19 +314,62 @@ int launch_command(std::vector &argv) { } +int launch_command(const std::vector &argv) { + if (argv.empty()) return 0; + + std::string cmd = argv[0]; + lowercase(cmd); + auto iter = builtins.find(cmd); + if (iter != builtins.end()) return iter->second(argv); + + std::vector cargv; + cargv.reserve(argv.size()+2); + + + // convert to char * for exec, add "mpw", and remove blanks. + + cargv.push_back(strdup("mpw")); + for (const auto &s : argv) { + if (!s.empty()) cargv.push_back(strdup(s.c_str())); + } + + // and 0-terminate. + cargv.push_back(nullptr); + + int rv = launch_command(cargv); + std::for_each(cargv.begin(), cargv.end(), free); + return rv; +} + int main(int argc, char **argv) { int pipes[2]; int ok; int child; +#if 0 + builtins.emplace("if", builtin_if); + builtins.emplace("end", builtin_end); + builtins.emplace("else", builtin_else); + builtins.emplace("set", builtin_set); +#endif + builtins = { + {"if", builtin_if}, + {"end", builtin_end}, + {"else", builtin_else}, + {"set", builtin_set}, + {"echo", builtin_echo}, + }; std::vectornew_argv; new_argv.push_back((char *)"mpw"); new_argv.push_back((char *)"Make"); + + + //new_argv.insert(new_argv.end(), argv + 1, argv + argc); // filter out --help and --dry-run