/** * Starting with the current directory, search the directory * list trying to find the base template file name. */ LOCAL tTemplate * loadTemplate(char const * pzFileName, char const * referrer) { static tmap_info_t mapInfo; static char zRealFile[ AG_PATH_MAX ]; /* * Find the template file somewhere */ { static char const * const apzSfx[] = { "tpl", "agl", NULL }; if (! SUCCESSFUL(findFile(pzFileName, zRealFile, apzSfx, referrer))) { errno = ENOENT; AG_CANT("map data file", pzFileName); } } /* * Make sure the specified file is a regular file. * Make sure the output time stamp is at least as recent. */ { struct stat stbf; if (stat(zRealFile, &stbf) != 0) AG_CANT("stat file", pzFileName); if (! S_ISREG(stbf.st_mode)) { errno = EINVAL; AG_CANT("not regular file", pzFileName); } if (outTime <= stbf.st_mtime) outTime = stbf.st_mtime + 1; } text_mmap(zRealFile, PROT_READ|PROT_WRITE, MAP_PRIVATE, &mapInfo); if (TEXT_MMAP_FAILED_ADDR(mapInfo.txt_data)) AG_ABEND(aprf("Could not open template '%s'", zRealFile)); if (pfDepends != NULL) append_source_name(zRealFile); /* * Process the leading pseudo-macro. The template proper * starts immediately after it. */ { tMacro * pSaveMac = pCurMacro; tTemplate * pRes; pCurMacro = NULL; pRes = digest_pseudo_macro(&mapInfo, zRealFile); pCurMacro = pSaveMac; text_munmap(&mapInfo); return pRes; } }
/** * This directive will insert definitions from another file into * the current collection. If the file name is adorned with * double quotes or angle brackets (as in a C program), then the * include is ignored. */ char * doDir_include(directive_enum_t id, char const * dir, char * scan_next) { static char const * const apzSfx[] = { DIRECT_INC_DEF_SFX, NULL }; scan_ctx_t * new_ctx; size_t inc_sz; char full_name[ AG_PATH_MAX + 1 ]; (void)id; dir = SPN_WHITESPACE_CHARS(dir); /* * Ignore C-style includes. This allows "C" files to be processed * for their "#define"s. */ if ((*dir == '"') || (*dir == '<')) return scan_next; if (! SUCCESSFUL( find_file(dir, full_name, apzSfx, cctx->scx_fname))) { errno = ENOENT; fswarn("search for", cctx->scx_fname); return scan_next; } /* * Make sure the specified file is a regular file and we can get * the correct size for it. */ inc_sz = file_size(full_name); if (inc_sz == 0) return scan_next; /* * Get the space for the output data and for context overhead. * This is an extra allocation and copy, but easier than rewriting * 'loadData()' for this special context. */ { size_t sz = sizeof(scan_ctx_t) + 4 + inc_sz; new_ctx = (scan_ctx_t *)AGALOC(sz, "inc def head"); memset(VOIDP(new_ctx), 0, sz); new_ctx->scx_line = 1; } /* * Link it into the context stack */ cctx->scx_scan = scan_next; new_ctx->scx_next = cctx; cctx = new_ctx; AGDUPSTR(new_ctx->scx_fname, full_name, "def file"); new_ctx->scx_scan = new_ctx->scx_data = scan_next = (char *)(new_ctx + 1); /* * Read all the data. Usually in a single read, but loop * in case multiple passes are required. */ { FILE * fp = fopen(full_name, "r" FOPEN_TEXT_FLAG); char * pz = scan_next; if (fp == NULL) AG_CANT(DIRECT_INC_CANNOT_OPEN, full_name); if (dep_fp != NULL) add_source_file(full_name); do { size_t rdct = fread(VOIDP(pz), (size_t)1, inc_sz, fp); if (rdct == 0) AG_CANT(DIRECT_INC_CANNOT_READ, full_name); pz += rdct; inc_sz -= rdct; } while (inc_sz > 0); fclose(fp); *pz = NUL; } return scan_next; }
/** * Prepare the raft of environment variables. * This runs before Guile starts and grabs the value for LD_LIBRARY_PATH. * Guile likes to fiddle that. When we run initialize(), we will force it * to match what we currently have. Additionally, force our environment * to be "C" and export all the variables that describe our system. */ LOCAL void prep_env(void) { /* * as of 2.0.2, Guile will fiddle with strings all on its own accord. * Coerce the environment into being POSIX ASCII strings so it keeps * its bloody stinking nose out of our data. */ putenv(C(char *, LC_ALL_IS_C)); /* * If GUILE_WARN_DEPRECATED has not been defined, then likely we are * not in a development environment and likely we don't want to give * our users any angst. */ if (getenv(GUILE_WARN_DEP_STR) == NULL) putenv(C(char *, GUILE_WARN_NO_ENV)); ld_lib_path = getenv(LD_LIB_PATH_STR); if (ld_lib_path == NULL) { ld_lib_path = LD_LIB_PATH_PFX; } else { size_t psz = strlen(ld_lib_path) + 1; char * p = AGALOC(LD_LIB_PATH_PFX_LEN + psz, "lp"); memcpy(p, LD_LIB_PATH_PFX, LD_LIB_PATH_PFX_LEN); memcpy(p + LD_LIB_PATH_PFX_LEN, ld_lib_path, psz); ld_lib_path = p; } /* * Set the last resort search directories first (lowest priority) * The lowest of the low is the config time install data dir. * Next is the *current* directory of this executable. * Last (highest priority) of the low priority is the library data dir. */ SET_OPT_TEMPL_DIRS(DFT_TPL_DIR_DATA); SET_OPT_TEMPL_DIRS(DFT_TPL_DIR_RELATIVE); SET_OPT_TEMPL_DIRS(LIBDATADIR); { char z[ SCRIBBLE_SIZE+8 ] = "__autogen__"; #if defined(HAVE_SOLARIS_SYSINFO) static const int nm[] = { SI_SYSNAME, SI_HOSTNAME, SI_ARCHITECTURE, SI_HW_PROVIDER, #ifdef SI_PLATFORM SI_PLATFORM, #endif SI_MACHINE }; int ix; long sz; add_sys_env(z); for (ix = 0; ix < sizeof(nm)/sizeof(nm[0]); ix++) { sz = sysinfo(nm[ix], z+2, sizeof(z) - 2); if (sz > 0) { sz += 2; while (z[sz-1] == NUL) sz--; strcpy(z + sz, ADD_ENV_VARS_SUFFIX_FMT+2); add_sys_env(z); } } #elif defined(HAVE_UNAME_SYSCALL) struct utsname unm; add_sys_env(z); if (uname(&unm) != 0) AG_CANT(UNAME_CALL_NAME, SYSCALL_NAME); if (snprintf(z+2, SCRIBBLE_SIZE, ADD_ENV_VARS_SUFFIX_FMT, unm.sysname) <= SCRIBBLE_SIZE) add_sys_env(z); if (snprintf(z+2, SCRIBBLE_SIZE, ADD_ENV_VARS_SUFFIX_FMT, unm.machine) <= SCRIBBLE_SIZE) add_sys_env(z); if (snprintf(z+2, SCRIBBLE_SIZE, ADD_ENV_VARS_SUFFIX_FMT, unm.nodename) <= SCRIBBLE_SIZE) add_sys_env(z); #else add_sys_env(z); #endif } }
/*=directive include * * arg: unadorned-file-name * * text: * This directive will insert definitions from another file into * the current collection. If the file name is adorned with * double quotes or angle brackets (as in a C program), then the * include is ignored. =*/ static char* doDir_include(char* pzArg, char* pzScan) { static char const * apzSfx[] = { "def", NULL }; tScanCtx* pCtx; size_t inclSize; char zFullName[ AG_PATH_MAX + 1 ]; /* * Ignore C-style includes. This allows "C" files to be processed * for their "#define"s. */ if ((*pzArg == '"') || (*pzArg == '<')) return pzScan; pCurCtx->pzScan = pzScan; if (! SUCCESSFUL( findFile(pzArg, zFullName, apzSfx, pCurCtx->pzCtxFname))) { fprintf(pfTrace, "WARNING: cannot find `%s' definitions file\n", pzArg); return pzScan; } /* * Make sure the specified file is a regular file and we can get * the correct size for it. */ { struct stat stbf; if (stat(zFullName, &stbf) != 0) { fprintf(pfTrace, "WARNING %d (%s): cannot stat `%s' " "for include\n", errno, strerror(errno), zFullName); return pzScan; } if (! S_ISREG(stbf.st_mode)) { fprintf(pfTrace, "WARNING: `%s' must be regular file to " "include\n", zFullName); return pzScan; } inclSize = stbf.st_size; if (outTime <= stbf.st_mtime) outTime = stbf.st_mtime + 1; } if (inclSize == 0) return pzScan; /* * Get the space for the output data and for context overhead. * This is an extra allocation and copy, but easier than rewriting * 'loadData()' for this special context. */ { size_t sz = sizeof(tScanCtx) + 4 + inclSize; pCtx = (tScanCtx*)AGALOC(sz, "include def header"); memset((void*)pCtx, 0, sz); pCtx->lineNo = 1; } /* * Link it into the context stack */ pCtx->pCtx = pCurCtx; pCurCtx = pCtx; AGDUPSTR(pCtx->pzCtxFname, zFullName, "def file name"); pCtx->pzScan = pCtx->pzData = pzScan = (char*)(pCtx + 1); /* * Read all the data. Usually in a single read, but loop * in case multiple passes are required. */ { FILE* fp = fopen(zFullName, "r" FOPEN_TEXT_FLAG); char* pz = pzScan; if (fp == NULL) AG_CANT("open file", zFullName); if (pfDepends != NULL) append_source_name(zFullName); do { size_t rdct = fread((void*)pz, (size_t)1, inclSize, fp); if (rdct == 0) AG_CANT("read file", zFullName); pz += rdct; inclSize -= rdct; } while (inclSize > 0); fclose(fp); *pz = NUL; } return pzScan; }
/** * Suck in the entire definitions file and parse it. */ LOCAL void readDefines(void) { char const * pzDefFile; char * pzData; size_t dataSize; size_t sizeLeft; FILE * fp; def_input_mode_t in_mode = ready_input(&pzDefFile, &dataSize); if (in_mode == INPUT_DONE) return; /* * Allocate the space we need for our definitions. */ sizeLeft = dataSize+4+sizeof(*pBaseCtx); pBaseCtx = (tScanCtx*)AGALOC(sizeLeft, "file buffer"); memset((void*)pBaseCtx, 0, sizeLeft); pBaseCtx->lineNo = 1; sizeLeft = dataSize; /* * Our base context will have its currency pointer set to this * input. It is also a scanning pointer, but since this buffer * is never deallocated, we do not have to remember the initial * value. (It may get reallocated here in this routine, tho...) */ pzData = pBaseCtx->pzScan = pBaseCtx->pzData = (char*)(pBaseCtx+1); pBaseCtx->pCtx = NULL; /* * Set the input file pointer, as needed */ if (in_mode == INPUT_STDIN) fp = stdin; else { fp = fopen(pzDefFile, "r" FOPEN_TEXT_FLAG); if (fp == NULL) AG_CANT("open", pzDefFile); if (pfDepends != NULL) append_source_name(pzDefFile); } /* * Read until done... */ for (;;) { size_t rdct = fread((void*)pzData, (size_t)1, sizeLeft, fp); /* * IF we are done, */ if (rdct == 0) { /* * IF it is because we are at EOF, then break out * ELSE abend. */ if (feof(fp) || (in_mode == INPUT_STDIN)) break; AG_CANT("read", pzDefFile); } /* * Advance input pointer, decrease remaining count */ pzData += rdct; sizeLeft -= rdct; /* * See if there is any space left */ if (sizeLeft == 0) { tScanCtx* p; off_t dataOff; /* * IF it is a regular file, then we are done */ if (in_mode != INPUT_STDIN) break; /* * We have more data and we are out of space. * Try to reallocate our input buffer. */ dataSize += (sizeLeft = 0x1000); dataOff = pzData - pBaseCtx->pzData; p = AGREALOC((void*)pBaseCtx, dataSize+4+sizeof(*pBaseCtx), "expanded file buffer"); /* * The buffer may have moved. Set the data pointer at an * offset within the new buffer and make sure our base pointer * has been corrected as well. */ if (p != pBaseCtx) { p->pzScan = \ p->pzData = (char*)(p+1); pzData = p->pzData + dataOff; pBaseCtx = p; } } } if (pzData == pBaseCtx->pzData) AG_ABEND("No definition data were read"); *pzData = NUL; AGDUPSTR(pBaseCtx->pzCtxFname, pzDefFile, "def file name"); manageAllocatedData(pBaseCtx); manageAllocatedData((void*)pBaseCtx->pzCtxFname); /* * Close the input file, parse the data * and alphabetically sort the definition tree contents. */ if (in_mode != INPUT_STDIN) fclose(fp); pCurCtx = pBaseCtx; dp_run_fsm(); }
/** * figure out which file descriptor to use for reading definitions. */ static def_input_mode_t ready_input(char const ** ppzfile, size_t * psz) { struct stat stbf; if (! ENABLED_OPT(DEFINITIONS)) { pBaseCtx = (tScanCtx*)AGALOC(sizeof(tScanCtx), "scan context"); memset((void*)pBaseCtx, 0, sizeof(tScanCtx)); pBaseCtx->lineNo = 1; pBaseCtx->pzCtxFname = "@@ No-Definitions @@"; manageAllocatedData(pBaseCtx); if (! ENABLED_OPT(SOURCE_TIME)) outTime = time(NULL); return INPUT_DONE; } *ppzfile = OPT_ARG(DEFINITIONS); if (OPT_VALUE_TRACE >= TRACE_EXPRESSIONS) fprintf(pfTrace, "Definition Load:\n"); /* * Check for stdin as the input file. We use the current time * as the modification time for stdin. We also note it so we * do not try to open it and we try to allocate more memory if * the stdin input exceeds our initial allocation of 16K. */ if (strcmp(*ppzfile, "-") == 0) { *ppzfile = OPT_ARG(DEFINITIONS) = "stdin"; if (getenv("REQUEST_METHOD") != NULL) { loadCgi(); pCurCtx = pBaseCtx; dp_run_fsm(); return INPUT_DONE; } accept_fifo: outTime = time(NULL); *psz = 0x4000 - (4+sizeof(*pBaseCtx)); return INPUT_STDIN; } /* * This, then, must be a regular file. Make sure of that and * find out how big it was and when it was last modified. */ if (stat(*ppzfile, &stbf) != 0) AG_CANT("stat", *ppzfile); if (! S_ISREG(stbf.st_mode)) { if (S_ISFIFO(stbf.st_mode)) goto accept_fifo; errno = EINVAL; AG_CANT("open non-regular file", *ppzfile); } /* * IF the source-time option has been enabled, then * our output file mod time will start as one second after * the mod time on this file. If any of the template files * are more recent, then it will be adjusted. */ *psz = stbf.st_size; if (ENABLED_OPT(SOURCE_TIME)) outTime = stbf.st_mtime + 1; else outTime = time(NULL); return INPUT_FILE; }