📄 tclwinpipe.c
字号:
/* * tclWinPipe.c -- * * This file implements the Windows-specific exec pipeline functions, * the "pipe" channel driver, and the "pid" Tcl command. * * Copyright (c) 1996-1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * SCCS: @(#) tclWinPipe.c 1.49 97/11/06 17:33:03 */#include "tclWinInt.h"#include <dos.h>#include <fcntl.h>#include <io.h>#include <sys/stat.h>/* * The following variable is used to tell whether this module has been * initialized. */static int initialized = 0;/* * The following defines identify the various types of applications that * run under windows. There is special case code for the various types. */#define APPL_NONE 0#define APPL_DOS 1#define APPL_WIN3X 2#define APPL_WIN32 3/* * The following constants and structures are used to encapsulate the state * of various types of files used in a pipeline. */#define WIN32S_PIPE 1 /* Win32s emulated pipe. */#define WIN32S_TMPFILE 2 /* Win32s emulated temporary file. */#define WIN_FILE 3 /* Basic Win32 file. *//* * This structure encapsulates the common state associated with all file * types used in a pipeline. */typedef struct WinFile { int type; /* One of the file types defined above. */ HANDLE handle; /* Open file handle. */} WinFile;/* * The following structure is used to keep track of temporary files under * Win32s and delete the disk file when the open handle is closed. * The type field will be WIN32S_TMPFILE. */typedef struct TmpFile { WinFile file; /* Common part. */ char name[MAX_PATH]; /* Name of temp file. */} TmpFile;/* * The following structure represents a synchronous pipe under Win32s. * The type field will be WIN32S_PIPE. The handle field will refer to * an open file when Tcl is reading from the "pipe", otherwise it is * INVALID_HANDLE_VALUE. */typedef struct WinPipe { WinFile file; /* Common part. */ struct WinPipe *otherPtr; /* Pointer to the WinPipe structure that * corresponds to the other end of this * pipe. */ char *fileName; /* The name of the staging file that gets * the data written to this pipe. Malloc'd. * and shared by both ends of the pipe. Only * when both ends are freed will fileName be * freed and the file it refers to deleted. */} WinPipe;/* * This list is used to map from pids to process handles. */typedef struct ProcInfo { HANDLE hProcess; DWORD dwProcessId; struct ProcInfo *nextPtr;} ProcInfo;static ProcInfo *procList;/* * State flags used in the PipeInfo structure below. */#define PIPE_PENDING (1<<0) /* Message is pending in the queue. */#define PIPE_ASYNC (1<<1) /* Channel is non-blocking. *//* * This structure describes per-instance data for a pipe based channel. */typedef struct PipeInfo { Tcl_Channel channel; /* Pointer to channel structure. */ int validMask; /* OR'ed combination of TCL_READABLE, * TCL_WRITABLE, or TCL_EXCEPTION: indicates * which operations are valid on the file. */ int watchMask; /* OR'ed combination of TCL_READABLE, * TCL_WRITABLE, or TCL_EXCEPTION: indicates * which events should be reported. */ int flags; /* State flags, see above for a list. */ TclFile readFile; /* Output from pipe. */ TclFile writeFile; /* Input from pipe. */ TclFile errorFile; /* Error output from pipe. */ int numPids; /* Number of processes attached to pipe. */ Tcl_Pid *pidPtr; /* Pids of attached processes. */ struct PipeInfo *nextPtr; /* Pointer to next registered pipe. */} PipeInfo;/* * The following pointer refers to the head of the list of pipes * that are being watched for file events. */static PipeInfo *firstPipePtr;/* * The following structure is what is added to the Tcl event queue when * pipe events are generated. */typedef struct PipeEvent { Tcl_Event header; /* Information that is standard for * all events. */ PipeInfo *infoPtr; /* Pointer to pipe info structure. Note * that we still have to verify that the * pipe exists before dereferencing this * pointer. */} PipeEvent;/* * Declarations for functions used only in this file. */static int ApplicationType(Tcl_Interp *interp, const char *fileName, char *fullName);static void BuildCommandLine(int argc, char **argv, Tcl_DString *linePtr);static void CopyChannel(HANDLE dst, HANDLE src);static BOOL HasConsole(void);static TclFile MakeFile(HANDLE handle);static char * MakeTempFile(Tcl_DString *namePtr);static int PipeBlockModeProc(ClientData instanceData, int mode);static void PipeCheckProc _ANSI_ARGS_((ClientData clientData, int flags));static int PipeCloseProc(ClientData instanceData, Tcl_Interp *interp);static int PipeEventProc(Tcl_Event *evPtr, int flags);static void PipeExitHandler(ClientData clientData);static int PipeGetHandleProc(ClientData instanceData, int direction, ClientData *handlePtr);static void PipeInit(void);static int PipeInputProc(ClientData instanceData, char *buf, int toRead, int *errorCode);static int PipeOutputProc(ClientData instanceData, char *buf, int toWrite, int *errorCode);static void PipeWatchProc(ClientData instanceData, int mask);static void PipeSetupProc _ANSI_ARGS_((ClientData clientData, int flags));static int TempFileName(char name[MAX_PATH]);/* * This structure describes the channel type structure for command pipe * based IO. */static Tcl_ChannelType pipeChannelType = { "pipe", /* Type name. */ PipeBlockModeProc, /* Set blocking or non-blocking mode.*/ PipeCloseProc, /* Close proc. */ PipeInputProc, /* Input proc. */ PipeOutputProc, /* Output proc. */ NULL, /* Seek proc. */ NULL, /* Set option proc. */ NULL, /* Get option proc. */ PipeWatchProc, /* Set up notifier to watch the channel. */ PipeGetHandleProc, /* Get an OS handle from channel. */};/* *---------------------------------------------------------------------- * * PipeInit -- * * This function initializes the static variables for this file. * * Results: * None. * * Side effects: * Creates a new event source. * *---------------------------------------------------------------------- */static voidPipeInit(){ initialized = 1; firstPipePtr = NULL; procList = NULL; Tcl_CreateEventSource(PipeSetupProc, PipeCheckProc, NULL); Tcl_CreateExitHandler(PipeExitHandler, NULL);}/* *---------------------------------------------------------------------- * * PipeExitHandler -- * * This function is called to cleanup the pipe module before * Tcl is unloaded. * * Results: * None. * * Side effects: * Removes the pipe event source. * *---------------------------------------------------------------------- */static voidPipeExitHandler(clientData) ClientData clientData; /* Old window proc */{ Tcl_DeleteEventSource(PipeSetupProc, PipeCheckProc, NULL); initialized = 0;}/* *---------------------------------------------------------------------- * * PipeSetupProc -- * * This procedure is invoked before Tcl_DoOneEvent blocks waiting * for an event. * * Results: * None. * * Side effects: * Adjusts the block time if needed. * *---------------------------------------------------------------------- */voidPipeSetupProc(data, flags) ClientData data; /* Not used. */ int flags; /* Event flags as passed to Tcl_DoOneEvent. */{ PipeInfo *infoPtr; Tcl_Time blockTime = { 0, 0 }; if (!(flags & TCL_FILE_EVENTS)) { return; } /* * Check to see if there is a watched pipe. If so, poll. */ for (infoPtr = firstPipePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->watchMask) { Tcl_SetMaxBlockTime(&blockTime); break; } }}/* *---------------------------------------------------------------------- * * PipeCheckProc -- * * This procedure is called by Tcl_DoOneEvent to check the pipe * event source for events. * * Results: * None. * * Side effects: * May queue an event. * *---------------------------------------------------------------------- */static voidPipeCheckProc(data, flags) ClientData data; /* Not used. */ int flags; /* Event flags as passed to Tcl_DoOneEvent. */{ PipeInfo *infoPtr; PipeEvent *evPtr; if (!(flags & TCL_FILE_EVENTS)) { return; } /* * Queue events for any watched pipes that don't already have events * queued. */ for (infoPtr = firstPipePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->watchMask && !(infoPtr->flags & PIPE_PENDING)) { infoPtr->flags |= PIPE_PENDING; evPtr = (PipeEvent *) ckalloc(sizeof(PipeEvent)); evPtr->header.proc = PipeEventProc; evPtr->infoPtr = infoPtr; Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL); } }}/* *---------------------------------------------------------------------- * * MakeFile -- * * This function constructs a new TclFile from a given data and * type value. * * Results: * Returns a newly allocated WinFile as a TclFile. * * Side effects: * None. * *---------------------------------------------------------------------- */static TclFileMakeFile(handle) HANDLE handle; /* Type-specific data. */{ WinFile *filePtr; filePtr = (WinFile *) ckalloc(sizeof(WinFile)); filePtr->type = WIN_FILE; filePtr->handle = handle; return (TclFile)filePtr;}/* *---------------------------------------------------------------------- * * TclpMakeFile -- * * Make a TclFile from a channel. * * Results: * Returns a new TclFile or NULL on failure. * * Side effects: * None. * *---------------------------------------------------------------------- */TclFileTclpMakeFile(channel, direction) Tcl_Channel channel; /* Channel to get file from. */ int direction; /* Either TCL_READABLE or TCL_WRITABLE. */{ HANDLE handle; if (Tcl_GetChannelHandle(channel, direction, (ClientData *) &handle) == TCL_OK) { return MakeFile(handle); } else { return (TclFile) NULL; }}/* *---------------------------------------------------------------------- * * TempFileName -- * * Gets a temporary file name and deals with the fact that the * temporary file path provided by Windows may not actually exist * if the TMP or TEMP environment variables refer to a * non-existent directory. * * Results: * 0 if error, non-zero otherwise. If non-zero is returned, the * name buffer will be filled with a name that can be used to * construct a temporary file. * * Side effects: * None. * *---------------------------------------------------------------------- */static intTempFileName(name) char name[MAX_PATH]; /* Buffer in which name for temporary * file gets stored. */{ if ((GetTempPath(MAX_PATH, name) == 0) || (GetTempFileName(name, "TCL", 0, name) == 0)) { name[0] = '.'; name[1] = '\0'; if (GetTempFileName(name, "TCL", 0, name) == 0) { return 0; } } return 1;}/* *---------------------------------------------------------------------- * * TclpCreateTempFile -- * * This function opens a unique file with the property that it * will be deleted when its file handle is closed. The temporary * file is created in the system temporary directory. * * Results: * Returns a valid TclFile, or NULL on failure. * * Side effects: * Creates a new temporary file. * *---------------------------------------------------------------------- */TclFileTclpCreateTempFile(contents, namePtr) char *contents; /* String to write into temp file, or NULL. */ Tcl_DString *namePtr; /* If non-NULL, pointer to initialized * DString that is filled with the name of * the temp file that was created. */{ char name[MAX_PATH]; HANDLE handle; if (TempFileName(name) == 0) { return NULL; } handle = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE, NULL); if (handle == INVALID_HANDLE_VALUE) { goto error; } /* * Write the file out, doing line translations on the way.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -