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