/* * rules are of the form: * <reg exp> <String> <repl exp> [<repl exp>] */ extern int getrules(void) { Biobuf *rfp; String *line; String *type; String *file; file = abspath("rewrite", UPASLIB, (String *)0); rfp = sysopen(s_to_c(file), "r", 0); if(rfp == 0) { rulep = 0; return -1; } rlastp = 0; line = s_new(); type = s_new(); while(s_getline(rfp, s_restart(line))) if(getrule(line, type, thissys) && altthissys) getrule(s_restart(line), type, altthissys); s_free(type); s_free(line); s_free(file); sysclose(rfp); return 0; }
static void pop(Joblist_t* job) { register Context_t* z; register Frame_t* p; register Rule_t* r; int n; Time_t tm; if (z = job->context) { n = state.targetview; state.targetview = z->targetview; z->targetview = n; p = state.frame; state.frame = z->frame; z->frame = p; for (;;) { if (!(r = getrule(p->context.name))) r = makerule(p->context.name); r->active = p->context.frame; tm = r->time; r->time = p->context.time; p->context.time = tm; if (p == p->parent) break; p = p->parent; } } job->status &= ~PUSHED; }
static void ralloc(Node p) { int i; unsigned mask[2]; mask[0] = tmask[0]; mask[1] = tmask[1]; assert(p); debug(fprint(stderr, "(rallocing %x)\n", p)); for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) { Node kid = p->x.kids[i]; Symbol r = kid->syms[RX]; assert(r && kid->x.registered); if (r->sclass != REGISTER && r->x.lastuse == kid) putreg(r); } if (!p->x.registered && NeedsReg[opindex(p->op)] && (*IR->x.rmap)(opkind(p->op))) { Symbol sym = p->syms[RX], set = sym; assert(sym); if (sym->temporary) set = (*IR->x.rmap)(opkind(p->op)); assert(set); if (set->sclass != REGISTER) { Symbol r; if (*IR->x._templates[getrule(p, p->x.inst)] == '?') for (i = 1; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) { Symbol r = p->x.kids[i]->syms[RX]; assert(p->x.kids[i]->x.registered); assert(r && r->x.regnode); assert(sym->x.wildcard || sym != r); mask[r->x.regnode->set] &= ~r->x.regnode->mask; } r = getreg(set, mask, p); if (sym->temporary) { Node q; r->x.lastuse = sym->x.lastuse; for (q = sym->x.lastuse; q; q = q->x.prevuse) { q->syms[RX] = r; q->x.registered = 1; if (sym->u.t.cse && q->x.copy) q->x.equatable = 1; } } else { p->syms[RX] = r; r->x.lastuse = p; } debug(dumpregs("(allocating %s to node %x)\n", r->x.name, (char *) p)); } } p->x.registered = 1; (*IR->x.clobber)(p); }
static void dumpcover(Node p, int nt, int in) { int rulenum, i; short *nts; Node kids[10]; p = reuse(p, nt); rulenum = getrule(p, nt); nts = IR->x._nts[rulenum]; fprint(stderr, "dumpcover(%x) = ", p); for (i = 0; i < in; i++) fprint(stderr, " "); dumprule(rulenum); (*IR->x._kids)(p, rulenum, kids); for (i = 0; nts[i]; i++) dumpcover(kids[i], nts[i], in+1); }
static void reduce(Node p, int nt) { int rulenum, i; short *nts; Node kids[10]; p = reuse(p, nt); rulenum = getrule(p, nt); nts = IR->x._nts[rulenum]; (*IR->x._kids)(p, rulenum, kids); for (i = 0; nts[i]; i++) reduce(kids[i], nts[i]); if (IR->x._isinstruction[rulenum]) { assert(p->x.inst == 0 || p->x.inst == nt); p->x.inst = nt; if (p->syms[RX] && p->syms[RX]->temporary) { debug(fprint(stderr, "(using %s)\n", p->syms[RX]->name)); p->syms[RX]->x.usecount++; } } }
static unsigned emitasm(Node p, int nt) { int rulenum; short *nts; char *fmt; Node kids[10]; p = reuse(p, nt); rulenum = getrule(p, nt); nts = IR->x._nts[rulenum]; fmt = IR->x._templates[rulenum]; assert(fmt); if (IR->x._isinstruction[rulenum] && p->x.emitted) print("%s", p->syms[RX]->x.name); else if (*fmt == '#') (*IR->x.emit2)(p); else { if (*fmt == '?') { fmt++; assert(p->kids[0]); if (p->syms[RX] == p->x.kids[0]->syms[RX]) while (*fmt++ != '\n') ; } for ((*IR->x._kids)(p, rulenum, kids); *fmt; fmt++) if (*fmt != '%') (void)putchar(*fmt); else if (*++fmt == 'F') print("%d", framesize); else if (*fmt >= '0' && *fmt <= '9') emitasm(kids[*fmt - '0'], nts[*fmt - '0']); else if (*fmt >= 'a' && *fmt < 'a' + NELEMS(p->syms)) fputs(p->syms[*fmt - 'a']->x.name, stdout); else (void)putchar(*fmt); } return 0; }
int tzparse(const char *name, struct state * sp, int lastditch) { const char *stdname; const char *dstname = NULL; size_t stdlen; size_t dstlen; long stdoffset; long dstoffset; pg_time_t *atp; unsigned char *typep; char *cp; int load_result; stdname = name; if (lastditch) { stdlen = strlen(name); /* length of standard zone name */ name += stdlen; if (stdlen >= sizeof sp->chars) stdlen = (sizeof sp->chars) - 1; stdoffset = 0; /* * Unlike the original zic library, do NOT invoke tzload() here; we * can't assume pg_open_tzfile() is sane yet, and we don't care about * leap seconds anyway. */ load_result = -1; } else { if (*name == '<') { name++; stdname = name; name = getqzname(name, '>'); if (*name != '>') return (-1); stdlen = name - stdname; name++; } else { name = getzname(name); stdlen = name - stdname; } if (*name == '\0') return -1; name = getoffset(name, &stdoffset); if (name == NULL) return -1; load_result = tzload(TZDEFRULES, NULL, sp, FALSE); } if (load_result != 0) sp->leapcnt = 0; /* so, we're off a little */ if (*name != '\0') { if (*name == '<') { dstname = ++name; name = getqzname(name, '>'); if (*name != '>') return -1; dstlen = name - dstname; name++; } else { dstname = name; name = getzname(name); dstlen = name - dstname; /* length of DST zone name */ } if (*name != '\0' && *name != ',' && *name != ';') { name = getoffset(name, &dstoffset); if (name == NULL) return -1; } else dstoffset = stdoffset - SECSPERHOUR; if (*name == '\0' && load_result != 0) name = TZDEFRULESTRING; if (*name == ',' || *name == ';') { struct rule start; struct rule end; int year; pg_time_t janfirst; pg_time_t starttime; pg_time_t endtime; ++name; if ((name = getrule(name, &start)) == NULL) return -1; if (*name++ != ',') return -1; if ((name = getrule(name, &end)) == NULL) return -1; if (*name != '\0') return -1; sp->typecnt = 2; /* standard time and DST */ /* * Two transitions per year, from EPOCH_YEAR forward. */ sp->ttis[0].tt_gmtoff = -dstoffset; sp->ttis[0].tt_isdst = 1; sp->ttis[0].tt_abbrind = stdlen + 1; sp->ttis[1].tt_gmtoff = -stdoffset; sp->ttis[1].tt_isdst = 0; sp->ttis[1].tt_abbrind = 0; atp = sp->ats; typep = sp->types; janfirst = 0; sp->timecnt = 0; for (year = EPOCH_YEAR; sp->timecnt + 2 <= TZ_MAX_TIMES; ++year) { pg_time_t newfirst; starttime = transtime(janfirst, year, &start, stdoffset); endtime = transtime(janfirst, year, &end, dstoffset); if (starttime > endtime) { *atp++ = endtime; *typep++ = 1; /* DST ends */ *atp++ = starttime; *typep++ = 0; /* DST begins */ } else { *atp++ = starttime; *typep++ = 0; /* DST begins */ *atp++ = endtime; *typep++ = 1; /* DST ends */ } sp->timecnt += 2; newfirst = janfirst; newfirst += year_lengths[isleap(year)] * SECSPERDAY; if (newfirst <= janfirst) break; janfirst = newfirst; } } else { long theirstdoffset; long theirdstoffset; long theiroffset; int isdst; int i; int j; if (*name != '\0') return -1; /* * Initial values of theirstdoffset and theirdstoffset. */ theirstdoffset = 0; for (i = 0; i < sp->timecnt; ++i) { j = sp->types[i]; if (!sp->ttis[j].tt_isdst) { theirstdoffset = -sp->ttis[j].tt_gmtoff; break; } } theirdstoffset = 0; for (i = 0; i < sp->timecnt; ++i) { j = sp->types[i]; if (sp->ttis[j].tt_isdst) { theirdstoffset = -sp->ttis[j].tt_gmtoff; break; } } /* * Initially we're assumed to be in standard time. */ isdst = FALSE; theiroffset = theirstdoffset; /* * Now juggle transition times and types tracking offsets as you * do. */ for (i = 0; i < sp->timecnt; ++i) { j = sp->types[i]; sp->types[i] = sp->ttis[j].tt_isdst; if (sp->ttis[j].tt_ttisgmt) { /* No adjustment to transition time */ } else { /* * If summer time is in effect, and the transition time * was not specified as standard time, add the summer time * offset to the transition time; otherwise, add the * standard time offset to the transition time. */ /* * Transitions from DST to DDST will effectively disappear * since POSIX provides for only one DST offset. */ if (isdst && !sp->ttis[j].tt_ttisstd) { sp->ats[i] += dstoffset - theirdstoffset; } else { sp->ats[i] += stdoffset - theirstdoffset; } } theiroffset = -sp->ttis[j].tt_gmtoff; if (sp->ttis[j].tt_isdst) theirdstoffset = theiroffset; else theirstdoffset = theiroffset; } /* * Finally, fill in ttis. ttisstd and ttisgmt need not be handled. */ sp->ttis[0].tt_gmtoff = -stdoffset; sp->ttis[0].tt_isdst = FALSE; sp->ttis[0].tt_abbrind = 0; sp->ttis[1].tt_gmtoff = -dstoffset; sp->ttis[1].tt_isdst = TRUE; sp->ttis[1].tt_abbrind = stdlen + 1; sp->typecnt = 2; } } else { dstlen = 0; sp->typecnt = 1; /* only standard time */ sp->timecnt = 0; sp->ttis[0].tt_gmtoff = -stdoffset; sp->ttis[0].tt_isdst = 0; sp->ttis[0].tt_abbrind = 0; } sp->charcnt = stdlen + 1; if (dstlen != 0) sp->charcnt += dstlen + 1; if ((size_t) sp->charcnt > sizeof sp->chars) return -1; cp = sp->chars; (void) strncpy(cp, stdname, stdlen); cp += stdlen; *cp++ = '\0'; if (dstlen != 0) { (void) strncpy(cp, dstname, dstlen); *(cp + dstlen) = '\0'; } return 0; }
static int tzparse(const char *name, register struct state *const sp, const int lastditch) { const char *stdname; const char *dstname; size_t stdlen; size_t dstlen; long stdoffset; long dstoffset; register time_t *atp; register unsigned char *typep; register char *cp; INITIALIZE(dstname); stdname = name; if (lastditch) { stdlen = strlen(name); /* length of standard zone name */ name += stdlen; if (stdlen >= sizeof sp->chars) stdlen = (sizeof sp->chars) - 1; stdoffset = 0; } else { name = getzname(name); stdlen = name - stdname; if (stdlen < 3) return -1; if (*name == '\0') return -1; name = getoffset(name, &stdoffset); if (name == NULL) return -1; } sp->leapcnt = 0; /* so, we're off a little */ if (*name != '\0') { dstname = name; name = getzname(name); dstlen = name - dstname; /* length of DST zone name */ if (dstlen < 3) return -1; if (*name != '\0' && *name != ',' && *name != ';') { name = getoffset(name, &dstoffset); if (name == NULL) return -1; } else dstoffset = stdoffset - SECSPERHOUR; /* Go parsing the daylight saving stuff */ if (*name == ',' || *name == ';') { struct rule start; struct rule end; register int year; register time_t janfirst; time_t starttime; time_t endtime; ++name; if ((name = getrule(name, &start)) == NULL) return -1; if (*name++ != ',') return -1; if ((name = getrule(name, &end)) == NULL) return -1; if (*name != '\0') return -1; sp->typecnt = 2; /* standard time and DST */ /* ** Two transitions per year, from EPOCH_YEAR to 2037. */ sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1); if (sp->timecnt > TZ_MAX_TIMES) return -1; sp->ttis[0].tt_gmtoff = -dstoffset; sp->ttis[0].tt_isdst = 1; sp->ttis[0].tt_abbrind = (int) (stdlen + 1); sp->ttis[1].tt_gmtoff = -stdoffset; sp->ttis[1].tt_isdst = 0; sp->ttis[1].tt_abbrind = 0; atp = sp->ats; typep = sp->types; janfirst = 0; for (year = EPOCH_YEAR; year <= 2037; ++year) { starttime = transtime(janfirst, year, &start, stdoffset); endtime = transtime(janfirst, year, &end, dstoffset); if (starttime > endtime) { *atp++ = endtime; *typep++ = 1; /* DST ends */ *atp++ = starttime; *typep++ = 0; /* DST begins */ } else { *atp++ = starttime; *typep++ = 0; /* DST begins */ *atp++ = endtime; *typep++ = 1; /* DST ends */ } janfirst += year_lengths[isleap(year)] * SECSPERDAY; } } else { register long theirstdoffset; register long theirdstoffset; register long theiroffset; register int isdst; register int i; register int j; if (*name != '\0') return -1; /* Initial values of theirstdoffset and theirdstoffset. */ theirstdoffset = 0; for (i = 0; i < sp->timecnt; ++i) { j = sp->types[i]; if (!sp->ttis[j].tt_isdst) { theirstdoffset = -sp->ttis[j].tt_gmtoff; break; } } theirdstoffset = 0; for (i = 0; i < sp->timecnt; ++i) { j = sp->types[i]; if (sp->ttis[j].tt_isdst) { theirdstoffset = -sp->ttis[j].tt_gmtoff; break; } } /* ** Initially we're assumed to be in standard time. */ isdst = FALSE; theiroffset = theirstdoffset; /* ** Now juggle transition times and types ** tracking offsets as you do. */ for (i = 0; i < sp->timecnt; ++i) { j = sp->types[i]; sp->types[i] = (unsigned char) sp->ttis[j].tt_isdst; if (sp->ttis[j].tt_ttisgmt) { /* No adjustment to transition time */ } else { /* ** If summer time is in effect, and the ** transition time was not specified as ** standard time, add the summer time ** offset to the transition time; ** otherwise, add the standard time ** offset to the transition time. */ /* ** Transitions from DST to DDST ** will effectively disappear since ** POSIX provides for only one DST ** offset. */ if (isdst && !sp->ttis[j].tt_ttisstd) { sp->ats[i] += dstoffset - theirdstoffset; } else { sp->ats[i] += stdoffset - theirstdoffset; } } theiroffset = -sp->ttis[j].tt_gmtoff; if (sp->ttis[j].tt_isdst) theirdstoffset = theiroffset; else theirstdoffset = theiroffset; } /* ** Finally, fill in ttis. ** ttisstd and ttisgmt need not be handled. */ sp->ttis[0].tt_gmtoff = -stdoffset; sp->ttis[0].tt_isdst = FALSE; sp->ttis[0].tt_abbrind = 0; sp->ttis[1].tt_gmtoff = -dstoffset; sp->ttis[1].tt_isdst = TRUE; sp->ttis[1].tt_abbrind = (int) (stdlen + 1); sp->typecnt = 2; } } else { dstlen = 0; sp->typecnt = 1; /* only standard time */ sp->timecnt = 0; sp->ttis[0].tt_gmtoff = -stdoffset; sp->ttis[0].tt_isdst = 0; sp->ttis[0].tt_abbrind = 0; } sp->charcnt = (int) (stdlen + 1); if (dstlen != 0) sp->charcnt += (int) (dstlen + 1); if ((size_t) sp->charcnt > sizeof sp->chars) return -1; cp = sp->chars; (void) strncpy(cp, stdname, stdlen); cp += stdlen; *cp++ = '\0'; if (dstlen != 0) { (void) strncpy(cp, dstname, dstlen); *(cp + dstlen) = '\0'; } return 0; }
void finish(int n) { Rule_t* r; int i; /* * old error intercept */ if (!state.hold && (r = internal.error) && (r->property & (P_target|P_functional)) == P_target) { state.hold = null; if (n && error_info.errors && !state.compileonly && !state.interrupt) { if (r->status == NOTYET) maketop(r, P_dontcare|P_foreground, NiL); state.hold = 0; if (r->status == EXISTS) { r->status = NOTYET; return; } } } /* * children exit without cleanup */ if (getpid() != state.pid) _exit(n); unparse(0); switch (state.finish) { case 0: /* * disable listing and wait for any jobs to finish */ state.finish++; alarm(0); state.list = 0; message((-1, "%s cleanup", state.interrupt ? "interrupt" : n > 0 ? "error" : "normal")); complete(NiL, NiL, NiL, 0); /*FALLTHROUGH*/ case 1: /* * make the done trap */ state.finish++; if (!state.compileonly && (r = getrule(external.done))) maketop(r, P_dontcare, NiL); /*FALLTHROUGH*/ case 2: /* * make the makedone trap */ state.finish++; if (!state.compileonly && (r = getrule(external.makedone))) maketop(r, P_dontcare, NiL); /*FALLTHROUGH*/ case 3: /* * wait for any job(s) to finish */ state.finish++; complete(NiL, NiL, NiL, 0); /*FALLTHROUGH*/ case 4: /* * put all jobs in foreground and save state */ state.finish++; state.jobs = 0; savestate(); /*FALLTHROUGH*/ case 5: /* * clean up temporaries */ state.finish++; remtmp(1); /*FALLTHROUGH*/ case 6: /* * drop the coshell */ state.finish++; drop(); /*FALLTHROUGH*/ case 7: /* * dump */ state.finish++; if (state.test & 0x00002000) { Vmstat_t vs; vmstat(Vmheap, &vs); error(0, "vm region %zu segments %zu busy %zu:%zu free %zu:%zu", vs.extent, vs.n_seg, vs.n_busy, vs.s_busy, vs.n_free, vs.s_free); } dump(sfstdout, error_info.trace <= -14); /*FALLTHROUGH*/ case 8: /* * final output */ state.finish++; if (state.errors && state.keepgoing && !n) n = 1; if (state.mam.out) { if (state.mam.regress) sfprintf(state.mam.out, "%sinfo finish regression\n", state.mam.label); else if (state.mam.dynamic || *state.mam.label) sfprintf(state.mam.out, "%sinfo finish %lu %d\n", state.mam.label, CURTIME, n); } for (i = 0; i < elementsof(state.io); i++) if (state.io[i] != sfstdin && state.io[i] != sfstdout && state.io[i] != sfstderr) sfclose(state.io[i]); if (state.errors && state.keepgoing) error(2, "*** %d action%s failed", state.errors, state.errors == 1 ? null : "s"); message((-1, "%s exit", state.interrupt ? "interrupt" : n ? "error" : "normal")); break; } if (state.interrupt) { n = 3; signal(state.interrupt, SIG_DFL); kill(getpid(), state.interrupt); pause(); } exit(n); }
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; }
int handle(void) { register int sig; register Rule_t* r; register Alarms_t* a; char* s; char* w; Var_t* v; Seconds_t t; if (!state.caught) return 0; while (state.caught) { state.caught = 0; for (sig = 1; sig <= sig_info.sigmax; sig++) if (trap.caught[sig]) { trap.caught[sig] = 0; /* * flush the output streams */ sfsync(sfstderr); sfsync(sfstdout); /* * continue if already in finish */ if (state.finish) { if (!state.interrupt) state.interrupt = sig; for (sig = 1; sig <= sig_info.sigmax; sig++) trap.caught[sig] = 0; return 0; } /* * check user trap (some cannot be trapped) */ w = 0; if (!state.compileonly) switch (sig) { case SIGALRM: s = fmtsignal(-sig); t = CURSECS; while ((a = trap.alarms) && a->time <= t) { trap.alarms = a->next; r = a->rule; a->next = trap.freealarms; trap.freealarms = a; maketop(r, (P_dontcare|P_force|P_ignore|P_repeat)|((r->property & P_make)?0:P_foreground), s); } setwakeup(); continue; default: s = fmtsignal(-sig); if ((r = catrule(external.interrupt, ".", s, 0)) || (r = getrule(external.interrupt))) { if (!(r->property & P_functional)) v = setvar(external.interrupt, s, 0); maketop(r, (P_dontcare|P_force|P_ignore|P_repeat)|((r->property & P_make)?0:P_foreground), s); if (r->property & P_functional) v = getvar(r->name); w = v->value; if (r->status == EXISTS && (streq(w, s) || streq(w, "continue"))) { message((-1, "trap %s handler %s status CONTINUE return %s", s, r->name, w)); continue; } message((-1, "trap %s handler %s status TERMINATE return %s", s, r->name, w)); } /*FALLTHROUGH*/ #ifdef SIGILL case SIGILL: #endif #ifdef SIGIOT case SIGIOT: #endif #ifdef SIGEMT case SIGEMT: #endif #ifdef SIGBUS case SIGBUS: #endif #ifdef SIGSEGV case SIGSEGV: #endif break; } /* * terminate outstanding jobs */ terminate(); /* * the interpreter resumes without exit */ if (state.interpreter) { if (state.waiting) return 1; longjmp(state.resume.label, 1); } /* * if external.interrupt=""|"exit" then exit * otherwise terminate via original signal */ if (w && (!*w || streq(w, "exit"))) state.interrupt = 0; else if (!state.interrupt) state.interrupt = sig; finish(3); /* * shouldn't get here */ exit(3); } } return 1; }
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); }
void trigger(register Rule_t* r, Rule_t* a, char* action, Flags_t flags) { register Joblist_t* job; register List_t* p; List_t* prereqs; int n; /* * update flags */ if (!a) a = r; if (state.exec && !state.touch || (a->property & P_always) && (!state.never || (flags & CO_URGENT))) flags |= CO_ALWAYS; if ((a->property | r->property) & P_local) flags |= CO_LOCAL; if (!state.jobs || (r->property & P_foreground) || (r->property & (P_make|P_functional)) == P_functional || (r->dynamic & D_hasmake)) flags |= CO_FOREGROUND|CO_LOCAL; if (state.keepgoing || state.unwind) flags |= CO_KEEPGOING; if (state.silent) flags |= CO_SILENT; if (state.ignore) flags |= CO_IGNORE; if (r->property & (P_functional|P_read)) flags |= CO_DATAFILE; if (action) { message((-1, "triggering %s action%s%s", r->name, r == a ? null : " using ", r == a ? null : a->name)); if (state.exec) jobs.triggered = r; r->dynamic |= D_triggered; if ((r->property & (P_joint|P_target)) == (P_joint|P_target)) for (p = r->prereqs->rule->prereqs; p; p = p->next) p->rule->dynamic |= D_triggered; if (!*action) action = 0; } if (state.coshell && (action && !(r->property & P_make) || (flags & CO_FOREGROUND))) { /* * the make thread blocks when too many jobs are outstanding */ n = (flags & CO_FOREGROUND) ? 0 : (state.jobs - 1); while ((cozombie(state.coshell) || cojobs(state.coshell) > n) && block(0)); if ((flags & CO_FOREGROUND) && r->active && r->active->parent && r->active->parent->prereqs && copending(state.coshell) > cojobs(state.coshell)) serial(r, r->active->parent->prereqs); } prereqs = r->prereqs; if (r->active && r->active->primary) { prereqs = cons(getrule(r->active->primary), prereqs); flags |= CO_PRIMARY; } if (r->property & P_make) { if (r->property & P_local) { r->status = EXISTS; return; } /* * make actions are done immediately, bypassing the job queue */ if (prereqs && complete(NiL, prereqs, NiL, 0)) r->status = (r->property & P_dontcare) ? IGNORE : FAILED; else { if (action && cancel(r, prereqs)) r->status = EXISTS; else if ((r->dynamic & (D_hasbefore|D_triggered)) == (D_hasbefore|D_triggered) && (makebefore(r) || complete(NiL, prereqs, NiL, 0))) r->status = (r->property & P_dontcare) ? IGNORE : FAILED; else { if (r->property & P_functional) setvar(r->name, null, 0); if (action) switch (parse(NiL, action, r->name, NiL)) { case EXISTS: if (!(r->property & (P_state|P_virtual))) statetime(r, 0); break; case FAILED: r->status = (r->property & P_dontcare) ? IGNORE : FAILED; break; case TOUCH: r->time = internal.internal->time; break; case UPDATE: if ((r->property & (P_state|P_virtual)) != (P_state|P_virtual)) r->time = CURTIME; break; } if (r->status == UPDATE) r->status = EXISTS; } } if ((r->property & (P_joint|P_target)) == (P_joint|P_target)) for (p = r->prereqs->rule->prereqs; p; p = p->next) if (p->rule != r) { p->rule->status = r->status; p->rule->time = r->time; } if ((r->dynamic & (D_hasafter|D_triggered)) == (D_hasafter|D_triggered)) { if (r->status == FAILED) { if (hasafter(r, P_failure) && !makeafter(r, P_failure) && !complete(NiL, prereqs, NiL, 0)) r->status = EXISTS; } else if (hasafter(r, P_after) && (makeafter(r, P_after) || complete(NiL, prereqs, NiL, 0))) r->status = (r->property & P_dontcare) ? IGNORE : FAILED; } } else { /* * only one repeat action at a time */ if ((r->property & P_repeat) && (r->property & (P_before|P_after)) && !(r->dynamic & D_hassemaphore)) { a = catrule(internal.semaphore->name, ".", r->name, 1); a->semaphore = 2; r->prereqs = append(r->prereqs, cons(a, NiL)); r->dynamic |= D_hassemaphore; } /* * check if any prerequisites are blocking execution * FAILED prerequisites cause the target to fail too */ n = READY; for (;;) { for (p = prereqs; p; p = p->next) { if ((a = p->rule)->dynamic & D_alias) a = makerule(a->name); if (a->property & P_after) continue; switch (a->status) { case FAILED: if (a->property & P_repeat) continue; r->status = (r->property & P_dontcare) ? IGNORE : FAILED; if ((r->property & (P_joint|P_target)) == (P_joint|P_target)) for (p = r->prereqs->rule->prereqs; p; p = p->next) if (p->rule != r) p->rule->status = (p->rule->property & P_dontcare) ? IGNORE : FAILED; return; case MAKING: if (a->active) error(1, "%s: prerequisite %s is active", r->name, a->name); else n = BLOCKED; break; } } if (n != READY) break; if (action) { if (cancel(r, prereqs)) return; if ((r->dynamic & D_intermediate) && r->must == 1) { n = INTERMEDIATE; jobs.intermediate++; break; } } if ((r->dynamic & (D_hasbefore|D_triggered)) != (D_hasbefore|D_triggered)) break; if (makebefore(r)) { r->status = (r->property & P_dontcare) ? IGNORE : FAILED; if ((r->property & (P_joint|P_target)) == (P_joint|P_target)) for (p = r->prereqs->rule->prereqs; p; p = p->next) if (p->rule != r) p->rule->status = (p->rule->property & P_dontcare) ? IGNORE : FAILED; return; } } if (action || n != READY) { /* * allocate a job cell and add to job list * the first READY job from the top is executed next */ if (job = jobs.freejob) jobs.freejob = jobs.freejob->next; else job = newof(0, Joblist_t, 1, 0); if (flags & CO_URGENT) { job->prev = 0; if (job->next = jobs.firstjob) jobs.firstjob->prev = job; else jobs.lastjob = job; jobs.firstjob = job; } else { job->next = 0; if (job->prev = jobs.lastjob) jobs.lastjob->next = job; else jobs.firstjob = job; jobs.lastjob = job; } /* * fill in the info */ job->target = r; job->prereqs = prereqs; job->status = n; job->flags = flags; job->action = action; r->status = MAKING; if ((r->property & (P_joint|P_target)) == (P_joint|P_target)) for (p = r->prereqs->rule->prereqs; p; p = p->next) if (p->rule != r) p->rule->status = r->status; if (n == READY) { execute(job); if (r->dynamic & D_hasafter) save(job); } else save(job); jobstatus(); } else { if (r->status == UPDATE) r->status = EXISTS; if ((r->property & (P_joint|P_target)) == (P_joint|P_target)) for (p = r->prereqs->rule->prereqs; p; p = p->next) if (p->rule->status == UPDATE) p->rule->status = EXISTS; if ((r->dynamic & (D_hasafter|D_triggered)) == (D_hasafter|D_triggered)) { if (r->status == FAILED) { if (hasafter(r, P_failure) && !makeafter(r, P_failure) && !complete(NiL, prereqs, NiL, 0)) r->status = EXISTS; } else if (hasafter(r, P_after) && (makeafter(r, P_after) || complete(NiL, prereqs, NiL, 0))) r->status = (r->property & P_dontcare) ? IGNORE : FAILED; if (r->status == EXISTS) { char* t; Sfio_t* tmp; tmp = sfstropen(); edit(tmp, r->name, KEEP, DELETE, DELETE); if (*(t = sfstruse(tmp))) newfile(r, t, r->time); sfstrclose(tmp); } } } if (r->dynamic & D_triggered) { r->time = CURTIME; if ((r->property & (P_joint|P_target)) == (P_joint|P_target)) for (p = r->prereqs->rule->prereqs; p; p = p->next) p->rule->time = r->time; } } }
int block(int check) { register Cojob_t* cojob; register Joblist_t* job; Rule_t* r; int n; int clear = 0; int resume = 0; if (!state.coshell || !copending(state.coshell)) { if (jobs.intermediate) { /* * mark the jobs that must be generated */ n = 0; for (job = jobs.firstjob; job; job = job->next) if (job->target->must > ((unsigned int)(job->target->dynamic & D_intermediate) != 0)) { n = 1; break; } if (n) { /* * some intermediates must be generated */ error(2, "some intermediates must be generated"); } else { /* * accept missing intermediates */ while (job = jobs.firstjob) { if (error_info.trace || state.explain) error(state.explain ? 0 : -1, "cancelling %s action -- %s", job->target->name, job->status == INTERMEDIATE ? "intermediate not needed" : "missing intermediates accepted"); job->target->status = EXISTS; discard(job); } jobs.intermediate = 0; return 1; } } return 0; } for (;;) { state.waiting = 1; if ((cojob = cowait(state.coshell, check ? (Cojob_t*)state.coshell : (Cojob_t*)0, -1)) && (job = (Joblist_t*)cojob->local)) job->cojob = 0; if (trap()) { if (state.interpreter) clear = resume = 1; if (!cojob) continue; } state.waiting = 0; if (!cojob) { if (check) return 0; break; } if (r = getrule(external.jobdone)) { if (!jobs.tmp) jobs.tmp = sfstropen(); sfprintf(jobs.tmp, "%s %d %s %s", job->target->name, cojob->status, fmtelapsed(cojob->user, CO_QUANT), fmtelapsed(cojob->sys, CO_QUANT)); call(r, sfstruse(jobs.tmp)); } if (cojob->status) { if (n = !EXITED_TERM(cojob->status) || EXIT_CODE(cojob->status)) { if ((job->target->dynamic & D_hasafter) && hasafter(job->target, P_failure)) n = 0; error(n ? 2 : state.explain ? 0 : -1, "%s%s code %d making %s%s", n ? "*** " : null, ERROR_translate(NiL, NiL, NiL, EXITED_TERM(cojob->status) ? "termination" : "exit"), EXIT_CODE(cojob->status), job->target->name, (job->flags & CO_IGNORE) ? ERROR_translate(NiL, NiL, NiL, " ignored") : null); } if (!(job->flags & CO_IGNORE)) { job->flags |= CO_ERRORS; if (state.keepgoing || !n) { if (n) state.errors++; job->flags |= CO_KEEPGOING; } } if (state.interrupt || !(job->flags & (CO_IGNORE|CO_KEEPGOING))) clear = 1; } message((-3, "job: %s: interrupt=%d clear=%d status=%d flags=%08x", job->target->name, state.interrupt, clear, cojob->status, job->flags)); /* * job is done */ if (done(job, clear, cojob)) return 1; } if (resume) longjmp(state.resume.label, 1); if (!state.finish) { if (!copending(state.coshell)) { if (clear) finish(1); } else if (!state.interrupt) error(3, "lost contact with coshell"); } return 0; }