Mercurial > illumos > onarm
diff usr/src/cmd/abi/spectrans/spec2map/xlator.c @ 0:c9caec207d52 b86
Initial porting based on b86
author | Koji Uno <koji.uno@sun.com> |
---|---|
date | Tue, 02 Jun 2009 18:56:50 +0900 |
parents | |
children | 1a15d5aaf794 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/abi/spectrans/spec2map/xlator.c Tue Jun 02 18:56:50 2009 +0900 @@ -0,0 +1,1034 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "@(#)xlator.c 1.12 05/06/08 SMI" + +/* + * Back-end functions for spec to mapfile converter + */ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include <errno.h> +#include <sys/utsname.h> +#include "xlator.h" +#include "util.h" +#include "bucket.h" + +/* Globals */ +enum { + /* These first four (commented out) are defined in parser.h */ + /* XLATOR_KW_NOTFOUND = 0, */ + /* XLATOR_KW_FUNC, */ + /* XLATOR_KW_DATA, */ + /* XLATOR_KW_END, */ + XLATOR_KW_VERSION = 4, + XLATOR_KW_ARCH, + XLATOR_KW_BINDING, + XLATOR_KW_FILTER, + XLATOR_KW_AUXILIARY +}; +#define FIRST_TOKEN 4 /* Must match the first token in the enum above */ + +static xlator_keyword_t Keywords[] = { + { "version", XLATOR_KW_VERSION }, + { "arch", XLATOR_KW_ARCH }, + { "binding", XLATOR_KW_BINDING }, + { "filter", XLATOR_KW_FILTER }, + { "auxiliary", XLATOR_KW_AUXILIARY }, + { NULL, XLATOR_KW_NOTFOUND } +}; + +static char const *OutputFile; +static char const *Curfile; +static char *Curfun; +static int Curline; +static Interface Iface; + +static int Verbosity; +static int TargetArchToken; /* set from -a option to front-end */ +char *TargetArchStr = NULL; /* from -a option to front-end */ +int IsFilterLib = 0; /* set from -F option to front-end */ +static int Supported_Arch = XLATOR_ALLARCH; /* from "Arch" SPEC keyword */ +static int Flags; + +/* + * WHAT!? + * from Version line + * 0 means architecture is not specified in the + * version line so it applies to all versions + */ +static int Version_Arch; +int Num_versfiles = 0; +static int Has_Version; + +static char *Versfile; + +static char *getversion(const char *); +static int version_sanity(const char *value, char **subv); +static int arch_version_sanity(char *av); +static char *getfilter(const char *); +static void writemapfile(FILE *); +static int set_version_arch(const char *); +static int set_supported_arch(const char *); + +/* + * xlator_init() + * back-end initialization + * returns pointer to Keywords on success + * returns NULL pointer on failure + */ +xlator_keyword_t * +xlator_init(const Translator_info *t_info) +{ + /* + * initially so we don't lose error messages from version_check + * we'll set this again later based on ti_info.ti_verbosity + */ + seterrseverity(WARNING); + + /* set verbosity */ + Verbosity = t_info->ti_verbosity; + seterrseverity(t_info->ti_verbosity); + + /* Obtain translator flags */ + Flags = t_info->ti_flags; + + /* + * set Library Type + * 1 if filter lib, 0 otherwise + */ + IsFilterLib = t_info->ti_libtype; + + /* set target architecture */ + TargetArchStr = t_info->ti_arch; + TargetArchToken = t_info->ti_archtoken; + + errlog(STATUS, "Architecture set to \"%s\"", TargetArchStr); + + /* set output file */ + OutputFile = t_info->ti_output_file; + if (OutputFile) { + errlog(STATUS, "Output will go into %s", + OutputFile); + } else { + OutputFile = "mapfile"; + errlog(STATUS, "Using default output filename: %s", + OutputFile); + } + + /* obtain name of version file */ + Versfile = t_info->ti_versfile; + + /* call create_lists() to setup for parse_versions() */ + create_lists(); + + /* Process Vers Files */ + if (parse_versions(Versfile)) { + return (NULL); + } + + return (Keywords); +} + +/* + * xlator_startlib() + * start of library + * returns: XLATOR_SUCCESS on success + * XLATOR_SKIP if library is to be skipped + * XLATOR_NONFATAL on error + */ +/*ARGSUSED*/ +int +xlator_startlib(char const *libname) +{ + errlog(TRACING, "xlator_startlib"); + return (XLATOR_SUCCESS); +} + +/* + * xlator_startfile() + * start of spec file + * returns: XLATOR_SUCCESS on success + * XLATOR_SKIP if file is to be skipped + * XLATOR_NONFATAL on error + */ +int +xlator_startfile(char const *filename) +{ + errlog(TRACING, "xlator_startfile"); + + Curfile = filename; + + return (XLATOR_SUCCESS); +} + +/* + * xlator_start_if () + * start of interface specification + * returns: XLATOR_SUCCESS on success + * XLATOR_SKIP if interface is to be skipped + * XLATOR_NONFATAL on error + * XLATOR_FATAL on fatal error + */ +int +xlator_start_if(const Meta_info meta_info, const int token, char *value) +{ + char rhs[BUFSIZ]; + char *kw; + int err; + + errlog(TRACING, "xlator_start_if %s", value); + + switch (token) { + case XLATOR_KW_FUNC: + kw = "Function"; + break; + case XLATOR_KW_DATA: + kw = "Data"; + break; + default: + /* This should never happen */ + errlog(ERROR, + "\"%s\", line %d: Implementation error! " + "Please file a bug\n", __FILE__, __LINE__); + return (XLATOR_FATAL); + } + + Curline = meta_info.mi_line_number; + seterrline(Curline, meta_info.mi_filename, kw, value); + + if (Curfun != NULL) { + errlog(INPUT|ERROR, + "Error: Interface spec is missing the " + "End keyword: %s", Curfun); + return (XLATOR_NONFATAL); + } + + err = sscanf(value, "%s", rhs); + if (err == 0 || err == EOF) { + errlog(INPUT|ERROR, + "Error: Missing argument in \"%s\" line", kw); + return (XLATOR_NONFATAL); + } + + Curfun = strdup(rhs); + + if (Curfun == NULL) { + errlog(ERROR | FATAL, + "Internal Error: strdup() failure in xlator_startif()"); + } + + Iface.IF_name = Curfun; + Iface.IF_type = token; /* FUNCTION or DATA */ + + Iface.IF_version = NULL; + Iface.IF_class = NULL; + Has_Version = 0; + Supported_Arch = XLATOR_ALLARCH; + Version_Arch = 0; + + Iface.IF_binding = DEFAULT; + + Iface.IF_filter = NULL; + Iface.IF_auxiliary = NULL; + + return (XLATOR_SUCCESS); +} + +/* + * xlator_take_kvpair() + * processes spec keyword-value pairs + * returns: XLATOR_SUCCESS on success + * XLATOR_NONFATAL on error + */ +int +xlator_take_kvpair(const Meta_info meta_info, const int token, + char *value) +{ + char *p; + char *subv = NULL; + char *key = Keywords[token-FIRST_TOKEN].key; + + Curline = meta_info.mi_line_number; + seterrline(Curline, meta_info.mi_filename, key, value); + + errlog(TRACING, + "take_kvpair called. ext_cnt=%d token=%d key=%s value=%s", + meta_info.mi_ext_cnt, token, key, value); + + if (Curfun == NULL) { + errlog(INPUT|ERROR, "Error: Keyword found outside " + "an interface specification block, line %d", Curline); + return (XLATOR_NONFATAL); + } + + switch (token) { + case XLATOR_KW_VERSION: + if (meta_info.mi_ext_cnt != 0) + return (XLATOR_SUCCESS); + + errlog(TRACING, "Version found. Setting Version to %s", value); + + /* Version line found ; used for auditing the SPEC */ + Has_Version = 1; + + /* remove trailing white space */ + p = strrchr(value, '\n'); + if (p) { + while (p >= value && isspace(*p)) { + *p = '\0'; + --p; + } + } + + /* is the version line valid */ + switch (version_sanity(value, &subv)) { + case VS_OK: /* OK, subv not set */ + break; + + case VS_INVARCH: /* Invalid Arch */ + errlog(INPUT|ERROR, "Error: Invalid architecture " + "string found in spec or version file: %s", subv); + free(subv); + return (XLATOR_NONFATAL); + + case VS_INVVERS: /* Invalid Version String */ + errlog(INPUT|ERROR, "Error: Invalid version string " + "in spec or version file: %s", subv); + free(subv); + return (XLATOR_NONFATAL); + + case VS_INVALID: /* Both Version and Arch are invalid */ + errlog(INPUT|ERROR, "Error: Invalid version and " + "architecture string in spec or version file" + ": %s", subv); + free(subv); + return (XLATOR_NONFATAL); + + default: /* BAD IMPLEMENTATION OF version_sanity */ + errlog(FATAL, "Error: bad return value from " + "version_sanity()! This should never happen!"); + } + + errlog(TRACING, "Version_Arch=%d", Version_Arch); + + Iface.IF_version = getversion(value); + break; + + case XLATOR_KW_ARCH: + if (meta_info.mi_ext_cnt != 0) + return (XLATOR_SUCCESS); + + if (value[0] != '\0') { + Supported_Arch = 0; + if (set_supported_arch(value)) { + errlog(INPUT|ERROR, + "Error: Unable to parse Arch line"); + return (XLATOR_NONFATAL); + } + } else { + errlog(INPUT | ERROR, "Error: Empty Arch line."); + } + + if (Supported_Arch == 0) { + errlog(INPUT | ERROR, + "Error: Unknown architecture defined in Arch line"); + } + + errlog(TRACING, + "Interface %s supports the following architectures: " + "%s\tSupported_Arch=%d", Curfun, value, Supported_Arch); + break; + + case XLATOR_KW_BINDING: + + /* + * Note that we allow extends for the binding keyword by + * not checking that meta_info.mi_ext_cnt == 0 here. + */ + + /* remove trailing white space */ + p = strrchr(value, '\n'); + if (p) { + while (p >= value && isspace(*p)) { + *p = '\0'; + --p; + } + } + + if (value[0] != '\0') { + if (strcmp(value, "direct") == 0) { + Iface.IF_binding = DIRECT; + } else if (strcmp(value, "nodirect") == 0) { + Iface.IF_binding = NODIRECT; + } else if (strcmp(value, "protected") == 0) { + Iface.IF_binding = PROTECTED; + } else { + errlog(INPUT|ERROR, + "Error: Invalid binding value: %s", value); + } + } else { + errlog(INPUT | ERROR, "Error: Empty Binding line."); + } + + errlog(TRACING, + "Interface %s has binding value: " + "%s", Curfun, value); + break; + + case XLATOR_KW_FILTER: + case XLATOR_KW_AUXILIARY: + /* + * The following is for the "extends" clause. As with + * XLATOR_KW_VERSION, we do not want to follow an "extends" + * chain to get the filter or auxiliary values: we want + * the first/most-tightly-bound one (mi_ext_cnt = 0). + */ + if (meta_info.mi_ext_cnt != 0) + return (XLATOR_SUCCESS); + + errlog(TRACING, "Filter[token=%d] found. Setting Filter to %s", + token, value); + + /* remove trailing white space */ + p = strrchr(value, '\n'); + if (p) { + while (p >= value && isspace(*p)) { + *p = '\0'; + --p; + } + } + + errlog(TRACING, "Version_Arch=%d", Version_Arch); + + if (token == XLATOR_KW_FILTER) { + Iface.IF_filter = getfilter(value); + } else if (token == XLATOR_KW_AUXILIARY) { + Iface.IF_auxiliary = getfilter(value); + } + + break; + default: + errlog(INPUT|ERROR, "Error: Unrecognized keyword snuck in!" + "\tThis is a programmer error: %s", key); + return (XLATOR_NONFATAL); + } + + return (XLATOR_SUCCESS); +} + +/* + * xlator_end_if () + * signal end of spec interface spec + * returns: XLATOR_SUCCESS on success + * XLATOR_NONFATAL on error + */ +/*ARGSUSED*/ +int +xlator_end_if(const Meta_info M, const char *value) +{ + int retval = XLATOR_NONFATAL; + int picky = Flags & XLATOR_PICKY_FLAG; + + seterrline(M.mi_line_number, M.mi_filename, "End", ""); + errlog(TRACING, "xlator_end_if"); + + if (Curfun == NULL) { + errlog(INPUT | ERROR, "Error: End without " + "matching Function or Data in file \"%s\"", Curfile); + goto cleanup; + } + + errlog(TRACING, "Interface=%s", Iface.IF_name); + + if (!Has_Version) { + if (picky) { + errlog(INPUT | ERROR, "Error: Interface has no " + "Version!\n\tInterface=%s\n\tSPEC File=%s", + Iface.IF_name, Curfile); + } else { + errlog(INPUT | WARNING, "Warning: Interface has " + "no Version!\n\tInterface=%s\n\tSPEC File=%s", + Iface.IF_name, Curfile); + retval = XLATOR_SUCCESS; + } + goto cleanup; + } + + if (Version_Arch & (~Supported_Arch)) { + errlog(INPUT | ERROR, "Error: Architectures in Version " + "line must be a subset of Architectures in Arch line\n" + "\tInterface=%s\n\tSPEC File=%s", Iface.IF_name, Curfile); + goto cleanup; + } + + if ((TargetArchToken & Supported_Arch) == 0) { + /* + * This interface is not for the architecture + * we are currently processing, so we skip it. + */ + retval = XLATOR_SUCCESS; + goto cleanup; + } + + if (Iface.IF_version == NULL) { + if (picky) { + errlog(ERROR|INPUT, + "Error: Version was not found for " + "\"%s\" architecture\n\tInterface=%s", + TargetArchStr, Iface.IF_name); + } else { + errlog(WARNING | INPUT, + "Warning: Version was not found for " + "\"%s\" architecture\n\tInterface=%s", + TargetArchStr, Iface.IF_name); + retval = XLATOR_SUCCESS; + } + goto cleanup; + } + + /* check Iface.IF_type */ + switch (Iface.IF_type) { + case FUNCTION: + errlog(VERBOSE, "Interface type = FUNCTION"); + break; + case DATA: + errlog(VERBOSE, "Interface type = DATA"); + break; + case NOTYPE: + errlog(WARNING, + "Warning: Interface is neither " + "DATA nor FUNCTION!!\n\t" + "Interface=%s\n\tSPEC File=%s", + Iface.IF_name, Curfile); + break; + default: + errlog(ERROR, "Error: Bad spec2map implementation!\n" + "\tInterface type is invalid\n" + "\tThis should never happen.\n" + "\tInterface=%s\tSPEC File=%s", Iface.IF_name, Curfile); + goto cleanup; + } + + (void) add_by_name(Iface.IF_version, &Iface); + + retval = XLATOR_SUCCESS; + +cleanup: + + /* cleanup */ + Iface.IF_name = NULL; + + free(Iface.IF_version); + Iface.IF_version = NULL; + + free(Iface.IF_class); + Iface.IF_class = NULL; + + free(Curfun); + Curfun = NULL; + + Supported_Arch = XLATOR_ALLARCH; + return (retval); +} + +/* + * xlator_endfile() + * signal end of spec file + * returns: XLATOR_SUCCESS on success + * XLATOR_NONFATAL on error + */ +int +xlator_endfile(void) +{ + + errlog(TRACING, "xlator_endfile"); + + Curfile = NULL; + + return (XLATOR_SUCCESS); +} + +/* + * xlator_endlib() + * signal end of library + * returns: XLATOR_SUCCESS on success + * XLATOR_NONFATAL on error + */ +int +xlator_endlib(void) +{ + FILE *mapfp; + int retval = XLATOR_SUCCESS; + + errlog(TRACING, "xlator_endlib"); + + /* Pretend to print mapfile */ + if (Verbosity >= TRACING) { + print_all_buckets(); + } + + /* Everything read, now organize it! */ + sort_buckets(); + add_local(); + + /* Create Output */ + mapfp = fopen(OutputFile, "w"); + if (mapfp == NULL) { + errlog(ERROR, + "Error: Unable to open output file \"%s\"\n\t%s", + OutputFile, strerror(errno)); + retval = XLATOR_NONFATAL; + } else { + writemapfile(mapfp); + (void) fclose(mapfp); + } + + return (retval); +} + +/* + * xlator_end() + * signal end of translation + * returns: XLATOR_SUCCESS on success + * XLATOR_NONFATAL on error + */ +int +xlator_end(void) +{ + errlog(TRACING, "xlator_end"); + + /* Destroy the list created by create_lists */ + delete_lists(); + + return (XLATOR_SUCCESS); +} + +/* + * getversion() + * called by xlator_take_kvpair when Version keyword is found + * parses the Version string and returns the one that matches + * the current target architecture + * + * the pointer returned by this function must be freed later. + */ +static char * +getversion(const char *value) +{ + char *v, *p; + char arch[ARCHBUFLEN]; + int archlen; + + /* up to ARCHBUFLEN-1 */ + (void) strncpy(arch, TargetArchStr, ARCHBUFLEN-1); + arch[ARCHBUFLEN-2] = '\0'; + (void) strcat(arch, "="); /* append an '=' */ + archlen = strlen(arch); + + errlog(VERBOSE, "getversion: value=%s", value); + + if (strchr(value, '=') != NULL) { + if ((v = strstr(value, arch)) != NULL) { + p = strdup(v + archlen); + if (p == NULL) { + errlog(ERROR | FATAL, + "Internal Error: strdup() failure " + "in getversion()"); + } + v = p; + while (!isspace(*v) && *v != '\0') + ++v; + *v = '\0'; + } else { + errlog(VERBOSE, "getversion returns: NULL"); + return (NULL); + } + } else { + p = strdup(value); + if (p == NULL) { + errlog(ERROR | FATAL, "Internal Error: strdup() " + "failure in getversion()"); + } + } + + if (p != NULL) + errlog(VERBOSE, "getversion returns: %s", p); + else + errlog(VERBOSE, "getversion returns: NULL"); + + return (p); +} + +/* + * getfilter() + * Called by xlator_take_kvpair when "filter" or "auxiliary" keyword is + * found. Parses the Filter/Auxiliary string and returns the one that + * matches the current target architecture + * + * The pointer returned by this function must be freed later. + * + * Note that returning NULL here indicates there was no desired + * arch=path item in value, i.e. for TargetArchStr the interface is + * not a filter. + */ +static char * +getfilter(const char *value) +{ + char *v, *p; + char arch[ARCHBUFLEN]; + int archlen; + + /* up to ARCHBUFLEN-1 */ + (void) strncpy(arch, TargetArchStr, ARCHBUFLEN-1); + arch[ARCHBUFLEN-2] = '\0'; + (void) strcat(arch, "="); /* append an '=' */ + archlen = strlen(arch); + + errlog(VERBOSE, "getfilter: value=%s", value); + + if (strchr(value, '=') != NULL) { + if ((v = strstr(value, arch)) != NULL) { + p = strdup(v + archlen); + if (p == NULL) { + errlog(ERROR | FATAL, + "Internal Error: strdup() failure " + "in getfilter()"); + } + v = p; + while (!isspace(*v) && *v != '\0') + ++v; + *v = '\0'; + } else { + errlog(VERBOSE, "getfilter returns: NULL"); + return (NULL); + } + } else { + p = strdup(value); + if (p == NULL) { + errlog(ERROR | FATAL, "Internal Error: strdup() " + "failure in getfilter()"); + } + } + + if (p != NULL) + errlog(VERBOSE, "getfilter returns: %s", p); + else + errlog(VERBOSE, "getfilter returns: NULL"); + + return (p); +} + +/* + * version_sanity() + * for each version info in the Version line + * check for its validity. + * Set Version_arch to reflect all supported architectures if successful. + * Upon return on failure, subv will contain the last version string + * processed + * returns: VS_OK OK + * VS_INVARCH Invalid Architecture + * VS_INVVERS Invalid Version String + * VS_INVALID Both Version and Architecture are invalid; + */ +static int +version_sanity(const char *value, char **subv) +{ + char *p, *v, *a; + int retval = VS_INVALID; + + if (strchr(value, '=')) { + /* Form 1: Version arch=Version_string */ + v = strdup(value); + if (v == NULL) { + errlog(ERROR | FATAL, + "Internal Error: strdup() failure in " + "version_sanity()"); + } + + /* process each arch=version string */ + p = v; + while ((a = strtok(p, " \t\n"))) { + if ((retval = arch_version_sanity(a)) != VS_OK) { + *subv = strdup(a); + if (subv == NULL) { + errlog(ERROR | FATAL, + "Internal Error: strdup() failure " + "in version_sanity()"); + } + break; + } + if ((retval = set_version_arch(a)) != VS_OK) { + /* set the global Version_arch */ + *subv = strdup(a); + if (subv == NULL) { + errlog(ERROR | FATAL, + "Internal Error: strdup() failure " + "in version_sanity()"); + } + break; + } + p = NULL; + } + free(v); + } else { + /* Form 2: Version Version_string */ + if (valid_version(value)) { + retval = VS_OK; + } else { + *subv = strdup(value); + if (subv == NULL) { + errlog(ERROR | FATAL, + "Internal Error: strdup() failure " + "in version_sanity()"); + } + } + } + return (retval); +} + +/* + * arch_version_sanity() + * checks version lines of the form "arch=version" + * av MUST be a string of the form "arch=version" (no spaces) + * returns: VS_OK OK + * VS_INVARCH Invalid Architecture + * VS_INVVERS Invalid Version String + * VS_INVALID Both Versions are invalid; + */ +static int +arch_version_sanity(char *av) +{ + char *p, *v; + int retval = VS_OK; + + p = strchr(av, '='); + if (p == NULL) { + errlog(INPUT|ERROR, "Error: Incorrect format of Version line"); + return (VS_INVALID); + } + + *p = '\0'; /* stick a '\0' where the '=' was */ + v = p + 1; + + if (valid_arch(av) == 0) + retval = VS_INVARCH; + + if (valid_version(v) == 0) + retval += VS_INVVERS; + + *p = '='; /* restore the '=' */ + + return (retval); +} + +/* + * writemapfile() + * called by xlator_endlib(); + * writes out the map file + */ +static void +writemapfile(FILE *mapfp) +{ + bucket_t *l; /* List of buckets. */ + bucket_t *b; /* Bucket within list. */ + struct bucketlist *bl; + table_t *t; + int i = 0, n = 0; + char **p; + + errlog(BEGIN, "writemapfile() {"); + for (l = first_list(); l != NULL; l = next_list()) { + + for (b = first_from_list(l); b != NULL; b = next_from_list()) { + errlog(TRACING, "b_name = %s", b->b_name); + print_bucket(b); /* Debugging routine. */ + + if (!b->b_was_printed) { + /* Ok, we can print it. */ + b->b_was_printed = 1; + (void) fprintf(mapfp, "%s {\n", b->b_name); + + if (b->b_weak != 1) { + char *strtab; + + (void) fprintf(mapfp, " global:\n"); + + strtab = get_stringtable( + b->b_global_table, 0); + + if (strtab == NULL) { + /* + * There were no interfaces + * in the bucket. + * Insert a dummy entry + * to avoid a "weak version" + */ + (void) fprintf(mapfp, + "\t%s;\n", b->b_name); + } + } else { + (void) fprintf(mapfp, + " # Weak version\n"); + } + /* Print all the interfaces in the bucket. */ + t = b->b_global_table; + n = t->used; + + for (i = 0; i <= n; ++i) { + (void) fprintf(mapfp, "\t%s;\n", + get_stringtable(t, i)); + } + + if (b->b_has_protecteds) { + t = b->b_protected_table; + n = t->used; + + (void) fprintf(mapfp, + " protected:\n"); + + for (i = 0; i <= n; ++i) { + (void) fprintf(mapfp, "\t%s;\n", + get_stringtable(t, i)); + } + } + + /* Conditionally add ``local: *;''. */ + if (b->b_has_locals) { + (void) fprintf(mapfp, + " local:\n\t*;\n}"); + } else { + (void) fprintf(mapfp, "}"); + } + /* Print name of all parents. */ + for (p = parents_of(b); + p != NULL && *p != '\0'; ++p) { + (void) fprintf(mapfp, " %s", *p); + } + bl = b->b_uncles; + while (bl != NULL) { + (void) fprintf(mapfp, " %s", + bl->bl_bucket->b_name); + bl = bl->bl_next; + } + + (void) fprintf(mapfp, ";\n\n"); + } else { + /* + * We've printed this one before, + * so don't do it again. + */ + /*EMPTY*/; + } + } + } + errlog(END, "}"); +} + +/* + * set_version_arch () + * input must be a string of the form "arch=version" + * turns on bits of global Version_Arch that correspond to the "arch" + * return VS_OK upon success + * VS_INVARCH if architecture is invalid + * EINVAL on other failure + */ +static int +set_version_arch(const char *arch) +{ + char *a, *p; + int x; + int retval = EINVAL; + + if (arch == NULL) + return (retval); + + a = strdup(arch); + if (a == NULL) { + errlog(ERROR | FATAL, + "Internal Error: strdup() failure in " + "set_version_arch()"); + } + + p = strchr(a, '='); + if (p) { + *p = '\0'; + x = arch_strtoi(a); + if (x == 0) { + errlog(INPUT|ERROR, + "Error: Invalid architecture: %s", a); + retval = VS_INVARCH; + } else { + Version_Arch |= x; + retval = 0; + } + } + + free(a); + return (retval); +} + +/* + * set_supported_arch () + * input must be a string listing the architectures to be supported + * turns on bits of global Supported_Arch that correspond to the architecture + * return 0 upon success, EINVAL on failure + */ +static int +set_supported_arch(const char *arch) +{ + char *a, *p, *tmp; + int retval = EINVAL; + + if (arch == NULL || *arch == '\0') + return (EINVAL); + + tmp = strdup(arch); + if (tmp == NULL) { + errlog(ERROR | FATAL, "Internal Error: strdup() failure in " + "set_supported_arch()"); + } + + p = tmp; + while ((a = strtok(p, " ,\t\n"))) { + int x; + x = arch_strtoi(a); + if (x == 0) { + errlog(INPUT|ERROR, + "Error: Invalid architecture: %s", a); + free(tmp); + return (EINVAL); + } + Supported_Arch |= x; + retval = 0; + p = NULL; + } + + free(tmp); + return (retval); +}