diff options
Diffstat (limited to 'getdefs/gdinit.c')
-rw-r--r-- | getdefs/gdinit.c | 490 |
1 files changed, 490 insertions, 0 deletions
diff --git a/getdefs/gdinit.c b/getdefs/gdinit.c new file mode 100644 index 0000000..321a582 --- /dev/null +++ b/getdefs/gdinit.c @@ -0,0 +1,490 @@ +/** + * \file gdinit.c + * + * getdefs Copyright (c) 1999-2012 by Bruce Korb - all rights reserved + * + * Author: Bruce Korb <bkorb@gnu.org> + * Time-stamp: "2011-12-29 10:02:47 bkorb" + * + * This file is part of AutoGen. + * AutoGen copyright (c) 1992-2012 by Bruce Korb - all rights reserved + * + * AutoGen is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AutoGen is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +static char const zNoList[] = "ERROR: block attr must have name list:\n\t%s\n"; + +/* = = = START-STATIC-FORWARD = = = */ +static char* +compressOptionText(char* pzS, char* pzE); + +static char* +fixupSubblockString(char const * pzSrc); + +static void +loadStdin(void); + +static void +set_define_re(void); + +static void +set_modtime(void); +/* = = = END-STATIC-FORWARD = = = */ + +LOCAL void +die(char const * fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "%s error: ", getdefsOptions.pzProgName); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + +LOCAL void +fserr_die(char const * fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "%s fserr %d (%s): ", getdefsOptions.pzProgName, + errno, strerror(errno)); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + +/* + * compressOptionText + */ +static char* +compressOptionText(char* pzS, char* pzE) +{ + char* pzR = pzS; /* result */ + char* pzD = pzS; /* destination */ + + for (;;) { + char ch; + + if (pzS >= pzE) + break; + + ch = (*(pzD++) = *(pzS++)); + + /* + * IF At end of line, skip to next '*' + */ + if (ch == '\n') { + while (*pzS != '*') { + pzS++; + if (pzS >= pzE) + goto compressDone; + } + } + } compressDone:; + + { + size_t len = (pzD - pzR); + pzD = malloc(len + 1); + if (pzD == NULL) + die("cannot dup %d byte string\n", (int)(pzD - pzR)); + + memcpy(pzD, pzR, len); + pzD[ len ] = NUL; + } + + /* + * Blank out trailing data. + */ + while (pzS < pzE) *(pzS++) = ' '; + return pzD; +} + + +/* + * fixupSubblockString + */ +static char* +fixupSubblockString(char const * pzSrc) +{ + char * pzString; + char * pzDest; + char * pzCopy; + + pzString = strdup(pzSrc); + + /* + * Make sure we find the '=' separator + */ + { + char * p = strchr(pzString, '='); + if (p == NULL) + die(zNoList, pzString); + + /* + * Trim the name + */ + pzDest = p++; + while ((pzDest > pzString) && IS_HORIZ_WHITE_CHAR(pzDest[-1])) pzDest--; + *(pzDest++) = NUL; + + /* + * Make sure at least one attribute name is defined + */ + while (IS_WHITESPACE_CHAR(*p)) p++; + if (*p == NUL) + die(zNoList, pzString); + + pzCopy = p; + } + + for (;;) { + /* + * Attribute names must start with an alpha + */ + if (! IS_ALPHABETIC_CHAR(*pzCopy)) { + fprintf(stderr, "ERROR: attribute names must start " + "with an alphabetic character:\n\t%s\n", + pzString); + USAGE(EXIT_FAILURE); + } + + /* + * Copy the name. + */ + while (IS_OPTION_NAME_CHAR(*pzCopy)) + *pzDest++ = *pzCopy++; + + /* + * Skip over one comma (optional) and any white space. + * If there is a newline, it must be after the comma. + */ + while (IS_HORIZ_WHITE_CHAR(*pzCopy)) pzCopy++; + if (*pzCopy == ',') + pzCopy++; + + while (IS_WHITESPACE_CHAR(*pzCopy)) pzCopy++; + if (*pzCopy == NUL) + break; + /* + * The final string contains only one space between attributes + */ + *pzDest++ = ' '; + } + + *pzDest = NUL; + + return pzString; +} + + +/* + * loadStdin + * + * The input file list is from stdin. + * + * We make some simplifying assumptions: + * *ALL* input lines are less than 4096 bytes. If this is not true, + * we may strip some white space in the middle of a line and presume + * a comment begins in the middle of a line or we only comment out + * the first 4096 bytes of a comment line. So, rather than all these + * problems, we just choke on it. + */ +static void +loadStdin(void) +{ + char z[ 4096 ]; + int ct = 0; + tCC** ppz = STACKLST_OPT(INPUT); + + if (isatty(STDIN_FILENO)) { + fputs("getdefs error: no inputs were specified and stdin is a tty\n", + stderr); + USAGE(EXIT_FAILURE); + } + + while (fgets(z, (int)sizeof(z), stdin) != NULL) { + char* pz = z + strlen(z); + + if (pz[-1] != '\n') { + tSCC zErr[] = + "getdefs error: input line not newline terminated\n"; + fputs(zErr, stderr); + exit(EXIT_FAILURE); + } + + while ((pz > z) && isspace(pz[-1])) pz--; + *pz = '\0'; + pz = z; + while (isspace(*pz)) pz++; + if ((*pz == '\0') || (*pz == '#')) continue; + if (access(pz, R_OK) != 0) continue; + + if (ct++ == 0) + *ppz = strdup(z); /* replace the "-" */ + else + SET_OPT_INPUT(strdup(z)); /* if 'strdup' fails, we die later */ + } +} + + +/* + * processEmbeddedOptions + * + * This routine processes the text contained within "/\*==--" + * and "=\*\/" as a single option. If that option is the SUBBLOCK + * option, it will need to be massaged for use. + */ +LOCAL void +processEmbeddedOptions(char* pzText) +{ + tSCC zStStr[] = "/*=--"; + tSCC zEndSt[] = "=*/"; + + for (;;) { + char* pzStart = strstr(pzText, zStStr); + char* pzEnd; + int sblct = 0; + + if (pzStart == NULL) + return; + + if (HAVE_OPT(SUBBLOCK)) + sblct = STACKCT_OPT(SUBBLOCK); + + pzEnd = strstr(pzStart, zEndSt); + if (pzEnd == NULL) + return; + + pzStart = compressOptionText(pzStart + sizeof(zStStr)-1, pzEnd); + + optionLoadLine(&getdefsOptions, pzStart); + + if (HAVE_OPT(SUBBLOCK) && (sblct != STACKCT_OPT(SUBBLOCK))) { + tCC** ppz = STACKLST_OPT(SUBBLOCK); + ppz[ sblct ] = fixupSubblockString(ppz[sblct]); + } + pzText = pzEnd + sizeof(zEndSt); + } +} + +/** + * set up the regular expression we search for + */ +static void +set_define_re(void) +{ + static char const default_pat[] = + "/\\*=(\\*|" + "([a-z][a-z0-9_]*(\\[[0-9]+\\]){0,1}|\\*)[ \t]+[a-z])"; + static char const pat_wrapper[] = "/\\*=(%s)"; + + char const * def_pat; + bool free_pat = false; + + /* + * Our default pattern is to accept all names following + * the '/' '*' '=' character sequence. We ignore case. + */ + if ((! HAVE_OPT(DEFS_TO_GET)) || (*OPT_ARG(DEFS_TO_GET) == NUL)) { + def_pat = default_pat; + + } else if (strncmp(OPT_ARG(DEFS_TO_GET), default_pat, 4) == 0) { + def_pat = OPT_ARG(DEFS_TO_GET); + + } else { + char const * pz = OPT_ARG(DEFS_TO_GET); + size_t len = strlen((char *)pz) + 16; + char * bf = malloc(len); + + if (bf == NULL) + die(zMallocErr, (int)len, "definition pattern"); + + /* + * IF a pattern has been supplied, enclose it with + * the '/' '*' '=' part of the pattern. + */ + snprintf(bf, len, pat_wrapper, pz); + def_pat = bf; + free_pat = true; + } + + /* + * Compile the regular expression that we are to search for + * to find each new definition in the source files. + */ + { + char zRER[MAXNAMELEN]; + static char const zReErr[] = + "Regex error %d (%s): Cannot compile reg expr:\n\t%s\n"; + + int rerr = regcomp(&define_re, def_pat, REG_EXTENDED | REG_ICASE); + if (rerr != 0) { + regerror(rerr, &define_re, zRER, sizeof(zRER)); + die(zReErr, rerr, zRER, def_pat); + } + + if (free_pat) + free((void *)def_pat); + + rerr = regcomp(&attrib_re, zAttribRe, REG_EXTENDED | REG_ICASE); + if (rerr != 0) { + regerror(rerr, &attrib_re, zRER, sizeof(zRER)); + die(zReErr, rerr, zRER, zAttribRe); + } + } +} + +/** + * Make sure each of the input files is findable. + * Also, while we are at it, compute the output file mod time + * based on the mod time of the most recent file. + */ +static void +set_modtime(void) +{ + int ct = STACKCT_OPT(INPUT); + char const ** ppz = STACKLST_OPT(INPUT); + struct stat stb; + + if ((ct == 1) && (strcmp(*ppz, "-") == 0)) { + /* + * Read the list of input files from stdin. + */ + loadStdin(); + ct = STACKCT_OPT( INPUT); + ppz = STACKLST_OPT(INPUT); + } + + do { + if (stat(*ppz++, &stb) != 0) + break; + + if (! S_ISREG(stb.st_mode)) { + errno = EINVAL; + break; + } + + if (++(stb.st_mtime) > modtime) + modtime = stb.st_mtime; + } while (--ct > 0); + + if (ct > 0) + fserr_die("stat-ing %s for text file\n", ppz[-1]); +} + +/** + * validateOptions + * + * - Sanity check the options + * - massage the SUBBLOCK options into something + * more easily used during the source text processing. + * - compile the regular expressions + * - make sure we can find all the input files and their mod times + * - Set up our entry ordering database (if specified) + * - Make sure we have valid strings for SRCFILE and LINENUM + * (if we are to use these things). + * - Initialize the user name characters array. + */ +LOCAL void +validateOptions(void) +{ + set_define_re(); + + /* + * Prepare each sub-block entry so we can parse easily later. + */ + if (HAVE_OPT(SUBBLOCK)) { + int ct = STACKCT_OPT( SUBBLOCK); + tCC** ppz = STACKLST_OPT(SUBBLOCK); + + /* + * FOR each SUBBLOCK argument, + * DO condense each name list to be a list of names + * separated by a single space and NUL terminated. + */ + do { + *ppz = fixupSubblockString(*ppz); + ppz++; + } while (--ct > 0); + } + + if (! HAVE_OPT(INPUT)) + SET_OPT_INPUT("-"); + + set_modtime(); + + /* + * IF the output is to have order AND it is to be based on a file, + * THEN load the contents of that file. + * IF we cannot load the file, + * THEN it must be new or empty. Allocate several K to start. + */ + if ( HAVE_OPT(ORDERING) + && (OPT_ARG(ORDERING) != NULL)) { + tSCC zIndexPreamble[] = + "# -*- buffer-read-only: t -*- vi: set ro:\n" + "#\n# DO NOT EDIT THIS FILE - it is auto-edited by getdefs\n"; + + pzIndexText = loadFile(OPT_ARG(ORDERING)); + if (pzIndexText == NULL) { + pzIndexText = pzEndIndex = pzIndexEOF = malloc((size_t)0x4000); + indexAlloc = 0x4000; + pzEndIndex += sprintf(pzEndIndex, "%s", zIndexPreamble); + } else { + pzEndIndex = pzIndexEOF = pzIndexText + strlen(pzIndexText); + indexAlloc = (pzEndIndex - pzIndexText) + 1; + } + + /* + * We map the name entries to a connonical form. + * By default, everything is mapped to lower case already. + * This call will map these three characters to '_'. + */ + strequate("_-^"); + } + + { + char const * pz = OPT_ARG(SRCFILE); + if ((pz == NULL) || (*pz == NUL)) + OPT_ARG(SRCFILE) = "srcfile"; + + pz = OPT_ARG(LINENUM); + if ((pz == NULL) || (*pz == NUL)) + OPT_ARG(LINENUM) = "linenum"; + } + + { + tSCC zAgNameChars[] = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789" "_-^"; + tSCC zUserNameChs[] = ":.$%*!~<>&@"; + tCC* p = zAgNameChars; + + while (*p) + zUserNameCh[(unsigned)(*p++)] = 3; + + p = zUserNameChs; + while (*p) + zUserNameCh[(unsigned)(*p++)] = 1; + } +} + + +/* emacs + * Local Variables: + * mode: C + * c-file-style: "stroustrup" + * indent-tabs-mode: nil + * End: + * end of getdefs/gdinit.c */ |