From 3b5e79ab2d5d2d3352affc1d7de8ea31b017e2ae Mon Sep 17 00:00:00 2001 From: psmith Date: Wed, 16 Sep 2009 17:07:01 +0000 Subject: [PATCH] - Add xcalloc() and call it - Fix memory errors found by valgrind - Remove multi_glob() and empower parse_file_seq() to do its job: the goal here is to remove the confusing reverse/re-reverse we do on the file lists: needed for future fixes. - Add a prefix arg to parse_file_seq() - Make concat() variadic so it can take arbitrary #'s of strings --- ChangeLog | 49 ++++ ar.c | 13 +- commands.c | 2 +- default.c | 3 +- dep.h | 18 +- file.c | 6 +- function.c | 12 +- implicit.c | 34 ++- main.c | 13 +- make.h | 4 +- misc.c | 85 ++++--- read.c | 592 ++++++++++++++++++++++-------------------------- remake.c | 2 +- rule.c | 5 +- tests/run_make_tests.pl | 2 +- variable.c | 14 +- vmsfunctions.c | 6 +- 17 files changed, 435 insertions(+), 425 deletions(-) diff --git a/ChangeLog b/ChangeLog index a994791..03f9145 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,52 @@ +2009-09-16 Paul Smith + + * misc.c (alloc_dep, free_dep): Now that we have xcalloc(), + convert to macros. + * dep.h: Create alloc_dep() / free_dep() macros. + + * implicit.c (pattern_search): Take advantage of the new + parse_file_seq() to add the directory prefix to each prereq. + + * dep.h: Remove multi_glob() and enhance parse_file_seq() to do it + all. Avoid reversing chains. Support adding prefixes. + * read.c (parse_file_seq): Rewrite to support globbing. Allow for + cached/non-cached results. + (eval): Remove multi_glob() & invoke new parse_file_seq(). + * rule.c (install_pattern_rule): Ditto. + * main.c (main): Ditto. + * implicit.c (pattern_search): Ditto. + * function.c (string_glob): Ditto. + * file.c (parse_prereqs): Ditto. + * default.c (set_default_suffixes): Ditto. + + * variable.c (parse_variable_definition): Don't run off the end of + the string if it ends in whitespace (found with valgrind). + + * commands.c (set_file_variables): Keep space for all targets in + $? if -B is given (found with valgrind). + +2009-09-15 Paul Smith + + * misc.c (concat): Make concat() variadic so it takes >3 arguments. + (xcalloc): Add new function. + * make.h: New declarations. + + * ar.c (ar_glob_match): New calling method for concat(). + * main.c (main): Ditto. + (decode_env_switches): Ditto. + * read.c (eval_makefile): Ditto. + (tilde_expand): Ditto. + (parse_file_seq): Ditto. + * variable.c (target_environment): Ditto. + (sync_Path_environment): Ditto. + + * ar.c (ar_glob_match): Use xcalloc(). + * dir.c (file_impossible): Ditto. + * file.c (enter_file): Ditto. + * job.c (new_job): Ditto. + * read.c (parse_file_seq): Ditto. + * vmsfunctions.c (opendir): Ditto. + 2009-09-14 Rafi Einstein (tiny patch) * w32/subproc/sub_proc.c (process_begin): Check *ep non-NULL diff --git a/ar.c b/ar.c index 304ee9c..728f8bc 100644 --- a/ar.c +++ b/ar.c @@ -196,9 +196,8 @@ ar_glob_match (int desc UNUSED, const char *mem, int truncated UNUSED, if (fnmatch (state->pattern, mem, FNM_PATHNAME|FNM_PERIOD) == 0) { /* We have a match. Add it to the chain. */ - struct nameseq *new = xmalloc (state->size); - memset (new, '\0', state->size); - new->name = strcache_add (concat (state->arname, mem, ")")); + struct nameseq *new = xcalloc (state->size); + new->name = strcache_add (concat (4, state->arname, "(", mem, ")")); new->next = state->chain; state->chain = new; ++state->n; @@ -249,7 +248,6 @@ ar_glob (const char *arname, const char *member_pattern, unsigned int size) struct ar_glob_state state; struct nameseq *n; const char **names; - char *name; unsigned int i; if (! glob_pattern_p (member_pattern, 1)) @@ -257,12 +255,7 @@ ar_glob (const char *arname, const char *member_pattern, unsigned int size) /* Scan the archive for matches. ar_glob_match will accumulate them in STATE.chain. */ - i = strlen (arname); - name = alloca (i + 2); - memcpy (name, arname, i); - name[i] = '('; - name[i + 1] = '\0'; - state.arname = name; + state.arname = arname; state.pattern = member_pattern; state.size = size; state.chain = 0; diff --git a/commands.c b/commands.c index 7bd9531..94c4867 100644 --- a/commands.c +++ b/commands.c @@ -181,7 +181,7 @@ set_file_variables (struct file *file) memcpy (cp, c, len); cp += len; *cp++ = FILE_LIST_SEPARATOR; - if (! d->changed) + if (! (d->changed || always_make_flag)) qmark_len -= len + 1; /* Don't space in $? for this one. */ } diff --git a/default.c b/default.c index 170378e..763db6d 100644 --- a/default.c +++ b/default.c @@ -543,8 +543,7 @@ set_default_suffixes (void) { char *p = default_suffixes; suffix_file->deps = (struct dep *) - multi_glob (parse_file_seq (&p, '\0', sizeof (struct dep), 1), - sizeof (struct dep), 0); + parse_file_seq (&p, sizeof (struct dep), '\0', NULL, 0); define_variable ("SUFFIXES", 8, default_suffixes, o_default, 0); } } diff --git a/dep.h b/dep.h index ec2420e..67dac33 100644 --- a/dep.h +++ b/dep.h @@ -55,22 +55,30 @@ struct nameseq }; -struct nameseq *multi_glob (struct nameseq *chain, unsigned int size, int exists_only); +#define PARSEFS_NONE (0x0000) +#define PARSEFS_NOSTRIP (0x0001) +#define PARSEFS_NOGLOB (0x0002) +#define PARSEFS_EXISTS (0x0004) +#define PARSEFS_NOCACHE (0x0008) + #ifdef VMS struct nameseq *parse_file_seq (); #else -struct nameseq *parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip); +struct nameseq *parse_file_seq (char **stringp, unsigned int size, + int stopchar, const char *prefix, int flags); #endif + char *tilde_expand (const char *name); #ifndef NO_ARCHIVES struct nameseq *ar_glob (const char *arname, const char *member_pattern, unsigned int size); #endif -#define dep_name(d) ((d)->name == 0 ? (d)->file->name : (d)->name) +#define dep_name(d) ((d)->name == 0 ? (d)->file->name : (d)->name) + +#define alloc_dep() (xcalloc (sizeof (struct dep))) +#define free_dep(_d) free (_d) -struct dep *alloc_dep (void); -void free_dep (struct dep *d); struct dep *copy_dep_chain (const struct dep *d); void free_dep_chain (struct dep *d); void free_ns_chain (struct nameseq *n); diff --git a/file.c b/file.c index a618beb..4e3bece 100644 --- a/file.c +++ b/file.c @@ -415,8 +415,7 @@ struct dep * parse_prereqs (char *p) { struct dep *new = (struct dep *) - multi_glob (parse_file_seq (&p, '|', sizeof (struct dep), 1), - sizeof (struct dep), 0); + parse_file_seq (&p, sizeof (struct dep), '|', NULL, 0); if (*p) { @@ -426,8 +425,7 @@ parse_prereqs (char *p) ++p; ood = (struct dep *) - multi_glob (parse_file_seq (&p, '\0', sizeof (struct dep), 1), - sizeof (struct dep), 0); + parse_file_seq (&p, sizeof (struct dep), '\0', NULL, 0); if (! new) new = ood; diff --git a/function.c b/function.c index 2e6d5cb..02dbbf8 100644 --- a/function.c +++ b/function.c @@ -355,13 +355,11 @@ string_glob (char *line) struct nameseq *chain; unsigned int idx; - chain = multi_glob (parse_file_seq - (&line, '\0', sizeof (struct nameseq), - /* We do not want parse_file_seq to strip `./'s. - That would break examples like: - $(patsubst ./%.c,obj/%.o,$(wildcard ./?*.c)). */ - 0), - sizeof (struct nameseq), 1); + chain = parse_file_seq (&line, sizeof (struct nameseq), '\0', NULL, + /* We do not want parse_file_seq to strip `./'s. + That would break examples like: + $(patsubst ./%.c,obj/%.o,$(wildcard ./?*.c)). */ + PARSEFS_NOSTRIP|PARSEFS_NOCACHE|PARSEFS_EXISTS); if (result == 0) { diff --git a/implicit.c b/implicit.c index ee88f97..4285b66 100644 --- a/implicit.c +++ b/implicit.c @@ -489,6 +489,7 @@ pattern_search (struct file *file, int archive, while (1) { + const char *dir = NULL; int add_dir = 0; int had_stem = 0; @@ -570,6 +571,16 @@ pattern_search (struct file *file, int archive, p2 = depname; } + /* If we need to add the directory prefix set it up. */ + if (add_dir) + { + unsigned long l = lastslash - filename + 1; + char *n = alloca (l + 1); + memcpy (n, filename, l); + n[l] = '\0'; + dir = n; + } + /* Parse the dependencies. */ while (1) @@ -580,33 +591,16 @@ pattern_search (struct file *file, int archive, ; *id_ptr = (struct idep *) - multi_glob ( - parse_file_seq (&p2, - order_only ? '\0' : '|', - sizeof (struct idep), - 1), sizeof (struct idep), 0); + parse_file_seq (&p2, sizeof (struct idep), + order_only ? '\0' : '|', dir, 0); - /* @@ It would be nice to teach parse_file_seq or - multi_glob to add prefix. This would save us some - reallocations. */ - - if (order_only || add_dir || had_stem) + if (order_only || had_stem) { - unsigned long l = lastslash - filename + 1; - for (d = *id_ptr; d != 0; d = d->next) { if (order_only) d->ignore_mtime = 1; - if (add_dir) - { - char *n = alloca (strlen (d->name) + l + 1); - memcpy (n, filename, l); - memcpy (n+l, d->name, strlen (d->name) + 1); - d->name = strcache_add (n); - } - if (had_stem) d->had_stem = 1; } diff --git a/main.c b/main.c index 1c30884..dd309df 100644 --- a/main.c +++ b/main.c @@ -1312,7 +1312,7 @@ main (int argc, char **argv, char **envp) && (strchr (argv[0], '/') != 0 || strchr (argv[0], '\\') != 0) # endif ) - argv[0] = xstrdup (concat (current_directory, "/", argv[0])); + argv[0] = xstrdup (concat (3, current_directory, "/", argv[0])); #else /* !__MSDOS__ */ if (current_directory[0] != '\0' && argv[0] != 0 && argv[0][0] != '/' && strchr (argv[0], '/') != 0 @@ -1321,7 +1321,7 @@ main (int argc, char **argv, char **envp) && strchr (argv[0], '\\') != 0 #endif ) - argv[0] = xstrdup (concat (current_directory, "/", argv[0])); + argv[0] = xstrdup (concat (3, current_directory, "/", argv[0])); #endif /* !__MSDOS__ */ #endif /* WINDOWS32 */ #endif @@ -2008,7 +2008,7 @@ main (int argc, char **argv, char **envp) /* This cast is OK since we never modify argv. */ argv[++i] = (char *) makefiles->list[j]; else - argv[i] = xstrdup (concat ("-f", makefiles->list[j], "")); + argv[i] = xstrdup (concat (2, "-f", makefiles->list[j])); ++j; } } @@ -2019,7 +2019,7 @@ main (int argc, char **argv, char **envp) { nargv = xmalloc ((nargc + 2) * sizeof (char *)); memcpy (nargv, argv, argc * sizeof (char *)); - nargv[nargc++] = xstrdup (concat ("-o", stdin_nm, "")); + nargv[nargc++] = xstrdup (concat (2, "-o", stdin_nm)); nargv[nargc] = 0; } else @@ -2192,8 +2192,7 @@ main (int argc, char **argv, char **envp) { struct nameseq *ns; - ns = multi_glob (parse_file_seq (&p, '\0', sizeof (struct nameseq), 1), - sizeof (struct nameseq), 0); + ns = parse_file_seq (&p, sizeof (struct nameseq), '\0', NULL, 0); if (ns) { /* .DEFAULT_GOAL should contain one target. */ @@ -2670,7 +2669,7 @@ decode_env_switches (char *envar, unsigned int len) definition. Add a dash and pass it along to decode_switches. We need permanent storage for this in case decode_switches saves pointers into the value. */ - argv[1] = xstrdup (concat ("-", argv[1], "")); + argv[1] = xstrdup (concat (2, "-", argv[1])); /* Parse those words. */ decode_switches (argc, argv, 1); diff --git a/make.h b/make.h index 3d8f7ee..60d1412 100644 --- a/make.h +++ b/make.h @@ -368,6 +368,7 @@ struct floc #endif #if HAVE_ANSI_COMPILER && USE_VARIADIC && HAVE_STDARG_H +const char *concat (unsigned int, ...); void message (int prefix, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); void error (const struct floc *flocp, const char *fmt, ...) @@ -375,6 +376,7 @@ void error (const struct floc *flocp, const char *fmt, ...) void fatal (const struct floc *flocp, const char *fmt, ...) __attribute__ ((noreturn, __format__ (__printf__, 2, 3))); #else +const char *concat (); void message (); void error (); void fatal (); @@ -384,8 +386,8 @@ void die (int) __attribute__ ((noreturn)); void log_working_directory (int); void pfatal_with_name (const char *) __attribute__ ((noreturn)); void perror_with_name (const char *, const char *); -char *concat (const char *, const char *, const char *); void *xmalloc (unsigned int); +void *xcalloc (unsigned int); void *xrealloc (void *, unsigned int); char *xstrdup (const char *); char *xstrndup (const char *, unsigned int); diff --git a/misc.c b/misc.c index 078da25..f822747 100644 --- a/misc.c +++ b/misc.c @@ -160,31 +160,49 @@ print_spaces (unsigned int n) } -/* Return a string whose contents concatenate those of s1, s2, s3. +/* Return a string whose contents concatenate the NUM strings provided This string lives in static, re-used memory. */ -char * -concat (const char *s1, const char *s2, const char *s3) +const char * +#if HAVE_ANSI_COMPILER && USE_VARIADIC && HAVE_STDARG_H +concat (unsigned int num, ...) +#else +concat (num, va_alist) + unsigned int num; + va_dcl +#endif { - unsigned int len1, len2, len3; static unsigned int rlen = 0; static char *result = NULL; + int ri = 0; - len1 = (s1 && *s1 != '\0') ? strlen (s1) : 0; - len2 = (s2 && *s2 != '\0') ? strlen (s2) : 0; - len3 = (s3 && *s3 != '\0') ? strlen (s3) : 0; +#if USE_VARIADIC + va_list args; +#endif - if (len1 + len2 + len3 + 1 > rlen) - result = xrealloc (result, (rlen = len1 + len2 + len3 + 10)); + VA_START (args, num); - if (len1) - memcpy (result, s1, len1); - if (len2) - memcpy (result + len1, s2, len2); - if (len3) - memcpy (result + len1 + len2, s3, len3); + while (num-- > 0) + { + const char *s = va_arg (args, const char *); + unsigned int l = s ? strlen (s) : 0; - result[len1+len2+len3] = '\0'; + if (l == 0) + continue; + + if (ri + l > rlen) + { + rlen = ((rlen ? rlen : 60) + l) * 2; + result = xrealloc (result, rlen); + } + + memcpy (result + ri, s, l); + ri += l; + } + + VA_END (args); + + result[ri] = '\0'; return result; } @@ -337,13 +355,14 @@ pfatal_with_name (const char *name) #ifndef HAVE_DMALLOC_H #undef xmalloc +#undef xcalloc #undef xrealloc #undef xstrdup void * xmalloc (unsigned int size) { - /* Make sure we don't allocate 0, for pre-ANSI libraries. */ + /* Make sure we don't allocate 0, for pre-ISO implementations. */ void *result = malloc (size ? size : 1); if (result == 0) fatal (NILF, _("virtual memory exhausted")); @@ -352,11 +371,22 @@ xmalloc (unsigned int size) void * +xcalloc (unsigned int size) +{ + /* Make sure we don't allocate 0, for pre-ISO implementations. */ + void *result = calloc (size ? size : 1, 1); + if (result == 0) + fatal (NILF, _("virtual memory exhausted")); + return result; +} + + +void * xrealloc (void *ptr, unsigned int size) { void *result; - /* Some older implementations of realloc() don't conform to ANSI. */ + /* Some older implementations of realloc() don't conform to ISO. */ if (! size) size = 1; result = ptr ? realloc (ptr, size) : malloc (size); @@ -494,25 +524,6 @@ find_next_token (const char **ptr, unsigned int *lengthptr) } -/* Allocate a new `struct dep' with all fields initialized to 0. */ - -struct dep * -alloc_dep () -{ - struct dep *d = xmalloc (sizeof (struct dep)); - memset (d, '\0', sizeof (struct dep)); - return d; -} - - -/* Free `struct dep' along with `name' and `stem'. */ - -void -free_dep (struct dep *d) -{ - free (d); -} - /* Copy a chain of `struct dep', making a new chain with the same contents as the old one. */ diff --git a/read.c b/read.c index 19d5559..bb85d4e 100644 --- a/read.c +++ b/read.c @@ -363,7 +363,8 @@ eval_makefile (const char *filename, int flags) unsigned int i; for (i = 0; include_directories[i] != 0; ++i) { - const char *included = concat (include_directories[i], "/", filename); + const char *included = concat (3, include_directories[i], + "/", filename); ebuf.fp = fopen (included, "r"); if (ebuf.fp) { @@ -473,7 +474,7 @@ eval_buffer (char *buffer) Returns a pointer to the first non-modifier character, and sets VMOD based on the modifiers found if any, plus V_ASSIGN is 1. */ -char * +static char * parse_var_assignment (const char *line, struct vmodifiers *vmod) { const char *p; @@ -833,10 +834,8 @@ eval (struct ebuffer *ebuf, int set_default) /* Parse the list of file names. */ p2 = p; - files = multi_glob (parse_file_seq (&p2, '\0', - sizeof (struct nameseq), - 1), - sizeof (struct nameseq), 0); + files = parse_file_seq (&p2, sizeof (struct nameseq), '\0', + NULL, 0); free (p); /* Save the state of conditionals and start @@ -1020,10 +1019,8 @@ eval (struct ebuffer *ebuf, int set_default) /* Make the colon the end-of-string so we know where to stop looking for targets. */ *colonp = '\0'; - filenames = multi_glob (parse_file_seq (&p2, '\0', - sizeof (struct nameseq), - 1), - sizeof (struct nameseq), 0); + filenames = parse_file_seq (&p2, sizeof (struct nameseq), '\0', + NULL, 0); *p2 = ':'; if (!filenames) @@ -1146,7 +1143,8 @@ eval (struct ebuffer *ebuf, int set_default) if (p != 0) { struct nameseq *target; - target = parse_file_seq (&p2, ':', sizeof (struct nameseq), 1); + target = parse_file_seq (&p2, sizeof (struct nameseq), ':', + NULL, PARSEFS_NOGLOB|PARSEFS_NOCACHE); ++p2; if (target == 0) fatal (fstart, _("missing target pattern")); @@ -2302,239 +2300,6 @@ find_percent_cached (const char **string) return (*p == '\0') ? NULL : p; } -/* Parse a string into a sequence of filenames represented as a - chain of struct nameseq's in reverse order and return that chain. - - The string is passed as STRINGP, the address of a string pointer. - The string pointer is updated to point at the first character - not parsed, which either is a null char or equals STOPCHAR. - - SIZE is how big to construct chain elements. - This is useful if we want them actually to be other structures - that have room for additional info. - - If STRIP is nonzero, strip `./'s off the beginning. */ - -struct nameseq * -parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip) -{ - struct nameseq *new = 0; - struct nameseq *new1, *lastnew1; - char *p = *stringp; - -#ifdef VMS -# define VMS_COMMA ',' -#else -# define VMS_COMMA 0 -#endif - - while (1) - { - const char *name; - char *q; - - /* Skip whitespace; see if any more names are left. */ - p = next_token (p); - if (*p == '\0') - break; - if (*p == stopchar) - break; - - /* There are, so find the end of the next name. */ - q = p; - p = find_char_unquote (q, stopchar, VMS_COMMA, 1, 0); -#ifdef VMS - /* convert comma separated list to space separated */ - if (p && *p == ',') - *p =' '; -#endif -#ifdef _AMIGA - if (stopchar == ':' && p && *p == ':' - && !(isspace ((unsigned char)p[1]) || !p[1] - || isspace ((unsigned char)p[-1]))) - p = find_char_unquote (p+1, stopchar, VMS_COMMA, 1, 0); -#endif -#ifdef HAVE_DOS_PATHS - /* For DOS paths, skip a "C:\..." or a "C:/..." until we find the - first colon which isn't followed by a slash or a backslash. - Note that tokens separated by spaces should be treated as separate - tokens since make doesn't allow path names with spaces */ - if (stopchar == ':') - while (p != 0 && !isspace ((unsigned char)*p) && - (p[1] == '\\' || p[1] == '/') && isalpha ((unsigned char)p[-1])) - p = find_char_unquote (p + 1, stopchar, VMS_COMMA, 1, 0); -#endif - if (p == 0) - p = q + strlen (q); - - if (strip) -#ifdef VMS - /* Skip leading `[]'s. */ - while (p - q > 2 && q[0] == '[' && q[1] == ']') -#else - /* Skip leading `./'s. */ - while (p - q > 2 && q[0] == '.' && q[1] == '/') -#endif - { - q += 2; /* Skip "./". */ - while (q < p && *q == '/') - /* Skip following slashes: ".//foo" is "foo", not "/foo". */ - ++q; - } - - /* Extract the filename just found, and skip it. */ - - if (q == p) - /* ".///" was stripped to "". */ -#if defined(VMS) - continue; -#elif defined(_AMIGA) - name = ""; -#else - name = "./"; -#endif - else -#ifdef VMS -/* VMS filenames can have a ':' in them but they have to be '\'ed but we need - * to remove this '\' before we can use the filename. - * xstrdup called because q may be read-only string constant. - */ - { - char *qbase = xstrdup (q); - char *pbase = qbase + (p-q); - char *q1 = qbase; - char *q2 = q1; - char *p1 = pbase; - - while (q1 != pbase) - { - if (*q1 == '\\' && *(q1+1) == ':') - { - q1++; - p1--; - } - *q2++ = *q1++; - } - name = strcache_add_len (qbase, p1 - qbase); - free (qbase); - } -#else - name = strcache_add_len (q, p - q); -#endif - - /* Add it to the front of the chain. */ - new1 = xmalloc (size); - memset (new1, '\0', size); - new1->name = name; - new1->next = new; - new = new1; - } - -#ifndef NO_ARCHIVES - - /* Look for multi-word archive references. - They are indicated by a elt ending with an unmatched `)' and - an elt further down the chain (i.e., previous in the file list) - with an unmatched `(' (e.g., "lib(mem"). */ - - new1 = new; - lastnew1 = 0; - while (new1 != 0) - if (new1->name[0] != '(' /* Don't catch "(%)" and suchlike. */ - && new1->name[strlen (new1->name) - 1] == ')' - && strchr (new1->name, '(') == 0) - { - /* NEW1 ends with a `)' but does not contain a `('. - Look back for an elt with an opening `(' but no closing `)'. */ - - struct nameseq *n = new1->next, *lastn = new1; - char *paren = 0; - while (n != 0 && (paren = strchr (n->name, '(')) == 0) - { - lastn = n; - n = n->next; - } - if (n != 0 - /* Ignore something starting with `(', as that cannot actually - be an archive-member reference (and treating it as such - results in an empty file name, which causes much lossage). */ - && n->name[0] != '(') - { - /* N is the first element in the archive group. - Its name looks like "lib(mem" (with no closing `)'). */ - - char *libname; - - /* Copy "lib(" into LIBNAME. */ - ++paren; - libname = alloca (paren - n->name + 1); - memcpy (libname, n->name, paren - n->name); - libname[paren - n->name] = '\0'; - - if (*paren == '\0') - { - /* N was just "lib(", part of something like "lib( a b)". - Edit it out of the chain and free its storage. */ - lastn->next = n->next; - free (n); - /* LASTN->next is the new stopping elt for the loop below. */ - n = lastn->next; - } - else - { - /* Replace N's name with the full archive reference. */ - n->name = strcache_add (concat (libname, paren, ")")); - } - - if (new1->name[1] == '\0') - { - /* NEW1 is just ")", part of something like "lib(a b )". - Omit it from the chain and free its storage. */ - if (lastnew1 == 0) - new = new1->next; - else - lastnew1->next = new1->next; - lastn = new1; - new1 = new1->next; - free (lastn); - } - else - { - /* Replace also NEW1->name, which already has closing `)'. */ - new1->name = strcache_add (concat (libname, new1->name, "")); - new1 = new1->next; - } - - /* Trace back from NEW1 (the end of the list) until N - (the beginning of the list), rewriting each name - with the full archive reference. */ - - while (new1 != n) - { - new1->name = strcache_add (concat (libname, new1->name, ")")); - lastnew1 = new1; - new1 = new1->next; - } - } - else - { - /* No frobnication happening. Just step down the list. */ - lastnew1 = new1; - new1 = new1->next; - } - } - else - { - lastnew1 = new1; - new1 = new1->next; - } - -#endif - - *stringp = p; - return new; -} - /* Find the next line of text in an eval buffer, combining continuation lines into one line. Return the number of actual lines read (> 1 if continuation lines). @@ -3034,7 +2799,7 @@ tilde_expand (const char *name) # endif /* !AMIGA && !WINDOWS32 */ if (home_dir != 0) { - char *new = xstrdup (concat (home_dir, "", name + 1)); + char *new = xstrdup (concat (2, home_dir, name + 1)); if (is_variable) free (home_dir); return new; @@ -3053,7 +2818,7 @@ tilde_expand (const char *name) if (userend == 0) return xstrdup (pwent->pw_dir); else - return xstrdup (concat (pwent->pw_dir, "/", userend + 1)); + return xstrdup (concat (3, pwent->pw_dir, "/", userend + 1)); } else if (userend != 0) *userend = '/'; @@ -3062,63 +2827,267 @@ tilde_expand (const char *name) #endif /* !VMS */ return 0; } + +/* Parse a string into a sequence of filenames represented as a chain of + struct nameseq's and return that chain. Optionally expand the strings via + glob(). -/* Given a chain of struct nameseq's describing a sequence of filenames, - in reverse of the intended order, return a new chain describing the - result of globbing the filenames. The new chain is in forward order. - The links of the old chain are freed or used in the new chain. - Likewise for the names in the old chain. + The string is passed as STRINGP, the address of a string pointer. + The string pointer is updated to point at the first character + not parsed, which either is a null char or equals STOPCHAR. SIZE is how big to construct chain elements. This is useful if we want them actually to be other structures that have room for additional info. - If EXISTS_ONLY is true only return existing files. */ + PREFIX, if non-null, is added to the beginning of each filename. + + FLAGS allows one or more of the following bitflags to be set: + PARSEFS_NOSTRIP - Do no strip './'s off the beginning + PARSEFS_NOGLOB - Do not expand globbing characters + PARSEFS_EXISTS - Only return globbed files that actually exist + (cannot also set NOGLOB) + PARSEFS_NOCACHE - Do not add filenames to the strcache (caller frees) + */ struct nameseq * -multi_glob (struct nameseq *chain, unsigned int size, int exists_only) +parse_file_seq (char **stringp, unsigned int size, int stopchar, + const char *prefix, int flags) { - void dir_setup_glob (glob_t *); + extern void dir_setup_glob (glob_t *glob); + + /* tmp points to tmpbuf after the prefix, if any. + tp is the end of the buffer. */ + static char *tmpbuf = NULL; + static int tmpbuf_len = 0; + + int cachep = (! (flags & PARSEFS_NOCACHE)); + struct nameseq *new = 0; - struct nameseq *old; - struct nameseq *nexto; + struct nameseq **newp = &new; +#define NEWELT(_n) do { \ + const char *__n = (_n); \ + *newp = xcalloc (size); \ + (*newp)->name = (cachep ? strcache_add (__n) : xstrdup (__n)); \ + newp = &(*newp)->next; \ + } while(0) + + char *p; glob_t gl; + char *tp; + +#ifdef VMS +# define VMS_COMMA ',' +#else +# define VMS_COMMA 0 +#endif + + if (size < sizeof (struct nameseq)) + size = sizeof (struct nameseq); - dir_setup_glob (&gl); + if (! (flags & PARSEFS_NOGLOB)) + dir_setup_glob (&gl); + + /* Get enough temporary space to construct the largest possible target. */ + { + int l = strlen (*stringp) + 1; + if (l > tmpbuf_len) + { + tmpbuf = xrealloc (tmpbuf, l); + tmpbuf_len = l; + } + } + tp = tmpbuf; - for (old = chain; old != 0; old = nexto) + /* Parse STRING. P will always point to the end of the parsed content. */ + p = *stringp; + while (1) { - int r; + const char *name; const char **nlist = 0; - int i = 0; - const char *gname; + char *tildep = 0; #ifndef NO_ARCHIVES char *arname = 0; char *memname = 0; #endif - nexto = old->next; - gname = old->name; + char *s; + int nlen; + int i; + + /* Skip whitespace; at the end of the string or STOPCHAR we're done. */ + p = next_token (p); + if (*p == '\0' || *p == stopchar) + break; + + /* There are names left, so find the end of the next name. + Throughout this iteration S points to the start. */ + s = p; + p = find_char_unquote (p, stopchar, VMS_COMMA, 1, 0); +#ifdef VMS + /* convert comma separated list to space separated */ + if (p && *p == ',') + *p =' '; +#endif +#ifdef _AMIGA + if (stopchar == ':' && p && *p == ':' + && !(isspace ((unsigned char)p[1]) || !p[1] + || isspace ((unsigned char)p[-1]))) + p = find_char_unquote (p+1, stopchar, VMS_COMMA, 1, 0); +#endif +#ifdef HAVE_DOS_PATHS + /* For DOS paths, skip a "C:\..." or a "C:/..." until we find the + first colon which isn't followed by a slash or a backslash. + Note that tokens separated by spaces should be treated as separate + tokens since make doesn't allow path names with spaces */ + if (stopchar == ':') + while (p != 0 && !isspace ((unsigned char)*p) && + (p[1] == '\\' || p[1] == '/') && isalpha ((unsigned char)p[-1])) + p = find_char_unquote (p + 1, stopchar, VMS_COMMA, 1, 0); +#endif + if (p == 0) + p = s + strlen (s); + + /* Strip leading "this directory" references. */ + if (! (flags & PARSEFS_NOSTRIP)) +#ifdef VMS + /* Skip leading `[]'s. */ + while (p - s > 2 && s[0] == '[' && s[1] == ']') +#else + /* Skip leading `./'s. */ + while (p - s > 2 && s[0] == '.' && s[1] == '/') +#endif + { + /* Skip "./" and all following slashes. */ + s += 2; + while (*s == '/') + ++s; + } + + /* Extract the filename just found, and skip it. + Set NAME to the string, and NLEN to its length. */ - if (gname[0] == '~') + if (s == p) + { + /* The name was stripped to empty ("./"). */ +#if defined(VMS) + continue; +#elif defined(_AMIGA) + /* PDS-- This cannot be right!! */ + tp[0] = '\0'; + nlen = 0; +#else + tp[0] = '.'; + tp[1] = '/'; + tp[2] = '\0'; + nlen = 2; +#endif + } + else { - char *newname = tilde_expand (old->name); - if (newname != 0) - gname = newname; +#ifdef VMS +/* VMS filenames can have a ':' in them but they have to be '\'ed but we need + * to remove this '\' before we can use the filename. + * xstrdup called because S may be read-only string constant. + */ + char *n = tp; + while (s < p) + { + if (s[0] == '\\' && s[1] == ':') + ++s; + *(n++) = *(s++); + } + n[0] = '\0'; + nlen = strlen (tp); +#else + nlen = p - s; + memcpy (tp, s, nlen); + tp[nlen] = '\0'; +#endif + } + + /* At this point, TP points to the element and NLEN is its length. */ + +#ifndef NO_ARCHIVES + /* If this is the start of an archive group that isn't complete, set up + to add the archive prefix for future files. + + TP == TMP means we're not already in an archive group. Ignore + something starting with `(', as that cannot actually be an + archive-member reference (and treating it as such results in an empty + file name, which causes much lossage). Also if it ends in ")" then + it's a complete reference so we don't need to treat it specially. */ + + if (tp == tmpbuf && tp[0] != '(' && tp[nlen-1] != ')') + { + char *n = strchr (tp, '('); + if (n) + { + /* This is the first element in an open archive group. It looks + like "lib(mem". Remember the close paren. */ + nlen -= (n + 1) - tp; + tp = n + 1; + + /* If we have just "lib(", part of something like "lib( a b)", + go to the next item. */ + if (! nlen) + continue; + } + } + + /* If we are inside an archive group, make sure it has an end. */ + if (tp > tmpbuf) + { + if (tp[nlen-1] == ')') + { + /* This is the natural end; reset TP. */ + tp = tmpbuf; + + /* This is just ")", something like "lib(a b )": skip it. */ + if (nlen == 1) + continue; + } + else + { + /* Not the end, so add a "fake" end. */ + tp[nlen++] = ')'; + tp[nlen] = '\0'; + } + } +#endif + + /* If we're not globbing we're done: add it to the end of the chain. + Go to the next item in the string. */ + if (flags & PARSEFS_NOGLOB) + { + NEWELT (concat (2, prefix, tp)); + continue; + } + + /* If we get here we know we're doing glob expansion. + TP is a string in tmpbuf. NLEN is no longer used. + We may need to do more work: after this NAME will be set. */ + name = tp; + + /* Expand tilde if applicable. */ + if (tp[0] == '~') + { + tildep = tilde_expand (tp); + if (tildep != 0) + name = tildep; } #ifndef NO_ARCHIVES - if (ar_name (gname)) + /* If NAME is an archive member reference replace it with the archive + file name, and save the member name in MEMNAME. We will glob on the + archive name and then reattach MEMNAME later. */ + if (ar_name (name)) { - /* OLD->name is an archive member reference. Replace it with the - archive file name, and save the member name in MEMNAME. We will - glob on the archive name and then reattach MEMNAME later. */ - ar_parse_name (gname, &arname, &memname); - gname = arname; + ar_parse_name (name, &arname, &memname); + name = arname; } #endif /* !NO_ARCHIVES */ - r = glob (gname, GLOB_NOSORT|GLOB_ALTDIRFUNC, NULL, &gl); - switch (r) + switch (glob (name, GLOB_NOSORT|GLOB_ALTDIRFUNC, NULL, &gl)) { case GLOB_NOSPACE: fatal (NILF, _("virtual memory exhausted")); @@ -3130,7 +3099,8 @@ multi_glob (struct nameseq *chain, unsigned int size, int exists_only) break; case GLOB_NOMATCH: - if (exists_only) + /* If we want only existing items, skip this one. */ + if (flags & PARSEFS_EXISTS) { i = 0; break; @@ -3140,8 +3110,8 @@ multi_glob (struct nameseq *chain, unsigned int size, int exists_only) default: /* By default keep this name. */ i = 1; - nlist = &gname; - break; + nlist = &name; + break; } /* For each matched element, add it to the list. */ @@ -3150,58 +3120,46 @@ multi_glob (struct nameseq *chain, unsigned int size, int exists_only) if (memname != 0) { /* Try to glob on MEMNAME within the archive. */ - struct nameseq *found - = ar_glob (nlist[i], memname, size); + struct nameseq *found = ar_glob (nlist[i], memname, size); if (! found) - { - /* No matches. Use MEMNAME as-is. */ - unsigned int alen = strlen (nlist[i]); - unsigned int mlen = strlen (memname); - char *name; - struct nameseq *elt = xmalloc (size); - memset (elt, '\0', size); - - name = alloca (alen + 1 + mlen + 2); - memcpy (name, nlist[i], alen); - name[alen] = '('; - memcpy (name+alen+1, memname, mlen); - name[alen + 1 + mlen] = ')'; - name[alen + 1 + mlen + 1] = '\0'; - elt->name = strcache_add (name); - elt->next = new; - new = elt; - } + /* No matches. Use MEMNAME as-is. */ + NEWELT (concat (5, prefix, nlist[i], "(", memname, ")")); else { - /* Find the end of the FOUND chain. */ - struct nameseq *f = found; - while (f->next != 0) - f = f->next; - - /* Attach the chain being built to the end of the FOUND - chain, and make FOUND the new NEW chain. */ - f->next = new; - new = found; + /* We got a chain of items. Attach them. */ + (*newp)->next = found; + + /* Find and set the new end. Massage names if necessary. */ + while (1) + { + if (! cachep) + found->name = xstrdup (concat (2, prefix, name)); + else if (prefix) + found->name = strcache_add (concat (2, prefix, name)); + + if (found->next == 0) + break; + + found = found->next; + } + newp = &found->next; } } else #endif /* !NO_ARCHIVES */ - { - struct nameseq *elt = xmalloc (size); - memset (elt, '\0', size); - elt->name = strcache_add (nlist[i]); - elt->next = new; - new = elt; - } + NEWELT (concat (2, prefix, nlist[i])); + + globfree (&gl); - if (r == 0) - globfree (&gl); - free (old); #ifndef NO_ARCHIVES if (arname) free (arname); #endif + + if (tildep) + free (tildep); } + *stringp = p; return new; } diff --git a/remake.c b/remake.c index 4cf8bd7..a70cbee 100644 --- a/remake.c +++ b/remake.c @@ -870,7 +870,7 @@ notice_finished_file (struct file *file) really check the target's mtime again. Otherwise, assume the target would have been updated. */ - if (question_flag || just_print_flag || touch_flag && file->cmds != 0) + if ((question_flag || just_print_flag || touch_flag) && file->cmds) { for (i = file->cmds->ncommand_lines; i > 0; --i) if (! (file->cmds->lines_flags[i-1] & COMMANDS_RECURSE)) diff --git a/rule.c b/rule.c index 652c7a2..64a1a2d 100644 --- a/rule.c +++ b/rule.c @@ -376,9 +376,8 @@ install_pattern_rule (struct pspec *p, int terminal) ++r->suffixes[0]; ptr = p->dep; - r->deps = (struct dep *) multi_glob (parse_file_seq (&ptr, '\0', - sizeof (struct dep), 1), - sizeof (struct dep), 0); + r->deps = (struct dep *) parse_file_seq (&ptr, sizeof (struct dep), '\0', + NULL, 0); if (new_pattern_rule (r, 0)) { diff --git a/tests/run_make_tests.pl b/tests/run_make_tests.pl index 092991b..2071b17 100755 --- a/tests/run_make_tests.pl +++ b/tests/run_make_tests.pl @@ -32,7 +32,7 @@ $valgrind = 0; # invoke make with valgrind $valgrind_args = ''; $memcheck_args = '--num-callers=15 --tool=memcheck --leak-check=full'; -$massif_args = '--num-callers=15 --tool=massif --alloc-fn=xmalloc --alloc-fn=xrealloc --alloc-fn=xstrdup --alloc-fn=xstrndup'; +$massif_args = '--num-callers=15 --tool=massif --alloc-fn=xmalloc --alloc-fn=xcalloc --alloc-fn=xrealloc --alloc-fn=xstrdup --alloc-fn=xstrndup'; $pure_log = undef; $command_string = ''; diff --git a/variable.c b/variable.c index 10bbc54..90c447c 100644 --- a/variable.c +++ b/variable.c @@ -979,7 +979,7 @@ target_environment (struct file *file) strcmp(v->name, "PATH") == 0) convert_Path_to_windows32(value, ';'); #endif - *result++ = xstrdup (concat (v->name, "=", value)); + *result++ = xstrdup (concat (3, v->name, "=", value)); free (value); } else @@ -989,7 +989,7 @@ target_environment (struct file *file) strcmp(v->name, "PATH") == 0) convert_Path_to_windows32(v->value, ';'); #endif - *result++ = xstrdup (concat (v->name, "=", v->value)); + *result++ = xstrdup (concat (3, v->name, "=", v->value)); } } @@ -1324,7 +1324,10 @@ parse_variable_definition (const char *p, enum variable_flavor *flavor) { wspace = 1; p = next_token (p); - c = *p++; + c = *p; + if (c == '\0') + return NULL; + ++p; } @@ -1333,8 +1336,9 @@ parse_variable_definition (const char *p, enum variable_flavor *flavor) *flavor = f_recursive; return (char *)p; } + /* Match assignment variants (:=, +=, ?=) */ - else if (*p == '=') + if (*p == '=') { switch (c) { @@ -1592,7 +1596,7 @@ sync_Path_environment (void) * Create something WINDOWS32 world can grok */ convert_Path_to_windows32 (path, ';'); - environ_path = xstrdup (concat ("PATH", "=", path)); + environ_path = xstrdup (concat (3, "PATH", "=", path)); putenv (environ_path); free (path); } diff --git a/vmsfunctions.c b/vmsfunctions.c index 51a270e..2c87cb7 100644 --- a/vmsfunctions.c +++ b/vmsfunctions.c @@ -34,13 +34,11 @@ this program. If not, see . */ DIR * opendir (char *dspec) { - struct DIR *dir = (struct DIR *)xmalloc (sizeof (struct DIR)); - struct NAM *dnam = (struct NAM *)xmalloc (sizeof (struct NAM)); + struct DIR *dir = xcalloc (sizeof (struct DIR)); + struct NAM *dnam = xmalloc (sizeof (struct NAM)); struct FAB *dfab = &dir->fab; char *searchspec = xmalloc (MAXNAMLEN + 1); - memset (dir, 0, sizeof *dir); - *dfab = cc$rms_fab; *dnam = cc$rms_nam; sprintf (searchspec, "%s*.*;", dspec); -- 2.11.4.GIT