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