#include #include #include #define CPP_MAX_PATH_SIZE 1000 class AbstractIterator { public: bool more; char ch; long line; long column; char *filename; virtual void next() = 0; }; class StringIterator : public AbstractIterator { public: StringIterator(const char *s, const char *fn) { filename = (char*)malloc(strlen(fn)+1); strcpy(filename, fn); _s = s; line = 1; column = 1; ch = *_s++; more = ch != '\0'; } ~StringIterator() { delete filename; } void next() { if (ch == '\0') return; if (ch == '\n') { line++; column = 1; } else column++; ch = *_s++; if (ch == '\r') ch = *_s++; more = ch != '\0'; } private: const char *_s; }; class FileIterator : public AbstractIterator { public: FileIterator(const char *fn) { filename = (char*)malloc(strlen(fn)+1); strcpy(filename, fn); _f = fopen(filename, "r"); more = _f != 0; ch = '\n'; line = 0; column = 0; next(); } ~FileIterator() { delete filename; } void next() { if (!more) return; if (ch == '\n') { line++; column = 0; } column++; ch = fgetc(_f); more = !feof(_f); if (!more) { ch = '\0'; fclose(_f); _f = 0; } else if (ch == '\r') next(); } private: FILE *_f; }; class TrigraphIterator : public AbstractIterator { public: TrigraphIterator(AbstractIterator *source_it) : _source_it(source_it) { filename = _source_it->filename; _a[0] = _source_it->ch; _source_it->next(); _a[1] = _source_it->ch; ch = '\n'; line = 0; more = true; _next_column = 1; next(); } void next() { if (_a[0] == '\0') { more = false; ch = '\0'; return; } if (ch == '\n') { line++; column = 1; } else column = _next_column; ch = _a[0]; _a[0] = _a[1]; _source_it->next(); _a[1] = _source_it->ch; if (ch == '?' && _a[0] == '?') { char rch = '\0'; if (_a[1] == '=') rch = '#'; else if (_a[1] == '/') rch = '\\'; else if (_a[1] == 39) rch = '^'; else if (_a[1] == '(') rch = '['; else if (_a[1] == ')') rch = ']'; else if (_a[1] == '!') rch = '|'; else if (_a[1] == '<') rch = '{'; else if (_a[1] == '>') rch = '}'; else if (_a[1] == '-') rch = '~'; if (rch != '\0') { ch = rch; _next_column = column + 3; _source_it->next(); _a[0] = _source_it->ch; _source_it->next(); _a[1] = _source_it->ch; return; } } _next_column = column + 1; } private: AbstractIterator *_source_it; char _a[2]; long _next_column; }; class LineSpliceIterator : public AbstractIterator { public: LineSpliceIterator(AbstractIterator *source_it) : _source_it(source_it) { filename = _source_it->filename; _a = _source_it->ch; next(); } void next() { if (_a == '\0') { more = false; ch = '\0'; return; } ch = _a; line = _source_it->line; column = _source_it->column; _source_it->next(); _a = _source_it->ch; while (ch == '\\' && _a == '\n') { _source_it->next(); ch = _source_it->ch; line = _source_it->line; column = _source_it->column; _source_it->next(); _a = _source_it->ch; } more = ch != '\0'; } private: AbstractIterator *_source_it; char _a; }; class CommentStripIterator : public AbstractIterator { public: CommentStripIterator(AbstractIterator *source_it) : _source_it(source_it) { filename = _source_it->filename; _a = _source_it->ch; _state = 0; more = true; next(); } void next() { switch(_state) { case 0: goto s0; case 1: goto s1; case 2: goto s2; case 3: goto s3; case 4: goto s4; case 5: goto s5; case 6: goto s6; case 7: goto s7; case 8: goto s8; case 9: goto s9; } s0: if (_a == '\0') { more = false; ch = '\0'; return; } ch = _a; line = _source_it->line; column = _source_it->column; _source_it->next(); _a = _source_it->ch; if (ch == '/' && (_a == '/' || _a == '*')) { if (_a == '/') { while (_a != '\0' && _a != '\n') { _source_it->next(); _a = _source_it->ch; } } else { ch = ' '; _state = 1; return; s1: _source_it->next(); ch = _source_it->ch; _source_it->next(); _a = _source_it->ch; while (ch != '\0' && (ch != '*' || _a != '/')) { ch = _a; _source_it->next(); _a = _source_it->ch; } if (ch != '\0') { _source_it->next(); _a = _source_it->ch; line = _source_it->line; column = _source_it->column; } } _state = 0; goto s0; } if (ch == '"') { _state = 2; return; s2: ch = _a; line = _source_it->line; column = _source_it->column; while (ch != '\0' && ch != '"') { if (ch == '\\') { _state = 3; return; s3: _source_it->next(); ch = _source_it->ch; line = _source_it->line; column = _source_it->column; } _state = 4; return; s4: _source_it->next(); ch = _source_it->ch; line = _source_it->line; column = _source_it->column; } if (ch == '"') { _state = 5; return; s5: _source_it->next(); _a = _source_it->ch; line = _source_it->line; column = _source_it->column; } _state = 0; goto s0; } if (ch == '\'') { _state = 6; return; s6: ch = _a; line = _source_it->line; column = _source_it->column; if (ch == '\\') { _state = 7; return; s7: _source_it->next(); ch = _source_it->ch; line = _source_it->line; column = _source_it->column; } _state = 8; return; s8: _source_it->next(); ch = _source_it->ch; line = _source_it->line; column = _source_it->column; _state = 0; if (ch == '\'') { _state = 9; return; s9: _source_it->next(); _a = _source_it->ch; line = _source_it->line; column = _source_it->column; } _state = 0; goto s0; } } private: AbstractIterator *_source_it; char _a; int _state; }; class IncludePathResolver { }; class AbstractIncludePathResolver { public: virtual AbstractIterator *iteratorFor(const char *path, bool include_next, AbstractIterator *context) = 0; }; class Define { public: char *name; bool defined; char *str_value; Define *next; Define(const char *_name, const char *value, Define *_next) : defined(true), next(_next), str_value(0) { name = (char*)malloc(strlen(_name)+1); strcpy(name, _name); setValue(value); } ~Define() { free(name); if (str_value != 0) free(str_value); delete next; } int getIntValue() { if (!defined) return 0; if (str_value == 0) return 1; int sign = 1; char *s = str_value; if (*s == '-') sign = -1; int result = 0; while ('0' <= *s && *s <= '9') result = 10 * result + *s++ - '0'; return sign * result; } void setValue(const char *value) { defined = true; if (str_value != 0) free(str_value); if (value == 0) str_value = 0; else { str_value = (char*)malloc(strlen(value)+1); strcpy(str_value, value); } } static void addDefine(Define *&defines, const char *name, const char *value) { for (Define *define = defines; define != 0; define = define->next) if (strcmp(define->name, name) == 0) { define->setValue(value); return; } defines = new Define(name, value, defines); } static void removeDefine(Define *defines, const char *name) { for (Define *define = defines; define != 0; define = define->next) if (strcmp(define->name, name) == 0) { define->defined = false; return; } } static bool isDefined(Define *defines, const char *name) { for (Define *define = defines; define != 0; define = define->next) if (strcmp(define->name, name) == 0) return define->defined; return false; } static Define *getDefine(Define *defines, const char *name) { for (Define *define = defines; define != 0; define = define->next) if (strcmp(define->name, name) == 0) return define; return 0; } }; class InlineIncludesIterator : public AbstractIterator { public: InlineIncludesIterator(AbstractIterator *source_it, AbstractIncludePathResolver *includePathResolver, Define *&defines) : _source_it(source_it), _includePathResolver(includePathResolver), _defines(defines) { filename = _source_it->filename; ch = _source_it->ch; line = _source_it->line; column = _source_it->column; more = true; _state = 0; _skip_level = 0; _done = false; next(); } void next() { switch(_state) { case 0: goto s0; case 1: goto s1; case 2: goto s2; case 3: goto s3; case 4: goto s4; case 5: goto s5; case 6: goto s0; case 7: goto s7; case 8: goto s8; case 9: goto s9; case 10: goto s10; case 11: goto s11; case 12: goto s12; case 13: goto s13; } s0: while (ch != '\0') { _state = 0; while (ch == ' ') { if (_skip_level == 0) { _state = 1; return; s1:; } _source_it->next(); ch = _source_it->ch; line = _source_it->line; column = _source_it->column; } if (ch == '#') { _i = 0; _source_it->next(); ch = _source_it->ch; line = _source_it->line; column = _source_it->column; _name[0] = '#'; _i = 1; while (ch == ' ' || ch == '\t') { _source_it->next(); ch = _source_it->ch; line = _source_it->line; column = _source_it->column; } while (('a' <= ch && ch <= 'z') || ch == '_') { if (_i < 19) _name[_i++] = ch; _source_it->next(); ch = _source_it->ch; line = _source_it->line; column = _source_it->column; } _name[_i] = '\0'; if (strcmp(_name, "#if") == 0 || strcmp(_name, "#elif") == 0) { bool exec_if = false; if (strcmp(_name, "#if") == 0) { if (_skip_level > 0) _skip_level++; else exec_if = true; } else // elif { if (_done) ; else if (_skip_level == 0) { _done = true; _skip_level = 1; } else if (_skip_level == 1) { _skip_level = 0; exec_if = true; } } if (exec_if) { int i = 0; while (ch != '\0' && ch != '\n') { if (_i < 10000) _value[i++] = ch; _source_it->next(); ch = _source_it->ch; } _value[i] = '\0'; skip_space(); const char *s = _value; if (evaluate_cond(s) == 0) _skip_level = 1; else _done = true; if (*s != '\0') fprintf(stderr, "Error: %s:%ld parsing |%s|%s|\n", filename, line, _value, s); } } else if (strcmp(_name, "#ifdef") == 0) { if (_skip_level > 0) _skip_level++; else { skip_space(); parse_ident(_name, 100); if (_name[0] != '\0' && !Define::isDefined(_defines, _name)) _skip_level = 1; else _done = true; } } else if (strcmp(_name, "#ifndef") == 0) { if (_skip_level > 0) _skip_level++; else { skip_space(); parse_ident(_name, 100); if (_name[0] != '\0' && Define::isDefined(_defines, _name)) _skip_level = 1; else _done = true; } } else if (strcmp(_name, "#else") == 0) { if (_done) ; else if (_skip_level == 0) _skip_level = 1; else if (_skip_level == 1) _skip_level = 0; /*if (_skip_level == 0) _skip_level = 1; else if (_skip_level == 1) _skip_level = 0; */ } else if (strcmp(_name, "#endif") == 0) { if (_skip_level > 0) { if (--_skip_level == 0) _done = false; } } else if (_skip_level > 0) ; // skip all other directives else if ((strcmp(_name, "#include") == 0/* || strcmp(_name, "#include_next") == 0*/)&& (ch == ' ' || ch == '"' || ch == '<')) { skip_space(); { bool include_next = strcmp(_name, "#include_next") == 0; char include_fn[CPP_MAX_PATH_SIZE]; include_fn[0] = ch; int _i = 1; char _end_quote = ch == '<' ? '>' : '"'; _source_it->next(); ch = _source_it->ch; while (ch != '\0' && ch != _end_quote) { include_fn[_i++] = ch; _source_it->next(); ch = _source_it->ch; } if (ch == _end_quote) include_fn[_i++] = _end_quote; include_fn[_i] = '\0'; _nested_iterator = _includePathResolver->iteratorFor(include_fn, include_next, this); } while (_nested_iterator->ch != '\0') { ch = _nested_iterator->ch; filename = _nested_iterator->filename; line = _nested_iterator->line; column = _nested_iterator->column; _state = 2; return; s2: _nested_iterator->next(); } delete _nested_iterator; filename = _source_it->filename; ch = _source_it->ch; while (ch != '\0' && ch != '\n') { _source_it->next(); ch = _source_it->ch; } if (ch == '\n') { _source_it->next(); ch = _source_it->ch; line = _source_it->line; column = _source_it->column; continue; } } else if (strcmp(_name, "#define") == 0) { _i = 0; while (_name[_i] != '\0') { ch = _name[_i++]; _state = 3; return; s3:; } ch = _source_it->ch; line = _source_it->line; column = _source_it->column; // skip spaces while (ch == ' ') { _state = 4; return; s4: _source_it->next(); ch = _source_it->ch; line = _source_it->line; column = _source_it->column; } // parse name of define _i = 0; while (is_ident()) { if (_i < 100) _name[_i++] = ch; _state = 5; return; s5: _source_it->next(); ch = _source_it->ch; line = _source_it->line; column = _source_it->column; } _name[_i] = '\0'; // skip spaces while (ch == ' ') { _state = 6; return; s6: _source_it->next(); ch = _source_it->ch; line = _source_it->line; column = _source_it->column; } // parse name of define _i = 0; while (ch != '\0' && ch != '\n') { if (_i < 10000) _value[_i++] = ch; _state = 7; return; s7: _source_it->next(); ch = _source_it->ch; line = _source_it->line; column = _source_it->column; } _value[_i] = '\0'; if (_name[0] != '\0') Define::addDefine(_defines, _name, _value); } else if (strcmp(_name, "#undef") == 0) { _i = 0; while (_name[_i] != '\0') { ch = _name[_i++]; _state = 8; return; s8:; } ch = _source_it->ch; line = _source_it->line; column = _source_it->column; // skip spaces while (ch == ' ') { _state = 9; return; s9: _source_it->next(); ch = _source_it->ch; line = _source_it->line; column = _source_it->column; } // parse name of define _i = 0; while (is_ident()) { if (_i < 100) _name[_i++] = ch; _state = 10; return; s10: _source_it->next(); ch = _source_it->ch; line = _source_it->line; column = _source_it->column; } _name[_i] = '\0'; if (_name[0] != '\0') Define::removeDefine(_defines, _name); } else { if (strcmp(_name, "#warning") != 0 && strcmp(_name, "#pragma") != 0 && strcmp(_name, "#error") != 0) fprintf(stderr, "Unknown %s.%ld unknown redirective |%s|\n", filename, line, _name); _i = 0; while (_name[_i] != '\0') { ch = _name[_i++]; _state = 11; return; s11:; } ch = _source_it->ch; line = _source_it->line; column = _source_it->column; } } while (ch != '\0' && ch != '\n') { if (_skip_level == 0) { _state = 12; return; s12:; } _source_it->next(); ch = _source_it->ch; line = _source_it->line; column = _source_it->column; } if (ch == '\n') { if (_skip_level == 0) { _state = 13; return; s13:; } _source_it->next(); ch = _source_it->ch; line = _source_it->line; column = _source_it->column; } } more = false; } private: void skip_space() { while (ch == ' ' || ch == '\t') { _source_it->next(); ch = _source_it->ch; line = _source_it->line; column = _source_it->column; } } void parse_ident(char *name, int len) { _i = 0; while (is_ident()) { if (_i < len) name[_i++] = ch; _source_it->next(); ch = _source_it->ch; line = _source_it->line; column = _source_it->column; } name[_i] = '\0'; } bool is_ident() { return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ch == '_' || (_i > 0 && '0' <= ch && ch <= '9'); } bool is_ident_start(char ch) { return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ch == '_'; } bool is_ident_next(char ch) { return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ch == '_' || ('0' <= ch && ch <= '9'); } int evaluate_cond(const char *&s) { int v = evaluate_or(s); if (*s == '?') { s++; int then_v = evaluate_or(s); int else_v = 0; if (*s == ':') { s++; else_v = evaluate_cond(s); } return v != 0 ? then_v : else_v; } return v; } int evaluate_or(const char *&s) { int v = evaluate_and(s); while (s[0] == '|' && s[1] == '|') { s += 2; int n_v = evaluate_cmp(s); v = v || n_v; } return v; } int evaluate_and(const char *&s) { int v = evaluate_cmp(s); while (s[0] == '&' && s[1] == '&') { s += 2; int n_v = evaluate_cmp(s); v = v && n_v; } return v; } int evaluate_cmp(const char *&s) { int v = evaluate_mul(s); if (s[0] == '>' && s[1] == '=') { s += 2; return v >= evaluate_mul(s); } if (s[0] == '>') { s++; return v > evaluate_mul(s); } if (s[0] == '<' && s[1] == '=') { s += 2; return v <= evaluate_mul(s); } if (s[0] == '<') { s++; return v < evaluate_mul(s); } if (s[0] == '=' && s[1] == '=') { s += 2; return v == evaluate_mul(s); } if (s[0] == '!' && s[1] == '=') { s += 2; return v != evaluate_mul(s); } return v; } int evaluate_mul(const char *&s) { int v = evaluate_add(s); for (;;) if (s[0] == '*') { s++; v *= evaluate_add(s); } else if (s[0] == '/') { s++; int divider = evaluate_add(s); if (divider != 0) v /= divider; } else break; return v; } int evaluate_add(const char *&s) { int v = evaluate_term(s); for (;;) if (s[0] == '+') { s++; v += evaluate_term(s); } else if (s[0] == '-') { s++; v -= evaluate_term(s); } else break; return v; } int evaluate_term(const char *&s) { int result = 0; while (*s == ' ' || *s == '\t') s++; if (*s == '(') { s++; result = evaluate_cond(s); if (*s == ')') s++; } else if (is_ident_start(*s)) { char id[101]; int i = 0; for (; is_ident_next(*s); s++) if (i < 100) id[i++] = *s; id[i] = '\0'; if (strcmp(id, "defined") == 0) { while (*s == ' ' || *s == '\t') s++; int b = 0; while (*s == '(') { b++; s++; while (*s == ' ' || *s == '\t') s++; } i = 0; for (; is_ident_next(*s); s++) if (i < 100) id[i++] = *s; id[i] = '\0'; while (*s == ' ' || *s == '\t') s++; result = Define::isDefined(_defines, id); while (*s == ')' && b > 0) { b--; s++; while (*s == ' ' || *s == '\t') s++; } } else { Define *define = Define::getDefine(_defines, id); result = define != 0 ? define->getIntValue() : 0; } } else if ('0' <= *s && *s <= '9') { while ('0' <= *s && *s <= '9') result = 10 * result + *s++ - '0'; if (*s == 'L') s++; } else if (*s == '\'') { s++; if (*s == '\\') s++; result = *s++; if (*s == '\'') s++; } else if (*s == '!') { s++; result = !evaluate_term(s); } while (*s == ' ' || *s == '\t') s++; return result; } AbstractIterator *_source_it; AbstractIncludePathResolver *_includePathResolver; Define *&_defines; int _state; char _name[101]; char _value[100000]; int _i; char _end_quote; AbstractIterator *_nested_iterator; int _skip_level; bool _done; }; #define MAX_LINE_SIZE 10000 #define MAX_PATH_SIZE 1000 char *copystr(const char *str) { char *new_str = (char*)malloc(strlen(str) + 1); strcpy(new_str, str); return new_str; } class File; int nr_sources = 0; class Source { public: char *url; int nr; File *files; Source *next; Source(const char *u) : url(copystr(u)), files(0), next(0) { nr = nr_sources++; } }; Source *sources = 0; void add_source(const char *url, File *file); class Usage; class Step; void map_filename(const char *fn, char *mapped_fn) { mapped_fn[0] = '\0'; if (strncmp(fn, "/sysa/", 6) == 0) strcpy(mapped_fn, "../git/live-bootstrap"); strcat(mapped_fn, fn); } class MergeChild; int nr_files = 0; class File { public: char *name; int nr; bool exists; bool produced; Step *produced_by; bool exec; bool used_as_input; bool removed; Source *source; File *next_source_file; File *alias; File *copy_from; Usage *usages; MergeChild *mergeChildren; File *next; File(const char *fn) : exists(false), produced(false), produced_by(0), exec(false), next(0), source(0), next_source_file(0), alias(0), copy_from(0), usages(0), mergeChildren(0) { name = (char*)malloc(strlen(fn)+1); strcpy(name, fn); nr = nr_files++; if (strncmp(name, "/usr/bin", 6) != 0) { char mapped_name[MAX_PATH_SIZE]; map_filename(name, mapped_name); FILE *f = fopen(mapped_name, "r"); if (f != 0) { exists = true; fclose(f); } } } File *existing() { for (File *f = this; f != 0; f = f->copy_from) if (f->exists) return f; return 0; } void set_source(const char *url) { Source **ref_source = &sources; for (; *ref_source != 0; ref_source = &(*ref_source)->next) if (strcmp((*ref_source)->url, url) == 0) break; if (*ref_source == 0) { *ref_source = new Source(url); } source = *ref_source; File **ref_file = &(*ref_source)->files; while (*ref_file != 0) ref_file = &(*ref_file)->next_source_file; *ref_file = this; } FILE *open() { return fopen(name, "r"); } }; File *files = 0; class MergeChild { public: File *child; MergeChild *next; MergeChild(File *file) : child(file), next(0) {} }; void combine_dir_fn(const char *dir, const char *fn, char *filename) { if (fn[0] == '/') { strcpy(filename, fn); return; } if (fn[0] == '.' && fn[1] == '/') fn += 2; strcpy(filename, dir); char *t = filename + strlen(filename); if (fn[0] == '.' && fn[1] == '\0') return; *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, bool use_alias = true) { File **ref = &files; for (; *ref != 0; ref = &(*ref)->next) if (strcmp((*ref)->name, full_fn) == 0) return (*ref)->alias != 0 && use_alias ? (*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); } File *find_file(const char *fn) { for (File *file = files; file != 0; file = file->next) if (strcmp(file->name, fn) == 0) return file->alias != 0 ? file->alias : file; return 0; } File *find_exec_file(const char *fn) { char full_fn[MAX_PATH_SIZE]; if (*fn == '/') strcpy(full_fn, fn); else combine_dir_fn("/usr/bin", fn, full_fn); return find_file(full_fn); } int nr_steps = 0; class Step { public: int nr; Usage *uses; Step *next; Step() : uses(0), next(0) { nr = nr_steps++; } bool hasInputUseOf(File *f); }; 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->produced_by = step; 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); } }; bool Step::hasInputUseOf(File *f) { for (Usage *use = uses; use != 0; use = use->next_use) if (use->file == f && use->as_input) return true; return false; } 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; } class SubModule { public: char *path; char *url; SubModule *next; SubModule(const char *p, const 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, SubModule *subModules) { FILE *f = fopen(fn, "r"); if (f == 0) return 0; char complete_path[MAX_LINE_SIZE]; strcpy(complete_path, fn); char *s_path = strstr(complete_path, ".gitmodules"); char path[MAX_LINE_SIZE]; char url[MAX_LINE_SIZE]; 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'; sprintf(s_path, "%s/", path + 8); 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/%%s", 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=%%s", url + 43); else sprintf(complete_url, "%s%%s", url + 7); printf("Submodule %s %s|\n", complete_path, complete_url); subModules = new SubModule(complete_path, complete_url, subModules); } } return subModules; } class Directory { public: char *path; Directory *next; Directory(const char *p, Directory *n) : path(copystr(p)), next(n) {} }; Directory *directories = 0; bool is_directory(const char *path) { for (Directory *dir = directories; dir != 0; dir = dir->next) if (strcmp(dir->path, path) == 0) return true; return false; } void add_directory(const char *path) { if (!is_directory(path)) directories = new Directory(path, directories); } 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); void path_of_filename(const char *fn, char *path); const char *file_ext(const char *fn); FILE *open_file(const char *dir, const char *fn); void write_html(FILE *f, SubModule *submodules); int main(int argc, char *argv[]) { char cur_path[MAX_PATH_SIZE]; #define STAGE0POSIX "../git/stage0-posix/" const char *stage0_path = STAGE0POSIX "kaem.amd64"; SubModule *subModules = new SubModule(STAGE0POSIX "", "https://github.com/oriansj/stage0-posix/blob/master/%s", 0); subModules = read_sub_modules(STAGE0POSIX ".gitmodules", subModules); dir_of_filename(stage0_path, cur_path); fprintf(stdout, "Cur path: %s\n", cur_path); FILE *fout = fopen("out.txt", "w"); 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"; subModules = new SubModule("../git/live-bootstrap/", "https://github.com/fosslinux/live-bootstrap/blob/master/%s", subModules); subModules = new SubModule("../git/live-bootstrap/sysa/tcc-0.9.26/build/mes-0.24.2/", "https://git.savannah.gnu.org/cgit/mes.git/tree/%s?h=v0.24.2", subModules); subModules = new SubModule("../git/live-bootstrap/sysa/tcc-0.9.27/build/mes-0.24.2/", "https://git.savannah.gnu.org/cgit/mes.git/tree/%s?h=v0.24.2", subModules); subModules = new SubModule("../git/live-bootstrap/sysa/tcc-0.9.26/build/tcc-0.9.26-1136-g5bba73cc/", "https://gitlab.com/janneke/tinycc/-/blob/ff2210b308321f27ee07476d07f24b5095602b17/%s", subModules); subModules = new SubModule("../git/live-bootstrap/sysa/make-3.82/build/make-3.82/", "https://git.savannah.gnu.org/cgit/make.git/tree/%s?h=3.82", subModules); subModules = new SubModule("../git/live-bootstrap/sysa/coreutils-5.0/build/coreutils-5.0/", "https://git.savannah.gnu.org/cgit/coreutils.git/tree/%s?h=COREUTILS-5_0", subModules); subModules = new SubModule("/sysa/mes-0.24.2", "https://github.com/fosslinux/live-bootstrap/blob/master/sysa/mes-0.24.2/%s", subModules); subModules = new SubModule("/sysa/mes-0.24.2/build/mes-0.24.2/", "https://git.savannah.gnu.org/cgit/mes.git/tree/%s?h=v0.24.2", subModules); dir_of_filename(live_bootstrap, cur_path); fprintf(stdout, "Cur path: %s\n", cur_path); add_directory("/sysa"); add_directory("/sysa/disfiles"); add_directory("/usr/bin"); add_directory("/usr/lib"); add_directory("/usr/include"); add_directory("/usr/src"); add_directory("/sysa/mes-0.24.2/build/mes-0.24.2/include/mes"); 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("distfiles", "/sysa/disfiles", false, live_bootstrap_vars); live_bootstrap_vars = new Var("bindir", "/usr/bin", false, live_bootstrap_vars); live_bootstrap_vars = new Var("libdir", "/usr/lib", false, live_bootstrap_vars); live_bootstrap_vars = new Var("incdir", "/usr/include", false, live_bootstrap_vars); live_bootstrap_vars = new Var("srcdir", "/usr/src", false, live_bootstrap_vars); live_bootstrap_vars = new Var("mes_cpu:-x86", "x86", false, live_bootstrap_vars); live_bootstrap_vars = new Var("stage0_cpu:-x86", "stage0_cpu", false, live_bootstrap_vars); live_bootstrap_vars = new Var("prefix", "/usr", 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(STAGE0POSIX "AMD64/bin/blood-elf","/usr/bin/blood-elf"); copy_file(STAGE0POSIX "AMD64/bin/catm","/usr/bin/catm"); copy_file(STAGE0POSIX "AMD64/bin/chmod","/usr/bin/chmod"); copy_file(STAGE0POSIX "AMD64/bin/get_machine","/usr/bin/get_machine"); copy_file(STAGE0POSIX "AMD64/bin/hex2","/usr/bin/hex2"); copy_file(STAGE0POSIX "AMD64/bin/kaem","/usr/bin/kaem"); copy_file(STAGE0POSIX "AMD64/bin/match","/usr/bin/match"); copy_file(STAGE0POSIX "AMD64/bin/M1","/usr/bin/M1"); copy_file(STAGE0POSIX "AMD64/bin/M2-Mesoplanet","/usr/bin/M2-Mesoplanet"); copy_file(STAGE0POSIX "AMD64/bin/M2-Planet","/usr/bin/M2-Planet"); copy_file(STAGE0POSIX "AMD64/bin/mkdir","/usr/bin/mkdir"); copy_file(STAGE0POSIX "AMD64/bin/sha256sum","/usr/bin/sha256sum"); copy_file(STAGE0POSIX "AMD64/bin/unbz2","/usr/bin/unbz2"); copy_file(STAGE0POSIX "AMD64/bin/ungz","/usr/bin/ungz"); copy_file(STAGE0POSIX "AMD64/bin/untar","/usr/bin/untar"); copy_file(STAGE0POSIX "AMD64/bin/cp","/usr/bin/cp"); copy_file(STAGE0POSIX "AMD64/bin/replace","/usr/bin/replace"); copy_file(STAGE0POSIX "AMD64/bin/rm","/usr/bin/rm"); copy_file(STAGE0POSIX "x86/x86_defs.M1","/M2libc/x86/x86_defs.M1"); result = parse_kaem_file(file_of_filename(live_bootstrap), live_bootstrap_vars, cur_path, fout); fprintf(fout, "Result: %s\n", result ? "OK" : "FAIL"); fclose(fout); FILE *f_html = fopen("livebootstrap.html", "w"); if (f_html != 0) { write_html(f_html, subModules); fclose(f_html); } return 0; } void parse_c_file(const char *cur_path, File *file, const char **includes, Define *&defines, int nr_includes, Step *step, FILE *fout); 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; bool in_then = false; 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; } } } add_directory(cur_path); 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) in_then = true; else if ( strcmp(exp_command_line, "else") == 0 || strcmp(exp_command_line, "fi") == 0) in_then = false; 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 = find_exec_file(args[0]); if (exec_file == 0) 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) { MergeChild **ref_child; 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); ref_child = &file->mergeChildren; } else { usage->is_input(fout); *ref_child = new MergeChild(file); ref_child = &(*ref_child)->next; } } } 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++; if (*s == ' ') *s++ = '\0'; char *target = 0; if (*s != '\0') { // Skip checksum while (*s == ' ') s++; while (*s != '\0' && *s != ' ') s++; // See if target name is specified if (*s == ' ') { while (*s == ' ') s++; target = s; while (*s > ' ') s++; *s = '\0'; } } File *source_file = get_file(distfiles, target != 0 ? target : file_of_filename(line)); source_file->set_source(line); indent(fout); fprintf(fout, "URL for %s : %s\n", source_file->name, source_file->source->url); } fclose(f_source); } } char outputSHA256SUM[MAX_PATH_SIZE]; strcpy(outputSHA256SUM, args[1]); strcat(outputSHA256SUM, ".SHA256SUM"); (new Usage(get_file(cur_path, outputSHA256SUM), step))->is_output(fout); } } 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, 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) { for (int arg_nr = 1; arg_nr < nr_args; arg_nr++) { char dirname[MAX_PATH_SIZE]; combine_dir_fn(cur_path, args[arg_nr], dirname); add_directory(dirname); } } 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 (in_then) ; // ignore cp else if (nr_args != 3) fprintf(fout, "ERROR: cp requires two arguments"); else { File *source_file = get_file(cur_path, args[1]); (new Usage(source_file, step))->is_input(fout); char target[MAX_PATH_SIZE]; combine_dir_fn(cur_path, args[2], target); File *target_file = 0; if (target[strlen(target) - 1] == '/' || is_directory(target)) { 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])); target_file = get_file(target_fn); } else target_file = get_file(target); target_file->copy_from = source_file; (new Usage(target_file, 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 *s_input = 0; const char *includes[10]; int nr_includes = 0; bool o_flag = false; File *c_file = 0; Define *defines = 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) ; else if (strcmp(arg, "-S") == 0 && arg_nr + 1 < nr_args) ; else if (strcmp(arg, "-D") == 0 && arg_nr + 1 < nr_args) { arg = args[++arg_nr]; char *s = arg + 1; while (*s != '\0' && *s != '=') s++; if (*s == '=') { *s = '\0'; s++; } Define::addDefine(defines, arg, *s == '\0' ? 0 : s); } 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; c_file = get_file(cur_path, arg); (new Usage(c_file, step))->is_input(fout); } } else if (strcmp(arg, "-L") == 0 && arg_nr + 1 < nr_args) { arg_nr++; char libdir[MAX_PATH_SIZE]; combine_dir_fn(cur_path, args[arg_nr], libdir); strcat(libdir, "/"); int len = strlen(libdir); for (File *file = files; file != 0; file = file->next) if (strncmp(libdir, file->name, len) == 0 && strcmp(file_ext(file->name), "a") == 0) (new Usage(file, step))->is_input(fout); } else if (strcmp(arg, "-nostdlib") == 0) ; else if (strcmp(arg, "-o") == 0 && arg_nr + 1 < nr_args) { (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_output(fout); o_flag = true; } else if (strcmp(arg, "-l") == 0 && arg_nr + 1 < nr_args) arg_nr++; 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; } 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; c_file = get_file(cur_path, arg); } else if (strcmp(file_ext(arg), "s") == 0) { if (s_input != 0) fprintf(fout, "ERROR: more than one .s file\n"); else s_input = arg; } (new Usage(get_file(cur_path, arg), step))->is_input(fout); } } if (!string_input) { if (c_input == 0 && s_input == 0) fprintf(fout, "ERROR: No c and s input\n"); else if (!o_flag && strcmp(c_input + strlen(c_input) - 2, ".c") == 0) { c_input[strlen(c_input) - 1] = 'o'; (new Usage(get_file(cur_path, file_of_filename(c_input)), step))->is_output(fout); c_input[strlen(c_input) - 1] = 's'; (new Usage(get_file(cur_path, file_of_filename(c_input)), step))->is_output(fout); } if (scm_input == 0) fprintf(fout, "ERROR: No scm input\n"); if (c_file != 0) { if (!c_file->exists) fprintf(fout, "Warning: Cannot parse C file '%s'\n", c_file->name); else parse_c_file(cur_path, c_file, includes, defines, nr_includes, step, fout); } } } 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_output(fout); (new Usage(get_file(cur_path, args[arg_nr + 1]), step))->is_input(fout); } } else { char *c_input = 0; const char *includes[10]; int nr_includes = 0; bool o_flag = false; Define *defines = 0; Define::addDefine(defines, "__TINYC__", 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) || strncmp(arg, "-D", 2) == 0) { if (arg[2] == '\0') arg = args[++arg_nr]; else arg += 2; char *s = arg + 1; while (*s != '\0' && *s != '=') s++; if (*s == '=') { *s = '\0'; s++; } Define::addDefine(defines, arg, *s == '\0' ? 0 : s); } else if ((strcmp(arg, "-I") == 0 && arg_nr + 1 < nr_args) || strncmp(arg, "-I", 2) == 0) { if (arg[2] == '\0') arg = args[++arg_nr]; else arg += 2; includes[nr_includes++] = (arg[0] == '.' && arg[1] == '\0') ? "" : arg; } else if (strcmp(arg, "-L") == 0 && arg_nr + 1 < nr_args) { arg_nr++; } else if (strcmp(arg, "-o") == 0 && arg_nr + 1 < nr_args) { (new Usage(get_file(cur_path, args[++arg_nr]), step))->is_output(fout); o_flag = true; } 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); } } includes[nr_includes++] = "/usr/include"; if (c_input == 0) { fprintf(fout, "ERROR: No c input\n"); } else { File *c_file = get_file(cur_path, c_input); if (!o_flag) { c_input[strlen(c_input)-1] = 'o'; (new Usage(get_file(cur_path, file_of_filename(c_input)), step))->is_output(fout); } if (c_file != 0) { fprintf(fout, "PARSE: %s|\n", c_file->name); if (c_file->existing() != 0) parse_c_file(cur_path, c_file, includes, defines, nr_includes, step, fout); else if (c_file->mergeChildren != 0) { for (MergeChild *child = c_file->mergeChildren; child != 0; child = child->next) if (child->child->existing() != 0) { fprintf(fout, "PARSE %s|\n", child->child->name); parse_c_file(cur_path, child->child, includes, defines, nr_includes, step, fout); } else fprintf(fout, "File %s does not exist\n", child->child->name); } else { fprintf(fout, "Warning: Cannot parse C file '%s'\n", c_file->name); } } } } } else if (strcmp(exec_fn, "make") == 0) { File *make_file = 0; bool is_install = false; 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) { make_file = get_file(cur_path, args[++arg_nr]); } else { indent(fout); fprintf(fout, " make switch: %s\n", arg); if (strcmp(arg, "install") == 0) is_install = true; } } if (make_file == 0) { char makefile_fn[MAX_PATH_SIZE]; combine_dir_fn(cur_path, "Makefile", makefile_fn); make_file = find_file(makefile_fn); if (make_file == 0) { FILE *make_f = fopen(makefile_fn, "r"); if (make_f != 0) { fclose(make_f); make_file = get_file(makefile_fn); } else { combine_dir_fn(cur_path, "makefile", makefile_fn); make_file = find_file(makefile_fn); if (make_file == 0) { FILE *make_f = fopen(makefile_fn, "r"); if (make_f != 0) { fclose(make_f); make_file = get_file(makefile_fn); } } } } } if (make_file != 0) { (new Usage(make_file, step))->is_input(fout); while (make_file->copy_from != 0) make_file = make_file->copy_from; FILE *make_f = fopen(make_file->name, "r"); if (make_f == 0) fprintf(fout, "ERROR: Cannot open file %s\n", make_file->name); else { bool is_coreutils = strstr(make_file->name, "coreutils") != 0; char line[500]; while (fgets(line, 499, make_f)) { char *s = line; while (*s != '\0' && *s <= ' ') s++; if (strncmp(s, "all", 3) == 0) { s += 3; while (*s != '\0' && *s <= ' ') s++; if (*s == ':') { s++; for (;;) { while (*s != '\0' && *s <= ' ') s++; if (*s == '\0') break; char target_name[30]; int k = 0; while (*s > ' ') if (k < 29) target_name[k++] = *s++; target_name[k] = '\0'; if (strcmp(target_name, "$(BINARIES)") == 0) ; // skip else { char *t_name; if (strncmp(target_name, "$(SRC_DIR)", 10) == 0) { target_name[7] = 's'; target_name[8] = 'r'; target_name[9] = 'c'; t_name = target_name + 7; } else t_name = target_name; if (is_install) { (new Usage(get_file(cur_path, t_name), step))->is_input(fout); char output_target[MAX_PATH_SIZE]; sprintf(output_target, "/usr/bin%s", t_name + 3); (new Usage(get_file(output_target, false), step))->is_output(fout); } else (new Usage(get_file(cur_path, t_name), step))->is_output(fout); } } } } else if (is_coreutils && strncmp(line, "COREUTILS = ", 12) == 0) { s += 12; for (;;) { while (*s != '\0' && *s <= ' ') s++; if (*s == '\0') break; char target_name[30]; strcpy(target_name, "src/"); int k = 4; while (*s > ' ') if (k < 29) target_name[k++] = *s++; target_name[k] = '\0'; if (is_install) { (new Usage(get_file(cur_path, target_name), step))->is_input(fout); char output_target[MAX_PATH_SIZE]; sprintf(output_target, "/usr/bin%s", target_name + 3); (new Usage(get_file(output_target, false), step))->is_output(fout); } else (new Usage(get_file(cur_path, target_name), step))->is_output(fout); } } } fclose(make_f); } } 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 if (strcmp(exec_fn, "ln") == 0) { char *input_fn = 0; char *output_fn = 0; for (int arg_nr = 1; arg_nr < nr_args; arg_nr++) { char *arg = args[arg_nr]; if (strcmp(arg, "-s") == 0 && arg_nr + 1 < nr_args) ; else if (input_fn == 0) input_fn = arg; else output_fn = arg; } if (output_fn != 0) { (new Usage(get_file(cur_path, input_fn), step))->is_input(fout); (new Usage(get_file(cur_path, output_fn), step))->is_output(fout); } } else if (strcmp(exec_fn, "install") == 0) { char *input_fn = 0; char *out_dir = 0; for (int arg_nr = 1; arg_nr < nr_args; arg_nr++) { char *arg = args[arg_nr]; if (strcmp(arg, "-m") == 0 && arg_nr + 1 < nr_args) arg_nr++; else if (input_fn == 0) input_fn = arg; else out_dir = arg; } if (out_dir != 0) { char output_fn[MAX_PATH_SIZE]; sprintf(output_fn, "%s/%s", out_dir, file_of_filename(input_fn)); (new Usage(get_file(cur_path, input_fn), step))->is_input(fout); (new Usage(get_file(cur_path, output_fn), step))->is_output(fout); } } else if (strcmp(exec_fn, "tar") == 0) { if (nr_args < 3 || strcmp(args[1], "xf") != 0) fprintf(fout, "ERROR: Unknown tar options\n"); else { (new Usage(get_file(cur_path, args[2]), step))->is_input(fout); } } 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; } void path_of_filename(const char *full_fn, char *path) { strcpy(path, full_fn); char *last = path; for (char *s = path; *s != '\0'; s++) if (*s == '/') last = s; *last = '\0'; } 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; else if (*s == '/') ext = ""; return ext; } bool include_source = false; void output_file(FILE *f, const char *name, bool binary) { char filename[MAX_PATH_SIZE]; if (strncmp(name, "/sysa/", 6) == 0) strcpy(filename, "../git/live-bootstrap"); else filename[0] = '\0'; strcat(filename, name); FILE *fsource = fopen(filename, "r"); if (fsource != 0) { fprintf(f, "
");
        if (binary)
        {
            int i = 0;
            unsigned char ch = fgetc(fsource);
            while (!feof(fsource))
            {
                fprintf(f, " %02X", ch);
                if (++i % 10 == 0)
                    fprintf(f, "\n");
                ch = fgetc(fsource);
            }
        }
        else
        {
            char ch = fgetc(fsource);
            int col = 0;
            while (!feof(fsource))
            {
                col++;
                if (ch == '<')
                    fprintf(f, "<");
                else if (ch == '>')
                    fprintf(f, ">");
                else if (ch == '&')
                    fprintf(f, "&");
                else if ((unsigned char)ch == 160)
                    fprintf(f, " ");
                else if ((unsigned char)ch == 169)
                    fprintf(f, "©");
                else if ((unsigned char)ch == 194)
                    fprintf(f, "Â");
                else if ((unsigned char)ch == 195)
                    fprintf(f, "Ã");
                else if ((unsigned char)ch == 197)
                    fprintf(f, "Å");
                else if (ch < 0)
                    fprintf(f, "&#%d;", (unsigned char)ch);
                else if (ch == '\n' || ch == 12)
                {
                    fprintf(f, "\n");
                    col = 0;
                }
                else if (ch == '\t')
                {
                    fprintf(f, " ");
                    while (col % 4 > 0)
                    {
                        fprintf(f, " ");
                        col++;
                    }
                }
                else if (ch < ' ')
                    ; // skip control characters
                else
                    fprintf(f, "%c", ch);
                ch = fgetc(fsource);
            }
        }
        
        fprintf(f, "
"); fclose(fsource); } } void write_html_file(FILE *f, File *file, SubModule *submodules, bool binary) { fprintf(f, "

%s

\n\n", file->nr, file->name); if (file->source != 0) { fprintf(f, "Source: %s\n

\n", file->source->url, file->source->url); } else { bool git = false; for (SubModule *sm = submodules; sm != 0; sm = sm->next) { int len = strlen(sm->path); if (strncmp(file->name, sm->path, len) == 0) { char url[MAX_PATH_SIZE]; sprintf(url, sm->url, file->name + len); file->set_source(url); fprintf(f, "Source: %s\n

\n", file->source->nr, url); git = true; break; } } if (!git) fprintf(f, "(No source)\n\n"); } 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"); if (!file->exists) { int len = strlen(file->name); if (len > 7 && strcmp(file->name + len - 7, ".tar.gz") == 0) ; // skip else if (len > 8 && strcmp(file->name + len - 8, ".tar.bz2") == 0) ; // skip else fprintf(f, "NoInput\n"); } else if (include_source) { output_file(f, file->name, binary); } } void write_html(FILE *f, SubModule *submodules) { fprintf(f, "\nlive-bootstrap\n" "\n\n

live-bootstrap

" "\n" "This page is produced by the program keam_parser.cpp,\n" "which parser the contents of GitHub repositories\n" "oriansj/stage0 and\n" "fosslinux/live-bootstrap\n" "(the commit 5ea8dd3)\n" "in order to find all the dependencies and list relevant input sources.\n" "(This is still work in progress.)\n" "

\n" "The code displayed on this page is not copyrighted by me but by the owners of\n" "respective repositories.\n" "

\n"); 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, true); 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, true); 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, false); 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->produced_by != 0 ? 'S' : 'F', use->file->produced_by != 0 ? use->file->produced_by->nr : 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"); fprintf(f, "\n

Sources

\n\n"); for (Source *source = sources; source != 0; source = source->next) { fprintf(f, "\n

%s

\n\n", source->nr, source->url, source->url); if (source->files->next_source_file == 0) fprintf(f, "File: %s\n", source->files->nr, source->files->name); else { fprintf(f, "Files:
\n
    \n"); for (File *file = source->files; file != 0; file = file->next_source_file) fprintf(f, "
  • %s\n", file->nr, file->name); fprintf(f, "
\n"); } output_file(f, source->files->name, source->files->exec); } fprintf(f, "\n\n" "


\n" "
\n" "Home\n" "
\n" "\n"); } class LocalIncludeResolver : public AbstractIncludePathResolver { public: LocalIncludeResolver(const char *cur_path, char *c_file_path, const char **includes, int nr_includes, Define *&defines, Step *step, FILE *fout) : _cur_path(cur_path), _c_file_path(c_file_path), _nr_includes(nr_includes), _defines(defines), _step(step), _fout(fout) { for (int i = 0; i < _nr_includes; i++) { combine_dir_fn(_cur_path, includes[i], _includes[i]); int len = strlen(_includes[i]); if (len > 0 && _includes[i][len-1] == '/') _includes[i][len-1] = '\0'; fprintf(_fout, "Info: Include '%s'\n", _includes[i]); } } AbstractIterator *iteratorFor(const char *path, bool include_next, AbstractIterator *context) { char path2[MAX_PATH_SIZE]; strcpy(path2, path + 1); char include_fn[MAX_PATH_SIZE]; char mapped_fn[MAX_PATH_SIZE]; FILE *f = 0; File *file = 0; if ( (path[0] == '<' && path2[strlen(path2) - 1] == '>') || (path[0] == '"' && path2[strlen(path2) - 1] == '"')) { path2[strlen(path2) - 1] = '\0'; if (include_next) { int diff_len = strlen(context->filename) - strlen(path2); fprintf(stderr, "include_next %s %s\n", context->filename, path2); return new StringIterator("","unknown"); } if (path[0] == '"') { combine_dir_fn(_c_file_path, path2, include_fn); file = find_file(include_fn); if (file != 0) { while (file->copy_from) file = file->copy_from; map_filename(file->name, mapped_fn); fprintf(_fout, "Info '%s' '%s'\n", file->name, mapped_fn); f = fopen(mapped_fn, "r"); } else { map_filename(include_fn, mapped_fn); fprintf(_fout, "Info '%s' '%s'\n", include_fn, mapped_fn); f = fopen(mapped_fn, "r"); } } for (int i = 0; i < _nr_includes && (file == 0 && f == 0); i++) { combine_dir_fn(_includes[i], path2, include_fn); file = find_file(include_fn); if (file != 0) { while (file->copy_from) file = file->copy_from; map_filename(file->name, mapped_fn); fprintf(_fout, "Info %d '%s' '%s'\n", i, file->name, mapped_fn); f = fopen(mapped_fn, "r"); } else { map_filename(include_fn, mapped_fn); fprintf(_fout, "Info %d '%s' '%s'\n", i, include_fn, mapped_fn); f = fopen(mapped_fn, "r"); } } } if (file != 0 || f != 0) { while (f == 0 && file->copy_from != 0) { file = file->copy_from; fprintf(_fout, "Info: Try '%s'\n", file->name); map_filename(file->name, mapped_fn); f = fopen(mapped_fn, "r"); } if (f != 0) { fclose(f); if (file == 0) file = get_file(include_fn); if (_step->hasInputUseOf(file)) return new StringIterator("","unknown"); // Lets process include file once (new Usage(file, _step))->is_input(_fout); return new InlineIncludesIterator( new CommentStripIterator( new LineSpliceIterator( new TrigraphIterator( new FileIterator(mapped_fn)))), this, _defines); } else fprintf(_fout, "Info: %s.%ld Cannot parse include file %s\n", context->filename, context->line, path); } else fprintf(_fout, "Warning: %s.%ld Cannot parse include file %s\n", context->filename, context->line, path); return new StringIterator("","unknown"); } private: const char *_cur_path; const char *_c_file_path; char _includes[10][MAX_PATH_SIZE]; int _nr_includes; Define *&_defines; Step *_step; FILE *_fout; int _nested_level; struct { const char *file_name; int at; } _nested[100]; }; void parse_c_file(const char *cur_path, File *file, const char **includes, Define *&defines, int nr_includes, Step *step, FILE *fout) { char c_file_path[MAX_PATH_SIZE]; path_of_filename(file->name, c_file_path); if (!file->exists) { file = file->existing(); if (file == 0) { fprintf(fout, "ERROR: file does not exist\n"); return; } fprintf(fout, "Info: Copied from %s\n", file->name); } char mapped_fn[MAX_PATH_SIZE]; map_filename(file->name, mapped_fn); FileIterator *fileIterator = new FileIterator(mapped_fn); TrigraphIterator *trigraphIterator = new TrigraphIterator(fileIterator); LineSpliceIterator *lineSpliceIterator = new LineSpliceIterator(trigraphIterator); CommentStripIterator *commentStripIterator = new CommentStripIterator(lineSpliceIterator); LocalIncludeResolver includeResolver(cur_path, c_file_path, includes, nr_includes, defines, step, fout); InlineIncludesIterator inlineIncludesIterator(commentStripIterator, &includeResolver, defines); const char *prev_file = ""; while (inlineIncludesIterator.more) { inlineIncludesIterator.next(); } if (pp_out != 0) fclose(pp_out); }