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