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