⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 shell.c

📁 nedit 是一款linux下的开发源码的功能强大的编辑器
💻 C
📖 第 1 页 / 共 3 页
字号:
    kill(- cmdData->childPid, SIGTERM);    finishCmdExecution(window, True);}/*** Issue a shell command and feed it the string "input".  Output can be** directed either to text widget "textW" where it replaces the text between** the positions "replaceLeft" and "replaceRight", to a separate pop-up dialog** (OUTPUT_TO_DIALOG), or to a macro-language string (OUTPUT_TO_STRING).  If** "input" is NULL, no input is fed to the process.  If an input string is** provided, it is freed when the command completes.  Flags:****   ACCUMULATE     	Causes output from the command to be saved up until**  	    	    	the command completes.**   ERROR_DIALOGS  	Presents stderr output separately in popup a dialog,**  	    	    	and also reports failed exit status as a popup dialog**  	    	    	including the command output.**   REPLACE_SELECTION  Causes output to replace the selection in textW.**   RELOAD_FILE_AFTER  Causes the file to be completely reloaded after the**  	    	    	command completes.**   OUTPUT_TO_DIALOG   Send output to a pop-up dialog instead of textW**   OUTPUT_TO_STRING   Output to a macro-language string instead of a text**  	    	    	widget or dialog.**** REPLACE_SELECTION, ERROR_DIALOGS, and OUTPUT_TO_STRING can only be used** along with ACCUMULATE (these operations can't be done incrementally).*/static void issueCommand(WindowInfo *window, const char *command, char *input,	int inputLen, int flags, Widget textW, int replaceLeft,	int replaceRight, int fromMacro){    int stdinFD, stdoutFD, stderrFD;    XtAppContext context = XtWidgetToApplicationContext(window->shell);    shellCmdInfo *cmdData;    pid_t childPid;        /* verify consistency of input parameters */    if ((flags & ERROR_DIALOGS || flags & REPLACE_SELECTION ||	    flags & OUTPUT_TO_STRING) && !(flags & ACCUMULATE))    	return;        /* a shell command called from a macro must be executed in the same       window as the macro, regardless of where the output is directed,       so the user can cancel them as a unit */    if (fromMacro)    	window = MacroRunWindow();        /* put up a watch cursor over the waiting window */    if (!fromMacro)    	BeginWait(window->shell);        /* enable the cancel menu item */    if (!fromMacro)    	XtSetSensitive(window->cancelShellItem, True);    /* fork the subprocess and issue the command */    childPid = forkCommand(window->shell, command, window->path, &stdinFD,	    &stdoutFD, (flags & ERROR_DIALOGS) ? &stderrFD : NULL);        /* set the pipes connected to the process for non-blocking i/o */    if (fcntl(stdinFD, F_SETFL, O_NONBLOCK) < 0)    	perror("NEdit: Internal error (fcntl)");    if (fcntl(stdoutFD, F_SETFL, O_NONBLOCK) < 0)    	perror("NEdit: Internal error (fcntl1)");    if (flags & ERROR_DIALOGS) {	if (fcntl(stderrFD, F_SETFL, O_NONBLOCK) < 0)    	    perror("NEdit: Internal error (fcntl2)");    }        /* if there's nothing to write to the process' stdin, close it now */    if (input == NULL)    	close(stdinFD);        /* Create a data structure for passing process information around       amongst the callback routines which will process i/o and completion */    cmdData = (shellCmdInfo *)XtMalloc(sizeof(shellCmdInfo));    window->shellCmdData = cmdData;    cmdData->flags = flags;    cmdData->stdinFD = stdinFD;    cmdData->stdoutFD = stdoutFD;    cmdData->stderrFD = stderrFD;    cmdData->childPid = childPid;    cmdData->outBufs = NULL;    cmdData->errBufs = NULL;    cmdData->input = input;    cmdData->inPtr = input;    cmdData->textW = textW;    cmdData->bannerIsUp = False;    cmdData->fromMacro = fromMacro;    cmdData->leftPos = replaceLeft;    cmdData->rightPos = replaceRight;    cmdData->inLength = inputLen;        /* Set up timer proc for putting up banner when process takes too long */    if (fromMacro)    	cmdData->bannerTimeoutID = 0;    else    	cmdData->bannerTimeoutID = XtAppAddTimeOut(context, BANNER_WAIT_TIME,    	    	bannerTimeoutProc, window);    /* Set up timer proc for flushing output buffers periodically */    if ((flags & ACCUMULATE) || textW == NULL)    	cmdData->flushTimeoutID = 0;    else	cmdData->flushTimeoutID = XtAppAddTimeOut(context, OUTPUT_FLUSH_FREQ,	    	flushTimeoutProc, window);    	    /* set up callbacks for activity on the file descriptors */    cmdData->stdoutInputID = XtAppAddInput(context, stdoutFD,    	    (XtPointer)XtInputReadMask, stdoutReadProc, window);    if (input != NULL)    	cmdData->stdinInputID = XtAppAddInput(context, stdinFD,    	    	(XtPointer)XtInputWriteMask, stdinWriteProc, window);    else    	cmdData->stdinInputID = 0;    if (flags & ERROR_DIALOGS)	cmdData->stderrInputID = XtAppAddInput(context, stderrFD,    		(XtPointer)XtInputReadMask, stderrReadProc, window);    else    	cmdData->stderrInputID = 0;        /* If this was called from a macro, preempt the macro untill shell       command completes */    if (fromMacro)    	PreemptMacro();}/*** Called when the shell sub-process stdout stream has data.  Reads data into** the "outBufs" buffer chain in the window->shellCommandData data structure.*/static void stdoutReadProc(XtPointer clientData, int *source, XtInputId *id){    WindowInfo *window = (WindowInfo *)clientData;    shellCmdInfo *cmdData = window->shellCmdData;    buffer *buf;    int nRead;    /* read from the process' stdout stream */    buf = (buffer *)XtMalloc(sizeof(buffer));    nRead = read(cmdData->stdoutFD, buf->contents, IO_BUF_SIZE);        /* error in read */    if (nRead == -1) { /* error */	if (errno != EWOULDBLOCK && errno != EAGAIN) {	    perror("NEdit: Error reading shell command output");	    XtFree((char *)buf);	    finishCmdExecution(window, True);	}	return;    }        /* end of data.  If the stderr stream is done too, execution of the       shell process is complete, and we can display the results */    if (nRead == 0) {    	XtFree((char *)buf);    	XtRemoveInput(cmdData->stdoutInputID);    	cmdData->stdoutInputID = 0;    	if (cmdData->stderrInputID == 0)    	    finishCmdExecution(window, False);    	return;    }        /* characters were read successfully, add buf to linked list of buffers */    buf->length = nRead;    addOutput(&cmdData->outBufs, buf);}/*** Called when the shell sub-process stderr stream has data.  Reads data into** the "errBufs" buffer chain in the window->shellCommandData data structure.*/static void stderrReadProc(XtPointer clientData, int *source, XtInputId *id){    WindowInfo *window = (WindowInfo *)clientData;    shellCmdInfo *cmdData = window->shellCmdData;    buffer *buf;    int nRead;        /* read from the process' stderr stream */    buf = (buffer *)XtMalloc(sizeof(buffer));    nRead = read(cmdData->stderrFD, buf->contents, IO_BUF_SIZE);        /* error in read */    if (nRead == -1) {	if (errno != EWOULDBLOCK && errno != EAGAIN) {	    perror("NEdit: Error reading shell command error stream");	    XtFree((char *)buf);	    finishCmdExecution(window, True);	}	return;    }        /* end of data.  If the stdout stream is done too, execution of the       shell process is complete, and we can display the results */    if (nRead == 0) {    	XtFree((char *)buf);    	XtRemoveInput(cmdData->stderrInputID);    	cmdData->stderrInputID = 0;    	if (cmdData->stdoutInputID == 0)    	    finishCmdExecution(window, False);    	return;    }        /* characters were read successfully, add buf to linked list of buffers */    buf->length = nRead;    addOutput(&cmdData->errBufs, buf);}/*** Called when the shell sub-process stdin stream is ready for input.  Writes** data from the "input" text string passed to issueCommand.*/static void stdinWriteProc(XtPointer clientData, int *source, XtInputId *id){    WindowInfo *window = (WindowInfo *)clientData;    shellCmdInfo *cmdData = window->shellCmdData;    int nWritten;    nWritten = write(cmdData->stdinFD, cmdData->inPtr, cmdData->inLength);    if (nWritten == -1) {	if (errno == EPIPE) {	    /* Just shut off input to broken pipes.  User is likely feeding	       it to a command which does not take input */	    XtRemoveInput(cmdData->stdinInputID);	    cmdData->stdinInputID = 0;    	    close(cmdData->stdinFD);    	    cmdData->inPtr = NULL;    	} else if (errno != EWOULDBLOCK && errno != EAGAIN) {    	    perror("NEdit: Write to shell command failed");    	    finishCmdExecution(window, True);    	}    } else {	cmdData->inPtr += nWritten;	cmdData->inLength -= nWritten;	if (cmdData->inLength <= 0) {	    XtRemoveInput(cmdData->stdinInputID);	    cmdData->stdinInputID = 0;    	    close(cmdData->stdinFD);    	    cmdData->inPtr = NULL;    	}    }}/*** Timer proc for putting up the "Shell Command in Progress" banner if** the process is taking too long.*/static void bannerTimeoutProc(XtPointer clientData, XtIntervalId *id){    WindowInfo *window = (WindowInfo *)clientData;    shellCmdInfo *cmdData = window->shellCmdData;        cmdData->bannerIsUp = True;    SetModeMessage(window,    	    "Shell Command in Progress -- Press Ctrl+. to Cancel");    cmdData->bannerTimeoutID = 0;}/*** Buffer replacement wrapper routine to be used for inserting output from ** a command into the buffer, which takes into account that the buffer may ** have been shrunken by the user (eg, by Undo). If necessary, the starting** and ending positions (part of the state of the command) are corrected.*/static void safeBufReplace(textBuffer *buf, int *start, int *end, 	const char *text){    if (*start > buf->length)	*start = buf->length;    if (*end > buf->length)	*end = buf->length;    BufReplace(buf, *start, *end, text);}/*** Timer proc for flushing output buffers periodically when the process** takes too long.*/static void flushTimeoutProc(XtPointer clientData, XtIntervalId *id){    WindowInfo *window = (WindowInfo *)clientData;    shellCmdInfo *cmdData = window->shellCmdData;    textBuffer *buf = TextGetBuffer(cmdData->textW);    int len;    char *outText;        /* shouldn't happen, but it would be bad if it did */    if (cmdData->textW == NULL)    	return;    outText = coalesceOutput(&cmdData->outBufs, &len);    if (len != 0) {	if (BufSubstituteNullChars(outText, len, buf)) {	    safeBufReplace(buf, &cmdData->leftPos, &cmdData->rightPos, outText);	    TextSetCursorPos(cmdData->textW, cmdData->leftPos+strlen(outText));	    cmdData->leftPos += len;	    cmdData->rightPos = cmdData->leftPos;	} else	    fprintf(stderr, "NEdit: Too much binary data\n");    }    XtFree(outText);    /* re-establish the timer proc (this routine) to continue processing */    cmdData->flushTimeoutID = XtAppAddTimeOut(    	    XtWidgetToApplicationContext(window->shell),    	    OUTPUT_FLUSH_FREQ, flushTimeoutProc, clientData);}/*** Clean up after the execution of a shell command sub-process and present** the output/errors to the user as requested in the initial issueCommand** call.  If "terminatedOnError" is true, don't bother trying to read the** output, just close the i/o descriptors, free the memory, and restore the** user interface state.*/static void finishCmdExecution(WindowInfo *window, int terminatedOnError){    shellCmdInfo *cmdData = window->shellCmdData;    textBuffer *buf;    int status, failure, errorReport, reselectStart, outTextLen, errTextLen;    int resp, cancel = False, fromMacro = cmdData->fromMacro;    char *outText, *errText = NULL;    /* Cancel any pending i/o on the file descriptors */    if (cmdData->stdoutInputID != 0)    	XtRemoveInput(cmdData->stdoutInputID);    if (cmdData->stdinInputID != 0)    	XtRemoveInput(cmdData->stdinInputID);    if (cmdData->stderrInputID != 0)    	XtRemoveInput(cmdData->stderrInputID);    /* Close any file descriptors remaining open */    close(cmdData->stdoutFD);    if (cmdData->flags & ERROR_DIALOGS)    	close(cmdData->stderrFD);    if (cmdData->inPtr != NULL)    	close(cmdData->stdinFD);    /* Free the provided input text */    if (cmdData->input != NULL)	XtFree(cmdData->input);        /* Cancel pending timeouts */    if (cmdData->flushTimeoutID != 0)    	XtRemoveTimeOut(cmdData->flushTimeoutID);    if (cmdData->bannerTimeoutID != 0)    	XtRemoveTimeOut(cmdData->bannerTimeoutID);        /* Clean up waiting-for-shell-command-to-complete mode */    if (!cmdData->fromMacro) {	EndWait(window->shell);	XtSetSensitive(window->cancelShellItem, False);	if (cmdData->bannerIsUp)    	    ClearModeMessage(window);    }        /* If the process was killed or became inaccessable, give up */    if (terminatedOnError) {	freeBufList(&cmdData->outBufs);	freeBufList(&cmdData->errBufs);    	waitpid(cmdData->childPid, &status, 0);	goto cmdDone;    }    /* Assemble the output from the process' stderr and stdout streams into       null terminated strings, and free the buffer lists used to collect it */    outText = coalesceOutput(&cmdData->outBufs, &outTextLen);    if (cmdData->flags & ERROR_DIALOGS)    	errText = coalesceOutput(&cmdData->errBufs, &errTextLen);    /* Wait for the child process to complete and get its return status */    waitpid(cmdData->childPid, &status, 0);        /* Present error and stderr-information dialogs.  If a command returned       error output, or if the process' exit status indicated failure,       present the information to the user. */    if (cmdData->flags & ERROR_DIALOGS)    {        failure = WIFEXITED(status) && WEXITSTATUS(status) != 0;        errorReport = *errText != '\0';        if (failure && errorReport)        {            removeTrailingNewlines(errText);            truncateString(errText, DF_MAX_MSG_LENGTH);            resp = DialogF(DF_WARN, window->shell, 2, "Warning", "%s", "Cancel",                    "Proceed", errText);            cancel = resp == 1;        } else if (failure)        {            truncateString(outText, DF_MAX_MSG_LENGTH-70);            resp = DialogF(DF_WARN, window->shell, 2, "Command Failure",                    "Command reported failed exit status.\n"                    "Output from command:\n%s", "Cancel", "Proceed", outText);            cancel = resp == 1;        } else if (errorReport)        {            removeTrailingNewlines(errText);            truncateString(errText, DF_MAX_MSG_LENGTH);            resp = DialogF(DF_INF, window->shell, 2, "Information", "%s",                    "Proceed", "Cancel", errText);            cancel = resp == 2;        }        XtFree(errText);        if (cancel)        {            XtFree(outText);            goto cmdDone;        }    }        /* If output is to a dialog, present the dialog.  Otherwise insert the       (remaining) output in the text widget as requested, and move the       insert point to the end */    if (cmdData->flags & OUTPUT_TO_DIALOG) {    	removeTrailingNewlines(outText);	if (*outText != '\0')    	    createOutputDialog(window->shell, outText);    } else if (cmdData->flags & OUTPUT_TO_STRING) {    	ReturnShellCommandOutput(window,outText, WEXITSTATUS(status));    } else {	buf = TextGetBuffer(cmdData->textW);	if (!BufSubstituteNullChars(outText, outTextLen, buf)) {	    fprintf(stderr,"NEdit: Too much binary data in shell cmd output\n");	    outText[0] = '\0';	}	if (cmdData->flags & REPLACE_SELECTION) {	    reselectStart = buf->primary.rectangular ? -1 : buf->primary.start;	    BufReplaceSelected(buf, outText);	    TextSetCursorPos(cmdData->textW, buf->cursorPosHint);	    if (reselectStart != -1)	    	BufSelect(buf, reselectStart, reselectStart + strlen(outText));	} else {	    safeBufReplace(buf, &cmdData->leftPos, &cmdData->rightPos, outText);	    TextSetCursorPos(cmdData->textW, cmdData->leftPos+strlen(outText));	}    }    /* If the command requires the file to be reloaded afterward, reload it */    if (cmdData->flags & RELOAD_FILE_AFTER)    	RevertToSaved(window);    /* Command is complete, free data structure and continue macro execution */    XtFree(outText);

⌨️ 快捷键说明

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