summaryrefslogtreecommitdiff
path: root/usr/src/cmd/abi/spectrans/parser/frontend.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/abi/spectrans/parser/frontend.c')
-rw-r--r--usr/src/cmd/abi/spectrans/parser/frontend.c569
1 files changed, 569 insertions, 0 deletions
diff --git a/usr/src/cmd/abi/spectrans/parser/frontend.c b/usr/src/cmd/abi/spectrans/parser/frontend.c
new file mode 100644
index 0000000000..db33b99442
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/parser/frontend.c
@@ -0,0 +1,569 @@
+/*
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <dirent.h>
+#include <libgen.h>
+#include <sys/param.h>
+#include <errno.h>
+
+#include "parser.h"
+#include "errlog.h"
+
+static char const *ARCH_I386 = "i386";
+static char const *ARCH_SPARC = "sparc";
+static char const *ARCH_SPARCV9 = "sparcv9";
+static char const *ARCH_IA64 = "ia64";
+static char const *ARCH_AMD64 = "amd64";
+static char const *ARCH_ALL = "all";
+
+static int dofiles(const Translator_info *);
+static int read_spec(const Translator_info *, char *);
+
+static int Curlineno;
+
+xlator_keyword_t *keywordlist;
+
+/*
+ * frontend entry point
+ * returns the number of errors encountered
+ */
+int
+frontend(const Translator_info *T_info)
+{
+ int retval, i = 0, errors = 0;
+
+ keywordlist = xlator_init(T_info);
+ if (keywordlist == NULL) {
+ errlog(ERROR, "Error: Unable to get keywordlist\n");
+ return (1);
+ }
+
+ if (T_info->ti_verbosity >= STATUS) {
+ errlog(STATUS, "interesting keywords:\n");
+ while (keywordlist[i].key != NULL) {
+ errlog(STATUS, "\t%s\n", keywordlist[i].key);
+ ++i;
+ };
+ }
+
+ retval = xlator_startlib(T_info->ti_liblist);
+ switch (retval) {
+ case XLATOR_SKIP:
+ if (T_info->ti_verbosity >= STATUS)
+ errlog(STATUS, "Skipping %s\n", T_info->ti_liblist);
+ retval = 0;
+ break;
+
+ case XLATOR_NONFATAL:
+ ++errors;
+ retval = 0;
+ break;
+
+ case XLATOR_SUCCESS:
+ retval = dofiles(T_info);
+ errors += retval;
+ if ((retval = xlator_endlib()) != XLATOR_SUCCESS)
+ ++errors;
+ retval = 0;
+ break;
+
+ default:
+ errlog(ERROR | FATAL,
+ "Error: Invalid return code from xlator_startlib()\n");
+ exit(1);
+ }
+
+ if ((retval = xlator_end()) != XLATOR_SUCCESS)
+ ++errors;
+
+ return (errors);
+}
+
+/*
+ * dofiles(const Translator_info *T_info);
+ * iterate through files specified in the command line and process
+ * them one by one
+ * requires spec files to have a ".spec" suffix
+ * returns the number of errors;
+ */
+static int
+dofiles(const Translator_info *T_info)
+{
+ int nfiles, flen, findex, retval = 0, errors = 0;
+
+ nfiles = T_info->ti_nfiles;
+
+ for (findex = 0; findex < nfiles; ++findex) {
+ flen = strlen(filelist[findex]);
+ if ((flen <= 5) ||
+ strcmp(&filelist[findex][flen-5], ".spec") != 0) {
+ errlog(ERROR,
+ "Error: File specified does not have the "
+ ".spec extension: %s\n", filelist[findex]);
+ ++errors;
+ continue;
+ };
+ retval = read_spec(T_info, filelist[findex]);
+ errors += retval;
+ }
+ return (errors);
+}
+
+/*
+ * read_spec -
+ * Given a filename, this function will reads the spec file to
+ * recognize keywords which it passes along with the corresponding
+ * value to the back-end translator to process. The following
+ * back-end interfaces are called:
+ * xlator_startfile
+ * xlator_start_if
+ * xlator_take_kvpair
+ * xlator_end_if
+ * xlator_endfile
+ */
+static int
+read_spec(const Translator_info *T_info, char *spec_filename)
+{
+ FILE *spec_fp;
+ Meta_info meta_info;
+ char key[BUFSIZ], *value = NULL, *p = NULL;
+ char *buf2 = NULL;
+ int retval = 0, errors = 0, ki = 0; /* keyword indicator */
+ int start_if_fail = 0, skip_if = 0;
+ int extends_err = 0;
+
+ meta_info.mi_ext_cnt = 0; /* All info is non-extends */
+ meta_info.mi_flags = 0;
+
+ retval = xlator_startfile(spec_filename);
+
+ switch (retval) {
+ case XLATOR_SKIP:
+ if (T_info->ti_verbosity >= WARNING)
+ errlog(WARNING, "Warning: Skipping %s\n",
+ spec_filename);
+ return (errors);
+
+ case XLATOR_NONFATAL:
+ errlog(ERROR, "Error in xlator_startfile\n");
+ ++errors;
+ return (errors);
+
+ case XLATOR_SUCCESS:
+ break;
+
+ default:
+ errlog(ERROR,
+ "Error: Invalid return code from xlator_startfile()\n");
+ ++errors;
+ return (errors);
+ };
+
+ /* file processing */
+ spec_fp = fopen(spec_filename, "r");
+ if (spec_fp == NULL) {
+ errlog(ERROR, "Error: Unable to open spec file %s: %s\n",
+ spec_filename, strerror(errno));
+ ++errors;
+ return (errors);
+ }
+
+ (void) strncpy(meta_info.mi_filename, spec_filename, BUFSIZ);
+ meta_info.mi_line_number = 0;
+ Curlineno = meta_info.mi_line_number;
+ while (meta_info.mi_nlines = readline(&buf2, spec_fp)) {
+ meta_info.mi_line_number += meta_info.mi_nlines;
+ Curlineno = meta_info.mi_line_number;
+ if (!non_empty(buf2)) {
+ free(buf2);
+ buf2 = NULL;
+ continue;
+ }
+ p = realloc(value, sizeof (char)*(strlen(buf2)+1));
+ if (p == NULL) {
+ errlog(ERROR | FATAL,
+ "Error: Unable to allocate memory for "
+ "value: %d\n", errno);
+ }
+ value = p;
+ split(buf2, key, value);
+ ki = interesting_keyword(keywordlist, key);
+ switch (ki) {
+ case XLATOR_KW_FUNC: /* Function keyword */
+ case XLATOR_KW_DATA: /* Data keyword */
+ meta_info.mi_extended = 0;
+ retval = xlator_start_if(meta_info, ki, value);
+ switch (retval) {
+ case XLATOR_FATAL: /* FATAL ERROR */
+ if (T_info->ti_verbosity >= STATUS) {
+ errlog(STATUS,
+ "Error in xlator_start_if: ");
+ }
+ ++errors;
+ return (errors);
+ case XLATOR_NONFATAL: /* NON-FATAL ERROR */
+ if (T_info->ti_verbosity >= STATUS)
+ errlog(STATUS,
+ "Error in xlator_start_if\n");
+ ++errors;
+ start_if_fail = 1;
+ break;
+ case XLATOR_SUCCESS: /* OK */
+ start_if_fail = 0;
+ extends_err = check4extends(spec_filename,
+ value, T_info->ti_archtoken, spec_fp);
+ switch (extends_err) {
+ case -1: /* Error */
+ errlog(ERROR, "\"%s\", line %d: "
+ "Error occurred while "
+ "checking for extends clause\n",
+ spec_filename, Curlineno);
+ ++errors;
+ /*FALLTHRU*/
+ case 0: /* No Extends */
+ break;
+ case 1: /* Extends */
+ meta_info.mi_extended = 1;
+ extends_err = do_extends(meta_info,
+ T_info, value);
+ if (extends_err) {
+ errors += extends_err;
+ }
+ break;
+ default: /* Programmer Error */
+ errlog(ERROR | FATAL,
+ "Error: invalid return from "
+ "check4extends %d\n", extends_err);
+ }
+ break;
+ case XLATOR_SKIP: /* SKIP */
+ if (T_info->ti_verbosity >= WARNING)
+ errlog(WARNING, "Warning: Skipping "
+ "interface %s\n", value);
+ skip_if = 1;
+ start_if_fail = 0;
+ break;
+ default:
+ /* Invalid Return */
+ errlog(ERROR | FATAL,
+ "Error: Invalid return code "
+ "from xlator_start_if (): %d\n", retval);
+ }
+ break;
+ case XLATOR_KW_END: /* END keyword */
+ if (start_if_fail == 0 && skip_if == 0) {
+ retval = xlator_end_if(meta_info, value);
+ if (retval)
+ ++errors;
+ }
+ skip_if = 0;
+ break;
+ case XLATOR_KW_NOTFOUND:
+ if (T_info->ti_verbosity >= TRACING)
+ errlog(TRACING, "uninteresting keyword: %s\n",
+ key);
+ break;
+ default:
+ if (skip_if == 0 && start_if_fail == 0) {
+ retval = xlator_take_kvpair(meta_info,
+ ki, value);
+ if (retval) {
+ if (T_info->ti_verbosity >= STATUS)
+ errlog(STATUS, "Error in "
+ "xlator_take_kvpair\n");
+ ++errors;
+ }
+ }
+ }
+ free(buf2);
+ buf2 = NULL;
+ }
+
+ if ((retval = xlator_endfile()) != XLATOR_SUCCESS) {
+ if (T_info->ti_verbosity >= STATUS)
+ errlog(STATUS, "Error in xlator_endfile\n");
+ ++errors;
+ }
+ free(p);
+ (void) fclose(spec_fp);
+ return (errors);
+}
+
+/*
+ * interesting_keyword(char **keywordlist, const char *key) {
+ * returns the token associated with key if key is found in keywordlist
+ * returns XLATOR_KW_NOTFOUND if key is NOT found in keywordlist
+ * "Function" and "End" are always interesting, return XLATOR_KW_FUNC
+ * and XLATOR_KW_DATA respectively;
+ * "End" is always interesting, return XLATOR_KW_END;
+ *
+ */
+int
+interesting_keyword(xlator_keyword_t *keywordlist, const char *key)
+{
+ int i = 0;
+
+ if (strcasecmp(key, "data") == 0) {
+ return (XLATOR_KW_DATA);
+ }
+ if (strcasecmp(key, "function") == 0) {
+ return (XLATOR_KW_FUNC);
+ }
+
+ if (strcasecmp(key, "end") == 0)
+ return (XLATOR_KW_END);
+
+ while (keywordlist[i].key != NULL) {
+ if (strcasecmp(keywordlist[i].key, key) == 0)
+ return (keywordlist[i].token);
+ ++i;
+ }
+ return (XLATOR_KW_NOTFOUND);
+}
+
+/*
+ * line_to_buf(char *dest, const char *src) {
+ * appends src to dest, dynamically increasing the size of dest.
+ * replaces the trailing '\' continuation character with a space.
+ *
+ * if src is continuation of dest, dest != NULL, and
+ * the last character in dest before the newline must be a `\'
+ * if src is not continuation of dest, then dest must be NULL
+ */
+char *
+line_to_buf(char *dest, const char *src)
+{
+ int slen = strlen(src);
+ int dlen;
+
+ if (dest == NULL) {
+ /* We're being called for the first time */
+ dest = malloc(sizeof (char) * (slen + 1));
+ if (dest == NULL) {
+ errlog(ERROR | FATAL,
+ "Error: Unable to allocate memory for dest\n");
+ }
+ (void) strcpy(dest, src);
+ return (dest);
+ }
+
+ dlen = strlen(dest);
+
+ dest = realloc(dest, (size_t)(sizeof (char) * (dlen+slen+1)));
+ if (dest == NULL) {
+ errlog(ERROR | FATAL,
+ "Error: Unable to allocate memory for dest\n");
+ }
+
+ if (dlen > 1) {
+ /*
+ * remove continuation character
+ * we replace the '\' from the previous line with a space
+ */
+ if (dest[dlen-2] == '\\') {
+ dest[dlen-2] = ' ';
+ }
+ }
+
+ /* join the two strings */
+ (void) strcat(dest, src);
+
+ return (dest);
+}
+
+/*
+ * non_empty(const char *str)
+ * assumes str is non null
+ * checks if str is a non empty string
+ * returns 1 if string contains non whitespace
+ * returns 0 if string contains only whitespace
+ */
+int
+non_empty(const char *str)
+{
+ while (*str != '\0') {
+ if (!isspace(*str))
+ return (1);
+ ++str;
+ };
+ return (0);
+}
+
+/*
+ * split(const char *line, char *key, char *value);
+ * splits the line into keyword (key) and value pair
+ */
+void
+split(const char *line, char *key, char *value)
+{
+ char *p;
+
+ p = (char *)line;
+
+ /* skip leading whitespace */
+ while (isspace(*p)&& *p != '\0')
+ ++p;
+
+ /* copy keyword from line into key */
+ while (!isspace(*p) && *p != '\0')
+ *key++ = *p++;
+
+ *key = '\0';
+
+ /* skip whitespace */
+ while (isspace(*p) && *p != '\0')
+ p++;
+
+ (void) strcpy(value, p);
+
+}
+
+/*
+ * check4extends(char *filename, char *value, int arch, FILE *fp)
+ * if no arch keyword is found or there is a MATCHING arch keyword
+ * returns 1 if value is of the form "data|function name extends"
+ * -1 for error
+ * 0 no other keyword after the function name
+ * else
+ * return 0
+ *
+ * filename is used only for error reporting
+ */
+int
+check4extends(const char *filename, const char *value, int arch, FILE *fp)
+{
+ char fun[BUFSIZ];
+ char extends[BUFSIZ];
+ int n;
+
+ if (arch_match(fp, arch)) {
+ split(value, fun, extends);
+ n = strlen(extends);
+ if (extends[n-1] == '\n')
+ extends[n-1] = '\0';
+ if (strncasecmp("extends", extends, 7) == 0) {
+ return (1);
+ } else {
+ if (*extends != '\0') {
+ errlog(ERROR, "\"%s\", line %d: Error: "
+ "Trailing garbage after function name\n",
+ filename, Curlineno);
+ return (-1);
+ }
+ }
+ }
+ return (0);
+}
+
+/*
+ * remcomment (char *buf)
+ * replace comments with single whitespace
+ */
+/* XXX: There is currently no way to escape a comment character */
+void
+remcomment(char const *buf)
+{
+ char *p;
+ p = strchr(buf, '#');
+ if (p) {
+ *p = ' ';
+ *(p+1) = '\0';
+ }
+}
+
+/*
+ * arch_strtoi()
+ *
+ * input: string
+ * return: XLATOR_I386 if string == ARCH_I386
+ * XLATOR_SPARC if string == ARCH_SPARC
+ * XLATOR_SPARCV9 if string == ARCH_SPARCV9
+ * XLATOR_IA64 if string == ARCH_IA64
+ * XLATOR_AMD64 if string == ARCH_AMD64
+ * XLATOR_ALLARCH if string == ARCH_ALL
+ * 0 if outside the known set {i386, sparc, sparcv9, ia64, amd64}.
+ */
+int
+arch_strtoi(const char *arch_str)
+{
+ if (arch_str != NULL) {
+ if (strcmp(arch_str, ARCH_I386) == 0)
+ return (XLATOR_I386);
+ else if (strcmp(arch_str, ARCH_SPARC) == 0)
+ return (XLATOR_SPARC);
+ else if (strcmp(arch_str, ARCH_SPARCV9) == 0)
+ return (XLATOR_SPARCV9);
+ else if (strcmp(arch_str, ARCH_IA64) == 0)
+ return (XLATOR_IA64);
+ else if (strcmp(arch_str, ARCH_AMD64) == 0)
+ return (XLATOR_AMD64);
+ else if (strcmp(arch_str, ARCH_ALL) == 0)
+ return (XLATOR_ALLARCH);
+ } else {
+ errlog(ERROR, "\"%s\", line %d: Error: "
+ "arch keyword with no value");
+ }
+ return (0);
+}
+
+int
+readline(char **buffer, FILE *fp)
+{
+ int nlines = 0;
+ int len;
+ char buf[BUFSIZ];
+
+ if (fgets(buf, BUFSIZ, fp)) {
+ nlines++;
+ /* replace comments with single whitespace */
+ remcomment(buf);
+
+ /* get complete line */
+ *buffer = line_to_buf(*buffer, buf); /* append buf to buffer */
+ len = strlen(buf);
+ if (len > 1) {
+ /* handle continuation lines */
+ while (buf[len-2] == '\\') {
+ if (!fgets(buf, BUFSIZ, fp)) {
+ *buffer = line_to_buf(*buffer, buf);
+ break;
+ }
+ nlines++;
+ len = strlen(buf);
+ *buffer = line_to_buf(*buffer, buf);
+ }
+ } /* end of 'get complete line' */
+ }
+ return (nlines);
+}