/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2020 Justine Alexandra Roberts Tunney │ │ │ │ This program is free software; you can redistribute it and/or modify │ │ it under the terms of the GNU General Public License as published by │ │ the Free Software Foundation; version 2 of the License. │ │ │ │ This program is distributed in the hope that it will be useful, but │ │ WITHOUT ANY WARRANTY; without even the implied warranty of │ │ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ │ General Public License for more details. │ │ │ │ You should have received a copy of the GNU General Public License │ │ along with this program; if not, write to the Free Software │ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "ape/relocations.h" #include "libc/alg/arraylist2.internal.h" #include "libc/calls/calls.h" #include "libc/calls/struct/stat.h" #include "libc/conv/itoa.h" #include "libc/log/check.h" #include "libc/log/log.h" #include "libc/mem/mem.h" #include "libc/runtime/runtime.h" #include "libc/str/str.h" #include "libc/sysv/consts/map.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/prot.h" #define LOOKINGAT(p, pe, s) LookingAt(p, pe, s, strlen(s)) #define APPENDSTR(s) AppendData(s, strlen(s)) struct Output { size_t i, n; const char *p; }; struct Visited { size_t i, n; const char **p; }; static struct stat st; static struct Output output; static struct Visited visited; static void Visit(const char *); static bool HasVisited(const char *path) { int i; for (i = 0; i < visited.i; ++i) { if (strcmp(path, visited.p[i]) == 0) { return true; } } return false; } static void AppendData(const char *s, size_t n) { CONCAT(&output.p, &output.i, &output.n, s, n); } static void AppendInt(long x) { char ibuf[21]; AppendData(ibuf, int64toarray_radix10(x, ibuf)); } static bool LookingAt(const char *p, const char *pe, const char *s, size_t n) { return pe - p >= n && memcmp(p, s, n) == 0; } static void Process(const char *p, const char *pe, const char *path, bool isheader) { int level; bool noformat; const char *p2, *dq, *name; for (noformat = level = 0; p < pe; p = p2) { p2 = memchr(p, '\n', pe - p); p2 = p2 ? p2 + 1 : pe; if (LOOKINGAT(p, pe, "#if")) { if (isheader && !level++) continue; } if (LOOKINGAT(p, pe, "#endif")) { if (isheader && !--level) continue; } if (LOOKINGAT(p, pe, "/* clang-format off */")) { noformat = true; } else if (LOOKINGAT(p, pe, "/* clang-format on */")) { noformat = false; } if (LOOKINGAT(p, pe, "#include \"")) { name = p + strlen("#include \""); dq = memchr(name, '"', pe - name); if (dq) { Visit(strndup(name, dq - name)); continue; } } AppendData(p, p2 - p); } if (noformat) { APPENDSTR("/* clang-format on */\n"); } } static void Visit(const char *path) { int fd; char *map; bool isheader; if (!endswith(path, ".h") && !endswith(path, ".inc")) return; if (endswith(path, ".internal.h")) return; if (endswith(path, "/internal.h")) return; if (endswith(path, ".internal.inc")) return; if (endswith(path, "/internal.inc")) return; isheader = endswith(path, ".h"); if (isheader && HasVisited(path)) return; APPENDSTR("\n\f\n/*!BEGIN "); APPENDSTR(path); APPENDSTR(" */\n\n"); APPEND(&visited.p, &visited.i, &visited.n, &path); CHECK_NE(-1, (fd = open(path, O_RDONLY))); CHECK_NE(-1, fstat(fd, &st)); if (st.st_size) { CHECK_NE(MAP_FAILED, (map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0))); Process(map, map + st.st_size, path, isheader); LOGIFNEG1(munmap(map, st.st_size)); } LOGIFNEG1(close(fd)); } int main(int argc, char *argv[]) { int i; APPENDSTR("#ifndef COSMOPOLITAN_H_\n"); APPENDSTR("#define COSMOPOLITAN_H_\n"); APPENDSTR("#define IMAGE_BASE_VIRTUAL "); AppendInt(IMAGE_BASE_VIRTUAL); APPENDSTR("\n"); APPENDSTR("#define IMAGE_BASE_PHYSICAL "); AppendInt(IMAGE_BASE_PHYSICAL); APPENDSTR("\n"); for (i = 1; i < argc; ++i) { Visit(argv[i]); } APPENDSTR("\n"); APPENDSTR("#endif /* COSMOPOLITAN_H_ */\n"); CHECK_EQ(output.i, write(1, output.p, output.i)); return 0; }