diff options
Diffstat (limited to 'getdefs/getdefs.c')
-rw-r--r-- | getdefs/getdefs.c | 1196 |
1 files changed, 1196 insertions, 0 deletions
diff --git a/getdefs/getdefs.c b/getdefs/getdefs.c new file mode 100644 index 0000000..26dd5d1 --- /dev/null +++ b/getdefs/getdefs.c @@ -0,0 +1,1196 @@ +/** + * \file getdefs.c + * + * getdefs Copyright (c) 1999-2012 by Bruce Korb - all rights reserved + * + * Time-stamp: "2012-04-14 11:15:08 bkorb" + * Author: Bruce Korb <bkorb@gnu.org> + * + * 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 zBogusDef[] = "Bogus definition:\n%s\n"; + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Forward procedure pointers + */ +typedef int (compar_func)(const void *, const void *); +static compar_func compar_text, compar_defname; + +/* START-STATIC-FORWARD */ +static char* +assignIndex(char* pzOut, char* pzDef); + +static int +awaitAutogen(void); + +static void +buildDefinition(char * pzDef, char const * pzFile, int line, char * pzOut); + +static tSuccess +buildPreamble(char ** ppzDef, char ** ppzOut, char const * pzFile, int line); + +static int +compar_defname(const void* p1, const void* p2); + +static int +compar_text(const void* p1, const void* p2); + +static void +doPreamble(FILE* outFp); + +static void +printEntries(FILE* fp); + +static void +processFile(char const * pzFile); + +static void +set_first_idx(void); + +static FILE* +open_ag_file(char ** pzBase); + +static FILE* +open_ag_proc_pipe(char ** pzBase); + +static void +exec_autogen(char ** pzBase); + +static FILE* +startAutogen(void); + +static void +update_db(void); +/* END-STATIC-FORWARD */ + +#ifndef HAVE_STRSIGNAL +# include "compat/strsignal.c" +#endif + +#ifndef HAVE_CHMOD +# include "compat/chmod.c" +#endif + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * MAIN + */ +int +main(int argc, char ** argv) +{ + FILE* outFp; + + optionProcess(&getdefsOptions, argc, argv); + validateOptions(); + + outFp = startAutogen(); + + doPreamble(outFp); + + /* + * Process each input file + */ + { + int ct = STACKCT_OPT(INPUT); + char const ** ppz = STACKLST_OPT(INPUT); + + do { + processFile(*ppz++); + } while (--ct > 0); + } + + /* + * IF we don't have an ordering file, but we do have a "first index", + * THEN alphabetize by definition name. + */ + if ((pzIndexText == NULL) && HAVE_OPT(FIRST_INDEX)) { + qsort((void*)papzBlocks, blkUseCt, sizeof(char*), compar_defname); + set_first_idx(); + } + + else if (ENABLED_OPT(ORDERING) && (blkUseCt > 1)) + qsort((void*)papzBlocks, blkUseCt, sizeof(char*), &compar_text); + + printEntries(outFp); +#ifdef HAVE_FCHMOD + fchmod(fileno(outFp), S_IRUSR|S_IRGRP|S_IROTH); +#endif + fclose(outFp); + + /* + * IF output is to a file + * THEN set the permissions and modification times + */ + if ( (WHICH_IDX_AUTOGEN == INDEX_OPT_OUTPUT) + && (outFp != stdout) ) { + struct utimbuf tbuf; + tbuf.actime = time((time_t*)NULL); + tbuf.modtime = modtime + 1; + utime(OPT_ARG(OUTPUT), &tbuf); +#ifndef HAVE_CHMOD + chmod(OPT_ARG(OUTPUT), S_IRUSR|S_IRGRP|S_IROTH); +#endif + } + + /* + * IF we are keeping a database of indexes + * AND we have augmented the contents, + * THEN append the new entries to the file. + */ + if ((pzIndexText != NULL) && (pzEndIndex != pzIndexEOF)) + update_db(); + + if (agPid != -1) + return awaitAutogen(); + + return EXIT_SUCCESS; +} + + +/* + * assignIndex + */ +static char* +assignIndex(char* pzOut, char* pzDef) +{ + char* pzMatch; + size_t len = strlen(pzDef); + int idx; + + /* + * Make the source text all lower case and map + * '-', '^' and '_' characters to '_'. + */ + strtransform(pzDef, pzDef); + + /* + * IF there is already an entry, + * THEN put the index into the output. + */ + pzMatch = strstr(pzIndexText, pzDef); + if (pzMatch != NULL) { + pzMatch += len; + while (isspace(*pzMatch)) pzMatch++; + while ((*pzOut++ = *pzMatch++) != ']') ; + return pzOut; + } + + /* + * We have a new entry. Make sure we have room for it + * in our in-memory string + */ + if (((pzEndIndex - pzIndexText) + len + 64 ) > indexAlloc) { + char* pz; + indexAlloc += 0x1FFF; + indexAlloc &= ~0x0FFF; + pz = (char*)realloc((void*)pzIndexText, indexAlloc); + if (pz == NULL) { + fputs("Realloc of index text failed\n", stderr); + exit(EXIT_FAILURE); + } + + /* + * IF the allocation moved, + * THEN adjust all our pointers. + */ + if (pz != pzIndexText) { + pzIndexEOF = pz + (pzIndexEOF - pzIndexText); + pzEndIndex = pz + (pzEndIndex - pzIndexText); + pzIndexText = pz; + } + } + + /* + * IF there are no data in our text database, + * THEN use default index. + */ + if (pzEndIndex == pzIndexText) + idx = OPT_VALUE_FIRST_INDEX; + else do { + char* pz = strrchr(pzDef, ' '); + *pz = NUL; + len = strlen(pzDef); + + /* + * Find the last entry for the current category of entries + */ + pzMatch = strstr(pzIndexText, pzDef); + if (pzMatch == NULL) { + /* + * No entries for this category. Use default index. + */ + idx = OPT_VALUE_FIRST_INDEX; + *pz = ' '; + break; + } + + for (;;) { + char* pzn = strstr(pzMatch + len, pzDef); + if (pzn == NULL) + break; + pzMatch = pzn; + } + + /* + * Skip forward to the '[' character and convert the + * number that follows to a long. + */ + *pz = ' '; + pzMatch = strchr(pzMatch + len, '['); + idx = strtol(pzMatch+1, (char**)NULL, 0)+1; + } while (false); + + /* + * Add the new entry to our text database and + * place a copy of the value into our output. + */ + pzEndIndex += sprintf(pzEndIndex, "%-40s [%d]\n", pzDef, idx); + pzOut += sprintf(pzOut, "[%d]", idx); + + return pzOut; +} + + +/* + * awaitAutogen + */ +static int +awaitAutogen(void) +{ + int status; + waitpid(agPid, &status, 0); + if (WIFEXITED(status)) { + status = WEXITSTATUS(status); + if (status != EXIT_SUCCESS) { + fprintf(stderr, "ERROR: %s exited with status %d\n", + pzAutogen, status); + } + return status; + } + + if (WIFSIGNALED( status )) { + status = WTERMSIG( status ); + fprintf(stderr, "ERROR: %s exited due to %d signal (%s)\n", + pzAutogen, status, strsignal(status)); + } + else + fprintf(stderr, "ERROR: %s exited due to unknown reason %d\n", + pzAutogen, status); + + return EXIT_FAILURE; +} + + +/* + * buildDefinition + */ +static void +buildDefinition(char * pzDef, char const * pzFile, int line, char * pzOut) +{ + static char const zSrcFile[] = " %s = '%s';\n"; + static char const zLineNum[] = " %s = '%d';\n"; + + bool these_are_global_defs; + tSuccess preamble; + int re_res; + char* pzNextDef = NULL; + regmatch_t match[2]; + + if (*pzDef == '*') { + these_are_global_defs = true; + strcpy(pzOut, zGlobal); + pzOut += sizeof(zGlobal)-1; + pzOut += sprintf(pzOut, zLineId, line, pzFile); + + pzDef = strchr(pzDef, '\n'); + preamble = PROBLEM; + + } else { + these_are_global_defs = false; + preamble = buildPreamble(&pzDef, &pzOut, pzFile, line); + if (FAILED(preamble)) { + *pzOut = NUL; + return; + } + } + + /* + * FOR each attribute for this entry, ... + */ + for (;;) { + /* + * Find the next attribute regular expression + */ + re_res = regexec(&attrib_re, pzDef, COUNT(match), match, 0); + switch (re_res) { + case 0: + /* + * NUL-terminate the current attribute. + * Set the "next" pointer to the start of the next attribute name. + */ + pzDef[ match[0].rm_so ] = NUL; + if (pzNextDef != NULL) + pzOut = emitDefinition(pzNextDef, pzOut); + pzNextDef = pzDef = pzDef + match[1].rm_so; + break; + + case REG_NOMATCH: + /* + * No more attributes. + */ + if (pzNextDef == NULL) { + *pzOut++ = '\n'; *pzOut++ = '#'; + sprintf(pzOut, zNoData, pzFile, line); + fputs(pzOut, stderr); + pzOut += strlen(pzOut); + return; + } + + pzOut = emitDefinition(pzNextDef, pzOut); + goto eachAttrDone; + break; + + default: + { + char zRER[ MAXNAMELEN ]; + static char const zErr[] = "error %d (%s) finding `%s' in\n%s\n\n"; + regerror(re_res, &attrib_re, zRER, sizeof(zRER)); + *pzOut++ = '\n'; + *pzOut++ = '#'; + sprintf(pzOut, zErr, re_res, zRER, zAttribRe, pzDef); + fprintf(stderr, "getdefs: %s", zErr); + return; + } + } + } eachAttrDone:; + + if (these_are_global_defs) { + *pzOut = NUL; + return; + } + + if (HAVE_OPT(COMMON_ASSIGN)) { + int ct = STACKCT_OPT(COMMON_ASSIGN); + char const ** ppz = STACKLST_OPT(COMMON_ASSIGN); + do { + pzOut += sprintf(pzOut, " %s;\n", *ppz++); + } while (--ct > 0); + } + + if (HAVE_OPT(SRCFILE)) + pzOut += sprintf(pzOut, zSrcFile, OPT_ARG(SRCFILE), pzFile); + + if (HAVE_OPT(LINENUM)) + pzOut += sprintf(pzOut, zLineNum, OPT_ARG(LINENUM), line); + + /* + * IF the preamble had a problem, it is because it could not + * emit the final "#endif\n" directive. Do that now. + */ + if (HADGLITCH(preamble)) + strcpy(pzOut, "};\n#endif\n"); + else strcpy(pzOut, "};\n"); +} + + +/* + * buildPreamble + */ +static tSuccess +buildPreamble(char ** ppzDef, char ** ppzOut, char const * pzFile, int line) +{ + char * pzDef = *ppzDef; + char * pzOut = *ppzOut; + + char zDefText[ MAXNAMELEN ]; + char * pzDefText = zDefText; + char zNameText[ MAXNAMELEN ]; + char * pzNameText = zNameText; + char * pzIfText = NULL; + + /* + * Copy out the name of the entry type + */ + *pzDefText++ = '`'; + while (isalnum(*pzDef) || (*pzDef == '_') || (*pzDef == '.') + || (*pzDef == '[') || (*pzDef == ']')) + *pzDefText++ = *pzDef++; + + *pzDefText = NUL; + + pzDef += strspn(pzDef, "* \t"); + + /* + * Copy out the name for this entry of the above entry type. + */ + while (isalnum(*pzDef) || (*pzDef == '_')) + *pzNameText++ = *pzDef++; + *pzNameText = NUL; + + if ( (zDefText[1] == NUL) + || (zNameText[0] == NUL) ) { + fprintf(stderr, zNoData, pzFile, line); + return FAILURE; + } + + pzDef += strspn(pzDef, " \t"); + + /* + * IF these names are followed by a comma and an "if" clause, + * THEN we emit the definition with "#if..."/"#endif" around it + */ + if (*pzDef == ',') { + pzDef += strspn(pzDef+1, " \t")+1; + if ((pzDef[0] == 'i') && (pzDef[1] == 'f')) + pzIfText = pzDef; + } + + pzDef = strchr(pzDef, '\n'); + if (pzDef == NULL) { + fprintf(stderr, zNoData, pzFile, line); + return FAILURE; + } + + *pzDef = NUL; + + /* + * Now start the output. First, the "#line" directive, + * then any "#ifdef..." line and finally put the + * entry type name into the output. + */ + pzOut += sprintf(pzOut, zLineId, line, pzFile); + if (pzIfText != NULL) + pzOut += sprintf(pzOut, "#%s\n", pzIfText); + { + char* pz = zDefText+1; + while (*pz != NUL) + *pzOut++ = *pz++; + } + + /* + * IF we are indexing the entries, + * THEN build the string by which we are indexing + * and insert the index into the output. + */ + if (pzIndexText != NULL) { + sprintf(pzDefText, " %s'", zNameText); + pzOut = assignIndex(pzOut, zDefText); + } + + /* + * Now insert the name with a consistent name string prefix + * that we use to locate the sort key later. + */ + pzOut += sprintf(pzOut, "%s%s';\n", zNameTag, zNameText); + *ppzOut = pzOut; + *ppzDef = pzDef; + *pzDef = '\n'; /* restore the newline. Used in pattern match */ + + /* + * Returning "PROBLEM" means the caller must emit the "#endif\n" + * at the end of the definition. + */ + return (pzIfText != NULL) ? PROBLEM : SUCCESS; +} + + +/* + * compar_defname + */ +static int +compar_defname(const void* p1, const void* p2) +{ + char const * pzS1 = *(char const * const *)p1; + char const * pz1 = strstr(pzS1, zNameTag); + char const * pzS2 = *(char const * const *)p2; + char const * pz2 = strstr(pzS2, zNameTag); + + if (pz1 == NULL) { + if (strncmp(*(char const * const *)p1, zGlobal, sizeof(zGlobal)-1) == 0) + return -1; + + die(zBogusDef, *(char const * const *)p1); + } + + if (pz2 == NULL) { + if (strncmp(*(char const * const *)p2, zGlobal, sizeof(zGlobal)-1) == 0) + return 1; + + die(zBogusDef, *(char const * const *)p2); + } + + /* + * Back up to the name of the definition + */ + while ((pz1 > pzS1) && (*--pz1 != '\n')) ; + while ((pz2 > pzS2) && (*--pz2 != '\n')) ; + + return strcmp(pz1, pz2); +} + + +/* + * compar_text + * + * merely returns the relative ordering of two input strings. + * The arguments are pointers to pointers to NUL-terminated strings. + * IF the definiton was mal-formed, an error message was printed + * earlier. When we get here, we wil fail to find the "zNameTag" + * string and EXIT_FAILURE. + */ +static int +compar_text(const void* p1, const void* p2) +{ + char* pz1 = strstr(*(char const * const *)p1, zNameTag); + char* pe1; + char* pz2 = strstr(*(char const * const *)p2, zNameTag); + char* pe2; + int res; + + if (pz1 == NULL) { + if (strncmp(*(char const * const *)p1, zGlobal, sizeof(zGlobal)-1) == 0) + return -1; + + die(zBogusDef, *(char const * const *)p1); + } + + if (pz2 == NULL) { + if (strncmp(*(char const * const *)p2, zGlobal, sizeof(zGlobal)-1) == 0) + return 1; + + die(zBogusDef, *(char const * const *)p2); + } + + pz1 += sizeof(zNameTag)-1; + pe1 = strchr(pz1, '\''); + + if (pe1 == NULL) + die(zBogusDef, *(char const * const *)p1); + + pz2 += sizeof(zNameTag)-1; + pe2 = strchr(pz2, '\''); + + if (pe2 == NULL) + die(zBogusDef, *(char const * const *)p2); + + *pe1 = *pe2 = NUL; + + /* + * We know ordering is enabled because we only get called when + * it is enabled. If the option was also specified, then + * we sort without case sensitivity (and we compare '-', '_' + * and '^' as being equal as well). Otherwise, we do a + * strict string comparison. + */ + if (HAVE_OPT(ORDERING)) + res = streqvcmp(pz1, pz2); + else res = strcmp(pz1, pz2); + *pe1 = *pe2 = '\''; + return res; +} + + +/* + * doPreamble + */ +static void +doPreamble(FILE* outFp) +{ + /* + * Emit the "autogen definitions xxx;" line + */ + fprintf(outFp, zAgDef, OPT_ARG(TEMPLATE)); + + if (HAVE_OPT(FILELIST)) { + static char const zFmt[] = "%-12s = '%s';\n"; + char const * pzName = OPT_ARG(FILELIST); + + if ((pzName == NULL) || (*pzName == NUL)) + pzName = "infile"; + + if (HAVE_OPT(INPUT)) { + int ct = STACKCT_OPT(INPUT); + char const ** ppz = STACKLST_OPT(INPUT); + + do { + fprintf(outFp, zFmt, pzName, *ppz++); + } while (--ct > 0); + } + + if (HAVE_OPT(COPY)) { + int ct = STACKCT_OPT(COPY); + char const ** ppz = STACKLST_OPT(COPY); + + do { + fprintf(outFp, zFmt, pzName, *ppz++); + } while (--ct > 0); + } + fputc('\n', outFp); + } + + /* + * IF there are COPY files to be included, + * THEN emit the '#include' directives + */ + if (HAVE_OPT(COPY)) { + int ct = STACKCT_OPT(COPY); + char const ** ppz = STACKLST_OPT(COPY); + do { + fprintf(outFp, "#include %s\n", *ppz++); + } while (--ct > 0); + fputc('\n', outFp); + } + + /* + * IF there are global assignments, then emit them + * (these do not get sorted, so we write directly now.) + */ + if (HAVE_OPT(ASSIGN)) { + int ct = STACKCT_OPT(ASSIGN); + char const ** ppz = STACKLST_OPT(ASSIGN); + do { + fprintf(outFp, "%s;\n", *ppz++); + } while (--ct > 0); + fputc('\n', outFp); + } +} + + +/* + * loadFile + */ +LOCAL char* +loadFile(char const * pzFname) +{ + FILE* fp = fopen(pzFname, "r" FOPEN_BINARY_FLAG); + int res; + char* pzText; + char* pzRead; + size_t rdsz; + + if (fp == (FILE*)NULL) + return NULL; + /* + * Find out how much data we need to read. + * And make sure we are reading a regular file. + */ + { + struct stat stb; + res = fstat(fileno(fp), &stb); + if (res != 0) + fserr_die("stat-ing %s\n", pzFname); + + if (! S_ISREG(stb.st_mode)) { + fprintf(stderr, "error file %s is not a regular file\n", + pzFname); + exit(EXIT_FAILURE); + } + rdsz = stb.st_size; + if (rdsz < 16) + die("Error file %s only contains %d bytes.\n" + "\tit cannot contain autogen definitions\n", + pzFname, (int)rdsz); + } + + /* + * Allocate the space we need for the ENTIRE file. + */ + pzRead = pzText = (char*)malloc(rdsz + 1); + if (pzText == NULL) + die("Error: could not allocate %d bytes\n", (int)rdsz + 1); + + /* + * Read as much as we can get until we have read the file. + */ + do { + size_t rdct = fread((void*)pzRead, (size_t)1, rdsz, fp); + + if (rdct == 0) + fserr_die("reading file %s\n", pzFname); + + pzRead += rdct; + rdsz -= rdct; + } while (rdsz > 0); + + *pzRead = NUL; + fclose(fp); + return pzText; +} + + +/* + * printEntries + */ +static void +printEntries(FILE* fp) +{ + int ct = blkUseCt; + char** ppz = papzBlocks; + + if (ct == 0) + exit(EXIT_FAILURE); + + for (;;) { + char* pz = *(ppz++); + fputs(pz, fp); + free((void*)pz); + if (--ct <= 0) + break; + fputc('\n', fp); + } + free((void*)papzBlocks); +} + + +/* + * processFile + */ +static void +processFile(char const * pzFile) +{ + char* pzText = loadFile(pzFile); /* full text */ + char* pzScan; /* Scanning Pointer */ + char* pzDef; /* Def block start */ + char* pzNext; /* start next search */ + char* pzDta; /* data value */ + int lineNo = 1; + char* pzOut; + regmatch_t matches[MAX_SUBMATCH+1]; + + if (pzText == NULL) + fserr_die("read opening %s\n", pzFile); + + processEmbeddedOptions(pzText); + pzNext = pzText; + + while (pzScan = pzNext, + regexec(&define_re, pzScan, COUNT(matches), matches, 0) == 0) { + + static char const zNoEnd[] = + "Error: definition in %s at line %d has no end\n"; + static char const zNoSubexp[] = + "Warning: entry type not found on line %d in %s:\n\t%s\n"; + + int linesInDef = 0; + + /* + * Make sure there is a subexpression match!! + */ + if (matches[1].rm_so == -1) { + char* pz = NULL; + char ch = NUL; + + pzDef = pzScan + matches[0].rm_so; + if (strlen(pzDef) > 30) { + pz = pzDef + 30; + ch = *pz; + *pz = NUL; + } + + fprintf(stderr, zNoSubexp, lineNo, pzFile, pzDef); + if (pz != NULL) + *pz = ch; + continue; + } + + pzDef = pzScan + matches[0].rm_so + sizeof("/*=") - 1; + pzNext = strstr(pzDef, "=*/"); + if (pzNext == NULL) + die(zNoEnd, pzFile, lineNo); + + *pzNext = NUL; + pzNext += 3; + /* + * Count the number of lines skipped to the start of the def. + */ + for (;;) { + pzScan = strchr(pzScan, '\n'); + if (pzScan++ == NULL) + break; + if (pzScan >= pzDef) + break; + lineNo++; + } + + pzOut = pzDta = (char*)malloc(2 * strlen(pzDef) + 8000); + + /* + * Count the number of lines in the definition itself. + * It will find and stop on the "=* /\n" line. + */ + pzScan = pzDef; + for (;;) { + pzScan = strchr(pzScan, '\n'); + if (pzScan++ == NULL) + break; + linesInDef++; + } + + /* + * OK. We are done figuring out where the boundaries of the + * definition are and where we will resume our processing. + */ + buildDefinition(pzDef, pzFile, lineNo, pzOut); + pzDta = (char*)realloc((void*)pzDta, strlen(pzDta) + 1); + lineNo += linesInDef; + + if (++blkUseCt > blkAllocCt) { + blkAllocCt += 32; + papzBlocks = (char**)realloc((void*)papzBlocks, + blkAllocCt * sizeof(char*)); + if (papzBlocks == (char**)NULL) + die("Realloc error for %d pointers\n", (int)blkAllocCt); + } + papzBlocks[ blkUseCt-1 ] = pzDta; + } + + free((void*)pzText); +} + + +/* + * set_first_idx + * + * Go through all our different kinds of defines. On the first occurrence + * of each different name, check for an index value. If not supplied, + * then insert ``[OPT_VALUE_FIRST_INDEX]'' after the object name. + */ +static void +set_first_idx(void) +{ + char zNm[ 128 ] = { NUL }; + int nmLn = 1; + int ct = blkUseCt; + char** ppz = papzBlocks; + + if (ct == 0) + exit(EXIT_FAILURE); + + for (; --ct >= 0; ppz++) { + char * pzOld = *ppz; + int changed = (strneqvcmp(pzOld, zNm, nmLn) != 0); + char * pzNew; + + /* + * IF the name still matches, then check the following character. + * If it is whitespace or an open bracket, then + * it's the old type. Continue to the next entry. + */ + if (! changed) { + if (isspace(pzOld[ nmLn ]) || (pzOld[nmLn] == '[')) + continue; + } + + pzNew = zNm; + nmLn = 0; + while (isalnum(*pzOld) + || (*pzOld == '_') || (*pzOld == '-') || (*pzOld == '^')) { + nmLn++; + *(pzNew++) = *(pzOld++); + } + *pzNew = NUL; + + /* + * IF the source has specified its own index, then do not + * supply our own new one. + */ + if (*pzOld != '[') { + pzNew = (char*)malloc(strlen(pzOld) + nmLn + 10); + sprintf(pzNew, "%s[%d]%s", zNm, + (int)OPT_VALUE_FIRST_INDEX, pzOld); + free((void*)(*ppz)); + *ppz = pzNew; + } + } +} + +static FILE* +open_ag_file(char ** pzBase) +{ + switch (WHICH_IDX_AUTOGEN) { + case INDEX_OPT_OUTPUT: + { + static char const zFileFmt[] = " * %s\n"; + FILE* fp; + + if (*pzBase != NULL) + free(*pzBase); + + if (strcmp(OPT_ARG(OUTPUT), "-") == 0) + return stdout; + + unlink(OPT_ARG(OUTPUT)); + fp = fopen(OPT_ARG(OUTPUT), "w" FOPEN_BINARY_FLAG); + fprintf(fp, zDne, OPT_ARG(OUTPUT)); + + if (HAVE_OPT(INPUT)) { + int ct = STACKCT_OPT(INPUT); + char const ** ppz = STACKLST_OPT(INPUT); + do { + fprintf(fp, zFileFmt, *ppz++); + } while (--ct > 0); + } + + fputs(" */\n", fp); + return fp; + } + + case INDEX_OPT_AUTOGEN: + if (! ENABLED_OPT(AUTOGEN)) { + if (*pzBase != NULL) + free(*pzBase); + + return stdout; + } + + if ( ( OPT_ARG(AUTOGEN) != NULL) + && (*OPT_ARG(AUTOGEN) != NUL )) + pzAutogen = OPT_ARG(AUTOGEN); + + break; + } + + return NULL; +} + +static FILE* +open_ag_proc_pipe(char ** pzBase) +{ + FILE * agFp; + + int pfd[2]; + + if (pipe(pfd) != 0) + fserr_die("creating pipe\n"); + + agPid = fork(); + + switch (agPid) { + case 0: + /* + * We are the child. Close the write end of the pipe + * and force STDIN to become the read end. + */ + close(pfd[1]); + if (dup2(pfd[0], STDIN_FILENO) != 0) + fserr_die("dup pipe[0]\n"); + break; + + case -1: + fserr_die("on fork()\n"); + + default: + /* + * We are the parent. Close the read end of the pipe + * and get a FILE* pointer for the write file descriptor + */ + close(pfd[0]); + agFp = fdopen(pfd[1], "w" FOPEN_BINARY_FLAG); + if (agFp == (FILE*)NULL) + fserr_die("fdopening pipe[1]\n"); + free(*pzBase); + return agFp; + } + + return NULL; +} + +static void +exec_autogen(char ** pzBase) +{ + char const ** paparg; + char const ** pparg; + int argCt = 5; + + /* + * IF we don't have template search directories, + * THEN allocate the default arg counter of pointers and + * set the program name into it. + * ELSE insert each one into the arg list. + */ + if (! HAVE_OPT(AGARG)) { + paparg = pparg = (char const **)malloc(argCt * sizeof(char*)); + *pparg++ = pzAutogen; + + } else { + int ct = STACKCT_OPT(AGARG); + char const ** ppz = STACKLST_OPT(AGARG); + + argCt += ct; + paparg = pparg = (char const **)malloc(argCt * sizeof(char*)); + *pparg++ = pzAutogen; + + do { + *pparg++ = *ppz++; + } while (--ct > 0); + } + + *pparg++ = *pzBase; + *pparg++ = "--"; + *pparg++ = "-"; + *pparg++ = NULL; + +#ifdef DEBUG + fputc('\n', stderr); + pparg = paparg; + for (;;) { + fputs(*pparg++, stderr); + if (*pparg == NULL) + break; + fputc(' ', stderr); + } + fputc('\n', stderr); + fputc('\n', stderr); +#endif + + execvp(pzAutogen, (char**)(void*)paparg); + fserr_die("exec of %s %s %s %s\n", paparg[0], paparg[1], paparg[2], + paparg[3]); +} + +/* + * startAutogen + */ +static FILE* +startAutogen(void) +{ + char* pz; + FILE* agFp; + char* pzBase = NULL; + + /* + * Compute the base name. + * + * If an argument was specified, use that without question. + * IF a definition pattern is supplied, and it looks like + * a normal name, then use that. + * If neither of these work, then use the current directory name. + */ + if (HAVE_OPT(BASE_NAME)) { + pzBase = malloc(strlen(OPT_ARG(BASE_NAME)) + 3); + strcpy(pzBase, "-b"); + strcpy(pzBase+2, OPT_ARG(BASE_NAME)); + } + else { + /* + * IF we have a definition name pattern, + * THEN copy the leading part that consists of name-like characters. + */ + if (HAVE_OPT(DEFS_TO_GET)) { + char const * pzS = OPT_ARG(DEFS_TO_GET); + pzBase = malloc(strlen(pzS) + 3); + strcpy(pzBase, "-b"); + + pz = pzBase + 2; + while (isalnum(*pzS) || (*pzS == '_')) + *pz++ = *pzS++; + if (pz == pzBase + 2) { + free(pzBase); + pzBase = NULL; + } + else + *pz = NUL; + } + + /* + * IF no pattern or it does not look like a name, ... + */ + if (pzBase == NULL) { + char zSrch[ MAXPATHLEN ]; + if (getcwd(zSrch, sizeof(zSrch)) == NULL) + fserr_die("on getcwd\n"); + + pz = strrchr(zSrch, '/'); + if (pz == NULL) + pz = zSrch; + else pz++; + pzBase = malloc(strlen(pz) + 3); + strcpy(pzBase, "-b"); + strcpy(pzBase+2, pz); + } + } + + /* + * For our template name, we take the argument (if supplied). + * If not, then whatever we decided our base name was will also + * be our template name. + */ + if (! HAVE_OPT(TEMPLATE)) + SET_OPT_TEMPLATE(strdup(pzBase+2)); + + /* + * Now, what kind of output have we? + * If it is a file, open it up and return. + * If it is an alternate autogen program, + * then set it to whatever the argument said it was. + * If the option was not supplied, we default to + * whatever we set the "pzAutogen" pointer to above. + */ + if (HAVE_OPT(AUTOGEN)) { + agFp = open_ag_file(&pzBase); + if (agFp != NULL) + return agFp; + } + + agFp = open_ag_proc_pipe(&pzBase); + if (agFp != NULL) + return agFp; + + exec_autogen(&pzBase); + return (FILE*)NULL; +} + + +/* + * update_db + */ +static void +update_db(void) +{ + FILE* fp; + + if (chmod(OPT_ARG(ORDERING), 0666) == 0) { + fp = fopen(OPT_ARG(ORDERING), "a" FOPEN_BINARY_FLAG); + + } else { + unlink(OPT_ARG(ORDERING)); + fp = fopen(OPT_ARG(ORDERING), "w" FOPEN_BINARY_FLAG); + pzIndexEOF = pzIndexText; + } + + if (fp == (FILE*)NULL) + fserr_die("opening %s for write/append\n", OPT_ARG(ORDERING)); + + fwrite(pzIndexEOF, (size_t)(pzEndIndex - pzIndexEOF), (size_t)1, fp); +#ifdef HAVE_FCHMOD + fchmod(fileno(fp), 0444); + fclose(fp); +#else + fclose(fp); + chmod(OPT_ARG(ORDERING), 0444); +#endif +} + +/* emacs + * Local Variables: + * mode: C + * c-file-style: "stroustrup" + * indent-tabs-mode: nil + * End: + * end of getdefs/getdefs.c */ |