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