OSDN Git Service

8d7288c8a6b9da035b9066e138c1fe1bd2f70222
[pf3gnuchains/sourceware.git] / tcl / win / tclWinPipe.c
1 /* 
2  * tclWinPipe.c --
3  *
4  *      This file implements the Windows-specific exec pipeline functions,
5  *      the "pipe" channel driver, and the "pid" Tcl command.
6  *
7  * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
8  *
9  * See the file "license.terms" for information on usage and redistribution
10  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11  *
12  * RCS: @(#) $Id$
13  */
14
15 #include "tclWinInt.h"
16
17 /* CYGNUS LOCAL */
18 #ifndef __CYGWIN__
19 #include <dos.h>
20 #endif
21 /* END CYGNUS LOCAL */
22
23 #include <fcntl.h>
24 #include <io.h>
25 #include <sys/stat.h>
26
27 /*
28  * The following variable is used to tell whether this module has been
29  * initialized.
30  */
31
32 static int initialized = 0;
33
34 /*
35  * The pipeMutex locks around access to the initialized and procList variables,
36  * and it is used to protect background threads from being terminated while
37  * they are using APIs that hold locks.
38  */
39
40 TCL_DECLARE_MUTEX(pipeMutex)
41
42 /*
43  * The following defines identify the various types of applications that 
44  * run under windows.  There is special case code for the various types.
45  */
46
47 #define APPL_NONE       0
48 #define APPL_DOS        1
49 #define APPL_WIN3X      2
50 #define APPL_WIN32      3
51
52 /*
53  * The following constants and structures are used to encapsulate the state
54  * of various types of files used in a pipeline.
55  * This used to have a 1 && 2 that supported Win32s.
56  */
57
58 #define WIN_FILE 3              /* Basic Win32 file. */
59
60 /*
61  * This structure encapsulates the common state associated with all file
62  * types used in a pipeline.
63  */
64
65 typedef struct WinFile {
66     int type;                   /* One of the file types defined above. */
67     HANDLE handle;              /* Open file handle. */
68 } WinFile;
69
70 /*
71  * This list is used to map from pids to process handles.
72  */
73
74 typedef struct ProcInfo {
75     HANDLE hProcess;
76     DWORD dwProcessId;
77     struct ProcInfo *nextPtr;
78 } ProcInfo;
79
80 static ProcInfo *procList;
81
82 /*
83  * Bit masks used in the flags field of the PipeInfo structure below.
84  */
85
86 #define PIPE_PENDING    (1<<0)  /* Message is pending in the queue. */
87 #define PIPE_ASYNC      (1<<1)  /* Channel is non-blocking. */
88
89 /*
90  * Bit masks used in the sharedFlags field of the PipeInfo structure below.
91  */
92
93 #define PIPE_EOF        (1<<2)  /* Pipe has reached EOF. */
94 #define PIPE_EXTRABYTE  (1<<3)  /* The reader thread has consumed one byte. */
95
96 /*
97  * This structure describes per-instance data for a pipe based channel.
98  */
99
100 typedef struct PipeInfo {
101     struct PipeInfo *nextPtr;   /* Pointer to next registered pipe. */
102     Tcl_Channel channel;        /* Pointer to channel structure. */
103     int validMask;              /* OR'ed combination of TCL_READABLE,
104                                  * TCL_WRITABLE, or TCL_EXCEPTION: indicates
105                                  * which operations are valid on the file. */
106     int watchMask;              /* OR'ed combination of TCL_READABLE,
107                                  * TCL_WRITABLE, or TCL_EXCEPTION: indicates
108                                  * which events should be reported. */
109     int flags;                  /* State flags, see above for a list. */
110     TclFile readFile;           /* Output from pipe. */
111     TclFile writeFile;          /* Input from pipe. */
112     TclFile errorFile;          /* Error output from pipe. */
113     int numPids;                /* Number of processes attached to pipe. */
114     Tcl_Pid *pidPtr;            /* Pids of attached processes. */
115     Tcl_ThreadId threadId;      /* Thread to which events should be reported.
116                                  * This value is used by the reader/writer
117                                  * threads. */
118     HANDLE writeThread;         /* Handle to writer thread. */
119     HANDLE readThread;          /* Handle to reader thread. */
120     HANDLE writable;            /* Manual-reset event to signal when the
121                                  * writer thread has finished waiting for
122                                  * the current buffer to be written. */
123     HANDLE readable;            /* Manual-reset event to signal when the
124                                  * reader thread has finished waiting for
125                                  * input. */
126     HANDLE startWriter;         /* Auto-reset event used by the main thread to
127                                  * signal when the writer thread should attempt
128                                  * to write to the pipe. */
129     HANDLE startReader;         /* Auto-reset event used by the main thread to
130                                  * signal when the reader thread should attempt
131                                  * to read from the pipe. */
132     DWORD writeError;           /* An error caused by the last background
133                                  * write.  Set to 0 if no error has been
134                                  * detected.  This word is shared with the
135                                  * writer thread so access must be
136                                  * synchronized with the writable object.
137                                  */
138     char *writeBuf;             /* Current background output buffer.
139                                  * Access is synchronized with the writable
140                                  * object. */
141     int writeBufLen;            /* Size of write buffer.  Access is
142                                  * synchronized with the writable
143                                  * object. */
144     int toWrite;                /* Current amount to be written.  Access is
145                                  * synchronized with the writable object. */
146     int readFlags;              /* Flags that are shared with the reader
147                                  * thread.  Access is synchronized with the
148                                  * readable object.  */
149     char extraByte;             /* Buffer for extra character consumed by
150                                  * reader thread.  This byte is shared with
151                                  * the reader thread so access must be
152                                  * synchronized with the readable object. */
153 } PipeInfo;
154
155 typedef struct ThreadSpecificData {
156     /*
157      * The following pointer refers to the head of the list of pipes
158      * that are being watched for file events.
159      */
160     
161     PipeInfo *firstPipePtr;
162 } ThreadSpecificData;
163
164 static Tcl_ThreadDataKey dataKey;
165
166 /*
167  * The following structure is what is added to the Tcl event queue when
168  * pipe events are generated.
169  */
170
171 typedef struct PipeEvent {
172     Tcl_Event header;           /* Information that is standard for
173                                  * all events. */
174     PipeInfo *infoPtr;          /* Pointer to pipe info structure.  Note
175                                  * that we still have to verify that the
176                                  * pipe exists before dereferencing this
177                                  * pointer. */
178 } PipeEvent;
179
180 /*
181  * Declarations for functions used only in this file.
182  */
183
184 static int              ApplicationType(Tcl_Interp *interp,
185                             const char *fileName, char *fullName);
186 static void             BuildCommandLine(const char *executable, int argc, 
187                             char **argv, Tcl_DString *linePtr);
188 static BOOL             HasConsole(void);
189 static int              PipeBlockModeProc(ClientData instanceData, int mode);
190 static void             PipeCheckProc(ClientData clientData, int flags);
191 static int              PipeClose2Proc(ClientData instanceData,
192                             Tcl_Interp *interp, int flags);
193 static int              PipeEventProc(Tcl_Event *evPtr, int flags);
194 static void             PipeExitHandler(ClientData clientData);
195 static int              PipeGetHandleProc(ClientData instanceData,
196                             int direction, ClientData *handlePtr);
197 static void             PipeInit(void);
198 static int              PipeInputProc(ClientData instanceData, char *buf,
199                             int toRead, int *errorCode);
200 static int              PipeOutputProc(ClientData instanceData, char *buf,
201                             int toWrite, int *errorCode);
202 static DWORD WINAPI     PipeReaderThread(LPVOID arg);
203 static void             PipeSetupProc(ClientData clientData, int flags);
204 static void             PipeWatchProc(ClientData instanceData, int mask);
205 static DWORD WINAPI     PipeWriterThread(LPVOID arg);
206 static void             ProcExitHandler(ClientData clientData);
207 static int              TempFileName(WCHAR name[MAX_PATH]);
208 static int              WaitForRead(PipeInfo *infoPtr, int blocking);
209
210 /*
211  * This structure describes the channel type structure for command pipe
212  * based IO.
213  */
214
215 static Tcl_ChannelType pipeChannelType = {
216     "pipe",                     /* Type name. */
217     TCL_CHANNEL_VERSION_2,      /* v2 channel */
218     TCL_CLOSE2PROC,             /* Close proc. */
219     PipeInputProc,              /* Input proc. */
220     PipeOutputProc,             /* Output proc. */
221     NULL,                       /* Seek proc. */
222     NULL,                       /* Set option proc. */
223     NULL,                       /* Get option proc. */
224     PipeWatchProc,              /* Set up notifier to watch the channel. */
225     PipeGetHandleProc,          /* Get an OS handle from channel. */
226     PipeClose2Proc,             /* close2proc */
227     PipeBlockModeProc,          /* Set blocking or non-blocking mode.*/
228     NULL,                       /* flush proc. */
229     NULL,                       /* handler proc. */
230 };
231 \f
232 /*
233  *----------------------------------------------------------------------
234  *
235  * PipeInit --
236  *
237  *      This function initializes the static variables for this file.
238  *
239  * Results:
240  *      None.
241  *
242  * Side effects:
243  *      Creates a new event source.
244  *
245  *----------------------------------------------------------------------
246  */
247
248 static void
249 PipeInit()
250 {
251     ThreadSpecificData *tsdPtr;
252
253     /*
254      * Check the initialized flag first, then check again in the mutex.
255      * This is a speed enhancement.
256      */
257
258     if (!initialized) {
259         Tcl_MutexLock(&pipeMutex);
260         if (!initialized) {
261             initialized = 1;
262             procList = NULL;
263             Tcl_CreateExitHandler(ProcExitHandler, NULL);
264         }
265         Tcl_MutexUnlock(&pipeMutex);
266     }
267
268     tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
269     if (tsdPtr == NULL) {
270         tsdPtr = TCL_TSD_INIT(&dataKey);
271         tsdPtr->firstPipePtr = NULL;
272         Tcl_CreateEventSource(PipeSetupProc, PipeCheckProc, NULL);
273         Tcl_CreateThreadExitHandler(PipeExitHandler, NULL);
274     }
275 }
276 \f
277 /*
278  *----------------------------------------------------------------------
279  *
280  * PipeExitHandler --
281  *
282  *      This function is called to cleanup the pipe module before
283  *      Tcl is unloaded.
284  *
285  * Results:
286  *      None.
287  *
288  * Side effects:
289  *      Removes the pipe event source.
290  *
291  *----------------------------------------------------------------------
292  */
293
294 static void
295 PipeExitHandler(
296     ClientData clientData)      /* Old window proc */
297 {
298     Tcl_DeleteEventSource(PipeSetupProc, PipeCheckProc, NULL);
299 }
300 \f
301 /*
302  *----------------------------------------------------------------------
303  *
304  * ProcExitHandler --
305  *
306  *      This function is called to cleanup the process list before
307  *      Tcl is unloaded.
308  *
309  * Results:
310  *      None.
311  *
312  * Side effects:
313  *      Resets the process list.
314  *
315  *----------------------------------------------------------------------
316  */
317
318 static void
319 ProcExitHandler(
320     ClientData clientData)      /* Old window proc */
321 {
322     Tcl_MutexLock(&pipeMutex);
323     initialized = 0;
324     Tcl_MutexUnlock(&pipeMutex);
325 }
326 \f
327 /*
328  *----------------------------------------------------------------------
329  *
330  * PipeSetupProc --
331  *
332  *      This procedure is invoked before Tcl_DoOneEvent blocks waiting
333  *      for an event.
334  *
335  * Results:
336  *      None.
337  *
338  * Side effects:
339  *      Adjusts the block time if needed.
340  *
341  *----------------------------------------------------------------------
342  */
343
344 void
345 PipeSetupProc(
346     ClientData data,            /* Not used. */
347     int flags)                  /* Event flags as passed to Tcl_DoOneEvent. */
348 {
349     PipeInfo *infoPtr;
350     Tcl_Time blockTime = { 0, 0 };
351     int block = 1;
352     WinFile *filePtr;
353     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
354
355     if (!(flags & TCL_FILE_EVENTS)) {
356         return;
357     }
358     
359     /*
360      * Look to see if any events are already pending.  If they are, poll.
361      */
362
363     for (infoPtr = tsdPtr->firstPipePtr; infoPtr != NULL; 
364             infoPtr = infoPtr->nextPtr) {
365         if (infoPtr->watchMask & TCL_WRITABLE) {
366             filePtr = (WinFile*) infoPtr->writeFile;
367             if (WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT) {
368                 block = 0;
369             }
370         }
371         if (infoPtr->watchMask & TCL_READABLE) {
372             filePtr = (WinFile*) infoPtr->readFile;
373             if (WaitForRead(infoPtr, 0) >= 0) {
374                 block = 0;
375             }
376         }
377     }
378     if (!block) {
379         Tcl_SetMaxBlockTime(&blockTime);
380     }
381 }
382 \f
383 /*
384  *----------------------------------------------------------------------
385  *
386  * PipeCheckProc --
387  *
388  *      This procedure is called by Tcl_DoOneEvent to check the pipe
389  *      event source for events. 
390  *
391  * Results:
392  *      None.
393  *
394  * Side effects:
395  *      May queue an event.
396  *
397  *----------------------------------------------------------------------
398  */
399
400 static void
401 PipeCheckProc(
402     ClientData data,            /* Not used. */
403     int flags)                  /* Event flags as passed to Tcl_DoOneEvent. */
404 {
405     PipeInfo *infoPtr;
406     PipeEvent *evPtr;
407     WinFile *filePtr;
408     int needEvent;
409     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
410
411     if (!(flags & TCL_FILE_EVENTS)) {
412         return;
413     }
414     
415     /*
416      * Queue events for any ready pipes that don't already have events
417      * queued.
418      */
419
420     for (infoPtr = tsdPtr->firstPipePtr; infoPtr != NULL; 
421             infoPtr = infoPtr->nextPtr) {
422         if (infoPtr->flags & PIPE_PENDING) {
423             continue;
424         }
425         
426         /*
427          * Queue an event if the pipe is signaled for reading or writing.
428          */
429
430         needEvent = 0;
431         filePtr = (WinFile*) infoPtr->writeFile;
432         if ((infoPtr->watchMask & TCL_WRITABLE) &&
433                 (WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT)) {
434             needEvent = 1;
435         }
436         
437         filePtr = (WinFile*) infoPtr->readFile;
438         if ((infoPtr->watchMask & TCL_READABLE) &&
439                 (WaitForRead(infoPtr, 0) >= 0)) {
440             needEvent = 1;
441         }
442
443         if (needEvent) {
444             infoPtr->flags |= PIPE_PENDING;
445             evPtr = (PipeEvent *) ckalloc(sizeof(PipeEvent));
446             evPtr->header.proc = PipeEventProc;
447             evPtr->infoPtr = infoPtr;
448             Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
449         }
450     }
451 }
452 \f
453 /*
454  *----------------------------------------------------------------------
455  *
456  * TclWinMakeFile --
457  *
458  *      This function constructs a new TclFile from a given data and
459  *      type value.
460  *
461  * Results:
462  *      Returns a newly allocated WinFile as a TclFile.
463  *
464  * Side effects:
465  *      None.
466  *
467  *----------------------------------------------------------------------
468  */
469
470 TclFile
471 TclWinMakeFile(
472     HANDLE handle)              /* Type-specific data. */
473 {
474     WinFile *filePtr;
475
476     filePtr = (WinFile *) ckalloc(sizeof(WinFile));
477     filePtr->type = WIN_FILE;
478     filePtr->handle = handle;
479
480     return (TclFile)filePtr;
481 }
482 \f
483 /*
484  *----------------------------------------------------------------------
485  *
486  * TempFileName --
487  *
488  *      Gets a temporary file name and deals with the fact that the
489  *      temporary file path provided by Windows may not actually exist
490  *      if the TMP or TEMP environment variables refer to a 
491  *      non-existent directory.
492  *
493  * Results:    
494  *      0 if error, non-zero otherwise.  If non-zero is returned, the
495  *      name buffer will be filled with a name that can be used to 
496  *      construct a temporary file.
497  *
498  * Side effects:
499  *      None.
500  *
501  *----------------------------------------------------------------------
502  */
503
504 static int
505 TempFileName(name)
506     WCHAR name[MAX_PATH];       /* Buffer in which name for temporary 
507                                  * file gets stored. */
508 {
509     TCHAR *prefix;
510
511     prefix = (tclWinProcs->useWide) ? (TCHAR *) L"TCL" : (TCHAR *) "TCL";
512     if ((*tclWinProcs->getTempPathProc)(MAX_PATH, name) != 0) {
513         if ((*tclWinProcs->getTempFileNameProc)((TCHAR *) name, prefix, 0, 
514                 name) != 0) {
515             return 1;
516         }
517     }
518     if (tclWinProcs->useWide) {
519         ((WCHAR *) name)[0] = '.';
520         ((WCHAR *) name)[1] = '\0';
521     } else {
522         ((char *) name)[0] = '.';
523         ((char *) name)[1] = '\0';
524     }
525     return (*tclWinProcs->getTempFileNameProc)((TCHAR *) name, prefix, 0, 
526             name);
527 }
528 \f
529 /*
530  *----------------------------------------------------------------------
531  *
532  * TclpMakeFile --
533  *
534  *      Make a TclFile from a channel.
535  *
536  * Results:
537  *      Returns a new TclFile or NULL on failure.
538  *
539  * Side effects:
540  *      None.
541  *
542  *----------------------------------------------------------------------
543  */
544
545 TclFile
546 TclpMakeFile(channel, direction)
547     Tcl_Channel channel;        /* Channel to get file from. */
548     int direction;              /* Either TCL_READABLE or TCL_WRITABLE. */
549 {
550     HANDLE handle;
551
552     if (Tcl_GetChannelHandle(channel, direction, 
553             (ClientData *) &handle) == TCL_OK) {
554         return TclWinMakeFile(handle);
555     } else {
556         return (TclFile) NULL;
557     }
558 }
559 \f
560 /*
561  *----------------------------------------------------------------------
562  *
563  * TclpOpenFile --
564  *
565  *      This function opens files for use in a pipeline.
566  *
567  * Results:
568  *      Returns a newly allocated TclFile structure containing the
569  *      file handle.
570  *
571  * Side effects:
572  *      None.
573  *
574  *----------------------------------------------------------------------
575  */
576
577 TclFile
578 TclpOpenFile(path, mode)
579     CONST char *path;           /* The name of the file to open. */
580     int mode;                   /* In what mode to open the file? */
581 {
582     HANDLE handle;
583     DWORD accessMode, createMode, shareMode, flags;
584     Tcl_DString ds;
585     TCHAR *nativePath;
586     
587     /*
588      * Map the access bits to the NT access mode.
589      */
590
591     switch (mode & (O_RDONLY | O_WRONLY | O_RDWR)) {
592         case O_RDONLY:
593             accessMode = GENERIC_READ;
594             break;
595         case O_WRONLY:
596             accessMode = GENERIC_WRITE;
597             break;
598         case O_RDWR:
599             accessMode = (GENERIC_READ | GENERIC_WRITE);
600             break;
601         default:
602             TclWinConvertError(ERROR_INVALID_FUNCTION);
603             return NULL;
604     }
605
606     /*
607      * Map the creation flags to the NT create mode.
608      */
609
610     switch (mode & (O_CREAT | O_EXCL | O_TRUNC)) {
611         case (O_CREAT | O_EXCL):
612         case (O_CREAT | O_EXCL | O_TRUNC):
613             createMode = CREATE_NEW;
614             break;
615         case (O_CREAT | O_TRUNC):
616             createMode = CREATE_ALWAYS;
617             break;
618         case O_CREAT:
619             createMode = OPEN_ALWAYS;
620             break;
621         case O_TRUNC:
622         case (O_TRUNC | O_EXCL):
623             createMode = TRUNCATE_EXISTING;
624             break;
625         default:
626             createMode = OPEN_EXISTING;
627             break;
628     }
629
630     nativePath = Tcl_WinUtfToTChar(path, -1, &ds);
631
632     /*
633      * If the file is not being created, use the existing file attributes.
634      */
635
636     flags = 0;
637     if (!(mode & O_CREAT)) {
638         flags = (*tclWinProcs->getFileAttributesProc)(nativePath);
639         if (flags == 0xFFFFFFFF) {
640             flags = 0;
641         }
642     }
643
644     /*
645      * Set up the file sharing mode.  We want to allow simultaneous access.
646      */
647
648     shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
649
650     /*
651      * Now we get to create the file.
652      */
653
654     handle = (*tclWinProcs->createFileProc)(nativePath, accessMode, 
655             shareMode, NULL, createMode, flags, NULL);
656     Tcl_DStringFree(&ds);
657
658     if (handle == INVALID_HANDLE_VALUE) {
659         DWORD err;
660         
661         err = GetLastError();
662         if ((err & 0xffffL) == ERROR_OPEN_FAILED) {
663             err = (mode & O_CREAT) ? ERROR_FILE_EXISTS : ERROR_FILE_NOT_FOUND;
664         }
665         TclWinConvertError(err);
666         return NULL;
667     }
668
669     /*
670      * Seek to the end of file if we are writing.
671      */
672
673     if (mode & O_WRONLY) {
674         SetFilePointer(handle, 0, NULL, FILE_END);
675     }
676
677     return TclWinMakeFile(handle);
678 }
679 \f
680 /*
681  *----------------------------------------------------------------------
682  *
683  * TclpCreateTempFile --
684  *
685  *      This function opens a unique file with the property that it
686  *      will be deleted when its file handle is closed.  The temporary
687  *      file is created in the system temporary directory.
688  *
689  * Results:
690  *      Returns a valid TclFile, or NULL on failure.
691  *
692  * Side effects:
693  *      Creates a new temporary file.
694  *
695  *----------------------------------------------------------------------
696  */
697
698 TclFile
699 TclpCreateTempFile(contents)
700     CONST char *contents;       /* String to write into temp file, or NULL. */
701 {
702     WCHAR name[MAX_PATH];
703     CONST char *native;
704     Tcl_DString dstring;
705     HANDLE handle;
706
707     if (TempFileName(name) == 0) {
708         return NULL;
709     }
710
711     handle = (*tclWinProcs->createFileProc)((TCHAR *) name, 
712             GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 
713             FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE, NULL);
714     if (handle == INVALID_HANDLE_VALUE) {
715         goto error;
716     }
717
718     /*
719      * Write the file out, doing line translations on the way.
720      */
721
722     if (contents != NULL) {
723         DWORD result, length;
724         CONST char *p;
725
726         /*
727          * Convert the contents from UTF to native encoding
728          */
729         native = Tcl_UtfToExternalDString(NULL, contents, -1, &dstring);
730         
731         for (p = native; *p != '\0'; p++) {
732             if (*p == '\n') {
733                 length = p - native;
734                 if (length > 0) {
735                     if (!WriteFile(handle, native, length, &result, NULL)) {
736                         goto error;
737                     }
738                 }
739                 if (!WriteFile(handle, "\r\n", 2, &result, NULL)) {
740                     goto error;
741                 }
742                 native = p+1;
743             }
744         }
745         length = p - native;
746         if (length > 0) {
747             if (!WriteFile(handle, native, length, &result, NULL)) {
748                 goto error;
749             }
750         }
751         Tcl_DStringFree(&dstring);
752         if (SetFilePointer(handle, 0, NULL, FILE_BEGIN) == 0xFFFFFFFF) {
753             goto error;
754         }
755     }
756
757     return TclWinMakeFile(handle);
758
759   error:
760     /* Free the native representation of the contents if necessary */
761     if (contents != NULL) {
762         Tcl_DStringFree(&dstring);
763     }
764
765     TclWinConvertError(GetLastError());
766     CloseHandle(handle);
767     (*tclWinProcs->deleteFileProc)((TCHAR *) name);
768     return NULL;
769 }
770 \f
771 /*
772  *----------------------------------------------------------------------
773  *
774  * TclpCreatePipe --
775  *
776  *      Creates an anonymous pipe.
777  *
778  * Results:
779  *      Returns 1 on success, 0 on failure. 
780  *
781  * Side effects:
782  *      Creates a pipe.
783  *
784  *----------------------------------------------------------------------
785  */
786
787 int
788 TclpCreatePipe(
789     TclFile *readPipe,  /* Location to store file handle for
790                                  * read side of pipe. */
791     TclFile *writePipe) /* Location to store file handle for
792                                  * write side of pipe. */
793 {
794     HANDLE readHandle, writeHandle;
795
796     if (CreatePipe(&readHandle, &writeHandle, NULL, 0) != 0) {
797         *readPipe = TclWinMakeFile(readHandle);
798         *writePipe = TclWinMakeFile(writeHandle);
799         return 1;
800     }
801
802     TclWinConvertError(GetLastError());
803     return 0;
804 }
805 \f
806 /*
807  *----------------------------------------------------------------------
808  *
809  * TclpCloseFile --
810  *
811  *      Closes a pipeline file handle.  These handles are created by
812  *      TclpOpenFile, TclpCreatePipe, or TclpMakeFile.
813  *
814  * Results:
815  *      0 on success, -1 on failure.
816  *
817  * Side effects:
818  *      The file is closed and deallocated.
819  *
820  *----------------------------------------------------------------------
821  */
822
823 int
824 TclpCloseFile(
825     TclFile file)       /* The file to close. */
826 {
827     WinFile *filePtr = (WinFile *) file;
828
829     switch (filePtr->type) {
830         case WIN_FILE:
831             /*
832              * Don't close the Win32 handle if the handle is a standard channel
833              * during the exit process.  Otherwise, one thread may kill the
834              * stdio of another.
835              */
836
837             if (!TclInExit() 
838                     || ((GetStdHandle(STD_INPUT_HANDLE) != filePtr->handle)
839                             && (GetStdHandle(STD_OUTPUT_HANDLE) != filePtr->handle)
840                             && (GetStdHandle(STD_ERROR_HANDLE) != filePtr->handle))) {
841                 if (CloseHandle(filePtr->handle) == FALSE) {
842                     TclWinConvertError(GetLastError());
843                     ckfree((char *) filePtr);
844                     return -1;
845                 }
846             }
847             break;
848
849         default:
850             panic("TclpCloseFile: unexpected file type");
851     }
852
853     ckfree((char *) filePtr);
854     return 0;
855 }
856 \f
857 /*
858  *--------------------------------------------------------------------------
859  *
860  * TclpGetPid --
861  *
862  *      Given a HANDLE to a child process, return the process id for that
863  *      child process.
864  *
865  * Results:
866  *      Returns the process id for the child process.  If the pid was not 
867  *      known by Tcl, either because the pid was not created by Tcl or the 
868  *      child process has already been reaped, -1 is returned.
869  *
870  * Side effects:
871  *      None.
872  *
873  *--------------------------------------------------------------------------
874  */
875
876 unsigned long
877 TclpGetPid(
878     Tcl_Pid pid)                /* The HANDLE of the child process. */
879 {
880     ProcInfo *infoPtr;
881
882     Tcl_MutexLock(&pipeMutex);
883     for (infoPtr = procList; infoPtr != NULL; infoPtr = infoPtr->nextPtr) {
884         if (infoPtr->hProcess == (HANDLE) pid) {
885             Tcl_MutexUnlock(&pipeMutex);
886             return infoPtr->dwProcessId;
887         }
888     }
889     Tcl_MutexUnlock(&pipeMutex);
890     return (unsigned long) -1;
891 }
892 \f
893 /*
894  *----------------------------------------------------------------------
895  *
896  * TclpCreateProcess --
897  *
898  *      Create a child process that has the specified files as its 
899  *      standard input, output, and error.  The child process runs
900  *      asynchronously under Windows NT and Windows 9x, and runs
901  *      with the same environment variables as the creating process.
902  *
903  *      The complete Windows search path is searched to find the specified 
904  *      executable.  If an executable by the given name is not found, 
905  *      automatically tries appending ".com", ".exe", and ".bat" to the 
906  *      executable name.
907  *
908  * Results:
909  *      The return value is TCL_ERROR and an error message is left in
910  *      the interp's result if there was a problem creating the child 
911  *      process.  Otherwise, the return value is TCL_OK and *pidPtr is
912  *      filled with the process id of the child process.
913  * 
914  * Side effects:
915  *      A process is created.
916  *      
917  *----------------------------------------------------------------------
918  */
919
920 int
921 TclpCreateProcess(
922     Tcl_Interp *interp,         /* Interpreter in which to leave errors that
923                                  * occurred when creating the child process.
924                                  * Error messages from the child process
925                                  * itself are sent to errorFile. */
926     int argc,                   /* Number of arguments in following array. */
927     char **argv,                /* Array of argument strings.  argv[0]
928                                  * contains the name of the executable
929                                  * converted to native format (using the
930                                  * Tcl_TranslateFileName call).  Additional
931                                  * arguments have not been converted. */
932     TclFile inputFile,          /* If non-NULL, gives the file to use as
933                                  * input for the child process.  If inputFile
934                                  * file is not readable or is NULL, the child
935                                  * will receive no standard input. */
936     TclFile outputFile,         /* If non-NULL, gives the file that
937                                  * receives output from the child process.  If
938                                  * outputFile file is not writeable or is
939                                  * NULL, output from the child will be
940                                  * discarded. */
941     TclFile errorFile,          /* If non-NULL, gives the file that
942                                  * receives errors from the child process.  If
943                                  * errorFile file is not writeable or is NULL,
944                                  * errors from the child will be discarded.
945                                  * errorFile may be the same as outputFile. */
946     Tcl_Pid *pidPtr)            /* If this procedure is successful, pidPtr
947                                  * is filled with the process id of the child
948                                  * process. */
949 {
950     int result, applType, createFlags;
951     Tcl_DString cmdLine;        /* Complete command line (TCHAR). */
952     STARTUPINFOA startInfo;
953     PROCESS_INFORMATION procInfo;
954     SECURITY_ATTRIBUTES secAtts;
955     HANDLE hProcess, h, inputHandle, outputHandle, errorHandle;
956     char execPath[MAX_PATH * TCL_UTF_MAX];
957     WinFile *filePtr;
958
959     PipeInit();
960
961     applType = ApplicationType(interp, argv[0], execPath);
962     if (applType == APPL_NONE) {
963         return TCL_ERROR;
964     }
965
966     result = TCL_ERROR;
967     Tcl_DStringInit(&cmdLine);
968     hProcess = GetCurrentProcess();
969
970     /*
971      * STARTF_USESTDHANDLES must be used to pass handles to child process.
972      * Using SetStdHandle() and/or dup2() only works when a console mode 
973      * parent process is spawning an attached console mode child process.
974      */
975
976     ZeroMemory(&startInfo, sizeof(startInfo));
977     startInfo.cb = sizeof(startInfo);
978     startInfo.dwFlags   = STARTF_USESTDHANDLES;
979     startInfo.hStdInput = INVALID_HANDLE_VALUE;
980     startInfo.hStdOutput= INVALID_HANDLE_VALUE;
981     startInfo.hStdError = INVALID_HANDLE_VALUE;
982
983     secAtts.nLength = sizeof(SECURITY_ATTRIBUTES);
984     secAtts.lpSecurityDescriptor = NULL;
985     secAtts.bInheritHandle = TRUE;
986
987     /*
988      * We have to check the type of each file, since we cannot duplicate 
989      * some file types.  
990      */
991
992     inputHandle = INVALID_HANDLE_VALUE;
993     if (inputFile != NULL) {
994         filePtr = (WinFile *)inputFile;
995         if (filePtr->type == WIN_FILE) {
996             inputHandle = filePtr->handle;
997         }
998     }
999     outputHandle = INVALID_HANDLE_VALUE;
1000     if (outputFile != NULL) {
1001         filePtr = (WinFile *)outputFile;
1002         if (filePtr->type == WIN_FILE) {
1003             outputHandle = filePtr->handle;
1004         }
1005     }
1006     errorHandle = INVALID_HANDLE_VALUE;
1007     if (errorFile != NULL) {
1008         filePtr = (WinFile *)errorFile;
1009         if (filePtr->type == WIN_FILE) {
1010             errorHandle = filePtr->handle;
1011         }
1012     }
1013
1014     /*
1015      * Duplicate all the handles which will be passed off as stdin, stdout
1016      * and stderr of the child process. The duplicate handles are set to
1017      * be inheritable, so the child process can use them.
1018      */
1019
1020     if (inputHandle == INVALID_HANDLE_VALUE) {
1021         /* 
1022          * If handle was not set, stdin should return immediate EOF.
1023          * Under Windows95, some applications (both 16 and 32 bit!) 
1024          * cannot read from the NUL device; they read from console
1025          * instead.  When running tk, this is fatal because the child 
1026          * process would hang forever waiting for EOF from the unmapped 
1027          * console window used by the helper application.
1028          *
1029          * Fortunately, the helper application detects a closed pipe 
1030          * as an immediate EOF and can pass that information to the 
1031          * child process.
1032          */
1033
1034         if (CreatePipe(&startInfo.hStdInput, &h, &secAtts, 0) != FALSE) {
1035             CloseHandle(h);
1036         }
1037     } else {
1038         DuplicateHandle(hProcess, inputHandle, hProcess, &startInfo.hStdInput,
1039                 0, TRUE, DUPLICATE_SAME_ACCESS);
1040     }
1041     if (startInfo.hStdInput == INVALID_HANDLE_VALUE) {
1042         TclWinConvertError(GetLastError());
1043         Tcl_AppendResult(interp, "couldn't duplicate input handle: ",
1044                 Tcl_PosixError(interp), (char *) NULL);
1045         goto end;
1046     }
1047
1048     if (outputHandle == INVALID_HANDLE_VALUE) {
1049         /*
1050          * If handle was not set, output should be sent to an infinitely 
1051          * deep sink.  Under Windows 95, some 16 bit applications cannot
1052          * have stdout redirected to NUL; they send their output to
1053          * the console instead.  Some applications, like "more" or "dir /p", 
1054          * when outputting multiple pages to the console, also then try and
1055          * read from the console to go the next page.  When running tk, this
1056          * is fatal because the child process would hang forever waiting
1057          * for input from the unmapped console window used by the helper
1058          * application.
1059          *
1060          * Fortunately, the helper application will detect a closed pipe
1061          * as a sink.
1062          */
1063
1064         if ((TclWinGetPlatformId() == VER_PLATFORM_WIN32_WINDOWS) 
1065                 && (applType == APPL_DOS)) {
1066             if (CreatePipe(&h, &startInfo.hStdOutput, &secAtts, 0) != FALSE) {
1067                 CloseHandle(h);
1068             }
1069         } else {
1070             startInfo.hStdOutput = CreateFileA("NUL:", GENERIC_WRITE, 0,
1071                     &secAtts, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1072         }
1073     } else {
1074         DuplicateHandle(hProcess, outputHandle, hProcess, &startInfo.hStdOutput, 
1075                 0, TRUE, DUPLICATE_SAME_ACCESS);
1076     }
1077     if (startInfo.hStdOutput == INVALID_HANDLE_VALUE) {
1078         TclWinConvertError(GetLastError());
1079         Tcl_AppendResult(interp, "couldn't duplicate output handle: ",
1080                 Tcl_PosixError(interp), (char *) NULL);
1081         goto end;
1082     }
1083
1084     if (errorHandle == INVALID_HANDLE_VALUE) {
1085         /*
1086          * If handle was not set, errors should be sent to an infinitely
1087          * deep sink.
1088          */
1089
1090         startInfo.hStdError = CreateFileA("NUL:", GENERIC_WRITE, 0,
1091                 &secAtts, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1092     } else {
1093         DuplicateHandle(hProcess, errorHandle, hProcess, &startInfo.hStdError, 
1094                 0, TRUE, DUPLICATE_SAME_ACCESS);
1095     } 
1096     if (startInfo.hStdError == INVALID_HANDLE_VALUE) {
1097         TclWinConvertError(GetLastError());
1098         Tcl_AppendResult(interp, "couldn't duplicate error handle: ",
1099                 Tcl_PosixError(interp), (char *) NULL);
1100         goto end;
1101     }
1102     /* 
1103      * If we do not have a console window, then we must run DOS and
1104      * WIN32 console mode applications as detached processes. This tells
1105      * the loader that the child application should not inherit the
1106      * console, and that it should not create a new console window for
1107      * the child application.  The child application should get its stdio 
1108      * from the redirection handles provided by this application, and run
1109      * in the background.
1110      *
1111      * If we are starting a GUI process, they don't automatically get a 
1112      * console, so it doesn't matter if they are started as foreground or
1113      * detached processes.  The GUI window will still pop up to the
1114      * foreground.
1115      */
1116
1117     if (TclWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {
1118         if (HasConsole()) {
1119             createFlags = 0;
1120         } else if (applType == APPL_DOS) {
1121             /*
1122              * Under NT, 16-bit DOS applications will not run unless they
1123              * can be attached to a console.  If we are running without a
1124              * console, run the 16-bit program as an normal process inside
1125              * of a hidden console application, and then run that hidden
1126              * console as a detached process.
1127              */
1128
1129             startInfo.wShowWindow = SW_HIDE;
1130             startInfo.dwFlags |= STARTF_USESHOWWINDOW;
1131             createFlags = CREATE_NEW_CONSOLE;
1132             Tcl_DStringAppend(&cmdLine, "cmd.exe /c ", -1);
1133         } else {
1134             createFlags = DETACHED_PROCESS;
1135         } 
1136     } else {
1137         if (HasConsole()) {
1138             createFlags = 0;
1139         } else {
1140             createFlags = DETACHED_PROCESS;
1141         }
1142         
1143         if (applType == APPL_DOS) {
1144             /*
1145              * Under Windows 95, 16-bit DOS applications do not work well 
1146              * with pipes:
1147              *
1148              * 1. EOF on a pipe between a detached 16-bit DOS application 
1149              * and another application is not seen at the other
1150              * end of the pipe, so the listening process blocks forever on 
1151              * reads.  This inablity to detect EOF happens when either a 
1152              * 16-bit app or the 32-bit app is the listener.  
1153              *
1154              * 2. If a 16-bit DOS application (detached or not) blocks when 
1155              * writing to a pipe, it will never wake up again, and it
1156              * eventually brings the whole system down around it.
1157              *
1158              * The 16-bit application is run as a normal process inside
1159              * of a hidden helper console app, and this helper may be run
1160              * as a detached process.  If any of the stdio handles is
1161              * a pipe, the helper application accumulates information 
1162              * into temp files and forwards it to or from the DOS 
1163              * application as appropriate.  This means that DOS apps 
1164              * must receive EOF from a stdin pipe before they will actually
1165              * begin, and must finish generating stdout or stderr before 
1166              * the data will be sent to the next stage of the pipe.
1167              *
1168              * The helper app should be located in the same directory as
1169              * the tcl dll.
1170              */
1171
1172             if (createFlags != 0) {
1173                 startInfo.wShowWindow = SW_HIDE;
1174                 startInfo.dwFlags |= STARTF_USESHOWWINDOW;
1175                 createFlags = CREATE_NEW_CONSOLE;
1176             }
1177             Tcl_DStringAppend(&cmdLine, "tclpip" STRINGIFY(TCL_MAJOR_VERSION) 
1178                     STRINGIFY(TCL_MINOR_VERSION) ".dll ", -1);
1179         }
1180     }
1181     
1182     /*
1183      * cmdLine gets the full command line used to invoke the executable,
1184      * including the name of the executable itself.  The command line
1185      * arguments in argv[] are stored in cmdLine separated by spaces. 
1186      * Special characters in individual arguments from argv[] must be 
1187      * quoted when being stored in cmdLine.
1188      *
1189      * When calling any application, bear in mind that arguments that 
1190      * specify a path name are not converted.  If an argument contains 
1191      * forward slashes as path separators, it may or may not be 
1192      * recognized as a path name, depending on the program.  In general,
1193      * most applications accept forward slashes only as option 
1194      * delimiters and backslashes only as paths.
1195      *
1196      * Additionally, when calling a 16-bit dos or windows application, 
1197      * all path names must use the short, cryptic, path format (e.g., 
1198      * using ab~1.def instead of "a b.default").  
1199      */
1200
1201     BuildCommandLine(execPath, argc, argv, &cmdLine);
1202
1203     if ((*tclWinProcs->createProcessProc)(NULL, 
1204             (TCHAR *) Tcl_DStringValue(&cmdLine), NULL, NULL, TRUE, 
1205             createFlags, NULL, NULL, &startInfo, &procInfo) == 0) {
1206         TclWinConvertError(GetLastError());
1207         Tcl_AppendResult(interp, "couldn't execute \"", argv[0],
1208                 "\": ", Tcl_PosixError(interp), (char *) NULL);
1209         goto end;
1210     }
1211
1212     /*
1213      * This wait is used to force the OS to give some time to the DOS
1214      * process.
1215      */
1216
1217     if (applType == APPL_DOS) {
1218         WaitForSingleObject(procInfo.hProcess, 50);
1219     }
1220
1221     /* 
1222      * "When an application spawns a process repeatedly, a new thread 
1223      * instance will be created for each process but the previous 
1224      * instances may not be cleaned up.  This results in a significant 
1225      * virtual memory loss each time the process is spawned.  If there 
1226      * is a WaitForInputIdle() call between CreateProcess() and
1227      * CloseHandle(), the problem does not occur." PSS ID Number: Q124121
1228      */
1229
1230     WaitForInputIdle(procInfo.hProcess, 5000);
1231     CloseHandle(procInfo.hThread);
1232
1233     *pidPtr = (Tcl_Pid) procInfo.hProcess;
1234     if (*pidPtr != 0) {
1235         TclWinAddProcess(procInfo.hProcess, procInfo.dwProcessId);
1236     }
1237     result = TCL_OK;
1238
1239     end:
1240     Tcl_DStringFree(&cmdLine);
1241     if (startInfo.hStdInput != INVALID_HANDLE_VALUE) {
1242         CloseHandle(startInfo.hStdInput);
1243     }
1244     if (startInfo.hStdOutput != INVALID_HANDLE_VALUE) {
1245         CloseHandle(startInfo.hStdOutput);
1246     }
1247     if (startInfo.hStdError != INVALID_HANDLE_VALUE) {
1248         CloseHandle(startInfo.hStdError);
1249     }
1250     return result;
1251 }
1252
1253 \f
1254 /*
1255  *----------------------------------------------------------------------
1256  *
1257  * HasConsole --
1258  *
1259  *      Determines whether the current application is attached to a
1260  *      console.
1261  *
1262  * Results:
1263  *      Returns TRUE if this application has a console, else FALSE.
1264  *
1265  * Side effects:
1266  *      None.
1267  *
1268  *----------------------------------------------------------------------
1269  */
1270
1271 static BOOL
1272 HasConsole()
1273 {
1274     HANDLE handle;
1275     
1276     handle = CreateFileA("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE,
1277             NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1278
1279     if (handle != INVALID_HANDLE_VALUE) {
1280         CloseHandle(handle);
1281         return TRUE;
1282     } else {
1283         return FALSE;
1284     }
1285 }
1286 \f
1287 /*
1288  *--------------------------------------------------------------------
1289  *
1290  * ApplicationType --
1291  *
1292  *      Search for the specified program and identify if it refers to a DOS,
1293  *      Windows 3.X, or Win32 program.  Used to determine how to invoke 
1294  *      a program, or if it can even be invoked.
1295  *
1296  *      It is possible to almost positively identify DOS and Windows 
1297  *      applications that contain the appropriate magic numbers.  However, 
1298  *      DOS .com files do not seem to contain a magic number; if the program 
1299  *      name ends with .com and could not be identified as a Windows .com
1300  *      file, it will be assumed to be a DOS application, even if it was
1301  *      just random data.  If the program name does not end with .com, no 
1302  *      such assumption is made.
1303  *
1304  *      The Win32 procedure GetBinaryType incorrectly identifies any 
1305  *      junk file that ends with .exe as a dos executable and some 
1306  *      executables that don't end with .exe as not executable.  Plus it 
1307  *      doesn't exist under win95, so I won't feel bad about reimplementing
1308  *      functionality.
1309  *
1310  * Results:
1311  *      The return value is one of APPL_DOS, APPL_WIN3X, or APPL_WIN32
1312  *      if the filename referred to the corresponding application type.
1313  *      If the file name could not be found or did not refer to any known 
1314  *      application type, APPL_NONE is returned and an error message is 
1315  *      left in interp.  .bat files are identified as APPL_DOS.
1316  *
1317  * Side effects:
1318  *      None.
1319  *
1320  *----------------------------------------------------------------------
1321  */
1322
1323 static int
1324 ApplicationType(interp, originalName, fullName)
1325     Tcl_Interp *interp;         /* Interp, for error message. */
1326     const char *originalName;   /* Name of the application to find. */
1327     char fullName[];            /* Filled with complete path to 
1328                                  * application. */
1329 {
1330     int applType, i, nameLen, found;
1331     HANDLE hFile;
1332     TCHAR *rest;
1333     char *ext;
1334     char buf[2];
1335     DWORD attr, read;
1336     IMAGE_DOS_HEADER header;
1337     Tcl_DString nameBuf, ds;
1338     TCHAR *nativeName;
1339     WCHAR nativeFullPath[MAX_PATH];
1340     static char extensions[][5] = {"", ".com", ".exe", ".bat"};
1341
1342     /* Look for the program as an external program.  First try the name
1343      * as it is, then try adding .com, .exe, and .bat, in that order, to
1344      * the name, looking for an executable.
1345      *
1346      * Using the raw SearchPath() procedure doesn't do quite what is 
1347      * necessary.  If the name of the executable already contains a '.' 
1348      * character, it will not try appending the specified extension when
1349      * searching (in other words, SearchPath will not find the program 
1350      * "a.b.exe" if the arguments specified "a.b" and ".exe").   
1351      * So, first look for the file as it is named.  Then manually append 
1352      * the extensions, looking for a match.  
1353      */
1354
1355     applType = APPL_NONE;
1356     Tcl_DStringInit(&nameBuf);
1357     Tcl_DStringAppend(&nameBuf, originalName, -1);
1358     nameLen = Tcl_DStringLength(&nameBuf);
1359
1360     for (i = 0; i < (int) (sizeof(extensions) / sizeof(extensions[0])); i++) {
1361         Tcl_DStringSetLength(&nameBuf, nameLen);
1362         Tcl_DStringAppend(&nameBuf, extensions[i], -1);
1363         nativeName = Tcl_WinUtfToTChar(Tcl_DStringValue(&nameBuf), 
1364                 Tcl_DStringLength(&nameBuf), &ds);
1365         found = (*tclWinProcs->searchPathProc)(NULL, nativeName, NULL, 
1366                 MAX_PATH, nativeFullPath, &rest);
1367         Tcl_DStringFree(&ds);
1368         if (found == 0) {
1369             continue;
1370         }
1371
1372         /*
1373          * Ignore matches on directories or data files, return if identified
1374          * a known type.
1375          */
1376
1377         attr = (*tclWinProcs->getFileAttributesProc)((TCHAR *) nativeFullPath);
1378         if ((attr == 0xffffffff) || (attr & FILE_ATTRIBUTE_DIRECTORY)) {
1379             continue;
1380         }
1381         strcpy(fullName, Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds));
1382         Tcl_DStringFree(&ds);
1383
1384         ext = strrchr(fullName, '.');
1385         if ((ext != NULL) && (stricmp(ext, ".bat") == 0)) {
1386             applType = APPL_DOS;
1387             break;
1388         }
1389         
1390         hFile = (*tclWinProcs->createFileProc)((TCHAR *) nativeFullPath, 
1391                 GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 
1392                 FILE_ATTRIBUTE_NORMAL, NULL);
1393         if (hFile == INVALID_HANDLE_VALUE) {
1394             continue;
1395         }
1396
1397         header.e_magic = 0;
1398         ReadFile(hFile, (void *) &header, sizeof(header), &read, NULL);
1399         if (header.e_magic != IMAGE_DOS_SIGNATURE) {
1400             /* 
1401              * Doesn't have the magic number for relocatable executables.  If 
1402              * filename ends with .com, assume it's a DOS application anyhow.
1403              * Note that we didn't make this assumption at first, because some
1404              * supposed .com files are really 32-bit executables with all the
1405              * magic numbers and everything.  
1406              */
1407
1408             CloseHandle(hFile);
1409             if ((ext != NULL) && (strcmp(ext, ".com") == 0)) {
1410                 applType = APPL_DOS;
1411                 break;
1412             }
1413             continue;
1414         }
1415         if (header.e_lfarlc != sizeof(header)) {
1416             /* 
1417              * All Windows 3.X and Win32 and some DOS programs have this value
1418              * set here.  If it doesn't, assume that since it already had the 
1419              * other magic number it was a DOS application.
1420              */
1421
1422             CloseHandle(hFile);
1423             applType = APPL_DOS;
1424             break;
1425         }
1426
1427         /* 
1428          * The DWORD at header.e_lfanew points to yet another magic number.
1429          */
1430
1431         buf[0] = '\0';
1432         SetFilePointer(hFile, header.e_lfanew, NULL, FILE_BEGIN);
1433         ReadFile(hFile, (void *) buf, 2, &read, NULL);
1434         CloseHandle(hFile);
1435
1436         if ((buf[0] == 'N') && (buf[1] == 'E')) {
1437             applType = APPL_WIN3X;
1438         } else if ((buf[0] == 'P') && (buf[1] == 'E')) {
1439             applType = APPL_WIN32;
1440         } else {
1441             /*
1442              * Strictly speaking, there should be a test that there
1443              * is an 'L' and 'E' at buf[0..1], to identify the type as 
1444              * DOS, but of course we ran into a DOS executable that 
1445              * _doesn't_ have the magic number -- specifically, one
1446              * compiled using the Lahey Fortran90 compiler.
1447              */
1448
1449             applType = APPL_DOS;
1450         }
1451         break;
1452     }
1453     Tcl_DStringFree(&nameBuf);
1454
1455     if (applType == APPL_NONE) {
1456         TclWinConvertError(GetLastError());
1457         Tcl_AppendResult(interp, "couldn't execute \"", originalName,
1458                 "\": ", Tcl_PosixError(interp), (char *) NULL);
1459         return APPL_NONE;
1460     }
1461
1462     if ((applType == APPL_DOS) || (applType == APPL_WIN3X)) {
1463         /* 
1464          * Replace long path name of executable with short path name for 
1465          * 16-bit applications.  Otherwise the application may not be able
1466          * to correctly parse its own command line to separate off the 
1467          * application name from the arguments.
1468          */
1469
1470         (*tclWinProcs->getShortPathNameProc)((TCHAR *) nativeFullPath, 
1471                 nativeFullPath, MAX_PATH);
1472         strcpy(fullName, Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds));
1473         Tcl_DStringFree(&ds);
1474     }
1475     return applType;
1476 }
1477 \f
1478 /*    
1479  *----------------------------------------------------------------------
1480  *
1481  * BuildCommandLine --
1482  *
1483  *      The command line arguments are stored in linePtr separated
1484  *      by spaces, in a form that CreateProcess() understands.  Special 
1485  *      characters in individual arguments from argv[] must be quoted 
1486  *      when being stored in cmdLine.
1487  *
1488  * Results:
1489  *      None.
1490  *
1491  * Side effects:
1492  *      None.
1493  *
1494  *----------------------------------------------------------------------
1495  */
1496
1497 static void
1498 BuildCommandLine(
1499     CONST char *executable,     /* Full path of executable (including 
1500                                  * extension).  Replacement for argv[0]. */
1501     int argc,                   /* Number of arguments. */
1502     char **argv,                /* Argument strings in UTF. */
1503     Tcl_DString *linePtr)       /* Initialized Tcl_DString that receives the
1504                                  * command line (TCHAR). */
1505 {
1506     CONST char *arg, *start, *special;
1507     int quote, i;
1508     Tcl_DString ds;
1509
1510     Tcl_DStringInit(&ds);
1511
1512     /*
1513      * Prime the path.
1514      */
1515     
1516     Tcl_DStringAppend(&ds, Tcl_DStringValue(linePtr), -1);
1517     
1518     for (i = 0; i < argc; i++) {
1519         if (i == 0) {
1520             arg = executable;
1521         } else {
1522             arg = argv[i];
1523             Tcl_DStringAppend(&ds, " ", 1);
1524         }
1525
1526         quote = 0;
1527         if (argv[i][0] == '\0') {
1528             quote = 1;
1529         } else {
1530             for (start = argv[i]; *start != '\0'; start++) {
1531                 if (isspace(*start)) { /* INTL: ISO space. */
1532                     quote = 1;
1533                     break;
1534                 }
1535             }
1536         }
1537         if (quote) {
1538             Tcl_DStringAppend(&ds, "\"", 1);
1539         }
1540
1541         start = arg;        
1542         for (special = arg; ; ) {
1543             if ((*special == '\\') && 
1544                     (special[1] == '\\' || special[1] == '"')) {
1545                 Tcl_DStringAppend(&ds, start, special - start);
1546                 start = special;
1547                 while (1) {
1548                     special++;
1549                     if (*special == '"') {
1550                         /* 
1551                          * N backslashes followed a quote -> insert 
1552                          * N * 2 + 1 backslashes then a quote.
1553                          */
1554
1555                         Tcl_DStringAppend(&ds, start, special - start);
1556                         break;
1557                     }
1558                     if (*special != '\\') {
1559                         break;
1560                     }
1561                 }
1562                 Tcl_DStringAppend(&ds, start, special - start);
1563                 start = special;
1564             }
1565             if (*special == '"') {
1566                 Tcl_DStringAppend(&ds, start, special - start);
1567                 Tcl_DStringAppend(&ds, "\\\"", 2);
1568                 start = special + 1;
1569             }
1570             if (*special == '\0') {
1571                 break;
1572             }
1573             special++;
1574         }
1575         Tcl_DStringAppend(&ds, start, special - start);
1576         if (quote) {
1577             Tcl_DStringAppend(&ds, "\"", 1);
1578         }
1579     }
1580     Tcl_WinUtfToTChar(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds), linePtr);
1581     Tcl_DStringFree(&ds);
1582 }
1583 \f
1584 /*
1585  *----------------------------------------------------------------------
1586  *
1587  * TclpCreateCommandChannel --
1588  *
1589  *      This function is called by Tcl_OpenCommandChannel to perform
1590  *      the platform specific channel initialization for a command
1591  *      channel.
1592  *
1593  * Results:
1594  *      Returns a new channel or NULL on failure.
1595  *
1596  * Side effects:
1597  *      Allocates a new channel.
1598  *
1599  *----------------------------------------------------------------------
1600  */
1601
1602 Tcl_Channel
1603 TclpCreateCommandChannel(
1604     TclFile readFile,           /* If non-null, gives the file for reading. */
1605     TclFile writeFile,          /* If non-null, gives the file for writing. */
1606     TclFile errorFile,          /* If non-null, gives the file where errors
1607                                  * can be read. */
1608     int numPids,                /* The number of pids in the pid array. */
1609     Tcl_Pid *pidPtr)            /* An array of process identifiers. */
1610 {
1611     char channelName[16 + TCL_INTEGER_SPACE];
1612     int channelId;
1613     DWORD id;
1614     PipeInfo *infoPtr = (PipeInfo *) ckalloc((unsigned) sizeof(PipeInfo));
1615
1616     PipeInit();
1617
1618     infoPtr->watchMask = 0;
1619     infoPtr->flags = 0;
1620     infoPtr->readFlags = 0;
1621     infoPtr->readFile = readFile;
1622     infoPtr->writeFile = writeFile;
1623     infoPtr->errorFile = errorFile;
1624     infoPtr->numPids = numPids;
1625     infoPtr->pidPtr = pidPtr;
1626     infoPtr->writeBuf = 0;
1627     infoPtr->writeBufLen = 0;
1628     infoPtr->writeError = 0;
1629
1630     /*
1631      * Use one of the fds associated with the channel as the
1632      * channel id.
1633      */
1634
1635     if (readFile) {
1636         channelId = (int) ((WinFile*)readFile)->handle;
1637     } else if (writeFile) {
1638         channelId = (int) ((WinFile*)writeFile)->handle;
1639     } else if (errorFile) {
1640         channelId = (int) ((WinFile*)errorFile)->handle;
1641     } else {
1642         channelId = 0;
1643     }
1644
1645     infoPtr->validMask = 0;
1646
1647     infoPtr->threadId = Tcl_GetCurrentThread();
1648
1649     if (readFile != NULL) {
1650         /*
1651          * Start the background reader thread.
1652          */
1653
1654         infoPtr->readable = CreateEvent(NULL, TRUE, TRUE, NULL);
1655         infoPtr->startReader = CreateEvent(NULL, FALSE, FALSE, NULL);
1656         infoPtr->readThread = CreateThread(NULL, 8000, PipeReaderThread,
1657                 infoPtr, 0, &id);
1658         SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST); 
1659         infoPtr->validMask |= TCL_READABLE;
1660     } else {
1661         infoPtr->readThread = 0;
1662     }
1663     if (writeFile != NULL) {
1664         /*
1665          * Start the background writeer thwrite.
1666          */
1667
1668         infoPtr->writable = CreateEvent(NULL, TRUE, TRUE, NULL);
1669         infoPtr->startWriter = CreateEvent(NULL, FALSE, FALSE, NULL);
1670         infoPtr->writeThread = CreateThread(NULL, 8000, PipeWriterThread,
1671                 infoPtr, 0, &id);
1672         SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST); 
1673         infoPtr->validMask |= TCL_WRITABLE;
1674     }
1675
1676     /*
1677      * For backward compatibility with previous versions of Tcl, we
1678      * use "file%d" as the base name for pipes even though it would
1679      * be more natural to use "pipe%d".
1680      * Use the pointer to keep the channel names unique, in case
1681      * channels share handles (stdin/stdout).
1682      */
1683
1684     wsprintfA(channelName, "file%lx", infoPtr);
1685     infoPtr->channel = Tcl_CreateChannel(&pipeChannelType, channelName,
1686             (ClientData) infoPtr, infoPtr->validMask);
1687
1688     /*
1689      * Pipes have AUTO translation mode on Windows and ^Z eof char, which
1690      * means that a ^Z will be appended to them at close. This is needed
1691      * for Windows programs that expect a ^Z at EOF.
1692      */
1693
1694     Tcl_SetChannelOption((Tcl_Interp *) NULL, infoPtr->channel,
1695             "-translation", "auto");
1696     Tcl_SetChannelOption((Tcl_Interp *) NULL, infoPtr->channel,
1697             "-eofchar", "\032 {}");
1698     return infoPtr->channel;
1699 }
1700 \f
1701 /*
1702  *----------------------------------------------------------------------
1703  *
1704  * TclGetAndDetachPids --
1705  *
1706  *      Stores a list of the command PIDs for a command channel in
1707  *      the interp's result.
1708  *
1709  * Results:
1710  *      None.
1711  *
1712  * Side effects:
1713  *      Modifies the interp's result.
1714  *
1715  *----------------------------------------------------------------------
1716  */
1717
1718 void
1719 TclGetAndDetachPids(
1720     Tcl_Interp *interp,
1721     Tcl_Channel chan)
1722 {
1723     PipeInfo *pipePtr;
1724     Tcl_ChannelType *chanTypePtr;
1725     int i;
1726     char buf[TCL_INTEGER_SPACE];
1727
1728     /*
1729      * Punt if the channel is not a command channel.
1730      */
1731
1732     chanTypePtr = Tcl_GetChannelType(chan);
1733     if (chanTypePtr != &pipeChannelType) {
1734         return;
1735     }
1736
1737     pipePtr = (PipeInfo *) Tcl_GetChannelInstanceData(chan);
1738     for (i = 0; i < pipePtr->numPids; i++) {
1739         wsprintfA(buf, "%lu", TclpGetPid(pipePtr->pidPtr[i]));
1740         Tcl_AppendElement(interp, buf);
1741         Tcl_DetachPids(1, &(pipePtr->pidPtr[i]));
1742     }
1743     if (pipePtr->numPids > 0) {
1744         ckfree((char *) pipePtr->pidPtr);
1745         pipePtr->numPids = 0;
1746     }
1747 }
1748 \f
1749 /*
1750  *----------------------------------------------------------------------
1751  *
1752  * PipeBlockModeProc --
1753  *
1754  *      Set blocking or non-blocking mode on channel.
1755  *
1756  * Results:
1757  *      0 if successful, errno when failed.
1758  *
1759  * Side effects:
1760  *      Sets the device into blocking or non-blocking mode.
1761  *
1762  *----------------------------------------------------------------------
1763  */
1764
1765 static int
1766 PipeBlockModeProc(
1767     ClientData instanceData,    /* Instance data for channel. */
1768     int mode)                   /* TCL_MODE_BLOCKING or
1769                                  * TCL_MODE_NONBLOCKING. */
1770 {
1771     PipeInfo *infoPtr = (PipeInfo *) instanceData;
1772     
1773     /*
1774      * Pipes on Windows can not be switched between blocking and nonblocking,
1775      * hence we have to emulate the behavior. This is done in the input
1776      * function by checking against a bit in the state. We set or unset the
1777      * bit here to cause the input function to emulate the correct behavior.
1778      */
1779
1780     if (mode == TCL_MODE_NONBLOCKING) {
1781         infoPtr->flags |= PIPE_ASYNC;
1782     } else {
1783         infoPtr->flags &= ~(PIPE_ASYNC);
1784     }
1785     return 0;
1786 }
1787 \f
1788 /*
1789  *----------------------------------------------------------------------
1790  *
1791  * PipeClose2Proc --
1792  *
1793  *      Closes a pipe based IO channel.
1794  *
1795  * Results:
1796  *      0 on success, errno otherwise.
1797  *
1798  * Side effects:
1799  *      Closes the physical channel.
1800  *
1801  *----------------------------------------------------------------------
1802  */
1803
1804 static int
1805 PipeClose2Proc(
1806     ClientData instanceData,    /* Pointer to PipeInfo structure. */
1807     Tcl_Interp *interp,         /* For error reporting. */
1808     int flags)                  /* Flags that indicate which side to close. */
1809 {
1810     PipeInfo *pipePtr = (PipeInfo *) instanceData;
1811     Tcl_Channel errChan;
1812     int errorCode, result;
1813     PipeInfo *infoPtr, **nextPtrPtr;
1814     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
1815
1816     errorCode = 0;
1817     if ((!flags || (flags == TCL_CLOSE_READ))
1818             && (pipePtr->readFile != NULL)) {
1819         /*
1820          * Clean up the background thread if necessary.  Note that this
1821          * must be done before we can close the file, since the 
1822          * thread may be blocking trying to read from the pipe.
1823          */
1824
1825         if (pipePtr->readThread) {
1826             /*
1827              * Forcibly terminate the background thread.  We cannot rely on the
1828              * thread to cleanly terminate itself because we have no way of
1829              * closing the pipe handle without blocking in the case where the
1830              * thread is in the middle of an I/O operation.  Note that we need
1831              * to guard against terminating the thread while it is in the
1832              * middle of Tcl_ThreadAlert because it won't be able to release
1833              * the notifier lock.
1834              */
1835
1836             Tcl_MutexLock(&pipeMutex);
1837             TerminateThread(pipePtr->readThread, 0);
1838
1839             /*
1840              * Wait for the thread to terminate.  This ensures that we are
1841              * completely cleaned up before we leave this function. 
1842              */
1843
1844             WaitForSingleObject(pipePtr->readThread, INFINITE);
1845             Tcl_MutexUnlock(&pipeMutex);
1846
1847             CloseHandle(pipePtr->readThread);
1848             CloseHandle(pipePtr->readable);
1849             CloseHandle(pipePtr->startReader);
1850             pipePtr->readThread = NULL;
1851         }
1852         if (TclpCloseFile(pipePtr->readFile) != 0) {
1853             errorCode = errno;
1854         }
1855         pipePtr->validMask &= ~TCL_READABLE;
1856         pipePtr->readFile = NULL;
1857     }
1858     if ((!flags || (flags & TCL_CLOSE_WRITE))
1859             && (pipePtr->writeFile != NULL)) {
1860         /*
1861          * Wait for the writer thread to finish the current buffer, then
1862          * terminate the thread and close the handles.  If the channel is
1863          * nonblocking, there should be no pending write operations.
1864          */
1865
1866         if (pipePtr->writeThread) {
1867             WaitForSingleObject(pipePtr->writable, INFINITE);
1868
1869             /*
1870              * Forcibly terminate the background thread.  We cannot rely on the
1871              * thread to cleanly terminate itself because we have no way of
1872              * closing the pipe handle without blocking in the case where the
1873              * thread is in the middle of an I/O operation.  Note that we need
1874              * to guard against terminating the thread while it is in the
1875              * middle of Tcl_ThreadAlert because it won't be able to release
1876              * the notifier lock.
1877              */
1878
1879             Tcl_MutexLock(&pipeMutex);
1880             TerminateThread(pipePtr->writeThread, 0);
1881
1882             /*
1883              * Wait for the thread to terminate.  This ensures that we are
1884              * completely cleaned up before we leave this function. 
1885              */
1886
1887             WaitForSingleObject(pipePtr->writeThread, INFINITE);
1888             Tcl_MutexUnlock(&pipeMutex);
1889
1890
1891             CloseHandle(pipePtr->writeThread);
1892             CloseHandle(pipePtr->writable);
1893             CloseHandle(pipePtr->startWriter);
1894             pipePtr->writeThread = NULL;
1895         }
1896         if (TclpCloseFile(pipePtr->writeFile) != 0) {
1897             if (errorCode == 0) {
1898                 errorCode = errno;
1899             }
1900         }
1901         pipePtr->validMask &= ~TCL_WRITABLE;
1902         pipePtr->writeFile = NULL;
1903     }
1904
1905     pipePtr->watchMask &= pipePtr->validMask;
1906
1907     /*
1908      * Don't free the channel if any of the flags were set.
1909      */
1910
1911     if (flags) {
1912         return errorCode;
1913     }
1914
1915     /*
1916      * Remove the file from the list of watched files.
1917      */
1918
1919     for (nextPtrPtr = &(tsdPtr->firstPipePtr), infoPtr = *nextPtrPtr;
1920             infoPtr != NULL;
1921             nextPtrPtr = &infoPtr->nextPtr, infoPtr = *nextPtrPtr) {
1922         if (infoPtr == (PipeInfo *)pipePtr) {
1923             *nextPtrPtr = infoPtr->nextPtr;
1924             break;
1925         }
1926     }
1927
1928     /*
1929      * Wrap the error file into a channel and give it to the cleanup
1930      * routine.
1931      */
1932
1933     if (pipePtr->errorFile) {
1934         WinFile *filePtr;
1935
1936         filePtr = (WinFile*)pipePtr->errorFile;
1937         errChan = Tcl_MakeFileChannel((ClientData) filePtr->handle,
1938                 TCL_READABLE);
1939         ckfree((char *) filePtr);
1940     } else {
1941         errChan = NULL;
1942     }
1943
1944     result = TclCleanupChildren(interp, pipePtr->numPids, pipePtr->pidPtr,
1945             errChan);
1946
1947     if (pipePtr->numPids > 0) {
1948         ckfree((char *) pipePtr->pidPtr);
1949     }
1950
1951     if (pipePtr->writeBuf != NULL) {
1952         ckfree(pipePtr->writeBuf);
1953     }
1954
1955     ckfree((char*) pipePtr);
1956
1957     if (errorCode == 0) {
1958         return result;
1959     }
1960     return errorCode;
1961 }
1962 \f
1963 /*
1964  *----------------------------------------------------------------------
1965  *
1966  * PipeInputProc --
1967  *
1968  *      Reads input from the IO channel into the buffer given. Returns
1969  *      count of how many bytes were actually read, and an error indication.
1970  *
1971  * Results:
1972  *      A count of how many bytes were read is returned and an error
1973  *      indication is returned in an output argument.
1974  *
1975  * Side effects:
1976  *      Reads input from the actual channel.
1977  *
1978  *----------------------------------------------------------------------
1979  */
1980
1981 static int
1982 PipeInputProc(
1983     ClientData instanceData,            /* Pipe state. */
1984     char *buf,                          /* Where to store data read. */
1985     int bufSize,                        /* How much space is available
1986                                          * in the buffer? */
1987     int *errorCode)                     /* Where to store error code. */
1988 {
1989     PipeInfo *infoPtr = (PipeInfo *) instanceData;
1990     WinFile *filePtr = (WinFile*) infoPtr->readFile;
1991     DWORD count, bytesRead = 0;
1992     int result;
1993
1994     *errorCode = 0;
1995     /*
1996      * Synchronize with the reader thread.
1997      */
1998
1999     result = WaitForRead(infoPtr, (infoPtr->flags & PIPE_ASYNC) ? 0 : 1);
2000
2001     /*
2002      * If an error occurred, return immediately.
2003      */
2004
2005     if (result == -1) {
2006         *errorCode = errno;
2007         return -1;
2008     }
2009
2010     if (infoPtr->readFlags & PIPE_EXTRABYTE) {
2011         /*
2012          * The reader thread consumed 1 byte as a side effect of
2013          * waiting so we need to move it into the buffer.
2014          */
2015
2016         *buf = infoPtr->extraByte;
2017         infoPtr->readFlags &= ~PIPE_EXTRABYTE;
2018         buf++;
2019         bufSize--;
2020         bytesRead = 1;
2021
2022         /*
2023          * If further read attempts would block, return what we have.
2024          */
2025
2026         if (result == 0) {
2027             return bytesRead;
2028         }
2029     }
2030
2031     /*
2032      * Attempt to read bufSize bytes.  The read will return immediately
2033      * if there is any data available.  Otherwise it will block until
2034      * at least one byte is available or an EOF occurs.
2035      */
2036
2037     if (ReadFile(filePtr->handle, (LPVOID) buf, (DWORD) bufSize, &count,
2038             (LPOVERLAPPED) NULL) == TRUE) {
2039         return bytesRead + count;
2040     } else if (bytesRead) {
2041         /*
2042          * Ignore errors if we have data to return.
2043          */
2044
2045         return bytesRead;
2046     }
2047
2048     TclWinConvertError(GetLastError());
2049     if (errno == EPIPE) {
2050         infoPtr->readFlags |= PIPE_EOF;
2051         return 0;
2052     }
2053     *errorCode = errno;
2054     return -1;
2055 }
2056 \f
2057 /*
2058  *----------------------------------------------------------------------
2059  *
2060  * PipeOutputProc --
2061  *
2062  *      Writes the given output on the IO channel. Returns count of how
2063  *      many characters were actually written, and an error indication.
2064  *
2065  * Results:
2066  *      A count of how many characters were written is returned and an
2067  *      error indication is returned in an output argument.
2068  *
2069  * Side effects:
2070  *      Writes output on the actual channel.
2071  *
2072  *----------------------------------------------------------------------
2073  */
2074
2075 static int
2076 PipeOutputProc(
2077     ClientData instanceData,            /* Pipe state. */
2078     char *buf,                          /* The data buffer. */
2079     int toWrite,                        /* How many bytes to write? */
2080     int *errorCode)                     /* Where to store error code. */
2081 {
2082     PipeInfo *infoPtr = (PipeInfo *) instanceData;
2083     WinFile *filePtr = (WinFile*) infoPtr->writeFile;
2084     DWORD bytesWritten, timeout;
2085     
2086     *errorCode = 0;
2087     timeout = (infoPtr->flags & PIPE_ASYNC) ? 0 : INFINITE;
2088     if (WaitForSingleObject(infoPtr->writable, timeout) == WAIT_TIMEOUT) {
2089         /*
2090          * The writer thread is blocked waiting for a write to complete
2091          * and the channel is in non-blocking mode.
2092          */
2093
2094         errno = EAGAIN;
2095         goto error;
2096     }
2097     
2098     /*
2099      * Check for a background error on the last write.
2100      */
2101
2102     if (infoPtr->writeError) {
2103         TclWinConvertError(infoPtr->writeError);
2104         infoPtr->writeError = 0;
2105         goto error;
2106     }
2107
2108     if (infoPtr->flags & PIPE_ASYNC) {
2109         /*
2110          * The pipe is non-blocking, so copy the data into the output
2111          * buffer and restart the writer thread.
2112          */
2113
2114         if (toWrite > infoPtr->writeBufLen) {
2115             /*
2116              * Reallocate the buffer to be large enough to hold the data.
2117              */
2118
2119             if (infoPtr->writeBuf) {
2120                 ckfree(infoPtr->writeBuf);
2121             }
2122             infoPtr->writeBufLen = toWrite;
2123             infoPtr->writeBuf = ckalloc(toWrite);
2124         }
2125         memcpy(infoPtr->writeBuf, buf, toWrite);
2126         infoPtr->toWrite = toWrite;
2127         ResetEvent(infoPtr->writable);
2128         SetEvent(infoPtr->startWriter);
2129         bytesWritten = toWrite;
2130     } else {
2131         /*
2132          * In the blocking case, just try to write the buffer directly.
2133          * This avoids an unnecessary copy.
2134          */
2135
2136         if (WriteFile(filePtr->handle, (LPVOID) buf, (DWORD) toWrite,
2137                 &bytesWritten, (LPOVERLAPPED) NULL) == FALSE) {
2138             TclWinConvertError(GetLastError());
2139             goto error;
2140         }
2141     }
2142     return bytesWritten;
2143
2144     error:
2145     *errorCode = errno;
2146     return -1;
2147
2148 }
2149 \f
2150 /*
2151  *----------------------------------------------------------------------
2152  *
2153  * PipeEventProc --
2154  *
2155  *      This function is invoked by Tcl_ServiceEvent when a file event
2156  *      reaches the front of the event queue.  This procedure invokes
2157  *      Tcl_NotifyChannel on the pipe.
2158  *
2159  * Results:
2160  *      Returns 1 if the event was handled, meaning it should be removed
2161  *      from the queue.  Returns 0 if the event was not handled, meaning
2162  *      it should stay on the queue.  The only time the event isn't
2163  *      handled is if the TCL_FILE_EVENTS flag bit isn't set.
2164  *
2165  * Side effects:
2166  *      Whatever the notifier callback does.
2167  *
2168  *----------------------------------------------------------------------
2169  */
2170
2171 static int
2172 PipeEventProc(
2173     Tcl_Event *evPtr,           /* Event to service. */
2174     int flags)                  /* Flags that indicate what events to
2175                                  * handle, such as TCL_FILE_EVENTS. */
2176 {
2177     PipeEvent *pipeEvPtr = (PipeEvent *)evPtr;
2178     PipeInfo *infoPtr;
2179     WinFile *filePtr;
2180     int mask;
2181     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
2182
2183     if (!(flags & TCL_FILE_EVENTS)) {
2184         return 0;
2185     }
2186
2187     /*
2188      * Search through the list of watched pipes for the one whose handle
2189      * matches the event.  We do this rather than simply dereferencing
2190      * the handle in the event so that pipes can be deleted while the
2191      * event is in the queue.
2192      */
2193
2194     for (infoPtr = tsdPtr->firstPipePtr; infoPtr != NULL;
2195             infoPtr = infoPtr->nextPtr) {
2196         if (pipeEvPtr->infoPtr == infoPtr) {
2197             infoPtr->flags &= ~(PIPE_PENDING);
2198             break;
2199         }
2200     }
2201
2202     /*
2203      * Remove stale events.
2204      */
2205
2206     if (!infoPtr) {
2207         return 1;
2208     }
2209
2210     /*
2211      * Check to see if the pipe is readable.  Note
2212      * that we can't tell if a pipe is writable, so we always report it
2213      * as being writable unless we have detected EOF.
2214      */
2215
2216     filePtr = (WinFile*) ((PipeInfo*)infoPtr)->writeFile;
2217     mask = 0;
2218     if ((infoPtr->watchMask & TCL_WRITABLE) &&
2219             (WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT)) {
2220         mask = TCL_WRITABLE;
2221     }
2222
2223     filePtr = (WinFile*) ((PipeInfo*)infoPtr)->readFile;
2224     if ((infoPtr->watchMask & TCL_READABLE) &&
2225             (WaitForRead(infoPtr, 0) >= 0)) {
2226         if (infoPtr->readFlags & PIPE_EOF) {
2227             mask = TCL_READABLE;
2228         } else {
2229             mask |= TCL_READABLE;
2230         }
2231     }
2232
2233     /*
2234      * Inform the channel of the events.
2235      */
2236
2237     Tcl_NotifyChannel(infoPtr->channel, infoPtr->watchMask & mask);
2238     return 1;
2239 }
2240 \f
2241 /*
2242  *----------------------------------------------------------------------
2243  *
2244  * PipeWatchProc --
2245  *
2246  *      Called by the notifier to set up to watch for events on this
2247  *      channel.
2248  *
2249  * Results:
2250  *      None.
2251  *
2252  * Side effects:
2253  *      None.
2254  *
2255  *----------------------------------------------------------------------
2256  */
2257
2258 static void
2259 PipeWatchProc(
2260     ClientData instanceData,            /* Pipe state. */
2261     int mask)                           /* What events to watch for, OR-ed
2262                                          * combination of TCL_READABLE,
2263                                          * TCL_WRITABLE and TCL_EXCEPTION. */
2264 {
2265     PipeInfo **nextPtrPtr, *ptr;
2266     PipeInfo *infoPtr = (PipeInfo *) instanceData;
2267     int oldMask = infoPtr->watchMask;
2268     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
2269
2270     /*
2271      * Since most of the work is handled by the background threads,
2272      * we just need to update the watchMask and then force the notifier
2273      * to poll once. 
2274      */
2275
2276     infoPtr->watchMask = mask & infoPtr->validMask;
2277     if (infoPtr->watchMask) {
2278         Tcl_Time blockTime = { 0, 0 };
2279         if (!oldMask) {
2280             infoPtr->nextPtr = tsdPtr->firstPipePtr;
2281             tsdPtr->firstPipePtr = infoPtr;
2282         }
2283         Tcl_SetMaxBlockTime(&blockTime);
2284     } else {
2285         if (oldMask) {
2286             /*
2287              * Remove the pipe from the list of watched pipes.
2288              */
2289
2290             for (nextPtrPtr = &(tsdPtr->firstPipePtr), ptr = *nextPtrPtr;
2291                  ptr != NULL;
2292                  nextPtrPtr = &ptr->nextPtr, ptr = *nextPtrPtr) {
2293                 if (infoPtr == ptr) {
2294                     *nextPtrPtr = ptr->nextPtr;
2295                     break;
2296                 }
2297             }
2298         }
2299     }
2300 }
2301 \f
2302 /*
2303  *----------------------------------------------------------------------
2304  *
2305  * PipeGetHandleProc --
2306  *
2307  *      Called from Tcl_GetChannelHandle to retrieve OS handles from
2308  *      inside a command pipeline based channel.
2309  *
2310  * Results:
2311  *      Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if
2312  *      there is no handle for the specified direction. 
2313  *
2314  * Side effects:
2315  *      None.
2316  *
2317  *----------------------------------------------------------------------
2318  */
2319
2320 static int
2321 PipeGetHandleProc(
2322     ClientData instanceData,    /* The pipe state. */
2323     int direction,              /* TCL_READABLE or TCL_WRITABLE */
2324     ClientData *handlePtr)      /* Where to store the handle.  */
2325 {
2326     PipeInfo *infoPtr = (PipeInfo *) instanceData;
2327     WinFile *filePtr; 
2328
2329     if (direction == TCL_READABLE && infoPtr->readFile) {
2330         filePtr = (WinFile*) infoPtr->readFile;
2331         *handlePtr = (ClientData) filePtr->handle;
2332         return TCL_OK;
2333     }
2334     if (direction == TCL_WRITABLE && infoPtr->writeFile) {
2335         filePtr = (WinFile*) infoPtr->writeFile;
2336         *handlePtr = (ClientData) filePtr->handle;
2337         return TCL_OK;
2338     }
2339     return TCL_ERROR;
2340 }
2341 \f
2342 /*
2343  *----------------------------------------------------------------------
2344  *
2345  * Tcl_WaitPid --
2346  *
2347  *      Emulates the waitpid system call.
2348  *
2349  * Results:
2350  *      Returns 0 if the process is still alive, -1 on an error, or
2351  *      the pid on a clean close.  
2352  *
2353  * Side effects:
2354  *      Unless WNOHANG is set and the wait times out, the process
2355  *      information record will be deleted and the process handle
2356  *      will be closed.
2357  *
2358  *----------------------------------------------------------------------
2359  */
2360
2361 Tcl_Pid
2362 Tcl_WaitPid(
2363     Tcl_Pid pid,
2364     int *statPtr,
2365     int options)
2366 {
2367     ProcInfo *infoPtr, **prevPtrPtr;
2368     int flags;
2369     Tcl_Pid result;
2370     DWORD ret;
2371
2372     PipeInit();
2373
2374     /*
2375      * If no pid is specified, do nothing.
2376      */
2377     
2378     if (pid == 0) {
2379         *statPtr = 0;
2380         return 0;
2381     }
2382
2383     /*
2384      * Find the process on the process list.
2385      */
2386
2387     Tcl_MutexLock(&pipeMutex);
2388     prevPtrPtr = &procList;
2389     for (infoPtr = procList; infoPtr != NULL;
2390             prevPtrPtr = &infoPtr->nextPtr, infoPtr = infoPtr->nextPtr) {
2391          if (infoPtr->hProcess == (HANDLE) pid) {
2392             break;
2393         }
2394     }
2395     Tcl_MutexUnlock(&pipeMutex);
2396
2397     /*
2398      * If the pid is not one of the processes we know about (we started it)
2399      * then do nothing.
2400      */
2401                      
2402     if (infoPtr == NULL) {
2403         *statPtr = 0;
2404         return 0;
2405     }
2406
2407     /*
2408      * Officially "wait" for it to finish. We either poll (WNOHANG) or
2409      * wait for an infinite amount of time.
2410      */
2411     
2412     if (options & WNOHANG) {
2413         flags = 0;
2414     } else {
2415         flags = INFINITE;
2416     }
2417     ret = WaitForSingleObject(infoPtr->hProcess, flags);
2418     if (ret == WAIT_TIMEOUT) {
2419         *statPtr = 0;
2420         if (options & WNOHANG) {
2421             return 0;
2422         } else {
2423             result = 0;
2424         }
2425     } else if (ret != WAIT_FAILED) {
2426         GetExitCodeProcess(infoPtr->hProcess, (DWORD*)statPtr);
2427 #ifdef __OLD_CYGWIN__
2428         /* A cygwin program that exits because of a signal will set
2429            the exit status to 0x10000 | (sig << 8).  Fix that back
2430            into a standard Unix wait status.  */
2431        if ((*statPtr & 0x10000) != 0
2432            && (*statPtr & 0xff00) != 0
2433            && (*statPtr & ~ 0x1ff00) == 0) {
2434            *statPtr = (*statPtr >> 8) & 0xff;
2435        } else
2436 #endif
2437         *statPtr = ((*statPtr << 8) & 0xff00);
2438         result = pid;
2439     } else {
2440         errno = ECHILD;
2441         *statPtr = ECHILD;
2442         result = (Tcl_Pid) -1;
2443     }
2444
2445     /*
2446      * Remove the process from the process list and close the process handle.
2447      */
2448
2449     CloseHandle(infoPtr->hProcess);
2450     *prevPtrPtr = infoPtr->nextPtr;
2451     ckfree((char*)infoPtr);
2452
2453     return result;
2454 }
2455 \f
2456 /*
2457  *----------------------------------------------------------------------
2458  *
2459  * TclWinAddProcess --
2460  *
2461  *     Add a process to the process list so that we can use
2462  *     Tcl_WaitPid on the process.
2463  *
2464  * Results:
2465  *     None
2466  *
2467  * Side effects:
2468  *      Adds the specified process handle to the process list so
2469  *      Tcl_WaitPid knows about it.
2470  *
2471  *----------------------------------------------------------------------
2472  */
2473
2474 void
2475 TclWinAddProcess(hProcess, id)
2476     HANDLE hProcess;           /* Handle to process */
2477     DWORD id;                  /* Global process identifier */
2478 {
2479     ProcInfo *procPtr = (ProcInfo *) ckalloc(sizeof(ProcInfo));
2480     procPtr->hProcess = hProcess;
2481     procPtr->dwProcessId = id;
2482     Tcl_MutexLock(&pipeMutex);
2483     procPtr->nextPtr = procList;
2484     procList = procPtr;
2485     Tcl_MutexUnlock(&pipeMutex);
2486 }
2487 \f
2488 /*
2489  *----------------------------------------------------------------------
2490  *
2491  * Tcl_PidObjCmd --
2492  *
2493  *      This procedure is invoked to process the "pid" Tcl command.
2494  *      See the user documentation for details on what it does.
2495  *
2496  * Results:
2497  *      A standard Tcl result.
2498  *
2499  * Side effects:
2500  *      See the user documentation.
2501  *
2502  *----------------------------------------------------------------------
2503  */
2504
2505         /* ARGSUSED */
2506 int
2507 Tcl_PidObjCmd(
2508     ClientData dummy,           /* Not used. */
2509     Tcl_Interp *interp,         /* Current interpreter. */
2510     int objc,                   /* Number of arguments. */
2511     Tcl_Obj *CONST *objv)       /* Argument strings. */
2512 {
2513     Tcl_Channel chan;
2514     Tcl_ChannelType *chanTypePtr;
2515     PipeInfo *pipePtr;
2516     int i;
2517     Tcl_Obj *resultPtr;
2518     char buf[TCL_INTEGER_SPACE];
2519
2520     if (objc > 2) {
2521         Tcl_WrongNumArgs(interp, 1, objv, "?channelId?");
2522         return TCL_ERROR;
2523     }
2524     if (objc == 1) {
2525         resultPtr = Tcl_GetObjResult(interp);
2526         wsprintfA(buf, "%lu", (unsigned long) getpid());
2527         Tcl_SetStringObj(resultPtr, buf, -1);
2528     } else {
2529         chan = Tcl_GetChannel(interp, Tcl_GetStringFromObj(objv[1], NULL),
2530                 NULL);
2531         if (chan == (Tcl_Channel) NULL) {
2532             return TCL_ERROR;
2533         }
2534         chanTypePtr = Tcl_GetChannelType(chan);
2535         if (chanTypePtr != &pipeChannelType) {
2536             return TCL_OK;
2537         }
2538
2539         pipePtr = (PipeInfo *) Tcl_GetChannelInstanceData(chan);
2540         resultPtr = Tcl_GetObjResult(interp);
2541         for (i = 0; i < pipePtr->numPids; i++) {
2542             wsprintfA(buf, "%lu", TclpGetPid(pipePtr->pidPtr[i]));
2543             Tcl_ListObjAppendElement(/*interp*/ NULL, resultPtr,
2544                     Tcl_NewStringObj(buf, -1));
2545         }
2546     }
2547     return TCL_OK;
2548 }
2549 \f
2550 /*
2551  *----------------------------------------------------------------------
2552  *
2553  * WaitForRead --
2554  *
2555  *      Wait until some data is available, the pipe is at
2556  *      EOF or the reader thread is blocked waiting for data (if the
2557  *      channel is in non-blocking mode).
2558  *
2559  * Results:
2560  *      Returns 1 if pipe is readable.  Returns 0 if there is no data
2561  *      on the pipe, but there is buffered data.  Returns -1 if an
2562  *      error occurred.  If an error occurred, the threads may not
2563  *      be synchronized.
2564  *
2565  * Side effects:
2566  *      Updates the shared state flags and may consume 1 byte of data
2567  *      from the pipe.  If no error occurred, the reader thread is
2568  *      blocked waiting for a signal from the main thread.
2569  *
2570  *----------------------------------------------------------------------
2571  */
2572
2573 static int
2574 WaitForRead(
2575     PipeInfo *infoPtr,          /* Pipe state. */
2576     int blocking)               /* Indicates whether call should be
2577                                  * blocking or not. */
2578 {
2579     DWORD timeout, count;
2580     HANDLE *handle = ((WinFile *) infoPtr->readFile)->handle;
2581
2582     while (1) {
2583         /*
2584          * Synchronize with the reader thread.
2585          */
2586        
2587         timeout = blocking ? INFINITE : 0;
2588         if (WaitForSingleObject(infoPtr->readable, timeout) == WAIT_TIMEOUT) {
2589             /*
2590              * The reader thread is blocked waiting for data and the channel
2591              * is in non-blocking mode.
2592              */
2593
2594             errno = EAGAIN;
2595             return -1;
2596         }
2597
2598         /*
2599          * At this point, the two threads are synchronized, so it is safe
2600          * to access shared state.
2601          */
2602
2603
2604         /*
2605          * If the pipe has hit EOF, it is always readable.
2606          */
2607
2608         if (infoPtr->readFlags & PIPE_EOF) {
2609             return 1;
2610         }
2611     
2612         /*
2613          * Check to see if there is any data sitting in the pipe.
2614          */
2615
2616         if (PeekNamedPipe(handle, (LPVOID) NULL, (DWORD) 0,
2617                 (LPDWORD) NULL, &count, (LPDWORD) NULL) != TRUE) {
2618             TclWinConvertError(GetLastError());
2619             /*
2620              * Check to see if the peek failed because of EOF.
2621              */
2622
2623             if (errno == EPIPE) {
2624                 infoPtr->readFlags |= PIPE_EOF;
2625                 return 1;
2626             }
2627
2628             /*
2629              * Ignore errors if there is data in the buffer.
2630              */
2631
2632             if (infoPtr->readFlags & PIPE_EXTRABYTE) {
2633                 return 0;
2634             } else {
2635                 return -1;
2636             }
2637         }
2638
2639         /*
2640          * We found some data in the pipe, so it must be readable.
2641          */
2642
2643         if (count > 0) {
2644             return 1;
2645         }
2646
2647         /*
2648          * The pipe isn't readable, but there is some data sitting
2649          * in the buffer, so return immediately.
2650          */
2651
2652         if (infoPtr->readFlags & PIPE_EXTRABYTE) {
2653             return 0;
2654         }
2655
2656         /*
2657          * There wasn't any data available, so reset the thread and
2658          * try again.
2659          */
2660     
2661         ResetEvent(infoPtr->readable);
2662         SetEvent(infoPtr->startReader);
2663     }
2664 }
2665 \f
2666 /*
2667  *----------------------------------------------------------------------
2668  *
2669  * PipeReaderThread --
2670  *
2671  *      This function runs in a separate thread and waits for input
2672  *      to become available on a pipe.
2673  *
2674  * Results:
2675  *      None.
2676  *
2677  * Side effects:
2678  *      Signals the main thread when input become available.  May
2679  *      cause the main thread to wake up by posting a message.  May
2680  *      consume one byte from the pipe for each wait operation.
2681  *
2682  *----------------------------------------------------------------------
2683  */
2684
2685 static DWORD WINAPI
2686 PipeReaderThread(LPVOID arg)
2687 {
2688     PipeInfo *infoPtr = (PipeInfo *)arg;
2689     HANDLE *handle = ((WinFile *) infoPtr->readFile)->handle;
2690     DWORD count, err;
2691     int done = 0;
2692
2693     while (!done) {
2694         /*
2695          * Wait for the main thread to signal before attempting to wait.
2696          */
2697
2698         WaitForSingleObject(infoPtr->startReader, INFINITE);
2699
2700         /*
2701          * Try waiting for 0 bytes.  This will block until some data is
2702          * available on NT, but will return immediately on Win 95.  So,
2703          * if no data is available after the first read, we block until
2704          * we can read a single byte off of the pipe.
2705          */
2706
2707         if ((ReadFile(handle, NULL, 0, &count, NULL) == FALSE)
2708                 || (PeekNamedPipe(handle, NULL, 0, NULL, &count,
2709                         NULL) == FALSE)) {
2710             /*
2711              * The error is a result of an EOF condition, so set the
2712              * EOF bit before signalling the main thread.
2713              */
2714
2715             err = GetLastError();
2716             if (err == ERROR_BROKEN_PIPE) {
2717                 infoPtr->readFlags |= PIPE_EOF;
2718                 done = 1;
2719             } else if (err == ERROR_INVALID_HANDLE) {
2720                 break;
2721             }
2722         } else if (count == 0) {
2723             if (ReadFile(handle, &(infoPtr->extraByte), 1, &count, NULL)
2724                     != FALSE) {
2725                 /*
2726                  * One byte was consumed as a side effect of waiting
2727                  * for the pipe to become readable.
2728                  */
2729
2730                 infoPtr->readFlags |= PIPE_EXTRABYTE;
2731             } else {
2732                 err = GetLastError();
2733                 if (err == ERROR_BROKEN_PIPE) {
2734                     /*
2735                      * The error is a result of an EOF condition, so set the
2736                      * EOF bit before signalling the main thread.
2737                      */
2738
2739                     infoPtr->readFlags |= PIPE_EOF;
2740                     done = 1;
2741                 } else if (err == ERROR_INVALID_HANDLE) {
2742                     break;
2743                 }
2744             }
2745         }
2746
2747                 
2748         /*
2749          * Signal the main thread by signalling the readable event and
2750          * then waking up the notifier thread.
2751          */
2752
2753         SetEvent(infoPtr->readable);
2754         
2755         /*
2756          * Alert the foreground thread.  Note that we need to treat this like
2757          * a critical section so the foreground thread does not terminate
2758          * this thread while we are holding a mutex in the notifier code.
2759          */
2760
2761         Tcl_MutexLock(&pipeMutex);
2762         Tcl_ThreadAlert(infoPtr->threadId);
2763         Tcl_MutexUnlock(&pipeMutex);
2764     }
2765     return 0;
2766 }
2767 \f
2768 /*
2769  *----------------------------------------------------------------------
2770  *
2771  * PipeWriterThread --
2772  *
2773  *      This function runs in a separate thread and writes data
2774  *      onto a pipe.
2775  *
2776  * Results:
2777  *      Always returns 0.
2778  *
2779  * Side effects:
2780  *      Signals the main thread when an output operation is completed.
2781  *      May cause the main thread to wake up by posting a message.  
2782  *
2783  *----------------------------------------------------------------------
2784  */
2785
2786 static DWORD WINAPI
2787 PipeWriterThread(LPVOID arg)
2788 {
2789
2790     PipeInfo *infoPtr = (PipeInfo *)arg;
2791     HANDLE *handle = ((WinFile *) infoPtr->writeFile)->handle;
2792     DWORD count, toWrite;
2793     char *buf;
2794     int done = 0;
2795
2796     while (!done) {
2797         /*
2798          * Wait for the main thread to signal before attempting to write.
2799          */
2800
2801         WaitForSingleObject(infoPtr->startWriter, INFINITE);
2802
2803         buf = infoPtr->writeBuf;
2804         toWrite = infoPtr->toWrite;
2805
2806         /*
2807          * Loop until all of the bytes are written or an error occurs.
2808          */
2809
2810         while (toWrite > 0) {
2811             if (WriteFile(handle, buf, toWrite, &count, NULL) == FALSE) {
2812                 infoPtr->writeError = GetLastError();
2813                 done = 1; 
2814                 break;
2815             } else {
2816                 toWrite -= count;
2817                 buf += count;
2818             }
2819         }
2820         
2821         /*
2822          * Signal the main thread by signalling the writable event and
2823          * then waking up the notifier thread.
2824          */
2825
2826         SetEvent(infoPtr->writable);
2827
2828         /*
2829          * Alert the foreground thread.  Note that we need to treat this like
2830          * a critical section so the foreground thread does not terminate
2831          * this thread while we are holding a mutex in the notifier code.
2832          */
2833
2834         Tcl_MutexLock(&pipeMutex);
2835         Tcl_ThreadAlert(infoPtr->threadId);
2836         Tcl_MutexUnlock(&pipeMutex);
2837     }
2838     return 0;
2839 }
2840
2841
2842
2843