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_SetObjResult(interp, Tcl_ObjPrintf("pipe creation failed: %s", Tcl_PosixError(interp))); 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; }
/*! Sets the Tcl stderr and stdout channels to be the same as the C stderr and stdout streams. \author jfpatry */ void setup_tcl_std_channels() { /* Only need to do this under Win32 */ #if defined( NATIVE_WIN32_COMPILER ) Tcl_Channel stdout_chnl, stderr_chnl; /* I'm not sure why the _dup is necessary under Windows. See the Tcl_SetStdChannel manpage for more info. */ /* Create new stdout channel */ Tcl_SetStdChannel( NULL, TCL_STDOUT ); stdout_chnl = Tcl_MakeFileChannel( (ClientData) _get_osfhandle( _dup( _fileno(stdout) ) ), TCL_WRITABLE ); check_assertion( stdout_chnl, "Couldn't create new stdout channel" ); /* Create a new stderr channel */ Tcl_SetStdChannel( NULL, TCL_STDERR ); stderr_chnl = Tcl_MakeFileChannel( (ClientData) _get_osfhandle( _dup( _fileno(stderr) ) ), TCL_WRITABLE ); check_assertion( stderr_chnl, "Couldn't create new stderr channel" ); #endif }
RtclSignalAction::RtclSignalAction(Tcl_Interp* interp) : fpInterp(interp), fFdPipeRead(-1), fFdPipeWrite(-1), fShuttleChn(), fActionSet(), fpScript(), fOldAction() { for (size_t i=0; i<32; i++) { fActionSet[i] = false; ::memset(&fOldAction[i], 0, sizeof(fOldAction[0])); } int pipefd[2]; if (::pipe(pipefd) < 0) throw Rexception("RtclSignalAction::<ctor>", "pipe() failed: ", errno); fFdPipeRead = pipefd[0]; fFdPipeWrite = pipefd[1]; fShuttleChn = Tcl_MakeFileChannel((ClientData)fFdPipeRead, TCL_READABLE); Tcl_SetChannelOption(NULL, fShuttleChn, "-buffersize", "64"); Tcl_SetChannelOption(NULL, fShuttleChn, "-encoding", "binary"); Tcl_SetChannelOption(NULL, fShuttleChn, "-translation", "binary"); Tcl_CreateChannelHandler(fShuttleChn, TCL_READABLE, (Tcl_FileProc*) ThunkTclChannelHandler, (ClientData) this); }
static Tcl_Channel tcl_channel(value fd, int flags) { HANDLE h = Handle_val(fd); int optval, optsize; optsize = sizeof(optval); if (getsockopt((SOCKET) h, SOL_SOCKET, SO_TYPE, (char *)&optval, &optsize) == 0) return Tcl_MakeTcpClientChannel((ClientData) h); else return Tcl_MakeFileChannel((ClientData) h, flags); }
/* *---------------------------------------------------------------------- * * Tcl_CreatePipe -- * * System dependent interface to create a pipe for the [chan pipe] * command. Stolen from TclX. * * Parameters: * o interp - Errors returned in result. * o rchan, wchan - Returned read and write side. * o flags - Reserved for future use. * Results: * TCL_OK or TCL_ERROR. * *---------------------------------------------------------------------- */ int Tcl_CreatePipe( Tcl_Interp *interp, Tcl_Channel *rchan, Tcl_Channel *wchan, int flags) { int fileNums[2]; if (pipe(fileNums) < 0) { Tcl_AppendResult(interp, "pipe creation failed: ", Tcl_PosixError(interp), NULL); return TCL_ERROR; } *rchan = Tcl_MakeFileChannel((ClientData) INT2PTR(fileNums[0]), TCL_READABLE); Tcl_RegisterChannel(interp, *rchan); *wchan = Tcl_MakeFileChannel((ClientData) INT2PTR(fileNums[1]), TCL_WRITABLE); Tcl_RegisterChannel(interp, *wchan); return TCL_OK; }
/* ARGSUSED */ static int PipeCloseProc( ClientData instanceData, /* The pipe to close. */ Tcl_Interp *interp) /* For error reporting. */ { PipeState *pipePtr; Tcl_Channel errChan; int errorCode, result; errorCode = 0; result = 0; pipePtr = (PipeState *) instanceData; if (pipePtr->inFile) { if (TclpCloseFile(pipePtr->inFile) < 0) { errorCode = errno; } } if (pipePtr->outFile) { if ((TclpCloseFile(pipePtr->outFile) < 0) && (errorCode == 0)) { errorCode = errno; } } if (pipePtr->isNonBlocking || TclInExit()) { /* * If the channel is non-blocking or Tcl is being cleaned up, just * detach the children PIDs, reap them (important if we are in a * dynamic load module), and discard the errorFile. */ Tcl_DetachPids(pipePtr->numPids, pipePtr->pidPtr); Tcl_ReapDetachedProcs(); if (pipePtr->errorFile) { TclpCloseFile(pipePtr->errorFile); } } else { /* * Wrap the error file into a channel and give it to the cleanup * routine. */ if (pipePtr->errorFile) { errChan = Tcl_MakeFileChannel( (ClientData) INT2PTR(GetFd(pipePtr->errorFile)), TCL_READABLE); } else { errChan = NULL; } result = TclCleanupChildren(interp, pipePtr->numPids, pipePtr->pidPtr, errChan); } if (pipePtr->numPids != 0) { ckfree((char *) pipePtr->pidPtr); } ckfree((char *) pipePtr); if (errorCode == 0) { return result; } return errorCode; }
static int PipeClose2Proc( ClientData instanceData, /* The pipe to close. */ Tcl_Interp *interp, /* For error reporting. */ int flags) /* Flags that indicate which side to close. */ { PipeState *pipePtr = instanceData; Tcl_Channel errChan; int errorCode, result; errorCode = 0; result = 0; if (((!flags) || (flags & TCL_CLOSE_READ)) && (pipePtr->inFile != NULL)) { if (TclpCloseFile(pipePtr->inFile) < 0) { errorCode = errno; } else { pipePtr->inFile = NULL; } } 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()) { /* * If the channel is non-blocking or Tcl is being cleaned up, just * detach the children PIDs, reap them (important if we are in a * dynamic load module), and discard the errorFile. */ Tcl_DetachPids(pipePtr->numPids, pipePtr->pidPtr); Tcl_ReapDetachedProcs(); if (pipePtr->errorFile) { TclpCloseFile(pipePtr->errorFile); } } else { /* * Wrap the error file into a channel and give it to the cleanup * routine. */ if (pipePtr->errorFile) { errChan = Tcl_MakeFileChannel( INT2PTR(GetFd(pipePtr->errorFile)), TCL_READABLE); } else { errChan = NULL; } result = TclCleanupChildren(interp, pipePtr->numPids, pipePtr->pidPtr, errChan); } if (pipePtr->numPids != 0) { ckfree(pipePtr->pidPtr); } ckfree(pipePtr); if (errorCode == 0) { return result; } return errorCode; }
Tcl_Channel TclpGetDefaultStdChannel( int type) /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */ { Tcl_Channel channel = NULL; int fd = 0; /* Initializations needed to prevent */ int mode = 0; /* compiler warning (used before set). */ const char *bufMode = NULL; /* * Some #def's to make the code a little clearer! */ #define ZERO_OFFSET ((Tcl_SeekOffset) 0) #define ERROR_OFFSET ((Tcl_SeekOffset) -1) switch (type) { case TCL_STDIN: if ((TclOSseek(0, ZERO_OFFSET, SEEK_CUR) == ERROR_OFFSET) && (errno == EBADF)) { return NULL; } fd = 0; mode = TCL_READABLE; bufMode = "line"; break; case TCL_STDOUT: if ((TclOSseek(1, ZERO_OFFSET, SEEK_CUR) == ERROR_OFFSET) && (errno == EBADF)) { return NULL; } fd = 1; mode = TCL_WRITABLE; bufMode = "line"; break; case TCL_STDERR: if ((TclOSseek(2, ZERO_OFFSET, SEEK_CUR) == ERROR_OFFSET) && (errno == EBADF)) { return NULL; } fd = 2; mode = TCL_WRITABLE; bufMode = "none"; break; default: Tcl_Panic("TclGetDefaultStdChannel: Unexpected channel type"); break; } #undef ZERO_OFFSET #undef ERROR_OFFSET channel = Tcl_MakeFileChannel(INT2PTR(fd), mode); if (channel == NULL) { return NULL; } /* * Set up the normal channel options for stdio handles. */ if (Tcl_GetChannelType(channel) == &fileChannelType) { Tcl_SetChannelOption(NULL, channel, "-translation", "auto"); } else { Tcl_SetChannelOption(NULL, channel, "-translation", "auto crlf"); } Tcl_SetChannelOption(NULL, channel, "-buffering", bufMode); return channel; }
TclTextInterp::TclTextInterp(VMDApp *vmdapp, int guienabled, int mpienabled) : app(vmdapp) { interp = Tcl_CreateInterp(); #if 0 Tcl_InitMemory(interp); // enable Tcl memory debugging features // when compiled with TCL_MEM_DEBUG #endif commandPtr = Tcl_NewObj(); Tcl_IncrRefCount(commandPtr); consoleisatty = vmd_isatty(0); // whether we're interactive or not ignorestdin = 0; gotPartial = 0; needPrompt = 1; callLevel = 0; starttime = delay = 0; #if defined(VMDMPI) // // MPI builds of VMD cannot try to read any command input from the // console because it creates shutdown problems, at least with MPICH. // File-based command input is fine however. // // don't check for interactive console input if running in parallel if (mpienabled) ignorestdin = 1; #endif #if defined(ANDROIDARMV7A) // // For the time being, the Android builds won't attempt to get any // console input. Any input we're going to get is going to come via // some means other than stdin, such as a network socket, text box, etc. // // Don't check for interactive console input if compiled for Android ignorestdin = 1; #endif // set tcl_interactive, lets us run unix commands as from a shell #if !defined(VMD_NANOHUB) Tcl_SetVar(interp, "tcl_interactive", "1", 0); #else Tcl_SetVar(interp, "tcl_interactive", "0", 0); Tcl_Channel channel; #define CLIENT_READ (3) #define CLIENT_WRITE (4) channel = Tcl_MakeFileChannel((ClientData)CLIENT_READ, TCL_READABLE); if (channel != NULL) { const char *result; Tcl_RegisterChannel(interp, channel); result = Tcl_SetVar2(interp, "vmd_client", "read", Tcl_GetChannelName(channel), TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG); if (result == NULL) { fprintf(stderr, "can't create variable for client read channel\n"); } } channel = Tcl_MakeFileChannel((ClientData)CLIENT_WRITE, TCL_WRITABLE); if (channel != NULL) { const char *result; Tcl_RegisterChannel(interp, channel); result = Tcl_SetVar2(interp, "vmd_client", "write", Tcl_GetChannelName(channel), TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG); if (result == NULL) { fprintf(stderr, "can't create variable for client write channel\n"); } } write(CLIENT_WRITE, "vmd 1.0\n", 8); #endif // pass our instance of VMDApp to a hash table assoc. with the interpreter Tcl_SetAssocData(interp, "VMDApp", NULL, app); // Set up argc, argv0, and argv variables { char argcbuf[20]; sprintf(argcbuf, "%d", app->argc_m); Tcl_SetVar(interp, "argc", argcbuf, TCL_GLOBAL_ONLY); // it might be better to use the same thing that was passed to // Tcl_FindExecutable, but this is now Tcl_SetVar(interp, "argv0", app->argv_m[0], TCL_GLOBAL_ONLY); char *args = Tcl_Merge(app->argc_m-1, app->argv_m+1); Tcl_SetVar(interp, "argv", args, TCL_GLOBAL_ONLY); Tcl_Free(args); } #if defined(_MSC_VER) && TCL_MINOR_VERSION >= 4 // The Windows versions of Tcl 8.5.x have trouble finding // the Tcl library subdirectory for unknown reasons. // We force the appropriate env variables to be set in Tcl, // despite Windows. { char vmdinitscript[4096]; char * tcl_library = getenv("TCL_LIBRARY"); char * tk_library = getenv("TK_LIBRARY"); if (tcl_library) { sprintf(vmdinitscript, "set env(TCL_LIBRARY) {%s}", tcl_library); if (Tcl_Eval(interp, vmdinitscript) != TCL_OK) { msgErr << Tcl_GetStringResult(interp) << sendmsg; } } if (tk_library) { sprintf(vmdinitscript, "set env(TK_LIBRARY) {%s}", tk_library); if (Tcl_Eval(interp, vmdinitscript) != TCL_OK) { msgErr << Tcl_GetStringResult(interp) << sendmsg; } } } #endif if (Tcl_Init(interp) == TCL_ERROR) { // new with 7.6 msgErr << "Tcl startup error: " << Tcl_GetStringResult(interp) << sendmsg; } #ifdef VMDTK // and the Tk commands (but only if a GUI is available!) if (guienabled) { if (Tk_Init(interp) == TCL_ERROR) { msgErr << "Tk startup error: " << Tcl_GetStringResult(interp) << sendmsg; } else { Tcl_StaticPackage(interp, "Tk", (Tcl_PackageInitProc *) Tk_Init, (Tcl_PackageInitProc *) NULL); } } // end of check that GUI is allowed #endif add_commands(); }
int _ged_run_rtwizard(struct ged *gedp) { int i; FILE *fp_in; #ifndef _WIN32 int pipe_in[2]; int pipe_err[2]; #else HANDLE pipe_in[2], pipe_inDup; HANDLE pipe_err[2], pipe_errDup; STARTUPINFO si = {0}; PROCESS_INFORMATION pi = {0}; SECURITY_ATTRIBUTES sa = {0}; struct bu_vls line = BU_VLS_INIT_ZERO; #endif struct ged_run_rt *run_rtp; struct _ged_rt_client_data *drcdp; #ifndef _WIN32 int pid; int ret; ret = pipe(pipe_in); if (ret < 0) perror("pipe"); ret = pipe(pipe_err); if (ret < 0) perror("pipe"); if ((pid = fork()) == 0) { /* make this a process group leader */ setpgid(0, 0); /* Redirect stdin and stderr */ (void)close(0); ret = dup(pipe_in[0]); if (ret < 0) perror("dup"); (void)close(2); ret = dup(pipe_err[1]); if (ret < 0) perror("dup"); /* close pipes */ (void)close(pipe_in[0]); (void)close(pipe_in[1]); (void)close(pipe_err[0]); (void)close(pipe_err[1]); for (i = 3; i < 20; i++) (void)close(i); (void)execvp(gedp->ged_gdp->gd_rt_cmd[0], gedp->ged_gdp->gd_rt_cmd); perror(gedp->ged_gdp->gd_rt_cmd[0]); exit(16); } /* As parent, send view information down pipe */ (void)close(pipe_in[0]); fp_in = fdopen(pipe_in[1], "w"); (void)close(pipe_err[1]); (void)fclose(fp_in); /* must be BU_GET() to match release in _ged_rt_output_handler */ BU_GET(run_rtp, struct ged_run_rt); BU_LIST_INIT(&run_rtp->l); BU_LIST_APPEND(&gedp->ged_gdp->gd_headRunRt.l, &run_rtp->l); run_rtp->fd = pipe_err[0]; run_rtp->pid = pid; /* must be BU_GET() to match release in _ged_rt_output_handler */ BU_GET(drcdp, struct _ged_rt_client_data); drcdp->gedp = gedp; drcdp->rrtp = run_rtp; Tcl_CreateFileHandler(run_rtp->fd, TCL_READABLE, _ged_rt_output_handler, (ClientData)drcdp); return 0; #else sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; /* Create a pipe for the child process's STDOUT. */ CreatePipe(&pipe_err[0], &pipe_err[1], &sa, 0); /* Create noninheritable read handle and close the inheritable read handle. */ DuplicateHandle(GetCurrentProcess(), pipe_err[0], GetCurrentProcess(), &pipe_errDup , 0, FALSE, DUPLICATE_SAME_ACCESS); CloseHandle(pipe_err[0]); /* Create a pipe for the child process's STDIN. */ CreatePipe(&pipe_in[0], &pipe_in[1], &sa, 0); /* Duplicate the write handle to the pipe so it is not inherited. */ DuplicateHandle(GetCurrentProcess(), pipe_in[1], GetCurrentProcess(), &pipe_inDup, 0, FALSE, /* not inherited */ DUPLICATE_SAME_ACCESS); CloseHandle(pipe_in[1]); si.cb = sizeof(STARTUPINFO); si.lpReserved = NULL; si.lpReserved2 = NULL; si.cbReserved2 = 0; si.lpDesktop = NULL; si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = pipe_in[0]; si.hStdOutput = pipe_err[1]; si.hStdError = pipe_err[1]; for (i = 0; i < gedp->ged_gdp->gd_rt_cmd_len; i++) { bu_vls_printf(&line, "\"%s\" ", gedp->ged_gdp->gd_rt_cmd[i]); } CreateProcess(NULL, bu_vls_addr(&line), NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &si, &pi); bu_vls_free(&line); CloseHandle(pipe_in[0]); CloseHandle(pipe_err[1]); /* As parent, send view information down pipe */ fp_in = _fdopen(_open_osfhandle((intptr_t)pipe_inDup, _O_TEXT), "wb"); (void)fclose(fp_in); /* must be BU_GET() to match release in _ged_rt_output_handler */ BU_GET(run_rtp, struct ged_run_rt); BU_LIST_INIT(&run_rtp->l); BU_LIST_APPEND(&gedp->ged_gdp->gd_headRunRt.l, &run_rtp->l); run_rtp->fd = pipe_errDup; run_rtp->hProcess = pi.hProcess; run_rtp->pid = pi.dwProcessId; run_rtp->aborted=0; run_rtp->chan = Tcl_MakeFileChannel(run_rtp->fd, TCL_READABLE); /* must be BU_GET() to match release in _ged_rt_output_handler */ BU_GET(drcdp, struct _ged_rt_client_data); drcdp->gedp = gedp; drcdp->rrtp = run_rtp; Tcl_CreateChannelHandler(run_rtp->chan, TCL_READABLE, _ged_rt_output_handler, (ClientData)drcdp); return 0; #endif }