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 27*753d2d2eSraf #pragma ident "%Z%%M% %I% %E% SMI" 28*753d2d2eSraf 29*753d2d2eSraf #include <stdio.h> 30*753d2d2eSraf #include <string.h> 31*753d2d2eSraf #include <stdlib.h> 32*753d2d2eSraf #include <unistd.h> 33*753d2d2eSraf #include <libgen.h> 34*753d2d2eSraf #include <errno.h> 35*753d2d2eSraf #include "parser.h" 36*753d2d2eSraf #include "errlog.h" 37*753d2d2eSraf 38*753d2d2eSraf static int find_fun(char *key, char *value, char *parentfun); 39*753d2d2eSraf 40*753d2d2eSraf /* 41*753d2d2eSraf * handles the extends clause of the 'function' keyword 42*753d2d2eSraf * Returns the number of errors encountered 43*753d2d2eSraf * This function is recursive. 44*753d2d2eSraf */ 45*753d2d2eSraf int 46*753d2d2eSraf do_extends(const Meta_info parentM, const Translator_info *T_info, char *value) 47*753d2d2eSraf { 48*753d2d2eSraf static int extends_count = 0; 49*753d2d2eSraf char funname[BUFSIZ], filename[MAXPATHLEN], parentfun[BUFSIZ], 50*753d2d2eSraf buf[BUFSIZ], key[20]; 51*753d2d2eSraf char *ifilename, *f, *p; 52*753d2d2eSraf char *localvalue = NULL, *buf2 = NULL; 53*753d2d2eSraf FILE *efp; 54*753d2d2eSraf Meta_info M; 55*753d2d2eSraf int found = 0, errors = 0, ki = 0; 56*753d2d2eSraf int retval; 57*753d2d2eSraf int scan; 58*753d2d2eSraf 59*753d2d2eSraf ++extends_count; 60*753d2d2eSraf 61*753d2d2eSraf if (extends_count > MAX_EXTENDS) { 62*753d2d2eSraf errlog(ERROR, "\"%s\", line %d: Error: Too many levels of " 63*753d2d2eSraf "extends\n", parentM.mi_filename, parentM.mi_line_number); 64*753d2d2eSraf ++errors; 65*753d2d2eSraf goto ret; 66*753d2d2eSraf } 67*753d2d2eSraf 68*753d2d2eSraf scan = sscanf(value, "%s %s %s %s", funname, buf, filename, parentfun); 69*753d2d2eSraf switch (scan) { 70*753d2d2eSraf case 0: /* funname not set */ 71*753d2d2eSraf case 1: /* buf not set, though ignored */ 72*753d2d2eSraf case 2: /* filename not set */ 73*753d2d2eSraf errlog(ERROR, "\"%s\", line %d: Error: Couldn't parse " 74*753d2d2eSraf "'data' or 'function' line\n", 75*753d2d2eSraf parentM.mi_filename, parentM.mi_line_number); 76*753d2d2eSraf ++errors; 77*753d2d2eSraf goto ret; 78*753d2d2eSraf break; 79*753d2d2eSraf case 3: 80*753d2d2eSraf (void) strncpy(parentfun, funname, BUFSIZ); 81*753d2d2eSraf parentfun[BUFSIZ-1] = '\0'; 82*753d2d2eSraf break; 83*753d2d2eSraf default: 84*753d2d2eSraf break; 85*753d2d2eSraf } 86*753d2d2eSraf 87*753d2d2eSraf /* All info is from parent file - extends */ 88*753d2d2eSraf M.mi_ext_cnt = extends_count; 89*753d2d2eSraf 90*753d2d2eSraf if (T_info->ti_verbosity >= TRACING) { 91*753d2d2eSraf errlog(TRACING, "Extending file %s\nExtending function %s\n" 92*753d2d2eSraf "SPEC's from %s\n", filename, parentfun, 93*753d2d2eSraf T_info->ti_dash_I); 94*753d2d2eSraf } 95*753d2d2eSraf 96*753d2d2eSraf f = pathfind(T_info->ti_dash_I, filename, "f"); 97*753d2d2eSraf if (f == NULL) { 98*753d2d2eSraf errlog(ERROR, "\"%s\", line %d: Error: Unable to find spec " 99*753d2d2eSraf "file \"%s\"\n", parentM.mi_filename, 100*753d2d2eSraf parentM.mi_line_number, filename); 101*753d2d2eSraf ++errors; 102*753d2d2eSraf goto ret; 103*753d2d2eSraf } 104*753d2d2eSraf ifilename = strdup(f); 105*753d2d2eSraf if (ifilename == NULL) { 106*753d2d2eSraf errlog(ERROR | FATAL, "Error: strdup() of filename failed\n"); 107*753d2d2eSraf } 108*753d2d2eSraf efp = fopen(ifilename, "r"); 109*753d2d2eSraf if (efp == NULL) { 110*753d2d2eSraf errlog(ERROR, "\"%s\", line %d: Error: Unable to open " 111*753d2d2eSraf "file \"%s\"\n", parentM.mi_filename, 112*753d2d2eSraf parentM.mi_line_number, ifilename); 113*753d2d2eSraf free(ifilename); 114*753d2d2eSraf ++errors; 115*753d2d2eSraf goto ret; 116*753d2d2eSraf } 117*753d2d2eSraf 118*753d2d2eSraf (void) strncpy(M.mi_filename, ifilename, MAXPATHLEN); 119*753d2d2eSraf M.mi_line_number = 0; 120*753d2d2eSraf 121*753d2d2eSraf /* search for begin function */ 122*753d2d2eSraf while (M.mi_nlines = readline(&buf2, efp)) { 123*753d2d2eSraf M.mi_line_number += M.mi_nlines; 124*753d2d2eSraf 125*753d2d2eSraf if (!non_empty(buf2)) { /* is line non empty */ 126*753d2d2eSraf free(buf2); 127*753d2d2eSraf buf2 = NULL; 128*753d2d2eSraf continue; 129*753d2d2eSraf } 130*753d2d2eSraf p = realloc(localvalue, sizeof (char)*(strlen(buf2)+1)); 131*753d2d2eSraf if (p == NULL) { 132*753d2d2eSraf errlog(ERROR | FATAL, "Error (do_extends): " 133*753d2d2eSraf "Unable to allocate memory\n"); 134*753d2d2eSraf } 135*753d2d2eSraf localvalue = p; 136*753d2d2eSraf split(buf2, key, localvalue); 137*753d2d2eSraf if ((found = find_fun(key, localvalue, parentfun))) { 138*753d2d2eSraf /* check if architecture matches */ 139*753d2d2eSraf if (found = arch_match(efp, T_info->ti_archtoken)) 140*753d2d2eSraf break; 141*753d2d2eSraf } 142*753d2d2eSraf free(buf2); 143*753d2d2eSraf buf2 = NULL; 144*753d2d2eSraf } 145*753d2d2eSraf 146*753d2d2eSraf if (found) { 147*753d2d2eSraf int extends_err = 0; 148*753d2d2eSraf static int extends_warn = 0; 149*753d2d2eSraf extends_err = check4extends(ifilename, localvalue, 150*753d2d2eSraf T_info->ti_archtoken, efp); 151*753d2d2eSraf switch (extends_err) { 152*753d2d2eSraf case -1: /* Error */ 153*753d2d2eSraf errlog(ERROR, "\"%s\", line %d: Error occurred while " 154*753d2d2eSraf "checking for extends clause\n", 155*753d2d2eSraf M.mi_filename, M.mi_line_number); 156*753d2d2eSraf ++errors; 157*753d2d2eSraf /*FALLTHRU*/ 158*753d2d2eSraf case 0: /* No Extends */ 159*753d2d2eSraf break; 160*753d2d2eSraf case 1: /* Extends */ 161*753d2d2eSraf /* 162*753d2d2eSraf * Warning on more then one level of extends 163*753d2d2eSraf * but only warn once. 164*753d2d2eSraf */ 165*753d2d2eSraf if (extends_count == 1) { 166*753d2d2eSraf extends_warn = 1; 167*753d2d2eSraf } 168*753d2d2eSraf if ((extends_err = do_extends(M, T_info, localvalue)) 169*753d2d2eSraf != 0) { 170*753d2d2eSraf if (extends_count == 1) { 171*753d2d2eSraf errlog(ERROR, "\"%s\", line %d: " 172*753d2d2eSraf "Error occurred while " 173*753d2d2eSraf "processing 'extends'\n", 174*753d2d2eSraf parentM.mi_filename, 175*753d2d2eSraf parentM.mi_line_number); 176*753d2d2eSraf } 177*753d2d2eSraf errors += extends_err; 178*753d2d2eSraf } 179*753d2d2eSraf if (extends_warn == 1 && extends_count == 1) { 180*753d2d2eSraf errlog(ERROR, "\"%s\", line %d: " 181*753d2d2eSraf "Warning: \"%s\" does not extend " 182*753d2d2eSraf "a base specification", 183*753d2d2eSraf parentM.mi_filename, 184*753d2d2eSraf parentM.mi_line_number, 185*753d2d2eSraf funname); 186*753d2d2eSraf } 187*753d2d2eSraf break; 188*753d2d2eSraf default: /* Programmer Error */ 189*753d2d2eSraf errlog(ERROR | FATAL, 190*753d2d2eSraf "Error: invalid return from " 191*753d2d2eSraf "check4extends: %d\n", extends_err); 192*753d2d2eSraf } 193*753d2d2eSraf 194*753d2d2eSraf free(buf2); 195*753d2d2eSraf buf2 = NULL; 196*753d2d2eSraf 197*753d2d2eSraf while (M.mi_nlines = readline(&buf2, efp)) { 198*753d2d2eSraf M.mi_line_number += M.mi_nlines; 199*753d2d2eSraf 200*753d2d2eSraf if (!non_empty(buf2)) { /* is line non empty */ 201*753d2d2eSraf free(buf2); 202*753d2d2eSraf buf2 = NULL; 203*753d2d2eSraf continue; 204*753d2d2eSraf } 205*753d2d2eSraf p = realloc(localvalue, sizeof (char)*(strlen(buf2)+1)); 206*753d2d2eSraf if (p == NULL) { 207*753d2d2eSraf p = realloc(NULL, 208*753d2d2eSraf sizeof (char)*(strlen(buf2)+1)); 209*753d2d2eSraf if (p == NULL) { 210*753d2d2eSraf errlog(ERROR | FATAL, 211*753d2d2eSraf "Error: unable to " 212*753d2d2eSraf "allocate memory\n"); 213*753d2d2eSraf } 214*753d2d2eSraf } 215*753d2d2eSraf localvalue = p; 216*753d2d2eSraf split(buf2, key, localvalue); 217*753d2d2eSraf ki = interesting_keyword(keywordlist, key); 218*753d2d2eSraf switch (ki) { 219*753d2d2eSraf case XLATOR_KW_END: 220*753d2d2eSraf goto end; 221*753d2d2eSraf break; 222*753d2d2eSraf case XLATOR_KW_FUNC: 223*753d2d2eSraf case XLATOR_KW_DATA: 224*753d2d2eSraf errlog(ERROR, "\"%s\", line %d: " 225*753d2d2eSraf "Error: Interface is missing \"end\"\n" 226*753d2d2eSraf "\"%s\", line %d: Error while processing " 227*753d2d2eSraf "%s\n", M.mi_filename, M.mi_line_number, 228*753d2d2eSraf parentM.mi_filename, 229*753d2d2eSraf parentM.mi_line_number, ifilename); 230*753d2d2eSraf ++errors; 231*753d2d2eSraf goto end; 232*753d2d2eSraf break; 233*753d2d2eSraf case XLATOR_KW_NOTFOUND: 234*753d2d2eSraf if (T_info->ti_verbosity >= TRACING) 235*753d2d2eSraf errlog(STATUS, 236*753d2d2eSraf "uninteresting keyword: %s\n", key); 237*753d2d2eSraf break; 238*753d2d2eSraf default: 239*753d2d2eSraf retval = xlator_take_kvpair(M, ki, localvalue); 240*753d2d2eSraf if (retval) { 241*753d2d2eSraf if (T_info->ti_verbosity >= STATUS) 242*753d2d2eSraf errlog(STATUS, 243*753d2d2eSraf "Error in " 244*753d2d2eSraf "xlator_take_kvpair\n"); 245*753d2d2eSraf ++errors; 246*753d2d2eSraf } 247*753d2d2eSraf } 248*753d2d2eSraf free(buf2); 249*753d2d2eSraf buf2 = NULL; 250*753d2d2eSraf } 251*753d2d2eSraf } else { 252*753d2d2eSraf errlog(ERROR, "\"%s\", line %d: Error: Unable to find " 253*753d2d2eSraf "function %s in %s\n", parentM.mi_filename, 254*753d2d2eSraf parentM.mi_line_number, parentfun, ifilename); 255*753d2d2eSraf ++errors; 256*753d2d2eSraf } 257*753d2d2eSraf end: 258*753d2d2eSraf (void) fclose(efp); 259*753d2d2eSraf free(localvalue); 260*753d2d2eSraf free(ifilename); 261*753d2d2eSraf free(buf2); 262*753d2d2eSraf ret: 263*753d2d2eSraf extends_count--; 264*753d2d2eSraf return (errors); 265*753d2d2eSraf } 266*753d2d2eSraf 267*753d2d2eSraf /* 268*753d2d2eSraf * find_fun() 269*753d2d2eSraf * given a key value pair, and the name of the function you are 270*753d2d2eSraf * searching for in the SPEC source file, this function returns 1 271*753d2d2eSraf * if the beginning of the function in the SPEC source file is found. 272*753d2d2eSraf * returns 0 otherwise. 273*753d2d2eSraf */ 274*753d2d2eSraf static int 275*753d2d2eSraf find_fun(char *key, char *value, char *parentfun) 276*753d2d2eSraf { 277*753d2d2eSraf char pfun[BUFSIZ]; 278*753d2d2eSraf 279*753d2d2eSraf if (strcasecmp(key, "function") != 0 && 280*753d2d2eSraf strcasecmp(key, "data") != 0) { 281*753d2d2eSraf return (0); 282*753d2d2eSraf } 283*753d2d2eSraf 284*753d2d2eSraf (void) sscanf(value, "%1023s", pfun); 285*753d2d2eSraf 286*753d2d2eSraf if (strcmp(pfun, parentfun) == 0) { 287*753d2d2eSraf return (1); 288*753d2d2eSraf } 289*753d2d2eSraf 290*753d2d2eSraf return (0); 291*753d2d2eSraf } 292*753d2d2eSraf 293*753d2d2eSraf /* 294*753d2d2eSraf * arch_match(FILE *fp, int arch) 295*753d2d2eSraf * This function takes a FILE pointer, and an architecture token 296*753d2d2eSraf * The FILE pointer is assumed to point at the beginning of a Function 297*753d2d2eSraf * or Data specification (specifically at the first line of spec AFTER 298*753d2d2eSraf * the Function or Data line) 299*753d2d2eSraf * It reads all the way to the "End" line. 300*753d2d2eSraf * If it finds an "arch" keyword along the way, it is checked to see if 301*753d2d2eSraf * it matches the architecture currently being generated and returns 302*753d2d2eSraf * 1 if a match is found. If a match is not found, it returns a 303*753d2d2eSraf * 0. If no "arch" keyword is found, it returns 1. 304*753d2d2eSraf * 305*753d2d2eSraf * XXX - the algorithm in arch_match is very inefficient. it read through 306*753d2d2eSraf * the file to find "arch" and rewinds before returning. 307*753d2d2eSraf * Later all the data that was skipped while searching for "arch" may 308*753d2d2eSraf * be needed and it is re-read from the disk. It would be nice to just 309*753d2d2eSraf * read the data once. 310*753d2d2eSraf */ 311*753d2d2eSraf int 312*753d2d2eSraf arch_match(FILE *fp, int arch) 313*753d2d2eSraf { 314*753d2d2eSraf off_t offset; 315*753d2d2eSraf char key[20], buf[BUFSIZ], *buf2 = NULL, *localvalue = NULL, *p; 316*753d2d2eSraf int len; 317*753d2d2eSraf int has_arch = 0; 318*753d2d2eSraf int archset = 0; 319*753d2d2eSraf 320*753d2d2eSraf offset = ftello(fp); 321*753d2d2eSraf if (offset == -1) { 322*753d2d2eSraf errlog(ERROR|FATAL, "Unable to determine file position\n"); 323*753d2d2eSraf } 324*753d2d2eSraf 325*753d2d2eSraf while (fgets(buf, BUFSIZ, fp)) { 326*753d2d2eSraf /* replace comments with single whitespace */ 327*753d2d2eSraf remcomment(buf); 328*753d2d2eSraf 329*753d2d2eSraf /* get complete line */ 330*753d2d2eSraf buf2 = line_to_buf(buf2, buf); /* append buf to buf2 */ 331*753d2d2eSraf len = strlen(buf); 332*753d2d2eSraf if (len > 1) { 333*753d2d2eSraf while (buf[len-2] == '\\') { 334*753d2d2eSraf if (!fgets(buf, BUFSIZ, fp)) { 335*753d2d2eSraf buf2 = line_to_buf(buf2, buf); 336*753d2d2eSraf break; 337*753d2d2eSraf } 338*753d2d2eSraf len = strlen(buf); 339*753d2d2eSraf buf2 = line_to_buf(buf2, buf); 340*753d2d2eSraf } 341*753d2d2eSraf } /* end of 'get complete line' */ 342*753d2d2eSraf 343*753d2d2eSraf if (!non_empty(buf2)) { /* is line non empty */ 344*753d2d2eSraf free(buf2); 345*753d2d2eSraf buf2 = NULL; 346*753d2d2eSraf continue; 347*753d2d2eSraf } 348*753d2d2eSraf p = realloc(localvalue, sizeof (char)*(strlen(buf2)+1)); 349*753d2d2eSraf if (p == NULL) { 350*753d2d2eSraf p = realloc(NULL, 351*753d2d2eSraf sizeof (char)*(strlen(buf2)+1)); 352*753d2d2eSraf if (p == NULL) { 353*753d2d2eSraf errlog(ERROR | FATAL, 354*753d2d2eSraf "Error: unable to " 355*753d2d2eSraf "allocate memory\n"); 356*753d2d2eSraf } 357*753d2d2eSraf } 358*753d2d2eSraf localvalue = p; 359*753d2d2eSraf split(buf2, key, localvalue); 360*753d2d2eSraf if (strcasecmp(key, "arch") == 0) { 361*753d2d2eSraf char *alist = localvalue, *a; 362*753d2d2eSraf has_arch = 1; 363*753d2d2eSraf while ((a = strtok(alist, " ,\n")) != NULL) { 364*753d2d2eSraf archset = arch_strtoi(a); 365*753d2d2eSraf if (arch & archset) { 366*753d2d2eSraf free(buf2); 367*753d2d2eSraf free(p); 368*753d2d2eSraf if (fseeko(fp, offset, SEEK_SET) < 0) { 369*753d2d2eSraf errlog(ERROR|FATAL, 370*753d2d2eSraf "%s", strerror(errno)); 371*753d2d2eSraf } 372*753d2d2eSraf return (1); 373*753d2d2eSraf } 374*753d2d2eSraf alist = NULL; 375*753d2d2eSraf } 376*753d2d2eSraf } else if (strcasecmp(key, "end") == 0) { 377*753d2d2eSraf break; 378*753d2d2eSraf } 379*753d2d2eSraf free(buf2); 380*753d2d2eSraf buf2 = NULL; 381*753d2d2eSraf } 382*753d2d2eSraf 383*753d2d2eSraf end: 384*753d2d2eSraf free(buf2); 385*753d2d2eSraf free(p); 386*753d2d2eSraf 387*753d2d2eSraf if (fseeko(fp, offset, SEEK_SET) < 0) { 388*753d2d2eSraf errlog(ERROR|FATAL, "%s", strerror(errno)); 389*753d2d2eSraf } 390*753d2d2eSraf if (has_arch == 0) 391*753d2d2eSraf return (1); 392*753d2d2eSraf 393*753d2d2eSraf return (0); 394*753d2d2eSraf } 395