#include #include #include #define MAX_LINE_SIZE 10000 #define MAX_PATH_SIZE 1000 class SubModule { public: char *path; char *url; SubModule *next; SubModule(char *p, char *u, SubModule *n) : next(n) { path = (char*)malloc(strlen(p)+1); strcpy(path, p); url = (char*)malloc(strlen(u)+1); strcpy(url, u); } }; SubModule *read_sub_modules(const char *fn) { FILE *f = fopen(fn, "r"); if (f == 0) return 0; char path[MAX_LINE_SIZE]; char url[MAX_LINE_SIZE]; SubModule *subModules = 0; while (fgets(path, MAX_LINE_SIZE-1, f) && fgets(path, MAX_LINE_SIZE-1, f) && fgets(url, MAX_LINE_SIZE-1, f)) { if (strncmp(path, "\tpath = ", 8) == 0 && strncmp(url, "\turl = ", 7) == 0) { while (path[strlen(path)-1] < ' ') path[strlen(path)-1] = '\0'; while (url[strlen(url)-1] < ' ') url[strlen(url)-1] = '\0'; char *s = strstr(url, ".git"); if (s != 0) *s = '\0'; int len = strlen(url); char complete_url[MAX_LINE_SIZE]; if (strncmp(url + 7, "https://github.com/", 19) == 0) sprintf(complete_url, "%s/tree/master/", url + 7); else if (strncmp(url + 7, "https://git.savannah.nongnu.org/git/", 36) == 0) sprintf(complete_url, "https://git.savannah.nongnu.org/gitweb/?p=%s.git;a=blob;f=", url + 43); else strcpy(complete_url, url + 7); printf("Submodule %s %s|\n", path + 8, complete_url); subModules = new SubModule(path + 8, complete_url, subModules); } } return subModules; } class Var; bool parse_kaem_file(const char *fn, Var *vars, const char *parent_cur_path, FILE *fout); void dir_of_filename(const char *fn, char *dir); const char *file_of_filename(const char *fn); const char *file_ext(const char *fn); FILE *open_file(const char *dir, const char *fn); class Usage; int nr_files = 0; class File { public: char *name; int nr; bool exists; bool produced; bool exec; bool used_as_input; bool removed; char *url; File *alias; Usage *usages; File *next; File(const char *fn) : exists(false), produced(false), exec(false), next(0), url(0), alias(0), usages(0) { name = (char*)malloc(strlen(fn)+1); strcpy(name, fn); nr = nr_files++; FILE *f = fopen(name, "r"); if (f != 0) { exists = true; fclose(f); } } FILE *open() { return fopen(name, "r"); } }; File *files = 0; void combine_dir_fn(const char *dir, const char *fn, char *filename) { if (fn[0] == '.' && fn[1] == '/') fn += 2; strcpy(filename, dir); char *t = filename + strlen(filename); *t++ = '/'; for (const char *s = fn; *s != '\0'; s++) if (s[0] == '.' && s[1] == '.') { if (t[-1] == '/') { --t; *t = '\0'; } s++; for (char *r = filename; *r != '\0'; r++) if (*r == '/') t = r; } else *t++ = *s; *t = '\0'; } File *get_file(const char *full_fn) { File **ref = &files; for (; *ref != 0; ref = &(*ref)->next) if (strcmp((*ref)->name, full_fn) == 0) return (*ref)->alias != 0 ? (*ref)->alias : (*ref); *ref = new File(full_fn); return *ref; } File *get_file(const char *dir, const char *fn) { if (fn[0] == '/') return get_file(fn); char full_fn[MAX_PATH_SIZE]; combine_dir_fn(dir, fn, full_fn); return get_file(full_fn); } int nr_steps = 0; class Step { public: int nr; Usage *uses; Step *next; Step() : uses(0), next(0) { nr = nr_steps++; } }; Step *all_steps = 0; Step **ref_next = &all_steps; Step *next_step() { Step *step = new Step(); *ref_next = step; ref_next = &step->next; return step; } int indent_depth = 0; void indent(FILE *fout) { fprintf(fout, "%*.*s", indent_depth, indent_depth, ""); } class Usage { public: bool as_input; bool as_output; bool as_exec; bool as_removed; File *file; Step *step; Usage *next_use; Usage *next_usage; Usage (File *_file, Step *_step) : as_input(false), as_output(false), as_exec(false), as_removed(false), file(_file), step(_step), next_use(0), next_usage(0) { Usage **ref_use = &step->uses; while (*ref_use != 0) ref_use = &(*ref_use)->next_use; *ref_use = this; Usage **ref_usage = &file->usages; while (*ref_usage != 0) ref_usage = &(*ref_usage)->next_usage; *ref_usage = this; } void is_input(FILE *fout) { as_input = true; file->used_as_input = true; indent(fout); fprintf(fout, "%s file: %s\n", file->exists ? "Existing" : file->produced ? "Produced" : "Input", file->name); } void is_output(FILE *fout) { as_output = true; indent(fout); fprintf(fout, "Output file: %s\n", file->name); file->produced = true; file->removed = false; } void is_exec(FILE *fout) { as_exec = true; indent(fout); fprintf(fout, "Exec file: %s", file->name); if (!file->exists && !file->produced) fprintf(fout, " Not existing nor produced"); if (file->exists) fprintf(fout, " Existing"); if (file->produced) fprintf(fout, " Produced"); fprintf(fout, "\n"); } void is_removed(FILE *fout) { as_removed = true; file->removed = true; indent(fout); fprintf(fout, "Deleted file: %s\n", file->name); } }; void write_html(FILE *f, SubModule *submodules); class Var { public: char *name; char *value; bool alias; Var *next; Var(const char *n, const char *v, bool a, Var *nv) : next(nv), alias(a) { name = (char*)malloc(strlen(n) + 1); strcpy(name, n); value = (char*)malloc(strlen(v) + 1); strcpy(value, v); } }; char *get_var(Var *vars, const char *name) { for (; vars != 0; vars = vars->next) if (!vars->alias && strcmp(vars->name, name) == 0) return vars->value; return 0; } void copy_file(const char *src, const char *dest) { File *src_file = get_file(src); File *dest_file = get_file(dest); dest_file->alias = src_file; } int main(int argc, char *argv[]) { char cur_path[MAX_PATH_SIZE]; const char *stage0_path = "../git/stage0-posix/kaem.amd64"; SubModule *subModules = read_sub_modules("../git/stage0-posix/.gitmodules"); dir_of_filename(stage0_path, cur_path); fprintf(stdout, "Cur path: %s\n", cur_path); FILE *fout = stdout; bool result = parse_kaem_file(file_of_filename(stage0_path), new Var("EXE_SUFFIX", "", false, 0), cur_path, fout); fprintf(fout, "Result: %s\n", result ? "OK" : "FAIL"); const char *live_bootstrap = "../git/live-bootstrap/sysa/run.kaem"; dir_of_filename(live_bootstrap, cur_path); fprintf(stdout, "Cur path: %s\n", cur_path); Var *live_bootstrap_vars = 0; live_bootstrap_vars = new Var("ARCH", "AMD64", false, live_bootstrap_vars); live_bootstrap_vars = new Var("sysa", "/sysa", false, live_bootstrap_vars); live_bootstrap_vars = new Var("bindir", "/sysa/bin", false, live_bootstrap_vars); live_bootstrap_vars = new Var("libdir", "/sysa/lib", false, live_bootstrap_vars); live_bootstrap_vars = new Var("incdir", "/sysa/include", false, live_bootstrap_vars); live_bootstrap_vars = new Var("srcdir", "/sysa/src", false, live_bootstrap_vars); live_bootstrap_vars = new Var("distfiles", "/sysa/disfiles", false, live_bootstrap_vars); live_bootstrap_vars = new Var("mes_cpu:-x86", "mes_cpu", false, live_bootstrap_vars); live_bootstrap_vars = new Var("stage0_cpu:-x86", "stage0_cpu", false, live_bootstrap_vars); live_bootstrap_vars = new Var("prefix", "/sysa", false, live_bootstrap_vars); live_bootstrap_vars = new Var("UPDATE_CHECKSUMS", "False", false, live_bootstrap_vars); live_bootstrap_vars = new Var("PREFIX", "PREFIX", false, live_bootstrap_vars); copy_file("../git/stage0-posix/AMD64/bin/blood-elf","/sysa/bin/blood-elf"); copy_file("../git/stage0-posix/AMD64/bin/catm","/sysa/bin/catm"); copy_file("../git/stage0-posix/AMD64/bin/chmod","/sysa/bin/chmod"); copy_file("../git/stage0-posix/AMD64/bin/get_machine","/sysa/bin/get_machine"); copy_file("../git/stage0-posix/AMD64/bin/hex2","/sysa/bin/hex2"); copy_file("../git/stage0-posix/AMD64/bin/kaem","/sysa/bin/kaem"); copy_file("../git/stage0-posix/AMD64/bin/match","/sysa/bin/match"); copy_file("../git/stage0-posix/AMD64/bin/M1","/sysa/bin/M1"); copy_file("../git/stage0-posix/AMD64/bin/M2-Mesoplanet","/sysa/bin/M2-Mesoplanet"); copy_file("../git/stage0-posix/AMD64/bin/M2-Planet","/sysa/bin/M2-Planet"); copy_file("../git/stage0-posix/AMD64/bin/mkdir","/sysa/bin/mkdir"); copy_file("../git/stage0-posix/AMD64/bin/sha256sum","/sysa/bin/sha256sum"); copy_file("../git/stage0-posix/AMD64/bin/unbz2","/sysa/bin/unbz2"); copy_file("../git/stage0-posix/AMD64/bin/ungz","/sysa/bin/ungz"); copy_file("../git/stage0-posix/AMD64/bin/untar","/sysa/bin/untar"); copy_file("../git/stage0-posix/AMD64/bin/cp","/sysa/bin/cp"); copy_file("../git/stage0-posix/AMD64/bin/replace","/sysa/bin/replace"); copy_file("../git/stage0-posix/AMD64/bin/rm","/sysa/bin/rm"); result = parse_kaem_file(file_of_filename(live_bootstrap), live_bootstrap_vars, cur_path, fout); fprintf(fout, "Result: %s\n", result ? "OK" : "FAIL"); FILE *f_html = fopen("kaem_parser.html", "w"); if (f_html != 0) { write_html(f_html, subModules); fclose(f_html); } return 0; } int nesting = 0; File *nested_files[20]; bool nested_exec[20]; bool parse_kaem_file(const char *fn, Var *vars, const char *parent_cur_path, FILE *fout) { char cur_path[MAX_PATH_SIZE]; strcpy(cur_path, parent_cur_path); char *bin_path = get_var(vars, "bindir"); if (bin_path == 0) bin_path = cur_path; Step *prev_make_step = 0; FILE *f = open_file(cur_path, fn); if (f == 0) { if (strcmp(cur_path, "/sysa/mes-0.24.2/build/mes-0.24.2") == 0 && strcmp(fn, "kaem.run") == 0) f = fopen("../git/mes/kaem.run", "r"); if (f == 0) { fprintf(fout, "ERROR: Cannot open file '%s/%s'\n", cur_path, fn); return false; } } indent(fout); fprintf(fout, "Parse kaem file: %s/%s\n", cur_path, fn); indent_depth += 2; char buffer[MAX_LINE_SIZE]; while (fgets(buffer, MAX_LINE_SIZE-1, f)) { int len = strlen(buffer); while (len > 0 && buffer[len-1] < ' ') buffer[--len] = '\0'; if (buffer[0] != '\0' && buffer[0] != '#') { char command_line[MAX_LINE_SIZE]; strcpy(command_line, buffer); for (;;) { int len = strlen(command_line); if (command_line[len-1] != '\\') break; command_line[len-1] = '\0'; if (!fgets(buffer, MAX_LINE_SIZE-1, f)) break; if (buffer[0] == '\0' && buffer[0] == '#') break; int len2 = strlen(buffer); while (len2 > 0 && buffer[len2-1] < ' ') buffer[--len2] = '\0'; strcat(command_line, buffer); } indent(fout); fprintf(fout, "Process %s\n", command_line); char exp_command_line[MAX_LINE_SIZE]; int i = 0; char *s = command_line; if (('a' <= *s && *s <= 'z') || ('A' <= *s && *s <= 'Z')) { bool alias_used = false; char command[40]; int j = 0; while (('a' <= *s && *s <= 'z') || ('A' <= *s && *s <= 'Z')) command[j++] = *s++; command[j] = '\0'; if (*s == ' ') { for (Var *var = vars; var != 0; var = var->next) if (var->alias && strcmp(var->name, command) == 0) { for (const char *v = var->value; *v != '\0'; v++) exp_command_line[i++] = *v; alias_used = true; break; } } if (!alias_used) s = command_line; } for (; *s != '\0';) { if (s[0] == '$' && s[1] == '{') { s += 2; char name[50]; int j = 0; while (*s != '\0' && *s != '}') name[j++] = *s++; name[j] = '\0'; bool var_found = false; for (Var *var = vars; var != 0; var = var->next) if (!var->alias && strcmp(var->name, name) == 0) { for (const char *v = var->value; *v != '\0'; v++) exp_command_line[i++] = *v; var_found = true; break; } if (*s == '}') s++; if (!var_found) { fprintf(fout, "ERROR: '%s' not found\n", name); } } else if (*s < ' ') { exp_command_line[i++] = ' '; s++; } else exp_command_line[i++] = *s++; } exp_command_line[i] = '\0'; indent(fout); fprintf(fout, "Exp: %s\n", exp_command_line); char *args[1000]; int nr_args = 0; for (char *s = exp_command_line; ;) { while (*s != '\0' && *s <= ' ') s++; if (*s == '\0' || *s == '#') break; args[nr_args++] = s; while (*s > ' ') if (*s == '\\' && s[1] != '\0') s += 2; else if (*s == '"' && *s != '#') { s++; while (*s != '\0' && *s != '"') s++; if (*s == '"') s++; } else s++; if (*s == '\0' || *s == '#') break; *s++ = '\0'; } if (strcmp(exp_command_line, "cd") == 0) { if (nr_args != 2) { fprintf(fout, "ERROR: cd does not have one argument\n"); } else { char *s = args[1]; if (*s == '/') { strcpy(cur_path, s); } else if (strncmp(s, "../git/", 7) == 0) { strcpy(cur_path, s); } else { while (*s != '\0') { if (s[0] == '.' && s[1] == '.') { s += 2; char *last = 0; for (char *t = cur_path; *t != '\0'; t++) if (*t == '/') last = t; if (last != 0) *last = '\0'; if (*s != '/') break; s++; } else { char *end = cur_path + strlen(cur_path); *end++ = '/'; while (*s != '\0' && *s != ' ') *end++ = *s++; *end = '\0'; break; } } } indent(fout); fprintf(fout, "cd to %s\n", cur_path); } } else if (strcmp(exp_command_line, "exec") == 0) { indent(fout); fprintf(fout, "exec\n"); } else if (strcmp(exp_command_line, "set") == 0) { } else if (strcmp(exp_command_line, "echo") == 0) { } else if ( strcmp(exp_command_line, "if") == 0 || strcmp(exp_command_line, "else") == 0 || strcmp(exp_command_line, "fi") == 0) { } else { bool is_var_decl = false; bool alias = false; s = exp_command_line; if (strcmp(s, "alias") == 0 && nr_args > 1) { s = args[1]; alias = true; } if (('a' <= *s && *s <= 'z') || ('A' <= *s && *s <= 'Z')) { char name[50]; int i = 0; while (('a' <= *s && *s <= 'z') || ('A' <= *s && *s <= 'Z') || *s == '_' || ('0' <= *s && *s <= '9')) name[i++] = *s++; name[i] = '\0'; if (s[0] == '=') { s++; char close_char = '\0'; if (*s == '"') { close_char = '"'; s++; } is_var_decl = true; char value[200]; i = 0; while (*s != '\0' && *s != close_char) value[i++] = *s++; if (*s != '\0' && *s == close_char) s++; value[i] = '\0'; indent(fout); fprintf(fout, "Decl %s = |%s|\n", name, value); vars = new Var(name, value, alias, vars); } } if (!is_var_decl) { indent_depth += 2; int argnr = 1; Step *step = next_step(); for (int n = 0; n < nesting; n++) { Usage *usage = new Usage(nested_files[n], step); if (nested_exec[n]) usage->as_exec = true; else usage->as_input = true; } File *exec_file = get_file(args[0][0] == '.' ? cur_path : bin_path, args[0]); exec_file->exec = true; Usage *usage = new Usage(exec_file, step); usage->is_exec(fout); const char *exec_fn = file_of_filename(args[0]); if (strcmp(exec_fn, "kaem-optional-seed") == 0 || strcmp(exec_fn, "kaem-0") == 0) { if (nr_args != 2) fprintf(fout, "ERROR: kaem-0 requires one argument\n"); else { char *kaem_input_fn = args[1]; nested_files[nesting] = step->uses->file; nested_exec[nesting] = true; nesting++; parse_kaem_file(kaem_input_fn[0] == '.' && kaem_input_fn[1] == '/' ? kaem_input_fn + 2 : kaem_input_fn, vars, cur_path, fout); nesting--; } } else if (strcmp(exec_fn, "kaem") == 0) { char *kaem_input_fn = 0; for (int arg_nr = 1; arg_nr < nr_args; arg_nr++) { char *arg = args[arg_nr]; if (strcmp(arg, "--verbose") == 0) ; else if (strcmp(arg, "--strict") == 0) ; else if (strcmp(arg, "--file") == 0 && arg_nr + 1 < nr_args) { kaem_input_fn = args[arg_nr + 1]; arg_nr++; } else fprintf(fout, "WARNING: Unknown kaem argument '%s'\n", arg); } if (kaem_input_fn != 0) { nested_files[nesting] = step->uses->file; nested_exec[nesting] = true; nesting++; parse_kaem_file(kaem_input_fn[0] == '.' && kaem_input_fn[1] == '/' ? kaem_input_fn + 2 : kaem_input_fn, vars, cur_path, fout); nesting--; } } else if (strcmp(exec_fn, "catm") == 0) { for (int arg_nr = 1; arg_nr < nr_args; arg_nr++) { char *arg = args[arg_nr]; File *file = get_file(cur_path, arg); Usage *usage = new Usage(file, step); if (arg_nr == 1) usage->is_output(fout); else usage->is_input(fout); } } else if (strcmp(exec_fn, "M2") == 0 || strcmp(exec_fn, "M2-Planet") == 0) { for (int arg_nr = 1; arg_nr < nr_args; arg_nr++) { char *arg = args[arg_nr]; if (strcmp(arg, "--architecture") == 0) arg_nr++; else if (strcmp(arg, "--bootstrap-mode") == 0) ; else if (strcmp(arg, "--debug") == 0) ; else if (strcmp(arg, "-f") == 0 && arg_nr + 1 < nr_args) (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_input(fout); else if (strcmp(arg, "-o") == 0 && arg_nr + 1 < nr_args) (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_output(fout); else fprintf(fout, "Warning: Skipped '%s'\n", arg); } } else if (strcmp(exec_fn, "blood-elf-0") == 0 || strcmp(exec_fn, "blood-elf") == 0) { for (int arg_nr = 1; arg_nr < nr_args; arg_nr++) { char *arg = args[arg_nr]; if (strcmp(arg, "--64") == 0) ; else if (strcmp(arg, "--little-endian") == 0) ; else if (strcmp(arg, "-f") == 0 && arg_nr + 1 < nr_args) (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_input(fout); else if (strcmp(arg, "-o") == 0 && arg_nr + 1 < nr_args) (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_output(fout); else fprintf(fout, "Warning: Skipped '%s'\n", arg); } } else if (strcmp(exec_fn, "M1-0") == 0 || strcmp(exec_fn, "M1") == 0) { for (int arg_nr = 1; arg_nr < nr_args; arg_nr++) { char *arg = args[arg_nr]; if (strcmp(arg, "--architecture") == 0) arg_nr++; else if (strcmp(arg, "--little-endian") == 0) ; else if (strcmp(arg, "-f") == 0 && arg_nr + 1 < nr_args) (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_input(fout); else if (strcmp(arg, "-o") == 0 && arg_nr + 1 < nr_args) (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_output(fout); else fprintf(fout, "Warning: Skipped '%s'\n", arg); } } else if (strcmp(exec_fn, "hex2-1") == 0 || strcmp(exec_fn, "hex2") == 0) { for (int arg_nr = 1; arg_nr < nr_args; arg_nr++) { char *arg = args[arg_nr]; if (strcmp(arg, "--architecture") == 0) arg_nr++; else if (strcmp(arg, "--little-endian") == 0) ; else if (strcmp(arg, "--base-address") == 0) arg_nr++; else if (strcmp(arg, "-f") == 0 && arg_nr + 1 < nr_args) (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_input(fout); else if (strcmp(arg, "-o") == 0 && arg_nr + 1 < nr_args) (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_output(fout); else fprintf(fout, "Warning: Skipped '%s'\n", arg); } } else if (strcmp(exec_fn, "checksum-transcriber") == 0) { if (nr_args == 2) { File *sources_file = get_file(cur_path, args[1]); (new Usage(sources_file, step))->is_input(fout); char *distfiles = get_var(vars, "distfiles"); if (distfiles != 0) { FILE *f_source = fopen(sources_file->name, "r"); if (f_source != 0) { char line[300]; while (fgets(line, 299, f_source)) { char *s = line; while (*s != '\0' && *s != ' ') s++; *s = '\0'; const char *fn = file_of_filename(line); File *source_file = get_file(distfiles, fn); source_file->url = (char*)malloc(strlen(line)+1); strcpy(source_file->url, line); indent(fout); fprintf(fout, "URL for %s : %s\n", source_file->name, source_file->url); } fclose(f_source); } } } } else if (strcmp(exec_fn, "M2-Mesoplanet") == 0) { for (int arg_nr = 1; arg_nr < nr_args; arg_nr++) { char *arg = args[arg_nr]; if (strcmp(arg, "--architecture") == 0) arg_nr++; else if (strcmp(arg, "--operating-system") == 0) arg_nr++; else if (strcmp(arg, "-f") == 0 && arg_nr + 1 < nr_args) (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_input(fout); else if (strcmp(arg, "-o") == 0 && arg_nr + 1 < nr_args) (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_output(fout); else (new Usage(get_file(cur_path, arg), step))->is_input(fout); } } else if (strcmp(exec_fn, "sha256sum") == 0) { for (int arg_nr = 1; arg_nr < nr_args; arg_nr++) { char *arg = args[arg_nr]; if (strcmp(arg, "-c") == 0 && arg_nr + 1 < nr_args) (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_input(fout); else if (strcmp(arg, "-o") == 0) { for (arg_nr += 2; arg_nr < nr_args; arg_nr++) { File *file = get_file(bin_path, file_of_filename(args[arg_nr])); if (prev_make_step != 0 && (!file->produced && !file->exists)) { indent(fout); fprintf(fout, " Assuming file %s was created with last make\n", file->name); (new Usage(file, prev_make_step))->is_output(fout); } } } else fprintf(fout, "Warning: Skipped '%s'\n", arg); } } else if (strcmp(exec_fn, "mkdir") == 0) { // Skip arguments } else if (strcmp(exec_fn, "ungz") == 0 || strcmp(exec_fn, "unbz2") == 0) { for (int arg_nr = 1; arg_nr < nr_args; arg_nr++) { char *arg = args[arg_nr]; if (strcmp(arg, "--file") == 0 && arg_nr + 1 < nr_args) (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_input(fout); else if (strcmp(arg, "--output") == 0 && arg_nr + 1 < nr_args) (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_output(fout); else (new Usage(get_file(cur_path, arg), step))->is_input(fout); } } else if (strcmp(exec_fn, "untar") == 0) { for (int arg_nr = 1; arg_nr < nr_args; arg_nr++) { char *arg = args[arg_nr]; if (strcmp(arg, "--non-strict") == 0) ; else if (strcmp(arg, "--file") == 0 && arg_nr + 1 < nr_args) (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_input(fout); else (new Usage(get_file(cur_path, arg), step))->is_input(fout); } } else if (strcmp(exec_fn, "rm") == 0) { for (int arg_nr = 1; arg_nr < nr_args; arg_nr++) { char *arg = args[arg_nr]; (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_removed(fout); } } else if (strcmp(exec_fn, "cp") == 0) { if (nr_args != 3) fprintf(fout, "ERROR: cp requires two arguments"); else { (new Usage(get_file(cur_path, args[1]), step))->is_input(fout); char *target = args[2]; if (target[strlen(target) - 1] == '/' || (bin_path != 0 && strcmp(bin_path, target) == 0)) { char target_fn[MAX_PATH_SIZE]; strcpy(target_fn, target); if (target[strlen(target) - 1] != '/') strcat(target_fn, "/"); strcat(target_fn, file_of_filename(args[1])); (new Usage(get_file(cur_path, target_fn), step))->is_output(fout); } else (new Usage(get_file(cur_path, args[2]), step))->is_output(fout); } } else if (strcmp(exec_fn, "chmod") == 0) { // ignore } else if (strcmp(exec_fn, "replace") == 0) { for (int arg_nr = 1; arg_nr < nr_args; arg_nr++) { char *arg = args[arg_nr]; if (strcmp(arg, "--file") == 0 && arg_nr + 1 < nr_args) (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_input(fout); else if (strcmp(arg, "--output") == 0 && arg_nr + 1 < nr_args) (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_output(fout); else if (strcmp(arg, "--match-on") == 0 && arg_nr + 1 < nr_args) arg_nr++; else if (strcmp(arg, "--replace_with") == 0) { if (arg_nr + 1 < nr_args) arg_nr++; } else (new Usage(get_file(cur_path, arg), step))->is_input(fout); } } else if (strcmp(exec_fn, "mes-m2") == 0 || strcmp(exec_fn, "mes") == 0) { bool string_input = false; char *scm_input = 0; char *c_input = 0; char *includes[10]; int nr_includes = 0; for (int arg_nr = 1; arg_nr < nr_args; arg_nr++) { char *arg = args[arg_nr]; if (strcmp(arg, "--no-auto-compile") == 0 && strcmp(exec_fn, "mes") == 0) ; else if (strcmp(arg, "-e") == 0 && arg_nr + 1 < nr_args) arg_nr++; else if (strcmp(arg, "--") == 0 && arg_nr + 1 < nr_args) { c_input = arg; arg_nr++; } else if (strcmp(arg, "-D") == 0 && arg_nr + 1 < nr_args) arg_nr++; else if (strcmp(arg, "-I") == 0 && arg_nr + 1 < nr_args) includes[nr_includes++] = args[++arg_nr]; else if (strcmp(arg, "-c") == 0 && arg_nr + 1 < nr_args) { arg = args[++arg_nr]; if (arg[0] == '"') string_input = true; else { if (c_input != 0) fprintf(fout, "ERROR: more than one c file\n"); else c_input = arg; (new Usage(get_file(cur_path, arg), step))->is_input(fout); char output_fn[MAX_PATH_SIZE]; strcpy(output_fn, arg); char *ext = output_fn + (strlen(output_fn) - 2); if (strcmp(".c", ext) == 0) { ext[1] = 'o'; (new Usage(get_file(cur_path, output_fn), step))->is_output(fout); } } } else if (strcmp(arg, "-L") == 0 && arg_nr + 1 < nr_args) { arg_nr++; if (strcmp(args[arg_nr], ".") != 0) (new Usage(get_file(cur_path, args[arg_nr]), step))->is_input(fout); } else if (strcmp(arg, "-o") == 0 && arg_nr + 1 < nr_args) (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_output(fout); else if (strncmp(arg, "-l", 2) == 0) ; else { int len = strlen(arg); if (strcmp(file_ext(arg), "scm") == 0) { if (scm_input != 0) fprintf(fout, "ERROR: more than one .scm file\n"); else scm_input = arg; } (new Usage(get_file(cur_path, arg), step))->is_input(fout); } } if (!string_input) { if (c_input == 0) fprintf(fout, "ERROR: No c input\n"); if (scm_input == 0) fprintf(fout, "ERROR: No scm input\n"); } } else if ( strcmp(exec_fn, "mes-tcc") == 0 || strcmp(exec_fn, "boot0-tcc") == 0 || strcmp(exec_fn, "boot1-tcc") == 0 || strcmp(exec_fn, "boot2-tcc") == 0 || strcmp(exec_fn, "boot3-tcc") == 0 || strcmp(exec_fn, "boot4-tcc") == 0 || strcmp(exec_fn, "boot5-tcc") == 0 || strcmp(exec_fn, "tcc") == 0 || strcmp(exec_fn, "tcc-0.9.26") == 0) { if (strcmp(args[1], "-version") == 0) ; else if (strcmp(args[1], "-ar") == 0) { int arg_nr = 2; if (arg_nr < nr_args && strcmp(args[arg_nr], "cr") == 0) arg_nr++; if (arg_nr + 2 != nr_args) fprintf(fout, "ERROR: -ar requires two more arguments\n"); else { (new Usage(get_file(cur_path, args[arg_nr]), step))->is_input(fout); (new Usage(get_file(cur_path, args[arg_nr + 1]), step))->is_output(fout); } } else { char *c_input = 0; char *includes[10]; int nr_includes = 0; for (int arg_nr = 2; arg_nr < nr_args; arg_nr++) { char *arg = args[arg_nr]; if (strcmp(arg, "-c") == 0) ; else if (strcmp(arg, "-g") == 0) ; else if (strcmp(arg, "-v") == 0) ; else if (strcmp(arg, "-static") == 0) ; else if (strcmp(arg, "-D") == 0 && arg_nr + 1 < nr_args) arg_nr++; else if (strncmp(arg, "-D", 2) == 0) ; else if (strcmp(arg, "-I") == 0 && arg_nr + 1 < nr_args) includes[nr_includes++] = args[++arg_nr]; else if (strncmp(arg, "-I", 2) == 0) ; else if (strcmp(arg, "-L") == 0 && arg_nr + 1 < nr_args) { arg_nr++; if (strcmp(args[arg_nr], ".") != 0) (new Usage(get_file(cur_path, args[arg_nr]), step))->is_input(fout); } else if (strcmp(arg, "-o") == 0 && arg_nr + 1 < nr_args) (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_output(fout); else if (strncmp(arg, "-l", 2) == 0) ; else { if (strcmp(file_ext(arg), ".c") == 0) { if (c_input != 0) fprintf(fout, "ERROR: more than one c file\n"); else c_input = arg; } (new Usage(get_file(cur_path, arg), step))->is_input(fout); } } if (c_input != 0) { } } } else if (strcmp(exec_fn, "make") == 0) { for (int arg_nr = 1; arg_nr < nr_args; arg_nr++) { char *arg = args[arg_nr]; if (strcmp(arg, "--version") == 0) ; else if (strcmp(arg, "-f") == 0 && arg_nr + 1 < nr_args) (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_input(fout); else { indent(fout); fprintf(fout, " make switch: %s\n", arg); } } prev_make_step = step; } else if (strcmp(exec_fn, "gzip") == 0) { bool deflate = false; for (int arg_nr = 1; arg_nr < nr_args; arg_nr++) { char *arg = args[arg_nr]; if (strcmp(arg, "-d") == 0) deflate = true; else if (strcmp(arg, "-f") == 0 && arg_nr + 1 < nr_args) { arg = args[++arg_nr]; (new Usage(get_file(cur_path, arg), step))->is_input(fout); char *ext = (char *)file_ext(arg); if (deflate && strcmp(ext, "gz") == 0) { ext[-1] = '0'; (new Usage(get_file(cur_path, arg), step))->is_output(fout); } } else { fprintf(fout, "ERROR: %s\n", arg); } } } else if (strcmp(exec_fn, "patch") == 0) { bool deflate = false; for (int arg_nr = 1; arg_nr < nr_args; arg_nr++) { char *arg = args[arg_nr]; if (strcmp(arg, "-Np0") == 0) deflate = true; else if (strcmp(arg, "-i") == 0 && arg_nr + 1 < nr_args) (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_input(fout); else { fprintf(fout, "ERROR: %s\n", arg); } } } else if (strcmp(exec_fn, "bunzip2") == 0) { for (int arg_nr = 1; arg_nr < nr_args; arg_nr++) { char *arg = args[arg_nr]; if (strcmp(arg, "-f") == 0 && arg_nr + 1 < nr_args) { arg = args[++arg_nr]; (new Usage(get_file(cur_path, arg), step))->is_input(fout); char *ext = (char *)file_ext(arg); if (strcmp(ext, "bz2") == 0) { ext[-1] = '0'; (new Usage(get_file(cur_path, arg), step))->is_output(fout); } } else { fprintf(fout, "ERROR: %s\n", arg); } } } else { for (int arg_nr = 1; arg_nr < nr_args; arg_nr++) { char *arg = args[arg_nr]; if (*arg == '-') { int i = 0; indent(fout); fprintf(fout, "Switch %s\n", arg); if (strcmp(arg, "--base-address") == 0 || strcmp(arg, "--operating-system") == 0 || strcmp(arg, "--architecture") == 0) { arg_nr++; } } else { File *file = get_file(cur_path, arg); Usage *usage = new Usage(file, step); if (file->exists || file->produced) usage->is_input(fout); else usage->is_output(fout); } } } indent_depth -= 2; } } } } fclose(f); indent_depth -= 2; return true; } void dir_of_filename(const char *fn, char *dir) { strcpy(dir, fn); char *last = 0; for (char *s = dir; *s != '\0'; s++) if (*s == '/') last = s; if (last != 0) *last = '\0'; } const char *file_of_filename(const char *full_fn) { const char *fn = full_fn; for (const char *s = full_fn; *s != '\0'; s++) if (*s == '/') fn = s + 1; return fn; } FILE *open_file(const char *dir, const char *fn) { char filename[MAX_PATH_SIZE]; sprintf(filename, "%s/%s", dir, fn); return fopen(filename, "r"); } const char *file_ext(const char *fn) { const char *ext = ""; for (const char *s = fn; *s != '\0'; s++) if (*s == '.') ext = s + 1; return ext; } void write_html_file(FILE *f, File *file, SubModule *submodules) { fprintf(f, "

%s

\n\n", file->nr, file->name, file->name); if (file->exists && strncmp(file->name, "../git/", 7) == 0) { char *s = file->name + 7; if (strncmp(s, "stage0-posix/", 13) == 0) { s += 13; int len; const char *url = "https://github.com/oriansj/stage0-posix"; for (SubModule *sm = submodules; sm != 0; sm = sm->next) { len = strlen(sm->path); if (strncmp(s, sm->path, len) == 0 && s[len] == '/') { url = sm->url; break; } } fprintf(f, "Git: %s%s\n

\n", url, s + len + 1, url, s + len + 1); } } if (file->exec) fprintf(f, "Executable%s\n", file->exists ? " seed!" : ""); fprintf(f, "

    \n"); for (Usage *usage = file->usages; usage != 0; usage = usage->next_usage) fprintf(f, "
  • %s step %d\n", usage->as_exec ? "Used as executable" : usage->as_input ? "Used as input" : usage->as_output ? "Produced by" : "Used in", usage->step->nr, usage->step->nr); fprintf(f, "
\n\n"); } void write_html(FILE *f, SubModule *submodules) { fprintf(f, "\noutput\n\n\n

output

"); fprintf(f, "\n\n

Binary seeds files

\n\n"); for (File *file = files; file != 0; file = file->next) if (file->exec && file->exists) write_html_file(f, file, submodules); fprintf(f, "

Input binary files

\n\n"); for (File *file = files; file != 0; file = file->next) if (file->exec && !file->exists && !file->produced) write_html_file(f, file, submodules); fprintf(f, "

Input source files

\n\n"); for (File *file = files; file != 0; file = file->next) if (!file->exec && file->used_as_input && !file->produced) write_html_file(f, file, submodules); fprintf(f, "\n

Steps

\n\n"); for (Step *step = all_steps; step != 0; step = step->next) { fprintf(f, "

Step %d

\n\n
    \n", step->nr, step->nr); for (Usage *use = step->uses; use != 0; use = use->next_use) { if (use->as_exec || use->as_input) fprintf(f, "
  • %s %s\n", use->as_exec ? "Executes" : use->as_input ? "Uses as input" : use->as_output ? "Produceses" : "Uses", use->file->nr, use->file->name); if (use->as_output) { fprintf(f, "
  • Produces %s\n", use->file->name); fprintf(f, "
      \n"); for (Usage *usage = use->file->usages; usage != 0; usage = usage->next_usage) if (usage->as_exec || usage->as_input) fprintf(f, "
    • %s step %d\n", usage->as_exec ? "Used as executable" : usage->as_input ? "Used as input" : usage->as_output ? "Produced by" : "Used in", usage->step->nr, usage->step->nr); fprintf(f, "
    \n\n"); } } fprintf(f, "
\n\n"); } fprintf(f, "\n

Output files

\n\n
    \n"); for (File *file = files; file != 0; file = file->next) if (file->produced) { bool used_as_input = false; int step_nr = -1; for (Usage *usage = file->usages; usage != 0 && !used_as_input; usage = usage->next_usage) { if (usage->as_input || usage->as_exec) used_as_input = true; if (usage->as_output) step_nr = usage->step->nr; } if (!used_as_input || file->exec) { fprintf(f, "
  • %s", file->name); if (step_nr > 0) fprintf(f, " produced by step %d", step_nr, step_nr); if (used_as_input) fprintf(f, " (also executed)"); fprintf(f, "\n"); } } fprintf(f, "
\n\n\n"); }