Index: /trunk/src/kmk/Makefile.am
===================================================================
--- /trunk/src/kmk/Makefile.am	(revision 1439)
+++ /trunk/src/kmk/Makefile.am	(revision 1440)
@@ -126,4 +126,5 @@
 	-DCONFIG_WITH_EVALPLUS \
 	-DCONFIG_WITH_MAKE_STATS \
+	-DCONFIG_WITH_COMMANDS_FUNC \
 	-DCONFIG_PRETTY_COMMAND_PRINTING \
 	\
Index: /trunk/src/kmk/Makefile.kmk
===================================================================
--- /trunk/src/kmk/Makefile.kmk	(revision 1439)
+++ /trunk/src/kmk/Makefile.kmk	(revision 1440)
@@ -126,4 +126,5 @@
 	CONFIG_WITH_EVALPLUS \
 	CONFIG_WITH_MAKE_STATS \
+	CONFIG_WITH_COMMANDS_FUNC \
 	CONFIG_PRETTY_COMMAND_PRINTING \
 	\
Index: /trunk/src/kmk/commands.c
===================================================================
--- /trunk/src/kmk/commands.c	(revision 1439)
+++ /trunk/src/kmk/commands.c	(revision 1440)
@@ -332,5 +332,9 @@
 
   cmds->any_recurse = 0;
+#ifdef CONFIG_WITH_COMMANDS_FUNC
+  cmds->lines_flags = xmalloc (nlines * sizeof (cmds->lines_flags[0]));
+#else
   cmds->lines_flags = xmalloc (nlines);
+#endif 
   for (idx = 0; idx < nlines; ++idx)
     {
@@ -338,5 +342,9 @@
 
       for (p = lines[idx];
+#ifdef CONFIG_WITH_COMMANDS_FUNC
+           isblank ((unsigned char)*p) || *p == '-' || *p == '@' || *p == '+' || *p == '%';
+#else
            isblank ((unsigned char)*p) || *p == '-' || *p == '@' || *p == '+';
+#endif
            ++p)
         switch (*p)
@@ -351,4 +359,9 @@
             flags |= COMMANDS_NOERROR;
             break;
+#ifdef CONFIG_WITH_COMMANDS_FUNC
+          case '%':
+            flags |= COMMAND_GETTER_SKIP_IT;
+            break;
+#endif
           }
 
Index: /trunk/src/kmk/commands.h
===================================================================
--- /trunk/src/kmk/commands.h	(revision 1439)
+++ /trunk/src/kmk/commands.h	(revision 1440)
@@ -26,5 +26,9 @@
     unsigned int ncommand_lines;/* Number of command lines.  */
     char **command_lines;	/* Commands chopped up into lines.  */
+#ifdef CONFIG_WITH_COMMANDS_FUNC
+    short *lines_flags;		/* One set of flag bits for each line.  */
+#else
     char *lines_flags;		/* One set of flag bits for each line.  */
+#endif
     int any_recurse;		/* Nonzero if any `lines_recurse' elt has */
 				/* the COMMANDS_RECURSE bit set.  */
@@ -42,4 +46,7 @@
 # define COMMANDS_KMK_BUILTIN   128 /* kmk: kmk builtin command. */
 #endif
+#ifdef CONFIG_WITH_COMMANDS_FUNC
+# define COMMAND_GETTER_SKIP_IT 256 /* $(commands target) skips this: % */
+#endif
 
 void execute_file_commands (struct file *file);
Index: /trunk/src/kmk/expand.c
===================================================================
--- /trunk/src/kmk/expand.c	(revision 1439)
+++ /trunk/src/kmk/expand.c	(revision 1440)
@@ -506,4 +506,35 @@
 
 
+#ifdef CONFIG_WITH_COMMANDS_FUNC
+/* Expand LINE for FILE.  Error messages refer to the file and line where
+   FILE's commands were found.  Expansion uses FILE's variable set list.
+
+   Differs from variable_expand_for_file in that it takes a pointer to
+   where in the variable buffer to start outputting the expanded string.  */
+
+char *
+variable_expand_for_file_2 (char *o, const char *line, struct file *file)
+{
+  char *result;
+  struct variable_set_list *save;
+
+  if (file == 0)
+    return variable_expand_string (o, line, (long)-1);
+
+  save = current_variable_set_list;
+  current_variable_set_list = file->variables;
+  if (file->cmds && file->cmds->fileinfo.filenm)
+    reading_file = &file->cmds->fileinfo;
+  else
+    reading_file = 0;
+  result = variable_expand_string (o, line, (long)-1);
+  current_variable_set_list = save;
+  reading_file = 0;
+
+  return result;
+}
+
+
+#endif /* CONFIG_WITH_COMMANDS_FUNC */
 /* Like allocated_variable_expand, but for += target-specific variables.
    First recursively construct the variable value from its appended parts in
Index: /trunk/src/kmk/function.c
===================================================================
--- /trunk/src/kmk/function.c	(revision 1439)
+++ /trunk/src/kmk/function.c	(revision 1440)
@@ -2355,5 +2355,5 @@
    writing rules. */
 static char *
-func_xargs (char *o, char **argv, const char *funcname)
+func_xargs (char *o, char **argv, const char *funcname UNUSED)
 {
   int argc;
@@ -2517,4 +2517,7 @@
         if (!isblank (ch)
          && ch != '@'
+#ifdef CONFIG_WITH_COMMANDS_FUNC
+         && ch != '%'
+#endif
          && ch != '+'
          && ch != '-')
@@ -2532,6 +2535,7 @@
               char *ne_retval, const char *funcname)
 {
-    /* give up at once if not comp-cmds. */
-    if (strcmp (funcname, "comp-cmds") != 0)
+    /* give up at once if not comp-cmds or comp-cmds-ex. */
+    if (strcmp (funcname, "comp-cmds") != 0
+     && strcmp (funcname, "comp-cmds-ex") != 0)
       o = variable_buffer_output (o, ne_retval, strlen (ne_retval));
     else
@@ -2640,5 +2644,6 @@
 
   comp-cmds will compare command by command, ignoring not only leading
-  and trailing spaces on each line but also leading one leading '@' and '-'.
+  and trailing spaces on each line but also leading one leading '@', 
+  '-', '+' and '%'
 */
 static char *
@@ -2666,14 +2671,14 @@
     /* ignore trailing and leading blanks */
     s1 = var1->value;
+    e1 = s1 + var1->value_length;
     while (isblank ((unsigned char) *s1))
       s1++;
-    e1 = s1 + var1->value_length;
     while (e1 > s1 && isblank ((unsigned char) e1[-1]))
       e1--;
 
     s2 = var2->value;
+    e2 = s2 + var2->value_length;
     while (isblank ((unsigned char) *s2))
       s2++;
-    e2 = s2 + var2->value_length;
     while (e2 > s2 && isblank ((unsigned char) e2[-1]))
       e2--;
@@ -2762,4 +2767,53 @@
   return o;
 }
+
+/*
+  $(comp-cmds-ex cmds1,cmds2,not-equal-return)
+
+  Compares the two strings and return the string in the third argument 
+  if not equal. If equal, nothing is returned.
+
+  The comparision will be performed command by command, ignoring not 
+  only leading and trailing spaces on each line but also leading one 
+  leading '@', '-', '+' and '%'.
+*/
+static char *
+func_comp_cmds_ex (char *o, char **argv, const char *funcname)
+{
+  const char *s1, *e1, *x1, *s2, *e2, *x2;
+  char *a1 = NULL, *a2 = NULL;
+  size_t l, l1, l2;
+
+  /* the simple cases */
+  s1 = argv[0];
+  s2 = argv[1];
+  if (s1 == s2)
+    return variable_buffer_output (o, "", 0);       /* eq */
+  l1 = strlen (argv[0]);
+  l2 = strlen (argv[1]);
+
+  if (    l1 == l2
+      &&  !memcmp (s1, s2, l1))
+    return variable_buffer_output (o, "", 0);       /* eq */
+
+  /* ignore trailing and leading blanks */
+  e1 = s1 + l1;
+  while (isblank ((unsigned char) *s1))
+    s1++;
+  while (e1 > s1 && isblank ((unsigned char) e1[-1]))
+    e1--;
+
+  e2 = s2 + l1;
+  while (isblank ((unsigned char) *s2))
+    s2++;
+  while (e2 > s2 && isblank ((unsigned char) e2[-1]))
+    e2--;
+
+  if (e1 - s1 != e2 - s2)
+    return comp_vars_ne (o, s1, e1, s2, e2, argv[2], funcname);
+  if (!memcmp (s1, s2, e1 - s1))
+    return variable_buffer_output (o, "", 0);       /* eq */
+  return comp_vars_ne (o, s1, e1, s2, e2, argv[2], funcname);
+}
 #endif
 
@@ -2851,5 +2905,5 @@
    fails. */
 static char *
-func_file_size (char *o, char **argv, const char *funcname)
+func_file_size (char *o, char **argv, const char *funcname UNUSED)
 {
   struct stat st;
@@ -2924,5 +2978,5 @@
    their full location if found. Prints nothing if not found. */
 static char *
-func_which (char *o, char **argv, const char *funcname)
+func_which (char *o, char **argv, const char *funcname UNUSED)
 {
   const char *path;
@@ -3006,5 +3060,5 @@
 /* Push an item (string without spaces). */
 static char *
-func_stack_push (char *o, char **argv, const char *funcname)
+func_stack_push (char *o, char **argv, const char *funcname UNUSED)
 {
   do_variable_definition(NILF, argv[0], argv[1], o_file, f_append, 0 /* !target_var */);
@@ -3179,5 +3233,5 @@
 /* Add two or more integer numbers. */
 static char *
-func_int_add (char *o, char **argv, const char *funcname)
+func_int_add (char *o, char **argv, const char *funcname UNUSED)
 {
   math_int num;
@@ -3193,5 +3247,5 @@
 /* Subtract two or more integer numbers. */
 static char *
-func_int_sub (char *o, char **argv, const char *funcname)
+func_int_sub (char *o, char **argv, const char *funcname UNUSED)
 {
   math_int num;
@@ -3207,5 +3261,5 @@
 /* Multiply two or more integer numbers. */
 static char *
-func_int_mul (char *o, char **argv, const char *funcname)
+func_int_mul (char *o, char **argv, const char *funcname UNUSED)
 {
   math_int num;
@@ -3221,5 +3275,5 @@
 /* Divide an integer number by one or more divisors. */
 static char *
-func_int_div (char *o, char **argv, const char *funcname)
+func_int_div (char *o, char **argv, const char *funcname UNUSED)
 {
   math_int num;
@@ -3245,5 +3299,5 @@
 /* Divide and return the remainder. */
 static char *
-func_int_mod (char *o, char **argv, const char *funcname)
+func_int_mod (char *o, char **argv, const char *funcname UNUSED)
 {
   math_int num;
@@ -3264,5 +3318,5 @@
 /* 2-complement. */
 static char *
-func_int_not (char *o, char **argv, const char *funcname)
+func_int_not (char *o, char **argv, const char *funcname UNUSED)
 {
   math_int num;
@@ -3276,5 +3330,5 @@
 /* Bitwise AND (two or more numbers). */
 static char *
-func_int_and (char *o, char **argv, const char *funcname)
+func_int_and (char *o, char **argv, const char *funcname UNUSED)
 {
   math_int num;
@@ -3290,5 +3344,5 @@
 /* Bitwise OR (two or more numbers). */
 static char *
-func_int_or (char *o, char **argv, const char *funcname)
+func_int_or (char *o, char **argv, const char *funcname UNUSED)
 {
   math_int num;
@@ -3304,5 +3358,5 @@
 /* Bitwise XOR (two or more numbers). */
 static char *
-func_int_xor (char *o, char **argv, const char *funcname)
+func_int_xor (char *o, char **argv, const char *funcname UNUSED)
 {
   math_int num;
@@ -3416,5 +3470,5 @@
    the variable. */
 static char *
-func_os2_libpath (char *o, char **argv, const char *funcname)
+func_os2_libpath (char *o, char **argv, const char *funcname UNUSED)
 {
   char buf[4096];
@@ -3503,5 +3557,5 @@
 /* Retrieve make statistics. */
 static char *
-func_make_stats (char *o, char **argv, const char *funcname)
+func_make_stats (char *o, char **argv, const char *funcname UNUSED)
 {
   char buf[512];
@@ -3551,5 +3605,190 @@
   return o;
 }
-#endif
+#endif  /* CONFIG_WITH_MAKE_STATS */
+
+#ifdef CONFIG_WITH_COMMANDS_FUNC
+/* Gets all the commands for a target, separated by newlines.
+ 
+   This is useful when creating and checking target dependencies since
+   it reduces the amount of work and the memory consuption. A new prefix
+   character '%' has been introduced for skipping certain lines, like 
+   for instance the one calling this function and pushing to a dep file.
+   Blank lines are also skipped.
+
+   The commands function takes exactly one argument, which is the name of 
+   the target which commands should be returned. 
+
+   The commands-sc is identical to commands except that it uses a ';' to 
+   separate the commands.
+
+   The commands-usr is similar to commands except that it takes a 2nd
+   argument that is used to separate the commands. */
+char *
+func_commands (char *o, char **argv, const char *funcname)
+{
+  struct file *file;
+  static int recursive = 0;
+
+  if (recursive)
+    return variable_buffer_output (o, "recursive", sizeof ("recursive") - 1);
+  recursive = 1;
+
+  file = lookup_file (argv[0]);
+  if (file) 
+    {
+      int i, cmd_sep_len;
+      struct commands *cmds = file->cmds;
+      const char *cmd_sep;
+
+      if (!strcmp (funcname, "commands"))
+        {
+          cmd_sep = "\n";
+          cmd_sep_len = 1;
+        }
+      else if (!strcmp (funcname, "commands-sc"))
+        {
+          cmd_sep = ";";
+          cmd_sep_len = 1;
+        }
+      else /*if (!strcmp (funcname, "commands-usr"))*/
+        {
+          cmd_sep = argv[1];
+          cmd_sep_len = strlen (cmd_sep);
+        }
+
+      initialize_file_variables (file, 1 /* reading - FIXME: we don't know? */);
+      set_file_variables (file);
+      chop_commands (cmds);
+
+      for (i = 0; i < cmds->ncommand_lines; i++) 
+        {
+          char *p;
+          char *in, *out, *ref;
+
+          /* Skip it if it has a '%' prefix or is blank. */
+          if (cmds->lines_flags[i] & COMMAND_GETTER_SKIP_IT)
+            continue;
+          p = cmds->command_lines[i];
+          while (isblank ((unsigned char)*p))
+            p++;
+          if (*p == '\0') 
+            continue;
+
+          /* --- copied from new_job() in job.c --- */
+
+          /* Collapse backslash-newline combinations that are inside variable
+             or function references.  These are left alone by the parser so
+             that they will appear in the echoing of commands (where they look
+             nice); and collapsed by construct_command_argv when it tokenizes.
+             But letting them survive inside function invocations loses because
+             we don't want the functions to see them as part of the text.  */
+
+          /* IN points to where in the line we are scanning.
+             OUT points to where in the line we are writing.
+             When we collapse a backslash-newline combination,
+             IN gets ahead of OUT.  */
+
+          in = out = p;
+          while ((ref = strchr (in, '$')) != 0)
+            {
+              ++ref;		/* Move past the $.  */
+
+              if (out != in)
+                /* Copy the text between the end of the last chunk
+                   we processed (where IN points) and the new chunk
+                   we are about to process (where REF points).  */
+                memmove (out, in, ref - in);
+
+              /* Move both pointers past the boring stuff.  */
+              out += ref - in;
+              in = ref;
+
+              if (*ref == '(' || *ref == '{')
+                {
+                  char openparen = *ref;
+                  char closeparen = openparen == '(' ? ')' : '}';
+                  int count;
+                  char *p;
+
+                  *out++ = *in++;	/* Copy OPENPAREN.  */
+                  /* IN now points past the opening paren or brace.
+                     Count parens or braces until it is matched.  */
+                  count = 0;
+                  while (*in != '\0')
+                    {
+                      if (*in == closeparen && --count < 0)
+                        break;
+                      else if (*in == '\\' && in[1] == '\n')
+                        {
+                          /* We have found a backslash-newline inside a
+                             variable or function reference.  Eat it and
+                             any following whitespace.  */
+
+                          int quoted = 0;
+                          for (p = in - 1; p > ref && *p == '\\'; --p)
+                            quoted = !quoted;
+
+                          if (quoted)
+                            /* There were two or more backslashes, so this is
+                               not really a continuation line.  We don't collapse
+                               the quoting backslashes here as is done in
+                               collapse_continuations, because the line will
+                               be collapsed again after expansion.  */
+                            *out++ = *in++;
+                          else
+                            {
+                              /* Skip the backslash, newline and
+                                 any following whitespace.  */
+                              in = next_token (in + 2);
+
+                              /* Discard any preceding whitespace that has
+                                 already been written to the output.  */
+                              while (out > ref
+                                     && isblank ((unsigned char)out[-1]))
+                                --out;
+
+                              /* Replace it all with a single space.  */
+                              *out++ = ' ';
+                            }
+                        }
+                      else
+                        {
+                          if (*in == openparen)
+                            ++count;
+
+                          *out++ = *in++;
+                        }
+                    }
+                }
+            }
+
+          /* There are no more references in this line to worry about.
+             Copy the remaining uninteresting text to the output.  */
+          if (out != in)
+            strcpy (out, in);
+
+          /* --- copied from new_job() in job.c --- */
+
+          /* Finally, expand the line.  */
+          if (i)
+            o = variable_buffer_output (o, cmd_sep, cmd_sep_len);
+          o = variable_expand_for_file_2 (o, cmds->command_lines[i], file);
+
+          /* blank, if so, drop it. */
+          p = o;
+          while (isblank ((unsigned char)*o))
+            o++;
+          if (o != '\0')
+            o = strchr (o, '\0');
+          else
+            o = p - cmd_sep_len;
+        }
+    }
+  /* else FIXME: bitch about it? */
+
+  recursive = 0;
+  return o;
+}
+#endif  /* CONFIG_WITH_COMMANDS_FUNC */
 
 /* Lookup table for builtin functions.
@@ -3633,4 +3872,5 @@
   { STRING_SIZE_TUPLE("comp-vars"),     3,  3,  1,  func_comp_vars},
   { STRING_SIZE_TUPLE("comp-cmds"),     3,  3,  1,  func_comp_vars},
+  { STRING_SIZE_TUPLE("comp-cmds-ex"),  3,  3,  1,  func_comp_cmds_ex},
 #endif
 #ifdef CONFIG_WITH_DATE
@@ -3676,4 +3916,9 @@
   { STRING_SIZE_TUPLE("make-stats"),    0, ~0,  0,  func_make_stats},
 #endif
+#ifdef CONFIG_WITH_COMMANDS_FUNC
+  { STRING_SIZE_TUPLE("commands"),      1,  1,  1,  func_commands},
+  { STRING_SIZE_TUPLE("commands-sc"),   1,  1,  1,  func_commands},
+  { STRING_SIZE_TUPLE("commands-usr"),  2,  2,  1,  func_commands},
+#endif
 #ifdef KMK_HELPERS
   { STRING_SIZE_TUPLE("kb-src-tool"),   1,  1,  0,  func_kbuild_source_tool},
Index: /trunk/src/kmk/job.c
===================================================================
--- /trunk/src/kmk/job.c	(revision 1439)
+++ /trunk/src/kmk/job.c	(revision 1440)
@@ -1056,4 +1056,8 @@
       else if (*p == '-')
 	child->noerror = 1;
+#ifdef CONFIG_WITH_COMMANDS_FUNC
+      else if (*p == '%')
+        flags |= COMMAND_GETTER_SKIP_IT;
+#endif 
       else if (!isblank ((unsigned char)*p))
 #ifndef CONFIG_WITH_KMK_BUILTIN
Index: /trunk/src/kmk/kmkbuiltin/append.c
===================================================================
--- /trunk/src/kmk/kmkbuiltin/append.c	(revision 1439)
+++ /trunk/src/kmk/kmkbuiltin/append.c	(revision 1440)
@@ -42,5 +42,5 @@
 {
     fprintf(pf,
-            "usage: %s [-nv] file [string ...]\n"
+            "usage: %s [-cnv] file [string ...]\n"
             "   or: %s --version\n"
             "   or: %s --help\n",
@@ -61,4 +61,5 @@
 #ifndef kmk_builtin_append
     int fVariables = 0;
+    int fCommands = 0;
 #endif
 
@@ -82,4 +83,12 @@
                 switch (*psz)
                 {
+                    case 'c':
+#ifndef kmk_builtin_append
+                        fCommands = 1;
+                        break;
+#else
+                        errx(1, "Option '-c' isn't supported in external mode.");
+                        return usage(stderr);
+#endif
                     case 'n':
                         fNewLine = 1;
@@ -134,5 +143,18 @@
             fputc(fNewLine ? '\n' : ' ', pFile);
 #ifndef kmk_builtin_append
-        if (fVariables)
+        if (fCommands)
+        {
+            char *pszOldBuf;
+            unsigned cchOldBuf;
+            char *pchEnd;
+
+            install_variable_buffer(&pszOldBuf, &cchOldBuf);
+
+            pchEnd = func_commands(variable_buffer, &argv[i], "commands");
+            fwrite(variable_buffer, 1, pchEnd - variable_buffer, pFile);
+
+            restore_variable_buffer(pszOldBuf, cchOldBuf);
+        }
+        else if (fVariables)
         {
             struct variable *pVar = lookup_variable(psz, cch);
Index: /trunk/src/kmk/variable.c
===================================================================
--- /trunk/src/kmk/variable.c	(revision 1439)
+++ /trunk/src/kmk/variable.c	(revision 1440)
@@ -1046,4 +1046,5 @@
   && defined (CONFIG_WITH_EVALPLUS) \
   && defined (CONFIG_WITH_MAKE_STATS) \
+  && defined (CONFIG_WITH_COMMANDS_FUNC) \
   && defined (KMK_HELPERS)
   (void) define_variable ("KMK_FEATURES", 12,
@@ -1052,5 +1053,5 @@
                           " abspathex"
                           " toupper tolower"
-                          " comp-vars comp-cmds"
+                          " comp-vars comp-cmds comp-cmds-ex"
                           " stack"
                           " math-int"
@@ -1064,4 +1065,5 @@
                           " evalctx evalval evalvalctx evalcall evalcall2"
                           " make-stats"
+                          " commands"
                           " kb-src-tool kb-obj-base kb-obj-suff kb-src-prop kb-src-one "
                           , o_default, 0);
@@ -1079,5 +1081,5 @@
 #  endif
 #  if defined (CONFIG_WITH_VALUE_LENGTH) && defined(CONFIG_WITH_COMPARE)
-  strcat (buf, " comp-vars comp-cmds");
+  strcat (buf, " comp-vars comp-cmds comp-cmds-ex");
 #  endif
 #  if defined (CONFIG_WITH_STACK)
@@ -1114,4 +1116,7 @@
   strcat (buf, " make-stats");
 #  endif
+#  if defined (CONFIG_WITH_COMMANDS_FUNC)
+  strcat (buf, " commands");
+#  endif
 #  if defined (KMK_HELPERS)
   strcat (buf, " kb-src-tool kb-obj-base kb-obj-suff kb-src-prop kb-src-one");
Index: /trunk/src/kmk/variable.h
===================================================================
--- /trunk/src/kmk/variable.h	(revision 1439)
+++ /trunk/src/kmk/variable.h	(revision 1440)
@@ -132,4 +132,7 @@
 char *variable_expand (const char *line);
 char *variable_expand_for_file (const char *line, struct file *file);
+#ifdef CONFIG_WITH_COMMANDS_FUNC
+char *variable_expand_for_file_2 (char *o, const char *line, struct file *file);
+#endif
 char *allocated_variable_expand_for_file (const char *line, struct file *file);
 #define	allocated_variable_expand(line) \
@@ -153,4 +156,7 @@
                            const char *replace_percent);
 char *patsubst_expand (char *o, const char *text, char *pattern, char *replace);
+#ifdef CONFIG_WITH_COMMANDS_FUNC
+char *func_commands (char *o, char **argv, const char *funcname);
+#endif
 
 /* expand.c */
