2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A/*
2N/A * Just in case we're not in a build environment, make sure that
2N/A * TEXT_DOMAIN gets set to something.
2N/A */
2N/A#if !defined(TEXT_DOMAIN)
2N/A#define TEXT_DOMAIN "SYS_TEST"
2N/A#endif
2N/A
2N/A#include <meta.h>
2N/A
2N/A#include <ctype.h>
2N/A
2N/A/*
2N/A * free md.tab struct
2N/A */
2N/Avoid
2N/Ameta_tab_free(
2N/A md_tab_t *tabp
2N/A)
2N/A{
2N/A size_t line;
2N/A
2N/A Free(tabp->filename);
2N/A Free(tabp->data);
2N/A if (tabp->lines != NULL) {
2N/A assert(tabp->alloc > 0);
2N/A for (line = 0; (line < tabp->nlines); ++line) {
2N/A md_tab_line_t *linep = &tabp->lines[line];
2N/A
2N/A if (linep->context != NULL)
2N/A Free(linep->context);
2N/A if (linep->cname != NULL)
2N/A Free(linep->cname);
2N/A if (linep->argv != NULL) {
2N/A assert(linep->alloc > 0);
2N/A Free(linep->argv);
2N/A }
2N/A }
2N/A Free(tabp->lines);
2N/A }
2N/A Free(tabp);
2N/A}
2N/A
2N/A/*
2N/A * (re)allocate argv array
2N/A */
2N/Astatic void
2N/Arealloc_argv(
2N/A md_tab_line_t *linep,
2N/A size_t argc
2N/A)
2N/A{
2N/A /* allocate in chunks */
2N/A argc = roundup(argc, TAB_ARG_ALLOC);
2N/A if (argc < linep->alloc)
2N/A return;
2N/A
2N/A /* (re)allocate */
2N/A if (linep->alloc == 0) {
2N/A linep->argv = Malloc(argc * sizeof (*linep->argv));
2N/A } else {
2N/A assert(linep->argv != NULL);
2N/A linep->argv =
2N/A Realloc(linep->argv, (argc * sizeof (*linep->argv)));
2N/A }
2N/A
2N/A /* zero out new stuff */
2N/A (void) memset(&linep->argv[linep->alloc], 0,
2N/A ((argc - linep->alloc) * sizeof (*linep->argv)));
2N/A
2N/A /* adjust for new size */
2N/A linep->alloc = argc;
2N/A}
2N/A
2N/A/*
2N/A * (re)allocate line array
2N/A */
2N/Astatic void
2N/Arealloc_lines(
2N/A md_tab_t *tabp,
2N/A size_t nlines
2N/A)
2N/A{
2N/A /* allocate in chunks */
2N/A nlines = roundup(nlines, TAB_LINE_ALLOC);
2N/A if (nlines < tabp->alloc)
2N/A return;
2N/A
2N/A /* (re)allocate */
2N/A if (tabp->alloc == 0) {
2N/A assert(tabp->lines == NULL);
2N/A tabp->lines = Malloc(nlines * sizeof (*tabp->lines));
2N/A } else {
2N/A assert(tabp->lines != NULL);
2N/A tabp->lines =
2N/A Realloc(tabp->lines, (nlines * sizeof (*tabp->lines)));
2N/A }
2N/A
2N/A /* zero out new stuff */
2N/A (void) memset(&tabp->lines[tabp->alloc], 0,
2N/A ((nlines - tabp->alloc) * sizeof (*tabp->lines)));
2N/A
2N/A /* adjust for new size */
2N/A tabp->alloc = nlines;
2N/A}
2N/A
2N/A/*
2N/A * parse up md.tab struct
2N/A */
2N/Astatic void
2N/Aparse_tab(
2N/A md_tab_t *tabp,
2N/A char *metatab_name,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A uint_t lineno = 1;
2N/A char *p = tabp->data;
2N/A char *e = tabp->data + tabp->total - 1;
2N/A char *context;
2N/A size_t len;
2N/A
2N/A /* we can count on '\n\0' as the last characters */
2N/A assert(tabp->total >= 2);
2N/A assert(tabp->data[tabp->total - 2] == '\n');
2N/A assert(tabp->data[tabp->total - 1] == '\0');
2N/A
2N/A /* allocate context buffer "file line XXX" */
2N/A assert(tabp->filename != NULL);
2N/A len = strlen(tabp->filename) +
2N/A strlen(dgettext(TEXT_DOMAIN, "%s line %u")) + 20 + 1;
2N/A context = Malloc(len);
2N/A
2N/A /* parse lines */
2N/A while (p < e && *p != '\0') {
2N/A md_tab_line_t *linep;
2N/A char *t;
2N/A
2N/A /* allocate new line */
2N/A realloc_lines(tabp, (tabp->nlines + 1));
2N/A linep = &tabp->lines[tabp->nlines];
2N/A (void) snprintf(context, len,
2N/A dgettext(TEXT_DOMAIN, "%s line %u"), tabp->filename,
2N/A lineno);
2N/A
2N/A /* comments */
2N/A if (*p == '#') {
2N/A while (*p != '\n')
2N/A ++p;
2N/A }
2N/A
2N/A /* coalesce \ continuations */
2N/A t = p;
2N/A while (*t != '\n') {
2N/A if ((*t == '\\') && (*(t + 1) == '\n')) {
2N/A *t++ = ' ';
2N/A *t = ' ';
2N/A ++lineno;
2N/A }
2N/A ++t;
2N/A }
2N/A
2N/A /* leading whitespace */
2N/A while ((*p != '\n') && (isspace(*p)))
2N/A ++p;
2N/A
2N/A /* count lines */
2N/A if (*p == '\n') {
2N/A ++p;
2N/A ++lineno;
2N/A continue;
2N/A }
2N/A
2N/A /* tokenize line */
2N/A while ((p < e) && (*p != '\n')) {
2N/A char **argvp;
2N/A
2N/A /* allocate new token */
2N/A realloc_argv(linep, (linep->argc + 1));
2N/A argvp = &linep->argv[linep->argc++];
2N/A
2N/A /* find end of token */
2N/A *argvp = p;
2N/A while ((*p != '\n') && (! isspace(*p)))
2N/A ++p;
2N/A
2N/A /* terminate */
2N/A if (*p == '\n') {
2N/A *p++ = '\0';
2N/A ++lineno;
2N/A break;
2N/A }
2N/A
2N/A /* eat white space */
2N/A *p++ = '\0';
2N/A while ((p < e) && (*p != '\n') && (isspace(*p)))
2N/A ++p;
2N/A }
2N/A tabp->nlines++;
2N/A
2N/A /* fill in the rest */
2N/A assert((linep->argc > 0) && (linep->argv != NULL) &&
2N/A (linep->argv[0][0] != '\0') &&
2N/A (! isspace(linep->argv[0][0])));
2N/A linep->context = Strdup(context);
2N/A linep->type = meta_get_init_type(linep->argc, linep->argv);
2N/A linep->cname = meta_canonicalize(NULL, linep->argv[0]);
2N/A /* if cname is NULL then the meta/hsp name is invalid */
2N/A if (linep->cname == NULL) {
2N/A (void) mderror(ep, MDE_SYNTAX, metatab_name);
2N/A break;
2N/A }
2N/A }
2N/A
2N/A /* cleanup */
2N/A Free(context);
2N/A}
2N/A
2N/A/*
2N/A * read in md.tab file and return struct
2N/A */
2N/Amd_tab_t *
2N/Ameta_tab_parse(
2N/A char *filename,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_tab_t *tabp = NULL;
2N/A int fd = -1;
2N/A struct stat statbuf;
2N/A size_t sofar;
2N/A char *p;
2N/A
2N/A /* open tab file */
2N/A if (filename == NULL)
2N/A filename = METATAB;
2N/A if ((fd = open(filename, O_RDONLY, 0)) < 0) {
2N/A (void) mdsyserror(ep, errno, filename);
2N/A goto out;
2N/A }
2N/A if (fstat(fd, &statbuf) != 0) {
2N/A (void) mdsyserror(ep, errno, filename);
2N/A goto out;
2N/A }
2N/A
2N/A /* allocate table */
2N/A tabp = Zalloc(sizeof (*tabp));
2N/A tabp->filename = Strdup(filename);
2N/A tabp->total = statbuf.st_size + 2; /* terminating "\n\0" */
2N/A tabp->data = Malloc(tabp->total);
2N/A
2N/A /* read in data */
2N/A sofar = 0;
2N/A p = tabp->data;
2N/A while (sofar < statbuf.st_size) {
2N/A int cnt;
2N/A
2N/A if ((cnt = read(fd, p, 8192)) < 0) {
2N/A (void) mdsyserror(ep, errno, filename);
2N/A goto out;
2N/A } else if (cnt == 0) {
2N/A (void) mderror(ep, MDE_SYNTAX, filename);
2N/A goto out;
2N/A }
2N/A sofar += cnt;
2N/A p += cnt;
2N/A }
2N/A tabp->data[tabp->total - 2] = '\n';
2N/A tabp->data[tabp->total - 1] = '\0';
2N/A
2N/A /* close file */
2N/A if (close(fd) != 0) {
2N/A (void) mdsyserror(ep, errno, filename);
2N/A fd = -1;
2N/A goto out;
2N/A }
2N/A fd = -1;
2N/A
2N/A /* parse it up */
2N/A parse_tab(tabp, filename, ep);
2N/A
2N/A /* return success if file was correctly parsed */
2N/A if (mdisok(ep))
2N/A return (tabp);
2N/A
2N/A /* cleanup, return error */
2N/Aout:
2N/A if (fd >= 0)
2N/A (void) close(fd);
2N/A if (tabp != NULL)
2N/A meta_tab_free(tabp);
2N/A return (NULL);
2N/A}
2N/A
2N/A/*
2N/A * find line in md.tab
2N/A */
2N/Amd_tab_line_t *
2N/Ameta_tab_find(
2N/A mdsetname_t *sp,
2N/A md_tab_t *tabp,
2N/A char *name,
2N/A mdinittypes_t type
2N/A)
2N/A{
2N/A char *cname = meta_canonicalize(sp, name);
2N/A size_t line;
2N/A
2N/A /* if name is not legal meta name then return NULL */
2N/A if (cname == NULL)
2N/A return (NULL);
2N/A
2N/A for (line = 0; (line < tabp->nlines); ++line) {
2N/A md_tab_line_t *linep = &tabp->lines[line];
2N/A
2N/A assert((linep->argc > 0) && (linep->argv[0] != NULL));
2N/A if (((linep->type & type) != 0) &&
2N/A (strcmp(linep->cname, cname) == 0)) {
2N/A Free(cname);
2N/A return (linep);
2N/A }
2N/A }
2N/A Free(cname);
2N/A return (NULL);
2N/A}