1*2155Seric # include	"stdio.h"
2*2155Seric # include	"seven/types.h"
3*2155Seric # include	"seven/macros.h"
4*2155Seric # include	"fatal.h"
5*2155Seric 
6*2155Seric SCCSID(@(#)vc.c	4.1);
7*2155Seric USXALLOC();
8*2155Seric 
9*2155Seric /*
10*2155Seric  * The symbol table size is set to a limit of forty keywords per input
11*2155Seric  * file.  Should this limit be changed it should also be changed in the
12*2155Seric  * Help file.
13*2155Seric  */
14*2155Seric 
15*2155Seric # define SYMSIZE 40
16*2155Seric # define PARMSIZE 10
17*2155Seric # define NSLOTS 32
18*2155Seric 
19*2155Seric # define USD  1
20*2155Seric # define DCL 2
21*2155Seric # define ASG 4
22*2155Seric 
23*2155Seric # define EQ '='
24*2155Seric # define NEQ '!'
25*2155Seric # define GT '>'
26*2155Seric # define LT '<'
27*2155Seric # define DELIM " \t"
28*2155Seric # define TRUE 1
29*2155Seric # define FALSE 0
30*2155Seric 
31*2155Seric char	Ctlchar	':';
32*2155Seric 
33*2155Seric struct	symtab	{
34*2155Seric 	int	usage;
35*2155Seric 	char	name[PARMSIZE];
36*2155Seric 	char	*value;
37*2155Seric 	int	lenval;
38*2155Seric };
39*2155Seric struct	symtab	Sym[SYMSIZE];
40*2155Seric 
41*2155Seric struct {
42*2155Seric 	char	chr;
43*2155Seric };
44*2155Seric 
45*2155Seric int	Skiptabs;
46*2155Seric int	Repall;
47*2155Seric 
48*2155Seric /*
49*2155Seric  * Delflag is used to indicate when text is to be skipped.  It is decre-
50*2155Seric  * mented whenever an if condition is false, or when an if occurs
51*2155Seric  * within a false if/end statement.  It is decremented whenever an end is
52*2155Seric  * encountered and the Delflag is greater than zero.  Whenever Delflag
53*2155Seric  * is greater than zero text is skipped.
54*2155Seric  */
55*2155Seric 
56*2155Seric int	Delflag;
57*2155Seric 
58*2155Seric /*
59*2155Seric  * Ifcount keeps track of the number of ifs and ends.  Each time
60*2155Seric  * an if is encountered Ifcount is incremented and each time an end is
61*2155Seric  * encountered it is decremented.
62*2155Seric  */
63*2155Seric 
64*2155Seric int	Ifcount;
65*2155Seric int	Lineno;
66*2155Seric 
67*2155Seric char	*Repflag;
68*2155Seric char	*Linend;
69*2155Seric int	Silent;
70*2155Seric 
71*2155Seric 
72*2155Seric /*
73*2155Seric  * The main program reads a line of text and sends it to be processed
74*2155Seric  * if it is a version control statement. If it is a line of text and
75*2155Seric  * the Delflag is equal to zero, it is written to the standard output.
76*2155Seric  */
77*2155Seric 
78*2155Seric main(argc, argv)
79*2155Seric int argc;
80*2155Seric char *argv[];
81*2155Seric {
82*2155Seric 	register  char *lineptr, *p;
83*2155Seric 	register int i;
84*2155Seric 	char line[512];
85*2155Seric 	extern int Fflags;
86*2155Seric 
87*2155Seric 	Fflags = FTLCLN | FTLMSG | FTLEXIT;
88*2155Seric 	setsig();
89*2155Seric 	for(i = 1; i< argc; i++) {
90*2155Seric 		p = argv[i];
91*2155Seric 		if (p[0] == '-')
92*2155Seric 			switch (p[1]) {
93*2155Seric 			case 's':
94*2155Seric 				Silent = 1;
95*2155Seric 				break;
96*2155Seric 			case 't':
97*2155Seric 				Skiptabs = 1;
98*2155Seric 				break;
99*2155Seric 			case 'a':
100*2155Seric 				Repall = 1;
101*2155Seric 				break;
102*2155Seric 			case 'c':
103*2155Seric 				Ctlchar = p[2];
104*2155Seric 				break;
105*2155Seric 			}
106*2155Seric 		else {
107*2155Seric 			p[size(p) - 1] = '\n';
108*2155Seric 			asgfunc(p);
109*2155Seric 		}
110*2155Seric 	}
111*2155Seric 	while (fgets(line,sizeof(line),stdin) != NULL) {
112*2155Seric 		lineptr = line;
113*2155Seric 		Lineno++;
114*2155Seric 
115*2155Seric 		if (Repflag != 0) {
116*2155Seric 			free(Repflag);
117*2155Seric 			Repflag = 0;
118*2155Seric 		}
119*2155Seric 
120*2155Seric 		if (Skiptabs) {
121*2155Seric 			for (p = lineptr; *p; p++)
122*2155Seric 				if (*p == '\t')
123*2155Seric 					break;
124*2155Seric 			if (*p++ == '\t')
125*2155Seric 				lineptr = p;
126*2155Seric 		}
127*2155Seric 
128*2155Seric 		if (lineptr[0] != Ctlchar) {
129*2155Seric 			if (lineptr[0] == '\\' && lineptr[1] == Ctlchar)
130*2155Seric 				for (p = &lineptr[1]; *lineptr++ = *p++; )
131*2155Seric 					;
132*2155Seric 			if(Delflag == 0) {
133*2155Seric 				if (Repall)
134*2155Seric 					repfunc(line);
135*2155Seric 				else
136*2155Seric 					fputs(line,stdout);
137*2155Seric 			}
138*2155Seric 			continue;
139*2155Seric 		}
140*2155Seric 
141*2155Seric 		lineptr++;
142*2155Seric 
143*2155Seric 		if (imatch("if ", lineptr))
144*2155Seric 			iffunc(&lineptr[3]);
145*2155Seric 		else if (imatch("end", lineptr))
146*2155Seric 			endfunc();
147*2155Seric 		else if (Delflag == 0) {
148*2155Seric 			if (imatch("asg ", lineptr))
149*2155Seric 				asgfunc(&lineptr[4]);
150*2155Seric 			else if (imatch("dcl ", lineptr))
151*2155Seric 				dclfunc(&lineptr[4]);
152*2155Seric 			else if (imatch("err", lineptr))
153*2155Seric 				errfunc(&lineptr[3]);
154*2155Seric 			else if (imatch("msg", lineptr))
155*2155Seric 				msgfunc(&lineptr[3]);
156*2155Seric 			else if (lineptr[0] == Ctlchar)
157*2155Seric 				repfunc(&lineptr[1]);
158*2155Seric 			else if (imatch("on", lineptr))
159*2155Seric 				Repall = 1;
160*2155Seric 			else if (imatch("off", lineptr))
161*2155Seric 				Repall = 0;
162*2155Seric 			else if (imatch("ctl ", lineptr))
163*2155Seric 				Ctlchar = lineptr[4];
164*2155Seric 			else error("unknown command on line %d (901)",Lineno);
165*2155Seric 		}
166*2155Seric 	}
167*2155Seric 	for(i = 0; Sym[i].usage != 0 && i<SYMSIZE; i++) {
168*2155Seric 		if ((Sym[i].usage&USD) == 0)
169*2155Seric 			warn("`%s' never used (902)\n",Sym[i].name);
170*2155Seric 		if ((Sym[i].usage&DCL) == 0)
171*2155Seric 			warn("`%s' never declared (903)\n", Sym[i].name);
172*2155Seric 		if ((Sym[i].usage&ASG) == 0)
173*2155Seric 			warn("`%s' never assigned a value (920)\n", Sym[i].name);
174*2155Seric 	}
175*2155Seric 	if (Ifcount > 0)
176*2155Seric 		error("`if' with no matching `end' (904)");
177*2155Seric 	exit(0);
178*2155Seric }
179*2155Seric 
180*2155Seric 
181*2155Seric /*
182*2155Seric  * Asgfunc accepts a pointer to a line picks up a keyword name, an
183*2155Seric  * equal sign and a value and calls putin to place it in the symbol table.
184*2155Seric  */
185*2155Seric 
186*2155Seric asgfunc(aptr)
187*2155Seric register char *aptr;
188*2155Seric {
189*2155Seric 	register char *end, *aname;
190*2155Seric 	char *avalue;
191*2155Seric 
192*2155Seric 	aptr = replace(aptr);
193*2155Seric 	NONBLANK(aptr);
194*2155Seric 	aname = aptr;
195*2155Seric 	end = Linend;
196*2155Seric 	aptr = findstr(aptr,"= \t");
197*2155Seric 	if (*aptr == ' ' || *aptr == '\t') {
198*2155Seric 		*aptr++ = '\0';
199*2155Seric 		aptr = findch(aptr,'=');
200*2155Seric 	}
201*2155Seric 	if (aptr == end)
202*2155Seric 		error("syntax on line %d (917)",Lineno);
203*2155Seric 	*aptr++ = '\0';
204*2155Seric 	avalue = getid(aptr);
205*2155Seric 	chksize(aname);
206*2155Seric 	putin(aname, avalue);
207*2155Seric }
208*2155Seric 
209*2155Seric 
210*2155Seric /*
211*2155Seric  * Dclfunc accepts a pointer to a line and picks up keywords
212*2155Seric  * separated by commas.  It calls putin to put each keyword in the
213*2155Seric  * symbol table.  It returns when it sees a newline.
214*2155Seric  */
215*2155Seric 
216*2155Seric dclfunc(dptr)
217*2155Seric register char *dptr;
218*2155Seric {
219*2155Seric 	register char *end, *dname;
220*2155Seric 	int i;
221*2155Seric 
222*2155Seric 	dptr = replace(dptr);
223*2155Seric 	end = Linend;
224*2155Seric 	NONBLANK(dptr);
225*2155Seric 	while (dptr < end) {
226*2155Seric 		dname = dptr;
227*2155Seric 		dptr = findch(dptr,',');
228*2155Seric 		*dptr++ = '\0';
229*2155Seric 		chksize(dname);
230*2155Seric 		if (Sym[i = lookup(dname)].usage&DCL)
231*2155Seric 			error("`%s' declared twice on line %d (905)",
232*2155Seric 				dname, Lineno);
233*2155Seric 		else
234*2155Seric 			Sym[i].usage =| DCL;
235*2155Seric 		NONBLANK(dptr);
236*2155Seric 	}
237*2155Seric }
238*2155Seric 
239*2155Seric 
240*2155Seric /*
241*2155Seric  * Errfunc calls fatal which stops the process.
242*2155Seric  */
243*2155Seric 
244*2155Seric errfunc(eptr)
245*2155Seric char *eptr;
246*2155Seric {
247*2155Seric 	warn("ERROR:%s\n",replace(eptr));
248*2155Seric 	error("err statement on line %d (915)", Lineno);
249*2155Seric }
250*2155Seric 
251*2155Seric 
252*2155Seric /*
253*2155Seric  * Endfunc indicates an end has been found by decrementing the if count
254*2155Seric  * flag.  If because of a previous if statement, text was being skipped,
255*2155Seric  * Delflag is also decremented.
256*2155Seric  */
257*2155Seric 
258*2155Seric endfunc()
259*2155Seric {
260*2155Seric 	if (--Ifcount < 0)
261*2155Seric 		error("`end' without matching `if' on line %d (910)",Lineno);
262*2155Seric 	if (Delflag > 0)
263*2155Seric 		Delflag--;
264*2155Seric 	return;
265*2155Seric }
266*2155Seric 
267*2155Seric 
268*2155Seric /*
269*2155Seric  * Msgfunc accepts a pointer to a line and prints that line on the
270*2155Seric  * diagnostic output.
271*2155Seric  */
272*2155Seric 
273*2155Seric msgfunc(mptr)
274*2155Seric char *mptr;
275*2155Seric {
276*2155Seric 	warn("Message(%d):%s\n", Lineno, replace(mptr));
277*2155Seric }
278*2155Seric 
279*2155Seric 
280*2155Seric repfunc(s)
281*2155Seric char *s;
282*2155Seric {
283*2155Seric 	fprintf(stdout,"%s\n",replace(s));
284*2155Seric }
285*2155Seric 
286*2155Seric 
287*2155Seric /*
288*2155Seric  * Iffunc and the three functions following it, door, doand, and exp
289*2155Seric  * are responsible for parsing and interperting the condition in the
290*2155Seric  * if statement.  The BNF used is as follows:
291*2155Seric  *	<iffunc> ::=   [ "not" ] <door> EOL
292*2155Seric  *	<door> ::=     <doand> | <doand> "|" <door>
293*2155Seric  *	<doand>::=     <exp> | <exp> "&" <doand>
294*2155Seric  *	<exp>::=       "(" <door> ")" | <value> <operator> <value>
295*2155Seric  *	<operator>::=  "=" | "!=" | "<" | ">"
296*2155Seric  * And has precedence over or.  If the condition is false the Delflag
297*2155Seric  * is bumped to indicate that lines are to be skipped.
298*2155Seric  * An external variable, sptr is used for processing the line in
299*2155Seric  * iffunc, door, doand, exp, getid.
300*2155Seric  * Iffunc accepts a pointer to a line and sets sptr to that line.  The
301*2155Seric  * rest of iffunc, door, and doand follow the BNF exactly.
302*2155Seric  */
303*2155Seric 
304*2155Seric char *sptr;
305*2155Seric 
306*2155Seric iffunc(iptr)
307*2155Seric char *iptr;
308*2155Seric {
309*2155Seric 	register int value, not;
310*2155Seric 
311*2155Seric 	Ifcount++;
312*2155Seric 	if (Delflag > 0)
313*2155Seric 		Delflag++;
314*2155Seric 
315*2155Seric 	else {
316*2155Seric 		sptr = replace(iptr);
317*2155Seric 		NONBLANK(sptr);
318*2155Seric 		if (imatch("not ", sptr)) {
319*2155Seric 			not = FALSE;
320*2155Seric 			sptr =+ 4;
321*2155Seric 		}
322*2155Seric 		else not = TRUE;
323*2155Seric 
324*2155Seric 		value = door();
325*2155Seric 		if( *sptr != 0)
326*2155Seric 			error("syntax on line %d (918)",Lineno);
327*2155Seric 
328*2155Seric 		if (value != not)
329*2155Seric 			Delflag++;
330*2155Seric 	}
331*2155Seric 
332*2155Seric 	return;
333*2155Seric }
334*2155Seric 
335*2155Seric 
336*2155Seric door()
337*2155Seric {
338*2155Seric 	int value;
339*2155Seric 	value = doand();
340*2155Seric 	NONBLANK(sptr);
341*2155Seric 	while (*sptr=='|') {
342*2155Seric 		sptr++;
343*2155Seric 		value =| doand();
344*2155Seric 		NONBLANK(sptr);
345*2155Seric 	}
346*2155Seric 	return(value);
347*2155Seric }
348*2155Seric 
349*2155Seric 
350*2155Seric doand()
351*2155Seric {
352*2155Seric 	int value;
353*2155Seric 	value = exp();
354*2155Seric 	NONBLANK(sptr);
355*2155Seric 	while (*sptr=='&') {
356*2155Seric 		sptr++;
357*2155Seric 		value =& exp();
358*2155Seric 		NONBLANK(sptr);
359*2155Seric 	}
360*2155Seric 	return(value);
361*2155Seric }
362*2155Seric 
363*2155Seric 
364*2155Seric /*
365*2155Seric  * After exp checks for parentheses, it picks up a value by calling getid,
366*2155Seric  * picks up an operator and calls getid to pick up the second value.
367*2155Seric  * Then based on the operator it calls either numcomp or equal to see
368*2155Seric  * if the exp is true or false and returns the correct value.
369*2155Seric  */
370*2155Seric 
371*2155Seric exp()
372*2155Seric {
373*2155Seric 	register char op, save;
374*2155Seric 	register int value;
375*2155Seric 	char *id1, *id2, next;
376*2155Seric 
377*2155Seric 	NONBLANK(sptr);
378*2155Seric 	if(*sptr == '(') {
379*2155Seric 		sptr++;
380*2155Seric 		value = door();
381*2155Seric 		NONBLANK(sptr);
382*2155Seric 		if (*sptr == ')') {
383*2155Seric 			sptr++;
384*2155Seric 			return(value);
385*2155Seric 		}
386*2155Seric 		else error("parenthesis error on line %d (911)",Lineno);
387*2155Seric 	}
388*2155Seric 
389*2155Seric 	id1 = getid(sptr);
390*2155Seric 	if (op = *sptr)
391*2155Seric 		*sptr++ = '\0';
392*2155Seric 	if (op == NEQ && (next = *sptr++) == '\0')
393*2155Seric 		--sptr;
394*2155Seric 	id2 = getid(sptr);
395*2155Seric 	save = *sptr;
396*2155Seric 	*sptr = '\0';
397*2155Seric 
398*2155Seric 	if(op ==LT || op == GT) {
399*2155Seric 		value = numcomp(id1, id2);
400*2155Seric 		if ((op == GT && value == 1) || (op == LT && value == -1))
401*2155Seric 			value = TRUE;
402*2155Seric 		else value = FALSE;
403*2155Seric 	}
404*2155Seric 
405*2155Seric 	else if (op==EQ || (op==NEQ && next==EQ)) {
406*2155Seric 		value = equal(id1, id2);
407*2155Seric 		if ( op == NEQ)
408*2155Seric 			value = !value;
409*2155Seric 	}
410*2155Seric 
411*2155Seric 	else error("invalid operator on line %d (912)", Lineno);
412*2155Seric 	*sptr = save;
413*2155Seric 	return(value);
414*2155Seric }
415*2155Seric 
416*2155Seric 
417*2155Seric /*
418*2155Seric  * Getid picks up a value off a line and returns a pointer to the value.
419*2155Seric  */
420*2155Seric 
421*2155Seric getid(gptr)
422*2155Seric register char *gptr;
423*2155Seric {
424*2155Seric 	register char c, *id;
425*2155Seric 
426*2155Seric 	NONBLANK(gptr);
427*2155Seric 	id = gptr;
428*2155Seric 	gptr = findstr(gptr,DELIM);
429*2155Seric 	if (*gptr)
430*2155Seric 		*gptr++ = '\0';
431*2155Seric 	NONBLANK(gptr);
432*2155Seric 	sptr = gptr;
433*2155Seric 	return(id);
434*2155Seric }
435*2155Seric 
436*2155Seric 
437*2155Seric /*
438*2155Seric  * Numcomp accepts two pointers to strings of digits and calls numck
439*2155Seric  * to see if the strings contain only digits.  It returns -1 if
440*2155Seric  * the first is less than the second, 1 if the first is greater than the
441*2155Seric  * second and 0 if the two are equal.
442*2155Seric  */
443*2155Seric 
444*2155Seric numcomp(id1, id2)
445*2155Seric register char *id1, *id2;
446*2155Seric {
447*2155Seric 	int k1, k2;
448*2155Seric 
449*2155Seric 	numck(id1);
450*2155Seric 	numck(id2);
451*2155Seric 	while (*id1 == '0')
452*2155Seric 		id1++;
453*2155Seric 	while (*id2 == '0')
454*2155Seric 		id2++;
455*2155Seric 	if ((k1 = size(id1)) > (k2 = size(id2)))
456*2155Seric 		return(1);
457*2155Seric 	else if (k1 < k2)
458*2155Seric 		return(-1);
459*2155Seric 	else while(*id1 != '\0') {
460*2155Seric 		if(*id1 > *id2)
461*2155Seric 			return(1);
462*2155Seric 		else if(*id1 < *id2)
463*2155Seric 			return(-1);
464*2155Seric 		id1++;
465*2155Seric 		id2++;
466*2155Seric 	}
467*2155Seric 	return(0);
468*2155Seric }
469*2155Seric 
470*2155Seric 
471*2155Seric /*
472*2155Seric  * Numck accepts a pointer to a string and checks to see if they are
473*2155Seric  * all digits.  If they're not it calls fatal, otherwise it returns.
474*2155Seric  */
475*2155Seric 
476*2155Seric numck(nptr)
477*2155Seric register char *nptr;
478*2155Seric {
479*2155Seric 	for (; *nptr != '\0'; nptr++)
480*2155Seric 		if (!numeric(*nptr))
481*2155Seric 			error("non-numerical value on line %d (914)",Lineno);
482*2155Seric 	return;
483*2155Seric }
484*2155Seric 
485*2155Seric 
486*2155Seric /*
487*2155Seric  * Replace accepts a pointer to a line and scans the line for a keyword
488*2155Seric  * enclosed in control characters.  If it doesn't find one it returns
489*2155Seric  * a pointer to the begining of the line.  Otherwise, it calls
490*2155Seric  * lookup to find the keyword.
491*2155Seric  * It rewrites the line substituting the value for the
492*2155Seric  * keyword enclosed in control characters.  It then continues scanning
493*2155Seric  * the line until no control characters are found and returns a pointer to
494*2155Seric  * the begining of the new line.
495*2155Seric  */
496*2155Seric 
497*2155Seric # define INCR(int) if (++int==NSLOTS) error(subrng,Lineno)
498*2155Seric char *subrng "out of space [line %d] (916)";
499*2155Seric 
500*2155Seric replace(ptr)
501*2155Seric char *ptr;
502*2155Seric {
503*2155Seric 	char *slots[NSLOTS];
504*2155Seric 	int i,j,newlen;
505*2155Seric 	register char *s, *t, *p;
506*2155Seric 
507*2155Seric 	for (s=ptr; *s++!='\n';);
508*2155Seric 	*(--s) = '\0';
509*2155Seric 	Linend = s;
510*2155Seric 	i = -1;
511*2155Seric 	for (p=ptr; *(s=findch(p,Ctlchar)); p=t) {
512*2155Seric 		*s++ = '\0';
513*2155Seric 		INCR(i);
514*2155Seric 		slots[i] = p;
515*2155Seric 		if (*(t=findch(s,Ctlchar))==0)
516*2155Seric 			error("unmatched `%c' on line %d (907)",Ctlchar,Lineno);
517*2155Seric 		*t++ = '\0';
518*2155Seric 		INCR(i);
519*2155Seric 		slots[i] = Sym[j = lookup(s)].value;
520*2155Seric 		Sym[j].usage =| USD;
521*2155Seric 	}
522*2155Seric 	INCR(i);
523*2155Seric 	slots[i] = p;
524*2155Seric 	if (i==0) return(ptr);
525*2155Seric 	newlen = 0;
526*2155Seric 	for (j=0; j<=i; j++)
527*2155Seric 		newlen =+ (size(slots[j])-1);
528*2155Seric 	t = Repflag = alloc(++newlen);
529*2155Seric 	for (j=0; j<=i; j++)
530*2155Seric 		t = ecopy(slots[j],t);
531*2155Seric 	Linend = t;
532*2155Seric 	return(Repflag);
533*2155Seric }
534*2155Seric 
535*2155Seric 
536*2155Seric /*
537*2155Seric  * Lookup accepts a pointer to a keyword name and searches the symbol
538*2155Seric  * table for the keyword.  It returns its index in the table if its there,
539*2155Seric  * otherwise it puts the keyword in the table.
540*2155Seric  */
541*2155Seric 
542*2155Seric lookup(lname)
543*2155Seric char *lname;
544*2155Seric {
545*2155Seric 	register int i;
546*2155Seric 	register char *t;
547*2155Seric 	register struct symtab *s;
548*2155Seric 
549*2155Seric 	t = lname;
550*2155Seric 	while ((i.chr = *t++) &&
551*2155Seric 		((i.chr>='A' && i.chr<='Z') || (i.chr>='a' && i.chr<='z') ||
552*2155Seric 			(i.chr!= *lname && i.chr>='0' && i.chr<='9')));
553*2155Seric 	if (i.chr)
554*2155Seric 		error("invalid keyword name on line %d (909)",Lineno);
555*2155Seric 
556*2155Seric 	for(i =0; Sym[i].usage != 0 && i<SYMSIZE; i++)
557*2155Seric 		if (equal(lname, Sym[i].name)) return(i);
558*2155Seric 	s = &Sym[i];
559*2155Seric 	if (s->usage == 0) {
560*2155Seric 		copy(lname,s->name);
561*2155Seric 		copy("",(s->value = alloc(s->lenval = 1)));
562*2155Seric 		return(i);
563*2155Seric 	}
564*2155Seric 	error("out of space (906)");
565*2155Seric }
566*2155Seric 
567*2155Seric 
568*2155Seric /*
569*2155Seric  * Putin accepts a pointer to a keyword name, and a pointer to a value.
570*2155Seric  * It puts this information in the symbol table by calling lookup.
571*2155Seric  * It returns the index of the name in the table.
572*2155Seric  */
573*2155Seric 
574*2155Seric putin(pname, pvalue)
575*2155Seric char *pname;
576*2155Seric char *pvalue;
577*2155Seric {
578*2155Seric 	register int i;
579*2155Seric 	register struct symtab *s;
580*2155Seric 
581*2155Seric 	s = &Sym[i = lookup(pname)];
582*2155Seric 	free(s->value);
583*2155Seric 	s->lenval = size(pvalue);
584*2155Seric 	copy(pvalue, (s->value = alloc(s->lenval)));
585*2155Seric 	s->usage =| ASG;
586*2155Seric 	return(i);
587*2155Seric }
588*2155Seric 
589*2155Seric 
590*2155Seric chksize(s)
591*2155Seric char *s;
592*2155Seric {
593*2155Seric 	if (size(s) > PARMSIZE)
594*2155Seric 		error("keyword name too long on line %d (908)",Lineno);
595*2155Seric }
596*2155Seric 
597*2155Seric 
598*2155Seric findch(astr,match)
599*2155Seric char *astr, match;
600*2155Seric {
601*2155Seric 	register char *s, *t, c;
602*2155Seric 	char *temp;
603*2155Seric 
604*2155Seric 	for (s=astr; (c = *s) && c!=match; s++)
605*2155Seric 		if (c=='\\') {
606*2155Seric 			if (s[1]==0)
607*2155Seric 				error("syntax on line %d (919)",Lineno);
608*2155Seric 			else {
609*2155Seric 				for (t = (temp=s) + 1; *s++ = *t++;);
610*2155Seric 				s = temp;
611*2155Seric 			}
612*2155Seric 		}
613*2155Seric 	return(s);
614*2155Seric }
615*2155Seric 
616*2155Seric 
617*2155Seric ecopy(s1,s2)
618*2155Seric char *s1, *s2;
619*2155Seric {
620*2155Seric 	register char *r1, *r2;
621*2155Seric 
622*2155Seric 	r1 = s1;
623*2155Seric 	r2 = s2;
624*2155Seric 	while (*r2++ = *r1++);
625*2155Seric 	return(--r2);
626*2155Seric }
627*2155Seric 
628*2155Seric 
629*2155Seric error(arg)
630*2155Seric {
631*2155Seric 	fatal(sprintf(Error,"%r",&arg));
632*2155Seric }
633*2155Seric 
634*2155Seric 
635*2155Seric findstr(astr,pat)
636*2155Seric char *astr, *pat;
637*2155Seric {
638*2155Seric 	register char *s, *t, c;
639*2155Seric 	char *temp;
640*2155Seric 
641*2155Seric 	for (s=astr; (c = *s) && any(c,pat)==0; s++)
642*2155Seric 		if (c=='\\') {
643*2155Seric 			if (s[1]==0)
644*2155Seric 				error("syntax on line %d (919)",Lineno);
645*2155Seric 			else {
646*2155Seric 				for (t = (temp=s) + 1; *s++ = *t++;);
647*2155Seric 				s = temp;
648*2155Seric 			}
649*2155Seric 		}
650*2155Seric 	return(s);
651*2155Seric }
652*2155Seric 
653*2155Seric 
654*2155Seric warn(arg)
655*2155Seric {
656*2155Seric 	if (!Silent)
657*2155Seric 		fprintf(stderr,"%r",&arg);
658*2155Seric }
659