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