diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2012-08-11 16:45:31 +0000 |
---|---|---|
committer | Lorry <lorry@roadtrain.codethink.co.uk> | 2012-10-18 12:43:06 +0000 |
commit | 7c432b265ed7ca5f8304938db73912df8ce35032 (patch) | |
tree | c95de7bee7b742ed92b9924d904adca706e48d80 /agen5/agDep.c | |
download | autogen-a3e93d54c56a526903e9e0915a50e72ea9e22811.tar.gz |
Imported from /srv/lorry/lorry-area/autogen/autogen-5.16.2.tar.gz.HEADautogen-5.16.2master
Diffstat (limited to 'agen5/agDep.c')
-rw-r--r-- | agen5/agDep.c | 447 |
1 files changed, 447 insertions, 0 deletions
diff --git a/agen5/agDep.c b/agen5/agDep.c new file mode 100644 index 0000000..06665d4 --- /dev/null +++ b/agen5/agDep.c @@ -0,0 +1,447 @@ + +/** + * @file tpDep.c + * + * Time-stamp: "2012-04-07 09:01:06 bkorb" + * + * This module will load a template and return a template structure. + * + * This file is part of AutoGen. + * Copyright (c) 1992-2012 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/>. + */ + +typedef struct flist flist_t; +struct flist { + flist_t * next; + char fname[1]; +}; + +static flist_t * src_flist = NULL; +static flist_t * targ_flist = NULL; + +/** + * Add a source file to the dependency list + * + * @param pz pointer to file name + */ +LOCAL void +add_source_file(char const * pz) +{ + flist_t ** lp; + + /* + * If a source is also a target, then we've created it. + * Do not list in source dependencies. + */ + lp = &targ_flist; + while (*lp != NULL) { + if (strcmp(pz, (*lp)->fname) == 0) + return; + lp = &((*lp)->next); + } + + /* + * No check for duplicate in source list. Add if not found. + */ + lp = &src_flist; + while (*lp != NULL) { + if (strcmp(pz, (*lp)->fname) == 0) + return; + lp = &((*lp)->next); + } + + { + size_t l = strlen(pz); + flist_t * p = AGALOC(sizeof(*p) + l, "sfile"); + *lp = p; + p->next = NULL; + memcpy(p->fname, pz, l + 1); + if (OPT_VALUE_TRACE >= TRACE_SERVER_SHELL) + fprintf(trace_fp, TRACE_ADD_SRC_FILE_FMT, p->fname); + } +} + +/** + * remove a source file from the dependency list + * + * @param pz pointer to file name + */ +LOCAL void +rm_source_file(char const * pz) +{ + flist_t ** pp = &src_flist; //!< point to where to stash removed "next" + flist_t ** lp = &src_flist; //!< list scanning pointer + + for (;;) { + if (*lp == NULL) + return; + if (strcmp(pz, (*lp)->fname) == 0) + break; + pp = lp; + lp = &((*lp)->next); + } + { + flist_t * p = *lp; + *pp = p->next; + if (OPT_VALUE_TRACE >= TRACE_SERVER_SHELL) + fprintf(trace_fp, TRACE_RM_SRC_FILE_FMT, p->fname); + AGFREE(p); + } +} + +/** + * Add a target file to the dependency list. Avoid files in temp directories. + * + * @param pz pointer to file name + */ +LOCAL void +add_target_file(char const * pz) +{ + flist_t ** lp; + + /* + * Skip anything stashed in the temp directory. + */ + if ( (temp_tpl_dir_len > 0) + && (strncmp(pz, pz_temp_tpl, temp_tpl_dir_len) == 0) + && (pz[temp_tpl_dir_len] == NUL)) + return; + + /* + * Target files override sources, just in case. + * (We sometimes extract from files we are about to replace.) + */ + rm_source_file(pz); + + /* + * avoid duplicates and add to end of list + */ + lp = &targ_flist; + while (*lp != NULL) { + if (strcmp(pz, (*lp)->fname) == 0) + return; + lp = &((*lp)->next); + } + + { + size_t l = strlen(pz); + flist_t * p = AGALOC(sizeof(*p) + l, "tfile"); + *lp = p; + p->next = NULL; + memcpy(p->fname, pz, l + 1); + if (OPT_VALUE_TRACE >= TRACE_SERVER_SHELL) + fprintf(trace_fp, TRACE_ADD_TARG_FILE_FMT, p->fname); + } +} + +/** + * Remove a target file from the dependency list + * + * @param pz pointer to file name + */ +LOCAL void +rm_target_file(char const * pz) +{ + flist_t ** lp = &targ_flist; //!< list scanning pointer + + for (;;) { + if (*lp == NULL) + return; + if (strcmp(pz, (*lp)->fname) == 0) + break; + lp = &((*lp)->next); + } + { + flist_t * p = *lp; + *lp = p->next; + if (OPT_VALUE_TRACE >= TRACE_SERVER_SHELL) + fprintf(trace_fp, TRACE_RM_TARG_FILE_FMT, p->fname); + AGFREE(p); + } +} + +/** + * Create a dependency output file + */ +LOCAL void +start_dep_file(void) +{ + + /* + * Set dep_file to a temporary file name + */ + { + char * tfile_name; + size_t dep_name_len; + + if (dep_file == NULL) { + dep_name_len = strlen(OPT_ARG(BASE_NAME)); + tfile_name = AGALOC(dep_name_len + TEMP_SUFFIX_LEN + 1, "dfileb"); + memcpy(tfile_name, OPT_ARG(BASE_NAME), dep_name_len); + memcpy(tfile_name + dep_name_len, TEMP_SUFFIX, + TEMP_SUFFIX_LEN + 1); + + } else { + dep_name_len = strlen(dep_file); + tfile_name = AGALOC(dep_name_len + TEMP_SUFFIX_LEN, "dfile"); + memcpy(tfile_name, dep_file, dep_name_len); + memcpy(tfile_name + dep_name_len, TEMP_SUFFIX + 2, + TEMP_SUFFIX_LEN - 1); + } + + if (dep_target == NULL) { + /* + * If there is no target name, then the target is our output file. + */ + char * q = AGALOC(dep_name_len + 1, "t-name"); + dep_target = q; + memcpy(q, tfile_name, dep_name_len); + q[dep_name_len] = NUL; + } + + mkstemp(tfile_name); + dep_file = tfile_name; + } + + /* + * Create the file and write the leader. + */ + dep_fp = fopen(dep_file, "w"); + + if (dep_fp == NULL) + AG_CANT(START_DEP_FOPEN_MSG, dep_file); + + fprintf(dep_fp, START_DEP_FILE_FMT, autogenOptions.pzProgPath); + + { + int ac = autogenOptions.origArgCt - 1; + char ** av = autogenOptions.origArgVect + 1; + + for (;;) { + char * arg = *(av++); + fprintf(dep_fp, START_DEP_ARG_FMT, arg); + if (--ac == 0) break; + fputs(DEP_FILE_SPLICE_STR, dep_fp); + } + fputs("\n", dep_fp); + } + + { + char const * pnm = autogenOptions.pzPROGNAME; + char const * bnm = strchr(dep_target, '/'); + char * pz; + + if (bnm != NULL) + bnm++; + else + bnm = dep_target; + + { + size_t sz = strlen(pnm) + strlen(bnm) + 2; // underscore + NUL + + pz_targ_base = pz = AGALOC(sz, "t list"); + sprintf(pz, DEP_FILE_TARG_FMT, pnm, bnm); + } + + /* + * Now scan over the characters in "pz_targ_base". Anything that + * is not a legal name character gets replaced with an underscore. + */ + for (;;) { + unsigned int ch = (unsigned int)*(pz++); + if (ch == NUL) + break; + if (! IS_ALPHANUMERIC_CHAR(ch)) + pz[-1] = '_'; + } + } +} + +/** + * Set modification time and rename into result file name. + */ +static void +tidy_dep_file(void) +{ + static mode_t const fil_mode = + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + + /* + * Trim off the temporary suffix and rename the dependency file into + * place. We used a mkstemp name in case autogen failed. + */ + do { + char * pze = strrchr(dep_file, '-'); + char * pzn; + size_t len; + + if (pze == NULL) break; + + len = (pze - dep_file); + pzn = AGALOC(len + 1, "dep file"); + memcpy(pzn, dep_file, len); + pzn[len] = NUL; + + unlink(pzn); + rename(dep_file, pzn); + AGFREE(dep_file); + dep_file = pzn; + } while (false); + +#ifdef HAVE_FCHMOD + fchmod(fileno(dep_fp), fil_mode); + fclose(dep_fp); +#else + fclose(dep_fp); + chmod(dep_file, fil_mode); +#endif + dep_fp = NULL; + + { + struct utimbuf tbuf = { + .actime = time(NULL), + .modtime = start_time + }; + + utime(dep_file, &tbuf); + + /* + * If the target is not the dependency file, then ensure that the + * file exists and set its time to the same time. Ignore all errors. + */ + if (strcmp(dep_file, dep_target) != 0) { + if (access(dep_target, R_OK) != 0) + close( open(dep_target, O_CREAT, fil_mode)); + + utime(dep_target, &tbuf); + AGFREE(dep_target); + } + } + + AGFREE(dep_file); +} + +/** + * Print out and free a list of files. + */ +static void +print_list(flist_t * flist, char const * TMPDIR, size_t tmpdir_len) +{ + /* + * Omit temporary sources. They are identified several ways: + * 1. the file must be accessible + * 2. the file must not match our temporary file template + * 3. the file must not match TMPDIR from the environment + */ + while (flist != NULL) { + flist_t * p = flist; + + do { + if (access(p->fname, R_OK) != 0) + break; // no longer accessible + + if ( (temp_tpl_dir_len > 0) + && (strncmp(pz_temp_tpl, p->fname, temp_tpl_dir_len) == 0) + && (p->fname[temp_tpl_dir_len] == DIRCH)) + break; // autogen temp file + + if ( (strncmp(TMPDIR, p->fname, tmpdir_len) == 0) + && (p->fname[tmpdir_len] == DIRCH) ) + break; // TMPDIR directory file + + fprintf(dep_fp, DEP_List, p->fname); + } while (false); + + flist = p->next; + AGFREE(p); + } +} + +/** + * Finish off the dependency file. Write out the lists of files, + * a rule to fulfill make's needs and, optionally, clean up rules. + * then close the file and tidy up. + */ +LOCAL void +wrap_up_depends(void) +{ + char const * TMPDIR = getenv("TMPDIR"); + size_t tmpdir_len; + if (TMPDIR != NULL) { + tmpdir_len = strlen(TMPDIR); + } else { + TMPDIR = "/tmp"; + tmpdir_len = 4; + } + + fprintf(dep_fp, DEP_TList, pz_targ_base); + print_list(targ_flist, TMPDIR, tmpdir_len); + + fprintf(dep_fp, DEP_SList, pz_targ_base); + print_list(src_flist, TMPDIR, tmpdir_len); + + targ_flist = src_flist = NULL; + fprintf(dep_fp, DEP_FILE_WRAP_FMT, pz_targ_base, dep_target); + + if (dep_phonies) { + /* + * Remove the target file name IFF it is different from + * the dependency file name. The dependency file will not be + * removed, but it will be sent waaay back in time. + */ + char * p, *q; + AGDUPSTR(p, dep_file, "xx"); + + q = p + strlen(p) - (TEMP_SUFFIX_LEN - 2); + if ((q > p) && (*q == '-')) + *q = NUL; + q = p; + + /* DO NOT REMOVE DEPENDENCY FILE */ + if (strcmp(dep_target, p) == 0) + p = (char *)zNil; + fprintf(dep_fp, DEP_FILE_CLEAN_FMT, dep_target, pz_targ_base, p); + AGFREE(q); + } + +#if 0 + if (serv_id != NULLPROCESS) { + char * pz = shell_cmd("echo ${AG_Dep_File}"); + if (*pz != NUL) { + /* + * The target we are crating will now depend upon the target + * created by the spawned autogen run. That spawned run script + * is responsible for ensuring that if there are multiple targets, + * then they are all chained together so we only worry about one. + */ + static char const incfmt[] = + "\n%s : %s\ninclude %s\n"; + static char const targ[] = ".targ"; + size_t ln = strlen(pz); + char * pt = AGALOC(ln + sizeof(targ), targ); + if (strcmp(pz + ln - 4, ".dep") == 0) + ln -= 4; + memcpy(pt, pz, ln); + memcpy(pt + ln, targ, sizeof(targ)); + fprintf(dep_fp, incfmt, dep_target, pt, pz); + AGFREE(pt); + } + + AGFREE(pz); + } +#endif + tidy_dep_file(); +} |