/*
 * make.c - a program for maintaining computer programs
 *	written by MORI, Koichiro (kmori@mixcosy)
 */

static char rcsID[] = "$Header: RCS/make.c 1.13 90/11/02 11:48:00 kmori Exp $";

/*
 * Compile switch
 *	-DOLDLSIFASHION		Set if '<' & '.PATH' required
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <time.h>
#include <dos.h>
#pragma	nonrec



char	Usage[] = "\
Make (C) 1987-1990 by MORI, Koichiro $Revision: 1.13 $\n\
Usage: make [options] [MACRO=value] [targets...]\n\
options:\n\
	-f FILE	read make command from file 'FILE'\n\
	-i	ignore return code\n\
	-k	make targets as many as possible\n\
	-n	do not execute; print what will be done\n\
	-r	do not use makedef\n\
	-s	do work silently\n\
	-t	only update timestamps\n\
";

typedef	char	bool;
#define	YES	1
#define	NO	0


typedef	struct command {
	struct command	*next;
	char		body[0];
} command;


typedef	struct	atom	{
	struct	atom	*next;
	char		*name;
	char		*macro;
	struct	list	*src;
	command		*commands;
	time_t		uptime;
	bool		visit;
	bool		userdef;
	char		type;
} ATOM;

typedef	struct	list	{
	struct	list	*next;
	struct	atom	*atom;
} LIST;



bool	Nflag, Tflag, Sflag, Iflag, Dflag, Kflag;	/* make options */

bool	Case;		/* true if differentiating upper/lower case */
bool	BsdMacro;	/* true if ${..} treated as macro expansion */



#define	MAXBACK	2048

FILE	*Mfp;
char	*Mfile;
int	Lineno;
char	Backs[MAXBACK];
char	*Backp = Backs;

#define	MAXNAME	100



#define	forall(x, y)	for ((x) = (y); (x) != NULL; (x) = (x)->next)



/*
 *
 */


void	error(char *p, char *str)
{
	fprintf(stderr, "make: ");
	if (Mfp != NULL)
		fprintf(stderr, "%s %d: ", Mfile, Lineno);
	fprintf(stderr, p, str);
	exit(1);
}



#define	new(t, n)	((t *)rawnew(sizeof(t) * (n)))
void	*rawnew(unsigned size)
{
	void	*p;

	if ((p = calloc(size, 1)) == NULL)
		error("out of memory\n", NULL);
	return (p);
}


int	cmpsym(char *s, char *t)
{
	if (Case)
		return (strcmp(s, t));
	for (; *s && tolower(*s) == tolower(*t); s++, t++)
		;
	return (*s - *t);
}






#define	NHASH	1024
static	ATOM	*Atoms[NHASH];

unsigned hash(char *s)
{
	unsigned n;

	n = 0;
	while (*s)
		n = n * 129 + tolower(*s++);
	return (n % NHASH);
}


ATOM	*lookup1(char *name, bool reg)
{
	ATOM	*a;
	char	*s;
	unsigned n;

	forall (a, Atoms[n = hash(name)]) {
		if (cmpsym(a->name, name) == 0)
			return (a);
	}
	if (*name != '.' && (s = getenv(name)) != NULL) {
		a = new(ATOM, 1);
		a->name = strcpy(new(char, strlen(name) + 1), name);
		a->next = Atoms[n];
		Atoms[n] = a;
		a->macro = s;
		return (a);
	}
	if (reg) {
		a = new(ATOM, 1);
		a->name = strcpy(new(char, strlen(name) + 1), name);
		a->next = Atoms[n];
		Atoms[n] = a;
		return (a);
	}
	return (NULL);
}

#define	lookup(name)	lookup1(name, 0)
#define	intern(name)	lookup1(name, 1)




/*
 *	Module get/put
 */

int	unget(int c)
{
	if (c == EOF)
		return (EOF);
	if (Backp >= Backs + MAXBACK)
		error("can't unget (maybe too long macro)\n", NULL);
	return (*Backp++ = c);
}


void	ungets(char *s)
{
	char	*p;

	for (p = s + strlen(s); --p >= s; )
		unget((int)*p);
}


int	quoget()
{
	int	c;

	if (Backp > Backs)
		return (*--Backp);
	if (Mfp == NULL)
		return (EOF);
	c = getc(Mfp);
	if (c == '\n')
		Lineno++;
}



static char Longmsg[] = "Too long identifier: %s...\n";


int	get()
{
	char	name[MAXNAME + 1];
	char	*p;
	int	c, term;
	ATOM	*m;

	for (;;) {
		if ((c = quoget()) != '$' || (c = quoget()) == '$')
			return (c);
		if (!BsdMacro && c == '{')
			return (-'{');
		if (c == '@' || c == '<' || c == '*' || c == '>' || c == '?' ||
			c == '#' || c == '&' || c == '[' || c == ':')
			return (-c);
		/* do macro evaluation */
		p = name;
		if (c == '(' || c == '{') {
			term = c == '(' ? ')' : '}';
			while ((c = quoget()) != term) {
				if (p >= name + MAXNAME) {
					*p = '\0';
					error(Longmsg, name);
				}
				*p++ = c;
			}
		}
		else if (!BsdMacro && (isalpha(c) || isdigit(c))) {
			while (isalpha(c) || isdigit(c)) {
				if (p >= name + MAXNAME) {
					*p = '\0';
					error(Longmsg, name);
				}
				*p++ = c;
				c = quoget();
			}
			unget(c);
		}
		else
			*p++ = c;
		*p = '\0';
		if ((m = lookup(name)) != NULL && m->macro != NULL)
			ungets(m->macro);
	}
}


/*
 */


	static	ATOM	*Backtok = NULL;


bool	isbreak(int c)
{
	return (c == ' ' || c == '\t' || c == '\n' ||
		c == EOF || c == '=' || c == '#' || c == '<');
}

bool	ColonBreak = NO;

ATOM	*gettok()
{
	char	buf[MAXNAME + 1];
	char	*p;
	int	c, b;
	ATOM	*a;

	if ((a = Backtok) != NULL) {
		Backtok = NULL;
		return (a);
	}
	for (;;) {
		while ((c = get()) == ' ' || c == '\t')
			;
		if (c != '\\')
			break;
		if ((b = get()) != '\n') {
			unget(b);
			break;
		}
	}
	if (c == '#')
		while ((c = quoget()) != '\n' && c != EOF)
			;
	p = buf;
	if (c == EOF)
		return (NULL);
	else if (c == '\n' || c == ':' || c == '=' || c == '<' || c == ';')
		*p++ = c;
	else {
		while (! isbreak(c)) {
			if (c == ':' && ColonBreak && isbreak(unget(get())))
				break;
			if (p >= buf + MAXNAME) {
				*p = '\0';
				error(Longmsg, buf);
			}
			*p++ = c;
			c = get();
		}
		unget(c);
	}
	*p = '\0';
	return (intern(buf));
}



void	ungettok(ATOM *a)
{
	if (Backtok != NULL)
		error("can't ungettok\n", NULL);
	Backtok = a;
}



/* reserve some keywords */

ATOM	*NEWLINE, *EQUAL, *COLON, *LESS, *SEMICOLON,
	*SUFFIXES, *IGNORE, *SILENT, *MFLAGS, *MAKE, *CASE, *MACRO;

void	initgettok()
{
	NEWLINE	= intern("\n");
	EQUAL	= intern("=");
	COLON	= intern(":");
	LESS	= intern("<");
	SEMICOLON = intern(";");
	SUFFIXES = intern(".SUFFIXES");
	IGNORE = intern(".IGNORE");
	SILENT = intern(".SILENT");
	CASE = intern(".CASE");
	MACRO = intern(".MACRO");
	MFLAGS = intern("MFLAGS");
	MAKE = intern("MAKE");
}





LIST	*cons(ATOM *atom, LIST *next)
{
	LIST	*l;

	l = new(LIST, 1);
	l->next = next;
	l->atom = atom;
	return (l);
}

recursive LIST	*append(LIST *x, LIST *y)
{
	return (x == NULL ? y : cons(x->atom, append(x->next, y)));
}


recursive LIST	*getlist()
{
	ATOM	*s;

	if ((s = gettok()) == NULL || s == NEWLINE ||
		s == LESS || s == EQUAL || s == COLON || s == SEMICOLON) {
		ungettok(s);
		return (NULL);
	}
	return (cons(s, getlist()));
}


static	char	Lines[2048];

command	*getcom(ATOM *t)
{
	int	c;
	char	*s;
	command	*p, *q;

	p = NULL;
	for (;;) {
		c = quoget();
		if (c == '#') {
			while ((c = quoget()) != '\n' && c != EOF)
				;
			continue;
		} else if (t != SEMICOLON && c != '\t')
			break;
		t = NULL;
		while (c == ' ' || c == '\t')
			c = quoget();
		s = Lines;
		while (c != '\n' && c != EOF) {
			*s++ = c;
			c = quoget();
		}
		*s++ = '\n';
		*s++ = '\0';
		q = rawnew(sizeof(command) + (s - Lines));
		strcpy(q->body, Lines);
		q->next = p;
		p = q;
	}
	unget(c);
	return (p);
}


char	*getline()
{
	int	c;
	char	*s;

	while ((c = quoget()) == ' ' || c == '\t')
		;
	s = Lines;
	while (c != '\n' && c != EOF) {
		*s = c;
		c = quoget();
		if (*s == '\\' && c == '\n') {
			while ((c = quoget()) == ' ' || c == '\t')
				;
		} else {
			s++;
		}
	}
	*s++ = '\0';
	return (strcpy(new(char, s - Lines), Lines));
}


bool	exist(char *file)
{
	int	fd;

	if ((fd = open(file, 0)) < 0)
		return (NO);
	close(fd);
	return (YES);
}

time_t	timeof(ATOM *file)
{
	time_t	times[2];

	if (file->uptime != 0)
		return (file->uptime);
	if (gftime(file->name, times))
		return (0);
	return (file->uptime = times[1]);
}


void	touch(ATOM *file)
{
	time_t	times[2];

	file->uptime = times[0] = times[1] = time(0);
	utime(file->name, times);
}



void	setcommand(ATOM *atom, command *com)
{
	if (com == NULL)
		return;
	if (atom->name[0] != '.' &&
		atom->commands != NULL && atom->commands != com)
		error("2 or more commands for '%s'\n", atom->name);
	atom->commands = com;
}


ATOM	*readmake(char *fn)
{
	ATOM	*a, *deftar;
	LIST	*l, *r, *f;
	char	type;
	command	*com;
	char	*mac;

	errno = 0;
	Mfile = fn;
	Lineno = 1;
	if (strcmp(fn, "-") == 0)
		Mfp = stdin;
	else
		if ((Mfp = fopen(fn, "r")) == NULL)
			return (NULL);
	deftar = NULL;
	ColonBreak = YES;
	while ((a = gettok()) != NULL) {
		if (a == NEWLINE)
			continue;
		ungettok(a);
		l = getlist();
		if ((type = ':', (a = gettok()) == COLON) ||
			(type = '<', a == LESS)) {
		/* dependency line */
			ColonBreak = NO;
			r = getlist();
			ColonBreak = YES;
			if ((a = gettok()) != NEWLINE && a != SEMICOLON)
				error("bad delimiter: '%s'\n", a->name);
			com = getcom(a);
			forall (f, l) {
				if (f->atom == SILENT)
					Sflag = YES;
				else if (f->atom ==  IGNORE)
					Iflag = YES;
				else if (f->atom == SUFFIXES && r == NULL)
					f->atom->src = NULL;
				else if (f->atom == CASE)
					Case = YES;
				else if (f->atom == MACRO)
					BsdMacro = YES;
				setcommand(f->atom, com);
				f->atom->src = append(f->atom->src, r);
				if (deftar == NULL && f->atom->name[0] != '.')
					deftar = f->atom;
				f->atom->type = type;
			}
		} else if (a == EQUAL) {
		/* macro definition */
			mac = getline();
			forall (f, l)
				if (! f->atom->userdef)
					f->atom->macro = mac;
		} else
			error("missing ':' after '%s'\n", l->atom->name);
	}
	fclose(Mfp);
	Mfp = NULL;
	return (deftar);
}


char	*suffix(char *s)
{
	char	*p;

	p = NULL;
	while (*s) {
		if (*s == '.')
			p = s;
		s++;
	}
	return (p ? p : s);
}


char	*prefix(char *buf, char *s)
{
	char	*p, *d;

	p = suffix(s);
	d = buf;
	while (s < p)
		*d++ = *s++;
	*d = '\0';
	return (buf);
}


char	*barename(char *s)
{
	char	*p, c;

	p = s;
	while (c = *p++)
		if (c == ':' || c == '\\' || c == '/')
			s = p;
	return (s);
}


void	complete_unix(ATOM *tar)	/* complete commands */
{
	LIST	*l;
#ifdef	OLDLSIFASHION
	LIST	*m;
#endif
	ATOM	*a, *b, *p;
	char	*path, *s, *t, delim, c;
	char	buff[MAXNAME * 2];

	/* search .SUFFIXES */
	forall (l, SUFFIXES->src) {
		strcat(strcpy(buff, l->atom->name), suffix(tar->name));
		if ((a = lookup(buff)) == NULL || a->commands == NULL)
			continue;
		strcat(prefix(buff, tar->name), l->atom->name);
		if (Dflag)
			fprintf(stderr, "searching %s...", buff);
		if (lookup(buff) || exist(buff)) {
			if (Dflag)
				fprintf(stderr, "found\n");
			b = intern(buff);
			tar->src = cons(b, tar->src);
			if (tar->commands == NULL)
				tar->commands = a->commands;
			return;
		}
		if (Dflag)
			putchar('\n');
	}
#ifdef	OLDLSIFASHION
	/* if there's PATH definition, try other directories */
	forall (m, intern(".PATH")->src) {
		forall (l, SUFFIXES->src) {
			strcat(strcpy(buff, l->atom->name), suffix(tar->name));
			if ((a = lookup(buff)) == NULL || a->commands == NULL)
				continue;
			strcpy(buff, m->atom->name);
			if (buff[0] != '\0' &&
				(c = buff[strlen(buff) - 1]) != ':' &&
					c != '\\' && c != '/')
				strcat(buff, "/");
			prefix(buff + strlen(buff), barename(tar->name));
			strcat(buff, l->atom->name);
			if (Dflag)
				fprintf(stderr, "searching %s...", buff);
			if (lookup(buff) || exist(buff)) {
				if (Dflag)
					fprintf(stderr, "found\n");
				b = intern(buff);
				tar->src = cons(b, tar->src);
				if (tar->commands == NULL)
					tar->commands = a->commands;
				return;
			}
			if (Dflag)
				putchar('\n');
		}
	}
#endif
	/* if VPATH macro is defined, try other directories */
	if ((p = lookup("VPATH")) == NULL || p->macro == NULL)
		return;
	path = p->macro;
	if ((p = lookup("VPATHDELIM")) != NULL && p->macro && *p->macro)
		delim = *p->macro;
	else
		delim = ':';
	while (*path) {
		forall (l, SUFFIXES->src) {
			strcat(strcpy(buff, l->atom->name), suffix(tar->name));
			if ((a = lookup(buff)) == NULL || a->commands == NULL)
				continue;
			for (s = path, t = buff; *s && *s != delim; s++, t++)
				*t = *s;
			if (t > buff &&
				(c = t[-1]) != ':' && c != '\\' && c != '/')
				*t++ = '/';
			prefix(t, barename(tar->name));
			strcat(buff, l->atom->name);
			if (Dflag)
				fprintf(stderr, "searching %s...", buff);
			if (lookup(buff) || exist(buff)) {
				if (Dflag)
					fprintf(stderr, "found\n");
				b = intern(buff);
				tar->src = cons(b, tar->src);
				if (tar->commands == NULL)
					tar->commands = a->commands;
				return;
			}
			if (Dflag)
				putchar('\n');
		}
		while (*path && *path++ != delim)
			;
	}
}


#ifdef	OLDLSIFASHION
recursive
bool	makepath(ATOM *src, ATOM *tar)
{
	LIST	*l;
	char	buff[MAXNAME * 2];
	ATOM	*a, *b;

	if (tar == src)
		return (YES);
	/* search .SUFFIXES */
	forall (l, SUFFIXES->src) {
		strcat(strcpy(buff, l->atom->name), suffix(tar->name));
		if ((a = lookup(buff)) == NULL || a->command == NULL)
			continue;
		prefix(buff, src->name);
		prefix(buff + strlen(buff), a->name);
		b = intern(buff);
		if (makepath(src, b)) {
			src->type = ' ';
			tar->src = cons(b, tar->src);
			if (tar->commands == NULL)
				tar->commands = a->commands;
			return (YES);
		}
	}
	return (NO);
}




recursive
void	complsi1(LIST *src, ATOM *tar)
{
	if (src == NULL)
		return;
	complsi1(src->next, tar);
	if (! makepath(src->atom, tar))
		error("Don't know how to deal with %s\n", src->atom->name);
}


void	complete_lsi(ATOM *tar)
{
	LIST	*l, *p;

	fprintf(stderr, "Warning: old-fashioned dependency line: <\n");
	l = tar->src;
	complsi1(tar->src, tar);
	for (p = tar->src; p != NULL && p->next != l; p = p->next)
		;
	if (p != NULL)
		p->next = NULL;	/* remove old list */
	tar->type = ':';
}
#endif



#define	MAXCOLUMN	70
char	CloseChar;
FILE	*Fp;
char	*Cp;
char	Cmdline[128];
int	ExecRc;
int	Column;
char	Delim;


void	checkCp(int n)
{
	if (Cp + n > Cmdline + 127) {
		*Cp = '\0';
		fprintf(stderr, "make: Too long command line:\n");
		fprintf(stderr, "	%s...\n", Cmdline);
		exit(1);
	}
}



char	*skipsp(char *s)
{
	while (*s == ' ' || *s == '\t')
		s++;
	return (s);
}


char	*requireShell(char *s)
{
	char	c;

	while (c = *s++) {
		if (c == '<' || c == '>' || c == '|')
			return (s - 1);
		if (c == '"' || c == '\'') {
			while (*s && *s++ != c)
				;
		}
	}
	return (NULL);
}


void	exput(char c)
{
	if (ExecRc)
		return;
	if (Fp != NULL) {
		if (c == CloseChar) {
			putc('\n', Fp);
			putc('\x1A', Fp);	/* 27-Oct-1988 */
			fclose(Fp);
			Fp = NULL;
		} else {
			Column++;
			putc(c, Fp);
			if (c == '\n')
				Column = 0;
			if (Column > MAXCOLUMN && c == Delim) {
				putc('\n', Fp);
				Column = 0;
			}
		}
	} else if (c == '\n') {
		int	n, ret;
		char	*p;
		char	cmd[128];
		bool	silent = Sflag, ignore = Iflag,
			shell = NO, evergo = NO;

		*Cp = '\0';
		p = Cp = Cmdline;
		for (; ; p++) {
			if (*p == '+')
				shell = YES;
			else if (*p == '@')
				silent = YES;
			else if (*p == '-')
				ignore = YES;
			else if (*p == '*')
				evergo = YES;
			else if (*p == ' ' || *p == '\t')
				;
			else
				break;
		}
		if (*p == '#' || *p == '\0')
			return;		/* comment 06-Feb-1989 19:06 */
		if (! silent)
			fprintf(stderr, "%s\n", p);
		if (Nflag && !evergo)
			return;
		if (shell || requireShell(p))
			ret = system(p);
		else {
			n = strcspn(p, " \t");
			strncpy(cmd, p, n);
			cmd[n] = '\0';
			ret = spawnlp(0, cmd, cmd, p + n, NULL);
			if (ret < 0)
				ret = system(p);
		}
		if (! ignore && ret != 0) {
			fprintf(stderr, "\a**** Error %d\n", ret);
			if (Kflag) {
				ExecRc = ret;
				return;
			}
			exit(ret);
		}
	} else {
		checkCp(1);
		*Cp++ = c;
	}
}


void	exputs(char *s)
{
	char	c;

	while (c = *s++)
		exput(c);
}


int	execute(ATOM *tar)
{
	static	char	buf[MAXNAME + 1];
	command *p;
	int	c;
	LIST	*f;
	bool	x;

	Delim = ' ';
	ExecRc = 0;
	/* copy commands */
	for (p = tar->commands; p != NULL; p = p->next)
		ungets(p->body);
	Cp = Cmdline;
	Fp = NULL;
	while ((c = get()) != EOF) {
		switch (c) {
		case -'@':
			exputs(tar->name);
			break;
		case -'*':
			exputs(prefix(buf, tar->name));
			break;
		case -'<':
			exputs(tar->src->atom->name);
			break;
		case -'>':
			exputs(prefix(buf, tar->src->atom->name));
			break;
		case -'?':
			x = NO;
			forall (f, tar->src)
				if (timeof(f->atom) > timeof(tar)) {
					if (x)
						exput(Delim);
					exputs(f->atom->name);
					x = YES;
				}
			break;
		case -'#':
			x = NO;
			forall (f, tar->src) {
				if (x)
					exput(Delim);
				exputs(f->atom->name);
				x = YES;
			}
			break;
		case -'&':
			x = NO;
			forall (f, tar->src) {
				if (x)
					exput(Delim);
				exputs(prefix(buf, f->atom->name));
				x = YES;
			}
			break;
		case -':':
			Delim = get();
			break;
		case -'[':
			CloseChar = ']';
			goto makeresp;
		case -'{':
			CloseChar = '}';
		makeresp:
			if (Fp != NULL)
				error("can't nest $[\n", NULL);
			checkCp(6);
			strcpy(Cp, "make.i");
			Fp = fopen(Cp, "w");
			Column = 0;
			Cp += strlen(Cp);
			break;
		default:
			exput(c);
			break;
		}
	}
	if (Fp != NULL)
		error("unbalanced \n", NULL);
	return (ExecRc);
}


bool	needtodo(ATOM *tar)
{
	LIST	*f;
	time_t	tm;

	if (tar->commands != NULL && tar->src == NULL)
		return (YES);
	if ((tm = timeof(tar)) == 0)
		return (YES);
	forall (f, tar->src)
		if (timeof(f->atom) > tm)
			return (YES);
	return (NO);
}


int	Dlev;
int	Nexec;

recursive int	makethis(ATOM *tar)
{
	LIST	*f;
	int	n;

#ifdef	OLDLSIFASHION
	if (tar->type == '<')
		complete_lsi(tar);
	else
#endif
	if (tar->type != ' ' && tar->commands == NULL)
		complete_unix(tar);
	if (Dflag) {
		int	i;

		for (i = 0; i < Dlev; i++)
			fprintf(stderr, "  ");
		fprintf(stderr, "-%s\n", tar->name);
	}
	if (tar->visit)
		error("'%s' is defined recursively\n", tar->name);
	tar->visit = YES;
	Dlev++;
	n = 0;
	forall (f, tar->src)
		n |= makethis(f->atom);
	tar->visit = NO;
	Dlev--;
	if (n != 0)
		return (n);
	if (! needtodo(tar))
		return (0);
	else if (tar->commands == NULL) {
		if (tar->src == NULL)
			error("Don't know how to make %s\n", tar->name);
		return (0);
	} else if (Tflag) {
		touch(tar);
		return (0);
	} else {
		Nexec++;
		n = execute(tar);
		if (Nflag)
			tar->uptime = time(0);
		else
			tar->uptime = 0;
		return (n);
	}
}



int	domake(ATOM *tar)
{
	int	rc;

	Nexec = 0;
	if ((rc = makethis(tar)) != 0)
		fprintf(stderr, "Failed to make %s\n", tar->name);
	else if (Nexec == 0)
		fprintf(stderr, "%s is up to date.\n", tar->name);
	return (rc);
}



void	defmac(char *s)
{
	char	buf[MAXNAME + 1], *p;
	ATOM	*a;

	p = buf;
	while (*s && *s != '=') {
		if (p >= buf + MAXNAME) {
			*p = '\0';
			error(Longmsg, buf);
		}
		*p++ = *s++;
	}
	*p = '\0';
	if (*s == '=')
		s++;
	a = intern(buf);
	a->macro = s;
	a->userdef = YES;
}



char	*getfull(char *buf, char *file)
{
	int	fd;
	char	*p, *d;

	fd = -1;
	strcpy(buf, file);
	if ((fd = open(buf, 0)) < 0 && (p = getenv("PATH")) != NULL) {
		while (*p) {
			d = buf;
			while (*p && *p != ';')
				*d++ = *p++;
			if (d > buf && d[-1] != ':' && d[-1] != '\\')
				*d++ = '\\';
			strcpy(d, file);
			if ((fd = open(buf, 0)) >= 0)
				break;
			if (*p == ';')
				p++;
		}
	}
	if (fd >= 0)
		close(fd);
	else
		strcpy(buf, file);
	return (buf);
}


void	main(int argc, char *argv[])
{
	char	*makef = "makefile";
	bool	rflag = NO;
	ATOM	*tar;
	char	*p, c, buf[256], *mf;
	int	i, n, rc;

	strcpy(buf, "*make");
	mf = buf + strlen(buf);
	while (++argv, --argc != 0 && argv[0][0] == '-') {
		*mf++ = ' ';
		strcpy(mf, argv[0]);
		mf += strlen(mf);
		for (p = argv[0] + 1; c = *p++; ) {
			switch (c) {
			case 'n':
				Nflag = YES;
				break;
			case 't':
				Tflag = YES;
				break;
			case 's':
				Sflag = YES;
				break;
			case 'd':
				Dflag = YES;
				break;
			case 'r':
				rflag = YES;
				break;
			case 'i':
				Iflag = YES;
				break;
			case 'k':
				Kflag = YES;
				break;
			case 'f':
				if (--argc != 0) {
					makef = *++argv;
					*mf++ = ' ';
					strcpy(mf, makef);
					mf += strlen(mf);
					break;
				}
				/* thru */
			default:
				fprintf(stderr, Usage);
				exit(1);
			}
		}
	}

/* init gettok */
	initgettok();

/* do macro-definitions in command line */
	for (i = 0; i < argc; i++) {
		if (strchr(argv[i], '=')) {
			defmac(argv[i]);
			*mf++ = ' ';
			strcpy(mf, argv[i]);
			mf += strlen(mf);
		}
	}

/* set MAKE, MFLAGS macro */
	*mf = '\0';

	MAKE->macro = strcpy(new(char, strlen(buf) + 1), buf);
	MFLAGS->macro = MAKE->macro + 5;

/* read makefile */
	if (!rflag)
		readmake(getfull(buf, "makedef"));
	tar = readmake(makef);

/* make */
	n = 0;
	rc = 0;
	for (i = 0; i < argc; i++)
		if (strchr(argv[i], '=') == NULL) {
			rc |= domake(intern(argv[i]));
			n++;
		}
	if (n == 0) {
		if (tar == NULL) {
			if (errno) {
				fprintf(stderr, "make: ");
				perror(makef);
				exit(1);
			} else
				error("No target defined in %s\n", makef);
		}
		rc |= domake(tar);
	}
	exit(rc);
}
