tclpipe.c

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

C
1,071
字号
                    Tcl_AppendResult(interp,                            "child wait status didn't make sense\n",                            (char *) NULL);                }	    }	}    }    /*     * Read the standard error file.  If there's anything there,     * then return an error and add the file's contents to the result     * string.     */    anyErrorInfo = 0;    if (errorChan != NULL) {	/*	 * Make sure we start at the beginning of the file.	 */        if (interp != NULL) {	    int count;	    Tcl_Obj *objPtr;	    	    Tcl_Seek(errorChan, (Tcl_WideInt)0, SEEK_SET);	    objPtr = Tcl_NewObj();	    count = Tcl_ReadChars(errorChan, objPtr, -1, 0);	    if (count < 0) {		result = TCL_ERROR;		Tcl_DecrRefCount(objPtr);		Tcl_ResetResult(interp);		Tcl_AppendResult(interp, "error reading stderr output file: ",			Tcl_PosixError(interp), NULL);	    } else if (count > 0) {		anyErrorInfo = 1;		Tcl_SetObjResult(interp, objPtr);		result = TCL_ERROR;	    } else {		Tcl_DecrRefCount(objPtr);	    }	}	Tcl_Close(NULL, errorChan);    }    /*     * If a child exited abnormally but didn't output any error information     * at all, generate an error message here.     */    if ((abnormalExit != 0) && (anyErrorInfo == 0) && (interp != NULL)) {	Tcl_AppendResult(interp, "child process exited abnormally",		(char *) NULL);    }    return result;}/* *---------------------------------------------------------------------- * * TclCreatePipeline -- * *	Given an argc/argv array, instantiate a pipeline of processes *	as described by the argv. * *	This procedure is unofficially exported for use by BLT. * * Results: *	The return value is a count of the number of new processes *	created, or -1 if an error occurred while creating the pipeline. *	*pidArrayPtr is filled in with the address of a dynamically *	allocated array giving the ids of all of the processes.  It *	is up to the caller to free this array when it isn't needed *	anymore.  If inPipePtr is non-NULL, *inPipePtr is filled in *	with the file id for the input pipe for the pipeline (if any): *	the caller must eventually close this file.  If outPipePtr *	isn't NULL, then *outPipePtr is filled in with the file id *	for the output pipe from the pipeline:  the caller must close *	this file.  If errFilePtr isn't NULL, then *errFilePtr is filled *	with a file id that may be used to read error output after the *	pipeline completes. * * Side effects: *	Processes and pipes are created. * *---------------------------------------------------------------------- */intTclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr,	outPipePtr, errFilePtr)    Tcl_Interp *interp;		/* Interpreter to use for error reporting. */    int argc;			/* Number of entries in argv. */    CONST char **argv;		/* Array of strings describing commands in				 * pipeline plus I/O redirection with <,				 * <<,  >, etc.  Argv[argc] must be NULL. */    Tcl_Pid **pidArrayPtr;	/* Word at *pidArrayPtr gets filled in with				 * address of array of pids for processes				 * in pipeline (first pid is first process				 * in pipeline). */    TclFile *inPipePtr;		/* If non-NULL, input to the pipeline comes				 * from a pipe (unless overridden by				 * redirection in the command).  The file				 * id with which to write to this pipe is				 * stored at *inPipePtr.  NULL means command				 * specified its own input source. */    TclFile *outPipePtr;	/* If non-NULL, output to the pipeline goes				 * to a pipe, unless overriden by redirection				 * in the command.  The file id with which to				 * read frome this pipe is stored at				 * *outPipePtr.  NULL means command specified				 * its own output sink. */    TclFile *errFilePtr;	/* If non-NULL, all stderr output from the				 * pipeline will go to a temporary file				 * created here, and a descriptor to read				 * the file will be left at *errFilePtr.				 * The file will be removed already, so				 * closing this descriptor will be the end				 * of the file.  If this is NULL, then				 * all stderr output goes to our stderr.				 * If the pipeline specifies redirection				 * then the file will still be created				 * but it will never get any data. */{    Tcl_Pid *pidPtr = NULL;	/* Points to malloc-ed array holding all				 * the pids of child processes. */    int numPids;		/* Actual number of processes that exist				 * at *pidPtr right now. */    int cmdCount;		/* Count of number of distinct commands				 * found in argc/argv. */    CONST char *inputLiteral = NULL;	/* If non-null, then this points to a				 * string containing input data (specified				 * via <<) to be piped to the first process				 * in the pipeline. */    TclFile inputFile = NULL;	/* If != NULL, gives file to use as input for				 * first process in pipeline (specified via <				 * or <@). */    int inputClose = 0;		/* If non-zero, then inputFile should be     				 * closed when cleaning up. */    int inputRelease = 0;    TclFile outputFile = NULL;	/* Writable file for output from last command				 * in pipeline (could be file or pipe).  NULL				 * means use stdout. */    int outputClose = 0;	/* If non-zero, then outputFile should be     				 * closed when cleaning up. */    int outputRelease = 0;    TclFile errorFile = NULL;	/* Writable file for error output from all				 * commands in pipeline.  NULL means use				 * stderr. */    int errorClose = 0;		/* If non-zero, then errorFile should be     				 * closed when cleaning up. */    int errorRelease = 0;    CONST char *p;    int skip, lastBar, lastArg, i, j, atOK, flags, errorToOutput;    Tcl_DString execBuffer;    TclFile pipeIn;    TclFile curInFile, curOutFile, curErrFile;    Tcl_Channel channel;    if (inPipePtr != NULL) {	*inPipePtr = NULL;    }    if (outPipePtr != NULL) {	*outPipePtr = NULL;    }    if (errFilePtr != NULL) {	*errFilePtr = NULL;    }    Tcl_DStringInit(&execBuffer);        pipeIn = NULL;    curInFile = NULL;    curOutFile = NULL;    numPids = 0;    /*     * First, scan through all the arguments to figure out the structure     * of the pipeline.  Process all of the input and output redirection     * arguments and remove them from the argument list in the pipeline.     * Count the number of distinct processes (it's the number of "|"     * arguments plus one) but don't remove the "|" arguments because      * they'll be used in the second pass to seperate the individual      * child processes.  Cannot start the child processes in this pass      * because the redirection symbols may appear anywhere in the      * command line -- e.g., the '<' that specifies the input to the      * entire pipe may appear at the very end of the argument list.     */    lastBar = -1;    cmdCount = 1;    for (i = 0; i < argc; i++) {        skip = 0;	p = argv[i];	switch (*p++) {	case '|':	    if (*p == '&') {		p++;	    }	    if (*p == '\0') {		if ((i == (lastBar + 1)) || (i == (argc - 1))) {		    Tcl_SetResult(interp,			    "illegal use of | or |& in command",			    TCL_STATIC);		    goto error;		}	    }	    lastBar = i;	    cmdCount++;	    break;	case '<':	    if (inputClose != 0) {		inputClose = 0;		TclpCloseFile(inputFile);	    }	    if (inputRelease != 0) {		inputRelease = 0;		TclpReleaseFile(inputFile);	    }	    if (*p == '<') {		inputFile = NULL;		inputLiteral = p + 1;		skip = 1;		if (*inputLiteral == '\0') {		    inputLiteral = argv[i + 1];		    if (inputLiteral == NULL) {			Tcl_AppendResult(interp, "can't specify \"", argv[i],				"\" as last word in command", (char *) NULL);			goto error;		    }		    skip = 2;		}	    } else {		inputLiteral = NULL;		inputFile = FileForRedirect(interp, p, 1, argv[i], 			argv[i + 1], O_RDONLY, &skip, &inputClose, &inputRelease);		if (inputFile == NULL) {		    goto error;		}	    }	    break;	case '>':	    atOK = 1;	    flags = O_WRONLY | O_CREAT | O_TRUNC;	    errorToOutput = 0;	    if (*p == '>') {		p++;		atOK = 0;		flags = O_WRONLY | O_CREAT;	    }	    if (*p == '&') {		if (errorClose != 0) {		    errorClose = 0;		    TclpCloseFile(errorFile);		}		errorToOutput = 1;		p++;	    }	    /*	     * Close the old output file, but only if the error file is	     * not also using it.	     */	    if (outputClose != 0) {		outputClose = 0;		if (errorFile == outputFile) {		    errorClose = 1;		} else {		    TclpCloseFile(outputFile);		}	    }	    if (outputRelease != 0) {		outputRelease = 0;		if (errorFile == outputFile) {		    errorRelease = 1;		} else {		    TclpReleaseFile(outputFile);		}	    }	    outputFile = FileForRedirect(interp, p, atOK, argv[i], 		    argv[i + 1], flags, &skip, &outputClose, &outputRelease);	    if (outputFile == NULL) {		goto error;	    }	    if (errorToOutput) {		if (errorClose != 0) {		    errorClose = 0;		    TclpCloseFile(errorFile);		}		if (errorRelease != 0) {		    errorRelease = 0;		    TclpReleaseFile(errorFile);		}		errorFile = outputFile;	    }	    break;	case '2':	    if (*p != '>') {		break;	    }	    p++;	    atOK = 1;	    flags = O_WRONLY | O_CREAT | O_TRUNC;	    if (*p == '>') {		p++;		atOK = 0;		flags = O_WRONLY | O_CREAT;	    }	    if (errorClose != 0) {		errorClose = 0;		TclpCloseFile(errorFile);	    }	    if (errorRelease != 0) {		errorRelease = 0;		TclpReleaseFile(errorFile);	    }	    errorFile = FileForRedirect(interp, p, atOK, argv[i], 		    argv[i + 1], flags, &skip, &errorClose, &errorRelease);	    if (errorFile == NULL) {		goto error;	    }	    break;	}	if (skip != 0) {	    for (j = i + skip; j < argc; j++) {		argv[j - skip] = argv[j];	    }	    argc -= skip;	    i -= 1;	}    }    if (inputFile == NULL) {	if (inputLiteral != NULL) {	    /*	     * The input for the first process is immediate data coming from	     * Tcl.  Create a temporary file for it and put the data into the	     * file.	     */	    inputFile = TclpCreateTempFile(inputLiteral);	    if (inputFile == NULL) {		Tcl_AppendResult(interp,			"couldn't create input file for command: ",			Tcl_PosixError(interp), (char *) NULL);		goto error;	    }	    inputClose = 1;	} else if (inPipePtr != NULL) {	    /*	     * The input for the first process in the pipeline is to	     * come from a pipe that can be written from by the caller.	     */

⌨️ 快捷键说明

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