summaryrefslogtreecommitdiff
path: root/agen5/agDep.c
diff options
context:
space:
mode:
Diffstat (limited to 'agen5/agDep.c')
-rw-r--r--agen5/agDep.c447
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();
+}