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