Index: trunk/src/kmk/kmkbuiltin.c
===================================================================
--- trunk/src/kmk/kmkbuiltin.c	(revision 3039)
+++ trunk/src/kmk/kmkbuiltin.c	(revision 3040)
@@ -43,4 +43,5 @@
 #endif
 
+
 int kmk_builtin_command(const char *pszCmd, struct child *pChild, char ***ppapszArgvToSpawn, pid_t *pPidSpawned)
 {
@@ -48,4 +49,7 @@
     char      **argv;
     int         rc;
+    char       *pszzCmd;
+    char       *pszDst;
+    int         fOldStyle = 0;
 
     /*
@@ -54,5 +58,5 @@
     if (strncmp(pszCmd, "kmk_builtin_", sizeof("kmk_builtin_") - 1))
     {
-        printf("kmk_builtin: Invalid command prefix '%s'!\n", pszCmd);
+        fprintf(stderr, "kmk_builtin: Invalid command prefix '%s'!\n", pszCmd);
         return 1;
     }
@@ -61,48 +65,21 @@
      * Parse arguments.
      */
-    argc = 0;
-    argv = NULL;
-    while (*pszCmd)
-    {
-        const char *pszEnd;
-        const char *pszNext;
-        int         fEscaped = 0;
-        size_t      cch;
+    rc      = 0;
+    argc    = 0;
+    argv    = NULL;
+    pszzCmd = pszDst = (char *)strdup(pszCmd);
+    if (!pszDst)
+    {
+        fprintf(stderr, "kmk_builtin: out of memory. argc=%d\n", argc);
+        return 1;
+    }
+    do
+    {
+        const char * const pszSrcStart = pszCmd;
+        char ch;
+        char chQuote;
 
         /*
-         * Find start and end of the current command.
-         */
-        if (*pszCmd == '"' || *pszCmd == '\'')
-        {
-            pszEnd = pszCmd;
-            for (;;)
-            {
-                pszEnd = strchr(pszEnd + 1, *pszCmd);
-                if (!pszEnd)
-                {
-                    printf("kmk_builtin: Unbalanced quote in argument %d: %s\n", argc + 1, pszCmd);
-                    while (argc--)
-                        free(argv[argc]);
-                    free(argv);
-                    return 1;
-                }
-                /* two quotes -> escaped quote. */
-                if (pszEnd[0] != pszEnd[1])
-                    break;
-                fEscaped = 1;
-            }
-            pszNext = pszEnd + 1;
-            pszCmd++;
-        }
-        else
-        {
-            pszEnd = pszCmd;
-            while (!isspace(*pszEnd) && *pszEnd)
-                pszEnd++;
-            pszNext = pszEnd;
-        }
-
-        /*
-         * Make argument.
+         * Start new argument.
          */
         if (!(argc % 16))
@@ -111,56 +88,135 @@
             if (!pv)
             {
-                printf("kmk_builtin: out of memory. argc=%d\n", argc);
+                fprintf(stderr, "kmk_builtin: out of memory. argc=%d\n", argc);
+                rc = 1;
                 break;
             }
             argv = (char **)pv;
         }
-        cch = pszEnd - pszCmd;
-        argv[argc] = malloc(cch + 1);
-        if (!argv[argc])
+        argv[argc++] = pszDst;
+        argv[argc]   = NULL;
+
+        if (!fOldStyle)
         {
-            printf("kmk_builtin: out of memory. argc=%d len=%d\n", argc, (int)(pszEnd - pszCmd + 1));
+            /*
+             * Process the next argument, bourne style.
+             */
+            chQuote = 0;
+            ch = *pszCmd++;
+            do
+            {
+                /* Unquoted mode? */
+                if (chQuote == 0)
+                {
+                    if (ch != '\'' && ch != '"')
+                    {
+                        if (!isspace(ch))
+                        {
+                            if (ch != '\\')
+                                *pszDst++ = ch;
+                            else
+                            {
+                                ch = *pszCmd++;
+                                if (ch)
+                                    *pszDst++ = ch;
+                                else
+                                {
+                                    fprintf(stderr, "kmk_builtin: Incomplete escape sequence in argument %d: %s\n",
+                                            argc, pszSrcStart);
+                                    rc = 1;
+                                    break;
+                                }
+                            }
+                        }
+                        else
+                            break;
+                    }
+                    else
+                        chQuote = ch;
+                }
+                /* Quoted mode */
+                else if (ch != chQuote)
+                {
+                    if (   ch != '\\'
+                        || chQuote == '\'')
+                        *pszDst++ = ch;
+                    else
+                    {
+                        ch = *pszCmd++;
+                        if (ch)
+                        {
+                            if (   ch != '\\'
+                                && ch != '"'
+                                && ch != '`'
+                                && ch != '$'
+                                && ch != '\n')
+                                *pszDst++ = '\\';
+                            *pszDst++ = ch;
+                        }
+                        else
+                        {
+                            fprintf(stderr, "kmk_builtin: Unbalanced quote in argument %d: %s\n", argc, pszSrcStart);
+                            rc = 1;
+                            break;
+                        }
+                    }
+                }
+                else
+                    chQuote = 0;
+            } while ((ch = *pszCmd++) != '\0');
+        }
+        else
+        {
+            /*
+             * Old style in case we ever need it.
+             */
+            ch = *pszCmd++;
+            if (ch != '"' && ch != '\'')
+            {
+                do
+                    *pszDst++ = ch;
+                while ((ch = *pszCmd++) != '\0' && !isspace(ch));
+            }
+            else
+            {
+                chQuote = ch;
+                for (;;)
+                {
+                    char *pszEnd = strchr(pszCmd, chQuote);
+                    if (pszEnd)
+                    {
+                        fprintf(stderr, "kmk_builtin: Unbalanced quote in argument %d: %s\n", argc, pszSrcStart);
+                        rc = 1;
+                        break;
+                    }
+                    memcpy(pszDst, pszCmd, pszEnd - pszCmd);
+                    pszDst += pszEnd - pszCmd;
+                    if (pszEnd[1] != chQuote)
+                        break;
+                    *pszDst++ = chQuote;
+                }
+            }
+        }
+        *pszDst++ = '\0';
+
+        /*
+         * Skip argument separators (IFS=space() for now).  Check for EOS.
+         */
+        if (ch != 0)
+            while ((ch = *pszCmd) && isspace(ch))
+                pszCmd++;
+        if (ch == 0)
             break;
-        }
-        memcpy(argv[argc], pszCmd, cch);
-        argv[argc][cch] = '\0';
-
-        /* unescape quotes? */
-        if (fEscaped)
-        {
-            char ch = pszCmd[-1];
-            char *pszW = argv[argc];
-            char *pszR = argv[argc];
-            while (*pszR)
-            {
-                if (*pszR == ch)
-                    pszR++;
-                *pszW++ = *pszR++;
-            }
-            *pszW = '\0';
-        }
-        /* commit it */
-        argv[++argc] = NULL;
-
-        /*
-         * Next
-         */
-        pszCmd = pszNext;
-        while (isspace(*pszCmd) && *pszCmd)
-            pszCmd++;
-    }
+    } while (rc == 0);
 
     /*
      * Execute the command if parsing was successful.
      */
-    if (!*pszCmd)
+    if (rc == 0)
         rc = kmk_builtin_command_parsed(argc, argv, pChild, ppapszArgvToSpawn, pPidSpawned);
-    else
-        rc = 1;
 
     /* clean up and return. */
-    while (argc--)
-        free(argv[argc]);
     free(argv);
+    free(pszzCmd);
     return rc;
 }
@@ -178,5 +234,5 @@
     if (strncmp(pszCmd, "kmk_builtin_", sizeof("kmk_builtin_") - 1))
     {
-        printf("kmk_builtin: Invalid command prefix '%s'!\n", pszCmd);
+        fprintf(stderr, "kmk_builtin: Invalid command prefix '%s'!\n", pszCmd);
         return 1;
     }
@@ -241,5 +297,5 @@
     else
     {
-        printf("kmk_builtin: Unknown command '%s'!\n", pszCmd);
+        fprintf(stderr, "kmk_builtin: Unknown command '%s'!\n", pszCmd);
         return 1;
     }
