diff options
Diffstat (limited to 'unix/tclUnixPipe.c')
-rw-r--r-- | unix/tclUnixPipe.c | 195 |
1 files changed, 138 insertions, 57 deletions
diff --git a/unix/tclUnixPipe.c b/unix/tclUnixPipe.c index eb3a218..30a6da8 100644 --- a/unix/tclUnixPipe.c +++ b/unix/tclUnixPipe.c @@ -49,8 +49,8 @@ typedef struct PipeState { */ static int PipeBlockModeProc(ClientData instanceData, int mode); -static int PipeCloseProc(ClientData instanceData, - Tcl_Interp *interp); +static int PipeClose2Proc(ClientData instanceData, + Tcl_Interp *interp, int flags); static int PipeGetHandleProc(ClientData instanceData, int direction, ClientData *handlePtr); static int PipeInputProc(ClientData instanceData, char *buf, @@ -66,10 +66,10 @@ static int SetupStdFile(TclFile file, int type); * I/O: */ -static Tcl_ChannelType pipeChannelType = { +static const Tcl_ChannelType pipeChannelType = { "pipe", /* Type name. */ TCL_CHANNEL_VERSION_5, /* v5 channel */ - PipeCloseProc, /* Close proc. */ + TCL_CLOSE2PROC, /* Close proc. */ PipeInputProc, /* Input proc. */ PipeOutputProc, /* Output proc. */ NULL, /* Seek proc. */ @@ -77,7 +77,7 @@ static Tcl_ChannelType pipeChannelType = { NULL, /* Get option proc. */ PipeWatchProc, /* Initialize notifier. */ PipeGetHandleProc, /* Get OS handles out of channel. */ - NULL, /* close2proc. */ + PipeClose2Proc, /* close2proc. */ PipeBlockModeProc, /* Set blocking or non-blocking mode.*/ NULL, /* flush proc. */ NULL, /* handler proc. */ @@ -109,12 +109,11 @@ TclpMakeFile( { ClientData data; - if (Tcl_GetChannelHandle(channel, direction, - (ClientData *) &data) == TCL_OK) { - return MakeFile(PTR2INT(data)); - } else { - return (TclFile) NULL; + if (Tcl_GetChannelHandle(channel, direction, &data) != TCL_OK) { + return NULL; } + + return MakeFile(PTR2INT(data)); } /* @@ -262,12 +261,46 @@ TclpTempFileName(void) fcntl(fd, F_SETFD, FD_CLOEXEC); unlink(fileName); /* INTL: Native. */ - result = TclpNativeToNormalized((ClientData) fileName); + result = TclpNativeToNormalized(fileName); close(fd); return result; } /* + *----------------------------------------------------------------------------- + * + * TclpTempFileNameForLibrary -- + * + * Constructs a file name in the native file system where a + * dynamically loaded library may be placed. + * + * Results: + * Returns the constructed file name. If an error occurs, + * returns NULL and leaves an error message in the interpreter + * result. + * + * On Unix, it works to load a shared object from a file of any + * name, so this function is merely a thin wrapper around + * TclpTempFileName(). + * + *----------------------------------------------------------------------------- + */ + +Tcl_Obj* +TclpTempFileNameForLibrary(Tcl_Interp* interp, /* Tcl interpreter */ + Tcl_Obj* path) /* Path name of the library + * in the VFS */ +{ + Tcl_Obj* retval; + retval = TclpTempFileName(); + if (retval == NULL) { + Tcl_AppendResult(interp, "couldn't create temporary file: ", + Tcl_PosixError(interp), NULL); + } + return retval; +} + +/* *---------------------------------------------------------------------- * * TclpCreatePipe -- @@ -419,9 +452,8 @@ TclpCreateProcess( * deallocated later */ - dsArray = (Tcl_DString *) - TclStackAlloc(interp, argc * sizeof(Tcl_DString)); - newArgv = (char **) TclStackAlloc(interp, (argc+1) * sizeof(char *)); + dsArray = TclStackAlloc(interp, argc * sizeof(Tcl_DString)); + newArgv = TclStackAlloc(interp, (argc+1) * sizeof(char *)); newArgv[argc] = NULL; for (i = 0; i < argc; i++) { newArgv[i] = Tcl_UtfToExternalDString(NULL, argv[i], -1, &dsArray[i]); @@ -769,13 +801,56 @@ TclpCreateCommandChannel( sprintf(channelName, "file%d", channelId); statePtr->channel = Tcl_CreateChannel(&pipeChannelType, channelName, - (ClientData) statePtr, mode); + statePtr, mode); return statePtr->channel; } /* *---------------------------------------------------------------------- * + * Tcl_CreatePipe -- + * + * System dependent interface to create a pipe for the [chan pipe] + * command. Stolen from TclX. + * + * Results: + * TCL_OK or TCL_ERROR. + * + * Side effects: + * Registers two channels. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_CreatePipe( + Tcl_Interp *interp, /* Errors returned in result. */ + Tcl_Channel *rchan, /* Returned read side. */ + Tcl_Channel *wchan, /* Returned write side. */ + int flags) /* Reserved for future use. */ +{ + int fileNums[2]; + + if (pipe(fileNums) < 0) { + Tcl_AppendResult(interp, "pipe creation failed: ", + Tcl_PosixError(interp), NULL); + return TCL_ERROR; + } + + fcntl(fileNums[0], F_SETFD, FD_CLOEXEC); + fcntl(fileNums[1], F_SETFD, FD_CLOEXEC); + + *rchan = Tcl_MakeFileChannel(INT2PTR(fileNums[0]), TCL_READABLE); + Tcl_RegisterChannel(interp, *rchan); + *wchan = Tcl_MakeFileChannel(INT2PTR(fileNums[1]), TCL_WRITABLE); + Tcl_RegisterChannel(interp, *wchan); + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * * TclGetAndDetachPids -- * * This function is invoked in the generic implementation of a @@ -850,15 +925,13 @@ PipeBlockModeProc( { PipeState *psPtr = instanceData; - if (psPtr->inFile) { - if (TclUnixSetBlockingMode(GetFd(psPtr->inFile), mode) < 0) { - return errno; - } + if (psPtr->inFile + && TclUnixSetBlockingMode(GetFd(psPtr->inFile), mode) < 0) { + return errno; } - if (psPtr->outFile) { - if (TclUnixSetBlockingMode(GetFd(psPtr->outFile), mode) < 0) { - return errno; - } + if (psPtr->outFile + && TclUnixSetBlockingMode(GetFd(psPtr->outFile), mode) < 0) { + return errno; } psPtr->isNonBlocking = (mode == TCL_MODE_NONBLOCKING); @@ -869,11 +942,10 @@ PipeBlockModeProc( /* *---------------------------------------------------------------------- * - * PipeCloseProc -- + * PipeClose2Proc * * This function is invoked by the generic IO level to perform - * channel-type-specific cleanup when a command pipeline channel is - * closed. + * pipeline-type-specific half or full-close. * * Results: * 0 on success, errno otherwise. @@ -884,29 +956,42 @@ PipeBlockModeProc( *---------------------------------------------------------------------- */ - /* ARGSUSED */ static int -PipeCloseProc( +PipeClose2Proc( ClientData instanceData, /* The pipe to close. */ - Tcl_Interp *interp) /* For error reporting. */ + Tcl_Interp *interp, /* For error reporting. */ + int flags) /* Flags that indicate which side to close. */ { - PipeState *pipePtr; + PipeState *pipePtr = instanceData; Tcl_Channel errChan; int errorCode, result; errorCode = 0; result = 0; - pipePtr = (PipeState *) instanceData; - if (pipePtr->inFile) { + + if (((!flags) || (flags & TCL_CLOSE_READ)) && (pipePtr->inFile != NULL)) { if (TclpCloseFile(pipePtr->inFile) < 0) { errorCode = errno; + } else { + pipePtr->inFile = NULL; } } - if (pipePtr->outFile) { - if ((TclpCloseFile(pipePtr->outFile) < 0) && (errorCode == 0)) { + if (((!flags) || (flags & TCL_CLOSE_WRITE)) && (pipePtr->outFile != NULL) + && (errorCode == 0)) { + if (TclpCloseFile(pipePtr->outFile) < 0) { errorCode = errno; + } else { + pipePtr->outFile = NULL; } } + + /* + * If half-closing, stop here. + */ + + if (flags) { + return errorCode; + } if (pipePtr->isNonBlocking || TclInExit()) { /* @@ -929,7 +1014,8 @@ PipeCloseProc( if (pipePtr->errorFile) { errChan = Tcl_MakeFileChannel( - (ClientData) INT2PTR(GetFd(pipePtr->errorFile)), TCL_READABLE); + INT2PTR(GetFd(pipePtr->errorFile)), + TCL_READABLE); } else { errChan = NULL; } @@ -973,7 +1059,7 @@ PipeInputProc( * buffer? */ int *errorCodePtr) /* Where to store error code. */ { - PipeState *psPtr = (PipeState *) instanceData; + PipeState *psPtr = instanceData; int bytesRead; /* How many bytes were actually read from the * input device? */ @@ -994,9 +1080,8 @@ PipeInputProc( if (bytesRead < 0) { *errorCodePtr = errno; return -1; - } else { - return bytesRead; } + return bytesRead; } /* @@ -1024,7 +1109,7 @@ PipeOutputProc( int toWrite, /* How many bytes to write? */ int *errorCodePtr) /* Where to store error code. */ { - PipeState *psPtr = (PipeState *) instanceData; + PipeState *psPtr = instanceData; int written; *errorCodePtr = 0; @@ -1041,9 +1126,8 @@ PipeOutputProc( if (written < 0) { *errorCodePtr = errno; return -1; - } else { - return written; } + return written; } /* @@ -1070,15 +1154,14 @@ PipeWatchProc( * TCL_READABLE, TCL_WRITABLE and * TCL_EXCEPTION. */ { - PipeState *psPtr = (PipeState *) instanceData; + PipeState *psPtr = instanceData; int newmask; if (psPtr->inFile) { newmask = mask & (TCL_READABLE | TCL_EXCEPTION); if (newmask) { Tcl_CreateFileHandler(GetFd(psPtr->inFile), mask, - (Tcl_FileProc *) Tcl_NotifyChannel, - (ClientData) psPtr->channel); + (Tcl_FileProc *) Tcl_NotifyChannel, psPtr->channel); } else { Tcl_DeleteFileHandler(GetFd(psPtr->inFile)); } @@ -1087,8 +1170,7 @@ PipeWatchProc( newmask = mask & (TCL_WRITABLE | TCL_EXCEPTION); if (newmask) { Tcl_CreateFileHandler(GetFd(psPtr->outFile), mask, - (Tcl_FileProc *) Tcl_NotifyChannel, - (ClientData) psPtr->channel); + (Tcl_FileProc *) Tcl_NotifyChannel, psPtr->channel); } else { Tcl_DeleteFileHandler(GetFd(psPtr->outFile)); } @@ -1119,14 +1201,14 @@ PipeGetHandleProc( int direction, /* TCL_READABLE or TCL_WRITABLE */ ClientData *handlePtr) /* Where to store the handle. */ { - PipeState *psPtr = (PipeState *) instanceData; + PipeState *psPtr = instanceData; if (direction == TCL_READABLE && psPtr->inFile) { - *handlePtr = (ClientData) INT2PTR(GetFd(psPtr->inFile)); + *handlePtr = INT2PTR(GetFd(psPtr->inFile)); return TCL_OK; } if (direction == TCL_WRITABLE && psPtr->outFile) { - *handlePtr = (ClientData) INT2PTR(GetFd(psPtr->outFile)); + *handlePtr = INT2PTR(GetFd(psPtr->outFile)); return TCL_OK; } return TCL_ERROR; @@ -1190,6 +1272,11 @@ Tcl_PidObjCmd( int objc, /* Number of arguments. */ Tcl_Obj *const *objv) /* Argument strings. */ { + Tcl_Channel chan; + PipeState *pipePtr; + int i; + Tcl_Obj *resultPtr, *longObjPtr; + if (objc > 2) { Tcl_WrongNumArgs(interp, 1, objv, "?channelId?"); return TCL_ERROR; @@ -1201,18 +1288,12 @@ Tcl_PidObjCmd( /* * Get the channel and make sure that it refers to a pipe. */ - Tcl_Channel chan; - const Tcl_ChannelType *chanTypePtr; - PipeState *pipePtr; - int i; - Tcl_Obj *resultPtr, *longObjPtr; chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL); - if (chan == (Tcl_Channel) NULL) { + if (chan == NULL) { return TCL_ERROR; } - chanTypePtr = Tcl_GetChannelType(chan); - if (chanTypePtr != &pipeChannelType) { + if (Tcl_GetChannelType(chan) != &pipeChannelType) { return TCL_OK; } |