Пример #1
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]");
}
Пример #2
0
static char*
getrec(register Sfio_t* sp, register int delimiter, register int flags)
{
	register int	c;
	register char*	glob;

	sfstrseek(sp, 0, SEEK_SET);
	glob = ed.global;
	while ((c = getchr()) != delimiter) {
		if (c == '\n') {
			ed.peekc = c;
			break;
		}
		if (c == EOF) {
			if (glob)
				ed.peekc = (flags & REC_LINE) ? 0 : c;
			else if (delimiter != '\n' || (flags & (REC_LINE|REC_SPLICE)))
				error(2, "unexpected EOF");
			else if (flags & REC_TEXT)
				return 0;
			break;
		}
		if (c == '\\' && ((c = getchr()) != delimiter || (flags & REC_SPLICE) && c != '\n') && c && !(flags & REC_IGNORE))
			sfputc(sp, '\\');
		if (!c)
			error(1, "null character ignored");
		else if (!(flags & REC_IGNORE))
			sfputc(sp, c);
	}
	if (flags & REC_TERMINATE)
		sfputc(sp, c);
	if (!(glob = sfstruse(sp)))
		error(ERROR_SYSTEM|3, "out of space");
	return glob;
}
Пример #3
0
static int
tempget(Sfio_t* sp)
{
	if (sfstrtell(sp) > sfstrsize(sp) / 2)
		sfstrseek(sp, 0, SEEK_SET);
	return sfstrtell(sp);
}
Пример #4
0
static ssize_t
helpwrite(int fd, const void* buf, size_t len)
{
	ssize_t	n;

	NoP(fd);
	n = ed.help ? sfwrite(sfstderr, buf, len) : ed.verbose ? sfputr(ed.msg, "?", '\n') : 0;
	sfstrseek(ed.buffer.help, 0, SEEK_SET);
	sfwrite(ed.buffer.help, buf, len - 1);
	sfputc(ed.buffer.help, 0);
	return n;
}
Пример #5
0
static void
join(void)
{
	register Line_t*	a1;
	char*			s;

	nonzero();
	sfstrseek(ed.buffer.work, 0, SEEK_SET);
	for (a1 = ed.addr1; a1 <= ed.addr2;)
		sfputr(ed.buffer.work, lineget((a1++)->offset), -1);
	a1 = ed.dot = ed.addr1;
	if (!(s = sfstruse(ed.buffer.work)))
		error(ERROR_SYSTEM|3, "out of space");
	replace(a1, s);
	if (a1 < ed.addr2)
		rdelete(a1 + 1, ed.addr2);
}
Пример #6
0
static void
exfile(void)
{
	if (sfclose(ed.iop))
		error(ERROR_SYSTEM|1, "io error");
	ed.iop = 0;
	if (ed.verbose) {
		if (ed.help) {
			sfprintf(ed.msg, "\"%s\" %lu line%s, %lu character%s", error_info.file, ed.lines, plural(ed.lines), ed.bytes, plural(ed.bytes));
			if (ed.warn_null) {
				sfprintf(ed.msg, ", %lu null%s", ed.warn_null, plural(ed.warn_null));
				ed.warn_null = 0;
			}
			if (ed.warn_newline) {
				sfprintf(ed.msg, ", newline appended");
				ed.warn_newline = 0;
			}
			sfputc(ed.msg, '\n');
		}
		else
			sfprintf(ed.msg, "%d\n", ed.bytes);
	}
	if (ed.warn_null || ed.warn_newline) {
		char*	sep = "";

		sfstrseek(ed.buffer.line, 0, SEEK_SET);
		if (ed.warn_null) {
			sfprintf(ed.buffer.line, "%d null character%s ignored", ed.warn_null, plural(ed.warn_null));
			ed.warn_null = 0;
			sep = ", ";
		}
		if (ed.warn_newline) {
			sfprintf(ed.buffer.line, "%snewline appended to last line", sep);
			ed.warn_newline = 0;
		}
		if (!(sep = sfstruse(ed.buffer.line)))
			error(ERROR_SYSTEM|3, "out of space");
		error(1, "%s", sep);
	}
	error_info.file = 0;
}
Пример #7
0
static int
flush(Sfio_t* op)
{
	register Col_t*	col;
	register size_t	n;

	if ((col = state.cols) && sfstrtell(col->sp))
	{
		do
		{
			n = sfstrtell(col->sp);
			if (sfwrite(op, sfstrseek(col->sp, 0, SEEK_SET), n) != n || sfsync(op))
			{
				error(ERROR_SYSTEM|2, "write error");
				return -1;
			}
		} while (col = col->next);
	}
	state.cache = state.window;
	return 0;
}
Пример #8
0
static void
handle(void)
{
	register int	c;
	char*		s;
	char*		b;
	mode_t		mask;

	if (ed.caught == SIGINT) {
		ed.caught = 0;
		ed.lastc = '\n';
		sfputc(ed.msg, '\n');
		error(2, "interrupt");
	}
	for (c = 0; c < elementsof(signals); c++)
		signal(signals[c], SIG_IGN);
	if (ed.dol > ed.zero) {
		ed.addr1 = ed.zero + 1;
		ed.addr2 = ed.dol;
		mask = umask(S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
		b = "ed.hup";
		if (!(ed.iop = sfopen(NiL, b, "w")) && !ed.restricted && (s = getenv("HOME"))) {
			sfstrseek(ed.buffer.line, 0, SEEK_SET);
			sfprintf(ed.buffer.line, "%s/%s", s, b);
			if (!(b = sfstruse(ed.buffer.line)))
				error(ERROR_SYSTEM|3, "out of space");
			ed.iop = sfopen(NiL, b, "w");
		}
		umask(mask);
		if (!ed.iop)
			error(ERROR_SYSTEM|1, "%s: cannot save changes", b);
		else {
			error_info.file = b;
			putfile();
		}
	}
	ed.modified = 0;
	quit(0);
}
Пример #9
0
int
pzheadwrite(Pz_t* pz, Sfio_t* op)
{
	register size_t	i;
	register size_t	m;
	register size_t	n;
	register char*	s;

	if (pz->flags & PZ_HEAD)
		return 0;
	pz->oop = op;
	if (!(pz->flags & PZ_NOGZIP))
		sfdcgzip(op, 0);
	if (pz->flags & PZ_NOPZIP)
		return 0;
	sfputc(op, PZ_MAGIC_1);
	sfputc(op, PZ_MAGIC_2);
	if (sfsync(op))
		return -1;
	sfputc(op, pz->major = PZ_MAJOR);
	sfputc(op, pz->minor = PZ_MINOR);
	sfputu(op, pz->win);
	if (pz->disc->comment)
	{
		sfputc(op, PZ_HDR_comment);
		m = strlen(pz->disc->comment) + 1;
		sfputu(op, m);
		sfwrite(op, pz->disc->comment, m);
	}
	if (pz->det && (m = sfstrtell(pz->det)))
	{
		sfputc(op, PZ_HDR_options);
		if (!(s = sfstruse(pz->det)))
		{
			if (pz->disc->errorf)
				(*pz->disc->errorf)(pz, pz->disc, ERROR_SYSTEM|2, "out of space");
			return -1;
		}
		m++;
		sfputu(op, m);
		sfwrite(op, s, m);
	}
	if (i = pz->prefix.count)
	{
		sfputc(op, PZ_HDR_prefix);
		if (pz->prefix.terminator >= 0)
		{
			m = 0;
			while (i-- > 0)
			{
				if (!(s = sfgetr(pz->io, pz->prefix.terminator, 0)))
				{
					if (pz->disc->errorf)
						(*pz->disc->errorf)(pz, pz->disc, 2, "%s: cannot read %I*u prefix record%s from data", pz->path, sizeof(pz->prefix.count), pz->prefix.count, pz->prefix.count == 1 ? "" : "s");
					return -1;
				}
				m += n = sfvalue(pz->io);
				sfwrite(pz->tmp, s, n);
			}
			s = sfstrseek(pz->tmp, 0, SEEK_SET);
		}
		else
		{
			m = i;
			if (!(s = (char*)sfreserve(pz->io, m, 0)))
			{
				if (pz->disc->errorf)
					(*pz->disc->errorf)(pz, pz->disc, 2, "%s: cannot read %I*u prefix byte%s from data", pz->path, sizeof(pz->prefix.count), pz->prefix.count, pz->prefix.count == 1 ? "" : "s");
				return -1;
			}
		}
		sfputu(op, m);
		sfwrite(op, s, m);
	}
	pz->flags |= PZ_HEAD;
	return pzpartwrite(pz, op);
}
Пример #10
0
int
main(int argc, char** argv)
{
	char*	s;

	NoP(argc);
	if (s = strrchr(*argv, '/')) s++;
	else s = *argv;
	ed.restricted = streq(s, "red");
	error_info.id = s;
	error_info.write = helpwrite;
	init();
	for (;;)
	{
		for (;;) {
			switch (optget(argv, usage)) {

			case 'O':
				ed.reflags |= REG_LENIENT;
				continue;

			case 'S':
				ed.reflags &= ~REG_LENIENT;
				continue;

			case 'h':
				ed.help = 1;
				continue;

			case 'o':
				ed.msg = sfstderr;
				sfstrseek(ed.buffer.file, 0, SEEK_SET);
				sfputr(ed.buffer.file, "/dev/stdout", 0);
				continue;

			case 'p':
				sfstrseek(ed.buffer.prompt, 0, SEEK_SET);
				sfputr(ed.buffer.prompt, opt_info.arg, 0);
				ed.prompt = 1;
				continue;

			case 'q':
				signal(SIGQUIT, SIG_DFL);
				ed.verbose = 1;
				continue;

			case 's':
				ed.verbose = 0;
				continue;

			case '?':
				ed.help++;
				error(ERROR_USAGE|4, "%s", opt_info.arg);
				ed.help--;
				break;

			case ':':
				ed.help++;
				error(2, "%s", opt_info.arg);
				ed.help--;
				continue;

			}
			break;
		}
		if (!*(argv += opt_info.index) || **argv != '-' || *(*argv + 1))
			break;
		ed.verbose = 0;
	}
	if (*argv) {
		if (*(argv + 1))
			error(ERROR_USAGE|4, "%s", optusage(NiL));
		sfprintf(ed.buffer.global, "e %s", *argv);
		if (!(ed.global = sfstruse(ed.buffer.global)))
			error(ERROR_SYSTEM|3, "out of space");
	}
	edit();
	sfdcslow(sfstdin);
	setjmp(ed.again);
	commands();
	quit(0);
	exit(0);
}
Пример #11
0
static void
commands(void)
{
	register Line_t*	a1;
	register int		c;
	register int		n;
	char*			s;
	int			lastsep;

	for (;;) {
		trap();
		if (ed.print & (REG_SUB_LIST|REG_SUB_NUMBER|REG_SUB_PRINT)) {
			ed.addr1 = ed.addr2 = ed.dot;
			print();
		}
		if (!ed.global) {
			ed.evented = 0;
			if (ed.prompt > 0)
				sfputr(ed.msg, sfstrbase(ed.buffer.prompt), -1);
		}
		if ((c = getchr()) == ',' || c == ';') {
			ed.given = 1;
			ed.addr1 = (lastsep = c) == ',' ? ed.zero + 1 : ed.dot;
			a1 = ed.dol;
			c = getchr();
		}
		else {
			ed.addr1 = 0;
			ed.peekc = c;
			c = '\n';
			for (;;) {
				lastsep = c;
				a1 = address();
				c = getchr();
				if (c != ',' && c != ';')
					break;
				if (lastsep == ',')
					error(2, "invalid address");
				if (!a1) {
					a1 = ed.zero + 1;
					if (a1 > ed.dol)
						a1--;
				}
				ed.addr1 = a1;
				if (c == ';')
					ed.dot = a1;
			}
			if (lastsep != '\n' && !a1)
				a1 = ed.dol;
		}
		if (!(ed.addr2 = a1)) {
			ed.given = 0;
			ed.addr2 = ed.dot;	
		}
		else
			ed.given = 1;
		if (!ed.addr1)
			ed.addr1 = ed.addr2;
		switch (c) {

		case 'a':
			add(0);
			continue;

		case 'c':
			nonzero();
			newline();
			rdelete(ed.addr1, ed.addr2);
			append(getline, ed.addr1 - 1, NiL);
			continue;

		case 'd':
			nonzero();
			newline();
			rdelete(ed.addr1, ed.addr2);
			continue;

		case 'E':
			ed.modified = 0;
			c = 'e';
			/*FALLTHROUGH*/
		case 'e':
			setnoaddr();
			if (ed.verbose && ed.modified) {
				ed.modified = 0;
				error(2, "modified data not written");
			}
			/*FALLTHROUGH*/
		case 'r':
			filename(c);
			setwide();
			squeeze(0);
			c = ed.zero != ed.dol;
			append(getfile, ed.addr2, NiL);
			ed.modified = c;
			exfile();
			continue;

		case 'f':
			setnoaddr();
			filename(c);
			putrec(sfstrbase(ed.buffer.file));
			continue;

		case 'G':
			global(1, 1);
			continue;

		case 'g':
			global(1, 0);
			continue;

		case 'H':
			ed.help = !ed.help;
			/*FALLTHROUGH*/
		case 'h':
			setnoaddr();
			newline();
			if (ed.help || c == 'h')
				sfputr(ed.msg, sfstrbase(ed.buffer.help), '\n');
			continue;

		case 'i':
			add(-1);
			continue;

		case 'j':
			if (!ed.given)
				ed.addr2++;
			newline();
			join();
			continue;

		case 'k':
			nonzero();
			if ((c = getchr()) == EOF || (c -= MARK_MIN) < 0 || c >= elementsof(ed.marks))
				error(2, "invalid mark");
			newline();
			ed.addr2->offset |= LINE_MARKED;
			ed.marks[c] = ed.addr2->offset & ~LINE_GLOBAL;
			ed.marked = 1;
			continue;

		case 'm':
			move(0);
			continue;

		case 'n':
			ed.print |= REG_SUB_NUMBER;
			newline();
			print();
			continue;

		case '\n':
			if (!a1) {
				a1 = ed.dot + 1;
				ed.addr2 = a1;
				ed.addr1 = a1;
			}
			if (lastsep == ';')
				ed.addr1 = a1;
			print();
			continue;

		case 'l':
			ed.print |= REG_SUB_LIST;
			/*FALLTHROUGH*/
		case 'p':
			newline();
			print();
			continue;

		case 'P':
			setnoaddr();
			s = getrec(ed.buffer.line, '\n', 0);
			if (*s || !(ed.prompt = -ed.prompt) && (s = "*")) {
				sfstrseek(ed.buffer.prompt, 0, SEEK_SET);
				sfputr(ed.buffer.prompt, s, 0);
				ed.prompt = 1;
			}
			continue;

		case 'Q':
			ed.modified = 0;
			/*FALLTHROUGH*/
		case 'q':
			setnoaddr();
			newline();
			quit(0);
			continue;

		case 'S':
			setnoaddr();
			newline();
			s = strchr(usage, '\n') + 5;
			sfprintf(ed.msg, "file=\"%s\"%s%s%s prompt=\"%s\" tmp=%lu%s event=%lu version=\"%-.*s\"\n", sfstrbase(ed.buffer.file), ed.modified ? " modified" : "", ed.help ? " help" : "", ed.verbose ? " verbose" : "", sfstrbase(ed.buffer.prompt), ed.tmpoff, ed.tmpoff > BLOCK_TMP ? "[file]" : "", ed.event, strchr(s, '\n') - s, s);
			continue;

		case 's':
			nonzero();
			substitute(ed.global != 0);
			continue;

		case 't':
			move(1);
			continue;

		case 'u':
			setnoaddr();
			newline();
			undo();
			continue;

		case 'V':
			global(0, 1);
			continue;

		case 'v':
			global(0, 0);
			continue;

		case 'W':
		case 'w':
			setwide();
			squeeze(ed.dol > ed.zero);
			if ((n = getchr()) != 'q' && n != 'Q') {
				ed.peekc = n;
				n = 0;
			}
			filename(c);
			if (ed.dol > ed.zero)
				putfile();
			exfile();
			if (n == 'Q' || ed.addr1 <= ed.zero + 1 && ed.addr2 == ed.dol)
				ed.modified = 0;
			if (n)
				quit(0);
			continue;

		case 'z':
			nonzero();
			page();
			continue;

		case '=':
			setwide();
			squeeze(0);
			newline();
			sfprintf(ed.msg, "%d\n", ed.addr2 - ed.zero);
			continue;

		case '!':
			if (ed.restricted)
				error(2, "%c: restricted command", c);
			shell();
			continue;

		case '#':
			setnoaddr();
			getrec(ed.buffer.line, '\n', REC_IGNORE);
			continue;

		case EOF:
			return;

		}
		error(2, "unknown command");
	}
}
Пример #12
0
static void
filename(int c)
{
	register char*	p;
	register int	sh = 0;

	ed.bytes = 0;
	ed.lines = 0;
	p = getrec(ed.buffer.line, '\n', REC_LINE);
	if (*p) {
		if (!isspace(*p))
			error(2, "no space after command");
		for (p++; isspace(*p); p++)
			;
		if (!*p)
			error(2, "file name expected");
		if (c != 'f') {
			if (*p == '!') {
				p++;
				sh = 1;
			}
			else if (*p == '\\' && *(p + 1) == '!')
				p++;
		}
		if (ed.restricted) {
			register char*	s = p;

			if (sh)
				p--;
			else
				for (;;)
				{
					switch (*s++)
					{
					case 0:
						break;
					case '/':
					case '\n':
					case '\\':
						sh = 1;
						break;
					default:
						continue;
					}
					break;
				}
			if (sh)
				error(2, "%s: restricted file name", p);
		}
		if (!sh && (!*sfstrbase(ed.buffer.file) || c == 'e' || c == 'f')) {
			sfstrseek(ed.buffer.file, 0, SEEK_SET);
			sfputr(ed.buffer.file, p, 0);
		}
		if (c == 'f')
			return;
	}
	else if (c == 'f')
		return;
	else if (!*(p = sfstrbase(ed.buffer.file)))
		error(2, "file name expected");
	if (c == 'e') {
		edit();
		ed.addr2 = ed.zero;
	}
	if (sh) {
		if (!(ed.iop = sfpopen(NiL, p, (c == 'e' || c == 'r') ? "r" : "w")))
			error(ERROR_SYSTEM|2, "%s: cannot execute shell command", p);
		p--;
	}
	else if (c == 'e' || c == 'r') {
		if (!(ed.iop = sfopen(NiL, p, "r")))
			error(ERROR_SYSTEM|2, "%s: cannot read", p);
	}
	else if ((c != 'W' || !(ed.iop = sfopen(NiL, p, "a"))) && !(ed.iop = sfopen(NiL, p, "w")))
		error(ERROR_SYSTEM|2, "%s: cannot write", p);
	error_info.file = p;
}
Пример #13
0
static void
shell(void)
{
	register char*	s;
	register char*	f = 0;
	register int	c;

	if (ed.given)
		squeeze(ed.dol > ed.zero);
	s = getrec(ed.buffer.line, '\n', 0);
	if (s[0] == '!' && !s[1]) {
		if (!*sfstrbase(ed.buffer.shell))
			error(2, "no saved shell command");
		f = sfstrbase(ed.buffer.file);
	}
	else if (!s[0])
		error(2, "empty shell command");
	else
		SWP(ed.buffer.shell, ed.buffer.line);
	s = sfstrbase(ed.buffer.shell);
	sfstrseek(ed.buffer.line, 0, SEEK_SET);
	sfputc(ed.buffer.line, '!');
	while (c = *s++) {
		if (c == '\\') {
			if (*s != '%')
				sfputc(ed.buffer.line, c);
			sfputc(ed.buffer.line, *s++);
		}
		else if (c == '%')
			sfputr(ed.buffer.line, f = sfstrbase(ed.buffer.file), -1);
		else
			sfputc(ed.buffer.line, c);
	}
	if (ed.given) {
		if (!ed.tmpfile && !(ed.tmpfile = pathtemp(NiL, 0, NiL, error_info.id, NiL)))
			error(ERROR_SYSTEM|2, "cannot generate temp file name");
		if (!(ed.iop = sfopen(NiL, ed.tmpfile, "w")))
			error(ERROR_SYSTEM|2, "%s: cannot create temp file", ed.tmpfile);
		error_info.file = ed.tmpfile;
		if (ed.dol > ed.zero)
			putfile();
		exfile();
		ed.bytes = 0;
		ed.lines = 0;
		sfprintf(ed.buffer.line, " < %s", ed.tmpfile);
		if (!(s = sfstruse(ed.buffer.line)))
			error(ERROR_SYSTEM|3, "out of space");
		if (!(ed.iop = sfpopen(NiL, s + 1, "r")))
			error(ERROR_SYSTEM|2, "%s: cannot execute shell command", s);
		error_info.file = s;
		rdelete(ed.addr1, ed.addr2);
		append(getfile, ed.dot, NiL);
		exfile();
		remove(ed.tmpfile);
	}
	else {
		if (!(s = sfstruse(ed.buffer.line)))
			error(ERROR_SYSTEM|3, "out of space");
		s++;
		if (f)
			putrec(s);
		if (!(ed.iop = sfpopen(NiL, s, "")))
			error(ERROR_SYSTEM|2, "%s: cannot execute shell command", s);
		if (sfclose(ed.iop)) {
			ed.iop = 0;
			error(ERROR_SYSTEM|2, "%s: shell command exit error", s);
		}
		if (ed.verbose)
			putrec("!");
	}
}
Пример #14
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;
}
Пример #15
0
static void
act(register Ftw_t* ftw, int op)
{
	char*	s;
	Sfio_t*	fp;
	int	i;
	int	j;
	int	k;
	int	n;
	int	r;

	switch (op)
	{
	case ACT_CMDARG:
		if ((i = cmdarg(state.cmd, ftw->path, ftw->pathlen)) >= state.errexit)
			exit(i);
		break;
	case ACT_CODE:
		if (findwrite(state.find, ftw->path, ftw->pathlen, (ftw->info & FTW_D) ? "system/dir" : (char*)0))
			state.finderror = 1;
		break;
	case ACT_CODETYPE:
		fp = sfopen(NiL, PATH(ftw), "r");
		if (findwrite(state.find, ftw->path, ftw->pathlen, magictype(state.magic, fp, PATH(ftw), &ftw->statb)))
			state.finderror = 1;
		if (fp)
			sfclose(fp);
		break;
	case ACT_EVAL:
		eval(state.action, ftw);
		break;
	case ACT_INTERMEDIATE:
		intermediate(ftw, ftw->path);
		break;
	case ACT_LIST:
		sfputr(sfstdout, ftw->path, '\n');
		break;
	case ACT_SNAPSHOT:
		print(state.snapshot.tmp, ftw, state.snapshot.format.path);
		sfputc(state.snapshot.tmp, state.snapshot.format.delim);
		i = sfstrtell(state.snapshot.tmp);
		print(state.snapshot.tmp, ftw, state.snapshot.format.easy);
		j = sfstrtell(state.snapshot.tmp);
		s = sfstrbase(state.snapshot.tmp);
		r = SNAPSHOT_new;
		if (!state.snapshot.prev)
			k = 1;
		else
		{
			do
			{
				if (!(k = urlcmp(state.snapshot.prev, s, state.snapshot.format.delim)))
				{
					r = SNAPSHOT_changed;
					if (!(k = memcmp(state.snapshot.prev + i, s + i, j - i) || state.snapshot.prev[j] != state.snapshot.format.delim))
					{
						if ((n = (int)sfvalue(sfstdin)) > 4 && state.snapshot.prev[n-2] == state.snapshot.format.delim)
						{
							sfwrite(sfstdout, state.snapshot.prev, n - 4);
							sfputc(sfstdout, '\n');
						}
						else
							sfwrite(sfstdout, state.snapshot.prev, n);
					}
				}
				else if (k > 0)
					break;
				else if (k < 0 && (n = (int)sfvalue(sfstdin)) > 4 && (state.snapshot.prev[n-2] != state.snapshot.format.delim || state.snapshot.prev[n-3] != SNAPSHOT_deleted))
				{
					sfwrite(sfstdout, state.snapshot.prev, n - (state.snapshot.prev[n-2] == state.snapshot.format.delim ? 4 : 1));
					sfputc(sfstdout, state.snapshot.format.delim);
					sfputc(sfstdout, SNAPSHOT_deleted);
					sfputc(sfstdout, state.snapshot.format.delim);
					sfputc(sfstdout, '\n');
					if (state.cmdflags & CMD_TRACE)
						error(1, "%s deleted", ftw->path);
				}
				if (!(state.snapshot.prev = sfgetr(sfstdin, '\n', 0)))
					break;
			} while (k < 0);
		}
		if (k)
		{
			if (state.snapshot.format.hard && (ftw->info & FTW_F))
			{
				sfputc(state.snapshot.tmp, state.snapshot.format.delim);
				print(state.snapshot.tmp, ftw, state.snapshot.format.hard);
			}
			sfputc(state.snapshot.tmp, state.snapshot.format.delim);
			sfputc(state.snapshot.tmp, r);
			sfputc(state.snapshot.tmp, state.snapshot.format.delim);
			sfputr(sfstdout, sfstruse(state.snapshot.tmp), '\n');
			if (state.cmdflags & CMD_TRACE)
				error(1, "%s %s", ftw->path, r == SNAPSHOT_new ? "new" : "changed");
		}
		else
			sfstrseek(state.snapshot.tmp, SEEK_SET, 0);
		break;
	}
}
Пример #16
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);
}