Index: /trunk/src/kmk/kbuild.c
===================================================================
--- /trunk/src/kmk/kbuild.c	(revision 3321)
+++ /trunk/src/kmk/kbuild.c	(revision 3322)
@@ -382,16 +382,16 @@
 kbuild_apply_defpath(struct variable *pDefPath, char **ppsz, unsigned int *pcch, unsigned int *pcchAlloc, int fCanFree)
 {
-    const char *pszIterator;
-    const char *pszInCur;
     unsigned int cchInCur;
     unsigned int cchMaxRelative = 0;
-    unsigned int cRelativePaths;
+    const char *pszInCur;
 
     /*
      * The first pass, count the relative paths.
      */
-    cRelativePaths = 0;
-    pszIterator = *ppsz;
-    while ((pszInCur = find_next_token(&pszIterator, &cchInCur)) != NULL)
+    const char *pszIterator = *ppsz;
+    const char * const pszEos = pszIterator + *pcch;
+    unsigned int cRelativePaths = 0;
+    assert(*pszEos == '\0');
+    while ((pszInCur = find_next_file_token(&pszIterator, pszEos, &cchInCur)) != NULL)
     {
         /* is relative? */
@@ -438,5 +438,5 @@
         cRelativePaths = 0;
         pszIterator = *ppsz;
-        while ((pszInCur = find_next_token(&pszIterator, &cchInCur)))
+        while ((pszInCur = find_next_file_token(&pszIterator, pszEos, &cchInCur)))
         {
             /* is relative? */
Index: /trunk/src/kmk/makeint.h
===================================================================
--- /trunk/src/kmk/makeint.h	(revision 3321)
+++ /trunk/src/kmk/makeint.h	(revision 3322)
@@ -679,4 +679,5 @@
 #ifdef KMK
 char *find_next_token_eos (const char **ptr, const char *eos, unsigned int *lengthptr);
+char *find_next_file_token (const char **ptr, const char *eos, unsigned int *lengthptr);
 #endif
 #ifndef CONFIG_WITH_VALUE_LENGTH
Index: /trunk/src/kmk/misc.c
===================================================================
--- /trunk/src/kmk/misc.c	(revision 3321)
+++ /trunk/src/kmk/misc.c	(revision 3322)
@@ -600,5 +600,42 @@
 #endif
 }
+
 #ifdef KMK
+/* Finds the ends of the variable expansion starting at S, stopping at EOS if
+   not found before. */
+static char *find_end_of_variable_expansion (const char *s, char const *eos)
+{
+  char const openparen  = s[1];
+  char const closeparen = openparen == '(' ? ')' : '}';
+  int levels = 0;
+
+  assert (s[0] == '$');
+  assert (s[1] == '(' || s[1] == '{');
+
+  s += 2;
+  while (s != eos)
+    {
+      unsigned char ch = *s;
+      if (ch != '\0')
+        {
+          if (ch != closeparen)
+            {
+              if (ch != openparen)
+                { /* likely */ }
+              else
+                levels++;
+            }
+          else if (levels <= 1)
+            break;
+          else
+            levels--;
+        }
+      else
+        break;
+      s++;
+    }
+
+  return (char *)s;
+}
 
 /* Same as find_next_token with two exception:
@@ -611,16 +648,16 @@
   const char *p = *ptr;
   const char *e;
-  int level = 0;
 
   /* skip blanks */
-  for (; p != eos; p++)
-    {
-      unsigned char ch = *p;
-      if (!MY_IS_BLANK(ch))
-        {
-          if (!ch)
-            return NULL;
-          break;
-        }
+  while (p != eos)
+    {
+      unsigned char const ch = *p;
+      unsigned int const map = stopchar_map[ch] & (MAP_NUL | MAP_BLANK);
+      if (map & MAP_BLANK)
+        p++;
+      else if (!(map & MAP_NUL))
+        break;
+      else
+        return NULL;
     }
   if (p == eos)
@@ -628,22 +665,101 @@
 
   /* skip ahead until EOS or blanks. */
-  for (e = p; e != eos; e++)
-    {
-      unsigned char ch = *e;
-      if (MY_IS_BLANK_OR_EOS(ch))
-        {
-          if (!ch || level == 0)
+  e = p;
+  while (e != eos)
+    {
+      unsigned char const ch = *e;
+      unsigned int const map = stopchar_map[ch] & (MAP_NUL | MAP_BLANK | MAP_VARIABLE);
+      if (!map)
+        e++; /* likely */
+      /* Dollar can be escaped by duplication ($$) and when not, they need to
+         be skipped over. */
+      else if (map & MAP_VARIABLE)
+        {
+          e++;
+          if (&e[1] != eos)
+            {
+              unsigned ch2 = *e;
+              if (ch2 == ch)
+                e++; /* escaped */
+              else if (ch == '(' || ch == '}')
+                e = find_end_of_variable_expansion (e - 1, eos);
+            }
+          else
             break;
         }
-      else if (ch == '$')
-        {
-          if (&e[1] != eos && (e[1] == '(' || e[1] == '{'))
+      else
+        break; /* MAP_NUL or MAP_BLANK */
+    }
+
+  *ptr = e;
+  if (lengthptr != 0)
+    *lengthptr = e - p;
+
+  return (char *)p;
+}
+
+/* Same as find_next_token_eos but takes GNU make quoting into account,
+   but without doing any unquoting like find_char_unquote & parse_file_seq. */
+
+char *
+find_next_file_token (const char **ptr, const char *eos, unsigned int *lengthptr)
+{
+  const char *p = *ptr;
+  const char *e;
+
+  /* skip blanks */
+  while (p != eos)
+    {
+      unsigned char const ch = *p;
+      unsigned int const map = stopchar_map[ch] & (MAP_NUL | MAP_BLANK);
+      if (map & MAP_BLANK)
+        p++;
+      else if (!(map & MAP_NUL))
+        break;
+      else
+        return NULL;
+    }
+  if (p == eos)
+    return NULL;
+
+  /* skip ahead until EOS or blanks. */
+  e = p;
+  while (e != eos)
+    {
+      unsigned char const ch = *e;
+      unsigned int const map = stopchar_map[ch] & (MAP_NUL | MAP_BLANK | MAP_VARIABLE);
+      if (!map)
+        e++; /* likely */
+      /* Dollar can be escaped by duplication ($$) and when not, they need to
+         be skipped over. */
+      else if (map & MAP_VARIABLE)
+        {
+          e++;
+          if (&e[1] != eos)
             {
-              level++;
-              e++;
+              unsigned ch2 = *e;
+              if (ch2 == ch)
+                e++; /* escaped */
+              else if (ch == '(' || ch == '}')
+                e = find_end_of_variable_expansion (e - 1, eos);
             }
-        }
-      else if ((ch == ')' || ch == '}') &&  level > 0)
-        level--;
+          else
+            break;
+        }
+      else if (map & MAP_NUL)
+        break;
+      /* A blank can be escaped using a backslash. */
+      else if (e[-1] != '\\')
+        break;
+      else
+        {
+          int slashes = 1;
+          while (&e[-slashes] != p && e[-slashes - 1] == '\\')
+            slashes++;
+          if (slashes & 1)
+            e++;
+          else
+            break;
+        }
     }
 
