mirror of
https://github.com/ksherlock/mpw.git
synced 2024-11-24 13:32:39 +00:00
mow-make command
This commit is contained in:
parent
dd460a21eb
commit
cd99626176
@ -60,6 +60,14 @@ add_custom_command(
|
||||
DEPENDS debugger.h template_parser.h
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT mpw-make-parse.cpp
|
||||
COMMAND ragel -p -G2 -o mpw-make-parse.cpp "${CMAKE_CURRENT_SOURCE_DIR}/mpw-make-parse.rl"
|
||||
MAIN_DEPENDENCY mpw-make-parse.rl
|
||||
DEPENDS debugger.h
|
||||
)
|
||||
|
||||
|
||||
|
||||
set_source_files_properties(
|
||||
loadtrap.cpp lexer.cpp template_loader.cpp
|
||||
@ -85,3 +93,7 @@ set_target_properties(mpw PROPERTIES LINK_FLAGS "-ledit")
|
||||
add_executable(disasm disasm.cpp)
|
||||
target_link_libraries(disasm CPU_LIB)
|
||||
target_link_libraries(disasm MACOS_LIB)
|
||||
|
||||
|
||||
add_executable(mpw-make mpw-make-parse.cpp mpw-make.cpp)
|
||||
|
||||
|
171
bin/mpw-make-parse.rl
Normal file
171
bin/mpw-make-parse.rl
Normal file
@ -0,0 +1,171 @@
|
||||
|
||||
/*
|
||||
* ragel code to extract commands from mpw make output
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sysexits.h>
|
||||
|
||||
/*
|
||||
|
||||
PascalIIGS IRModule.p
|
||||
asmiigs TheHeader.aii
|
||||
|
||||
reziigs IRModule.r -o IRModule
|
||||
|
||||
LinkIIGS TheHeader.aii.obj IRModule.p.obj ?
|
||||
-lib "{PIIGSLibraries}"PLib ?
|
||||
-o IRModule ?
|
||||
-t $BC -at $4001
|
||||
DuplicateIIgs -y -m IRModule :
|
||||
|
||||
*/
|
||||
|
||||
%%{
|
||||
machine make;
|
||||
alphtype unsigned char;
|
||||
|
||||
main := |*
|
||||
|
||||
0xb6 '\n' => {
|
||||
// line continuation marker.
|
||||
// terminate the current token?
|
||||
};
|
||||
|
||||
|
||||
'\n' => {
|
||||
// terminate the command.
|
||||
if (!token.empty()) {
|
||||
argv.push_back(strdup(token.c_str()));
|
||||
token.clear();
|
||||
}
|
||||
if (argv.size() > 1) {
|
||||
int ok = launch_command(argv);
|
||||
if (ok != 0) {
|
||||
fprintf(stderr, "command failed with exit code %d\n", ok);
|
||||
return ok;
|
||||
}
|
||||
}
|
||||
|
||||
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()));
|
||||
token.clear();
|
||||
}
|
||||
};
|
||||
|
||||
'"{' [A-Za-z][A-Za-z0-9]* '}"' => {
|
||||
// environment variable. remove quotes.
|
||||
token.append(ts + 1, te - 1);
|
||||
};
|
||||
|
||||
any => {
|
||||
token.push_back(*ts);
|
||||
};
|
||||
|
||||
*|;
|
||||
}%%
|
||||
|
||||
namespace {
|
||||
|
||||
%% write data nofinal;
|
||||
|
||||
}
|
||||
|
||||
extern int launch_command(std::vector<char *> &argv);
|
||||
|
||||
int parse_makefile(int fd) {
|
||||
|
||||
std::string token;
|
||||
std::vector<char *> argv;
|
||||
|
||||
unsigned char buffer[4096];
|
||||
|
||||
const unsigned char *ts;
|
||||
const unsigned char *te;
|
||||
const unsigned char *p;
|
||||
const unsigned char *pe;
|
||||
const unsigned char *eof;
|
||||
|
||||
int cs, act;
|
||||
|
||||
unsigned offset = 0;
|
||||
|
||||
|
||||
%% write init;
|
||||
|
||||
// strdup so it can be free() later.
|
||||
argv.push_back(strdup("mpw"));
|
||||
|
||||
|
||||
bool done = false;
|
||||
while (!done) {
|
||||
ssize_t s;
|
||||
s = read(fd, buffer + offset, sizeof(buffer) - offset);
|
||||
if (s < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
perror("read: ");
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
|
||||
p = buffer + offset;
|
||||
pe = p + s;
|
||||
if (s == 0) {
|
||||
done = true;
|
||||
eof = pe;
|
||||
}
|
||||
|
||||
%% write exec;
|
||||
|
||||
if (cs == make_error) {
|
||||
fprintf(stderr, "lexer error\n");
|
||||
exit(EX_DATAERR);
|
||||
}
|
||||
// if inside a token, shift data around.
|
||||
|
||||
if (ts == 0) {
|
||||
offset = 0;
|
||||
} else {
|
||||
offset = pe - ts;
|
||||
memmove(buffer, ts, offset);
|
||||
|
||||
te = buffer + (te - ts);
|
||||
ts = buffer;
|
||||
|
||||
if (offset == sizeof(buffer)) {
|
||||
fprintf(stderr, "buffer exceeded\n");
|
||||
exit(EX_SOFTWARE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
// any remaining argv?
|
||||
if (argv.size() > 1) {
|
||||
fprintf(stderr, "warning: unterminated line\n");
|
||||
|
||||
int ok = launch_command(argv);
|
||||
if (ok != 0) {
|
||||
fprintf(stderr, "command failed with exit code %d\n", ok);
|
||||
return ok;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto cp : argv) { free(cp); }
|
||||
argv.clear();
|
||||
|
||||
return 0;
|
||||
}
|
231
bin/mpw-make.cpp
Normal file
231
bin/mpw-make.cpp
Normal file
@ -0,0 +1,231 @@
|
||||
/*
|
||||
*
|
||||
* Run MPW's make.
|
||||
*
|
||||
* MPW Make prints a list of commands to stdout.
|
||||
* read and execute them.
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
#include <algorithm>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sysexits.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
int parse_makefile(int fd);
|
||||
void help(void);
|
||||
void launch_make(std::vector<char *> &argv);
|
||||
void print_command(const std::vector<char *> &argv);
|
||||
int launch_command(std::vector<char *> &argv);
|
||||
|
||||
bool dry_run = false;
|
||||
|
||||
void help(void) {
|
||||
|
||||
#undef _
|
||||
#define _(x) puts(x)
|
||||
|
||||
_("Make # build up-to-date version of a program");
|
||||
_("Make [option...] [target...]");
|
||||
_(" -d name[=value] # define variable name (overrides makefile definition)");
|
||||
_(" -e # rebuild everything regardless of dates");
|
||||
_(" -f filename # read dependencies from specified file (default: MakeFile)");
|
||||
_(" -i dirname # additional directory to search for include files");
|
||||
_(" -[no]mf # [don't] use temporary memory (default: mf)");
|
||||
_(" -p # write progress information to diagnostics");
|
||||
_(" -r # display the roots of the dependency graph");
|
||||
_(" -s # display the structure of the dependency graph");
|
||||
_(" -t # touch dates of targets and prerequisites");
|
||||
_(" -u # write list of unreachable targets to diagnostics");
|
||||
_(" -v # write verbose explanations to diagnostics (implies -p)");
|
||||
_(" -w # suppress warning messages");
|
||||
_(" -y # like -v, but omit announcing up-to-date targets");
|
||||
_("");
|
||||
_(" --help # display help");
|
||||
_(" --dry-run # show what commands would run");
|
||||
#undef _
|
||||
}
|
||||
|
||||
|
||||
void launch_make(std::vector<char *> &argv) {
|
||||
int ok;
|
||||
|
||||
if (argv.empty() || argv.back() != nullptr)
|
||||
argv.push_back(nullptr);
|
||||
|
||||
ok = execvp(argv.front(), argv.data());
|
||||
perror("execvp: ");
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
|
||||
void print_command(const std::vector<char *> &argv) {
|
||||
|
||||
for (auto cp : argv) {
|
||||
if (cp) printf("%s ", cp);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int launch_command(std::vector<char *> &argv) {
|
||||
|
||||
int pid;
|
||||
|
||||
// parse command-line
|
||||
// launch command.
|
||||
// wait for a return status.
|
||||
//puts(cmd.c_str());
|
||||
|
||||
if (argv.empty() || argv.back() != nullptr)
|
||||
argv.push_back(nullptr);
|
||||
|
||||
print_command(argv);
|
||||
if (dry_run) return 0;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
perror("fork: ");
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
execvp(argv.front(), argv.data());
|
||||
perror("execvp: ");
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
int status;
|
||||
pid_t ok;
|
||||
ok = waitpid(pid, &status, 0);
|
||||
if (ok < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
perror("waitpid:");
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if (WIFEXITED(status)) return WEXITSTATUS(status);
|
||||
if (WIFSIGNALED(status)) return -1;
|
||||
fprintf(stderr, "waitpid - unexpected result\n");
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
int pipes[2];
|
||||
int ok;
|
||||
int child;
|
||||
|
||||
|
||||
std::vector<char *>new_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
|
||||
|
||||
std::copy_if(argv + 1, argv + argc, std::back_inserter(new_argv),
|
||||
[](char *cp){
|
||||
if (strcmp(cp, "--help") == 0) {
|
||||
help();
|
||||
exit(0);
|
||||
return false;
|
||||
}
|
||||
if (strcmp(cp, "--dry-run") == 0) {
|
||||
dry_run = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
|
||||
ok = pipe(pipes);
|
||||
if (ok < 0) {
|
||||
perror("pipe: ");
|
||||
}
|
||||
|
||||
child = fork();
|
||||
if (child < 0) {
|
||||
perror("fork: ");
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
|
||||
if (child == 0) {
|
||||
// child.
|
||||
//close(STDIN_FILENO);
|
||||
//close(STDOUT_FILENO);
|
||||
//close(STDERR_FILENO);
|
||||
|
||||
ok = dup2(pipes[1], STDOUT_FILENO);
|
||||
if (ok < 0) {
|
||||
perror("dup2: ");
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
close(pipes[0]);
|
||||
close(pipes[1]);
|
||||
|
||||
launch_make(new_argv); // no return.
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// parent process.
|
||||
// read commands from pipe[0] and execute them.
|
||||
// 0xb6 is a line continuation marker.
|
||||
//int fd = pipes[0];
|
||||
|
||||
/*
|
||||
FILE *f = fdopen(pipes[0], "r");
|
||||
if (!f) {
|
||||
perror("fdopen: ");
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
*/
|
||||
close(pipes[1]);
|
||||
|
||||
// prevent children from inheriting the pipe fd.
|
||||
fcntl(pipes[0], F_SETFD, FD_CLOEXEC);
|
||||
|
||||
ok = parse_makefile(pipes[0]);
|
||||
close(pipes[0]);
|
||||
|
||||
|
||||
// return any error from make itself.
|
||||
for(;;) {
|
||||
int status;
|
||||
int ok = waitpid(child, &status, 0);
|
||||
if (ok < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
perror("waitpid: ");
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
|
||||
if (WIFEXITED(status)) {
|
||||
ok = WEXITSTATUS(status);
|
||||
if (ok) exit(ok);
|
||||
break;
|
||||
}
|
||||
if (WIFSIGNALED(status))
|
||||
exit(1);
|
||||
|
||||
fprintf(stderr, "waitpid - unexpected result\n");
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
|
||||
return ok ? 2 : 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user