xlator.c revision 753d2d2e8e7fd0c9bcf736d9bf2f2faf4d6234cc
/*
* 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
* 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 "%Z%%M% %I% %E% 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 "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,
};
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 int Verbosity;
static int TargetArchToken; /* set from -a option to front-end */
int IsFilterLib = 0; /* set from -F option to front-end */
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 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
*/
{
/*
* initially so we don't lose error messages from version_check
* we'll set this again later based on ti_info.ti_verbosity
*/
/* set verbosity */
/* Obtain translator flags */
/*
* set Library Type
* 1 if filter lib, 0 otherwise
*/
/* set target architecture */
/* set output file */
if (OutputFile) {
} else {
OutputFile = "mapfile";
}
/* obtain name of version file */
/* 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)
{
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)
{
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
{
char *kw;
int err;
switch (token) {
case XLATOR_KW_FUNC:
kw = "Function";
break;
case XLATOR_KW_DATA:
kw = "Data";
break;
default:
/* This should never happen */
"\"%s\", line %d: Implementation error! "
return (XLATOR_FATAL);
}
"Error: Interface spec is missing the "
"End keyword: %s", Curfun);
return (XLATOR_NONFATAL);
}
"Error: Missing argument in \"%s\" line", kw);
return (XLATOR_NONFATAL);
}
"Internal Error: strdup() failure in xlator_startif()");
}
Has_Version = 0;
Version_Arch = 0;
return (XLATOR_SUCCESS);
}
/*
* xlator_take_kvpair()
* processes spec keyword-value pairs
* returns: XLATOR_SUCCESS on success
* XLATOR_NONFATAL on error
*/
int
char *value)
{
char *p;
"take_kvpair called. ext_cnt=%d token=%d key=%s value=%s",
"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);
/* Version line found ; used for auditing the SPEC */
Has_Version = 1;
/* remove trailing white space */
if (p) {
*p = '\0';
--p;
}
}
/* is the version line valid */
case VS_OK: /* OK, subv not set */
break;
case VS_INVARCH: /* Invalid Arch */
"string found in spec or version file: %s", subv);
return (XLATOR_NONFATAL);
case VS_INVVERS: /* Invalid Version String */
"in spec or version file: %s", subv);
return (XLATOR_NONFATAL);
case VS_INVALID: /* Both Version and Arch are invalid */
"architecture string in spec or version file"
": %s", subv);
return (XLATOR_NONFATAL);
default: /* BAD IMPLEMENTATION OF version_sanity */
"version_sanity()! This should never happen!");
}
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)) {
"Error: Unable to parse Arch line");
return (XLATOR_NONFATAL);
}
} else {
}
if (Supported_Arch == 0) {
"Error: Unknown architecture defined in Arch line");
}
"Interface %s supports the following architectures: "
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 */
if (p) {
*p = '\0';
--p;
}
}
if (value[0] != '\0') {
} else {
"Error: Invalid binding value: %s", value);
}
} else {
}
"Interface %s has binding 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);
/* remove trailing white space */
if (p) {
*p = '\0';
--p;
}
}
if (token == XLATOR_KW_FILTER) {
} else if (token == XLATOR_KW_AUXILIARY) {
}
break;
default:
"\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
{
int retval = XLATOR_NONFATAL;
"matching Function or Data in file \"%s\"", Curfile);
goto cleanup;
}
if (!Has_Version) {
if (picky) {
"Version!\n\tInterface=%s\n\tSPEC File=%s",
} else {
"no Version!\n\tInterface=%s\n\tSPEC File=%s",
}
goto cleanup;
}
if (Version_Arch & (~Supported_Arch)) {
"line must be a subset of Architectures in Arch line\n"
goto cleanup;
}
if ((TargetArchToken & Supported_Arch) == 0) {
/*
* This interface is not for the architecture
* we are currently processing, so we skip it.
*/
goto cleanup;
}
if (picky) {
"Error: Version was not found for "
"\"%s\" architecture\n\tInterface=%s",
} else {
"Warning: Version was not found for "
"\"%s\" architecture\n\tInterface=%s",
}
goto cleanup;
}
/* check Iface.IF_type */
case FUNCTION:
break;
case DATA:
break;
case NOTYPE:
"Warning: Interface is neither "
"DATA nor FUNCTION!!\n\t"
"Interface=%s\n\tSPEC File=%s",
break;
default:
"\tInterface type is invalid\n"
"\tThis should never happen.\n"
goto cleanup;
}
/* cleanup */
return (retval);
}
/*
* xlator_endfile()
* signal end of spec file
* returns: XLATOR_SUCCESS on success
* XLATOR_NONFATAL on error
*/
int
xlator_endfile(void)
{
return (XLATOR_SUCCESS);
}
/*
* xlator_endlib()
* signal end of library
* returns: XLATOR_SUCCESS on success
* XLATOR_NONFATAL on error
*/
int
xlator_endlib(void)
{
int retval = XLATOR_SUCCESS;
/* Pretend to print mapfile */
}
/* Everything read, now organize it! */
sort_buckets();
add_local();
/* Create Output */
"Error: Unable to open output file \"%s\"\n\t%s",
} else {
}
return (retval);
}
/*
* xlator_end()
* signal end of translation
* returns: XLATOR_SUCCESS on success
* XLATOR_NONFATAL on error
*/
int
xlator_end(void)
{
/* 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 */
if (p == NULL) {
"Internal Error: strdup() failure "
"in getversion()");
}
v = p;
while (!isspace(*v) && *v != '\0')
++v;
*v = '\0';
} else {
return (NULL);
}
} else {
if (p == NULL) {
"failure in getversion()");
}
}
if (p != NULL)
else
return (p);
}
/*
* getfilter()
* Called by xlator_take_kvpair when "filter" or "auxiliary" keyword is
* 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 *
{
char *v, *p;
char arch[ARCHBUFLEN];
int archlen;
/* up to ARCHBUFLEN-1 */
if (p == NULL) {
"Internal Error: strdup() failure "
"in getfilter()");
}
v = p;
while (!isspace(*v) && *v != '\0')
++v;
*v = '\0';
} else {
return (NULL);
}
} else {
if (p == NULL) {
"failure in getfilter()");
}
}
if (p != NULL)
else
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
{
char *p, *v, *a;
int retval = VS_INVALID;
/* Form 1: Version arch=Version_string */
if (v == NULL) {
"Internal Error: strdup() failure in "
"version_sanity()");
}
/* process each arch=version string */
p = v;
while ((a = strtok(p, " \t\n"))) {
"Internal Error: strdup() failure "
"in version_sanity()");
}
break;
}
/* set the global Version_arch */
"Internal Error: strdup() failure "
"in version_sanity()");
}
break;
}
p = NULL;
}
free(v);
} else {
/* Form 2: Version Version_string */
if (valid_version(value)) {
} else {
"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;
if (p == NULL) {
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
{
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;
print_bucket(b); /* Debugging routine. */
if (!b->b_was_printed) {
/* Ok, we can print it. */
b->b_was_printed = 1;
if (b->b_weak != 1) {
char *strtab;
b->b_global_table, 0);
/*
* There were no interfaces
* in the bucket.
* Insert a dummy entry
* to avoid a "weak version"
*/
"\t%s;\n", b->b_name);
}
} else {
" # Weak version\n");
}
/* Print all the interfaces in the bucket. */
t = b->b_global_table;
n = t->used;
for (i = 0; i <= n; ++i) {
get_stringtable(t, i));
}
if (b->b_has_protecteds) {
t = b->b_protected_table;
n = t->used;
" protected:\n");
for (i = 0; i <= n; ++i) {
get_stringtable(t, i));
}
}
/* Conditionally add ``local: *;''. */
if (b->b_has_locals) {
" local:\n\t*;\n}");
} else {
}
/* Print name of all parents. */
for (p = parents_of(b);
p != NULL && *p != '\0'; ++p) {
}
}
} else {
/*
* We've printed this one before,
* so don't do it again.
*/
/*EMPTY*/;
}
}
}
}
/*
* 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;
return (retval);
if (a == NULL) {
"Internal Error: strdup() failure in "
"set_version_arch()");
}
p = strchr(a, '=');
if (p) {
*p = '\0';
x = arch_strtoi(a);
if (x == 0) {
"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;
return (EINVAL);
"set_supported_arch()");
}
p = tmp;
while ((a = strtok(p, " ,\t\n"))) {
int x;
x = arch_strtoi(a);
if (x == 0) {
"Error: Invalid architecture: %s", a);
return (EINVAL);
}
Supported_Arch |= x;
retval = 0;
p = NULL;
}
return (retval);
}