xref: /titanic_52/usr/src/cmd/abi/spectrans/spec2map/xlator.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 2003 Sun Microsystems, Inc.  All rights reserved.
24*753d2d2eSraf  * Use is subject to license terms.
25*753d2d2eSraf  */
26*753d2d2eSraf 
27*753d2d2eSraf #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*753d2d2eSraf 
29*753d2d2eSraf /*
30*753d2d2eSraf  *  Back-end functions for spec to mapfile converter
31*753d2d2eSraf  */
32*753d2d2eSraf 
33*753d2d2eSraf #include <stdio.h>
34*753d2d2eSraf #include <stdlib.h>
35*753d2d2eSraf #include <ctype.h>
36*753d2d2eSraf #include <string.h>
37*753d2d2eSraf #include <errno.h>
38*753d2d2eSraf #include <sys/utsname.h>
39*753d2d2eSraf #include "xlator.h"
40*753d2d2eSraf #include "util.h"
41*753d2d2eSraf #include "bucket.h"
42*753d2d2eSraf 
43*753d2d2eSraf /* Globals */
44*753d2d2eSraf enum {
45*753d2d2eSraf 	/* These first four (commented out) are defined in parser.h */
46*753d2d2eSraf 	/* XLATOR_KW_NOTFOUND = 0, */
47*753d2d2eSraf 	/* XLATOR_KW_FUNC, */
48*753d2d2eSraf 	/* XLATOR_KW_DATA, */
49*753d2d2eSraf 	/* XLATOR_KW_END, */
50*753d2d2eSraf 	XLATOR_KW_VERSION = 4,
51*753d2d2eSraf 	XLATOR_KW_ARCH,
52*753d2d2eSraf 	XLATOR_KW_BINDING,
53*753d2d2eSraf 	XLATOR_KW_FILTER,
54*753d2d2eSraf 	XLATOR_KW_AUXILIARY
55*753d2d2eSraf };
56*753d2d2eSraf #define	FIRST_TOKEN 4	/* Must match the first token in the enum above */
57*753d2d2eSraf 
58*753d2d2eSraf static xlator_keyword_t Keywords[] = {
59*753d2d2eSraf 	{ "version", XLATOR_KW_VERSION },
60*753d2d2eSraf 	{ "arch", XLATOR_KW_ARCH },
61*753d2d2eSraf 	{ "binding", XLATOR_KW_BINDING },
62*753d2d2eSraf 	{ "filter", XLATOR_KW_FILTER },
63*753d2d2eSraf 	{ "auxiliary", XLATOR_KW_AUXILIARY },
64*753d2d2eSraf 	{ NULL, XLATOR_KW_NOTFOUND }
65*753d2d2eSraf };
66*753d2d2eSraf 
67*753d2d2eSraf static char	const *OutputFile;
68*753d2d2eSraf static char	const *Curfile;
69*753d2d2eSraf static char	*Curfun;
70*753d2d2eSraf static int	Curline;
71*753d2d2eSraf static Interface Iface;
72*753d2d2eSraf 
73*753d2d2eSraf static int  Verbosity;
74*753d2d2eSraf static int  TargetArchToken;		/* set from -a option to front-end */
75*753d2d2eSraf char *TargetArchStr = NULL;		/* from -a option to front-end */
76*753d2d2eSraf int IsFilterLib = 0;			/* set from -F option to front-end */
77*753d2d2eSraf static int  Supported_Arch = XLATOR_ALLARCH;	/* from "Arch" SPEC keyword */
78*753d2d2eSraf static int	Flags;
79*753d2d2eSraf 
80*753d2d2eSraf /*
81*753d2d2eSraf  * WHAT!?
82*753d2d2eSraf  * from Version line
83*753d2d2eSraf  * 0 means architecture is not specified in the
84*753d2d2eSraf  * version line so it applies to all versions
85*753d2d2eSraf  */
86*753d2d2eSraf static int  Version_Arch;
87*753d2d2eSraf int  Num_versfiles = 0;
88*753d2d2eSraf static int  Has_Version;
89*753d2d2eSraf 
90*753d2d2eSraf static char *Versfile;
91*753d2d2eSraf 
92*753d2d2eSraf static char *getversion(const char *);
93*753d2d2eSraf static int version_sanity(const char *value, char **subv);
94*753d2d2eSraf static int arch_version_sanity(char *av);
95*753d2d2eSraf static char *getfilter(const char *);
96*753d2d2eSraf static void writemapfile(FILE *);
97*753d2d2eSraf static int set_version_arch(const char *);
98*753d2d2eSraf static int set_supported_arch(const char *);
99*753d2d2eSraf 
100*753d2d2eSraf /*
101*753d2d2eSraf  * xlator_init()
102*753d2d2eSraf  *    back-end initialization
103*753d2d2eSraf  *    returns pointer to Keywords on success
104*753d2d2eSraf  *    returns NULL pointer on failure
105*753d2d2eSraf  */
106*753d2d2eSraf xlator_keyword_t *
107*753d2d2eSraf xlator_init(const Translator_info *t_info)
108*753d2d2eSraf {
109*753d2d2eSraf 	/*
110*753d2d2eSraf 	 * initially so we don't lose error messages from version_check
111*753d2d2eSraf 	 * we'll set this again later based on ti_info.ti_verbosity
112*753d2d2eSraf 	 */
113*753d2d2eSraf 	seterrseverity(WARNING);
114*753d2d2eSraf 
115*753d2d2eSraf 	/* set verbosity */
116*753d2d2eSraf 	Verbosity = t_info->ti_verbosity;
117*753d2d2eSraf 	seterrseverity(t_info->ti_verbosity);
118*753d2d2eSraf 
119*753d2d2eSraf 	/* Obtain translator flags */
120*753d2d2eSraf 	Flags = t_info->ti_flags;
121*753d2d2eSraf 
122*753d2d2eSraf 	/*
123*753d2d2eSraf 	 * set Library Type
124*753d2d2eSraf 	 * 1 if filter lib, 0 otherwise
125*753d2d2eSraf 	 */
126*753d2d2eSraf 	IsFilterLib = t_info->ti_libtype;
127*753d2d2eSraf 
128*753d2d2eSraf 	/* set target architecture */
129*753d2d2eSraf 	TargetArchStr = t_info->ti_arch;
130*753d2d2eSraf 	TargetArchToken = t_info->ti_archtoken;
131*753d2d2eSraf 
132*753d2d2eSraf 	errlog(STATUS, "Architecture set to \"%s\"", TargetArchStr);
133*753d2d2eSraf 
134*753d2d2eSraf 	/* set output file */
135*753d2d2eSraf 	OutputFile = t_info->ti_output_file;
136*753d2d2eSraf 	if (OutputFile) {
137*753d2d2eSraf 		errlog(STATUS, "Output will go into %s",
138*753d2d2eSraf 		    OutputFile);
139*753d2d2eSraf 	} else {
140*753d2d2eSraf 		OutputFile = "mapfile";
141*753d2d2eSraf 		errlog(STATUS, "Using default output filename: %s",
142*753d2d2eSraf 		    OutputFile);
143*753d2d2eSraf 	}
144*753d2d2eSraf 
145*753d2d2eSraf 	/* obtain name of version file */
146*753d2d2eSraf 	Versfile = t_info->ti_versfile;
147*753d2d2eSraf 
148*753d2d2eSraf 	/* call create_lists() to setup for parse_versions() */
149*753d2d2eSraf 	create_lists();
150*753d2d2eSraf 
151*753d2d2eSraf 	/* Process Vers Files */
152*753d2d2eSraf 	if (parse_versions(Versfile)) {
153*753d2d2eSraf 		return (NULL);
154*753d2d2eSraf 	}
155*753d2d2eSraf 
156*753d2d2eSraf 	return (Keywords);
157*753d2d2eSraf }
158*753d2d2eSraf 
159*753d2d2eSraf /*
160*753d2d2eSraf  * xlator_startlib()
161*753d2d2eSraf  *    start of library
162*753d2d2eSraf  *    returns:  XLATOR_SUCCESS	on success
163*753d2d2eSraf  *              XLATOR_SKIP		if library is to be skipped
164*753d2d2eSraf  *              XLATOR_NONFATAL	on error
165*753d2d2eSraf  */
166*753d2d2eSraf /*ARGSUSED*/
167*753d2d2eSraf int
168*753d2d2eSraf xlator_startlib(char const *libname)
169*753d2d2eSraf {
170*753d2d2eSraf 	errlog(TRACING, "xlator_startlib");
171*753d2d2eSraf 	return (XLATOR_SUCCESS);
172*753d2d2eSraf }
173*753d2d2eSraf 
174*753d2d2eSraf /*
175*753d2d2eSraf  * xlator_startfile()
176*753d2d2eSraf  *    start of spec file
177*753d2d2eSraf  *    returns:  XLATOR_SUCCESS	on success
178*753d2d2eSraf  *              XLATOR_SKIP		if file is to be skipped
179*753d2d2eSraf  *              XLATOR_NONFATAL	on error
180*753d2d2eSraf  */
181*753d2d2eSraf int
182*753d2d2eSraf xlator_startfile(char const *filename)
183*753d2d2eSraf {
184*753d2d2eSraf 	errlog(TRACING, "xlator_startfile");
185*753d2d2eSraf 
186*753d2d2eSraf 	Curfile = filename;
187*753d2d2eSraf 
188*753d2d2eSraf 	return (XLATOR_SUCCESS);
189*753d2d2eSraf }
190*753d2d2eSraf 
191*753d2d2eSraf /*
192*753d2d2eSraf  * xlator_start_if ()
193*753d2d2eSraf  *    start of interface specification
194*753d2d2eSraf  *    returns:  XLATOR_SUCCESS	on success
195*753d2d2eSraf  *              XLATOR_SKIP		if interface is to be skipped
196*753d2d2eSraf  *              XLATOR_NONFATAL	on error
197*753d2d2eSraf  *              XLATOR_FATAL	on fatal error
198*753d2d2eSraf  */
199*753d2d2eSraf int
200*753d2d2eSraf xlator_start_if(const Meta_info meta_info, const int token, char *value)
201*753d2d2eSraf {
202*753d2d2eSraf 	char rhs[BUFSIZ];
203*753d2d2eSraf 	char *kw;
204*753d2d2eSraf 	int err;
205*753d2d2eSraf 
206*753d2d2eSraf 	errlog(TRACING, "xlator_start_if %s", value);
207*753d2d2eSraf 
208*753d2d2eSraf 	switch (token) {
209*753d2d2eSraf 	case XLATOR_KW_FUNC:
210*753d2d2eSraf 		kw = "Function";
211*753d2d2eSraf 		break;
212*753d2d2eSraf 	case XLATOR_KW_DATA:
213*753d2d2eSraf 		kw = "Data";
214*753d2d2eSraf 		break;
215*753d2d2eSraf 	default:
216*753d2d2eSraf 		/* This should never happen */
217*753d2d2eSraf 		errlog(ERROR,
218*753d2d2eSraf 		    "\"%s\", line %d: Implementation error! "
219*753d2d2eSraf 		    "Please file a bug\n", __FILE__, __LINE__);
220*753d2d2eSraf 		return (XLATOR_FATAL);
221*753d2d2eSraf 	}
222*753d2d2eSraf 
223*753d2d2eSraf 	Curline = meta_info.mi_line_number;
224*753d2d2eSraf 	seterrline(Curline, meta_info.mi_filename, kw, value);
225*753d2d2eSraf 
226*753d2d2eSraf 	if (Curfun != NULL) {
227*753d2d2eSraf 		errlog(INPUT|ERROR,
228*753d2d2eSraf 		    "Error: Interface spec is missing the "
229*753d2d2eSraf 		    "End keyword: %s", Curfun);
230*753d2d2eSraf 		return (XLATOR_NONFATAL);
231*753d2d2eSraf 	}
232*753d2d2eSraf 
233*753d2d2eSraf 	err = sscanf(value, "%s", rhs);
234*753d2d2eSraf 	if (err == 0 || err == EOF) {
235*753d2d2eSraf 		errlog(INPUT|ERROR,
236*753d2d2eSraf 		    "Error: Missing argument in \"%s\" line", kw);
237*753d2d2eSraf 		return (XLATOR_NONFATAL);
238*753d2d2eSraf 	}
239*753d2d2eSraf 
240*753d2d2eSraf 	Curfun = strdup(rhs);
241*753d2d2eSraf 
242*753d2d2eSraf 	if (Curfun == NULL) {
243*753d2d2eSraf 		errlog(ERROR | FATAL,
244*753d2d2eSraf 		    "Internal Error: strdup() failure in xlator_startif()");
245*753d2d2eSraf 	}
246*753d2d2eSraf 
247*753d2d2eSraf 	Iface.IF_name = Curfun;
248*753d2d2eSraf 	Iface.IF_type = token;		/* FUNCTION or DATA */
249*753d2d2eSraf 
250*753d2d2eSraf 	Iface.IF_version = NULL;
251*753d2d2eSraf 	Iface.IF_class = NULL;
252*753d2d2eSraf 	Has_Version = 0;
253*753d2d2eSraf 	Supported_Arch = XLATOR_ALLARCH;
254*753d2d2eSraf 	Version_Arch = 0;
255*753d2d2eSraf 
256*753d2d2eSraf 	Iface.IF_binding = DEFAULT;
257*753d2d2eSraf 
258*753d2d2eSraf 	Iface.IF_filter = NULL;
259*753d2d2eSraf 	Iface.IF_auxiliary = NULL;
260*753d2d2eSraf 
261*753d2d2eSraf 	return (XLATOR_SUCCESS);
262*753d2d2eSraf }
263*753d2d2eSraf 
264*753d2d2eSraf /*
265*753d2d2eSraf  * xlator_take_kvpair()
266*753d2d2eSraf  *    processes spec keyword-value pairs
267*753d2d2eSraf  *    returns:  XLATOR_SUCCESS	on success
268*753d2d2eSraf  *              XLATOR_NONFATAL	on error
269*753d2d2eSraf  */
270*753d2d2eSraf int
271*753d2d2eSraf xlator_take_kvpair(const Meta_info meta_info, const int token,
272*753d2d2eSraf 	char *value)
273*753d2d2eSraf {
274*753d2d2eSraf 	char *p;
275*753d2d2eSraf 	char *subv = NULL;
276*753d2d2eSraf 	char *key = Keywords[token-FIRST_TOKEN].key;
277*753d2d2eSraf 
278*753d2d2eSraf 	Curline = meta_info.mi_line_number;
279*753d2d2eSraf 	seterrline(Curline, meta_info.mi_filename, key, value);
280*753d2d2eSraf 
281*753d2d2eSraf 	errlog(TRACING,
282*753d2d2eSraf 	    "take_kvpair called. ext_cnt=%d token=%d key=%s value=%s",
283*753d2d2eSraf 	    meta_info.mi_ext_cnt, token, key, value);
284*753d2d2eSraf 
285*753d2d2eSraf 	if (Curfun == NULL) {
286*753d2d2eSraf 		errlog(INPUT|ERROR, "Error: Keyword found outside "
287*753d2d2eSraf 		    "an interface specification block, line %d", Curline);
288*753d2d2eSraf 		return (XLATOR_NONFATAL);
289*753d2d2eSraf 	}
290*753d2d2eSraf 
291*753d2d2eSraf 	switch (token) {
292*753d2d2eSraf 	case XLATOR_KW_VERSION:
293*753d2d2eSraf 		if (meta_info.mi_ext_cnt  !=  0)
294*753d2d2eSraf 			return (XLATOR_SUCCESS);
295*753d2d2eSraf 
296*753d2d2eSraf 		errlog(TRACING, "Version found. Setting Version to %s", value);
297*753d2d2eSraf 
298*753d2d2eSraf 		/* Version line found ; used for auditing the SPEC */
299*753d2d2eSraf 		Has_Version = 1;
300*753d2d2eSraf 
301*753d2d2eSraf 		/* remove trailing white space */
302*753d2d2eSraf 		p = strrchr(value, '\n');
303*753d2d2eSraf 		if (p) {
304*753d2d2eSraf 			while (p >= value && isspace(*p)) {
305*753d2d2eSraf 				*p = '\0';
306*753d2d2eSraf 				--p;
307*753d2d2eSraf 			}
308*753d2d2eSraf 		}
309*753d2d2eSraf 
310*753d2d2eSraf 		/* is the version line valid */
311*753d2d2eSraf 		switch (version_sanity(value, &subv)) {
312*753d2d2eSraf 		case VS_OK:		/* OK, subv not set */
313*753d2d2eSraf 			break;
314*753d2d2eSraf 
315*753d2d2eSraf 		case VS_INVARCH:	/* Invalid Arch */
316*753d2d2eSraf 			errlog(INPUT|ERROR, "Error: Invalid architecture "
317*753d2d2eSraf 			    "string found in spec or version file: %s", subv);
318*753d2d2eSraf 			free(subv);
319*753d2d2eSraf 			return (XLATOR_NONFATAL);
320*753d2d2eSraf 
321*753d2d2eSraf 		case VS_INVVERS:	/* Invalid Version String */
322*753d2d2eSraf 			errlog(INPUT|ERROR, "Error: Invalid version string "
323*753d2d2eSraf 			    "in spec or version file: %s", subv);
324*753d2d2eSraf 			free(subv);
325*753d2d2eSraf 			return (XLATOR_NONFATAL);
326*753d2d2eSraf 
327*753d2d2eSraf 		case VS_INVALID:	/* Both Version and Arch are invalid */
328*753d2d2eSraf 			errlog(INPUT|ERROR, "Error: Invalid version and "
329*753d2d2eSraf 			    "architecture string in spec or version file"
330*753d2d2eSraf 				": %s", subv);
331*753d2d2eSraf 			free(subv);
332*753d2d2eSraf 			return (XLATOR_NONFATAL);
333*753d2d2eSraf 
334*753d2d2eSraf 		default:	/* BAD IMPLEMENTATION OF version_sanity */
335*753d2d2eSraf 			errlog(FATAL, "Error: bad return value from "
336*753d2d2eSraf 			    "version_sanity()! This should never happen!");
337*753d2d2eSraf 		}
338*753d2d2eSraf 
339*753d2d2eSraf 		errlog(TRACING, "Version_Arch=%d", Version_Arch);
340*753d2d2eSraf 
341*753d2d2eSraf 		Iface.IF_version = getversion(value);
342*753d2d2eSraf 		break;
343*753d2d2eSraf 
344*753d2d2eSraf 	case XLATOR_KW_ARCH:
345*753d2d2eSraf 		if (meta_info.mi_ext_cnt  !=  0)
346*753d2d2eSraf 			return (XLATOR_SUCCESS);
347*753d2d2eSraf 
348*753d2d2eSraf 		if (value[0] != '\0') {
349*753d2d2eSraf 			Supported_Arch = 0;
350*753d2d2eSraf 			if (set_supported_arch(value)) {
351*753d2d2eSraf 				errlog(INPUT|ERROR,
352*753d2d2eSraf 				    "Error: Unable to parse Arch line");
353*753d2d2eSraf 				return (XLATOR_NONFATAL);
354*753d2d2eSraf 			}
355*753d2d2eSraf 		} else {
356*753d2d2eSraf 			errlog(INPUT | ERROR, "Error: Empty Arch line.");
357*753d2d2eSraf 		}
358*753d2d2eSraf 
359*753d2d2eSraf 		if (Supported_Arch == 0) {
360*753d2d2eSraf 			errlog(INPUT | ERROR,
361*753d2d2eSraf 			    "Error: Unknown architecture defined in Arch line");
362*753d2d2eSraf 		}
363*753d2d2eSraf 
364*753d2d2eSraf 		errlog(TRACING,
365*753d2d2eSraf 		    "Interface %s supports the following architectures: "
366*753d2d2eSraf 		    "%s\tSupported_Arch=%d", Curfun, value, Supported_Arch);
367*753d2d2eSraf 		break;
368*753d2d2eSraf 
369*753d2d2eSraf 	case XLATOR_KW_BINDING:
370*753d2d2eSraf 
371*753d2d2eSraf 		/*
372*753d2d2eSraf 		 * Note that we allow extends for the binding keyword by
373*753d2d2eSraf 		 * not checking that meta_info.mi_ext_cnt == 0 here.
374*753d2d2eSraf 		 */
375*753d2d2eSraf 
376*753d2d2eSraf 		/* remove trailing white space */
377*753d2d2eSraf 		p = strrchr(value, '\n');
378*753d2d2eSraf 		if (p) {
379*753d2d2eSraf 			while (p >= value && isspace(*p)) {
380*753d2d2eSraf 				*p = '\0';
381*753d2d2eSraf 				--p;
382*753d2d2eSraf 			}
383*753d2d2eSraf 		}
384*753d2d2eSraf 
385*753d2d2eSraf 		if (value[0] != '\0') {
386*753d2d2eSraf 			if (strcmp(value, "direct") == 0) {
387*753d2d2eSraf 				Iface.IF_binding = DIRECT;
388*753d2d2eSraf 			} else if (strcmp(value, "nodirect") == 0) {
389*753d2d2eSraf 				Iface.IF_binding = NODIRECT;
390*753d2d2eSraf 			} else if (strcmp(value, "protected") == 0) {
391*753d2d2eSraf 				Iface.IF_binding = PROTECTED;
392*753d2d2eSraf 			} else {
393*753d2d2eSraf 				errlog(INPUT|ERROR,
394*753d2d2eSraf 				    "Error: Invalid binding value: %s", value);
395*753d2d2eSraf 			}
396*753d2d2eSraf 		} else {
397*753d2d2eSraf 			errlog(INPUT | ERROR, "Error: Empty Binding line.");
398*753d2d2eSraf 		}
399*753d2d2eSraf 
400*753d2d2eSraf 		errlog(TRACING,
401*753d2d2eSraf 		    "Interface %s has binding value: "
402*753d2d2eSraf 		    "%s", Curfun, value);
403*753d2d2eSraf 		break;
404*753d2d2eSraf 
405*753d2d2eSraf 	case XLATOR_KW_FILTER:
406*753d2d2eSraf 	case XLATOR_KW_AUXILIARY:
407*753d2d2eSraf 		/*
408*753d2d2eSraf 		 * The following is for the "extends" clause.  As with
409*753d2d2eSraf 		 * XLATOR_KW_VERSION, we do not want to follow an "extends"
410*753d2d2eSraf 		 * chain to get the filter or auxiliary values: we want
411*753d2d2eSraf 		 * the first/most-tightly-bound one (mi_ext_cnt = 0).
412*753d2d2eSraf 		 */
413*753d2d2eSraf 		if (meta_info.mi_ext_cnt  !=  0)
414*753d2d2eSraf 			return (XLATOR_SUCCESS);
415*753d2d2eSraf 
416*753d2d2eSraf 		errlog(TRACING, "Filter[token=%d] found. Setting Filter to %s",
417*753d2d2eSraf 		    token, value);
418*753d2d2eSraf 
419*753d2d2eSraf 		/* remove trailing white space */
420*753d2d2eSraf 		p = strrchr(value, '\n');
421*753d2d2eSraf 		if (p) {
422*753d2d2eSraf 			while (p >= value && isspace(*p)) {
423*753d2d2eSraf 				*p = '\0';
424*753d2d2eSraf 				--p;
425*753d2d2eSraf 			}
426*753d2d2eSraf 		}
427*753d2d2eSraf 
428*753d2d2eSraf 		errlog(TRACING, "Version_Arch=%d", Version_Arch);
429*753d2d2eSraf 
430*753d2d2eSraf 		if (token == XLATOR_KW_FILTER) {
431*753d2d2eSraf 			Iface.IF_filter = getfilter(value);
432*753d2d2eSraf 		} else if (token == XLATOR_KW_AUXILIARY) {
433*753d2d2eSraf 			Iface.IF_auxiliary = getfilter(value);
434*753d2d2eSraf 		}
435*753d2d2eSraf 
436*753d2d2eSraf 		break;
437*753d2d2eSraf 	default:
438*753d2d2eSraf 		errlog(INPUT|ERROR, "Error: Unrecognized keyword snuck in!"
439*753d2d2eSraf 		    "\tThis is a programmer error: %s", key);
440*753d2d2eSraf 		return (XLATOR_NONFATAL);
441*753d2d2eSraf 	}
442*753d2d2eSraf 
443*753d2d2eSraf 	return (XLATOR_SUCCESS);
444*753d2d2eSraf }
445*753d2d2eSraf 
446*753d2d2eSraf /*
447*753d2d2eSraf  * xlator_end_if ()
448*753d2d2eSraf  *  signal end of spec interface spec
449*753d2d2eSraf  *     returns: XLATOR_SUCCESS on success
450*753d2d2eSraf  *		XLATOR_NONFATAL	on error
451*753d2d2eSraf  */
452*753d2d2eSraf /*ARGSUSED*/
453*753d2d2eSraf int
454*753d2d2eSraf xlator_end_if(const Meta_info M, const char *value)
455*753d2d2eSraf {
456*753d2d2eSraf 	int retval = XLATOR_NONFATAL;
457*753d2d2eSraf 	int picky = Flags & XLATOR_PICKY_FLAG;
458*753d2d2eSraf 
459*753d2d2eSraf 	seterrline(M.mi_line_number, M.mi_filename, "End", "");
460*753d2d2eSraf 	errlog(TRACING, "xlator_end_if");
461*753d2d2eSraf 
462*753d2d2eSraf 	if (Curfun == NULL) {
463*753d2d2eSraf 		errlog(INPUT | ERROR, "Error: End without "
464*753d2d2eSraf 		    "matching Function or Data in file \"%s\"", Curfile);
465*753d2d2eSraf 		goto cleanup;
466*753d2d2eSraf 	}
467*753d2d2eSraf 
468*753d2d2eSraf 	errlog(TRACING, "Interface=%s", Iface.IF_name);
469*753d2d2eSraf 
470*753d2d2eSraf 	if (!Has_Version) {
471*753d2d2eSraf 		if (picky) {
472*753d2d2eSraf 			errlog(INPUT | ERROR, "Error: Interface has no "
473*753d2d2eSraf 			    "Version!\n\tInterface=%s\n\tSPEC File=%s",
474*753d2d2eSraf 			    Iface.IF_name, Curfile);
475*753d2d2eSraf 		} else {
476*753d2d2eSraf 			errlog(INPUT | WARNING, "Warning: Interface has "
477*753d2d2eSraf 			    "no Version!\n\tInterface=%s\n\tSPEC File=%s",
478*753d2d2eSraf 			    Iface.IF_name, Curfile);
479*753d2d2eSraf 			retval = XLATOR_SUCCESS;
480*753d2d2eSraf 		}
481*753d2d2eSraf 		goto cleanup;
482*753d2d2eSraf 	}
483*753d2d2eSraf 
484*753d2d2eSraf 	if (Version_Arch & (~Supported_Arch)) {
485*753d2d2eSraf 		errlog(INPUT | ERROR, "Error: Architectures in Version "
486*753d2d2eSraf 		    "line must be a subset of Architectures in Arch line\n"
487*753d2d2eSraf 		    "\tInterface=%s\n\tSPEC File=%s", Iface.IF_name, Curfile);
488*753d2d2eSraf 		goto cleanup;
489*753d2d2eSraf 	}
490*753d2d2eSraf 
491*753d2d2eSraf 	if ((TargetArchToken & Supported_Arch) == 0) {
492*753d2d2eSraf 		/*
493*753d2d2eSraf 		 * This interface is not for the architecture
494*753d2d2eSraf 		 * we are currently processing, so we skip it.
495*753d2d2eSraf 		 */
496*753d2d2eSraf 		retval = XLATOR_SUCCESS;
497*753d2d2eSraf 		goto cleanup;
498*753d2d2eSraf 	}
499*753d2d2eSraf 
500*753d2d2eSraf 	if (Iface.IF_version == NULL) {
501*753d2d2eSraf 		if (picky) {
502*753d2d2eSraf 			errlog(ERROR|INPUT,
503*753d2d2eSraf 			    "Error:  Version was not found for "
504*753d2d2eSraf 			    "\"%s\" architecture\n\tInterface=%s",
505*753d2d2eSraf 			    TargetArchStr, Iface.IF_name);
506*753d2d2eSraf 		} else {
507*753d2d2eSraf 			errlog(WARNING | INPUT,
508*753d2d2eSraf 			    "Warning:  Version was not found for "
509*753d2d2eSraf 			    "\"%s\" architecture\n\tInterface=%s",
510*753d2d2eSraf 			    TargetArchStr, Iface.IF_name);
511*753d2d2eSraf 			retval = XLATOR_SUCCESS;
512*753d2d2eSraf 		}
513*753d2d2eSraf 		goto cleanup;
514*753d2d2eSraf 	}
515*753d2d2eSraf 
516*753d2d2eSraf 	/* check Iface.IF_type */
517*753d2d2eSraf 	switch (Iface.IF_type) {
518*753d2d2eSraf 	case FUNCTION:
519*753d2d2eSraf 		errlog(VERBOSE, "Interface type = FUNCTION");
520*753d2d2eSraf 		break;
521*753d2d2eSraf 	case DATA:
522*753d2d2eSraf 		errlog(VERBOSE, "Interface type = DATA");
523*753d2d2eSraf 		break;
524*753d2d2eSraf 	case NOTYPE:
525*753d2d2eSraf 		errlog(WARNING,
526*753d2d2eSraf 		    "Warning: Interface is neither "
527*753d2d2eSraf 		    "DATA nor FUNCTION!!\n\t"
528*753d2d2eSraf 		    "Interface=%s\n\tSPEC File=%s",
529*753d2d2eSraf 		    Iface.IF_name, Curfile);
530*753d2d2eSraf 		break;
531*753d2d2eSraf 	default:
532*753d2d2eSraf 		errlog(ERROR, "Error: Bad spec2map implementation!\n"
533*753d2d2eSraf 		    "\tInterface type is invalid\n"
534*753d2d2eSraf 		    "\tThis should never happen.\n"
535*753d2d2eSraf 		    "\tInterface=%s\tSPEC File=%s", Iface.IF_name, Curfile);
536*753d2d2eSraf 		goto cleanup;
537*753d2d2eSraf 	}
538*753d2d2eSraf 
539*753d2d2eSraf 	(void) add_by_name(Iface.IF_version, &Iface);
540*753d2d2eSraf 
541*753d2d2eSraf 	retval = XLATOR_SUCCESS;
542*753d2d2eSraf 
543*753d2d2eSraf cleanup:
544*753d2d2eSraf 
545*753d2d2eSraf 	/* cleanup */
546*753d2d2eSraf 	Iface.IF_name = NULL;
547*753d2d2eSraf 
548*753d2d2eSraf 	free(Iface.IF_version);
549*753d2d2eSraf 	Iface.IF_version = NULL;
550*753d2d2eSraf 
551*753d2d2eSraf 	free(Iface.IF_class);
552*753d2d2eSraf 	Iface.IF_class = NULL;
553*753d2d2eSraf 
554*753d2d2eSraf 	free(Curfun);
555*753d2d2eSraf 	Curfun = NULL;
556*753d2d2eSraf 
557*753d2d2eSraf 	Supported_Arch = XLATOR_ALLARCH;
558*753d2d2eSraf 	return (retval);
559*753d2d2eSraf }
560*753d2d2eSraf 
561*753d2d2eSraf /*
562*753d2d2eSraf  * xlator_endfile()
563*753d2d2eSraf  *   signal end of spec file
564*753d2d2eSraf  *    returns:  XLATOR_SUCCESS	on success
565*753d2d2eSraf  *              XLATOR_NONFATAL	on error
566*753d2d2eSraf  */
567*753d2d2eSraf int
568*753d2d2eSraf xlator_endfile(void)
569*753d2d2eSraf {
570*753d2d2eSraf 
571*753d2d2eSraf 	errlog(TRACING, "xlator_endfile");
572*753d2d2eSraf 
573*753d2d2eSraf 	Curfile = NULL;
574*753d2d2eSraf 
575*753d2d2eSraf 	return (XLATOR_SUCCESS);
576*753d2d2eSraf }
577*753d2d2eSraf 
578*753d2d2eSraf /*
579*753d2d2eSraf  * xlator_endlib()
580*753d2d2eSraf  *   signal end of library
581*753d2d2eSraf  *    returns:  XLATOR_SUCCESS	on success
582*753d2d2eSraf  *              XLATOR_NONFATAL	on error
583*753d2d2eSraf  */
584*753d2d2eSraf int
585*753d2d2eSraf xlator_endlib(void)
586*753d2d2eSraf {
587*753d2d2eSraf 	FILE *mapfp;
588*753d2d2eSraf 	int retval = XLATOR_SUCCESS;
589*753d2d2eSraf 
590*753d2d2eSraf 	errlog(TRACING, "xlator_endlib");
591*753d2d2eSraf 
592*753d2d2eSraf 	/* Pretend to print mapfile */
593*753d2d2eSraf 	if (Verbosity >= TRACING) {
594*753d2d2eSraf 		print_all_buckets();
595*753d2d2eSraf 	}
596*753d2d2eSraf 
597*753d2d2eSraf 	/* Everything read, now organize it! */
598*753d2d2eSraf 	sort_buckets();
599*753d2d2eSraf 	add_local();
600*753d2d2eSraf 
601*753d2d2eSraf 	/* Create Output */
602*753d2d2eSraf 	mapfp = fopen(OutputFile, "w");
603*753d2d2eSraf 	if (mapfp == NULL) {
604*753d2d2eSraf 		errlog(ERROR,
605*753d2d2eSraf 		    "Error: Unable to open output file \"%s\"\n\t%s",
606*753d2d2eSraf 		    OutputFile, strerror(errno));
607*753d2d2eSraf 		retval = XLATOR_NONFATAL;
608*753d2d2eSraf 	} else {
609*753d2d2eSraf 		writemapfile(mapfp);
610*753d2d2eSraf 		(void) fclose(mapfp);
611*753d2d2eSraf 	}
612*753d2d2eSraf 
613*753d2d2eSraf 	return (retval);
614*753d2d2eSraf }
615*753d2d2eSraf 
616*753d2d2eSraf /*
617*753d2d2eSraf  * xlator_end()
618*753d2d2eSraf  *   signal end of translation
619*753d2d2eSraf  *    returns:  XLATOR_SUCCESS	on success
620*753d2d2eSraf  *              XLATOR_NONFATAL	on error
621*753d2d2eSraf  */
622*753d2d2eSraf int
623*753d2d2eSraf xlator_end(void)
624*753d2d2eSraf {
625*753d2d2eSraf 	errlog(TRACING, "xlator_end");
626*753d2d2eSraf 
627*753d2d2eSraf 	/* Destroy the list created by create_lists */
628*753d2d2eSraf 	delete_lists();
629*753d2d2eSraf 
630*753d2d2eSraf 	return (XLATOR_SUCCESS);
631*753d2d2eSraf }
632*753d2d2eSraf 
633*753d2d2eSraf /*
634*753d2d2eSraf  * getversion()
635*753d2d2eSraf  * called by xlator_take_kvpair when Version keyword is found
636*753d2d2eSraf  * parses the Version string and returns the one that matches
637*753d2d2eSraf  * the current target architecture
638*753d2d2eSraf  *
639*753d2d2eSraf  * the pointer returned by this function must be freed later.
640*753d2d2eSraf  */
641*753d2d2eSraf static char *
642*753d2d2eSraf getversion(const char *value)
643*753d2d2eSraf {
644*753d2d2eSraf 	char *v, *p;
645*753d2d2eSraf 	char arch[ARCHBUFLEN];
646*753d2d2eSraf 	int archlen;
647*753d2d2eSraf 
648*753d2d2eSraf 	/* up to ARCHBUFLEN-1 */
649*753d2d2eSraf 	(void) strncpy(arch, TargetArchStr, ARCHBUFLEN-1);
650*753d2d2eSraf 	arch[ARCHBUFLEN-2] = '\0';
651*753d2d2eSraf 	(void) strcat(arch, "=");		/* append an '=' */
652*753d2d2eSraf 	archlen = strlen(arch);
653*753d2d2eSraf 
654*753d2d2eSraf 	errlog(VERBOSE, "getversion: value=%s", value);
655*753d2d2eSraf 
656*753d2d2eSraf 	if (strchr(value, '=') != NULL) {
657*753d2d2eSraf 		if ((v = strstr(value, arch)) != NULL) {
658*753d2d2eSraf 			p = strdup(v + archlen);
659*753d2d2eSraf 			if (p == NULL) {
660*753d2d2eSraf 				errlog(ERROR | FATAL,
661*753d2d2eSraf 				    "Internal Error: strdup() failure "
662*753d2d2eSraf 				    "in getversion()");
663*753d2d2eSraf 			}
664*753d2d2eSraf 			v = p;
665*753d2d2eSraf 			while (!isspace(*v) && *v != '\0')
666*753d2d2eSraf 				++v;
667*753d2d2eSraf 			*v = '\0';
668*753d2d2eSraf 		} else {
669*753d2d2eSraf 			errlog(VERBOSE, "getversion returns: NULL");
670*753d2d2eSraf 			return (NULL);
671*753d2d2eSraf 		}
672*753d2d2eSraf 	} else {
673*753d2d2eSraf 		p = strdup(value);
674*753d2d2eSraf 		if (p == NULL) {
675*753d2d2eSraf 			errlog(ERROR | FATAL, "Internal Error: strdup() "
676*753d2d2eSraf 			    "failure in getversion()");
677*753d2d2eSraf 		}
678*753d2d2eSraf 	}
679*753d2d2eSraf 
680*753d2d2eSraf 	if (p != NULL)
681*753d2d2eSraf 		errlog(VERBOSE, "getversion returns: %s", p);
682*753d2d2eSraf 	else
683*753d2d2eSraf 		errlog(VERBOSE, "getversion returns: NULL");
684*753d2d2eSraf 
685*753d2d2eSraf 	return (p);
686*753d2d2eSraf }
687*753d2d2eSraf 
688*753d2d2eSraf /*
689*753d2d2eSraf  * getfilter()
690*753d2d2eSraf  * Called by xlator_take_kvpair when "filter" or "auxiliary" keyword is
691*753d2d2eSraf  * found.  Parses the Filter/Auxiliary string and returns the one that
692*753d2d2eSraf  * matches the current target architecture
693*753d2d2eSraf  *
694*753d2d2eSraf  * The pointer returned by this function must be freed later.
695*753d2d2eSraf  *
696*753d2d2eSraf  * Note that returning NULL here indicates there was no desired
697*753d2d2eSraf  * arch=path item in value, i.e. for TargetArchStr the interface is
698*753d2d2eSraf  * not a filter.
699*753d2d2eSraf  */
700*753d2d2eSraf static char *
701*753d2d2eSraf getfilter(const char *value)
702*753d2d2eSraf {
703*753d2d2eSraf 	char *v, *p;
704*753d2d2eSraf 	char arch[ARCHBUFLEN];
705*753d2d2eSraf 	int archlen;
706*753d2d2eSraf 
707*753d2d2eSraf 	/* up to ARCHBUFLEN-1 */
708*753d2d2eSraf 	(void) strncpy(arch, TargetArchStr, ARCHBUFLEN-1);
709*753d2d2eSraf 	arch[ARCHBUFLEN-2] = '\0';
710*753d2d2eSraf 	(void) strcat(arch, "=");		/* append an '=' */
711*753d2d2eSraf 	archlen = strlen(arch);
712*753d2d2eSraf 
713*753d2d2eSraf 	errlog(VERBOSE, "getfilter: value=%s", value);
714*753d2d2eSraf 
715*753d2d2eSraf 	if (strchr(value, '=') != NULL) {
716*753d2d2eSraf 		if ((v = strstr(value, arch)) != NULL) {
717*753d2d2eSraf 			p = strdup(v + archlen);
718*753d2d2eSraf 			if (p == NULL) {
719*753d2d2eSraf 				errlog(ERROR | FATAL,
720*753d2d2eSraf 				    "Internal Error: strdup() failure "
721*753d2d2eSraf 				    "in getfilter()");
722*753d2d2eSraf 			}
723*753d2d2eSraf 			v = p;
724*753d2d2eSraf 			while (!isspace(*v) && *v != '\0')
725*753d2d2eSraf 				++v;
726*753d2d2eSraf 			*v = '\0';
727*753d2d2eSraf 		} else {
728*753d2d2eSraf 			errlog(VERBOSE, "getfilter returns: NULL");
729*753d2d2eSraf 			return (NULL);
730*753d2d2eSraf 		}
731*753d2d2eSraf 	} else {
732*753d2d2eSraf 		p = strdup(value);
733*753d2d2eSraf 		if (p == NULL) {
734*753d2d2eSraf 			errlog(ERROR | FATAL, "Internal Error: strdup() "
735*753d2d2eSraf 			    "failure in getfilter()");
736*753d2d2eSraf 		}
737*753d2d2eSraf 	}
738*753d2d2eSraf 
739*753d2d2eSraf 	if (p != NULL)
740*753d2d2eSraf 		errlog(VERBOSE, "getfilter returns: %s", p);
741*753d2d2eSraf 	else
742*753d2d2eSraf 		errlog(VERBOSE, "getfilter returns: NULL");
743*753d2d2eSraf 
744*753d2d2eSraf 	return (p);
745*753d2d2eSraf }
746*753d2d2eSraf 
747*753d2d2eSraf /*
748*753d2d2eSraf  * version_sanity()
749*753d2d2eSraf  *    for each version info in the Version line
750*753d2d2eSraf  *    check for its validity.
751*753d2d2eSraf  *    Set Version_arch to reflect all supported architectures if successful.
752*753d2d2eSraf  *    Upon return on failure, subv will contain the last version string
753*753d2d2eSraf  *    processed
754*753d2d2eSraf  *    returns: VS_OK	OK
755*753d2d2eSraf  *             VS_INVARCH    Invalid Architecture
756*753d2d2eSraf  *             VS_INVVERS    Invalid Version String
757*753d2d2eSraf  *             VS_INVALID    Both Version and Architecture are invalid;
758*753d2d2eSraf  */
759*753d2d2eSraf static int
760*753d2d2eSraf version_sanity(const char *value, char **subv)
761*753d2d2eSraf {
762*753d2d2eSraf 	char *p, *v, *a;
763*753d2d2eSraf 	int retval = VS_INVALID;
764*753d2d2eSraf 
765*753d2d2eSraf 	if (strchr(value, '=')) {
766*753d2d2eSraf 		/* Form 1:   Version	arch=Version_string */
767*753d2d2eSraf 		v = strdup(value);
768*753d2d2eSraf 		if (v == NULL) {
769*753d2d2eSraf 			errlog(ERROR | FATAL,
770*753d2d2eSraf 			    "Internal Error: strdup() failure in "
771*753d2d2eSraf 			    "version_sanity()");
772*753d2d2eSraf 		}
773*753d2d2eSraf 
774*753d2d2eSraf 		/* process each arch=version string */
775*753d2d2eSraf 		p = v;
776*753d2d2eSraf 		while ((a = strtok(p, " \t\n"))) {
777*753d2d2eSraf 			if ((retval = arch_version_sanity(a)) != VS_OK) {
778*753d2d2eSraf 				*subv = strdup(a);
779*753d2d2eSraf 				if (subv == NULL) {
780*753d2d2eSraf 					errlog(ERROR | FATAL,
781*753d2d2eSraf 					    "Internal Error: strdup() failure "
782*753d2d2eSraf 					    "in version_sanity()");
783*753d2d2eSraf 				}
784*753d2d2eSraf 				break;
785*753d2d2eSraf 			}
786*753d2d2eSraf 			if ((retval = set_version_arch(a)) != VS_OK) {
787*753d2d2eSraf 				/* set the global Version_arch */
788*753d2d2eSraf 				*subv = strdup(a);
789*753d2d2eSraf 				if (subv == NULL) {
790*753d2d2eSraf 					errlog(ERROR | FATAL,
791*753d2d2eSraf 					    "Internal Error: strdup() failure "
792*753d2d2eSraf 					    "in version_sanity()");
793*753d2d2eSraf 				}
794*753d2d2eSraf 				break;
795*753d2d2eSraf 			}
796*753d2d2eSraf 			p = NULL;
797*753d2d2eSraf 		}
798*753d2d2eSraf 		free(v);
799*753d2d2eSraf 	} else {
800*753d2d2eSraf 		/* Form 2: Version		Version_string */
801*753d2d2eSraf 		if (valid_version(value)) {
802*753d2d2eSraf 			retval = VS_OK;
803*753d2d2eSraf 		} else {
804*753d2d2eSraf 			*subv = strdup(value);
805*753d2d2eSraf 			if (subv == NULL) {
806*753d2d2eSraf 				errlog(ERROR | FATAL,
807*753d2d2eSraf 				    "Internal Error: strdup() failure "
808*753d2d2eSraf 				    "in version_sanity()");
809*753d2d2eSraf 			}
810*753d2d2eSraf 		}
811*753d2d2eSraf 	}
812*753d2d2eSraf 	return (retval);
813*753d2d2eSraf }
814*753d2d2eSraf 
815*753d2d2eSraf /*
816*753d2d2eSraf  * arch_version_sanity()
817*753d2d2eSraf  *    checks version lines of the form "arch=version"
818*753d2d2eSraf  *    av MUST be a string of the form "arch=version" (no spaces)
819*753d2d2eSraf  *    returns: VS_OK	OK
820*753d2d2eSraf  *             VS_INVARCH    Invalid Architecture
821*753d2d2eSraf  *             VS_INVVERS    Invalid Version String
822*753d2d2eSraf  *             VS_INVALID    Both Versions are invalid;
823*753d2d2eSraf  */
824*753d2d2eSraf static int
825*753d2d2eSraf arch_version_sanity(char *av)
826*753d2d2eSraf {
827*753d2d2eSraf 	char *p, *v;
828*753d2d2eSraf 	int retval = VS_OK;
829*753d2d2eSraf 
830*753d2d2eSraf 	p = strchr(av, '=');
831*753d2d2eSraf 	if (p == NULL) {
832*753d2d2eSraf 		errlog(INPUT|ERROR, "Error: Incorrect format of Version line");
833*753d2d2eSraf 		return (VS_INVALID);
834*753d2d2eSraf 	}
835*753d2d2eSraf 
836*753d2d2eSraf 	*p = '\0';	/* stick a '\0' where the '=' was */
837*753d2d2eSraf 	v = p + 1;
838*753d2d2eSraf 
839*753d2d2eSraf 	if (valid_arch(av) == 0)
840*753d2d2eSraf 		retval = VS_INVARCH;
841*753d2d2eSraf 
842*753d2d2eSraf 	if (valid_version(v) == 0)
843*753d2d2eSraf 		retval += VS_INVVERS;
844*753d2d2eSraf 
845*753d2d2eSraf 	*p = '=';	/* restore the '=' */
846*753d2d2eSraf 
847*753d2d2eSraf 	return (retval);
848*753d2d2eSraf }
849*753d2d2eSraf 
850*753d2d2eSraf /*
851*753d2d2eSraf  * writemapfile()
852*753d2d2eSraf  *    called by xlator_endlib();
853*753d2d2eSraf  *    writes out the map file
854*753d2d2eSraf  */
855*753d2d2eSraf static void
856*753d2d2eSraf writemapfile(FILE *mapfp)
857*753d2d2eSraf {
858*753d2d2eSraf 	bucket_t *l;	/* List of buckets. */
859*753d2d2eSraf 	bucket_t *b;	/* Bucket within list. */
860*753d2d2eSraf 	struct bucketlist *bl;
861*753d2d2eSraf 	table_t *t;
862*753d2d2eSraf 	int i = 0, n = 0;
863*753d2d2eSraf 	char **p;
864*753d2d2eSraf 
865*753d2d2eSraf 	errlog(BEGIN, "writemapfile() {");
866*753d2d2eSraf 	for (l = first_list(); l != NULL; l = next_list()) {
867*753d2d2eSraf 
868*753d2d2eSraf 		for (b = first_from_list(l); b != NULL; b = next_from_list()) {
869*753d2d2eSraf 			errlog(TRACING, "b_name = %s", b->b_name);
870*753d2d2eSraf 			print_bucket(b); /* Debugging routine. */
871*753d2d2eSraf 
872*753d2d2eSraf 			if (!b->b_was_printed) {
873*753d2d2eSraf 				/* Ok, we can print it. */
874*753d2d2eSraf 				b->b_was_printed = 1;
875*753d2d2eSraf 				(void) fprintf(mapfp, "%s {\n", b->b_name);
876*753d2d2eSraf 
877*753d2d2eSraf 				if (b->b_weak != 1) {
878*753d2d2eSraf 					char *strtab;
879*753d2d2eSraf 
880*753d2d2eSraf 					(void) fprintf(mapfp, "    global:\n");
881*753d2d2eSraf 
882*753d2d2eSraf 					strtab = get_stringtable(
883*753d2d2eSraf 						b->b_global_table, 0);
884*753d2d2eSraf 
885*753d2d2eSraf 					if (strtab == NULL) {
886*753d2d2eSraf 						/*
887*753d2d2eSraf 						 * There were no interfaces
888*753d2d2eSraf 						 * in the bucket.
889*753d2d2eSraf 						 * Insert a dummy entry
890*753d2d2eSraf 						 * to avoid a "weak version"
891*753d2d2eSraf 						 */
892*753d2d2eSraf 						(void) fprintf(mapfp,
893*753d2d2eSraf 						    "\t%s;\n", b->b_name);
894*753d2d2eSraf 					}
895*753d2d2eSraf 				} else {
896*753d2d2eSraf 					(void) fprintf(mapfp,
897*753d2d2eSraf 					    "    # Weak version\n");
898*753d2d2eSraf 				}
899*753d2d2eSraf 				/* Print all the interfaces in the bucket. */
900*753d2d2eSraf 				t = b->b_global_table;
901*753d2d2eSraf 				n = t->used;
902*753d2d2eSraf 
903*753d2d2eSraf 				for (i = 0; i <= n; ++i) {
904*753d2d2eSraf 					(void) fprintf(mapfp, "\t%s;\n",
905*753d2d2eSraf 					    get_stringtable(t, i));
906*753d2d2eSraf 				}
907*753d2d2eSraf 
908*753d2d2eSraf 				if (b->b_has_protecteds) {
909*753d2d2eSraf 					t = b->b_protected_table;
910*753d2d2eSraf 					n = t->used;
911*753d2d2eSraf 
912*753d2d2eSraf 					(void) fprintf(mapfp,
913*753d2d2eSraf 					    "    protected:\n");
914*753d2d2eSraf 
915*753d2d2eSraf 					for (i = 0; i <= n; ++i) {
916*753d2d2eSraf 						(void) fprintf(mapfp, "\t%s;\n",
917*753d2d2eSraf 						    get_stringtable(t, i));
918*753d2d2eSraf 					}
919*753d2d2eSraf 				}
920*753d2d2eSraf 
921*753d2d2eSraf 				/* Conditionally add ``local: *;''. */
922*753d2d2eSraf 				if (b->b_has_locals) {
923*753d2d2eSraf 					(void) fprintf(mapfp,
924*753d2d2eSraf 					    "    local:\n\t*;\n}");
925*753d2d2eSraf 				} else {
926*753d2d2eSraf 					(void) fprintf(mapfp, "}");
927*753d2d2eSraf 				}
928*753d2d2eSraf 				/* Print name of all parents. */
929*753d2d2eSraf 				for (p = parents_of(b);
930*753d2d2eSraf 				    p !=  NULL && *p != '\0'; ++p) {
931*753d2d2eSraf 					(void) fprintf(mapfp, " %s", *p);
932*753d2d2eSraf 				}
933*753d2d2eSraf 				bl = b->b_uncles;
934*753d2d2eSraf 				while (bl != NULL) {
935*753d2d2eSraf 					(void) fprintf(mapfp, " %s",
936*753d2d2eSraf 					    bl->bl_bucket->b_name);
937*753d2d2eSraf 					bl = bl->bl_next;
938*753d2d2eSraf 				}
939*753d2d2eSraf 
940*753d2d2eSraf 				(void) fprintf(mapfp, ";\n\n");
941*753d2d2eSraf 			} else {
942*753d2d2eSraf 				/*
943*753d2d2eSraf 				 * We've printed this one before,
944*753d2d2eSraf 				 * so don't do it again.
945*753d2d2eSraf 				 */
946*753d2d2eSraf 				/*EMPTY*/;
947*753d2d2eSraf 			}
948*753d2d2eSraf 		}
949*753d2d2eSraf 	}
950*753d2d2eSraf 	errlog(END, "}");
951*753d2d2eSraf }
952*753d2d2eSraf 
953*753d2d2eSraf /*
954*753d2d2eSraf  * set_version_arch ()
955*753d2d2eSraf  * input must be a string of the form "arch=version"
956*753d2d2eSraf  * turns on bits of global Version_Arch that correspond to the "arch"
957*753d2d2eSraf  * return VS_OK upon success
958*753d2d2eSraf  *  VS_INVARCH if architecture is invalid
959*753d2d2eSraf  *  EINVAL on other failure
960*753d2d2eSraf  */
961*753d2d2eSraf static int
962*753d2d2eSraf set_version_arch(const char *arch)
963*753d2d2eSraf {
964*753d2d2eSraf 	char	*a, *p;
965*753d2d2eSraf 	int	x;
966*753d2d2eSraf 	int	retval = EINVAL;
967*753d2d2eSraf 
968*753d2d2eSraf 	if (arch == NULL)
969*753d2d2eSraf 		return (retval);
970*753d2d2eSraf 
971*753d2d2eSraf 	a = strdup(arch);
972*753d2d2eSraf 	if (a == NULL) {
973*753d2d2eSraf 		errlog(ERROR | FATAL,
974*753d2d2eSraf 		    "Internal Error: strdup() failure in "
975*753d2d2eSraf 		    "set_version_arch()");
976*753d2d2eSraf 	}
977*753d2d2eSraf 
978*753d2d2eSraf 	p = strchr(a, '=');
979*753d2d2eSraf 	if (p) {
980*753d2d2eSraf 		*p = '\0';
981*753d2d2eSraf 		x = arch_strtoi(a);
982*753d2d2eSraf 		if (x == 0) {
983*753d2d2eSraf 			errlog(INPUT|ERROR,
984*753d2d2eSraf 			    "Error: Invalid architecture: %s", a);
985*753d2d2eSraf 			retval = VS_INVARCH;
986*753d2d2eSraf 		} else {
987*753d2d2eSraf 			Version_Arch |= x;
988*753d2d2eSraf 			retval = 0;
989*753d2d2eSraf 		}
990*753d2d2eSraf 	}
991*753d2d2eSraf 
992*753d2d2eSraf 	free(a);
993*753d2d2eSraf 	return (retval);
994*753d2d2eSraf }
995*753d2d2eSraf 
996*753d2d2eSraf /*
997*753d2d2eSraf  * set_supported_arch ()
998*753d2d2eSraf  * input must be a string listing the architectures to be supported
999*753d2d2eSraf  * turns on bits of global Supported_Arch that correspond to the architecture
1000*753d2d2eSraf  * return 0 upon success, EINVAL on failure
1001*753d2d2eSraf  */
1002*753d2d2eSraf static int
1003*753d2d2eSraf set_supported_arch(const char *arch)
1004*753d2d2eSraf {
1005*753d2d2eSraf 	char	*a, *p, *tmp;
1006*753d2d2eSraf 	int	retval = EINVAL;
1007*753d2d2eSraf 
1008*753d2d2eSraf 	if (arch == NULL || *arch == '\0')
1009*753d2d2eSraf 		return (EINVAL);
1010*753d2d2eSraf 
1011*753d2d2eSraf 	tmp = strdup(arch);
1012*753d2d2eSraf 	if (tmp == NULL) {
1013*753d2d2eSraf 		errlog(ERROR | FATAL, "Internal Error: strdup() failure in "
1014*753d2d2eSraf 		    "set_supported_arch()");
1015*753d2d2eSraf 	}
1016*753d2d2eSraf 
1017*753d2d2eSraf 	p = tmp;
1018*753d2d2eSraf 	while ((a = strtok(p, " ,\t\n"))) {
1019*753d2d2eSraf 		int x;
1020*753d2d2eSraf 		x = arch_strtoi(a);
1021*753d2d2eSraf 		if (x == 0) {
1022*753d2d2eSraf 			errlog(INPUT|ERROR,
1023*753d2d2eSraf 			    "Error: Invalid architecture: %s", a);
1024*753d2d2eSraf 			free(tmp);
1025*753d2d2eSraf 			return (EINVAL);
1026*753d2d2eSraf 		}
1027*753d2d2eSraf 		Supported_Arch |= x;
1028*753d2d2eSraf 		retval = 0;
1029*753d2d2eSraf 		p = NULL;
1030*753d2d2eSraf 	}
1031*753d2d2eSraf 
1032*753d2d2eSraf 	free(tmp);
1033*753d2d2eSraf 	return (retval);
1034*753d2d2eSraf }
1035