plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

input.c (11496B)


      1 #include <u.h>
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 #include <string.h>
      5 #include <ctype.h>
      6 #include <errno.h>
      7 #include "grap.h"
      8 #include "y.tab.h"
      9 
     10 Infile	infile[10];
     11 Infile	*curfile = infile;
     12 
     13 #define	MAXSRC	50
     14 Src	src[MAXSRC];	/* input source stack */
     15 Src	*srcp	= src;
     16 
     17 void pushsrc(int type, char *ptr)	/* new input source */
     18 {
     19 	if (++srcp >= src + MAXSRC)
     20 		ERROR "inputs nested too deep" FATAL;
     21 	srcp->type = type;
     22 	srcp->sp = ptr;
     23 	if (dbg) {
     24 		printf("\n%3ld ", (long)(srcp - src));
     25 		switch (srcp->type) {
     26 		case File:
     27 			printf("push file %s\n", ptr);
     28 			break;
     29 		case Macro:
     30 			printf("push macro <%s>\n", ptr);
     31 			break;
     32 		case Char:
     33 			printf("push char <%c>\n", *ptr);
     34 			break;
     35 		case Thru:
     36 			printf("push thru\n");
     37 			break;
     38 		case String:
     39 			printf("push string <%s>\n", ptr);
     40 			break;
     41 		case Free:
     42 			printf("push free <%s>\n", ptr);
     43 			break;
     44 		default:
     45 			ERROR "pushed bad type %d", srcp->type FATAL;
     46 		}
     47 	}
     48 }
     49 
     50 void popsrc(void)	/* restore an old one */
     51 {
     52 	if (srcp <= src)
     53 		ERROR "too many inputs popped" FATAL;
     54 	if (dbg) {
     55 		printf("%3ld ", (long)(srcp - src));
     56 		switch (srcp->type) {
     57 		case File:
     58 			printf("pop file\n");
     59 			break;
     60 		case Macro:
     61 			printf("pop macro\n");
     62 			break;
     63 		case Char:
     64 			printf("pop char <%c>\n", *srcp->sp);
     65 			break;
     66 		case Thru:
     67 			printf("pop thru\n");
     68 			break;
     69 		case String:
     70 			printf("pop string\n");
     71 			break;
     72 		case Free:
     73 			printf("pop free\n");
     74 			break;
     75 		default:
     76 			ERROR "pop weird input %d", srcp->type FATAL;
     77 		}
     78 	}
     79 	srcp--;
     80 }
     81 
     82 void definition(char *s)	/* collect definition for s and install */
     83 				/* definitions picked up lexically */
     84 {
     85 	char *p;
     86 	Obj *stp;
     87 
     88 	p = delimstr("definition");
     89 	stp = lookup(s, 0);
     90 	if (stp != NULL) {	/* it's there before */
     91 		if (stp->type != DEFNAME) {
     92 			ERROR "%s used as variable and definition", s WARNING;
     93 			return;
     94 		}
     95 		free(stp->val);
     96 	} else {
     97 		stp = lookup(s, 1);
     98 		stp->type = DEFNAME;
     99 	}
    100 	stp->val = p;
    101 	dprintf("installing %s as `%s'\n", s, p);
    102 }
    103 
    104 char *delimstr(char *s)	/* get body of X ... X */
    105 			/* message if too big */
    106 {
    107 	int c, delim, rdelim, n, deep;
    108 	static char *buf = NULL;
    109 	static int nbuf = 0;
    110 	char *p;
    111 
    112 	if (buf == NULL)
    113 		buf = grow(buf, "buf", nbuf += 1000, sizeof(buf[0]));
    114 	while ((delim = input()) == ' ' || delim == '\t' || delim == '\n')
    115 		;
    116 	rdelim = baldelim(delim, "{}");		/* could be "(){}[]`'" */
    117 	deep = 1;
    118 	for (p = buf; ; ) {
    119 		c = input();
    120 		if (c == rdelim)
    121 			if (--deep == 0)
    122 				break;
    123 		if (c == delim)
    124 			deep++;
    125 		if (p >= buf + nbuf) {
    126 			n = p - buf;
    127 			buf = grow(buf, "buf", nbuf += 1000, sizeof(buf[0]));
    128 			p = buf + n;
    129 		}
    130 		if (c == EOF)
    131 			ERROR "end of file in %s %c %.20s... %c", s, delim, buf, delim FATAL;
    132 		*p++ = c;
    133 	}
    134 	*p = '\0';
    135 	dprintf("delimstr %s %c <%s> %c\n", s, delim, buf, delim);
    136 	return tostring(buf);
    137 }
    138 
    139 int
    140 baldelim(int c, char *s)	/* replace c by balancing entry in s */
    141 {
    142 	for ( ; *s; s += 2)
    143 		if (*s == c)
    144 			return s[1];
    145 	return c;
    146 }
    147 
    148 Arg	args[10];	/* argument frames */
    149 Arg	*argfp = args;	/* frame pointer */
    150 int	argcnt;		/* number of arguments seen so far */
    151 
    152 void dodef(Obj *stp)	/* collect args and switch input to defn */
    153 {
    154 	int i, len;
    155 	char *p;
    156 	Arg *ap;
    157 
    158 	ap = argfp+1;
    159 	if (ap >= args+10)
    160 		ERROR "arguments too deep" FATAL;
    161 	argcnt = 0;
    162 	if (input() != '(')
    163 		ERROR "disaster in dodef" FATAL;
    164 	if (ap->argval == 0)
    165 		ap->argval = malloc(1000);
    166 	for (p = ap->argval; (len = getarg(p)) != -1; p += len) {
    167 		ap->argstk[argcnt++] = p;
    168 		if (input() == ')')
    169 			break;
    170 	}
    171 	for (i = argcnt; i < MAXARGS; i++)
    172 		ap->argstk[i] = "";
    173 	if (dbg)
    174 		for (i = 0; i < argcnt; i++)
    175 			printf("arg %ld.%d = <%s>\n", (long)(ap-args), i+1, ap->argstk[i]);
    176 	argfp = ap;
    177 	pushsrc(Macro, stp->val);
    178 }
    179 
    180 int
    181 getarg(char *p)	/* pick up single argument, store in p, return length */
    182 {
    183 	int n, c, npar;
    184 
    185 	n = npar = 0;
    186 	for ( ;; ) {
    187 		c = input();
    188 		if (c == EOF)
    189 			ERROR "end of file in getarg!" FATAL;
    190 		if (npar == 0 && (c == ',' || c == ')'))
    191 			break;
    192 		if (c == '"')	/* copy quoted stuff intact */
    193 			do {
    194 				*p++ = c;
    195 				n++;
    196 			} while ((c = input()) != '"' && c != EOF);
    197 		else if (c == '(')
    198 			npar++;
    199 		else if (c == ')')
    200 			npar--;
    201 		n++;
    202 		*p++ = c;
    203 	}
    204 	*p = 0;
    205 	unput(c);
    206 	return(n + 1);
    207 }
    208 
    209 #define	PBSIZE	2000
    210 char	pbuf[PBSIZE];		/* pushback buffer */
    211 char	*pb	= pbuf-1;	/* next pushed back character */
    212 
    213 char	ebuf[200];		/* collect input here for error reporting */
    214 char	*ep	= ebuf;
    215 
    216 int	begin	= 0;
    217 extern	int	thru;
    218 extern	Obj	*thrudef;
    219 extern	char	*untilstr;
    220 
    221 int
    222 input(void)
    223 {
    224 	register int c;
    225 
    226 	if (thru && begin) {
    227 		do_thru();
    228 		begin = 0;
    229 	}
    230 	c = nextchar();
    231 	dprintf(" <%c>", c);
    232 	if (ep >= ebuf + sizeof ebuf)
    233 		ep = ebuf;
    234 	return *ep++ = c;
    235 }
    236 
    237 int
    238 nextchar(void)
    239 {
    240 	register int c;
    241 
    242 	c = 0; /* gcc */
    243 
    244   loop:
    245 	switch (srcp->type) {
    246 	case Free:	/* free string */
    247 		free(srcp->sp);
    248 		popsrc();
    249 		goto loop;
    250 	case Thru:	/* end of pushed back line */
    251 		begin = 1;
    252 		popsrc();
    253 		c = '\n';
    254 		break;
    255 	case Char:
    256 		if (pb >= pbuf) {
    257 			c = *pb--;
    258 			popsrc();
    259 			break;
    260 		} else {	/* can't happen? */
    261 			popsrc();
    262 			goto loop;
    263 		}
    264 	case String:
    265 		c = *srcp->sp++;
    266 		if (c == '\0') {
    267 			popsrc();
    268 			goto loop;
    269 		} else {
    270 			if (*srcp->sp == '\0')	/* empty, so pop */
    271 				popsrc();
    272 			break;
    273 		}
    274 	case Macro:
    275 		c = *srcp->sp++;
    276 		if (c == '\0') {
    277 			if (--argfp < args)
    278 				ERROR "argfp underflow" FATAL;
    279 			popsrc();
    280 			goto loop;
    281 		} else if (c == '$' && isdigit((uchar)*srcp->sp)) {	/* $3 */
    282 			int n = 0;
    283 			while (isdigit((uchar)*srcp->sp))
    284 				n = 10 * n + *srcp->sp++ - '0';
    285 			if (n > 0 && n <= MAXARGS)
    286 				pushsrc(String, argfp->argstk[n-1]);
    287 			goto loop;
    288 		}
    289 		break;
    290 	case File:
    291 		c = getc(curfile->fin);
    292 		if (c == EOF) {
    293 			if (curfile == infile)
    294 				ERROR "end of file inside .G1/.G2" FATAL;
    295 			if (curfile->fin != stdin) {
    296 				fclose(curfile->fin);
    297 				free(curfile->fname);	/* assumes allocated */
    298 			}
    299 			curfile--;
    300 			printf(".lf %d %s\n", curfile->lineno, curfile->fname);
    301 			popsrc();
    302 			thru = 0;	/* chicken out */
    303 			thrudef = 0;
    304 			if (untilstr) {
    305 				free(untilstr);
    306 				untilstr = 0;
    307 			}
    308 			goto loop;
    309 		}
    310 		if (c == '\n')
    311 			curfile->lineno++;
    312 		break;
    313 	}
    314 	return c;
    315 }
    316 
    317 void do_thru(void)	/* read one line, make into a macro expansion */
    318 {
    319 	int c, i;
    320 	char *p;
    321 	Arg *ap;
    322 
    323 	ap = argfp+1;
    324 	if (ap >= args+10)
    325 		ERROR "arguments too deep" FATAL;
    326 	if (ap->argval == NULL)
    327 		ap->argval = malloc(1000);
    328 	p = ap->argval;
    329 	argcnt = 0;
    330 	c = nextchar();
    331 	if (thru == 0) {	/* end of file was seen, so thru is done */
    332 		unput(c);
    333 		return;
    334 	}
    335 	for ( ; c != '\n' && c != EOF; ) {
    336 		if (c == ' ' || c == '\t') {
    337 			c = nextchar();
    338 			continue;
    339 		}
    340 		if (argcnt >= MAXARGS)
    341 			ERROR "too many fields on input line" FATAL;
    342 		ap->argstk[argcnt++] = p;
    343 		if (c == '"') {
    344 			do {
    345 				*p++ = c;
    346 				if ((c = nextchar()) == '\\') {
    347 					*p++ = c;
    348 					*p++ = nextchar();
    349 					c = nextchar();
    350 				}
    351 			} while (c != '"' && c != '\n' && c != EOF);
    352 			*p++ = '"';
    353 			if (c == '"')
    354 				c = nextchar();
    355 		} else {
    356 			do {
    357 				*p++ = c;
    358 			} while ((c = nextchar())!=' ' && c!='\t' && c!='\n' && c!=',' && c!=EOF);
    359 			if (c == ',')
    360 				c = nextchar();
    361 		}
    362 		*p++ = '\0';
    363 	}
    364 	if (c == EOF)
    365 		ERROR "unexpected end of file in do_thru" FATAL;
    366 	if (argcnt == 0) {	/* ignore blank line */
    367 		pushsrc(Thru, (char *) 0);
    368 		return;
    369 	}
    370 	for (i = argcnt; i < MAXARGS; i++)
    371 		ap->argstk[i] = "";
    372 	if (dbg)
    373 		for (i = 0; i < argcnt; i++)
    374 			printf("arg %ld.%d = <%s>\n", (long)(ap-args), i+1, ap->argstk[i]);
    375 	if (strcmp(ap->argstk[0], ".G2") == 0) {
    376 		thru = 0;
    377 		thrudef = 0;
    378 		pushsrc(String, "\n.G2\n");
    379 		return;
    380 	}
    381 	if (untilstr && strcmp(ap->argstk[0], untilstr) == 0) {
    382 		thru = 0;
    383 		thrudef = 0;
    384 		free(untilstr);
    385 		untilstr = 0;
    386 		return;
    387 	}
    388 	pushsrc(Thru, (char *) 0);
    389 	dprintf("do_thru pushing back <%s>\n", thrudef->val);
    390 	argfp = ap;
    391 	pushsrc(Macro, thrudef->val);
    392 }
    393 
    394 int
    395 unput(int c)
    396 {
    397 	if (++pb >= pbuf + sizeof pbuf)
    398 		ERROR "pushback overflow" FATAL;
    399 	if (--ep < ebuf)
    400 		ep = ebuf + sizeof(ebuf) - 1;
    401 	*pb = c;
    402 	pushsrc(Char, pb);
    403 	return c;
    404 }
    405 
    406 void pbstr(char *s)
    407 {
    408 	pushsrc(String, s);
    409 }
    410 
    411 double errcheck(double x, char *s)
    412 {
    413 	if (errno == EDOM) {
    414 		errno = 0;
    415 		ERROR "%s argument out of domain", s WARNING;
    416 	} else if (errno == ERANGE) {
    417 		errno = 0;
    418 		ERROR "%s result out of range", s WARNING;
    419 	}
    420 	return x;
    421 }
    422 
    423 char	errbuf[200];
    424 
    425 void yyerror(char *s)
    426 {
    427 	extern char *cmdname;
    428 	int ern = errno;	/* cause some libraries clobber it */
    429 
    430 	if (synerr)
    431 		return;
    432 	fflush(stdout);
    433 	fprintf(stderr, "%s: %s", cmdname, s);
    434 	if (ern > 0) {
    435 		errno = ern;
    436 		perror("???");
    437 	}
    438 	fprintf(stderr, " near %s:%d\n",
    439 		curfile->fname, curfile->lineno+1);
    440 	eprint();
    441 	synerr = 1;
    442 	errno = 0;
    443 }
    444 
    445 void eprint(void)	/* try to print context around error */
    446 {
    447 	char *p, *q;
    448 
    449 	p = ep - 1;
    450 	if (p > ebuf && *p == '\n')
    451 		p--;
    452 	for ( ; p >= ebuf && *p != '\n'; p--)
    453 		;
    454 	while (*p == '\n')
    455 		p++;
    456 	fprintf(stderr, " context is\n\t");
    457 	for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
    458 		;
    459 	for (; p < q; p++)
    460 		if (isprint((uchar)*p))
    461 			putc(*p, stderr);
    462 	fprintf(stderr, " >>> ");
    463 	for (; p < ep; p++)
    464 		if (isprint((uchar)*p))
    465 			putc(*p, stderr);
    466 	fprintf(stderr, " <<< ");
    467 	while (pb >= pbuf)
    468 		putc(*pb--, stderr);
    469 	fgets(ebuf, sizeof ebuf, curfile->fin);
    470 	fprintf(stderr, "%s", ebuf);
    471 	pbstr("\n.G2\n");	/* safety first */
    472 	ep = ebuf;
    473 }
    474 
    475 int yywrap(void) {return 1;}
    476 
    477 char	*newfile = 0;		/* filename for file copy */
    478 char	*untilstr = 0;		/* string that terminates a thru */
    479 int	thru	= 0;		/* 1 if copying thru macro */
    480 Obj	*thrudef = 0;		/* macro being used */
    481 
    482 void copyfile(char *s)	/* remember file to start reading from */
    483 {
    484 	newfile = s;
    485 }
    486 
    487 void copydef(Obj *p)	/* remember macro Obj */
    488 {
    489 	thrudef = p;
    490 }
    491 
    492 Obj *copythru(char *s)	/* collect the macro name or body for thru */
    493 {
    494 	Obj *p;
    495 	char *q;
    496 
    497 	p = lookup(s, 0);
    498 	if (p != NULL) {
    499 		if (p->type == DEFNAME) {
    500 			p->val = addnewline(p->val);
    501 			return p;
    502 		} else
    503 			ERROR "%s used as define and name", s FATAL;
    504 	}
    505 	/* have to collect the definition */
    506 	pbstr(s);	/* first char is the delimiter */
    507 	q = delimstr("thru body");
    508 	p = lookup("nameless", 1);
    509 	if (p != NULL)
    510 		if (p->val)
    511 			free(p->val);
    512 	p->type = DEFNAME;
    513 	p->val = q;
    514 	p->val = addnewline(p->val);
    515 	dprintf("installing nameless as `%s'\n", p->val);
    516 	return p;
    517 }
    518 
    519 char *addnewline(char *p)	/* add newline to end of p */
    520 {
    521 	int n;
    522 
    523 	n = strlen(p);
    524 	if (p[n-1] != '\n') {
    525 		p = realloc(p, n+2);
    526 		p[n] = '\n';
    527 		p[n+1] = '\0';
    528 	}
    529 	return p;
    530 }
    531 
    532 void copyuntil(char *s)	/* string that terminates a thru */
    533 {
    534 	untilstr = s;
    535 }
    536 
    537 void copy(void)	/* begin input from file, etc. */
    538 {
    539 	FILE *fin;
    540 
    541 	if (newfile) {
    542 		if ((fin = fopen(newfile, "r")) == NULL)
    543 			ERROR "can't open file %s", newfile FATAL;
    544 		curfile++;
    545 		curfile->fin = fin;
    546 		curfile->fname = tostring(newfile);
    547 		curfile->lineno = 0;
    548 		printf(".lf 1 %s\n", curfile->fname);
    549 		pushsrc(File, curfile->fname);
    550 		newfile = 0;
    551 	}
    552 	if (thrudef) {
    553 		thru = 1;
    554 		begin = 1;	/* wrong place */
    555 	}
    556 }
    557 
    558 char	shellbuf[1000], *shellp;
    559 
    560 void shell_init(void)	/* set up to interpret a shell command */
    561 {
    562 	fprintf(tfd, "# shell cmd...\n");
    563 	sprintf(shellbuf, "rc -c '");
    564 	shellp = shellbuf + strlen(shellbuf);
    565 }
    566 
    567 void shell_text(char *s)	/* add string to command being collected */
    568 {
    569 	/* fprintf(tfd, "#add <%s> to <%s>\n", s, shellbuf); */
    570 	while (*s) {
    571 		if (*s == '\'')	{	/* protect interior quotes */
    572 			*shellp++ = '\'';
    573 			*shellp++ = '\\';
    574 			*shellp++ = '\'';
    575 		}
    576 		*shellp++ = *s++;
    577 	}
    578 }
    579 
    580 void shell_exec(void)	/* do it */
    581 {
    582 	/* fprintf(tfd, "# run <%s>\n", shellbuf); */
    583 	*shellp++ = '\'';
    584 	*shellp = '\0';
    585 	system(shellbuf);
    586 }