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

📄 editline.c

📁 MINIX系统源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  $Revision: 1.7 $
**
**  Main editing routines for editline library.
*/
#include "editline.h"
#include <signal.h>
#include <ctype.h>

/*
**  Manifest constants.
*/
#define SCREEN_WIDTH	80
#define SCREEN_ROWS	24
#define NO_ARG		(-1)
#define DEL		127
#define CTL(x)		((x) & 0x1F)
#define ISCTL(x)	((x) && (x) < ' ')
#define UNCTL(x)	((x) + 64)
#define META(x)		((x) | 0x80)
#define ISMETA(x)	((x) & 0x80)
#define UNMETA(x)	((x) & 0x7F)
#if	!defined(HIST_SIZE)
#define HIST_SIZE	20
#endif	/* !defined(HIST_SIZE) */

/*
**  Command status codes.
*/
typedef enum _STATUS {
    CSdone, CSeof, CSmove, CSdispatch, CSstay, CSsignal
} STATUS;

/*
**  The type of case-changing to perform.
*/
typedef enum _CASE {
    TOupper, TOlower
} CASE;

/*
**  Key to command mapping.
*/
typedef struct _KEYMAP {
    CHAR	Key;
    STATUS	(*Function)();
} KEYMAP;

/*
**  Command history structure.
*/
typedef struct _HISTORY {
    int		Size;
    int		Pos;
    CHAR	*Lines[HIST_SIZE];
} HISTORY;

/*
**  Globals.
*/
int		rl_eof;
int		rl_erase;
int		rl_intr;
int		rl_kill;
int		rl_quit;

STATIC CHAR		NIL[] = "";
STATIC CONST CHAR	*Input = NIL;
STATIC CHAR		*Line;
STATIC CONST char	*Prompt;
STATIC CHAR		*Yanked;
STATIC char		*Screen;
STATIC char		NEWLINE[]= CRLF;
STATIC HISTORY		H;
STATIC int		Repeat;
STATIC int		End;
STATIC int		Mark;
STATIC int		OldPoint;
STATIC int		Point;
STATIC int		PushBack;
STATIC int		Pushed;
STATIC int		Signal;
FORWARD KEYMAP		Map[33];
FORWARD KEYMAP		MetaMap[17];
STATIC SIZE_T		Length;
STATIC SIZE_T		ScreenCount;
STATIC SIZE_T		ScreenSize;
STATIC char		*backspace;
STATIC int		TTYwidth;
STATIC int		TTYrows;

/* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */
int		rl_meta_chars = 0;

/*
**  Declarations.
*/
STATIC CHAR	*editinput();
extern int	read();
extern int	write();
#if	defined(USE_TERMCAP)
extern char	*getenv();
extern char	*tgetstr();
extern int	tgetent();
#endif	/* defined(USE_TERMCAP) */

/*
**  TTY input/output functions.
*/

STATIC void
TTYflush()
{
    if (ScreenCount) {
	(void)write(1, Screen, ScreenCount);
	ScreenCount = 0;
    }
}

STATIC void
TTYput(c)
    CHAR	c;
{
    Screen[ScreenCount] = c;
    if (++ScreenCount >= ScreenSize - 1) {
	ScreenSize += SCREEN_INC;
	RENEW(Screen, char, ScreenSize);
    }
}

STATIC void
TTYputs(p)
    CHAR	*p;
{
    while (*p)
	TTYput(*p++);
}

STATIC void
TTYshow(c)
    CHAR	c;
{
    if (c == DEL) {
	TTYput('^');
	TTYput('?');
    }
    else if (ISCTL(c)) {
	TTYput('^');
	TTYput(UNCTL(c));
    }
    else if (rl_meta_chars && ISMETA(c)) {
	TTYput('M');
	TTYput('-');
	TTYput(UNMETA(c));
    }
    else
	TTYput(c);
}

STATIC void
TTYstring(p)
    CHAR	*p;
{
    while (*p)
	TTYshow(*p++);
}

STATIC unsigned int
TTYget()
{
    CHAR	c;

    TTYflush();
    if (Pushed) {
	Pushed = 0;
	return PushBack;
    }
    if (*Input)
	return *Input++;
    return read(0, &c, (SIZE_T)1) == 1 ? c : EOF;
}

#define TTYback()	(backspace ? TTYputs((CHAR *)backspace) : TTYput('\b'))

STATIC void
TTYbackn(n)
    int		n;
{
    while (--n >= 0)
	TTYback();
}

STATIC void
TTYinfo()
{
    static int		init;
#if	defined(USE_TERMCAP)
    char		*term;
    char		buff[2048];
    char		*bp;
#endif	/* defined(USE_TERMCAP) */
#if	defined(TIOCGWINSZ)
    struct winsize	W;
#endif	/* defined(TIOCGWINSZ) */

    if (init) {
#if	defined(TIOCGWINSZ)
	/* Perhaps we got resized. */
	if (ioctl(0, TIOCGWINSZ, &W) >= 0
	 && W.ws_col > 0 && W.ws_row > 0) {
	    TTYwidth = (int)W.ws_col;
	    TTYrows = (int)W.ws_row;
	}
#endif	/* defined(TIOCGWINSZ) */
	return;
    }
    init++;

    TTYwidth = TTYrows = 0;
#if	defined(USE_TERMCAP)
    bp = &buff[0];
    if ((term = getenv("TERM")) == NULL)
	term = "dumb";
    if (tgetent(buff, term) < 0) {
       TTYwidth = SCREEN_WIDTH;
       TTYrows = SCREEN_ROWS;
       return;
    }
    if ((backspace = tgetstr("le", &bp)) != NULL)
	backspace = strdup(backspace);
    TTYwidth = tgetnum("co");
    TTYrows = tgetnum("li");
#endif	/* defined(USE_TERMCAP) */

#if	defined(TIOCGWINSZ)
    if (ioctl(0, TIOCGWINSZ, &W) >= 0) {
	TTYwidth = (int)W.ws_col;
	TTYrows = (int)W.ws_row;
    }
#endif	/* defined(TIOCGWINSZ) */

    if (TTYwidth <= 0 || TTYrows <= 0) {
	TTYwidth = SCREEN_WIDTH;
	TTYrows = SCREEN_ROWS;
    }
}


/*
**  Print an array of words in columns.
*/
STATIC void
columns(ac, av)
    int		ac;
    CHAR	**av;
{
    CHAR	*p;
    int		i;
    int		j;
    int		k;
    int		len;
    int		skip;
    int		longest;
    int		cols;

    /* Find longest name, determine column count from that. */
    for (longest = 0, i = 0; i < ac; i++)
	if ((j = strlen((char *)av[i])) > longest)
	    longest = j;
    cols = TTYwidth / (longest + 3);

    TTYputs((CHAR *)NEWLINE);
    for (skip = ac / cols + 1, i = 0; i < skip; i++) {
	for (j = i; j < ac; j += skip) {
	    for (p = av[j], len = strlen((char *)p), k = len; --k >= 0; p++)
		TTYput(*p);
	    if (j + skip < ac)
		while (++len < longest + 3)
		    TTYput(' ');
	}
	TTYputs((CHAR *)NEWLINE);
    }
}

STATIC void
reposition()
{
    int		i;
    CHAR	*p;

    TTYput('\r');
    TTYputs((CONST CHAR *)Prompt);
    for (i = Point, p = Line; --i >= 0; p++)
	TTYshow(*p);
}

STATIC void
left(Change)
    STATUS	Change;
{
    TTYback();
    if (Point) {
	if (ISCTL(Line[Point - 1]))
	    TTYback();
        else if (rl_meta_chars && ISMETA(Line[Point - 1])) {
	    TTYback();
	    TTYback();
	}
    }
    if (Change == CSmove)
	Point--;
}

STATIC void
right(Change)
    STATUS	Change;
{
    TTYshow(Line[Point]);
    if (Change == CSmove)
	Point++;
}

STATIC STATUS
ring_bell()
{
    TTYput('\07');
    TTYflush();
    return CSstay;
}

STATIC STATUS
do_macro(c)
    unsigned int	c;
{
    CHAR		name[4];

    name[0] = '_';
    name[1] = c;
    name[2] = '_';
    name[3] = '\0';

    if ((Input = (CHAR *)getenv((char *)name)) == NULL) {
	Input = NIL;
	return ring_bell();
    }
    return CSstay;
}

STATIC STATUS
do_forward(move)
    STATUS	move;
{
    int		i;
    CHAR	*p;

    i = 0;
    do {
	p = &Line[Point];
	for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++)
	    if (move == CSmove)
		right(CSstay);

	for (; Point < End && isalnum(*p); Point++, p++)
	    if (move == CSmove)
		right(CSstay);

	if (Point == End)
	    break;
    } while (++i < Repeat);

    return CSstay;
}

STATIC STATUS
do_case(type)
    CASE	type;
{
    int		i;
    int		end;
    int		count;
    CHAR	*p;

    (void)do_forward(CSstay);
    if (OldPoint != Point) {
	if ((count = Point - OldPoint) < 0)
	    count = -count;
	Point = OldPoint;
	if ((end = Point + count) > End)
	    end = End;
	for (i = Point, p = &Line[i]; i < end; i++, p++) {
	    if (type == TOupper) {
		if (islower(*p))
		    *p = toupper(*p);
	    }
	    else if (isupper(*p))
		*p = tolower(*p);
	    right(CSmove);
	}
    }
    return CSstay;
}

STATIC STATUS
case_down_word()
{
    return do_case(TOlower);
}

STATIC STATUS
case_up_word()
{
    return do_case(TOupper);
}

STATIC void
ceol()
{
    int		extras;
    int		i;
    CHAR	*p;

    for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) {
	TTYput(' ');
	if (ISCTL(*p)) {
	    TTYput(' ');
	    extras++;
	}
	else if (rl_meta_chars && ISMETA(*p)) {
	    TTYput(' ');
	    TTYput(' ');
	    extras += 2;
	}
    }

    for (i += extras; i > Point; i--)
	TTYback();
}

STATIC void
clear_line()
{
    Point = -strlen(Prompt);
    TTYput('\r');
    ceol();
    Point = 0;
    End = 0;
    Line[0] = '\0';
}

STATIC STATUS
insert_string(p)
    CHAR	*p;
{
    SIZE_T	len;
    int		i;
    CHAR	*new;
    CHAR	*q;

    len = strlen((char *)p);
    if (End + len >= Length) {
	if ((new = NEW(CHAR, Length + len + MEM_INC)) == NULL)
	    return CSstay;
	if (Length) {
	    COPYFROMTO(new, Line, Length);
	    DISPOSE(Line);
	}
	Line = new;
	Length += len + MEM_INC;
    }

    for (q = &Line[Point], i = End - Point; --i >= 0; )
	q[len + i] = q[i];
    COPYFROMTO(&Line[Point], p, len);
    End += len;
    Line[End] = '\0';
    TTYstring(&Line[Point]);
    Point += len;

    return Point == End ? CSstay : CSmove;
}

STATIC STATUS
redisplay()
{
    TTYputs((CONST CHAR *)NEWLINE);
    TTYputs((CONST CHAR *)Prompt);
    TTYstring(Line);
    return CSmove;
}

STATIC STATUS
toggle_meta_mode()
{
    rl_meta_chars = ! rl_meta_chars;
    return redisplay();
}


STATIC CHAR *
next_hist()
{
    return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];
}

STATIC CHAR *
prev_hist()
{
    return H.Pos == 0 ? NULL : H.Lines[--H.Pos];
}

STATIC STATUS
do_insert_hist(p)
    CHAR	*p;
{
    if (p == NULL)
	return ring_bell();
    Point = 0;
    reposition();
    ceol();
    End = 0;
    return insert_string(p);
}

STATIC STATUS
do_hist(move)
    CHAR	*(*move)();
{
    CHAR	*p;
    int		i;

    i = 0;
    do {
	if ((p = (*move)()) == NULL)
	    return ring_bell();
    } while (++i < Repeat);
    return do_insert_hist(p);
}

STATIC STATUS
h_next()
{
    return do_hist(next_hist);
}

STATIC STATUS
h_prev()
{
    return do_hist(prev_hist);
}

STATIC STATUS
h_first()
{
    return do_insert_hist(H.Lines[H.Pos = 0]);
}

STATIC STATUS
h_last()
{
    return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);
}

/*
**  Return zero if pat appears as a substring in text.
*/
STATIC int
substrcmp(text, pat, len)
    char	*text;
    char	*pat;
    int		len;
{
    char	c;

    if ((c = *pat) == '\0')
        return *text == '\0';
    for ( ; *text; text++)
        if (*text == c && strncmp(text, pat, len) == 0)
            return 0;
    return 1;
}

STATIC CHAR *
search_hist(search, move)
    CHAR	*search;
    CHAR	*(*move)();
{
    static CHAR	*old_search;
    int		len;
    int		pos;
    int		(*match)();
    char	*pat;

    /* Save or get remembered search pattern. */
    if (search && *search) {
	if (old_search)
	    DISPOSE(old_search);
	old_search = (CHAR *)strdup((char *)search);
    }
    else {
	if (old_search == NULL || *old_search == '\0')
            return NULL;
	search = old_search;
    }

    /* Set up pattern-finder. */
    if (*search == '^') {
	match = strncmp;
	pat = (char *)(search + 1);
    }
    else {
	match = substrcmp;
	pat = (char *)search;
    }
    len = strlen(pat);

    for (pos = H.Pos; (*move)() != NULL; )
	if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0)
            return H.Lines[H.Pos];
    H.Pos = pos;
    return NULL;
}

STATIC STATUS
h_search()
{
    static int	Searching;
    CONST char	*old_prompt;
    CHAR	*(*move)();
    CHAR	*p;

    if (Searching)
	return ring_bell();
    Searching = 1;

    clear_line();
    old_prompt = Prompt;
    Prompt = "Search: ";
    TTYputs((CONST CHAR *)Prompt);
    move = Repeat == NO_ARG ? prev_hist : next_hist;
    p = editinput();
    Prompt = old_prompt;
    Searching = 0;
    TTYputs((CONST CHAR *)Prompt);
    if (p == NULL && Signal > 0) {
	Signal = 0;
	clear_line();
	return redisplay();
    }
    p = search_hist(p, move);
    clear_line();
    if (p == NULL) {
	(void)ring_bell();
	return redisplay();
    }
    return do_insert_hist(p);
}

STATIC STATUS
fd_char()
{
    int		i;

    i = 0;
    do {
	if (Point >= End)
	    break;
	right(CSmove);
    } while (++i < Repeat);
    return CSstay;
}

STATIC void
save_yank(begin, i)
    int		begin;
    int		i;
{
    if (Yanked) {
	DISPOSE(Yanked);
	Yanked = NULL;
    }

    if (i < 1)
	return;

    if ((Yanked = NEW(CHAR, (SIZE_T)i + 1)) != NULL) {
	COPYFROMTO(Yanked, &Line[begin], i);
	Yanked[i] = '\0';
    }
}

STATIC STATUS
delete_string(count)
    int		count;
{
    int		i;
    CHAR	*p;

    if (count <= 0 || End == Point)
	return ring_bell();

    if (count == 1 && Point == End - 1) {
	/* Optimize common case of delete at end of line. */
	End--;
	p = &Line[Point];
	i = 1;
	TTYput(' ');
	if (ISCTL(*p)) {
	    i = 2;
	    TTYput(' ');
	}

⌨️ 快捷键说明

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