xref: /onnv-gate/usr/src/cmd/abi/spectrans/spec2map/versions.c (revision 2775:892d346f56a9)
1*2775Sraf /*
2*2775Sraf  * CDDL HEADER START
3*2775Sraf  *
4*2775Sraf  * The contents of this file are subject to the terms of the
5*2775Sraf  * Common Development and Distribution License, Version 1.0 only
6*2775Sraf  * (the "License").  You may not use this file except in compliance
7*2775Sraf  * with the License.
8*2775Sraf  *
9*2775Sraf  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*2775Sraf  * or http://www.opensolaris.org/os/licensing.
11*2775Sraf  * See the License for the specific language governing permissions
12*2775Sraf  * and limitations under the License.
13*2775Sraf  *
14*2775Sraf  * When distributing Covered Code, include this CDDL HEADER in each
15*2775Sraf  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*2775Sraf  * If applicable, add the following below this CDDL HEADER, with the
17*2775Sraf  * fields enclosed by brackets "[]" replaced with your own identifying
18*2775Sraf  * information: Portions Copyright [yyyy] [name of copyright owner]
19*2775Sraf  *
20*2775Sraf  * CDDL HEADER END
21*2775Sraf  */
22*2775Sraf /*
23*2775Sraf  * Copyright (c) 1997-1999 by Sun Microsystems, Inc.
24*2775Sraf  * All rights reserved.
25*2775Sraf  */
26*2775Sraf #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*2775Sraf 
28*2775Sraf #include <stdio.h>
29*2775Sraf #include <string.h>
30*2775Sraf #include <ctype.h>
31*2775Sraf #include "xlator.h"
32*2775Sraf #include "util.h"
33*2775Sraf #include "bucket.h"
34*2775Sraf #include "errlog.h"
35*2775Sraf 
36*2775Sraf /* Types: */
37*2775Sraf #define	TRUE	1
38*2775Sraf #define	FALSE	0
39*2775Sraf #define	MAXLINE 1024
40*2775Sraf 
41*2775Sraf 
42*2775Sraf typedef enum {
43*2775Sraf 	PARENT, UNCLE
44*2775Sraf } RELATION;
45*2775Sraf 
46*2775Sraf 
47*2775Sraf /* Statics: */
48*2775Sraf /* The parser is a dfa, driven by the following: */
49*2775Sraf static FILE *Fp;
50*2775Sraf static const char *Filename;
51*2775Sraf static char Previous[MAXLINE];
52*2775Sraf static char LeftMostChild[MAXLINE];
53*2775Sraf static int Selected = FALSE;
54*2775Sraf static int Line;
55*2775Sraf static int Errors;
56*2775Sraf 
57*2775Sraf 
58*2775Sraf /* The grammar is: */
59*2775Sraf static int arch(void);
60*2775Sraf static int comment(void);
61*2775Sraf static int arch_name(void);
62*2775Sraf static int set_list(void);
63*2775Sraf static int set(void);
64*2775Sraf 
65*2775Sraf /* The supporting code is: */
66*2775Sraf static int accept_token(char *);
67*2775Sraf static void skip_to(char *);
68*2775Sraf 
69*2775Sraf /* And the tokenizer is: */
70*2775Sraf static char *tokenize(char *);
71*2775Sraf static char *currtok(void);
72*2775Sraf static char *nexttok(void);
73*2775Sraf static char *skipb(char *);
74*2775Sraf static char *skipover(char *);
75*2775Sraf static char *CurrTok = NULL;
76*2775Sraf 
77*2775Sraf static int set_parents(void);
78*2775Sraf 
79*2775Sraf static table_t *Vers;
80*2775Sraf static table_t *Varch;
81*2775Sraf 
82*2775Sraf static void init_tables(void);
83*2775Sraf 
84*2775Sraf static void add_valid_arch(char *);
85*2775Sraf static void add_valid_version(char *vers_name);
86*2775Sraf 
87*2775Sraf 
88*2775Sraf #define	in_specials(c)  ((c) == '{' || (c) == '}' || (c) == '+' || \
89*2775Sraf 	(c) == '-' || (c) == ';' || (c) == ':' || (c) == ',' || \
90*2775Sraf 	(c) == '[' || (c) == ']')
91*2775Sraf 
92*2775Sraf #define	eq(s1, s2)	(strcmp((s1), (s2)) == 0)
93*2775Sraf 
94*2775Sraf 
95*2775Sraf /*
96*2775Sraf  * parse_versions -- parse the file whose name is passed, return
97*2775Sraf  *	the number of (fatal) errors encountered. Currently only
98*2775Sraf  *	knows about reading set files and writing vers files.
99*2775Sraf  */
100*2775Sraf int
parse_versions(const char * fileName)101*2775Sraf parse_versions(const char *fileName)
102*2775Sraf {
103*2775Sraf 
104*2775Sraf 	/* Prime the set-file parser dfa: */
105*2775Sraf 	assert(fileName != NULL, "passed null filename to parse_versions");
106*2775Sraf 	errlog(BEGIN, "parse_versions(%s) {", fileName);
107*2775Sraf 
108*2775Sraf 
109*2775Sraf 	if ((Fp = fopen(fileName, "r")) == NULL) {
110*2775Sraf 		(void) fprintf(stderr, "Cannot open version file \"%s\"\n",
111*2775Sraf 		    fileName);
112*2775Sraf 		errlog(END, "} /* parse_versions */");
113*2775Sraf 		return (1);
114*2775Sraf 	}
115*2775Sraf 	Filename = fileName;
116*2775Sraf 	Line = 0;
117*2775Sraf 
118*2775Sraf 	errlog(VERBOSE, "reading set file %s looking for architecture %s",
119*2775Sraf 	    Filename, TargetArchStr);
120*2775Sraf 
121*2775Sraf 	/* Run the dfa. */
122*2775Sraf 	while (arch())
123*2775Sraf 		continue;
124*2775Sraf 
125*2775Sraf 	(void) fclose(Fp);
126*2775Sraf 	/* print_all_buckets(); */
127*2775Sraf 	errlog(END, "} /* parse_versions */");
128*2775Sraf 	return (Errors);
129*2775Sraf }
130*2775Sraf 
131*2775Sraf 
132*2775Sraf /*
133*2775Sraf  * The parser. This implements the grammar:
134*2775Sraf  *    setfile::= (arch())+ <EOF>
135*2775Sraf  *             | <EOF>
136*2775Sraf  *    arch::= <ARCHITECTURE> "{" (set_list())* "}"
137*2775Sraf  *    set_list::= (set())+ ";"
138*2775Sraf  *    set::= <IDENTIFIER> ["[" "WEAK" "]"] ":" "{" (ancestors) "}" ";"
139*2775Sraf  *    ancestors::= <IDENTIFIER> | <ancestors> "," <IDENTIFIER>
140*2775Sraf  *    where <ARCHITECTURE> and <IDENTIFIER> are tokens.
141*2775Sraf  */
142*2775Sraf static int
arch(void)143*2775Sraf arch(void)
144*2775Sraf {
145*2775Sraf 	int olderrors;
146*2775Sraf 
147*2775Sraf 	errlog(BEGIN, "arch() {");
148*2775Sraf 	if (comment()) {
149*2775Sraf 		errlog(END, "} /* arch */");
150*2775Sraf 		return (TRUE);
151*2775Sraf 	}
152*2775Sraf 	if (arch_name() == FALSE) {
153*2775Sraf 		errlog(END, "} /* arch */");
154*2775Sraf 		return (FALSE);
155*2775Sraf 	}
156*2775Sraf 	if (accept_token("{") == FALSE) {
157*2775Sraf 		errlog(END, "} /* arch */");
158*2775Sraf 		return (FALSE);
159*2775Sraf 	}
160*2775Sraf 
161*2775Sraf 	olderrors = Errors;
162*2775Sraf 	if (set_list() == FALSE) {
163*2775Sraf 		if (olderrors != Errors) {
164*2775Sraf 			errlog(END, "} /* arch */");
165*2775Sraf 			return (FALSE);
166*2775Sraf 		}
167*2775Sraf 	}
168*2775Sraf 
169*2775Sraf 	errlog(END, "} /* arch */");
170*2775Sraf 	return (TRUE);
171*2775Sraf }
172*2775Sraf 
173*2775Sraf static int
comment(void)174*2775Sraf comment(void)
175*2775Sraf {
176*2775Sraf 	char *token = currtok();
177*2775Sraf 
178*2775Sraf 	if (token == NULL || *token != '#') {
179*2775Sraf 		return (FALSE);
180*2775Sraf 	} else {
181*2775Sraf 		/* Swallow token. */
182*2775Sraf 		token =  nexttok();
183*2775Sraf 		return (TRUE);
184*2775Sraf 	}
185*2775Sraf }
186*2775Sraf 
187*2775Sraf static int
arch_name(void)188*2775Sraf arch_name(void)
189*2775Sraf {
190*2775Sraf 	char *token = currtok();
191*2775Sraf 
192*2775Sraf 	errlog(BEGIN, "arch_name() {");
193*2775Sraf 	errlog(VERBOSE, "token = '%s';",
194*2775Sraf 		token ? token : "<NULL>");
195*2775Sraf 
196*2775Sraf 	if (token == NULL) {
197*2775Sraf 		errlog(END, "} /* arch_name */");
198*2775Sraf 		return (FALSE);
199*2775Sraf 
200*2775Sraf 	} else if (in_specials(*token)) {
201*2775Sraf 		/* It's not an architecture */
202*2775Sraf 		Selected = FALSE;
203*2775Sraf 
204*2775Sraf 		/* Report a syntax error: TBD */
205*2775Sraf 		errlog(INPUT | ERROR, "found special char. %c "
206*2775Sraf 		    "while looking for an architecture name",
207*2775Sraf 		    *token);
208*2775Sraf 
209*2775Sraf 		skip_to("}");	/* The follower set for arch_name. */
210*2775Sraf 		errlog(END, "} /* arch name */");
211*2775Sraf 
212*2775Sraf 		Errors++;
213*2775Sraf 		return (FALSE);
214*2775Sraf 
215*2775Sraf 	} else if (!eq(token, TargetArchStr)) {
216*2775Sraf 		/* It's an architecture ... */
217*2775Sraf 		errlog(VERBOSE, "Begin unselected architecture: %s", token);
218*2775Sraf 		add_valid_arch(token);
219*2775Sraf 		(void) nexttok();
220*2775Sraf 
221*2775Sraf 		/* ... but the the wrong one. */
222*2775Sraf 		Selected = FALSE;
223*2775Sraf 		errlog(END, "} /* arch name */");
224*2775Sraf 		return (TRUE);
225*2775Sraf 	} else {
226*2775Sraf 		/* Found the right architecture. */
227*2775Sraf 		errlog(VERBOSE, "Begin selected architecture: %s", token);
228*2775Sraf 		add_valid_arch(token);
229*2775Sraf 		(void) nexttok();
230*2775Sraf 		Selected = TRUE;
231*2775Sraf 		errlog(END, "} /* arch name */");
232*2775Sraf 		return (TRUE);
233*2775Sraf 	}
234*2775Sraf }
235*2775Sraf 
236*2775Sraf 
237*2775Sraf static int
set_list(void)238*2775Sraf set_list(void)
239*2775Sraf {
240*2775Sraf 	int olderrors;
241*2775Sraf 	char *token = currtok();
242*2775Sraf 
243*2775Sraf 	errlog(BEGIN, "set_list() {");
244*2775Sraf 	errlog(VERBOSE, "token = '%s'",
245*2775Sraf 	    (token) ? token : "<NULL>");
246*2775Sraf 	if (set() == FALSE) {
247*2775Sraf 		errlog(END, "} /* set_list */");
248*2775Sraf 		return (FALSE);
249*2775Sraf 	}
250*2775Sraf 
251*2775Sraf 	olderrors = Errors;
252*2775Sraf 	while (set()) {
253*2775Sraf 		continue;
254*2775Sraf 	}
255*2775Sraf 	if (olderrors != Errors) {
256*2775Sraf 		errlog(END, "} /* set_list */");
257*2775Sraf 		return (FALSE);
258*2775Sraf 	}
259*2775Sraf 
260*2775Sraf 	errlog(END, "} /* set_list */");
261*2775Sraf 	return (TRUE);
262*2775Sraf }
263*2775Sraf 
264*2775Sraf 
265*2775Sraf static int
set(void)266*2775Sraf set(void)
267*2775Sraf {
268*2775Sraf 	char *token = currtok();
269*2775Sraf 	int has_parent = 0;
270*2775Sraf 
271*2775Sraf 	errlog(BEGIN, "set() {");
272*2775Sraf 	errlog(VERBOSE, "token = '%s'",
273*2775Sraf 	    (token) ? token : "<NULL>");
274*2775Sraf 
275*2775Sraf 	if (in_specials(*token)) {
276*2775Sraf 		errlog(INPUT|ERROR, "unexpected token \"%s\" found. "
277*2775Sraf 		    "Version name expected", token);
278*2775Sraf 		Errors++;
279*2775Sraf 		errlog(END, "} /* set */");
280*2775Sraf 		return (FALSE);
281*2775Sraf 	}
282*2775Sraf 
283*2775Sraf 	errlog(VERBOSE, "Begin Version: %s", token);
284*2775Sraf 	*Previous = '\0';
285*2775Sraf 	if (Selected) {
286*2775Sraf 		if (add_parent(token, Previous, 0) == FALSE) {
287*2775Sraf 			errlog(INPUT | ERROR, "unable to add a parent version "
288*2775Sraf 			    "from the set file");
289*2775Sraf 			Errors++;
290*2775Sraf 			errlog(END, "} /* set */");
291*2775Sraf 			return (FALSE);
292*2775Sraf 		}
293*2775Sraf 	}
294*2775Sraf 
295*2775Sraf 	add_valid_version(token);
296*2775Sraf 	(void) strncpy(LeftMostChild, token, MAXLINE);
297*2775Sraf 	LeftMostChild[MAXLINE-1] = '\0';
298*2775Sraf 	(void) strncpy(Previous, token, MAXLINE);
299*2775Sraf 	Previous[MAXLINE-1] = '\0';
300*2775Sraf 
301*2775Sraf 	token = nexttok();
302*2775Sraf 
303*2775Sraf 	switch (*token) {
304*2775Sraf 		case ':':
305*2775Sraf 			errlog(VERBOSE, "token ':' found");
306*2775Sraf 			(void) accept_token(":");
307*2775Sraf 			if (set_parents() == FALSE) {
308*2775Sraf 				errlog(END, "} /* set */");
309*2775Sraf 				return (FALSE);
310*2775Sraf 			}
311*2775Sraf 			if (accept_token(";") == FALSE) {
312*2775Sraf 				errlog(END, "} /* set */");
313*2775Sraf 				return (FALSE);
314*2775Sraf 			}
315*2775Sraf 			errlog(VERBOSE, "End Version");
316*2775Sraf 			break;
317*2775Sraf 
318*2775Sraf 		case ';':
319*2775Sraf 			errlog(VERBOSE, "token ';' found");
320*2775Sraf 			(void) accept_token(";");
321*2775Sraf 			errlog(VERBOSE, "End version ':'");
322*2775Sraf 			break;
323*2775Sraf 
324*2775Sraf 		case '[':
325*2775Sraf 			(void) accept_token("[");
326*2775Sraf 			if (accept_token("WEAK") == FALSE) {
327*2775Sraf 				errlog(END, "} /* set */");
328*2775Sraf 				return (FALSE);
329*2775Sraf 			}
330*2775Sraf 			if (accept_token("]") == FALSE) {
331*2775Sraf 				errlog(END, "} /* set */");
332*2775Sraf 				return (FALSE);
333*2775Sraf 			}
334*2775Sraf 			token = currtok();
335*2775Sraf 			if (eq(token, ":")) {
336*2775Sraf 				(void) accept_token(":");
337*2775Sraf 				has_parent = 1;
338*2775Sraf 			} else if (eq(token, ";")) {
339*2775Sraf 				(void) accept_token(";");
340*2775Sraf 			} else {
341*2775Sraf 				errlog(ERROR|INPUT,
342*2775Sraf 				    "Unexpected token \"%s\" found. ':'"
343*2775Sraf 				    "or ';' expected.", token);
344*2775Sraf 				Errors++;
345*2775Sraf 				errlog(END, "} /* set */");
346*2775Sraf 				return (FALSE);
347*2775Sraf 			}
348*2775Sraf 			errlog(VERBOSE, "WEAK version detected\n");
349*2775Sraf 			if (Selected)
350*2775Sraf 				set_weak(LeftMostChild, TRUE);
351*2775Sraf 
352*2775Sraf 			if (has_parent) {
353*2775Sraf 				if (set_parents() == FALSE) {
354*2775Sraf 					errlog(END, "} /* set */");
355*2775Sraf 					return (FALSE);
356*2775Sraf 				}
357*2775Sraf 				if (accept_token(";") == FALSE) {
358*2775Sraf 					errlog(END, "} /* set */");
359*2775Sraf 					return (FALSE);
360*2775Sraf 				}
361*2775Sraf 			}
362*2775Sraf 			errlog(VERBOSE, "End Version");
363*2775Sraf 			break;
364*2775Sraf 		default:
365*2775Sraf 			/* CSTYLED */
366*2775Sraf 			errlog(ERROR|INPUT,
367*2775Sraf 			    "Unexpected token \"%s\" found. ';' expected.",
368*2775Sraf 			    token);
369*2775Sraf 			Errors++;
370*2775Sraf 			errlog(END, "} /* set */");
371*2775Sraf 			return (FALSE);
372*2775Sraf 	}
373*2775Sraf 
374*2775Sraf 	token = currtok();
375*2775Sraf 	if (eq(token, "}")) {
376*2775Sraf 		(void) accept_token("}");
377*2775Sraf 		errlog(VERBOSE, "End architecture");
378*2775Sraf 		errlog(END, "} /* set */");
379*2775Sraf 		return (FALSE);
380*2775Sraf 	}
381*2775Sraf 
382*2775Sraf 	errlog(END, "} /* set */");
383*2775Sraf 	return (TRUE);
384*2775Sraf }
385*2775Sraf 
386*2775Sraf static int
set_parents(void)387*2775Sraf set_parents(void)
388*2775Sraf {
389*2775Sraf 	char *token = currtok();
390*2775Sraf 	int uncle;
391*2775Sraf 
392*2775Sraf 	errlog(BEGIN, "set_parents() {");
393*2775Sraf 	errlog(VERBOSE, "token = '%s'",
394*2775Sraf 	    (token) ? token : "<NULL>");
395*2775Sraf 
396*2775Sraf 	if (accept_token("{") == FALSE) {
397*2775Sraf 		errlog(INPUT|ERROR, "set_parents(): Unexpected token: %s\n",
398*2775Sraf 		    token);
399*2775Sraf 		Errors++;
400*2775Sraf 		errlog(END, "} /* set_parents */");
401*2775Sraf 		return (FALSE);
402*2775Sraf 	}
403*2775Sraf 
404*2775Sraf 	token = currtok();
405*2775Sraf 
406*2775Sraf 	if (in_specials(*token)) {
407*2775Sraf 		errlog(INPUT|ERROR, "set_parents(): Unexpected token: %c "
408*2775Sraf 		    "found. Version token expected", *token);
409*2775Sraf 		Errors++;
410*2775Sraf 		errlog(END, "} /* set_parents */");
411*2775Sraf 		return (FALSE);
412*2775Sraf 	}
413*2775Sraf 
414*2775Sraf 	uncle = 0;
415*2775Sraf 	while (token && *token != '}') {
416*2775Sraf 		errlog(VERBOSE, "Begin parent list: %s\n", token);
417*2775Sraf 		if (Selected) {
418*2775Sraf 			if (uncle)
419*2775Sraf 				(void) add_uncle(token, LeftMostChild, 0);
420*2775Sraf 			else
421*2775Sraf 				(void) add_parent(token, Previous, 0);
422*2775Sraf 		}
423*2775Sraf 		(void) strncpy(Previous, token, MAXLINE);
424*2775Sraf 		add_valid_version(token);
425*2775Sraf 		Previous[MAXLINE-1] = '\0';
426*2775Sraf 
427*2775Sraf 		token = nexttok();
428*2775Sraf 
429*2775Sraf 		if (*token == ',') {
430*2775Sraf 			token = nexttok();
431*2775Sraf 			/* following identifiers are all uncles */
432*2775Sraf 			uncle = 1;
433*2775Sraf 			continue;
434*2775Sraf 		}
435*2775Sraf 
436*2775Sraf 		if (*token == '}') {
437*2775Sraf 			if (accept_token("}") == FALSE) {
438*2775Sraf 				errlog(END, "} /* set_parents */");
439*2775Sraf 				return (FALSE);
440*2775Sraf 			}
441*2775Sraf 			errlog(VERBOSE, "set_parent: End of parent list");
442*2775Sraf 			errlog(END, "} /* set_parents */");
443*2775Sraf 			return (TRUE);
444*2775Sraf 		}
445*2775Sraf 
446*2775Sraf 		errlog(INPUT|ERROR,
447*2775Sraf 		    "set_parents(): Unexpected token \"%s\" "
448*2775Sraf 		    "found. ',' or '}' were expected", token);
449*2775Sraf 		Errors++;
450*2775Sraf 		errlog(END, "} /* set_parents */");
451*2775Sraf 		return (FALSE);
452*2775Sraf 	}
453*2775Sraf 	errlog(END, "} /* set_parents */");
454*2775Sraf 	return (TRUE);
455*2775Sraf }
456*2775Sraf 
457*2775Sraf 
458*2775Sraf /*
459*2775Sraf  * parser support routines
460*2775Sraf  */
461*2775Sraf 
462*2775Sraf 
463*2775Sraf /*
464*2775Sraf  * accept_token -- get a specified token or complain loudly.
465*2775Sraf  */
466*2775Sraf static int
accept_token(char * expected)467*2775Sraf accept_token(char *expected)
468*2775Sraf {
469*2775Sraf 	char *token = currtok();
470*2775Sraf 
471*2775Sraf 	assert(expected != NULL, "null token passed to accept_token");
472*2775Sraf 	errlog(OTHER | TRACING, "accept_token, at %s expecting %s",
473*2775Sraf 		(token) ? token : "<NULL>", expected);
474*2775Sraf 
475*2775Sraf 	if (token == NULL) {
476*2775Sraf 		/* We're at EOF */
477*2775Sraf 		return (TRUE);
478*2775Sraf 	}
479*2775Sraf 	if (eq(token, expected)) {
480*2775Sraf 		(void) nexttok();
481*2775Sraf 		return (TRUE);
482*2775Sraf 	} else {
483*2775Sraf 		errlog(INPUT | ERROR,
484*2775Sraf 			"accept_token, found %s while looking for %s",
485*2775Sraf 			(token) ? token : "<NULL>", expected);
486*2775Sraf 		++Errors;
487*2775Sraf 		return (FALSE);
488*2775Sraf 	}
489*2775Sraf }
490*2775Sraf 
491*2775Sraf static void
skip_to(char * target)492*2775Sraf skip_to(char *target)
493*2775Sraf {
494*2775Sraf 	char *token = currtok();
495*2775Sraf 
496*2775Sraf 	assert(target != NULL, "null target passed to skip_to");
497*2775Sraf 	while (token && !eq(token, target)) {
498*2775Sraf 		errlog(VERBOSE, "skipping over %s",
499*2775Sraf 			(token) ? token : "<NULL>");
500*2775Sraf 		token = nexttok();
501*2775Sraf 	}
502*2775Sraf }
503*2775Sraf 
504*2775Sraf 
505*2775Sraf /*
506*2775Sraf  * tokenizer -- below the grammar lives this, like a troll
507*2775Sraf  *	under a bridge.
508*2775Sraf  */
509*2775Sraf 
510*2775Sraf 
511*2775Sraf /*
512*2775Sraf  * skipb -- skip over blanks (whitespace, actually), stopping
513*2775Sraf  *      on first non-blank.
514*2775Sraf  */
515*2775Sraf static char *
skipb(char * p)516*2775Sraf skipb(char *p)
517*2775Sraf {
518*2775Sraf 
519*2775Sraf 	while (*p && isspace(*p))
520*2775Sraf 		++p;
521*2775Sraf 	return (p);
522*2775Sraf }
523*2775Sraf 
524*2775Sraf /*
525*2775Sraf  * skipover -- skip over non-separators (alnum, . and _, actually),
526*2775Sraf  *      stopping on first separator.
527*2775Sraf  */
528*2775Sraf static char *
skipover(char * p)529*2775Sraf skipover(char *p)
530*2775Sraf {
531*2775Sraf 
532*2775Sraf 	while (*p && (isalnum(*p) || (*p == '_' || *p == '.')))
533*2775Sraf 		++p;
534*2775Sraf 	return (p);
535*2775Sraf }
536*2775Sraf 
537*2775Sraf 
538*2775Sraf /*
539*2775Sraf  * currtok/nexttok -- get the current/next token
540*2775Sraf  */
541*2775Sraf static char *
currtok(void)542*2775Sraf currtok(void)
543*2775Sraf {
544*2775Sraf 
545*2775Sraf 	if (CurrTok == NULL) {
546*2775Sraf 		(void) nexttok();
547*2775Sraf 	}
548*2775Sraf 	return (CurrTok);
549*2775Sraf }
550*2775Sraf 
551*2775Sraf static char *
nexttok(void)552*2775Sraf nexttok(void)
553*2775Sraf {
554*2775Sraf 	static char line[MAXLINE];
555*2775Sraf 	char *p;
556*2775Sraf 
557*2775Sraf 	if ((p = tokenize(NULL)) == NULL) {
558*2775Sraf 		/* We're at an end of line. */
559*2775Sraf 		do {
560*2775Sraf 			if (fgets(line, sizeof (line), Fp) == NULL) {
561*2775Sraf 				/* Which is also end of file. */
562*2775Sraf 				CurrTok = NULL;
563*2775Sraf 				return (NULL);
564*2775Sraf 			}
565*2775Sraf 			++Line;
566*2775Sraf 			seterrline(Line, Filename, "", line);
567*2775Sraf 		} while ((p = tokenize(line)) == NULL);
568*2775Sraf 	}
569*2775Sraf 	CurrTok = p;
570*2775Sraf 	return (p);
571*2775Sraf }
572*2775Sraf 
573*2775Sraf 
574*2775Sraf 
575*2775Sraf /*
576*2775Sraf  * tokenize -- a version of the standard strtok with specific behavior.
577*2775Sraf  */
578*2775Sraf static char *
tokenize(char * line)579*2775Sraf tokenize(char *line)
580*2775Sraf {
581*2775Sraf 	static char *p = NULL;
582*2775Sraf 	static char saved = 0;
583*2775Sraf 	char *q;
584*2775Sraf 
585*2775Sraf 	if (line == NULL && p == NULL) {
586*2775Sraf 		/* It's the very first time */
587*2775Sraf 		return (NULL);
588*2775Sraf 	} else if (line != NULL) {
589*2775Sraf 		/* Initialize with a new line */
590*2775Sraf 		q = skipb(line);
591*2775Sraf 	} else {
592*2775Sraf 		/* Restore previous line. */
593*2775Sraf 		*p = saved;
594*2775Sraf 		q = skipb(p);
595*2775Sraf 	}
596*2775Sraf 	/* q is at the beginning of a token or at EOL, p is irrelevant. */
597*2775Sraf 
598*2775Sraf 	if (*q == '\0') {
599*2775Sraf 		/* It's at EOL. */
600*2775Sraf 		p = q;
601*2775Sraf 	} else if (in_specials(*q)) {
602*2775Sraf 		/* We have a special-character token. */
603*2775Sraf 		p = q + 1;
604*2775Sraf 	} else if (*q == '#') {
605*2775Sraf 		/* The whole rest of the line is a comment token. */
606*2775Sraf 		return (NULL);
607*2775Sraf 	} else {
608*2775Sraf 		/* We have a word token. */
609*2775Sraf 		p = skipover(q);
610*2775Sraf 	}
611*2775Sraf 	saved = *p;
612*2775Sraf 	*p = '\0';
613*2775Sraf 
614*2775Sraf 	if (p == q) {
615*2775Sraf 		/* End of line */
616*2775Sraf 		return (NULL);
617*2775Sraf 	} else {
618*2775Sraf 		return (q);
619*2775Sraf 	}
620*2775Sraf }
621*2775Sraf 
622*2775Sraf 
623*2775Sraf /*
624*2775Sraf  * valid_version -- see if a version string was mentioned in the set file.
625*2775Sraf  */
626*2775Sraf int
valid_version(const char * vers_name)627*2775Sraf valid_version(const char *vers_name)
628*2775Sraf {
629*2775Sraf 
630*2775Sraf 	if (Vers == NULL) {
631*2775Sraf 		init_tables();
632*2775Sraf 	}
633*2775Sraf 	return (in_stringtable(Vers, vers_name));
634*2775Sraf }
635*2775Sraf 
636*2775Sraf /*
637*2775Sraf  * valid_arch -- see if the arch was mentioned in the set file.
638*2775Sraf  */
639*2775Sraf int
valid_arch(const char * arch_name)640*2775Sraf valid_arch(const char *arch_name)
641*2775Sraf {
642*2775Sraf 
643*2775Sraf 	if (Vers == NULL) {
644*2775Sraf 		init_tables();
645*2775Sraf 	}
646*2775Sraf 	return (in_stringtable(Varch, arch_name));
647*2775Sraf }
648*2775Sraf 
649*2775Sraf /*
650*2775Sraf  * add_valid_version and _arch -- add a name to the table.
651*2775Sraf  */
652*2775Sraf static void
add_valid_version(char * vers_name)653*2775Sraf add_valid_version(char *vers_name)
654*2775Sraf {
655*2775Sraf 	errlog(BEGIN, "add_valid_version(\"%s\") {", vers_name);
656*2775Sraf 	if (Vers == NULL) {
657*2775Sraf 		init_tables();
658*2775Sraf 	}
659*2775Sraf 	Vers = add_to_stringtable(Vers, vers_name);
660*2775Sraf 	errlog(END, "}");
661*2775Sraf }
662*2775Sraf 
663*2775Sraf static void
add_valid_arch(char * arch_name)664*2775Sraf add_valid_arch(char *arch_name)
665*2775Sraf {
666*2775Sraf 
667*2775Sraf 	errlog(BEGIN, "add_valid_arch(\"%s\") {", arch_name);
668*2775Sraf 	if (Vers == NULL) {
669*2775Sraf 		init_tables();
670*2775Sraf 	}
671*2775Sraf 	Varch = add_to_stringtable(Varch, arch_name);
672*2775Sraf 	errlog(END, "}");
673*2775Sraf }
674*2775Sraf 
675*2775Sraf /*
676*2775Sraf  * init_tables -- creat them when first used.
677*2775Sraf  */
678*2775Sraf static void
init_tables(void)679*2775Sraf init_tables(void)
680*2775Sraf {
681*2775Sraf 	Vers = create_stringtable(TABLE_INITIAL);
682*2775Sraf 	Varch = create_stringtable(TABLE_INITIAL);
683*2775Sraf }
684