OSDN Git Service

Please enter the commit message for your changes. Lines starting
[eos/base.git] / util / src / TclTk / blt2.5 / generic / bltBgexec.c
diff --git a/util/src/TclTk/blt2.5/generic/bltBgexec.c b/util/src/TclTk/blt2.5/generic/bltBgexec.c
deleted file mode 100644 (file)
index 6e0ca1f..0000000
+++ /dev/null
@@ -1,2258 +0,0 @@
-/*
- * bltBgexec.c --
- *
- *     This module implements a background "exec" command for the
- *     BLT toolkit.
- *
- * Copyright 1993-1998 Lucent Technologies, Inc.
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that the copyright notice and warranty
- * disclaimer appear in supporting documentation, and that the names
- * of Lucent Technologies any of their entities not be used in
- * advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission.
- *
- * Lucent Technologies disclaims all warranties with regard to this
- * software, including all implied warranties of merchantability and
- * fitness.  In no event shall Lucent Technologies be liable for any
- * special, indirect or consequential damages or any damages
- * whatsoever resulting from loss of use, data or profits, whether in
- * an action of contract, negligence or other tortuous action, arising
- * out of or in connection with the use or performance of this
- * software.
- *
- *     The "bgexec" command was created by George Howlett.
- */
-
-#include "bltInt.h"
-
-#ifndef NO_BGEXEC
-
-#include <fcntl.h>
-#include <signal.h>
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-#include <sys/types.h>
-
-#include "bltWait.h"
-#include "bltSwitch.h"
-
-#if (TCL_MAJOR_VERSION == 7)
-#define FILEHANDLER_USES_TCLFILES 1
-#else
-typedef int Tcl_File;
-#endif
-
-static Tcl_CmdProc BgexecCmd;
-
-#ifdef WIN32
-typedef struct {
-    DWORD pid;
-    HANDLE hProcess;
-} Process;
-#else
-typedef int Process;
-#endif
-
-#if (TCL_VERSION_NUMBER <  _VERSION(8,1,0)) 
-typedef void *Tcl_Encoding;    /* Make up dummy type for encoding.  */
-#endif
-
-#define ENCODING_ASCII         ((Tcl_Encoding)NULL)
-#define ENCODING_BINARY                ((Tcl_Encoding)1)
-
-/*
- *     As of Tcl 7.6, we're using our own version of the old
- *     Tcl_CreatePipeline routine.  I would have tried to use
- *     Tcl_OpenCommandChannel but you can't get at the array of
- *     process ids, unless of course you pry open the undocumented
- *     structure PipeStatus as clientData.  Nor could I figure out
- *     how to set one side of the pipe to be non-blocking.  The whole
- *     channel API seems overly complex for what its supposed to
- *     do. [And maybe that's why it keeps changing every release.]
- */
-extern int Blt_CreatePipeline _ANSI_ARGS_((Tcl_Interp *interp, int argc,
-       char **argv, Process **pidPtrPtr, int *inPipePtr, int *outPipePtr,
-       int *errFilePtr));
-
-#ifdef WIN32
-#define read(fd, buf, size)    Blt_AsyncRead((fd),(buf),(size))
-#define close(fd)              CloseHandle((HANDLE)fd)
-#define Tcl_CreateFileHandler  Blt_CreateFileHandler
-#define Tcl_DeleteFileHandler  Blt_DeleteFileHandler
-#define kill                   KillProcess
-#define waitpid                        WaitProcess
-#endif
-
-#define        EXPECTED_NUM_TIMERS     4
-
-#define READ_AGAIN     (0)
-#define READ_EOF       (-1)
-#define READ_ERROR     (-2)
-
-/* The wait-related definitions are taken from tclUnix.h */
-
-#define TRACE_FLAGS (TCL_TRACE_WRITES | TCL_TRACE_UNSETS | TCL_GLOBAL_ONLY)
-
-#define BLOCK_SIZE     1024    /* Size of allocation blocks for buffer */
-#define DEF_BUFFER_SIZE        (BLOCK_SIZE * 8)
-#define MAX_READS       100    /* Maximum number of successful reads
-                                * before stopping to let Tcl catch up
-                                * on events */
-
-#ifndef NSIG
-#define NSIG           32      /* Number of signals available */
-#endif /*NSIG*/
-
-#ifndef SIGINT
-#define SIGINT         2
-#endif /* SIGINT */
-
-#ifndef SIGQUIT
-#define SIGQUIT                3
-#endif /* SIGQUIT */
-
-#ifndef SIGKILL
-#define SIGKILL                9
-#endif /* SIGKILL */
-
-#ifndef SIGTERM
-#define SIGTERM                14
-#endif /* SIGTERM */
-
-typedef struct {
-    int number;
-    char *name;
-} SignalId;
-
-static SignalId signalIds[] =
-{
-#ifdef SIGABRT
-    {SIGABRT, "SIGABRT"},
-#endif
-#ifdef SIGALRM
-    {SIGALRM, "SIGALRM"},
-#endif
-#ifdef SIGBUS
-    {SIGBUS, "SIGBUS"},
-#endif
-#ifdef SIGCHLD
-    {SIGCHLD, "SIGCHLD"},
-#endif
-#if defined(SIGCLD) && (!defined(SIGCHLD) || (SIGCLD != SIGCHLD))
-    {SIGCLD, "SIGCLD"},
-#endif
-#ifdef SIGCONT
-    {SIGCONT, "SIGCONT"},
-#endif
-#if defined(SIGEMT) && (!defined(SIGXCPU) || (SIGEMT != SIGXCPU))
-    {SIGEMT, "SIGEMT"},
-#endif
-#ifdef SIGFPE
-    {SIGFPE, "SIGFPE"},
-#endif
-#ifdef SIGHUP
-    {SIGHUP, "SIGHUP"},
-#endif
-#ifdef SIGILL
-    {SIGILL, "SIGILL"},
-#endif
-#ifdef SIGINT
-    {SIGINT, "SIGINT"},
-#endif
-#ifdef SIGIO
-    {SIGIO, "SIGIO"},
-#endif
-#if defined(SIGIOT) && (!defined(SIGABRT) || (SIGIOT != SIGABRT))
-    {SIGIOT, "SIGIOT"},
-#endif
-#ifdef SIGKILL
-    {SIGKILL, "SIGKILL"},
-#endif
-#if defined(SIGLOST) && (!defined(SIGIOT) || (SIGLOST != SIGIOT)) && (!defined(SIGURG) || (SIGLOST != SIGURG))
-    {SIGLOST, "SIGLOST"},
-#endif
-#ifdef SIGPIPE
-    {SIGPIPE, "SIGPIPE"},
-#endif
-#if defined(SIGPOLL) && (!defined(SIGIO) || (SIGPOLL != SIGIO))
-    {SIGPOLL, "SIGPOLL"},
-#endif
-#ifdef SIGPROF
-    {SIGPROF, "SIGPROF"},
-#endif
-#if defined(SIGPWR) && (!defined(SIGXFSZ) || (SIGPWR != SIGXFSZ))
-    {SIGPWR, "SIGPWR"},
-#endif
-#ifdef SIGQUIT
-    {SIGQUIT, "SIGQUIT"},
-#endif
-#ifdef SIGSEGV
-    {SIGSEGV, "SIGSEGV"},
-#endif
-#ifdef SIGSTOP
-    {SIGSTOP, "SIGSTOP"},
-#endif
-#ifdef SIGSYS
-    {SIGSYS, "SIGSYS"},
-#endif
-#ifdef SIGTERM
-    {SIGTERM, "SIGTERM"},
-#endif
-#ifdef SIGTRAP
-    {SIGTRAP, "SIGTRAP"},
-#endif
-#ifdef SIGTSTP
-    {SIGTSTP, "SIGTSTP"},
-#endif
-#ifdef SIGTTIN
-    {SIGTTIN, "SIGTTIN"},
-#endif
-#ifdef SIGTTOU
-    {SIGTTOU, "SIGTTOU"},
-#endif
-#if defined(SIGURG) && (!defined(SIGIO) || (SIGURG != SIGIO))
-    {SIGURG, "SIGURG"},
-#endif
-#if defined(SIGUSR1) && (!defined(SIGIO) || (SIGUSR1 != SIGIO))
-    {SIGUSR1, "SIGUSR1"},
-#endif
-#if defined(SIGUSR2) && (!defined(SIGURG) || (SIGUSR2 != SIGURG))
-    {SIGUSR2, "SIGUSR2"},
-#endif
-#ifdef SIGVTALRM
-    {SIGVTALRM, "SIGVTALRM"},
-#endif
-#ifdef SIGWINCH
-    {SIGWINCH, "SIGWINCH"},
-#endif
-#ifdef SIGXCPU
-    {SIGXCPU, "SIGXCPU"},
-#endif
-#ifdef SIGXFSZ
-    {SIGXFSZ, "SIGXFSZ"},
-#endif
-    {-1, "unknown signal"},
-};
-
-/*
- * Sink buffer:
- *   ____________________
- *  |                    |  "size"     current allocated length of buffer.
- *  |                    |
- *  |--------------------|  "fill"      fill point (# characters in buffer).
- *  |  Raw               |
- *  |--------------------|  "mark"      Marks end of cooked characters.
- *  |                    |
- *  |  Cooked            |
- *  |                    |
- *  |                    |
- *  |--------------------|  "lastMark"  Mark end of processed characters.
- *  |                    |
- *  |                    |
- *  |  Processed         |
- *  |                    |
- *  |____________________| 0
- */
-typedef struct {
-    char *name;                        /* Name of the sink */
-
-    char *doneVar;             /* Name of a Tcl variable (malloc'ed)
-                                * set to the collected data of the
-                                * last UNIX subprocess. */
-
-    char *updateVar;           /* Name of a Tcl variable (malloc'ed)
-                                * updated as data is read from the
-                                * pipe. */
-
-    char **updateCmd;          /* Start of a Tcl command executed
-                                * whenever data is read from the
-                                * pipe. */
-
-#if (TCL_MAJOR_VERSION >= 8)
-    Tcl_Obj **objv;            /*  */
-    int objc;                  /*  */
-#endif
-
-    int flags;                 
-
-    Tcl_File file;             /* Used for backward compatability
-                                * with Tcl 7.5 */
-    Tcl_Encoding encoding;
-    int fd;                    /* File descriptor of the pipe. */
-    int status;
-
-    int echo;                  /* Indicates if the pipeline's stderr stream
-                                * should be echoed */
-    unsigned char *byteArr;    /* Stores pipeline output (malloc-ed):
-                                * Initially points to static storage
-                                */
-    size_t size;               /* Size of dynamically allocated buffer. */
-
-    size_t fill;               /* # of bytes read into the buffer. Marks
-                                * the current fill point of the buffer. */
-
-    size_t mark;               /* # of bytes translated (cooked). */
-    size_t lastMark;           /* # of bytes as of the last read.
-                                * This indicates the start of the new
-                                * data in the buffer since the last
-                                * time the "update" variable was
-                                * set. */
-
-    char *command;          /* Command callback. */
-    unsigned char staticSpace[DEF_BUFFER_SIZE];        /* Static space */
-
-} Sink;
-
-#define SINK_BUFFERED          (1<<0)
-#define SINK_KEEP_NL           (1<<1)
-#define SINK_NOTIFY            (1<<2)
-
-typedef struct {
-    char *statVar;             /* Name of a Tcl variable set to the
-                                * exit status of the last
-                                * process. Setting this variable
-                                * triggers the termination of all
-                                * subprocesses (regardless whether
-                                * they have already completed) */
-
-    int signalNum;             /* If non-zero, indicates the signal
-                                * to send subprocesses when cleaning
-                                * up.*/
-    int localVars;    /* Use local vars. */
-    int keepNewline;           /* If non-zero, indicates to set Tcl
-                                * output variables with trailing
-                                * newlines intact */
-
-    int lineBuffered;          /* If non-zero, indicates provide data
-                                * to update variable and update proc on
-                                * a line-by-line basis. */
-
-    int interval;              /* Interval to poll for the exiting
-                                * processes */
-    char *outputEncodingName;  /* Name of decoding scheme to use when
-                                * translating output data. */
-    char *errorEncodingName;   /* Name of decoding scheme to use when
-                                * translating output data. */
-
-    /* Private */
-    Tcl_Interp *interp;                /* Interpreter containing variables */
-
-    int nProcs;                        /* Number of processes in pipeline */
-    Process *procArr;          /* Array of process tokens from pipeline.
-                                * The token for Unix are pid_t, while
-                                * for Win32 they're handles. */
-
-    int traced;                        /* Indicates that the status variable
-                                * is currently being traced. */
-    int detached;              /* Indicates that the pipeline is
-                                * detached from standard I/O, running
-                                * in the background. */
-    int nTimers;               /* Number of timer handlers */
-    Tcl_TimerToken *timerTokens;/* Array of tokens for timer handlers which 
-                                * polls for the exit status of each
-                                * sub-process. If zero, there's no
-                                * timer handler queued. */
-
-    int *exitCodePtr;          /* Pointer to a memory location to
-                                * contain the last process' exit
-                                * code. */
-    int *donePtr;
-
-    Sink sink1, sink2;
-    int maxBytes;           /* Max string length. */
-    int maxExceed;
-    int varFlags;
-    int doRaise;
-    int closeKill;
-    int cKilled;
-} BackgroundInfo;
-
-
-static Blt_SwitchParseProc StringToSignal;
-static Blt_SwitchCustom killSignalSwitch =
-{
-    StringToSignal, (Blt_SwitchFreeProc *)NULL, (ClientData)0,
-};
-
-static Blt_SwitchSpec switchSpecs[] = 
-{
-    {BLT_SWITCH_INT, "-check",
-       Blt_Offset(BackgroundInfo, interval), 0},
-    {BLT_SWITCH_INT, "-closeonkill", 
-         Blt_Offset(BackgroundInfo, closeKill), 0},
-    {BLT_SWITCH_STRING, "-command", 
-         Blt_Offset(BackgroundInfo, sink1.command), 0},
-    {BLT_SWITCH_STRING, "-decodeerror", 
-         Blt_Offset(BackgroundInfo, errorEncodingName), 0},
-    {BLT_SWITCH_STRING, "-decodeoutput", 
-         Blt_Offset(BackgroundInfo, outputEncodingName), 0},
-    {BLT_SWITCH_BOOLEAN, "-echo", 
-         Blt_Offset(BackgroundInfo, sink2.echo), 0},
-    {BLT_SWITCH_STRING, "-error", 
-         Blt_Offset(BackgroundInfo, sink2.doneVar), 0},
-    {BLT_SWITCH_BOOLEAN, "-keepnewline", 
-       Blt_Offset(BackgroundInfo, keepNewline), 0},
-    {BLT_SWITCH_CUSTOM, "-killsignal", 
-       Blt_Offset(BackgroundInfo, signalNum), 0, &killSignalSwitch},
-    {BLT_SWITCH_STRING, "-lasterror", 
-       Blt_Offset(BackgroundInfo, sink2.updateVar), 0},
-    {BLT_SWITCH_STRING, "-lastoutput", 
-       Blt_Offset(BackgroundInfo, sink1.updateVar), 0},
-    {BLT_SWITCH_INT, "-limit",
-       Blt_Offset(BackgroundInfo, maxBytes), 0},
-    {BLT_SWITCH_BOOLEAN, "-linebuffered", 
-       Blt_Offset(BackgroundInfo, lineBuffered), 0},
-    {BLT_SWITCH_BOOLEAN, "-local", 
-       Blt_Offset(BackgroundInfo, localVars), 0},
-    {BLT_SWITCH_LIST, "-onerror", 
-       Blt_Offset(BackgroundInfo, sink2.updateCmd), 0},
-    {BLT_SWITCH_LIST, "-onoutput", 
-       Blt_Offset(BackgroundInfo, sink1.updateCmd), 0},
-    {BLT_SWITCH_STRING, "-output", 
-        Blt_Offset(BackgroundInfo, sink1.doneVar), 0},
-    {BLT_SWITCH_BOOLEAN, "-raise", 
-       Blt_Offset(BackgroundInfo, doRaise), 0},
-   /* {BLT_SWITCH_STRING, "-update", 
-       Blt_Offset(BackgroundInfo, sink1.updateVar), 0},*/
-    {BLT_SWITCH_END, NULL, 0, 0}
-};
-
-static char *VariableProc _ANSI_ARGS_((ClientData clientData,
-       Tcl_Interp *interp, char *part1, char *part2, int flags));
-static void TimerProc _ANSI_ARGS_((ClientData clientData));
-static void StdoutProc _ANSI_ARGS_((ClientData clientData, int mask));
-static void StderrProc _ANSI_ARGS_((ClientData clientData, int mask));
-static void AddTimerHandler _ANSI_ARGS_((BackgroundInfo *bgPtr,int interval));
-static void InterpDeleted _ANSI_ARGS_(( ClientData clientData, Tcl_Interp *interp));
-
-/*
- *----------------------------------------------------------------------
- *
- * GetSignal --
- *
- *     Convert a string represent a signal number into its integer
- *     value.
- *
- * Results:
- *     The return value is a standard Tcl result.
- *
- *----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-static int
-StringToSignal(clientData, interp, switchName, string, record, offset)
-    ClientData clientData;     /* Contains a pointer to the tabset containing
-                                * this image. */
-    Tcl_Interp *interp;                /* Interpreter to send results back to */
-    char *switchName;          /* Not used. */
-    char *string;              /* String representation */
-    char *record;              /* Structure record */
-    int offset;                        /* Offset to field in structure */
-{
-    int *signalPtr = (int *)(record + offset);
-    int signalNum;
-
-    if ((string == NULL) || (*string == '\0')) {
-       *signalPtr = 0;
-       return TCL_OK;
-    }
-    if (isdigit(UCHAR(string[0]))) {
-       if (Tcl_GetInt(interp, string, &signalNum) != TCL_OK) {
-           return TCL_ERROR;
-       }
-    } else {
-       char *name;
-       register SignalId *sigPtr;
-
-       name = string;
-
-       /*  Clip off any "SIG" prefix from the signal name */
-       if ((name[0] == 'S') && (name[1] == 'I') && (name[2] == 'G')) {
-           name += 3;
-       }
-       signalNum = -1;
-       for (sigPtr = signalIds; sigPtr->number > 0; sigPtr++) {
-           if (strcmp(sigPtr->name + 3, name) == 0) {
-               signalNum = sigPtr->number;
-               break;
-           }
-       }
-       if (signalNum < 0) {
-           Tcl_AppendResult(interp, "unknown signal \"", string, "\"",
-               (char *)NULL);
-           return TCL_ERROR;
-       }
-    }
-    if ((signalNum < 0) || (signalNum > NSIG)) {
-       /* Outside range of signals */
-       Tcl_AppendResult(interp, "signal number \"", string,
-           "\" is out of range", (char *)NULL);
-       return TCL_ERROR;
-    }
-    *signalPtr = signalNum;
-    return TCL_OK;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * GetSinkData --
- *
- *     Returns the data currently saved in the buffer
- *
- *----------------------------------------------------------------------
- */
-static void
-GetSinkData(sinkPtr, dataPtr, lengthPtr)
-    Sink *sinkPtr;
-    unsigned char **dataPtr;
-    size_t *lengthPtr;
-{
-    size_t length;
-
-    sinkPtr->byteArr[sinkPtr->mark] = '\0';
-    length = sinkPtr->mark;
-    if ((sinkPtr->mark > 0) && (sinkPtr->encoding != ENCODING_BINARY)) {
-       unsigned char *last;
-
-       last = sinkPtr->byteArr + (sinkPtr->mark - 1);
-       if ((!(sinkPtr->flags & SINK_KEEP_NL)) && (*last == '\n')) {
-           length--;
-       }
-    }
-    *dataPtr = sinkPtr->byteArr;
-    *lengthPtr = length;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NextBlock --
- *
- *     Returns the next block of data since the last time this
- *     routine was called.
- *
- *---------------------------------------------------------------------- 
- */
-static unsigned char *
-NextBlock(sinkPtr, lengthPtr)
-    Sink *sinkPtr;
-    int *lengthPtr;
-{
-    unsigned char *string;
-    int length;
-
-    string = sinkPtr->byteArr + sinkPtr->lastMark;
-    length = sinkPtr->mark - sinkPtr->lastMark;
-    sinkPtr->lastMark = sinkPtr->mark;
-    if (length > 0) {
-       if ((!(sinkPtr->flags & SINK_KEEP_NL)) && 
-           (string[length - 1] == '\n')) {
-           length--;
-       }
-       *lengthPtr = length;
-       return string;
-    }
-    return NULL;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NextLine --
- *
- *     Returns the next line of data.
- *
- *----------------------------------------------------------------------
- */
-static unsigned char *
-NextLine(sinkPtr, lengthPtr)
-    Sink *sinkPtr;
-    int *lengthPtr;
-{
-    if (sinkPtr->mark > sinkPtr->lastMark) {
-       unsigned char *string;
-       int newBytes;
-       register int i;
-
-       string = sinkPtr->byteArr + sinkPtr->lastMark;
-       newBytes = sinkPtr->mark - sinkPtr->lastMark;
-       for (i = 0; i < newBytes; i++) {
-           if (string[i] == '\n') {
-               int length;
-               
-               length = i + 1;
-               sinkPtr->lastMark += length;
-               if (!(sinkPtr->flags & SINK_KEEP_NL)) {
-                   length--;           /* Backup over the newline. */
-               }
-               *lengthPtr = length;
-               return string;
-           }
-       }
-       /* Newline not found.  On errors or EOF, also return a partial line. */
-       if (sinkPtr->status < 0) {
-           *lengthPtr = newBytes;
-           sinkPtr->lastMark = sinkPtr->mark;
-           return string;
-       }
-    }
-    return NULL;
-}
-/*
- *----------------------------------------------------------------------
- *
- * ResetSink --
- *
- *     Removes the bytes already processed from the buffer, possibly
- *     resetting it to empty.  This used when we don't care about
- *     keeping all the data collected from the channel (no -output
- *     flag and the process is detached).
- *
- *---------------------------------------------------------------------- 
- */
-static void
-ResetSink(sinkPtr)
-    Sink *sinkPtr;
-{ 
-    if ((sinkPtr->flags & SINK_BUFFERED) && 
-       (sinkPtr->fill > sinkPtr->lastMark)) {
-       register size_t i, j;
-
-       /* There may be bytes remaining in the buffer, awaiting
-        * another read before we see the next newline.  So move the
-        * bytes to the front of the array. */
-
-       for (i = 0, j = sinkPtr->lastMark; j < sinkPtr->fill; i++, j++) {
-           sinkPtr->byteArr[i] = sinkPtr->byteArr[j];
-       }
-       /* Move back the fill point and processed point. */
-       sinkPtr->fill -= sinkPtr->lastMark;
-       sinkPtr->mark -= sinkPtr->lastMark;
-    } else {
-       sinkPtr->mark = sinkPtr->fill = 0;
-    }
-    sinkPtr->lastMark = 0;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * InitSink --
- *
- *     Initializes the buffer's storage.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     Storage is cleared.
- *
- *----------------------------------------------------------------------
- */
-static void
-InitSink(bgPtr, sinkPtr, name, encoding)
-    BackgroundInfo *bgPtr;
-    Sink *sinkPtr;
-    char *name;
-    Tcl_Encoding encoding;
-{
-    sinkPtr->name = name;
-    sinkPtr->echo = FALSE;
-    sinkPtr->fd = -1;
-    sinkPtr->file = (Tcl_File)NULL;
-    sinkPtr->byteArr = sinkPtr->staticSpace;
-    sinkPtr->size = DEF_BUFFER_SIZE;
-    sinkPtr->encoding = encoding;
-    if (bgPtr->keepNewline) {
-       sinkPtr->flags |= SINK_KEEP_NL;
-    }
-    if (bgPtr->lineBuffered) {
-       sinkPtr->flags |= SINK_BUFFERED;
-    }  
-    if ((sinkPtr->updateCmd != NULL) || 
-       (sinkPtr->updateVar != NULL) ||
-       (sinkPtr->echo)) {
-       sinkPtr->flags |= SINK_NOTIFY;
-    }
-#if (TCL_MAJOR_VERSION >= 8)
-    if (sinkPtr->updateCmd != NULL) {
-       Tcl_Obj **objArr;
-       char **p;
-       int count;
-       register int i;
-
-       count = 0;
-       for (p = sinkPtr->updateCmd; *p != NULL; p++) {
-           count++;
-       }
-       objArr = Blt_Malloc((count + 1) * sizeof(Tcl_Obj *));
-       for (i = 0; i < count; i++) {
-           objArr[i] = Tcl_NewStringObj(sinkPtr->updateCmd[i], -1);
-           Tcl_IncrRefCount(objArr[i]);
-       }
-       sinkPtr->objv = objArr;
-       sinkPtr->objc = count + 1;
-    }
-#endif
-    ResetSink(sinkPtr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * FreeSinkBuffer --
- *
- *     Frees the buffer's storage, freeing any malloc'ed space.
- *
- * Results:
- *     None.
- *
- *----------------------------------------------------------------------
- */
-static void
-FreeSinkBuffer(sinkPtr)
-    Sink *sinkPtr;
-{
-    if (sinkPtr->byteArr != sinkPtr->staticSpace) {
-       Blt_Free(sinkPtr->byteArr);
-    }
-    sinkPtr->fd = -1;
-    sinkPtr->file = (Tcl_File)NULL;
-#if (TCL_MAJOR_VERSION >= 8)
-    if (sinkPtr->objv != NULL) {
-       register int i;
-
-       for (i = 0; i < sinkPtr->objc - 1; i++) {
-           Tcl_DecrRefCount(sinkPtr->objv[i]);
-       }
-       Blt_Free(sinkPtr->objv);
-    }
-#endif
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * ExtendSinkBuffer --
- *
- *     Doubles the size of the current buffer.
- *
- * Results:
- *     None.
- *
- *----------------------------------------------------------------------
- */
-static int
-ExtendSinkBuffer(sinkPtr)
-    Sink *sinkPtr;
-{
-    unsigned char *arrayPtr;
-    register unsigned char *srcPtr, *destPtr, *endPtr;
-    /*
-     * Allocate a new array, double the old size
-     */
-    sinkPtr->size += sinkPtr->size;
-    arrayPtr = Blt_Malloc(sizeof(unsigned char) * sinkPtr->size);
-    if (arrayPtr == NULL) {
-       return -1;
-    }
-    srcPtr = sinkPtr->byteArr;
-    endPtr = sinkPtr->byteArr + sinkPtr->fill;
-    destPtr = arrayPtr;
-    while (srcPtr < endPtr) {
-       *destPtr++ = *srcPtr++;
-    }
-    if (sinkPtr->byteArr != sinkPtr->staticSpace) {
-       Blt_Free(sinkPtr->byteArr);
-    }
-    sinkPtr->byteArr = arrayPtr;
-
-    return (sinkPtr->size - sinkPtr->fill); /* Return bytes left. */
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ReadBytes --
- *
- *     Reads and appends any available data from a given file descriptor
- *     to the buffer.
- *
- * Results:
- *     Returns TCL_OK when EOF is found, TCL_RETURN if reading
- *     data would block, and TCL_ERROR if an error occurred.
- *
- *----------------------------------------------------------------------
- */
-static void
-ReadBytes(bgPtr, sinkPtr)
-    BackgroundInfo *bgPtr;
-    Sink *sinkPtr;
-{
-    int nBytes, bytesLeft;
-    register int i;
-    unsigned char *array;
-
-    /*
-     * ------------------------------------------------------------------
-     *
-     *         Worry about indefinite postponement.
-     *
-     *         Typically we want to stay in the read loop as long as it takes
-     *         to collect all the data that's currently available.  But if
-     *         it's coming in at a constant high rate, we need to arbitrarily
-     *         break out at some point. This allows for both setting the
-     *         update variable and the Tk program to handle idle events.
-     *
-     * ------------------------------------------------------------------
-     */
-
-    for (i = 0; i < MAX_READS; i++) {
-
-       /* Allocate a larger buffer when the number of remaining bytes
-        * is below the threshold BLOCK_SIZE.  */
-
-       bytesLeft = sinkPtr->size - sinkPtr->fill;
-
-       if (bytesLeft < BLOCK_SIZE) {
-           bytesLeft = ExtendSinkBuffer(sinkPtr);
-           if (bytesLeft < 0) {
-               sinkPtr->status = READ_ERROR;
-               return;
-           }
-       }
-       array = sinkPtr->byteArr + sinkPtr->fill;
-
-       /*
-        * Read into a buffer but make sure we leave room for a
-        * trailing NUL byte.
-        */
-       nBytes = read(sinkPtr->fd, array, bytesLeft - 1);
-       if (nBytes == 0) {      /* EOF: break out of loop. */
-           sinkPtr->status = READ_EOF;
-           return;
-       }
-       if (nBytes < 0) {
-#ifdef O_NONBLOCK
-#define BLOCKED                EAGAIN
-#else
-#define BLOCKED                EWOULDBLOCK
-#endif /*O_NONBLOCK*/
-           /* Either an error has occurred or no more data is
-            * currently available to read.  */
-           if (errno == BLOCKED) {
-               sinkPtr->status = READ_AGAIN;
-               return;
-           }
-           sinkPtr->byteArr[0] = '\0';
-           sinkPtr->status = READ_ERROR;
-           return;
-       }
-       sinkPtr->fill += nBytes;
-       sinkPtr->byteArr[sinkPtr->fill] = '\0';
-    }
-    sinkPtr->status = nBytes;
-}
-
-#define IsOpenSink(sinkPtr)  ((sinkPtr)->fd != -1)
-
-static void
-CloseSink(bgPtr, interp, sinkPtr) 
-    BackgroundInfo *bgPtr;
-    Tcl_Interp *interp;
-    Sink *sinkPtr;
-{
-    unsigned char *data = NULL;
-    size_t length;
-    
-    if (IsOpenSink(sinkPtr)) {
-       close(sinkPtr->fd);
-#ifdef FILEHANDLER_USES_TCLFILES
-       Tcl_DeleteFileHandler(sinkPtr->file);
-       Tcl_FreeFile(sinkPtr->file);
-#else
-       Tcl_DeleteFileHandler(sinkPtr->fd);
-#endif
-       sinkPtr->file = (Tcl_File)NULL;
-       sinkPtr->fd = -1;
-
-#if WINDEBUG
-       PurifyPrintf("CloseSink: set done var %s\n", sinkPtr->name);
-#endif
-       if (sinkPtr->doneVar != NULL && !Tcl_InterpDeleted(interp)) {
-           /* 
-            * If data is to be collected, set the "done" variable
-            * with the contents of the buffer.  
-            */
-           GetSinkData(sinkPtr, &data, &length);
-#if (TCL_VERSION_NUMBER <  _VERSION(8,1,0)) 
-           data[length] = '\0';
-           if (Tcl_SetVar(interp, sinkPtr->doneVar, data, 
-                          bgPtr->varFlags) == NULL) {
-               Tcl_BackgroundError(interp);
-           }
-#else
-           if (Tcl_SetVar2Ex(interp, sinkPtr->doneVar, NULL, 
-                             Tcl_NewByteArrayObj(data, length),
-                             (bgPtr->varFlags | TCL_LEAVE_ERR_MSG)) == NULL) {
-               Tcl_BackgroundError(interp);
-           }
-#endif
-       }
-#if WINDEBUG
-       PurifyPrintf("CloseSink %s: done\n", sinkPtr->name);
-#endif
-    }
-}
-
-static void
-SinkCallback(interp, sinkPtr, status) 
-    Tcl_Interp *interp;
-    Sink *sinkPtr;
-    char *status;
-{
-    unsigned char *data = NULL;
-    size_t length;
-    if (sinkPtr->command != NULL && !Tcl_InterpDeleted(interp)) {
-        Tcl_DString dStr;
-        Tcl_DStringInit(&dStr);
-        GetSinkData(sinkPtr, &data, &length);
-        Tcl_DStringAppend(&dStr, sinkPtr->command, -1);
-        Tcl_DStringAppendElement(&dStr, data);
-        Tcl_DStringAppendElement(&dStr, status);
-        if (Tcl_GlobalEval(interp, Tcl_DStringValue(&dStr)) != TCL_OK) {
-            Tcl_BackgroundError(interp);
-        }
-        Tcl_DStringFree(&dStr);
-    }
-}
-/*
- *----------------------------------------------------------------------
- *
- * CookSink --
- *
- *     For Windows, translate CR/NL combinations to NL alone.
- *
- * Results:
- *     None.
- *
- * Side Effects:
- *     The size of the byte array may shrink and array contents
- *     shifted as carriage returns are found and removed.
- *
- *----------------------------------------------------------------------
- */
-static void
-CookSink(interp, sinkPtr)
-    Tcl_Interp *interp;
-    Sink *sinkPtr;
-{
-    unsigned char *srcPtr, *endPtr;
-#ifdef WIN32
-    size_t oldMark;
-
-    oldMark = sinkPtr->mark;
-#endif
-    if (sinkPtr->encoding == ENCODING_BINARY) { /* binary */
-       /* No translation needed. */
-       sinkPtr->mark = sinkPtr->fill; 
-    } else if (sinkPtr->encoding == ENCODING_ASCII) { /* ascii */
-#if (TCL_VERSION_NUMBER <  _VERSION(8,1,0)) 
-       /* Convert NUL bytes to question marks. */
-       srcPtr = sinkPtr->byteArr + sinkPtr->mark;
-       endPtr = sinkPtr->byteArr + sinkPtr->fill;
-       while (srcPtr < endPtr) {
-           if (*srcPtr == '\0') {
-               *srcPtr = '?';
-           }
-           srcPtr++;
-       }
-#endif /* < 8.1.0 */
-       /* One-to-one translation. mark == fill. */
-       sinkPtr->mark = sinkPtr->fill;
-#if (TCL_VERSION_NUMBER >= _VERSION(8,1,0)) 
-    } else { /* unicode. */
-       int nSrcCooked, nCooked;
-       int result;
-       size_t cookedSize, spaceLeft, needed;
-       size_t nRaw, nLeftOver;
-       unsigned char *destPtr;
-       unsigned char *raw, *cooked;
-       unsigned char leftover[100];
-       
-       raw = sinkPtr->byteArr + sinkPtr->mark;
-       nRaw = sinkPtr->fill - sinkPtr->mark;
-       /* Ideally, the cooked buffer size should be smaller */
-       cookedSize = nRaw * TCL_UTF_MAX + 1;
-       cooked = Blt_Malloc(cookedSize);
-       result = Tcl_ExternalToUtf(interp, sinkPtr->encoding, 
-                       (char *)raw, nRaw, 0, NULL, (char *)cooked, 
-                       cookedSize, &nSrcCooked, &nCooked, NULL);
-       nLeftOver = 0;
-       if (result == TCL_CONVERT_MULTIBYTE) {
-           /* 
-            * Last multibyte sequence wasn't completed.  Save the
-            * extra characters in a temporary buffer.  
-            */
-           nLeftOver = (nRaw - nSrcCooked);
-           srcPtr = sinkPtr->byteArr + (sinkPtr->mark + nSrcCooked); 
-           endPtr = srcPtr + nLeftOver;
-           destPtr = leftover;
-           while (srcPtr < endPtr) {
-               *destPtr++ = *srcPtr++;
-           }
-       } 
-       /*
-        * Create a bigger 
-        */
-                                                
-       needed = nLeftOver + nCooked;
-       spaceLeft = sinkPtr->size - sinkPtr->mark;
-       if (spaceLeft >= needed) {
-           spaceLeft = ExtendSinkBuffer(sinkPtr);
-       }
-       assert(spaceLeft > needed);
-       /* 
-        * Replace the characters from the mark with the translated 
-        * characters.
-        */
-       srcPtr = cooked;
-       endPtr = cooked + nCooked;
-       destPtr = sinkPtr->byteArr + sinkPtr->mark;
-       while (srcPtr < endPtr) {
-           *destPtr++ = *srcPtr++;
-       }
-       /* Add the number of newly translated characters to the mark */
-       sinkPtr->mark += nCooked;
-       
-       srcPtr = leftover;
-       endPtr = leftover + nLeftOver;
-       while (srcPtr < endPtr) {
-           *destPtr++ = *srcPtr++;
-       }
-       sinkPtr->fill = sinkPtr->mark + nLeftOver;
-#endif /* >= 8.1.0  */
-    }
-#ifdef WIN32
-    /* 
-     * Translate CRLF character sequences to LF characters.  We have to
-     * do this after converting the string to UTF from UNICODE.
-     */
-    if (sinkPtr->encoding != ENCODING_BINARY) {
-       int count;
-       unsigned char *destPtr;
-
-       destPtr = srcPtr = sinkPtr->byteArr + oldMark;
-       endPtr = sinkPtr->byteArr + sinkPtr->fill;
-       *endPtr = '\0';
-       count = 0;
-       for (endPtr--; srcPtr < endPtr; srcPtr++) {
-           if ((*srcPtr == '\r') && (*(srcPtr + 1) == '\n')) {
-               count++;
-               continue;               /* Skip the CR in CR/LF sequences. */
-           }
-           if (srcPtr != destPtr) {
-               *destPtr = *srcPtr;     /* Collapse the string, overwriting
-                                        * the \r's encountered. */
-           }
-           destPtr++;
-       }
-       sinkPtr->mark -= count;
-       sinkPtr->fill -= count;
-       *destPtr = *srcPtr;     /* Copy the last byte */
-       if (*destPtr == '\r') {
-           sinkPtr->mark--;
-       }
-    }
-#endif /* WIN32 */
-}
-
-#ifdef WIN32
-/*
- *----------------------------------------------------------------------
- *
- * WaitProcess --
- *
- *     Emulates the waitpid system call under the Win32 API.
- *
- * Results:
- *     Returns 0 if the process is still alive, -1 on an error, or
- *     the pid on a clean close.
- *
- * Side effects:
- *     Unless WNOHANG is set and the wait times out, the process
- *     information record will be deleted and the process handle
- *     will be closed.
- *
- *----------------------------------------------------------------------
- */
-#define WINDEBUG 0
-static int
-WaitProcess(
-    Process child,
-    int *statusPtr,
-    int flags)
-{
-    int result;
-    DWORD status, exitCode;
-    int timeout;
-
-#if WINDEBUG
-    PurifyPrintf("WAITPID(%x)\n", child.hProcess);
-#endif
-    *statusPtr = 0;
-    if (child.hProcess == INVALID_HANDLE_VALUE) {
-       errno = EINVAL;
-       return -1;
-    }
-#if WINDEBUG
-    PurifyPrintf("WAITPID: waiting for 0x%x\n", child.hProcess);
-#endif
-    timeout = (flags & WNOHANG) ? 0 : INFINITE;
-    status = WaitForSingleObject(child.hProcess, timeout);
-                                
-#if WINDEBUG
-    PurifyPrintf("WAITPID: wait status is %d\n", status);
-#endif
-    switch (status) {
-    case WAIT_FAILED:
-       errno = ECHILD;
-       *statusPtr = ECHILD;
-       result = -1;
-       break;
-
-    case WAIT_TIMEOUT:
-       if (timeout == 0) {
-           return 0;           /* Try again */
-       }
-       result = 0;
-       break;
-
-    default:
-    case WAIT_ABANDONED:
-    case WAIT_OBJECT_0:
-       GetExitCodeProcess(child.hProcess, &exitCode);
-       *statusPtr = ((exitCode << 8) & 0xff00);
-#if WINDEBUG
-       PurifyPrintf("WAITPID: exit code of %d is %d (%x)\n", child.hProcess,
-           *statusPtr, exitCode);
-#endif
-       result = child.pid;
-       assert(result != -1);
-       break;
-    }
-    CloseHandle(child.hProcess);
-    return result;
-}
-
-static BOOL CALLBACK
-EnumWindowsProc(HWND hWnd, LPARAM lParam)
-{
-    DWORD pid = 0;
-    Process *procPtr = (Process *)lParam;
-
-    GetWindowThreadProcessId(hWnd, &pid);
-    if (pid == procPtr->pid) {
-       PostMessage(hWnd, WM_CLOSE, 0, 0);
-    }
-    return TRUE;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * KillProcess --
- *
- *     Emulates the UNIX kill system call under Win32 API.
- *
- * Results:
- *     Returns 0 if the process is killed, -1 on an error.
- *
- * Side effects:
- *     Process is terminated.
- *
- *----------------------------------------------------------------------
- */
-static int
-KillProcess(Process proc, int signal)
-{
-    DWORD status;
-
-    if ((proc.hProcess == NULL) || (proc.hProcess == INVALID_HANDLE_VALUE)) {
-       errno = EINVAL;
-       return -1;
-    }
-
-    EnumWindows(EnumWindowsProc, (LPARAM)&proc);
-
-    /* 
-     * Wait on the handle. If it signals, great. If it times out,
-     * then call TerminateProcess on it.  
-     *
-     * On Windows 95/98 this also has the added benefit of stopping
-     * KERNEL32.dll from dumping.  The 2 second number is arbitrary.
-     * (1 second seems to fail intermittently).
-     */
-    status = WaitForSingleObject(proc.hProcess, 2000);
-    if (status == WAIT_OBJECT_0) {
-       return 0;
-    }
-    if (!TerminateProcess(proc.hProcess, 1)) {
-#if WINDEBUG
-       PurifyPrintf("can't terminate process (handle=%d): %s\n",
-                    proc.hProcess, Blt_LastError());
-#endif /* WINDEBUG */
-       return -1;
-    }
-    return 0;
-}
-
-#endif /* WIN32 */
-
-#if (TCL_VERSION_NUMBER < _VERSION(8,1,0)) 
-
-static void
-NotifyOnUpdate(bgPtr, interp, sinkPtr, data, nBytes)
-    BackgroundInfo *bgPtr;
-    Tcl_Interp *interp;
-    Sink *sinkPtr;
-    unsigned char *data;
-    int nBytes;
-{
-    char save;
-
-#if WINDEBUG_0
-    PurifyPrintf("read %s\n", data);
-#endif
-    if (data[0] == '\0') {
-       return;
-    }
-    save = data[nBytes];
-    data[nBytes] = '\0';
-    if (sinkPtr->echo) {
-       Tcl_Channel channel;
-       
-       channel = Tcl_GetStdChannel(TCL_STDERR);
-       if (channel == NULL) {
-           Tcl_AppendResult(interp, "can't get stderr channel", (char *)NULL);
-           Tcl_BackgroundError(interp);
-           sinkPtr->echo = FALSE;
-       } else {
-           Tcl_Write(channel, data, nBytes);
-           if (save == '\n') {
-               Tcl_Write(channel, "\n", 1);
-           }
-           Tcl_Flush(channel);
-       }
-    }
-    if (sinkPtr->updateCmd != NULL) {
-       Tcl_DString dString;
-       int result;
-       register char **p;
-
-       Tcl_DStringInit(&dString);
-       for (p = sinkPtr->updateCmd; *p != NULL; p++) {
-           Tcl_DStringAppendElement(&dString, *p);
-       }
-       Tcl_DStringAppendElement(&dString, data);
-       result = Tcl_GlobalEval(interp, Tcl_DStringValue(&dString));
-       Tcl_DStringFree(&dString);
-       if (result != TCL_OK) {
-           Tcl_BackgroundError(interp);
-       }
-    }
-    if (sinkPtr->updateVar != NULL) {
-       int flags;
-       char *result;
-
-       flags = (bgPtr->varFlags | TCL_LEAVE_ERR_MSG);
-       result = Tcl_SetVar(interp, sinkPtr->updateVar, data, flags);
-       if (result == NULL) {
-           Tcl_BackgroundError(interp);
-       }
-    }
-    data[nBytes] = save;
-}
-
-#else 
-
-static void
-NotifyOnUpdate(bgPtr, interp, sinkPtr, data, nBytes)
-    BackgroundInfo *bgPtr;
-    Tcl_Interp *interp;
-    Sink *sinkPtr;
-    unsigned char *data;
-    int nBytes;
-{
-    Tcl_Obj *objPtr;
-
-#if WINDEBUG_0
-    PurifyPrintf("read %s\n", data);
-#endif
-    if ((nBytes == 0) || (data[0] == '\0')) {
-       return;
-    }
-    if (sinkPtr->echo) {
-       Tcl_Channel channel;
-       
-       channel = Tcl_GetStdChannel(TCL_STDERR);
-       if (channel == NULL) {
-           Tcl_AppendResult(interp, "can't get stderr channel", (char *)NULL);
-           Tcl_BackgroundError(interp);
-           sinkPtr->echo = FALSE;
-       } else {
-           if (data[nBytes] == '\n') {
-               objPtr = Tcl_NewByteArrayObj(data, nBytes + 1);
-           } else {
-               objPtr = Tcl_NewByteArrayObj(data, nBytes);
-           }
-           Tcl_WriteObj(channel, objPtr);
-           Tcl_Flush(channel);
-       }
-    }
-
-    objPtr = Tcl_NewByteArrayObj(data, nBytes);
-    Tcl_IncrRefCount(objPtr);
-    if (sinkPtr->objv != NULL) {
-       int result;
-
-       sinkPtr->objv[sinkPtr->objc - 1] = objPtr;
-       result = Tcl_EvalObjv(interp, sinkPtr->objc, sinkPtr->objv, TCL_GLOBAL_ONLY);
-       if (result != TCL_OK) {
-           Tcl_BackgroundError(interp);
-       }
-    }
-    if (sinkPtr->updateVar != NULL) {
-       Tcl_Obj *result;
-
-       result = Tcl_SetVar2Ex(interp, sinkPtr->updateVar, NULL, objPtr, 
-              (bgPtr->varFlags | TCL_LEAVE_ERR_MSG));
-       if (result == NULL) {
-           Tcl_BackgroundError(interp);
-       }
-    }
-    Tcl_DecrRefCount(objPtr);
-}
-
-#endif /* < 8.1.0 */
-
-static int
-CollectData(bgPtr, sinkPtr)
-    BackgroundInfo *bgPtr;
-    Sink *sinkPtr;
-{
-    if ((bgPtr->detached) && (sinkPtr->doneVar == NULL) && (sinkPtr->command == NULL)) {
-       ResetSink(sinkPtr);
-    }
-    ReadBytes(bgPtr, sinkPtr);
-    CookSink(bgPtr->interp, sinkPtr);
-    if ((sinkPtr->mark > sinkPtr->lastMark) && 
-       (sinkPtr->flags & SINK_NOTIFY)) {
-       unsigned char *data;
-       int length;
-
-       if (sinkPtr->flags & SINK_BUFFERED) {
-           /* For line-by-line updates, call NotifyOnUpdate for each
-            * new complete line.  */
-           while ((data = NextLine(sinkPtr, &length)) != NULL) {
-               NotifyOnUpdate(bgPtr, bgPtr->interp, sinkPtr, data, length);
-           }
-       } else {
-           data = NextBlock(sinkPtr, &length);
-           NotifyOnUpdate(bgPtr, bgPtr->interp, sinkPtr, data, length);
-       }
-    }
-    if (bgPtr->maxBytes>0) {
-        if (sinkPtr->mark >= bgPtr->maxBytes) {
-            bgPtr->maxExceed = 1;
-            return TCL_BREAK;
-        }
-    }
-    if (sinkPtr->status >= 0) {
-       return TCL_OK;
-    }
-    if (sinkPtr->status == READ_ERROR) {
-       Tcl_AppendResult(bgPtr->interp, "can't read data from ", sinkPtr->name,
-           ": ", Tcl_PosixError(bgPtr->interp), (char *)NULL);
-       Tcl_BackgroundError(bgPtr->interp);
-       return TCL_ERROR;
-    }
-#if WINDEBUG
-    PurifyPrintf("CollectData %s: done\n", sinkPtr->name);
-#endif
-    return TCL_RETURN;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * CreateSinkHandler --
- *
- *     Creates a file handler for the given sink.  The file
- *     descriptor is also set for non-blocking I/O.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     The memory allocated to the BackgroundInfo structure released.
- *
- *----------------------------------------------------------------------
- */
-static int
-CreateSinkHandler(bgPtr, sinkPtr, proc)
-    BackgroundInfo *bgPtr;
-    Sink *sinkPtr;
-    Tcl_FileProc *proc;
-{
-#ifndef WIN32
-    int flags;
-
-    flags = fcntl(sinkPtr->fd, F_GETFL);
-#ifdef O_NONBLOCK
-    flags |= O_NONBLOCK;
-#else
-    flags |= O_NDELAY;
-#endif
-    if (fcntl(sinkPtr->fd, F_SETFL, flags) < 0) {
-       Tcl_AppendResult(bgPtr->interp, "can't set file descriptor ",
-           Blt_Itoa(sinkPtr->fd), " to non-blocking:",
-           Tcl_PosixError(bgPtr->interp), (char *)NULL);
-       return TCL_ERROR;
-    }
-#endif /* WIN32 */
-#ifdef FILEHANDLER_USES_TCLFILES
-    sinkPtr->file = Tcl_GetFile((ClientData)sinkPtr->fd, TCL_UNIX_FD);
-    Tcl_CreateFileHandler(sinkPtr->file, TCL_READABLE, proc, bgPtr);
-#else
-    Tcl_CreateFileHandler(sinkPtr->fd, TCL_READABLE, proc, bgPtr);
-#endif /* FILEHANDLER_USES_TCLFILES */
-    return TCL_OK;
-}
-
-static void
-DisableTriggers(bgPtr)
-    BackgroundInfo *bgPtr;     /* Background info record. */
-{
-    int k;
-
-    if (bgPtr->traced) {
-       Tcl_UntraceVar(bgPtr->interp, bgPtr->statVar, TRACE_FLAGS, 
-               VariableProc, bgPtr);
-       bgPtr->traced = FALSE;
-    }
-    if (IsOpenSink(&bgPtr->sink1)) {
-       CloseSink(bgPtr, bgPtr->interp, &bgPtr->sink1);
-    }
-    if (IsOpenSink(&bgPtr->sink2)) {
-       CloseSink(bgPtr, bgPtr->interp, &bgPtr->sink2);
-    }
-    for( k = 0 ; k < bgPtr->nTimers ; k++ ){
-      Tcl_DeleteTimerHandler(bgPtr->timerTokens[k]);
-    }
-    bgPtr->nTimers = 0;
-    if (bgPtr->donePtr != NULL) {
-       *bgPtr->donePtr = TRUE;
-    }
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * FreeBackgroundInfo --
- *
- *     Releases the memory allocated for the backgrounded process.
- *
- *----------------------------------------------------------------------
- */
-static void
-FreeBackgroundInfo(bgPtr)
-    BackgroundInfo *bgPtr;
-{
-    Blt_FreeSwitches(bgPtr->interp, switchSpecs, (char *)bgPtr, 0);
-    if (bgPtr->statVar != NULL) {
-       Blt_Free(bgPtr->statVar);
-    }
-    if (bgPtr->procArr != NULL) {
-       Blt_Free(bgPtr->procArr);
-    }
-    if (bgPtr->timerTokens != NULL) {
-       Blt_Free(bgPtr->timerTokens);
-    }
-    Blt_Free(bgPtr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * DestroyBackgroundInfo --
- *
- *     This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
- *     to clean up the internal structure (BackgroundInfo) at a safe
- *     time (when no one is using it anymore).
- *
- * Results:
- *     None.b
- *
- * Side effects:
- *     The memory allocated to the BackgroundInfo structure released.
- *
- *----------------------------------------------------------------------
- */
-/* ARGSUSED */
-static void
-DestroyBackgroundInfo(bgPtr)
-    BackgroundInfo *bgPtr;     /* Background info record. */
-{
-    Tcl_DontCallWhenDeleted(bgPtr->interp, InterpDeleted, (ClientData)bgPtr);
-    DisableTriggers(bgPtr);
-    FreeSinkBuffer(&bgPtr->sink2);
-    FreeSinkBuffer(&bgPtr->sink1);
-    if (bgPtr->procArr != NULL) {
-       register int i;
-
-       for (i = 0; i < bgPtr->nProcs; i++) {
-           if (bgPtr->signalNum > 0) {
-               kill(bgPtr->procArr[i], bgPtr->signalNum);
-           }
-#ifdef WIN32
-           Tcl_DetachPids(1, (Tcl_Pid *)&bgPtr->procArr[i].pid);
-#else
-#if (TCL_MAJOR_VERSION == 7)
-           Tcl_DetachPids(1, &bgPtr->procArr[i]);
-#else
-           Tcl_DetachPids(1, (Tcl_Pid *)&bgPtr->procArr[i]);
-#endif /* TCL_MAJOR_VERSION == 7 */
-#endif /* WIN32 */
-       }
-    }
-    FreeBackgroundInfo(bgPtr);
-    Tcl_ReapDetachedProcs();
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * VariableProc --
- *
- *     Kills all currently running subprocesses (given the specified
- *     signal). This procedure is called when the user sets the status
- *     variable associated with this group of child subprocesses.
- *
- * Results:
- *     Always returns NULL.  Only called from a variable trace.
- *
- * Side effects:
- *     The subprocesses are signaled for termination using the
- *     specified kill signal.  Additionally, any resources allocated
- *     to track the subprocesses is released.
- *
- * ----------------------------------------------------------------------
- */
-/* ARGSUSED */
-static char *
-VariableProc(
-    ClientData clientData,     /* File output information. */
-    Tcl_Interp *interp,
-    char *part1,
-    char *part2,               /* Not Used. */
-    int flags)
-{
-    if (flags & TRACE_FLAGS) {
-       BackgroundInfo *bgPtr = clientData;
-
-       /* Kill all child processes that remain alive. */
-       if ((bgPtr->procArr != NULL) && (bgPtr->signalNum > 0)) {
-           register int i;
-
-           for (i = 0; i < bgPtr->nProcs; i++) {
-               kill(bgPtr->procArr[i], bgPtr->signalNum);
-           }
-             if (bgPtr->closeKill>0 && bgPtr->nProcs>0) {
-                 bgPtr->cKilled = 1;
-                 AddTimerHandler( bgPtr, bgPtr->closeKill ) ;
-             }
-         }
-    }
-    return NULL;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TimerProc --
- *
- *     This is a timer handler procedure which gets called
- *     periodically to reap any of the sub-processes if they have
- *     terminated.  After the last process has terminated, the
- *     contents of standard output are stored
- *     in the output variable, which triggers the cleanup proc (using
- *     a variable trace). The status the last process to exit is
- *     written to the status variable.
- *
- * Results:
- *     None.  Called from the Tcl event loop.
- *
- * Side effects:
- *     Many. The contents of procArr is shifted, leaving only those
- *     sub-processes which have not yet terminated.  If there are
- *     still subprocesses left, this procedure is placed in the timer
- *     queue again. Otherwise the output and possibly the status
- *     variables are updated.  The former triggers the cleanup
- *     routine which will destroy the information and resources
- *     associated with these background processes.
- *
- *----------------------------------------------------------------------
- */
-static void
-TimerProc(clientData)
-    ClientData clientData;
-{
-    BackgroundInfo *bgPtr = clientData;
-    register int i;
-    unsigned int lastPid;
-    int pid;
-    enum PROCESS_STATUS { 
-       PROCESS_EXITED, PROCESS_STOPPED, PROCESS_KILLED, PROCESS_UNKNOWN,
-       PROCESS_MAX
-    } pcode;
-    WAIT_STATUS_TYPE waitStatus, lastStatus;
-    int nLeft;                 /* Number of processes still not reaped */
-    char string[200];
-    Tcl_DString dString;
-    int code;
-    CONST char *result;
-
-    lastPid = (unsigned int)-1;
-    *((int *)&waitStatus) = 0;
-    *((int *)&lastStatus) = 0;
-
-    nLeft = 0;
-    for (i = 0; i < bgPtr->nProcs; i++) {
-#ifdef WIN32
-       pid = WaitProcess(bgPtr->procArr[i], (int *)&waitStatus, WNOHANG);
-#else
-       pid = waitpid(bgPtr->procArr[i], (int *)&waitStatus, WNOHANG);
-#endif
-       if (pid == 0) {         /*  Process has not terminated yet */
-           if (nLeft < i) {
-               bgPtr->procArr[nLeft] = bgPtr->procArr[i];
-           }
-           nLeft++;            /* Count the number of processes left */
-       } else if (pid != -1) {
-           /*
-            * Save the status information associated with the subprocess.
-            * We'll use it only if this is the last subprocess to be reaped.
-            */
-           lastStatus = waitStatus;
-           lastPid = (unsigned int)pid;
-       }
-    }
-    bgPtr->nProcs = nLeft;
-
-    if ((nLeft > 0) || (IsOpenSink(&bgPtr->sink1)) || 
-       (IsOpenSink(&bgPtr->sink2))) {
-       /* Keep polling for the status of the children that are left */
-         if (bgPtr->closeKill>0 && bgPtr->cKilled) {
-             if (IsOpenSink(&bgPtr->sink1)) {
-                 CloseSink(bgPtr, bgPtr->interp, &bgPtr->sink1);
-             }
-             if (IsOpenSink(&bgPtr->sink2)) {
-                 CloseSink(bgPtr, bgPtr->interp, &bgPtr->sink2);
-             }
-         }
-         AddTimerHandler( bgPtr, bgPtr->interval ) ;
-#if WINDEBUG
-       PurifyPrintf("schedule TimerProc(nProcs=%d)\n", nLeft);
-#endif
-       return;
-    }
-
-    /*
-     * All child processes have completed.  Set the status variable
-     * with the status of the last process reaped.  The status is a
-     * list of an error token, the exit status, and a message.
-     */
-
-    code = WEXITSTATUS(lastStatus);
-    Tcl_DStringInit(&dString);
-    if (bgPtr->maxExceed) {
-        Tcl_DStringAppendElement(&dString, "MAXBYTES");
-        pcode = PROCESS_MAX;
-    } else if (WIFEXITED(lastStatus)) {
-       Tcl_DStringAppendElement(&dString, "EXITED");
-       pcode = PROCESS_EXITED;
-    } else if (WIFSIGNALED(lastStatus)) {
-       Tcl_DStringAppendElement(&dString, "KILLED");
-       pcode = PROCESS_KILLED;
-       code = -1;
-    } else if (WIFSTOPPED(lastStatus)) {
-       Tcl_DStringAppendElement(&dString, "STOPPED");
-       pcode = PROCESS_STOPPED;
-       code = -1;
-    } else {
-       Tcl_DStringAppendElement(&dString, "UNKNOWN");
-       pcode = PROCESS_UNKNOWN;
-    }
-#ifdef WIN32
-    sprintf(string, "%u", lastPid);
-    Tcl_DStringAppendElement(&dString, string);
-#else
-    Tcl_DStringAppendElement(&dString, Blt_Itoa(lastPid));
-#endif
-    Tcl_DStringAppendElement(&dString, Blt_Itoa(code));
-    switch(pcode) {
-    case PROCESS_MAX:
-       Tcl_DStringAppendElement(&dString, "max bytes exceeded");
-       break;
-    case PROCESS_EXITED:
-        if (bgPtr->cKilled) {
-            Tcl_DStringAppendElement(&dString, "kill signal");
-        } else {
-            Tcl_DStringAppendElement(&dString, "child completed normally");
-       }
-       break;
-    case PROCESS_KILLED:
-       Tcl_DStringAppendElement(&dString, 
-                               Tcl_SignalMsg((int)(WTERMSIG(lastStatus))));
-       break;
-    case PROCESS_STOPPED:
-       Tcl_DStringAppendElement(&dString, 
-                Tcl_SignalMsg((int)(WSTOPSIG(lastStatus))));
-       break;
-    case PROCESS_UNKNOWN:
-       sprintf(string, "child completed with unknown status 0x%x",
-           *((int *)&lastStatus));
-       Tcl_DStringAppendElement(&dString, string);
-       break;
-    }
-    if (bgPtr->exitCodePtr != NULL) {
-       *bgPtr->exitCodePtr = code;
-    }
-    DisableTriggers(bgPtr);
-    result = Tcl_SetVar(bgPtr->interp, bgPtr->statVar, 
-       Tcl_DStringValue(&dString), bgPtr->varFlags | TCL_LEAVE_ERR_MSG);
-    SinkCallback(bgPtr->interp, &bgPtr->sink1, Tcl_DStringValue(&dString));
-    Tcl_DStringFree(&dString);
-    if (result == NULL) {
-       Tcl_BackgroundError(bgPtr->interp);
-    }
-    if (bgPtr->detached) {
-       DestroyBackgroundInfo(bgPtr);
-    }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Stdoutproc --
- *
- *     This procedure is called when output from the detached pipeline
- *     is available.  The output is read and saved in a buffer in the
- *     BackgroundInfo structure.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     Data is stored in the buffer.  This character array may
- *     be increased as more space is required to contain the output
- *     of the pipeline.
- *
- *----------------------------------------------------------------------
- */
-/* ARGSUSED */
-static void
-StdoutProc(clientData, mask)
-    ClientData clientData;     /* File output information. */
-    int mask;                  /* Not used. */
-{
-    BackgroundInfo *bgPtr = clientData;
-
-    if (CollectData(bgPtr, &bgPtr->sink1) == TCL_OK) {
-       return;
-    }
-    /*
-     * Either EOF or an error has occurred.  In either case, close the
-     * sink. Note that closing the sink will also remove the file
-     * handler, so this routine will not be called again.
-     */
-    CloseSink(bgPtr, bgPtr->interp, &bgPtr->sink1);
-
-    /*
-     * If both sinks (stdout and stderr) are closed, this doesn't
-     * necessarily mean that the process has terminated.  Set up a
-     * timer handler to periodically poll for the exit status of each
-     * process.  Initially check at the next idle interval.
-     */
-    if (!IsOpenSink(&bgPtr->sink2)) {
-       AddTimerHandler( bgPtr, 0 ) ;
-    }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * StderrProc --
- *
- *     This procedure is called when error from the detached pipeline
- *     is available.  The error is read and saved in a buffer in the
- *     BackgroundInfo structure.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     Data is stored in the buffer.  This character array may
- *     be increased as more space is required to contain the stderr
- *     of the pipeline.
- *
- *----------------------------------------------------------------------
- */
-/* ARGSUSED */
-static void
-StderrProc(clientData, mask)
-    ClientData clientData;     /* File output information. */
-    int mask;                  /* Not used. */
-{
-    BackgroundInfo *bgPtr = clientData;
-    
-    if (CollectData(bgPtr, &bgPtr->sink2) == TCL_OK) {
-       return;
-    }
-    /*
-     * Either EOF or an error has occurred.  In either case, close the
-     * sink. Note that closing the sink will also remove the file
-     * handler, so this routine will not be called again.
-     */
-    CloseSink(bgPtr, bgPtr->interp, &bgPtr->sink2);
-
-    /*
-     * If both sinks (stdout and stderr) are closed, this doesn't
-     * necessarily mean that the process has terminated.  Set up a
-     * timer handler to periodically poll for the exit status of each
-     * process.  Initially check at the next idle interval.
-     */
-    if (!IsOpenSink(&bgPtr->sink1)) {
-       AddTimerHandler( bgPtr, 0 ) ;
-    }
-}
-
-static void
-AddTimerHandler( bgPtr, interval )
-    BackgroundInfo *bgPtr;
-    int interval;
-{
-    if(!(bgPtr->timerTokens)){
-      bgPtr->timerTokens = Blt_Calloc(EXPECTED_NUM_TIMERS, sizeof(Tcl_TimerToken *));
-    }
-    if( ++bgPtr->nTimers >= EXPECTED_NUM_TIMERS ){
-      bgPtr->timerTokens = Blt_Realloc( bgPtr->timerTokens,
-                                       bgPtr->nTimers * sizeof(Tcl_TimerToken *) ) ;
-    }
-    bgPtr->timerTokens[bgPtr->nTimers-1] = Tcl_CreateTimerHandler(interval, 
-                                                                 TimerProc,
-                                                                 bgPtr);
-}
-
-static void
-InterpDeleted(clientData, interp)
-ClientData clientData; /* Thread-specific data. */
-Tcl_Interp *interp;            /* Current interpreter. */
-{
-    BackgroundInfo *bgPtr = (BackgroundInfo *)clientData;
-    DestroyBackgroundInfo(bgPtr);
-}
-
-void
-MakeLocal( char *ns, char **str) {
-    Tcl_DString dStr;
-    if (ns == NULL) return;
-    if (!strcmp(ns,"::")) return;
-    if (!strncmp(*str,"::",2)) return;
-    Tcl_DStringInit(&dStr);
-    Tcl_DStringAppend(&dStr, ns, -1);
-    Tcl_DStringAppend(&dStr, "::", -1);
-    Tcl_DStringAppend(&dStr, *str, -1);
-    Blt_Free(*str);
-    *str = Blt_Strdup( Tcl_DStringValue(&dStr) );
-    Tcl_DStringFree(&dStr);
-}
-/*
- *----------------------------------------------------------------------
- *
- * BgexecCmd --
- *
- *     This procedure is invoked to process the "bgexec" Tcl command.
- *     See the user documentation for details on what it does.
- *
- * Results:
- *     A standard Tcl result.
- *
- * Side effects:
- *     See the user documentation.
- *
- *----------------------------------------------------------------------
- */
-/* ARGSUSED */
-static int
-BgexecCmd(clientData, interp, argc, argv)
-    ClientData clientData;     /* Thread-specific data. */
-    Tcl_Interp *interp;                /* Current interpreter. */
-    int argc;                  /* Number of arguments. */
-    char **argv;               /* Argument strings. */
-{
-    int *outFdPtr, *errFdPtr;
-    int nProcs;
-    Process *pidPtr;
-    char *lastArg;
-    BackgroundInfo *bgPtr;
-    int i, term = 0, tail = 0;
-    int detached;
-    Tcl_Encoding encoding;
-
-    if (argc < 3) {
-       Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
-           " varName ?options? command ?arg...?\"", (char *)NULL);
-       return TCL_ERROR;
-    }
-
-    /* Check if the command line is to be run detached (the last
-     * argument is "&") */
-    lastArg = argv[argc - 1];
-    detached = ((lastArg[0] == '&') && (lastArg[1] == '\0'));
-    if (detached) {
-       argc--;
-       argv[argc] = NULL;      /* Remove the '&' argument */
-    }
-    bgPtr = Blt_Calloc(1, sizeof(BackgroundInfo));
-    assert(bgPtr);
-
-    /* Initialize the background information record */
-    bgPtr->interp = interp;
-    bgPtr->signalNum = SIGKILL;
-    bgPtr->nProcs = -1;
-    bgPtr->interval = 1000;
-    bgPtr->detached = detached;
-    bgPtr->keepNewline = TRUE;
-    bgPtr->statVar = Blt_Strdup(argv[1]);
-    bgPtr->timerTokens = NULL;
-    bgPtr->nTimers = 0;
-    bgPtr->closeKill = 0;
-
-    /* Try to clean up any detached processes */
-    Tcl_ReapDetachedProcs();
-
-    for (i=2; i<argc; i += 2) {
-        if (!strcmp(argv[i],"--")) {
-            term = i+1;
-            tail = (argc-i);
-            break;
-        }
-    }
-    i = Blt_ProcessSwitches(interp, switchSpecs, argc - 2 - tail, argv + 2, 
-       (char *)bgPtr, BLT_SWITCH_ARGV_PARTIAL);
-    if (i < 0) {
-       FreeBackgroundInfo(bgPtr);
-       return TCL_ERROR;
-    }
-    bgPtr->varFlags = TCL_GLOBAL_ONLY;
-    if (bgPtr->localVars) {
-        if (detached) {
-            bgPtr->varFlags = TCL_NAMESPACE_ONLY;
-        } else {
-            bgPtr->varFlags = 0;
-        }
-    }
-    if (term) {
-        i = term;
-    } else {
-        i += 2;
-    }
-    /* Must be at least one argument left as the command to execute. */
-    if (argc <= i) {
-       Tcl_AppendResult(interp, "missing command to execute: should be \"",
-           argv[0], " varName ?options? command ?arg...?\"", (char *)NULL);
-       FreeBackgroundInfo(bgPtr);
-       return TCL_ERROR;
-    }
-
-    if (bgPtr->localVars && (detached)) {
-        char *ns = NULL;
-        Tcl_Namespace *nsPtr;
-        nsPtr = Tcl_GetCurrentNamespace(interp);
-        
-        if (nsPtr != NULL) {
-            ns = nsPtr->fullName;
-        }
-        if (bgPtr->statVar) MakeLocal(ns, &bgPtr->statVar);
-        if (bgPtr->sink1.doneVar) MakeLocal(ns, &bgPtr->sink1.doneVar);
-        if (bgPtr->sink1.command) MakeLocal(ns, &bgPtr->sink1.command);
-        if (bgPtr->sink1.updateVar) MakeLocal(ns, &bgPtr->sink1.updateVar);
-        if (bgPtr->sink2.doneVar) MakeLocal(ns, &bgPtr->sink2.doneVar);
-        if (bgPtr->sink2.command) MakeLocal(ns, &bgPtr->sink2.command);
-        if (bgPtr->sink2.updateVar) MakeLocal(ns, &bgPtr->sink2.updateVar);
-    }
-    
-    /* Put a trace on the exit status variable.  The will also allow
-     * the user to prematurely terminate the pipeline by simply
-     * setting it.  */
-    if (Tcl_TraceVar(interp, bgPtr->statVar, TRACE_FLAGS, VariableProc, bgPtr) != TCL_OK) {
-        FreeBackgroundInfo(bgPtr);
-        return TCL_ERROR;
-    }
-    bgPtr->traced = TRUE;
-
-    encoding = ENCODING_ASCII;
-    if (bgPtr->outputEncodingName != NULL) {
-       if (strcmp(bgPtr->outputEncodingName, "binary") == 0) {
-           encoding = ENCODING_BINARY;
-       } else {
-#if (TCL_VERSION_NUMBER >= _VERSION(8,1,0)) 
-           encoding = Tcl_GetEncoding(interp, bgPtr->outputEncodingName);
-           if (encoding == NULL) {
-               goto error;
-           }
-#endif
-       }
-    }
-    InitSink(bgPtr, &bgPtr->sink1, "stdout", encoding);
-    if (bgPtr->errorEncodingName != NULL) {
-       if (strcmp(bgPtr->errorEncodingName, "binary") == 0) {
-           encoding = ENCODING_BINARY;
-       } else {
-#if (TCL_VERSION_NUMBER >= _VERSION(8,1,0)) 
-           encoding = Tcl_GetEncoding(interp, bgPtr->errorEncodingName);
-           if (encoding == NULL) {
-               goto error;
-           }
-#endif
-       }
-    }
-    InitSink(bgPtr, &bgPtr->sink2, "stderr", encoding);
-
-    outFdPtr = errFdPtr = (int *)NULL;
-#ifdef WIN32
-    if ((!bgPtr->detached) || 
-       (bgPtr->sink1.doneVar != NULL) || 
-       (bgPtr->sink1.command != NULL) || 
-       (bgPtr->sink1.updateVar != NULL) || 
-       (bgPtr->sink1.updateCmd != NULL)) {
-       outFdPtr = &bgPtr->sink1.fd;
-    }
-#else
-    outFdPtr = &bgPtr->sink1.fd;
-#endif
-    if ((bgPtr->sink2.doneVar != NULL) || 
-       (bgPtr->sink2.updateVar != NULL) ||
-       (bgPtr->sink2.updateCmd != NULL) || 
-       (bgPtr->sink2.echo)) {
-       errFdPtr = &bgPtr->sink2.fd;
-    }
-    nProcs = Blt_CreatePipeline(interp, argc - i, argv + i, &pidPtr,
-       (int *)NULL, outFdPtr, errFdPtr);
-    if (nProcs < 0) {
-       goto error;
-    }
-    bgPtr->procArr = pidPtr;
-    bgPtr->nProcs = nProcs;
-
-    if (bgPtr->sink1.fd == -1) {
-
-       /* If output has been redirected, start polling immediately
-        * for the exit status of each process.  Normally, this is
-        * done only after stdout has been closed by the last process,
-        * but here stdout has been redirected. The default polling
-        * interval is every 1 second.  */
-
-       AddTimerHandler( bgPtr, bgPtr->interval ) ;
-
-    } else if (CreateSinkHandler(bgPtr, &bgPtr->sink1, StdoutProc) != TCL_OK) {
-       goto error;
-    }
-    if ((bgPtr->sink2.fd != -1) &&
-       (CreateSinkHandler(bgPtr, &bgPtr->sink2, StderrProc) != TCL_OK)) {
-       goto error;
-    }
-    Tcl_CallWhenDeleted(interp, InterpDeleted, (ClientData)bgPtr);
-    if (bgPtr->detached) {     
-       char string[200];
-
-       /* If detached, return a list of the child process ids instead
-        * of the output of the pipeline. */
-       for (i = 0; i < nProcs; i++) {
-#ifdef WIN32
-           sprintf(string, "%u", (unsigned int)bgPtr->procArr[i].pid);
-#else 
-           sprintf(string, "%d", bgPtr->procArr[i]);
-#endif
-           Tcl_AppendElement(interp, string);
-       }
-    } else {
-       int exitCode;
-       int done, doRaise;
-
-       bgPtr->exitCodePtr = &exitCode;
-       bgPtr->donePtr = &done;
-
-       exitCode = done = 0;
-       while (!done) {
-           Tcl_DoOneEvent(0);
-       }
-       DisableTriggers(bgPtr);
-         if ((exitCode == 0 || bgPtr->doRaise==0) && (bgPtr->sink1.doneVar == NULL) && (bgPtr->sink1.command == NULL)) {
-           unsigned char *data;
-           size_t length;
-
-           /* Return the output of the pipeline. */
-           GetSinkData(&bgPtr->sink1, &data, &length);
-#if (TCL_VERSION_NUMBER <  _VERSION(8,1,0)) 
-           data[length] = '\0';
-           Tcl_SetResult(interp, data, TCL_VOLATILE);
-#else
-           Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(data, length));
-#endif
-       }
-       /* Clean up resources used. */
-        doRaise = bgPtr->doRaise;
-       DestroyBackgroundInfo(bgPtr);
-       if ((doRaise) && exitCode != 0) {
-           Tcl_AppendResult(interp, "child process exited abnormally",
-               (char *)NULL);
-           return TCL_ERROR;
-       }
-    }
-    return TCL_OK;
-  error:
-    DisableTriggers(bgPtr);
-    DestroyBackgroundInfo(bgPtr);
-    return TCL_ERROR;
-}
-
-
-static int
-KillCmd(clientData, interp, argc, argv)
-    ClientData clientData;     /* Thread-specific data. */
-    Tcl_Interp *interp;                /* Current interpreter. */
-    int argc;                  /* Number of arguments. */
-    char **argv;               /* Argument strings. */
-{
-     char *string;
-     int signalNum = SIGKILL;
-     int pid;
-#ifdef WIN32
-     HANDLE h;
-#endif
-
-     if (argc>3) {
-         Tcl_AppendResult(interp, "too many args", 0);
-         return TCL_ERROR;
-     }
-     if (argc<2) {
-         Tcl_AppendResult(interp, "pid required", 0);
-         return TCL_ERROR;
-     }
-     if (Tcl_GetInt(interp, argv[1], &pid) != TCL_OK) {
-         return TCL_ERROR;
-     }
-
-#ifdef WIN32
-     if (argc!=2) {
-         Tcl_AppendResult(interp, "windows does not support signo", 0);
-         return TCL_ERROR;
-     }
-     if (!(h = OpenProcess (PROCESS_TERMINATE, 0, pid))) {
-            Tcl_AppendResult (interp, "invalid pid or access", NULL);
-            return TCL_ERROR;
-     }
-
-     if (TerminateProcess (h, 1) == 0) {
-            Tcl_AppendResult (interp, "TerminateProcess failure", NULL);
-            return TCL_ERROR;
-     }
-
-     CloseHandle (h);
-#else
-     if (argc==3) {
-        string = argv[2];
-        if (isdigit(UCHAR(string[0]))) {
-           if (Tcl_GetInt(interp, string, &signalNum) != TCL_OK) {
-              return TCL_ERROR;
-          }
-        } else {
-           char *name;
-           register SignalId *sigPtr;
-
-           name = string;
-
-           /*  Clip off any "SIG" prefix from the signal name */
-           if ((name[0] == 'S') && (name[1] == 'I') && (name[2] == 'G')) {
-               name += 3;
-           }
-           signalNum = -1;
-           for (sigPtr = signalIds; sigPtr->number > 0; sigPtr++) {
-               if (strcmp(sigPtr->name + 3, name) == 0) {
-                   signalNum = sigPtr->number;
-                   break;
-               }
-           }
-           if (signalNum < 0) {
-               Tcl_AppendResult(interp, "unknown signal \"", string, "\"",
-                   (char *)NULL);
-               return TCL_ERROR;
-           }
-        }
-        if ((signalNum < 0) || (signalNum > NSIG)) {
-           /* Outside range of signals */
-           Tcl_AppendResult(interp, "signal number \"", string,
-               "\" is out of range", (char *)NULL);
-           return TCL_ERROR;
-        }
-     }
-     kill(pid, signalNum);
-#endif
-     return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Blt_BgexecInit --
- *
- *     This procedure is invoked to initialize the "bgexec" Tcl
- *     command.  See the user documentation for details on what it
- *     does.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     See the user documentation.
- *
- *----------------------------------------------------------------------
- */
-int
-Blt_BgexecInit(interp)
-    Tcl_Interp *interp;
-{
-    static Blt_CmdSpec cmdSpec = {"bgexec", BgexecCmd, };
-    static Blt_CmdSpec cmdSpec2 = {"kill", KillCmd, };
-
-    if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) {
-       return TCL_ERROR;
-    }
-    if (Blt_InitCmd(interp, "blt", &cmdSpec2) == NULL) {
-       return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-#endif /* NO_BGEXEC */