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
do_extends(const Meta_info parentM,const Translator_info * T_info,char * value)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
find_fun(char * key,char * value,char * parentfun)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
arch_match(FILE * fp,int arch)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