scc

A fork of https://git.simple-cc.org/scc/ for Qute

git clone https://git.8pit.net/scc.git

   1#include <assert.h>
   2#include <ctype.h>
   3#include <errno.h>
   4#include <limits.h>
   5#include <stdarg.h>
   6#include <stdio.h>
   7#include <stdlib.h>
   8#include <string.h>
   9
  10#include "make.h"
  11
  12#define MAXREPL  30
  13#define TABSIZ   64
  14#define MAXTOKEN FILENAME_MAX
  15#define ITEM     128
  16
  17typedef struct macro Macro;
  18
  19enum inputype {
  20	FTFILE,
  21	FTEXPAN,
  22};
  23
  24enum {
  25	STBEGIN,
  26	STINTERNAL,
  27	STREPLACE,
  28	STTO,
  29	STEND,
  30};
  31
  32struct input {
  33	int siz;
  34	int type;
  35
  36	FILE *fp;
  37	struct loc loc;
  38
  39	int pos;
  40	char *buf;
  41
  42	struct input *prev;
  43};
  44
  45struct macro {
  46	char *name;
  47	char *value;
  48	int where;
  49
  50	struct macro *next;
  51};
  52
  53static struct input *input;
  54static char token[MAXTOKEN];
  55static int tok;
  56static Macro *htab[TABSIZ];
  57
  58void
  59dumpmacros(void)
  60{
  61	Macro **pp, *p;
  62
  63	for (pp = htab; pp < &htab[TABSIZ]; ++pp) {
  64		for (p = *pp; p; p = p->next)
  65			printf("%s = %s\n", p->name, getmacro(p->name));
  66	}
  67}
  68
  69static Macro *
  70lookup(char *name)
  71{
  72	Macro *mp;
  73	int h = hash(name) & TABSIZ-1;
  74
  75	for (mp = htab[h]; mp && strcmp(mp->name, name); mp = mp->next)
  76		;
  77
  78	if (mp)
  79		return mp;
  80
  81	mp = emalloc(sizeof(*mp));
  82	mp->name = estrdup(name);
  83	mp->value = estrdup("");
  84	mp->next = htab[h];
  85	mp->where = UNDEF;
  86	htab[h] = mp;
  87
  88	return mp;
  89}
  90
  91static char *
  92macroinfo(char *name, int *pwhere, Macro **mpp)
  93{
  94	char *s, *t;
  95	int hide, where;
  96	Macro *mp = lookup(name);
  97
  98	hide = 0;
  99	if (!strcmp(name, "SHELL") || !strcmp(name, "MAKEFLAGS"))
 100		hide = 1;
 101
 102	s = mp->value;
 103	where = mp->where;
 104
 105	if (!hide && (where == UNDEF || where == INTERNAL || eflag)) {
 106		t = getenv(name);
 107		if (t) {
 108			where = ENVIRON;
 109			s = t;
 110		}
 111	}
 112
 113	if (pwhere)
 114		*pwhere = where;
 115	if (mpp)
 116		*mpp = mp;
 117
 118	return s;
 119}
 120
 121char *
 122getmacro(char *name)
 123{
 124	return macroinfo(name, NULL, NULL);
 125}
 126
 127void
 128setmacro(char *name, char *val, int where, int export)
 129{
 130	int owhere, set;
 131	char *s;
 132	Macro *mp;
 133
 134	assert(where != ENVIRON);
 135
 136	s = macroinfo(name, &owhere, &mp);
 137
 138	/*
 139	 *  Default values are defined before anything else, and marked
 140	 *  as INTERNAL because they are injected as parseable text, and
 141	 *  MAKEFILE and INTERNAL variables are always overriden. ENVIRON
 142	 *  macros are generated in macroinfo() and this is why this function
 143	 *  should not receive a where == ENVIRON ever.
 144	 */
 145	switch (owhere) {
 146	case UNDEF:
 147	case INTERNAL:
 148	case MAKEFILE:
 149		set = 1;
 150		break;
 151	case ENVIRON:
 152		set = (where == MAKEFLAGS || where == CMDLINE);
 153		set |= (where == MAKEFILE && !eflag);
 154		break;
 155	case MAKEFLAGS:
 156		set = (where == CMDLINE || where == MAKEFLAGS);
 157		break;
 158	case CMDLINE:
 159		set = (where == CMDLINE);
 160		break;
 161	default:
 162		abort();
 163	}
 164
 165	if (!set) {
 166		debug("hidding override of %s from '%s' to '%s'", name, s, val);
 167	} else {
 168		debug("override %s from '%s' to '%s'", name, s, val);
 169		free(mp->value);
 170		mp->value = estrdup(val);
 171		mp->where = where;
 172
 173		if (export && strcmp(name, "SHELL") != 0) {
 174			debug("exporting macro %s", name);
 175			exportvar(name, val);
 176		}
 177	}
 178}
 179
 180void
 181freeloc(struct loc *loc)
 182{
 183	free(loc->fname);
 184}
 185
 186static struct loc *
 187getloc(void)
 188{
 189	struct input *ip;
 190
 191	for (ip = input; ip && ip->type != FTFILE; ip = ip->prev)
 192		;
 193	if (!ip)
 194		return NULL;
 195
 196	return &ip->loc;
 197}
 198
 199
 200void
 201error(char *fmt, ...)
 202{
 203	va_list va;
 204	struct loc *loc;
 205
 206	fprintf(stderr, "make: error: ");
 207	if ((loc = getloc()) != NULL)
 208		fprintf(stderr, "%s:%d: ", loc->fname, loc->lineno);
 209
 210	va_start(va, fmt);
 211	vfprintf(stderr, fmt, va);
 212	va_end(va);
 213	putc('\n', stderr);
 214
 215	exit(EXIT_FAILURE);
 216}
 217
 218void
 219warning(char *fmt, ...)
 220{
 221	va_list va;
 222	struct loc *loc;
 223
 224	fprintf(stderr, "make: warning: ");
 225	if ((loc = getloc()) != NULL)
 226		fprintf(stderr, "%s:%d: ", loc->fname, loc->lineno);
 227
 228	va_start(va, fmt);
 229	vfprintf(stderr, fmt, va);
 230	va_end(va);
 231	putc('\n', stderr);
 232}
 233
 234static void
 235pop(void)
 236{
 237	struct input *ip = input->prev;
 238
 239	if (input->type == FTFILE) {
 240		if (input->fp)
 241			fclose(input->fp);
 242		freeloc(&input->loc);
 243	}
 244	free(input->buf);
 245	free(input);
 246
 247	input = ip;
 248}
 249
 250static void
 251push(int type, ...)
 252{
 253	int line, len, pos;
 254	FILE *fp = NULL;
 255	char *buf, *s, *fname = NULL;
 256	va_list va;
 257	struct input *ip;
 258
 259	va_start(va, type);
 260	switch (type) {
 261	case FTFILE:
 262		fp = va_arg(va, FILE *);
 263		s = va_arg(va, char *);
 264		line = va_arg(va, int);
 265		fname = estrdup(s);
 266		buf = emalloc(BUFSIZ);
 267		pos = len = BUFSIZ;
 268		break;
 269	case FTEXPAN:
 270		s = va_arg(va, char *);
 271		buf = estrdup(s);
 272		line = pos = 0;
 273		len = strlen(s);
 274		break;
 275	}
 276	va_end(va);
 277
 278	ip = emalloc(sizeof(*ip));
 279	ip->siz = len;
 280	ip->buf = buf;
 281	ip->type = type;
 282	ip->fp = fp;
 283	ip->loc.fname = fname;
 284	ip->loc.lineno = line;
 285	ip->pos = pos;
 286	ip->prev = input;
 287
 288	input = ip;
 289}
 290
 291static char *
 292trim(char *s)
 293{
 294	size_t len;
 295
 296	while (isspace(*s))
 297		s++;
 298
 299	for (len = strlen(s); len > 0 && isspace(s[len-1]); --len)
 300		s[len-1] = '\0';
 301
 302	return s;
 303}
 304
 305static void
 306include(char *s)
 307{
 308	int len;
 309	FILE *fp;
 310	char *fil, *t;
 311
 312	s = trim(s);
 313	fil = expandstring(s, NULL, getloc());
 314
 315	t = trim(fil);
 316	if (strlen(t) != 0) {
 317		debug("including '%s'", t);
 318		if ((fp = fopen(t, "r")) == NULL)
 319			error("opening %s:%s", t, strerror(errno));
 320		push(FTFILE, fp, t, 0);
 321	}
 322
 323	free(fil);
 324}
 325
 326static char *
 327nextline(void)
 328{
 329	int c;
 330	FILE *fp;
 331	char *s, *lim;
 332
 333	assert(input->type == FTFILE);
 334
 335repeat:
 336	fp = input->fp;
 337	if (!fp || feof(fp))
 338		return NULL;
 339
 340	lim = &input->buf[input->siz];
 341	for (s = input->buf; s < lim; *s++ = c) {
 342		c = getc(fp);
 343		if (c == '\n' || c == EOF) {
 344			input->loc.lineno++;
 345			*s++ = '\n';
 346			break;
 347		}
 348		if (c > UCHAR_MAX || c < 0)
 349			error("invalid character '%c' (%d)", c, c);
 350	}
 351
 352
 353	if (s == lim)
 354		error("too long line");
 355	if (ferror(fp))
 356		error(strerror(errno));
 357	*s = '\0';
 358
 359	if (!strcmp(input->buf, ""))
 360		goto repeat;
 361
 362	if (!strncmp(input->buf, "include", 7) && isblank(input->buf[7])) {
 363		input->pos = input->siz;
 364		include(input->buf+7);
 365		goto repeat;
 366	}
 367
 368	input->pos = 0;
 369
 370
 371	return input->buf;
 372}
 373
 374static int
 375empty(struct input *ip)
 376{
 377	return ip->pos == ip->siz || ip->buf[ip->pos] == '\0';
 378}
 379
 380static int
 381moreinput(void)
 382{
 383	while (input) {
 384		if (!empty(input))
 385			break;
 386
 387		switch (input->type) {
 388		case FTEXPAN:
 389			pop();
 390			break;
 391		case FTFILE:
 392			if (!nextline())
 393				pop();
 394			break;
 395		}
 396	}
 397
 398	return input != NULL;
 399}
 400
 401static int
 402nextc(void)
 403{
 404	if (!moreinput())
 405		return EOF;
 406
 407	return input->buf[input->pos++];
 408}
 409
 410/*
 411 * This function only can be called after a call to nextc
 412 * that didn't return EOF. It can return '\0', but as
 413 * it is used only to check against '$' then it is not
 414 * a problem.
 415 */
 416static int
 417ahead(void)
 418{
 419	return input->buf[input->pos];
 420}
 421
 422static int
 423back(int c)
 424{
 425	if (c == EOF)
 426		return c;
 427	assert(input->pos > 0);
 428	return input->buf[--input->pos] = c;
 429}
 430
 431static void
 432comment(void)
 433{
 434	int c;
 435
 436	while ((c = nextc()) != EOF && c != '\n') {
 437		if (c == '\\' && nextc() == EOF)
 438			break;
 439	}
 440}
 441
 442static void
 443skipspaces(void)
 444{
 445	int c;
 446
 447	for (c = nextc(); c == ' ' || c == '\t'; c = nextc())
 448		;
 449	back(c);
 450}
 451
 452static int
 453validchar(int c)
 454{
 455	if (c == EOF)
 456		return 0;
 457	return c == '.' || c == '/' || c == '_' || c == '-' || isalnum(c);
 458}
 459
 460static char *
 461expandmacro(char *name)
 462{
 463	char *s;
 464
 465	s = expandstring(getmacro(name), NULL, getloc());
 466	debug("macro %s expanded to '%s'", name, s);
 467
 468	return s;
 469}
 470
 471static void
 472replace(char *line, char *repl, char *to)
 473{
 474	int siz, at, len, replsiz, tosiz, sep, pos;
 475	char *oline, *s, *cur, *buf;
 476
 477	debug("replacing '%s', with '%s' to '%s'", line, repl, to);
 478	oline = line;
 479	tosiz = strlen(to);
 480	replsiz = strlen(repl);
 481
 482	buf = NULL;
 483	for (pos = 0; *line; pos += siz) {
 484		cur = NULL;
 485		siz = 0;
 486
 487		for (siz = 0; *line == ' ' || *line == '\t'; ++siz) {
 488			cur = erealloc(cur, siz+1);
 489			cur[siz] = *line++;
 490		}
 491
 492		len = strcspn(line, " \t");
 493		at = len - replsiz;
 494		if (at < 0 || memcmp(line + at, repl, replsiz)) {
 495			cur = erealloc(cur, siz + len);
 496			memcpy(cur + siz, line, len);
 497			siz += len;
 498		} else {
 499			cur = erealloc(cur, siz + at + tosiz);
 500			memcpy(cur + siz, line, at);
 501			memcpy(cur + siz + at, to, tosiz);
 502			siz += at + tosiz;
 503		}
 504
 505		line += len;
 506		buf = erealloc(buf, pos + siz);
 507		memcpy(buf + pos, cur, siz);
 508		free(cur);
 509	}
 510
 511	if (pos > 0) {
 512		buf = erealloc(buf, pos + 1);
 513		buf[pos] = '\0';
 514		debug("\treplace '%s' with '%s'", oline, buf);
 515		push(FTEXPAN, buf);
 516	}
 517
 518	free(buf);
 519}
 520
 521static void
 522expandsimple(Target *tp)
 523{
 524	char *s;
 525	Target **p;
 526	int len, c;
 527
 528	switch (c = nextc()) {
 529	case '@':
 530		if (!tp || !tp->target)
 531			return;
 532		push(FTEXPAN, tp->target);
 533		break;
 534	case '<':
 535		if (!tp || !tp->req)
 536			return;
 537		push(FTEXPAN, tp->req);
 538		break;
 539	case '*':
 540		if (!tp || !tp->target)
 541			return;
 542		s = strrchr(tp->target, '.');
 543		if (!s) {
 544			push(FTEXPAN, tp->target);
 545			return;
 546		}
 547
 548		len = s - tp->target;
 549		s = emalloc(len+1);
 550		memcpy(s, tp->target, len);
 551		s[len] = '\0';
 552		push(FTEXPAN, s);
 553		free(s);
 554		break;
 555	case '?':
 556		if (!tp)
 557			return;
 558
 559		if (tp->req && stamp(tp->req) > tp->stamp) {
 560			push(FTEXPAN, " ");
 561			push(FTEXPAN, tp->req);
 562		}
 563
 564		for (p = tp->deps; p && *p; ++p) {
 565			if (stamp((*p)->name) > tp->stamp) {
 566				push(FTEXPAN, " ");
 567				push(FTEXPAN, (*p)->name);
 568			}
 569		}
 570		break;
 571	default:
 572		token[0] = c;
 573		token[1] = '\0';
 574		s = expandmacro(token);
 575		push(FTEXPAN, s);
 576		free(s);
 577		break;
 578	}
 579}
 580
 581static int
 582internal(int ch)
 583{
 584	switch (ch) {
 585	case '@':
 586	case '?':
 587	case '*':
 588	case '<':
 589		return 1;
 590	default:
 591		return 0;
 592	}
 593}
 594
 595static void
 596expansion(Target *tp)
 597{
 598	int delim, c, repli, toi, namei, st;
 599	char name[MAXTOKEN], repl[MAXREPL], to[MAXREPL];
 600	char *s, *erepl;
 601
 602	c = nextc();
 603	if (c == '(')
 604		delim = ')';
 605	else if (c == '{')
 606		delim = '}';
 607	else
 608		delim = 0;
 609
 610	if (!delim) {
 611		back(c);
 612		expandsimple(tp);
 613		return;
 614	}
 615
 616	s = NULL;
 617	namei = repli = toi = 0;
 618	st = STBEGIN;
 619
 620	while (st != STEND && (c = nextc()) != EOF) {
 621		switch (st) {
 622		case STBEGIN:
 623			if (c == ':') {
 624				st = STREPLACE;
 625				name[namei] = '\0';
 626				s = expandmacro(name);
 627				break;
 628			}
 629			if (c == delim) {
 630				name[namei] = '\0';
 631				s = expandmacro(name);
 632				goto no_replace;
 633			}
 634			if (namei == MAXTOKEN-1)
 635				error("expansion text too long");
 636
 637			if (namei == 0 && internal(c)) {
 638				name[namei++] = '$';
 639				name[namei++] = c;
 640				name[namei] = '\0';
 641				st = STINTERNAL;
 642				s = expandstring(name, tp, getloc());
 643				break;
 644			}
 645
 646			if (!validchar(c))
 647				error("invalid macro name in expansion");
 648			name[namei++] = c;
 649			break;
 650		case STINTERNAL:
 651			if (c == delim)
 652				goto no_replace;
 653			if (c != ':')
 654				error("invalid internal macro in expansion");
 655			st = STREPLACE;
 656			break;
 657		case STREPLACE:
 658			if (c == '=') {
 659				st = STTO;
 660				break;
 661			}
 662			if (c == delim)
 663				error("invalid replacement pattern in expansion");
 664			if (repli == MAXREPL-1)
 665				error("macro replacement too big");
 666			repl[repli++] = c;
 667			break;
 668		case STTO:
 669			if (c == delim) {
 670				st = STEND;
 671				break;
 672			}
 673
 674			if (toi == MAXREPL-1)
 675				error("macro substiturion too big");
 676			to[toi++] = c;
 677			break;
 678		}
 679	}
 680
 681	if (c == EOF)
 682		error("found eof while parsing expansion");
 683
 684	repl[repli] = '\0';
 685	to[toi] = '\0';
 686
 687	erepl = expandstring(repl, tp, getloc());
 688	replace(s, erepl, to);
 689
 690	free(erepl);
 691	free(s);
 692	return;
 693
 694no_replace:
 695	push(FTEXPAN, s);
 696	free(s);
 697}
 698
 699/*
 700 * Horrible hack to do string expansion.
 701 * We cannot use normal push and nextc because that
 702 * would consume characters of the current file too.
 703 * For that reason it cleans the input and it recovers
 704 * it later.
 705 */
 706char *
 707expandstring(char *line, Target *tp, struct loc *loc)
 708{
 709	int c, n;
 710	char *s;
 711	struct input *ip = input;
 712
 713	input = NULL;
 714	push(FTFILE, NULL, loc->fname, loc->lineno);
 715	push(FTEXPAN, line);
 716
 717	n = 0;
 718	s = NULL;
 719	while ((c = nextc()) != EOF) {
 720		if (c != '$') {
 721			s = erealloc(s, ++n);
 722			s[n-1] = c;
 723			continue;
 724		}
 725
 726		if ((c = nextc()) == '$') {
 727			s = erealloc(s, n += 2);
 728			s[n-2] = '$';
 729			s[n-1] = '$';
 730		} else {
 731			back(c);
 732			expansion(tp);
 733		}
 734	}
 735
 736	s = erealloc(s, n+1);
 737	s[n] = '\0';
 738	input = ip;
 739
 740	return s;
 741}
 742
 743static int
 744item(void)
 745{
 746	int c;
 747	char *s;
 748	char buf[MAXTOKEN];
 749
 750	for (s = buf; s < &buf[MAXTOKEN] - 1; ) {
 751		c = nextc();
 752		if (c == '$' && ahead() != '$')
 753			expansion(NULL);
 754		else if (validchar(c))
 755			*s++ = c;
 756		else
 757			break;
 758	}
 759	back(c);
 760
 761	if (s >= &buf[MAXTOKEN] - 1)
 762		error("token too long");
 763	if (s == buf)
 764		error("invalid empty token");
 765	*s++ = '\0';
 766	memcpy(token, buf, s - buf);
 767
 768	return ITEM;
 769}
 770
 771static int
 772next(void)
 773{
 774	int c;
 775
 776repeat:
 777	/*
 778	 * It is better to avoid skipspaces() here, because
 779	 * it can generate the need for 2 calls to back(),
 780	 * and we need the character anyway.
 781	 */
 782	c = nextc();
 783	if (c == ' ' || c == '\t')
 784		goto repeat;
 785
 786	if (c == '\\') {
 787		if ((c = nextc()) == '\n')
 788			goto repeat;
 789		back(c);
 790		c = '\\';
 791	}
 792
 793	switch (c) {
 794	case EOF:
 795		strcpy(token, "<EOF>");
 796		tok = EOF;
 797		break;
 798	case '$':
 799		if ((c = nextc()) == '$')
 800			goto single;
 801		back(c);
 802		expansion(NULL);
 803		goto repeat;
 804	case '#':
 805		comment();
 806		c = '\n';
 807	case ';':
 808	case ':':
 809	case '=':
 810	case '\n':
 811	single:
 812		token[0] = c;
 813		token[1] = '\0';
 814		tok = c;
 815		break;
 816	default:
 817		if (!validchar(c))
 818			error("unexpected character '%c'", c);
 819		back(c);
 820		tok = item();
 821		break;
 822	}
 823
 824	return tok;
 825}
 826
 827static char *
 828readmacrodef(void)
 829{
 830	int n, c;
 831	char *line;
 832
 833	n = 0;
 834	line = NULL;
 835	while ((c = nextc()) != EOF) {
 836		line = erealloc(line, n+1);
 837		if (c == '\n')
 838			break;
 839		if (c == '#') {
 840			comment();
 841			break;
 842		}
 843		if (c == '\\') {
 844			if ((c = nextc()) != '\n') {
 845				back(c);
 846				c = '\\';
 847			} else {
 848				skipspaces();
 849				c = ' ';
 850			}
 851		}
 852
 853		line[n++] = c;
 854	}
 855	if (c == EOF)
 856		error("EOF while looking for end of line");
 857	line[n] = '\0';
 858
 859	return line;
 860}
 861
 862static struct action
 863readcmd(void)
 864{
 865	int n, c;
 866	struct loc *loc;
 867	struct action act;
 868
 869	skipspaces();
 870
 871	loc = getloc();
 872	act.loc.fname = estrdup(loc->fname);
 873	act.loc.lineno = loc->lineno;
 874
 875	n = 0;
 876	act.line = NULL;
 877	while ((c = nextc()) != EOF) {
 878		act.line = erealloc(act.line, n+1);
 879		if (c == '\n')
 880			break;
 881		if (c == '\\') {
 882			if ((c = nextc()) == '\n') {
 883				if ((c = nextc()) != '\t')
 884					back(c);
 885				continue;
 886			}
 887			back(c);
 888			c = '\\';
 889		}
 890		act.line[n++] = c;
 891	}
 892	if (c == EOF)
 893		error("EOF while looking for end of command");
 894	act.line[n] = '\0';
 895
 896	return act;
 897}
 898
 899static void
 900rule(char *targets[], int ntargets)
 901{
 902	int c, i, j, ndeps, nactions;
 903	struct action *acts;
 904	char **deps = NULL;
 905
 906	if (ntargets == 0)
 907		error("missing target");
 908
 909	for (ndeps = 0; next() == ITEM; ++ndeps) {
 910		deps = erealloc(deps, (ndeps+1) * sizeof(char *));
 911		deps[ndeps] = estrdup(token);
 912	}
 913
 914	if (tok != '\n' && tok != ';')
 915		error("garbage at the end of the line");
 916
 917	nactions = 0;
 918	acts = NULL;
 919	if (tok == ';') {
 920		nactions++;
 921		acts = erealloc(acts, nactions * sizeof(*acts));
 922		acts[nactions-1] = readcmd();
 923	}
 924
 925	for (;;) {
 926		if ((c = nextc()) == '#') {
 927			comment();
 928			continue;
 929		}
 930		if (c != '\t')
 931			break;
 932		nactions++;
 933		acts = erealloc(acts, nactions * sizeof(*acts));
 934		acts[nactions-1] = readcmd();
 935	}
 936	back(c);
 937
 938	for (i = 0; i < ntargets; i++) {
 939		addtarget(targets[i], ndeps);
 940		for (j = 0; j < ndeps; j++)
 941			adddep(targets[i], deps[j]);
 942		if (nactions > 0)
 943			addrule(targets[i], acts, nactions);
 944	}
 945
 946	for (i = 0; i < ndeps; i++)
 947		free(deps[i]);
 948	free(deps);
 949
 950	for (i = 0; i < nactions; i++) {
 951		free(acts[i].line);
 952		freeloc(&acts[i].loc);
 953	}
 954	free(acts);
 955}
 956
 957static void
 958assign(char *macros[], int where, int n)
 959{
 960	char *defs;
 961
 962	if (n != 1)
 963		error("invalid macro definition");
 964
 965	skipspaces();
 966	defs = readmacrodef();
 967	setmacro(*macros, defs, where, NOEXPORT);
 968	free(defs);
 969}
 970
 971void
 972parseinput(int where)
 973{
 974	int i, n;
 975	char **targets;
 976
 977	while (moreinput()) {
 978		n = 0;
 979		targets = NULL;
 980
 981		next();
 982		if (tok == '\n')
 983			continue;
 984
 985		while (tok == ITEM) {
 986			n++;
 987			targets = erealloc(targets, n * sizeof(char *));
 988			targets[n-1] = estrdup(token);
 989			next();
 990		}
 991
 992		switch (tok) {
 993		case ':':
 994			rule(targets, n);
 995			break;
 996		case '=':
 997			assign(targets, where, n);
 998			break;
 999		default:
1000			error("unexpected token '%s'(%d)", token, tok);
1001		}
1002
1003		for (i = 0; i < n; i++)
1004			free(targets[i]);
1005		free(targets);
1006	}
1007}
1008
1009int
1010parse(char *fname)
1011{
1012	FILE *fp;
1013
1014	if (!fname) {
1015		fp = stdin;
1016		fname = "<stdin>";
1017	} else if ((fp = fopen(fname, "r")) == NULL) {
1018		return 0;
1019	}
1020
1021	debug("parsing %s", fname);
1022	push(FTFILE, fp, fname, 0);
1023	parseinput(MAKEFILE);
1024
1025	return 1;
1026}
1027
1028void
1029inject(char *s)
1030{
1031	push(FTFILE, NULL, "<internal>", 0);
1032	push(FTEXPAN, s);
1033	parseinput(INTERNAL);
1034}