]> git.ipfire.org Git - thirdparty/make.git/commitdiff
Create a character map to use for locating stop-points in strings.
authorPaul Smith <psmith@gnu.org>
Sat, 22 Jun 2013 04:22:08 +0000 (00:22 -0400)
committerPaul Smith <psmith@gnu.org>
Sat, 22 Jun 2013 04:22:08 +0000 (00:22 -0400)
In various places we were passing flags and characters to compare, then
using complex conditionals to see where to stop in string searches.
Performance numbers reveal that we were spending as much as 23% of our
processing time in these functions, most of it in the comparison lines.
Instead create a character map and use a single bitwise comparison to
determine if this is any one of the stop characters.

14 files changed:
ChangeLog
default.c
dep.h
dir.c
file.c
function.c
implicit.c
job.c
main.c
makeint.h
misc.c
read.c
rule.c
variable.c

index ded8974e89b1d5dad469618a635e4cfa0748c9e5..fe7cd99f5786b55260fa985ab19ce3fe0cf0f788 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,39 @@
+2013-06-22  Paul Smith  <psmith@gnu.org>
+
+       Improve performance by using a character map to determine where we
+       want to stop searching strings, rather than discrete comparisons.
+
+       * read.c (find_char_unquote): Pass a stop map instead of various
+       flags and use that to check when to stop parsing the string.
+       (eval): Use the new find_char_unquote() calling signature.
+       (remove_comments): Ditto.
+       (unescape_char): Ditto.
+       (find_percent_cached): Ditto.
+       (parse_file_seq): Use a stop-map flag.
+       * main.c (stopchar_map): Character map definition.
+       (initialize_stopchar_map): Initialize the map definition.
+       (main): Invoke the map initialization function.
+       * misc.c (end_of_token_w32): Remove unused function.
+       * dir.c (dosify): Use STOP_SET to check for stop chars.
+       * main.c (main): Ditto.
+       * misc.c (end_of_token): Ditto.
+       * function.c (subst_expand): Ditto.
+       (func_notdir_suffix): Ditto.
+       (func_basename_dir): Ditto.
+       (abspath): Ditto.
+       * job.c (is_bourne_compatible_shell): Ditto.
+       * variable.c (parse_variable_definition): Ditto.
+       * read.c (eval): Ditto.
+       (conditional_line): Ditto.
+       (find_percent_cached): Ditto.
+       * dep.h (PARSE_FILE_SEQ): Update function declaration.
+       * default.c (set_default_suffixes): Update PARSE_FILE_SEQ() call.
+       * file.c (split_prereqs): Ditto.
+       * function.c (string_glob): Ditto.
+       * implicit.c (pattern_search): Ditto.
+       * rule.c (install_pattern_rule): Ditto.
+       * main.c (main): Ditto.
+
 2013-06-21  Paul Smith  <psmith@gnu.org>
 
        * main.c (verify_flag): Global variable to determine whether to
index d471eafe806e9a218df898e2866e3121da68492f..32b878a9baf71972b57327577836eea15d2e9b2e 100644 (file)
--- a/default.c
+++ b/default.c
@@ -547,7 +547,7 @@ set_default_suffixes (void)
     {
       struct dep *d;
       char *p = default_suffixes;
-      suffix_file->deps = enter_prereqs (PARSE_FILE_SEQ (&p, struct dep, '\0',
+      suffix_file->deps = enter_prereqs (PARSE_FILE_SEQ (&p, struct dep, MAP_NUL,
                                                          NULL, 0),
                                         NULL);
       for (d = suffix_file->deps; d; d = d->next)
diff --git a/dep.h b/dep.h
index d1d3bbbf7d75de53696ac664d03dca8dd468698b..a7c74a1e9adc589525e2f862b12534e9d8fd27d1 100644 (file)
--- a/dep.h
+++ b/dep.h
@@ -53,13 +53,12 @@ struct nameseq
     const char *name;
   };
 
-
-#define PARSEFS_NONE    (0x0000)
-#define PARSEFS_NOSTRIP (0x0001)
-#define PARSEFS_NOAR    (0x0002)
-#define PARSEFS_NOGLOB  (0x0004)
-#define PARSEFS_EXISTS  (0x0008)
-#define PARSEFS_NOCACHE (0x0010)
+#define PARSEFS_NONE    0x0000
+#define PARSEFS_NOSTRIP 0x0001
+#define PARSEFS_NOAR    0x0002
+#define PARSEFS_NOGLOB  0x0004
+#define PARSEFS_EXISTS  0x0008
+#define PARSEFS_NOCACHE 0x0010
 
 #define PARSE_FILE_SEQ(_s,_t,_c,_p,_f) \
             (_t *)parse_file_seq ((_s),sizeof (_t),(_c),(_p),(_f))
@@ -68,7 +67,7 @@ struct nameseq
 void *parse_file_seq ();
 #else
 void *parse_file_seq (char **stringp, unsigned int size,
-                      int stopchar, const char *prefix, int flags);
+                      int stopmap, const char *prefix, int flags);
 #endif
 
 char *tilde_expand (const char *name);
diff --git a/dir.c b/dir.c
index 87b8eb34a79fea56101cad7e96954199c5017590..5681275e68cd936ddc573ca9cdbb754129e69677 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -16,6 +16,7 @@ this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "makeint.h"
 #include "hash.h"
+#include "dep.h"
 
 #ifdef  HAVE_DIRENT_H
 # include <dirent.h>
@@ -84,21 +85,21 @@ dosify (const char *filename)
   df = dos_filename;
 
   /* First, transform the name part.  */
-  for (i = 0; *filename != '\0' && i < 8 && *filename != '.'; ++i)
+  for (i = 0; i < 8 && ! STOP_SET (*filename, MAP_DOT|MAP_NUL); ++i)
     *df++ = tolower ((unsigned char)*filename++);
 
   /* Now skip to the next dot.  */
-  while (*filename != '\0' && *filename != '.')
+  while (! STOP_SET (*filename, MAP_DOT|MAP_NUL))
     ++filename;
   if (*filename != '\0')
     {
       *df++ = *filename++;
-      for (i = 0; *filename != '\0' && i < 3 && *filename != '.'; ++i)
+      for (i = 0; i < 3 && ! STOP_SET (*filename, MAP_DOT|MAP_NUL); ++i)
         *df++ = tolower ((unsigned char)*filename++);
     }
 
   /* Look for more dots.  */
-  while (*filename != '\0' && *filename != '.')
+  while (! STOP_SET (*filename, MAP_DOT|MAP_NUL))
     ++filename;
   if (*filename == '.')
     return filename;
diff --git a/file.c b/file.c
index b392aced2eb6e5afc87ef9bd2d4572b50d85d8ed..284e19a10380f18671d3b516f7dea3e4954aec5b 100644 (file)
--- a/file.c
+++ b/file.c
@@ -430,7 +430,7 @@ remove_intermediates (int sig)
 struct dep *
 split_prereqs (char *p)
 {
-  struct dep *new = PARSE_FILE_SEQ (&p, struct dep, '|', NULL, 0);
+  struct dep *new = PARSE_FILE_SEQ (&p, struct dep, MAP_PIPE, NULL, 0);
 
   if (*p)
     {
@@ -439,7 +439,7 @@ split_prereqs (char *p)
       struct dep *ood;
 
       ++p;
-      ood = PARSE_FILE_SEQ (&p, struct dep, '\0', NULL, 0);
+      ood = PARSE_FILE_SEQ (&p, struct dep, MAP_NUL, NULL, 0);
 
       if (! new)
         new = ood;
index 896cbb2afc25fd5bb9209203b5ebc79b6dc5328d..431c0603740025e01909b5a2096467413100f1d2 100644 (file)
@@ -116,7 +116,7 @@ subst_expand (char *o, const char *text, const char *subst, const char *replace,
          or only at the ends of words, check that this case qualifies.  */
       if (by_word
           && ((p > text && !isblank ((unsigned char)p[-1]))
-              || (p[slen] != '\0' && !isblank ((unsigned char)p[slen]))))
+              || ! STOP_SET (p[slen], MAP_BLANK|MAP_NUL)))
         /* Struck out.  Output the rest of the string that is
            no longer to be replaced.  */
         o = variable_buffer_output (o, subst, slen);
@@ -357,7 +357,7 @@ string_glob (char *line)
   struct nameseq *chain;
   unsigned int idx;
 
-  chain = PARSE_FILE_SEQ (&line, struct nameseq, '\0', NULL,
+  chain = PARSE_FILE_SEQ (&line, struct nameseq, MAP_NUL, NULL,
                           /* We do not want parse_file_seq to strip './'s.
                              That would break examples like:
                              $(patsubst ./%.c,obj/%.o,$(wildcard ./?*.c)).  */
@@ -507,16 +507,6 @@ func_flavor (char *o, char **argv, const char *funcname UNUSED)
   return o;
 }
 
-#ifdef VMS
-# define IS_PATHSEP(c) ((c) == ']')
-#else
-# ifdef HAVE_DOS_PATHS
-#  define IS_PATHSEP(c) ((c) == '/' || (c) == '\\')
-# else
-#  define IS_PATHSEP(c) ((c) == '/')
-# endif
-#endif
-
 
 static char *
 func_notdir_suffix (char *o, char **argv, const char *funcname)
@@ -529,17 +519,13 @@ func_notdir_suffix (char *o, char **argv, const char *funcname)
 
   int is_suffix = funcname[0] == 's';
   int is_notdir = !is_suffix;
+  int stop = MAP_PATHSEP | (is_suffix ? MAP_DOT : 0);
   while ((p2 = find_next_token (&list_iterator, &len)) != 0)
     {
-      const char *p = p2 + len;
+      const char *p = p2 + len - 1;
 
-
-      while (p >= p2 && (!is_suffix || *p != '.'))
-        {
-          if (IS_PATHSEP (*p))
-            break;
-          --p;
-        }
+      while (p >= p2 && ! STOP_SET (*p, stop))
+        --p;
 
       if (p >= p2)
         {
@@ -586,16 +572,12 @@ func_basename_dir (char *o, char **argv, const char *funcname)
 
   int is_basename = funcname[0] == 'b';
   int is_dir = !is_basename;
-
+  int stop = MAP_PATHSEP | (is_basename ? MAP_DOT : 0) | MAP_NUL;
   while ((p2 = find_next_token (&p3, &len)) != 0)
     {
-      const char *p = p2 + len;
-      while (p >= p2 && (!is_basename  || *p != '.'))
-        {
-          if (IS_PATHSEP (*p))
-            break;
-          --p;
-        }
+      const char *p = p2 + len - 1;
+      while (p >= p2 && ! STOP_SET (*p, stop))
+        --p;
 
       if (p >= p2 && (is_dir))
         o = variable_buffer_output (o, p2, ++p - p2);
@@ -1984,9 +1966,9 @@ abspath (const char *name, char *apath)
       strcpy (apath, starting_directory);
 
 #ifdef HAVE_DOS_PATHS
-      if (IS_PATHSEP(name[0]))
+      if (STOP_SET (name[0], MAP_PATHSEP))
         {
-          if (IS_PATHSEP(name[1]))
+          if (STOP_SET (name[1], MAP_PATHSEP))
             {
               /* A UNC.  Don't prepend a drive letter.  */
               apath[0] = name[0];
@@ -2011,7 +1993,7 @@ abspath (const char *name, char *apath)
       /* Get past the root, since we already copied it.  */
       name += root_len;
 #ifdef HAVE_DOS_PATHS
-      if (!IS_PATHSEP(apath[2]))
+      if (! STOP_SET (apath[2], MAP_PATHSEP))
         {
           /* Convert d:foo into d:./foo and increase root_len.  */
           apath[2] = '.';
@@ -2031,11 +2013,11 @@ abspath (const char *name, char *apath)
       unsigned long len;
 
       /* Skip sequence of multiple path-separators.  */
-      while (IS_PATHSEP(*start))
+      while (STOP_SET (*start, MAP_PATHSEP))
         ++start;
 
       /* Find end of path component.  */
-      for (end = start; *end != '\0' && !IS_PATHSEP(*end); ++end)
+      for (end = start; ! STOP_SET (*end, MAP_PATHSEP|MAP_NUL); ++end)
         ;
 
       len = end - start;
@@ -2048,11 +2030,12 @@ abspath (const char *name, char *apath)
         {
           /* Back up to previous component, ignore if at root already.  */
           if (dest > apath + root_len)
-            for (--dest; !IS_PATHSEP(dest[-1]); --dest);
+            for (--dest; ! STOP_SET (dest[-1], MAP_PATHSEP); --dest)
+              ;
         }
       else
         {
-          if (!IS_PATHSEP(dest[-1]))
+          if (! STOP_SET (dest[-1], MAP_PATHSEP))
             *dest++ = '/';
 
           if (dest + len >= apath_limit)
@@ -2065,7 +2048,7 @@ abspath (const char *name, char *apath)
     }
 
   /* Unless it is root strip trailing separator.  */
-  if (dest > apath + root_len && IS_PATHSEP(dest[-1]))
+  if (dest > apath + root_len && STOP_SET (dest[-1], MAP_PATHSEP))
     --dest;
 
   *dest = '\0';
index 9712780d34130597fc9afb98cab1e60fb4848f56..97233a629bfceeebe88db968a0fe697769964c29 100644 (file)
@@ -634,7 +634,7 @@ pattern_search (struct file *file, int archive,
                   p = variable_expand_for_file (depname, file);
 
                   /* Parse the expanded string. */
-                  dl = PARSE_FILE_SEQ (&p, struct dep, order_only ? '\0' : '|',
+                  dl = PARSE_FILE_SEQ (&p, struct dep, order_only ? MAP_NUL : MAP_PIPE,
                                        add_dir ? dir : NULL, 0);
 
                   for (d = dl; d != NULL; d = d->next)
diff --git a/job.c b/job.c
index 507b90db7dfb6c02b52838279e17909d3af0f25b..ef24caa09b0531fbe114bf338032f3f5fa068114 100644 (file)
--- a/job.c
+++ b/job.c
@@ -459,7 +459,7 @@ is_bourne_compatible_shell (const char *path)
       len = strlen (unix_shells[i]);
 #if defined(WINDOWS32) || defined(__MSDOS__)
       if ((strncasecmp (name, unix_shells[i], len) == 0) &&
-          (strlen (name) >= len && (name[len] == '\0' || name[len] == '.')))
+          (strlen (name) >= len && STOP_SET (name[len], MAP_DOT|MAP_NUL)))
 #else
       if ((strncmp (name, unix_shells[i], len) == 0) &&
           (strlen (name) >= len && name[len] == '\0'))
diff --git a/main.c b/main.c
index a14f34b723b695a8300ad859323e7a15f5d51016..147f77d768e12b615aff410529d8e9fce703fa03 100644 (file)
--- a/main.c
+++ b/main.c
@@ -548,6 +548,13 @@ int not_parallel;
    warning at the end of the run. */
 
 int clock_skew_detected;
+
+/* Map of possible stop characters for searching strings.  */
+#ifndef UCHAR_MAX
+# define UCHAR_MAX 255
+#endif
+unsigned short stopchar_map[UCHAR_MAX + 1] = {0};
+
 \f
 /* Mask of signals that are being caught with fatal_error_signal.  */
 
@@ -590,6 +597,41 @@ initialize_global_hash_tables (void)
   hash_init_function_table ();
 }
 
+/* This character map locate stop chars when parsing GNU makefiles.
+   Each element is true if we should stop parsing on that character.  */
+
+static void
+initialize_stopchar_map ()
+{
+  int i;
+
+  stopchar_map[(int)'\0'] = MAP_NUL;
+  stopchar_map[(int)'#'] = MAP_COMMENT;
+  stopchar_map[(int)';'] = MAP_SEMI;
+  stopchar_map[(int)'='] = MAP_EQUALS;
+  stopchar_map[(int)':'] = MAP_COLON;
+  stopchar_map[(int)'%'] = MAP_PERCENT;
+  stopchar_map[(int)'|'] = MAP_PIPE;
+  stopchar_map[(int)'.'] = MAP_DOT;
+  stopchar_map[(int)','] = MAP_COMMA;
+  stopchar_map[(int)'$'] = MAP_VARIABLE;
+
+  stopchar_map[(int)'/'] = MAP_PATHSEP;
+#if defined(VMS)
+  stopchar_map[(int)']'] = MAP_PATHSEP;
+#elif defined(HAVE_DOS_PATHS)
+  stopchar_map[(int)'\\'] = MAP_PATHSEP;
+#endif
+
+  for (i = 1; i <= UCHAR_MAX; ++i)
+    {
+      if (isblank(i))
+        stopchar_map[i] = MAP_BLANK;
+      if (isspace(i))
+        stopchar_map[i] |= MAP_SPACE;
+    }
+}
+
 static const char *
 expand_command_line_file (char *name)
 {
@@ -1026,6 +1068,8 @@ main (int argc, char **argv, char **envp)
   no_default_sh_exe = 1;
 #endif
 
+  initialize_stopchar_map();
+
 #ifdef SET_STACK_SIZE
  /* Get rid of any avoidable limit on stack size.  */
   {
@@ -1278,7 +1322,7 @@ main (int argc, char **argv, char **envp)
         int do_not_define = 0;
         char *ep = envp[i];
 
-        while (*ep != '\0' && *ep != '=')
+        while (! STOP_SET (*ep, MAP_EQUALS))
           ++ep;
 #ifdef WINDOWS32
         if (!unix_path && strneq (envp[i], "PATH=", 5))
@@ -2420,7 +2464,7 @@ main (int argc, char **argv, char **envp)
             {
               struct nameseq *ns;
 
-              ns = PARSE_FILE_SEQ (&p, struct nameseq, '\0', NULL, 0);
+              ns = PARSE_FILE_SEQ (&p, struct nameseq, MAP_NUL, NULL, 0);
               if (ns)
                 {
                   /* .DEFAULT_GOAL should contain one target. */
index a145970b5538196fdd35dc45fc34d6ff99d1f2ac..f119680716c85ff38b65ce662b54a0ab53d9dea6 100644 (file)
--- a/makeint.h
+++ b/makeint.h
@@ -364,7 +364,6 @@ char *strsignal (int signum);
 
 void sync_Path_environment (void);
 int w32_kill (pid_t pid, int sig);
-char *end_of_token_w32 (const char *s, char stopchar);
 int find_and_set_default_shell (const char *token);
 
 /* indicates whether or not we have Bourne shell */
@@ -382,6 +381,34 @@ extern int unixy_shell;
 #define WIN32_LEAN_AND_MEAN
 #endif  /* WINDOWS32 */
 
+#define ANY_SET(_v,_m)  (((_v)&(_m)) != 0)
+#define NONE_SET(_v,_m) (! ANY_SET ((_v),(_m)))
+
+#define MAP_NUL         0x0001
+#define MAP_BLANK       0x0002
+#define MAP_SPACE       0x0004
+#define MAP_COMMENT     0x0008
+#define MAP_SEMI        0x0010
+#define MAP_EQUALS      0x0020
+#define MAP_COLON       0x0040
+#define MAP_PERCENT     0x0080
+#define MAP_PIPE        0x0100
+#define MAP_DOT         0x0200
+#define MAP_COMMA       0x0400
+
+/* This means not only a '$', but skip the variable reference.  */
+#define MAP_VARIABLE    0x4000
+/* The set of characters which are path separators is OS-specific.  */
+#define MAP_PATHSEP     0x8000
+
+#ifdef VMS
+# define MAP_VMSCOMMA   MAP_COMMA
+#else
+# define MAP_VMSCOMMA   0x0000
+#endif
+
+#define STOP_SET(_v,_m) ANY_SET (stopchar_map[(int)(_v)],(_m))
+
 #if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT)
 # define SET_STACK_SIZE
 #endif
@@ -555,6 +582,8 @@ extern const gmk_floc **expanding_var;
 
 extern char **environ;
 
+extern unsigned short stopchar_map[];
+
 extern int just_print_flag, silent_flag, ignore_errors_flag, keep_going_flag;
 extern int print_data_base_flag, question_flag, touch_flag, always_make_flag;
 extern int env_overrides, no_builtin_rules_flag, no_builtin_variables_flag;
diff --git a/misc.c b/misc.c
index d89b29bbea5995da2dd7df2f05266fd2d5933b65..1b1441b1dd770c2efc6a90eb297bfb824cc34b00 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -483,41 +483,11 @@ lindex (const char *s, const char *limit, int c)
 char *
 end_of_token (const char *s)
 {
-  while (*s != '\0' && !isblank ((unsigned char)*s))
+  while (! STOP_SET (*s, MAP_BLANK|MAP_NUL))
     ++s;
   return (char *)s;
 }
 
-#ifdef WINDOWS32
-/*
- * Same as end_of_token, but take into account a stop character
- */
-char *
-end_of_token_w32 (const char *s, char stopchar)
-{
-  const char *p = s;
-  int backslash = 0;
-
-  while (*p != '\0' && *p != stopchar
-         && (backslash || !isblank ((unsigned char)*p)))
-    {
-      if (*p++ == '\\')
-        {
-          backslash = !backslash;
-          while (*p == '\\')
-            {
-              backslash = !backslash;
-              ++p;
-            }
-        }
-      else
-        backslash = 0;
-    }
-
-  return (char *)p;
-}
-#endif
-
 /* Return the address of the first nonwhitespace or null in the string S.  */
 
 char *
diff --git a/read.c b/read.c
index d6e6fcb11edc2958046fcf744ec3b0b75cd70e0c..07bc8da99dc53f92b4e745fdf806e446b05c08ec 100644 (file)
--- a/read.c
+++ b/read.c
@@ -155,8 +155,7 @@ static void record_target_var (struct nameseq *filenames, char *defn,
 static enum make_word_type get_next_mword (char *buffer, char *delim,
                                            char **startp, unsigned int *length);
 static void remove_comments (char *line);
-static char *find_char_unquote (char *string, int stop1, int stop2,
-                                int blank, int ignorevars);
+static char *find_char_unquote (char *string, int map);
 static char *unescape_char (char *string, int c);
 
 
@@ -758,7 +757,7 @@ eval (struct ebuffer *ebuf, int set_default)
       if (in_ignored_define)
         {
           /* See if this is an endef line (plus optional comment).  */
-          if (word1eq ("endef") && (*p2 == '\0' || *p2 == '#'))
+          if (word1eq ("endef") && STOP_SET (*p2, MAP_COMMENT|MAP_NUL))
             in_ignored_define = 0;
 
           continue;
@@ -872,7 +871,7 @@ eval (struct ebuffer *ebuf, int set_default)
 
           /* Parse the list of file names.  Don't expand archive references!  */
           p2 = p;
-          files = PARSE_FILE_SEQ (&p2, struct nameseq, '\0', NULL,
+          files = PARSE_FILE_SEQ (&p2, struct nameseq, MAP_NUL, NULL,
                                   PARSEFS_NOAR);
           free (p);
 
@@ -930,7 +929,7 @@ eval (struct ebuffer *ebuf, int set_default)
           /* Parse the list of file names.
              Don't expand archive references or strip "./"  */
           p2 = p;
-          files = PARSE_FILE_SEQ (&p2, struct nameseq, '\0', NULL,
+          files = PARSE_FILE_SEQ (&p2, struct nameseq, MAP_NUL, NULL,
                                   PARSEFS_NOAR);
           free (p);
 
@@ -989,7 +988,7 @@ eval (struct ebuffer *ebuf, int set_default)
 
         /* Search the line for an unquoted ; that is not after an
            unquoted #.  */
-        cmdleft = find_char_unquote (line, ';', '#', 0, 1);
+        cmdleft = find_char_unquote (line, MAP_SEMI|MAP_COMMENT|MAP_VARIABLE);
         if (cmdleft != 0 && *cmdleft == '#')
           {
             /* We found a comment before a semicolon.  */
@@ -1036,7 +1035,7 @@ eval (struct ebuffer *ebuf, int set_default)
             if (cmdleft == 0)
               {
                 /* Look for a semicolon in the expanded line.  */
-                cmdleft = find_char_unquote (p2, ';', 0, 0, 0);
+                cmdleft = find_char_unquote (p2, MAP_SEMI);
 
                 if (cmdleft != 0)
                   {
@@ -1063,7 +1062,7 @@ eval (struct ebuffer *ebuf, int set_default)
                   }
               }
 
-            colonp = find_char_unquote (p2, ':', 0, 0, 0);
+            colonp = find_char_unquote (p2, MAP_COLON);
 #ifdef HAVE_DOS_PATHS
             /* The drive spec brain-damage strikes again...  */
             /* Note that the only separators of targets in this context
@@ -1072,7 +1071,7 @@ eval (struct ebuffer *ebuf, int set_default)
             while (colonp && (colonp[1] == '/' || colonp[1] == '\\') &&
                    colonp > p2 && isalpha ((unsigned char)colonp[-1]) &&
                    (colonp == p2 + 1 || strchr (" \t(", colonp[-2]) != 0))
-              colonp = find_char_unquote (colonp + 1, ':', 0, 0, 0);
+              colonp = find_char_unquote (colonp + 1, MAP_COLON);
 #endif
             if (colonp != 0)
               break;
@@ -1108,7 +1107,7 @@ eval (struct ebuffer *ebuf, int set_default)
         /* Make the colon the end-of-string so we know where to stop
            looking for targets.  Start there again once we're done.  */
         *colonp = '\0';
-        filenames = PARSE_FILE_SEQ (&p2, struct nameseq, '\0', NULL, 0);
+        filenames = PARSE_FILE_SEQ (&p2, struct nameseq, MAP_NUL, NULL, 0);
         *colonp = ':';
         p2 = colonp;
 
@@ -1163,7 +1162,7 @@ eval (struct ebuffer *ebuf, int set_default)
 
         /* This is a normal target, _not_ a target-specific variable.
            Unquote any = in the dependency list.  */
-        find_char_unquote (lb_next, '=', 0, 0, 0);
+        find_char_unquote (lb_next, MAP_EQUALS);
 
         /* Remember the command prefix for this target.  */
         prefix = cmd_prefix;
@@ -1181,7 +1180,7 @@ eval (struct ebuffer *ebuf, int set_default)
             /* Look for a semicolon in the expanded line.  */
             if (cmdleft == 0)
               {
-                cmdleft = find_char_unquote (p2, ';', 0, 0, 0);
+                cmdleft = find_char_unquote (p2, MAP_SEMI);
                 if (cmdleft != 0)
                   *(cmdleft++) = '\0';
               }
@@ -1235,7 +1234,7 @@ eval (struct ebuffer *ebuf, int set_default)
         if (p != 0)
           {
             struct nameseq *target;
-            target = PARSE_FILE_SEQ (&p2, struct nameseq, ':', NULL,
+            target = PARSE_FILE_SEQ (&p2, struct nameseq, MAP_COLON, NULL,
                                      PARSEFS_NOGLOB);
             ++p2;
             if (target == 0)
@@ -1387,7 +1386,7 @@ remove_comments (char *line)
 {
   char *comment;
 
-  comment = find_char_unquote (line, '#', 0, 0, 0);
+  comment = find_char_unquote (line, MAP_COMMENT);
 
   if (comment != 0)
     /* Cut off the line at the #.  */
@@ -1620,7 +1619,7 @@ conditional_line (char *line, int len, const gmk_floc *flocp)
          and cannot be an 'else' or 'endif'.  */
 
       /* Find the length of the next word.  */
-      for (p = line+1; *p != '\0' && !isspace ((unsigned char)*p); ++p)
+      for (p = line+1; ! STOP_SET (*p, MAP_SPACE|MAP_NUL); ++p)
         ;
       len = p - line;
 
@@ -2211,37 +2210,24 @@ record_files (struct nameseq *filenames, const char *pattern,
    STOPCHAR _cannot_ be '$' if IGNOREVARS is true.  */
 
 static char *
-find_char_unquote (char *string, int stop1, int stop2, int blank,
-                   int ignorevars)
+find_char_unquote (char *string, int map)
 {
   unsigned int string_len = 0;
   char *p = string;
 
-  if (ignorevars)
-    ignorevars = '$';
+  /* Always stop on NUL.  */
+  map |= MAP_NUL;
 
   while (1)
     {
-      if (stop2 && blank)
-        while (*p != '\0' && *p != ignorevars && *p != stop1 && *p != stop2
-               && ! isblank ((unsigned char) *p))
-          ++p;
-      else if (stop2)
-        while (*p != '\0' && *p != ignorevars && *p != stop1 && *p != stop2)
-          ++p;
-      else if (blank)
-        while (*p != '\0' && *p != ignorevars && *p != stop1
-               && ! isblank ((unsigned char) *p))
-          ++p;
-      else
-        while (*p != '\0' && *p != ignorevars && *p != stop1)
-          ++p;
+      while (! STOP_SET (*p, map))
+        ++p;
 
       if (*p == '\0')
         break;
 
       /* If we stopped due to a variable reference, skip over its contents.  */
-      if (*p == ignorevars)
+      if (STOP_SET (*p, MAP_VARIABLE))
         {
           char openparen = p[1];
 
@@ -2349,7 +2335,7 @@ unescape_char (char *string, int c)
 char *
 find_percent (char *pattern)
 {
-  return find_char_unquote (pattern, '%', 0, 0, 0);
+  return find_char_unquote (pattern, MAP_PERCENT);
 }
 
 /* Search STRING for an unquoted % and handle quoting.  Returns a pointer to
@@ -2372,7 +2358,7 @@ find_percent_cached (const char **string)
 
   while (1)
     {
-      while (*p != '\0' && *p != '%')
+      while (! STOP_SET (*p, MAP_PERCENT|MAP_NUL))
         ++p;
 
       if (*p == '\0')
@@ -2987,7 +2973,7 @@ tilde_expand (const char *name)
   */
 
 void *
-parse_file_seq (char **stringp, unsigned int size, int stopchar,
+parse_file_seq (char **stringp, unsigned int size, int stopmap,
                 const char *prefix, int flags)
 {
   extern void dir_setup_glob (glob_t *glob);
@@ -2997,7 +2983,7 @@ parse_file_seq (char **stringp, unsigned int size, int stopchar,
   static char *tmpbuf = NULL;
   static int tmpbuf_len = 0;
 
-  int cachep = (! (flags & PARSEFS_NOCACHE));
+  int cachep = NONE_SET (flags, PARSEFS_NOCACHE);
 
   struct nameseq *new = 0;
   struct nameseq **newp = &new;
@@ -3012,16 +2998,13 @@ parse_file_seq (char **stringp, unsigned int size, int stopchar,
   glob_t gl;
   char *tp;
 
-#ifdef VMS
-# define VMS_COMMA ','
-#else
-# define VMS_COMMA 0
-#endif
+  /* Always stop on NUL.  */
+  stopmap |= MAP_NUL;
 
   if (size < sizeof (struct nameseq))
     size = sizeof (struct nameseq);
 
-  if (! (flags & PARSEFS_NOGLOB))
+  if (NONE_SET (flags, PARSEFS_NOGLOB))
     dir_setup_glob (&gl);
 
   /* Get enough temporary space to construct the largest possible target.  */
@@ -3053,39 +3036,39 @@ parse_file_seq (char **stringp, unsigned int size, int stopchar,
 
       /* Skip whitespace; at the end of the string or STOPCHAR we're done.  */
       p = next_token (p);
-      if (*p == '\0' || *p == stopchar)
+      if (STOP_SET (*p, stopmap))
         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);
+      p = find_char_unquote (p, stopmap|MAP_VMSCOMMA|MAP_BLANK);
 #ifdef VMS
         /* convert comma separated list to space separated */
       if (p && *p == ',')
         *p =' ';
 #endif
 #ifdef _AMIGA
-      if (stopchar == ':' && p && *p == ':'
+      if (p && STOP_SET (*p, stopmap & MAP_COLON)
           && !(isspace ((unsigned char)p[1]) || !p[1]
                || isspace ((unsigned char)p[-1])))
-        p = find_char_unquote (p+1, stopchar, VMS_COMMA, 1, 0);
+        p = find_char_unquote (p+1, stopmap|MAP_VMSCOMMA|MAP_BLANK);
 #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 == ':')
+    if (stopmap | MAP_COLON)
       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);
+        p = find_char_unquote (p + 1, stopmap|MAP_VMSCOMMA|MAP_BLANK);
 #endif
       if (p == 0)
         p = s + strlen (s);
 
       /* Strip leading "this directory" references.  */
-      if (! (flags & PARSEFS_NOSTRIP))
+      if (NONE_SET (flags, PARSEFS_NOSTRIP))
 #ifdef VMS
         /* Skip leading '[]'s.  */
         while (p - s > 2 && s[0] == '[' && s[1] == ']')
@@ -3159,7 +3142,7 @@ parse_file_seq (char **stringp, unsigned int size, int stopchar,
          Finally, note that archive groups must end with ')' as the last
          character, so ensure there's some word ending like that before
          considering this an archive group.  */
-      if (! (flags & PARSEFS_NOAR)
+      if (NONE_SET (flags, PARSEFS_NOAR)
           && tp == tmpbuf && tp[0] != '(' && tp[nlen-1] != ')')
         {
           char *n = strchr (tp, '(');
@@ -3175,8 +3158,7 @@ parse_file_seq (char **stringp, unsigned int size, int stopchar,
                   /* Find the end of this word.  We don't want to unquote and
                      we don't care about quoting since we're looking for the
                      last char in the word. */
-                  while (*e != '\0' && *e != stopchar && *e != VMS_COMMA
-                         && ! isblank ((unsigned char) *e))
+                  while (! STOP_SET (*e, stopmap|MAP_BLANK|MAP_VMSCOMMA))
                     ++e;
                   /* If we didn't move, we're done now.  */
                   if (e == o)
@@ -3225,7 +3207,7 @@ parse_file_seq (char **stringp, unsigned int size, int stopchar,
 
       /* 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)
+      if (ANY_SET (flags, PARSEFS_NOGLOB))
         {
           NEWELT (concat (2, prefix, tmpbuf));
           continue;
@@ -3248,7 +3230,7 @@ parse_file_seq (char **stringp, unsigned int size, int stopchar,
       /* 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 (! (flags & PARSEFS_NOAR) && ar_name (name))
+      if (NONE_SET (flags, PARSEFS_NOAR) && ar_name (name))
         {
           ar_parse_name (name, &arname, &memname);
           name = arname;
@@ -3256,7 +3238,7 @@ parse_file_seq (char **stringp, unsigned int size, int stopchar,
 #endif /* !NO_ARCHIVES */
 
       /* glob() is expensive: don't call it unless we need to.  */
-      if (!(flags & PARSEFS_EXISTS) && strpbrk (name, "?*[") == NULL)
+      if (NONE_SET (flags, PARSEFS_EXISTS) && strpbrk (name, "?*[") == NULL)
         {
           globme = 0;
           i = 1;
@@ -3276,7 +3258,7 @@ parse_file_seq (char **stringp, unsigned int size, int stopchar,
 
           case GLOB_NOMATCH:
             /* If we want only existing items, skip this one.  */
-            if (flags & PARSEFS_EXISTS)
+            if (ANY_SET (flags, PARSEFS_EXISTS))
               {
                 i = 0;
                 break;
diff --git a/rule.c b/rule.c
index a1f1e7af561fcf1540906ab6744cc59f0826a3fc..9a9e2294a4a34cf075c5aa23a5ff9324ef5a4dc6 100644 (file)
--- a/rule.c
+++ b/rule.c
@@ -373,7 +373,7 @@ install_pattern_rule (struct pspec *p, int terminal)
   ++r->suffixes[0];
 
   ptr = p->dep;
-  r->deps = PARSE_FILE_SEQ (&ptr, struct dep, '\0', NULL, 0);
+  r->deps = PARSE_FILE_SEQ (&ptr, struct dep, MAP_NUL, NULL, 0);
 
   if (new_pattern_rule (r, 0))
     {
index f76b02bf562687f9aa6ad883a514a1c0305f634d..74e866aeb46d6e2ad85cf2cdf6c58852c2770931 100644 (file)
@@ -1419,7 +1419,7 @@ parse_variable_definition (const char *p, struct variable *var)
       int c = *p++;
 
       /* If we find a comment or EOS, it's not a variable definition.  */
-      if (c == '\0' || c == '#')
+      if (STOP_SET (c, MAP_COMMENT|MAP_NUL))
         return NULL;
 
       if (c == '$')