xref: /titanic_50/usr/src/cmd/abi/spectrans/parser/extends.c (revision 753d2d2e8e7fd0c9bcf736d9bf2f2faf4d6234cc)
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