Index: trunk/src/kWorker/Makefile.kmk
===================================================================
--- trunk/src/kWorker/Makefile.kmk	(revision 3191)
+++ trunk/src/kWorker/Makefile.kmk	(revision 3192)
@@ -36,5 +36,6 @@
 kWorker_SOURCES = \
 	kWorker.c \
-       ../kmk/kmkbuiltin/kDepObj.c
+       ../kmk/kmkbuiltin/kDepObj.c \
+       ../kmk/kmkbuiltin/err.c
 kWorker_INCS = \
 	../kmk/ \
Index: trunk/src/kWorker/kWorker.c
===================================================================
--- trunk/src/kWorker/kWorker.c	(revision 3191)
+++ trunk/src/kWorker/kWorker.c	(revision 3192)
@@ -10290,5 +10290,8 @@
     /* Command switch. */
     if (kHlpStrComp(pszCmd, "kDepObj") == 0)
-        return kmk_builtin_kDepObj(cPostCmdArgs, (char **)papszPostCmdArgs, NULL);
+    {
+        KMKBUILTINCTX Ctx = { papszPostCmdArgs[0], NULL };
+        return kmk_builtin_kDepObj(cPostCmdArgs, (char **)papszPostCmdArgs, NULL, &Ctx);
+    }
 
     return kwErrPrintfRc(42 + 5 , "Unknown post command: '%s'\n", pszCmd);
Index: trunk/src/kmk/Makefile.kmk
===================================================================
--- trunk/src/kmk/Makefile.kmk	(revision 3191)
+++ trunk/src/kmk/Makefile.kmk	(revision 3192)
@@ -83,4 +83,12 @@
 endif
 
+#
+# Template for building standalone built-in utilities.
+#
+TEMPLATE_BIN-KMK-BUILTIN = Template for standalone built-in utilies.
+TEMPLATE_BIN-KMK-BUILTIN_EXTENDS = BIN-KMK
+TEMPLATE_BIN-KMK-BUILTIN_EXTENDS_BY = appending
+TEMPLATE_BIN-KMK-BUILTIN_DEFS += KMK_BUILTIN_STANDALONE
+TEMPLATE_BIN-KMK-BUILTIN_SOURCES += kmkbuiltin/err.c
 
 #
@@ -93,5 +101,4 @@
 kmkmissing_NOINST = 1
 kmkmissing_SOURCES = \
-	kmkbuiltin/err.c \
 	kmkbuiltin/fts.c \
 	kmkbuiltin/setmode.c \
@@ -328,5 +335,8 @@
 	kmkbuiltin/sleep.c \
 	kmkbuiltin/test.c \
-	kmkbuiltin/touch.c
+	kmkbuiltin/touch.c \
+       \
+	kmkbuiltin/err.c
+
 
 ## @todo kmkbuiltin/redirect.c
@@ -364,28 +374,23 @@
 	kDepObj \
 
-kmk_append_TEMPLATE = BIN-KMK
-kmk_append_DEFS = kmk_builtin_append=main
+kmk_append_TEMPLATE = BIN-KMK-BUILTIN
 kmk_append_INCS = .
 kmk_append_SOURCES = \
 	kmkbuiltin/append.c
 
-kmk_cat_TEMPLATE = BIN-KMK
-kmk_cat_DEFS = kmk_builtin_cat=main
+kmk_cat_TEMPLATE = BIN-KMK-BUILTIN
 kmk_cat_SOURCES = \
 	kmkbuiltin/cat.c
 
-kmk_chmod_TEMPLATE = BIN-KMK
-kmk_chmod_DEFS = kmk_builtin_chmod=main
+kmk_chmod_TEMPLATE = BIN-KMK-BUILTIN
 kmk_chmod_SOURCES = \
 	kmkbuiltin/chmod.c
 
-kmk_cmp_TEMPLATE = BIN-KMK
-kmk_cmp_DEFS = kmk_builtin_cmp=main
+kmk_cmp_TEMPLATE = BIN-KMK-BUILTIN
 kmk_cmp_SOURCES = \
 	kmkbuiltin/cmp.c \
 	kmkbuiltin/cmp_util.c
 
-kmk_cp_TEMPLATE = BIN-KMK
-kmk_cp_DEFS = kmk_builtin_cp=main
+kmk_cp_TEMPLATE = BIN-KMK-BUILTIN
 kmk_cp_SOURCES = \
 	kmkbuiltin/cp.c \
@@ -393,51 +398,42 @@
 	kmkbuiltin/cmp_util.c
 
-kmk_echo_TEMPLATE = BIN-KMK
-kmk_echo_DEFS = kmk_builtin_echo=main
+kmk_echo_TEMPLATE = BIN-KMK-BUILTIN
 kmk_echo_SOURCES = \
 	kmkbuiltin/echo.c
 
-kmk_expr_TEMPLATE = BIN-KMK
-kmk_expr_DEFS = kmk_builtin_expr=main
+kmk_expr_TEMPLATE = BIN-KMK-BUILTIN
 kmk_expr_SOURCES = \
 	kmkbuiltin/expr.c
 
-kmk_install_TEMPLATE = BIN-KMK
-kmk_install_DEFS = kmk_builtin_install=main
+kmk_install_TEMPLATE = BIN-KMK-BUILTIN
 kmk_install_SOURCES = \
 	kmkbuiltin/install.c
 
-kmk_ln_TEMPLATE = BIN-KMK
-kmk_ln_DEFS = kmk_builtin_ln=main
+kmk_ln_TEMPLATE = BIN-KMK-BUILTIN
 kmk_ln_SOURCES = \
 	kmkbuiltin/ln.c
 
-kmk_mkdir_TEMPLATE = BIN-KMK
-kmk_mkdir_DEFS = kmk_builtin_mkdir=main
+kmk_mkdir_TEMPLATE = BIN-KMK-BUILTIN
 kmk_mkdir_SOURCES = \
 	kmkbuiltin/mkdir.c
 
-kmk_md5sum_TEMPLATE = BIN-KMK
-kmk_md5sum_DEFS = kmk_builtin_md5sum=main
+kmk_md5sum_TEMPLATE = BIN-KMK-BUILTIN
 kmk_md5sum_SOURCES = \
 	kmkbuiltin/md5sum.c
 kmk_md5sum_LIBS = $(LIB_KUTIL)
 
-kmk_mv_TEMPLATE = BIN-KMK
-kmk_mv_DEFS = kmk_builtin_mv=main
+kmk_mv_TEMPLATE = BIN-KMK-BUILTIN
 kmk_mv_SOURCES = \
 	kmkbuiltin/mv.c
 
-kmk_printf_TEMPLATE = BIN-KMK
-kmk_printf_DEFS = kmk_builtin_printf=main
+kmk_printf_TEMPLATE = BIN-KMK-BUILTIN
 kmk_printf_SOURCES = \
 	kmkbuiltin/printf.c
 
-kmk_rm_TEMPLATE = BIN-KMK
-kmk_rm_DEFS = kmk_builtin_rm=main
+kmk_rm_TEMPLATE = BIN-KMK-BUILTIN
 kmk_rm_SOURCES = \
 	kmkbuiltin/rm.c
 
-kmk_redirect_TEMPLATE = BIN-KMK
+kmk_redirect_TEMPLATE = BIN-KMK-BUILTIN
 kmk_redirect_SOURCES = \
 	kmkbuiltin/redirect.c
@@ -445,26 +441,21 @@
 	../lib/startuphacks-win.c
 
-kmk_rmdir_TEMPLATE = BIN-KMK
-kmk_rmdir_DEFS = kmk_builtin_rmdir=main
+kmk_rmdir_TEMPLATE = BIN-KMK-BUILTIN
 kmk_rmdir_SOURCES = \
 	kmkbuiltin/rmdir.c
 
-kmk_sleep_TEMPLATE = BIN-KMK
-kmk_sleep_DEFS = kmk_builtin_sleep=main
+kmk_sleep_TEMPLATE = BIN-KMK-BUILTIN
 kmk_sleep_SOURCES = \
 	kmkbuiltin/sleep.c
 
-kmk_test_TEMPLATE = BIN-KMK
-kmk_test_DEFS = kmk_builtin_test=main
+kmk_test_TEMPLATE = BIN-KMK-BUILTIN
 kmk_test_SOURCES = \
 	kmkbuiltin/test.c
 
-kmk_touch_TEMPLATE = BIN-KMK
-kmk_touch_DEFS = kmk_builtin_touch=main
+kmk_touch_TEMPLATE = BIN-KMK-BUILTIN
 kmk_touch_SOURCES = \
 	kmkbuiltin/touch.c
 
-kDepIDB_TEMPLATE = BIN-KMK
-kDepIDB_DEFS = kmk_builtin_kDepIDB=main
+kDepIDB_TEMPLATE = BIN-KMK-BUILTIN
 kDepIDB_INCS = .
 kDepIDB_LIBS = $(LIB_KDEP) $(LIB_KUTIL)
@@ -472,6 +463,5 @@
 	kmkbuiltin/kDepIDB.c
 
-kDepObj_TEMPLATE = BIN-KMK
-kDepObj_DEFS = kmk_builtin_kDepObj=main
+kDepObj_TEMPLATE = BIN-KMK-BUILTIN
 kDepObj_INCS = .
 kDepObj_LIBS = $(LIB_KDEP) $(LIB_KUTIL)
Index: trunk/src/kmk/dir-nt-bird.c
===================================================================
--- trunk/src/kmk/dir-nt-bird.c	(revision 3191)
+++ trunk/src/kmk/dir-nt-bird.c	(revision 3192)
@@ -40,4 +40,6 @@
 #endif
 #include <assert.h>
+#include "kmkbuiltin.h"
+#include "kmkbuiltin/err.h"
 
 #include "nt_fullpath.h" /* for the time being - will be implemented here later on. */
@@ -730,5 +732,5 @@
 
 
-int kmk_builtin_dircache(int argc, char **argv, char **envp)
+int kmk_builtin_dircache(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx)
 {
     assert(GetCurrentThreadId() == g_idMainThread);
@@ -743,5 +745,5 @@
                 return 0;
             }
-            fprintf(stderr, "kmk_builtin_dircache: the 'invalidate' command takes no arguments!\n");
+            errx(pCtx, 2, "the 'invalidate' command takes no arguments!\n");
         }
         else if (strcmp(pszCmd, "invalidate-missing") == 0)
@@ -752,5 +754,5 @@
                 return 0;
             }
-            fprintf(stderr, "kmk_builtin_dircache: the 'invalidate-missing' command takes no arguments!\n");
+            errx(pCtx, 2, "the 'invalidate-missing' command takes no arguments!\n");
         }
         else if (strcmp(pszCmd, "volatile") == 0)
@@ -769,8 +771,8 @@
         }
         else
-            fprintf(stderr, "kmk_builtin_dircache: Invalid command '%s'!\n", pszCmd);
-    }
-    else
-        fprintf(stderr, "kmk_builtin_dircache: No command given!\n");
+            errx(pCtx, 2, "Invalid command '%s'!\n", pszCmd);
+    }
+    else
+        errx(pCtx, 2, "No command given!\n");
 
     K_NOREF(envp);
Index: trunk/src/kmk/job.c
===================================================================
--- trunk/src/kmk/job.c	(revision 3191)
+++ trunk/src/kmk/job.c	(revision 3192)
@@ -1481,4 +1481,12 @@
     }
 
+  /* We're sure we're going to invoke a command: set up the output.  */
+  output_start ();
+
+  /* Flush the output streams so they won't have things written twice.  */
+
+  fflush (stdout);
+  fflush (stderr);
+
 #ifdef CONFIG_WITH_KMK_BUILTIN
   /* If builtin command then pass it on to the builtin shell interpreter. */
@@ -1538,12 +1546,4 @@
     }
 #endif /* CONFIG_WITH_KMK_BUILTIN */
-
-  /* We're sure we're going to invoke a command: set up the output.  */
-  output_start ();
-
-  /* Flush the output streams so they won't have things written twice.  */
-
-  fflush (stdout);
-  fflush (stderr);
 
   /* Decide whether to give this child the 'good' standard input
Index: trunk/src/kmk/kmkbuiltin.c
===================================================================
--- trunk/src/kmk/kmkbuiltin.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin.c	(revision 3192)
@@ -392,11 +392,15 @@
                     big_int nsStart = print_stats_flag ? nano_timestamp() : 0;
 #endif
+                    KMKBUILTINCTX Ctx;
                     int const iUmask = umask(0);        /* save umask */
                     umask(iUmask);
 
+                    Ctx.pszProgName = pEntry->uName.s.sz;
+                    Ctx.pOut = pChild ? &pChild->output : NULL;
+
                     if (pEntry->uFnSignature == FN_SIG_MAIN)
-                        rc = pEntry->u.pfnMain(argc, argv, papszEnvVars);
+                        rc = pEntry->u.pfnMain(argc, argv, papszEnvVars, &Ctx);
                     else if (pEntry->uFnSignature == FN_SIG_MAIN_SPAWNS)
-                        rc = pEntry->u.pfnMainSpawns(argc, argv, papszEnvVars, pChild, pPidSpawned);
+                        rc = pEntry->u.pfnMainSpawns(argc, argv, papszEnvVars, &Ctx, pChild, pPidSpawned);
                     else if (pEntry->uFnSignature == FN_SIG_MAIN_TO_SPAWN)
                     {
@@ -406,5 +410,5 @@
                          * problem then (the call stack shows what's been going on).
                          */
-                        rc = pEntry->u.pfnMainToSpawn(argc, argv, papszEnvVars, ppapszArgvToSpawn);
+                        rc = pEntry->u.pfnMainToSpawn(argc, argv, papszEnvVars, &Ctx, ppapszArgvToSpawn);
                         if (   !rc
                             && *ppapszArgvToSpawn
@@ -429,5 +433,4 @@
                         rc = 99;
 
-                    g_progname = "kmk";                 /* paranoia, make sure it's not pointing at a freed argv[0]. */
                     umask(iUmask);                      /* restore it */
 
Index: trunk/src/kmk/kmkbuiltin.h
===================================================================
--- trunk/src/kmk/kmkbuiltin.h	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin.h	(revision 3192)
@@ -34,4 +34,5 @@
 # include <sys/types.h>
 #endif
+#include <fcntl.h>
 
 /* For the GNU/hurd weirdo. */
@@ -57,9 +58,38 @@
 #endif
 
+/** This is for telling open() to open to return a close-on-exec descriptor. */
+#ifdef _O_NOINHERIT
+# define KMK_OPEN_NO_INHERIT        _O_NOINHERIT
+#elif defined(O_NOINHERIT)
+# define KMK_OPEN_NO_INHERIT        O_NOINHERIT
+#elif defined(O_CLOEXEC)
+# define KMK_OPEN_NO_INHERIT        O_CLOEXEC
+#else
+# define KMK_OPEN_NO_INHERIT        0
+#endif
+
+
 #include "kbuild_version.h"
+#ifndef KMK_BUILTIN_STANDALONE
+# include "../output.h"
+#endif
 
 struct child;
 int kmk_builtin_command(const char *pszCmd, struct child *pChild, char ***ppapszArgvToSpawn, pid_t *pPidSpawned);
 int kmk_builtin_command_parsed(int argc, char **argv, struct child *pChild, char ***ppapszArgvToSpawn, pid_t *pPidSpawned);
+
+
+/**
+ * KMK built-in command execution context.
+ */
+typedef struct KMKBUILTINCTX
+{
+    /** The program name to use in error messages. */
+    const char *pszProgName;
+    /** The KMK output synchronizer.   */
+    struct output *pOut;
+} KMKBUILTINCTX;
+/** Pointer to kmk built-in command execution context. */
+typedef KMKBUILTINCTX *PKMKBUILTINCTX;
 
 /**
@@ -81,9 +111,9 @@
         uintptr_t uPfn;
 #define FN_SIG_MAIN             0
-        int (* pfnMain)(int argc, char **argv, char **envp);
+        int (* pfnMain)(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx);
 #define FN_SIG_MAIN_SPAWNS      1
-        int (* pfnMainSpawns)(int argc, char **argv, char **envp, struct child *pChild, pid_t *pPid);
+        int (* pfnMainSpawns)(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx, struct child *pChild, pid_t *pPid);
 #define FN_SIG_MAIN_TO_SPAWN    2
-        int (* pfnMainToSpawn)(int argc, char **argv, char **envp, char ***ppapszArgvToSpawn);
+        int (* pfnMainToSpawn)(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx, char ***ppapszArgvToSpawn);
     } u;
     size_t      uFnSignature : 8;
@@ -94,52 +124,48 @@
 typedef KMKBUILTINENTRY const *PCKMKBUILTINENTRY;
 
-#ifndef kmk_builtin_append
-extern int kmk_builtin_append(int argc, char **argv, char **envp, struct child *pChild, pid_t *pPidSpawned);
-#endif
-extern int kmk_builtin_cp(int argc, char **argv, char **envp);
-extern int kmk_builtin_cat(int argc, char **argv, char **envp);
-extern int kmk_builtin_chmod(int argc, char **argv, char **envp);
-extern int kmk_builtin_cmp(int argc, char **argv, char **envp);
-extern int kmk_builtin_dircache(int argc, char **argv, char **envp);
-extern int kmk_builtin_echo(int argc, char **argv, char **envp);
-extern int kmk_builtin_expr(int argc, char **argv, char **envp);
-extern int kmk_builtin_install(int argc, char **argv, char **envp);
-extern int kmk_builtin_ln(int argc, char **argv, char **envp);
-extern int kmk_builtin_md5sum(int argc, char **argv, char **envp);
-extern int kmk_builtin_mkdir(int argc, char **argv, char **envp);
-extern int kmk_builtin_mv(int argc, char **argv, char **envp);
-extern int kmk_builtin_printf(int argc, char **argv, char **envp);
-extern int kmk_builtin_redirect(int argc, char **argv, char **envp, struct child *pChild, pid_t *pPidSpawned);
-extern int kmk_builtin_rm(int argc, char **argv, char **envp);
-extern int kmk_builtin_rmdir(int argc, char **argv, char **envp);
-extern int kmk_builtin_sleep(int argc, char **argv, char **envp);
-extern int kmk_builtin_test(int argc, char **argv, char **envp
-#ifndef kmk_builtin_test
-                            , char ***ppapszArgvSpawn
-#endif
-                            );
-extern int kmk_builtin_touch(int argc, char **argv, char **envp);
+extern int kmk_builtin_append(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx, struct child *pChild, pid_t *pPidSpawned);
+extern int kmk_builtin_cp(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx);
+extern int kmk_builtin_cat(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx);
+extern int kmk_builtin_chmod(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx);
+extern int kmk_builtin_cmp(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx);
+extern int kmk_builtin_dircache(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx);
+extern int kmk_builtin_echo(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx);
+extern int kmk_builtin_expr(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx);
+extern int kmk_builtin_install(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx);
+extern int kmk_builtin_ln(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx);
+extern int kmk_builtin_md5sum(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx);
+extern int kmk_builtin_mkdir(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx);
+extern int kmk_builtin_mv(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx);
+extern int kmk_builtin_printf(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx);
+extern int kmk_builtin_redirect(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx, struct child *pChild, pid_t *pPidSpawned);
+extern int kmk_builtin_rm(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx);
+extern int kmk_builtin_rmdir(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx);
+extern int kmk_builtin_sleep(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx);
+extern int kmk_builtin_test(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx, char ***ppapszArgvSpawn);
+extern int kmk_builtin_touch(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx);
 #ifdef KBUILD_OS_WINDOWS
-extern int kmk_builtin_kSubmit(int argc, char **argv, char **envp, struct child *pChild, pid_t *pPidSpawned);
+extern int kmk_builtin_kSubmit(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx, struct child *pChild, pid_t *pPidSpawned);
 extern int kSubmitSubProcGetResult(intptr_t pvUser, int *prcExit, int *piSigNo);
 extern int kSubmitSubProcKill(intptr_t pvUser, int iSignal);
 extern void kSubmitSubProcCleanup(intptr_t pvUser);
 #endif
-extern int kmk_builtin_kDepIDB(int argc, char **argv, char **envp);
-extern int kmk_builtin_kDepObj(int argc, char **argv, char **envp);
+extern int kmk_builtin_kDepIDB(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx);
+extern int kmk_builtin_kDepObj(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx);
 
 extern char *kmk_builtin_func_printf(char *o, char **argv, const char *funcname);
 
 /* common-env-and-cwd-opt.c: */
-extern int kBuiltinOptEnvSet(char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars,
+extern int kBuiltinOptEnvSet(PKMKBUILTINCTX pCtx, char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars,
                              int cVerbosity, const char *pszValue);
-extern int kBuiltinOptEnvAppend(char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars,
+extern int kBuiltinOptEnvAppend(PKMKBUILTINCTX pCtx, char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars,
                                 int cVerbosity, const char *pszValue);
-extern int kBuiltinOptEnvPrepend(char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars,
+extern int kBuiltinOptEnvPrepend(PKMKBUILTINCTX pCtx, char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars,
                                  int cVerbosity, const char *pszValue);
-extern int kBuiltinOptEnvUnset(char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars, int cVerbosity, const char *pszVarToRemove);
-extern int kBuiltinOptEnvZap(char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars, int cVerbosity);
+extern int kBuiltinOptEnvUnset(PKMKBUILTINCTX pCtx, char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars,
+                               int cVerbosity, const char *pszVarToRemove);
+extern int kBuiltinOptEnvZap(PKMKBUILTINCTX pCtx, char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars,
+                             int cVerbosity);
 extern void kBuiltinOptEnvCleanup(char ***ppapszEnv, unsigned cEnvVars, unsigned *pcAllocatedEnvVars);
-extern int kBuiltinOptChDir(char *pszCwd, size_t cbCwdBuf, const char *pszValue);
+extern int kBuiltinOptChDir(PKMKBUILTINCTX pCtx, char *pszCwd, size_t cbCwdBuf, const char *pszValue);
 
 #ifdef CONFIG_WITH_KMK_BUILTIN_STATS
Index: trunk/src/kmk/kmkbuiltin/append.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/append.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/append.c	(revision 3192)
@@ -24,8 +24,8 @@
  */
 
-/*******************************************************************************
-*   Header Files                                                               *
-*******************************************************************************/
-#ifndef kmk_builtin_append
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#ifndef KMK_BUILTIN_STANDALONE
 # include "makeint.h"
 # include "filedef.h"
@@ -46,5 +46,5 @@
 # include <alloca.h>
 #endif
-#if !defined(kmk_builtin_append) && defined(KBUILD_OS_WINDOWS) && defined(CONFIG_NEW_WIN_CHILDREN)
+#if !defined(KMK_BUILTIN_STANDALONE) && defined(KBUILD_OS_WINDOWS) && defined(CONFIG_NEW_WIN_CHILDREN)
 # include "../w32/winchildren.h"
 #endif
@@ -173,9 +173,5 @@
  * Appends text to a textfile, creating the textfile if necessary.
  */
-#ifndef kmk_builtin_append
-int kmk_builtin_append(int argc, char **argv, char **envp, struct child *pChild, pid_t *pPidSpawned)
-#else
-int main(int argc, char **argv, char **envp)
-#endif
+int kmk_builtin_append(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx, struct child *pChild, pid_t *pPidSpawned)
 {
 #if defined(KBUILD_OS_WINDOWS) || defined(KBUILD_OS_OS2)
@@ -195,9 +191,9 @@
     int fVariables = 0;
     int fCommands = 0;
-#ifndef kmk_builtin_append
+#ifndef KMK_BUILTIN_STANDALONE
     int fLookForInserts = 0;
-#endif
-
-    g_progname = argv[0];
+#else
+    (void)pChild; (void)pPidSpawned;
+#endif
 
     /*
@@ -221,12 +217,12 @@
                         if (fVariables)
                         {
-                            errx(1, "Option '-c' clashes with '-v'.");
+                            errx(pCtx, 1, "Option '-c' clashes with '-v'.");
                             return kmk_builtin_append_usage(argv[0], stderr);
                         }
-#ifndef kmk_builtin_append
+#ifndef KMK_BUILTIN_STANDALONE
                         fCommands = 1;
                         break;
 #else
-                        errx(1, "Option '-c' isn't supported in external mode.");
+                        errx(pCtx, 1, "Option '-c' isn't supported in external mode.");
                         return kmk_builtin_append_usage(argv[0], stderr);
 #endif
@@ -234,5 +230,5 @@
                         if (fVariables)
                         {
-                            errx(1, "Option '-d' must come before '-v'!");
+                            errx(pCtx, 1, "Option '-d' must come before '-v'!");
                             return kmk_builtin_append_usage(argv[0], stderr);
                         }
@@ -242,12 +238,12 @@
                         if (fVariables || fCommands)
                         {
-                            errx(1, fVariables ? "Option '-i' clashes with '-v'." : "Option '-i' clashes with '-c'.");
+                            errx(pCtx, 1, fVariables ? "Option '-i' clashes with '-v'." : "Option '-i' clashes with '-c'.");
                             return kmk_builtin_append_usage(argv[0], stderr);
                         }
-#ifndef kmk_builtin_append
+#ifndef KMK_BUILTIN_STANDALONE
                         fLookForInserts = 1;
                         break;
 #else
-                        errx(1, "Option '-C' isn't supported in external mode.");
+                        errx(pCtx, 1, "Option '-C' isn't supported in external mode.");
                         return kmk_builtin_append_usage(argv[0], stderr);
 #endif
@@ -264,16 +260,16 @@
                         if (fCommands)
                         {
-                            errx(1, "Option '-v' clashes with '-c'.");
+                            errx(pCtx, 1, "Option '-v' clashes with '-c'.");
                             return kmk_builtin_append_usage(argv[0], stderr);
                         }
-#ifndef kmk_builtin_append
+#ifndef KMK_BUILTIN_STANDALONE
                         fVariables = 1;
                         break;
 #else
-                        errx(1, "Option '-v' isn't supported in external mode.");
+                        errx(pCtx, 1, "Option '-v' isn't supported in external mode.");
                         return kmk_builtin_append_usage(argv[0], stderr);
 #endif
                     default:
-                        errx(1, "Invalid option '%c'! (%s)", *psz, argv[i]);
+                        errx(pCtx, 1, "Invalid option '%c'! (%s)", *psz, argv[i]);
                         return kmk_builtin_append_usage(argv[0], stderr);
                 }
@@ -300,7 +296,7 @@
     {
         if (i <= argc)
-            errx(1, "missing filename!");
+            errx(pCtx, 1, "missing filename!");
         else
-            errx(1, "missing define name!");
+            errx(pCtx, 1, "missing define name!");
         return kmk_builtin_append_usage(argv[0], stderr);
     }
@@ -334,5 +330,5 @@
                 write_to_buf(&OutBuf, STR_TUPLE(" "));
         }
-#ifndef kmk_builtin_append
+#ifndef KMK_BUILTIN_STANDALONE
         if (fCommands)
         {
@@ -417,10 +413,10 @@
      * Write the buffer (unless we ran out of heap already).
      */
-#if !defined(kmk_builtin_append) && defined(KBUILD_OS_WINDOWS) && defined(CONFIG_NEW_WIN_CHILDREN)
+#if !defined(KMK_BUILTIN_STANDALONE) && defined(KBUILD_OS_WINDOWS) && defined(CONFIG_NEW_WIN_CHILDREN)
     if (!OutBuf.fOutOfMemory)
     {
         rc = MkWinChildCreateAppend(pszFilename, &OutBuf.pszBuf, OutBuf.offBuf, fTruncate, pChild, pPidSpawned);
         if (rc != 0)
-            rc = errx(rc, "MkWinChildCreateAppend failed: %u", rc);
+            rc = errx(pCtx, rc, "MkWinChildCreateAppend failed: %u", rc);
         if (OutBuf.pszBuf)
             free(OutBuf.pszBuf);
@@ -440,15 +436,23 @@
                 rc = 0;
             else
-                rc = err(1, "error writing %lu bytes to '%s'", (unsigned long)OutBuf.offBuf, pszFilename);
+                rc = err(pCtx, 1, "error writing %lu bytes to '%s'", (unsigned long)OutBuf.offBuf, pszFilename);
             if (close(fd) < 0)
-                rc = err(1, "error closing '%s'", pszFilename);
+                rc = err(pCtx, 1, "error closing '%s'", pszFilename);
         }
         else
-            rc = err(1, "failed to open '%s'", pszFilename);
+            rc = err(pCtx, 1, "failed to open '%s'", pszFilename);
         free(OutBuf.pszBuf);
     }
     else
-        rc = errx(1, "out of memory for output buffer! (%u needed)", OutBuf.offBuf + 1);
+        rc = errx(pCtx, 1, "out of memory for output buffer! (%u needed)", OutBuf.offBuf + 1);
     return rc;
 }
 
+#ifdef KMK_BUILTIN_STANDALONE
+int main(int argc, char **argv, char **envp)
+{
+    KMKBUILTINCTX Ctx = { "kmk_append", NULL };
+    return kmk_builtin_append(argc, argv, envp, &Ctx, NULL, NULL);
+}
+#endif
+
Index: trunk/src/kmk/kmkbuiltin/cat.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/cat.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/cat.c	(revision 3192)
@@ -93,15 +93,15 @@
 
 
-static int usage(FILE *);
-static int scanfiles(char *argv[], int cooked);
-static int cook_cat(FILE *);
-static int raw_cat(int);
+static int usage(PKMKBUILTINCTX pCtx, int fIsErr);
+static int scanfiles(PKMKBUILTINCTX pCtx, char *argv[], int cooked);
+static int cook_cat(PKMKBUILTINCTX pCtx, FILE *);
+static int raw_cat(PKMKBUILTINCTX pCtx, int);
 
 #ifndef NO_UDOM_SUPPORT
-static int udom_open(const char *path, int flags);
+static int udom_open(PKMKBUILTINCTX pCtx, const char *path, int flags);
 #endif
 
 int
-kmk_builtin_cat(int argc, char *argv[], char **envp)
+kmk_builtin_cat(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx)
 {
 	int ch, rc;
@@ -112,5 +112,4 @@
 
 	/* kmk: reset getopt and set progname */
-	g_progname = argv[0];
 	opterr = 1;
 	optarg = NULL;
@@ -118,8 +117,6 @@
 	optind = 0; /* init */
 
-#ifdef kmk_builtin_cat /* kmk did this already. */
+#ifdef KMK_BUILTIN_STANDALONE /* kmk did this already. */
 	setlocale(LC_CTYPE, "");
-#else
-	fflush(stdout);
 #endif
 
@@ -142,5 +139,7 @@
 			break;
 		case 'u':
+#ifdef KMK_BUILTIN_STANDALONE /* don't allow messing with stdout */
 			setbuf(stdout, NULL);
+#endif
 			break;
 		case 'v':
@@ -148,36 +147,46 @@
 			break;
 		case 261:
-			usage(stdout);
+			usage(pCtx, 0);
 			return 0;
 		case 262:
 			return kbuild_version(argv[0]);
 		default:
-			return usage(stderr);
+			return usage(pCtx, 1);
 		}
 	argv += optind;
 
 	if (bflag || eflag || nflag || sflag || tflag || vflag)
-		rc = scanfiles(argv, 1);
+		rc = scanfiles(pCtx, argv, 1);
 	else
-		rc = scanfiles(argv, 0);
-#ifdef kmk_builtin_cat /* only in the external program. */
+		rc = scanfiles(pCtx, argv, 0);
+#ifdef KMK_BUILTIN_STANDALONE /* don't allow messing with stdout */
 	if (fclose(stdout))
-		return err(1, "stdout");
+		return err(pCtx, 1, "stdout");
 #endif
 	return rc;
 }
 
-static int
-usage(FILE *fp)
-{
-	fprintf(fp, "usage: %s [-benstuv] [file ...]\n"
-	            "   or: %s --help\n"
-	            "   or: %s --version\n",
-	        g_progname, g_progname, g_progname);
+#ifdef KMK_BUILTIN_STANDALONE
+int main(int argc, char **argv, char **envp)
+{
+    KMKBUILTINCTX Ctx = { "kmk_cat", NULL };
+    return kmk_builtin_cat(argc, argv, envp, &Ctx);
+}
+#endif
+
+static int
+usage(PKMKBUILTINCTX pCtx, int fIsErr)
+{
+	kmk_builtin_ctx_printf(pCtx, fIsErr,
+			       "usage: %s [-benstuv] [file ...]\n"
+			       "   or: %s --help\n"
+			       "   or: %s --version\n",
+			       pCtx->pszProgName, pCtx->pszProgName,
+			       pCtx->pszProgName);
 	return 1;
 }
 
 static int
-scanfiles(char *argv[], int cooked)
+scanfiles(PKMKBUILTINCTX pCtx, char *argv[], int cooked)
 {
 	int i = 0;
@@ -198,20 +207,20 @@
 #ifndef NO_UDOM_SUPPORT
 			if (fd < 0 && errno == EOPNOTSUPP)
-				fd = udom_open(path, O_RDONLY);
+				fd = udom_open(pCtx, path, O_RDONLY);
 #endif
 		}
 		if (fd < 0) {
-			warn("%s", path);
+			warn(pCtx, "%s", path);
 			rc2 = 1; /* non fatal */
 		} else if (cooked) {
 			if (fd == STDIN_FILENO)
-				rc = cook_cat(stdin);
+				rc = cook_cat(pCtx, stdin);
 			else {
 				fp = fdopen(fd, "r");
-				rc = cook_cat(fp);
+				rc = cook_cat(pCtx, fp);
 				fclose(fp);
 			}
 		} else {
-			rc = raw_cat(fd);
+			rc = raw_cat(pCtx, fd);
 			if (fd != STDIN_FILENO)
 				close(fd);
@@ -224,6 +233,17 @@
 }
 
-static int
-cook_cat(FILE *fp)
+static int cat_putchar(PKMKBUILTINCTX pCtx, char ch)
+{
+#ifndef KMK_BUILTIN_STANDALONE
+	if (pCtx->pOut) {
+		output_write_text(pCtx->pOut, 0, &ch, 1);
+		return 0;
+	}
+#endif
+	return putchar(ch);
+}
+
+static int
+cook_cat(PKMKBUILTINCTX pCtx, FILE *fp)
 {
 	int ch, gobble, line, prev;
@@ -246,5 +266,5 @@
 			}
 			if (nflag && (!bflag || ch != '\n')) {
-				(void)fprintf(stdout, "%6d\t", ++line);
+				kmk_builtin_ctx_printf(pCtx, 0, "%6d\t", ++line);
 				if (ferror(stdout))
 					break;
@@ -252,9 +272,9 @@
 		}
 		if (ch == '\n') {
-			if (eflag && putchar('$') == EOF)
+			if (eflag && cat_putchar(pCtx, '$') == EOF)
 				break;
 		} else if (ch == '\t') {
 			if (tflag) {
-				if (putchar('^') == EOF || putchar('I') == EOF)
+				if (cat_putchar(pCtx, '^') == EOF || cat_putchar(pCtx, 'I') == EOF)
 					break;
 				continue;
@@ -262,11 +282,11 @@
 		} else if (vflag) {
 			if (!isascii(ch) && !isprint(ch)) {
-				if (putchar('M') == EOF || putchar('-') == EOF)
+				if (cat_putchar(pCtx, 'M') == EOF || cat_putchar(pCtx, '-') == EOF)
 					break;
 				ch = toascii(ch);
 			}
 			if (iscntrl(ch)) {
-				if (putchar('^') == EOF ||
-				    putchar(ch == '\177' ? '?' :
+				if (cat_putchar(pCtx, '^') == EOF ||
+				    cat_putchar(pCtx, ch == '\177' ? '?' :
 				    ch | 0100) == EOF)
 					break;
@@ -274,19 +294,19 @@
 			}
 		}
-		if (putchar(ch) == EOF)
+		if (cat_putchar(pCtx, ch) == EOF)
 			break;
 	}
 	if (ferror(fp)) {
-		warn("%s", filename);
+		warn(pCtx, "%s", filename);
 		rc = 1;
 		clearerr(fp);
 	}
 	if (ferror(stdout))
-		return err(1, "stdout");
+		return err(pCtx, 1, "stdout");
 	return rc;
 }
 
 static int
-raw_cat(int rfd)
+raw_cat(PKMKBUILTINCTX pCtx, int rfd)
 {
 	int off, wfd = fileno(stdout);
@@ -299,5 +319,5 @@
 	if (buf == NULL) {
 		if (fstat(wfd, &sbuf))
-			return err(1, "%s", filename);
+			return err(pCtx, 1, "%s", filename);
 #ifdef KBUILD_OS_WINDOWS
 		bsize = 16384;
@@ -306,12 +326,19 @@
 #endif
 		if ((buf = malloc(bsize)) == NULL)
-			return err(1, "buffer");
+			return err(pCtx, 1, "buffer");
 	}
 	while ((nr = read(rfd, buf, bsize)) > 0)
-		for (off = 0; nr; nr -= nw, off += nw)
-			if ((nw = write(wfd, buf + off, (size_t)nr)) < 0)
-				return err(1, "stdout");
+		for (off = 0; nr; nr -= nw, off += nw) {
+#ifndef KMK_BUILTIN_STANDALONE
+			if (pCtx->pOut)
+				nw = output_write_text(pCtx->pOut, 0, buf, nr);
+			else
+#endif
+				nw = write(wfd, buf + off, (size_t)nr);
+			if (nw < 0)
+				return err(pCtx, 1, "stdout");
+		}
 	if (nr < 0) {
-		warn("%s", filename);
+		warn(pCtx, "%s", filename);
 		return 1;
 	}
@@ -322,5 +349,5 @@
 
 static int
-udom_open(const char *path, int flags)
+udom_open(PKMKBUILTINCTX pCtx, const char *path, int flags)
 {
 	struct sockaddr_un sou;
@@ -356,9 +383,9 @@
 		case O_RDONLY:
 			if (shutdown(fd, SHUT_WR) == -1)
-				warn(NULL);
+				warn(pCtx, NULL);
 			break;
 		case O_WRONLY:
 			if (shutdown(fd, SHUT_RD) == -1)
-				warn(NULL);
+				warn(pCtx, NULL);
 			break;
 		default:
@@ -370,2 +397,3 @@
 
 #endif
+
Index: trunk/src/kmk/kmkbuiltin/chmod.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/chmod.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/chmod.c	(revision 3192)
@@ -75,5 +75,5 @@
 #endif
 
-static int usage(FILE *);
+static int usage(PKMKBUILTINCTX pCtx, int is_err);
 
 static struct option long_options[] =
@@ -86,5 +86,5 @@
 
 int
-kmk_builtin_chmod(int argc, char *argv[], char **envp)
+kmk_builtin_chmod(int argc, char *argv[], char **envp, PKMKBUILTINCTX pCtx)
 {
 	FTS *ftsp;
@@ -98,5 +98,4 @@
 
 	/* kmk: reset getopt and set progname */
-	g_progname = argv[0];
 	opterr = 1;
 	optarg = NULL;
@@ -153,5 +152,5 @@
 			break;
 		case 261:
-			usage(stdout);
+			usage(pCtx, 0);
 			return 0;
 		case 262:
@@ -159,5 +158,5 @@
 		case '?':
 		default:
-			return usage(stderr);
+			return usage(pCtx, 1);
 		}
 done:	argv += optind;
@@ -165,10 +164,10 @@
 
 	if (argc < 2)
-		return usage(stderr);
+		return usage(pCtx, 1);
 
 	if (Rflag) {
 		fts_options = FTS_PHYSICAL;
 		if (hflag)
-			return errx(1,
+			return errx(pCtx, 1,
 		"the -R and -h options may not be specified together.");
 		if (Hflag)
@@ -188,8 +187,8 @@
 	mode = *argv;
 	if ((set = bsd_setmode(mode)) == NULL)
-		return errx(1, "invalid file mode: %s", mode);
+		return errx(pCtx, 1, "invalid file mode: %s", mode);
 
 	if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
-		return err(1, "fts_open");
+		return err(pCtx, 1, "fts_open");
 	for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
 		switch (p->fts_info) {
@@ -199,10 +198,10 @@
 			continue;
 		case FTS_DNR:			/* Warn, chmod, continue. */
-			warnx("fts: %s: %s", p->fts_path, strerror(p->fts_errno));
+			warnx(pCtx, "fts: %s: %s", p->fts_path, strerror(p->fts_errno));
 			rval = 1;
 			break;
 		case FTS_ERR:			/* Warn, continue. */
 		case FTS_NS:
-			warnx("fts: %s: %s", p->fts_path, strerror(p->fts_errno));
+			warnx(pCtx, "fts: %s: %s", p->fts_path, strerror(p->fts_errno));
 			rval = 1;
 			continue;
@@ -225,9 +224,9 @@
 			continue;
 		if ((*change_mode)(p->fts_accpath, newmode) && !fflag) {
-			warn("%schmod: %s", hflag ? "l" : "", p->fts_path);
+			warn(pCtx, "%schmod: %s", hflag ? "l" : "", p->fts_path);
 			rval = 1;
 		} else {
 			if (vflag) {
-				(void)printf("%s", p->fts_path);
+				kmk_builtin_ctx_printf(pCtx, 0, "%s", p->fts_path);
 
 				if (vflag > 1) {
@@ -238,9 +237,9 @@
 					    S_IFMT) | newmode, m2);
 
-					(void)printf(": 0%o [%s] -> 0%o [%s]",
+					kmk_builtin_ctx_printf(pCtx, 0, ": 0%o [%s] -> 0%o [%s]",
 					    (unsigned int)p->fts_statp->st_mode, m1,
 					    (unsigned int)((p->fts_statp->st_mode & S_IFMT) | newmode), m2);
 				}
-				(void)printf("\n");
+				kmk_builtin_ctx_printf(pCtx, 0, "\n");
 			}
 
@@ -248,5 +247,5 @@
 	}
 	if (errno)
-		rval = err(1, "fts_read");
+		rval = err(pCtx, 1, "fts_read");
 	free(set);
 	fts_close(ftsp);
@@ -255,12 +254,21 @@
 
 int
-usage(FILE *out)
-{
-	(void)fprintf(out,
+usage(PKMKBUILTINCTX pCtx, int is_err)
+{
+	kmk_builtin_ctx_printf(pCtx, is_err,
 	    "usage: %s [-fhv] [-R [-H | -L | -P]] mode file ...\n"
 	    "   or: %s --version\n"
 	    "   or: %s --help\n",
-	    g_progname, g_progname, g_progname);
+	    pCtx->pszProgName, pCtx->pszProgName, pCtx->pszProgName);
 
 	return 1;
 }
+
+#ifdef KMK_BUILTIN_STANDALONE
+int main(int argc, char **argv, char **envp)
+{
+    KMKBUILTINCTX Ctx = { "kmk_chmod", NULL };
+    return kmk_builtin_chmod(argc, argv, envp, &Ctx);
+}
+#endif
+
Index: trunk/src/kmk/kmkbuiltin/cmp.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/cmp.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/cmp.c	(revision 3192)
@@ -64,8 +64,8 @@
 
 
-static int usage(FILE *);
+static int usage(PKMKBUILTINCTX pCtx, int is_err);
 
 int
-kmk_builtin_cmp(int argc, char *argv[], char **envp)
+kmk_builtin_cmp(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx)
 {
     off_t skip1 = 0, skip2 = 0;
@@ -74,10 +74,9 @@
     char *file1, *file2;
 
-#ifdef kmk_builtin_cmp
+#ifdef KMK_BUILTIN_STANDALONE
     setlocale(LC_ALL, "");
 #endif
 
     /* reset getopt and set progname. */
-    g_progname = argv[0];
     opterr = 1;
     optarg = NULL;
@@ -96,5 +95,5 @@
                 break;
             case 261:
-                usage(stdout);
+                usage(pCtx, 0);
                 return 0;
             case 262:
@@ -102,5 +101,5 @@
             case '?':
             default:
-                return usage(stderr);
+                return usage(pCtx, 1);
         }
     }
@@ -109,5 +108,5 @@
 
     if (argc < 2 || argc > 4)
-        return usage(stderr);
+        return usage(pCtx, 1);
 
     file1 = argv[0];
@@ -121,5 +120,5 @@
         skip1 = strtoll(argv[2], &ep, 0);
         if (errno || ep == argv[2])
-            return errx(ERR_EXIT, "strtoll(%s,,) failed", argv[2]);
+            return errx(pCtx, ERR_EXIT, "strtoll(%s,,) failed", argv[2]);
 
         if (argc == 4)
@@ -127,18 +126,28 @@
             skip2 = strtoll(argv[3], &ep, 0);
             if (errno || ep == argv[3])
-                return errx(ERR_EXIT, "strtoll(%s,,) failed", argv[3]);
+                return errx(pCtx, ERR_EXIT, "strtoll(%s,,) failed", argv[3]);
 	}
     }
 
-    return cmp_file_and_file_ex(file1, skip1, file2, skip2, sflag, lflag, 0);
+    return cmp_file_and_file_ex(pCtx, file1, skip1, file2, skip2, sflag, lflag, 0);
 }
 
 static int
-usage(FILE *fp)
+usage(PKMKBUILTINCTX pCtx, int is_err)
 {
-    fprintf(fp, "usage: %s [-l | -s] file1 file2 [skip1 [skip2]]\n"
-                "   or: %s --help\n"
-                "   or: %s --version\n",
-            g_progname, g_progname, g_progname);
+    kmk_builtin_ctx_printf(pCtx, is_err,
+                           "usage: %s [-l | -s] file1 file2 [skip1 [skip2]]\n"
+                           "   or: %s --help\n"
+                           "   or: %s --version\n",
+                           pCtx->pszProgName, pCtx->pszProgName, pCtx->pszProgName);
     return ERR_EXIT;
 }
+
+#ifdef KMK_BUILTIN_STANDALONE
+int main(int argc, char **argv, char **envp)
+{
+    KMKBUILTINCTX Ctx = { "kmk_cmp", NULL };
+    return kmk_builtin_cmp(argc, argv, envp, &Ctx);
+}
+#endif
+
Index: trunk/src/kmk/kmkbuiltin/cmp_extern.h
===================================================================
--- trunk/src/kmk/kmkbuiltin/cmp_extern.h	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/cmp_extern.h	(revision 3192)
@@ -36,14 +36,14 @@
 #define ERR_EXIT	2	/* error exit code */
 
-int cmp_file_and_file(const char *file1, const char *file2, int sflag, int lflag, int special);
-int cmp_file_and_file_ex(const char *file1, off_t skip1, 
+int cmp_file_and_file(PKMKBUILTINCTX pCtx, const char *file1, const char *file2, int sflag, int lflag, int special);
+int cmp_file_and_file_ex(PKMKBUILTINCTX pCtx, const char *file1, off_t skip1,
                          const char *file2, off_t skip2, int sflag, int lflag, int special);
-int cmp_fd_and_file(int fd1, const char *file1,
+int cmp_fd_and_file(PKMKBUILTINCTX pCtx, int fd1, const char *file1,
                     const char *file2, int sflag, int lflag, int special);
-int cmp_fd_and_file_ex(int fd1, const char *file1, off_t skip1,
+int cmp_fd_and_file_ex(PKMKBUILTINCTX pCtx, int fd1, const char *file1, off_t skip1,
                        const char *file2, off_t skip2, int sflag, int lflag, int special);
-int cmp_fd_and_fd(int fd1, const char *file1, 
+int cmp_fd_and_fd(PKMKBUILTINCTX pCtx, int fd1, const char *file1,
                   int fd2, const char *file2, int sflag, int lflag, int special);
-int cmp_fd_and_fd_ex(int fd1, const char *file1, off_t skip1,
+int cmp_fd_and_fd_ex(PKMKBUILTINCTX pCtx, int fd1, const char *file1, off_t skip1,
                      int fd2, const char *file2, off_t skip2,  int sflag, int lflag, int special);
 
Index: trunk/src/kmk/kmkbuiltin/cmp_util.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/cmp_util.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/cmp_util.c	(revision 3192)
@@ -66,35 +66,35 @@
 
 static int
-errmsg(const char *file, off_t byte, off_t line, int lflag)
+errmsg(PKMKBUILTINCTX pCtx, const char *file, off_t byte, off_t line, int lflag)
 {
     if (lflag)
 #ifdef _MSC_VER
-        return err(ERR_EXIT, "%s: char %I64d, line %lld", file, (__int64)byte, (long long)line);
-#else
-        return err(ERR_EXIT, "%s: char %lld, line %lld", file, (long long)byte, (long long)line);
-#endif
-    return err(ERR_EXIT, "%s", file);
+        return err(pCtx, ERR_EXIT, "%s: char %I64d, line %lld", file, (__int64)byte, (long long)line);
+#else
+        return err(pCtx, ERR_EXIT, "%s: char %lld, line %lld", file, (long long)byte, (long long)line);
+#endif
+    return err(pCtx, ERR_EXIT, "%s", file);
 }
 
 
 static int
-eofmsg(const char *file, off_t byte, off_t line, int sflag, int lflag)
+eofmsg(PKMKBUILTINCTX pCtx, const char *file, off_t byte, off_t line, int sflag, int lflag)
 {
     if (!sflag)
     {
         if (!lflag)
-            warnx("EOF on %s", file);
+            warnx(pCtx, "EOF on %s", file);
         else
         {
 #ifdef _MSC_VER
             if (line > 0)
-                warnx("EOF on %s: char %I64d, line %I64d", file, (__int64)byte, (__int64)line);
+                warnx(pCtx, "EOF on %s: char %I64d, line %I64d", file, (__int64)byte, (__int64)line);
             else
-                warnx("EOF on %s: char %I64d", file, (__int64)byte);
+                warnx(pCtx, "EOF on %s: char %I64d", file, (__int64)byte);
 #else
             if (line > 0)
-                warnx("EOF on %s: char %lld, line %lld", file, (long long)byte, (long long)line);
+                warnx(pCtx, "EOF on %s: char %lld, line %lld", file, (long long)byte, (long long)line);
             else
-                warnx("EOF on %s: char %lld", file, (long long)byte);
+                warnx(pCtx, "EOF on %s: char %lld", file, (long long)byte);
 #endif
         }
@@ -105,12 +105,12 @@
 
 static int
-diffmsg(const char *file1, const char *file2, off_t byte, off_t line, int sflag)
+diffmsg(PKMKBUILTINCTX pCtx, const char *file1, const char *file2, off_t byte, off_t line, int sflag)
 {
     if (!sflag)
 #ifdef _MSC_VER
-        printf("%s %s differ: char %I64d, line %I64d\n",
+        kmk_builtin_ctx_printf(pCtx, 0, "%s %s differ: char %I64d, line %I64d\n",
                file1, file2, (__int64)byte, (__int64)line);
 #else
-        printf("%s %s differ: char %lld, line %lld\n",
+        kmk_builtin_ctx_printf(pCtx, 0, "%s %s differ: char %lld, line %lld\n",
                file1, file2, (long long)byte, (long long)line);
 #endif
@@ -123,5 +123,5 @@
  */
 static int
-c_special(int fd1, const char *file1, off_t skip1,
+c_special(PKMKBUILTINCTX pCtx, int fd1, const char *file1, off_t skip1,
           int fd2, const char *file2, off_t skip2,
           int lflag, int sflag)
@@ -134,5 +134,5 @@
     fd1dup = dup(fd1);
     if (fd1 < 0)
-        return err(ERR_EXIT, "%s", file1);
+        return err(pCtx, ERR_EXIT, "%s", file1);
     fp1 = fdopen(fd1dup, "rb");
     if (!fp1)
@@ -140,5 +140,5 @@
     if (!fp1)
     {
-        err(ERR_EXIT, "%s", file1);
+        err(pCtx, ERR_EXIT, "%s", file1);
         close(fd1dup);
         return ERR_EXIT;
@@ -189,12 +189,12 @@
                         if (!lflag)
                         {
-                            rc = diffmsg(file1, file2, byte, line, sflag);
+                            rc = diffmsg(pCtx, file1, file2, byte, line, sflag);
                             break;
                         }
                         rc = DIFF_EXIT;
 #ifdef _MSC_VER
-                        printf("%6i64d %3o %3o\n", (__int64)byte, ch1, ch2);
-#else
-                        printf("%6lld %3o %3o\n", (long long)byte, ch1, ch2);
+                        kmk_builtin_ctx_printf(pCtx, 0, "%6i64d %3o %3o\n", (__int64)byte, ch1, ch2);
+#else
+                        kmk_builtin_ctx_printf(pCtx, 0, "%6lld %3o %3o\n", (long long)byte, ch1, ch2);
 #endif
                     }
@@ -206,7 +206,7 @@
             /* Check for errors and length differences (EOF). */
             if (ferror(fp1) && rc != ERR_EXIT)
-                rc = errmsg(file1, byte, line, lflag);
+                rc = errmsg(pCtx, file1, byte, line, lflag);
             if (ferror(fp2) && rc != ERR_EXIT)
-                rc = errmsg(file2, byte, line, lflag);
+                rc = errmsg(pCtx, file2, byte, line, lflag);
             if (rc == OK_EXIT)
             {
@@ -214,8 +214,8 @@
                 {
                     if (!feof(fp2))
-                        rc = eofmsg(file1, byte, line, sflag, lflag);
+                        rc = eofmsg(pCtx, file1, byte, line, sflag, lflag);
                 }
                 else if (feof(fp2))
-                    rc = eofmsg(file2, byte, line, sflag, lflag);
+                    rc = eofmsg(pCtx, file2, byte, line, sflag, lflag);
             }
 
@@ -224,10 +224,10 @@
         else
         {
-            rc = err(ERR_EXIT, "%s", file2);
+            rc = err(pCtx, ERR_EXIT, "%s", file2);
             close(fd2dup);
         }
     }
     else
-        rc = err(ERR_EXIT, "%s", file2);
+        rc = err(pCtx, ERR_EXIT, "%s", file2);
 
     fclose(fp1);
@@ -241,5 +241,5 @@
  */
 static int
-c_regular(int fd1, const char *file1, off_t skip1, off_t len1,
+c_regular(PKMKBUILTINCTX pCtx, int fd1, const char *file1, off_t skip1, off_t len1,
           int fd2, const char *file2, off_t skip2, off_t len2, int sflag, int lflag)
 {
@@ -253,8 +253,8 @@
 
     if (skip1 > len1)
-        return eofmsg(file1, len1 + 1, 0, sflag, lflag);
+        return eofmsg(pCtx, file1, len1 + 1, 0, sflag, lflag);
     len1 -= skip1;
     if (skip2 > len2)
-        return eofmsg(file2, len2 + 1, 0, sflag, lflag);
+        return eofmsg(pCtx, file2, len2 + 1, 0, sflag, lflag);
     len2 -= skip2;
 
@@ -290,7 +290,7 @@
                 dfound = 1;
 #ifdef _MSC_VER
-                printf("%6I64d %3o %3o\n", (__int64)byte, ch, *p2);
-#else
-                printf("%6lld %3o %3o\n", (long long)byte, ch, *p2);
+                kmk_builtin_ctx_printf(pCtx, 0, "%6I64d %3o %3o\n", (__int64)byte, ch, *p2);
+#else
+                kmk_builtin_ctx_printf(pCtx, 0, "%6lld %3o %3o\n", (long long)byte, ch, *p2);
 #endif
             }
@@ -305,5 +305,5 @@
 
     if (len1 != len2)
-        return eofmsg(len1 > len2 ? file2 : file1, byte, line, sflag, lflag);
+        return eofmsg(pCtx, len1 > len2 ? file2 : file1, byte, line, sflag, lflag);
     if (dfound)
         return DIFF_EXIT;
@@ -311,5 +311,5 @@
 
 l_mmap_failed:
-    return c_special(fd1, file1, skip1, fd2, file2, skip2, lflag, sflag);
+    return c_special(pCtx, fd1, file1, skip1, fd2, file2, skip2, lflag, sflag);
 }
 
@@ -320,5 +320,5 @@
  */
 static int
-c_regular(int fd1, const char *file1, off_t skip1, off_t len1,
+c_regular(PKMKBUILTINCTX pCtx, int fd1, const char *file1, off_t skip1, off_t len1,
           int fd2, const char *file2, off_t skip2, off_t len2, int sflag, int lflag)
 {
@@ -332,8 +332,8 @@
 
     if (skip1 > len1)
-        return eofmsg(file1, len1 + 1, 0, sflag, lflag);
+        return eofmsg(pCtx, file1, len1 + 1, 0, sflag, lflag);
     len1 -= skip1;
     if (skip2 > len2)
-        return eofmsg(file2, len2 + 1, 0, sflag, lflag);
+        return eofmsg(pCtx, file2, len2 + 1, 0, sflag, lflag);
     len2 -= skip2;
 
@@ -343,5 +343,5 @@
     {
         if (skip1 && lseek(fd1, 0, SEEK_SET) < 0)
-            return err(1, "seek failed");
+            return err(pCtx, 1, "seek failed");
         goto l_special;
     }
@@ -383,11 +383,11 @@
                     free(b1);
                     free(b2);
-                    return diffmsg(file1, file2, byte, line, sflag);
+                    return diffmsg(pCtx, file1, file2, byte, line, sflag);
                 }
                 dfound = 1;
 #ifdef _MSC_VER
-                printf("%6I64d %3o %3o\n", (__int64)byte, ch, *p2);
-#else
-                printf("%6lld %3o %3o\n", (long long)byte, ch, *p2);
+                kmk_builtin_ctx_printf(pCtx, 0, "%6I64d %3o %3o\n", (__int64)byte, ch, *p2);
+#else
+                kmk_builtin_ctx_printf(pCtx, 0, "%6lld %3o %3o\n", (long long)byte, ch, *p2);
 #endif
             }
@@ -400,5 +400,5 @@
 
     if (len1 != len2)
-        return eofmsg(len1 > len2 ? file2 : file1, byte, line, sflag, lflag);
+        return eofmsg(pCtx, len1 > len2 ? file2 : file1, byte, line, sflag, lflag);
     if (dfound)
         return DIFF_EXIT;
@@ -409,5 +409,5 @@
         ||  lseek(fd2, 0, SEEK_SET) < 0)
     {
-        err(1, "seek failed");
+        err(pCtx, 1, "seek failed");
         free(b1);
         free(b2);
@@ -418,5 +418,5 @@
     free(b2);
 l_special:
-    return c_special(fd1, file1, skip1, fd2, file2, skip2, lflag, sflag);
+    return c_special(pCtx, fd1, file1, skip1, fd2, file2, skip2, lflag, sflag);
 }
 #endif  /* non-mmap c_regular */
@@ -427,5 +427,5 @@
  */
 int
-cmp_fd_and_fd_ex(int fd1, const char *file1, off_t skip1,
+cmp_fd_and_fd_ex(PKMKBUILTINCTX pCtx, int fd1, const char *file1, off_t skip1,
                  int fd2, const char *file2, off_t skip2,
                  int sflag, int lflag, int special)
@@ -435,15 +435,15 @@
 
     if (fstat(fd1, &st1))
-        return err(ERR_EXIT, "%s", file1);
+        return err(pCtx, ERR_EXIT, "%s", file1);
     if (fstat(fd2, &st2))
-        return err(ERR_EXIT, "%s", file2);
+        return err(pCtx, ERR_EXIT, "%s", file2);
 
     if (    !S_ISREG(st1.st_mode)
         ||  !S_ISREG(st2.st_mode)
         ||  special)
-        rc = c_special(fd1, file1, skip1,
+        rc = c_special(pCtx, fd1, file1, skip1,
                        fd2, file2, skip2, sflag, lflag);
     else
-        rc = c_regular(fd1, file1, skip1, st1.st_size,
+        rc = c_regular(pCtx, fd1, file1, skip1, st1.st_size,
                        fd2, file2, skip2, st2.st_size, sflag, lflag);
     return rc;
@@ -455,9 +455,9 @@
  */
 int
-cmp_fd_and_fd(int fd1, const char *file1,
+cmp_fd_and_fd(PKMKBUILTINCTX pCtx, int fd1, const char *file1,
               int fd2, const char *file2,
               int sflag, int lflag, int special)
 {
-    return cmp_fd_and_fd_ex(fd1, file1, 0, fd2, file2, 0, sflag, lflag, special);
+    return cmp_fd_and_fd_ex(pCtx, fd1, file1, 0, fd2, file2, 0, sflag, lflag, special);
 }
 
@@ -467,5 +467,5 @@
  */
 int
-cmp_fd_and_file_ex(int fd1, const char *file1, off_t skip1,
+cmp_fd_and_file_ex(PKMKBUILTINCTX pCtx, int fd1, const char *file1, off_t skip1,
                    const char *file2, off_t skip2,
                    int sflag, int lflag, int special)
@@ -484,5 +484,5 @@
     if (fd2 >= 0)
     {
-        rc = cmp_fd_and_fd_ex(fd1, file1, skip1,
+        rc = cmp_fd_and_fd_ex(pCtx, fd1, file1, skip1,
                               fd2, file2, skip2, sflag, lflag, special);
         close(fd2);
@@ -491,5 +491,5 @@
     {
         if (!sflag)
-            warn("%s", file2);
+            warn(pCtx, "%s", file2);
         rc = ERR_EXIT;
     }
@@ -502,9 +502,9 @@
  */
 int
-cmp_fd_and_file(int fd1, const char *file1,
+cmp_fd_and_file(PKMKBUILTINCTX pCtx, int fd1, const char *file1,
                 const char *file2,
                 int sflag, int lflag, int special)
 {
-    return cmp_fd_and_file_ex(fd1, file1, 0,
+    return cmp_fd_and_file_ex(pCtx, fd1, file1, 0,
                                    file2, 0, sflag, lflag, special);
 }
@@ -515,5 +515,5 @@
  */
 int
-cmp_file_and_file_ex(const char *file1, off_t skip1,
+cmp_file_and_file_ex(PKMKBUILTINCTX pCtx, const char *file1, off_t skip1,
                      const char *file2, off_t skip2,
                      int sflag, int lflag, int special)
@@ -523,10 +523,10 @@
 
     if (lflag && sflag)
-        return errx(ERR_EXIT, "only one of -l and -s may be specified");
+        return errx(pCtx, ERR_EXIT, "only one of -l and -s may be specified");
 
     if (!strcmp(file1, "-"))
     {
         if (!strcmp(file2, "-"))
-            return errx(ERR_EXIT, "standard input may only be specified once");
+            return errx(pCtx, ERR_EXIT, "standard input may only be specified once");
         file1 = "stdin";
         fd1 = 1;
@@ -537,5 +537,5 @@
     if (fd1 >= 0)
     {
-        rc = cmp_fd_and_file_ex(fd1, file1, skip1,
+        rc = cmp_fd_and_file_ex(pCtx, fd1, file1, skip1,
                                      file2, skip2, sflag, lflag, special);
         close(fd1);
@@ -544,5 +544,5 @@
     {
         if (!sflag)
-            warn("%s", file1);
+            warn(pCtx, "%s", file1);
         rc = ERR_EXIT;
     }
@@ -556,7 +556,7 @@
  */
 int
-cmp_file_and_file(const char *file1, const char *file2, int sflag, int lflag, int special)
-{
-    return cmp_file_and_file_ex(file1, 0, file2, 0, sflag, lflag, special);
-}
-
+cmp_file_and_file(PKMKBUILTINCTX pCtx, const char *file1, const char *file2, int sflag, int lflag, int special)
+{
+    return cmp_file_and_file_ex(pCtx, file1, 0, file2, 0, sflag, lflag, special);
+}
+
Index: trunk/src/kmk/kmkbuiltin/common-env-and-cwd-opt.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/common-env-and-cwd-opt.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/common-env-and-cwd-opt.c	(revision 3192)
@@ -50,4 +50,5 @@
  *
  * @returns The duplicate enviornment.
+ * @param   pCtx                The built-in command context.
  * @param   papszEnv            The read-only vector.
  * @param   cEnvVars            The number of variables.
@@ -56,5 +57,6 @@
  * @param   cVerbosity          The verbosity level.
  */
-static char **kBuiltinOptEnvDuplicate(char **papszEnv, unsigned cEnvVars, unsigned *pcAllocatedEnvVars, int cVerbosity)
+static char **kBuiltinOptEnvDuplicate(PKMKBUILTINCTX pCtx, char **papszEnv, unsigned cEnvVars, unsigned *pcAllocatedEnvVars,
+                                      int cVerbosity)
 {
     unsigned cAllocatedEnvVars = (cEnvVars + 2 + 0xf) & ~(unsigned)0xf;
@@ -72,5 +74,5 @@
                     free(papszEnvNew[i]);
                 free(papszEnvNew);
-                errx(1, "out of memory for duplicating environment variables!", i);
+                errx(pCtx, 1, "out of memory for duplicating environment variables!", i);
                 return NULL;
             }
@@ -80,5 +82,5 @@
     }
     else
-        errx(1, "out of memory for duplicating environment vector!");
+        errx(pCtx, 1, "out of memory for duplicating environment vector!");
     return papszEnvNew;
 }
@@ -90,4 +92,5 @@
  *
  * @returns 0 on success, non-zero exit code on error.
+ * @param   pCtx                The built-in command context.
  * @param   papszEnv            The environment vector.
  * @param   pcEnvVars           Pointer to the variable holding the number of
@@ -98,5 +101,5 @@
  * @param   pszValue            The var=value string to apply.
  */
-static int kBuiltinOptEnvAddVar(char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars,
+static int kBuiltinOptEnvAddVar(PKMKBUILTINCTX pCtx, char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars,
                                 int cVerbosity, const char *pszValue)
 {
@@ -109,14 +112,14 @@
         papszEnv = (char **)realloc(papszEnv, *pcAllocatedEnvVars * sizeof(papszEnv[0]));
         if (!papszEnv)
-            return errx(1, "out of memory growing environment vector!");
+            return errx(pCtx, 1, "out of memory growing environment vector!");
         *ppapszEnv = papszEnv;
     }
     papszEnv[cEnvVars] = strdup(pszValue);
     if (!papszEnv[cEnvVars])
-        return errx(1, "out of memory adding environment variable!");
+        return errx(pCtx, 1, "out of memory adding environment variable!");
     papszEnv[++cEnvVars]   = NULL;
     *pcEnvVars = cEnvVars;
     if (cVerbosity > 0)
-        warnx("added '%s'", papszEnv[cEnvVars - 1]);
+        warnx(pCtx, "added '%s'", papszEnv[cEnvVars - 1]);
     return 0;
 }
@@ -128,4 +131,5 @@
  *
  * @returns 0 on success, non-zero exit code on error.
+ * @param   pCtx                The built-in command context.
  * @param   papszEnv            The environment vector.
  * @param   cEnvVars            Number of environment variables.
@@ -135,5 +139,5 @@
  * @param   iEnvVar             Where to start searching after.
  */
-static int kBuiltinOptEnvRemoveDuplicates(char **papszEnv, unsigned cEnvVars, int cVerbosity,
+static int kBuiltinOptEnvRemoveDuplicates(PKMKBUILTINCTX pCtx, char **papszEnv, unsigned cEnvVars, int cVerbosity,
                                           const char *pszValue, size_t cchVar, unsigned iEnvVar)
 {
@@ -143,5 +147,5 @@
         {
             if (cVerbosity > 0)
-                warnx("removing duplicate '%s'", papszEnv[iEnvVar]);
+                warnx(pCtx, "removing duplicate '%s'", papszEnv[iEnvVar]);
             free(papszEnv[iEnvVar]);
             cEnvVars--;
@@ -159,4 +163,5 @@
  *
  * @returns 0 on success, non-zero exit code on error.
+ * @param   pCtx                The built-in command context.
  * @param   ppapszEnv           The environment vector pointer.
  * @param   pcEnvVars           Pointer to the variable holding the number of
@@ -167,5 +172,6 @@
  * @param   pszValue            The var=value string to apply.
  */
-int kBuiltinOptEnvSet(char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars, int cVerbosity, const char *pszValue)
+int kBuiltinOptEnvSet(PKMKBUILTINCTX pCtx, char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars,
+                      int cVerbosity, const char *pszValue)
 {
     const char *pszEqual = strchr(pszValue, '=');
@@ -179,7 +185,7 @@
         if (!*pcAllocatedEnvVars)
         {
-            papszEnv = kBuiltinOptEnvDuplicate(papszEnv, cEnvVars, pcAllocatedEnvVars, cVerbosity);
+            papszEnv = kBuiltinOptEnvDuplicate(pCtx, papszEnv, cEnvVars, pcAllocatedEnvVars, cVerbosity);
             if (!papszEnv)
-                return errx(1, "out of memory duplicating enviornment (setenv)!");
+                return errx(pCtx, 1, "out of memory duplicating enviornment (setenv)!");
             *ppapszEnv = papszEnv;
         }
@@ -192,16 +198,16 @@
             {
                 if (cVerbosity > 0)
-                    warnx("replacing '%s' with '%s'", papszEnv[iEnvVar], pszValue);
+                    warnx(pCtx, "replacing '%s' with '%s'", papszEnv[iEnvVar], pszValue);
                 free(papszEnv[iEnvVar]);
                 papszEnv[iEnvVar] = strdup(pszValue);
                 if (!papszEnv[iEnvVar])
-                    return errx(1, "out of memory for modified environment variable!");
-
-                return kBuiltinOptEnvRemoveDuplicates(papszEnv, cEnvVars, cVerbosity, pszValue, cchVar, iEnvVar);
+                    return errx(pCtx, 1, "out of memory for modified environment variable!");
+
+                return kBuiltinOptEnvRemoveDuplicates(pCtx, papszEnv, cEnvVars, cVerbosity, pszValue, cchVar, iEnvVar);
             }
         }
-        return kBuiltinOptEnvAddVar(ppapszEnv, pcEnvVars, pcAllocatedEnvVars, cVerbosity, pszValue);
-    }
-    return errx(1, "Missing '=': -E %s", pszValue);
+        return kBuiltinOptEnvAddVar(pCtx, ppapszEnv, pcEnvVars, pcAllocatedEnvVars, cVerbosity, pszValue);
+    }
+    return errx(pCtx, 1, "Missing '=': -E %s", pszValue);
 }
 
@@ -211,4 +217,5 @@
  *
  * @returns 0 on success, non-zero exit code on error.
+ * @param   pCtx                The built-in command context.
  * @param   ppapszEnv           The environment vector pointer.
  * @param   pcEnvVars           Pointer to the variable holding the number of
@@ -219,5 +226,5 @@
  * @param   pszValue            The var=value string to apply.
  */
-static int kBuiltinOptEnvAppendPrepend(char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars,
+static int kBuiltinOptEnvAppendPrepend(PKMKBUILTINCTX pCtx, char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars,
                                        int cVerbosity, const char *pszValue, int fAppend)
 {
@@ -232,7 +239,7 @@
         if (!*pcAllocatedEnvVars)
         {
-            papszEnv = kBuiltinOptEnvDuplicate(papszEnv, cEnvVars, pcAllocatedEnvVars, cVerbosity);
+            papszEnv = kBuiltinOptEnvDuplicate(pCtx, papszEnv, cEnvVars, pcAllocatedEnvVars, cVerbosity);
             if (!papszEnv)
-                return errx(1, "out of memory duplicating environment (append)!");
+                return errx(pCtx, 1, "out of memory duplicating environment (append)!");
             *ppapszEnv = papszEnv;
         }
@@ -248,5 +255,5 @@
                 char  *pszNew      = malloc(cchVar + 1 + cchOldValue + cchNewValue + 1);
                 if (!pszNew)
-                    return errx(1, "out of memory appending to environment variable!");
+                    return errx(pCtx, 1, "out of memory appending to environment variable!");
                 if (fAppend)
                 {
@@ -262,14 +269,14 @@
 
                 if (cVerbosity > 0)
-                    warnx("replacing '%s' with '%s'", pszCur, pszNew);
+                    warnx(pCtx, "replacing '%s' with '%s'", pszCur, pszNew);
                 free(pszCur);
                 papszEnv[iEnvVar] = pszNew;
 
-                return kBuiltinOptEnvRemoveDuplicates(papszEnv, cEnvVars, cVerbosity, pszValue, cchVar, iEnvVar);
+                return kBuiltinOptEnvRemoveDuplicates(pCtx, papszEnv, cEnvVars, cVerbosity, pszValue, cchVar, iEnvVar);
             }
         }
-        return kBuiltinOptEnvAddVar(ppapszEnv, pcEnvVars, pcAllocatedEnvVars, cVerbosity, pszValue);
-    }
-    return errx(1, "Missing '=': -E %s", pszValue);
+        return kBuiltinOptEnvAddVar(pCtx, ppapszEnv, pcEnvVars, pcAllocatedEnvVars, cVerbosity, pszValue);
+    }
+    return errx(pCtx, 1, "Missing '=': -E %s", pszValue);
 }
 
@@ -279,4 +286,5 @@
  *
  * @returns 0 on success, non-zero exit code on error.
+ * @param   pCtx                The built-in command context.
  * @param   ppapszEnv           The environment vector pointer.
  * @param   pcEnvVars           Pointer to the variable holding the number of
@@ -287,7 +295,8 @@
  * @param   pszValue            The var=value string to apply.
  */
-int kBuiltinOptEnvAppend(char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars, int cVerbosity, const char *pszValue)
-{
-    return kBuiltinOptEnvAppendPrepend(ppapszEnv, pcEnvVars, pcAllocatedEnvVars, cVerbosity, pszValue, 1 /*fAppend*/);
+int kBuiltinOptEnvAppend(PKMKBUILTINCTX pCtx, char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars,
+                         int cVerbosity, const char *pszValue)
+{
+    return kBuiltinOptEnvAppendPrepend(pCtx, ppapszEnv, pcEnvVars, pcAllocatedEnvVars, cVerbosity, pszValue, 1 /*fAppend*/);
 }
 
@@ -297,4 +306,5 @@
  *
  * @returns 0 on success, non-zero exit code on error.
+ * @param   pCtx                The built-in command context.
  * @param   ppapszEnv           The environment vector pointer.
  * @param   pcEnvVars           Pointer to the variable holding the number of
@@ -305,7 +315,8 @@
  * @param   pszValue            The var=value string to apply.
  */
-int kBuiltinOptEnvPrepend(char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars, int cVerbosity, const char *pszValue)
-{
-    return kBuiltinOptEnvAppendPrepend(ppapszEnv, pcEnvVars, pcAllocatedEnvVars, cVerbosity, pszValue, 0 /*fAppend*/);
+int kBuiltinOptEnvPrepend(PKMKBUILTINCTX pCtx, char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars,
+                          int cVerbosity, const char *pszValue)
+{
+    return kBuiltinOptEnvAppendPrepend(pCtx, ppapszEnv, pcEnvVars, pcAllocatedEnvVars, cVerbosity, pszValue, 0 /*fAppend*/);
 }
 
@@ -315,4 +326,5 @@
  *
  * @returns 0 on success, non-zero exit code on error.
+ * @param   pCtx                The built-in command context.
  * @param   ppapszEnv           The environment vector pointer.
  * @param   pcEnvVars           Pointer to the variable holding the number of
@@ -324,5 +336,6 @@
  * @param   pszVarToRemove      The name of the variable to remove.
  */
-int kBuiltinOptEnvUnset(char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars, int cVerbosity, const char *pszVarToRemove)
+int kBuiltinOptEnvUnset(PKMKBUILTINCTX pCtx, char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars,
+                        int cVerbosity, const char *pszVarToRemove)
 {
     if (strchr(pszVarToRemove, '=') == NULL)
@@ -339,11 +352,11 @@
             {
                 if (cVerbosity > 0)
-                    warnx(!cRemoved ? "removing '%s'" : "removing duplicate '%s'", papszEnv[iEnvVar]);
+                    warnx(pCtx, !cRemoved ? "removing '%s'" : "removing duplicate '%s'", papszEnv[iEnvVar]);
 
                 if (!*pcAllocatedEnvVars)
                 {
-                    papszEnv = kBuiltinOptEnvDuplicate(papszEnv, cEnvVars, pcAllocatedEnvVars, cVerbosity);
+                    papszEnv = kBuiltinOptEnvDuplicate(pCtx, papszEnv, cEnvVars, pcAllocatedEnvVars, cVerbosity);
                     if (!papszEnv)
-                        return errx(1, "out of memory duplicating environment (unset)!");
+                        return errx(pCtx, 1, "out of memory duplicating environment (unset)!");
                     *ppapszEnv = papszEnv;
                 }
@@ -360,8 +373,8 @@
 
         if (cVerbosity > 0 && !cRemoved)
-            warnx("not found '%s'", pszVarToRemove);
+            warnx(pCtx, "not found '%s'", pszVarToRemove);
     }
     else
-        return errx(1, "Found invalid variable name character '=' in: -U %s", pszVarToRemove);
+        return errx(pCtx, 1, "Found invalid variable name character '=' in: -U %s", pszVarToRemove);
     return 0;
 }
@@ -372,4 +385,5 @@
  *
  * @returns 0 on success, non-zero exit code on error.
+ * @param   pCtx                The built-in command context.
  * @param   ppapszEnv           The environment vector pointer.
  * @param   pcEnvVars           Pointer to the variable holding the number of
@@ -380,5 +394,5 @@
  * @param   cVerbosity          The verbosity level.
  */
-int kBuiltinOptEnvZap(char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars, int cVerbosity)
+int kBuiltinOptEnvZap(PKMKBUILTINCTX pCtx, char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars, int cVerbosity)
 {
     if (*pcAllocatedEnvVars > 0)
@@ -396,5 +410,5 @@
         char **papszEnv = calloc(4, sizeof(char *));
         if (!papszEnv)
-            return err(1, "out of memory!");
+            return err(pCtx, 1, "out of memory!");
         *ppapszEnv = papszEnv;
         *pcAllocatedEnvVars = 4;
@@ -435,4 +449,5 @@
  *
  * @returns 0 on success, non-zero exit code on error.
+ * @param   pCtx                The built-in command context.
  * @param   pszCwd              The CWD buffer.  Contains current CWD on input,
  *                              modified by @a pszValue on output.
@@ -440,5 +455,5 @@
  * @param   pszValue            The --chdir value to apply.
  */
-int kBuiltinOptChDir(char *pszCwd, size_t cbCwdBuf, const char *pszValue)
+int kBuiltinOptChDir(PKMKBUILTINCTX pCtx, char *pszCwd, size_t cbCwdBuf, const char *pszValue)
 {
     size_t cchNewCwd = strlen(pszValue);
@@ -454,5 +469,5 @@
                 offDst = 2; /* Take drive letter from CWD. */
             else
-                return errx(1, "UNC relative CWD not implemented: cur='%s' new='%s'", pszCwd, pszValue);
+                return errx(pCtx, 1, "UNC relative CWD not implemented: cur='%s' new='%s'", pszCwd, pszValue);
         }
         else if (   pszValue[1] == ':'
@@ -473,5 +488,5 @@
                 int iDrive = tolower(pszValue[0]) - 'a' + 1;
                 if (!_getdcwd(iDrive, pszCwd, cbCwdBuf))
-                    return err(1, "_getdcwd(%d,,) failed", iDrive);
+                    return err(pCtx, 1, "_getdcwd(%d,,) failed", iDrive);
                 pszValue += 2;
                 cchNewCwd -= 2;
@@ -493,5 +508,5 @@
              pszCwd[offDst++] = '/';
         if (offDst + cchNewCwd >= cbCwdBuf)
-            return errx(1, "Too long CWD: %*.*s%s", offDst, offDst, pszCwd, pszValue);
+            return errx(pCtx, 1, "Too long CWD: %*.*s%s", offDst, offDst, pszCwd, pszValue);
         memcpy(&pszCwd[offDst], pszValue, cchNewCwd + 1);
     }
Index: trunk/src/kmk/kmkbuiltin/cp.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/cp.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/cp.c	(revision 3192)
@@ -157,13 +157,13 @@
 
 
-static int copy(char *[], enum op, int);
+static int copy(PKMKBUILTINCTX pCtx, char *[], enum op, int);
 static int mastercmp(const FTSENT **, const FTSENT **);
 #ifdef SIGINFO
 static void siginfo(int __unused);
 #endif
-static int usage(FILE *);
+static int usage(PKMKBUILTINCTX, int);
 
 int
-kmk_builtin_cp(int argc, char *argv[], char **envp)
+kmk_builtin_cp(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx)
 {
 	struct stat to_stat, tmp_stat;
@@ -180,8 +180,7 @@
         info = 0;
 	cp_ignore_non_existing = cp_changed_only = 0;
-	kBuildProtectionInit(&g_ProtData);
+	kBuildProtectionInit(&g_ProtData, pCtx);
 
         /* reset getopt and set progname. */
-        g_progname = argv[0];
         opterr = 1;
         optarg = NULL;
@@ -229,5 +228,5 @@
 			break;
 		case CP_OPT_HELP:
-			usage(stdout);
+			usage(pCtx, 0);
 			kBuildProtectionTerm(&g_ProtData);
 			return 0;
@@ -261,5 +260,5 @@
 		default:
 			kBuildProtectionTerm(&g_ProtData);
-		        return usage(stderr);
+		        return usage(pCtx, 1);
 		}
 	argc -= optind;
@@ -268,5 +267,5 @@
 	if (argc < 2) {
 		kBuildProtectionTerm(&g_ProtData);
-		return usage(stderr);
+		return usage(pCtx, 1);
 	}
 
@@ -275,9 +274,9 @@
 		if (Rflag) {
 			kBuildProtectionTerm(&g_ProtData);
-			return errx(1,
+			return errx(pCtx, 1,
 		    "the -R and -r options may not be specified together.");
 		}
 		if (Hflag || Lflag || Pflag)
-			errx(1,
+			errx(pCtx, 1,
 	"the -H, -L, and -P options may not be specified with the -r option.");
 		fts_options &= ~FTS_PHYSICAL;
@@ -303,5 +302,5 @@
 	if (strlcpy(to.p_path, target, sizeof(to.p_path)) >= sizeof(to.p_path)) {
 		kBuildProtectionTerm(&g_ProtData);
-		return errx(1, "%s: name too long", target);
+		return errx(pCtx, 1, "%s: name too long", target);
 	}
 	to.p_end = to.p_path + strlen(to.p_path);
@@ -335,5 +334,5 @@
 	if (r == -1 && errno != ENOENT) {
 		kBuildProtectionTerm(&g_ProtData);
-		return err(1, "stat: %s", to.p_path);
+		return err(pCtx, 1, "stat: %s", to.p_path);
 	}
 	if (r == -1 || !S_ISDIR(to_stat.st_mode)) {
@@ -343,5 +342,5 @@
 		if (argc > 1) {
 			kBuildProtectionTerm(&g_ProtData);
-			return usage(stderr);
+			return usage(pCtx, 1);
 		}
 		/*
@@ -368,8 +367,8 @@
 			kBuildProtectionTerm(&g_ProtData);
 			if (r == -1)
-				return errx(1, "directory %s does not exist",
+				return errx(pCtx, 1, "directory %s does not exist",
 				            to.p_path);
 			else
-				return errx(1, "%s is not a directory", to.p_path);
+				return errx(pCtx, 1, "%s is not a directory", to.p_path);
 		}
 	} else
@@ -387,5 +386,5 @@
 				     : KBUILDPROTECTIONTYPE_FULL,
 				     to.p_path)) {
-	    rc = copy(argv, type, fts_options);
+	    rc = copy(pCtx, argv, type, fts_options);
 	}
 
@@ -394,6 +393,14 @@
 }
 
+#ifdef KMK_BUILTIN_STANDALONE
+int main(int argc, char **argv, char **envp)
+{
+    KMKBUILTINCTX Ctx = { "kmk_cp", NULL };
+    return kmk_builtin_cp(argc, argv, envp, &Ctx);
+}
+#endif
+
 static int
-copy(char *argv[], enum op type, int fts_options)
+copy(PKMKBUILTINCTX pCtx, char *argv[], enum op type, int fts_options)
 {
 	struct stat to_stat;
@@ -413,5 +420,5 @@
 
 	if ((ftsp = fts_open(argv, fts_options, mastercmp)) == NULL)
-		return err(1, "fts_open");
+		return err(pCtx, 1, "fts_open");
 	for (badcp = rval = 0; (curr = fts_read(ftsp)) != NULL; badcp = 0) {
                 int copied = 0;
@@ -422,5 +429,5 @@
 			    && curr->fts_errno == ENOENT) {
 				if (vflag) {
-					warnx("fts: %s: %s", curr->fts_path,
+					warnx(pCtx, "fts: %s: %s", curr->fts_path,
 					      strerror(curr->fts_errno));
 				}
@@ -430,10 +437,10 @@
 		case FTS_DNR:
 		case FTS_ERR:
-			warnx("fts: %s: %s",
+			warnx(pCtx, "fts: %s: %s",
 			    curr->fts_path, strerror(curr->fts_errno));
 			badcp = rval = 1;
 			continue;
 		case FTS_DC:			/* Warn, continue. */
-			warnx("%s: directory causes a cycle", curr->fts_path);
+			warnx(pCtx, "%s: directory causes a cycle", curr->fts_path);
 			badcp = rval = 1;
 			continue;
@@ -490,5 +497,5 @@
 			*target_mid = 0;
 			if (target_mid - to.p_path + nlen >= PATH_MAX) {
-				warnx("%s%s: name too long (not copied)",
+				warnx(pCtx, "%s%s: name too long (not copied)",
 				    to.p_path, p);
 				badcp = rval = 1;
@@ -519,5 +526,5 @@
 			 */
 			if (pflag) {
-				if (setfile(curr->fts_statp, -1))
+				if (setfile(pCtx, curr->fts_statp, -1))
 				    rval = 1;
 			} else {
@@ -526,5 +533,5 @@
 				    ((mode | S_IRWXU) & mask) != (mode & mask))
 					if (chmod(to.p_path, mode & mask) != 0){
-						warn("chmod: %s", to.p_path);
+						warn(pCtx, "chmod: %s", to.p_path);
 						rval = 1;
 					}
@@ -541,5 +548,5 @@
 			    to_stat.st_ino == curr->fts_statp->st_ino &&
 			    to_stat.st_ino != 0) {
-				warnx("%s and %s are identical (not copied).",
+				warnx(pCtx, "%s and %s are identical (not copied).",
 				    to.p_path, curr->fts_path);
 				badcp = rval = 1;
@@ -550,5 +557,5 @@
 			if (!S_ISDIR(curr->fts_statp->st_mode) &&
 			    S_ISDIR(to_stat.st_mode)) {
-				warnx("cannot overwrite directory %s with "
+				warnx(pCtx, "cannot overwrite directory %s with "
 				    "non-directory %s",
 				    to.p_path, curr->fts_path);
@@ -566,8 +573,8 @@
 			    ((fts_options & FTS_COMFOLLOW) &&
 			    curr->fts_level == 0)) {
-				if (copy_file(curr, dne, cp_changed_only, &copied))
+				if (copy_file(pCtx, curr, dne, cp_changed_only, &copied))
 					badcp = rval = 1;
 			} else {
-				if (copy_link(curr, !dne))
+				if (copy_link(pCtx, curr, !dne))
 					badcp = rval = 1;
 			}
@@ -576,5 +583,5 @@
 		case S_IFDIR:
 			if (!Rflag && !rflag) {
-				warnx("%s is a directory (not copied).",
+				warnx(pCtx, "%s is a directory (not copied).",
 				    curr->fts_path);
 				(void)fts_set(ftsp, curr, FTS_SKIP);
@@ -593,8 +600,8 @@
 				if (mkdir(to.p_path,
 				    curr->fts_statp->st_mode | S_IRWXU) < 0)
-					return err(1, "mkdir: %s", to.p_path);
+					return err(pCtx, 1, "mkdir: %s", to.p_path);
 			} else if (!S_ISDIR(to_stat.st_mode)) {
 				errno = ENOTDIR;
-				return err(1, "to-mode: %s", to.p_path);
+				return err(pCtx, 1, "to-mode: %s", to.p_path);
 			}
 			/*
@@ -610,8 +617,8 @@
 		case S_IFCHR:
 			if (Rflag) {
-				if (copy_special(curr->fts_statp, !dne))
+				if (copy_special(pCtx, curr->fts_statp, !dne))
 					badcp = rval = 1;
 			} else {
-				if (copy_file(curr, dne, cp_changed_only, &copied))
+				if (copy_file(pCtx, curr, dne, cp_changed_only, &copied))
 					badcp = rval = 1;
 			}
@@ -621,22 +628,22 @@
 #endif
 			if (Rflag) {
-				if (copy_fifo(curr->fts_statp, !dne))
+				if (copy_fifo(pCtx, curr->fts_statp, !dne))
 					badcp = rval = 1;
 			} else {
-				if (copy_file(curr, dne, cp_changed_only, &copied))
+				if (copy_file(pCtx, curr, dne, cp_changed_only, &copied))
 					badcp = rval = 1;
 			}
 			break;
 		default:
-			if (copy_file(curr, dne, cp_changed_only, &copied))
+			if (copy_file(pCtx, curr, dne, cp_changed_only, &copied))
 				badcp = rval = 1;
 			break;
 		}
 		if (vflag && !badcp)
-			(void)printf(copied ? "%s -> %s\n" : "%s matches %s - not copied\n",
-				     curr->fts_path, to.p_path);
+			kmk_builtin_ctx_printf(pCtx, 0, copied ? "%s -> %s\n" : "%s matches %s - not copied\n",
+					       curr->fts_path, to.p_path);
 	}
 	if (errno)
-		return err(1, "fts_read");
+		return err(pCtx, 1, "fts_read");
 	return (rval);
 }
@@ -679,7 +686,7 @@
 
 static int
-usage(FILE *fp)
+usage(PKMKBUILTINCTX pCtx, int fIsErr)
 {
-	fprintf(fp,
+	kmk_builtin_ctx_printf(pCtx, fIsErr,
 "usage: %s [options] src target\n"
 "   or: %s [options] src1 ... srcN directory\n"
@@ -728,5 +735,6 @@
 "yourself in the foot.\n"
 		,
-	        g_progname, g_progname, g_progname, g_progname,
+	        pCtx->pszProgName, pCtx->pszProgName,
+		pCtx->pszProgName, pCtx->pszProgName,
 	        kBuildProtectionDefaultDepth(), kBuildProtectionDefaultDepth());
 	return 1;
Index: trunk/src/kmk/kmkbuiltin/cp_extern.h
===================================================================
--- trunk/src/kmk/kmkbuiltin/cp_extern.h	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/cp_extern.h	(revision 3192)
@@ -55,7 +55,7 @@
 extern volatile sig_atomic_t info;
 
-int	copy_fifo(struct stat *, int);
-int	copy_file(const FTSENT *, int, int, int *);
-int	copy_link(const FTSENT *, int);
-int	copy_special(struct stat *, int);
-int	setfile(struct stat *, int);
+int	copy_fifo(PKMKBUILTINCTX pCtx, struct stat *, int);
+int	copy_file(PKMKBUILTINCTX pCtx, const FTSENT *, int, int, int *);
+int	copy_link(PKMKBUILTINCTX pCtx, const FTSENT *, int);
+int	copy_special(PKMKBUILTINCTX pCtx, struct stat *, int);
+int	setfile(PKMKBUILTINCTX pCtx, struct stat *, int);
Index: trunk/src/kmk/kmkbuiltin/cp_utils.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/cp_utils.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/cp_utils.c	(revision 3192)
@@ -87,5 +87,5 @@
 
 int
-copy_file(const FTSENT *entp, int dne, int changed_only, int *pcopied)
+copy_file(PKMKBUILTINCTX pCtx, const FTSENT *entp, int dne, int changed_only, int *pcopied)
 {
 	static char buf[MAXBSIZE];
@@ -103,5 +103,5 @@
 
 	if ((from_fd = open(entp->fts_path, O_RDONLY | O_BINARY, 0)) == -1) {
-		warn("open: %s", entp->fts_path);
+		warn(pCtx, "open: %s", entp->fts_path);
 		return (1);
 	}
@@ -120,5 +120,5 @@
 		/* compare the files first if requested */
 		if (changed_only) {
-                        if (cmp_fd_and_file(from_fd, entp->fts_path, to.p_path,
+                        if (cmp_fd_and_file(pCtx, from_fd, entp->fts_path, to.p_path,
 					    1 /* silent */, 0 /* lflag */,
 					    0 /* special */) == OK_EXIT) {
@@ -129,5 +129,5 @@
     				close(from_fd);
 				if ((from_fd = open(entp->fts_path, O_RDONLY | O_BINARY, 0)) == -1) {
-					warn("open: %s", entp->fts_path);
+					warn(pCtx, "open: %s", entp->fts_path);
 					return (1);
 				}
@@ -138,5 +138,5 @@
 		if (nflag) {
 			if (vflag)
-				printf("%s not overwritten\n", to.p_path);
+				kmk_builtin_ctx_printf(pCtx, 0, "%s not overwritten\n", to.p_path);
 			return (0);
 		} else if (iflag) {
@@ -148,5 +148,5 @@
 			if (checkch != 'y' && checkch != 'Y') {
 				(void)close(from_fd);
-				(void)fprintf(stderr, "not overwritten\n");
+				kmk_builtin_ctx_printf(pCtx, 1, "not overwritten\n");
 				return (1);
 			}
@@ -167,5 +167,5 @@
 
 	if (to_fd == -1) {
-		warn("open: %s", to.p_path);
+		warn(pCtx, "open: %s", to.p_path);
 		(void)close(from_fd);
 		return (1);
@@ -185,5 +185,5 @@
 		if ((p = mmap(NULL, (size_t)fs->st_size, PROT_READ,
 		    MAP_SHARED, from_fd, (off_t)0)) == MAP_FAILED) {
-			warn("mmap: %s", entp->fts_path);
+			warn(pCtx, "mmap: %s", entp->fts_path);
 			rval = 1;
 		} else {
@@ -195,5 +195,5 @@
 				if (info) {
 					info = 0;
-					(void)fprintf(stderr,
+					kmk_builtin_ctx_printf(pCtx, 1,
 						"%s -> %s %3d%%\n",
 						entp->fts_path, to.p_path,
@@ -205,10 +205,10 @@
 			}
 			if (wcount != (ssize_t)wresid) {
-				warn("write[%zd != %zu]: %s", wcount, wresid, to.p_path);
+				warn(pCtx, "write[%zd != %zu]: %s", wcount, wresid, to.p_path);
 				rval = 1;
 			}
 			/* Some systems don't unmap on close(2). */
 			if (munmap(p, fs->st_size) < 0) {
-				warn("munmap: %s", entp->fts_path);
+				warn(pCtx, "munmap: %s", entp->fts_path);
 				rval = 1;
 			}
@@ -225,5 +225,5 @@
 				if (info) {
 					info = 0;
-					(void)fprintf(stderr,
+					kmk_builtin_ctx_printf(pCtx, 1,
 						"%s -> %s %3d%%\n",
 						entp->fts_path, to.p_path,
@@ -235,5 +235,5 @@
 			}
 			if (wcount != (ssize_t)wresid) {
-				warn("write[%zd != %zu]: %s", wcount, wresid, to.p_path);
+				warn(pCtx, "write[%zd != %zu]: %s", wcount, wresid, to.p_path);
 				rval = 1;
 				break;
@@ -241,5 +241,5 @@
 		}
 		if (rcount < 0) {
-			warn("read: %s", entp->fts_path);
+			warn(pCtx, "read: %s", entp->fts_path);
 			rval = 1;
 		}
@@ -253,9 +253,9 @@
 	 */
 
-	if (pflag && setfile(fs, to_fd))
+	if (pflag && setfile(pCtx, fs, to_fd))
 		rval = 1;
 	(void)close(from_fd);
 	if (close(to_fd)) {
-		warn("close: %s", to.p_path);
+		warn(pCtx, "close: %s", to.p_path);
 		rval = 1;
 	}
@@ -264,5 +264,5 @@
 
 int
-copy_link(const FTSENT *p, int exists)
+copy_link(PKMKBUILTINCTX pCtx, const FTSENT *p, int exists)
 {
 	int len;
@@ -270,49 +270,49 @@
 
 	if ((len = readlink(p->fts_path, llink, sizeof(llink) - 1)) == -1) {
-		warn("readlink: %s", p->fts_path);
+		warn(pCtx, "readlink: %s", p->fts_path);
 		return (1);
 	}
 	llink[len] = '\0';
 	if (exists && unlink(to.p_path)) {
-		warn("unlink: %s", to.p_path);
+		warn(pCtx, "unlink: %s", to.p_path);
 		return (1);
 	}
 	if (symlink(llink, to.p_path)) {
-		warn("symlink: %s", llink);
-		return (1);
-	}
-	return (pflag ? setfile(p->fts_statp, -1) : 0);
-}
-
-int
-copy_fifo(struct stat *from_stat, int exists)
+		warn(pCtx, "symlink: %s", llink);
+		return (1);
+	}
+	return (pflag ? setfile(pCtx, p->fts_statp, -1) : 0);
+}
+
+int
+copy_fifo(PKMKBUILTINCTX pCtx, struct stat *from_stat, int exists)
 {
 	if (exists && unlink(to.p_path)) {
-		warn("unlink: %s", to.p_path);
+		warn(pCtx, "unlink: %s", to.p_path);
 		return (1);
 	}
 	if (mkfifo(to.p_path, from_stat->st_mode)) {
-		warn("mkfifo: %s", to.p_path);
-		return (1);
-	}
-	return (pflag ? setfile(from_stat, -1) : 0);
-}
-
-int
-copy_special(struct stat *from_stat, int exists)
+		warn(pCtx, "mkfifo: %s", to.p_path);
+		return (1);
+	}
+	return (pflag ? setfile(pCtx, from_stat, -1) : 0);
+}
+
+int
+copy_special(PKMKBUILTINCTX pCtx, struct stat *from_stat, int exists)
 {
 	if (exists && unlink(to.p_path)) {
-		warn("unlink: %s", to.p_path);
+		warn(pCtx, "unlink: %s", to.p_path);
 		return (1);
 	}
 	if (mknod(to.p_path, from_stat->st_mode, from_stat->st_rdev)) {
-		warn("mknod: %s", to.p_path);
-		return (1);
-	}
-	return (pflag ? setfile(from_stat, -1) : 0);
-}
-
-int
-setfile(struct stat *fs, int fd)
+		warn(pCtx, "mknod: %s", to.p_path);
+		return (1);
+	}
+	return (pflag ? setfile(pCtx, from_stat, -1) : 0);
+}
+
+int
+setfile(PKMKBUILTINCTX pCtx, struct stat *fs, int fd)
 {
 	static struct timeval tv[2];
@@ -335,5 +335,5 @@
 #endif
 	if (islink ? lutimes(to.p_path, tv) : utimes(to.p_path, tv)) {
-		warn("%sutimes: %s", islink ? "l" : "", to.p_path);
+		warn(pCtx, "%sutimes: %s", islink ? "l" : "", to.p_path);
 		rval = 1;
 	}
@@ -357,5 +357,5 @@
 		    chown(to.p_path, fs->st_uid, fs->st_gid))) {
 			if (errno != EPERM) {
-				warn("chown: %s", to.p_path);
+				warn(pCtx, "chown: %s", to.p_path);
 				rval = 1;
 			}
@@ -367,5 +367,5 @@
 		    (islink ? lchmod(to.p_path, fs->st_mode) :
 		    chmod(to.p_path, fs->st_mode))) {
-			warn("chmod: %s", to.p_path);
+			warn(pCtx, "chmod: %s", to.p_path);
 			rval = 1;
 		}
@@ -377,5 +377,5 @@
 		    (islink ? (errno = ENOSYS) :
 		    chflags(to.p_path, fs->st_flags))) {
-			warn("chflags: %s", to.p_path);
+			warn(pCtx, "chflags: %s", to.p_path);
 			rval = 1;
 		}
Index: trunk/src/kmk/kmkbuiltin/echo.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/echo.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/echo.c	(revision 3192)
@@ -1,165 +1,125 @@
-/*
- * Copyright (c) 1989, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+/* $Id$ */
+/** @file
+ * kMk Builtin command - echo
  */
 
-#if 0
-#ifndef lint
-static char const copyright[] =
-"@(#) Copyright (c) 1989, 1993\n\
-	The Regents of the University of California.  All rights reserved.\n";
-#endif /* not lint */
+/*
+ * Copyright (c) 2018 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
+ *
+ * This file is part of kBuild.
+ *
+ * kBuild is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * kBuild is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with kBuild.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
 
-#ifndef lint
-static char sccsid[] = "@(#)echo.c	8.1 (Berkeley) 5/31/93";
-#endif /* not lint */
-#include <sys/cdefs.h>
-/*__FBSDID("$FreeBSD: src/bin/echo/echo.c,v 1.17 2004/04/06 20:06:46 markm Exp $");*/
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifdef _MSC_VER
+# include <io.h>
 #endif
 
-#include "config.h"
-#include <sys/types.h>
-#ifndef _MSC_VER
-#include <sys/uio.h>
+#include "kmkbuiltin.h"
+#include "err.h"
+
+
+int kmk_builtin_echo(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx)
+{
+    int     rcExit = 0;
+    int     iFirst = 1;
+    int     i;
+    char   *pszBuf;
+    size_t  cbBuf;
+
+    /*
+     * Check for the -n option.
+     */
+    int fNoNewLine = 0;
+    if (   argc > iFirst
+        && strcmp(argv[iFirst], "-n") == 0)
+    {
+        iFirst++;
+        fNoNewLine = 1;
+    }
+
+    /*
+     * Calc buffer size and allocate it.
+     */
+    cbBuf = 1 + 1;
+    for (i = 1; i < argc; i++)
+        cbBuf += (i > iFirst) + strlen(argv[i]);
+    pszBuf = (char *)malloc(cbBuf);
+    if (pszBuf)
+    {
+        /*
+         * Assembler the output into the buffer.
+         */
+        char *pszDst = pszBuf;
+        for (i = iFirst; i < argc; i++)
+        {
+            const char *pszArg = argv[i];
+            size_t      cchArg = strlen(pszArg);
+
+            /* Check for "\c" in final argument (same as -n). */
+            if (i + 1 >= argc
+                && cchArg >= 2
+                && pszArg[cchArg - 2] == '\\'
+                && pszArg[cchArg - 1] == 'c')
+            {
+                fNoNewLine = 1;
+                cchArg -= 2;
+            }
+            if (i > iFirst)
+                *pszDst++ = ' ';
+            memcpy(pszDst, pszArg, cchArg);
+            pszDst += cchArg;
+        }
+        if (!fNoNewLine)
+            *pszDst++ = '\n';
+        *pszDst = '\0';
+
+        /*
+         * Push it out.
+         */
+#ifndef KMK_BUILTIN_STANDALONE
+        if (output_write_text(pCtx->pOut, 0, pszBuf, pszDst - pszBuf) == -1)
+            rcExit = err(pCtx, 1, "output_write_text");
+#else
+        if (write(STDOUT_FILENO, pszBuf, pszDst - pszBuf) == -1)
+            rcExit = err(pCtx, 1, "write");
+#endif
+        free(pszBuf);
+    }
+    else
+        rcExit = err(pCtx, 1, "malloc(%lu)", (unsigned long)cbBuf);
+    return rcExit;
+}
+
+#ifdef KMK_BUILTIN_STANDALONE
+int main(int argc, char **argv, char **envp)
+{
+    KMKBUILTINCTX Ctx = { "kmk_echo", NULL };
+    return kmk_builtin_echo(argc, argv, envp, &Ctx);
+}
 #endif
 
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#ifndef _MSC_VER
-#include <unistd.h>
-#else
-#include "mscfakes.h"
-#endif
-
-#ifndef IOV_MAX
-#define IOV_MAX 1024
-#endif
-
-
-/*
- * Report an error and exit.
- * Use it instead of err(3) to avoid linking-in stdio.
- */
-static void
-errexit(const char *prog, const char *reason)
-{
-	char *errstr = strerror(errno);
-	ssize_t cchIgn = 0; /* this is to shut up irrelevant warnings on linux. */
-#ifdef _MSC_VER
-	int doserrno = _doserrno;
-	char szDosErr[48];
-	sprintf(szDosErr, " (doserrno=%d)", doserrno);
-#endif
-	cchIgn += write(STDERR_FILENO, prog, strlen(prog));
-	cchIgn += write(STDERR_FILENO, ": ", 2);
-	cchIgn += write(STDERR_FILENO, reason, strlen(reason));
-	cchIgn += write(STDERR_FILENO, ": ", 2);
-	cchIgn += write(STDERR_FILENO, errstr, strlen(errstr));
-#ifdef _MSC_VER
-	cchIgn += write(STDERR_FILENO, szDosErr, strlen(szDosErr));
-#endif
-	cchIgn += write(STDERR_FILENO, "\n", 1);
-	(void)cchIgn;
-}
-
-int
-kmk_builtin_echo(int argc, char *argv[])
-{
-	int nflag;	/* if not set, output a trailing newline. */
-	int veclen;	/* number of writev arguments. */
-	struct iovec *iov, *vp, *iovfree; /* Elements to write, current element. */
-	char space[] = " ";
-	char newline[] = "\n";
-	char *progname = argv[0];
-
-	/* This utility may NOT do getopt(3) option parsing. */
-	if (*++argv && !strcmp(*argv, "-n")) {
-		++argv;
-		--argc;
-		nflag = 1;
-	} else
-		nflag = 0;
-
-	veclen = (argc >= 2) ? (argc - 2) * 2 + 1 : 0;
-
-	if ((iovfree = vp = iov = malloc((veclen + 1) * sizeof(struct iovec))) == NULL) {
-		errexit(progname, "malloc");
-                exit(1);
-        }
-
-	while (argv[0] != NULL) {
-		size_t len;
-
-		len = strlen(argv[0]);
-
-		/*
-		 * If the next argument is NULL then this is this
-		 * the last argument, therefore we need to check
-		 * for a trailing \c.
-		 */
-		if (argv[1] == NULL) {
-			/* is there room for a '\c' and is there one? */
-			if (len >= 2 &&
-			    argv[0][len - 2] == '\\' &&
-			    argv[0][len - 1] == 'c') {
-				/* chop it and set the no-newline flag. */
-				len -= 2;
-				nflag = 1;
-			}
-		}
-		vp->iov_base = *argv;
-		vp++->iov_len = len;
-		if (*++argv) {
-			vp->iov_base = space;
-			vp++->iov_len = 1;
-		}
-	}
-	if (!nflag) {
-		veclen++;
-		vp->iov_base = newline;
-		vp++->iov_len = 1;
-	}
-	/* assert(veclen == (vp - iov)); */
-	while (veclen) {
-		int nwrite;
-
-		nwrite = (veclen > IOV_MAX) ? IOV_MAX : veclen;
-		if (writev(STDOUT_FILENO, iov, nwrite) == -1) {
-			 errexit(progname, "write");
-                         free(iovfree);
-                         return 1;
-                }
-		iov += nwrite;
-		veclen -= nwrite;
-	}
-	free(iovfree);
-	return 0;
-}
Index: trunk/src/kmk/kmkbuiltin/err.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/err.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/err.c	(revision 3192)
@@ -27,5 +27,10 @@
 *   Header Files                                                               *
 *******************************************************************************/
-#include "config.h"
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#else
+# include <stdlib.h>
+# define snprintf _snprintf
+#endif
 #include <stdio.h>
 #include <stdarg.h>
@@ -33,4 +38,7 @@
 #include <errno.h>
 #include "err.h"
+#if !defined(KMK_BUILTIN_STANDALONE) && !defined(KWORKER)
+# include "../output.h"
+#endif
 
 #ifdef KBUILD_OS_WINDOWS
@@ -41,155 +49,286 @@
 #endif
 
-
-/** The current program name. */
-const char *g_progname = "kmk";
-
-
-int err(int eval, const char *fmt, ...)
-{
-    va_list args;
-    int error = errno;
-
-    /* stderr is unbuffered, so try format the whole message and print it in
-       one go so it won't be split by other output. */
-    char szMsg[4096];
-    int cchMsg = snprintf(szMsg, sizeof(szMsg), "%s: ", g_progname);
-    if (cchMsg < (int)sizeof(szMsg) - 1 && cchMsg > 0)
-    {
-        int cchMsg2;
-        va_start(args, fmt);
-        cchMsg += cchMsg2 = vsnprintf(&szMsg[cchMsg], sizeof(szMsg) - cchMsg, fmt, args);
-        va_end(args);
-
-        if (   cchMsg < (int)sizeof(szMsg) - 1
-            && cchMsg2 >= 0)
-        {
-            cchMsg += cchMsg2 = snprintf(&szMsg[cchMsg], sizeof(szMsg) - cchMsg, ": %s\n", strerror(error));
-            if (   cchMsg < (int)sizeof(szMsg) - 1
+int err(PKMKBUILTINCTX pCtx, int eval, const char *fmt, ...)
+{
+    /*
+     * We format into a buffer and pass that onto output.c or fwrite.
+     */
+    int     error = errno;
+    char   *pszToFree = NULL;
+    char    szMsgStack[4096];
+    char   *pszMsg = szMsgStack;
+    size_t  cbMsg = sizeof(szMsgStack);
+    for (;;)
+    {
+        int cchMsg = snprintf(pszMsg, cbMsg, "%s: error: ", pCtx->pszProgName);
+        if (cchMsg < (int)cbMsg - 1 && cchMsg > 0)
+        {
+            int cchMsg2;
+            va_list va;
+            va_start(va, fmt);
+            cchMsg += cchMsg2 = vsnprintf(&pszMsg[cchMsg], cbMsg - cchMsg, fmt, va);
+            va_end(va);
+
+            if (   cchMsg < (int)cbMsg - 1
                 && cchMsg2 >= 0)
             {
-                fwrite(szMsg, cchMsg, 1, stderr);
+                cchMsg += cchMsg2 = snprintf(&pszMsg[cchMsg], cbMsg - cchMsg, ": %s\n", strerror(error));
+                if (   cchMsg < (int)cbMsg - 1
+                    && cchMsg2 >= 0)
+                {
+#if !defined(KMK_BUILTIN_STANDALONE) && !defined(KWORKER)
+                    if (pCtx->pOut)
+                        output_write_text(pCtx->pOut, 1 /*is_err*/, pszMsg, cchMsg);
+                    else
+#endif
+                    {
+                        fflush(stdout);
+                        fwrite(pszMsg, cchMsg, 1, stderr);
+                        fflush(stderr); /* paranoia */
+                    }
+                    if (pszToFree)
+                        free(pszToFree);
+                    errno = error;
+                    return eval;
+                }
+            }
+        }
+
+        /* double the buffer size and retry */
+        if (pszToFree)
+            free(pszToFree);
+        cbMsg *= 2;
+        pszToFree = malloc(cbMsg);
+        if (!pszToFree)
+        {
+            fprintf(stderr, "out of memory!\n");
+            errno = error;
+            return eval;
+        }
+    }
+}
+
+
+int errx(PKMKBUILTINCTX pCtx, int eval, const char *fmt, ...)
+{
+    /*
+     * We format into a buffer and pass that onto output.c or fwrite.
+     */
+    char   *pszToFree = NULL;
+    char    szMsgStack[4096];
+    char   *pszMsg = szMsgStack;
+    size_t  cbMsg = sizeof(szMsgStack);
+    for (;;)
+    {
+        int cchMsg = snprintf(pszMsg, cbMsg, "%s: error: ", pCtx->pszProgName);
+        if (cchMsg < (int)cbMsg - 1 && cchMsg > 0)
+        {
+            int cchMsg2;
+            va_list va;
+            va_start(va, fmt);
+            cchMsg += cchMsg2 = vsnprintf(&pszMsg[cchMsg], cbMsg - cchMsg, fmt, va);
+            va_end(va);
+
+            if (   cchMsg < (int)cbMsg - 2
+                && cchMsg2 >= 0)
+            {
+                /* ensure newline */
+                if (pszMsg[cchMsg - 1] != '\n')
+                {
+                    pszMsg[cchMsg++] = '\n';
+                    pszMsg[cchMsg] = '\0';
+                }
+
+#if !defined(KMK_BUILTIN_STANDALONE) && !defined(KWORKER)
+                if (pCtx->pOut)
+                    output_write_text(pCtx->pOut, 1 /*is_err*/, pszMsg, cchMsg);
+                else
+#endif
+                {
+                    fflush(stdout);
+                    fwrite(pszMsg, cchMsg, 1, stderr);
+                    fflush(stderr); /* paranoia */
+                }
+                if (pszToFree)
+                    free(pszToFree);
                 return eval;
             }
-
-        }
-
-    }
-
-    /* fallback */
-    fprintf(stderr, "%s: ", g_progname);
-    va_start(args, fmt);
-    vfprintf(stderr, fmt, args);
-    va_end(args);
-    fprintf(stderr, ": %s\n", strerror(error));
-
-    return eval;
-}
-
-
-int errx(int eval, const char *fmt, ...)
-{
-    va_list args;
-
-    /* stderr is unbuffered, so try format the whole message and print it in
-       one go so it won't be split by other output. */
-    char szMsg[4096];
-    int cchMsg = snprintf(szMsg, sizeof(szMsg), "%s: ", g_progname);
-    if (cchMsg < (int)sizeof(szMsg) - 1 && cchMsg > 0)
-    {
-        int cchMsg2;
-        va_start(args, fmt);
-        cchMsg += cchMsg2 = vsnprintf(&szMsg[cchMsg], sizeof(szMsg) - cchMsg, fmt, args);
-        va_end(args);
-
-        if (   cchMsg < (int)sizeof(szMsg) - 1
-            && cchMsg2 >= 0)
-        {
-            szMsg[cchMsg++] = '\n';
-            fwrite(szMsg, cchMsg, 1, stderr);
+        }
+
+        /* double the buffer size and retry */
+        if (pszToFree)
+            free(pszToFree);
+        cbMsg *= 2;
+        pszToFree = malloc(cbMsg);
+        if (!pszToFree)
+        {
+            fprintf(stderr, "out of memory!\n");
             return eval;
         }
-
-    }
-
-    /* fallback */
-    fprintf(stderr, "%s: ", g_progname);
-    va_start(args, fmt);
-    vfprintf(stderr, fmt, args);
-    va_end(args);
-    fprintf(stderr, "\n");
-
-    return eval;
-}
-
-void warn(const char *fmt, ...)
-{
-    int error = errno;
-    va_list args;
-
-    /* stderr is unbuffered, so try format the whole message and print it in
-       one go so it won't be split by other output. */
-    char szMsg[4096];
-    int cchMsg = snprintf(szMsg, sizeof(szMsg), "%s: ", g_progname);
-    if (cchMsg < (int)sizeof(szMsg) - 1 && cchMsg > 0)
-    {
-        int cchMsg2;
-        va_start(args, fmt);
-        cchMsg += cchMsg2 = vsnprintf(&szMsg[cchMsg], sizeof(szMsg) - cchMsg, fmt, args);
-        va_end(args);
-
-        if (   cchMsg < (int)sizeof(szMsg) - 1
-            && cchMsg2 >= 0)
-        {
-            cchMsg += cchMsg2 = snprintf(&szMsg[cchMsg], sizeof(szMsg) - cchMsg, ": %s\n", strerror(error));
-            if (   cchMsg < (int)sizeof(szMsg) - 1
+    }
+}
+
+void warn(PKMKBUILTINCTX pCtx, const char *fmt, ...)
+{
+    /*
+     * We format into a buffer and pass that onto output.c or fwrite.
+     */
+    int     error = errno;
+    char   *pszToFree = NULL;
+    char    szMsgStack[4096];
+    char   *pszMsg = szMsgStack;
+    size_t  cbMsg = sizeof(szMsgStack);
+    for (;;)
+    {
+        int cchMsg = snprintf(pszMsg, cbMsg, "%s: ", pCtx->pszProgName);
+        if (cchMsg < (int)cbMsg - 1 && cchMsg > 0)
+        {
+            int cchMsg2;
+            va_list va;
+            va_start(va, fmt);
+            cchMsg += cchMsg2 = vsnprintf(&pszMsg[cchMsg], cbMsg - cchMsg, fmt, va);
+            va_end(va);
+
+            if (   cchMsg < (int)cbMsg - 1
                 && cchMsg2 >= 0)
             {
-                fwrite(szMsg, cchMsg, 1, stderr);
+                cchMsg += cchMsg2 = snprintf(&pszMsg[cchMsg], cbMsg - cchMsg, ": %s\n", strerror(error));
+                if (   cchMsg < (int)cbMsg - 1
+                    && cchMsg2 >= 0)
+                {
+#if !defined(KMK_BUILTIN_STANDALONE) && !defined(KWORKER)
+                    if (pCtx->pOut)
+                        output_write_text(pCtx->pOut, 1 /*is_err*/, pszMsg, cchMsg);
+                    else
+#endif
+                    {
+                        fflush(stdout);
+                        fwrite(pszMsg, cchMsg, 1, stderr);
+                        fflush(stderr); /* paranoia */
+                    }
+                    if (pszToFree)
+                        free(pszToFree);
+                    errno = error;
+                    return;
+                }
+            }
+        }
+
+        /* double the buffer size and retry */
+        if (pszToFree)
+            free(pszToFree);
+        cbMsg *= 2;
+        pszToFree = malloc(cbMsg);
+        if (!pszToFree)
+        {
+            fprintf(stderr, "out of memory!\n");
+            errno = error;
+            return;
+        }
+    }
+}
+
+void warnx(PKMKBUILTINCTX pCtx, const char *fmt, ...)
+{
+    /*
+     * We format into a buffer and pass that onto output.c or fwrite.
+     */
+    char   *pszToFree = NULL;
+    char    szMsgStack[4096];
+    char   *pszMsg = szMsgStack;
+    size_t  cbMsg = sizeof(szMsgStack);
+    for (;;)
+    {
+        int cchMsg = snprintf(pszMsg, cbMsg, "%s: ", pCtx->pszProgName);
+        if (cchMsg < (int)cbMsg - 1 && cchMsg > 0)
+        {
+            int cchMsg2;
+            va_list va;
+            va_start(va, fmt);
+            cchMsg += cchMsg2 = vsnprintf(&pszMsg[cchMsg], cbMsg - cchMsg, fmt, va);
+            va_end(va);
+
+            if (   cchMsg < (int)cbMsg - 2
+                && cchMsg2 >= 0)
+            {
+                /* ensure newline */
+                if (pszMsg[cchMsg - 1] != '\n')
+                {
+                    pszMsg[cchMsg++] = '\n';
+                    pszMsg[cchMsg] = '\0';
+                }
+
+#if !defined(KMK_BUILTIN_STANDALONE) && !defined(KWORKER)
+                if (pCtx->pOut)
+                    output_write_text(pCtx->pOut, 1 /*is_err*/, pszMsg, cchMsg);
+                else
+#endif
+                {
+                    fflush(stdout);
+                    fwrite(pszMsg, cchMsg, 1, stderr);
+                    fflush(stderr); /* paranoia */
+                }
+                if (pszToFree)
+                    free(pszToFree);
                 return;
             }
-
-        }
-    }
-
-    /* fallback */
-    fprintf(stderr, "%s: ", g_progname);
-    va_start(args, fmt);
-    vfprintf(stderr, fmt, args);
-    va_end(args);
-    fprintf(stderr, ": %s\n", strerror(error));
-}
-
-void warnx(const char *fmt, ...)
-{
-    va_list args;
-
-    /* stderr is unbuffered, so try format the whole message and print it in
-       one go so it won't be split by other output. */
-    char szMsg[4096];
-    int cchMsg = snprintf(szMsg, sizeof(szMsg), "%s: ", g_progname);
-    if (cchMsg < (int)sizeof(szMsg) - 1 && cchMsg > 0)
-    {
-        int cchMsg2;
-        va_start(args, fmt);
-        cchMsg += cchMsg2 = vsnprintf(&szMsg[cchMsg], sizeof(szMsg) - cchMsg, fmt, args);
-        va_end(args);
-
-        if (   cchMsg < (int)sizeof(szMsg) - 1
-            && cchMsg2 >= 0)
-        {
-            szMsg[cchMsg++] = '\n';
-            fwrite(szMsg, cchMsg, 1, stderr);
+        }
+
+        /* double the buffer size and retry */
+        if (pszToFree)
+            free(pszToFree);
+        cbMsg *= 2;
+        pszToFree = malloc(cbMsg);
+        if (!pszToFree)
+        {
+            fprintf(stderr, "out of memory!\n");
             return;
         }
-
-    }
-
-    /* fallback */
-    fprintf(stderr, "%s: ", g_progname);
-    va_start(args, fmt);
-    vfprintf(stderr, fmt, args);
-    va_end(args);
-    fprintf(stderr, "\n");
-}
-
+    }
+}
+
+void kmk_builtin_ctx_printf(PKMKBUILTINCTX pCtx, int fIsErr, const char *pszFormat, ...)
+{
+    /*
+     * We format into a buffer and pass that onto output.c or fwrite.
+     */
+    char   *pszToFree = NULL;
+    char    szMsgStack[4096];
+    char   *pszMsg = szMsgStack;
+    size_t  cbMsg = sizeof(szMsgStack);
+    for (;;)
+    {
+        int cchMsg;
+        va_list va;
+        va_start(va, pszFormat);
+        cchMsg = vsnprintf(pszMsg, cbMsg, pszFormat, va);
+        va_end(va);
+        if (cchMsg < (int)cbMsg - 1 && cchMsg > 0)
+        {
+#if !defined(KMK_BUILTIN_STANDALONE) && !defined(KWORKER)
+            if (pCtx->pOut)
+                output_write_text(pCtx->pOut, fIsErr, pszMsg, cchMsg);
+            else
+#endif
+            {
+                fwrite(pszMsg, cchMsg, 1, fIsErr ? stderr : stdout);
+                fflush(fIsErr ? stderr : stdout);
+            }
+            if (pszToFree)
+                free(pszToFree);
+            return;
+        }
+
+        /* double the buffer size and retry */
+        if (pszToFree)
+            free(pszToFree);
+        cbMsg *= 2;
+        pszToFree = malloc(cbMsg);
+        if (!pszToFree)
+        {
+            fprintf(stderr, "out of memory!\n");
+            return;
+        }
+    }
+}
+
Index: trunk/src/kmk/kmkbuiltin/err.h
===================================================================
--- trunk/src/kmk/kmkbuiltin/err.h	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/err.h	(revision 3192)
@@ -27,9 +27,11 @@
 #define ___err_h
 
-extern const char *g_progname;
-int err(int eval, const char *fmt, ...);
-int errx(int eval, const char *fmt, ...);
-void warn(const char *fmt, ...);
-void warnx(const char *fmt, ...);
+#include "../kmkbuiltin.h"
+
+int  err(PKMKBUILTINCTX pCtx, int eval, const char *fmt, ...);
+int  errx(PKMKBUILTINCTX pCtx, int eval, const char *fmt, ...);
+void warn(PKMKBUILTINCTX pCtx, const char *fmt, ...);
+void warnx(PKMKBUILTINCTX pCtx, const char *fmt, ...);
+void kmk_builtin_ctx_printf(PKMKBUILTINCTX pCtx, int fIsErr, const char *pszFormat, ...);
 
 #endif
Index: trunk/src/kmk/kmkbuiltin/expr.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/expr.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/expr.c	(revision 3192)
@@ -22,22 +22,23 @@
 #endif
 #include "err.h"
-#include "getopt.h"
 #include "kmkbuiltin.h"
 
-static struct val	*make_int(int);
-static struct val	*make_str(char *);
-static void		 free_value(struct val *);
+typedef struct EXPRINSTANCE *PEXPRINSTANCE;
+
+static struct val	*make_int(PEXPRINSTANCE, int);
+static struct val	*make_str(PEXPRINSTANCE, char *);
+static void		 free_value(PEXPRINSTANCE, struct val *);
 static int		 is_integer(struct val *, int *);
-static int		 to_integer(struct val *);
-static void		 to_string(struct val *);
-static int		 is_zero_or_null(struct val *);
-static void		 nexttoken(int);
-static struct val	*eval6(void);
-static struct val	*eval5(void);
-static struct val	*eval4(void);
-static struct val	*eval3(void);
-static struct val	*eval2(void);
-static struct val	*eval1(void);
-static struct val	*eval0(void);
+static int		 to_integer(PEXPRINSTANCE, struct val *);
+static void		 to_string(PEXPRINSTANCE, struct val *);
+static int		 is_zero_or_null(PEXPRINSTANCE, struct val *);
+static void		 nexttoken(PEXPRINSTANCE, int);
+static struct val	*eval6(PEXPRINSTANCE);
+static struct val	*eval5(PEXPRINSTANCE);
+static struct val	*eval4(PEXPRINSTANCE);
+static struct val	*eval3(PEXPRINSTANCE);
+static struct val	*eval2(PEXPRINSTANCE);
+static struct val	*eval1(PEXPRINSTANCE);
+static struct val	*eval0(PEXPRINSTANCE);
 
 enum token {
@@ -58,31 +59,34 @@
 };
 
-static enum token	token;
-static struct val     *tokval;
-static char	      **av;
-static jmp_buf          g_expr_jmp;
-static void           **recorded_allocations;
-static int 		num_recorded_allocations;
-
-
-static void expr_mem_record_alloc(void *ptr)
-{
-	if (!(num_recorded_allocations & 31)) {
-    		void *newtab = realloc(recorded_allocations, (num_recorded_allocations + 33) * sizeof(void *));
+typedef struct EXPRINSTANCE {
+    PKMKBUILTINCTX  pCtx;
+    enum token      token;
+    struct val     *tokval;
+    char          **av;
+    jmp_buf         g_expr_jmp;
+    void          **recorded_allocations;
+    int             num_recorded_allocations;
+} EXPRINSTANCE;
+
+
+static void expr_mem_record_alloc(PEXPRINSTANCE pThis, void *ptr)
+{
+	if (!(pThis->num_recorded_allocations & 31)) {
+    		void *newtab = realloc(pThis->recorded_allocations, (pThis->num_recorded_allocations + 33) * sizeof(void *));
 		if (!newtab)
-			longjmp(g_expr_jmp, err(3, NULL));
-		recorded_allocations = (void **)newtab;
-	}
-	recorded_allocations[num_recorded_allocations++] = ptr;
-}
-
-
-static void expr_mem_record_free(void *ptr)
-{
-	int i = num_recorded_allocations;
+			longjmp(pThis->g_expr_jmp, err(pThis->pCtx, 3, NULL));
+		pThis->recorded_allocations = (void **)newtab;
+	}
+	pThis->recorded_allocations[pThis->num_recorded_allocations++] = ptr;
+}
+
+
+static void expr_mem_record_free(PEXPRINSTANCE pThis, void *ptr)
+{
+	int i = pThis->num_recorded_allocations;
 	while (i-- > 0)
-		if (recorded_allocations[i] == ptr) {
-			num_recorded_allocations--;
-			recorded_allocations[i] = recorded_allocations[num_recorded_allocations];
+		if (pThis->recorded_allocations[i] == ptr) {
+			pThis->num_recorded_allocations--;
+			pThis->recorded_allocations[i] = pThis->recorded_allocations[pThis->num_recorded_allocations];
 			return;
 		}
@@ -90,23 +94,23 @@
 }
 
-static void expr_mem_init(void)
-{
-	num_recorded_allocations = 0;
-	recorded_allocations = NULL;
-}
-
-static void expr_mem_cleanup(void)
-{
-	if (recorded_allocations) {
-		while (num_recorded_allocations-- > 0)
-			free(recorded_allocations[num_recorded_allocations]);
-		free(recorded_allocations);
-		recorded_allocations = NULL;
-	}
-}
-
-
-static struct val *
-make_int(int i)
+static void expr_mem_init(PEXPRINSTANCE pThis)
+{
+	pThis->num_recorded_allocations = 0;
+	pThis->recorded_allocations = NULL;
+}
+
+static void expr_mem_cleanup(PEXPRINSTANCE pThis)
+{
+	if (pThis->recorded_allocations) {
+		while (pThis->num_recorded_allocations-- > 0)
+			free(pThis->recorded_allocations[pThis->num_recorded_allocations]);
+		free(pThis->recorded_allocations);
+		pThis->recorded_allocations = NULL;
+	}
+}
+
+
+static struct val *
+make_int(PEXPRINSTANCE pThis, int i)
 {
 	struct val     *vp;
@@ -114,6 +118,6 @@
 	vp = (struct val *) malloc(sizeof(*vp));
 	if (vp == NULL)
-		longjmp(g_expr_jmp, err(3, NULL));
-	expr_mem_record_alloc(vp);
+		longjmp(pThis->g_expr_jmp, err(pThis->pCtx, 3, NULL));
+	expr_mem_record_alloc(pThis, vp);
 	vp->type = integer;
 	vp->u.i = i;
@@ -123,5 +127,5 @@
 
 static struct val *
-make_str(char *s)
+make_str(PEXPRINSTANCE pThis, char *s)
 {
 	struct val     *vp;
@@ -129,7 +133,7 @@
 	vp = (struct val *) malloc(sizeof(*vp));
 	if (vp == NULL || ((vp->u.s = strdup(s)) == NULL))
-		longjmp(g_expr_jmp, err(3, NULL));
-	expr_mem_record_alloc(vp->u.s);
-	expr_mem_record_alloc(vp);
+		longjmp(pThis->g_expr_jmp, err(pThis->pCtx, 3, NULL));
+	expr_mem_record_alloc(pThis, vp->u.s);
+	expr_mem_record_alloc(pThis, vp);
 	vp->type = string;
 	return vp;
@@ -138,12 +142,12 @@
 
 static void
-free_value(struct val *vp)
+free_value(PEXPRINSTANCE pThis, struct val *vp)
 {
 	if (vp->type == string) {
-		expr_mem_record_free(vp->u.s);
+		expr_mem_record_free(pThis, vp->u.s);
 		free(vp->u.s);
 	}
 	free(vp);
-	expr_mem_record_free(vp);
+	expr_mem_record_free(pThis, vp);
 }
 
@@ -193,5 +197,5 @@
 /* coerce to vp to an integer */
 static int
-to_integer(struct val *vp)
+to_integer(PEXPRINSTANCE pThis, struct val *vp)
 {
 	int		r;
@@ -201,5 +205,5 @@
 
 	if (is_integer(vp, &r)) {
-		expr_mem_record_free(vp->u.s);
+		expr_mem_record_free(pThis, vp->u.s);
 		free(vp->u.s);
 		vp->u.i = r;
@@ -214,5 +218,5 @@
 /* coerce to vp to an string */
 static void
-to_string(struct val *vp)
+to_string(PEXPRINSTANCE pThis, struct val *vp)
 {
 	char	       *tmp;
@@ -222,6 +226,6 @@
 
 	if (asprintf(&tmp, "%d", vp->u.i) == -1)
-		longjmp(g_expr_jmp, err(3, NULL));
-	expr_mem_record_alloc(tmp);
+		longjmp(pThis->g_expr_jmp, err(pThis->pCtx, 3, NULL));
+	expr_mem_record_alloc(pThis, tmp);
 
 	vp->type = string;
@@ -230,10 +234,10 @@
 
 static int
-is_zero_or_null(struct val *vp)
+is_zero_or_null(PEXPRINSTANCE pThis, struct val *vp)
 {
 	if (vp->type == integer) {
 		return (vp->u.i == 0);
 	} else {
-		return (*vp->u.s == 0 || (to_integer(vp) && vp->u.i == 0));
+		return (*vp->u.s == 0 || (to_integer(pThis, vp) && vp->u.i == 0));
 	}
 	/* NOTREACHED */
@@ -241,13 +245,13 @@
 
 static void
-nexttoken(int pat)
+nexttoken(PEXPRINSTANCE pThis, int pat)
 {
 	char	       *p;
 
-	if ((p = *av) == NULL) {
-		token = EOI;
+	if ((p = *pThis->av) == NULL) {
+		pThis->token = EOI;
 		return;
 	}
-	av++;
+	pThis->av++;
 
 
@@ -258,5 +262,5 @@
 
 			if ((i = strchr(x, *p)) != NULL) {
-				token = i - x;
+				pThis->token = i - x;
 				return;
 			}
@@ -264,17 +268,17 @@
 			switch (*p) {
 			case '<':
-				token = LE;
+				pThis->token = LE;
 				return;
 			case '>':
-				token = GE;
+				pThis->token = GE;
 				return;
 			case '!':
-				token = NE;
+				pThis->token = NE;
 				return;
 			}
 		}
 	}
-	tokval = make_str(p);
-	token = OPERAND;
+	pThis->tokval = make_str(pThis, p);
+	pThis->token = OPERAND;
 	return;
 }
@@ -287,31 +291,31 @@
 #endif
 static void
-error(void)
-{
-	longjmp(g_expr_jmp, errx(2, "syntax error"));
+error(PEXPRINSTANCE pThis)
+{
+	longjmp(pThis->g_expr_jmp, errx(pThis->pCtx, 2, "syntax error"));
 	/* NOTREACHED */
 }
 
 static struct val *
-eval6(void)
+eval6(PEXPRINSTANCE pThis)
 {
 	struct val     *v;
 
-	if (token == OPERAND) {
-		nexttoken(0);
-		return tokval;
-
-	} else if (token == RP) {
-		nexttoken(0);
-		v = eval0();
-
-		if (token != LP) {
-			error();
+	if (pThis->token == OPERAND) {
+		nexttoken(pThis, 0);
+		return pThis->tokval;
+
+	} else if (pThis->token == RP) {
+		nexttoken(pThis, 0);
+		v = eval0(pThis);
+
+		if (pThis->token != LP) {
+			error(pThis);
 			/* NOTREACHED */
 		}
-		nexttoken(0);
+		nexttoken(pThis, 0);
 		return v;
 	} else {
-		error();
+		error(pThis);
 	}
 	/* NOTREACHED */
@@ -320,5 +324,5 @@
 /* Parse and evaluate match (regex) expressions */
 static struct val *
-eval5(void)
+eval5(PEXPRINSTANCE pThis)
 {
 #ifdef KMK_WITH_REGEX
@@ -332,18 +336,18 @@
 	struct val     *l;
 
-	l = eval6();
-	while (token == MATCH) {
+	l = eval6(pThis);
+	while (pThis->token == MATCH) {
 #ifdef KMK_WITH_REGEX
-		nexttoken(1);
-		r = eval6();
+		nexttoken(pThis, 1);
+		r = eval6(pThis);
 
 		/* coerce to both arguments to strings */
-		to_string(l);
-		to_string(r);
+		to_string(pThis, l);
+		to_string(pThis, r);
 
 		/* compile regular expression */
 		if ((eval = regcomp(&rp, r->u.s, 0)) != 0) {
 			regerror(eval, &rp, errbuf, sizeof(errbuf));
-			longjmp(g_expr_jmp, errx(2, "%s", errbuf));
+			longjmp(pThis->g_expr_jmp, errx(pThis->pCtx, 2, "%s", errbuf));
 		}
 
@@ -353,25 +357,25 @@
 			if (rm[1].rm_so >= 0) {
 				*(l->u.s + rm[1].rm_eo) = '\0';
-				v = make_str(l->u.s + rm[1].rm_so);
+				v = make_str(pThis, l->u.s + rm[1].rm_so);
 
 			} else {
-				v = make_int((int)(rm[0].rm_eo - rm[0].rm_so));
+				v = make_int(pThis, (int)(rm[0].rm_eo - rm[0].rm_so));
 			}
 		} else {
 			if (rp.re_nsub == 0) {
-				v = make_int(0);
+				v = make_int(pThis, 0);
 			} else {
-				v = make_str("");
+				v = make_str(pThis, "");
 			}
 		}
 
 		/* free arguments and pattern buffer */
-		free_value(l);
-		free_value(r);
+		free_value(pThis, l);
+		free_value(pThis, r);
 		regfree(&rp);
 
 		l = v;
 #else
-		longjmp(g_expr_jmp, errx(2, "regex not supported, sorry."));
+		longjmp(pThis->g_expr_jmp, errx(pThis->pCtx, 2, "regex not supported, sorry."));
 #endif
 	}
@@ -382,16 +386,16 @@
 /* Parse and evaluate multiplication and division expressions */
 static struct val *
-eval4(void)
+eval4(PEXPRINSTANCE pThis)
 {
 	struct val     *l, *r;
 	enum token	op;
 
-	l = eval5();
-	while ((op = token) == MUL || op == DIV || op == MOD) {
-		nexttoken(0);
-		r = eval5();
-
-		if (!to_integer(l) || !to_integer(r)) {
-			longjmp(g_expr_jmp, errx(2, "non-numeric argument"));
+	l = eval5(pThis);
+	while ((op = pThis->token) == MUL || op == DIV || op == MOD) {
+		nexttoken(pThis, 0);
+		r = eval5(pThis);
+
+		if (!to_integer(pThis, l) || !to_integer(pThis, r)) {
+			longjmp(pThis->g_expr_jmp, errx(pThis->pCtx, 2, "non-numeric argument"));
 		}
 
@@ -400,5 +404,5 @@
 		} else {
 			if (r->u.i == 0) {
-				longjmp(g_expr_jmp, errx(2, "division by zero"));
+				longjmp(pThis->g_expr_jmp, errx(pThis->pCtx, 2, "division by zero"));
 			}
 			if (op == DIV) {
@@ -409,5 +413,5 @@
 		}
 
-		free_value(r);
+		free_value(pThis, r);
 	}
 
@@ -417,16 +421,16 @@
 /* Parse and evaluate addition and subtraction expressions */
 static struct val *
-eval3(void)
+eval3(PEXPRINSTANCE pThis)
 {
 	struct val     *l, *r;
 	enum token	op;
 
-	l = eval4();
-	while ((op = token) == ADD || op == SUB) {
-		nexttoken(0);
-		r = eval4();
-
-		if (!to_integer(l) || !to_integer(r)) {
-			longjmp(g_expr_jmp, errx(2, "non-numeric argument"));
+	l = eval4(pThis);
+	while ((op = pThis->token) == ADD || op == SUB) {
+		nexttoken(pThis, 0);
+		r = eval4(pThis);
+
+		if (!to_integer(pThis, l) || !to_integer(pThis, r)) {
+			longjmp(pThis->g_expr_jmp, errx(pThis->pCtx, 2, "non-numeric argument"));
 		}
 
@@ -437,5 +441,5 @@
 		}
 
-		free_value(r);
+		free_value(pThis, r);
 	}
 
@@ -445,5 +449,5 @@
 /* Parse and evaluate comparison expressions */
 static struct val *
-eval2(void)
+eval2(PEXPRINSTANCE pThis)
 {
 	struct val     *l, *r;
@@ -451,9 +455,9 @@
 	int		v = 0, li, ri;
 
-	l = eval3();
-	while ((op = token) == EQ || op == NE || op == LT || op == GT ||
+	l = eval3(pThis);
+	while ((op = pThis->token) == EQ || op == NE || op == LT || op == GT ||
 	    op == LE || op == GE) {
-		nexttoken(0);
-		r = eval3();
+		nexttoken(pThis, 0);
+		r = eval3(pThis);
 
 		if (is_integer(l, &li) && is_integer(r, &ri)) {
@@ -481,6 +485,6 @@
 			}
 		} else {
-			to_string(l);
-			to_string(r);
+			to_string(pThis, l);
+			to_string(pThis, r);
 
 			switch (op) {
@@ -508,7 +512,7 @@
 		}
 
-		free_value(l);
-		free_value(r);
-		l = make_int(v);
+		free_value(pThis, l);
+		free_value(pThis, r);
+		l = make_int(pThis, v);
 	}
 
@@ -518,19 +522,19 @@
 /* Parse and evaluate & expressions */
 static struct val *
-eval1(void)
+eval1(PEXPRINSTANCE pThis)
 {
 	struct val     *l, *r;
 
-	l = eval2();
-	while (token == AND) {
-		nexttoken(0);
-		r = eval2();
-
-		if (is_zero_or_null(l) || is_zero_or_null(r)) {
-			free_value(l);
-			free_value(r);
-			l = make_int(0);
+	l = eval2(pThis);
+	while (pThis->token == AND) {
+		nexttoken(pThis, 0);
+		r = eval2(pThis);
+
+		if (is_zero_or_null(pThis, l) || is_zero_or_null(pThis, r)) {
+			free_value(pThis, l);
+			free_value(pThis, r);
+			l = make_int(pThis, 0);
 		} else {
-			free_value(r);
+			free_value(pThis, r);
 		}
 	}
@@ -541,18 +545,18 @@
 /* Parse and evaluate | expressions */
 static struct val *
-eval0(void)
+eval0(PEXPRINSTANCE pThis)
 {
 	struct val     *l, *r;
 
-	l = eval1();
-	while (token == OR) {
-		nexttoken(0);
-		r = eval1();
-
-		if (is_zero_or_null(l)) {
-			free_value(l);
+	l = eval1(pThis);
+	while (pThis->token == OR) {
+		nexttoken(pThis, 0);
+		r = eval1(pThis);
+
+		if (is_zero_or_null(pThis, l)) {
+			free_value(pThis, l);
 			l = r;
 		} else {
-			free_value(r);
+			free_value(pThis, r);
 		}
 	}
@@ -563,45 +567,51 @@
 
 int
-kmk_builtin_expr(int argc, char *argv[], char **envp)
-{
-	struct val     *vp;
+kmk_builtin_expr(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx)
+{
+	EXPRINSTANCE This;
+	struct val *vp;
 	int rval;
-
-	/* re-init globals */
-	token = 0;
-	tokval = 0;
-	av = 0;
-	expr_mem_init();
-
-#ifdef kmk_builtin_expr /* kmk already does this. */
-	(void) setlocale(LC_ALL, "");
-#endif
 
 	if (argc > 1 && !strcmp(argv[1], "--"))
 		argv++;
 
-	av = argv + 1;
-
-	rval = setjmp(g_expr_jmp);
+	/* Init globals */
+	This.pCtx = pCtx;
+	This.token = 0;
+	This.tokval = 0;
+	This.av = argv + 1;
+	expr_mem_init(&This);
+
+	rval = setjmp(This.g_expr_jmp);
 	if (!rval) {
-		nexttoken(0);
-		vp = eval0();
-
-		if (token != EOI) {
-			error();
+		nexttoken(&This, 0);
+		vp = eval0(&This);
+
+		if (This.token != EOI) {
+			error(&This);
 			/* NOTREACHED */
 		}
 
 		if (vp->type == integer)
-			printf("%d\n", vp->u.i);
+			kmk_builtin_ctx_printf(pCtx, 0, "%d\n", vp->u.i);
 		else
-			printf("%s\n", vp->u.s);
-
-		rval = is_zero_or_null(vp);
+			kmk_builtin_ctx_printf(pCtx, 0, "%s\n", vp->u.s);
+
+		rval = is_zero_or_null(&This, vp);
 	}
 	/* else: longjmp */
 
 	/* cleanup */
-	expr_mem_cleanup();
+	expr_mem_cleanup(&This);
 	return rval;
 }
+
+#ifdef KMK_BUILTIN_STANDALONE
+int main(int argc, char **argv, char **envp)
+{
+	KMKBUILTINCTX Ctx = { "kmk_expr", NULL };
+	(void) setlocale(LC_ALL, "");
+	return kmk_builtin_expr(argc, argv, envp, &Ctx);
+}
+#endif
+
Index: trunk/src/kmk/kmkbuiltin/install.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/install.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/install.c	(revision 3192)
@@ -122,13 +122,26 @@
 #endif
 
-static gid_t gid;
-static uid_t uid;
-static int dobackup, docompare, dodir, dopreserve, dostrip, nommap, safecopy, verbose, mode_given;
-static mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
-static const char *suffix = BACKUP_SUFFIX;
-static int ignore_perm_errors;
-static int hard_link_files_when_possible;
-static int dos2unix;
-
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+typedef struct INSTALLINSTANCE
+{
+    PKMKBUILTINCTX pCtx;
+
+    gid_t gid;
+    uid_t uid;
+    int dobackup, docompare, dodir, dopreserve, dostrip, nommap, safecopy, verbose, mode_given;
+    mode_t mode;
+    const char *suffix;
+    int ignore_perm_errors;
+    int hard_link_files_when_possible;
+    int dos2unix;
+} INSTALLINSTANCE;
+typedef INSTALLINSTANCE *PINSTALLINSTANCE;
+
+
+/*********************************************************************************************************************************
+*   Global Variables                                                                                                             *
+*********************************************************************************************************************************/
 static struct option long_options[] =
 {
@@ -145,13 +158,13 @@
 
 
-static int	copy(int, const char *, int *, const char *);
+static int	copy(PINSTALLINSTANCE, int, const char *, int *, const char *);
 static int	compare(int, size_t, int, size_t);
-static int	create_newfile(const char *, int, struct stat *);
+static int	create_newfile(PINSTALLINSTANCE, const char *, int, struct stat *);
 static int	create_tempfile(const char *, char *, size_t);
-static int	install(const char *, const char *, u_long, u_int);
-static int	install_dir(char *);
-static u_long	numeric_id(const char *, const char *);
-static int	strip(const char *);
-static int	usage(FILE *);
+static int	install(PINSTALLINSTANCE, const char *, const char *, u_long, u_int);
+static int	install_dir(PINSTALLINSTANCE, char *);
+static u_long	numeric_id(PINSTALLINSTANCE, const char *, const char *);
+static int	strip(PINSTALLINSTANCE, const char *);
+static int	usage(PKMKBUILTINCTX, int);
 static char    *last_slash(const char *);
 static KBOOL	needs_dos2unix_conversion(const char *pszFilename);
@@ -159,6 +172,7 @@
 
 int
-kmk_builtin_install(int argc, char *argv[], char ** envp)
-{
+kmk_builtin_install(int argc, char *argv[], char ** envp, PKMKBUILTINCTX pCtx)
+{
+	INSTALLINSTANCE This;
 	struct stat from_sb, to_sb;
 	mode_t *set;
@@ -170,16 +184,24 @@
 	(void)envp;
 
-	/* reinitialize globals */
-	mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
-	suffix = BACKUP_SUFFIX;
-	gid = 0;
-	uid = 0;
-	dobackup = docompare = dodir = dopreserve = dostrip = nommap = safecopy = verbose = mode_given = 0;
-	ignore_perm_errors = geteuid() != 0;
-	hard_link_files_when_possible = 0;
-	dos2unix = 0;
+	/* Initialize global instance data. */
+	This.pCtx = pCtx;
+	This.mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+	This.suffix = BACKUP_SUFFIX;
+	This.gid = 0;
+	This.uid = 0;
+	This.dobackup = 0;
+	This.docompare = 0;
+	This.dodir = 0;
+	This.dopreserve = 0;
+	This.dostrip = 0;
+	This.nommap = 0;
+	This.safecopy = 0;
+	This.verbose = 0;
+	This.mode_given = 0;
+	This.ignore_perm_errors = geteuid() != 0;
+	This.hard_link_files_when_possible = 0;
+	This.dos2unix = 0;
 
 	/* reset getopt and set progname. */
-	g_progname = argv[0];
 	opterr = 1;
 	optarg = NULL;
@@ -192,11 +214,11 @@
 		switch(ch) {
 		case 'B':
-			suffix = optarg;
+			This.suffix = optarg;
 			/* FALLTHROUGH */
 		case 'b':
-			dobackup = 1;
+			This.dobackup = 1;
 			break;
 		case 'C':
-			docompare = 1;
+			This.docompare = 1;
 			break;
 		case 'c':
@@ -204,5 +226,5 @@
 			break;
 		case 'd':
-			dodir = 1;
+			This.dodir = 1;
 			break;
 		case 'f':
@@ -210,5 +232,5 @@
 			flags = optarg;
 			if (strtofflags(&flags, &fset, NULL))
-				return errx(EX_USAGE, "%s: invalid flag", flags);
+				return errx(pCtx, EX_USAGE, "%s: invalid flag", flags);
 			iflags |= SETFLAGS;
 #else
@@ -220,13 +242,12 @@
 			break;
 		case 'M':
-			nommap = 1;
+			This.nommap = 1;
 			break;
                 case 'm':
 			if (!(set = bsd_setmode(optarg)))
-				return errx(EX_USAGE, "invalid file mode: %s",
-				            optarg);
-			mode = bsd_getmode(set, 0);
+				return errx(pCtx, EX_USAGE, "invalid file mode: %s", optarg);
+			This.mode = bsd_getmode(set, 0);
 			free(set);
-			mode_given = 1;
+			This.mode_given = 1;
 			break;
 		case 'o':
@@ -234,41 +255,41 @@
 			break;
 		case 'p':
-			docompare = dopreserve = 1;
+			This.docompare = This.dopreserve = 1;
 			break;
 		case 'S':
-			safecopy = 1;
+			This.safecopy = 1;
 			break;
 		case 's':
-			dostrip = 1;
+			This.dostrip = 1;
 			break;
 		case 'v':
-			verbose = 1;
+			This.verbose = 1;
 			break;
 		case 261:
-			usage(stdout);
+			usage(pCtx, 0);
 			return 0;
 		case 262:
 			return kbuild_version(argv[0]);
 		case 263:
-			ignore_perm_errors = 1;
+			This.ignore_perm_errors = 1;
 			break;
 		case 264:
-			ignore_perm_errors = 0;
+			This.ignore_perm_errors = 0;
 			break;
                 case 265:
-                        hard_link_files_when_possible = 1;
+                        This.hard_link_files_when_possible = 1;
                         break;
                 case 266:
-                        hard_link_files_when_possible = 0;
+                        This.hard_link_files_when_possible = 0;
                         break;
 		case 267:
-			dos2unix = 1;
+			This.dos2unix = 1;
 			break;
 		case 268:
-			dos2unix = -1;
+			This.dos2unix = -1;
 			break;
 		case '?':
 		default:
-			return usage(stderr);
+			return usage(pCtx, 1);
 		}
 	argc -= optind;
@@ -276,28 +297,28 @@
 
 	/* some options make no sense when creating directories */
-	if (dostrip && dodir) {
-		warnx("-d and -s may not be specified together");
-		return usage(stderr);
+	if (This.dostrip && This.dodir) {
+		warnx(pCtx, "-d and -s may not be specified together");
+		return usage(pCtx, 1);
 	}
 
 	/* must have at least two arguments, except when creating directories */
-	if (argc == 0 || (argc == 1 && !dodir))
-		return usage(stderr);
+	if (argc == 0 || (argc == 1 && !This.dodir))
+		return usage(pCtx, 1);
 
 	/*   and unix2dos doesn't combine well with a couple of other options. */
-	if (dos2unix != 0) {
-		if (docompare) {
-			warnx("-C/-p and --dos2unix/unix2dos may not be specified together");
-			return usage(stderr);
-		}
-		if (dostrip) {
-			warnx("-s and --dos2unix/unix2dos may not be specified together");
-			return usage(stderr);
+	if (This.dos2unix != 0) {
+		if (This.docompare) {
+			warnx(pCtx, "-C/-p and --dos2unix/unix2dos may not be specified together");
+			return usage(pCtx, 1);
+		}
+		if (This.dostrip) {
+			warnx(pCtx, "-s and --dos2unix/unix2dos may not be specified together");
+			return usage(pCtx, 1);
 		}
 	}
 
 	/* need to make a temp copy so we can compare stripped version */
-	if (docompare && dostrip)
-		safecopy = 1;
+	if (This.docompare && This.dostrip)
+		This.safecopy = 1;
 
 	/* get group and owner id's */
@@ -310,10 +331,10 @@
 #endif
 		{
-			gid = (gid_t)numeric_id(group, "group");
-			if (gid == (gid_t)-1)
+			This.gid = (gid_t)numeric_id(&This, group, "group");
+			if (This.gid == (gid_t)-1)
 				return 1;
 		}
 	} else
-		gid = (gid_t)-1;
+		This.gid = (gid_t)-1;
 
 	if (owner != NULL) {
@@ -325,14 +346,14 @@
 #endif
 		{
-			uid = (uid_t)numeric_id(owner, "user");
-			if (uid == (uid_t)-1)
+			This.uid = (uid_t)numeric_id(&This, owner, "user");
+			if (This.uid == (uid_t)-1)
 				return 1;
 		}
 	} else
-		uid = (uid_t)-1;
-
-	if (dodir) {
+		This.uid = (uid_t)-1;
+
+	if (This.dodir) {
 		for (; *argv != NULL; ++argv) {
-			int rc = install_dir(*argv);
+			int rc = install_dir(&This, *argv);
 			if (rc)
 				return rc;
@@ -345,5 +366,5 @@
 	if (!no_target && S_ISDIR(to_sb.st_mode)) {
 		for (; *argv != to_name; ++argv) {
-			int rc = install(*argv, to_name, fset, iflags | DIRECTORY);
+			int rc = install(&This, *argv, to_name, fset, iflags | DIRECTORY);
 			if (rc)
 				return rc;
@@ -354,14 +375,14 @@
 	/* can't do file1 file2 directory/file */
 	if (argc != 2) {
-		warnx("wrong number or types of arguments");
-		return usage(stderr);
+		warnx(pCtx, "wrong number or types of arguments");
+		return usage(pCtx, 1);
 	}
 
 	if (!no_target) {
 		if (stat(*argv, &from_sb))
-			return err(EX_OSERR, "%s", *argv);
+			return err(pCtx, EX_OSERR, "%s", *argv);
 		if (!S_ISREG(to_sb.st_mode)) {
 			errno = EFTYPE;
-			return err(EX_OSERR, "%s", to_name);
+			return err(pCtx, EX_OSERR, "%s", to_name);
 		}
 		if (to_sb.st_dev == from_sb.st_dev &&
@@ -369,13 +390,21 @@
 		    to_sb.st_ino == from_sb.st_ino &&
 		    to_sb.st_ino != 0 &&
-		    !hard_link_files_when_possible)
-			return errx(EX_USAGE,
+		    !This.hard_link_files_when_possible)
+			return errx(pCtx, EX_USAGE,
 			            "%s and %s are the same file", *argv, to_name);
 	}
-	return install(*argv, to_name, fset, iflags);
-}
+	return install(&This, *argv, to_name, fset, iflags);
+}
+
+#ifdef KMK_BUILTIN_STANDALONE
+int main(int argc, char **argv, char **envp)
+{
+	KMKBUILTINCTX Ctx = { "kmk_install", NULL };
+	return kmk_builtin_install(argc, argv, envp, &Ctx);
+}
+#endif
 
 static u_long
-numeric_id(const char *name, const char *type)
+numeric_id(PINSTALLINSTANCE pThis, const char *name, const char *type)
 {
 	u_long val;
@@ -389,7 +418,7 @@
 	val = strtoul(name, &ep, 10);
 	if (errno)
-		return err(-1, "%s", name);
+		return err(pThis->pCtx, -1, "%s", name);
 	if (*ep != '\0')
-		return errx(-1, "unknown %s %s", type, name);
+		return errx(pThis->pCtx, -1, "unknown %s %s", type, name);
 	return (val);
 }
@@ -400,5 +429,5 @@
  */
 static int
-install(const char *from_name, const char *to_name, u_long fset, u_int flags)
+install(PINSTALLINSTANCE pThis, const char *from_name, const char *to_name, u_long fset, u_int flags)
 {
 	struct stat from_sb, temp_sb, to_sb;
@@ -428,8 +457,8 @@
 	    ) {
 		if (stat(from_name, &from_sb))
-			return err(EX_OSERR, "%s", from_name);
+			return err(pThis->pCtx, EX_OSERR, "%s", from_name);
 		if (!S_ISREG(from_sb.st_mode)) {
 			errno = EFTYPE;
-			return err(EX_OSERR, "%s", from_name);
+			return err(pThis->pCtx, EX_OSERR, "%s", from_name);
 		}
 		/* Build the target path. */
@@ -450,13 +479,13 @@
 	if (target && !S_ISREG(to_sb.st_mode)) {
 		errno = EFTYPE;
-		warn("%s", to_name);
+		warn(pThis->pCtx, "%s", to_name);
 		return EX_OK;
 	}
 
 	/* Only copy safe if the target exists. */
-	tempcopy = safecopy && target;
+	tempcopy = pThis->safecopy && target;
 
 	/* Try hard linking if wanted and possible. */
-	if (hard_link_files_when_possible)
+	if (pThis->hard_link_files_when_possible)
 	{
 #ifdef KBUILD_OS_OS2
@@ -466,11 +495,11 @@
 		if (devnull) {
 			why_not = "/dev/null";
-		} else if (dostrip) {
+		} else if (pThis->dostrip) {
 			why_not = "strip (-s)";
-		} else if (docompare) {
+		} else if (pThis->docompare) {
 			why_not = "compare (-C)";
-		} else if (dobackup) {
+		} else if (pThis->dobackup) {
 			why_not = "backup (-b/-B)";
-		} else if (safecopy) {
+		} else if (pThis->safecopy) {
 			why_not = "safe copy (-S)";
 		} else if (lstat(from_name, &temp_sb)) {
@@ -481,20 +510,21 @@
 			why_not = "not regular file";
 # if defined(KBUILD_OS_WINDOWS) || defined(KBUILD_OS_OS2)
-		} else if ((mode & S_IWUSR) != (from_sb.st_mode & S_IWUSR)) {
+		} else if ((pThis->mode & S_IWUSR) != (from_sb.st_mode & S_IWUSR)) {
 # else
-		} else if (mode != (from_sb.st_mode & ALLPERMS)) {
+		} else if (pThis->mode != (from_sb.st_mode & ALLPERMS)) {
 # endif
-			printf("install: warning: Not hard linking, mode differs: 0%03o, desires 0%03o\n"
-			       "install: src path '%s'\n"
-			       "install: dst path '%s'\n",
-			       (from_sb.st_mode & ALLPERMS), mode, from_name, to_name);
+			kmk_builtin_ctx_printf(pThis->pCtx, 0,
+				"install: warning: Not hard linking, mode differs: 0%03o, desires 0%03o\n"
+				"install: src path '%s'\n"
+				"install: dst path '%s'\n",
+				(from_sb.st_mode & ALLPERMS), pThis->mode, from_name, to_name);
 			why_not = NULL;
-		} else if (uid != (uid_t)-1 && gid != from_sb.st_uid) {
+		} else if (pThis->uid != (uid_t)-1 && pThis->uid != from_sb.st_uid) {
 			why_not = "uid mismatch";
-		} else if (gid != (gid_t)-1 && gid != from_sb.st_gid) {
+		} else if (pThis->gid != (gid_t)-1 && pThis->gid != from_sb.st_gid) {
 			why_not = "gid mismatch";
-		} else if (dos2unix > 0 && needs_dos2unix_conversion(from_name)) {
+		} else if (pThis->dos2unix > 0 && needs_dos2unix_conversion(from_name)) {
 			why_not = "dos2unix";
-		} else if (dos2unix < 0 && needs_unix2dos_conversion(from_name)) {
+		} else if (pThis->dos2unix < 0 && needs_unix2dos_conversion(from_name)) {
 			why_not = "unix2dos";
 		} else {
@@ -505,17 +535,18 @@
 			}
 			if (rcLink == 0) {
-			    if (verbose)
-				    printf("install: %s -> %s (hardlinked)\n", from_name, to_name);
+			    if (pThis->verbose)
+				    kmk_builtin_ctx_printf(pThis->pCtx, 0,
+							   "install: %s -> %s (hardlinked)\n", from_name, to_name);
 			    goto l_done;
 			}
-			if (verbose)
-				printf("install: hard linking '%s' to '%s' failed: %s\n",
+			if (pThis->verbose)
+				kmk_builtin_ctx_printf(pThis->pCtx, 0, "install: hard linking '%s' to '%s' failed: %s\n",
 				       to_name, from_name, strerror(errno));
 			why_not = NULL;
 		}
 #endif
-		if (verbose && why_not)
-		    printf("install: not hard linking '%s' to '%s' because: %s\n",
-			   to_name, from_name, why_not);
+		if (pThis->verbose && why_not)
+		    kmk_builtin_ctx_printf(pThis->pCtx, 0, "install: not hard linking '%s' to '%s' because: %s\n",
+					   to_name, from_name, why_not);
 
 		/* Can't hard link or we failed, continue as nothing happend. */
@@ -523,10 +554,10 @@
 
 	if (!devnull && (from_fd = open(from_name, O_RDONLY | O_BINARY, 0)) < 0)
-		return err(EX_OSERR, "%s", from_name);
+		return err(pThis->pCtx, EX_OSERR, "%s", from_name);
 
 	/* If we don't strip, we can compare first. */
-	if (docompare && !dostrip && target) {
+	if (pThis->docompare && !pThis->dostrip && target) {
 		if ((to_fd = open(to_name, O_RDONLY | O_BINARY, 0)) < 0) {
-			rc = err(EX_OSERR, "%s", to_name);
+			rc = err(pThis->pCtx, EX_OSERR, "%s", to_name);
 			goto l_done;
 		}
@@ -549,19 +580,17 @@
 			    sizeof(tempfile));
 			if (to_fd < 0) {
-				rc = err(EX_OSERR, "%s", tempfile);
+				rc = err(pThis->pCtx, EX_OSERR, "%s", tempfile);
 				goto l_done;
 			}
 		} else {
-			if ((to_fd = create_newfile(to_name, target,
-			    &to_sb)) < 0) {
-				rc = err(EX_OSERR, "%s", to_name);
+			if ((to_fd = create_newfile(pThis, to_name, target, &to_sb)) < 0) {
+				rc = err(pThis->pCtx, EX_OSERR, "%s", to_name);
 				goto l_done;
 			}
-			if (verbose)
-				(void)printf("install: %s -> %s\n",
-				    from_name, to_name);
+			if (pThis->verbose)
+				kmk_builtin_ctx_printf(pThis->pCtx, 0, "install: %s -> %s\n", from_name, to_name);
 		}
 		if (!devnull) {
-			rc = copy(from_fd, from_name, &to_fd, tempcopy ? tempfile : to_name);
+			rc = copy(pThis, from_fd, from_name, &to_fd, tempcopy ? tempfile : to_name);
 			if (rc)
     				goto l_done;
@@ -569,5 +598,5 @@
 	}
 
-	if (dostrip) {
+	if (pThis->dostrip) {
 #if defined(__EMX__) || defined(_MSC_VER)
 		/* close before we strip. */
@@ -575,5 +604,5 @@
 		to_fd = -1;
 #endif
-		rc = strip(tempcopy ? tempfile : to_name);
+		rc = strip(pThis, tempcopy ? tempfile : to_name);
 		if (rc)
 			goto l_done;
@@ -588,5 +617,5 @@
 		to_fd = open(tempcopy ? tempfile : to_name, O_RDONLY | O_BINARY, 0);
 		if (to_fd < 0) {
-			rc = err(EX_OSERR, "stripping %s", to_name);
+			rc = err(pThis->pCtx, EX_OSERR, "stripping %s", to_name);
 			goto l_done;
 		}
@@ -596,10 +625,10 @@
 	 * Compare the stripped temp file with the target.
 	 */
-	if (docompare && dostrip && target) {
+	if (pThis->docompare && pThis->dostrip && target) {
 		temp_fd = to_fd;
 
 		/* Re-open to_fd using the real target name. */
 		if ((to_fd = open(to_name, O_RDONLY | O_BINARY, 0)) < 0) {
-			rc = err(EX_OSERR, "%s", to_name);
+			rc = err(pThis->pCtx, EX_OSERR, "%s", to_name);
 			goto l_done;
 		}
@@ -609,5 +638,5 @@
 			(void)unlink(tempfile);
 			errno = serrno;
-			rc = err(EX_OSERR, "%s", tempfile);
+			rc = err(pThis->pCtx, EX_OSERR, "%s", tempfile);
 			goto l_done;
 		}
@@ -649,31 +678,30 @@
 			(void)chflags(to_name, to_sb.st_flags & ~NOCHANGEBITS);
 #endif
-		if (dobackup) {
-			if ((size_t)snprintf(backup, MAXPATHLEN, "%s%s", to_name,
-			    suffix) != strlen(to_name) + strlen(suffix)) {
+		if (pThis->dobackup) {
+			if (   (size_t)snprintf(backup, MAXPATHLEN, "%s%s", to_name, pThis->suffix)
+			    != strlen(to_name) + strlen(pThis->suffix)) {
 				unlink(tempfile);
-				rc = errx(EX_OSERR, "%s: backup filename too long",
+				rc = errx(pThis->pCtx, EX_OSERR, "%s: backup filename too long",
 				          to_name);
 				goto l_done;
 			}
-			if (verbose)
-				(void)printf("install: %s -> %s\n", to_name, backup);
+			if (pThis->verbose)
+				kmk_builtin_ctx_printf(pThis->pCtx, 0, "install: %s -> %s\n", to_name, backup);
 			if (rename(to_name, backup) < 0) {
 				serrno = errno;
 				unlink(tempfile);
 				errno = serrno;
-				rc = err(EX_OSERR, "rename: %s to %s", to_name,
+				rc = err(pThis->pCtx, EX_OSERR, "rename: %s to %s", to_name,
 				         backup);
 				goto l_done;
 			}
 		}
-		if (verbose)
-			(void)printf("install: %s -> %s\n", from_name, to_name);
+		if (pThis->verbose)
+			kmk_builtin_ctx_printf(pThis->pCtx, 0, "install: %s -> %s\n", from_name, to_name);
 		if (rename(tempfile, to_name) < 0) {
 			serrno = errno;
 			unlink(tempfile);
 			errno = serrno;
-			rc = err(EX_OSERR, "rename: %s to %s",
-			         tempfile, to_name);
+			rc = err(pThis->pCtx, EX_OSERR, "rename: %s to %s", tempfile, to_name);
 			goto l_done;
 		}
@@ -682,5 +710,5 @@
 		(void) close(to_fd);
 		if ((to_fd = open(to_name, O_RDONLY | O_BINARY, 0)) < 0) {
-			rc = err(EX_OSERR, "%s", to_name);
+			rc = err(pThis->pCtx, EX_OSERR, "%s", to_name);
 			goto l_done;
 		}
@@ -690,5 +718,5 @@
 	 * Preserve the timestamp of the source file if necessary.
 	 */
-	if (dopreserve && !files_match && !devnull) {
+	if (pThis->dopreserve && !files_match && !devnull) {
 		tvb[0].tv_sec = from_sb.st_atime;
 		tvb[0].tv_usec = 0;
@@ -702,5 +730,5 @@
 		(void)unlink(to_name);
 		errno = serrno;
-		rc = err(EX_OSERR, "%s", to_name);
+		rc = err(pThis->pCtx, EX_OSERR, "%s", to_name);
 		goto l_done;
 	}
@@ -720,30 +748,31 @@
 #endif
 
-	if ((gid != (gid_t)-1 && gid != to_sb.st_gid) ||
-	    (uid != (uid_t)-1 && uid != to_sb.st_uid))
-		if (fchown(to_fd, uid, gid) == -1) {
-    			if (errno == EPERM && ignore_perm_errors) {
-				warn("%s: ignoring chown uid=%d gid=%d failure", to_name, (int)uid, (int)gid);
+	if ((pThis->gid != (gid_t)-1 && pThis->gid != to_sb.st_gid) ||
+	    (pThis->uid != (uid_t)-1 && pThis->uid != to_sb.st_uid))
+		if (fchown(to_fd, pThis->uid, pThis->gid) == -1) {
+    			if (errno == EPERM && pThis->ignore_perm_errors) {
+				warn(pThis->pCtx, "%s: ignoring chown uid=%d gid=%d failure",
+				     to_name, (int)pThis->uid, (int)pThis->gid);
 			} else {
 				serrno = errno;
 				(void)unlink(to_name);
 				errno = serrno;
-				rc = err(EX_OSERR,"%s: chown/chgrp", to_name);
+				rc = err(pThis->pCtx, EX_OSERR,"%s: chown/chgrp", to_name);
 				goto l_done;
 			}
 		}
 
-	if (mode != (to_sb.st_mode & ALLPERMS))
-		if (fchmod(to_fd, mode)) {
+	if (pThis->mode != (to_sb.st_mode & ALLPERMS))
+		if (fchmod(to_fd, pThis->mode)) {
 			serrno = errno;
-			if (serrno == EPERM && ignore_perm_errors) {
-				fchmod(to_fd, mode & (ALLPERMS & ~0007000));
+			if (serrno == EPERM && pThis->ignore_perm_errors) {
+				fchmod(to_fd, pThis->mode & (ALLPERMS & ~0007000));
 				errno = errno;
-				warn("%s: ignoring chmod 0%o failure", to_name, (int)(mode & ALLPERMS));
+				warn(pThis->pCtx, "%s: ignoring chmod 0%o failure", to_name, (int)(pThis->mode & ALLPERMS));
 			} else  {
 				serrno = errno;
 				(void)unlink(to_name);
 				errno = serrno;
-				rc = err(EX_OSERR, "%s: chmod", to_name);
+				rc = err(pThis->pCtx, EX_OSERR, "%s: chmod", to_name);
 				goto l_done;
 			}
@@ -758,16 +787,15 @@
 	 */
 #ifdef UF_IMMUTABLE
-	if (!devnull && (flags & SETFLAGS ||
-	    (from_sb.st_flags & ~UF_NODUMP) != to_sb.st_flags) &&
-	    fchflags(to_fd,
-	    flags & SETFLAGS ? fset : from_sb.st_flags & ~UF_NODUMP)) {
+	if (   !devnull
+	    && (flags & SETFLAGS || (from_sb.st_flags & ~UF_NODUMP) != to_sb.st_flags)
+	    && fchflags(to_fd, flags & SETFLAGS ? fset : from_sb.st_flags & ~UF_NODUMP)) {
 		if (flags & SETFLAGS) {
 			if (errno == EOPNOTSUPP)
-				warn("%s: chflags", to_name);
+				warn(pThis->pCtx, "%s: chflags", to_name);
 			else {
 				serrno = errno;
 				(void)unlink(to_name);
 				errno = serrno;
-				rc = err(EX_OSERR, "%s: chflags", to_name);
+				rc = err(pThis->pCtx, EX_OSERR, "%s: chflags", to_name);
 				goto l_done;
 			}
@@ -851,5 +879,5 @@
  */
 int
-create_newfile(const char *path, int target, struct stat *sbp)
+create_newfile(PINSTALLINSTANCE pThis, const char *path, int target, struct stat *sbp)
 {
 	char backup[MAXPATHLEN];
@@ -868,19 +896,16 @@
 #endif
 
-		if (dobackup) {
-			if ((size_t)snprintf(backup, MAXPATHLEN, "%s%s",
-			    path, suffix) != strlen(path) + strlen(suffix)) {
-				errx(EX_OSERR, "%s: backup filename too long",
-				     path);
+		if (pThis->dobackup) {
+			if (   (size_t)snprintf(backup, MAXPATHLEN, "%s%s", path, pThis->suffix)
+			    != strlen(path) + strlen(pThis->suffix)) {
+				errx(pThis->pCtx, EX_OSERR, "%s: backup filename too long", path);
 				errno = ENAMETOOLONG;
 				return -1;
 			}
-			(void)snprintf(backup, MAXPATHLEN, "%s%s",
-			    path, suffix);
-			if (verbose)
-				(void)printf("install: %s -> %s\n",
-				    path, backup);
+			(void)snprintf(backup, MAXPATHLEN, "%s%s", path, pThis->suffix);
+			if (pThis->verbose)
+				kmk_builtin_ctx_printf(pThis->pCtx, 0, "install: %s -> %s\n", path, backup);
 			if (rename(path, backup) < 0) {
-				err(EX_OSERR, "rename: %s to %s", path, backup);
+				err(pThis->pCtx, EX_OSERR, "rename: %s to %s", path, backup);
 				return -1;
 			}
@@ -899,5 +924,5 @@
  * Write error handler.
  */
-static int write_error(int *ptr_to_fd, const char *to_name, int nw)
+static int write_error(PINSTALLINSTANCE pThis, int *ptr_to_fd, const char *to_name, int nw)
 {
     int serrno = errno;
@@ -906,5 +931,5 @@
     (void)unlink(to_name);
     errno = nw > 0 ? EIO : serrno;
-    return err(EX_OSERR, "%s", to_name);
+    return err(pThis->pCtx, EX_OSERR, "%s", to_name);
 }
 
@@ -912,5 +937,5 @@
  * Read error handler.
  */
-static int read_error(const char *from_name, int *ptr_to_fd, const char *to_name)
+static int read_error(PINSTALLINSTANCE pThis, const char *from_name, int *ptr_to_fd, const char *to_name)
 {
     int serrno = errno;
@@ -919,5 +944,5 @@
     (void)unlink(to_name);
     errno = serrno;
-    return err(EX_OSERR, "%s", from_name);
+    return err(pThis->pCtx, EX_OSERR, "%s", from_name);
 }
 
@@ -927,5 +952,5 @@
  */
 static int
-copy(int from_fd, const char *from_name, int *ptr_to_fd, const char *to_name)
+copy(PINSTALLINSTANCE pThis, int from_fd, const char *from_name, int *ptr_to_fd, const char *to_name)
 {
 	KBOOL fPendingCr = K_FALSE;
@@ -937,9 +962,9 @@
 	/* Rewind file descriptors. */
 	if (lseek(from_fd, (off_t)0, SEEK_SET) == (off_t)-1)
-		return err(EX_OSERR, "lseek: %s", from_name);
+		return err(pThis->pCtx, EX_OSERR, "lseek: %s", from_name);
 	if (lseek(to_fd, (off_t)0, SEEK_SET) == (off_t)-1)
-		return err(EX_OSERR, "lseek: %s", to_name);
-
-	if (dos2unix == 0) {
+		return err(pThis->pCtx, EX_OSERR, "lseek: %s", to_name);
+
+	if (pThis->dos2unix == 0) {
 		/*
 		 * Copy bytes, no conversion.
@@ -947,6 +972,6 @@
 		while ((nr = read(from_fd, buf, sizeof(buf))) > 0)
 			if ((nw = write(to_fd, buf, nr)) != nr)
-				return write_error(ptr_to_fd, to_name, nw);
-	} else if (dos2unix > 0) {
+				return write_error(pThis, ptr_to_fd, to_name, nw);
+	} else if (pThis->dos2unix > 0) {
 		/*
 		 * CRLF -> LF is a reduction, so we can work with full buffers.
@@ -956,5 +981,5 @@
 				&& buf[0] != '\n'
 				&& (nw = write(to_fd, "\r", 1)) != 1)
-				return write_error(ptr_to_fd, to_name, nw);
+				return write_error(pThis, ptr_to_fd, to_name, nw);
 
 			fPendingCr = dos2unix_convert_to_unix(buf, nr, buf, &cchDst);
@@ -962,5 +987,5 @@
 			nw = write(to_fd, buf, cchDst);
 			if (nw != (int)cchDst)
-				return write_error(ptr_to_fd, to_name, nw);
+				return write_error(pThis, ptr_to_fd, to_name, nw);
 		}
 	} else {
@@ -978,5 +1003,5 @@
 				&& pchSrc[0] != '\n'
 				&& (nw = write(to_fd, "\r", 1))!= 1)
-				return write_error(ptr_to_fd, to_name, nw);
+				return write_error(pThis, ptr_to_fd, to_name, nw);
 
 			fPendingCr = dos2unix_convert_to_dos(pchSrc, nr, buf, &cchDst);
@@ -984,5 +1009,5 @@
 			nw = write(to_fd, buf, cchDst);
 			if (nw != (int)cchDst)
-				return write_error(ptr_to_fd, to_name, nw);
+				return write_error(pThis, ptr_to_fd, to_name, nw);
 		}
 	}
@@ -990,10 +1015,10 @@
 	/* Check for read error. */
 	if (nr != 0)
-		return read_error(from_name, ptr_to_fd, to_name);
+		return read_error(pThis, from_name, ptr_to_fd, to_name);
 
 	/* When converting, we might have a pending final CR to write. */
-    if (   fPendingCr
-		&& (nw = write(to_fd, "\r", 1))!= 1)
-		return write_error(ptr_to_fd, to_name, nw);
+	if (   fPendingCr
+	    && (nw = write(to_fd, "\r", 1))!= 1)
+		return write_error(pThis, ptr_to_fd, to_name, nw);
 
     return EX_OK;
@@ -1005,5 +1030,5 @@
  */
 static int
-strip(const char *to_name)
+strip(PINSTALLINSTANCE pThis, const char *to_name)
 {
 #if defined(__EMX__) || defined(_MSC_VER)
@@ -1011,4 +1036,5 @@
 	if (stripbin == NULL)
 		stripbin = "strip";
+	(void)pThis;
 	return spawnlp(P_WAIT, stripbin, stripbin, to_name, NULL);
 #else
@@ -1023,5 +1049,5 @@
 		(void)unlink(to_name);
 		errno = serrno;
-		return err(EX_TEMPFAIL, "fork");
+		return err(pThis->pCtx, EX_TEMPFAIL, "fork");
 	case 0:
 		stripbin = getenv("STRIPBIN");
@@ -1029,5 +1055,5 @@
 			stripbin = "strip";
 		execlp(stripbin, stripbin, to_name, (char *)NULL);
-		err(EX_OSERR, "exec(%s)", stripbin);
+		err(pThis->pCtx, EX_OSERR, "exec(%s)", stripbin);
                 exit(EX_OSERR);
 	default:
@@ -1036,5 +1062,5 @@
 			(void)unlink(to_name);
                         errno = serrno;
-			return err(EX_SOFTWARE, "waitpid");
+			return err(pThis->pCtx, EX_SOFTWARE, "waitpid");
 			/* NOTREACHED */
 		}
@@ -1049,5 +1075,5 @@
  */
 static int
-install_dir(char *path)
+install_dir(PINSTALLINSTANCE pThis, char *path)
 {
 	char *p;
@@ -1067,19 +1093,18 @@
 			if (stat(path, &sb)) {
 				if (errno != ENOENT || mkdir(path, 0755) < 0) {
-					return err(EX_OSERR, "mkdir %s", path);
+					return err(pThis->pCtx, EX_OSERR, "mkdir %s", path);
 					/* NOTREACHED */
-				} else if (verbose)
-					(void)printf("install: mkdir %s\n",
-						     path);
+				} else if (pThis->verbose)
+					kmk_builtin_ctx_printf(pThis->pCtx, 0, "install: mkdir %s\n", path);
 			} else if (!S_ISDIR(sb.st_mode))
-				return errx(EX_OSERR, "%s exists but is not a directory", path);
+				return errx(pThis->pCtx, EX_OSERR, "%s exists but is not a directory", path);
 			if (!(*p = ch))
 				break;
  		}
 
-	if ((gid != (gid_t)-1 || uid != (uid_t)-1) && chown(path, uid, gid))
-		warn("chown %u:%u %s", uid, gid, path);
-	if (chmod(path, mode))
-		warn("chmod %o %s", mode, path);
+	if ((pThis->gid != (gid_t)-1 || pThis->uid != (uid_t)-1) && chown(path, pThis->uid, pThis->gid))
+		warn(pThis->pCtx, "chown %u:%u %s", pThis->uid, pThis->gid, path);
+	if (chmod(path, pThis->mode))
+		warn(pThis->pCtx, "chmod %o %s", pThis->mode, path);
 	return EX_OK;
 }
@@ -1090,7 +1115,7 @@
  */
 static int
-usage(FILE *pf)
-{
-	fprintf(pf,
+usage(PKMKBUILTINCTX pCtx, int fIsErr)
+{
+	kmk_builtin_ctx_printf(pCtx, fIsErr,
 "usage: %s [-bCcpSsv] [--[no-]hard-link-files-when-possible]\n"
 "            [--[no-]ignore-perm-errors] [-B suffix] [-f flags] [-g group]\n"
@@ -1101,5 +1126,6 @@
 "   or: %s --help\n"
 "   or: %s --version\n",
-			g_progname, g_progname, g_progname, g_progname, g_progname);
+		pCtx->pszProgName, pCtx->pszProgName, pCtx->pszProgName,
+		pCtx->pszProgName, pCtx->pszProgName);
 	return EX_USAGE;
 }
Index: trunk/src/kmk/kmkbuiltin/kDepIDB.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/kDepIDB.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/kDepIDB.c	(revision 3192)
@@ -46,4 +46,5 @@
 #include "k/kTypes.h"
 #include "kDep.h"
+#include "err.h"
 #include "kmkbuiltin.h"
 
@@ -66,6 +67,6 @@
 typedef struct KDEPIDBGLOBALS
 {
+    PKMKBUILTINCTX pCtx;
     DEPGLOBALS  Core;
-    const char *argv0;
 } KDEPIDBGLOBALS;
 typedef KDEPIDBGLOBALS *PKDEPIDBGLOBALS;
@@ -197,20 +198,11 @@
 {
     if (pHdr->cbPage * pHdr->cPages != cbFile)
-    {
-        fprintf(stderr, "%s: error: Bad PDB 2.0 header - cbPage * cPages != cbFile.\n", pThis->argv0);
-        return 1;
-    }
+        return errx(pThis->pCtx, 1, "Bad PDB 2.0 header - cbPage * cPages != cbFile.");
     if (pHdr->iStartPage >= pHdr->cPages && pHdr->iStartPage <= 0)
-    {
-        fprintf(stderr, "%s: error: Bad PDB 2.0 header - iStartPage=%u cPages=%u.\n", pThis->argv0,
-                pHdr->iStartPage, pHdr->cPages);
-        return 1;
-    }
+        return errx(pThis->pCtx, 1, "Bad PDB 2.0 header - iStartPage=%u cPages=%u.",
+                    pHdr->iStartPage, pHdr->cPages);
     if (pHdr->iRootPages >= pHdr->cPages && pHdr->iRootPages <= 0)
-    {
-        fprintf(stderr, "%s: error: Bad PDB 2.0 header - iRootPages=%u cPage=%u.\n", pThis->argv0,
-                pHdr->iStartPage, pHdr->cPages);
-        return 1;
-    }
+        return errx(pThis->pCtx, 1, "Bad PDB 2.0 header - iRootPages=%u cPage=%u.",
+                    pHdr->iStartPage, pHdr->cPages);
     return 0;
 }
@@ -251,6 +243,5 @@
             else
             {
-                fprintf(stderr, "%s: warning: Invalid page index %u (max %u)!\n", pThis->argv0,
-                        (unsigned)off, pHdr->cPages);
+                warnx(pThis->pCtx, "warning: Invalid page index %u (max %u)!\n", (unsigned)off, pHdr->cPages);
                 memset(pbBuf + iPage * cbPage, 0, cbPage);
             }
@@ -261,5 +252,8 @@
     }
     else
-        fprintf(stderr, "%s: error: failed to allocate %lu bytes\n", pThis->argv0, (unsigned long)(cPages * cbPage + 1));
+    {
+        errx(pThis->pCtx, 1, "failed to allocate %lu bytes", (unsigned long)(cPages * cbPage + 1));
+        return NULL;
+    }
     return pbBuf;
 }
@@ -311,5 +305,5 @@
         ||  cbStream == ~(KU32)0)
     {
-        fprintf(stderr, "%s: error: Invalid stream %d\n", pThis->argv0, iStream);
+        errx(pThis->pCtx, 1, "Invalid stream %d", iStream);
         return NULL;
     }
@@ -493,13 +487,7 @@
 {
     if (pHdr->cbPage * pHdr->cPages != cbFile)
-    {
-        fprintf(stderr, "%s: error: Bad PDB 2.0 header - cbPage * cPages != cbFile.\n", pThis->argv0);
-        return 1;
-    }
+        return errx(pThis->pCtx, 1, "Bad PDB 2.0 header - cbPage * cPages != cbFile.");
     if (pHdr->iStartPage >= pHdr->cPages && pHdr->iStartPage <= 0)
-    {
-        fprintf(stderr, "%s: error: Bad PDB 2.0 header - cbPage * cPages != cbFile.\n", pThis->argv0);
-        return 1;
-    }
+        return errx(pThis->pCtx, 1, "Bad PDB 2.0 header - cbPage * cPages != cbFile.");
     return 0;
 }
@@ -529,5 +517,5 @@
     }
     else
-        fprintf(stderr, "%s: error: failed to allocate %lu bytes\n", pThis->argv0, (unsigned long)(cPages * pHdr->cbPage + 1));
+        errx(pThis->pCtx, 1, "failed to allocate %lu bytes", (unsigned long)(cPages * pHdr->cbPage + 1));
     return pbBuf;
 }
@@ -573,5 +561,5 @@
         ||  cbStream == ~(KU32)0)
     {
-        fprintf(stderr, "%s: error: Invalid stream %d\n", pThis->argv0, iStream);
+        errx(pThis->pCtx, 1, "Invalid stream %d", iStream);
         return NULL;
     }
@@ -653,8 +641,5 @@
         rc = Pdb20Process(pThis, pbFile, cbFile);
     else
-    {
-        fprintf(stderr, "%s: error: Doesn't recognize the header of the Visual C++ IDB file.\n", pThis->argv0);
-        rc = 1;
-    }
+        rc = errx(pThis->pCtx, 1, "Doesn't recognize the header of the Visual C++ IDB file.");
 
     depFreeFileMemory(pbFile, pvOpaque);
@@ -663,14 +648,15 @@
 
 
-static void kDepIDBUsage(const char *a_argv0)
-{
-    printf("usage: %s -o <output> -t <target> [-fqs] <vc idb-file>\n"
-           "   or: %s --help\n"
-           "   or: %s --version\n",
-           a_argv0, a_argv0, a_argv0);
-}
-
-
-int kmk_builtin_kDepIDB(int argc, char *argv[], char **envp)
+static void kDepIDBUsage(PKMKBUILTINCTX pCtx, int fIsErr)
+{
+    kmk_builtin_ctx_printf(pCtx, fIsErr,
+                           "usage: %s -o <output> -t <target> [-fqs] <vc idb-file>\n"
+                           "   or: %s --help\n"
+                           "   or: %s --version\n",
+                           pCtx->pszProgName, pCtx->pszProgName, pCtx->pszProgName);
+}
+
+
+int kmk_builtin_kDepIDB(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx)
 {
     int             i;
@@ -689,5 +675,5 @@
 
     /* Init the instance data. */
-    This.argv0 = argv[0];
+    This.pCtx = pCtx;
 
     /*
@@ -696,5 +682,5 @@
     if (argc <= 1)
     {
-        kDepIDBUsage(This.argv0);
+        kDepIDBUsage(pCtx, 0);
         return 1;
     }
@@ -723,15 +709,9 @@
                     pszOutput = &argv[i][2];
                     if (pOutput)
-                    {
-                        fprintf(stderr, "%s: syntax error: only one output file!\n", This.argv0);
-                        return 1;
-                    }
+                        return errx(pCtx, 2, "only one output file!");
                     if (!*pszOutput)
                     {
                         if (++i >= argc)
-                        {
-                            fprintf(stderr, "%s: syntax error: The '-o' argument is missing the filename.\n", This.argv0);
-                            return 1;
-                        }
+                            return errx(pCtx, 2, "The '-o' argument is missing the filename.");
                         pszOutput = argv[i];
                     }
@@ -741,8 +721,5 @@
                         pOutput = fopen(pszOutput, "w" KMK_FOPEN_NO_INHERIT_MODE);
                     if (!pOutput)
-                    {
-                        fprintf(stderr, "%s: error: Failed to create output file '%s'.\n", This.argv0, pszOutput);
-                        return 1;
-                    }
+                        return err(pCtx, 1, "Failed to create output file '%s'", pszOutput);
                     break;
                 }
@@ -754,16 +731,10 @@
                 {
                     if (pszTarget)
-                    {
-                        fprintf(stderr, "%s: syntax error: only one target!\n", This.argv0);
-                        return 1;
-                    }
+                        return errx(pCtx, 2, "only one target!");
                     pszTarget = &argv[i][2];
                     if (!*pszTarget)
                     {
                         if (++i >= argc)
-                        {
-                            fprintf(stderr, "%s: syntax error: The '-t' argument is missing the target name.\n", This.argv0);
-                            return 1;
-                        }
+                            return errx(pCtx, 2, "The '-t' argument is missing the target name.");
                         pszTarget = argv[i];
                     }
@@ -802,9 +773,9 @@
                  */
                 case '?':
-                    kDepIDBUsage(This.argv0);
+                    kDepIDBUsage(pCtx, 0);
                     return 0;
                 case 'V':
                 case 'v':
-                    return kbuild_version(This.argv0);
+                    return kbuild_version(pCtx->pszProgName);
 
                 /*
@@ -812,7 +783,7 @@
                  */
                 default:
-                    fprintf(stderr, "%s: syntax error: Invalid argument '%s'.\n", This.argv0, argv[i]);
-                    kDepIDBUsage(This.argv0);
-                    return 1;
+                    errx(pCtx, 2, "Invalid argument '%s.'", argv[i]);
+                    kDepIDBUsage(pCtx, 1);
+                    return 2;
             }
         }
@@ -821,8 +792,5 @@
             pInput = fopen(argv[i], "rb" KMK_FOPEN_NO_INHERIT_MODE);
             if (!pInput)
-            {
-                fprintf(stderr, "%s: error: Failed to open input file '%s'.\n", This.argv0, argv[i]);
-                return 1;
-            }
+                return err(pCtx, 1, "Failed to open input file '%s'", argv[i]);
             fInput = 1;
         }
@@ -834,8 +802,5 @@
         {
             if (++i < argc)
-            {
-                fprintf(stderr, "%s: syntax error: No arguments shall follow the input spec.\n", This.argv0);
-                return 1;
-            }
+                return errx(pCtx, 2, "No arguments shall follow the input spec.");
             break;
         }
@@ -846,18 +811,9 @@
      */
     if (!pInput)
-    {
-        fprintf(stderr, "%s: syntax error: No input!\n", This.argv0);
-        return 1;
-    }
+        return errx(pCtx, 2, "No input!");
     if (!pOutput)
-    {
-        fprintf(stderr, "%s: syntax error: No output!\n", This.argv0);
-        return 1;
-    }
+        return errx(pCtx, 2, "No output!");
     if (!pszTarget)
-    {
-        fprintf(stderr, "%s: syntax error: No target!\n", This.argv0);
-        return 1;
-    }
+        return errx(pCtx, 2, "No target!");
 
     /*
@@ -884,13 +840,10 @@
      */
     if (!i && ferror(pOutput))
-    {
-        i = 1;
-        fprintf(stderr, "%s: error: Error writing to '%s'.\n", This.argv0, pszOutput);
-    }
+        i = errx(pCtx, 1, "Error writing to '%s'.", pszOutput);
     fclose(pOutput);
     if (i)
     {
         if (unlink(pszOutput))
-            fprintf(stderr, "%s: warning: failed to remove output file '%s' on failure.\n", This.argv0, pszOutput);
+            warnx(pCtx, "warning: failed to remove output file '%s' on failure.", pszOutput);
     }
 
@@ -899,2 +852,10 @@
 }
 
+#ifdef KMK_BUILTIN_STANDALONE
+int main(int argc, char **argv, char **envp)
+{
+    KMKBUILTINCTX Ctx = { "kmk_kDepIDB", NULL };
+    return kmk_builtin_kDepIDB(argc, argv, envp, &Ctx);
+}
+#endif
+
Index: trunk/src/kmk/kmkbuiltin/kDepObj.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/kDepObj.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/kDepObj.c	(revision 3192)
@@ -39,4 +39,5 @@
 #else
 # include <io.h>
+typedef intptr_t ssize_t;
 #endif
 #include "k/kDefs.h"
@@ -44,4 +45,5 @@
 #include "k/kLdrFmts/pe.h"
 #include "kDep.h"
+#include "err.h"
 #include "kmkbuiltin.h"
 
@@ -170,8 +172,8 @@
 typedef struct KDEPOBJGLOBALS
 {
+    /** The command execution context. */
+    PKMKBUILTINCTX pCtx;
     /** Core instance. */
     DEPGLOBALS Core;
-    /** the executable name. */
-    const char *argv0;
     /** The file.    */
     const char *pszFile;
@@ -194,24 +196,15 @@
 static int kDepErr(PKDEPOBJGLOBALS pThis, int rc, const char *pszFormat, ...)
 {
+    char szMsg[2048];
     va_list va;
-    const char *psz;
-    const char *pszName = pThis->argv0;
-
-    fflush(stdout);
-
-    /* The message prefix. */
-    while ((psz = strpbrk(pszName, "/\\:")) != NULL)
-        pszName = psz + 1;
+    va_start(va, pszFormat);
+    vsnprintf(szMsg, sizeof(szMsg) - 1, pszFormat, va);
+    va_end(va);
+    szMsg[sizeof(szMsg) - 1] = '\0';
 
     if (pThis->pszFile)
-        fprintf(stderr, "%s: %s: error: ", pszName, pThis->pszFile);
+        warnx(pThis->pCtx, "%s: error: %s", pThis->pszFile, szMsg);
     else
-        fprintf(stderr, "%s: error: ", pszName);
-
-    /* The message. */
-    va_start(va, pszFormat);
-    vfprintf(stderr, pszFormat, va);
-    va_end(va);
-
+        errx(pThis->pCtx, rc, "%s", szMsg);
     return rc;
 }
@@ -294,5 +287,5 @@
                 PCKDEPOMFTHEADR pTHeadr = (PCKDEPOMFTHEADR)pHdr;
                 if (1 + pTHeadr->Name.cch + 1 != pHdr->cbRec)
-                    return kDepErr(pThis, 1, "%#07x - Bad %cHEADR record, length mismatch.\n",
+                    return kDepErr(pThis, 1, "%#07x - Bad %cHEADR record, length mismatch.",
                                    (const KU8*)pHdr - pbFile, pHdr->bType == KDEPOMF_THEADR ? 'T' : 'L');
                 if (    (   pTHeadr->Name.cch > 2
@@ -325,7 +318,7 @@
 
                 if (pHdr->cbRec < 2 + 1)
-                    return kDepErr(pThis, 1, "%#07x - Bad COMMENT record, too small.\n", (const KU8*)pHdr - pbFile);
+                    return kDepErr(pThis, 1, "%#07x - Bad COMMENT record, too small.", (const KU8*)pHdr - pbFile);
                 if (uData.pb[0] & 0x3f)
-                    return kDepErr(pThis, 1, "%#07x - Bad COMMENT record, reserved flags set.\n", (const KU8*)pHdr - pbFile);
+                    return kDepErr(pThis, 1, "%#07x - Bad COMMENT record, reserved flags set.", (const KU8*)pHdr - pbFile);
                 uClass = uData.pb[1];
                 uData.pb += 2;
@@ -344,5 +337,5 @@
                             if (pHdr->cbRec == 2 + 1)
                                 return 0;
-                            return kDepErr(pThis, 1, "%#07lx - Bad DEPENDENCY FILE record, length mismatch. (%u/%u)\n",
+                            return kDepErr(pThis, 1, "%#07lx - Bad DEPENDENCY FILE record, length mismatch. (%u/%u)",
                                            (long)((const KU8 *)pHdr - pbFile),
                                            K_OFFSETOF(KDEPOMFDEPFILE, Name.ach[pDep->Name.cch]) + 1,
@@ -398,5 +391,5 @@
                     KU16 uSeg = kDepObjOMFGetIndex(&uData, &cbRecLeft);
                     if (uSeg == KU16_MAX)
-                        return kDepErr(pThis, 1, "%#07lx - Bad LINNUM32 record\n", (long)((const KU8 *)pHdr - pbFile));
+                        return kDepErr(pThis, 1, "%#07lx - Bad LINNUM32 record", (long)((const KU8 *)pHdr - pbFile));
                     K_NOREF(uGrp);
 
@@ -415,5 +408,5 @@
 
                         if (cbRecLeft < 2+1+1+2+2+4)
-                            return kDepErr(pThis, 1, "%#07lx - Bad LINNUM32 record, too short\n", (long)((const KU8 *)pHdr - pbFile));
+                            return kDepErr(pThis, 1, "%#07lx - Bad LINNUM32 record, too short", (long)((const KU8 *)pHdr - pbFile));
                         cbRecLeft  -= 2+1+1+2+2+4;
                         uLine       = *uData.pu16++;
@@ -431,5 +424,5 @@
 
                         if (uLine != 0)
-                            return kDepErr(pThis, 1, "%#07lx - Bad LINNUM32 record, line %#x (MBZ)\n", (long)((const KU8 *)pHdr - pbFile), uLine);
+                            return kDepErr(pThis, 1, "%#07lx - Bad LINNUM32 record, line %#x (MBZ)", (long)((const KU8 *)pHdr - pbFile), uLine);
                         cLinFiles = iLinFile = KU32_MAX;
                         if (   uLinNumType == 3 /* file names table */
@@ -437,5 +430,5 @@
                             cLinNums = 0; /* no line numbers */
                         else if (uLinNumType > 4)
-                            return kDepErr(pThis, 1, "%#07lx - Bad LINNUM32 record, type %#x unknown\n", (long)((const KU8 *)pHdr - pbFile), uLinNumType);
+                            return kDepErr(pThis, 1, "%#07lx - Bad LINNUM32 record, type %#x unknown", (long)((const KU8 *)pHdr - pbFile), uLinNumType);
                     }
                     else
@@ -452,5 +445,5 @@
                         {
                             if (cbRecLeft < cbEntry)
-                                return kDepErr(pThis, 1, "%#07lx - Bad LINNUM32 record, incomplete line entry\n", (long)((const KU8 *)pHdr - pbFile));
+                                return kDepErr(pThis, 1, "%#07lx - Bad LINNUM32 record, incomplete line entry", (long)((const KU8 *)pHdr - pbFile));
 
                             switch (uLinNumType)
@@ -492,5 +485,5 @@
 
                             if (cbRecLeft < 4+4+4)
-                                return kDepErr(pThis, 1, "%#07lx - Bad LINNUM32 record, incomplete file/path table header\n", (long)((const KU8 *)pHdr - pbFile));
+                                return kDepErr(pThis, 1, "%#07lx - Bad LINNUM32 record, incomplete file/path table header", (long)((const KU8 *)pHdr - pbFile));
                             cbRecLeft -= 4+4+4;
 
@@ -501,5 +494,5 @@
                                      uLinNumType == 3 ? "file names" : "path", cLinFiles, cLinFiles, iFirstCol, cCols));
                             if (cLinFiles == KU32_MAX)
-                                return kDepErr(pThis, 1, "%#07lx - Bad LINNUM32 record, too many file/path table entries.\n", (long)((const KU8 *)pHdr - pbFile));
+                                return kDepErr(pThis, 1, "%#07lx - Bad LINNUM32 record, too many file/path table entries.", (long)((const KU8 *)pHdr - pbFile));
                             iLinFile = 0;
                         }
@@ -510,5 +503,5 @@
                             int cbName = *uData.pb++;
                             if (cbRecLeft < 1 + cbName)
-                                return kDepErr(pThis, 1, "%#07lx - Bad LINNUM32 record, file/path table entry too long.\n", (long)((const KU8 *)pHdr - pbFile));
+                                return kDepErr(pThis, 1, "%#07lx - Bad LINNUM32 record, file/path table entry too long.", (long)((const KU8 *)pHdr - pbFile));
                             iLinFile++;
                             dprintf(("#%" KU32_PRI": %.*s\n", iLinFile, cbName, uData.pch));
@@ -542,5 +535,5 @@
 
     if (cbLeft)
-        return kDepErr(pThis, 1, "%#07x - Unexpected EOF. cbLeft=%#x\n", (const KU8*)pHdr - pbFile, cbLeft);
+        return kDepErr(pThis, 1, "%#07x - Unexpected EOF. cbLeft=%#x", (const KU8*)pHdr - pbFile, cbLeft);
 
     if (iSrc == 0 && iMaybeSrc <= 1)
@@ -612,6 +605,6 @@
         if (off + sizeof(*pHdr) >= cbSyms)
         {
-            fprintf(stderr, "%s: CV symbol table entry at %08" KX32_PRI " is too long; cbSyms=%#" KX32_PRI "\n",
-                    pThis->argv0, off, cbSyms);
+            kDepErr(pThis, 1, "CV symbol table entry at %08" KX32_PRI " is too long; cbSyms=%#" KX32_PRI "",
+                    off, cbSyms);
             return 1; /* FIXME */
         }
@@ -620,6 +613,6 @@
         if (off + cbData + sizeof(*pHdr) > cbSyms)
         {
-            fprintf(stderr, "%s: CV symbol table entry at %08" KX32_PRI " is too long; cbData=%#" KX32_PRI " cbSyms=%#" KX32_PRI "\n",
-                    pThis->argv0, off, cbData, cbSyms);
+            kDepErr(pThis, 1, "CV symbol table entry at %08" KX32_PRI " is too long; cbData=%#" KX32_PRI " cbSyms=%#" KX32_PRI,
+                    off, cbData, cbSyms);
             return 1; /* FIXME */
         }
@@ -645,5 +638,5 @@
                 dprintf(("%06" KX32_PRI " %06" KX32_PRI ": String table\n", off, cbData));
                 if (pchStrTab)
-                    fprintf(stderr, "%s: warning: Found yet another string table!\n", pThis->argv0);
+                    warnx(pThis->pCtx, "%s: warning: Found yet another string table!", pThis->pszFile);
                 pchStrTab = uData.pch;
                 cbStrTab = cbData;
@@ -654,5 +647,5 @@
                 dprintf(("%06" KX32_PRI " %06" KX32_PRI ": Source files\n", off, cbData));
                 if (uSrcFiles.pb)
-                    fprintf(stderr, "%s: warning: Found yet another source files table!\n", pThis->argv0);
+                    warnx(pThis->pCtx, "%s: warning: Found yet another source files table!", pThis->pszFile);
                 uSrcFiles = uData;
                 cbSrcFiles = cbData;
@@ -703,34 +696,22 @@
          */
         if (off + 8 > cbSrcFiles)
-        {
-            fprintf(stderr, "%s: CV source file entry at %08" KX32_PRI " is too long; cbSrcFiles=%#" KX32_PRI "\n",
-                    pThis->argv0, off, cbSrcFiles);
-            return 1;
-        }
+            return kDepErr(pThis, 1, "CV source file entry at %08" KX32_PRI " is too long; cbSrcFiles=%#" KX32_PRI,
+                           off, cbSrcFiles);
         uSrc.pb = uSrcFiles.pb + off;
         u16Type = uSrc.pu16[2];
         cbSrc = u16Type == 0x0110 ? 6 + 16 + 2 : 6 + 2;
         if (off + cbSrc > cbSrcFiles)
-        {
-            fprintf(stderr, "%s: CV source file entry at %08" KX32_PRI " is too long; cbSrc=%#" KX32_PRI " cbSrcFiles=%#" KX32_PRI "\n",
-                    pThis->argv0, off, cbSrc, cbSrcFiles);
-            return 1;
-        }
+            return kDepErr(pThis, 1, "CV source file entry at %08" KX32_PRI " is too long; cbSrc=%#" KX32_PRI " cbSrcFiles=%#" KX32_PRI,
+                           off, cbSrc, cbSrcFiles);
 
         offFile = *uSrc.pu32;
         if (offFile > cbStrTab)
-        {
-            fprintf(stderr, "%s: CV source file entry at %08" KX32_PRI " is out side the string table; offFile=%#" KX32_PRI " cbStrTab=%#" KX32_PRI "\n",
-                    pThis->argv0, off, offFile, cbStrTab);
-            return 1;
-        }
+            return kDepErr(pThis, 1, "CV source file entry at %08" KX32_PRI " is out side the string table; offFile=%#" KX32_PRI " cbStrTab=%#" KX32_PRI,
+                    off, offFile, cbStrTab);
         pszFile = pchStrTab + offFile;
         cchFile = strlen(pszFile);
         if (cchFile == 0)
-        {
-            fprintf(stderr, "%s: CV source file entry at %08" KX32_PRI " has an empty file name; offFile=%#x" KX32_PRI "\n",
-                    pThis->argv0, off, offFile);
-            return 1;
-        }
+            return kDepErr(pThis, 1, "CV source file entry at %08" KX32_PRI " has an empty file name; offFile=%#x" KX32_PRI,
+                           off, offFile);
 
         /*
@@ -822,8 +803,9 @@
  * @returns K_TRUE if it's COFF, K_FALSE otherwise.
  *
+ * @param   pThis   The kDepObj instance data.
  * @param   pb      The start of the file.
  * @param   cb      The file size.
  */
-KBOOL kDepObjCOFFTest(const KU8 *pbFile, KSIZE cbFile)
+KBOOL kDepObjCOFFTest(PKDEPOBJGLOBALS pThis, const KU8 *pbFile, KSIZE cbFile)
 {
     IMAGE_FILE_HEADER const         *pFileHdr   = (IMAGE_FILE_HEADER const *)pbFile;
@@ -864,15 +846,15 @@
             && pBigObjHdr->Machine != IMAGE_FILE_MACHINE_EBC)
         {
-            fprintf(stderr, "kDepObj: error: bigobj Machine not supported: %#x\n", pBigObjHdr->Machine);
+            kDepErr(pThis, 1, "bigobj Machine not supported: %#x", pBigObjHdr->Machine);
             return K_FALSE;
         }
         if (pBigObjHdr->Flags != 0)
         {
-            fprintf(stderr, "kDepObj: error: bigobj Flags field is non-zero: %#x\n", pBigObjHdr->Flags);
+            kDepErr(pThis, 1, "bigobj Flags field is non-zero: %#x", pBigObjHdr->Flags);
             return K_FALSE;
         }
         if (pBigObjHdr->SizeOfData != 0)
         {
-            fprintf(stderr, "kDepObj: error: bigobj SizeOfData field is non-zero: %#x\n", pBigObjHdr->SizeOfData);
+            kDepErr(pThis, 1, "bigobj SizeOfData field is non-zero: %#x", pBigObjHdr->SizeOfData);
             return K_FALSE;
         }
@@ -977,11 +959,8 @@
     if (kDepObjOMFTest(pbFile, cbFile))
         rc = kDepObjOMFParse(pThis, pbFile, cbFile);
-    else if (kDepObjCOFFTest(pbFile, cbFile))
+    else if (kDepObjCOFFTest(pThis, pbFile, cbFile))
         rc = kDepObjCOFFParse(pThis, pbFile, cbFile);
     else
-    {
-        fprintf(stderr, "%s: error: Doesn't recognize the header of the OMF/COFF file.\n", pThis->argv0);
-        rc = 1;
-    }
+        rc = kDepErr(pThis, 1, "Doesn't recognize the header of the OMF/COFF file.");
 
     depFreeFileMemory(pbFile, pvOpaque);
@@ -990,14 +969,15 @@
 
 
-static void kDebObjUsage(const char *a_argv0)
-{
-    printf("usage: %s -o <output> -t <target> [-fqs] [-e <ignore-ext>] <OMF or COFF file>\n"
-           "   or: %s --help\n"
-           "   or: %s --version\n",
-           a_argv0, a_argv0, a_argv0);
+static void kDebObjUsage(PKMKBUILTINCTX pCtx, int fIsErr)
+{
+    kmk_builtin_ctx_printf(pCtx, fIsErr,
+                           "usage: %s -o <output> -t <target> [-fqs] [-e <ignore-ext>] <OMF or COFF file>\n"
+                           "   or: %s --help\n"
+                           "   or: %s --version\n",
+                           pCtx->pszProgName, pCtx->pszProgName, pCtx->pszProgName);
 }
 
 
-int kmk_builtin_kDepObj(int argc, char *argv[], char **envp)
+int kmk_builtin_kDepObj(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx)
 {
     int             i;
@@ -1017,5 +997,5 @@
 
     /* Init instance data.   */
-    This.argv0  = argv[0];
+    This.pCtx = pCtx;
     This.pszFile = NULL;
 
@@ -1025,5 +1005,5 @@
     if (argc <= 1)
     {
-        kDebObjUsage(argv[0]);
+        kDebObjUsage(pCtx, 0);
         return 1;
     }
@@ -1047,6 +1027,6 @@
                 else
                 {
-                    fprintf(stderr, "%s: syntax error: Invalid argument '%s'.\n", argv[0], argv[i]);
-                    kDebObjUsage(argv[0]);
+                    errx(pCtx, 2, "Invalid argument '%s'.", argv[i]);
+                    kDebObjUsage(pCtx, 1);
                     return 2;
                 }
@@ -1067,8 +1047,5 @@
                         pszValue = argv[i];
                     else
-                    {
-                        fprintf(stderr, "%s: syntax error: The '-%c' option takes a value.\n", argv[0], chOpt);
-                        return 2;
-                    }
+                        return errx(pCtx, 2, "The '-%c' option takes a value.", chOpt);
                     break;
 
@@ -1087,8 +1064,5 @@
                 {
                     if (pOutput)
-                    {
-                        fprintf(stderr, "%s: syntax error: only one output file!\n", argv[0]);
-                        return 2;
-                    }
+                        return errx(pCtx, 2, "only one output file!");
                     pszOutput = pszValue;
                     if (pszOutput[0] == '-' && !pszOutput[1])
@@ -1097,8 +1071,5 @@
                         pOutput = fopen(pszOutput, "w");
                     if (!pOutput)
-                    {
-                        fprintf(stderr, "%s: error: Failed to create output file '%s'.\n", argv[0], pszOutput);
-                        return 1;
-                    }
+                        return err(pCtx, 1, "Failed to create output file '%s'", pszOutput);
                     break;
                 }
@@ -1110,8 +1081,5 @@
                 {
                     if (pszTarget)
-                    {
-                        fprintf(stderr, "%s: syntax error: only one target!\n", argv[0]);
-                        return 1;
-                    }
+                        return errx(pCtx, 2, "only one target!");
                     pszTarget = pszValue;
                     break;
@@ -1151,8 +1119,5 @@
                 {
                     if (pszIgnoreExt)
-                    {
-                        fprintf(stderr, "%s: syntax error: The '-e' option can only be used once!\n", argv[0]);
-                        return 2;
-                    }
+                        return errx(pCtx, 2, "The '-e' option can only be used once!");
                     pszIgnoreExt = pszValue;
                     break;
@@ -1163,5 +1128,5 @@
                  */
                 case '?':
-                    kDebObjUsage(argv[0]);
+                    kDebObjUsage(pCtx, 0);
                     return 0;
                 case 'V':
@@ -1173,6 +1138,6 @@
                  */
                 default:
-                    fprintf(stderr, "%s: syntax error: Invalid argument '%s'.\n", argv[0], argv[i]);
-                    kDebObjUsage(argv[0]);
+                    errx(pCtx, 2, "Invalid argument '%s'.", argv[i]);
+                    kDebObjUsage(pCtx, 1);
                     return 2;
             }
@@ -1182,8 +1147,5 @@
             pInput = fopen(argv[i], "rb");
             if (!pInput)
-            {
-                fprintf(stderr, "%s: error: Failed to open input file '%s'.\n", argv[0], argv[i]);
-                return 1;
-            }
+                return err(pCtx, 1, "Failed to open input file '%s'", argv[i]);
             fInput = 1;
         }
@@ -1195,8 +1157,5 @@
         {
             if (++i < argc)
-            {
-                fprintf(stderr, "%s: syntax error: No arguments shall follow the input spec.\n", argv[0]);
-                return 1;
-            }
+                return errx(pCtx, 2, "No arguments shall follow the input spec.");
             break;
         }
@@ -1207,18 +1166,9 @@
      */
     if (!pInput)
-    {
-        fprintf(stderr, "%s: syntax error: No input!\n", argv[0]);
-        return 1;
-    }
+        return errx(pCtx, 2, "No input!");
     if (!pOutput)
-    {
-        fprintf(stderr, "%s: syntax error: No output!\n", argv[0]);
-        return 1;
-    }
+        return errx(pCtx, 2, "No output!");
     if (!pszTarget)
-    {
-        fprintf(stderr, "%s: syntax error: No target!\n", argv[0]);
-        return 1;
-    }
+        return errx(pCtx, 2, "No target!");
 
     /*
@@ -1245,13 +1195,10 @@
      */
     if (!i && ferror(pOutput))
-    {
-        i = 1;
-        fprintf(stderr, "%s: error: Error writing to '%s'.\n", argv[0], pszOutput);
-    }
+        i = errx(pCtx, 1, "Error writing to '%s'", pszOutput);
     fclose(pOutput);
     if (i)
     {
         if (unlink(pszOutput))
-            fprintf(stderr, "%s: warning: failed to remove output file '%s' on failure.\n", argv[0], pszOutput);
+            warn(pCtx, "warning: failed to remove output file '%s' on failure.", pszOutput);
     }
 
@@ -1260,2 +1207,10 @@
 }
 
+#ifdef KMK_BUILTIN_STANDALONE
+int main(int argc, char **argv, char **envp)
+{
+    KMKBUILTINCTX Ctx = { "kDepObj", NULL };
+    return kmk_builtin_kDepObj(argc, argv, envp, &Ctx);
+}
+#endif
+
Index: trunk/src/kmk/kmkbuiltin/kSubmit.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/kSubmit.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/kSubmit.c	(revision 3192)
@@ -293,4 +293,5 @@
  *
  * @returns 0 on success, non-zero value on failure.
+ * @param   pCtx                The command execution context.
  * @param   pWorker             The worker structure.  Caller does the linking
  *                              (as we might be reusing an existing worker
@@ -299,5 +300,5 @@
  * @param   cVerbosity          The verbosity level.
  */
-static int kSubmitSpawnWorker(PWORKERINSTANCE pWorker, int cVerbosity)
+static int kSubmitSpawnWorker(PKMKBUILTINCTX pCtx, PWORKERINSTANCE pWorker, int cVerbosity)
 {
 #if defined(KBUILD_OS_WINDOWS) || defined(KBUILD_OS_OS2)
@@ -319,5 +320,5 @@
         pVarVolatile = lookup_variable(TUPLE("PATH_OUT_BASE"));
         if (!pVarVolatile)
-            warn("Neither PATH_OUT_BASE nor PATH_OUT was found.");
+            warn(pCtx, "Neither PATH_OUT_BASE nor PATH_OUT was found.");
     }
 
@@ -346,5 +347,6 @@
             if (   cchBinPath < sizeof(g_szArch)
                 || memcmp(&szExecutable[cchBinPath - sizeof(g_szArch) + 1], g_szArch, sizeof(g_szArch) - 1) != 0)
-                return errx(1, "KBUILD_BIN_PATH does not end with main architecture (%s) as expected: %s", pszBinPath, g_szArch);
+                return errx(pCtx, 1, "KBUILD_BIN_PATH does not end with main architecture (%s) as expected: %s",
+                            pszBinPath, g_szArch);
             cchExectuable -= sizeof(g_szArch) - 1;
             memcpy(&szExecutable[cchExectuable], g_szAltArch, sizeof(g_szAltArch) - 1);
@@ -417,22 +419,22 @@
                         pWorker->pid = GetProcessId(pWorker->hProcess);
                         if (cVerbosity > 0)
-                            fprintf(stderr, "kSubmit: created %d bit worker %d\n", pWorker->cBits, pWorker->pid);
+                            warnx(pCtx, "created %d bit worker %d\n", pWorker->cBits, pWorker->pid);
                         return 0;
                     }
-                    err(1, "_spawnve(,%s,,)", szExecutable);
+                    err(pCtx, 1, "_spawnve(,%s,,)", szExecutable);
                     CloseHandle(pWorker->OverlappedRead.hEvent);
                     pWorker->OverlappedRead.hEvent = INVALID_HANDLE_VALUE;
                 }
                 else
-                    errx(1, "CreateEventW failed: %u", GetLastError());
+                    errx(pCtx, 1, "CreateEventW failed: %u", GetLastError());
                 CloseHandle(pWorker->hPipe);
                 pWorker->hPipe = INVALID_HANDLE_VALUE;
             }
             else
-                errx(1, "Opening named pipe failed: %u", GetLastError());
+                errx(pCtx, 1, "Opening named pipe failed: %u", GetLastError());
             CloseHandle(hWorkerPipe);
         }
         else
-            errx(1, "CreateNamedPipeW failed: %u", GetLastError());
+            errx(pCtx, 1, "CreateNamedPipeW failed: %u", GetLastError());
 
 #else
@@ -441,13 +443,11 @@
          */
         if (socketpair(AF_LOCAL, SOCK_STREAM, 0, aiPair) == 0)
-        {
             pWorker->fdSocket = aiPair[1];
-        }
         else
-            err(1, "socketpair");
+            err(pCtx, 1, "socketpair");
 #endif
     }
     else
-        errx(1, "KBUILD_BIN_PATH is too long");
+        errx(pCtx, 1, "KBUILD_BIN_PATH is too long");
     return -1;
 }
@@ -458,9 +458,10 @@
  *
  * @returns Pointer to the selected worker instance.  NULL on error.
+ * @param   pCtx                The command execution context.
  * @param   pWorker             The idle worker instance to respawn.
  *                              On failure this will be freed!
  * @param   cBitsWorker         The worker bitness - 64 or 32.
  */
-static int kSubmitRespawnWorker(PWORKERINSTANCE pWorker, int cVerbosity)
+static int kSubmitRespawnWorker(PKMKBUILTINCTX pCtx, PWORKERINSTANCE pWorker, int cVerbosity)
 {
     /*
@@ -475,10 +476,10 @@
     {
         if (!CloseHandle(pWorker->hPipe))
-            warnx("CloseHandle(pWorker->hPipe): %u", GetLastError());
+            warnx(pCtx, "CloseHandle(pWorker->hPipe): %u", GetLastError());
         pWorker->hPipe = INVALID_HANDLE_VALUE;
     }
 
     if (!CloseHandle(pWorker->OverlappedRead.hEvent))
-        warnx("CloseHandle(pWorker->OverlappedRead.hEvent): %u", GetLastError());
+        warnx(pCtx, "CloseHandle(pWorker->OverlappedRead.hEvent): %u", GetLastError());
     pWorker->OverlappedRead.hEvent = INVALID_HANDLE_VALUE;
 
@@ -491,9 +492,9 @@
         rcWait = WaitForSingleObject(pWorker->hProcess, 100);
         if (rcWait != WAIT_OBJECT_0)
-            warnx("WaitForSingleObject returns %u (and TerminateProcess %d)", rcWait, fRc);
+            warnx(pCtx, "WaitForSingleObject returns %u (and TerminateProcess %d)", rcWait, fRc);
     }
 
     if (!CloseHandle(pWorker->hProcess))
-        warnx("CloseHandle(pWorker->hProcess): %u", GetLastError());
+        warnx(pCtx, "CloseHandle(pWorker->hProcess): %u", GetLastError());
     pWorker->hProcess = INVALID_HANDLE_VALUE;
 
@@ -505,5 +506,5 @@
     {
         if (close(pWorker->fdSocket) != 0)
-            warn("close(pWorker->fdSocket)");
+            warn(pCtx, "close(pWorker->fdSocket)");
         pWorker->fdSocket = -1;
     }
@@ -512,5 +513,5 @@
     pidWait = waitpid(pWorker->pid, &rc, 0);
     if (pidWait != pWorker->pid)
-        warn("waitpid(pWorker->pid,,0)");
+        warn(pCtx, "waitpid(pWorker->pid,,0)");
 #endif
 
@@ -523,5 +524,5 @@
      * Respawn it.
      */
-    if (kSubmitSpawnWorker(pWorker, cVerbosity) == 0)
+    if (kSubmitSpawnWorker(pCtx, pWorker, cVerbosity) == 0)
     {
         /*
@@ -546,5 +547,5 @@
  * @param   cBitsWorker         The worker bitness - 64 or 32.
  */
-static PWORKERINSTANCE kSubmitSelectWorkSpawnNewIfNecessary(unsigned cBitsWorker, int cVerbosity)
+static PWORKERINSTANCE kSubmitSelectWorkSpawnNewIfNecessary(PKMKBUILTINCTX pCtx, unsigned cBitsWorker, int cVerbosity)
 {
     /*
@@ -564,5 +565,5 @@
     pWorker = (PWORKERINSTANCE)xcalloc(sizeof(*pWorker));
     pWorker->cBits = cBitsWorker;
-    if (kSubmitSpawnWorker(pWorker, cVerbosity) == 0)
+    if (kSubmitSpawnWorker(pCtx, pWorker, cVerbosity) == 0)
     {
         /*
@@ -715,4 +716,5 @@
  * @returns 0 on success, non-zero on failure.
  *
+ * @param   pCtx                The command execution context.
  * @param   pWorker             The work to send the request to.  The worker is
  *                              on the idle list.
@@ -722,5 +724,6 @@
  * @param   cVerbosity          The verbosity level.
  */
-static int kSubmitSendJobMessage(PWORKERINSTANCE pWorker, void const *pvMsg, uint32_t cbMsg, int fNoRespawning, int cVerbosity)
+static int kSubmitSendJobMessage(PKMKBUILTINCTX pCtx, PWORKERINSTANCE pWorker, void const *pvMsg, uint32_t cbMsg,
+                                 int fNoRespawning, int cVerbosity)
 {
     int cRetries;
@@ -738,6 +741,6 @@
         {
             if (cVerbosity > 0)
-                fprintf(stderr,  "kSubmit: Respawning worker (#1)...\n");
-            if (kSubmitRespawnWorker(pWorker, cVerbosity) != 0)
+                warnx(pCtx, "Respawning worker (#1)...\n");
+            if (kSubmitRespawnWorker(pCtx, pWorker, cVerbosity) != 0)
                 return 2;
         }
@@ -772,5 +775,5 @@
                 && dwErr != ERROR_NO_DATA)
             || cRetries <= 0)
-            return errx(1, "Error writing to worker: %u", dwErr);
+            return errx(pCtx, 1, "Error writing to worker: %u", dwErr);
 #else
         ssize_t cbWritten
@@ -788,5 +791,5 @@
                && errno != ECONNRESET))
             || cRetries <= 0)
-            return err(1, "Error writing to worker");
+            return err(pCtx, 1, "Error writing to worker");
 # error "later"
 #endif
@@ -796,6 +799,6 @@
          */
         if (cVerbosity > 0)
-            fprintf(stderr,  "kSubmit: Respawning worker (#2)...\n");
-        if (kSubmitRespawnWorker(pWorker, cVerbosity) != 0)
+            warnx(pCtx, "Respawning worker (#2)...\n");
+        if (kSubmitRespawnWorker(pCtx, pWorker, cVerbosity) != 0)
             return 2;
     }
@@ -814,15 +817,16 @@
  * which the process can terminate without us having to actively wait for it.
  *
+ * @param   pCtx                The command execution context.
  * @param   pWorker             The worker instance.
  */
-static void kSubmitCloseConnectOnExitingWorker(PWORKERINSTANCE pWorker)
+static void kSubmitCloseConnectOnExitingWorker(PKMKBUILTINCTX pCtx, PWORKERINSTANCE pWorker)
 {
 #ifdef KBUILD_OS_WINDOWS
     if (!CloseHandle(pWorker->hPipe))
-        warnx("CloseHandle(pWorker->hPipe): %u", GetLastError());
+        warnx(pCtx, "CloseHandle(pWorker->hPipe): %u", GetLastError());
     pWorker->hPipe = INVALID_HANDLE_VALUE;
 #else
     if (close(pWorker->fdSocket) != 0)
-        warn("close(pWorker->fdSocket)");
+        warn(pCtx, "close(pWorker->fdSocket)");
     pWorker->fdSocket = -1;
 #endif
@@ -836,16 +840,17 @@
  *
  * @returns Exit code.
+ * @param   pCtx                The command execution context.
  * @param   pWorker             The worker instance.
  * @param   dwErr               The error code.
  * @param   pszWhere            Where it failed.
  */
-static int kSubmitWinReadFailed(PWORKERINSTANCE pWorker, DWORD dwErr, const char *pszWhere)
+static int kSubmitWinReadFailed(PKMKBUILTINCTX pCtx, PWORKERINSTANCE pWorker, DWORD dwErr, const char *pszWhere)
 {
     DWORD dwExitCode;
 
     if (pWorker->cbResultRead == 0)
-        errx(1, "%s/ReadFile failed: %u", pszWhere, dwErr);
+        errx(pCtx, 1, "%s/ReadFile failed: %u", pszWhere, dwErr);
     else
-        errx(1, "%s/ReadFile failed: %u (read %u bytes)", pszWhere, dwErr, pWorker->cbResultRead);
+        errx(pCtx, 1, "%s/ReadFile failed: %u (read %u bytes)", pszWhere, dwErr, pWorker->cbResultRead);
     assert(dwErr != 0);
 
@@ -870,7 +875,8 @@
  * @returns 0 if we got the whole result, -1 if I/O is pending, and windows last
  *          error on ReadFile failure.
+ * @param   pCtx                The command execution context.
  * @param   pWorker             The worker instance.
  */
-static int kSubmitReadMoreResultWin(PWORKERINSTANCE pWorker, const char *pszWhere)
+static int kSubmitReadMoreResultWin(PKMKBUILTINCTX pCtx, PWORKERINSTANCE pWorker, const char *pszWhere)
 {
     /*
@@ -895,5 +901,5 @@
             if (dwErr == ERROR_IO_PENDING)
                 return -1;
-            return kSubmitWinReadFailed(pWorker, dwErr, pszWhere);
+            return kSubmitWinReadFailed(pCtx, pWorker, dwErr, pszWhere);
         }
 
@@ -913,4 +919,5 @@
  *
  * @returns Exit code.
+ * @param   pCtx                The command execution context.
  * @param   pWorker             The worker instance to mark as active.
  * @param   cVerbosity          The verbosity level.
@@ -920,5 +927,5 @@
  *                              and we've returned the exit code of the job.
  */
-static int kSubmitMarkActive(PWORKERINSTANCE pWorker, int cVerbosity, struct child *pChild, pid_t *pPidSpawned)
+static int kSubmitMarkActive(PKMKBUILTINCTX pCtx, PWORKERINSTANCE pWorker, int cVerbosity, struct child *pChild, pid_t *pPidSpawned)
 {
 #ifdef KBUILD_OS_WINDOWS
@@ -934,5 +941,5 @@
      */
 l_again:
-    rc = kSubmitReadMoreResultWin(pWorker, "kSubmitMarkActive");
+    rc = kSubmitReadMoreResultWin(pCtx, pWorker, "kSubmitMarkActive");
     if (rc == -1)
     {
@@ -943,5 +950,5 @@
         {
             /* We need to do the waiting here because sub_proc.c has too much to do. */
-            warnx("Too many processes for sub_proc.c to handle!");
+            warnx(pCtx, "Too many processes for sub_proc.c to handle!");
             WaitForSingleObject(pWorker->OverlappedRead.hEvent, INFINITE);
             goto l_again;
@@ -953,5 +960,5 @@
         {
             /* We need to do the waiting here because sub_proc.c has too much to do. */
-            warnx("MkWinChildCreateSubmit failed!");
+            warnx(pCtx, "MkWinChildCreateSubmit failed!");
             WaitForSingleObject(pWorker->OverlappedRead.hEvent, INFINITE);
             goto l_again;
@@ -963,5 +970,5 @@
         assert(rc == 0 || pWorker->Result.s.rcExit != 0);
         if (pWorker->Result.s.bWorkerExiting)
-            kSubmitCloseConnectOnExitingWorker(pWorker);
+            kSubmitCloseConnectOnExitingWorker(pCtx, pWorker);
         *pPidSpawned = 0;
         return pWorker->Result.s.rcExit;
@@ -998,4 +1005,6 @@
 {
     PWORKERINSTANCE pWorker = (PWORKERINSTANCE)pvUser;
+    KMKBUILTINCTX   FakeCtx = { "kSubmit/GetResult", NULL };
+    PKMKBUILTINCTX  pCtx = &FakeCtx;
 
     /*
@@ -1012,5 +1021,5 @@
         while (pWorker->cbResultRead < sizeof(pWorker->Result))
         {
-            int rc = kSubmitReadMoreResultWin(pWorker, "kSubmitSubProcGetResult/more");
+            int rc = kSubmitReadMoreResultWin(pCtx, pWorker, "kSubmitSubProcGetResult/more");
             if (rc == -1)
                 return -1;
@@ -1022,5 +1031,5 @@
     {
         DWORD dwErr = GetLastError();
-        kSubmitWinReadFailed(pWorker, dwErr, "kSubmitSubProcGetResult/result");
+        kSubmitWinReadFailed(pCtx, pWorker, dwErr, "kSubmitSubProcGetResult/result");
     }
 
@@ -1039,5 +1048,5 @@
     }
     if (pWorker->Result.s.bWorkerExiting)
-        kSubmitCloseConnectOnExitingWorker(pWorker);
+        kSubmitCloseConnectOnExitingWorker(pCtx, pWorker);
 
     return 0;
@@ -1074,4 +1083,6 @@
     DWORD           msStartTick;
     DWORD           cKillRaids = 0;
+    KMKBUILTINCTX   FakeCtx = { "kSubmit/atexit", NULL };
+    PKMKBUILTINCTX  pCtx = &FakeCtx;
 
     /*
@@ -1079,7 +1090,7 @@
      */
     for (pWorker = g_IdleList.pHead; pWorker != NULL; pWorker = pWorker->pNext)
-        kSubmitCloseConnectOnExitingWorker(pWorker);
+        kSubmitCloseConnectOnExitingWorker(pCtx, pWorker);
     for (pWorker = g_BusyList.pHead; pWorker != NULL; pWorker = pWorker->pNext)
-        kSubmitCloseConnectOnExitingWorker(pWorker);
+        kSubmitCloseConnectOnExitingWorker(pCtx, pWorker);
 
     /*
@@ -1157,5 +1168,5 @@
                 if (cKillRaids == 1 && getenv("KMK_KSUBMIT_NO_KILL") == NULL)
                 {
-                    fprintf(stderr, "kmk/kSubmit: Killing %u lingering worker processe(s)!\n", cHandles);
+                    warnx(pCtx, "Killing %u lingering worker processe(s)!\n", cHandles);
                     for (pWorker = g_IdleList.pHead; pWorker != NULL; pWorker = pWorker->pNext)
                         if (pWorker->hProcess != INVALID_HANDLE_VALUE)
@@ -1167,5 +1178,5 @@
                 else
                 {
-                    fprintf(stderr, "kmk/kSubmit: Giving up on the last %u worker processe(s). :-(\n", cHandles);
+                    warnx(pCtx, "Giving up on the last %u worker processe(s). :-(\n", cHandles);
                     return;
                 }
@@ -1176,6 +1187,6 @@
                    bad ones as well as completed ones. */
                 size_t idx;
-                fprintf(stderr, "kmk/kSubmit: WaitForMultipleObjects unexpectedly returned %#u (err=%u)\n",
-                        dwWait, GetLastError());
+                warnx(pCtx, "WaitForMultipleObjects unexpectedly returned %#u (err=%u)\n",
+                      dwWait, GetLastError());
                 for (idx = 0; idx < cHandles; idx++)
                 {
@@ -1194,56 +1205,56 @@
 
 
-static int usage(FILE *pOut,  const char *argv0)
-{
-    fprintf(pOut,
-            "usage: %s [-Z|--zap-env] [-E|--set <var=val>] [-U|--unset <var=val>]\n"
-            "           [-A|--append <var=val>] [-D|--prepend <var=val>]\n"
-            "           [-C|--chdir <dir>] [--wcc-brain-damage] [--no-pch-caching]\n"
-            "           [-3|--32-bit] [-6|--64-bit] [-v]\n"
-            "           [-P|--post-cmd <cmd> [args]] -- <program> [args]\n"
-            "   or: %s --help\n"
-            "   or: %s --version\n"
-            "\n"
-            "Options:\n"
-            "  -Z, --zap-env, -i, --ignore-environment\n"
-            "    Zaps the environment. Position dependent.\n"
-            "  -E, --set <var>=[value]\n"
-            "    Sets an enviornment variable putenv fashion. Position dependent.\n"
-            "  -U, --unset <var>\n"
-            "    Removes an environment variable. Position dependent.\n"
-            "  -A, --append <var>=<value>\n"
-            "    Appends the given value to the environment variable.\n"
-            "  -D,--prepend <var>=<value>\n"
-            "    Prepends the given value to the environment variable.\n"
-            "  -C, --chdir <dir>\n"
-            "    Specifies the current directory for the program.  Relative paths\n"
-            "    are relative to the previous -C option.  Default is getcwd value.\n"
-            "  -3, --32-bit\n"
-            "    Selects a 32-bit kWorker process. Default: kmk bit count\n"
-            "  -6, --64-bit\n"
-            "    Selects a 64-bit kWorker process. Default: kmk bit count\n"
-            "  --wcc-brain-damage\n"
-            "    Works around wcc and wcc386 (Open Watcom) not following normal\n"
-            "    quoting conventions on Windows, OS/2, and DOS.\n"
-            "  --no-pch-caching\n"
-            "    Do not cache precompiled header files because they're being created.\n"
-            "  -v,--verbose\n"
-            "    More verbose execution.\n"
-            "  -P|--post-cmd <cmd> ...\n"
-            "    For running a built-in command on the output, specifying the command\n"
-            "    and all it's parameters.  Currently supported commands:\n"
-            "        kDepObj\n"
-            "  -V,--version\n"
-            "    Show the version number.\n"
-            "  -h,--help\n"
-            "    Show this usage information.\n"
-            "\n"
-            ,
-            argv0, argv0, argv0);
+static int kmk_builtin_kSubmit_usage(PKMKBUILTINCTX pCtx, int fIsErr)
+{
+    kmk_builtin_ctx_printf(pCtx, fIsErr,
+                           "usage: %s [-Z|--zap-env] [-E|--set <var=val>] [-U|--unset <var=val>]\n"
+                           "           [-A|--append <var=val>] [-D|--prepend <var=val>]\n"
+                           "           [-C|--chdir <dir>] [--wcc-brain-damage] [--no-pch-caching]\n"
+                           "           [-3|--32-bit] [-6|--64-bit] [-v]\n"
+                           "           [-P|--post-cmd <cmd> [args]] -- <program> [args]\n"
+                           "   or: %s --help\n"
+                           "   or: %s --version\n"
+                           "\n"
+                           "Options:\n"
+                           "  -Z, --zap-env, -i, --ignore-environment\n"
+                           "    Zaps the environment. Position dependent.\n"
+                           "  -E, --set <var>=[value]\n"
+                           "    Sets an enviornment variable putenv fashion. Position dependent.\n"
+                           "  -U, --unset <var>\n"
+                           "    Removes an environment variable. Position dependent.\n"
+                           "  -A, --append <var>=<value>\n"
+                           "    Appends the given value to the environment variable.\n"
+                           "  -D,--prepend <var>=<value>\n"
+                           "    Prepends the given value to the environment variable.\n"
+                           "  -C, --chdir <dir>\n"
+                           "    Specifies the current directory for the program.  Relative paths\n"
+                           "    are relative to the previous -C option.  Default is getcwd value.\n"
+                           "  -3, --32-bit\n"
+                           "    Selects a 32-bit kWorker process. Default: kmk bit count\n"
+                           "  -6, --64-bit\n"
+                           "    Selects a 64-bit kWorker process. Default: kmk bit count\n"
+                           "  --wcc-brain-damage\n"
+                           "    Works around wcc and wcc386 (Open Watcom) not following normal\n"
+                           "    quoting conventions on Windows, OS/2, and DOS.\n"
+                           "  --no-pch-caching\n"
+                           "    Do not cache precompiled header files because they're being created.\n"
+                           "  -v,--verbose\n"
+                           "    More verbose execution.\n"
+                           "  -P|--post-cmd <cmd> ...\n"
+                           "    For running a built-in command on the output, specifying the command\n"
+                           "    and all it's parameters.  Currently supported commands:\n"
+                           "        kDepObj\n"
+                           "  -V,--version\n"
+                           "    Show the version number.\n"
+                           "  -h,--help\n"
+                           "    Show this usage information.\n"
+                           "\n"
+                           ,
+                           pCtx->pszProgName, pCtx->pszProgName, pCtx->pszProgName);
     return 2;
 }
 
 
-int kmk_builtin_kSubmit(int argc, char **argv, char **envp, struct child *pChild, pid_t *pPidSpawned)
+int kmk_builtin_kSubmit(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx, struct child *pChild, pid_t *pPidSpawned)
 {
     int             rcExit = 0;
@@ -1262,6 +1273,4 @@
     PATH_VAR(szCwd);
 
-    g_progname = argv[0];
-
     /*
      * Create default program environment.
@@ -1273,5 +1282,5 @@
     { /* likely */ }
     else
-        return err(1, "getcwd_fs failed\n");
+        return err(pCtx, 1, "getcwd_fs failed\n");
 
     /* The environment starts out in read-only mode and will be duplicated if modified. */
@@ -1298,6 +1307,6 @@
                 else
                 {
-                    errx(1, "Incomplete option: '-'");
-                    return usage(stderr, argv[0]);
+                    errx(pCtx, 1, "Incomplete option: '-'");
+                    return kmk_builtin_kSubmit_usage(pCtx, 1);
                 }
             }
@@ -1354,6 +1363,6 @@
                 else
                 {
-                    errx(2, "Unknown option: '%s'", pszArg - 2);
-                    return usage(stderr, argv[0]);
+                    errx(pCtx, 2, "Unknown option: '%s'", pszArg - 2);
+                    return kmk_builtin_kSubmit_usage(pCtx, 1);
                 }
                 pszArg = "";
@@ -1378,6 +1387,6 @@
                         else
                         {
-                            errx(1, "Option -%c requires a value!", chOpt);
-                            return usage(stderr, argv[0]);
+                            errx(pCtx, 1, "Option -%c requires a value!", chOpt);
+                            return kmk_builtin_kSubmit_usage(pCtx, 1);
                         }
                         break;
@@ -1388,5 +1397,5 @@
                     case 'Z':
                     case 'i': /* GNU env compatibility. */
-                        rcExit = kBuiltinOptEnvZap(&papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity);
+                        rcExit = kBuiltinOptEnvZap(pCtx, &papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity);
                         if (rcExit == 0)
                             break;
@@ -1394,5 +1403,5 @@
 
                     case 'E':
-                        rcExit = kBuiltinOptEnvSet(&papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
+                        rcExit = kBuiltinOptEnvSet(pCtx, &papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
                         if (rcExit == 0)
                             break;
@@ -1400,5 +1409,5 @@
 
                     case 'A':
-                        rcExit = kBuiltinOptEnvAppend(&papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
+                        rcExit = kBuiltinOptEnvAppend(pCtx, &papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
                         if (rcExit == 0)
                             break;
@@ -1406,5 +1415,5 @@
 
                     case 'D':
-                        rcExit = kBuiltinOptEnvPrepend(&papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
+                        rcExit = kBuiltinOptEnvPrepend(pCtx, &papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
                         if (rcExit == 0)
                             break;
@@ -1412,5 +1421,5 @@
 
                     case 'U':
-                        rcExit = kBuiltinOptEnvUnset(&papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
+                        rcExit = kBuiltinOptEnvUnset(pCtx, &papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
                         if (rcExit == 0)
                             break;
@@ -1418,5 +1427,5 @@
 
                     case 'C':
-                        rcExit = kBuiltinOptChDir(szCwd, cbCwdBuf, pszValue);
+                        rcExit = kBuiltinOptChDir(pCtx, szCwd, cbCwdBuf, pszValue);
                         if (rcExit == 0)
                             break;
@@ -1425,10 +1434,10 @@
                     case 'P':
                         if (cPostCmdArgs > 0)
-                            return errx(1, "The -P option can only be used once!");
+                            return errx(pCtx, 1, "The -P option can only be used once!");
                         if (*pszArg != '\0')
-                            return errx(1, "The cmd part of the -P needs to be a separate argument!");
+                            return errx(pCtx, 1, "The cmd part of the -P needs to be a separate argument!");
                         iPostCmd = ++iArg;
                         if (iArg >= argc)
-                            return errx(1, "The -P option requires a command following it!");
+                            return errx(pCtx, 1, "The -P option requires a command following it!");
                         while (iArg < argc && strcmp(argv[iArg], "--") != 0)
                             iArg++;
@@ -1454,5 +1463,5 @@
 
                     case 'h':
-                        usage(stdout, argv[0]);
+                        kmk_builtin_kSubmit_usage(pCtx, 0);
                         kBuiltinOptEnvCleanup(&papszEnvVars, cEnvVars, &cAllocatedEnvVars);
                         return 0;
@@ -1466,6 +1475,6 @@
         else
         {
-            errx(1, "Unknown argument: '%s'", pszArg);
-            return usage(stderr, argv[0]);
+            errx(pCtx, 1, "Unknown argument: '%s'", pszArg);
+            return kmk_builtin_kSubmit_usage(pCtx, 1);
         }
     }
@@ -1480,5 +1489,5 @@
                                                            fWatcomBrainDamage, fNoPchCaching,
                                                            &argv[iPostCmd], cPostCmdArgs, &cbMsg);
-        PWORKERINSTANCE pWorker = kSubmitSelectWorkSpawnNewIfNecessary(cBitsWorker, cVerbosity);
+        PWORKERINSTANCE pWorker = kSubmitSelectWorkSpawnNewIfNecessary(pCtx, cBitsWorker, cVerbosity);
         if (pWorker)
         {
@@ -1486,7 +1495,7 @@
                 pszExecutable = argv[iArg];
 
-            rcExit = kSubmitSendJobMessage(pWorker, pvMsg, cbMsg, 0 /*fNoRespawning*/, cVerbosity);
+            rcExit = kSubmitSendJobMessage(pCtx, pWorker, pvMsg, cbMsg, 0 /*fNoRespawning*/, cVerbosity);
             if (rcExit == 0)
-                rcExit = kSubmitMarkActive(pWorker, cVerbosity, pChild, pPidSpawned);
+                rcExit = kSubmitMarkActive(pCtx, pWorker, cVerbosity, pChild, pPidSpawned);
 
             if (!g_fAtExitRegistered)
@@ -1500,6 +1509,6 @@
     else
     {
-        errx(1, "Nothing to executed!");
-        rcExit = usage(stderr, argv[0]);
+        errx(pCtx, 1, "Nothing to executed!");
+        rcExit = kmk_builtin_kSubmit_usage(pCtx, 1);
     }
 
Index: trunk/src/kmk/kmkbuiltin/kbuild_protection.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/kbuild_protection.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/kbuild_protection.c	(revision 3192)
@@ -116,5 +116,5 @@
  *          On failure an error is printed, eval is set and -1 is returned.
  */
-static int countPathComponents(const char *pszPath)
+static int countPathComponents(PCKBUILDPROTECTION pThis, const char *pszPath)
 {
     int cComponents = 0;
@@ -158,5 +158,5 @@
             if (!pszTmp)
             {
-                err(1, "_getdcwd");
+                err(pThis->pCtx, 1, "_getdcwd");
                 return -1;
             }
@@ -196,5 +196,5 @@
         if (!getcwd(szCwd, sizeof(szCwd)))
         {
-            err(1, "getcwd");
+            err(pThis->pCtx, 1, "getcwd");
             return -1;
         }
@@ -217,7 +217,8 @@
  * @param   pThis   Pointer to the instance data.
  */
-void kBuildProtectionInit(PKBUILDPROTECTION pThis)
+void kBuildProtectionInit(PKBUILDPROTECTION pThis, PKMKBUILTINCTX pCtx)
 {
     pThis->uMagic = KBUILD_PROTECTION_MAGIC;
+    pThis->pCtx = pCtx;
     pThis->afTypes[KBUILDPROTECTIONTYPE_FULL] = 0;
     pThis->afTypes[KBUILDPROTECTIONTYPE_RECURSIVE] = 1;
@@ -268,5 +269,5 @@
     /* number or path? */
     if (!isdigit(*pszValue) || strpbrk(pszValue, ":/\\"))
-        pThis->cProtectionDepth = countPathComponents(pszValue);
+        pThis->cProtectionDepth = countPathComponents(pThis, pszValue);
     else
     {
@@ -280,9 +281,9 @@
         }
         if (!pThis->cProtectionDepth || pszValue == pszMore || *pszMore)
-            return errx(1, "bogus protection depth: %s", pszValue);
+            return errx(pThis->pCtx, 1, "bogus protection depth: %s", pszValue);
     }
 
     if (pThis->cProtectionDepth < 1)
-        return  errx(1, "bogus protection depth: %s", pszValue);
+        return  errx(pThis->pCtx, 1, "bogus protection depth: %s", pszValue);
     return 0;
 }
@@ -351,10 +352,10 @@
          * Count the path and compare it with the required depth.
          */
-        int cComponents = countPathComponents(pszPath);
+        int cComponents = countPathComponents(pThis, pszPath);
         if (cComponents < 0)
             return -1;
         if ((unsigned int)cComponents <= pThis->cProtectionDepth)
         {
-            errx(1, "%s: protected", pszPath);
+            errx(pThis->pCtx, 1, "%s: protected", pszPath);
             return -1;
         }
Index: trunk/src/kmk/kmkbuiltin/kbuild_protection.h
===================================================================
--- trunk/src/kmk/kmkbuiltin/kbuild_protection.h	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/kbuild_protection.h	(revision 3192)
@@ -27,4 +27,5 @@
 #define ___kbuild_protection_h
 
+
 /**
  * The different protection types.
@@ -47,4 +48,5 @@
     unsigned int    uMagic;
     unsigned int    cProtectionDepth;
+    struct KMKBUILTINCTX *pCtx;
     unsigned char   afTypes[KBUILDPROTECTIONTYPE_MAX];
 } KBUILDPROTECTION;
@@ -53,5 +55,5 @@
 
 
-void kBuildProtectionInit(PKBUILDPROTECTION pThis);
+void kBuildProtectionInit(PKBUILDPROTECTION pThis, struct KMKBUILTINCTX *pCtx);
 void kBuildProtectionTerm(PKBUILDPROTECTION pThis);
 int  kBuildProtectionScanEnv(PKBUILDPROTECTION pThis, char **papszEnv, const char *pszPrefix);
Index: trunk/src/kmk/kmkbuiltin/ln.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/ln.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/ln.c	(revision 3192)
@@ -61,12 +61,20 @@
 #include "kmkbuiltin.h"
 
-static int	fflag;				/* Unlink existing files. */
-static int	hflag;				/* Check new name for symlink first. */
-static int	iflag;				/* Interactive mode. */
-static int	sflag;				/* Symbolic, not hard, link. */
-static int	vflag;				/* Verbose output. */
-					/* System link call. */
-static int (*linkf)(const char *, const char *);
-static char	linkch;
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+typedef struct LNINSTANCE
+{
+    PKMKBUILTINCTX pCtx;
+    int	fflag;				/* Unlink existing files. */
+    int	hflag;				/* Check new name for symlink first. */
+    int	iflag;				/* Interactive mode. */
+    int	sflag;				/* Symbolic, not hard, link. */
+    int	vflag;				/* Verbose output. */
+    int (*linkf)(const char *, const char *); /* System link call. */
+    char	linkch;
+} LNINSTANCE;
+typedef LNINSTANCE *PLNINSTANCE;
+
 static struct option long_options[] =
 {
@@ -77,11 +85,12 @@
 
 
-static int	linkit(const char *, const char *, int);
-static int	usage(FILE *);
+static int	linkit(PLNINSTANCE,const char *, const char *, int);
+static int	usage(PKMKBUILTINCTX, int);
 
 
 int
-kmk_builtin_ln(int argc, char *argv[], char **envp)
-{
+kmk_builtin_ln(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx)
+{
+	LNINSTANCE This;
 	struct stat sb;
 	char *sourcedir;
@@ -89,10 +98,14 @@
 
 	/* initialize globals. */
-	fflag = hflag = iflag = sflag = vflag = 0;
-	linkch = 0;
-	linkf = NULL;
+	This.pCtx = pCtx;
+	This.fflag = 0;
+	This.hflag = 0;
+	This.iflag = 0;
+	This.sflag = 0;
+	This.vflag = 0;
+	This.linkch = 0;
+	This.linkf = NULL;
 
 	/* kmk: reset getopt() and set program name. */
-	g_progname = argv[0];
 	opterr = 1;
 	optarg = NULL;
@@ -103,23 +116,23 @@
 		switch (ch) {
 		case 'f':
-			fflag = 1;
-			iflag = 0;
+			This.fflag = 1;
+			This.iflag = 0;
 			break;
 		case 'h':
 		case 'n':
-			hflag = 1;
+			This.hflag = 1;
 			break;
 		case 'i':
-			iflag = 1;
-			fflag = 0;
+			This.iflag = 1;
+			This.fflag = 0;
 			break;
 		case 's':
-			sflag = 1;
+			This.sflag = 1;
 			break;
 		case 'v':
-			vflag = 1;
+			This.vflag = 1;
 			break;
 		case 261:
-			usage(stdout);
+			usage(pCtx, 0);
 			return 0;
 		case 262:
@@ -127,5 +140,5 @@
 		case '?':
 		default:
-			return usage(stderr);
+			return usage(pCtx, 1);
 		}
 
@@ -133,15 +146,15 @@
 	argc -= optind;
 
-	linkf = sflag ? symlink : link;
-	linkch = sflag ? '-' : '=';
+	This.linkf = This.sflag ? symlink : link;
+	This.linkch = This.sflag ? '-' : '=';
 
 	switch(argc) {
 	case 0:
-		return usage(stderr);
+		return usage(pCtx, 1);
 		/* NOTREACHED */
 	case 1:				/* ln target */
-		return linkit(argv[0], ".", 1);
+		return linkit(&This, argv[0], ".", 1);
 	case 2:				/* ln target source */
-		return linkit(argv[0], argv[1], 0);
+		return linkit(&This, argv[0], argv[1], 0);
 	default:
 		;
@@ -149,5 +162,5 @@
 					/* ln target1 target2 directory */
 	sourcedir = argv[argc - 1];
-	if (hflag && lstat(sourcedir, &sb) == 0 && S_ISLNK(sb.st_mode)) {
+	if (This.hflag && lstat(sourcedir, &sb) == 0 && S_ISLNK(sb.st_mode)) {
 		/*
 		 * We were asked not to follow symlinks, but found one at
@@ -155,17 +168,17 @@
 		 */
 		errno = ENOTDIR;
-		return err(1, "st_mode: %s", sourcedir);
+		return err(pCtx, 1, "st_mode: %s", sourcedir);
 	}
 	if (stat(sourcedir, &sb))
-		return err(1, "stat: %s", sourcedir);
+		return err(pCtx, 1, "stat: %s", sourcedir);
 	if (!S_ISDIR(sb.st_mode))
-		return usage(stderr);
+		return usage(pCtx, 1);
 	for (exitval = 0; *argv != sourcedir; ++argv)
-		exitval |= linkit(*argv, sourcedir, 1);
+		exitval |= linkit(&This, *argv, sourcedir, 1);
 	return exitval;
 }
 
 static int
-linkit(const char *target, const char *source, int isdir)
+linkit(PLNINSTANCE pThis, const char *target, const char *source, int isdir)
 {
 	struct stat sb;
@@ -174,8 +187,8 @@
 	char path[PATH_MAX];
 
-	if (!sflag) {
+	if (!pThis->sflag) {
 		/* If target doesn't exist, quit now. */
 		if (stat(target, &sb)) {
-			warn("stat: %s", target);
+			warn(pThis->pCtx, "stat: %s", target);
 			return (1);
 		}
@@ -183,5 +196,5 @@
 		if (S_ISDIR(sb.st_mode)) {
 			errno = EISDIR;
-			warn("st_mode: %s", target);
+			warn(pThis->pCtx, "st_mode: %s", target);
 			return (1);
 		}
@@ -194,5 +207,5 @@
 	if (isdir ||
 	    (lstat(source, &sb) == 0 && S_ISDIR(sb.st_mode)) ||
-	    (!hflag && stat(source, &sb) == 0 && S_ISDIR(sb.st_mode))) {
+	    (!pThis->hflag && stat(source, &sb) == 0 && S_ISDIR(sb.st_mode))) {
 #if defined(_MSC_VER) || defined(__OS2__)
 		char *p2 = strrchr(target, '\\');
@@ -210,5 +223,5 @@
 		    (ssize_t)sizeof(path)) {
 			errno = ENAMETOOLONG;
-			warn("snprintf: %s", target);
+			warn(pThis->pCtx, "snprintf: %s", target);
 			return (1);
 		}
@@ -221,10 +234,10 @@
 	 * and interactively if -i was specified.
 	 */
-	if (fflag && exists) {
+	if (pThis->fflag && exists) {
 		if (unlink(source)) {
-			warn("unlink: %s", source);
-			return (1);
-		}
-	} else if (iflag && exists) {
+			warn(pThis->pCtx, "unlink: %s", source);
+			return (1);
+		}
+	} else if (pThis->iflag && exists) {
 		fflush(stdout);
 		fprintf(stderr, "replace %s? ", source);
@@ -234,10 +247,10 @@
 			ch = getchar();
 		if (first != 'y' && first != 'Y') {
-			fprintf(stderr, "not replaced\n");
+			kmk_builtin_ctx_printf(pThis->pCtx, 1, "not replaced\n");
 			return (1);
 		}
 
 		if (unlink(source)) {
-			warn("unlink: %s", source);
+			warn(pThis->pCtx, "unlink: %s", source);
 			return (1);
 		}
@@ -245,22 +258,33 @@
 
 	/* Attempt the link. */
-	if ((*linkf)(target, source)) {
-		warn("%s: %s", linkf == link ? "link" : "symlink", source);
+	if ((*pThis->linkf)(target, source)) {
+		warn(pThis->pCtx, "%s: %s", pThis->linkf == link ? "link" : "symlink", source);
 		return (1);
 	}
-	if (vflag)
-		(void)printf("%s %c> %s\n", source, linkch, target);
+	if (pThis->vflag)
+		kmk_builtin_ctx_printf(pThis->pCtx, 0, "%s %c> %s\n", source, pThis->linkch, target);
 	return (0);
 }
 
 static int
-usage(FILE *pf)
-{
-	fprintf(pf, "usage: %s [-fhinsv] source_file [target_file]\n"
-				"   or: %s [-fhinsv] source_file ... target_dir\n"
-                "   or: %s source_file target_file\n"
-				"   or: %s --help\n"
-				"   or: %s --version\n",
-                g_progname, g_progname, g_progname, g_progname, g_progname);
+usage(PKMKBUILTINCTX pCtx, int fIsErr)
+{
+	kmk_builtin_ctx_printf(pCtx,fIsErr,
+		"usage: %s [-fhinsv] source_file [target_file]\n"
+		"   or: %s [-fhinsv] source_file ... target_dir\n"
+		"   or: %s source_file target_file\n"
+		"   or: %s --help\n"
+		"   or: %s --version\n",
+		pCtx->pszProgName, pCtx->pszProgName, pCtx->pszProgName,
+		pCtx->pszProgName, pCtx->pszProgName);
 	return 1;
 }
+
+#ifdef KMK_BUILTIN_STANDALONE
+int main(int argc, char **argv, char **envp)
+{
+	KMKBUILTINCTX Ctx = { "kmk_ln", NULL };
+	return kmk_builtin_ln(argc, argv, envp, &Ctx);
+}
+#endif
+
Index: trunk/src/kmk/kmkbuiltin/md5sum.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/md5sum.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/md5sum.c	(revision 3192)
@@ -49,25 +49,25 @@
  * Prints the usage and return 1.
  */
-static int usage(FILE *pOut)
-{
-    fprintf(pOut,
-            "usage: md5sum [-bt] [-o list-file] file(s)\n"
-            "   or: md5sum [-btwq] -c list-file(s)\n"
-            "   or: md5sum [-btq] -C MD5 file\n"
-            "\n"
-            " -c, --check       Check MD5 and files found in the specified list file(s).\n"
-            "                   The default is to compute MD5 sums of the specified files\n"
-            "                   and print them to stdout in list form.\n"
-            " -C, --check-file  This is followed by an MD5 sum and the file to check.\n"
-            " -b, --binary      Read files in binary mode. (default)\n"
-            " -t, --text        Read files in text mode.\n"
-            " -m, --manifest    Output in kBuild fetch 'manifest' format.\n"
-            " -p, --progress    Show progress indicator on large files.\n"
-            " -o, --output      Name of the output list file. Useful with -p.\n"
-            " -q, --status      Be quiet.\n"
-            " -w, --warn        Ignored. Always warn, unless quiet.\n"
-            " -h, --help        This usage info.\n"
-            " -v, --version     Show version information and exit.\n"
-            );
+static int usage(PKMKBUILTINCTX pCtx, int fIsErr)
+{
+    kmk_builtin_ctx_printf(pCtx, fIsErr,
+                           "usage: md5sum [-bt] [-o list-file] file(s)\n"
+                           "   or: md5sum [-btwq] -c list-file(s)\n"
+                           "   or: md5sum [-btq] -C MD5 file\n"
+                           "\n"
+                           " -c, --check       Check MD5 and files found in the specified list file(s).\n"
+                           "                   The default is to compute MD5 sums of the specified files\n"
+                           "                   and print them to stdout in list form.\n"
+                           " -C, --check-file  This is followed by an MD5 sum and the file to check.\n"
+                           " -b, --binary      Read files in binary mode. (default)\n"
+                           " -t, --text        Read files in text mode.\n"
+                           " -m, --manifest    Output in kBuild fetch 'manifest' format.\n"
+                           " -p, --progress    Show progress indicator on large files.\n"
+                           " -o, --output      Name of the output list file. Useful with -p.\n"
+                           " -q, --status      Be quiet.\n"
+                           " -w, --warn        Ignored. Always warn, unless quiet.\n"
+                           " -h, --help        This usage info.\n"
+                           " -v, --version     Show version information and exit.\n"
+                           );
     return 1;
 }
@@ -405,4 +405,5 @@
  *
  * @returns 0 if it matches, 1 if it doesn't or an error occurs.
+ * @param   pCtx        The command execution context.
  * @param   pszFilename The name of the file to check.
  * @param   pszDigest   The MD5 digest string.
@@ -411,5 +412,6 @@
  * @param   fProgress   Whether to show an progress indicator on large files.
  */
-static int check_one_file(const char *pszFilename, const char *pszDigest, unsigned fText, unsigned fQuiet, unsigned fProgress)
+static int check_one_file(PKMKBUILTINCTX pCtx, const char *pszFilename, const char *pszDigest, unsigned fText,
+                          unsigned fQuiet, unsigned fProgress)
 {
     unsigned char Digest[16];
@@ -425,13 +427,12 @@
         {
             if (!fQuiet)
-                fprintf(stdout, "%s: ", pszFilename);
+                kmk_builtin_ctx_printf(pCtx, 0, "%s: ", pszFilename);
             rc = check_md5sum(pvFile, Digest, fProgress);
             close_file(pvFile);
             if (!fQuiet)
             {
-                fprintf(stdout, "%s\n", !rc ? "OK" : rc < 0 ? "FAILURE" : "ERROR");
-                fflush(stdout);
+                kmk_builtin_ctx_printf(pCtx, 0, "%s\n", !rc ? "OK" : rc < 0 ? "FAILURE" : "ERROR");
                 if (rc > 0)
-                    errx(1, "Error reading '%s': %s", pszFilename, strerror(rc));
+                    errx(pCtx, 1, "Error reading '%s': %s", pszFilename, strerror(rc));
             }
             if (rc)
@@ -441,5 +442,5 @@
         {
             if (!fQuiet)
-                errx(1, "Failed to open '%s': %s", pszFilename, strerror(errno));
+                errx(pCtx, 1, "Failed to open '%s': %s", pszFilename, strerror(errno));
             rc = 1;
         }
@@ -447,6 +448,6 @@
     else
     {
-        errx(1, "Malformed MD5 digest '%s'!", pszDigest);
-        errx(1, "                      %*s^", rc - 1, "");
+        errx(pCtx, 1, "Malformed MD5 digest '%s'!", pszDigest);
+        errx(pCtx, 1, "                      %*s^", rc - 1, "");
         rc = 1;
     }
@@ -460,11 +461,13 @@
  *
  * @returns 0 if all checks out file, 1 if one or more fails or there are read errors.
+ * @param   pCtx            The command execution context.
  * @param   pszFilename     The name of the file.
  * @param   fText           The default mode, text or binary. Only used when fBinaryTextOpt is true.
  * @param   fBinaryTextOpt  Whether a -b or -t option was specified and should be used.
  * @param   fQuiet          Whether to be quiet.
- * @param   fProgress   Whether to show an progress indicator on large files.
- */
-static int check_files(const char *pszFilename, int fText, int fBinaryTextOpt, int fQuiet, unsigned fProgress)
+ * @param   fProgress       Whether to show an progress indicator on large files.
+ */
+static int check_files(PKMKBUILTINCTX pCtx, const char *pszFilename, int fText, int fBinaryTextOpt,
+                       int fQuiet, unsigned fProgress)
 {
     int rc = 0;
@@ -539,13 +542,12 @@
                         {
                             if (!fQuiet)
-                                fprintf(stdout, "%s: ", pszFilename);
+                                kmk_builtin_ctx_printf(pCtx, 0, "%s: ", pszFilename);
                             rc2 = check_md5sum(pvFile, Digest, fProgress);
                             close_file(pvFile);
                             if (!fQuiet)
                             {
-                                fprintf(stdout, "%s\n", !rc2 ? "OK" : rc2 < 0 ? "FAILURE" : "ERROR");
-                                fflush(stdout);
+                                kmk_builtin_ctx_printf(pCtx, 0, "%s\n", !rc2 ? "OK" : rc2 < 0 ? "FAILURE" : "ERROR");
                                 if (rc2 > 0)
-                                    errx(1, "Error reading '%s': %s", pszFilename, strerror(rc2));
+                                    errx(pCtx, 1, "Error reading '%s': %s", pszFilename, strerror(rc2));
                             }
                             if (rc2)
@@ -555,5 +557,5 @@
                         {
                             if (!fQuiet)
-                                errx(1, "Failed to open '%s': %s", pszFilename, strerror(errno));
+                                errx(pCtx, 1, "Failed to open '%s': %s", pszFilename, strerror(errno));
                             rc = 1;
                         }
@@ -561,13 +563,13 @@
                     else if (!fQuiet)
                     {
-                        errx(1, "%s (%d): Ignoring malformed digest '%s' (digest)", pszFilename, iLine, pszDigest);
-                        errx(1, "%s (%d):                            %*s^", pszFilename, iLine, rc2 - 1, "");
+                        errx(pCtx, 1, "%s (%d): Ignoring malformed digest '%s' (digest)", pszFilename, iLine, pszDigest);
+                        errx(pCtx, 1, "%s (%d):                            %*s^", pszFilename, iLine, rc2 - 1, "");
                     }
                 }
                 else if (!fQuiet)
-                    errx(1, "%s (%d): Ignoring malformed line!", pszFilename, iLine);
+                    errx(pCtx, 1, "%s (%d): Ignoring malformed line!", pszFilename, iLine);
             }
             else if (!fQuiet)
-                errx(1, "%s (%d): Ignoring malformed line!", pszFilename, iLine);
+                errx(pCtx, 1, "%s (%d): Ignoring malformed line!", pszFilename, iLine);
         } /* while more lines */
 
@@ -576,5 +578,5 @@
     else
     {
-        errx(1, "Failed to open '%s': %s", pszFilename, strerror(errno));
+        errx(pCtx, 1, "Failed to open '%s': %s", pszFilename, strerror(errno));
         rc = 1;
     }
@@ -588,4 +590,5 @@
  *
  * @returns 0 on success, 1 on any kind of failure.
+ * @param   pCtx            Command context.
  * @param   pszFilename     The file to process.
  * @param   fText           The mode to open the file in.
@@ -595,5 +598,5 @@
  * @param   pOutput         Where to write the list. Progress is always written to stdout.
  */
-static int md5sum_file(const char *pszFilename, unsigned fText, unsigned fQuiet, unsigned fProgress,
+static int md5sum_file(PKMKBUILTINCTX pCtx, const char *pszFilename, unsigned fText, unsigned fQuiet, unsigned fProgress,
                        unsigned fManifest, FILE *pOutput)
 {
@@ -631,5 +634,5 @@
                 if (pOutput)
                     fprintf(pOutput, "%s %s%s\n", szDigest, fText ? "" : "*", pszFilename);
-                fprintf(stdout, "%s %s%s\n", szDigest, fText ? "" : "*", pszFilename);
+                kmk_builtin_ctx_printf(pCtx, 0, "%s %s%s\n", szDigest, fText ? "" : "*", pszFilename);
             }
             else
@@ -637,14 +640,14 @@
                 if (pOutput)
                     fprintf(pOutput, "%s_SIZE := %" KU64_PRI "\n%s_MD5  := %s\n", pszFilename, cbFile, pszFilename, szDigest);
-                fprintf(stdout, "%s_SIZE := %" KU64_PRI "\n%s_MD5  := %s\n", pszFilename, cbFile, pszFilename, szDigest);
+                kmk_builtin_ctx_printf(pCtx, 0, "%s_SIZE := %" KU64_PRI "\n%s_MD5  := %s\n",
+                                       pszFilename, cbFile, pszFilename, szDigest);
             }
             if (pOutput)
                 fflush(pOutput);
-            fflush(stdout);
         }
         else
         {
             if (!fQuiet)
-                errx(1, "Failed to open '%s': %s", pszFilename, strerror(rc));
+                errx(pCtx, 1, "Failed to open '%s': %s", pszFilename, strerror(rc));
             rc = 1;
         }
@@ -653,5 +656,5 @@
     {
         if (!fQuiet)
-            errx(1, "Failed to open '%s': %s", pszFilename, strerror(errno));
+            errx(pCtx, 1, "Failed to open '%s': %s", pszFilename, strerror(errno));
         rc = 1;
     }
@@ -665,5 +668,5 @@
  * Somewhat similar to the GNU coreutil md5sum command.
  */
-int kmk_builtin_md5sum(int argc, char **argv, char **envp)
+int kmk_builtin_md5sum(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx)
 {
     int i;
@@ -679,11 +682,9 @@
     FILE *pOutput = NULL;
 
-    g_progname = argv[0];
-
     /*
      * Print usage if no arguments.
      */
     if (argc <= 1)
-        return usage(stderr);
+        return usage(pCtx, 1);
 
     /*
@@ -751,5 +752,9 @@
 
                     case 'p':
-                        fProgress = 1;
+                        fProgress = 1 && isatty(fileno(stdout))
+#ifndef KMK_BUILTIN_STANDALONE
+                                 && (!pCtx->pOut || !pCtx->pOut->syncout)
+#endif
+                                  ;
                         break;
 
@@ -763,5 +768,5 @@
 
                     case 'h':
-                        usage(stdout);
+                        usage(pCtx, 0);
                         return 0;
 
@@ -783,5 +788,5 @@
                         else
                         {
-                            errx(1, "'-C' is missing the MD5 sum!");
+                            errx(pCtx, 1, "'-C' is missing the MD5 sum!");
                             return 1;
                         }
@@ -790,9 +795,9 @@
                         else
                         {
-                            errx(1, "'-C' is missing the filename!");
+                            errx(pCtx, 1, "'-C' is missing the filename!");
                             return 1;
                         }
 
-                        rc |= check_one_file(pszFilename, pszDigest, fText, fQuiet, fProgress && !fQuiet);
+                        rc |= check_one_file(pCtx, pszFilename, pszDigest, fText, fQuiet, fProgress && !fQuiet);
                         psz = "\0";
                         break;
@@ -806,5 +811,5 @@
                         if (fChecking)
                         {
-                            errx(1, "'-o' cannot be used with -c or -C!");
+                            errx(pCtx, 1, "'-o' cannot be used with -c or -C!");
                             return 1;
                         }
@@ -816,5 +821,5 @@
                         else
                         {
-                            errx(1, "'-o' is missing the file name!");
+                            errx(pCtx, 1, "'-o' is missing the file name!");
                             return 1;
                         }
@@ -825,11 +830,11 @@
 
                     default:
-                        errx(1, "Invalid option '%c'! (%s)", *psz, argv[i]);
-                        return usage(stderr);
+                        errx(pCtx, 1, "Invalid option '%c'! (%s)", *psz, argv[i]);
+                        return usage(pCtx, 1);
                 }
             } while (*++psz);
         }
         else if (fChecking)
-            rc |= check_files(argv[i], fText, fBinaryTextOpt, fQuiet, fProgress && !fQuiet);
+            rc |= check_files(pCtx, argv[i], fText, fBinaryTextOpt, fQuiet, fProgress && !fQuiet);
         else
         {
@@ -842,5 +847,5 @@
                 if (!pOutput)
                 {
-                    rc = err(1, "fopen(\"%s\", \"w" KMK_FOPEN_NO_INHERIT_MODE "\") failed", pszOutput);
+                    rc = err(pCtx, 1, "fopen(\"%s\", \"w" KMK_FOPEN_NO_INHERIT_MODE "\") failed", pszOutput);
                     break;
                 }
@@ -848,5 +853,5 @@
             }
 
-            rc |= md5sum_file(argv[i], fText, fQuiet, fProgress && !fQuiet && !fManifest, fManifest, pOutput);
+            rc |= md5sum_file(pCtx, argv[i], fText, fQuiet, fProgress && !fQuiet && !fManifest, fManifest, pOutput);
         }
         i++;
@@ -858,2 +863,12 @@
 }
 
+
+#ifdef KMK_BUILTIN_STANDALONE
+int main(int argc, char **argv, char **envp)
+{
+    KMKBUILTINCTX Ctx = { "kmk_md5sum", NULL };
+    return kmk_builtin_md5sum(argc, argv, envp, &Ctx);
+}
+#endif
+
+
Index: trunk/src/kmk/kmkbuiltin/mkdir.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/mkdir.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/mkdir.c	(revision 3192)
@@ -72,5 +72,4 @@
 
 
-static int vflag;
 static struct option long_options[] =
 {
@@ -84,23 +83,19 @@
 extern mode_t bsd_getmode(const void *bbox, mode_t omode);
 
-static int	build(char *, mode_t);
-static int	usage(FILE *);
+static int	build(PKMKBUILTINCTX pCtx, char *, mode_t, int);
+static int	usage(PKMKBUILTINCTX pCtx, int fIsErr);
 
 
 int
-kmk_builtin_mkdir(int argc, char *argv[], char **envp)
-{
-	int ch, exitval, success, pflag;
+kmk_builtin_mkdir(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx)
+{
+	int ch, exitval, success, pflag, vflag;
 	mode_t omode, *set = (mode_t *)NULL;
 	char *mode;
 
-	omode = pflag = 0;
+	omode = pflag = vflag = 0;
 	mode = NULL;
 
-	/* reinitialize globals */
-	vflag = 0;
-
 	/* kmk: reset getopt and set progname */
-	g_progname = argv[0];
 	opterr = 1;
 	optarg = NULL;
@@ -119,11 +114,11 @@
 			break;
 		case 261:
-			usage(stdout);
+			usage(pCtx, 0);
 			return 0;
 		case 262:
 			return kbuild_version(argv[0]);
 		case '?':
-			default:
-			return usage(stderr);
+		default:
+			return usage(pCtx, 1);
 		}
 
@@ -131,5 +126,5 @@
 	argv += optind;
 	if (argv[0] == NULL)
-		return usage(stderr);
+		return usage(pCtx, 1);
 
 	if (mode == NULL) {
@@ -137,5 +132,5 @@
 	} else {
 		if ((set = bsd_setmode(mode)) == NULL)
-                        return errx(1, "invalid file mode: %s", mode);
+                        return errx(pCtx, 1, "invalid file mode: %s", mode);
 		omode = bsd_getmode(set, S_IRWXU | S_IRWXG | S_IRWXO);
 		free(set);
@@ -145,14 +140,14 @@
 		success = 1;
 		if (pflag) {
-			if (build(*argv, omode))
+			if (build(pCtx, *argv, omode, vflag))
 				success = 0;
 		} else if (mkdir(*argv, omode) < 0) {
 			if (errno == ENOTDIR || errno == ENOENT)
-				warn("mkdir: %s", dirname(*argv));
+				warn(pCtx, "mkdir: %s", dirname(*argv));
 			else
-                                warn("mkdir: %s", *argv);
+                                warn(pCtx, "mkdir: %s", *argv);
 			success = 0;
 		} else if (vflag)
-			(void)printf("%s\n", *argv);
+			kmk_builtin_ctx_printf(pCtx, 0, "%s\n", *argv);
 
 		if (!success)
@@ -166,5 +161,5 @@
 		 */
 		if (success && mode != NULL && chmod(*argv, omode) == -1) {
-			warn("chmod: %s", *argv);
+			warn(pCtx, "chmod: %s", *argv);
 			exitval = 1;
 		}
@@ -173,6 +168,14 @@
 }
 
+#ifdef KMK_BUILTIN_STANDALONE
+int main(int argc, char **argv, char **envp)
+{
+    KMKBUILTINCTX Ctx = { "kmk_mkdir", NULL };
+    return kmk_builtin_mkdir(argc, argv, envp, &Ctx);
+}
+#endif
+
 static int
-build(char *path, mode_t omode)
+build(PKMKBUILTINCTX pCtx, char *path, mode_t omode, int vflag)
 {
 	struct stat sb;
@@ -251,5 +254,5 @@
 			    || errno == EACCES /* (ditto) */) {
 				if (stat(path, &sb) < 0) {
-					warn("stat: %s", path);
+					warn(pCtx, "stat: %s", path);
 					retval = 1;
 					break;
@@ -259,15 +262,15 @@
 					else
 						errno = ENOTDIR;
-					warn("st_mode: %s", path);
+					warn(pCtx, "st_mode: %s", path);
 					retval = 1;
 					break;
 				}
 			} else {
-				warn("mkdir: %s", path);
+				warn(pCtx, "mkdir: %s", path);
 				retval = 1;
 				break;
 			}
 		} else if (vflag)
-			printf("%s\n", path);
+			kmk_builtin_ctx_printf(pCtx, 0, "%s\n", path);
 		if (!last)
 		    *p = '/';
@@ -279,10 +282,12 @@
 
 static int
-usage(FILE *pf)
-{
-	fprintf(pf, "usage: %s [-pv] [-m mode] directory ...\n"
-	            "   or: %s --help\n"
-	            "   or: %s --version\n",
-	        g_progname, g_progname, g_progname);
+usage(PKMKBUILTINCTX pCtx, int fIsErr)
+{
+	kmk_builtin_ctx_printf(pCtx, fIsErr,
+	                       "usage: %s [-pv] [-m mode] directory ...\n"
+	                       "   or: %s --help\n"
+	                       "   or: %s --version\n",
+	                       pCtx->pszProgName, pCtx->pszProgName, pCtx->pszProgName);
 	return EX_USAGE;
 }
+
Index: trunk/src/kmk/kmkbuiltin/mscfakes.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/mscfakes.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/mscfakes.c	(revision 3192)
@@ -446,6 +446,6 @@
     }
 
+    fprintf(stderr, "warning: symlink() is available on this version of Windows!\n");
     errno = ENOSYS;
-    err(1, "symlink() is not implemented on windows!");
     return -1;
 }
Index: trunk/src/kmk/kmkbuiltin/mv.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/mv.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/mv.c	(revision 3192)
@@ -47,4 +47,8 @@
 #endif
 
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
 #include "config.h"
 #include <sys/types.h>
@@ -89,5 +93,18 @@
 
 
-static int fflg, iflg, nflg, vflg;
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+typedef struct MVINSTANCE
+{
+    PKMKBUILTINCTX pCtx;
+    int fflg, iflg, nflg, vflg;
+} MVINSTANCE;
+typedef MVINSTANCE *PMVINSTANCE;
+
+
+/*********************************************************************************************************************************
+*   Global Variables                                                                                                             *
+*********************************************************************************************************************************/
 static struct option long_options[] =
 {
@@ -98,12 +115,16 @@
 
 
-static int	do_move(char *, char *);
+/*********************************************************************************************************************************
+*   Internal Functions                                                                                                           *
+*********************************************************************************************************************************/
+extern void 	bsd_strmode(mode_t mode, char *p); /* strmode.c */
+
+static int	do_move(PMVINSTANCE, char *, char *);
 #ifdef CROSS_DEVICE_MOVE
 static int	fastcopy(char *, char *, struct stat *);
 static int	copy(char *, char *);
 #endif
-static int	usage(FILE *);
-
-extern void bsd_strmode(mode_t mode, char *p);
+static int	usage(PKMKBUILTINCTX, int);
+
 
 #if !defined(__FreeBSD__) && !defined(__APPLE__) && !defined(__DragonFly__) && !defined(__OpenBSD__)
@@ -132,6 +153,7 @@
 
 int
-kmk_builtin_mv(int argc, char *argv[], char **envp)
-{
+kmk_builtin_mv(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx)
+{
+	MVINSTANCE This;
 	size_t baselen, len;
 	int rval;
@@ -141,9 +163,12 @@
 	char path[PATH_MAX];
 
-	/* kmk: reinitialize globals */
-	fflg = iflg = nflg = vflg = 0;
+	/* Initialize instance. */
+	This.pCtx = pCtx;
+	This.fflg = 0;
+	This.iflg = 0;
+	This.nflg = 0;
+	This.vflg = 0;
 
 	/* kmk: reset getopt and set progname */
-	g_progname = argv[0];
 	opterr = 1;
 	optarg = NULL;
@@ -154,25 +179,25 @@
 		switch (ch) {
 		case 'i':
-			iflg = 1;
-			fflg = nflg = 0;
+			This.iflg = 1;
+			This.fflg = This.nflg = 0;
 			break;
 		case 'f':
-			fflg = 1;
-			iflg = nflg = 0;
+			This.fflg = 1;
+			This.iflg = This.nflg = 0;
 			break;
 		case 'n':
-			nflg = 1;
-			fflg = iflg = 0;
+			This.nflg = 1;
+			This.fflg = This.iflg = 0;
 			break;
 		case 'v':
-			vflg = 1;
+			This.vflg = 1;
 			break;
 		case 261:
-			usage(stdout);
+			usage(pCtx, 0);
 			return 0;
 		case 262:
 			return kbuild_version(argv[0]);
 		default:
-			return usage(stderr);
+			return usage(pCtx, 1);
 		}
 	argc -= optind;
@@ -180,5 +205,5 @@
 
 	if (argc < 2)
-		return usage(stderr);
+		return usage(pCtx, 1);
 
 	/*
@@ -188,14 +213,15 @@
 	if (stat(argv[argc - 1], &sb) || !S_ISDIR(sb.st_mode)) {
 		if (argc > 2)
-			return usage(stderr);
-		return do_move(argv[0], argv[1]);
+			return usage(pCtx, 1);
+		return do_move(&This, argv[0], argv[1]);
 	}
 
 	/* It's a directory, move each file into it. */
-	if (strlen(argv[argc - 1]) > sizeof(path) - 1)
-		return errx(1, "%s: destination pathname too long", *argv);
-	(void)strcpy(path, argv[argc - 1]);
-	baselen = strlen(path);
+	baselen = strlen(argv[argc - 1]);
+	if (baselen > sizeof(path) - 1)
+		return errx(pCtx, 1, "%s: destination pathname too long", *argv);
+	memcpy(path, argv[argc - 1], baselen);
 	endp = &path[baselen];
+	*endp = '\0';
 #if defined(_MSC_VER) || defined(__EMX__)
 	if (!baselen || (*(endp - 1) != '/' && *(endp - 1) != '\\' && *(endp - 1) != ':')) {
@@ -225,9 +251,9 @@
 
 		if ((baselen + (len = strlen(p))) >= PATH_MAX) {
-			warnx("%s: destination pathname too long", *argv);
+			warnx(pCtx, "%s: destination pathname too long", *argv);
 			rval = 1;
 		} else {
 			memmove(endp, p, (size_t)len + 1);
-			if (do_move(*argv, path))
+			if (do_move(&This, *argv, path))
 				rval = 1;
 		}
@@ -236,6 +262,14 @@
 }
 
+#ifdef KMK_BUILTIN_STANDALONE
+int main(int argc, char **argv, char **envp)
+{
+    KMKBUILTINCTX Ctx = { "kmk_mv", NULL };
+    return kmk_builtin_mv(argc, argv, envp, &Ctx);
+}
+#endif
+
 static int
-do_move(char *from, char *to)
+do_move(PMVINSTANCE pThis, char *from, char *to)
 {
 	struct stat sb;
@@ -248,9 +282,9 @@
 	 * make sure the user wants to clobber it.
 	 */
-	if (!fflg && !access(to, F_OK)) {
+	if (!pThis->fflg && !access(to, F_OK)) {
 
 		/* prompt only if source exist */
 		if (lstat(from, &sb) == -1) {
-			warn("%s", from);
+			warn(pThis->pCtx, "%s", from);
 			return (1);
 		}
@@ -258,9 +292,9 @@
 #define YESNO "(y/n [n]) "
 		ask = 0;
-		if (nflg) {
-			if (vflg)
-				printf("%s not overwritten\n", to);
+		if (pThis->nflg) {
+			if (pThis->vflg)
+				kmk_builtin_ctx_printf(pThis->pCtx, 0, "%s not overwritten\n", to);
 			return (0);
-		} else if (iflg) {
+		} else if (pThis->iflg) {
 			(void)fprintf(stderr, "overwrite %s? %s", to, YESNO);
 			ask = 1;
@@ -274,9 +308,10 @@
 		}
 		if (ask) {
+			fflush(stderr);
 			first = ch = getchar();
 			while (ch != '\n' && ch != EOF)
 				ch = getchar();
 			if (first != 'y' && first != 'Y') {
-				(void)fprintf(stderr, "not overwritten\n");
+				kmk_builtin_ctx_printf(pThis->pCtx, 1, "not overwritten\n");
 				return (0);
 			}
@@ -284,6 +319,6 @@
 	}
 	if (!rename(from, to)) {
-		if (vflg)
-			printf("%s -> %s\n", from, to);
+		if (pThis->vflg)
+			kmk_builtin_ctx_printf(pThis->pCtx, 0, "%s -> %s\n", from, to);
 		return (0);
 	}
@@ -292,6 +327,6 @@
 		remove(to);
 		if (!rename(from, to)) {
-			if (vflg)
-				printf("%s -> %s\n", from, to);
+			if (pThis->vflg)
+				kmk_builtin_ctx_printf(pThis->pCtx, 0, "%s -> %s\n", from, to);
 			return (0);
 		}
@@ -301,5 +336,5 @@
 	if (errno == EXDEV) {
 #ifndef CROSS_DEVICE_MOVE
-		warnx("cannot move `%s' to a different device: `%s'", from, to);
+		warnx(pThis->pCtx, "cannot move `%s' to a different device: `%s'", from, to);
 		return (1);
 #else
@@ -312,5 +347,5 @@
 		 */
 		if (lstat(from, &sb) == -1) {
-			warn("%s", from);
+			warn(pThis->pCtx, "%s", from);
 			return (1);
 		}
@@ -318,10 +353,10 @@
 			/* Can't mv(1) a mount point. */
 			if (realpath(from, path) == NULL) {
-				warnx("cannot resolve %s: %s", from, path);
+				warnx(pThis->pCtx, "cannot resolve %s: %s", from, path);
 				return (1);
 			}
 			if (!statfs(path, &sfs) &&
 			    !strcmp(path, sfs.f_mntonname)) {
-				warnx("cannot rename a mount point");
+				warnx(pThis->pCtx, "cannot rename a mount point");
 				return (1);
 			}
@@ -329,5 +364,5 @@
 #endif
 	} else {
-		warn("rename %s to %s", from, to);
+		warn(pThis->pCtx, "rename %s to %s", from, to);
 		return (1);
 	}
@@ -340,9 +375,9 @@
 	 */
 	if (lstat(from, &sb)) {
-		warn("%s", from);
+		warn(pThis->pCtx, "%s", from);
 		return (1);
 	}
 	return (S_ISREG(sb.st_mode) ?
-	    fastcopy(from, to, &sb) : copy(from, to));
+	    fastcopy(pThis, from, to, &sb) : copy(pThis, from, to));
 #endif
 }
@@ -451,5 +486,5 @@
 	}
 	if (vflg)
-		printf("%s -> %s\n", from, to);
+		kmk_builtin_ctx_printf(pThis->pCtx, 0, "%s -> %s\n", from, to);
 	return (0);
 }
@@ -503,11 +538,12 @@
 
 static int
-usage(FILE *pf)
-{
-	fprintf(pf, "usage: %s [-f | -i | -n] [-v] source target\n"
-	            "   or: %s [-f | -i | -n] [-v] source ... directory\n"
-	            "   or: %s --help\n"
-	            "   or: %s --version\n",
-	        g_progname, g_progname, g_progname, g_progname);
+usage(PKMKBUILTINCTX pCtx, int fIsErr)
+{
+	kmk_builtin_ctx_printf(pCtx, fIsErr,
+	                       "usage: %s [-f | -i | -n] [-v] source target\n"
+	                       "   or: %s [-f | -i | -n] [-v] source ... directory\n"
+	                       "   or: %s --help\n"
+	                       "   or: %s --version\n",
+	                       pCtx->pszProgName, pCtx->pszProgName, pCtx->pszProgName, pCtx->pszProgName);
 	return EX_USAGE;
 }
Index: trunk/src/kmk/kmkbuiltin/printf.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/printf.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/printf.c	(revision 3192)
@@ -46,5 +46,9 @@
 #endif*/ /* not lint */
 
-#if !defined(kmk_builtin_printf) && !defined(BUILTIN) && !defined(SHELL)
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#if !defined(KMK_BUILTIN_STANDALONE) && !defined(BUILTIN) && !defined(SHELL)
 # include "../makeint.h"
 # include "../filedef.h"
@@ -83,5 +87,19 @@
 #endif
 
-
+#if 0
+#ifdef BUILTIN		/* csh builtin */
+#define kmk_builtin_printf progprintf
+#endif
+
+#ifdef SHELL		/* sh (aka ash) builtin */
+#define kmk_builtin_printf printfcmd
+#include "../../bin/sh/bltin/bltin.h"
+#endif /* SHELL */
+#endif
+
+
+/*********************************************************************************************************************************
+*   Defined Constants And Macros                                                                                                 *
+*********************************************************************************************************************************/
 #if 0 /*def __GNUC__ - bird: gcc complains about non-ISO-standard escape. */
 #define ESCAPE '\e'
@@ -90,63 +108,14 @@
 #endif
 
-
-static size_t	b_length;
-static char	*b_fmt;
-static int	rval;
-static char  **gargv;
-#if !defined(kmk_builtin_printf) && !defined(BUILTIN) && !defined(SHELL)
-static char *g_o = NULL;
-#endif
-static struct option long_options[] =
-{
-    { "help",   					no_argument, 0, 261 },
-    { "version",   					no_argument, 0, 262 },
-    { 0, 0,	0, 0 },
-};
-
-
-static int	 common_printf(int argc, char *argv[]);
-static void	 conv_escape_str(char *, void (*)(int));
-static char	*conv_escape(char *, char *);
-static char	*conv_expand(const char *);
-static int	 getchr(void);
-static double	 getdouble(void);
-static int	 getwidth(void);
-static intmax_t	 getintmax(void);
-static uintmax_t getuintmax(void);
-static char	*getstr(void);
-static char	*mklong(const char *, int);
-static void      check_conversion(const char *, const char *);
-static int	 usage(FILE *);
-
-static int	flush_buffer(void);
-static void	b_count(int);
-static void	b_output(int);
-static int	wrap_putchar(int ch);
-static int	wrap_printf(const char *, ...);
-
-#ifdef BUILTIN		/* csh builtin */
-#define kmk_builtin_printf progprintf
-#endif
-
-#ifdef SHELL		/* sh (aka ash) builtin */
-#define kmk_builtin_printf printfcmd
-#include "../../bin/sh/bltin/bltin.h"
-#endif /* SHELL */
-
-/* Buffer the output because windows doesn't do line buffering of stdout. */
-static char 	g_achBuf[256];
-static size_t	g_cchBuf;
-
 #define PF(f, func) { \
 	if (fieldwidth != -1) { \
 		if (precision != -1) \
-			(void)wrap_printf(f, fieldwidth, precision, func); \
+			(void)wrap_printf(pThis, f, fieldwidth, precision, func); \
 		else \
-			(void)wrap_printf(f, fieldwidth, func); \
+			(void)wrap_printf(pThis, f, fieldwidth, func); \
 	} else if (precision != -1) \
-		(void)wrap_printf(f, precision, func); \
+		(void)wrap_printf(pThis, f, precision, func); \
 	else \
-		(void)wrap_printf(f, func); \
+		(void)wrap_printf(pThis, f, func); \
 }
 
@@ -163,11 +132,76 @@
 }
 
-int kmk_builtin_printf(int argc, char *argv[], char **envp)
-{
-	int rc;
+
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+typedef struct PRINTFINSTANCE
+{
+    PKMKBUILTINCTX pCtx;
+    size_t b_length;
+    char *b_fmt;
+    int	rval;
+    char **gargv;
+#ifndef KMK_BUILTIN_STANDALONE
+    char *g_o;
+#endif
+    /* Buffer the output because windows doesn't do line buffering of stdout. */
+    size_t g_cchBuf;
+    char g_achBuf[256];
+} PRINTFINSTANCE;
+typedef PRINTFINSTANCE *PPRINTFINSTANCE;
+
+
+/*********************************************************************************************************************************
+*   Global Variables                                                                                                             *
+*********************************************************************************************************************************/
+static struct option long_options[] =
+{
+    { "help",   					no_argument, 0, 261 },
+    { "version",   					no_argument, 0, 262 },
+    { 0, 0,	0, 0 },
+};
+
+
+/*********************************************************************************************************************************
+*   Internal Functions                                                                                                           *
+*********************************************************************************************************************************/
+static int	 common_printf(PPRINTFINSTANCE pThis, int argc, char *argv[]);
+static void	 conv_escape_str(PPRINTFINSTANCE, char *, void (*)(PPRINTFINSTANCE, int));
+static char	*conv_escape(PPRINTFINSTANCE, char *, char *);
+static char	*conv_expand(const char *);
+static int	 getchr(PPRINTFINSTANCE);
+static double	 getdouble(PPRINTFINSTANCE);
+static int	 getwidth(PPRINTFINSTANCE);
+static intmax_t	 getintmax(PPRINTFINSTANCE);
+static uintmax_t getuintmax(PPRINTFINSTANCE);
+static char	*getstr(PPRINTFINSTANCE);
+static char	*mklong(PPRINTFINSTANCE, const char *, int, char[64]);
+static void      check_conversion(PPRINTFINSTANCE, const char *, const char *);
+static int	 usage(PKMKBUILTINCTX, int);
+
+static int	flush_buffer(PPRINTFINSTANCE);
+static void	b_count(PPRINTFINSTANCE, int);
+static void	b_output(PPRINTFINSTANCE, int);
+static int	wrap_putchar(PPRINTFINSTANCE, int ch);
+static int	wrap_printf(PPRINTFINSTANCE, const char *, ...);
+
+
+
+int kmk_builtin_printf(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx)
+{
 	int ch;
+	PRINTFINSTANCE This;
+	This.pCtx = pCtx;
+	This.b_length = 0;
+	This.b_fmt = NULL;
+	This.rval = 0;
+	This.gargv = NULL;
+#ifndef KMK_BUILTIN_STANDALONE
+	This.g_o = NULL;
+#endif
+	This.g_cchBuf = 0;
 
 	/* kmk: reset getopt, set progname and reset buffer. */
-	g_progname = argv[0];
 	opterr = 1;
 	optarg = NULL;
@@ -175,12 +209,8 @@
 	optind = 0; /* init */
 
-#if !defined(SHELL) && !defined(BUILTIN) && !defined(kmk_builtin_printf) /* kmk did this already. */
-	(void)setlocale (LC_ALL, "");
-#endif
-
 	while ((ch = getopt_long(argc, argv, "", long_options, NULL)) != -1) {
 		switch (ch) {
 		case 261:
-			usage(stdout);
+			usage(pCtx, 0);
 			return 0;
 		case 262:
@@ -188,5 +218,5 @@
 		case '?':
 		default:
-			return usage(stderr);
+			return usage(pCtx, 1);
 		}
 	}
@@ -194,16 +224,21 @@
 	argv += optind;
 
-	if (argc < 1) {
-		return usage(stderr);
-	}
-
-	rc = common_printf(argc, argv);
-	return rc;
-}
-
-#ifndef kmk_builtin_printf
+	if (argc < 1)
+		return usage(pCtx, 1);
+	return common_printf(&This, argc, argv);
+}
+
+#ifdef KMK_BUILTIN_STANDALONE
+int main(int argc, char **argv, char **envp)
+{
+	KMKBUILTINCTX Ctx = { "kmk_printf", NULL };
+	setlocale(LC_ALL, "");
+	return kmk_builtin_printf(argc, argv, envp, &Ctx);
+}
+#else /* KMK_BUILTIN_STANDALONE */
 /* entry point used by function.c $(printf ..,..). */
 char *kmk_builtin_func_printf(char *o, char **argv, const char *funcname)
 {
+	PRINTFINSTANCE This;
 	int rc;
 	int argc;
@@ -211,9 +246,17 @@
 	for (argc = 0; argv[argc] != NULL; argc++)
 		/* nothing */;
-
-	g_o = o;
-	rc = common_printf(argc, argv);
-	o = g_o;
-	g_o = NULL;
+	if (argc == 0)
+	    fatal(NILF, strlen(funcname) + INTSTR_LENGTH, _("$(%s): no format string\n"), funcname);
+
+	This.pCtx = NULL;
+	This.b_length = 0;
+	This.b_fmt = NULL;
+	This.rval = 0;
+	This.gargv = NULL;
+	This.g_cchBuf = 0;
+	This.g_o = o;
+
+	rc = common_printf(&This, argc, argv);
+	o = This.g_o;
 
 	if (rc != 0)
@@ -221,7 +264,7 @@
 	return o;
 }
-#endif
-
-static int common_printf(int argc, char *argv[])
+#endif /* KMK_BUILTIN_STANDALONE */
+
+static int common_printf(PPRINTFINSTANCE pThis, int argc, char *argv[])
 {
 	char *fmt, *start;
@@ -230,14 +273,14 @@
 	char *format;
 	int ch;
+	char longbuf[64];
 
 	/* kmk: reinitialize globals */
-	b_length = 0;
-	b_fmt = NULL;
-	rval = 0;
-	gargv = NULL;
-	g_cchBuf = 0;
-
+	pThis->b_length = 0;
+	pThis->b_fmt = NULL;
+	pThis->rval = 0;
+	pThis->gargv = NULL;
+	pThis->g_cchBuf = 0;
 	format = *argv;
-	gargv = ++argv;
+	pThis->gargv = ++argv;
 
 #define SKIP1	"#-+ 0"
@@ -257,10 +300,10 @@
 			if (ch == '\\') {
 				char c_ch;
-				fmt = conv_escape(fmt, &c_ch);
-				wrap_putchar(c_ch);
+				fmt = conv_escape(pThis, fmt, &c_ch);
+				wrap_putchar(pThis, c_ch);
 				continue;
 			}
 			if (ch != '%' || (*fmt == '%' && ++fmt)) {
-				(void)wrap_putchar(ch);
+				(void)wrap_putchar(pThis, ch);
 				continue;
 			}
@@ -272,5 +315,5 @@
 			/* skip to field width */
 			fmt += strspn(fmt, SKIP1);
-			fieldwidth = *fmt == '*' ? getwidth() : -1;
+			fieldwidth = *fmt == '*' ? getwidth(pThis) : -1;
 
 			/* skip to possible '.', get following precision */
@@ -278,5 +321,5 @@
 			if (*fmt == '.')
 				++fmt;
-			precision = *fmt == '*' ? getwidth() : -1;
+			precision = *fmt == '*' ? getwidth(pThis) : -1;
 
 			fmt += strspn(fmt, SKIP2);
@@ -284,6 +327,6 @@
 			ch = *fmt;
 			if (!ch) {
-				flush_buffer();
-				warnx("missing format character");
+				flush_buffer(pThis);
+				warnx(pThis->pCtx, "missing format character");
 				return (1);
 			}
@@ -295,5 +338,5 @@
 
 			case 'B': {
-				const char *p = conv_expand(getstr());
+				const char *p = conv_expand(getstr(pThis));
 				*fmt = 's';
 				PF(start, p);
@@ -305,5 +348,5 @@
 				 * embedded nulls. */
 				static char *a, *t;
-				char *cp = getstr();
+				char *cp = getstr(pThis);
 				/* Free on entry in case shell longjumped out */
 				if (a != NULL)
@@ -314,28 +357,28 @@
 				t = NULL;
 				/* Count number of bytes we want to output */
-				b_length = 0;
-				conv_escape_str(cp, b_count);
-				t = malloc(b_length + 1);
+				pThis->b_length = 0;
+				conv_escape_str(pThis, cp, b_count);
+				t = malloc(pThis->b_length + 1);
 				if (t == NULL)
 					break;
-				memset(t, 'x', b_length);
-				t[b_length] = 0;
+				memset(t, 'x', pThis->b_length);
+				t[pThis->b_length] = 0;
 				/* Get printf to calculate the lengths */
 				*fmt = 's';
 				APF(&a, start, t);
-				b_fmt = a;
+				pThis->b_fmt = a;
 				/* Output leading spaces and data bytes */
-				conv_escape_str(cp, b_output);
+				conv_escape_str(pThis, cp, b_output);
 				/* Add any trailing spaces */
-				wrap_printf("%s", b_fmt);
+				wrap_printf(pThis, "%s", pThis->b_fmt);
 				break;
 			}
 			case 'c': {
-				char p = getchr();
+				char p = getchr(pThis);
 				PF(start, p);
 				break;
 			}
 			case 's': {
-				char *p = getstr();
+				char *p = getstr(pThis);
 				PF(start, p);
 				break;
@@ -343,6 +386,6 @@
 			case 'd':
 			case 'i': {
-				intmax_t p = getintmax();
-				char *f = mklong(start, ch);
+				intmax_t p = getintmax(pThis);
+				char *f = mklong(pThis, start, ch, longbuf);
 				PF(f, p);
 				break;
@@ -352,6 +395,6 @@
 			case 'x':
 			case 'X': {
-				uintmax_t p = getuintmax();
-				char *f = mklong(start, ch);
+				uintmax_t p = getuintmax(pThis);
+				char *f = mklong(pThis, start, ch, longbuf);
 				PF(f, p);
 				break;
@@ -362,11 +405,11 @@
 			case 'g':
 			case 'G': {
-				double p = getdouble();
+				double p = getdouble(pThis);
 				PF(start, p);
 				break;
 			}
 			default:
-				flush_buffer();
-				warnx("%s: invalid directive", start);
+				flush_buffer(pThis);
+				warnx(pThis->pCtx, "%s: invalid directive", start);
 				return 1;
 			}
@@ -374,13 +417,13 @@
 			*fmt = nextch;
 			/* escape if a \c was encountered */
-			if (rval & 0x100) {
-				flush_buffer();
-				return rval & ~0x100;
-			}
-		}
-	} while (gargv != argv && *gargv);
-
-	flush_buffer();
-	return rval;
+			if (pThis->rval & 0x100) {
+				flush_buffer(pThis);
+				return pThis->rval & ~0x100;
+			}
+		}
+	} while (pThis->gargv != argv && *pThis->gargv);
+
+	flush_buffer(pThis);
+	return pThis->rval;
 }
 
@@ -390,7 +433,7 @@
 static void
 /*ARGSUSED*/
-b_count(int ch)
-{
-	b_length++;
+b_count(PPRINTFINSTANCE pThis, int ch)
+{
+	pThis->b_length++;
 	(void)ch;
 }
@@ -399,16 +442,16 @@
 
 static void
-b_output(int ch)
+b_output(PPRINTFINSTANCE pThis, int ch)
 {
 	for (;;) {
-		switch (*b_fmt++) {
+		switch (*pThis->b_fmt++) {
 		case 0:
-			b_fmt--;
+			pThis->b_fmt--;
 			return;
 		case ' ':
-			wrap_putchar(' ');
+			wrap_putchar(pThis, ' ');
 			break;
 		default:
-			wrap_putchar(ch);
+			wrap_putchar(pThis, ch);
 			return;
 		}
@@ -416,20 +459,20 @@
 }
 
-static int wrap_putchar(int ch)
-{
-#ifndef kmk_builtin_printf
-	if (g_o) {
+static int wrap_putchar(PPRINTFINSTANCE pThis, int ch)
+{
+#ifndef KMK_BUILTIN_STANDALONE
+	if (pThis->g_o) {
 		char sz[2];
 		sz[0] = ch; sz[1] = '\0';
-		g_o = variable_buffer_output(g_o, sz, 1);
-		return ch;
-	}
+		pThis->g_o = variable_buffer_output(pThis->g_o, sz, 1);
+	}
+	else
 #endif
 	/* Buffered output. */
-	if (g_cchBuf + 1 < sizeof(g_achBuf)) {
-		g_achBuf[g_cchBuf++] = ch;
+	if (pThis->g_cchBuf + 1 < sizeof(pThis->g_achBuf)) {
+		pThis->g_achBuf[pThis->g_cchBuf++] = ch;
 	} else {
-		int rc = flush_buffer();
-		g_achBuf[g_cchBuf++] = ch;
+		int rc = flush_buffer(pThis);
+		pThis->g_achBuf[pThis->g_cchBuf++] = ch;
 		if (rc)
 			return -1;
@@ -438,5 +481,5 @@
 }
 
-static int wrap_printf(const char * fmt, ...)
+static int wrap_printf(PPRINTFINSTANCE pThis, const char * fmt, ...)
 {
 	ssize_t cchRet;
@@ -448,14 +491,14 @@
 	va_end(va);
 	if (cchRet >= 0) {
-#ifndef kmk_builtin_printf
-		if (g_o) {
-			g_o = variable_buffer_output(g_o, pszTmp, cchRet);
+#ifndef KMK_BUILTIN_STANDALONE
+		if (pThis->g_o) {
+			pThis->g_o = variable_buffer_output(pThis->g_o, pszTmp, cchRet);
 		} else
 #endif
 		{
-			if (cchRet + g_cchBuf <= sizeof(g_achBuf)) {
+			if (cchRet + pThis->g_cchBuf <= sizeof(pThis->g_achBuf)) {
 				/* We've got space in the buffer. */
-				memcpy(&g_achBuf[g_cchBuf], pszTmp, cchRet);
-				g_cchBuf += cchRet;
+				memcpy(&pThis->g_achBuf[pThis->g_cchBuf], pszTmp, cchRet);
+				pThis->g_cchBuf += cchRet;
 			} else {
 				/* Try write out complete lines. */
@@ -466,14 +509,18 @@
 					const char *pchNewLine = strchr(pszLeft, '\n');
 					ssize_t     cchLine    = pchNewLine ? pchNewLine - pszLeft + 1 : cchLeft;
-					if (g_cchBuf + cchLine <= sizeof(g_achBuf)) {
-						memcpy(&g_achBuf[g_cchBuf], pszLeft, cchLine);
-						g_cchBuf += cchLine;
+					if (pThis->g_cchBuf + cchLine <= sizeof(pThis->g_achBuf)) {
+						memcpy(&pThis->g_achBuf[pThis->g_cchBuf], pszLeft, cchLine);
+						pThis->g_cchBuf += cchLine;
 					} else {
-						if (flush_buffer() < 0) {
+						if (flush_buffer(pThis) < 0) {
 							return -1;
 						}
-						if (fwrite(pszLeft, cchLine, 1, stdout) < 1) {
+#ifndef KMK_BUILTIN_STANDALONE
+						if (output_write_text(pThis->pCtx->pOut, 0,pszLeft, cchLine) < 1)
+#else
+						if (fwrite(pszLeft, cchLine, 1, stdout) < 1)
+#endif
+
 							return -1;
-						}
 					}
 					pszLeft += cchLine;
@@ -490,10 +537,14 @@
  * Flushes the g_abBuf/g_cchBuf.
  */
-static int flush_buffer(void)
-{
-    if (g_cchBuf > 0) {
-		ssize_t cchToWrite = g_cchBuf;
-		ssize_t cchWritten = fwrite(g_achBuf, 1, g_cchBuf, stdout);
-		g_cchBuf = 0;
+static int flush_buffer(PPRINTFINSTANCE pThis)
+{
+    ssize_t cchToWrite = pThis->g_cchBuf;
+    if (cchToWrite > 0) {
+#ifndef KMK_BUILTIN_STANDALONE
+		ssize_t cchWritten = output_write_text(pThis->pCtx->pOut, 0, pThis->g_achBuf, cchToWrite);
+#else
+		ssize_t cchWritten = fwrite(pThis->g_achBuf, 1, cchToWrite, stdout);
+#endif
+		pThis->g_cchBuf = 0;
 		if (cchWritten >= cchToWrite) {
 			/* likely */
@@ -509,5 +560,9 @@
 
 			while (off < cchToWrite) {
-				cchWritten = fwrite(&g_achBuf[off], 1, cchToWrite - off, stdout);
+#ifndef KMK_BUILTIN_STANDALONE
+				cchWritten = output_write_text(pThis->pCtx->pOut, 0, &pThis->g_achBuf[off], cchToWrite - off);
+#else
+				cchWritten = fwrite(&pThis->g_achBuf[off], 1, cchToWrite - off, stdout);
+#endif
 				if (cchWritten > 0) {
 					off += cchWritten;
@@ -530,5 +585,5 @@
  */
 static void
-conv_escape_str(char *str, void (*do_putchar)(int))
+conv_escape_str(PPRINTFINSTANCE pThis, char *str, void (*do_putchar)(PPRINTFINSTANCE, int))
 {
 	int value;
@@ -538,5 +593,5 @@
 	while ((ch = *str++) != '\0') {
 		if (ch != '\\') {
-			do_putchar(ch);
+			do_putchar(pThis, ch);
 			continue;
 		}
@@ -545,5 +600,5 @@
 		if (ch == 'c') {
 			/* \c as in SYSV echo - abort all processing.... */
-			rval |= 0x100;
+			pThis->rval |= 0x100;
 			break;
 		}
@@ -561,5 +616,5 @@
 				octnum = (octnum << 3) | (*str++ - '0');
 			}
-			do_putchar(octnum);
+			do_putchar(pThis, octnum);
 			continue;
 		}
@@ -567,5 +622,5 @@
 		/* \[M][^|-]C as defined by vis(3) */
 		if (ch == 'M' && *str == '-') {
-			do_putchar(0200 | str[1]);
+			do_putchar(pThis, 0200 | str[1]);
 			str += 2;
 			continue;
@@ -583,11 +638,11 @@
 			else
 				value |= ch & 037;
-			do_putchar(value);
+			do_putchar(pThis, value);
 			continue;
 		}
 
 		/* Finally test for sequences valid in the format string */
-		str = conv_escape(str - 1, &c);
-		do_putchar(c);
+		str = conv_escape(pThis, str - 1, &c);
+		do_putchar(pThis, c);
 	}
 }
@@ -597,5 +652,5 @@
  */
 static char *
-conv_escape(char *str, char *conv_ch)
+conv_escape(PPRINTFINSTANCE pThis, char *str, char *conv_ch)
 {
 	int value;
@@ -643,6 +698,6 @@
 
 	default:
-		warnx("unknown escape sequence `\\%c'", ch);
-		rval = 1;
+		warnx(pThis->pCtx, "unknown escape sequence `\\%c'", ch);
+		pThis->rval = 1;
 		value = ch;
 		break;
@@ -720,12 +775,11 @@
 
 static char *
-mklong(const char *str, int ch)
-{
-	static char copy[64];
+mklong(PPRINTFINSTANCE pThis, const char *str, int ch, char copy[64])
+{
 	size_t len;
 
 	len = strlen(str) - 1;
-	if (len > sizeof(copy) - 5) {
-		warnx("format %s too complex\n", str);
+	if (len > 64 - 5) {
+		warnx(pThis->pCtx, "format %s too complex\n", str);
 		len = 4;
 	}
@@ -744,38 +798,38 @@
 
 static int
-getchr(void)
-{
-	if (!*gargv)
+getchr(PPRINTFINSTANCE pThis)
+{
+	if (!*pThis->gargv)
 		return 0;
-	return (int)**gargv++;
+	return (int)**pThis->gargv++;
 }
 
 static char *
-getstr(void)
+getstr(PPRINTFINSTANCE pThis)
 {
 	static char empty[] = "";
-	if (!*gargv)
+	if (!*pThis->gargv)
 		return empty;
-	return *gargv++;
+	return *pThis->gargv++;
 }
 
 static int
-getwidth(void)
+getwidth(PPRINTFINSTANCE pThis)
 {
 	long val;
 	char *s, *ep;
 
-	s = *gargv;
-	if (!*gargv)
+	s = *pThis->gargv;
+	if (!s)
 		return (0);
-	gargv++;
+	pThis->gargv++;
 
 	errno = 0;
 	val = strtoul(s, &ep, 0);
-	check_conversion(s, ep);
+	check_conversion(pThis, s, ep);
 
 	/* Arbitrarily 'restrict' field widths to 1Mbyte */
 	if (val < 0 || val > 1 << 20) {
-		warnx("%s: invalid field width", s);
+		warnx(pThis->pCtx, "%s: invalid field width", s);
 		return 0;
 	}
@@ -785,13 +839,13 @@
 
 static intmax_t
-getintmax(void)
+getintmax(PPRINTFINSTANCE pThis)
 {
 	intmax_t val;
 	char *cp, *ep;
 
-	cp = *gargv;
+	cp = *pThis->gargv;
 	if (cp == NULL)
 		return 0;
-	gargv++;
+	pThis->gargv++;
 
 	if (*cp == '\"' || *cp == '\'')
@@ -800,18 +854,18 @@
 	errno = 0;
 	val = strtoimax(cp, &ep, 0);
-	check_conversion(cp, ep);
+	check_conversion(pThis, cp, ep);
 	return val;
 }
 
 static uintmax_t
-getuintmax(void)
+getuintmax(PPRINTFINSTANCE pThis)
 {
 	uintmax_t val;
 	char *cp, *ep;
 
-	cp = *gargv;
+	cp = *pThis->gargv;
 	if (cp == NULL)
 		return 0;
-	gargv++;
+	pThis->gargv++;
 
 	if (*cp == '\"' || *cp == '\'')
@@ -822,6 +876,6 @@
 		cp++;
 	if (*cp == '-') {
-		warnx("%s: expected positive numeric value", cp);
-		rval = 1;
+		warnx(pThis->pCtx, "%s: expected positive numeric value", cp);
+		pThis->rval = 1;
 		return 0;
 	}
@@ -829,48 +883,53 @@
 	errno = 0;
 	val = strtoumax(cp, &ep, 0);
-	check_conversion(cp, ep);
+	check_conversion(pThis, cp, ep);
 	return val;
 }
 
 static double
-getdouble(void)
+getdouble(PPRINTFINSTANCE pThis)
 {
 	double val;
 	char *ep;
-
-	if (!*gargv)
+	char *s;
+
+	s = *pThis->gargv;
+	if (!s)
 		return (0.0);
-
-	if (**gargv == '\"' || **gargv == '\'')
-		return (double) *((*gargv++)+1);
+	pThis->gargv++;
+
+	if (*s == '\"' || *s == '\'')
+		return (double) s[1];
 
 	errno = 0;
-	val = strtod(*gargv, &ep);
-	check_conversion(*gargv++, ep);
+	val = strtod(s, &ep);
+	check_conversion(pThis, s, ep);
 	return val;
 }
 
 static void
-check_conversion(const char *s, const char *ep)
+check_conversion(PPRINTFINSTANCE pThis, const char *s, const char *ep)
 {
 	if (*ep) {
 		if (ep == s)
-			warnx("%s: expected numeric value", s);
+			warnx(pThis->pCtx, "%s: expected numeric value", s);
 		else
-			warnx("%s: not completely converted", s);
-		rval = 1;
+			warnx(pThis->pCtx, "%s: not completely converted", s);
+		pThis->rval = 1;
 	} else if (errno == ERANGE) {
-		warnx("%s: %s", s, strerror(ERANGE));
-		rval = 1;
+		warnx(pThis->pCtx, "%s: %s", s, strerror(ERANGE));
+		pThis->rval = 1;
 	}
 }
 
 static int
-usage(FILE *pf)
-{
-	fprintf(pf, "usage: %s format [arg ...]\n"
-				"   or: %s --help\n"
-				"   or: %s --version\n",
-			g_progname, g_progname, g_progname);
+usage(PKMKBUILTINCTX pCtx, int fIsErr)
+{
+	kmk_builtin_ctx_printf(pCtx, fIsErr,
+	                       "usage: %s format [arg ...]\n"
+	                       "   or: %s --help\n"
+	                       "   or: %s --version\n",
+	                       pCtx->pszProgName, pCtx->pszProgName, pCtx->pszProgName);
 	return 1;
 }
+
Index: trunk/src/kmk/kmkbuiltin/redirect.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/redirect.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/redirect.c	(revision 3192)
@@ -69,5 +69,5 @@
 # include "nt/nt_child_inject_standard_handles.h"
 #endif
-#if defined(__gnu_hurd__) && !defined(kmk_builtin_redirect) /* need constant */
+#if defined(__gnu_hurd__) && !defined(KMK_BUILTIN_STANDALONE) /* need constant */
 # undef GET_PATH_MAX
 # undef PATH_MAX
@@ -107,60 +107,45 @@
 
 
-static const char *name(const char *pszName)
+static int kmk_redirect_usage(PKMKBUILTINCTX pCtx, int fIsErr)
 {
-    const char *psz = strrchr(pszName, '/');
-#if defined(_MSC_VER) || defined(__OS2__)
-    const char *psz2 = strrchr(pszName, '\\');
-    if (!psz2)
-        psz2 = strrchr(pszName, ':');
-    if (psz2 && (!psz || psz2 > psz))
-        psz = psz2;
-#endif
-    return psz ? psz + 1 : pszName;
-}
-
-
-static int usage(FILE *pOut,  const char *argv0)
-{
-    argv0 = name(argv0);
-    fprintf(pOut,
-            "usage: %s [-[rwa+tb]<fd> <file>] [-d<fd>=<src-fd>] [-c<fd>]\n"
-            "           [-Z] [-E <var=val>] [-C <dir>] [--wcc-brain-damage]\n"
-            "           [-v] -- <program> [args]\n"
-            "   or: %s --help\n"
-            "   or: %s --version\n"
-            "\n"
-            "The rwa+tb is like for fopen, if not specified it defaults to w+.\n"
-            "The <fd> is either a number or an alias for the standard handles:\n"
-            "   i = stdin\n"
-            "   o = stdout\n"
-            "   e = stderr\n"
-            "\n"
-            "The -d switch duplicate the right hand file descriptor (src-fd) to the left\n"
-            "hand side one (fd). The latter is limited to standard handles on windows.\n"
-            "\n"
-            "The -c switch will close the specified file descriptor. Limited to standard\n"
-            "handles on windows.\n"
-            "\n"
-            "The -Z switch zaps the environment.\n"
-            "\n"
-            "The -E switch is for making changes to the environment in a putenv\n"
-            "fashion.\n"
-            "\n"
-            "The -C switch is for changing the current directory.  Please specify an\n"
-            "absolute program path as it's platform dependent whether this takes effect\n"
-            "before or after the executable is located.\n"
-            "\n"
-            "The --wcc-brain-damage switch is to work around wcc and wcc386 (Open Watcom)\n"
-            "not following normal quoting conventions on Windows, OS/2, and DOS.\n"
-            "\n"
-            "The -v switch is for making the thing more verbose.\n"
-            "\n"
-            "This command was originally just a quick hack to avoid invoking the shell\n"
-            "on Windows (cygwin) where forking is very expensive and has exhibited\n"
-            "stability issues on SMP machines.  It has since grown into something like\n"
-            "/usr/bin/env on steroids.\n"
-            ,
-            argv0, argv0, argv0);
+    kmk_builtin_ctx_printf(pCtx, fIsErr,
+                           "usage: %s [-[rwa+tb]<fd> <file>] [-d<fd>=<src-fd>] [-c<fd>]\n"
+                           "           [-Z] [-E <var=val>] [-C <dir>] [--wcc-brain-damage]\n"
+                           "           [-v] -- <program> [args]\n"
+                           "   or: %s --help\n"
+                           "   or: %s --version\n"
+                           "\n"
+                           "The rwa+tb is like for fopen, if not specified it defaults to w+.\n"
+                           "The <fd> is either a number or an alias for the standard handles:\n"
+                           "   i = stdin\n"
+                           "   o = stdout\n"
+                           "   e = stderr\n"
+                           "\n"
+                           "The -d switch duplicate the right hand file descriptor (src-fd) to the left\n"
+                           "hand side one (fd). The latter is limited to standard handles on windows.\n"
+                           "\n"
+                           "The -c switch will close the specified file descriptor. Limited to standard\n"
+                           "handles on windows.\n"
+                           "\n"
+                           "The -Z switch zaps the environment.\n"
+                           "\n"
+                           "The -E switch is for making changes to the environment in a putenv\n"
+                           "fashion.\n"
+                           "\n"
+                           "The -C switch is for changing the current directory.  Please specify an\n"
+                           "absolute program path as it's platform dependent whether this takes effect\n"
+                           "before or after the executable is located.\n"
+                           "\n"
+                           "The --wcc-brain-damage switch is to work around wcc and wcc386 (Open Watcom)\n"
+                           "not following normal quoting conventions on Windows, OS/2, and DOS.\n"
+                           "\n"
+                           "The -v switch is for making the thing more verbose.\n"
+                           "\n"
+                           "This command was originally just a quick hack to avoid invoking the shell\n"
+                           "on Windows (cygwin) where forking is very expensive and has exhibited\n"
+                           "stability issues on SMP machines.  It has since grown into something like\n"
+                           "/usr/bin/env on steroids.\n"
+                           ,
+                           pCtx->pszProgName, pCtx->pszProgName, pCtx->pszProgName);
     return 2;
 }
@@ -198,153 +183,4 @@
 
 
-#ifdef _MSC_VER
-
-/** Used by mscGetOsHandle. */
-static void __cdecl ignore_invalid_parameter(const wchar_t *a, const wchar_t *b, const wchar_t *c, unsigned d, uintptr_t e)
-{
-}
-
-/**
- * Safe way of getting the OS handle of a file descriptor without triggering
- * invalid parameter handling.
- *
- * @returns The handle value if open, INVALID_HANDLE_VALUE if not.
- * @param   fd                  The file descriptor in question.
- */
-static HANDLE mscGetOsHandle(int fd)
-{
-    intptr_t                    hHandle;
-    _invalid_parameter_handler  pfnOld = _get_invalid_parameter_handler();
-    _set_invalid_parameter_handler(ignore_invalid_parameter);
-    hHandle = _get_osfhandle(fd);
-    _set_invalid_parameter_handler(pfnOld);
-    return hHandle != -1 ? (HANDLE)hHandle : INVALID_HANDLE_VALUE;
-}
-
-/**
- * Checks if the specified file descriptor is open.
- *
- * @returns K_TRUE if open, K_FALSE if not.
- * @param   fd                  The file descriptor in question.
- */
-static KBOOL mscIsOpenFile(int fd)
-{
-    return mscGetOsHandle(fd) != INVALID_HANDLE_VALUE;
-}
-
-/**
- * Checks if the native handle is inheritable.
- *
- * @returns K_TRUE if it is, K_FALSE if it isn't or isn't a valid handle.
- * @param   hHandle             The native handle.
- */
-static KBOOL mscIsNativeHandleInheritable(HANDLE hHandle)
-{
-    DWORD fFlags = 0;
-    if (GetHandleInformation(hHandle, &fFlags))
-        return (fFlags & HANDLE_FLAG_INHERIT) != 0;
-    return K_FALSE;
-}
-
-/**
- * Checks if the file descriptor is inheritable or not.
- *
- * @returns K_TRUE if it is, K_FALSE if it isn't or isn't a valid descriptor.
- * @param   fd                  The file descriptor in question.
- */
-static KBOOL mscIsInheritable(int fd)
-{
-    HANDLE hHandle = mscGetOsHandle(fd);
-    if (hHandle != INVALID_HANDLE_VALUE)
-        return mscIsNativeHandleInheritable(hHandle);
-    return K_FALSE;
-}
-
-/**
- * A dup3 like function.
- *
- * @returns fdNew on success, -1 on failure w/ error details written to pStdErr.
- * @param   fdSource            The source descriptor.
- * @param   fdNew               The new descriptor.
- * @param   fFlags              The inherit and text/binary mode flag.
- * @param   pStdErr             Working stderr to write error details to.
- */
-static int mscDup3(int fdSource, int fdNew, int fFlags, FILE *pStdErr)
-{
-    if (!fFlags & _O_NOINHERIT)
-    {
-        /* ASSUMES fFlags doesn't include any changing _O_TEXT/_O_BINARY. */
-        int fdDup = _dup2(fdSource, fdNew);
-        if (fdDup != -1)
-            return fdDup;
-        fprintf(pStdErr, "%s: _dup2(%d,%d) failed: %s\n", g_progname, fdSource, fdNew, strerror(errno));
-    }
-    else
-    {
-        HANDLE   hSource = mscGetOsHandle(fdSource);
-        unsigned cTries  = 0;
-        int      aFdTries[48];
-
-        if (hSource != INVALID_HANDLE_VALUE)
-        {
-            HANDLE hCurProc = GetCurrentProcess();
-            BOOL   fInherit = !(fFlags & _O_NOINHERIT);
-
-            /*
-             * Make sure the old descriptor is closed and can be used again.
-             */
-            _invalid_parameter_handler pfnOld = _get_invalid_parameter_handler();
-            _set_invalid_parameter_handler(ignore_invalid_parameter);
-            close(fdNew);
-            _set_invalid_parameter_handler(pfnOld);
-
-            /*
-             * Duplicate the source handle till we've got a match.
-             */
-            for (;;)
-            {
-                HANDLE hDup = INVALID_HANDLE_VALUE;
-                if (DuplicateHandle(hCurProc, hSource, hCurProc, &hDup, 0 /* DesiredAccess */,
-                                    fInherit, DUPLICATE_SAME_ACCESS))
-                {
-                    int fdDup = _open_osfhandle((intptr_t)hDup, fFlags);
-                    if (fdDup != -1)
-                    {
-                        if (fdDup == fdNew)
-                        {
-                            while (cTries-- > 0)
-                                close(aFdTries[cTries]);
-                            return fdDup;
-                        }
-
-                        aFdTries[cTries++] = fdDup;
-                        if (   fdDup < fdNew
-                            && cTries < K_ELEMENTS(aFdTries))
-                            continue;
-                        fprintf(pStdErr, "%s: mscDup3(%d,%d): giving up! (last fdDup=%d)\n",
-                                g_progname, fdSource, fdNew, fdDup);
-                    }
-                    else
-                    {
-                        fprintf(pStdErr, "%s: _open_osfhandle(%#x) failed: %u\n", g_progname, hDup, strerror(errno));
-                        CloseHandle(hDup);
-                    }
-                }
-                else
-                    fprintf(pStdErr, "%s: DuplicateHandle(%#x) failed: %u\n", g_progname, hSource, GetLastError());
-                break;
-            }
-
-            while (cTries-- > 0)
-                close(aFdTries[cTries]);
-        }
-        else
-            fprintf(pStdErr, "%s: mscDup3(%d,%d): source descriptor is invalid!\n", g_progname, fdSource, fdNew);
-    }
-    return -1;
-}
-
-#endif /* _MSC_VER */
-
 static KBOOL kRedirectHasConflict(int fd, unsigned cOrders, REDIRECTORDERS *paOrders)
 {
@@ -374,4 +210,5 @@
  *          unless it matches @a fdTarget
  *
+ * @param   pCtx                The command execution context.
  * @param   pszFilename         The filename to open.
  * @param   fOpen               The open flags.
@@ -382,5 +219,5 @@
  * @param   fdTarget            The target descriptor.
  */
-static int kRedirectOpenWithoutConflict(const char *pszFilename, int fOpen, mode_t fMode,
+static int kRedirectOpenWithoutConflict(PKMKBUILTINCTX pCtx, const char *pszFilename, int fOpen, mode_t fMode,
                                         unsigned cOrders, REDIRECTORDERS *paOrders, int fRemoveOnFailure, int fdTarget)
 {
@@ -407,5 +244,5 @@
     fdOpened = open(pszFilename, fOpen | fNoInherit, fMode);
     if (fdOpened < 0)
-        return err(-1, "open(%s,%#x,) failed", pszFilename, fOpen);
+        return err(pCtx, -1, "open(%s,%#x,) failed", pszFilename, fOpen);
 
     /* Check for conflicts. */
@@ -453,5 +290,5 @@
         else
         {
-            err(-1, "open(%s,%#x,) #%u failed", pszFilename, cTries + 1, fOpen);
+            err(pCtx, -1, "open(%s,%#x,) #%u failed", pszFilename, cTries + 1, fOpen);
             break;
         }
@@ -463,5 +300,5 @@
      */
     if (fdOpened >= 0)
-        errx(-1, "failed to find a conflict free file descriptor for '%s'!", pszFilename);
+        errx(pCtx, -1, "failed to find a conflict free file descriptor for '%s'!", pszFilename);
 
     while (cTries-- > 0)
@@ -499,4 +336,35 @@
 
 
+/**
+ * Wrapper that chooses between fprintf and kmk_builtin_ctx_printf to get
+ * an error message to the user.
+ *
+ * @param   pCtx            The command execution context.
+ * @param   pWorkingStdErr  Work stderr.
+ * @param   pszFormat       The message format string.
+ * @param   ...             Format arguments.
+ */
+static void safe_err_printf(PKMKBUILTINCTX pCtx, FILE *pWorkingStdErr, const char *pszFormat, ...)
+{
+    char    szMsg[4096];
+    size_t  cchMsg;
+    va_list va;
+
+    va_start(va, pszFormat);
+    vsnprintf(szMsg, sizeof(szMsg) - 1, pszFormat, va);
+    va_end(va);
+    szMsg[sizeof(szMsg) - 1] = '\0';
+    cchMsg = strlen(szMsg);
+
+#ifdef KMK_BUILTIN_STANDALONE
+    (void)pCtx;
+#else
+    if (pCtx->pOut && pCtx->pOut->syncout)
+        output_write_text(pCtx->pOut, 1, szMsg, cchMsg);
+    else
+#endif
+        fwrite(szMsg, cchMsg, 1, pWorkingStdErr);
+}
+
 #if !defined(USE_POSIX_SPAWN) && !defined(KBUILD_OS_WINDOWS)
 
@@ -506,4 +374,5 @@
  *
  * @returns 0 on success, non-zero exit code on failure.
+ * @param   pCtx            The command execution context.
  * @param   pToSave         Pointer to the file order to save the target
  *                          descriptor of.
@@ -514,5 +383,6 @@
  *                          keep having a working one to report failures to.
  */
-static int kRedirectSaveHandle(REDIRECTORDERS *pToSave, unsigned cOrders, REDIRECTORDERS *paOrders, FILE **ppWorkingStdErr)
+static int kRedirectSaveHandle(PKMKBUILTINCTX pCtx, REDIRECTORDERS *pToSave, unsigned cOrders,
+                               REDIRECTORDERS *paOrders, FILE **ppWorkingStdErr)
 {
     int fdToSave = pToSave->fdTarget;
@@ -537,5 +407,5 @@
             if (fdDup == -1)
             {
-                fprintf(*ppWorkingStdErr, "%s: dup(%#x) failed: %u\n", g_progname, fdToSave, strerror(errno));
+                safe_err_printf(pCtx, *ppWorkingStdErr, "%s: dup(%#x) failed: %u\n", pCtx->pszProgName, fdToSave, strerror(errno));
                 break;
             }
@@ -550,5 +420,5 @@
                     if (*ppWorkingStdErr == NULL)
                     {
-                        fprintf(stderr, "%s: fdopen(%d,\"wt\") failed: %s\n", g_progname, fdDup, strerror(errno));
+                        safe_err_printf(pCtx, stderr, "%s: fdopen(%d,\"wt\") failed: %s\n", pCtx->pszProgName, fdDup, strerror(errno));
                         *ppWorkingStdErr = stderr;
                         close(fdDup);
@@ -585,4 +455,5 @@
  * Restores the target file descriptors affected by the file operation orders.
  *
+ * @param   pCtx            The command execution context.
  * @param   cOrders         Number of file operation orders.
  * @param   paOrders        The file operation orders.
@@ -591,5 +462,5 @@
  *                          it to stderr.
  */
-static void kRedirectRestoreFdOrders(unsigned cOrders, REDIRECTORDERS *paOrders, FILE **ppWorkingStdErr)
+static void kRedirectRestoreFdOrders(PKMKBUILTINCTX pCtx, unsigned cOrders, REDIRECTORDERS *paOrders, FILE **ppWorkingStdErr)
 {
     int iSavedErrno = errno;
@@ -613,6 +484,6 @@
             }
             else
-                fprintf(*ppWorkingStdErr, "%s: dup2(%d,%d) failed: %s\n",
-                        g_progname, paOrders[i].fdSaved, paOrders[i].fdTarget, strerror(errno));
+                safe_err_printf(pCtx, *ppWorkingStdErr, "%s: dup2(%d,%d) failed: %s\n",
+                                pCtx->pszProgName, paOrders[i].fdSaved, paOrders[i].fdTarget, strerror(errno));
         }
 
@@ -622,6 +493,7 @@
                 paOrders[i].fSaved = -1;
             else
-                fprintf(*ppWorkingStdErr, "%s: fcntl(%d,F_SETFD,%s) failed: %s\n",
-                        g_progname, paOrders[i].fdTarget, paOrders[i].fSaved & FD_CLOEXEC ? "FD_CLOEXEC" : "0", strerror(errno));
+                safe_err_printf(pCtx, *ppWorkingStdErr, "%s: fcntl(%d,F_SETFD,%s) failed: %s\n",
+                                pCtx->pszProgName, paOrders[i].fdTarget, paOrders[i].fSaved & FD_CLOEXEC ? "FD_CLOEXEC" : "0",
+                                strerror(errno));
         }
     }
@@ -634,4 +506,5 @@
  *
  * @returns 0 on success, exit code on failure.
+ * @param   pCtx            The command execution context.
  * @param   cOrders         Number of file operation orders.
  * @param   paOrders        File operation orders to execute.
@@ -639,5 +512,5 @@
  *                          kRedirectRestoreFdOrders).
  */
-static int kRedirectExecFdOrders(unsigned cOrders, REDIRECTORDERS *paOrders, FILE **ppWorkingStdErr)
+static int kRedirectExecFdOrders(PKMKBUILTINCTX pCtx, unsigned cOrders, REDIRECTORDERS *paOrders, FILE **ppWorkingStdErr)
 {
     unsigned i;
@@ -669,14 +542,15 @@
                             rcExit = 0;
                         else
-                            fprintf(*ppWorkingStdErr, "%s: fcntl(%d,F_SETFD,FD_CLOEXEC) failed: %s\n",
-                                    g_progname, fdTarget, strerror(errno));
+                            safe_err_printf(pCtx, *ppWorkingStdErr, "%s: fcntl(%d,F_SETFD,FD_CLOEXEC) failed: %s\n",
+                                            pCtx->pszProgName, fdTarget, strerror(errno));
                     }
                     else if (errno == EBADF)
                         rcExit = 0;
                     else
-                        fprintf(*ppWorkingStdErr, "%s: fcntl(%d,F_GETFD,0) failed: %s\n", g_progname, fdTarget, strerror(errno));
+                        safe_err_printf(pCtx, *ppWorkingStdErr, "%s: fcntl(%d,F_GETFD,0) failed: %s\n",
+                                        pCtx->pszProgName, fdTarget, strerror(errno));
                 }
                 else
-                    rcExit = kRedirectSaveHandle(&paOrders[i], cOrders, paOrders, ppWorkingStdErr);
+                    rcExit = kRedirectSaveHandle(pCtx, &paOrders[i], cOrders, paOrders, ppWorkingStdErr);
                 break;
             }
@@ -684,5 +558,5 @@
             case kRedirectOrder_Dup:
             case kRedirectOrder_Open:
-                rcExit = kRedirectSaveHandle(&paOrders[i], cOrders, paOrders, ppWorkingStdErr);
+                rcExit = kRedirectSaveHandle(pCtx, &paOrders[i], cOrders, paOrders, ppWorkingStdErr);
                 if (rcExit == 0)
                 {
@@ -692,9 +566,9 @@
                     {
                         if (paOrders[i].enmOrder == kRedirectOrder_Open)
-                            fprintf(*ppWorkingStdErr, "%s: dup2(%d [%s],%d) failed: %s\n", g_progname, paOrders[i].fdSource,
-                                    paOrders[i].pszFilename, paOrders[i].fdTarget, strerror(errno));
+                            safe_err_printf(pCtx, *ppWorkingStdErr, "%s: dup2(%d [%s],%d) failed: %s\n", pCtx->pszProgName,
+                                            paOrders[i].fdSource, paOrders[i].pszFilename, paOrders[i].fdTarget, strerror(errno));
                         else
-                            fprintf(*ppWorkingStdErr, "%s: dup2(%d,%d) failed: %s\n",
-                                    g_progname, paOrders[i].fdSource, paOrders[i].fdTarget, strerror(errno));
+                            safe_err_printf(pCtx, *ppWorkingStdErr, "%s: dup2(%d,%d) failed: %s\n",
+                                            pCtx->pszProgName, paOrders[i].fdSource, paOrders[i].fdTarget, strerror(errno));
                         rcExit = 10;
                     }
@@ -703,5 +577,5 @@
 
             default:
-                fprintf(*ppWorkingStdErr, "%s: error! invalid enmOrder=%d\n", g_progname, paOrders[i].enmOrder);
+                safe_err_printf(pCtx, *ppWorkingStdErr, "%s: error! invalid enmOrder=%d\n", pCtx->pszProgName, paOrders[i].enmOrder);
                 rcExit = 99;
                 break;
@@ -710,5 +584,5 @@
         if (rcExit != 0)
         {
-            kRedirectRestoreFdOrders(i, paOrders, ppWorkingStdErr);
+            kRedirectRestoreFdOrders(pCtx, i, paOrders, ppWorkingStdErr);
             return rcExit;
         }
@@ -799,4 +673,5 @@
  *
  * @returns 0 on success, non-zero on failure to create.
+ * @param   pCtx                The command execution context.
  * @param   pszExecutable       The child process executable.
  * @param   cArgs               Number of arguments.
@@ -808,6 +683,7 @@
  * @param   phProcess           Where to return process handle.
  */
-static int kRedirectCreateProcessWindows(const char *pszExecutable, int cArgs, char **papszArgs, char **papszEnvVars,
-                                         const char *pszCwd, unsigned cOrders, REDIRECTORDERS *paOrders, HANDLE *phProcess)
+static int kRedirectCreateProcessWindows(PKMKBUILTINCTX pCtx, const char *pszExecutable, int cArgs, char **papszArgs,
+                                         char **papszEnvVars, const char *pszCwd, unsigned cOrders,
+                                         REDIRECTORDERS *paOrders, HANDLE *phProcess)
 {
     size_t cbArgs;
@@ -828,5 +704,5 @@
     pszCmdLine = pch = (char *)malloc(cbArgs);
     if (!pszCmdLine)
-        return errx(9, "out of memory!");
+        return errx(pCtx, 9, "out of memory!");
     for (i = 0; i < cArgs; i++)
     {
@@ -901,5 +777,5 @@
             }
             else
-                rc = errx(10, "CreateProcessA(%s) failed: %u", pszExecutable, GetLastError());
+                rc = errx(pCtx, 10, "CreateProcessA(%s) failed: %u", pszExecutable, GetLastError());
         }
         else
@@ -923,9 +799,9 @@
                         if (   (paOrders[i].fOpen & O_APPEND)
                             && lseek(paOrders[i].fdSource, 0, SEEK_END) < 0)
-                            rc = err(10, "lseek-to-end failed on %d (for %d)", paOrders[i].fdSource, fdTarget);
+                            rc = err(pCtx, 10, "lseek-to-end failed on %d (for %d)", paOrders[i].fdSource, fdTarget);
                     case kRedirectOrder_Dup:
                         ahChild[fdTarget] = (HANDLE)_get_osfhandle(paOrders[i].fdSource);
                         if (ahChild[fdTarget] == NULL || ahChild[fdTarget] == INVALID_HANDLE_VALUE)
-                            rc = err(10, "_get_osfhandle failed on %d (for %d)", paOrders[i].fdSource, fdTarget);
+                            rc = err(pCtx, 10, "_get_osfhandle failed on %d (for %d)", paOrders[i].fdSource, fdTarget);
                         break;
                     case kRedirectOrder_Close:
@@ -949,7 +825,7 @@
                     rc = nt_child_inject_standard_handles(ProcInfo.hProcess, afReplace, ahChild, szErrMsg, sizeof(szErrMsg));
                     if (rc)
-                        rc = errx(10, "%s", szErrMsg);
+                        rc = errx(pCtx, 10, "%s", szErrMsg);
                     else if (!ResumeThread(ProcInfo.hThread))
-                        rc = errx(10, "ResumeThread failed: %u", GetLastError());
+                        rc = errx(pCtx, 10, "ResumeThread failed: %u", GetLastError());
 
                     /* Kill it if any of that fails. */
@@ -962,5 +838,5 @@
                 }
                 else
-                    rc = errx(10, "CreateProcessA(%s) failed: %u", pszExecutable, GetLastError());
+                    rc = errx(pCtx, 10, "CreateProcessA(%s) failed: %u", pszExecutable, GetLastError());
             }
         }
@@ -968,5 +844,5 @@
     }
     else
-        rc = errx(9, "out of memory!");
+        rc = errx(pCtx, 9, "out of memory!");
     free(pszCmdLine);
     return rc;
@@ -979,4 +855,5 @@
  *
  * @returns Exit code.
+ * @param   pCtx                The command execution context.
  * @param   pszExecutable       The child process executable.
  * @param   cArgs               Number of arguments.
@@ -998,5 +875,5 @@
  *                              is from the child or from our setup efforts.
  */
-static int kRedirectDoSpawn(const char *pszExecutable, int cArgs, char **papszArgs, int fWatcomBrainDamage,
+static int kRedirectDoSpawn(PKMKBUILTINCTX pCtx, const char *pszExecutable, int cArgs, char **papszArgs, int fWatcomBrainDamage,
                             char **papszEnvVars, const char *pszCwd, const char *pszSavedCwd,
                             unsigned cOrders, REDIRECTORDERS *paOrders,
@@ -1025,5 +902,5 @@
         memcpy(papszArgs, papszArgsOriginal, (cArgs + 1) * sizeof(papszArgs[0]));
     else
-        return errx(9, "out of memory!");
+        return errx(pCtx, 9, "out of memory!");
 
     rcExit = quote_argv(cArgs, papszArgs, fWatcomBrainDamage, 0 /*fFreeOrLeak*/);
@@ -1037,25 +914,25 @@
         {
             for (i = 0; i < cArgs; i++)
-                warnx("debug: argv[%i]=%s<eos>", i, papszArgs[i]);
+                warnx(pCtx, "debug: argv[%i]=%s<eos>", i, papszArgs[i]);
             for (i = 0; i < (int)cOrders; i++)
                 switch (paOrders[i].enmOrder)
                 {
                     case kRedirectOrder_Close:
-                        warnx("debug: close %d\n", paOrders[i].fdTarget);
+                        warnx(pCtx, "debug: close %d\n", paOrders[i].fdTarget);
                         break;
                     case kRedirectOrder_Dup:
-                        warnx("debug: dup %d to %d\n", paOrders[i].fdSource, paOrders[i].fdTarget);
+                        warnx(pCtx, "debug: dup %d to %d\n", paOrders[i].fdSource, paOrders[i].fdTarget);
                         break;
                     case kRedirectOrder_Open:
-                        warnx("debug: open '%s' (%#x) as [%d ->] %d\n",
+                        warnx(pCtx, "debug: open '%s' (%#x) as [%d ->] %d\n",
                               paOrders[i].pszFilename, paOrders[i].fOpen, paOrders[i].fdSource, paOrders[i].fdTarget);
                         break;
                     default:
-                        warnx("error! invalid enmOrder=%d", paOrders[i].enmOrder);
+                        warnx(pCtx, "error! invalid enmOrder=%d", paOrders[i].enmOrder);
                         assert(0);
                         break;
                 }
             if (pszSavedCwd)
-                warnx("debug: chdir %s\n", pszCwd);
+                warnx(pCtx, "debug: chdir %s\n", pszCwd);
         }
 
@@ -1067,5 +944,5 @@
         {
             if (chdir(pszCwd) < 0)
-                rcExit = errx(10, "Failed to change directory to '%s'", pszCwd);
+                rcExit = errx(pCtx, 10, "Failed to change directory to '%s'", pszCwd);
         }
 #endif /* KBUILD_OS_WINDOWS */
@@ -1077,5 +954,5 @@
              */
             FILE *pWorkingStdErr = NULL;
-            rcExit = kRedirectExecFdOrders(cOrders, paOrders, &pWorkingStdErr);
+            rcExit = kRedirectExecFdOrders(pCtx, cOrders, paOrders, &pWorkingStdErr);
             if (rcExit == 0)
 # endif
@@ -1088,5 +965,5 @@
                 /* Windows is slightly complicated due to handles and winchildren.c. */
                 HANDLE hProcess = INVALID_HANDLE_VALUE;
-                rcExit = kRedirectCreateProcessWindows(pszExecutable, cArgs, papszArgs, papszEnvVars,
+                rcExit = kRedirectCreateProcessWindows(pCtx, pszExecutable, cArgs, papszArgs, papszEnvVars,
                                                        pszSavedCwd ? pszCwd : NULL, cOrders, paOrders, &hProcess);
                 if (rcExit == 0)
@@ -1100,5 +977,5 @@
                     {
                         if (cVerbosity > 0)
-                            warnx("debug: spawned %d", *pPidSpawned);
+                            warnx(pCtx, "debug: spawned %d", *pPidSpawned);
                     }
                     else
@@ -1106,12 +983,12 @@
                         DWORD dwTmp;
 #  ifndef CONFIG_NEW_WIN_CHILDREN
-                        warn("sub_proc is out of slots, waiting for child...");
+                        warn(pCtx, "sub_proc is out of slots, waiting for child...");
 #  else
                         if (pPidSpawned)
-                            warn("MkWinChildCreateRedirect failed...");
+                            warn(pCtx, "MkWinChildCreateRedirect failed...");
 #  endif
                         dwTmp = WaitForSingleObject(hProcess, INFINITE);
                         if (dwTmp != WAIT_OBJECT_0)
-                            warn("WaitForSingleObject failed: %#x\n", dwTmp);
+                            warnx(pCtx, "WaitForSingleObject failed: %#x\n", dwTmp);
 
                         if (GetExitCodeProcess(hProcess, &dwTmp))
@@ -1119,5 +996,5 @@
                         else
                         {
-                            warn("GetExitCodeProcess failed: %u\n", GetLastError());
+                            warnx(pCtx, "GetExitCodeProcess failed: %u\n", GetLastError());
                             TerminateProcess(hProcess, 127);
                             rcExit = 127;
@@ -1133,13 +1010,13 @@
 # elif defined(KBUILD_OS_OS2)
                 *pPidSpawned = _spawnvpe(P_NOWAIT, pszExecutable, papszArgs, papszEnvVars);
-                kRedirectRestoreFdOrders(cOrders, paOrders, &pWorkingStdErr);
+                kRedirectRestoreFdOrders(pCtx, cOrders, paOrders, &pWorkingStdErr);
                 if (*pPidSpawned != -1)
                 {
                     if (cVerbosity > 0)
-                        warnx("debug: spawned %d", *pPidSpawned);
+                        warnx(pCtx, "debug: spawned %d", *pPidSpawned);
                 }
                 else
                 {
-                    rcExit = err(10, "_spawnvpe(%s) failed", pszExecutable);
+                    rcExit = err(pCtx, 10, "_spawnvpe(%s) failed", pszExecutable);
                     *pPidSpawned = 0;
                 }
@@ -1149,9 +1026,9 @@
                 {
                     if (cVerbosity > 0)
-                        warnx("debug: spawned %d", *pPidSpawned);
+                        warnx(pCtx, "debug: spawned %d", *pPidSpawned);
                 }
                 else
                 {
-                    rcExit = errx(10, "posix_spawnp(%s) failed: %s", pszExecutable, strerror(rcExit));
+                    rcExit = errx(pCtx, 10, "posix_spawnp(%s) failed: %s", pszExecutable, strerror(rcExit));
                     *pPidSpawned = 0;
                 }
@@ -1164,5 +1041,5 @@
 # ifdef KBUILD_OS_WINDOWS
                 HANDLE hProcess = INVALID_HANDLE_VALUE;
-                rcExit = kRedirectCreateProcessWindows(pszExecutable, cArgs, papszArgs, papszEnvVars,
+                rcExit = kRedirectCreateProcessWindows(pCtx, pszExecutable, cArgs, papszArgs, papszEnvVars,
                                                        pszSavedCwd ? pszCwd : NULL, cOrders, paOrders, &hProcess);
                 if (rcExit == 0)
@@ -1177,5 +1054,5 @@
                         rcExit = dwWait;
                     else
-                        rcExit = errx(11, "GetExitCodeProcess(%s) failed: %u", pszExecutable, GetLastError());
+                        rcExit = errx(pCtx, 11, "GetExitCodeProcess(%s) failed: %u", pszExecutable, GetLastError());
                 }
 
@@ -1183,13 +1060,13 @@
                 errno  = 0;
                 rcExit = (int)_spawnvpe(P_WAIT, pszExecutable, papszArgs, papszEnvVars);
-                kRedirectRestoreFdOrders(cOrders, paOrders, &pWorkingStdErr);
+                kRedirectRestoreFdOrders(pCtx, cOrders, paOrders, &pWorkingStdErr);
                 if (rcExit != -1 || errno == 0)
                 {
                     *pfIsChildExitCode = K_TRUE;
                     if (cVerbosity > 0)
-                        warnx("debug: exit code: %d", rcExit);
+                        warnx(pCtx, "debug: exit code: %d", rcExit);
                 }
                 else
-                    rcExit = err(10, "_spawnvpe(%s) failed", pszExecutable);
+                    rcExit = err(pCtx, 10, "_spawnvpe(%s) failed", pszExecutable);
 
 # else
@@ -1200,5 +1077,5 @@
                     *pfIsChildExitCode = K_TRUE;
                     if (cVerbosity > 0)
-                        warnx("debug: spawned %d", pidChild);
+                        warnx(pCtx, "debug: spawned %d", pidChild);
 
                     /* Wait for the child. */
@@ -1209,5 +1086,5 @@
                         {
                             if (cVerbosity > 0)
-                                warnx("debug: %d exit code: %d", pidChild, rcExit);
+                                warnx(pCtx, "debug: %d exit code: %d", pidChild, rcExit);
                             break;
                         }
@@ -1218,5 +1095,5 @@
                            )
                         {
-                            rcExit = err(11, "waitpid failed");
+                            rcExit = err(pCtx, 11, "waitpid failed");
                             kill(pidChild, SIGKILL);
                             break;
@@ -1225,5 +1102,5 @@
                 }
                 else
-                    rcExit = errx(10, "posix_spawnp(%s) failed: %s", pszExecutable, strerror(rcExit));
+                    rcExit = errx(pCtx, 10, "posix_spawnp(%s) failed: %s", pszExecutable, strerror(rcExit));
 # endif
 #endif /* !KMK */
@@ -1238,5 +1115,5 @@
         {
             if (chdir(pszSavedCwd) < 0)
-                warn("Failed to restore directory to '%s'", pszSavedCwd);
+                warn(pCtx, "Failed to restore directory to '%s'", pszSavedCwd);
         }
 #endif
@@ -1244,5 +1121,5 @@
 #ifdef _MSC_VER
     else
-        rcExit = errx(9, "quite_argv failed: %u", rcExit);
+        rcExit = errx(pCtx, 9, "quite_argv failed: %u", rcExit);
 
     /* Restore the original argv strings, freeing the quote_argv replacements. */
@@ -1260,9 +1137,5 @@
  * The function that does almost everything here... ugly.
  */
-#ifdef KMK
-int kmk_builtin_redirect(int argc, char **argv, char **envp, struct child *pChild, pid_t *pPidSpawned)
-#else
-int main(int argc, char **argv, char **envp)
-#endif
+int kmk_builtin_redirect(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx, struct child *pChild, pid_t *pPidSpawned)
 {
     int             rcExit = 0;
@@ -1290,8 +1163,6 @@
 
 
-    g_progname = argv[0];
-
     if (argc <= 1)
-        return usage(stderr, argv[0]);
+        return kmk_redirect_usage(pCtx, 1);
 
     /*
@@ -1305,5 +1176,5 @@
     { /* likely */ }
     else
-        return err(9, "getcwd failed");
+        return err(pCtx, 9, "getcwd failed");
 
     /* We start out with a read-only enviornment from kmk or the crt, and will
@@ -1321,5 +1192,5 @@
     rcExit = posix_spawn_file_actions_init(&FileActions);
     if (rcExit != 0)
-        rcExit = errx(9, "posix_spawn_file_actions_init failed: %s", strerror(rcExit));
+        rcExit = errx(pCtx, 9, "posix_spawn_file_actions_init failed: %s", strerror(rcExit));
 #endif
 
@@ -1384,6 +1255,6 @@
                 else
                 {
-                    errx(2, "Unknown option: '%s'", pszArg - 2);
-                    rcExit = usage(stderr, argv[0]);
+                    errx(pCtx, 2, "Unknown option: '%s'", pszArg - 2);
+                    rcExit = kmk_redirect_usage(pCtx, 1);
                     break;
                 }
@@ -1396,5 +1267,5 @@
             if (chOpt == 'h')
             {
-                usage(stdout, argv[0]);
+                kmk_redirect_usage(pCtx, 0);
                 rcExit = -1;
                 break;
@@ -1425,6 +1296,6 @@
                 else
                 {
-                    errx(2, "syntax error: Option -%c requires a value!", chOpt);
-                    rcExit = usage(stderr, argv[0]);
+                    errx(pCtx, 2, "syntax error: Option -%c requires a value!", chOpt);
+                    rcExit = kmk_redirect_usage(pCtx, 1);
                     break;
                 }
@@ -1457,5 +1328,5 @@
                             if (rc)
                             {
-                                rcExit = errx(9, "DosQueryExtLIBPATH(,%u) failed: %lu", ulVar, rc);
+                                rcExit = errx(pCtx, 9, "DosQueryExtLIBPATH(,%u) failed: %lu", ulVar, rc);
                                 free(apszSavedLibPaths[ulVar]);
                                 apszSavedLibPaths[ulVar] = NULL;
@@ -1463,5 +1334,5 @@
                         }
                         else
-                            rcExit = errx(9, "out of memory!");
+                            rcExit = errx(pCtx, 9, "out of memory!");
                     }
                     if (rcExit == 0)
@@ -1469,5 +1340,5 @@
                         rc = DosSetExtLIBPATH(pchEqual + 1, ulVar);
                         if (rc)
-                            rcExit = errx(9, "error: DosSetExtLibPath(\"%s\", %.*s (%lu)): %lu",
+                            rcExit = errx(pCtx, 9, "error: DosSetExtLibPath(\"%s\", %.*s (%lu)): %lu",
                                           pchEqual, pchEqual - pszValue, pchEqual + 1, ulVar, rc);
                     }
@@ -1480,5 +1351,5 @@
                 {
                     if (pchEqual[1] != '\0')
-                        rcExit = kBuiltinOptEnvSet(&papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
+                        rcExit = kBuiltinOptEnvSet(pCtx, &papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
                     else
                     {
@@ -1487,9 +1358,9 @@
                         {
                             pszCopy[pchEqual - pszValue] = '\0';
-                            rcExit = kBuiltinOptEnvUnset(&papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszCopy);
+                            rcExit = kBuiltinOptEnvUnset(pCtx, &papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszCopy);
                             free(pszCopy);
                         }
                         else
-                            rcExit = errx(1, "out of memory!");
+                            rcExit = errx(pCtx, 1, "out of memory!");
                     }
                     continue;
@@ -1508,11 +1379,11 @@
                     || strcmp(pszValue, "ENDLIBPATH") == 0
                     || strcmp(pszValue, "LIBPATHSTRICT") == 0)
-                    rcExit = errx(2, "error: '%s' cannot currently be appended or prepended to. Please use -E/--set for now.", pszValue);
+                    rcExit = errx(pCtx, 2, "error: '%s' cannot currently be appended or prepended to. Please use -E/--set for now.", pszValue);
                 else
 #endif
                 if (chOpt == 'A')
-                    rcExit = kBuiltinOptEnvAppend(&papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
+                    rcExit = kBuiltinOptEnvAppend(pCtx, &papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
                 else
-                    rcExit = kBuiltinOptEnvPrepend(&papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
+                    rcExit = kBuiltinOptEnvPrepend(pCtx, &papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
                 continue;
             }
@@ -1527,8 +1398,8 @@
                     || strcmp(pszValue, "ENDLIBPATH") == 0
                     || strcmp(pszValue, "LIBPATHSTRICT") == 0)
-                    rcExit = errx(2, "error: '%s' cannot be unset, only set to an empty value using -E/--set.", pszValue);
+                    rcExit = errx(pCtx, 2, "error: '%s' cannot be unset, only set to an empty value using -E/--set.", pszValue);
                 else
 #endif
-                    rcExit = kBuiltinOptEnvUnset(&papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
+                    rcExit = kBuiltinOptEnvUnset(pCtx, &papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
                 continue;
             }
@@ -1540,5 +1411,5 @@
                 || chOpt == 'i' /* GNU env compatibility. */ )
             {
-                rcExit = kBuiltinOptEnvZap(&papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity);
+                rcExit = kBuiltinOptEnvZap(pCtx, &papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity);
                 continue;
             }
@@ -1552,7 +1423,7 @@
                     pszSavedCwd = strdup(szCwd);
                 if (pszSavedCwd)
-                    rcExit = kBuiltinOptChDir(szCwd, cbCwdBuf, pszValue);
+                    rcExit = kBuiltinOptChDir(pCtx, szCwd, cbCwdBuf, pszValue);
                 else
-                    rcExit = err(9, "out of memory!");
+                    rcExit = err(pCtx, 9, "out of memory!");
                 continue;
             }
@@ -1593,5 +1464,5 @@
             else
             {
-                rcExit = errx(2, "error: too many file actions (max: %d)", K_ELEMENTS(aOrders));
+                rcExit = errx(pCtx, 2, "error: too many file actions (max: %d)", K_ELEMENTS(aOrders));
                 break;
             }
@@ -1605,10 +1476,10 @@
                 fd = (int)strtol(pszValue, &pszTmp, 0);
                 if (pszTmp == pszValue || *pszTmp != '\0')
-                    rcExit = errx(2, "error: failed to convert '%s' to a number", pszValue);
+                    rcExit = errx(pCtx, 2, "error: failed to convert '%s' to a number", pszValue);
                 else if (fd < 0)
-                    rcExit = errx(2, "error: negative fd %d (%s)", fd, pszValue);
+                    rcExit = errx(pCtx, 2, "error: negative fd %d (%s)", fd, pszValue);
 #ifdef ONLY_TARGET_STANDARD_HANDLES
                 else if (fd > 2)
-                    rcExit = errx(2, "error: %d is not a standard descriptor number", fd);
+                    rcExit = errx(pCtx, 2, "error: %d is not a standard descriptor number", fd);
 #endif
                 else
@@ -1620,5 +1491,5 @@
                     rcExit = posix_spawn_file_actions_addclose(&FileActions, fd);
                     if (rcExit != 0)
-                        rcExit = errx(2, "posix_spawn_file_actions_addclose(%d) failed: %s", fd, strerror(rcExit));
+                        rcExit = errx(pCtx, 2, "posix_spawn_file_actions_addclose(%d) failed: %s", fd, strerror(rcExit));
 #endif
                 }
@@ -1632,13 +1503,13 @@
                 fd = (int)strtol(pszValue, &pszEqual, 0);
                 if (pszEqual == pszValue)
-                    rcExit = errx(2, "error: failed to convert target descriptor of '-d %s' to a number", pszValue);
+                    rcExit = errx(pCtx, 2, "error: failed to convert target descriptor of '-d %s' to a number", pszValue);
                 else if (fd < 0)
-                    rcExit = errx(2, "error: negative target descriptor %d ('-d %s')", fd, pszValue);
+                    rcExit = errx(pCtx, 2, "error: negative target descriptor %d ('-d %s')", fd, pszValue);
 #ifdef ONLY_TARGET_STANDARD_HANDLES
                 else if (fd > 2)
-                    rcExit = errx(2, "error: target %d is not a standard descriptor number", fd);
+                    rcExit = errx(pCtx, 2, "error: target %d is not a standard descriptor number", fd);
 #endif
                 else if (*pszEqual != '=')
-                    rcExit = errx(2, "syntax error: expected '=' to follow target descriptor: '-d %s'", pszValue);
+                    rcExit = errx(pCtx, 2, "syntax error: expected '=' to follow target descriptor: '-d %s'", pszValue);
                 else
                 {
@@ -1646,7 +1517,7 @@
                     int fdSource = (int)strtol(++pszEqual, &pszEnd, 0);
                     if (pszEnd == pszEqual || *pszEnd != '\0')
-                        rcExit = errx(2, "error: failed to convert source descriptor of '-d %s' to a number", pszValue);
+                        rcExit = errx(pCtx, 2, "error: failed to convert source descriptor of '-d %s' to a number", pszValue);
                     else if (fdSource < 0)
-                        rcExit = errx(2, "error: negative source descriptor %d ('-d %s')", fdSource, pszValue);
+                        rcExit = errx(pCtx, 2, "error: negative source descriptor %d ('-d %s')", fdSource, pszValue);
                     else
                     {
@@ -1658,5 +1529,5 @@
                         rcExit = posix_spawn_file_actions_adddup2(&FileActions, fdSource, fd);
                         if (rcExit != 0)
-                            rcExit = errx(2, "posix_spawn_file_actions_addclose(%d) failed: %s", fd, strerror(rcExit));
+                            rcExit = errx(pCtx, 2, "posix_spawn_file_actions_addclose(%d) failed: %s", fd, strerror(rcExit));
 #endif
                     }
@@ -1713,5 +1584,5 @@
 
                     case '+':
-                        rcExit = errx(2, "syntax error: Unexpected '+' in '%s'", argv[iArg]);
+                        rcExit = errx(pCtx, 2, "syntax error: Unexpected '+' in '%s'", argv[iArg]);
                         continue;
 
@@ -1780,10 +1651,10 @@
                         fd = (int)strtol(pszValue, &pszArg, 0);
                         if (pszArg == pszValue)
-                            rcExit = errx(2, "error: failed to convert '%s' to a number", argv[iArg]);
+                            rcExit = errx(pCtx, 2, "error: failed to convert '%s' to a number", argv[iArg]);
                         else if (fd < 0)
-                            rcExit = errx(2, "error: negative fd %d (%s)", fd, argv[iArg]);
+                            rcExit = errx(pCtx, 2, "error: negative fd %d (%s)", fd, argv[iArg]);
 #ifdef ONLY_TARGET_STANDARD_HANDLES
                         else if (fd > 2)
-                            rcExit = errx(2, "error: %d is not a standard descriptor number", fd);
+                            rcExit = errx(pCtx, 2, "error: %d is not a standard descriptor number", fd);
 #endif
                         else
@@ -1795,5 +1666,5 @@
                      */
                     default:
-                        rcExit = errx(2, "error: failed to convert '%s' ('%s') to a file descriptor", pszArg, argv[iArg]);
+                        rcExit = errx(pCtx, 2, "error: failed to convert '%s' ('%s') to a file descriptor", pszArg, argv[iArg]);
                         continue;
                 }
@@ -1806,5 +1677,5 @@
                     if (*pszArg != ':' && *pszArg != '=')
                     {
-                        rcExit = errx(2, "syntax error: characters following the file descriptor: '%s' ('%s')",
+                        rcExit = errx(pCtx, 2, "syntax error: characters following the file descriptor: '%s' ('%s')",
                                       pszArg, argv[iArg]);
                         break;
@@ -1816,5 +1687,5 @@
                 else
                 {
-                    rcExit = errx(2, "syntax error: missing filename argument.");
+                    rcExit = errx(pCtx, 2, "syntax error: missing filename argument.");
                     break;
                 }
@@ -1825,5 +1696,5 @@
                  * this for windows anyway, just do it the same way everywhere.
                  */
-                fdOpened = kRedirectOpenWithoutConflict(pszArg, fOpen, 0666, cOrders, aOrders,
+                fdOpened = kRedirectOpenWithoutConflict(pCtx, pszArg, fOpen, 0666, cOrders, aOrders,
                                                         aOrders[cOrders].fRemoveOnFailure, fd);
                 if (fdOpened >= 0)
@@ -1841,5 +1712,5 @@
                         rcExit = posix_spawn_file_actions_adddup2(&FileActions, fdOpened, fd);
                         if (rcExit != 0)
-                            rcExit = err(9, "posix_spawn_file_actions_adddup2(,%d [%s], %d) failed: %s",
+                            rcExit = err(pCtx, 9, "posix_spawn_file_actions_adddup2(,%d [%s], %d) failed: %s",
                                          fdOpened, fd, pszArg, strerror(rcExit));
                     }
@@ -1852,6 +1723,6 @@
         else
         {
-            errx(2, "syntax error: Invalid argument '%s'.", argv[iArg]);
-            rcExit = usage(stderr, argv[0]);
+            errx(pCtx, 2, "syntax error: Invalid argument '%s'.", argv[iArg]);
+            rcExit = kmk_redirect_usage(pCtx, 1);
         }
     }
@@ -1867,5 +1738,5 @@
          * Do the spawning in a separate function (main is far to large as it is by now).
          */
-        rcExit = kRedirectDoSpawn(pszExecutable, argc - iArg, &argv[iArg], fWatcomBrainDamage,
+        rcExit = kRedirectDoSpawn(pCtx, pszExecutable, argc - iArg, &argv[iArg], fWatcomBrainDamage,
                                   papszEnvVars,
                                   szCwd, pszSavedCwd,
@@ -1882,6 +1753,6 @@
     else if (rcExit == 0)
     {
-        errx(2, "syntax error: nothing to execute!");
-        rcExit = usage(stderr, argv[0]);
+        errx(pCtx, 2, "syntax error: nothing to execute!");
+        rcExit = kmk_redirect_usage(pCtx, 1);
     }
     /* Help and version sets rcExit to -1. Change it to zero. */
@@ -1905,5 +1776,5 @@
             APIRET rc = DosSetExtLIBPATH(apszSavedLibPaths[ulLibPath], ulLibPath);
             if (rc != 0)
-                warnx("DosSetExtLIBPATH('%s',%u) failed with %u when restoring the original values!",
+                warnx(pCtx, "DosSetExtLIBPATH('%s',%u) failed with %u when restoring the original values!",
                       apszSavedLibPaths[ulLibPath], ulLibPath, rc);
             free(apszSavedLibPaths[ulLibPath]);
@@ -1914,2 +1785,11 @@
 }
 
+#ifdef KMK_BUILTIN_STANDALONE
+int main(int argc, char **argv, char **envp)
+{
+    KMKBUILTINCTX Ctx = { "kmk_redirect", NULL };
+    return kmk_builtin_redirect(argc, argv, envp, &Ctx, NULL, NULL);
+}
+#endif
+
+
Index: trunk/src/kmk/kmkbuiltin/rm.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/rm.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/rm.c	(revision 3192)
@@ -42,4 +42,8 @@
 #endif
 
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
 #include "config.h"
 #include <sys/stat.h>
@@ -90,4 +94,8 @@
 #include "k/kDefs.h"	/* for K_OS */
 
+
+/*********************************************************************************************************************************
+*   Defined Constants And Macros                                                                                                 *
+*********************************************************************************************************************************/
 #if defined(__EMX__) || defined(KBUILD_OS_WINDOWS)
 # define IS_SLASH(ch)   ( (ch) == '/' || (ch) == '\\' )
@@ -110,15 +118,32 @@
 #endif
 
-extern void bsd_strmode(mode_t mode, char *p);
-
-static int dflag, eval, fflag, iflag, Pflag, vflag, Wflag, stdin_ok;
+#if 1
+#define CUR_LINE_H2(x)  "[line " #x "]"
+#define CUR_LINE_H1(x)  CUR_LINE_H2(x)
+#define CUR_LINE()      CUR_LINE_H1(__LINE__)
+#else
+# define CUR_LINE()
+#endif
+
+
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+typedef struct RMINSTANCE
+{
+    PKMKBUILTINCTX pCtx;
+    int dflag, eval, fflag, iflag, Pflag, vflag, Wflag, stdin_ok;
 #ifdef KBUILD_OS_WINDOWS
-static int fUseNtDeleteFile;
-#endif
-static uid_t uid;
-
-static char *argv0;
-static KBUILDPROTECTION g_ProtData;
-
+    int fUseNtDeleteFile;
+#endif
+    uid_t uid;
+    KBUILDPROTECTION g_ProtData;
+} RMINSTANCE;
+typedef RMINSTANCE *PRMINSTANCE;
+
+
+/*********************************************************************************************************************************
+*   Global Variables                                                                                                             *
+*********************************************************************************************************************************/
 static struct option long_options[] =
 {
@@ -137,18 +162,16 @@
 
 
-static int	check(char *, char *, struct stat *);
-static void	checkdot(char **);
-static int	rm_file(char **);
-static int	rm_overwrite(char *, struct stat *);
-static int	rm_tree(char **);
-static int	usage(FILE *);
-
-#if 1
-#define CUR_LINE_H2(x)  "[line " #x "]"
-#define CUR_LINE_H1(x)  CUR_LINE_H2(x)
-#define CUR_LINE()      CUR_LINE_H1(__LINE__)
-#else
-# define CUR_LINE()
-#endif
+/*********************************************************************************************************************************
+*   Internal Functions                                                                                                           *
+*********************************************************************************************************************************/
+extern void bsd_strmode(mode_t mode, char *p); /* strmode.c */
+
+static int	check(PRMINSTANCE, char *, char *, struct stat *);
+static void	checkdot(PRMINSTANCE, char **);
+static int	rm_file(PRMINSTANCE, char **);
+static int	rm_overwrite(PRMINSTANCE, char *, struct stat *);
+static int	rm_tree(PRMINSTANCE, char **);
+static int	usage(PKMKBUILTINCTX, int);
+
 
 
@@ -161,19 +184,26 @@
  */
 int
-kmk_builtin_rm(int argc, char *argv[], char **envp)
-{
+kmk_builtin_rm(int argc, char *argv[], char **envp, PKMKBUILTINCTX pCtx)
+{
+	RMINSTANCE This;
 	int ch, rflag;
 
-	/* reinitialize globals */
-	argv0 = argv[0];
-	dflag = eval = fflag = iflag = Pflag = vflag = Wflag = stdin_ok = 0;
+	/* Init global instance data */
+	This.pCtx = pCtx;
+	This.dflag = 0;
+	This.eval = 0;
+	This.fflag = 0;
+	This.iflag = 0;
+	This.Pflag = 0;
+	This.vflag = 0;
+	This.Wflag = 0;
+	This.stdin_ok = 0;
 #ifdef KBUILD_OS_WINDOWS
-	fUseNtDeleteFile = 0;
-#endif
-	uid = 0;
-	kBuildProtectionInit(&g_ProtData);
+	This.fUseNtDeleteFile = 0;
+#endif
+	This.uid = 0;
+	kBuildProtectionInit(&This.g_ProtData, pCtx);
 
 	/* kmk: reset getopt and set program name. */
-	g_progname = argv[0];
 	opterr = 1;
 	optarg = NULL;
@@ -181,20 +211,20 @@
 	optind = 0; /* init */
 
-	Pflag = rflag = 0;
+	rflag = 0;
 	while ((ch = getopt_long(argc, argv, "dfiPRvW", long_options, NULL)) != -1)
-		switch(ch) {
+		switch (ch) {
 		case 'd':
-			dflag = 1;
+			This.dflag = 1;
 			break;
 		case 'f':
-			fflag = 1;
-			iflag = 0;
+			This.fflag = 1;
+			This.iflag = 0;
 			break;
 		case 'i':
-			fflag = 0;
-			iflag = 1;
+			This.fflag = 0;
+			This.iflag = 1;
 			break;
 		case 'P':
-			Pflag = 1;
+			This.Pflag = 1;
 			break;
 		case 'R':
@@ -205,33 +235,33 @@
 			break;
 		case 'v':
-			vflag = 1;
+			This.vflag = 1;
 			break;
 #ifdef FTS_WHITEOUT
 		case 'W':
-			Wflag = 1;
+			This.Wflag = 1;
 			break;
 #endif
 		case 261:
-			kBuildProtectionTerm(&g_ProtData);
-			usage(stdout);
+			kBuildProtectionTerm(&This.g_ProtData);
+			usage(pCtx, 0);
 			return 0;
 		case 262:
-			kBuildProtectionTerm(&g_ProtData);
+			kBuildProtectionTerm(&This.g_ProtData);
 			return kbuild_version(argv[0]);
 		case 263:
-			kBuildProtectionDisable(&g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE);
+			kBuildProtectionDisable(&This.g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE);
 			break;
 		case 264:
-			kBuildProtectionEnable(&g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE);
+			kBuildProtectionEnable(&This.g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE);
 			break;
 		case 265:
-			kBuildProtectionEnable(&g_ProtData, KBUILDPROTECTIONTYPE_FULL);
+			kBuildProtectionEnable(&This.g_ProtData, KBUILDPROTECTIONTYPE_FULL);
 			break;
 		case 266:
-			kBuildProtectionDisable(&g_ProtData, KBUILDPROTECTIONTYPE_FULL);
+			kBuildProtectionDisable(&This.g_ProtData, KBUILDPROTECTIONTYPE_FULL);
 			break;
 		case 267:
-			if (kBuildProtectionSetDepth(&g_ProtData, optarg)) {
-			    kBuildProtectionTerm(&g_ProtData);
+			if (kBuildProtectionSetDepth(&This.g_ProtData, optarg)) {
+			    kBuildProtectionTerm(&This.g_ProtData);
 			    return 1;
 			}
@@ -239,11 +269,11 @@
 #ifdef KBUILD_OS_WINDOWS
 		case 268:
-			fUseNtDeleteFile = 1;
+			This.fUseNtDeleteFile = 1;
 			break;
 #endif
 		case '?':
 		default:
-			kBuildProtectionTerm(&g_ProtData);
-			return usage(stderr);
+			kBuildProtectionTerm(&This.g_ProtData);
+			return usage(pCtx, 1);
 		}
 	argc -= optind;
@@ -251,31 +281,39 @@
 
 	if (argc < 1) {
-		kBuildProtectionTerm(&g_ProtData);
-		if (fflag)
+		kBuildProtectionTerm(&This.g_ProtData);
+		if (This.fflag)
 			return (0);
-		return usage(stderr);
-	}
-
-	if (!kBuildProtectionScanEnv(&g_ProtData, envp, "KMK_RM_")) {
-		checkdot(argv);
-		uid = geteuid();
+		return usage(pCtx, 1);
+	}
+
+	if (!kBuildProtectionScanEnv(&This.g_ProtData, envp, "KMK_RM_")) {
+		checkdot(&This, argv);
+		This.uid = geteuid();
 
 		if (*argv) {
-			stdin_ok = isatty(STDIN_FILENO);
+			This.stdin_ok = isatty(STDIN_FILENO);
 			if (rflag)
-				eval |= rm_tree(argv);
+				This.eval |= rm_tree(&This, argv);
 			else
-				eval |= rm_file(argv);
+				This.eval |= rm_file(&This, argv);
 		}
 	} else {
-		eval = 1;
-	}
-
-	kBuildProtectionTerm(&g_ProtData);
-	return eval;
+		This.eval = 1;
+	}
+
+	kBuildProtectionTerm(&This.g_ProtData);
+	return This.eval;
 }
 
+#ifdef KMK_BUILTIN_STANDALONE
+int main(int argc, char **argv, char **envp)
+{
+	KMKBUILTINCTX Ctx = { "kmk_rm", NULL };
+	return kmk_builtin_rm(argc, argv, envp, &Ctx);
+}
+#endif
+
 static int
-rm_tree(char **argv)
+rm_tree(PRMINSTANCE pThis, char **argv)
 {
 	FTS *fts;
@@ -291,5 +329,5 @@
 	int i;
 	for (i = 0; argv[i]; i++) {
-		if (kBuildProtectionEnforce(&g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE, argv[i])) {
+		if (kBuildProtectionEnforce(&pThis->g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE, argv[i])) {
 			return 1;
 		}
@@ -300,5 +338,5 @@
 	 * (-i) or can't ask anyway (stdin_ok), don't stat the file.
 	 */
-	needstat = !uid || (!fflag && !iflag && stdin_ok);
+	needstat = !pThis->uid || (!pThis->fflag && !pThis->iflag && pThis->stdin_ok);
 
 	/*
@@ -312,9 +350,9 @@
 		flags |= FTS_NOSTAT;
 #ifdef FTS_WHITEOUT
-	if (Wflag)
+	if (pThis->Wflag)
 		flags |= FTS_WHITEOUT;
 #endif
 	if (!(fts = fts_open(argv, flags, NULL))) {
-		return err(1, "fts_open");
+		return err(pThis->pCtx, 1, "fts_open");
 	}
 	while ((p = fts_read(fts)) != NULL) {
@@ -322,13 +360,11 @@
 		switch (p->fts_info) {
 		case FTS_DNR:
-			if (!fflag || p->fts_errno != ENOENT) {
-				fprintf(stderr, "fts: %s: %s: %s" CUR_LINE() "\n",
-				        argv0, p->fts_path, strerror(p->fts_errno));
-				eval = 1;
-			}
+			if (!pThis->fflag || p->fts_errno != ENOENT)
+				pThis->eval = errx(pThis->pCtx, 1, "fts: %s: %s" CUR_LINE() "\n",
+						   p->fts_path, strerror(p->fts_errno));
 			continue;
 		case FTS_ERR:
 			fts_close(fts);
-			return errx(1, "fts: %s: %s " CUR_LINE(), p->fts_path, strerror(p->fts_errno));
+			return errx(pThis->pCtx, 1, "fts: %s: %s " CUR_LINE(), p->fts_path, strerror(p->fts_errno));
 		case FTS_NS:
 			/*
@@ -338,19 +374,16 @@
 			if (!needstat)
 				break;
-			if (!fflag || p->fts_errno != ENOENT) {
-				fprintf(stderr, "fts: %s: %s: %s " CUR_LINE() "\n",
-				        argv0, p->fts_path, strerror(p->fts_errno));
-				eval = 1;
-			}
+			if (!pThis->fflag || p->fts_errno != ENOENT)
+				pThis->eval = errx(pThis->pCtx, 1, "fts: %s: %s " CUR_LINE() "\n",
+						   p->fts_path, strerror(p->fts_errno));
 			continue;
 		case FTS_D:
 			/* Pre-order: give user chance to skip. */
-			if (!fflag && !check(p->fts_path, p->fts_accpath,
-			    p->fts_statp)) {
+			if (!pThis->fflag && !check(pThis, p->fts_path, p->fts_accpath, p->fts_statp)) {
 				(void)fts_set(fts, p, FTS_SKIP);
 				p->fts_number = SKIPPED;
 			}
 #ifdef UF_APPEND
-			else if (!uid &&
+			else if (!pThis->uid &&
 				 (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
 				 !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
@@ -366,6 +399,5 @@
 			break;
 		default:
-			if (!fflag &&
-			    !check(p->fts_path, p->fts_accpath, p->fts_statp))
+			if (!pThis->fflag && !check(pThis, p->fts_path, p->fts_accpath, p->fts_statp))
 				continue;
 		}
@@ -374,5 +406,5 @@
 		 * Protect against deleting root files and directories.
 		 */
-		if (kBuildProtectionEnforce(&g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE, p->fts_accpath)) {
+		if (kBuildProtectionEnforce(&pThis->g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE, p->fts_accpath)) {
 			fts_close(fts);
 			return 1;
@@ -381,5 +413,5 @@
 		rval = 0;
 #ifdef UF_APPEND
-		if (!uid &&
+		if (!pThis->uid &&
 		    (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
 		    !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)))
@@ -405,8 +437,7 @@
 				rval = rmdir(p->fts_accpath);
 #endif
-				if (rval == 0 || (fflag && errno == ENOENT)) {
-					if (rval == 0 && vflag)
-						(void)printf("%s\n",
-						    p->fts_path);
+				if (rval == 0 || (pThis->fflag && errno == ENOENT)) {
+					if (rval == 0 && pThis->vflag)
+						kmk_builtin_ctx_printf(pThis->pCtx, 0, "%s\n", p->fts_path);
 #if defined(KMK) && defined(KBUILD_OS_WINDOWS)
 					if (rval == 0) {
@@ -423,8 +454,7 @@
 			case FTS_W:
 				rval = undelete(p->fts_accpath);
-				if (rval == 0 && (fflag && errno == ENOENT)) {
+				if (rval == 0 && (pThis->fflag && errno == ENOENT)) {
 					if (vflag)
-						(void)printf("%s\n",
-						    p->fts_path);
+						kmk_builtin_ctx_printf(pThis->pCtx, 0, "%s\n", p->fts_path);
 					continue;
 				}
@@ -438,10 +468,10 @@
 				 * the file, it can't be unlinked.
 				 */
-				if (fflag)
+				if (pThis->fflag)
 					continue;
 				/* FALLTHROUGH */
 			default:
-				if (Pflag)
-					if (!rm_overwrite(p->fts_accpath, NULL))
+				if (pThis->Pflag)
+					if (!rm_overwrite(pThis, p->fts_accpath, NULL))
 						continue;
 #ifdef KBUILD_OS_WINDOWS
@@ -455,8 +485,7 @@
 #endif
 
-				if (rval == 0 || (fflag && errno == ENOENT)) {
-					if (rval == 0 && vflag)
-						(void)printf("%s\n",
-						    p->fts_path);
+				if (rval == 0 || (pThis->fflag && errno == ENOENT)) {
+					if (rval == 0 && pThis->vflag)
+						kmk_builtin_ctx_printf(pThis->pCtx, 0, "%s\n", p->fts_path);
 					continue;
 				}
@@ -468,17 +497,15 @@
 err:
 #endif
-		fprintf(stderr, "%s: %s: %s: %s " CUR_LINE() "\n", operation, argv0, p->fts_path, strerror(errno));
-		eval = 1;
+		pThis->eval = errx(pThis->pCtx, 1, "%s: %s failed: %s " CUR_LINE() "\n", p->fts_path, operation, strerror(errno));
 	}
 	if (errno) {
-		fprintf(stderr, "%s: fts_read: %s " CUR_LINE() "\n", argv0, strerror(errno));
-		eval = 1;
+		pThis->eval = errx(pThis->pCtx, 1, "fts_read: %s " CUR_LINE() "\n", strerror(errno));
 	}
 	fts_close(fts);
-	return eval;
+	return pThis->eval;
 }
 
 static int
-rm_file(char **argv)
+rm_file(PRMINSTANCE pThis, char **argv)
 {
 	struct stat sb;
@@ -491,5 +518,5 @@
 	int i;
 	for (i = 0; argv[i]; i++) {
-		if (kBuildProtectionEnforce(&g_ProtData, KBUILDPROTECTIONTYPE_FULL, argv[i]))
+		if (kBuildProtectionEnforce(&pThis->g_ProtData, KBUILDPROTECTIONTYPE_FULL, argv[i]))
 			return 1;
 	}
@@ -504,5 +531,5 @@
 		if (lstat(f, &sb)) {
 #ifdef FTS_WHITEOUT
-			if (Wflag) {
+			if (pThis->Wflag) {
 				sb.st_mode = S_IFWHT|S_IWUSR|S_IRUSR;
 			} else {
@@ -510,24 +537,22 @@
 			{
 #endif
-				if (!fflag || errno != ENOENT) {
-					fprintf(stderr, "lstat: %s: %s: %s " CUR_LINE() "\n", argv0, f, strerror(errno));
-					eval = 1;
-				}
+				if (!pThis->fflag || errno != ENOENT)
+					pThis->eval = errx(pThis->pCtx, 1, "%s: lstat failed: %s " CUR_LINE() "\n",
+							   f, strerror(errno));
 				continue;
 			}
 #ifdef FTS_WHITEOUT
-		} else if (Wflag) {
-			fprintf(stderr, "%s: %s: %s\n", argv0, f, strerror(EEXIST));
-			eval = 1;
+		} else if (pThis->Wflag) {
+			errx(pThis->pCtx, "%s: %s\n", f, strerror(EEXIST));
+			pThis->eval = 1;
 			continue;
 #endif
 		}
 
-		if (S_ISDIR(sb.st_mode) && !dflag) {
-			fprintf(stderr, "%s: %s: is a directory\n", argv0, f);
-			eval = 1;
+		if (S_ISDIR(sb.st_mode) && !pThis->dflag) {
+			pThis->eval = errx(pThis->pCtx, 1, "%s: is a directory\n", f);
 			continue;
 		}
-		if (!fflag && !S_ISWHT(sb.st_mode) && !check(f, f, &sb))
+		if (!pThis->fflag && !S_ISWHT(sb.st_mode) && !check(pThis, f, f, &sb))
 			continue;
 		rval = 0;
@@ -546,6 +571,6 @@
 				operation = "rmdir";
 			} else {
-				if (Pflag)
-					if (!rm_overwrite(f, &sb))
+				if (pThis->Pflag)
+					if (!rm_overwrite(pThis, f, &sb))
 						continue;
 #ifndef KBUILD_OS_WINDOWS
@@ -553,5 +578,5 @@
 				operation = "unlink";
 #else
-				if (fUseNtDeleteFile) {
+				if (pThis->fUseNtDeleteFile) {
 					rval = birdUnlinkForcedFast(f);
 					operation = "NtDeleteFile";
@@ -563,12 +588,10 @@
 			}
 		}
-		if (rval && (!fflag || errno != ENOENT)) {
-			fprintf(stderr, "%s: %s: %s: %s" CUR_LINE() "\n", operation, argv0, f, strerror(errno));
-			eval = 1;
-		}
-		if (vflag && rval == 0)
-			(void)printf("%s\n", f);
-	}
-	return eval;
+		if (rval && (!pThis->fflag || errno != ENOENT))
+			pThis->eval = errx(pThis->pCtx, 1, "%s: %s failed: %s" CUR_LINE() "\n", f, operation, strerror(errno));
+		if (pThis->vflag && rval == 0)
+			kmk_builtin_ctx_printf(pThis->pCtx, 0, "%s\n", f);
+	}
+	return pThis->eval;
 }
 
@@ -585,5 +608,5 @@
  */
 static int
-rm_overwrite(char *file, struct stat *sbp)
+rm_overwrite(PRMINSTANCE pThis, char *file, struct stat *sbp)
 {
 	struct stat sb;
@@ -595,4 +618,5 @@
 	char *buf = NULL;
 	const char *operation = "lstat";
+	int error;
 
 	fd = -1;
@@ -605,5 +629,5 @@
 		return (1);
 	operation = "open";
-	if ((fd = open(file, O_WRONLY, 0)) == -1)
+	if ((fd = open(file, O_WRONLY | KMK_OPEN_NO_INHERIT, 0)) == -1)
 		goto err;
 #ifdef HAVE_FSTATFS
@@ -616,6 +640,9 @@
 	bsize = 1024;
 #endif
-	if ((buf = malloc(bsize)) == NULL)
-		exit(err(1, "%s: malloc", file));
+	if ((buf = malloc(bsize)) == NULL) {
+		err(pThis->pCtx, 1, "%s: malloc", file);
+		close(fd);
+		return 1;
+	}
 
 #define	PASS(byte) {							\
@@ -643,10 +670,11 @@
 	operation = "fsync/close";
 
-err:	eval = 1;
+err:	pThis->eval = 1;
+	error = errno;
 	if (buf)
 		free(buf);
 	if (fd != -1)
 		close(fd);
-	fprintf(stderr, "%s: %s: %s: %s" CUR_LINE() "\n", operation, argv0, file, strerror(errno));
+	errx(pThis->pCtx, 1, "%s: %s: %s: %s" CUR_LINE() "\n", operation, pThis->pCtx->pszProgName, file, strerror(error));
 	return (0);
 }
@@ -654,5 +682,5 @@
 
 static int
-check(char *path, char *name, struct stat *sp)
+check(PRMINSTANCE pThis, char *path, char *name, struct stat *sp)
 {
 	int ch, first;
@@ -660,6 +688,6 @@
 
 	/* Check -i first. */
-	if (iflag)
-		(void)fprintf(stderr, "remove %s? ", path);
+	if (pThis->iflag)
+		(void)fprintf(stderr, "%s: remove %s? ", pThis->pCtx->pszProgName, path);
 	else {
 		/*
@@ -672,9 +700,9 @@
 		 * barf later.
 		 */
-		if (!stdin_ok || S_ISLNK(sp->st_mode) || Pflag ||
+		if (!pThis->stdin_ok || S_ISLNK(sp->st_mode) || pThis->Pflag ||
 		    (!access(name, W_OK) &&
 #ifdef SF_APPEND
 		    !(sp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
-		    (!(sp->st_flags & (UF_APPEND|UF_IMMUTABLE)) || !uid))
+		    (!(sp->st_flags & (UF_APPEND|UF_IMMUTABLE)) || !pThis->uid))
 #else
                     1)
@@ -684,6 +712,8 @@
 		bsd_strmode(sp->st_mode, modep);
 #if defined(SF_APPEND) && K_OS != K_OS_GNU_KFBSD && K_OS != K_OS_GNU_HURD
-		if ((flagsp = fflagstostr(sp->st_flags)) == NULL)
-			exit(err(1, "fflagstostr"));
+		if ((flagsp = fflagstostr(sp->st_flags)) == NULL) {
+			err(pThis->pCtx, 1, "fflagstostr");
+			flagsp = "<bad-fflagstostr>";
+		}
 		(void)fprintf(stderr, "override %s%s%s/%s %s%sfor %s? ",
 		              modep + 1, modep[9] == ' ' ? "" : " ",
@@ -710,5 +740,5 @@
 #define ISDOT(a)	((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && !(a)[2])))
 static void
-checkdot(char **argv)
+checkdot(PRMINSTANCE pThis, char **argv)
 {
 	char *p, **save, **t;
@@ -737,6 +767,6 @@
 		if (ISDOT(p)) {
 			if (!complained++)
-				fprintf(stderr, "%s: \".\" and \"..\" may not be removed\n", argv0);
-			eval = 1;
+				warnx(pThis->pCtx, "\".\" and \"..\" may not be removed\n");
+			pThis->eval = 1;
 			for (save = t; (t[0] = t[1]) != NULL; ++t)
 				continue;
@@ -748,58 +778,59 @@
 
 static int
-usage(FILE *pf)
-{
-	fprintf(pf,
-		"usage: %s [options] file ...\n"
-		"   or: %s --help\n"
-		"   or: %s --version\n"
-		"\n"
-		"Options:\n"
-		"   -f\n"
-		"       Attempt to remove files without prompting, regardless of the file\n"
-		"       permission. Ignore non-existing files. Overrides previous -i's.\n"
-		"   -i\n"
-		"       Prompt for each file. Always.\n"
-		"   -d\n"
-		"       Attempt to remove directories as well as other kinds of files.\n"
-		"   -P\n"
-		"       Overwrite regular files before deleting; three passes: ff,0,ff\n"
-		"   -R\n"
-		"       Attempt to remove the file hierachy rooted in each file argument.\n"
-		"       This option implies -d and file protection.\n"
-		"   -v\n"
-		"       Be verbose, show files as they are removed.\n"
-		"   -W\n"
-		"       Undelete without files.\n"
-		"   --disable-protection\n"
-		"       Will disable the protection file protection applied with -R.\n"
-		"   --enable-protection\n"
-		"       Will enable the protection file protection applied with -R.\n"
-		"   --enable-full-protection\n"
-		"       Will enable the protection file protection for all operations.\n"
-		"   --disable-full-protection\n"
-		"       Will disable the protection file protection for all operations.\n"
-		"   --protection-depth\n"
-		"       Number or path indicating the file protection depth. Default: %d\n"
-		"\n"
-		"Environment:\n"
-		"    KMK_RM_DISABLE_PROTECTION\n"
-		"       Same as --disable-protection. Overrides command line.\n"
-		"    KMK_RM_ENABLE_PROTECTION\n"
-		"       Same as --enable-protection. Overrides everyone else.\n"
-		"    KMK_RM_ENABLE_FULL_PROTECTION\n"
-		"       Same as --enable-full-protection. Overrides everyone else.\n"
-		"    KMK_RM_DISABLE_FULL_PROTECTION\n"
-		"       Same as --disable-full-protection. Overrides command line.\n"
-		"    KMK_RM_PROTECTION_DEPTH\n"
-		"       Same as --protection-depth. Overrides command line.\n"
-		"\n"
-		"The file protection of the top %d layers of the file hierarchy is there\n"
-		"to try prevent makefiles from doing bad things to your system. This\n"
-		"protection is not bulletproof, but should help prevent you from shooting\n"
-		"yourself in the foot.\n"
-		,
-		g_progname, g_progname, g_progname,
-		kBuildProtectionDefaultDepth(), kBuildProtectionDefaultDepth());
+usage(PKMKBUILTINCTX pCtx, int fIsErr)
+{
+	kmk_builtin_ctx_printf(pCtx, fIsErr,
+	                       "usage: %s [options] file ...\n"
+	                       "   or: %s --help\n"
+	                       "   or: %s --version\n"
+	                       "\n"
+	                       "Options:\n"
+	                       "   -f\n"
+	                       "       Attempt to remove files without prompting, regardless of the file\n"
+	                       "       permission. Ignore non-existing files. Overrides previous -i's.\n"
+	                       "   -i\n"
+	                       "       Prompt for each file. Always.\n"
+	                       "   -d\n"
+	                       "       Attempt to remove directories as well as other kinds of files.\n"
+	                       "   -P\n"
+	                       "       Overwrite regular files before deleting; three passes: ff,0,ff\n"
+	                       "   -R\n"
+	                       "       Attempt to remove the file hierachy rooted in each file argument.\n"
+	                       "       This option implies -d and file protection.\n"
+	                       "   -v\n"
+	                       "       Be verbose, show files as they are removed.\n"
+	                       "   -W\n"
+	                       "       Undelete without files.\n"
+	                       "   --disable-protection\n"
+	                       "       Will disable the protection file protection applied with -R.\n"
+	                       "   --enable-protection\n"
+	                       "       Will enable the protection file protection applied with -R.\n"
+	                       "   --enable-full-protection\n"
+	                       "       Will enable the protection file protection for all operations.\n"
+	                       "   --disable-full-protection\n"
+	                       "       Will disable the protection file protection for all operations.\n"
+	                       "   --protection-depth\n"
+	                       "       Number or path indicating the file protection depth. Default: %d\n"
+	                       "\n"
+	                       "Environment:\n"
+	                       "    KMK_RM_DISABLE_PROTECTION\n"
+	                       "       Same as --disable-protection. Overrides command line.\n"
+	                       "    KMK_RM_ENABLE_PROTECTION\n"
+	                       "       Same as --enable-protection. Overrides everyone else.\n"
+	                       "    KMK_RM_ENABLE_FULL_PROTECTION\n"
+	                       "       Same as --enable-full-protection. Overrides everyone else.\n"
+	                       "    KMK_RM_DISABLE_FULL_PROTECTION\n"
+	                       "       Same as --disable-full-protection. Overrides command line.\n"
+	                       "    KMK_RM_PROTECTION_DEPTH\n"
+	                       "       Same as --protection-depth. Overrides command line.\n"
+	                       "\n"
+	                       "The file protection of the top %d layers of the file hierarchy is there\n"
+	                       "to try prevent makefiles from doing bad things to your system. This\n"
+	                       "protection is not bulletproof, but should help prevent you from shooting\n"
+	                       "yourself in the foot.\n"
+	                       ,
+	                       pCtx->pszProgName, pCtx->pszProgName, pCtx->pszProgName,
+	                       kBuildProtectionDefaultDepth(), kBuildProtectionDefaultDepth());
 	return EX_USAGE;
 }
+
Index: trunk/src/kmk/kmkbuiltin/rmdir.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/rmdir.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/rmdir.c	(revision 3192)
@@ -44,4 +44,8 @@
 #endif
 
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
 #include "config.h"
 #include "err.h"
@@ -60,16 +64,23 @@
 # include "mscfakes.h"
 #endif
-#if defined(KMK) && defined(KBUILD_OS_WINDOWS)
-extern int dir_cache_deleted_directory(const char *pszDir);
-#endif
-
-static int rm_path(char *);
-static int usage(FILE *);
-
-static int pflag;
-static int vflag;
-static int ignore_fail_on_non_empty;
-static int ignore_fail_on_not_exist;
-
+
+
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+typedef struct RMDIRINSTANCE
+{
+    PKMKBUILTINCTX pCtx;
+    int pflag;
+    int vflag;
+    int ignore_fail_on_non_empty;
+    int ignore_fail_on_not_exist;
+} RMDIRINSTANCE;
+typedef RMDIRINSTANCE *PRMDIRINSTANCE;
+
+
+/*********************************************************************************************************************************
+*   Global Variables                                                                                                             *
+*********************************************************************************************************************************/
 static struct option long_options[] =
 {
@@ -84,14 +95,29 @@
 
 
+
+/*********************************************************************************************************************************
+*   Internal Functions                                                                                                           *
+*********************************************************************************************************************************/
+#if !defined(KMK_BUILTIN_STANDALONE) && defined(KBUILD_OS_WINDOWS)
+extern int dir_cache_deleted_directory(const char *pszDir);
+#endif
+static int rm_path(PRMDIRINSTANCE, char *);
+static int usage(PKMKBUILTINCTX, int);
+
+
 int
-kmk_builtin_rmdir(int argc, char *argv[], char **envp)
-{
+kmk_builtin_rmdir(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx)
+{
+	RMDIRINSTANCE This;
 	int ch, errors;
 
-	/* reinitialize globals */
-	ignore_fail_on_not_exist = ignore_fail_on_non_empty = vflag = pflag = 0;
+	/* Initialize global instance. */
+	This.pCtx = pCtx;
+	This.ignore_fail_on_not_exist = 0;
+	This.ignore_fail_on_non_empty = 0;
+	This.vflag = 0;
+	This.pflag = 0;
 
 	/* kmk: reset getopt and set progname */
-	g_progname = argv[0];
 	opterr = 1;
 	optarg = NULL;
@@ -101,17 +127,17 @@
 		switch(ch) {
 		case 'p':
-			pflag = 1;
+			This.pflag = 1;
 			break;
 		case 'v':
-			vflag = 1;
+			This.vflag = 1;
 			break;
 		case 260:
-			ignore_fail_on_non_empty = 1;
+			This.ignore_fail_on_non_empty = 1;
 			break;
 		case 261:
-			ignore_fail_on_not_exist = 1;
+			This.ignore_fail_on_not_exist = 1;
 			break;
 		case 262:
-			usage(stdout);
+			usage(pCtx, 0);
 			return 0;
 		case 263:
@@ -119,5 +145,5 @@
 		case '?':
 		default:
-			return usage(stderr);
+			return usage(pCtx, 1);
 		}
 	argc -= optind;
@@ -129,23 +155,24 @@
 	for (errors = 0; *argv; argv++) {
 		if (rmdir(*argv) < 0) {
-			if (	(!ignore_fail_on_non_empty || (errno != ENOTEMPTY && errno != EPERM && errno != EACCES && errno != EINVAL && errno != EEXIST))
-			    &&	(!ignore_fail_on_not_exist || errno != ENOENT)) {
-				warn("rmdir: %s", *argv);
+			if (	(   !This.ignore_fail_on_non_empty
+				 || (errno != ENOTEMPTY && errno != EPERM && errno != EACCES && errno != EINVAL && errno != EEXIST))
+			    &&	(   !This.ignore_fail_on_not_exist
+				 || errno != ENOENT)) {
+				warn(pCtx, "rmdir: %s", *argv);
 				errors = 1;
 				continue;
 			}
-			if (!ignore_fail_on_not_exist || errno != ENOENT)
+			if (!This.ignore_fail_on_not_exist || errno != ENOENT)
 				continue;
 			/* (only ignored doesn't exist errors fall thru) */
 		} else {
-#if defined(KMK) && defined(KBUILD_OS_WINDOWS)
+#if !defined(KMK_BUILTIN_STANDALONE) && defined(KBUILD_OS_WINDOWS)
 			dir_cache_deleted_directory(*argv);
 #endif
-			if (vflag) {
-				printf("%s\n", *argv);
-			}
-		}
-		if (pflag)
-			errors |= rm_path(*argv);
+			if (This.vflag)
+				kmk_builtin_ctx_printf(pCtx, 0, "%s\n", *argv);
+		}
+		if (This.pflag)
+			errors |= rm_path(&This, *argv);
 	}
 
@@ -153,6 +180,14 @@
 }
 
+#ifdef KMK_BUILTIN_STANDALONE
+int main(int argc, char **argv, char **envp)
+{
+    KMKBUILTINCTX Ctx = { "kmk_rmdir", NULL };
+    return kmk_builtin_rmdir(argc, argv, envp, &Ctx);
+}
+#endif
+
 static int
-rm_path(char *path)
+rm_path(PRMDIRINSTANCE pThis, char *path)
 {
 	char *p;
@@ -186,9 +221,9 @@
 
 		if (rmdir(path) < 0) {
-			if (   ignore_fail_on_non_empty
+			if (   pThis->ignore_fail_on_non_empty
 			    && (   errno == ENOTEMPTY || errno == EPERM || errno == EACCES || errno == EINVAL || errno == EEXIST))
 				break;
-			if (!ignore_fail_on_not_exist || errno != ENOENT) {
-				warn("rmdir: %s", path);
+			if (!pThis->ignore_fail_on_not_exist || errno != ENOENT) {
+				warn(pThis->pCtx, "rmdir: %s", path);
 				return (1);
 			}
@@ -199,6 +234,6 @@
 		}
 #endif
-		if (vflag)
-			printf("%s\n", path);
+		if (pThis->vflag)
+			kmk_builtin_ctx_printf(pThis->pCtx, 0, "%s\n", path);
 	}
 
@@ -207,10 +242,12 @@
 
 static int
-usage(FILE *pf)
-{
-	(void)fprintf(pf, "usage: %s [-pv --ignore-fail-on-non-empty --ignore-fail-on-not-exist] directory ...\n"
-	                  "   or: %s --help\n"
-	                  "   or: %s --version\n",
-	              g_progname, g_progname, g_progname);
+usage(PKMKBUILTINCTX pCtx, int fIsErr)
+{
+	kmk_builtin_ctx_printf(pCtx, fIsErr,
+			       "usage: %s [-pv --ignore-fail-on-non-empty --ignore-fail-on-not-exist] directory ...\n"
+			       "   or: %s --help\n"
+			       "   or: %s --version\n",
+			       pCtx->pszProgName, pCtx->pszProgName, pCtx->pszProgName);
 	return 1;
 }
+
Index: trunk/src/kmk/kmkbuiltin/sleep.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/sleep.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/sleep.c	(revision 3192)
@@ -40,41 +40,28 @@
 #endif
 
+#include "err.h"
 #include "../kmkbuiltin.h"
 
 
-static const char *name(const char *pszName)
+static int kmk_builtin_sleep_usage(PKMKBUILTINCTX pCtx, int fIsErr)
 {
-    const char *psz = strrchr(pszName, '/');
-#if defined(_MSC_VER) || defined(__OS2__)
-    const char *psz2 = strrchr(pszName, '\\');
-    if (!psz2)
-        psz2 = strrchr(pszName, ':');
-    if (psz2 && (!psz || psz2 > psz))
-        psz = psz2;
-#endif
-    return psz ? psz + 1 : pszName;
-}
-
-
-static int usage(FILE *pOut,  const char *argv0)
-{
-    argv0 = name(argv0);
-    fprintf(pOut,
-            "usage: %s <seconds>[s]\n"
-            "   or: %s <milliseconds>ms\n"
-            "   or: %s <minutes>m\n"
-            "   or: %s <hours>h\n"
-            "   or: %s <days>d\n"
-            "   or: %s --help\n"
-            "   or: %s --version\n"
-            "\n"
-            "Only integer values are accepted.\n"
-            ,
-            argv0, argv0, argv0, argv0, argv0, argv0, argv0);
+    kmk_builtin_ctx_printf(pCtx, fIsErr,
+                           "usage: %s <seconds>[s]\n"
+                           "   or: %s <milliseconds>ms\n"
+                           "   or: %s <minutes>m\n"
+                           "   or: %s <hours>h\n"
+                           "   or: %s <days>d\n"
+                           "   or: %s --help\n"
+                           "   or: %s --version\n"
+                           "\n"
+                           "Only integer values are accepted.\n"
+                           ,
+                           pCtx->pszProgName, pCtx->pszProgName, pCtx->pszProgName, pCtx->pszProgName,
+                           pCtx->pszProgName, pCtx->pszProgName, pCtx->pszProgName);
     return 1;
 }
 
 
-int kmk_builtin_sleep(int argc, char **argv, char **envp)
+int kmk_builtin_sleep(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx)
 {
     long cMsToSleep;
@@ -88,5 +75,5 @@
      */
     if (argc != 2)
-        return usage(stderr, argv[0]);
+        return kmk_builtin_sleep_usage(pCtx, 1);
 
     /* help request */
@@ -96,5 +83,5 @@
         || !strcmp(argv[1], "--help"))
     {
-        usage(stdout, argv[0]);
+        kmk_builtin_sleep_usage(pCtx, 0);
         return 0;
     }
@@ -121,8 +108,5 @@
     cMsToSleep = strtol(pszInterval, &pszSuff, 0);
     if (pszSuff == pszInterval)
-    {
-        fprintf(stderr, "%s: malformed interval '%s'!\n", name(argv[0]), pszInterval);
-        return 1;
-    }
+        return errx(pCtx, 1, "malformed interval '%s'!\n", pszInterval);
 
     while (isspace(*pszSuff))
@@ -142,8 +126,5 @@
         {
             if (!isspace(pszSuff[i]))
-            {
-                fprintf(stderr, "%s: malformed interval '%s'!\n", name(argv[0]), pszInterval);
-                return 1;
-            }
+                return errx(pCtx, 1, "malformed interval '%s'!\n", pszInterval);
             i++;
         }
@@ -160,8 +141,5 @@
             ulFactor = 24*60*60*1000;
         else
-        {
-            fprintf(stderr, "%s: unknown suffix '%.*s'!\n", name(argv[0]), cchSuff, pszSuff);
-            return 1;
-        }
+            return errx(pCtx, 1, "unknown suffix '%.*s'!\n", cchSuff, pszSuff);
     }
 
@@ -169,8 +147,5 @@
     cMsToSleep *= ulFactor;
     if ((cMsToSleep / ulFactor) != (unsigned long)lTmp)
-    {
-        fprintf(stderr, "%s: time interval overflow!\n", name(argv[0]));
-        return 1;
-    }
+        return errx(pCtx, 1, "time interval overflow!\n");
 
     /*
@@ -195,2 +170,10 @@
 }
 
+#ifdef KMK_BUILTIN_STANDALONE
+int main(int argc, char **argv, char **envp)
+{
+    KMKBUILTINCTX Ctx = { "kmk_sleep", NULL };
+    return kmk_builtin_sleep(argc, argv, envp, &Ctx);
+}
+#endif
+
Index: trunk/src/kmk/kmkbuiltin/test.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/test.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/test.c	(revision 3192)
@@ -16,4 +16,8 @@
 #endif*/
 
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
 #include "config.h"
 #include <sys/stat.h>
@@ -32,4 +36,5 @@
 # include <process.h>
 # include "mscfakes.h"
+# include "quote_argv.h"
 #else
 # include <unistd.h>
@@ -40,4 +45,8 @@
 #include "kmkbuiltin.h"
 
+
+/*********************************************************************************************************************************
+*   Defined Constants And Macros                                                                                                 *
+*********************************************************************************************************************************/
 #ifndef __arraycount
 # define __arraycount(a) 	( sizeof(a) / sizeof(a[0]) )
@@ -45,4 +54,7 @@
 
 
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
 /* test(1) accepts the following grammar:
 	oexpr	::= aexpr | aexpr "-o" oexpr ;
@@ -118,4 +130,17 @@
 };
 
+/** kmk_test instance data.   */
+typedef struct TESTINSTANCE
+{
+    PKMKBUILTINCTX pCtx;
+    char **t_wp;
+    struct t_op const *t_wp_op;
+} TESTINSTANCE;
+typedef TESTINSTANCE *PTESTINSTANCE;
+
+
+/*********************************************************************************************************************************
+*   Global Variables                                                                                                             *
+*********************************************************************************************************************************/
 static const struct t_op cop[] = {
 	{"!",	UNOT,	BUNOP},
@@ -169,24 +194,25 @@
 };
 
-static char **t_wp;
-static struct t_op const *t_wp_op;
-
-static int syntax(const char *, const char *);
-static int oexpr(enum token);
-static int aexpr(enum token);
-static int nexpr(enum token);
-static int primary(enum token);
-static int binop(void);
+
+/*********************************************************************************************************************************
+*   Internal Functions                                                                                                           *
+*********************************************************************************************************************************/
+static int syntax(PTESTINSTANCE, const char *, const char *);
+static int oexpr(PTESTINSTANCE, enum token);
+static int aexpr(PTESTINSTANCE, enum token);
+static int nexpr(PTESTINSTANCE, enum token);
+static int primary(PTESTINSTANCE, enum token);
+static int binop(PTESTINSTANCE);
 static int test_access(struct stat *, mode_t);
 static int filstat(char *, enum token);
-static enum token t_lex(char *);
-static int isoperand(void);
-static int getn(const char *);
+static enum token t_lex(PTESTINSTANCE, char *);
+static int isoperand(PTESTINSTANCE);
+static int getn(PTESTINSTANCE, const char *);
 static int newerf(const char *, const char *);
 static int olderf(const char *, const char *);
 static int equalf(const char *, const char *);
-static int usage(const char *);
-
-#if !defined(kmk_builtin_test) || defined(ELECTRIC_HEAP)
+static int usage(PKMKBUILTINCTX, int);
+
+#if !defined(KMK_BUILTIN_STANDALONE) || defined(ELECTRIC_HEAP)
 extern void *xmalloc(unsigned int);
 #else
@@ -195,5 +221,5 @@
     void *p = malloc(sz);
     if (!p) {
-	    fprintf(stderr, "%s: malloc(%u) failed\n", g_progname, sz);
+	    fprintf(stderr, "kmk_test: malloc(%u) failed\n", sz);
 	    exit(1);
     }
@@ -202,15 +228,16 @@
 #endif
 
-int kmk_builtin_test(int argc, char **argv, char **envp
-#ifndef kmk_builtin_test
-		     , char ***ppapszArgvSpawn
-#endif
-		     )
-{
+
+
+int kmk_builtin_test(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx, char ***ppapszArgvSpawn)
+{
+	TESTINSTANCE This;
 	int res;
 	char **argv_spawn;
 	int i;
 
-	g_progname = argv[0];
+	This.pCtx = pCtx;
+	This.t_wp = NULL;
+	This.t_wp_op = NULL;
 
 	/* look for the '--', '--help' and '--version'. */
@@ -235,5 +262,5 @@
 			}
 			if (!strcmp(argv[i], "--help"))
-				return usage(argv[0]);
+				return usage(pCtx, 0);
 			if (!strcmp(argv[i], "--version"))
 				return kbuild_version(argv[0]);
@@ -242,7 +269,7 @@
 
 	/* are we '['? then check for ']'. */
-	if (strcmp(g_progname, "[") == 0) { /** @todo should skip the path in g_progname */
+	if (strcmp(argv[0], "[") == 0) { /** @todo should skip the path in g_progname */
 		if (strcmp(argv[--argc], "]"))
-			return errx(1, "missing ]");
+			return errx(pCtx, 1, "missing ]");
 		argv[argc] = NULL;
 	}
@@ -252,8 +279,8 @@
 		res = 1;
 	else {
-		t_wp = &argv[1];
-		res = oexpr(t_lex(*t_wp));
-		if (res != -42 && *t_wp != NULL && *++t_wp != NULL)
-			res = syntax(*t_wp, "unexpected operator");
+		This.t_wp = &argv[1];
+		res = oexpr(&This, t_lex(&This, *This.t_wp));
+		if (res != -42 && *This.t_wp != NULL && *++This.t_wp != NULL)
+			res = syntax(&This, *This.t_wp, "unexpected operator");
 		if (res == -42)
 			return 1; /* don't mix syntax errors with the argv_spawn ignore */
@@ -266,10 +293,18 @@
 			res = 0; /* ignored */
 		else {
-#ifdef kmk_builtin_test
+#ifdef KMK_BUILTIN_STANDALONE
 			/* try exec the specified process */
 # if defined(_MSC_VER)
-			res = _spawnvp(_P_WAIT, argv_spawn[0], argv_spawn);
-			if (res == -1)
-			    res = err(1, "_spawnvp(_P_WAIT,%s,..)", argv_spawn[0]);
+			int argc_spawn = 0;
+			while (argv_spawn[argc_spawn])
+				argc_spawn++;
+			if (quote_argv(argc, argv_spawn, 0 /*fWatcomBrainDamage*/, 0/*fFreeOrLeak*/) != -1)
+			{
+			    res = _spawnvp(_P_WAIT, argv_spawn[0], argv_spawn);
+			    if (res == -1)
+				res = err(pCtx, 1, "_spawnvp(_P_WAIT,%s,..)", argv_spawn[0]);
+			}
+			else
+			    res = err(pCtx, 1, "quote_argv: out of memory");
 # else
 			execvp(argv_spawn[0], argv_spawn);
@@ -305,59 +340,67 @@
 }
 
-static int
-syntax(const char *op, const char *msg)
+#ifdef KMK_BUILTIN_STANDALONE
+int main(int argc, char **argv, char **envp)
+{
+    KMKBUILTINCTX Ctx = { "kmk_test", NULL };
+    return kmk_builtin_test(argc, argv, envp, &Ctx, NULL);
+}
+#endif
+
+static int
+syntax(PTESTINSTANCE pThis, const char *op, const char *msg)
 {
 
 	if (op && *op)
-		errx(1, "%s: %s", op, msg);
+		errx(pThis->pCtx, 1, "%s: %s", op, msg);
 	else
-		errx(1, "%s", msg);
+		errx(pThis->pCtx, 1, "%s", msg);
 	return -42;
 }
 
 static int
-oexpr(enum token n)
+oexpr(PTESTINSTANCE pThis, enum token n)
 {
 	int res;
 
-	res = aexpr(n);
-	if (res == -42 || *t_wp == NULL)
+	res = aexpr(pThis, n);
+	if (res == -42 || *pThis->t_wp == NULL)
 		return res;
-	if (t_lex(*++t_wp) == BOR) {
-		int res2 = oexpr(t_lex(*++t_wp));
+	if (t_lex(pThis, *++(pThis->t_wp)) == BOR) {
+		int res2 = oexpr(pThis, t_lex(pThis, *++(pThis->t_wp)));
 		return res2 != -42 ? res2 || res : res2;
 	}
-	t_wp--;
+	pThis->t_wp--;
 	return res;
 }
 
 static int
-aexpr(enum token n)
+aexpr(PTESTINSTANCE pThis, enum token n)
 {
 	int res;
 
-	res = nexpr(n);
-	if (res == -42 || *t_wp == NULL)
+	res = nexpr(pThis, n);
+	if (res == -42 || *pThis->t_wp == NULL)
 		return res;
-	if (t_lex(*++t_wp) == BAND) {
-		int res2 = aexpr(t_lex(*++t_wp));
+	if (t_lex(pThis, *++(pThis->t_wp)) == BAND) {
+		int res2 = aexpr(pThis, t_lex(pThis, *++(pThis->t_wp)));
 		return res2 != -42 ? res2 && res : res2;
 	}
-	t_wp--;
+	pThis->t_wp--;
 	return res;
 }
 
 static int
-nexpr(enum token n)
+nexpr(PTESTINSTANCE pThis, enum token n)
 {
 	if (n == UNOT) {
-		int res = nexpr(t_lex(*++t_wp));
+		int res = nexpr(pThis, t_lex(pThis, *++(pThis->t_wp)));
 		return res != -42 ? !res : res;
 	}
-	return primary(n);
-}
-
-static int
-primary(enum token n)
+	return primary(pThis, n);
+}
+
+static int
+primary(PTESTINSTANCE pThis, enum token n)
 {
 	enum token nn;
@@ -367,46 +410,46 @@
 		return 0;		/* missing expression */
 	if (n == LPAREN) {
-		if ((nn = t_lex(*++t_wp)) == RPAREN)
+		if ((nn = t_lex(pThis, *++(pThis->t_wp))) == RPAREN)
 			return 0;	/* missing expression */
-		res = oexpr(nn);
-		if (res != -42 && t_lex(*++t_wp) != RPAREN)
-			return syntax(NULL, "closing paren expected");
+		res = oexpr(pThis, nn);
+		if (res != -42 && t_lex(pThis, *++(pThis->t_wp)) != RPAREN)
+			return syntax(pThis, NULL, "closing paren expected");
 		return res;
 	}
-	if (t_wp_op && t_wp_op->op_type == UNOP) {
+	if (pThis->t_wp_op && pThis->t_wp_op->op_type == UNOP) {
 		/* unary expression */
-		if (*++t_wp == NULL)
-			return syntax(t_wp_op->op_text, "argument expected");
+		if (*++(pThis->t_wp) == NULL)
+			return syntax(pThis, pThis->t_wp_op->op_text, "argument expected");
 		switch (n) {
 		case STREZ:
-			return strlen(*t_wp) == 0;
+			return strlen(*pThis->t_wp) == 0;
 		case STRNZ:
-			return strlen(*t_wp) != 0;
+			return strlen(*pThis->t_wp) != 0;
 		case FILTT:
-			return isatty(getn(*t_wp));
+			return isatty(getn(pThis, *pThis->t_wp));
 		default:
-			return filstat(*t_wp, n);
+			return filstat(*pThis->t_wp, n);
 		}
 	}
 
-	if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) {
-		return binop();
-	}
-
-	return strlen(*t_wp) > 0;
-}
-
-static int
-binop(void)
+	if (t_lex(pThis, pThis->t_wp[1]), pThis->t_wp_op && pThis->t_wp_op->op_type == BINOP) {
+		return binop(pThis);
+	}
+
+	return strlen(*pThis->t_wp) > 0;
+}
+
+static int
+binop(PTESTINSTANCE pThis)
 {
 	const char *opnd1, *opnd2;
 	struct t_op const *op;
 
-	opnd1 = *t_wp;
-	(void) t_lex(*++t_wp);
-	op = t_wp_op;
-
-	if ((opnd2 = *++t_wp) == NULL)
-		return syntax(op->op_text, "argument expected");
+	opnd1 = *pThis->t_wp;
+	(void) t_lex(pThis, *++(pThis->t_wp));
+	op = pThis->t_wp_op;
+
+	if ((opnd2 = *++(pThis->t_wp)) == NULL)
+		return syntax(pThis, op->op_text, "argument expected");
 
 	switch (op->op_num) {
@@ -420,15 +463,15 @@
 		return strcmp(opnd1, opnd2) > 0;
 	case INTEQ:
-		return getn(opnd1) == getn(opnd2);
+		return getn(pThis, opnd1) == getn(pThis, opnd2);
 	case INTNE:
-		return getn(opnd1) != getn(opnd2);
+		return getn(pThis, opnd1) != getn(pThis, opnd2);
 	case INTGE:
-		return getn(opnd1) >= getn(opnd2);
+		return getn(pThis, opnd1) >= getn(pThis, opnd2);
 	case INTGT:
-		return getn(opnd1) > getn(opnd2);
+		return getn(pThis, opnd1) > getn(pThis, opnd2);
 	case INTLE:
-		return getn(opnd1) <= getn(opnd2);
+		return getn(pThis, opnd1) <= getn(pThis, opnd2);
 	case INTLT:
-		return getn(opnd1) < getn(opnd2);
+		return getn(pThis, opnd1) < getn(pThis, opnd2);
 	case FILNT:
 		return newerf(opnd1, opnd2);
@@ -714,15 +757,12 @@
 			return NULL;
 		if (s[2] == '\0')
-			return bsearch(s + 1, mop2, __arraycount(mop2),
-			    sizeof(*mop2), compare1);
+			return bsearch(s + 1, mop2, __arraycount(mop2), sizeof(*mop2), compare1);
 		else if (s[3] != '\0')
 			return NULL;
 		else
-			return bsearch(s + 1, mop3, __arraycount(mop3),
-			    sizeof(*mop3), compare2);
+			return bsearch(s + 1, mop3, __arraycount(mop3), sizeof(*mop3), compare2);
 	} else {
 		if (s[1] == '\0')
-			return bsearch(s, cop, __arraycount(cop), sizeof(*cop),
-			    compare1);
+			return bsearch(s, cop, __arraycount(cop), sizeof(*cop), compare1);
 		else if (strcmp(s, cop2[0].op_text) == 0)
 			return cop2;
@@ -733,33 +773,33 @@
 
 static enum token
-t_lex(char *s)
+t_lex(PTESTINSTANCE pThis, char *s)
 {
 	struct t_op const *op;
 
 	if (s == NULL) {
-		t_wp_op = NULL;
+		pThis->t_wp_op = NULL;
 		return EOI;
 	}
 
 	if ((op = findop(s)) != NULL) {
-		if (!((op->op_type == UNOP && isoperand()) ||
-		    (op->op_num == LPAREN && *(t_wp+1) == 0))) {
-			t_wp_op = op;
+		if (!((op->op_type == UNOP && isoperand(pThis)) ||
+		    (op->op_num == LPAREN && *(pThis->t_wp+1) == 0))) {
+			pThis->t_wp_op = op;
 			return op->op_num;
 		}
 	}
-	t_wp_op = NULL;
+	pThis->t_wp_op = NULL;
 	return OPERAND;
 }
 
 static int
-isoperand(void)
+isoperand(PTESTINSTANCE pThis)
 {
 	struct t_op const *op;
 	char *s, *t;
 
-	if ((s  = *(t_wp+1)) == 0)
+	if ((s  = *(pThis->t_wp+1)) == 0)
 		return 1;
-	if ((t = *(t_wp+2)) == 0)
+	if ((t = *(pThis->t_wp+2)) == 0)
 		return 0;
 	if ((op = findop(s)) != NULL)
@@ -770,5 +810,5 @@
 /* atoi with error detection */
 static int
-getn(const char *s)
+getn(PTESTINSTANCE pThis, const char *s)
 {
 	char *p;
@@ -779,5 +819,5 @@
 
 	if (errno != 0)
-	      return errx(-42, "%s: out of range", s);
+	      return errx(pThis->pCtx, -42, "%s: out of range", s);
 
 	while (isspace((unsigned char)*p))
@@ -785,5 +825,5 @@
 
 	if (*p)
-	      return errx(-42, "%s: bad number", s);
+	      return errx(pThis->pCtx, -42, "%s: bad number", s);
 
 	return (int) r;
@@ -822,8 +862,8 @@
 
 static int
-usage(const char *argv0)
-{
-	fprintf(stdout,
-	        "usage: %s expression [-- <prog> [args]]\n", argv0);
+usage(PKMKBUILTINCTX pCtx, int fIsErr)
+{
+	kmk_builtin_ctx_printf(pCtx, fIsErr, "usage: %s expression [-- <prog> [args]]\n", pCtx->pszProgName);
 	return 0; /* only used in --help. */
 }
+
Index: trunk/src/kmk/kmkbuiltin/touch.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/touch.c	(revision 3191)
+++ trunk/src/kmk/kmkbuiltin/touch.c	(revision 3192)
@@ -91,4 +91,6 @@
 typedef struct KMKTOUCHOPTS
 {
+    /** Command execution context. */
+    PKMKBUILTINCTX  pCtx;
     /** What timestamps to modify on the files. */
     KMKTOUCHTARGET  enmWhatToTouch;
@@ -111,27 +113,4 @@
 typedef KMKTOUCHOPTS *PKMKTOUCHOPTS;
 
-
-
-static int touch_error(const char *pszMsg, ...)
-{
-    va_list va;
-    fputs(TOUCH_NAME ": error: ", stderr);
-    va_start(va, pszMsg);
-    vfprintf(stderr, pszMsg, va);
-    va_end(va);
-    fputc('\n', stderr);
-    return 1;
-}
-
-static int touch_syntax(const char *pszMsg, ...)
-{
-    va_list va;
-    fputs(TOUCH_NAME ": syntax error: ", stderr);
-    va_start(va, pszMsg);
-    vfprintf(stderr, pszMsg, va);
-    va_end(va);
-    fputc('\n', stderr);
-    return 2;
-}
 
 static int touch_usage(void)
@@ -189,5 +168,5 @@
  * Parses adjustment value: [-][[hh]mm]SS
  */
-static int touch_parse_adjust(const char *pszValue, int *piAdjustValue)
+static int touch_parse_adjust(PKMKBUILTINCTX pCtx, const char *pszValue, int *piAdjustValue)
 {
     const char * const  pszInValue = pszValue;
@@ -210,5 +189,5 @@
             if (   !IS_DIGIT(pszValue[0], 9)
                 || !IS_DIGIT(pszValue[0], 9))
-                return touch_syntax("Malformed hour part of -A value: %s", pszInValue);
+                return errx(pCtx, 2, "Malformed hour part of -A value: %s", pszInValue);
             *piAdjustValue = TWO_CHARS_TO_INT(pszValue[0], pszValue[1]) * 60 * 60;
             /* fall thru */
@@ -216,5 +195,5 @@
             if (   !IS_DIGIT(pszValue[cchValue - 4], 9) /* don't bother limit to 60 minutes */
                 || !IS_DIGIT(pszValue[cchValue - 3], 9))
-                return touch_syntax("Malformed minute part of -A value: %s", pszInValue);
+                return errx(pCtx, 2, "Malformed minute part of -A value: %s", pszInValue);
             *piAdjustValue += TWO_CHARS_TO_INT(pszValue[cchValue - 4], pszValue[cchValue - 3]) * 60;
             /* fall thru */
@@ -222,10 +201,10 @@
             if (   !IS_DIGIT(pszValue[cchValue - 2], 9) /* don't bother limit to 60 seconds */
                 || !IS_DIGIT(pszValue[cchValue - 1], 9))
-                return touch_syntax("Malformed second part of -A value: %s", pszInValue);
+                return errx(pCtx, 2, "Malformed second part of -A value: %s", pszInValue);
             *piAdjustValue += TWO_CHARS_TO_INT(pszValue[cchValue - 2], pszValue[cchValue - 1]);
             break;
 
         default:
-            return touch_syntax("Invalid -A value (length): %s", pszInValue);
+            return errx(pCtx, 2, "Invalid -A value (length): %s", pszInValue);
     }
 
@@ -241,5 +220,5 @@
  * Parse -d timestamp: YYYY-MM-DDThh:mm:SS[.frac][tz]
  */
-static int touch_parse_d_ts(const char *pszTs, struct timeval *pDst)
+static int touch_parse_d_ts(PKMKBUILTINCTX pCtx, const char *pszTs, struct timeval *pDst)
 {
     const char * const  pszTsIn = pszTs;
@@ -257,6 +236,6 @@
         || !IS_DIGIT(pszTs[3], 9)
         || pszTs[4] != '-')
-        return touch_error("Malformed timestamp '%s' given to -d: expected to start with 4 digit year followed by a dash",
-                           pszTsIn);
+        return errx(pCtx, 2, "Malformed timestamp '%s' given to -d: expected to start with 4 digit year followed by a dash",
+                    pszTsIn);
     ExpTime.tm_year = TWO_CHARS_TO_INT(pszTs[0], pszTs[1]) * 100
                     + TWO_CHARS_TO_INT(pszTs[2], pszTs[3])
@@ -268,6 +247,6 @@
         || !IS_DIGIT(pszTs[1], 9)
         || pszTs[2] != '-')
-        return touch_error("Malformed timestamp '%s' given to -d: expected to two digit month at position 6 followed by a dash",
-                           pszTsIn);
+        return errx(pCtx, 2, "Malformed timestamp '%s' given to -d: expected to two digit month at position 6 followed by a dash",
+                    pszTsIn);
     ExpTime.tm_mon = TWO_CHARS_TO_INT(pszTs[0], pszTs[1]) - 1;
     pszTs += 3;
@@ -277,6 +256,6 @@
         || !IS_DIGIT(pszTs[1], 9)
         || (pszTs[2] != 'T' && pszTs[2] != 't' && pszTs[2] != ' ') )
-        return touch_error("Malformed timestamp '%s' given to -d: expected to two digit day of month at position 9 followed by 'T' or space",
-                           pszTsIn);
+        return errx(pCtx, 2, "Malformed timestamp '%s' given to -d: expected to two digit day of month at position 9 followed by 'T' or space",
+                    pszTsIn);
     ExpTime.tm_mday = TWO_CHARS_TO_INT(pszTs[0], pszTs[1]);
     pszTs += 3;
@@ -286,6 +265,6 @@
         || !IS_DIGIT(pszTs[1], 9)
         || pszTs[2] != ':')
-        return touch_error("Malformed timestamp '%s' given to -d: expected to two digit hour at position 12 followed by colon",
-                           pszTsIn);
+        return errx(pCtx, 2, "Malformed timestamp '%s' given to -d: expected to two digit hour at position 12 followed by colon",
+                    pszTsIn);
     ExpTime.tm_hour = TWO_CHARS_TO_INT(pszTs[0], pszTs[1]);
     pszTs += 3;
@@ -295,6 +274,6 @@
         || !IS_DIGIT(pszTs[1], 9)
         || pszTs[2] != ':')
-        return touch_error("Malformed timestamp '%s' given to -d: expected to two digit minute at position 15 followed by colon",
-                           pszTsIn);
+        return errx(pCtx, 2, "Malformed timestamp '%s' given to -d: expected to two digit minute at position 15 followed by colon",
+                    pszTsIn);
     ExpTime.tm_min = TWO_CHARS_TO_INT(pszTs[0], pszTs[1]);
     pszTs += 3;
@@ -303,5 +282,5 @@
     if (   !IS_DIGIT(pszTs[0], 5)
         || !IS_DIGIT(pszTs[1], 9))
-        return touch_error("Malformed timestamp '%s' given to -d: expected to two digit seconds at position 12", pszTsIn);
+        return errx(pCtx, 2, "Malformed timestamp '%s' given to -d: expected to two digit seconds at position 12", pszTsIn);
     ExpTime.tm_sec = TWO_CHARS_TO_INT(pszTs[0], pszTs[1]);
     pszTs += 2;
@@ -315,5 +294,5 @@
         pszTs++;
         if (!IS_DIGIT(*pszTs, 9))
-            return touch_error("Malformed timestamp '%s' given to -d: empty fraction", pszTsIn);
+            return errx(pCtx, 2, "Malformed timestamp '%s' given to -d: empty fraction", pszTsIn);
 
         iFactor = 100000;
@@ -333,9 +312,10 @@
         pszTs++;
         if (*pszTs != '\0')
-            return touch_error("Malformed timestamp '%s' given to -d: Unexpected character(s) after zulu time indicator at end of timestamp",
-                               pszTsIn);
+            return errx(pCtx, 2,
+                        "Malformed timestamp '%s' given to -d: Unexpected character(s) after zulu time indicator at end of timestamp",
+                        pszTsIn);
     }
     else if (*pszTs != '\0')
-        return touch_error("Malformed timestamp '%s' given to -d: expected to 'Z' (zulu) or nothing at end of timestamp", pszTsIn);
+        return errx(pCtx, 2, "Malformed timestamp '%s' given to -d: expected to 'Z' (zulu) or nothing at end of timestamp", pszTsIn);
 
     /*
@@ -352,5 +332,5 @@
 #endif
         if (pDst->tv_sec == -1)
-            return touch_error("timegm failed on '%s': %s", pszTs, strerror(errno));
+            return errx(pCtx, 1, "timegm failed on '%s': %s", pszTs, strerror(errno));
     }
     else
@@ -358,5 +338,5 @@
         pDst->tv_sec = mktime(&ExpTime);
         if (pDst->tv_sec == -1)
-            return touch_error("mktime failed on '%s': %s", pszTs, strerror(errno));
+            return errx(pCtx, 1, "mktime failed on '%s': %s", pszTs, strerror(errno));
     }
     return 0;
@@ -367,5 +347,5 @@
  * Parse -t timestamp: [[CC]YY]MMDDhhmm[.SS]
  */
-static int touch_parse_ts(const char *pszTs, struct timeval *pDst)
+static int touch_parse_ts(PKMKBUILTINCTX pCtx, const char *pszTs, struct timeval *pDst)
 {
     size_t const    cchTs = strlen(pszTs);
@@ -380,5 +360,5 @@
      */
     if ((cchTs & 1) && pszTs[cchTs - 3] != '.')
-        return touch_error("Invalid timestamp given to -t: %s", pszTs);
+        return errx(pCtx, 2, "Invalid timestamp given to -t: %s", pszTs);
     switch (cchTs)
     {
@@ -392,12 +372,12 @@
         case 8 + 3 + 2 + 2: /* CCYYMMDDhhmm.SS */
             if (pszTs[cchTs - 3] != '.')
-                return touch_error("Invalid timestamp (-t) '%s': missing dot for seconds part", pszTs);
+                return errx(pCtx, 2, "Invalid timestamp (-t) '%s': missing dot for seconds part", pszTs);
             if (   !IS_DIGIT(pszTs[cchTs - 2], 5)
                 || !IS_DIGIT(pszTs[cchTs - 1], 9))
-                return touch_error("Invalid timestamp (-t) '%s': malformed seconds part", pszTs);
+                return errx(pCtx, 2, "Invalid timestamp (-t) '%s': malformed seconds part", pszTs);
             cchTsNoSec = cchTs - 3;
             break;
         default:
-            return touch_error("Invalid timestamp (-t) '%s': wrong length (%d)", pszTs, (int)cchTs);
+            return errx(pCtx, 1, "Invalid timestamp (-t) '%s': wrong length (%d)", pszTs, (int)cchTs);
     }
 
@@ -407,24 +387,24 @@
             if (   !IS_DIGIT(pszTs[cchTsNoSec - 12], 9)
                 || !IS_DIGIT(pszTs[cchTsNoSec - 11], 9))
-                return touch_error("Invalid timestamp (-t) '%s': malformed CC part", pszTs);
+                return errx(pCtx, 2, "Invalid timestamp (-t) '%s': malformed CC part", pszTs);
             /* fall thru */
         case 8 + 2:         /*   YYMMDDhhmm */
             if (   !IS_DIGIT(pszTs[cchTsNoSec - 10], 9)
                 || !IS_DIGIT(pszTs[cchTsNoSec -  9], 9))
-                return touch_error("Invalid timestamp (-t) '%s': malformed YY part", pszTs);
+                return errx(pCtx, 2, "Invalid timestamp (-t) '%s': malformed YY part", pszTs);
             /* fall thru */
         case 8:             /*     MMDDhhmm */
             if (   !IS_DIGIT(pszTs[cchTsNoSec - 8], 1)
                 || !IS_DIGIT(pszTs[cchTsNoSec - 7], 9) )
-                return touch_error("Invalid timestamp (-t) '%s': malformed month part", pszTs);
+                return errx(pCtx, 2, "Invalid timestamp (-t) '%s': malformed month part", pszTs);
             if (   !IS_DIGIT(pszTs[cchTsNoSec - 6], 3)
                 || !IS_DIGIT(pszTs[cchTsNoSec - 5], 9) )
-                return touch_error("Invalid timestamp (-t) '%s': malformed day part", pszTs);
+                return errx(pCtx, 2, "Invalid timestamp (-t) '%s': malformed day part", pszTs);
             if (   !IS_DIGIT(pszTs[cchTsNoSec - 4], 2)
                 || !IS_DIGIT(pszTs[cchTsNoSec - 3], 9) )
-                return touch_error("Invalid timestamp (-t) '%s': malformed hour part", pszTs);
+                return errx(pCtx, 2, "Invalid timestamp (-t) '%s': malformed hour part", pszTs);
             if (   !IS_DIGIT(pszTs[cchTsNoSec - 2], 5)
                 || !IS_DIGIT(pszTs[cchTsNoSec - 1], 9) )
-                return touch_error("Invalid timestamp (-t) '%s': malformed minute part", pszTs);
+                return errx(pCtx, 2, "Invalid timestamp (-t) '%s': malformed minute part", pszTs);
             break;
     }
@@ -435,9 +415,9 @@
     rc = gettimeofday(&Now, NULL);
     if (rc != 0)
-        return touch_error("gettimeofday failed: %s", strerror(errno));
+        return errx(pCtx, 1, "gettimeofday failed: %s", strerror(errno));
 
     pExpTime = localtime_r(&Now.tv_sec, &ExpTime);
     if (pExpTime == NULL)
-        return touch_error("localtime_r failed: %s", strerror(errno));
+        return errx(pCtx, 1, "localtime_r failed: %s", strerror(errno));
 
     /*
@@ -475,5 +455,5 @@
     if (pDst->tv_sec != -1)
         return 0;
-    return touch_error("mktime failed on '%s': %s", pszTs, strerror(errno));
+    return errx(pCtx, 1, "mktime failed on '%s': %s", pszTs, strerror(errno));
 }
 
@@ -482,5 +462,5 @@
  * Check for old timestamp: MMDDhhmm[YY]
  */
-static int touch_parse_old_ts(const char *pszOldTs, time_t Now, struct timeval *pDst)
+static int touch_parse_old_ts(PKMKBUILTINCTX pCtx, const char *pszOldTs, time_t Now, struct timeval *pDst)
 {
     /*
@@ -509,5 +489,5 @@
         pExpTime = localtime_r(&Now, &ExpTime);
         if (pExpTime == NULL)
-            return touch_error("localtime_r failed: %s", strerror(errno));
+            return errx(pCtx, 1, "localtime_r failed: %s", strerror(errno));
 
         /*
@@ -535,5 +515,5 @@
         if (pDst->tv_sec != -1)
             return 0;
-        return touch_error("mktime failed on '%s': %s", pszOldTs, strerror(errno));
+        return errx(pCtx, 1, "mktime failed on '%s': %s", pszOldTs, strerror(errno));
     }
 
@@ -544,8 +524,8 @@
 
 /**
- * Parses the arguments into pOpts.
+ * Parses the arguments into pThis.
  *
  * @returns exit code.
- * @param   pOpts               Options structure to return the parsed info in.
+ * @param   pThis               Options structure to return the parsed info in.
  *                              Caller initalizes this with defaults.
  * @param   cArgs               The number of arguments.
@@ -554,5 +534,5 @@
  *                              files.
  */
-static int touch_parse_args(PKMKTOUCHOPTS pOpts, int cArgs, char **papszArgs, KBOOL *pfExit)
+static int touch_parse_args(PKMKTOUCHOPTS pThis, int cArgs, char **papszArgs, KBOOL *pfExit)
 {
     int iAdjustValue = 0;
@@ -583,5 +563,5 @@
                 {
                     while (++iArg < cArgs)
-                        pOpts->papszFiles[pOpts->cFiles++] = papszArgs[iArg];
+                        pThis->papszFiles[pThis->cFiles++] = papszArgs[iArg];
                     break; /* '--' */
                 }
@@ -626,5 +606,5 @@
                     return kbuild_version(papszArgs[0]);
                 else
-                    return touch_syntax("Unknown option: --%s", pszLong);
+                    return errx(pThis->pCtx, 2, "Unknown option: --%s", pszLong);
             }
 
@@ -651,5 +631,5 @@
                             pszValue = papszArgs[++iArg];
                         else
-                            return touch_syntax("Option -%c requires a value", ch);
+                            return errx(pThis->pCtx, 2, "Option -%c requires a value", ch);
                         break;
 
@@ -663,13 +643,13 @@
                     /* -A [-][[HH]MM]SS */
                     case 'A':
-                        rc = touch_parse_adjust(pszValue, &iAdjustValue);
+                        rc = touch_parse_adjust(pThis->pCtx, pszValue, &iAdjustValue);
                         if (rc != 0)
                             return rc;
-                        if (pOpts->enmAction != kTouchActionSet)
+                        if (pThis->enmAction != kTouchActionSet)
                         {
-                            pOpts->enmAction = kTouchActionAdjust;
-                            pOpts->NewATime.tv_sec  = iAdjustValue;
-                            pOpts->NewATime.tv_usec = 0;
-                            pOpts->NewMTime = pOpts->NewATime;
+                            pThis->enmAction = kTouchActionAdjust;
+                            pThis->NewATime.tv_sec  = iAdjustValue;
+                            pThis->NewATime.tv_usec = 0;
+                            pThis->NewMTime = pThis->NewATime;
                         }
                         /* else: applied after parsing everything. */
@@ -677,17 +657,17 @@
 
                     case 'a':
-                        pOpts->enmWhatToTouch = kTouchAccessOnly;
+                        pThis->enmWhatToTouch = kTouchAccessOnly;
                         break;
 
                     case 'c':
-                        pOpts->fCreate = K_FALSE;
+                        pThis->fCreate = K_FALSE;
                         break;
 
                     case 'd':
-                        rc = touch_parse_d_ts(pszValue, &pOpts->NewATime);
+                        rc = touch_parse_d_ts(pThis->pCtx, pszValue, &pThis->NewATime);
                         if (rc != 0)
                             return rc;
-                        pOpts->enmAction = kTouchActionSet;
-                        pOpts->NewMTime  = pOpts->NewATime;
+                        pThis->enmAction = kTouchActionSet;
+                        pThis->NewMTime  = pThis->NewATime;
                         break;
 
@@ -697,9 +677,9 @@
 
                     case 'h':
-                        pOpts->fDereference = K_FALSE;
+                        pThis->fDereference = K_FALSE;
                         break;
 
                     case 'm':
-                        pOpts->enmWhatToTouch = kTouchModifyOnly;
+                        pThis->enmWhatToTouch = kTouchModifyOnly;
                         break;
 
@@ -708,15 +688,15 @@
                         struct stat St;
                         if (stat(pszValue, &St) != 0)
-                            return touch_error("Failed to stat '%s' (-r option): %s", pszValue, strerror(errno));
-
-                        pOpts->enmAction = kTouchActionSet;
-                        pOpts->NewATime.tv_sec  = St.st_atime;
-                        pOpts->NewMTime.tv_sec  = St.st_mtime;
+                            return errx(pThis->pCtx, 1, "Failed to stat '%s' (-r option): %s", pszValue, strerror(errno));
+
+                        pThis->enmAction = kTouchActionSet;
+                        pThis->NewATime.tv_sec  = St.st_atime;
+                        pThis->NewMTime.tv_sec  = St.st_mtime;
 #if FILE_TIMESTAMP_HI_RES
-                        pOpts->NewATime.tv_usec = St.st_atim.tv_nsec / 1000;
-                        pOpts->NewMTime.tv_usec = St.st_mtim.tv_nsec / 1000;
+                        pThis->NewATime.tv_usec = St.st_atim.tv_nsec / 1000;
+                        pThis->NewMTime.tv_usec = St.st_mtim.tv_nsec / 1000;
 #else
-                        pOpts->NewATime.tv_usec = 0;
-                        pOpts->NewMTime.tv_usec = 0;
+                        pThis->NewATime.tv_usec = 0;
+                        pThis->NewMTime.tv_usec = 0;
 #endif
                         break;
@@ -724,9 +704,9 @@
 
                     case 't':
-                        rc = touch_parse_ts(pszValue, &pOpts->NewATime);
+                        rc = touch_parse_ts(pThis->pCtx, pszValue, &pThis->NewATime);
                         if (rc != 0)
                             return rc;
-                        pOpts->enmAction = kTouchActionSet;
-                        pOpts->NewMTime  = pOpts->NewATime;
+                        pThis->enmAction = kTouchActionSet;
+                        pThis->NewMTime  = pThis->NewATime;
                         break;
 
@@ -734,10 +714,10 @@
                         if (   strcmp(pszValue, "atime") == 0
                             || strcmp(pszValue, "access") == 0)
-                            pOpts->enmWhatToTouch = kTouchAccessOnly;
+                            pThis->enmWhatToTouch = kTouchAccessOnly;
                         else if (   strcmp(pszValue, "mtime") == 0
                                  || strcmp(pszValue, "modify") == 0)
-                            pOpts->enmWhatToTouch = kTouchModifyOnly;
+                            pThis->enmWhatToTouch = kTouchModifyOnly;
                         else
-                            return touch_syntax("Unknown --time value: %s", pszValue);
+                            return errx(pThis->pCtx, 2, "Unknown --time value: %s", pszValue);
                         break;
 
@@ -746,5 +726,5 @@
 
                     default:
-                        return touch_syntax("Unknown option: -%c (%c%s)", ch, ch, pszArg);
+                        return errx(pThis->pCtx, 2, "Unknown option: -%c (%c%s)", ch, ch, pszArg);
                 }
 
@@ -752,5 +732,5 @@
         }
         else
-            pOpts->papszFiles[pOpts->cFiles++] = papszArgs[iArg];
+            pThis->papszFiles[pThis->cFiles++] = papszArgs[iArg];
     }
 
@@ -758,13 +738,13 @@
      * Allow adjusting specified timestamps too like BSD does.
      */
-    if (   pOpts->enmAction == kTouchActionSet
+    if (   pThis->enmAction == kTouchActionSet
         && iAdjustValue != 0)
     {
-        if (   pOpts->enmWhatToTouch == kTouchAccessAndModify
-            || pOpts->enmWhatToTouch == kTouchAccessOnly)
-            pOpts->NewATime.tv_sec += iAdjustValue;
-        if (   pOpts->enmWhatToTouch == kTouchAccessAndModify
-            || pOpts->enmWhatToTouch == kTouchModifyOnly)
-            pOpts->NewMTime.tv_sec += iAdjustValue;
+        if (   pThis->enmWhatToTouch == kTouchAccessAndModify
+            || pThis->enmWhatToTouch == kTouchAccessOnly)
+            pThis->NewATime.tv_sec += iAdjustValue;
+        if (   pThis->enmWhatToTouch == kTouchAccessAndModify
+            || pThis->enmWhatToTouch == kTouchModifyOnly)
+            pThis->NewMTime.tv_sec += iAdjustValue;
     }
 
@@ -772,20 +752,20 @@
      * Check for old timestamp: MMDDhhmm[YY]
      */
-    if (   pOpts->enmAction == kTouchActionCurrent
-        && pOpts->cFiles >= 2)
+    if (   pThis->enmAction == kTouchActionCurrent
+        && pThis->cFiles >= 2)
     {
         struct timeval OldTs;
-        rc = touch_parse_old_ts(pOpts->papszFiles[0], pOpts->NewATime.tv_sec, &OldTs);
+        rc = touch_parse_old_ts(pThis->pCtx, pThis->papszFiles[0], pThis->NewATime.tv_sec, &OldTs);
         if (rc == 0)
         {
             int iFile;
 
-            pOpts->NewATime = OldTs;
-            pOpts->NewMTime = OldTs;
-            pOpts->enmAction = kTouchActionSet;
-
-            for (iFile = 1; iFile < pOpts->cFiles; iFile++)
-                pOpts->papszFiles[iFile - 1] = pOpts->papszFiles[iFile];
-            pOpts->cFiles--;
+            pThis->NewATime = OldTs;
+            pThis->NewMTime = OldTs;
+            pThis->enmAction = kTouchActionSet;
+
+            for (iFile = 1; iFile < pThis->cFiles; iFile++)
+                pThis->papszFiles[iFile - 1] = pThis->papszFiles[iFile];
+            pThis->cFiles--;
         }
         else if (rc > 0)
@@ -796,10 +776,10 @@
      * Check that we've found at least one file argument.
      */
-    if (pOpts->cFiles > 0)
+    if (pThis->cFiles > 0)
     {
         *pfExit = K_FALSE;
         return 0;
     }
-    return touch_syntax("No file specified");
+    return errx(pThis->pCtx, 2, "No file specified");
 }
 
@@ -809,8 +789,8 @@
  *
  * @returns exit code.
- * @param   pOpts               The options.
+ * @param   pThis               The options.
  * @param   pszFile             The file to touch.
  */
-static int touch_process_file(PKMKTOUCHOPTS pOpts, const char *pszFile)
+static int touch_process_file(PKMKTOUCHOPTS pThis, const char *pszFile)
 {
     int             fd;
@@ -823,5 +803,5 @@
      * in effect, we silently skip the file if it doesn't already exist.
      */
-    if (pOpts->fDereference)
+    if (pThis->fDereference)
         rc = stat(pszFile, &St);
     else
@@ -830,25 +810,25 @@
     {
         if (errno != ENOENT)
-            return touch_error("Failed to stat '%s': %s", pszFile, strerror(errno));
-
-        if (!pOpts->fCreate)
+            return errx(pThis->pCtx, 1, "Failed to stat '%s': %s", pszFile, strerror(errno));
+
+        if (!pThis->fCreate)
             return 0;
-        fd = open(pszFile, O_WRONLY | O_CREAT, 0666);
+        fd = open(pszFile, O_WRONLY | O_CREAT | KMK_OPEN_NO_INHERIT, 0666);
         if (fd == -1)
-            return touch_error("Failed to create '%s': %s", pszFile, strerror(errno));
+            return errx(pThis->pCtx, 1, "Failed to create '%s': %s", pszFile, strerror(errno));
 
         /* If we're not setting the current time, we may need value stat info
            on the file, so get it thru the file descriptor before closing it. */
-        if (pOpts->enmAction == kTouchActionCurrent)
+        if (pThis->enmAction == kTouchActionCurrent)
             rc = 0;
         else
             rc = fstat(fd, &St);
         if (close(fd) != 0)
-            return touch_error("Failed to close '%s' after creation: %s", pszFile, strerror(errno));
+            return errx(pThis->pCtx, 1, "Failed to close '%s' after creation: %s", pszFile, strerror(errno));
         if (rc != 0)
-            return touch_error("Failed to fstat '%s' after creation: %s", pszFile, strerror(errno));
+            return errx(pThis->pCtx, 1, "Failed to fstat '%s' after creation: %s", pszFile, strerror(errno));
 
         /* We're done now if we're setting the current time. */
-        if (pOpts->enmAction == kTouchActionCurrent)
+        if (pThis->enmAction == kTouchActionCurrent)
             return 0;
     }
@@ -866,21 +846,21 @@
     aTimes[1].tv_usec = 0;
 #endif
-    if (   pOpts->enmWhatToTouch == kTouchAccessAndModify
-        || pOpts->enmWhatToTouch == kTouchAccessOnly)
-    {
-        if (   pOpts->enmAction == kTouchActionCurrent
-            || pOpts->enmAction == kTouchActionSet)
-            aTimes[0] = pOpts->NewATime;
+    if (   pThis->enmWhatToTouch == kTouchAccessAndModify
+        || pThis->enmWhatToTouch == kTouchAccessOnly)
+    {
+        if (   pThis->enmAction == kTouchActionCurrent
+            || pThis->enmAction == kTouchActionSet)
+            aTimes[0] = pThis->NewATime;
         else
-            aTimes[0].tv_sec += pOpts->NewATime.tv_sec;
-    }
-    if (   pOpts->enmWhatToTouch == kTouchAccessAndModify
-        || pOpts->enmWhatToTouch == kTouchModifyOnly)
-    {
-        if (   pOpts->enmAction == kTouchActionCurrent
-            || pOpts->enmAction == kTouchActionSet)
-            aTimes[1] = pOpts->NewMTime;
+            aTimes[0].tv_sec += pThis->NewATime.tv_sec;
+    }
+    if (   pThis->enmWhatToTouch == kTouchAccessAndModify
+        || pThis->enmWhatToTouch == kTouchModifyOnly)
+    {
+        if (   pThis->enmAction == kTouchActionCurrent
+            || pThis->enmAction == kTouchActionSet)
+            aTimes[1] = pThis->NewMTime;
         else
-            aTimes[1].tv_sec += pOpts->NewMTime.tv_sec;
+            aTimes[1].tv_sec += pThis->NewMTime.tv_sec;
     }
 
@@ -891,5 +871,5 @@
      * may do more than what we want (st_ctime).)
      */
-    if (pOpts->fDereference)
+    if (pThis->fDereference)
         rc = utimes(pszFile, aTimes);
     else
@@ -897,7 +877,7 @@
     if (rc != 0)
     {
-        if (pOpts->enmAction == kTouchActionCurrent)
+        if (pThis->enmAction == kTouchActionCurrent)
         {
-            if (pOpts->fDereference)
+            if (pThis->fDereference)
                 rc = utimes(pszFile, NULL);
             else
@@ -905,5 +885,5 @@
         }
         if (rc != 0)
-            rc = touch_error("%stimes failed on '%s': %s", pOpts->fDereference ? "" : "l", pszFile, strerror(errno));
+            rc = errx(pThis->pCtx, 1, "%stimes failed on '%s': %s", pThis->fDereference ? "" : "l", pszFile, strerror(errno));
     }
 
@@ -913,14 +893,10 @@
 
 /**
- * The function that does almost everything here... ugly.
+ * Actual main function for the touch command.
  */
-#ifdef KMK
-int kmk_builtin_touch(int argc, char **argv, char **envp)
-#else
-int main(int argc, char **argv, char **envp)
-#endif
+int kmk_builtin_touch(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx)
 {
     int             rc;
-    KMKTOUCHOPTS    Opts;
+    KMKTOUCHOPTS    This;
     K_NOREF(envp);
 
@@ -928,19 +904,20 @@
      * Initialize options with defaults and parse them.
      */
-    Opts.enmWhatToTouch = kTouchAccessAndModify;
-    Opts.enmAction      = kTouchActionCurrent;
-    Opts.fCreate        = K_TRUE;
-    Opts.fDereference   = K_TRUE;
-    Opts.cFiles         = 0;
-    Opts.papszFiles     = (char **)calloc(argc, sizeof(char *));
-    if (Opts.papszFiles)
-    {
-        rc = gettimeofday(&Opts.NewATime, NULL);
+    This.pCtx           = pCtx;
+    This.enmWhatToTouch = kTouchAccessAndModify;
+    This.enmAction      = kTouchActionCurrent;
+    This.fCreate        = K_TRUE;
+    This.fDereference   = K_TRUE;
+    This.cFiles         = 0;
+    This.papszFiles     = (char **)calloc(argc, sizeof(char *));
+    if (This.papszFiles)
+    {
+        rc = gettimeofday(&This.NewATime, NULL);
         if (rc == 0)
         {
             KBOOL fExit;
-            Opts.NewMTime = Opts.NewATime;
-
-            rc = touch_parse_args(&Opts, argc, argv, &fExit);
+            This.NewMTime = This.NewATime;
+
+            rc = touch_parse_args(&This, argc, argv, &fExit);
             if (rc == 0 && !fExit)
             {
@@ -949,7 +926,7 @@
                  */
                 int iFile;
-                for (iFile = 0; iFile < Opts.cFiles; iFile++)
+                for (iFile = 0; iFile < This.cFiles; iFile++)
                 {
-                    int rc2 = touch_process_file(&Opts, Opts.papszFiles[iFile]);
+                    int rc2 = touch_process_file(&This, This.papszFiles[iFile]);
                     if (rc2 != 0 && rc == 0)
                         rc = rc2;
@@ -958,10 +935,18 @@
         }
         else
-            rc = touch_error("gettimeofday failed: %s", strerror(errno));
-        free(Opts.papszFiles);
+            rc = errx(pCtx, 2, "gettimeofday failed: %s", strerror(errno));
+        free(This.papszFiles);
     }
     else
-        rc = touch_error("calloc failed");
+        rc = errx(pCtx, 2, "calloc failed");
     return rc;
 }
 
+#ifdef KMK_BUILTIN_STANDALONE
+int main(int argc, char **argv, char **envp)
+{
+    KMKBUILTINCTX Ctx = { "kmk_touch", NULL };
+    return kmk_builtin_touch(argc, argv, envp, &Ctx);
+}
+#endif
+
Index: trunk/src/kmk/output.c
===================================================================
--- trunk/src/kmk/output.c	(revision 3191)
+++ trunk/src/kmk/output.c	(revision 3192)
@@ -373,21 +373,27 @@
 
 /* write/fwrite like function, binary mode. */
-void
+ssize_t
 output_write_bin (struct output *out, int is_err, const char *src, size_t len)
 {
+  size_t ret = len;
   if (!out || !out->syncout)
     {
       FILE *f = is_err ? stderr : stdout;
 # ifdef KBUILD_OS_WINDOWS
-      /* On windows we need to disable \n -> \r\n convers that is common on
+      /* On windows we need to disable \n -> \r\n converts that is common on
          standard output/error.  Also optimize for console output. */
+      int saved_errno;
       int fd = fileno (f);
       int prev_mode = _setmode (fd, _O_BINARY);
       maybe_con_fwrite (src, len, 1, f);
-      fflush (f);
+      if (fflush (f) == EOF)
+        ret = -1;
+      saved_errno = errno;
       _setmode (fd, prev_mode);
+      errno = saved_errno;
 # else
       fwrite (src, len, 1, f);
-      fflush (f);
+      if (fflush (f) == EOF)
+        ret = -1;
 # endif
     }
@@ -410,21 +416,25 @@
         }
     }
+  return ret;
 }
 
 /* write/fwrite like function, text mode. */
-void
+ssize_t
 output_write_text (struct output *out, int is_err, const char *src, size_t len)
 {
 # if defined (KBUILD_OS_WINDOWS) || defined (KBUILD_OS_OS2) || defined (KBUILD_OS_DOS)
-  if (out && out->syncout)
+  ssize_t ret = len;
+  if (!out || !out->syncout)
     {
       /* ASSUME fwrite does the desired conversion. */
       FILE *f = is_err ? stderr : stdout;
 # ifdef KBUILD_OS_WINDOWS
-      maybe_con_fwrite (src, len, 1, f);
+      if (maybe_con_fwrite (src, len, 1, f) < 0)
+        ret = -1;
 # else
       fwrite (src, len, 1, f);
 # endif
-      fflush (f);
+      if (fflush (f) == EOF)
+        ret = -1;
     }
   else
@@ -443,6 +453,7 @@
         }
     }
+  return len;
 # else
-  output_write_bin (out, is_err, src, len);
+  return output_write_bin (out, is_err, src, len);
 # endif
 }
Index: trunk/src/kmk/output.h
===================================================================
--- trunk/src/kmk/output.h	(revision 3191)
+++ trunk/src/kmk/output.h	(revision 3192)
@@ -14,4 +14,7 @@
 You should have received a copy of the GNU General Public License along with
 this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef INCLUDED_MAKE_OUTPUT_H
+#define INCLUDED_MAKE_OUTPUT_H
 
 #ifdef CONFIG_WITH_OUTPUT_IN_MEMORY
@@ -81,6 +84,6 @@
 void outputs (int is_err, const char *msg);
 #ifdef CONFIG_WITH_OUTPUT_IN_MEMORY
-void output_write_bin (struct output *out, int is_err, const char *src, size_t len);
-void output_write_text (struct output *out, int is_err, const char *src, size_t len);
+ssize_t output_write_bin (struct output *out, int is_err, const char *src, size_t len);
+ssize_t output_write_text (struct output *out, int is_err, const char *src, size_t len);
 #endif
 
@@ -90,2 +93,5 @@
 void output_dump (struct output *out);
 #endif
+
+#endif /* INLCUDED_MAKE_OUTPUT_H */
+
Index: trunk/src/kmk/w32/winchildren.c
===================================================================
--- trunk/src/kmk/w32/winchildren.c	(revision 3191)
+++ trunk/src/kmk/w32/winchildren.c	(revision 3192)
@@ -1958,9 +1958,11 @@
 {
     PCKMKBUILTINENTRY pBuiltIn = pChild->u.BuiltIn.pBuiltIn;
+    KMKBUILTINCTX Ctx = { pBuiltIn->uName.s.sz, pChild->pMkChild ? &pChild->pMkChild->output : NULL };
     if (pBuiltIn->uFnSignature == FN_SIG_MAIN)
-        pChild->iExitCode = pBuiltIn->u.pfnMain(pChild->u.BuiltIn.cArgs, pChild->u.BuiltIn.papszArgs, pChild->u.BuiltIn.papszEnv);
+        pChild->iExitCode = pBuiltIn->u.pfnMain(pChild->u.BuiltIn.cArgs, pChild->u.BuiltIn.papszArgs,
+                                                pChild->u.BuiltIn.papszEnv, &Ctx);
     else if (pBuiltIn->uFnSignature == FN_SIG_MAIN_SPAWNS)
         pChild->iExitCode = pBuiltIn->u.pfnMainSpawns(pChild->u.BuiltIn.cArgs, pChild->u.BuiltIn.papszArgs,
-                                                      pChild->u.BuiltIn.papszEnv, pChild->pMkChild, NULL);
+                                                      pChild->u.BuiltIn.papszEnv, &Ctx, pChild->pMkChild, NULL);
     else
     {
