tclpipe.c

来自「tcl是工具命令语言」· C语言 代码 · 共 1,071 行 · 第 1/3 页

C
1,071
字号
	    if (TclpCreatePipe(&inputFile, inPipePtr) == 0) {		Tcl_AppendResult(interp, 			"couldn't create input pipe for command: ",			Tcl_PosixError(interp), (char *) NULL);		goto error;	    }	    inputClose = 1;	} else {	    /*	     * The input for the first process comes from stdin.	     */	    channel = Tcl_GetStdChannel(TCL_STDIN);	    if (channel != NULL) {		inputFile = TclpMakeFile(channel, TCL_READABLE);		if (inputFile != NULL) {		    inputRelease = 1;		}	    }	}    }    if (outputFile == NULL) {	if (outPipePtr != NULL) {	    /*	     * Output from the last process in the pipeline is to go to a	     * pipe that can be read by the caller.	     */	    if (TclpCreatePipe(outPipePtr, &outputFile) == 0) {		Tcl_AppendResult(interp, 			"couldn't create output pipe for command: ",			Tcl_PosixError(interp), (char *) NULL);		goto error;	    }	    outputClose = 1;	} else {	    /*	     * The output for the last process goes to stdout.	     */	    channel = Tcl_GetStdChannel(TCL_STDOUT);	    if (channel) {		outputFile = TclpMakeFile(channel, TCL_WRITABLE);		if (outputFile != NULL) {		    outputRelease = 1;		}	    }	}    }    if (errorFile == NULL) {	if (errFilePtr != NULL) {	    /*	     * Set up the standard error output sink for the pipeline, if	     * requested.  Use a temporary file which is opened, then deleted.	     * Could potentially just use pipe, but if it filled up it could	     * cause the pipeline to deadlock:  we'd be waiting for processes	     * to complete before reading stderr, and processes couldn't 	     * complete because stderr was backed up.	     */	    errorFile = TclpCreateTempFile(NULL);	    if (errorFile == NULL) {		Tcl_AppendResult(interp,			"couldn't create error file for command: ",			Tcl_PosixError(interp), (char *) NULL);		goto error;	    }	    *errFilePtr = errorFile;	} else {	    /*	     * Errors from the pipeline go to stderr.	     */	    channel = Tcl_GetStdChannel(TCL_STDERR);	    if (channel) {		errorFile = TclpMakeFile(channel, TCL_WRITABLE);		if (errorFile != NULL) {		    errorRelease = 1;		}	    }	}    }	    /*     * Scan through the argc array, creating a process for each     * group of arguments between the "|" characters.     */    Tcl_ReapDetachedProcs();    pidPtr = (Tcl_Pid *) ckalloc((unsigned) (cmdCount * sizeof(Tcl_Pid)));    curInFile = inputFile;    for (i = 0; i < argc; i = lastArg + 1) { 	int result, joinThisError;	Tcl_Pid pid;	CONST char *oldName;	/*	 * Convert the program name into native form. 	 */	if (Tcl_TranslateFileName(interp, argv[i], &execBuffer) == NULL) {	    goto error;	}	/*	 * Find the end of the current segment of the pipeline.	 */	joinThisError = 0;	for (lastArg = i; lastArg < argc; lastArg++) {	    if (argv[lastArg][0] == '|') { 		if (argv[lastArg][1] == '\0') { 		    break;		}		if ((argv[lastArg][1] == '&') && (argv[lastArg][2] == '\0')) {		    joinThisError = 1;		    break;		}	    }	}	argv[lastArg] = NULL;	/*	 * If this is the last segment, use the specified outputFile.	 * Otherwise create an intermediate pipe.  pipeIn will become the	 * curInFile for the next segment of the pipe.	 */	if (lastArg == argc) { 	    curOutFile = outputFile;	} else {	    if (TclpCreatePipe(&pipeIn, &curOutFile) == 0) {		Tcl_AppendResult(interp, "couldn't create pipe: ",			Tcl_PosixError(interp), (char *) NULL);		goto error;	    }	}	if (joinThisError != 0) {	    curErrFile = curOutFile;	} else {	    curErrFile = errorFile;	}	/*	 * Restore argv[i], since a caller wouldn't expect the contents of	 * argv to be modified.	 */	 	oldName = argv[i];	argv[i] = Tcl_DStringValue(&execBuffer);	result = TclpCreateProcess(interp, lastArg - i, argv + i,		curInFile, curOutFile, curErrFile, &pid);	argv[i] = oldName;	if (result != TCL_OK) {	    goto error;	}	Tcl_DStringFree(&execBuffer);	pidPtr[numPids] = pid;	numPids++;	/*	 * Close off our copies of file descriptors that were set up for	 * this child, then set up the input for the next child.	 */	if ((curInFile != NULL) && (curInFile != inputFile)) {	    TclpCloseFile(curInFile);	}	curInFile = pipeIn;	pipeIn = NULL;	if ((curOutFile != NULL) && (curOutFile != outputFile)) {	    TclpCloseFile(curOutFile);	}	curOutFile = NULL;    }    *pidArrayPtr = pidPtr;    /*     * All done.  Cleanup open files lying around and then return.     */cleanup:    Tcl_DStringFree(&execBuffer);    if (inputClose) {	TclpCloseFile(inputFile);    } else if (inputRelease) {	TclpReleaseFile(inputFile);    }    if (outputClose) {	TclpCloseFile(outputFile);    } else if (outputRelease) {	TclpReleaseFile(outputFile);    }    if (errorClose) {	TclpCloseFile(errorFile);    } else if (errorRelease) {	TclpReleaseFile(errorFile);    }    return numPids;    /*     * An error occurred.  There could have been extra files open, such     * as pipes between children.  Clean them all up.  Detach any child     * processes that have been created.     */error:    if (pipeIn != NULL) {	TclpCloseFile(pipeIn);    }    if ((curOutFile != NULL) && (curOutFile != outputFile)) {	TclpCloseFile(curOutFile);    }    if ((curInFile != NULL) && (curInFile != inputFile)) {	TclpCloseFile(curInFile);    }    if ((inPipePtr != NULL) && (*inPipePtr != NULL)) {	TclpCloseFile(*inPipePtr);	*inPipePtr = NULL;    }    if ((outPipePtr != NULL) && (*outPipePtr != NULL)) {	TclpCloseFile(*outPipePtr);	*outPipePtr = NULL;    }    if ((errFilePtr != NULL) && (*errFilePtr != NULL)) {	TclpCloseFile(*errFilePtr);	*errFilePtr = NULL;    }    if (pidPtr != NULL) {	for (i = 0; i < numPids; i++) {	    if (pidPtr[i] != (Tcl_Pid) -1) {		Tcl_DetachPids(1, &pidPtr[i]);	    }	}	ckfree((char *) pidPtr);    }    numPids = -1;    goto cleanup;}/* *---------------------------------------------------------------------- * * Tcl_OpenCommandChannel -- * *	Opens an I/O channel to one or more subprocesses specified *	by argc and argv.  The flags argument determines the *	disposition of the stdio handles.  If the TCL_STDIN flag is *	set then the standard input for the first subprocess will *	be tied to the channel:  writing to the channel will provide *	input to the subprocess.  If TCL_STDIN is not set, then *	standard input for the first subprocess will be the same as *	this application's standard input.  If TCL_STDOUT is set then *	standard output from the last subprocess can be read from the *	channel;  otherwise it goes to this application's standard *	output.  If TCL_STDERR is set, standard error output for all *	subprocesses is returned to the channel and results in an error *	when the channel is closed;  otherwise it goes to this *	application's standard error.  If TCL_ENFORCE_MODE is not set, *	then argc and argv can redirect the stdio handles to override *	TCL_STDIN, TCL_STDOUT, and TCL_STDERR;  if it is set, then it  *	is an error for argc and argv to override stdio channels for *	which TCL_STDIN, TCL_STDOUT, and TCL_STDERR have been set. * * Results: *	A new command channel, or NULL on failure with an error *	message left in interp. * * Side effects: *	Creates processes, opens pipes. * *---------------------------------------------------------------------- */Tcl_ChannelTcl_OpenCommandChannel(interp, argc, argv, flags)    Tcl_Interp *interp;		/* Interpreter for error reporting. Can                                 * NOT be NULL. */    int argc;			/* How many arguments. */    CONST char **argv;		/* Array of arguments for command pipe. */    int flags;			/* Or'ed combination of TCL_STDIN, TCL_STDOUT,				 * TCL_STDERR, and TCL_ENFORCE_MODE. */{    TclFile *inPipePtr, *outPipePtr, *errFilePtr;    TclFile inPipe, outPipe, errFile;    int numPids;    Tcl_Pid *pidPtr;    Tcl_Channel channel;    inPipe = outPipe = errFile = NULL;    inPipePtr = (flags & TCL_STDIN) ? &inPipe : NULL;    outPipePtr = (flags & TCL_STDOUT) ? &outPipe : NULL;    errFilePtr = (flags & TCL_STDERR) ? &errFile : NULL;        numPids = TclCreatePipeline(interp, argc, argv, &pidPtr, inPipePtr,            outPipePtr, errFilePtr);    if (numPids < 0) {	goto error;    }    /*     * Verify that the pipes that were created satisfy the     * readable/writable constraints.      */    if (flags & TCL_ENFORCE_MODE) {	if ((flags & TCL_STDOUT) && (outPipe == NULL)) {	    Tcl_AppendResult(interp, "can't read output from command:",		    " standard output was redirected", (char *) NULL);	    goto error;	}	if ((flags & TCL_STDIN) && (inPipe == NULL)) {	    Tcl_AppendResult(interp, "can't write input to command:",		    " standard input was redirected", (char *) NULL);	    goto error;	}    }        channel = TclpCreateCommandChannel(outPipe, inPipe, errFile,	    numPids, pidPtr);    if (channel == (Tcl_Channel) NULL) {        Tcl_AppendResult(interp, "pipe for command could not be created",                (char *) NULL);	goto error;    }    return channel;error:    if (numPids > 0) {	Tcl_DetachPids(numPids, pidPtr);	ckfree((char *) pidPtr);    }    if (inPipe != NULL) {	TclpCloseFile(inPipe);    }    if (outPipe != NULL) {	TclpCloseFile(outPipe);    }    if (errFile != NULL) {	TclpCloseFile(errFile);    }    return NULL;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?