New commands and bug fixes
authorRobert Pengelly <robertapengelly@hotmail.com>
Wed, 15 Oct 2025 03:40:28 +0000 (04:40 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Wed, 15 Oct 2025 03:40:28 +0000 (04:40 +0100)
Makefile.pdw [deleted file]
lib.c
lib.h
read.c
read.h
rule.c
variable.c
xmake.c

diff --git a/Makefile.pdw b/Makefile.pdw
deleted file mode 100644 (file)
index b269b7f..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#******************************************************************************
-# @file             Makefile.pdw
-#******************************************************************************
-AS=aswin
-CC=gccwin
-LD=ldwin
-
-COPTS=-S -O2 -fno-common -ansi -I. -I../pdos/pdpclib -I../pdos/src -D__WIN32__ -D__NOBIVA__ -D__PDOS__
-COBJ=cstr.o hashtab.o lib.o report.o read.o rule.o variable.o xmake.o
-
-all: clean xmake.exe
-
-xmake.exe: $(COBJ)
-  $(LD) -s -o xmake.exe ../pdos/pdpclib/w32start.o $(COBJ) ../pdos/pdpclib/msvcrt.a ../pdos/src/kernel32.a
-
-.c.o:
-  $(CC) $(COPTS) $<
-  $(AS) -o $@ $*.s
-  rm -f $*.s
-
-clean:
-  rm -f *.o xmake.exe
diff --git a/lib.c b/lib.c
index 94c69a5cb1dccf22d555dcf6300c06345b27a1fc..4931ba06c4f1d3ed0edf8941515f37a8ace75ecc 100644 (file)
--- a/lib.c
+++ b/lib.c
@@ -419,6 +419,32 @@ char *xstrndup (const char *__s, unsigned long __len) {
 
 }
 
+int xstrcasecmp (const char *__s1, const char *__s2) {
+
+    const unsigned char *p1 = (const unsigned char *) __s1;
+    const unsigned char *p2 = (const unsigned char *) __s2;
+    
+    while (*p1 != '\0') {
+    
+        if (tolower ((int) *p1) < tolower ((int) *p2)) {
+            return (-1);
+        } else if (tolower ((int) *p1) > tolower ((int) *p2)) {
+            return (1);
+        }
+        
+        p1++;
+        p2++;
+    
+    }
+    
+    if (*p2 == '\0') {
+        return (0);
+    }
+    
+    return (-1);
+
+}
+
 int parse_args (char **__args, int __cnt) {
 
     struct option *opt, *last;
diff --git a/lib.h b/lib.h
index d0afe68af5cd6495f8475b078aa5ecd6873cd617..871abcf4448b5dec40b0b244711e3b2ccfbb3672 100644 (file)
--- a/lib.h
+++ b/lib.h
@@ -18,12 +18,13 @@ struct option {
 };
 
 char *skip_whitespace (char *p);
+void dynarray_add (void *__ptab, unsigned long *__nb_ptr, void *__data);
 
 char *xstrdup (const char *__s);
 char *xstrndup (const char *__s, unsigned long __len);
 
+int xstrcasecmp (const char *__s1, const char *__s2);
 int parse_args (char **__args, int __cnt);
-void dynarray_add (void *__ptab, unsigned long *__nb_ptr, void *__data);
 
 void *xmalloc (unsigned long __sz);
 void *xrealloc (void *__ptr, unsigned long __sz);
diff --git a/read.c b/read.c
index b19c453184668664a4f26f2038e5002e28bdd821..b6cc7f8cbd410b533fb19082b6de0c65164bd627 100644 (file)
--- a/read.c
+++ b/read.c
@@ -172,7 +172,7 @@ static struct if_stack *cur_if_stack = 0;
 
 static void add_if_stack (void) {
 
-    struct if_stack *if_stack = xmalloc (sizeof *if_stack);
+    struct if_stack *if_stack = xmalloc (sizeof (*if_stack));
     
     if (cur_if_stack) {
         if_stack->prev_ignoring = cur_if_stack->ignoring;
@@ -265,22 +265,22 @@ static int read_lbuf (struct linebuf *lbuf, int set_default) {
     struct nameseq* filenames = 0;
     int ret;
     
-    char *cmds, *clean = 0, *depstr = 0, *q;
-    size_t clean_size = 0, cmds_idx = 0, cmds_sz = 256;
+    char *commands, *clean = 0, *depstr = 0, *q;
+    size_t clean_size = 0, commands_idx = 0, commands_sz = 256;
     
     char *colon, *semicolonp, *commentp;
     long lines_read;
     
     unsigned long line_no = 1;
-    cmds = xmalloc (cmds_sz);
+    commands = xmalloc (commands_sz + 1);
     
 #define     record_waiting_files()                                              \
     do {                                                                        \
         if (filenames) {                                                        \
-            record_files (lbuf->filename, line_no - 1, filenames, cmds, cmds_idx, depstr);                   \
-            filenames = 0;                                                      \
+            record_files (lbuf->filename, line_no - 1, filenames, commands,     \
+                commands_idx, depstr); filenames = 0;                           \
         }                                                                       \
-        cmds_idx = 0;                                                           \
+        commands_idx = 0;                                                       \
     } while (0)
     
     while ((lines_read = read_line (lbuf))) {
@@ -610,6 +610,8 @@ static int read_lbuf (struct linebuf *lbuf, int set_default) {
             continue;
         }
         
+        line = clean;
+        
         if (line[0] == ' ' || line[0] == '\t') {
         
             if (filenames) {
@@ -618,15 +620,15 @@ static int read_lbuf (struct linebuf *lbuf, int set_default) {
                     line++;
                 }
                 
-                if (cmds_idx + strlen (line) + 1 > cmds_sz) {
+                if (commands_idx + strlen (line) + 1 > commands_sz) {
                 
-                    cmds_sz = (cmds_idx + strlen (line) + 1) * 2;
-                    cmds = xrealloc (cmds, cmds_sz);
+                    commands_sz = (commands_idx + strlen (line) + 1) * 2;
+                    commands = xrealloc (commands, commands_sz);
                 
                 }
                 
                 src = line;
-                dst = &cmds[cmds_idx];
+                dst = &commands[commands_idx];
                 
                 for (; *src; src++, dst++) {
                 
@@ -645,8 +647,8 @@ static int read_lbuf (struct linebuf *lbuf, int set_default) {
                 
                 *dst = '\0';
                 
-                cmds_idx += dst - &cmds[cmds_idx] + 1;
-                cmds[cmds_idx - 1] = '\n';
+                commands_idx += dst - &commands[commands_idx] + 1;
+                commands[commands_idx - 1] = '\n';
                 
                 continue;
             
@@ -708,12 +710,7 @@ static int read_lbuf (struct linebuf *lbuf, int set_default) {
         
         }
         
-        if (*p == '$') {
-        
-            variable_expand_line (lbuf->filename, line_no, p);
-            continue;
-        
-        } else if (strchr (p, '=')) {
+        if (strchr (p, '=')) {
         
             record_waiting_files ();
             
@@ -722,6 +719,10 @@ static int read_lbuf (struct linebuf *lbuf, int set_default) {
         
         }
         
+        if (*p == '$') {
+            line = variable_expand_line (lbuf->filename, line_no, xstrdup (p));;
+        }
+        
         record_waiting_files ();
         
         semicolonp = strchr (line, ';');
@@ -759,15 +760,15 @@ static int read_lbuf (struct linebuf *lbuf, int set_default) {
         
         if (semicolonp) {
         
-            if (cmds_idx + strlen (semicolonp) + 1 > cmds_sz) {
+            if (commands_idx + strlen (semicolonp) + 1 > commands_sz) {
             
-                cmds_sz = (cmds_idx + strlen (semicolonp) + 1) * 2;
-                cmds = xrealloc (cmds, cmds_sz);
+                commands_sz = (commands_idx + strlen (semicolonp) + 1) * 2;
+                commands = xrealloc (commands, commands_sz);
             
             }
             
-            memcpy (&(cmds[cmds_idx]), semicolonp, strlen (semicolonp) + 1);
-            cmds_idx += strlen (semicolonp) + 1;
+            memcpy (&(commands[commands_idx]), semicolonp, strlen (semicolonp) + 1);
+            commands_idx += strlen (semicolonp) + 1;
         
         }
         
@@ -799,7 +800,7 @@ static int read_lbuf (struct linebuf *lbuf, int set_default) {
     }
     
     free (clean);
-    free (cmds);
+    free (commands);
     
     if (cur_if_stack) {
     
@@ -948,22 +949,22 @@ void *parse_nameseq (char *line, size_t size) {
 
 }
 
-void record_files (const char *filename, unsigned long line_no, struct nameseq *filenames, char *cmds, size_t cmds_idx, char *depstr) {
+void record_files (const char *filename, unsigned long line_no, struct nameseq *filenames, char *commands, size_t commands_idx, char *depstr) {
 
-    struct commands *cmds_p;
+    struct commands *commands_p;
     
     struct dep *deps;
     struct nameseq *ns, *old_ns;
     
-    if (cmds_idx > 0) {
+    if (commands_idx > 0) {
     
-        cmds_p = xmalloc (sizeof (*cmds_p));
+        commands_p = xmalloc (sizeof (*commands_p));
         
-        cmds_p->text = xstrndup (cmds, cmds_idx);
-        cmds_p->len = cmds_idx;
+        commands_p->text = xstrndup (commands, commands_idx);
+        commands_p->len = commands_idx;
     
     } else {
-        cmds_p = 0;
+        commands_p = 0;
     }
     
     if (depstr) {
@@ -975,9 +976,9 @@ void record_files (const char *filename, unsigned long line_no, struct nameseq *
     for (ns = filenames, old_ns = 0; ns; old_ns = ns, ns = ns->next, free (old_ns->name), free (old_ns)) {
     
         if (ns->name[0] == '.' && !strchr (ns->name, '\\') && !strchr (ns->name, '/')) {
-            rule_add_suffix (filename, line_no - 1, ns->name, cmds_p);
+            rule_add_suffix (filename, line_no - 1, ns->name, commands_p);
         } else {
-            rule_add (filename, line_no - 1, ns->name, deps, cmds_p);
+            rule_add (filename, line_no - 1, ns->name, deps, commands_p);
         }
     
     }
diff --git a/read.h b/read.h
index a880c0e4fd5627b50c44caae8d609ff9d6d90073..78adf4369aa637c03670d71c668cfada5fb1b00d 100644 (file)
--- a/read.h
+++ b/read.h
@@ -14,7 +14,7 @@ struct nameseq {
 
 };
 
-void record_files (const char *filename, unsigned long line_no, struct nameseq *filenames, char *cmds, size_t cmds_idx, char *depstr);
+void record_files (const char *filename, unsigned long line_no, struct nameseq *filenames, char *commands, size_t commands_idx, char *depstr);
 void *parse_nameseq (char *line, size_t size);
 
 #endif      /* _READ_H */
diff --git a/rule.c b/rule.c
index 0959631a4c76088ee73b1e6c68a4a64c397a9f60..c914146bb9d8a5bf4efde2c2ba4ef3313a65c93f 100644 (file)
--- a/rule.c
+++ b/rule.c
@@ -49,11 +49,34 @@ struct rule *rule_find (const char *name) {
         
         }
         
-        key = hashtab_get_key (&hashtab_rules, hash_tagged_name);
-        free (hash_tagged_name);
+        if (!(key = hashtab_get_key (&hashtab_rules, hash_tagged_name))) {
+        
+            free (hash_tagged_name);
+            
+            hash_tagged_name = xstrdup (name);
+            ptr = hash_tagged_name;
+            
+            /* Replace filename by '%'. */
+            if (*ptr) {
+            
+                dot = strrchr (ptr, '.');
+                *ptr++ = '%';
+                
+                if (dot) {
+                    memmove (ptr, dot, strlen (dot) + 1);
+                } else {
+                    *ptr = '\0';
+                }
+            
+            }
+            
+            key = hashtab_get_key (&hashtab_rules, hash_tagged_name);
+            free (hash_tagged_name);
+            
+            if (!key) {
+                return 0;
+            }
         
-        if (!key) {
-            return 0;
         }
     
     }
index a1fb77f6bdd6dd92e540bf6fdd5fbef72af381af..e52e5a246613967dcbd2c3ed5e96e41a54379e5d 100644 (file)
@@ -21,6 +21,7 @@
 
 #include    <stdio.h>
 
+#include    "cstr.h"
 #include    "hashtab.h"
 #include    "lib.h"
 #include    "read.h"
@@ -51,6 +52,21 @@ static char *func_eval (const char *filename, unsigned long line_no, char *input
 
 }
 
+static char *func_dir (const char *filename, unsigned long line_no, char *input) {
+
+    char *p;
+    
+    (void) filename;
+    (void) line_no;
+    
+    if ((p = strrchr (input, '/')) || (p = strrchr (input, '\\'))) {
+        return xstrndup (input, (p + 1) - input);
+    }
+    
+    return xstrdup ("./");
+
+}
+
 static char *func_error (const char *filename, unsigned long line_no, char *input) {
 
     fprintf (stderr, "%s: %s:%lu: *** %s. Stop.\n", program_name, filename, line_no, input);
@@ -60,6 +76,67 @@ static char *func_error (const char *filename, unsigned long line_no, char *inpu
 
 }
 
+static char *func_filter_out (const char *filename, unsigned long line_no, char *input) {
+
+    char *filter, *goals;
+    char *goal, *p;
+    
+    CString str;
+    cstr_new (&str);
+    
+    (void) filename;
+    (void) line_no;
+    
+    filter = xstrdup (input);
+    
+    if (!(goals = strstr (filter, ",")) || !goals[0]) {
+        return 0;
+    }
+    
+    *goals++ = 0;
+    
+    filter = skip_whitespace (filter);
+    goals = skip_whitespace (goals);
+    
+    for (;;) {
+    
+        if ((p = strchr (goals, ' '))) {
+        
+            goal = xstrndup (goals, p - goals);
+            
+            if (!strstr (filter, goal)) {
+                cstr_cat (&str, goal, strlen (goal));
+            }
+            
+            free (goal);
+            goals = skip_whitespace (p);
+        
+        } else {
+        
+            goal = xstrdup (goals);
+            
+            if (!strstr (filter, goal)) {
+                cstr_cat (&str, goal, strlen (goal));
+            }
+            
+            free (goal);
+            break;
+        
+        }
+    
+    }
+    
+    cstr_ccat (&str, '\0');
+    
+    if (*(goals = xstrdup (str.data))) {
+        return goals;
+    }
+    
+    free (goals);
+    return xstrdup ("@");
+
+}
+
 static char *func_subst (const char *filename, unsigned long line_no, char *input) {
 
     char *src, *dst, *new_body, *old_body, *p;
@@ -416,6 +493,20 @@ static char *func_shell (const char *filename, unsigned long line_no, char *inpu
 # include       <sys/wait.h>
 # include       <errno.h>
 # include       <unistd.h>
+
+static char *internal_commands[] = {
+
+    "if",
+    "for",
+    "done",
+    "fi",
+    "do",
+    "while",
+    "continue",
+    "find"
+
+};
+
 static char *func_shell (const char *filename, unsigned long line_no, char *input) {
 
     int pipefd[2], pid, status;
@@ -442,10 +533,157 @@ static char *func_shell (const char *filename, unsigned long line_no, char *inpu
     
     if (pid == 0) {
     
-        char *name = input, *space = 0, *slash;
+        unsigned long len;
+        char *temp;
+        
+        char **argv;
+        int argc = 1;
+        
+        char *prog = input, *space = 0, *ptr, *p;
+        int offset = 0, internal = 0, quote, i;
+        
+        if ((space = strchr (prog, ' '))) {
+        
+            ptr = space + 1;
+            
+            for (i = 0; ptr[i]; i++) {
+            
+                if (isspace ((int) ptr[i])) {
+                    argc++;
+                }
+            
+            }
+            
+            prog = xstrndup (prog, space - prog);
+            
+            if (!(p = strchr (prog, '/'))) {
+            
+                unsigned long count = sizeof (internal_commands) / sizeof (internal_commands[0]) - 1;
+                unsigned long i;
+                
+                for (i = 0; i < count; i++) {
+                
+                    if (xstrcasecmp (prog, internal_commands[i]) == 0) {
+                    
+                        if (prog) { free (prog); }
+                        prog = xstrdup (getenv ("SHELL"));
+                        
+                        internal = 1;
+                        break;
+                    
+                    }
+                
+                }
+            
+            }
+            
+            if (internal) {
+            
+                argv = xmalloc (sizeof (*argv) * 4);
+                
+                argv[1] = "-c";
+                argv[2] = input;
+                argc = 3;
+            
+            } else {
+            
+                argv = xmalloc (sizeof (*argv) * (argc + 1));
+                
+                for (i = 0; ; i++) {
+                
+                    if (!isspace ((int) ptr[i])) {
+                        break;
+                    }
+                
+                }
+                
+                argv[1] = ptr + i;
+                argc = 1;
+                quote = 0;
+                
+                while (ptr[i]) {
+                
+                    ptr[i - offset] = ptr[i];
+                    
+                    if (quote) {
+                    
+                        if (ptr[i] == '\\' && (ptr[i + 1] == quote || ptr[i + 1] == '\\')) {
+                        
+                            offset++;
+                            i++;
+                            
+                            ptr[i - offset] = ptr[i];
+                        
+                        } else if (ptr[i] == quote) {
+                        
+                            len = strlen (ptr + i + 1);
+                            temp = xstrdup (ptr + i + 1);
+                            
+                            memmove (ptr + i, temp, len);
+                            *(ptr + i + len) = '\0';
+                            
+                            quote = 0;
+                            i--;
+                        
+                        }
+                        
+                        i++;
+                    
+                    } else if (ptr[i] == '\'' || ptr[i] == '"') {
+                    
+                        quote = ptr[i];
+                        
+                        len = strlen (ptr + i + 1);
+                        temp = xstrdup (ptr + i + 1);
+                        
+                        memmove (ptr + i, temp, len);
+                        *(ptr + i + len) = '\0';
+                    
+                    } else if (isspace ((int) ptr[i])) {
+                    
+                        ptr[i - offset] = '\0';
+                        argc++;
+                        
+                        for (i = i + 1; ; i++) {
+                        
+                            if (!isspace ((int) ptr[i])) {
+                                break;
+                            }
+                        
+                        }
+                        
+                        argv[argc] = ptr + i - offset;
+                    
+                    } else {
+                        i++;
+                    }
+                
+                }
+                
+                if (argv[argc] != ptr + i - offset) {
+                
+                    ptr[i - offset] = '\0';
+                    argc++;
+                
+                }
+            
+            }
+        
+        } else {
+            argv = xmalloc (sizeof (*argv) * (argc + 1));
+        }
+            
+        argv[0] = prog;
+        argv[argc] = 0;
+        
+        if (strcmp (prog, "ls") == 0 && argc == 1) {
+        
+            argv = xrealloc (argv, sizeof (*argv) * 3);
+            argc = 2;
+            
+            argv[1] = "-C";
+            argv[2] = 0;
         
-        if ((space = strchr (name, ' '))) {
-            name = xstrndup (name, space - name);
         }
         
         dup2 (pipefd[1], STDOUT_FILENO);
@@ -453,9 +691,10 @@ static char *func_shell (const char *filename, unsigned long line_no, char *inpu
         close (pipefd[0]);
         close (pipefd[1]);
         
-        execlp (name, (slash = strrchr (name, '/')) ? (slash + 1) : name, space ? skip_whitespace (space) : NULL, NULL);
+        execvp (prog, argv);
+        free (argv);
         
-        fprintf (stderr, "%s: %s:%lu: %s: %s\n", program_name, filename, line_no, name, strerror (errno));
+        fprintf (stderr, "%s: %s:%lu: %s: %s\n", program_name, filename, line_no, prog, strerror (errno));
         exit (EXIT_FAILURE);
     
     }
@@ -536,16 +775,18 @@ static char *func_shell (const char *filename, unsigned long line_no, char *inpu
 
 static struct builtin_function builtin_functions[] ={
 
-    {   "error",    &func_error     },
+    {   "error",        &func_error         },
+    {   "filter-out",   &func_filter_out    },
     
 #if     defined (_WIN32) || defined (__WIN32__) || defined (unix) || defined (__unix) || defined (__unix__) || defined (__APPLE__)
-    {   "shell",    &func_shell     },
+    {   "shell",        &func_shell         },
 #endif
     
-    {   "eval",     &func_eval      },
-    {   "subst",    &func_subst     },
+    {   "dir",          &func_dir           },
+    {   "eval",         &func_eval          },
+    {   "subst",        &func_subst         },
     
-    {   0,          0               }
+    {   0,              0                   }
 
 };
 
@@ -802,7 +1043,7 @@ char *variable_expand_line (const char *filename, unsigned long line_no, char *l
                 
                 } else {
                 
-                    if (state->env_override || strcmp (content, "PATH") == 0) {
+                    if (state->env_override || strcmp (content, "PATH") == 0 || strcmp (content, "MAKEFLAGS") == 0) {
                     
                         if ((alloc_replacement = getenv (content))) {
                         
@@ -1111,7 +1352,22 @@ void parse_var_line (const char *filename, unsigned long line_no, char *line, en
 
 #else
         setenv ("PATH", new_value, 1);
-#endif    
+#endif
+    
+    } else if (strcmp (var_name, "MAKEFLAGS") == 0) {
+    
+#if     defined (_WIN32)
+
+        char *temp = xmalloc (10 + strlen (new_value) + 1);
+        
+        sprintf (temp, "MAKEFLAGS=%s", new_value);
+        _putenv (temp);
+        
+        free (temp);
+
+#else
+        setenv ("MAKEFLAGS", new_value, 1);
+#endif
     
     }
     
diff --git a/xmake.c b/xmake.c
index e99b81e32e8d9c094a37544c9cb3e5b27d507e9d..c80ce7b0dfa0f2441d3069db1e53b8f74d5d34e8 100644 (file)
--- a/xmake.c
+++ b/xmake.c
@@ -137,7 +137,7 @@ static int pipe_command (const char *filename, unsigned long line_no, char *inpu
         
         for (i = 0; i < count; i++) {
         
-            if (strcasecmp (lpApplicationName, internal_commands[i]) == 0) {
+            if (xstrcasecmp (lpApplicationName, internal_commands[i]) == 0) {
             
                 if (lpApplicationName) {
                     free (lpApplicationName);
@@ -329,6 +329,20 @@ static int pipe_command (const char *filename, unsigned long line_no, char *inpu
 # include       <sys/wait.h>
 # include       <errno.h>
 # include       <unistd.h>
+
+static char *internal_commands[] = {
+
+    "if",
+    "for",
+    "done",
+    "fi",
+    "do",
+    "while",
+    "continue",
+    "find"
+
+};
+
 static int pipe_command (const char *filename, unsigned long line_no, char *input, int is_ignoring_errors, const char *name) {
 
     int pipefd[2], pid, status;
@@ -354,11 +368,14 @@ static int pipe_command (const char *filename, unsigned long line_no, char *inpu
     
     if (pid == 0) {
     
+        unsigned long len;
+        char *temp;
+        
         char **argv;
         int argc = 1;
         
-        char *prog = input, *space = 0, *ptr;
-        int offset = 0, quote, i;
+        char *prog = input, *space = 0, *ptr, *p;
+        int offset = 0, internal = 0, quote, i;
         
         if ((space = strchr (prog, ' '))) {
         
@@ -373,83 +390,124 @@ static int pipe_command (const char *filename, unsigned long line_no, char *inpu
             }
             
             prog = xstrndup (prog, space - prog);
-            argv = xmalloc (sizeof (*argv) * (argc + 1));
             
-            for (i = 0; ; i++) {
+            if (!(p = strchr (prog, '/'))) {
             
-                if (!isspace ((int) ptr[i])) {
-                    break;
+                unsigned long count = sizeof (internal_commands) / sizeof (internal_commands[0]) - 1;
+                unsigned long i;
+                
+                for (i = 0; i < count; i++) {
+                
+                    if (xstrcasecmp (prog, internal_commands[i]) == 0) {
+                    
+                        internal = 1;
+                        break;
+                    
+                    }
+                
                 }
             
             }
             
-            argv[1] = ptr + i;
-            argc = 1;
-            quote = 0;
+            if (internal || strchr (input, '>')) {
             
-            while (ptr[i]) {
+                if (prog) { free (prog); }
+                
+                prog = xstrdup (getenv ("SHELL"));
+                argv = xmalloc (sizeof (*argv) * 4);
+                
+                argv[1] = "-c";
+                argv[2] = input;
+                argc = 3;
+            
+            } else {
             
-                ptr[i - offset] = ptr[i];
+                argv = xmalloc (sizeof (*argv) * (argc + 1));
+                
+                for (i = 0; ; i++) {
                 
-                if (quote) {
+                    if (!isspace ((int) ptr[i])) {
+                        break;
+                    }
                 
-                    if (ptr[i] == '\\' && (ptr[i + 1] == quote || ptr[i + 1] == '\\')) {
+                }
+                
+                argv[1] = ptr + i;
+                argc = 1;
+                quote = 0;
+                
+                while (ptr[i]) {
+                
+                    ptr[i - offset] = ptr[i];
+                    
+                    if (quote) {
                     
-                        offset++;
+                        if (ptr[i] == '\\' && (ptr[i + 1] == quote || ptr[i + 1] == '\\')) {
+                        
+                            offset++;
+                            i++;
+                            
+                            ptr[i - offset] = ptr[i];
+                        
+                        } else if (ptr[i] == quote) {
+                        
+                            len = strlen (ptr + i + 1);
+                            temp = xstrdup (ptr + i + 1);
+                            
+                            memmove (ptr + i, temp, len);
+                            *(ptr + i + len) = '\0';
+                            
+                            quote = 0;
+                            i--;
+                        
+                        }
+                        
                         i++;
+                    
+                    } else if (ptr[i] == '\'' || ptr[i] == '"') {
+                    
+                        quote = ptr[i];
+                        
+                        len = strlen (ptr + i + 1);
+                        temp = xstrdup (ptr + i + 1);
                         
-                        ptr[i - offset] = ptr[i];
+                        memmove (ptr + i, temp, len);
+                        *(ptr + i + len) = '\0';
                     
-                    } else if (ptr[i] == quote) {
+                    } else if (isspace ((int) ptr[i])) {
                     
-                        quote = 0;
-                        offset++;
+                        ptr[i - offset] = '\0';
+                        argc++;
+                        
+                        for (i = i + 1; ; i++) {
+                        
+                            if (!isspace ((int) ptr[i])) {
+                                break;
+                            }
+                        
+                        }
+                        
+                        argv[argc] = ptr + i - offset;
                     
+                    } else {
+                        i++;
                     }
-                    
-                    i++;
-                
-                } else if (ptr[i] == '\'' || ptr[i] == '"') {
                 
-                    if (argv[argc] == ptr + i - offset) {
-                        argv[argc]++;
-                    }
-                    
-                    quote = ptr[i];
-                    i++;
+                }
                 
-                } else if (isspace ((int) ptr[i])) {
+                if (argv[argc] != ptr + i - offset) {
                 
                     ptr[i - offset] = '\0';
                     argc++;
-                    
-                    for (i = i + 1; ; i++) {
-                    
-                        if (!isspace ((int) ptr[i])) {
-                            break;
-                        }
-                    
-                    }
-                    
-                    argv[argc] = ptr + i - offset;
                 
-                } else {
-                    i++;
                 }
             
             }
-            
-            if (argv[argc] != ptr + i - offset) {
-            
-                ptr[i - offset] = '\0';
-                argc++;
-            
-            }
         
         } else {
             argv = xmalloc (sizeof (*argv) * (argc + 1));
         }
-        
+            
         argv[0] = prog;
         argv[argc] = 0;
         
@@ -627,7 +685,7 @@ static int rule_run_command (const char *filename, unsigned long line_no, const
             fprintf (stderr, "%s: %s: No such file or directory\n", program_name, p);
             fprintf (stderr, "%s: *** [%s:%lu: %s] Error %d\n", program_name, filename, line_no, name, status);
             
-            if (!keep_going) {
+            if (!state->keep_going) {
                 exit (EXIT_FAILURE);
             }
         
@@ -670,7 +728,7 @@ static char *parse_command (char *text) {
     
     }
     
-    ret = xmalloc (strlen (cwd) + 1 + strlen (text));
+    ret = xmalloc (strlen (cwd) + 1 + strlen (text) + 1);
     sprintf (ret, "%s/%s", cwd, text);
     
     return ret;
@@ -708,14 +766,91 @@ static int run_commands (const char *filename, unsigned long line_no, struct com
 
 }
 
+static int file_exists (char *name) {
+
+    FILE *f;
+    
+    if (!(f = fopen (name, "r"))) {
+        return 0;
+    }
+    
+    fclose (f);
+    return 1;
+
+}
+
+static char *find_target (char *target) {
+
+    struct variable *vpath_var;
+    char *vpath;
+    
+    if (file_exists (target)) {
+        return target;
+    }
+    
+    if (!(vpath_var = variable_find ("VPATH"))) {
+        return 0;
+    }
+    
+    vpath = variable_expand_line ("<command-line>", 1, xstrdup (vpath_var->value));
+    
+    while (vpath && *vpath) {
+    
+        char *vpath_part, *new_target;
+        char saved_ch;
+        
+        while (*vpath && (isspace ((int) *vpath) || (*vpath == ';'))) {
+            vpath++;
+        }
+        
+        vpath_part = vpath;
+        
+        while (*vpath && !isspace ((int) *vpath) && *vpath != ';') {
+            vpath++;
+        }
+        
+        saved_ch = *vpath;
+        *vpath = '\0';
+        
+        new_target = xmalloc (strlen (vpath_part) + 1 + strlen (target) + 1);
+        strcpy (new_target, vpath_part);
+        
+        if (strchr (vpath_part, '\\')) {
+            strcat (new_target, "\\");
+        } else {
+            strcat (new_target, "/");
+        }
+        
+        strcat (new_target, target);
+        *vpath = saved_ch;
+        
+        if (file_exists (new_target)) {
+            return new_target;
+        }
+        
+        free (new_target);
+        
+        if (!(vpath = strchr (vpath, ';'))) {
+            break;
+        }
+        
+        vpath++;
+    
+    }
+    
+    return 0;
+
+}
+
 static int rule_use (struct rule *r, char *name) {
 
     struct dep *dep;
     
-    char *hash_name = 0, *filename = 0, *dot = 0, *n2 = 0;
+    char *hash_name = 0, *filename = 0, *dot = 0;
     int ret;
     
     char *p, *star_name, *lesser_name;
+    char *n2, *n3;
     
     CString str;
     cstr_new (&str);
@@ -728,7 +863,7 @@ static int rule_use (struct rule *r, char *name) {
             n2 = xmalloc (strlen (dep->name) + strlen (name) + 1);
             strncat (n2, dep->name, p - dep->name);
             
-            if (!(filename = strrchr (name, '/'))) {
+            /*if (!(filename = strrchr (name, '/'))) {
                 filename = strrchr (name, '\\');
             }
             
@@ -736,7 +871,9 @@ static int rule_use (struct rule *r, char *name) {
                 filename = name;
             } else {
                 filename++;
-            }
+            }*/
+            
+            filename = name;
             
             if ((dot = strrchr (filename, '.'))) {
                 strncat (n2, filename, dot - filename);
@@ -746,21 +883,57 @@ static int rule_use (struct rule *r, char *name) {
             
             strcat (n2, p + 1);
             
-            ret = rule_search_and_build (n2);
-            cstr_cat (&str, n2, strlen (n2));
+            if (!(n3 = find_target (n2))) {
+            
+                if ((ret = rule_search_and_build (n2))) {
+                
+                    free (n2);
+                    return ret;
+                
+                }
+                
+                cstr_cat (&str, n2, strlen (n2));
+                free (n2);
             
-            free (n2);
+            } else {
+            
+                free (n2);
+                
+                if ((ret = rule_search_and_build (n3))) {
+                
+                    free (n3);
+                    return ret;
+                
+                }
+                
+                cstr_cat (&str, n3, strlen (n3));
+                free (n3);
             
-            if (ret) {
-                return ret;
             }
+            
+            if (ret) { return ret; }
         
         } else {
         
-            cstr_cat (&str, dep->name, strlen (dep->name));
+            if (!(n3 = find_target (dep->name))) {
+            
+                if ((ret = rule_search_and_build (dep->name))) {
+                    return ret;
+                }
+                
+                cstr_cat (&str, dep->name, strlen (dep->name));
+            
+            } else {
+            
+                if ((ret = rule_search_and_build (n3))) {
+                
+                    free (n3);
+                    return ret;
+                
+                }
+                
+                cstr_cat (&str, n3, strlen (n3));
             
-            if ((ret = rule_search_and_build (dep->name))) {
-                return ret;
             }
         
         }
@@ -783,7 +956,49 @@ static int rule_use (struct rule *r, char *name) {
     doing_inference_rule_commands = 0;
     
     if (r->deps) {
-        lesser_name = xstrdup (r->deps->name);
+    
+        dep = r->deps;
+        
+        if ((p = strchr (dep->name, '%'))) {
+        
+            /* Replace the rule's '%' by the filename without extension. */
+            n2 = xmalloc (strlen (dep->name) + strlen (name) + 1);
+            strncat (n2, dep->name, p - dep->name);
+            
+            /*if (!(filename = strrchr (name, '/'))) {
+                filename = strrchr (name, '\\');
+            }
+            
+            if (!filename) {
+                filename = name;
+            } else {
+                filename++;
+            }*/
+            
+            filename = name;
+            
+            if ((dot = strrchr (filename, '.'))) {
+                strncat (n2, filename, dot - filename);
+            } else {
+                strcat (n2, filename);
+            }
+            
+            strcat (n2, p + 1);
+            
+            if (!(lesser_name = find_target (n2))) {
+                lesser_name = n2;
+            } else {
+                free (n2);
+            }
+        
+        } else {
+        
+            if (!(lesser_name = find_target (dep->name))) {
+                lesser_name = xstrdup (dep->name);
+            }
+        
+        }
+    
     } else {
         lesser_name = xstrdup ("");
     }
@@ -869,82 +1084,6 @@ static int single_suffix_rule_use (struct suffix_rule *s, char *name) {
 
 }
 
-static int file_exists (char *name) {
-
-    FILE *f;
-    
-    if (!(f = fopen (name, "r"))) {
-        return 0;
-    }
-    
-    fclose (f);
-    return 1;
-
-}
-
-static char *find_target (char *target) {
-
-    struct variable *vpath_var;
-    char *vpath;
-    
-    if (file_exists (target)) {
-        return target;
-    }
-    
-    if (!(vpath_var = variable_find ("VPATH"))) {
-        return 0;
-    }
-    
-    vpath = variable_expand_line ("<command-line>", 1, xstrdup (vpath_var->value));
-    
-    while (vpath && *vpath) {
-    
-        char *vpath_part, *new_target;
-        char saved_ch;
-        
-        while (*vpath && (isspace ((int) *vpath) || (*vpath == ';'))) {
-            vpath++;
-        }
-        
-        vpath_part = vpath;
-        
-        while (*vpath && !isspace ((int) *vpath) && *vpath != ';') {
-            vpath++;
-        }
-        
-        saved_ch = *vpath;
-        *vpath = '\0';
-        
-        new_target = xmalloc (strlen (vpath_part) + 1 + strlen (target) + 1);
-        strcpy (new_target, vpath_part);
-        
-        if (strchr (vpath_part, '\\')) {
-            strcat (new_target, "\\");
-        } else {
-            strcat (new_target, "/");
-        }
-        
-        strcat (new_target, target);
-        *vpath = saved_ch;
-        
-        if (file_exists (new_target)) {
-            return new_target;
-        }
-        
-        free (new_target);
-        
-        if (!(vpath = strchr (vpath, ';'))) {
-            break;
-        }
-        
-        vpath++;
-    
-    }
-    
-    return 0;
-
-}
-
 int rule_search_and_build (char *name) {
 
     struct rule *r;
@@ -1083,9 +1222,10 @@ int rule_search_and_build (char *name) {
 
 int main (int argc, char **argv) {
 
-    char *cwd = 0;
+    char *cwd = 0, *makeflags;
     int ret;
     
+    struct variable *makecmdgoals;
     unsigned long i;
     
     if (argc && *argv) {
@@ -1103,19 +1243,135 @@ int main (int argc, char **argv) {
     rules_init ();
     
     default_goal_var = variable_add (xstrdup (".DEFAULT_GOAL"), xstrdup (""), VAR_ORIGIN_FILE);
-    
     variable_add (xstrdup ("OS"), xstrdup (os_name), VAR_ORIGIN_FILE);
+    
+    state = xmalloc (sizeof (*state));
+    parse_args (argv, argc);
+    
+    if ((makeflags = getenv ("MAKEFLAGS"))) {
+    
+        char *ptr = xstrdup (makeflags), *temp;
+        int offset = 0, quote, i;
+        
+        char **argv;
+        int argc = 1;
+        
+        unsigned long len;
+        
+        for (i = 0; makeflags[i]; i++) {
+        
+            if (isspace ((int) makeflags[i])) {
+                argc++;
+            }
+        
+        }
+        
+        argv = xmalloc (sizeof (*argv) * (argc + 1));
+        i = 0;
+        
+        argv[1] = ptr + i;
+        argc = 1;
+        quote = 0;
+        
+        while (ptr[i]) {
+        
+            ptr[i - offset] = ptr[i];
+            
+            if (quote) {
+            
+                if (ptr[i] == '\\' && (ptr[i + 1] == quote || ptr[i + 1] == '\\')) {
+                
+                    offset++;
+                    i++;
+                    
+                    ptr[i - offset] = ptr[i];
+                
+                } else if (ptr[i] == quote) {
+                
+                    len = strlen (ptr + i + 1);
+                    temp = xstrdup (ptr + i + 1);
+                    
+                    memmove (ptr + i, temp, len);
+                    *(ptr + i + len) = '\0';
+                    
+                    quote = 0;
+                    i--;
+                
+                }
+                
+                i++;
+            
+            } else if (ptr[i] == '\'' || ptr[i] == '"') {
+            
+                quote = ptr[i];
+                
+                len = strlen (ptr + i + 1);
+                temp = xstrdup (ptr + i + 1);
+                
+                memmove (ptr + i, temp, len);
+                *(ptr + i + len) = '\0';
+            
+            } else if (isspace ((int) ptr[i])) {
+            
+                ptr[i - offset] = '\0';
+                argc++;
+                
+                for (i = i + 1; ; i++) {
+                
+                    if (!isspace ((int) ptr[i])) {
+                        break;
+                    }
+                
+                }
+                
+                argv[argc] = ptr + i - offset;
+            
+            } else {
+                i++;
+            }
+        
+        }
+        
+        if (argv[argc] != ptr + i - offset) {
+        
+            ptr[i - offset] = '\0';
+            argc++;
+        
+        }
+        
+        argv[argc] = 0;
+        parse_args (argv, argc);
+    
+    }
+    
     variable_add (xstrdup ("MAKE"), xstrdup (argv[0]), VAR_ORIGIN_FILE);
     
+    if (state->nb_goals) {
+    
+        CString str;
+        cstr_new (&str);
+
+        for (i = 0; i < state->nb_goals; i++) {
+
+            cstr_cat (&str, state->goals[i], strlen (state->goals[i]));
+            
+            if (i < state->nb_goals - 1) {
+                cstr_ccat (&str, ' ');
+            }
+
+        }
+
+        cstr_ccat (&str, '\0');
+        variable_add (xstrdup ("MAKECMDGOALS"), xstrdup (str.data), VAR_ORIGIN_FILE);
+    
+    }
+    
 #if     defined (unix) || defined (__unix) || defined (__unix__) || defined (__APPLE__)
     variable_add (xstrdup ("SHELL"), xstrdup ("/bin/sh"), VAR_ORIGIN_FILE);
 #else
     variable_add (xstrdup ("SHELL"), xstrdup ("sh.exe"), VAR_ORIGIN_FILE);
 #endif
     
-    state = xmalloc (sizeof (*state));
-    parse_args (argv, argc);
-    
     if (state->nb_directories > 0) {
     
         char *arg;
@@ -1228,7 +1484,30 @@ int main (int argc, char **argv) {
     
     }
     
-    if (state->nb_goals == 0) {
+    if ((makecmdgoals = variable_find ("MAKECMDGOALS"))) {
+    
+        char *value = makecmdgoals->value, *goal, *p;
+        
+        while (*value) {
+        
+            if ((p = strchr (value, ' '))) {
+                goal = xstrndup (value, p - value);
+            } else {
+                goal = xstrdup (value);
+            }
+            
+            value = skip_whitespace (value + strlen (goal));
+            
+            ret = rule_search_and_build (goal);
+            free (goal);
+            
+            if (ret && !state->keep_going) {
+                goto out;
+            }
+        
+        }
+    
+    } else {
     
         if (default_goal_var->value[0] == '\0') {
         
@@ -1239,13 +1518,7 @@ int main (int argc, char **argv) {
         
         }
         
-        dynarray_add (&state->goals, &state->nb_goals, xstrdup (default_goal_var->value));
-    
-    }
-    
-    for (i = 0; i < state->nb_goals; i++) {
-    
-        if ((ret = rule_search_and_build (state->goals[i]))) {
+        if ((ret = rule_search_and_build (default_goal_var->value))) {
         
             if (!state->keep_going) {
                 goto out;