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

📄 shell.c

📁 nedit 是一款linux下的开发源码的功能强大的编辑器
💻 C
📖 第 1 页 / 共 3 页
字号:
static const char CVSID[] = "$Id: shell.c,v 1.25 2003/05/02 19:19:02 edg Exp $";/********************************************************************************									       ** shell.c -- Nirvana Editor shell command execution			       **									       ** Copyright (C) 1999 Mark Edel						       **									       ** This is free software; you can redistribute it and/or modify it under the    ** terms of the GNU General Public License as published by the Free Software    ** Foundation; either version 2 of the License, or (at your option) any later   ** version.							               ** 									       ** This software is distributed in the hope that it will be useful, but WITHOUT ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or        ** FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License        ** for more details.							       ** 									       ** You should have received a copy of the GNU General Public License along with ** software; if not, write to the Free Software Foundation, Inc., 59 Temple     ** Place, Suite 330, Boston, MA  02111-1307 USA		                       **									       ** Nirvana Text Editor	    						       ** December, 1993							       **									       ** Written by Mark Edel							       **									       ********************************************************************************/#ifdef HAVE_CONFIG_H#include "../config.h"#endif#include "shell.h"#include "textBuf.h"#include "text.h"#include "nedit.h"#include "window.h"#include "preferences.h"#include "file.h"#include "macro.h"#include "interpret.h"#include "../util/DialogF.h"#include "../util/misc.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <signal.h>#include <sys/types.h>#ifndef __MVS__#include <sys/param.h>#endif#include <sys/wait.h>#include <unistd.h>#include <fcntl.h>#include <ctype.h>#include <errno.h>#ifdef notdef#ifdef IBM#define NBBY 8#include <sys/select.h>#endif#include <time.h>#endif#ifdef __EMX__#include <process.h>#endif#include <Xm/Xm.h>#include <Xm/MessageB.h>#include <Xm/Text.h>#include <Xm/Form.h>#include <Xm/PushBG.h>#ifdef HAVE_DEBUG_H#include "../debug.h"#endif/* Tuning parameters */#define IO_BUF_SIZE 4096	/* size of buffers for collecting cmd output */#define MAX_OUT_DIALOG_ROWS 30	/* max height of dialog for command output */#define MAX_OUT_DIALOG_COLS 80	/* max width of dialog for command output */#define OUTPUT_FLUSH_FREQ 1000	/* how often (msec) to flush output buffers    	    	    	    	   when process is taking too long */#define BANNER_WAIT_TIME 6000	/* how long to wait (msec) before putting up    	    	    	    	   Shell Command Executing... banner *//* flags for issueCommand */#define ACCUMULATE 1#define ERROR_DIALOGS 2#define REPLACE_SELECTION 4#define RELOAD_FILE_AFTER 8#define OUTPUT_TO_DIALOG 16#define OUTPUT_TO_STRING 32/* element of a buffer list for collecting output from shell processes */typedef struct bufElem {    struct bufElem *next;    int length;    char contents[IO_BUF_SIZE];} buffer;/* data attached to window during shell command execution with   information for controling and communicating with the process */typedef struct {    int flags;    int stdinFD, stdoutFD, stderrFD;    pid_t childPid;    XtInputId stdinInputID, stdoutInputID, stderrInputID;    buffer *outBufs, *errBufs;    char *input;    char *inPtr;    Widget textW;    int leftPos, rightPos;    int inLength;    XtIntervalId bannerTimeoutID, flushTimeoutID;    char bannerIsUp;    char fromMacro;} shellCmdInfo;static void issueCommand(WindowInfo *window, const char *command, char *input,	int inputLen, int flags, Widget textW, int replaceLeft,	int replaceRight, int fromMacro);static void stdoutReadProc(XtPointer clientData, int *source, XtInputId *id);static void stderrReadProc(XtPointer clientData, int *source, XtInputId *id);static void stdinWriteProc(XtPointer clientData, int *source, XtInputId *id);static void finishCmdExecution(WindowInfo *window, int terminatedOnError);static pid_t forkCommand(Widget parent, const char *command, const char *cmdDir,	int *stdinFD, int *stdoutFD, int *stderrFD);static void addOutput(buffer **bufList, buffer *buf);static char *coalesceOutput(buffer **bufList, int *length);static void freeBufList(buffer **bufList);static void removeTrailingNewlines(char *string);static void createOutputDialog(Widget parent, char *text);static void destroyOutDialogCB(Widget w, XtPointer callback, XtPointer closure);static void measureText(char *text, int wrapWidth, int *rows, int *cols,	int *wrapped);static void truncateString(char *string, int length);static void bannerTimeoutProc(XtPointer clientData, XtIntervalId *id);static void flushTimeoutProc(XtPointer clientData, XtIntervalId *id);static void safeBufReplace(textBuffer *buf, int *start, int *end, 	const char *text);static char *shellCommandSubstitutes(const char *inStr, const char *fileStr,	const char *lineStr);static int shellSubstituter(char *outStr, const char *inStr, const char *fileStr,	const char *lineStr, int outLen, int predictOnly);/*** Filter the current selection through shell command "command".  The selection** is removed, and replaced by the output from the command execution.  Failed** command status and output to stderr are presented in dialog form.*/void FilterSelection(WindowInfo *window, const char *command, int fromMacro){    int left, right, textLen;    char *text;    /* Can't do two shell commands at once in the same window */    if (window->shellCmdData != NULL) {    	XBell(TheDisplay, 0);    	return;    }    /* Get the selection and the range in character positions that it       occupies.  Beep and return if no selection */    text = BufGetSelectionText(window->buffer);    if (*text == '\0') {	XtFree(text);	XBell(TheDisplay, 0);	return;    }    textLen = strlen(text);    BufUnsubstituteNullChars(text, window->buffer);    left = window->buffer->primary.start;    right = window->buffer->primary.end;        /* Issue the command and collect its output */    issueCommand(window, command, text, textLen, ACCUMULATE | ERROR_DIALOGS |	    REPLACE_SELECTION, window->lastFocus, left, right, fromMacro);}/*** Execute shell command "command", depositing the result at the current** insert position or in the current selection if the window has a** selection.*/void ExecShellCommand(WindowInfo *window, const char *command, int fromMacro){    int left, right, flags = 0;    char *subsCommand, fullName[MAXPATHLEN];    int pos, line, column;    char lineNumber[11];    /* Can't do two shell commands at once in the same window */    if (window->shellCmdData != NULL) {    	XBell(TheDisplay, 0);    	return;    }        /* get the selection or the insert position */    pos = TextGetCursorPos(window->lastFocus);    if (GetSimpleSelection(window->buffer, &left, &right))    	flags = ACCUMULATE | REPLACE_SELECTION;    else    	left = right = pos;        /* Substitute the current file name for % and the current line number       for # in the shell command */    strcpy(fullName, window->path);    strcat(fullName, window->filename);    TextPosToLineAndCol(window->lastFocus, pos, &line, &column);    sprintf(lineNumber, "%d", line);        subsCommand = shellCommandSubstitutes(command, fullName, lineNumber);    if (subsCommand == NULL)    {        DialogF(DF_ERR, window->shell, 1, "Shell Command",                "Shell command is too long due to\n"                "filename substitutions with '%%' or\n"                "line number substitutions with '#'", "OK");        return;    }    /* issue the command */    issueCommand(window, subsCommand, NULL, 0, flags, window->lastFocus, left,	    right, fromMacro);    free(subsCommand);}/*** Execute shell command "command", on input string "input", depositing the** in a macro string (via a call back to ReturnShellCommandOutput).*/void ShellCmdToMacroString(WindowInfo *window, const char *command,   const char *input){    char *inputCopy;        /* Make a copy of the input string for issueCommand to hold and free       upon completion */    inputCopy = *input == '\0' ? NULL : XtNewString(input);        /* fork the command and begin processing input/output */    issueCommand(window, command, inputCopy, strlen(input),	    ACCUMULATE | OUTPUT_TO_STRING, NULL, 0, 0, True);}/*** Execute the line of text where the the insertion cursor is positioned** as a shell command.*/void ExecCursorLine(WindowInfo *window, int fromMacro){    char *cmdText;    int left, right, insertPos;    char *subsCommand, fullName[MAXPATHLEN];    int pos, line, column;    char lineNumber[11];    /* Can't do two shell commands at once in the same window */    if (window->shellCmdData != NULL) {    	XBell(TheDisplay, 0);    	return;    }    /* get all of the text on the line with the insert position */    pos = TextGetCursorPos(window->lastFocus);    if (!GetSimpleSelection(window->buffer, &left, &right)) {	left = right = pos;	left = BufStartOfLine(window->buffer, left);	right = BufEndOfLine(window->buffer, right);	insertPos = right;    } else    	insertPos = BufEndOfLine(window->buffer, right);    cmdText = BufGetRange(window->buffer, left, right);    BufUnsubstituteNullChars(cmdText, window->buffer);        /* insert a newline after the entire line */    BufInsert(window->buffer, insertPos, "\n");    /* Substitute the current file name for % and the current line number       for # in the shell command */    strcpy(fullName, window->path);    strcat(fullName, window->filename);    TextPosToLineAndCol(window->lastFocus, pos, &line, &column);    sprintf(lineNumber, "%d", line);        subsCommand = shellCommandSubstitutes(cmdText, fullName, lineNumber);    if (subsCommand == NULL)    {        DialogF(DF_ERR, window->shell, 1, "Shell Command",                "Shell command is too long due to\n"                "filename substitutions with '%%' or\n"                "line number substitutions with '#'", "OK");        return;    }    /* issue the command */    issueCommand(window, subsCommand, NULL, 0, 0, window->lastFocus, insertPos+1,	    insertPos+1, fromMacro);    free(subsCommand);    XtFree(cmdText);}/*** Do a shell command, with the options allowed to users (input source,** output destination, save first and load after) in the shell commands** menu.*/void DoShellMenuCmd(WindowInfo *window, const char *command,        int input, int output,	int outputReplacesInput, int saveFirst, int loadAfter, int fromMacro) {    int flags = 0;    char *text;    char *subsCommand, fullName[MAXPATHLEN];    int left, right, textLen;    int pos, line, column;    char lineNumber[11];    WindowInfo *inWindow = window;    Widget outWidget;    /* Can't do two shell commands at once in the same window */    if (window->shellCmdData != NULL) {    	XBell(TheDisplay, 0);    	return;    }    /* Substitute the current file name for % and the current line number       for # in the shell command */    strcpy(fullName, window->path);    strcat(fullName, window->filename);    pos = TextGetCursorPos(window->lastFocus);    TextPosToLineAndCol(window->lastFocus, pos, &line, &column);    sprintf(lineNumber, "%d", line);        subsCommand = shellCommandSubstitutes(command, fullName, lineNumber);    if (subsCommand == NULL)    {        DialogF(DF_ERR, window->shell, 1, "Shell Command",                "Shell command is too long due to\n"                "filename substitutions with '%%' or\n"                "line number substitutions with '#'", "OK");        return;    }    /* Get the command input as a text string.  If there is input, errors      shouldn't be mixed in with output, so set flags to ERROR_DIALOGS */    if (input == FROM_SELECTION) {	text = BufGetSelectionText(window->buffer);	if (*text == '\0') {    	    XtFree(text);            free(subsCommand);    	    XBell(TheDisplay, 0);    	    return;    	}    	flags |= ACCUMULATE | ERROR_DIALOGS;    } else if (input == FROM_WINDOW) {	text = BufGetAll(window->buffer);    	flags |= ACCUMULATE | ERROR_DIALOGS;    } else if (input == FROM_EITHER) {	text = BufGetSelectionText(window->buffer);	if (*text == '\0') {	    XtFree(text);	    text = BufGetAll(window->buffer);    	}    	flags |= ACCUMULATE | ERROR_DIALOGS;    } else /* FROM_NONE */    	text = NULL;        /* If the buffer was substituting another character for ascii-nuls,       put the nuls back in before exporting the text */    if (text != NULL) {	textLen = strlen(text);	BufUnsubstituteNullChars(text, window->buffer);    } else	textLen = 0;        /* Assign the output destination.  If output is to a new window,       create it, and run the command from it instead of the current       one, to free the current one from waiting for lengthy execution */    if (output == TO_DIALOG) {    	outWidget = NULL;	flags |= OUTPUT_TO_DIALOG;    	left = right = 0;    } else if (output == TO_NEW_WINDOW) {    	EditNewFile(NULL, False, NULL, window->path);    	outWidget = WindowList->textArea;	inWindow = WindowList;    	left = right = 0;    } else { /* TO_SAME_WINDOW */    	outWidget = window->lastFocus;    	if (outputReplacesInput && input != FROM_NONE) {    	    if (input == FROM_WINDOW) {    		left = 0;    		right = window->buffer->length;    	    } else if (input == FROM_SELECTION) {    	    	GetSimpleSelection(window->buffer, &left, &right);	        flags |= ACCUMULATE | REPLACE_SELECTION;    	    } else if (input == FROM_EITHER) {    	    	if (GetSimpleSelection(window->buffer, &left, &right))	            flags |= ACCUMULATE | REPLACE_SELECTION;	        else {	            left = 0;	            right = window->buffer->length;	        }	    }    	} else {	    if (GetSimpleSelection(window->buffer, &left, &right))	        flags |= ACCUMULATE | REPLACE_SELECTION;	    else    		left = right = TextGetCursorPos(window->lastFocus);    	}    }        /* If the command requires the file be saved first, save it */    if (saveFirst) {    	if (!SaveWindow(window)) {    	    if (input != FROM_NONE)    		XtFree(text);            free(subsCommand);    	    return;	}    }        /* If the command requires the file to be reloaded after execution, set       a flag for issueCommand to deal with it when execution is complete */    if (loadAfter)    	flags |= RELOAD_FILE_AFTER;    	    /* issue the command */    issueCommand(inWindow, subsCommand, text, textLen, flags, outWidget, left,	    right, fromMacro);    free(subsCommand);}/*** Cancel the shell command in progress*/void AbortShellCommand(WindowInfo *window){    shellCmdInfo *cmdData = window->shellCmdData;    if (cmdData == NULL)    	return;

⌨️ 快捷键说明

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