static void init(void) { register Sfio_t** ss; register int c; ed.interactive = -1; ed.msg = sfstdout; ed.all = BLOCK_LINE; ed.page.size = BREAK_PAGE; ed.redisc.re_version = REG_VERSION; ed.redisc.re_errorf = errorf; ed.re.re_disc = &ed.redisc; ed.reflags = REG_DISCIPLINE|REG_DELIMITED; if (!conformance(0, 0)) ed.reflags |= REG_LENIENT; ed.verbose = 1; for (c = 0; c < elementsof(signals); c++) if (signal(signals[c], interrupt) == SIG_IGN) signal(signals[c], SIG_IGN); for (ss = (Sfio_t**)&ed.buffer; ss < (Sfio_t**)(((char*)&ed.buffer) + sizeof(ed.buffer)); ss++) { if (!(*ss = sfstropen())) error(ERROR_SYSTEM|3, "cannot initialize internal buffer"); sfputc(*ss, 0); sfstrseek(*ss, 0, SEEK_SET); } sfputr(ed.buffer.help, "?", 0); if (!(ed.zero = newof(NiL, Line_t, ed.all, 0))) error(ERROR_SYSTEM|3, "out of space [zero]"); }
static char* getrec(register Sfio_t* sp, register int delimiter, register int flags) { register int c; register char* glob; sfstrseek(sp, 0, SEEK_SET); glob = ed.global; while ((c = getchr()) != delimiter) { if (c == '\n') { ed.peekc = c; break; } if (c == EOF) { if (glob) ed.peekc = (flags & REC_LINE) ? 0 : c; else if (delimiter != '\n' || (flags & (REC_LINE|REC_SPLICE))) error(2, "unexpected EOF"); else if (flags & REC_TEXT) return 0; break; } if (c == '\\' && ((c = getchr()) != delimiter || (flags & REC_SPLICE) && c != '\n') && c && !(flags & REC_IGNORE)) sfputc(sp, '\\'); if (!c) error(1, "null character ignored"); else if (!(flags & REC_IGNORE)) sfputc(sp, c); } if (flags & REC_TERMINATE) sfputc(sp, c); if (!(glob = sfstruse(sp))) error(ERROR_SYSTEM|3, "out of space"); return glob; }
static int tempget(Sfio_t* sp) { if (sfstrtell(sp) > sfstrsize(sp) / 2) sfstrseek(sp, 0, SEEK_SET); return sfstrtell(sp); }
static ssize_t helpwrite(int fd, const void* buf, size_t len) { ssize_t n; NoP(fd); n = ed.help ? sfwrite(sfstderr, buf, len) : ed.verbose ? sfputr(ed.msg, "?", '\n') : 0; sfstrseek(ed.buffer.help, 0, SEEK_SET); sfwrite(ed.buffer.help, buf, len - 1); sfputc(ed.buffer.help, 0); return n; }
static void join(void) { register Line_t* a1; char* s; nonzero(); sfstrseek(ed.buffer.work, 0, SEEK_SET); for (a1 = ed.addr1; a1 <= ed.addr2;) sfputr(ed.buffer.work, lineget((a1++)->offset), -1); a1 = ed.dot = ed.addr1; if (!(s = sfstruse(ed.buffer.work))) error(ERROR_SYSTEM|3, "out of space"); replace(a1, s); if (a1 < ed.addr2) rdelete(a1 + 1, ed.addr2); }
static void exfile(void) { if (sfclose(ed.iop)) error(ERROR_SYSTEM|1, "io error"); ed.iop = 0; if (ed.verbose) { if (ed.help) { sfprintf(ed.msg, "\"%s\" %lu line%s, %lu character%s", error_info.file, ed.lines, plural(ed.lines), ed.bytes, plural(ed.bytes)); if (ed.warn_null) { sfprintf(ed.msg, ", %lu null%s", ed.warn_null, plural(ed.warn_null)); ed.warn_null = 0; } if (ed.warn_newline) { sfprintf(ed.msg, ", newline appended"); ed.warn_newline = 0; } sfputc(ed.msg, '\n'); } else sfprintf(ed.msg, "%d\n", ed.bytes); } if (ed.warn_null || ed.warn_newline) { char* sep = ""; sfstrseek(ed.buffer.line, 0, SEEK_SET); if (ed.warn_null) { sfprintf(ed.buffer.line, "%d null character%s ignored", ed.warn_null, plural(ed.warn_null)); ed.warn_null = 0; sep = ", "; } if (ed.warn_newline) { sfprintf(ed.buffer.line, "%snewline appended to last line", sep); ed.warn_newline = 0; } if (!(sep = sfstruse(ed.buffer.line))) error(ERROR_SYSTEM|3, "out of space"); error(1, "%s", sep); } error_info.file = 0; }
static int flush(Sfio_t* op) { register Col_t* col; register size_t n; if ((col = state.cols) && sfstrtell(col->sp)) { do { n = sfstrtell(col->sp); if (sfwrite(op, sfstrseek(col->sp, 0, SEEK_SET), n) != n || sfsync(op)) { error(ERROR_SYSTEM|2, "write error"); return -1; } } while (col = col->next); } state.cache = state.window; return 0; }
static void handle(void) { register int c; char* s; char* b; mode_t mask; if (ed.caught == SIGINT) { ed.caught = 0; ed.lastc = '\n'; sfputc(ed.msg, '\n'); error(2, "interrupt"); } for (c = 0; c < elementsof(signals); c++) signal(signals[c], SIG_IGN); if (ed.dol > ed.zero) { ed.addr1 = ed.zero + 1; ed.addr2 = ed.dol; mask = umask(S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); b = "ed.hup"; if (!(ed.iop = sfopen(NiL, b, "w")) && !ed.restricted && (s = getenv("HOME"))) { sfstrseek(ed.buffer.line, 0, SEEK_SET); sfprintf(ed.buffer.line, "%s/%s", s, b); if (!(b = sfstruse(ed.buffer.line))) error(ERROR_SYSTEM|3, "out of space"); ed.iop = sfopen(NiL, b, "w"); } umask(mask); if (!ed.iop) error(ERROR_SYSTEM|1, "%s: cannot save changes", b); else { error_info.file = b; putfile(); } } ed.modified = 0; quit(0); }
int pzheadwrite(Pz_t* pz, Sfio_t* op) { register size_t i; register size_t m; register size_t n; register char* s; if (pz->flags & PZ_HEAD) return 0; pz->oop = op; if (!(pz->flags & PZ_NOGZIP)) sfdcgzip(op, 0); if (pz->flags & PZ_NOPZIP) return 0; sfputc(op, PZ_MAGIC_1); sfputc(op, PZ_MAGIC_2); if (sfsync(op)) return -1; sfputc(op, pz->major = PZ_MAJOR); sfputc(op, pz->minor = PZ_MINOR); sfputu(op, pz->win); if (pz->disc->comment) { sfputc(op, PZ_HDR_comment); m = strlen(pz->disc->comment) + 1; sfputu(op, m); sfwrite(op, pz->disc->comment, m); } if (pz->det && (m = sfstrtell(pz->det))) { sfputc(op, PZ_HDR_options); if (!(s = sfstruse(pz->det))) { if (pz->disc->errorf) (*pz->disc->errorf)(pz, pz->disc, ERROR_SYSTEM|2, "out of space"); return -1; } m++; sfputu(op, m); sfwrite(op, s, m); } if (i = pz->prefix.count) { sfputc(op, PZ_HDR_prefix); if (pz->prefix.terminator >= 0) { m = 0; while (i-- > 0) { if (!(s = sfgetr(pz->io, pz->prefix.terminator, 0))) { if (pz->disc->errorf) (*pz->disc->errorf)(pz, pz->disc, 2, "%s: cannot read %I*u prefix record%s from data", pz->path, sizeof(pz->prefix.count), pz->prefix.count, pz->prefix.count == 1 ? "" : "s"); return -1; } m += n = sfvalue(pz->io); sfwrite(pz->tmp, s, n); } s = sfstrseek(pz->tmp, 0, SEEK_SET); } else { m = i; if (!(s = (char*)sfreserve(pz->io, m, 0))) { if (pz->disc->errorf) (*pz->disc->errorf)(pz, pz->disc, 2, "%s: cannot read %I*u prefix byte%s from data", pz->path, sizeof(pz->prefix.count), pz->prefix.count, pz->prefix.count == 1 ? "" : "s"); return -1; } } sfputu(op, m); sfwrite(op, s, m); } pz->flags |= PZ_HEAD; return pzpartwrite(pz, op); }
int main(int argc, char** argv) { char* s; NoP(argc); if (s = strrchr(*argv, '/')) s++; else s = *argv; ed.restricted = streq(s, "red"); error_info.id = s; error_info.write = helpwrite; init(); for (;;) { for (;;) { switch (optget(argv, usage)) { case 'O': ed.reflags |= REG_LENIENT; continue; case 'S': ed.reflags &= ~REG_LENIENT; continue; case 'h': ed.help = 1; continue; case 'o': ed.msg = sfstderr; sfstrseek(ed.buffer.file, 0, SEEK_SET); sfputr(ed.buffer.file, "/dev/stdout", 0); continue; case 'p': sfstrseek(ed.buffer.prompt, 0, SEEK_SET); sfputr(ed.buffer.prompt, opt_info.arg, 0); ed.prompt = 1; continue; case 'q': signal(SIGQUIT, SIG_DFL); ed.verbose = 1; continue; case 's': ed.verbose = 0; continue; case '?': ed.help++; error(ERROR_USAGE|4, "%s", opt_info.arg); ed.help--; break; case ':': ed.help++; error(2, "%s", opt_info.arg); ed.help--; continue; } break; } if (!*(argv += opt_info.index) || **argv != '-' || *(*argv + 1)) break; ed.verbose = 0; } if (*argv) { if (*(argv + 1)) error(ERROR_USAGE|4, "%s", optusage(NiL)); sfprintf(ed.buffer.global, "e %s", *argv); if (!(ed.global = sfstruse(ed.buffer.global))) error(ERROR_SYSTEM|3, "out of space"); } edit(); sfdcslow(sfstdin); setjmp(ed.again); commands(); quit(0); exit(0); }
static void commands(void) { register Line_t* a1; register int c; register int n; char* s; int lastsep; for (;;) { trap(); if (ed.print & (REG_SUB_LIST|REG_SUB_NUMBER|REG_SUB_PRINT)) { ed.addr1 = ed.addr2 = ed.dot; print(); } if (!ed.global) { ed.evented = 0; if (ed.prompt > 0) sfputr(ed.msg, sfstrbase(ed.buffer.prompt), -1); } if ((c = getchr()) == ',' || c == ';') { ed.given = 1; ed.addr1 = (lastsep = c) == ',' ? ed.zero + 1 : ed.dot; a1 = ed.dol; c = getchr(); } else { ed.addr1 = 0; ed.peekc = c; c = '\n'; for (;;) { lastsep = c; a1 = address(); c = getchr(); if (c != ',' && c != ';') break; if (lastsep == ',') error(2, "invalid address"); if (!a1) { a1 = ed.zero + 1; if (a1 > ed.dol) a1--; } ed.addr1 = a1; if (c == ';') ed.dot = a1; } if (lastsep != '\n' && !a1) a1 = ed.dol; } if (!(ed.addr2 = a1)) { ed.given = 0; ed.addr2 = ed.dot; } else ed.given = 1; if (!ed.addr1) ed.addr1 = ed.addr2; switch (c) { case 'a': add(0); continue; case 'c': nonzero(); newline(); rdelete(ed.addr1, ed.addr2); append(getline, ed.addr1 - 1, NiL); continue; case 'd': nonzero(); newline(); rdelete(ed.addr1, ed.addr2); continue; case 'E': ed.modified = 0; c = 'e'; /*FALLTHROUGH*/ case 'e': setnoaddr(); if (ed.verbose && ed.modified) { ed.modified = 0; error(2, "modified data not written"); } /*FALLTHROUGH*/ case 'r': filename(c); setwide(); squeeze(0); c = ed.zero != ed.dol; append(getfile, ed.addr2, NiL); ed.modified = c; exfile(); continue; case 'f': setnoaddr(); filename(c); putrec(sfstrbase(ed.buffer.file)); continue; case 'G': global(1, 1); continue; case 'g': global(1, 0); continue; case 'H': ed.help = !ed.help; /*FALLTHROUGH*/ case 'h': setnoaddr(); newline(); if (ed.help || c == 'h') sfputr(ed.msg, sfstrbase(ed.buffer.help), '\n'); continue; case 'i': add(-1); continue; case 'j': if (!ed.given) ed.addr2++; newline(); join(); continue; case 'k': nonzero(); if ((c = getchr()) == EOF || (c -= MARK_MIN) < 0 || c >= elementsof(ed.marks)) error(2, "invalid mark"); newline(); ed.addr2->offset |= LINE_MARKED; ed.marks[c] = ed.addr2->offset & ~LINE_GLOBAL; ed.marked = 1; continue; case 'm': move(0); continue; case 'n': ed.print |= REG_SUB_NUMBER; newline(); print(); continue; case '\n': if (!a1) { a1 = ed.dot + 1; ed.addr2 = a1; ed.addr1 = a1; } if (lastsep == ';') ed.addr1 = a1; print(); continue; case 'l': ed.print |= REG_SUB_LIST; /*FALLTHROUGH*/ case 'p': newline(); print(); continue; case 'P': setnoaddr(); s = getrec(ed.buffer.line, '\n', 0); if (*s || !(ed.prompt = -ed.prompt) && (s = "*")) { sfstrseek(ed.buffer.prompt, 0, SEEK_SET); sfputr(ed.buffer.prompt, s, 0); ed.prompt = 1; } continue; case 'Q': ed.modified = 0; /*FALLTHROUGH*/ case 'q': setnoaddr(); newline(); quit(0); continue; case 'S': setnoaddr(); newline(); s = strchr(usage, '\n') + 5; sfprintf(ed.msg, "file=\"%s\"%s%s%s prompt=\"%s\" tmp=%lu%s event=%lu version=\"%-.*s\"\n", sfstrbase(ed.buffer.file), ed.modified ? " modified" : "", ed.help ? " help" : "", ed.verbose ? " verbose" : "", sfstrbase(ed.buffer.prompt), ed.tmpoff, ed.tmpoff > BLOCK_TMP ? "[file]" : "", ed.event, strchr(s, '\n') - s, s); continue; case 's': nonzero(); substitute(ed.global != 0); continue; case 't': move(1); continue; case 'u': setnoaddr(); newline(); undo(); continue; case 'V': global(0, 1); continue; case 'v': global(0, 0); continue; case 'W': case 'w': setwide(); squeeze(ed.dol > ed.zero); if ((n = getchr()) != 'q' && n != 'Q') { ed.peekc = n; n = 0; } filename(c); if (ed.dol > ed.zero) putfile(); exfile(); if (n == 'Q' || ed.addr1 <= ed.zero + 1 && ed.addr2 == ed.dol) ed.modified = 0; if (n) quit(0); continue; case 'z': nonzero(); page(); continue; case '=': setwide(); squeeze(0); newline(); sfprintf(ed.msg, "%d\n", ed.addr2 - ed.zero); continue; case '!': if (ed.restricted) error(2, "%c: restricted command", c); shell(); continue; case '#': setnoaddr(); getrec(ed.buffer.line, '\n', REC_IGNORE); continue; case EOF: return; } error(2, "unknown command"); } }
static void filename(int c) { register char* p; register int sh = 0; ed.bytes = 0; ed.lines = 0; p = getrec(ed.buffer.line, '\n', REC_LINE); if (*p) { if (!isspace(*p)) error(2, "no space after command"); for (p++; isspace(*p); p++) ; if (!*p) error(2, "file name expected"); if (c != 'f') { if (*p == '!') { p++; sh = 1; } else if (*p == '\\' && *(p + 1) == '!') p++; } if (ed.restricted) { register char* s = p; if (sh) p--; else for (;;) { switch (*s++) { case 0: break; case '/': case '\n': case '\\': sh = 1; break; default: continue; } break; } if (sh) error(2, "%s: restricted file name", p); } if (!sh && (!*sfstrbase(ed.buffer.file) || c == 'e' || c == 'f')) { sfstrseek(ed.buffer.file, 0, SEEK_SET); sfputr(ed.buffer.file, p, 0); } if (c == 'f') return; } else if (c == 'f') return; else if (!*(p = sfstrbase(ed.buffer.file))) error(2, "file name expected"); if (c == 'e') { edit(); ed.addr2 = ed.zero; } if (sh) { if (!(ed.iop = sfpopen(NiL, p, (c == 'e' || c == 'r') ? "r" : "w"))) error(ERROR_SYSTEM|2, "%s: cannot execute shell command", p); p--; } else if (c == 'e' || c == 'r') { if (!(ed.iop = sfopen(NiL, p, "r"))) error(ERROR_SYSTEM|2, "%s: cannot read", p); } else if ((c != 'W' || !(ed.iop = sfopen(NiL, p, "a"))) && !(ed.iop = sfopen(NiL, p, "w"))) error(ERROR_SYSTEM|2, "%s: cannot write", p); error_info.file = p; }
static void shell(void) { register char* s; register char* f = 0; register int c; if (ed.given) squeeze(ed.dol > ed.zero); s = getrec(ed.buffer.line, '\n', 0); if (s[0] == '!' && !s[1]) { if (!*sfstrbase(ed.buffer.shell)) error(2, "no saved shell command"); f = sfstrbase(ed.buffer.file); } else if (!s[0]) error(2, "empty shell command"); else SWP(ed.buffer.shell, ed.buffer.line); s = sfstrbase(ed.buffer.shell); sfstrseek(ed.buffer.line, 0, SEEK_SET); sfputc(ed.buffer.line, '!'); while (c = *s++) { if (c == '\\') { if (*s != '%') sfputc(ed.buffer.line, c); sfputc(ed.buffer.line, *s++); } else if (c == '%') sfputr(ed.buffer.line, f = sfstrbase(ed.buffer.file), -1); else sfputc(ed.buffer.line, c); } if (ed.given) { if (!ed.tmpfile && !(ed.tmpfile = pathtemp(NiL, 0, NiL, error_info.id, NiL))) error(ERROR_SYSTEM|2, "cannot generate temp file name"); if (!(ed.iop = sfopen(NiL, ed.tmpfile, "w"))) error(ERROR_SYSTEM|2, "%s: cannot create temp file", ed.tmpfile); error_info.file = ed.tmpfile; if (ed.dol > ed.zero) putfile(); exfile(); ed.bytes = 0; ed.lines = 0; sfprintf(ed.buffer.line, " < %s", ed.tmpfile); if (!(s = sfstruse(ed.buffer.line))) error(ERROR_SYSTEM|3, "out of space"); if (!(ed.iop = sfpopen(NiL, s + 1, "r"))) error(ERROR_SYSTEM|2, "%s: cannot execute shell command", s); error_info.file = s; rdelete(ed.addr1, ed.addr2); append(getfile, ed.dot, NiL); exfile(); remove(ed.tmpfile); } else { if (!(s = sfstruse(ed.buffer.line))) error(ERROR_SYSTEM|3, "out of space"); s++; if (f) putrec(s); if (!(ed.iop = sfpopen(NiL, s, ""))) error(ERROR_SYSTEM|2, "%s: cannot execute shell command", s); if (sfclose(ed.iop)) { ed.iop = 0; error(ERROR_SYSTEM|2, "%s: shell command exit error", s); } if (ed.verbose) putrec("!"); } }
int main(int argc, char** argv) { register char* s; register Rule_t* r; register List_t* p; int i; int args; int trace; char* t; char* buf; char* tok; Var_t* v; Stat_t st; Stat_t ds; Sfio_t* tmp; /* * initialize dynamic globals */ version = strdup(fmtident(version)); setlocale(LC_ALL, ""); error_info.id = idname; error_info.version = version; error_info.exit = finish; error_info.auxilliary = intercept; if (pathcheck(PATHCHECK, error_info.id, NiL)) return 1; error(-99, "startup"); settypes("*?[]", C_MATCH); settypes("+-|=", C_OPTVAL); settypes(" \t\n", C_SEP); settype(0, C_SEP); settypes(" \t\v\n:+&=;\"\\", C_TERMINAL); settype(0, C_TERMINAL); settypes("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_", C_ID1|C_ID2|C_VARIABLE1|C_VARIABLE2); settypes(".", C_VARIABLE1|C_VARIABLE2); settypes("0123456789", C_ID2|C_VARIABLE2); /* * close garbage fd's -- we'll be tidy from this point on * 3 may be /dev/tty on some systems * 0..9 for user redirection in shell * 10..19 left open by bugs in some shells * error_info.fd interited from parent * any close-on-exec fd's must have been done on our behalf */ i = 3; if (isatty(i)) i++; for (; i < 20; i++) if (i != error_info.fd && !fcntl(i, F_GETFD, 0)) close(i); /* * allocate the very temporary buffer streams */ internal.met = sfstropen(); internal.nam = sfstropen(); internal.tmp = sfstropen(); internal.val = sfstropen(); internal.wrk = sfstropen(); tmp = sfstropen(); sfstrrsrv(tmp, 2 * MAXNAME); /* * initialize the code and hash tables */ initcode(); inithash(); /* * set the default state */ state.alias = 1; state.exec = 1; state.global = 1; state.init = 1; #if DEBUG state.intermediate = 1; #endif state.io[0] = sfstdin; state.io[1] = sfstdout; state.io[2] = sfstderr; state.jobs = 1; state.pid = getpid(); state.readstate = MAXVIEW; state.scan = 1; state.start = CURTIME; state.stateview = -1; state.tabstops = 8; state.targetview = -1; #if BINDINDEX state.view[0].path = makerule("."); #else state.view[0].path = "."; #endif state.view[0].pathlen = 1; state.writeobject = state.writestate = "-"; /* * pwd initialization * * for project management, if . is group|other writeable * then change umask() for similar write protections */ buf = sfstrbase(tmp); internal.pwd = (s = getcwd(buf, MAXNAME)) ? strdup(s) : strdup("."); internal.pwdlen = strlen(internal.pwd); if (stat(".", &st)) error(3, "cannot stat ."); if (S_ISDIR(st.st_mode) && (st.st_mode & (S_IWGRP|S_IWOTH))) umask(umask(0) & ~(st.st_mode & (S_IWGRP|S_IWOTH))); /* * set some variable default values */ hashclear(table.var, HASH_ALLOCATE); setvar(external.make, argv[0], V_import); t = "lib/make"; setvar(external.lib, strdup((s = pathpath(t, argv[0], PATH_EXECUTE, buf, SF_BUFSIZE)) ? s : t), V_import); setvar(external.pwd, internal.pwd, V_import); setvar(external.version, version, V_import); hashset(table.var, HASH_ALLOCATE); /* * read the environment */ readenv(); if (v = getvar(external.nproc)) state.jobs = (int)strtol(v->value, NiL, 0); if ((v = getvar(external.pwd)) && !streq(v->value, internal.pwd)) { if (!stat(v->value, &st) && !stat(internal.pwd, &ds) && st.st_ino == ds.st_ino && st.st_dev == ds.st_dev) { free(internal.pwd); internal.pwd = strdup(v->value); internal.pwdlen = strlen(v->value); } else { v->property &= ~V_import; v->property |= V_free; v->value = strdup(internal.pwd); } } /* * initialize the internal rule pointers */ initrule(); /* * read the static initialization script */ sfputr(tmp, initstatic, -1); parse(NiL, sfstruse(tmp), "initstatic", NiL); /* * check and read the args file */ if (s = colonlist(tmp, external.args, 1, ' ')) { i = fs3d(0); tok = tokopen(s, 1); while (s = tokread(tok)) if (vecargs(vecfile(s), &argc, &argv) >= 0) break; else if (errno != ENOENT) error(1, "cannot read args file %s", s); tokclose(tok); fs3d(i); } state.argf = newof(0, int, argc, 0); /* * set the command line options * read the command line assignments * mark the command line scripts and targets */ state.init = 0; state.readonly = 1; state.argv = argv; state.argc = argc; if ((args = scanargs(state.argc, state.argv, state.argf)) < 0) return 1; state.readonly = 0; state.init = 1; if (state.base) state.readstate = 0; if (state.compileonly) { state.forceread = 1; state.virtualdot = 0; } /* * tone down the bootstrap noise */ if ((trace = error_info.trace) == -1) error_info.trace = 0; /* * check explicit environment overrides */ if (s = colonlist(tmp, external.import, 1, ' ')) { tok = tokopen(s, 1); while (s = tokread(tok)) { if (i = *s == '!') s++; if (v = getvar(s)) { if (i) v->property &= ~V_import; else v->property |= V_readonly; } } tokclose(tok); } /* * set up the traps */ inittrap(); /* * announce the version */ if (error_info.trace < 0) { errno = 0; error(error_info.trace, "%s [%d %s]", version, state.pid, timestr(state.start)); } /* * initialize the views */ state.global = 0; state.user = 1; initview(); /* * check for mam */ if (state.mam.out) { if (!state.mam.statix || *state.mam.label) error_info.write = mamerror; if (state.mam.regress || state.regress) { sfprintf(state.mam.out, "%sinfo mam %s %05d\n", state.mam.label, state.mam.type, state.mam.parent); if (state.mam.regress) sfprintf(state.mam.out, "%sinfo start regression\n", state.mam.label); } else { sfprintf(state.mam.out, "%sinfo mam %s %05d 1994-07-17 %s\n", state.mam.label, state.mam.type, state.mam.parent, version); if (!state.mam.statix || *state.mam.label) { sfprintf(state.mam.out, "%sinfo start %lu\n", state.mam.label, CURTIME); if (!state.mam.root || streq(state.mam.root, internal.pwd)) sfprintf(state.mam.out, "%sinfo pwd %s\n", state.mam.label, internal.pwd); else sfprintf(state.mam.out, "%sinfo pwd %s %s\n", state.mam.label, state.mam.root, mamname(makerule(internal.pwd))); buf = sfstrbase(tmp); if (state.fsview && !mount(NiL, buf, FS3D_GET|FS3D_ALL|FS3D_SIZE(sfstrsize(tmp)), NiL)) sfprintf(state.mam.out, "%sinfo view %s\n", state.mam.label, buf); } } } /* * read the dynamic initialization script */ if ((i = error_info.trace) > -20) error_info.trace = 0; sfputr(tmp, initdynamic, -1); parse(NiL, sfstruse(tmp), "initdynamic", NiL); error_info.trace = i; state.user = 0; state.init = 0; /* * read the explicit makefiles * readfile() handles the base and global rules * * NOTE: internal.tmplist is used to handle the effects of * load() on internal list pointers */ compref(NiL, 0); if (p = internal.makefiles->prereqs) { p = internal.tmplist->prereqs = listcopy(p); for (; p; p = p->next) readfile(p->rule->name, COMP_FILE, NiL); freelist(internal.tmplist->prereqs); internal.tmplist->prereqs = 0; } /* * if no explicit makefiles then try external.{convert,files} */ if (!state.makefile) { int sep; Sfio_t* exp; Sfio_t* imp; exp = 0; imp = sfstropen(); sep = 0; s = 0; if (*(t = getval(external.convert, VAL_PRIMARY))) { sfputr(tmp, t, 0); sfstrrsrv(tmp, MAXNAME); tok = tokopen(sfstrbase(tmp), 0); while (s = tokread(tok)) { if (!exp) exp = sfstropen(); if (t = colonlist(exp, s, 0, ' ')) { t = tokopen(t, 0); while (s = tokread(t)) { if (readfile(s, COMP_INCLUDE|COMP_DONTCARE, NiL)) break; if (sep) sfputc(imp, ','); else sep = 1; sfputr(imp, s, -1); } tokclose(t); if (s) break; } if (!(s = tokread(tok))) break; } tokclose(tok); sfstrseek(tmp, 0, SEEK_SET); } if (!s && (s = colonlist(tmp, external.files, 1, ' '))) { tok = tokopen(s, 1); while (s = tokread(tok)) { if (readfile(s, COMP_INCLUDE|COMP_DONTCARE, NiL)) break; if (sep) sfputc(imp, ','); else sep = 1; sfputr(imp, s, -1); } tokclose(tok); } if (!s) { /* * this readfile() pulls in the default base rules * that might resolve any delayed self-documenting * options in optcheck() */ if (readfile("-", COMP_FILE, NiL)) optcheck(1); if (*(s = sfstruse(imp))) error(state.errorid ? 1 : 3, "a makefile must be specified when %s omitted", s); else error(state.errorid ? 1 : 3, "a makefile must be specified"); } sfstrclose(imp); if (exp) sfstrclose(exp); } /* * validate external command line options */ optcheck(1); /* * check for listing of variable and rule definitions */ if (state.list) { dump(sfstdout, 0); return 0; } /* * check if makefiles to be compiled */ if (state.compile && !state.virtualdot && state.writeobject) { /* * make the compinit trap */ if (r = getrule(external.compinit)) { state.reading = 1; maketop(r, P_dontcare|P_foreground, NiL); state.reading = 0; } if (state.exec && state.objectfile) { message((-2, "compiling makefile input into %s", state.objectfile)); compile(state.objectfile, NiL); } /* * make the compdone trap */ if (r = getrule(external.compdone)) { state.reading = 1; maketop(r, P_dontcare|P_foreground, NiL); state.reading = 0; } } /* * makefile read cleanup */ if (state.compileonly) return 0; compref(NiL, 0); sfstrclose(tmp); state.compile = COMPILED; if (state.believe) { if (!state.maxview) state.believe = 0; else if (state.fsview) error(3, "%s: option currently works in 2d only", optflag(OPT_believe)->name); } /* * read the state file */ readstate(); /* * place the command line targets in internal.args */ if (internal.main->dynamic & D_dynamic) dynamic(internal.main); internal.args->prereqs = p = 0; for (i = args; i < state.argc; i++) if (state.argf[i] & ARG_TARGET) { List_t* q; q = cons(makerule(state.argv[i]), NiL); if (p) p = p->next = q; else internal.args->prereqs = p = q; } /* * the engine bootstrap is complete -- start user activities */ state.user = 1; /* * make the makeinit trap */ if (r = getrule(external.makeinit)) maketop(r, P_dontcare|P_foreground, NiL); /* * read the command line scripts */ for (i = args; i < state.argc; i++) if (state.argf[i] & ARG_SCRIPT) { state.reading = 1; parse(NiL, state.argv[i], "command line script", NiL); state.reading = 0; } /* * freeze the parameter files and candidate state variables */ state.user = 2; candidates(); /* * make the init trap */ if (r = getrule(external.init)) maketop(r, P_dontcare|P_foreground, NiL); /* * internal.args default to internal.main */ if (!internal.args->prereqs && internal.main->prereqs) internal.args->prereqs = listcopy(internal.main->prereqs); /* * turn up the volume again */ if (!error_info.trace) error_info.trace = trace; /* * make the prerequisites of internal.args */ if (internal.args->prereqs) while (internal.args->prereqs) { /* * we explicitly allow internal.args modifications */ r = internal.args->prereqs->rule; internal.making->prereqs = internal.args->prereqs; internal.args->prereqs = internal.args->prereqs->next; internal.making->prereqs->next = 0; maketop(r, 0, NiL); } else if (state.makefile) error(3, "%s: a main target must be specified", state.makefile); /* * finish up */ finish(0); return 0; }
static void act(register Ftw_t* ftw, int op) { char* s; Sfio_t* fp; int i; int j; int k; int n; int r; switch (op) { case ACT_CMDARG: if ((i = cmdarg(state.cmd, ftw->path, ftw->pathlen)) >= state.errexit) exit(i); break; case ACT_CODE: if (findwrite(state.find, ftw->path, ftw->pathlen, (ftw->info & FTW_D) ? "system/dir" : (char*)0)) state.finderror = 1; break; case ACT_CODETYPE: fp = sfopen(NiL, PATH(ftw), "r"); if (findwrite(state.find, ftw->path, ftw->pathlen, magictype(state.magic, fp, PATH(ftw), &ftw->statb))) state.finderror = 1; if (fp) sfclose(fp); break; case ACT_EVAL: eval(state.action, ftw); break; case ACT_INTERMEDIATE: intermediate(ftw, ftw->path); break; case ACT_LIST: sfputr(sfstdout, ftw->path, '\n'); break; case ACT_SNAPSHOT: print(state.snapshot.tmp, ftw, state.snapshot.format.path); sfputc(state.snapshot.tmp, state.snapshot.format.delim); i = sfstrtell(state.snapshot.tmp); print(state.snapshot.tmp, ftw, state.snapshot.format.easy); j = sfstrtell(state.snapshot.tmp); s = sfstrbase(state.snapshot.tmp); r = SNAPSHOT_new; if (!state.snapshot.prev) k = 1; else { do { if (!(k = urlcmp(state.snapshot.prev, s, state.snapshot.format.delim))) { r = SNAPSHOT_changed; if (!(k = memcmp(state.snapshot.prev + i, s + i, j - i) || state.snapshot.prev[j] != state.snapshot.format.delim)) { if ((n = (int)sfvalue(sfstdin)) > 4 && state.snapshot.prev[n-2] == state.snapshot.format.delim) { sfwrite(sfstdout, state.snapshot.prev, n - 4); sfputc(sfstdout, '\n'); } else sfwrite(sfstdout, state.snapshot.prev, n); } } else if (k > 0) break; else if (k < 0 && (n = (int)sfvalue(sfstdin)) > 4 && (state.snapshot.prev[n-2] != state.snapshot.format.delim || state.snapshot.prev[n-3] != SNAPSHOT_deleted)) { sfwrite(sfstdout, state.snapshot.prev, n - (state.snapshot.prev[n-2] == state.snapshot.format.delim ? 4 : 1)); sfputc(sfstdout, state.snapshot.format.delim); sfputc(sfstdout, SNAPSHOT_deleted); sfputc(sfstdout, state.snapshot.format.delim); sfputc(sfstdout, '\n'); if (state.cmdflags & CMD_TRACE) error(1, "%s deleted", ftw->path); } if (!(state.snapshot.prev = sfgetr(sfstdin, '\n', 0))) break; } while (k < 0); } if (k) { if (state.snapshot.format.hard && (ftw->info & FTW_F)) { sfputc(state.snapshot.tmp, state.snapshot.format.delim); print(state.snapshot.tmp, ftw, state.snapshot.format.hard); } sfputc(state.snapshot.tmp, state.snapshot.format.delim); sfputc(state.snapshot.tmp, r); sfputc(state.snapshot.tmp, state.snapshot.format.delim); sfputr(sfstdout, sfstruse(state.snapshot.tmp), '\n'); if (state.cmdflags & CMD_TRACE) error(1, "%s %s", ftw->path, r == SNAPSHOT_new ? "new" : "changed"); } else sfstrseek(state.snapshot.tmp, SEEK_SET, 0); break; } }
static void execute(register Joblist_t* job) { register List_t* p; char* s; char* t; int flags; Rule_t* r; Var_t* v; Sfio_t* tmp; Sfio_t* att; Sfio_t* sp; att = sfstropen(); tmp = sfstropen(); restore(job, tmp, att); job->status = RUNNING; job->target->mark &= ~M_waiting; if (state.targetcontext || state.maxview && !state.fsview && *job->target->name != '/' && (!(job->target->dynamic & D_regular) || job->target->view)) commit(job, job->target->name); if ((state.mam.dynamic || state.mam.regress) && state.user && !(job->target->property & (P_after|P_before|P_dontcare|P_make|P_state|P_virtual))) sfprintf(state.mam.out, "%sinit %s %s\n", state.mam.label, mamname(job->target), timefmt(NiL, CURTIME)); t = sfstruse(tmp); if (!(job->flags & CO_ALWAYS)) { if (state.touch) { if (state.virtualdot) { state.virtualdot = 0; lockstate(1); } if (!(job->target->property & (P_attribute|P_virtual))) { acceptrule(job->target); if ((job->target->property & (P_joint|P_target)) == (P_joint|P_target)) for (p = job->target->prereqs->rule->prereqs; p; p = p->next) if (p->rule != job->target) acceptrule(p->rule); } } else if (*t && (!state.silent || state.mam.regress)) dumpaction(state.mam.out ? state.mam.out : sfstdout, NiL, t, NiL); done(job, 0, NiL); } else { if (state.virtualdot && !notfile(job->target)) { state.virtualdot = 0; lockstate(1); } if (!state.coshell) { sp = sfstropen(); sfprintf(sp, "label=%s", idname); expand(sp, " $(" CO_ENV_OPTIONS ")"); flags = CO_ANY; if (state.cross) flags |= CO_CROSS; if (state.serialize && state.jobs > 1) flags |= CO_SERIALIZE; if (!(state.coshell = coopen(getval(CO_ENV_SHELL, VAL_PRIMARY), flags, sfstruse(sp)))) error(ERROR_SYSTEM|3, "coshell open error"); sfstrclose(sp); } if (p = internal.exports->prereqs) { Sfio_t* exp; exp = sfstropen(); do { if (v = getvar(p->rule->name)) { expand(exp, v->value); coexport(state.coshell, p->rule->name, sfstruse(exp)); } else if (s = strchr(p->rule->name, '=')) { *s = 0; expand(exp, s + 1); coexport(state.coshell, p->rule->name, sfstruse(exp)); *s = '='; } } while (p = p->next); sfstrclose(exp); #if 0 freelist(internal.exports->prereqs); #endif internal.exports->prereqs = 0; } if (job->flags & CO_DATAFILE) { static char* dot; static char* tmp; if (job->target->property & P_read) { if (!dot) dot = pathtemp(NiL, 0, null, idname, NiL); state.tmpfile = dot; } else { if (!tmp) tmp = pathtemp(NiL, 0, NiL, idname, NiL); state.tmpfile = tmp; } } #if !_HUH_1992_02_29 /* i386 and ftx m68k dump without this statement -- help */ message((-99, "execute: %s: t=0x%08x &t=0x%08x", job->target->name, t, &t)); #endif if (state.mam.out) dumpaction(state.mam.out, MAMNAME(job->target), t, NiL); if (r = getrule(external.makerun)) maketop(r, P_dontcare|P_foreground, NiL); if (!(job->cojob = coexec(state.coshell, t, job->flags, state.tmpfile, NiL, sfstruse(att)))) error(3, "%s: cannot send action to coshell", job->target->name); job->cojob->local = (void*)job; /* * grab semaphores */ if (job->target->dynamic & D_hassemaphore) { job->flags |= CO_SEMAPHORES; for (p = job->prereqs; p; p = p->next) if (p->rule->semaphore && --p->rule->semaphore == 1) p->rule->status = MAKING; } /* * check status and sync */ if (job->target->dynamic & D_hasafter) save(job); if (job->flags & (CO_DATAFILE|CO_FOREGROUND)) { complete(job->target, NiL, NiL, 0); if (job->target->property & (P_functional|P_read)) { if (sp = sfopen(NiL, state.tmpfile, "r")) { remove(state.tmpfile); if (job->target->property & P_read) parse(sp, NiL, job->target->name, NiL); else { char* e; sfmove(sp, tmp, SF_UNBOUND, -1); t = sfstrbase(tmp); e = sfstrseek(tmp, 0, SEEK_CUR); while (e > t && *(e - 1) == '\n') e--; sfstrseek(tmp, e - t, SEEK_SET); setvar(job->target->name, sfstruse(tmp), 0); } sfclose(sp); } else error(2, "%s: cannot read temporary data output file %s", job->target->name, state.tmpfile); state.tmpfile = 0; } } } sfstrclose(att); sfstrclose(tmp); }