Esempio n. 1
0
static void
splice(void)
{
	char*	s;
	int	n;

	if (ed.spend) {
		if (!ed.spl && !(ed.spl = sfstropen()))
			error(ERROR_SYSTEM|3, "cannot initialize splice buffer");
		sfwrite(ed.spl, ed.spbeg, ed.spend - ed.spbeg);
		ed.spend = 0;
		sfputc(ed.spl, '\n');
		while (s = sfgetr(sfstdin, '\n', 1)) {
			if ((n = sfvalue(sfstdin) - 1) > 0 && s[n - 1] == '\r')
				n--;
			if (n > 0 && s[n - 1] == '\\') {
				sfwrite(ed.spl, s, n - 1);
				sfputc(ed.spl, '\n');
			}
			else {
				sfwrite(ed.spl, s, n);
				break;
			}
		}
		if (!(s = sfstruse(ed.spl)))
			error(ERROR_SYSTEM|3, "out of space");
		ed.input = s + (ed.input - ed.spbeg);
	}
}
Esempio n. 2
0
Gpr_t *openGPRState(gpr_info* info)
{
    Gpr_t *state;

    if (!(state = newof(0, Gpr_t, 1, 0))) {
	error(ERROR_ERROR, "Could not create gvpr state: out of memory");
	return state;
    }

    if (!(state->tmp = sfstropen())) {
	error(ERROR_ERROR, "Could not create state tmpfile");
	free (state);
	return 0;
    }

    state->tvt = TV_flat;
    state->name_used = name_used;
    state->tvroot = 0;
    state->tvnext = 0;
    state->tvedge = 0;
    state->outFile = info->outFile;
    state->argc = info->argc;
    state->argv = info->argv;
    state->errf = info->errf;
    state->flags = info->flags;

    return state;
}
Esempio n. 3
0
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]");
}
Esempio n. 4
0
void
exerror(const char* format, ...)
{
	Sfio_t*	sp;

	if (expr.program->disc->errorf && !expr.program->errors && (sp = sfstropen()))
	{
		va_list	ap;
		char*	s;
		char	buf[64];

		expr.program->errors = 1;
		excontext(expr.program, buf, sizeof(buf));
		sfputr(sp, buf, -1);
		va_start(ap, format);
		sfvprintf(sp, format, ap);
		va_end(ap);
		if (!(s = sfstruse(sp)))
			s = "out of space";
		(*expr.program->disc->errorf)(expr.program, expr.program->disc, (expr.program->disc->flags & EX_FATAL) ? 3 : 2, "%s", s);
		sfclose(sp);
	}
	else if (expr.program->disc->flags & EX_FATAL)
		exit(1);
}
Esempio n. 5
0
static int
intercept(Sfio_t* sp, int level, int flags)
{
	register Rule_t*	r;
	char*			m;
	char*			s;
	char*			t;
	char*			e;
	int			n;
	int			i;
	Sfio_t*			tmp;

	NoP(sp);
	NoP(flags);
	if ((state.mam.level = level) > 0 && !state.hold && (r = internal.error) && (r->property & (P_functional|P_target)) == (P_functional|P_target) && !state.compileonly && !state.interrupt && (m = stakptr(0)) && (n = staktell()) > 0)
	{
		/*
		 * make the error trap
		 */

		state.hold = m;
		while (*m && *m != ':')
			m++;
		while (isspace(*++m));
		n -= m - state.hold;
		tmp = sfstropen();
		sfprintf(tmp, "%d %-.*s", level, n, m);
		s = sfstruse(tmp);

		/*
		 * return [ level | - ] [ message ]
		 * level is new level or - to retain old
		 * omitted message means it has been printed
		 */

		if (t = call(r, s))
		{
			i = strtol(t, &e, 0);
			if (e > t)
			{
				t = e;
				level = i;
			}
			else if (*t == '-')
				t++;
			while (isspace(*t))
				t++;
		}
		if (!t || !*t)
		{
			level |= ERROR_OUTPUT;
			message((-1, "suppressed %s message: `%-.*s'", level == 1 ? "warning" : "error", n, m));
		}
		sfstrclose(tmp);
		state.hold = 0;
	}
	return level;
}
Esempio n. 6
0
int
main(int argc, char** argv)
{
	Css_t*		css;
	Cssfd_t*	fp;
	Connection_t*	con;
	char*		e;
	State_t		state;

	NoP(argc);
	error_info.id = "css";
	memset(&state, 0, sizeof(state));
	state.disc.version = CSS_VERSION;
	state.disc.flags = CSS_DAEMON|CSS_ERROR|CSS_INTERRUPT;
	state.disc.acceptf = acceptf;
	state.disc.actionf = actionf;
	state.disc.errorf = errorf;
	state.disc.exceptf = exceptf;
	for (;;)
	{
		switch (optget(argv, usage))
		{
		case 't':
			state.disc.timeout = strelapsed(opt_info.arg, &e, 1);
			if (*e)
				error(3, "%s: invalid timeout value", opt_info.arg);
			state.disc.flags |= CSS_DORMANT;
			continue;
		case '?':
			error(ERROR_USAGE|4, "%s", opt_info.arg);
			continue;
		case ':':
			error(2, "%s", opt_info.arg);
			continue;
		}
		break;
	}
	argv += opt_info.index;
	if (!argv[0] || !argv[1])
		error(ERROR_USAGE|4, "%s", optusage(NiL));
	if (!(state.tmp = sfstropen()))
		error(ERROR_SYSTEM|3, "out of space [tmp stream]");
	if (!(state.proc = procopen(argv[1], argv + 1, NiL, NiL, PROC_READ|PROC_WRITE)))
		error(ERROR_SYSTEM|3, "%s: cannot execute", argv[1]);
	if (!(css = cssopen(argv[0], &state.disc)))
		return 1;
	if (!(fp = cssfd(css, state.proc->rfd, CS_POLL_READ)))
		error(ERROR_SYSTEM|3, "%s: cannot poll output", argv[1]);
	if (!(con = newof(0, Connection_t, 1, 0)))
		error(ERROR_SYSTEM|3, "out of space");
	fp->data = con;
	con->service = 1;
	csspoll(CS_NEVER, 0);
	return 1;
}
Esempio n. 7
0
static void
commit(Joblist_t* job, register char* s)
{
	register char*		t;
	register char*		v;
	register Rule_t*	r;
	Stat_t			st;

	if (t = strrchr(s, '/'))
	{
		*t = 0;
		if (r = bindfile(NiL, s, 0))
		{
			if (!r->view)
			{
				*t = '/';
				return;
			}
			if (*(v = r->name) != '/')
			{
				sfprintf(internal.nam, "%s/%s", state.view[r->view].root, v);
				v = sfstruse(internal.nam);
			}
			if (stat(v, &st))
				r = 0;
		}
		if (r || state.targetcontext && (!r || !r->time) && (st.st_mode = (S_IRWXU|S_IRWXG|S_IRWXO)) && tmxsetmtime(&st, state.start))
		{
			/*
			 * why not mkdir -p here?
			 */

			commit(job, s);
			if (((job->flags & CO_ALWAYS) || state.exec && state.touch) && (mkdir(s, st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) || stat(s, &st)))
				error(1, "%s: cannot create target directory %s", job->target->name, s);
			if (state.mam.out)
			{
				Sfio_t*	tmp = sfstropen();

				sfprintf(tmp, "mkdir %s", s);
				dumpaction(state.mam.out, MAMNAME(job->target), sfstruse(tmp), NiL);
				sfstrclose(tmp);
			}
			r = makerule(s);
			if (r->dynamic & D_alias)
				oldname(r);
			r->view = 0;
			r->time = tmxgetmtime(&st);
			if (r->dynamic & D_scanned)
				unbind(NiL, (char*)r, NiL);
		}
		*t = '/';
	}
}
Esempio n. 8
0
char*
_re_putc(int c)
{
	static Sfio_t*	sp;

	if (!sp && !(sp = sfstropen()))
		return 0;
	if (!c)
		return sfstruse(sp);
	sfputc(sp, c);
	return 0;
}
Esempio n. 9
0
int
main(int argc, char** argv)
{
	char*		e;
	State_t		state;

	NoP(argc);
	error_info.id = "mbb";
	memset(&state, 0, sizeof(state));
	state.disc.version = CSS_VERSION;
	state.disc.flags = CSS_DAEMON|CSS_ERROR|CSS_INTERRUPT|CSS_LOG;
	state.disc.acceptf = acceptf;
	state.disc.actionf = actionf;
	state.disc.errorf = errorf;
	state.disc.exceptf = exceptf;
	for (;;)
	{
		switch (optget(argv, usage))
		{
		case 'b':
			state.backlog = opt_info.num;
			continue;
		case 'd':
			error_info.trace = -opt_info.num;
			continue;
		case 't':
			state.disc.timeout = strelapsed(opt_info.arg, &e, 1);
			if (*e)
				error(3, "%s: invalid timeout value", opt_info.arg);
			state.disc.flags |= CSS_DORMANT;
			continue;
		case '?':
			error(ERROR_USAGE|4, "%s", opt_info.arg);
			continue;
		case ':':
			error(2, "%s", opt_info.arg);
			continue;
		}
		break;
	}
	argv += opt_info.index;
	if (!argv[0] || argv[1])
		error(ERROR_USAGE|4, "%s", optusage(NiL));
	if (!(state.tmp = sfstropen()))
		error(ERROR_SYSTEM|3, "out of space [tmp stream]");
	if (!cssopen(argv[0], &state.disc))
		return 1;
	umask(S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
	csspoll(CS_NEVER, 0);
	return 1;
}
Esempio n. 10
0
Time_t
tmxduration(const char* s, char** e)
{
	Time_t		ns;
	Time_t		ts;
	Time_t		now;
	char*		last;
	char*		t;
	char*		x;
	Sfio_t*		f;
	int		i;

	now = TMX_NOW;
	while (isspace(*s))
		s++;
	if (*s == 'P' || *s == 'p')
		ns = tmxdate(s, &last, now) - now;
	else
	{
		ns = strtod(s, &last) * TMX_RESOLUTION;
		if (*last && (f = sfstropen()))
		{
			sfprintf(f, "exact %s", s);
			t = sfstruse(f);
			ts = tmxdate(t, &x, now);
			if ((i = x - t - 6) > (last - s))
			{
				last = (char*)s + i;
				ns = ts - now;
			}
			else
			{
				sfprintf(f, "p%s", s);
				t = sfstruse(f);
				ts = tmxdate(t, &x, now);
				if ((i = x - t - 1) > (last - s))
				{
					last = (char*)s + i;
					ns = ts - now;
				}
			}
			sfstrclose(f);
		}
	}
	if (e)
		*e = last;
	return ns;
}
Esempio n. 11
0
/*
 * Read single line from stream.
 * Return "" on EOF.
 */
char *readLine(Expr_t * ex, int fd)
{
    Sfio_t *sp;
    int c;
    Sfio_t *tmps;
    char *line;

    if (fd < 0 || fd >= elementsof(ex->file) || !((sp = ex->file[fd]))) {
	exerror("readL: %d: invalid descriptor", fd);
	return "";
    }
    tmps = sfstropen();
    while (((c = sfgetc(sp)) > 0) && (c != '\n'))
	sfputc(tmps, c);
    if (c == '\n')
	sfputc(tmps, c);
    line = exstring(ex, sfstruse(tmps));
    sfclose(tmps);
    return line;
}
Esempio n. 12
0
int
vasprintf(char** s, const char* fmt, va_list args)
{
	Sfio_t*	f;
	int	v;

	if (f = sfstropen())
	{
		v = sfvprintf(f, fmt, args);
		if (!(*s = strdup(sfstruse(f))))
			v = -1;
		sfstrclose(f);
	}
	else
	{
		*s = 0;
		v = -1;
	}
	return v;
}
Esempio n. 13
0
void exwarn(const char *format, ...)
{
    Sfio_t *sp;

    if (expr.program->disc->errorf && (sp = sfstropen())) {
	va_list ap;
	char *s;
	char buf[64];

	excontext(expr.program, buf, sizeof(buf));
	sfputr(sp, buf, -1);
	sfputr(sp, "\n -- ", -1);
	va_start(ap, format);
	sfvprintf(sp, format, ap);
	va_end(ap);
	s = sfstruse(sp);
	(*expr.program->disc->errorf) (expr.program, expr.program->disc,
				       ERROR_WARNING, "%s", s);
	sfclose(sp);
    }
}
Esempio n. 14
0
static int
ccsfprintf(int from, int to, Sfio_t* sp, const char* format, ...)
{
	va_list		ap;
	Sfio_t*		tp;
	char*		s;
	int		n;

	va_start(ap, format);
	if (from == to)
		n = sfvprintf(sp, format, ap);
	else if (tp = sfstropen())
	{
		n = sfvprintf(tp, format, ap);
		s = sfstrbase(tp);
		ccmaps(s, n, from, to);
		n = sfwrite(sp, s, n);
		sfstrclose(tp);
	}
	else
		n = -1;
	return n;
}
Esempio n. 15
0
Expr_t*
exopen(register Exdisc_t* disc)
{
	register Expr_t*	program;
	register Exid_t*	sym;
	int			debug;

	if (!(program = newof(0, Expr_t, 1, 0)))
		return 0;
	program->symdisc.key = offsetof(Exid_t, name);
	debug = getenv("VMDEBUG") != 0;
	if (!(program->symbols = dtopen(&program->symdisc, Dtset)) ||
	    !(program->tmp = sfstropen()) ||
	    !(program->vm = (debug ? vmopen(Vmdcsbrk, Vmdebug, VM_DBCHECK|VM_DBABORT) : vmopen(Vmdcheap, Vmbest, 0))) ||
	    !(program->ve = (debug ? vmopen(Vmdcsbrk, Vmdebug, VM_DBCHECK|VM_DBABORT) : vmopen(Vmdcheap, Vmbest, 0))))
	{
		exclose(program, 1);
		return 0;
	}
	program->id = "libexpr:expr";
	program->disc = disc;
	setcontext(program);
	program->file[0] = sfstdin;
	program->file[1] = sfstdout;
	program->file[2] = sfstderr;
	strcpy(program->main.name, "main");
	program->main.lex = PROCEDURE;
	program->main.index = PROCEDURE;
	dtinsert(program->symbols, &program->main);
	if (!(disc->flags & EX_PURE))
		for (sym = exbuiltin; *sym->name; sym++)
			dtinsert(program->symbols, sym);
	if ((sym = disc->symbols))
		for (; *sym->name; sym++)
			dtinsert(program->symbols, sym);
	return program;
}
Esempio n. 16
0
static Sfio_t*
paxpart(Pax_t* pax, Paxarchive_t* ap, off_t n)
{
	register Part_t*	part;

	static int		fd = -1;

	if (!(part = ap->partio))
	{
		if (!(part = newof(0, Part_t, 1, 0)) || !(part->sp = sfstropen()))
		{
			paxnospace(pax);
			return 0;
		}
		part->sp->_flags &= ~(SF_READ|SF_WRITE|SF_STRING);
		if (ap->flags & PAX_IN)
			part->sp->_flags |= SF_READ;
		else
			part->sp->_flags |= SF_WRITE;
		if (fd < 0)
			fd = open("/dev/null", O_RDWR);
		part->sp->_file = fd;
		part->disc.readf = part_read;
		part->disc.writef = part_write;
		if (sfdisc(part->sp, &part->disc) != &part->disc)
		{
			sfclose(part->sp);
			free(part);
			return 0;
		}
		part->pax = pax;
		part->ap = ap;
		ap->partio = part;
	}
	part->n = n;
	return part->sp;
}
Esempio n. 17
0
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;
}
Esempio n. 18
0
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;
		}
	}
}
Esempio n. 19
0
char*
translate(const char* loc, const char* cmd, const char* cat, const char* msg)
{
	register char*	r;
	char*		t;
	int		p;
	int		oerrno;
	Catalog_t*	cp;
	Message_t*	mp;

	oerrno = errno;
	r = (char*)msg;

	/*
	 * quick out
	 */

	if (!cmd && !cat)
		goto done;
	if (cmd && (t = strrchr(cmd, '/')))
		cmd = (const char*)(t + 1);

	/*
	 * initialize the catalogs dictionary
	 */

	if (!state.catalogs)
	{
		if (state.error)
			goto done;
		if (!(state.tmp = sfstropen()))
		{
			state.error = 1;
			goto done;
		}
		if (!(state.catalogs = dtopen(&state.catalog_disc, Dtset)))
		{
			sfclose(state.tmp);
			state.error = 1;
			goto done;
		}
		if (streq(loc, "debug"))
			state.debug = loc;
	}

	/*
	 * get the message
	 * or do we have to spell it out for you
	 */

	if ((!cmd || !(mp = match(cmd, msg))) &&
	    (!cat || !(mp = match(cat, msg))) &&
	    (!error_info.catalog || !(mp = match(error_info.catalog, msg))) &&
	    (!ast.id || !(mp = match(ast.id, msg))) ||
	     !(cp = mp->cat))
	{
#if DEBUG_trace > 1
sfprintf(sfstderr, "AHA#%d:%s cmd %s cat %s:%s id %s msg `%s'\n", __LINE__, __FILE__, cmd, cat, error_info.catalog, ast.id, msg);
#endif
		goto done;
	}

	/*
	 * adjust for the current locale
	 */

#if DEBUG_trace
sfprintf(sfstderr, "AHA#%d:%s cp->locale `%s' %p loc `%s' %p\n", __LINE__, __FILE__, cp->locale, cp->locale, loc, loc);
#endif
	if (cp->locale != loc)
	{
		cp->locale = loc;
		if (cp->cat != NOCAT)
			catclose(cp->cat);
		if ((cp->cat = find(cp->locale, cp->name)) == NOCAT)
			cp->debug = streq(cp->locale, "debug");
		else
			cp->debug = 0;
#if DEBUG_trace
sfprintf(sfstderr, "AHA#%d:%s cp->cat %p cp->debug %d NOCAT %p\n", __LINE__, __FILE__, cp->cat, cp->debug, NOCAT);
#endif
	}
	if (cp->cat == NOCAT)
	{
		if (cp->debug)
		{
			p = tempget(state.tmp);
			sfprintf(state.tmp, "(%s,%d,%d)", cp->name, mp->set, mp->seq);
			r = tempuse(state.tmp, p);
		}
		else if (ast.locale.set & AST_LC_debug)
		{
			p = tempget(state.tmp);
			sfprintf(state.tmp, "(%s,%d,%d)%s", cp->name, mp->set, mp->seq, r);
			r = tempuse(state.tmp, p);
		}
		goto done;
	}

	/*
	 * get the translated message
	 */

	r = catgets(cp->cat, mp->set, mp->seq, msg);
	if (ast.locale.set & AST_LC_translate)
		sfprintf(sfstderr, "translate locale=%s catalog=%s set=%d seq=%d \"%s\" => \"%s\"\n", cp->locale, cp->name, mp->set, mp->seq, msg, r == (char*)msg ? "NOPE" : r);
	if (r != (char*)msg)
	{
		if (streq(r, (char*)msg))
			r = (char*)msg;
		else if (strcmp(fmtfmt(r), fmtfmt(msg)))
		{
			sfprintf(sfstderr, "locale %s catalog %s message %d.%d \"%s\" does not match \"%s\"\n", cp->locale, cp->name, mp->set, mp->seq, r, msg);
			r = (char*)msg;
		}
	}
	if (ast.locale.set & AST_LC_debug)
	{
		p = tempget(state.tmp);
		sfprintf(state.tmp, "(%s,%d,%d)%s", cp->name, mp->set, mp->seq, r);
		r = tempuse(state.tmp, p);
	}
 done:
	if (r == (char*)msg && loc == state.debug)
	{
		p = tempget(state.tmp);
		sfprintf(state.tmp, "(%s,%s,%s,\"%s\")", loc, cmd, cat, r);
		r = tempuse(state.tmp, p);
	}
	errno = oerrno;
	return r;
}
Esempio n. 20
0
static void
restore(register Joblist_t* job, Sfio_t* buf, Sfio_t* att)
{
	register char*	s;
	register char*	b;
	char*		u;
	char*		down;
	char*		back;
	char*		sep;
	int		downlen;
	int		localview;
	void*		pos;
	Var_t*		v;
	Sfio_t*		opt;
	Sfio_t*		tmp;
	Sfio_t*		context;

	push(job);
	localview = state.localview;
	state.localview = state.mam.statix && !state.expandview && state.user && !(job->flags & CO_ALWAYS);
	if ((job->flags & CO_LOCALSTACK) || (job->target->dynamic & D_hasscope))
	{
		register Rule_t*	r;
		register List_t*	p;

		job->flags |= CO_LOCALSTACK;
		pos = pushlocal();
		opt = sfstropen();
		if (job->target->dynamic & D_hasscope)
			for (p = job->prereqs; p; p = p->next)
				if ((r = p->rule)->dynamic & D_scope)
				{
					if (*r->name == '-')
						set(r->name, 1, opt);
					else
						parse(NiL, r->name, r->name, opt);
				}
				else if ((r->property & (P_make|P_local|P_use)) == (P_make|P_local) && r->action)
					parse(NiL, r->action, r->name, opt);
	}
	context = state.context;
	if (state.targetcontext && *(u = unbound(job->target)) != '/' && (s = strrchr(u, '/')))
	{
		size_t	n;
		int	c;

		tmp = sfstropen();
		downlen = s - u;
		*s = 0;
		sfprintf(tmp, "%s%c", u, 0);
		n = sfstrtell(tmp);
		c = '/';
		do
		{
			if (u = strchr(u, '/'))
				u++;
			else
				c = 0;
			sfputr(tmp, "..", c);
		} while (c);
		*s = '/';
		back = (down = sfstrbase(tmp)) + n;
		state.context = buf;
		buf = sfstropen();
		state.localview++;
	}
	else
		state.context = 0;
	if (job->action)
		expand(buf, job->action);
	if (state.context)
	{
		s = sfstruse(buf);
		sep = strchr(s, '\n') ? "\n" : "; ";
		sfprintf(state.context, "{ cd %s%s", down, sep);
		while (b = strchr(s, MARK_CONTEXT))
		{
			sfwrite(state.context, s, b - s);
			if (!(s = strchr(++b, MARK_CONTEXT)))
				error(PANIC, "unbalanced MARK_CONTEXT");
			*s++ = 0;
			if (*b == '/' || (u = getbound(b)) && *u == '/')
				sfputr(state.context, b, -1);
			else if (*b)
			{
				if (strneq(b, down, downlen))
					switch (*(b + downlen))
					{
					case 0:
						sfputc(state.context, '.');
						continue;
					case '/':
						sfputr(state.context, b + downlen + 1, -1);
						continue;
					}
				if (streq(b, "."))
					sfputr(state.context, back, -1);
				else if (isspace(*b))
					sfputr(state.context, b, -1);
				else
					sfprintf(state.context, "%s/%s", back, b);
			}
		}
		sfprintf(state.context, "%s%s}", s, sep);
		sfstrclose(tmp);
		sfstrclose(buf);
	}
	state.context = context;
	sfprintf(att, "label=%s", job->target->name);
	if ((v = getvar(CO_ENV_ATTRIBUTES)) && !(v->property & V_import))
		sfprintf(att, ",%s", v->value);
	if (job->flags & CO_LOCALSTACK)
	{
		poplocal(pos);
		if (*(s = sfstruse(opt)))
			set(s, 1, NiL);
		sfclose(opt);
	}
	state.localview = localview;
	pop(job);
}
Esempio n. 21
0
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);
}
Esempio n. 22
0
static int
prformat(Sfio_t* sp, void* vp, Sffmt_t* dp)
{
	register Fmt_t*		fmt = (Fmt_t*)dp;
	register Exnode_t*	node;
	register char*		s;
	register char*		txt;
	int			n;
	int			from;
	int			to;
	time_t			tm;

	dp->flags |= SFFMT_VALUE;
	if (fmt->args)
	{
		if (node = (dp->fmt == '*') ? fmt->args->param[dp->size] : fmt->args->arg)
			fmt->value = exeval(fmt->expr, node, fmt->env);
		else
			fmt->value.integer = 0;
		to = fmt->args->arg->type;
	}
	else if (!(fmt->actuals = fmt->actuals->data.operand.right))
		exerror("printf: not enough arguments");
	else
	{
		node = fmt->actuals->data.operand.left;
		from = node->type;
		switch (dp->fmt)
		{
		case 'f':
		case 'g':
			to = FLOATING;
			break;
		case 's':
		case '[':
			to = STRING;
			break;
		default:
			switch (from)
			{
			case INTEGER:
			case UNSIGNED:
				to = from;
				break;
			default:
				to = INTEGER;
				break;
			}
			break;
		}
		if (to == from)
			fmt->value = exeval(fmt->expr, node, fmt->env);
		else
		{
			node = excast(fmt->expr, node, to, NiL, 0);
			fmt->value = exeval(fmt->expr, node, fmt->env);
			node->data.operand.left = 0;
			exfree(fmt->expr, node);
			if (to == STRING)
			{
				if (fmt->value.string)
				{
					n = strlen(fmt->value.string);
					if (s = fmtbuf(n + 1))
						memcpy(s, fmt->value.string, n + 1);
					vmfree(fmt->expr->vm, fmt->value.string);
					fmt->value.string = s;
				}
				if (!fmt->value.string)
					fmt->value.string = "";
			}
		}
	}
	switch (to)
	{
	case STRING:
		*((char**)vp) = fmt->value.string;
		fmt->fmt.size = -1;
		break;
	case FLOATING:
		*((double*)vp) = fmt->value.floating;
		fmt->fmt.size = sizeof(double);
		break;
	default:
		*((Sflong_t*)vp) = fmt->value.integer;
		dp->size = sizeof(Sflong_t);
		break;
	}
	if (dp->n_str > 0)
	{
		if (!fmt->tmp && !(fmt->tmp = sfstropen()))
			txt = exnospace();
		else
		{
			sfprintf(fmt->tmp, "%.*s", dp->n_str, dp->t_str);
			txt = exstash(fmt->tmp, NiL);
		}
	}
	else
		txt = 0;
	switch (dp->fmt)
	{
	case 'q':
	case 'Q':
		s = *((char**)vp);
		*((char**)vp) = fmtquote(s, "$'", "'", strlen(s), 0);
		dp->fmt = 's';
		dp->size = -1;
		break;
	case 'S':
		dp->flags &= ~SFFMT_LONG;
		s = *((char**)vp);
		if (txt)
		{
			if (streq(txt, "identifier"))
			{
				if (*s && !isalpha(*s))
					*s++ = '_';
				for (; *s; s++)
					if (!isalnum(*s))
						*s = '_';
			}
			else if (streq(txt, "invert"))
			{
				for (; *s; s++)
					if (isupper(*s))
						*s = tolower(*s);
					else if (islower(*s))
						*s = toupper(*s);
			}
			else if (streq(txt, "lower"))
			{
				for (; *s; s++)
					if (isupper(*s))
						*s = tolower(*s);
			}
			else if (streq(txt, "upper"))
			{
				for (; *s; s++)
					if (islower(*s))
						*s = toupper(*s);
			}
			else if (streq(txt, "variable"))
			{
				for (; *s; s++)
					if (!isalnum(*s) && *s != '_')
						*s = '.';
			}
		}
		dp->fmt = 's';
		dp->size = -1;
		break;
	case 't':
	case 'T':
		if ((tm = *((Sflong_t*)vp)) == -1)
			tm = time(NiL);
		*((char**)vp) = fmttime(txt ? txt : "%?%K", tm);
		dp->fmt = 's';
		dp->size = -1;
		break;
	}
	return 0;
}
Esempio n. 23
0
int
main(int argc, char** argv)
{
	register Mc_t*	mc;
	register char*	s;
	register char*	t;
	register int	c;
	register int	q;
	register int	i;
	int		num;
	char*		b;
	char*		e;
	char*		catfile;
	char*		msgfile;
	Sfio_t*		sp;
	Sfio_t*		mp;
	Sfio_t*		tp;
	Xl_t*		px;
	Xl_t*		bp;

	Xl_t*		xp = 0;
	int		format = 0;
	int		list = 0;
	int		set = 0;

	NoP(argc);
	error_info.id = "msggen";
	for (;;)
	{
		switch (optget(argv, usage))
		{
		case 'f':
			format = list = 1;
			continue;
		case 'l':
			list = 1;
			continue;
		case 's':
			set = 1;
			continue;
		case '?':
			error(ERROR_USAGE|4, "%s", opt_info.arg);
			continue;
		case ':':
			error(2, "%s", opt_info.arg);
			continue;
		}
		break;
	}
	argv += opt_info.index;
	if (error_info.errors || !(catfile = *argv++))
		error(ERROR_USAGE|4, "%s", optusage(NiL));

	/*
	 * set and list only need catfile
	 */

	if (set)
	{
		sfprintf(sfstdout, "%d\n", mcindex(catfile, NiL, NiL, NiL));
		return error_info.errors != 0;
	}
	else if (list)
	{
		if (!(sp = sfopen(NiL, catfile, "r")))
			error(ERROR_SYSTEM|3, "%s: cannot read catalog", catfile);
		if (!(mc = mcopen(sp)))
			error(ERROR_SYSTEM|3, "%s: catalog content error", catfile);
		sfclose(sp);
		if (format)
		{
			for (set = 1; set <= mc->num; set++)
				if (mc->set[set].num)
				{
					sfprintf(sfstdout, "$set %d\n", set);
					for (num = 1; num <= mc->set[set].num; num++)
						if (s = mc->set[set].msg[num])
							sfprintf(sfstdout, "%d \"%s\"\n", num, fmtfmt(s));
				}
		}
		else
		{
			if (*mc->translation)
			{
				ccsfprintf(CC_NATIVE, CC_ASCII, sfstdout, "$translation ");
				sfprintf(sfstdout, "%s", mc->translation);
				ccsfprintf(CC_NATIVE, CC_ASCII, sfstdout, "\n");
			}
			ccsfprintf(CC_NATIVE, CC_ASCII, sfstdout, "$quote \"\n");
			for (set = 1; set <= mc->num; set++)
				if (mc->set[set].num)
				{
					ccsfprintf(CC_NATIVE, CC_ASCII, sfstdout, "$set %d\n", set);
					for (num = 1; num <= mc->set[set].num; num++)
						if (s = mc->set[set].msg[num])
						{
							ccsfprintf(CC_NATIVE, CC_ASCII, sfstdout, "%d \"", num);
							while (c = *s++)
							{
								/*INDENT...*/

			switch (c)
			{
			case 0x22: /* " */
			case 0x5C: /* \ */
				sfputc(sfstdout, 0x5C);
				break;
			case 0x07: /* \a */
				c = 0x61;
				sfputc(sfstdout, 0x5C);
				break;
			case 0x08: /* \b */
				c = 0x62;
				sfputc(sfstdout, 0x5C);
				break;
			case 0x0A: /* \n */
				c = 0x6E;
				sfputc(sfstdout, 0x5C);
				break;
			case 0x0B: /* \v */
				c = 0x76;
				sfputc(sfstdout, 0x5C);
				break;
			case 0x0C: /* \f */
				c = 0x66;
				sfputc(sfstdout, 0x5C);
				break;
			case 0x0D: /* \r */
				c = 0x72;
				sfputc(sfstdout, 0x5C);
				break;
			}

								/*...UNDENT*/
								sfputc(sfstdout, c);
							}
							ccsfprintf(CC_NATIVE, CC_ASCII, sfstdout, "\"\n");
						}
				}
		}
		mcclose(mc);
		return error_info.errors != 0;
	}
	else if (!(msgfile = *argv++) || *argv)
		error(3, "exactly one message file must be specified");

	/*
	 * open the files and handles
	 */

	if (!(tp = sfstropen()))
		error(ERROR_SYSTEM|3, "out of space [string stream]");
	if (!(mp = sfopen(NiL, msgfile, "r")))
		error(ERROR_SYSTEM|3, "%s: cannot read message file", msgfile);
	sp = sfopen(NiL, catfile, "r");
	if (!(mc = mcopen(sp)))
		error(ERROR_SYSTEM|3, "%s: catalog content error", catfile);
	if (sp)
		sfclose(sp);
	xp = translation(xp, mc->translation);

	/*
	 * read the message file
	 */

	q = 0;
	set = 1;
	error_info.file = msgfile;
	while (s = sfgetr(mp, '\n', 1))
	{
		error_info.line++;
		if (!*s)
			continue;
		if (*s == '$')
		{
			if (!*++s || isspace(*s))
				continue;
			for (t = s; *s && !isspace(*s); s++);
			if (*s)
				*s++ = 0;
			if (streq(t, "delset"))
			{
				while (isspace(*s))
					s++;
				num = (int)strtol(s, NiL, 0);
				if (num < mc->num && mc->set[num].num)
					for (i = 1; i <= mc->set[num].num; i++)
						mcput(mc, num, i, NiL);
			}
			else if (streq(t, "quote"))
				q = *s ? *s : 0;
			else if (streq(t, "set"))
			{
				while (isspace(*s))
					s++;
				num = (int)strtol(s, &e, 0);
				if (e != s)
					set = num;
				else
					error(2, "set number expected");
			}
			else if (streq(t, "translation"))
				xp = translation(xp, s);
		}
		else
		{
			t = s + sfvalue(mp);
			num = (int)strtol(s, &e, 0);
			if (e != s)
			{
				s = e;
				if (!*s)
				{
					if (mcput(mc, set, num, NiL))
						error(2, "(%d,%d): cannot delete message", set, num);
				}
				else if (isspace(*s++))
				{
					if (t > (s + 1) && *(t -= 2) == '\\')
					{
						sfwrite(tp, s, t - s);
						while (s = sfgetr(mp, '\n', 0))
						{
							error_info.line++;
							t = s + sfvalue(mp);
							if (t <= (s + 1) || *(t -= 2) != '\\')
								break;
							sfwrite(tp, s, t - s);
						}
						if (!(s = sfstruse(tp)))
							error(ERROR_SYSTEM|3, "out of space");
					}
					if (q)
					{
						if (*s++ != q)
						{
							error(2, "(%d,%d): %c quote expected", set, num, q);
							continue;
						}
						b = t = s;
						while (c = *s++)
						{
							if (c == '\\')
							{
								c = chresc(s - 1, &e);
								s = e;
								if (c)
									*t++ = c;
								else
									error(1, "nul character ignored");
							}
							else if (c == q)
								break;
							else
								*t++ = c;
						}
						if (*s)
						{
							error(2, "(%d,%d): characters after quote not expected", set, num);
							continue;
						}
						*t = 0;
						s = b;
					}
					if (mcput(mc, set, num, s))
						error(2, "(%d,%d): cannot add message", set, num);
				}
				else
					error(2, "message text expected");
			}
			else
				error(2, "message number expected");
		}
	}
	error_info.file = 0;
	error_info.line = 0;

	/*
	 * fix up the translation record
	 */

	if (xp)
	{
		t = "";
		for (;;)
		{
			for (bp = 0, px = xp; px; px = px->next)
				if (px->date && (!bp || strcoll(bp->date, px->date) < 0))
					bp = px;
			if (!bp)
				break;
			sfprintf(tp, "%s%s %s", t, bp->name, bp->date);
			t = ", ";
			bp->date = 0;
		}
		if (!(mc->translation = sfstruse(tp)))
			error(ERROR_SYSTEM|3, "out of space");
	}

	/*
	 * dump the catalog to a local temporary
	 * rename if no errors
	 */

	if (!(s = pathtemp(NiL, 0, "", error_info.id, NiL)) || !(sp = sfopen(NiL, s, "w")))
		error(ERROR_SYSTEM|3, "%s: cannot write catalog file", catfile);
	if (mcdump(mc, sp) || mcclose(mc) || sfclose(sp))
	{
		remove(s);
		error(ERROR_SYSTEM|3, "%s: temporary catalog file write error", s);
	}
	remove(catfile);
	if (rename(s, catfile))
		error(ERROR_SYSTEM|3, "%s: cannot rename from temporary catalog file %s", catfile, s);
	return error_info.errors != 0;
}
Esempio n. 24
0
int    b_print(int argc, char *argv[], Shbltin_t *context)
{
	register Sfio_t *outfile;
	register int exitval=0,n, fd = 1;
	register Shell_t *shp = context->shp;
	const char *options, *msg = e_file+4;
	char *format = 0, *fmttype=0;
	int sflag = 0, nflag=0, rflag=0, vflag=0;
	Namval_t *vname=0;
	Optdisc_t disc;
	disc.version = OPT_VERSION;
	disc.infof = infof;
	opt_info.disc = &disc;
	if(argc>0)
	{
		options = sh_optprint;
		nflag = rflag = 0;
		format = 0;
	}
	else
	{
		struct print *pp = (struct print*)context;
		shp = pp->sh;
		options = pp->options;
		if(argc==0)
		{
			nflag = pp->echon;
			rflag = pp->raw;
			argv++;
			goto skip;
		}
	}
	while((n = optget(argv,options))) switch(n)
	{
		case 'n':
			nflag++;
			break;
		case 'p':
			fd = shp->coutpipe;
			msg = e_query;
			break;
		case 'f':
			format = opt_info.arg;
			break;
		case 's':
			/* print to history file */
			if(!sh_histinit((void*)shp))
				errormsg(SH_DICT,ERROR_system(1),e_history);
			fd = sffileno(shp->gd->hist_ptr->histfp);
			sh_onstate(shp,SH_HISTORY);
			sflag++;
			break;
		case 'e':
			rflag = 0;
			break;
		case 'r':
			rflag = 1;
			break;
		case 'u':
			if(opt_info.arg[0]=='p' && opt_info.arg[1]==0)
			{
				fd = shp->coutpipe;
				msg = e_query;
				break;
			}
			fd = (int)strtol(opt_info.arg,&opt_info.arg,10);
			if(*opt_info.arg)
				fd = -1;
			else if(!sh_iovalidfd(shp,fd))
				fd = -1;
			else if(!(shp->inuse_bits&(1<<fd)) && (sh_inuse(shp,fd) || (shp->gd->hist_ptr && fd==sffileno(shp->gd->hist_ptr->histfp))))

				fd = -1;
			break;
		case 'j':
			fmttype = "json";
		case 'v':
			if(argc < 0)
			{
				if(!(vname = nv_open(opt_info.arg, shp->var_tree,NV_VARNAME|NV_NOARRAY)))
					errormsg(SH_DICT,2, "Cannot create variable %s", opt_info.arg);
			}
			else
				vflag='v';
			break;
		case 'C':
			vflag='C';
			break;
		case ':':
			/* The following is for backward compatibility */
#if OPT_VERSION >= 19990123
			if(strcmp(opt_info.name,"-R")==0)
#else
			if(strcmp(opt_info.option,"-R")==0)
#endif
			{
				rflag = 1;
				if(error_info.errors==0)
				{
					argv += opt_info.index+1;
					/* special case test for -Rn */
					if(strchr(argv[-1],'n'))
						nflag++;
					if(*argv && strcmp(*argv,"-n")==0)
					{

						nflag++;
						argv++;
					}
					goto skip2;
				}
			}
			else
				errormsg(SH_DICT,2, "%s", opt_info.arg);
			break;
		case '?':
			errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
			break;
	}
	argv += opt_info.index;
	if(error_info.errors || (argc<0 && !(format = *argv++)))
		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
	if(vflag && format)
		errormsg(SH_DICT,ERROR_usage(2),"-%c and -f are mutually exclusive",vflag);
skip:
	if(format)
		format = genformat(shp,format);
	/* handle special case of '-' operand for print */
	if(argc>0 && *argv && strcmp(*argv,"-")==0 && strcmp(argv[-1],"--"))
		argv++;
	if(vname)
	{
		if(!shp->strbuf2)
			shp->strbuf2 = sfstropen();
		outfile = shp->strbuf2;
		goto printv;
	}
skip2:
	if(fd < 0)
	{
		errno = EBADF;
		n = 0;
	}
	else if(!(n=shp->fdstatus[fd]))
		n = sh_iocheckfd(shp,fd,fd);
	if(!(n&IOWRITE))
	{
		/* don't print error message for stdout for compatibility */
		if(fd==1)
			return(1);
		errormsg(SH_DICT,ERROR_system(1),msg);
	}
	if(!(outfile=shp->sftable[fd]))
	{
		sh_onstate(shp,SH_NOTRACK);
		n = SF_WRITE|((n&IOREAD)?SF_READ:0);
		shp->sftable[fd] = outfile = sfnew(NIL(Sfio_t*),shp->outbuff,IOBSIZE,fd,n);
		sh_offstate(shp,SH_NOTRACK);
		sfpool(outfile,shp->outpool,SF_WRITE);
	}
Esempio n. 25
0
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;
}
Esempio n. 26
0
void
ppbuiltin(void)
{
	register int		c;
	register char*		p;
	register char*		a;

	int			n;
	int			op;
	char*			token;
	char*			t;
	long			number;
	long			onumber;
	struct ppinstk*		in;
	struct pplist*		list;
	struct ppsymbol*	sym;
	Sfio_t*			sp;

	number = pp.state;
	pp.state |= DISABLE|FILEPOP|NOSPACE;
	token = pp.token;
	p = pp.token = pp.tmpbuf;
	*(a = pp.args) = 0;
	if ((c = pplex()) != T_ID)
	{
		error(2, "%s: #(<identifier>...) expected", p);
		*p = 0;
	}
	switch (op = (int)hashget(pp.strtab, p))
	{
	case V_DEFAULT:
		n = 0;
		p = pp.token = pp.valbuf;
		if ((c = pplex()) == ',')
		{
			op = -1;
			c = pplex();
		}
		pp.state &= ~NOSPACE;
		for (;;)
		{
			if (!c)
			{
				error(2, "%s in #(...) argument", pptokchr(c));
				break;
			}
			if (c == '(') n++;
			else if (c == ')' && !n--) break;
			else if (c == ',' && !n && op > 0) op = 0;
			if (op) pp.token = pp.toknxt;
			c = pplex();
		}
		*pp.token = 0;
		pp.token = token;
		pp.state = number;
		break;
	case V_EMPTY:
		p = pp.valbuf;
		if ((c = pplex()) == ')') *p = '1';
		else
		{
			*p = '0';
			n = 0;
			for (;;)
			{
				if (!c)
				{
					error(2, "%s in #(...) argument", pptokchr(c));
					break;
				}
				if (c == '(') n++;
				else if (c == ')' && !n--) break;
				c = pplex();
			}
		}
		*(p + 1) = 0;
		pp.token = token;
		pp.state = number;
		break;
	case V_ITERATE:
		n = 0;
		pp.token = pp.valbuf;
		if ((c = pplex()) != T_ID || !(sym = ppsymref(pp.symtab, pp.token)) || !sym->macro || sym->macro->arity != 1 || (c = pplex()) != ',')
		{
			error(2, "#(%s <macro(x)>, ...) expected", p);
			for (;;)
			{
				if (!c)
				{
					error(2, "%s in #(...) argument", pptokchr(c));
					break;
				}
				if (c == '(') n++;
				else if (c == ')' && !n--) break;
				c = pplex();
			}
			*pp.valbuf = 0;
		}
		else while (c != ')')
		{
			p = pp.token;
			if (pp.token > pp.valbuf) *pp.token++ = ' ';
			STRCOPY(pp.token, sym->name, a);
			*pp.token++ = '(';
			if (!c || !(c = pplex()))
			{
				pp.token = p;
				error(2, "%s in #(...) argument", pptokchr(c));
				break;
			}
			pp.state &= ~NOSPACE;
			while (c)
			{
				if (c == '(') n++;
				else if (c == ')' && !n--) break;
				else if (c == ',' && !n) break;
				pp.token = pp.toknxt;
				c = pplex();
			}
			*pp.token++ = ')';
			pp.state |= NOSPACE;
		}
		p = pp.valbuf;
		pp.token = token;
		pp.state = number;
		break;
	default:
		pp.token = token;
		while (c != ')')
		{
			if (!c)
			{
				error(2, "%s in #(...) argument", pptokchr(c));
				break;
			}
			if ((c = pplex()) == T_ID && !*a)
				strcpy(a, pp.token);
		}
		pp.state = number;
		switch (op)
		{
		case V_ARGC:
			c = -1;
			for (in = pp.in; in; in = in->prev)
				if ((in->type == IN_MACRO || in->type == IN_MULTILINE) && (in->symbol->flags & SYM_FUNCTION))
				{
					c = *((unsigned char*)(pp.macp->arg[0] - 2));
					break;
				}
			sfsprintf(p = pp.valbuf, MAXTOKEN, "%d", c);
			break;
		case V_BASE:
			p = (a = strrchr(error_info.file, '/')) ? a + 1 : error_info.file;
			break;
		case V_DATE:
			if (!(p = pp.date))
			{
				time_t	tm;

				time(&tm);
				a = p = ctime(&tm) + 4;
				*(p + 20) = 0;
				for (p += 7; *p = *(p + 9); p++);
				pp.date = p = strdup(a);
			}
			break;
		case V_FILE:
			p = error_info.file;
			break;
		case V_LINE:
			sfsprintf(p = pp.valbuf, MAXTOKEN, "%d", error_info.line);
			break;
		case V_PATH:
			p = pp.path;
			break;
		case V_SOURCE:
			p = error_info.file;
			for (in = pp.in; in->prev; in = in->prev)
				if (in->prev->type == IN_FILE && in->file)
					p = in->file;
			break;
		case V_STDC:
			p = pp.valbuf;
			p[0] = ((pp.state & (COMPATIBILITY|TRANSITION)) || (pp.mode & (HOSTED|HOSTEDTRANSITION)) == (HOSTED|HOSTEDTRANSITION)) ? '0' : '1';
			p[1] = 0;
			break;
		case V_TIME:
			if (!(p = pp.time))
			{
				time_t	tm;

				time(&tm);
				p = ctime(&tm) + 11;
				*(p + 8) = 0;
				pp.time = p = strdup(p);
			}
			break;
		case V_VERSION:
			p = (char*)pp.version;
			break;
		case V_DIRECTIVE:
			pp.state |= NEWLINE;
			pp.mode |= RELAX;
			strcpy(p = pp.valbuf, "#");
			break;
		case V_GETENV:
			if (!(p = getenv(a))) p = "";
			break;
		case V_GETMAC:
			p = (sym = pprefmac(a, REF_NORMAL)) ? sym->macro->value : "";
			break;
		case V_GETOPT:
			sfsprintf(p = pp.valbuf, MAXTOKEN, "%ld", ppoption(a));
			break;
		case V_GETPRD:
			p = (list = (struct pplist*)hashget(pp.prdtab, a)) ? list->value : "";
			break;
		case V__PRAGMA:
			if ((c = pplex()) == '(')
			{
				number = pp.state;
				pp.state |= NOSPACE|STRIP;
				c = pplex();
				pp.state = number;
				if (c == T_STRING || c == T_WSTRING)
				{
					if (!(sp = sfstropen()))
						error(3, "temporary buffer allocation error");
					sfprintf(sp, "#%s %s\n", dirname(PRAGMA), pp.token);
					a = sfstruse(sp);
					if ((c = pplex()) == ')')
					{
						pp.state |= NEWLINE;
						PUSH_BUFFER(p, a, 1);
					}
					sfstrclose(sp);
				}
			}
			if (c != ')')
				error(2, "%s: (\"...\") expected", p);
			return;
		case V_FUNCTION:

#define BACK(a,p)	((a>p)?*--a:(number++?0:((p=pp.outbuf+PPBUFSIZ),(a=pp.outbuf+2*PPBUFSIZ),*--a)))
#define PEEK(a,p)	((a>p)?*(a-1):(number?0:*(pp.outbuf+2*PPBUFSIZ-1)))

			number = pp.outbuf != pp.outb;
			a = pp.outp;
			p = pp.outb;
			op = 0;
			while (c = BACK(a, p))
			{
				if (c == '"' || c == '\'')
				{
					op = 0;
					while ((n = BACK(a, p)) && n != c || PEEK(a, p) == '\\');
				}
				else if (c == '\n')
				{
					token = a;
					while (c = BACK(a, p))
						if (c == '\n')
						{
							a = token;
							break;
						}
						else if (c == '#' && PEEK(a, p) == '\n')
							break;
				}
				else if (c == ' ')
					/*ignore*/;
				else if (c == '{') /* '}' */
					op = 1;
				else if (op == 1)
				{
					if (c == ')')
					{
						op = 2;
						n = 1;
					}
					else
						op = 0;
				}
				else if (op == 2)
				{
					if (c == ')')
						n++;
					else if (c == '(' && !--n)
						op = 3;
				}
				else if (op == 3)
				{
					if (ppisidig(c))
					{
						for (t = p, token = a, onumber = number; ppisidig(PEEK(a, p)) && a >= p; BACK(a, p));
						p = pp.valbuf + 1;
						if (a > token)
						{
							for (; a < pp.outbuf+2*PPBUFSIZ; *p++ = *a++);
							a = pp.outbuf;
						}
						for (; a <= token; *p++ = *a++);
						*p = 0;
						p = pp.valbuf + 1;
						if (streq(p, "for") || streq(p, "if") || streq(p, "switch") || streq(p, "while"))
						{
							op = 0;
							p = t;
							number = onumber;
							continue;
						}
					}
					else
						op = 0;
					break;
				}
			}
			if (op == 3)
				p = strncpy(pp.funbuf, p, sizeof(pp.funbuf) - 1);
			else if (*pp.funbuf)
				p = pp.funbuf;
			else
				p = "__FUNCTION__";
			break;
		default:
			if (pp.builtin && (a = (*pp.builtin)(pp.valbuf, p, a)))
				p = a;
			break;
		}
		break;
	}
	if (strchr(p, MARK))
	{
		a = pp.tmpbuf;
		strcpy(a, p);
		c = p != pp.valbuf;
		p = pp.valbuf + c;
		for (;;)
		{
			if (p < pp.valbuf + MAXTOKEN - 2)
				switch (*p++ = *a++)
				{
				case 0:
					break;
				case MARK:
					*p++ = MARK;
					/*FALLTHROUGH*/
				default:
					continue;
				}
			break;
		}
		p = pp.valbuf + c;
	}
	if (p == pp.valbuf)
		PUSH_STRING(p);
	else
	{
		if (p == pp.valbuf + 1)
			*pp.valbuf = '"';
		else
		{
			if (strlen(p) > MAXTOKEN - 2)
				error(1, "%-.16s: builtin value truncated", p);
			sfsprintf(pp.valbuf, MAXTOKEN, "\"%-.*s", MAXTOKEN - 2, p);
		}
		PUSH_QUOTE(pp.valbuf, 1);
	}
}
Esempio n. 27
0
int
csclient(Cs_t* cs, int fd, const char* service, const char* prompt, char** argv, unsigned int flags)
{
	register int	i;
	char*		s;
	Sfio_t*		tmp;
	int		done;
	int		promptlen;
	int		timeout;
	ssize_t		n;
	int		sdf[2];
	Cspoll_t	fds[2];
	char		buf[8 * 1024];

	if (fd < 0 && (fd = csopen(cs, service, CS_OPEN_TEST)) < 0)
	{
		if (errno == ENOENT)
			error(3, "%s: server not running", service);
		else
			error(ERROR_SYSTEM|3, "%s: cannot open connect stream", service);
	}
#if _hdr_termios
	if (flags & CS_CLIENT_RAW)
	{
		tcgetattr(0, &state.old_term);
		atexit(restore);
		state.new_term = state.old_term;
		state.new_term.c_iflag &= ~(BRKINT|IGNPAR|PARMRK|INLCR|IGNCR|ICRNL);
		state.new_term.c_lflag &= ~(ECHO|ECHOK|ICANON|ISIG);
		state.new_term.c_cc[VTIME] = 0;
		state.new_term.c_cc[VMIN] = 1;
		tcsetattr(0, TCSANOW, &state.new_term);
	}
#endif
	sdf[0] = fd;
	sdf[1] = 1;
	if (argv && *argv)
	{
		fds[0].fd = 1;
		fds[0].events = CS_POLL_WRITE;
	}
	else
	{
		argv = 0;
		fds[0].fd = 0;
		fds[0].events = CS_POLL_READ;
	}
	fds[1].fd = fd;
	fds[1].events = CS_POLL_READ;
	done = 0;
	if (promptlen = (!argv && prompt && isatty(fds[0].fd) && isatty(1)) ? strlen(prompt) : 0)
		write(1, prompt, promptlen);
	timeout = CS_NEVER;
	tmp = 0;
	while (cspoll(cs, fds, elementsof(fds), timeout) > 0)
		for (i = 0; i < elementsof(fds); i++)
			if (fds[i].status & (CS_POLL_READ|CS_POLL_WRITE))
			{
				if (!i && argv)
				{
					if (!*argv)
					{
						argv = 0;
						fds[0].fd = 0;
						if (flags & CS_CLIENT_ARGV)
						{
							if (done++)
								return 0;
							timeout = 500;
						}
						fds[0].events = CS_POLL_READ;
						continue;
					}
					if (!tmp && !(tmp = sfstropen()))
						error(ERROR_SYSTEM|3, "out of space");
					for (;;)
					{
						s = *argv++;
						if ((flags & CS_CLIENT_SEP) && *s == ':' && !*(s + 1))
							break;
						if (sfstrtell(tmp))
							sfputc(tmp, ' ');
						sfprintf(tmp, "%s", s);
						if (!(flags & CS_CLIENT_SEP) || !*argv)
							break;
					}
					sfputc(tmp, '\n');
					n = sfstrtell(tmp);
					s = sfstruse(tmp);
				}
				else if ((n = read(fds[i].fd, s = buf, sizeof(buf) - 1)) < 0)
					error(ERROR_SYSTEM|3, "/dev/fd/%d: read error", fds[i].fd);
				if (!n)
				{
					if (done++)
						return 0;
					if (!i)
						write(sdf[i], "quit\n", 5);
					continue;
				}
				if (!i)
				{
#if _hdr_termios
					register char*	u;
					register int	m;

					s[n] = 0;
					if ((u = strchr(s, 035)))
					{
						if ((m = u - s) > 0 && write(sdf[i], s, m) != m)
							error(ERROR_SYSTEM|3, "/dev/fd/%d: write error", sdf[i]);
						tcsetattr(0, TCSANOW, &state.old_term);
						if (promptlen)
							write(1, prompt, promptlen);
						if ((n = read(fds[i].fd, s = buf, sizeof(buf) - 1)) <= 0)
						{
							write(1, "\n", 1);
							return 0;
						}
						buf[n - 1] = 0;
						if (*u == 'q' || *u == 'Q')
							return 0;
						tcsetattr(0, TCSANOW, &state.new_term);
						if (*u)
							error(1, "%s: unknown command", u);
						continue;
					}
#endif
				}
				if (write(sdf[i], s, n) != n)
					error(ERROR_SYSTEM|3, "/dev/fd/%d: write error", sdf[i]);
				if (sdf[i] == 1 && promptlen)
					write(1, prompt, promptlen);
			}
	return error_info.errors != 0;
}
Esempio n. 28
0
int
b_mime(int argc, char** argv, Shbltin_t* context)
{
	Mime_t*		mp;
	char*		s;
	Sfio_t*		sp;
	int		silent;
	Mimedisc_t	disc;

	cmdinit(argc, argv, context, ERROR_CATALOG, 0);
	silent = 0;
	for (;;)
	{
		switch (optget(argv, usage))
		{
		case 0:
			break;
		case 's':
			silent = 1;
			continue;
		case ':':
			error(2, "%s", opt_info.arg);
			continue;
		case '?':
			error(ERROR_usage(2), "%s", opt_info.arg);
			continue;
		}
		break;
	}
	argc -= opt_info.index;
	argv += opt_info.index;
	if (error_info.errors || argc > 1 && argc < 3)
		error(ERROR_usage(2), "%s", optusage(NiL));
	disc.version = MIME_VERSION;
	disc.flags = 0;
	disc.errorf = errorf;
	if (!(mp = mimeopen(&disc)))
		error(ERROR_exit(1), "mime library error");
	if (mimeload(mp, NiL, 0))
	{
		mimeclose(mp);
		error(ERROR_exit(1), "mime load error");
	}
	if (argc <= 1)
		mimelist(mp, sfstdout, argv[0]);
	else if (!(sp = sfstropen()))
		error(ERROR_exit(1), "out of space");
	else
	{
		for (argc = 3; s = argv[argc]; argc++)
			sfputr(sp, s, ';');
		if (!(s = sfstruse(sp)))
			error(ERROR_exit(1), "out of space");
		if (!(s = mimeview(mp, argv[0], argv[1], argv[2], s)))
		{
			if (silent)
				exit(1);
			error(ERROR_exit(1), "no %s view for mime type %s", argv[0], argv[2]);
		}
		else
			sfputr(sfstdout, s, '\n');
		sfclose(sp);
	}
	mimeclose(mp);
	return 0;
}
Esempio n. 29
0
static int
r2c(const char* file, Sfio_t* ip, Sfio_t* op)
{
	register char*		s;
	register char*		e;
	register int		d;
	register int		q;
	register int		t;
	register Col_t*		col;
	register size_t		w;
	register size_t		n;
	register size_t		m;
	char*			b;

	w = state.cache;
	d = state.delimiter;
	q = state.quote;
	t = state.terminator;
	while (s = sfgetr(ip, t, 0))
	{
		n = sfvalue(ip);
		if (w < n)
		{
			if (n > state.window)
			{
				error(2, "%s: input record larger than window size", file);
				return -1;
			}
			if (flush(op))
				return -1;
		}
		w -= n;
		col = state.cols;
		for (;;)
		{
			if (!col)
			{
				if (!(col = newof(0, Col_t, 1, 0)) || !(col->sp = sfstropen()))
					error(ERROR_SYSTEM|3, "out of space [column]");
				if (!state.cols)
					state.cols = col;
				else if (state.last)
					state.last->next = col;
				state.last = col;
			}
			if (q && *s == q)
			{
				b = s;
				e = s + n;
				while (++b < e)
					if (*b == q)
					{
						b++;
						break;
					}
				m = b - s;
			}
			else if (e = memchr(s, d, n))
				m = e - s + 1;
			else
				m = n;
			if (sfwrite(col->sp, s, m) != m)
			{
				error(ERROR_SYSTEM|2, "%s: column write error");
				return -1;
			}
			if (!e)
				break;
			s += m;
			n -= m;
			col = col->next;
		}
	}
	if (sfgetr(ip, -1, 0))
	{
		error(2, "%s: last record incomplete", file);
		return -1;
	}
	return 0;
}
Esempio n. 30
0
int
main(int argc, register char** argv)
{
	register int	n;
	register char*	s;
	char*		args;
	char*		codes;
	char**		av;
	char**		ap;
	int		i;
	int		count;
	int		len;
	int		traverse;
	int		size;
	Dir_t*		firstdir;
	Dir_t*		lastdir;
	Exnode_t*	x;
	Exnode_t*	y;
	Ftw_t		ftw;
	Finddisc_t	disc;

	setlocale(LC_ALL, "");
	error_info.id = "tw";
	av = argv + 1;
	args = 0;
	codes = 0;
	count = 0;
	size = 0;
	traverse = 1;
	firstdir = lastdir = newof(0, Dir_t, 1, 0);
	firstdir->name = ".";
	state.action = LIST;
	state.cmdflags = CMD_EXIT|CMD_IGNORE|CMD_IMPLICIT|CMD_NEWLINE;
	state.errexit = EXIT_QUIT;
	state.ftwflags = ftwflags()|FTW_DELAY;
	state.select = ALL;
	state.separator = '\n';
	memset(&disc, 0, sizeof(disc));
	for (;;)
	{
		switch (optget(argv, usage))
		{
		case 'a':
			args = opt_info.arg;
			state.cmdflags |= CMD_POST;
			continue;
		case 'c':
			if ((count = opt_info.num) < 0)
				error(3, "argument count must be >= 0");
			continue;
		case 'd':
			lastdir = lastdir->next = newof(0, Dir_t, 1, 0);
			lastdir->name = opt_info.arg;
			continue;
		case 'e':
			compile(opt_info.arg, 0);
			continue;
		case 'f':
			state.pattern = opt_info.arg;
			continue;
		case 'i':
			state.ignore = 1;
			continue;
		case 'l':
			state.localfs = 1;
			continue;
		case 'm':
			state.intermediate = 1;
			continue;
		case 'n':
			traverse = 0;
			continue;
		case 'p':
			state.ftwflags |= FTW_TWICE;
			continue;
		case 'q':
			state.cmdflags |= CMD_QUERY;
			continue;
		case 'r':
			state.ftwflags |= FTW_RECURSIVE;
			continue;
		case 's':
			if ((size = opt_info.num) < 0)
				error(3, "command size must be >= 0");
			continue;
		case 't':
			state.cmdflags |= CMD_TRACE;
			continue;
		case 'x':
			state.errexit = opt_info.arg ? opt_info.num : EXIT_QUIT;
			continue;
		case 'z':
			if (s = sfgetr(sfstdin, '\n', 1))
			{
				if (!(s = strdup(s)))
					error(ERROR_SYSTEM|3, "out of space");
				n = state.snapshot.format.delim = *s++;
				state.snapshot.format.path = s;
				if (!(s = strchr(s, n)))
				{
				osnap:
					error(3, "invalid snapshot on standard input");
				}
				*s++ = 0;
				if (!streq(state.snapshot.format.path, SNAPSHOT_ID))
					goto osnap;
				state.snapshot.format.path = s;
				if (!(s = strchr(s, n)))
					goto osnap;
				*s++ = 0;
				state.snapshot.format.easy = s;
				if (!(s = strchr(s, n)))
					goto osnap;
				*s++ = 0;
				if (*(state.snapshot.format.hard = s))
				{
					if (!(s = strchr(s, n)))
						goto osnap;
					*s = 0;
				}
				else
					state.snapshot.format.hard = 0;
				state.snapshot.sp = sfstdin;
				state.snapshot.prev = sfgetr(sfstdin, '\n', 0);
			}
			else
			{
				state.snapshot.format.path = SNAPSHOT_PATH;
				state.snapshot.format.easy = SNAPSHOT_EASY;
				state.snapshot.format.hard = SNAPSHOT_HARD;
				state.snapshot.format.delim = SNAPSHOT_DELIM[0];
			}
			if (!(state.snapshot.tmp = sfstropen()))
				error(ERROR_SYSTEM|3, "out of space");
			compile("sort:name;", 0);
			continue;
		case 'C':
			state.ftwflags |= FTW_NOSEEDOTDIR;
			continue;
		case 'D':
			error_info.trace = -opt_info.num;
			continue;
		case 'E':
			compile(opt_info.arg, 1);
			continue;
		case 'F':
			codes = opt_info.arg;
			continue;
		case 'G':
			disc.flags |= FIND_GENERATE;
			if (streq(opt_info.arg, "old"))
				disc.flags |= FIND_OLD;
			else if (streq(opt_info.arg, "gnu") || streq(opt_info.arg, "locate"))
				disc.flags |= FIND_GNU;
			else if (streq(opt_info.arg, "type"))
				disc.flags |= FIND_TYPE;
			else if (streq(opt_info.arg, "?"))
			{
				error(2, "formats are { default|dir type old gnu|locate }");
				return 0;
			}
			else if (!streq(opt_info.arg, "-") && !streq(opt_info.arg, "default") && !streq(opt_info.arg, "dir"))
				error(3, "%s: invalid find codes format -- { default|dir type old gnu|locate } expected", opt_info.arg);
			continue;
		case 'H':
			state.ftwflags |= FTW_META|FTW_PHYSICAL;
			continue;
		case 'I':
			state.icase = 1;
			continue;
		case 'L':
			state.ftwflags &= ~(FTW_META|FTW_PHYSICAL|FTW_SEEDOTDIR);
			continue;
		case 'P':
			state.ftwflags &= ~FTW_META;
			state.ftwflags |= FTW_PHYSICAL;
			continue;
		case 'S':
			state.separator = *opt_info.arg;
			continue;
		case 'X':
			state.ftwflags |= FTW_MOUNT;
			continue;
		case '?':
			error(ERROR_USAGE|4, "%s", opt_info.arg);
			continue;
		case ':':
			error(2, "%s", opt_info.arg);
			continue;
		}
		break;
	}
	argv += opt_info.index;
	argc -= opt_info.index;
	if (error_info.errors)
		error(ERROR_USAGE|4, "%s", optusage(NiL));

	/*
	 * do it
	 */

	if (state.snapshot.tmp)
		sfprintf(sfstdout, "%c%s%c%s%c%s%c%s%c\n",
			state.snapshot.format.delim, SNAPSHOT_ID,
			state.snapshot.format.delim, state.snapshot.format.path,
			state.snapshot.format.delim, state.snapshot.format.easy,
			state.snapshot.format.delim, state.snapshot.format.hard ? state.snapshot.format.hard : "",
			state.snapshot.format.delim);
	if (x = exexpr(state.program, "begin", NiL, 0))
		eval(x, NiL);
	if ((x = exexpr(state.program, "select", NiL, INTEGER)) || (x = exexpr(state.program, NiL, NiL, INTEGER)))
		state.select = x;
	if (!(state.ftwflags & FTW_PHYSICAL))
		state.ftwflags &= ~FTW_DELAY;
	memset(&ftw, 0, sizeof(ftw));
	ftw.path = ftw.name = "";
	if (traverse)
	{
		if (x = exexpr(state.program, "action", NiL, 0))
			state.action = x;
		if (x = exexpr(state.program, "sort", NiL, 0))
		{
			state.sortkey = x;
			y = 0;
			for (;;)
			{
				switch (x->op)
				{
				case ',':
					y = x->data.operand.right;
					/*FALLTHROUGH*/
				case '!':
				case '~':
				case S2B:
				case X2I:
					x = x->data.operand.left;
					continue;
				case ID:
					if (!(x = y))
						break;
					y = 0;
					continue;
				default:
					error(3, "invalid sort identifier (op 0x%02x)", x->op);
					break;
				}
				break;
			}
			state.sort = order;
		}
		if (*argv && (*argv)[0] == '-' && (*argv)[1] == 0)
		{
			state.ftwflags |= FTW_LIST;
			argv++;
			argc--;
		}
		if (*argv || args || count || !(state.cmdflags & CMD_IMPLICIT))
		{
			Cmddisc_t	disc;

			CMDDISC(&disc, state.cmdflags, errorf);
			state.cmd = cmdopen(argv, count, size, args, &disc);
			state.ftwflags |= FTW_DOT;
		}
		else
			state.cmdflags &= ~CMD_IMPLICIT;
		if (codes && (disc.flags & FIND_GENERATE))
		{
			char*	p;
			Dir_t*	dp;
			char	pwd[PATH_MAX];
			char	tmp[PATH_MAX];

			disc.version = FIND_VERSION;
			if (state.cmdflags & CMD_TRACE)
				disc.flags |= FIND_TYPE;
			if (state.cmdflags & CMD_QUERY)
				disc.flags |= FIND_OLD;
			disc.errorf = errorf;
			if (!(state.find = findopen(codes, NiL, NiL, &disc)))
				exit(2);
			if (disc.flags & FIND_TYPE)
			{
				state.act = ACT_CODETYPE;
				compile("_tw_init:mime;", 0);
				state.magicdisc.flags |= MAGIC_MIME;
			}
			else
				state.act = ACT_CODE;
			state.icase = 1;
			state.pattern = 0;
			state.sort = order;
			if (!state.program)
				compile("1", 0);
			if (!(state.sortkey = newof(0, Exnode_t, 1, 0)) || !(state.sortkey->data.variable.symbol = (Exid_t*)dtmatch(state.program->symbols, "name")))
				error(ERROR_SYSTEM|3, "out of space");
			state.sortkey->op = ID;
			s = p = 0;
			for (dp = (firstdir == lastdir) ? firstdir : firstdir->next; dp; dp = dp->next)
			{
				if (*(s = dp->name) == '/')
					sfsprintf(tmp, sizeof(tmp), "%s", s);
				else if (!p && !(p = getcwd(pwd, sizeof(pwd))))
					error(ERROR_SYSTEM|3, "cannot determine pwd path");
				else
					sfsprintf(tmp, sizeof(tmp), "%s/%s", p, s);
				pathcanon(tmp, sizeof(tmp), PATH_PHYSICAL);
				if (!(dp->name = strdup(tmp)))
					error(ERROR_SYSTEM|3, "out of space [PATH_PHYSICAL]");
			}
		}
		else if (state.snapshot.tmp)
			state.act = ACT_SNAPSHOT;
		else if (state.cmdflags & CMD_IMPLICIT)
			state.act = ACT_CMDARG;
		else if (state.action == LIST)
			state.act = ACT_LIST;
		else if (state.action)
			state.act = ACT_EVAL;
		if (state.intermediate)
		{
			state.actII = state.act;
			state.act = ACT_INTERMEDIATE;
		}
		if (state.pattern)
		{
			disc.version = FIND_VERSION;
			if (state.icase)
				disc.flags |= FIND_ICASE;
			disc.errorf = errorf;
			disc.dirs = ap = av;
			if (firstdir != lastdir)
				firstdir = firstdir->next;
			do {*ap++ = firstdir->name;} while (firstdir = firstdir->next);
			*ap = 0;
			if (!(state.find = findopen(codes, state.pattern, NiL, &disc)))
				exit(1);
			state.ftwflags |= FTW_TOP;
			n = state.select == ALL ? state.act : ACT_EVAL;
			while (s = findread(state.find))
			{
				switch (n)
				{
				case ACT_CMDARG:
					if ((i = cmdarg(state.cmd, s, strlen(s))) >= state.errexit)
						exit(i);
					break;
				case ACT_LIST:
					sfputr(sfstdout, s, '\n');
					break;
				default:
					ftwalk(s, tw, state.ftwflags, NiL);
					break;
				}
			}
		}
		else if (state.ftwflags & FTW_LIST)
		{
			sfopen(sfstdin, NiL, "rt");
			n = state.select == ALL && state.act == ACT_CMDARG;
			for (;;)
			{
				if (s = sfgetr(sfstdin, state.separator, 1))
					len = sfvalue(sfstdin) - 1;
				else if (state.separator != '\n')
				{
					state.separator = '\n';
					continue;
				}
				else if (s = sfgetr(sfstdin, state.separator, -1))
					len = sfvalue(sfstdin);
				else
					break;
				if (!n)
					ftwalk(s, tw, state.ftwflags, NiL);
				else if ((i = cmdarg(state.cmd, s, len)) >= state.errexit)
					exit(i);
			}
			if (sferror(sfstdin))
				error(ERROR_SYSTEM|2, "input read error");
		}
		else if (firstdir == lastdir)
			ftwalk(firstdir->name, tw, state.ftwflags, state.sort);
		else
		{
			ap = av;
			while (firstdir = firstdir->next)
				*ap++ = firstdir->name;
			*ap = 0;
			ftwalk((char*)av, tw, state.ftwflags|FTW_MULTIPLE, state.sort);
		}
		if (state.cmd && (i = cmdflush(state.cmd)) >= state.errexit)
			exit(i);
		if (state.find && (findclose(state.find) || state.finderror))
			exit(2);
	}
	else if (state.select)
		error_info.errors = eval(state.select, &ftw) == 0;
	if (x = exexpr(state.program, "end", NiL, 0))
		eval(x, &ftw);
	if (sfsync(sfstdout))
		error(ERROR_SYSTEM|2, "write error");
	exit(error_info.errors != 0);
}