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