/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1997-1999 by Sun Microsystems, Inc. * All rights reserved. */ #include #include #include #include #include #include #include "parser.h" #include "errlog.h" static int find_fun(char *key, char *value, char *parentfun); /* * handles the extends clause of the 'function' keyword * Returns the number of errors encountered * This function is recursive. */ int do_extends(const Meta_info parentM, const Translator_info *T_info, char *value) { static int extends_count = 0; char funname[BUFSIZ], filename[MAXPATHLEN], parentfun[BUFSIZ], buf[BUFSIZ], key[20]; char *ifilename, *f, *p; char *localvalue = NULL, *buf2 = NULL; FILE *efp; Meta_info M; int found = 0, errors = 0, ki = 0; int retval; int scan; ++extends_count; if (extends_count > MAX_EXTENDS) { errlog(ERROR, "\"%s\", line %d: Error: Too many levels of " "extends\n", parentM.mi_filename, parentM.mi_line_number); ++errors; goto ret; } scan = sscanf(value, "%s %s %s %s", funname, buf, filename, parentfun); switch (scan) { case 0: /* funname not set */ case 1: /* buf not set, though ignored */ case 2: /* filename not set */ errlog(ERROR, "\"%s\", line %d: Error: Couldn't parse " "'data' or 'function' line\n", parentM.mi_filename, parentM.mi_line_number); ++errors; goto ret; break; case 3: (void) strncpy(parentfun, funname, BUFSIZ); parentfun[BUFSIZ-1] = '\0'; break; default: break; } /* All info is from parent file - extends */ M.mi_ext_cnt = extends_count; if (T_info->ti_verbosity >= TRACING) { errlog(TRACING, "Extending file %s\nExtending function %s\n" "SPEC's from %s\n", filename, parentfun, T_info->ti_dash_I); } f = pathfind(T_info->ti_dash_I, filename, "f"); if (f == NULL) { errlog(ERROR, "\"%s\", line %d: Error: Unable to find spec " "file \"%s\"\n", parentM.mi_filename, parentM.mi_line_number, filename); ++errors; goto ret; } ifilename = strdup(f); if (ifilename == NULL) { errlog(ERROR | FATAL, "Error: strdup() of filename failed\n"); } efp = fopen(ifilename, "r"); if (efp == NULL) { errlog(ERROR, "\"%s\", line %d: Error: Unable to open " "file \"%s\"\n", parentM.mi_filename, parentM.mi_line_number, ifilename); free(ifilename); ++errors; goto ret; } (void) strncpy(M.mi_filename, ifilename, MAXPATHLEN); M.mi_line_number = 0; /* search for begin function */ while (M.mi_nlines = readline(&buf2, efp)) { M.mi_line_number += M.mi_nlines; if (!non_empty(buf2)) { /* is line non empty */ free(buf2); buf2 = NULL; continue; } p = realloc(localvalue, sizeof (char)*(strlen(buf2)+1)); if (p == NULL) { errlog(ERROR | FATAL, "Error (do_extends): " "Unable to allocate memory\n"); } localvalue = p; split(buf2, key, localvalue); if ((found = find_fun(key, localvalue, parentfun))) { /* check if architecture matches */ if (found = arch_match(efp, T_info->ti_archtoken)) break; } free(buf2); buf2 = NULL; } if (found) { int extends_err = 0; static int extends_warn = 0; extends_err = check4extends(ifilename, localvalue, T_info->ti_archtoken, efp); switch (extends_err) { case -1: /* Error */ errlog(ERROR, "\"%s\", line %d: Error occurred while " "checking for extends clause\n", M.mi_filename, M.mi_line_number); ++errors; /*FALLTHRU*/ case 0: /* No Extends */ break; case 1: /* Extends */ /* * Warning on more then one level of extends * but only warn once. */ if (extends_count == 1) { extends_warn = 1; } if ((extends_err = do_extends(M, T_info, localvalue)) != 0) { if (extends_count == 1) { errlog(ERROR, "\"%s\", line %d: " "Error occurred while " "processing 'extends'\n", parentM.mi_filename, parentM.mi_line_number); } errors += extends_err; } if (extends_warn == 1 && extends_count == 1) { errlog(ERROR, "\"%s\", line %d: " "Warning: \"%s\" does not extend " "a base specification", parentM.mi_filename, parentM.mi_line_number, funname); } break; default: /* Programmer Error */ errlog(ERROR | FATAL, "Error: invalid return from " "check4extends: %d\n", extends_err); } free(buf2); buf2 = NULL; while (M.mi_nlines = readline(&buf2, efp)) { M.mi_line_number += M.mi_nlines; if (!non_empty(buf2)) { /* is line non empty */ free(buf2); buf2 = NULL; continue; } p = realloc(localvalue, sizeof (char)*(strlen(buf2)+1)); if (p == NULL) { p = realloc(NULL, sizeof (char)*(strlen(buf2)+1)); if (p == NULL) { errlog(ERROR | FATAL, "Error: unable to " "allocate memory\n"); } } localvalue = p; split(buf2, key, localvalue); ki = interesting_keyword(keywordlist, key); switch (ki) { case XLATOR_KW_END: goto end; break; case XLATOR_KW_FUNC: case XLATOR_KW_DATA: errlog(ERROR, "\"%s\", line %d: " "Error: Interface is missing \"end\"\n" "\"%s\", line %d: Error while processing " "%s\n", M.mi_filename, M.mi_line_number, parentM.mi_filename, parentM.mi_line_number, ifilename); ++errors; goto end; break; case XLATOR_KW_NOTFOUND: if (T_info->ti_verbosity >= TRACING) errlog(STATUS, "uninteresting keyword: %s\n", key); break; default: retval = xlator_take_kvpair(M, ki, localvalue); if (retval) { if (T_info->ti_verbosity >= STATUS) errlog(STATUS, "Error in " "xlator_take_kvpair\n"); ++errors; } } free(buf2); buf2 = NULL; } } else { errlog(ERROR, "\"%s\", line %d: Error: Unable to find " "function %s in %s\n", parentM.mi_filename, parentM.mi_line_number, parentfun, ifilename); ++errors; } end: (void) fclose(efp); free(localvalue); free(ifilename); free(buf2); ret: extends_count--; return (errors); } /* * find_fun() * given a key value pair, and the name of the function you are * searching for in the SPEC source file, this function returns 1 * if the beginning of the function in the SPEC source file is found. * returns 0 otherwise. */ static int find_fun(char *key, char *value, char *parentfun) { char pfun[BUFSIZ]; if (strcasecmp(key, "function") != 0 && strcasecmp(key, "data") != 0) { return (0); } (void) sscanf(value, "%1023s", pfun); if (strcmp(pfun, parentfun) == 0) { return (1); } return (0); } /* * arch_match(FILE *fp, int arch) * This function takes a FILE pointer, and an architecture token * The FILE pointer is assumed to point at the beginning of a Function * or Data specification (specifically at the first line of spec AFTER * the Function or Data line) * It reads all the way to the "End" line. * If it finds an "arch" keyword along the way, it is checked to see if * it matches the architecture currently being generated and returns * 1 if a match is found. If a match is not found, it returns a * 0. If no "arch" keyword is found, it returns 1. * * XXX - the algorithm in arch_match is very inefficient. it read through * the file to find "arch" and rewinds before returning. * Later all the data that was skipped while searching for "arch" may * be needed and it is re-read from the disk. It would be nice to just * read the data once. */ int arch_match(FILE *fp, int arch) { off_t offset; char key[20], buf[BUFSIZ], *buf2 = NULL, *localvalue = NULL, *p; int len; int has_arch = 0; int archset = 0; offset = ftello(fp); if (offset == -1) { errlog(ERROR|FATAL, "Unable to determine file position\n"); } while (fgets(buf, BUFSIZ, fp)) { /* replace comments with single whitespace */ remcomment(buf); /* get complete line */ buf2 = line_to_buf(buf2, buf); /* append buf to buf2 */ len = strlen(buf); if (len > 1) { while (buf[len-2] == '\\') { if (!fgets(buf, BUFSIZ, fp)) { buf2 = line_to_buf(buf2, buf); break; } len = strlen(buf); buf2 = line_to_buf(buf2, buf); } } /* end of 'get complete line' */ if (!non_empty(buf2)) { /* is line non empty */ free(buf2); buf2 = NULL; continue; } p = realloc(localvalue, sizeof (char)*(strlen(buf2)+1)); if (p == NULL) { p = realloc(NULL, sizeof (char)*(strlen(buf2)+1)); if (p == NULL) { errlog(ERROR | FATAL, "Error: unable to " "allocate memory\n"); } } localvalue = p; split(buf2, key, localvalue); if (strcasecmp(key, "arch") == 0) { char *alist = localvalue, *a; has_arch = 1; while ((a = strtok(alist, " ,\n")) != NULL) { archset = arch_strtoi(a); if (arch & archset) { free(buf2); free(p); if (fseeko(fp, offset, SEEK_SET) < 0) { errlog(ERROR|FATAL, "%s", strerror(errno)); } return (1); } alist = NULL; } } else if (strcasecmp(key, "end") == 0) { break; } free(buf2); buf2 = NULL; } end: free(buf2); free(p); if (fseeko(fp, offset, SEEK_SET) < 0) { errlog(ERROR|FATAL, "%s", strerror(errno)); } if (has_arch == 0) return (1); return (0); }