12155Seric # include	"stdio.h"
22155Seric # include	"seven/types.h"
32155Seric # include	"seven/macros.h"
42155Seric # include	"fatal.h"
52155Seric 
6*33423Sbostic SCCSID(@(#)vc.c	4.3);
72155Seric USXALLOC();
82155Seric 
92155Seric /*
102155Seric  * The symbol table size is set to a limit of forty keywords per input
112155Seric  * file.  Should this limit be changed it should also be changed in the
122155Seric  * Help file.
132155Seric  */
142155Seric 
152155Seric # define SYMSIZE 40
162155Seric # define PARMSIZE 10
172155Seric # define NSLOTS 32
182155Seric 
192155Seric # define USD  1
202155Seric # define DCL 2
212155Seric # define ASG 4
222155Seric 
232155Seric # define EQ '='
242155Seric # define NEQ '!'
252155Seric # define GT '>'
262155Seric # define LT '<'
272155Seric # define DELIM " \t"
282155Seric # define TRUE 1
292155Seric # define FALSE 0
302155Seric 
312155Seric char	Ctlchar	':';
322155Seric 
332155Seric struct	symtab	{
342155Seric 	int	usage;
352155Seric 	char	name[PARMSIZE];
362155Seric 	char	*value;
372155Seric 	int	lenval;
382155Seric };
392155Seric struct	symtab	Sym[SYMSIZE];
402155Seric 
412155Seric struct {
422155Seric 	char	chr;
432155Seric };
442155Seric 
452155Seric int	Skiptabs;
462155Seric int	Repall;
472155Seric 
482155Seric /*
492155Seric  * Delflag is used to indicate when text is to be skipped.  It is decre-
502155Seric  * mented whenever an if condition is false, or when an if occurs
512155Seric  * within a false if/end statement.  It is decremented whenever an end is
522155Seric  * encountered and the Delflag is greater than zero.  Whenever Delflag
532155Seric  * is greater than zero text is skipped.
542155Seric  */
552155Seric 
562155Seric int	Delflag;
572155Seric 
582155Seric /*
592155Seric  * Ifcount keeps track of the number of ifs and ends.  Each time
602155Seric  * an if is encountered Ifcount is incremented and each time an end is
612155Seric  * encountered it is decremented.
622155Seric  */
632155Seric 
642155Seric int	Ifcount;
652155Seric int	Lineno;
662155Seric 
672155Seric char	*Repflag;
682155Seric char	*Linend;
692155Seric int	Silent;
702155Seric 
712155Seric 
722155Seric /*
732155Seric  * The main program reads a line of text and sends it to be processed
742155Seric  * if it is a version control statement. If it is a line of text and
752155Seric  * the Delflag is equal to zero, it is written to the standard output.
762155Seric  */
772155Seric 
main(argc,argv)782155Seric main(argc, argv)
792155Seric int argc;
802155Seric char *argv[];
812155Seric {
822155Seric 	register  char *lineptr, *p;
832155Seric 	register int i;
842155Seric 	char line[512];
852155Seric 	extern int Fflags;
862155Seric 
872155Seric 	Fflags = FTLCLN | FTLMSG | FTLEXIT;
882155Seric 	setsig();
892155Seric 	for(i = 1; i< argc; i++) {
902155Seric 		p = argv[i];
912155Seric 		if (p[0] == '-')
922155Seric 			switch (p[1]) {
932155Seric 			case 's':
942155Seric 				Silent = 1;
952155Seric 				break;
962155Seric 			case 't':
972155Seric 				Skiptabs = 1;
982155Seric 				break;
992155Seric 			case 'a':
1002155Seric 				Repall = 1;
1012155Seric 				break;
1022155Seric 			case 'c':
1032155Seric 				Ctlchar = p[2];
1042155Seric 				break;
1052155Seric 			}
1062155Seric 		else {
1072155Seric 			p[size(p) - 1] = '\n';
1082155Seric 			asgfunc(p);
1092155Seric 		}
1102155Seric 	}
1112155Seric 	while (fgets(line,sizeof(line),stdin) != NULL) {
1122155Seric 		lineptr = line;
1132155Seric 		Lineno++;
1142155Seric 
1152155Seric 		if (Repflag != 0) {
1162155Seric 			free(Repflag);
1172155Seric 			Repflag = 0;
1182155Seric 		}
1192155Seric 
1202155Seric 		if (Skiptabs) {
1212155Seric 			for (p = lineptr; *p; p++)
1222155Seric 				if (*p == '\t')
1232155Seric 					break;
1242155Seric 			if (*p++ == '\t')
1252155Seric 				lineptr = p;
1262155Seric 		}
1272155Seric 
1282155Seric 		if (lineptr[0] != Ctlchar) {
1292155Seric 			if (lineptr[0] == '\\' && lineptr[1] == Ctlchar)
1302155Seric 				for (p = &lineptr[1]; *lineptr++ = *p++; )
1312155Seric 					;
1322155Seric 			if(Delflag == 0) {
1332155Seric 				if (Repall)
1342155Seric 					repfunc(line);
1352155Seric 				else
1362155Seric 					fputs(line,stdout);
1372155Seric 			}
1382155Seric 			continue;
1392155Seric 		}
1402155Seric 
1412155Seric 		lineptr++;
1422155Seric 
1432155Seric 		if (imatch("if ", lineptr))
1442155Seric 			iffunc(&lineptr[3]);
1452155Seric 		else if (imatch("end", lineptr))
1462155Seric 			endfunc();
1472155Seric 		else if (Delflag == 0) {
1482155Seric 			if (imatch("asg ", lineptr))
1492155Seric 				asgfunc(&lineptr[4]);
1502155Seric 			else if (imatch("dcl ", lineptr))
1512155Seric 				dclfunc(&lineptr[4]);
1522155Seric 			else if (imatch("err", lineptr))
1532155Seric 				errfunc(&lineptr[3]);
1542155Seric 			else if (imatch("msg", lineptr))
1552155Seric 				msgfunc(&lineptr[3]);
1562155Seric 			else if (lineptr[0] == Ctlchar)
1572155Seric 				repfunc(&lineptr[1]);
1582155Seric 			else if (imatch("on", lineptr))
1592155Seric 				Repall = 1;
1602155Seric 			else if (imatch("off", lineptr))
1612155Seric 				Repall = 0;
1622155Seric 			else if (imatch("ctl ", lineptr))
1632155Seric 				Ctlchar = lineptr[4];
1642155Seric 			else error("unknown command on line %d (901)",Lineno);
1652155Seric 		}
1662155Seric 	}
1672155Seric 	for(i = 0; Sym[i].usage != 0 && i<SYMSIZE; i++) {
1682155Seric 		if ((Sym[i].usage&USD) == 0)
1692155Seric 			warn("`%s' never used (902)\n",Sym[i].name);
1702155Seric 		if ((Sym[i].usage&DCL) == 0)
1712155Seric 			warn("`%s' never declared (903)\n", Sym[i].name);
1722155Seric 		if ((Sym[i].usage&ASG) == 0)
1732155Seric 			warn("`%s' never assigned a value (920)\n", Sym[i].name);
1742155Seric 	}
1752155Seric 	if (Ifcount > 0)
1762155Seric 		error("`if' with no matching `end' (904)");
1772155Seric 	exit(0);
1782155Seric }
1792155Seric 
1802155Seric 
1812155Seric /*
1822155Seric  * Asgfunc accepts a pointer to a line picks up a keyword name, an
1832155Seric  * equal sign and a value and calls putin to place it in the symbol table.
1842155Seric  */
1852155Seric 
asgfunc(aptr)1862155Seric asgfunc(aptr)
1872155Seric register char *aptr;
1882155Seric {
1892155Seric 	register char *end, *aname;
1902155Seric 	char *avalue;
1912155Seric 
1922155Seric 	aptr = replace(aptr);
1932155Seric 	NONBLANK(aptr);
1942155Seric 	aname = aptr;
1952155Seric 	end = Linend;
1962155Seric 	aptr = findstr(aptr,"= \t");
1972155Seric 	if (*aptr == ' ' || *aptr == '\t') {
1982155Seric 		*aptr++ = '\0';
1992155Seric 		aptr = findch(aptr,'=');
2002155Seric 	}
2012155Seric 	if (aptr == end)
2022155Seric 		error("syntax on line %d (917)",Lineno);
2032155Seric 	*aptr++ = '\0';
2042155Seric 	avalue = getid(aptr);
2052155Seric 	chksize(aname);
2062155Seric 	putin(aname, avalue);
2072155Seric }
2082155Seric 
2092155Seric 
2102155Seric /*
2112155Seric  * Dclfunc accepts a pointer to a line and picks up keywords
2122155Seric  * separated by commas.  It calls putin to put each keyword in the
2132155Seric  * symbol table.  It returns when it sees a newline.
2142155Seric  */
2152155Seric 
dclfunc(dptr)2162155Seric dclfunc(dptr)
2172155Seric register char *dptr;
2182155Seric {
2192155Seric 	register char *end, *dname;
2202155Seric 	int i;
2212155Seric 
2222155Seric 	dptr = replace(dptr);
2232155Seric 	end = Linend;
2242155Seric 	NONBLANK(dptr);
2252155Seric 	while (dptr < end) {
2262155Seric 		dname = dptr;
2272155Seric 		dptr = findch(dptr,',');
2282155Seric 		*dptr++ = '\0';
2292155Seric 		chksize(dname);
2302155Seric 		if (Sym[i = lookup(dname)].usage&DCL)
2312155Seric 			error("`%s' declared twice on line %d (905)",
2322155Seric 				dname, Lineno);
2332155Seric 		else
23432774Sbostic 			Sym[i].usage |= DCL;
2352155Seric 		NONBLANK(dptr);
2362155Seric 	}
2372155Seric }
2382155Seric 
2392155Seric 
2402155Seric /*
2412155Seric  * Errfunc calls fatal which stops the process.
2422155Seric  */
2432155Seric 
errfunc(eptr)2442155Seric errfunc(eptr)
2452155Seric char *eptr;
2462155Seric {
2472155Seric 	warn("ERROR:%s\n",replace(eptr));
2482155Seric 	error("err statement on line %d (915)", Lineno);
2492155Seric }
2502155Seric 
2512155Seric 
2522155Seric /*
2532155Seric  * Endfunc indicates an end has been found by decrementing the if count
2542155Seric  * flag.  If because of a previous if statement, text was being skipped,
2552155Seric  * Delflag is also decremented.
2562155Seric  */
2572155Seric 
endfunc()2582155Seric endfunc()
2592155Seric {
2602155Seric 	if (--Ifcount < 0)
2612155Seric 		error("`end' without matching `if' on line %d (910)",Lineno);
2622155Seric 	if (Delflag > 0)
2632155Seric 		Delflag--;
2642155Seric 	return;
2652155Seric }
2662155Seric 
2672155Seric 
2682155Seric /*
2692155Seric  * Msgfunc accepts a pointer to a line and prints that line on the
2702155Seric  * diagnostic output.
2712155Seric  */
2722155Seric 
msgfunc(mptr)2732155Seric msgfunc(mptr)
2742155Seric char *mptr;
2752155Seric {
2762155Seric 	warn("Message(%d):%s\n", Lineno, replace(mptr));
2772155Seric }
2782155Seric 
2792155Seric 
repfunc(s)2802155Seric repfunc(s)
2812155Seric char *s;
2822155Seric {
2832155Seric 	fprintf(stdout,"%s\n",replace(s));
2842155Seric }
2852155Seric 
2862155Seric 
2872155Seric /*
2882155Seric  * Iffunc and the three functions following it, door, doand, and exp
2892155Seric  * are responsible for parsing and interperting the condition in the
2902155Seric  * if statement.  The BNF used is as follows:
2912155Seric  *	<iffunc> ::=   [ "not" ] <door> EOL
2922155Seric  *	<door> ::=     <doand> | <doand> "|" <door>
2932155Seric  *	<doand>::=     <exp> | <exp> "&" <doand>
2942155Seric  *	<exp>::=       "(" <door> ")" | <value> <operator> <value>
2952155Seric  *	<operator>::=  "=" | "!=" | "<" | ">"
2962155Seric  * And has precedence over or.  If the condition is false the Delflag
2972155Seric  * is bumped to indicate that lines are to be skipped.
2982155Seric  * An external variable, sptr is used for processing the line in
2992155Seric  * iffunc, door, doand, exp, getid.
3002155Seric  * Iffunc accepts a pointer to a line and sets sptr to that line.  The
3012155Seric  * rest of iffunc, door, and doand follow the BNF exactly.
3022155Seric  */
3032155Seric 
3042155Seric char *sptr;
3052155Seric 
iffunc(iptr)3062155Seric iffunc(iptr)
3072155Seric char *iptr;
3082155Seric {
3092155Seric 	register int value, not;
3102155Seric 
3112155Seric 	Ifcount++;
3122155Seric 	if (Delflag > 0)
3132155Seric 		Delflag++;
3142155Seric 
3152155Seric 	else {
3162155Seric 		sptr = replace(iptr);
3172155Seric 		NONBLANK(sptr);
3182155Seric 		if (imatch("not ", sptr)) {
3192155Seric 			not = FALSE;
32032774Sbostic 			sptr += 4;
3212155Seric 		}
3222155Seric 		else not = TRUE;
3232155Seric 
3242155Seric 		value = door();
3252155Seric 		if( *sptr != 0)
3262155Seric 			error("syntax on line %d (918)",Lineno);
3272155Seric 
3282155Seric 		if (value != not)
3292155Seric 			Delflag++;
3302155Seric 	}
3312155Seric 
3322155Seric 	return;
3332155Seric }
3342155Seric 
3352155Seric 
door()3362155Seric door()
3372155Seric {
3382155Seric 	int value;
3392155Seric 	value = doand();
3402155Seric 	NONBLANK(sptr);
3412155Seric 	while (*sptr=='|') {
3422155Seric 		sptr++;
34332774Sbostic 		value |= doand();
3442155Seric 		NONBLANK(sptr);
3452155Seric 	}
3462155Seric 	return(value);
3472155Seric }
3482155Seric 
3492155Seric 
doand()3502155Seric doand()
3512155Seric {
3522155Seric 	int value;
3532155Seric 	value = exp();
3542155Seric 	NONBLANK(sptr);
3552155Seric 	while (*sptr=='&') {
3562155Seric 		sptr++;
35732774Sbostic 		value &= exp();
3582155Seric 		NONBLANK(sptr);
3592155Seric 	}
3602155Seric 	return(value);
3612155Seric }
3622155Seric 
3632155Seric 
3642155Seric /*
3652155Seric  * After exp checks for parentheses, it picks up a value by calling getid,
3662155Seric  * picks up an operator and calls getid to pick up the second value.
3672155Seric  * Then based on the operator it calls either numcomp or equal to see
3682155Seric  * if the exp is true or false and returns the correct value.
3692155Seric  */
3702155Seric 
exp()3712155Seric exp()
3722155Seric {
3732155Seric 	register char op, save;
3742155Seric 	register int value;
3752155Seric 	char *id1, *id2, next;
3762155Seric 
3772155Seric 	NONBLANK(sptr);
3782155Seric 	if(*sptr == '(') {
3792155Seric 		sptr++;
3802155Seric 		value = door();
3812155Seric 		NONBLANK(sptr);
3822155Seric 		if (*sptr == ')') {
3832155Seric 			sptr++;
3842155Seric 			return(value);
3852155Seric 		}
3862155Seric 		else error("parenthesis error on line %d (911)",Lineno);
3872155Seric 	}
3882155Seric 
3892155Seric 	id1 = getid(sptr);
3902155Seric 	if (op = *sptr)
3912155Seric 		*sptr++ = '\0';
3922155Seric 	if (op == NEQ && (next = *sptr++) == '\0')
3932155Seric 		--sptr;
3942155Seric 	id2 = getid(sptr);
3952155Seric 	save = *sptr;
3962155Seric 	*sptr = '\0';
3972155Seric 
3982155Seric 	if(op ==LT || op == GT) {
3992155Seric 		value = numcomp(id1, id2);
4002155Seric 		if ((op == GT && value == 1) || (op == LT && value == -1))
4012155Seric 			value = TRUE;
4022155Seric 		else value = FALSE;
4032155Seric 	}
4042155Seric 
4052155Seric 	else if (op==EQ || (op==NEQ && next==EQ)) {
4062155Seric 		value = equal(id1, id2);
4072155Seric 		if ( op == NEQ)
4082155Seric 			value = !value;
4092155Seric 	}
4102155Seric 
4112155Seric 	else error("invalid operator on line %d (912)", Lineno);
4122155Seric 	*sptr = save;
4132155Seric 	return(value);
4142155Seric }
4152155Seric 
4162155Seric 
4172155Seric /*
4182155Seric  * Getid picks up a value off a line and returns a pointer to the value.
4192155Seric  */
4202155Seric 
getid(gptr)4212155Seric getid(gptr)
4222155Seric register char *gptr;
4232155Seric {
4242155Seric 	register char c, *id;
4252155Seric 
4262155Seric 	NONBLANK(gptr);
4272155Seric 	id = gptr;
4282155Seric 	gptr = findstr(gptr,DELIM);
4292155Seric 	if (*gptr)
4302155Seric 		*gptr++ = '\0';
4312155Seric 	NONBLANK(gptr);
4322155Seric 	sptr = gptr;
4332155Seric 	return(id);
4342155Seric }
4352155Seric 
4362155Seric 
4372155Seric /*
4382155Seric  * Numcomp accepts two pointers to strings of digits and calls numck
4392155Seric  * to see if the strings contain only digits.  It returns -1 if
4402155Seric  * the first is less than the second, 1 if the first is greater than the
4412155Seric  * second and 0 if the two are equal.
4422155Seric  */
4432155Seric 
numcomp(id1,id2)4442155Seric numcomp(id1, id2)
4452155Seric register char *id1, *id2;
4462155Seric {
4472155Seric 	int k1, k2;
4482155Seric 
4492155Seric 	numck(id1);
4502155Seric 	numck(id2);
4512155Seric 	while (*id1 == '0')
4522155Seric 		id1++;
4532155Seric 	while (*id2 == '0')
4542155Seric 		id2++;
4552155Seric 	if ((k1 = size(id1)) > (k2 = size(id2)))
4562155Seric 		return(1);
4572155Seric 	else if (k1 < k2)
4582155Seric 		return(-1);
4592155Seric 	else while(*id1 != '\0') {
4602155Seric 		if(*id1 > *id2)
4612155Seric 			return(1);
4622155Seric 		else if(*id1 < *id2)
4632155Seric 			return(-1);
4642155Seric 		id1++;
4652155Seric 		id2++;
4662155Seric 	}
4672155Seric 	return(0);
4682155Seric }
4692155Seric 
4702155Seric 
4712155Seric /*
4722155Seric  * Numck accepts a pointer to a string and checks to see if they are
4732155Seric  * all digits.  If they're not it calls fatal, otherwise it returns.
4742155Seric  */
4752155Seric 
numck(nptr)4762155Seric numck(nptr)
4772155Seric register char *nptr;
4782155Seric {
4792155Seric 	for (; *nptr != '\0'; nptr++)
4802155Seric 		if (!numeric(*nptr))
4812155Seric 			error("non-numerical value on line %d (914)",Lineno);
4822155Seric 	return;
4832155Seric }
4842155Seric 
4852155Seric 
4862155Seric /*
4872155Seric  * Replace accepts a pointer to a line and scans the line for a keyword
4882155Seric  * enclosed in control characters.  If it doesn't find one it returns
4892155Seric  * a pointer to the begining of the line.  Otherwise, it calls
4902155Seric  * lookup to find the keyword.
4912155Seric  * It rewrites the line substituting the value for the
4922155Seric  * keyword enclosed in control characters.  It then continues scanning
4932155Seric  * the line until no control characters are found and returns a pointer to
4942155Seric  * the begining of the new line.
4952155Seric  */
4962155Seric 
4972155Seric # define INCR(int) if (++int==NSLOTS) error(subrng,Lineno)
4982155Seric char *subrng "out of space [line %d] (916)";
4992155Seric 
replace(ptr)5002155Seric replace(ptr)
5012155Seric char *ptr;
5022155Seric {
5032155Seric 	char *slots[NSLOTS];
5042155Seric 	int i,j,newlen;
5052155Seric 	register char *s, *t, *p;
5062155Seric 
5072155Seric 	for (s=ptr; *s++!='\n';);
5082155Seric 	*(--s) = '\0';
5092155Seric 	Linend = s;
5102155Seric 	i = -1;
5112155Seric 	for (p=ptr; *(s=findch(p,Ctlchar)); p=t) {
5122155Seric 		*s++ = '\0';
5132155Seric 		INCR(i);
5142155Seric 		slots[i] = p;
5152155Seric 		if (*(t=findch(s,Ctlchar))==0)
5162155Seric 			error("unmatched `%c' on line %d (907)",Ctlchar,Lineno);
5172155Seric 		*t++ = '\0';
5182155Seric 		INCR(i);
5192155Seric 		slots[i] = Sym[j = lookup(s)].value;
52032774Sbostic 		Sym[j].usage |= USD;
5212155Seric 	}
5222155Seric 	INCR(i);
5232155Seric 	slots[i] = p;
5242155Seric 	if (i==0) return(ptr);
5252155Seric 	newlen = 0;
5262155Seric 	for (j=0; j<=i; j++)
52732774Sbostic 		newlen += (size(slots[j])-1);
5282155Seric 	t = Repflag = alloc(++newlen);
5292155Seric 	for (j=0; j<=i; j++)
5302155Seric 		t = ecopy(slots[j],t);
5312155Seric 	Linend = t;
5322155Seric 	return(Repflag);
5332155Seric }
5342155Seric 
5352155Seric 
5362155Seric /*
5372155Seric  * Lookup accepts a pointer to a keyword name and searches the symbol
5382155Seric  * table for the keyword.  It returns its index in the table if its there,
5392155Seric  * otherwise it puts the keyword in the table.
5402155Seric  */
5412155Seric 
lookup(lname)5422155Seric lookup(lname)
5432155Seric char *lname;
5442155Seric {
5452155Seric 	register int i;
5462155Seric 	register char *t;
5472155Seric 	register struct symtab *s;
5482155Seric 
5492155Seric 	t = lname;
5502155Seric 	while ((i.chr = *t++) &&
5512155Seric 		((i.chr>='A' && i.chr<='Z') || (i.chr>='a' && i.chr<='z') ||
5522155Seric 			(i.chr!= *lname && i.chr>='0' && i.chr<='9')));
5532155Seric 	if (i.chr)
5542155Seric 		error("invalid keyword name on line %d (909)",Lineno);
5552155Seric 
5562155Seric 	for(i =0; Sym[i].usage != 0 && i<SYMSIZE; i++)
5572155Seric 		if (equal(lname, Sym[i].name)) return(i);
5582155Seric 	s = &Sym[i];
5592155Seric 	if (s->usage == 0) {
5602155Seric 		copy(lname,s->name);
5612155Seric 		copy("",(s->value = alloc(s->lenval = 1)));
5622155Seric 		return(i);
5632155Seric 	}
5642155Seric 	error("out of space (906)");
5652155Seric }
5662155Seric 
5672155Seric 
5682155Seric /*
5692155Seric  * Putin accepts a pointer to a keyword name, and a pointer to a value.
5702155Seric  * It puts this information in the symbol table by calling lookup.
5712155Seric  * It returns the index of the name in the table.
5722155Seric  */
5732155Seric 
putin(pname,pvalue)5742155Seric putin(pname, pvalue)
5752155Seric char *pname;
5762155Seric char *pvalue;
5772155Seric {
5782155Seric 	register int i;
5792155Seric 	register struct symtab *s;
5802155Seric 
5812155Seric 	s = &Sym[i = lookup(pname)];
5822155Seric 	free(s->value);
5832155Seric 	s->lenval = size(pvalue);
5842155Seric 	copy(pvalue, (s->value = alloc(s->lenval)));
58532774Sbostic 	s->usage |= ASG;
5862155Seric 	return(i);
5872155Seric }
5882155Seric 
5892155Seric 
chksize(s)5902155Seric chksize(s)
5912155Seric char *s;
5922155Seric {
5932155Seric 	if (size(s) > PARMSIZE)
5942155Seric 		error("keyword name too long on line %d (908)",Lineno);
5952155Seric }
5962155Seric 
5972155Seric 
findch(astr,match)5982155Seric findch(astr,match)
5992155Seric char *astr, match;
6002155Seric {
6012155Seric 	register char *s, *t, c;
6022155Seric 	char *temp;
6032155Seric 
6042155Seric 	for (s=astr; (c = *s) && c!=match; s++)
6052155Seric 		if (c=='\\') {
6062155Seric 			if (s[1]==0)
6072155Seric 				error("syntax on line %d (919)",Lineno);
6082155Seric 			else {
6092155Seric 				for (t = (temp=s) + 1; *s++ = *t++;);
6102155Seric 				s = temp;
6112155Seric 			}
6122155Seric 		}
6132155Seric 	return(s);
6142155Seric }
6152155Seric 
6162155Seric 
ecopy(s1,s2)6172155Seric ecopy(s1,s2)
6182155Seric char *s1, *s2;
6192155Seric {
6202155Seric 	register char *r1, *r2;
6212155Seric 
6222155Seric 	r1 = s1;
6232155Seric 	r2 = s2;
6242155Seric 	while (*r2++ = *r1++);
6252155Seric 	return(--r2);
6262155Seric }
6272155Seric 
6282155Seric 
error(arg)6292155Seric error(arg)
6302155Seric {
631*33423Sbostic 	sprintf(Error,"%r",&arg);
632*33423Sbostic 	fatal(Error);
6332155Seric }
6342155Seric 
6352155Seric 
findstr(astr,pat)6362155Seric findstr(astr,pat)
6372155Seric char *astr, *pat;
6382155Seric {
6392155Seric 	register char *s, *t, c;
6402155Seric 	char *temp;
6412155Seric 
6422155Seric 	for (s=astr; (c = *s) && any(c,pat)==0; s++)
6432155Seric 		if (c=='\\') {
6442155Seric 			if (s[1]==0)
6452155Seric 				error("syntax on line %d (919)",Lineno);
6462155Seric 			else {
6472155Seric 				for (t = (temp=s) + 1; *s++ = *t++;);
6482155Seric 				s = temp;
6492155Seric 			}
6502155Seric 		}
6512155Seric 	return(s);
6522155Seric }
6532155Seric 
6542155Seric 
warn(arg)6552155Seric warn(arg)
6562155Seric {
6572155Seric 	if (!Silent)
6582155Seric 		fprintf(stderr,"%r",&arg);
6592155Seric }
660