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

📄 emacs.c

📁 一个开放源代码的 AT&T 的 Korn Shell 的复制品, 支持大多数 ksh89 的特性。
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  Emacs-like command line editing and history * *  created by Ron Natalie at BRL *  modified by Doug Kingston, Doug Gwyn, and Lou Salkind *  adapted to PD ksh by Eric Gisin */#include "config.h"#ifdef EMACS#include "sh.h"#include "ksh_stat.h"#include "ksh_dir.h"#include <ctype.h>#include "edit.h"static	Area	aedit;#define	AEDIT	&aedit		/* area for kill ring and macro defns */#undef CTRL			/* _BSD brain damage */#define	CTRL(x)		((x) == '?' ? 0x7F : (x) & 0x1F)	/* ASCII */#define	UNCTRL(x)	((x) == 0x7F ? '?' : (x) | 0x40)	/* ASCII *//* values returned by keyboard functions */#define	KSTD	0#define	KEOL	1		/* ^M, ^J */#define	KINTR	2		/* ^G, ^C */struct	x_ftab  {	int		(*xf_func) ARGS((int c));	const char	*xf_name;	short		xf_flags;};/* index into struct x_ftab x_ftab[] - small is good */typedef unsigned char Findex;struct x_defbindings {	Findex		xdb_func;	/* XFUNC_* */	unsigned char	xdb_tab;	unsigned char	xdb_char;};#define XF_ARG		1	/* command takes number prefix */#define	XF_NOBIND	2	/* not allowed to bind to function */#define	XF_PREFIX	4	/* function sets prefix *//* Separator for completion */#define	is_cfs(c)	(c == ' ' || c == '\t' || c == '"' || c == '\'')#define	is_mfs(c)	(!(isalnum(c) || c == '_' || c == '$'))  /* Separator for motion */#ifdef OS2  /* Deal with 8 bit chars & an extra prefix for function key (these two   * changes increase memory usage from 9,216 bytes to 24,416 bytes...)   */# define CHARMASK	0xFF		/* 8-bit ASCII character mask */# define X_NTABS	4		/* normal, meta1, meta2, meta3 */static int	x_prefix3 = 0xE0;#else /* OS2 */# define CHARMASK	0xFF		/* 8-bit character mask */# define X_NTABS	3		/* normal, meta1, meta2 */#endif /* OS2 */#define X_TABSZ		(CHARMASK+1)	/* size of keydef tables etc *//* Arguments for do_complete() * 0 = enumerate  M-= complete as much as possible and then list * 1 = complete   M-Esc * 2 = list       M-? */typedef enum { CT_LIST, 	/* list the possible completions */		 CT_COMPLETE,	/* complete to longest prefix */		 CT_COMPLIST	/* complete and then list (if non-exact) */	} Comp_type;/* { from 4.9 edit.h *//* * The following are used for my horizontal scrolling stuff */static char   *xbuf;		/* beg input buffer */static char   *xend;		/* end input buffer */static char    *xcp;		/* current position */static char    *xep;		/* current end */static char    *xbp;		/* start of visible portion of input buffer */static char    *xlp;		/* last char visible on screen */static int	x_adj_ok;/* * we use x_adj_done so that functions can tell  * whether x_adjust() has been called while they are active. */static int	x_adj_done;static int	xx_cols;static int	x_col;static int	x_displen;static int	x_arg;		/* general purpose arg */static int	x_arg_defaulted;/* x_arg not explicitly set; defaulted to 1 */static int	xlp_valid;/* end from 4.9 edit.h } */static	int	x_prefix1 = CTRL('['), x_prefix2 = CTRL('X');static	char   **x_histp;	/* history position */static	int	x_nextcmd;	/* for newline-and-next */static	char	*xmp;		/* mark pointer */static	Findex   x_last_command;static	Findex (*x_tab)[X_TABSZ];	/* key definition */static	char    *(*x_atab)[X_TABSZ];	/* macro definitions */static	unsigned char	x_bound[(X_TABSZ * X_NTABS + 7) / 8];#define	KILLSIZE	20static	char    *killstack[KILLSIZE];static	int	killsp, killtp;static	int	x_curprefix;static	char    *macroptr;static	int	prompt_skip;static int      x_ins       ARGS((char *cp));static void     x_delete    ARGS((int nc, int force_push));static int	x_bword     ARGS((void));static int	x_fword     ARGS((void));static void     x_goto      ARGS((char *cp));static void     x_bs        ARGS((int c));static int      x_size_str  ARGS((char *cp));static int      x_size      ARGS((int c));static void     x_zots      ARGS((char *str));static void     x_zotc      ARGS((int c));static void     x_load_hist ARGS((char **hp));static int      x_search    ARGS((char *pat, int sameline, int offset));static int      x_match     ARGS((char *str, char *pat));static void	x_redraw    ARGS((int limit));static void     x_push      ARGS((int nchars));static char *   x_mapin     ARGS((const char *cp));static char *   x_mapout    ARGS((int c));static void     x_print     ARGS((int prefix, int key));static void	x_adjust    ARGS((void));static void	x_e_ungetc  ARGS((int c));static int	x_e_getc    ARGS((void));static void	x_e_putc    ARGS((int c));static void	x_e_puts    ARGS((const char *s));static int	x_fold_case ARGS((int c));static char	*x_lastcp ARGS((void));static void	do_complete ARGS((int flags, Comp_type type));/* The lines between START-FUNC-TAB .. END-FUNC-TAB are run through a * script (emacs-gen.sh) that generates emacs.out which contains: *	- function declarations for x_* functions *	- defines of the form XFUNC_<name> where <name> is function *	  name, sans leading x_. * Note that the script treats #ifdef and { 0, 0, 0} specially - use with * caution. */#include "emacs.out"static const struct x_ftab x_ftab[] = {/* @START-FUNC-TAB@ */	{ x_abort,		"abort",			0 },	{ x_beg_hist,		"beginning-of-history",		0 },	{ x_comp_comm,		"complete-command",		0 },	{ x_comp_file,		"complete-file",		0 },	{ x_complete,		"complete",			0 },	{ x_del_back,		"delete-char-backward",		XF_ARG },	{ x_del_bword,		"delete-word-backward",		XF_ARG },	{ x_del_char,		"delete-char-forward",		XF_ARG },	{ x_del_fword,		"delete-word-forward",		XF_ARG },	{ x_del_line,		"kill-line",			0 },	{ x_draw_line,		"redraw",			0 },	{ x_end_hist,		"end-of-history",		0 },	{ x_end_of_text,	"eot",				0 },	{ x_enumerate,		"list",				0 },	{ x_eot_del,		"eot-or-delete",		XF_ARG },	{ x_error,		"error",			0 },	{ x_goto_hist,		"goto-history",			XF_ARG },	{ x_ins_string,		"macro-string",			XF_NOBIND },	{ x_insert,		"auto-insert",			XF_ARG },	{ x_kill,		"kill-to-eol",			XF_ARG },	{ x_kill_region,	"kill-region",			0 },	{ x_list_comm,		"list-command",			0 },	{ x_list_file,		"list-file",			0 },	{ x_literal,		"quote",			0 },	{ x_meta1,		"prefix-1",			XF_PREFIX },	{ x_meta2,		"prefix-2",			XF_PREFIX },	{ x_meta_yank,		"yank-pop",			0 },	{ x_mv_back,		"backward-char",		XF_ARG },	{ x_mv_begin,		"beginning-of-line",		0 },	{ x_mv_bword,		"backward-word",		XF_ARG },	{ x_mv_end,		"end-of-line",			0 },	{ x_mv_forw,		"forward-char",			XF_ARG },	{ x_mv_fword,		"forward-word",			XF_ARG },	{ x_newline,		"newline",			0 },	{ x_next_com,		"down-history",			XF_ARG },	{ x_nl_next_com,	"newline-and-next",		0 },	{ x_noop,		"no-op",			0 },	{ x_prev_com,		"up-history",			XF_ARG },	{ x_prev_histword,	"prev-hist-word",		XF_ARG },	{ x_search_char_forw,	"search-character-forward",	XF_ARG },	{ x_search_char_back,	"search-character-backward",	XF_ARG },	{ x_search_hist,	"search-history",		0 },	{ x_set_mark,		"set-mark-command",		0 },	{ x_stuff,		"stuff",			0 },	{ x_stuffreset,		"stuff-reset",			0 },	{ x_transpose,		"transpose-chars",		0 },	{ x_version,		"version",			0 },	{ x_xchg_point_mark,	"exchange-point-and-mark",	0 },	{ x_yank,		"yank",				0 },        { x_comp_list,		"complete-list",		0 },        { x_expand,		"expand-file",			0 },        { x_fold_capitialize,	"capitalize-word",		XF_ARG },        { x_fold_lower,		"downcase-word",		XF_ARG },        { x_fold_upper,		"upcase-word",			XF_ARG },        { x_set_arg,		"set-arg",			XF_NOBIND },        { x_comment,		"comment",			0 },#ifdef SILLY	{ x_game_of_life,	"play-game-of-life",		0 },#else	{ 0, 0, 0 },#endif#ifdef DEBUG        { x_debug_info,		"debug-info",			0 },#else	{ 0, 0, 0 },#endif#ifdef OS2	{ x_meta3,		"prefix-3",			XF_PREFIX },#else	{ 0, 0, 0 },#endif/* @END-FUNC-TAB@ */    };static	struct x_defbindings const x_defbindings[] = {	{ XFUNC_del_back,		0, CTRL('?') },	{ XFUNC_del_bword,		1, CTRL('?') },	{ XFUNC_eot_del,		0, CTRL('D') },	{ XFUNC_del_back,		0, CTRL('H') },	{ XFUNC_del_bword,		1, CTRL('H') },	{ XFUNC_del_bword,		1,      'h'  },	{ XFUNC_mv_bword,		1,      'b'  },	{ XFUNC_mv_fword,		1,      'f'  },	{ XFUNC_del_fword,		1,      'd'  },	{ XFUNC_mv_back,		0, CTRL('B') },	{ XFUNC_mv_forw,		0, CTRL('F') },	{ XFUNC_search_char_forw,	0, CTRL(']') },	{ XFUNC_search_char_back,	1, CTRL(']') },	{ XFUNC_newline,		0, CTRL('M') },	{ XFUNC_newline,		0, CTRL('J') },	{ XFUNC_end_of_text,		0, CTRL('_') },	{ XFUNC_abort,			0, CTRL('G') },	{ XFUNC_prev_com,		0, CTRL('P') },	{ XFUNC_next_com,		0, CTRL('N') },	{ XFUNC_nl_next_com,		0, CTRL('O') },	{ XFUNC_search_hist,		0, CTRL('R') },	{ XFUNC_beg_hist,		1,      '<'  },	{ XFUNC_end_hist,		1,      '>'  },	{ XFUNC_goto_hist,		1,      'g'  },	{ XFUNC_mv_end,			0, CTRL('E') },	{ XFUNC_mv_begin,		0, CTRL('A') },	{ XFUNC_draw_line,		0, CTRL('L') },	{ XFUNC_meta1,			0, CTRL('[') },	{ XFUNC_meta2,			0, CTRL('X') },	{ XFUNC_kill,			0, CTRL('K') },	{ XFUNC_yank,			0, CTRL('Y') },	{ XFUNC_meta_yank,		1,      'y'  },	{ XFUNC_literal,		0, CTRL('^') },        { XFUNC_comment,		1,	'#'  },#if defined(BRL) && defined(TIOCSTI)	{ XFUNC_stuff,			0, CTRL('T') },#else	{ XFUNC_transpose,		0, CTRL('T') },#endif	{ XFUNC_complete,		1, CTRL('[') },        { XFUNC_comp_list,		1,	'='  },	{ XFUNC_enumerate,		1,	'?'  },        { XFUNC_expand,			1,	'*'  },	{ XFUNC_comp_file,		1, CTRL('X') },	{ XFUNC_comp_comm,		2, CTRL('[') },	{ XFUNC_list_comm,		2,	'?'  },	{ XFUNC_list_file,		2, CTRL('Y') },	{ XFUNC_set_mark,		1,	' '  },	{ XFUNC_kill_region,		0, CTRL('W') },	{ XFUNC_xchg_point_mark,	2, CTRL('X') },	{ XFUNC_version,		0, CTRL('V') },#ifdef DEBUG        { XFUNC_debug_info,		1, CTRL('H') },#endif	{ XFUNC_prev_histword,		1,	'.'  },	{ XFUNC_prev_histword,		1,	'_'  },        { XFUNC_set_arg,		1,	'0'  },        { XFUNC_set_arg,		1,	'1'  },        { XFUNC_set_arg,		1,	'2'  },        { XFUNC_set_arg,		1,	'3'  },        { XFUNC_set_arg,		1,	'4'  },        { XFUNC_set_arg,		1,	'5'  },        { XFUNC_set_arg,		1,	'6'  },        { XFUNC_set_arg,		1,	'7'  },        { XFUNC_set_arg,		1,	'8'  },        { XFUNC_set_arg,		1,	'9'  },        { XFUNC_fold_upper,		1,	'U'  },        { XFUNC_fold_upper,		1,	'u'  },        { XFUNC_fold_lower,		1,	'L'  },        { XFUNC_fold_lower,		1,	'l'  },        { XFUNC_fold_capitialize,	1,	'C'  },        { XFUNC_fold_capitialize,	1,	'c'  },#ifdef OS2	{ XFUNC_meta3,			0,	0xE0 },	{ XFUNC_mv_back,		3,	'K'  },	{ XFUNC_mv_forw,		3,	'M'  },	{ XFUNC_next_com,		3,	'P'  },	{ XFUNC_prev_com,		3,	'H'  },#endif /* OS2 */	/* These for ansi arrow keys: arguablely shouldn't be here by	 * default, but its simpler/faster/smaller than using termcap	 * entries.	 */        { XFUNC_meta2,			1,	'['  },	{ XFUNC_prev_com,		2,	'A'  },	{ XFUNC_next_com,		2,	'B'  },	{ XFUNC_mv_forw,		2,	'C'  },	{ XFUNC_mv_back,		2,	'D'  },};intx_emacs(buf, len)	char *buf;	size_t len;{	int	c;	const char *p;	int	i;	Findex	f;	xbp = xbuf = buf; xend = buf + len;	xlp = xcp = xep = buf;	*xcp = 0;	xlp_valid = TRUE;	xmp = NULL;	x_curprefix = 0;	macroptr = (char *) 0;	x_histp = histptr + 1;	x_last_command = XFUNC_error;	xx_cols = x_cols;	x_col = promptlen(prompt, &p);	prompt_skip = p - prompt;	x_adj_ok = 1;	x_displen = xx_cols - 2 - x_col;	x_adj_done = 0;	pprompt(prompt, 0);	if (x_nextcmd >= 0) {		int off = source->line - x_nextcmd;		if (histptr - history >= off)			x_load_hist(histptr - off);		x_nextcmd = -1;	}	while (1) {		x_flush();		if ((c = x_e_getc()) < 0)			return 0;		f = x_curprefix == -1 ? XFUNC_insert			: x_tab[x_curprefix][c&CHARMASK]; 		if (!(x_ftab[f].xf_flags & XF_PREFIX)		    && x_last_command != XFUNC_set_arg)		{			x_arg = 1;			x_arg_defaulted = 1;		}		i = c | (x_curprefix << 8);		x_curprefix = 0;		switch (i = (*x_ftab[f].xf_func)(i))  {		  case KSTD:			if (!(x_ftab[f].xf_flags & XF_PREFIX))				x_last_command = f;			break;		  case KEOL:			i = xep - xbuf;			return i;		  case KINTR:	/* special case for interrupt */			trapsig(SIGINT);			x_mode(FALSE);			unwind(LSHELL);		}	}}static intx_insert(c)	int c;{	char	str[2];	/*	 *  Should allow tab and control chars.	 */	if (c == 0)  {		x_e_putc(BEL);		return KSTD;	}	str[0] = c;	str[1] = '\0';	while (x_arg--)		x_ins(str);	return KSTD;}static intx_ins_string(c)	int c;{	if (macroptr)   {		x_e_putc(BEL);		return KSTD;	}	macroptr = x_atab[c>>8][c & CHARMASK];	if (macroptr && !*macroptr) {		/* XXX bell? */		macroptr = (char *) 0;	}	return KSTD;}static intx_do_ins(cp, len)	const char *cp;	int len;{	if (xep+len >= xend) {		x_e_putc(BEL);		return -1;	}	memmove(xcp+len, xcp, xep - xcp + 1);	memmove(xcp, cp, len);	xcp += len;	xep += len;	return 0;}static intx_ins(s)	char	*s;{	char *cp = xcp;	register int	adj = x_adj_done;	if (x_do_ins(s, strlen(s)) < 0)		return -1;	/*	 * x_zots() may result in a call to x_adjust()	 * we want xcp to reflect the new position.	 */	xlp_valid = FALSE;	x_lastcp();	x_adj_ok = (xcp >= xlp);	x_zots(cp);	if (adj == x_adj_done)	/* has x_adjust() been called? */	{	  /* no */	  for (cp = xlp; cp > xcp; )	    x_bs(*--cp);	}	x_adj_ok = 1;	return 0;}static intx_del_back(c)	int c;{	int col = xcp - xbuf;	if (col == 0)  {		x_e_putc(BEL);		return KSTD;	}	if (x_arg > col)		x_arg = col;	x_goto(xcp - x_arg);	x_delete(x_arg, FALSE);	return KSTD;}static intx_del_char(c)	int c;{	int nleft = xep - xcp;	if (!nleft) {		x_e_putc(BEL);		return KSTD;	}	if (x_arg > nleft)		x_arg = nleft;	x_delete(x_arg, FALSE);	return KSTD;}/* Delete nc chars to the right of the cursor (including cursor position) */static voidx_delete(nc, force_push)	int nc;	int force_push;{	int	i,j;	char	*cp;		if (nc == 0)		return;	if (xmp != NULL && xmp > xcp) {		if (xcp + nc > xmp)			xmp = xcp;		else			xmp -= nc;	}	/*	 * This lets us yank a word we have deleted.	 */	if (nc > 1 || force_push)		x_push(nc);	xep -= nc;	cp = xcp;	j = 0;	i = nc;	while (i--)  {		j += x_size(*cp++);	}	memmove(xcp, xcp+nc, xep - xcp + 1);	/* Copies the null */	x_adj_ok = 0;			/* don't redraw */	x_zots(xcp);	/*	 * if we are already filling the line,	 * there is no need to ' ','\b'.	 * But if we must, make sure we do the minimum.	 */	if ((i = xx_cols - 2 - x_col) > 0)	{	  j = (j < i) ? j : i;	  i = j;	  while (i--)	    x_e_putc(' ');	  i = j;	  while (i--)	    x_e_putc('\b');	}	/*x_goto(xcp);*/	x_adj_ok = 1;	xlp_valid = FALSE;	for (cp = x_lastcp(); cp > xcp; )		x_bs(*--cp);	return;	}static intx_del_bword(c)	int c;{	x_delete(x_bword(), FALSE);	return KSTD;}static intx_mv_bword(c)	int c;{	(void)x_bword();	return KSTD;}static intx_mv_fword(c)	int c;{	x_goto(xcp + x_fword());	return KSTD;}static intx_del_fword(c)	int c;{	x_delete(x_fword(), FALSE);	return KSTD;}static intx_bword(){	int	nc = 0;	register char *cp = xcp;	if (cp == xbuf)  {		x_e_putc(BEL);		return 0;	}	while (x_arg--)	{	  while (cp != xbuf && is_mfs(cp[-1]))	  {	    cp--;	    nc++;	  }	  while (cp != xbuf && !is_mfs(cp[-1]))	  {	    cp--;	    nc++;	  }	}	x_goto(cp);	return nc;}static intx_fword(){	int	nc = 0;	register char	*cp = xcp;	if (cp == xep)  {		x_e_putc(BEL);		return 0;	}	while (x_arg--)	{	  while (cp != xep && is_mfs(*cp))	  {	    cp++;	    nc++;	  }	  while (cp != xep && !is_mfs(*cp))	  {	    cp++;	    nc++;	  }	}	return nc;}static voidx_goto(cp)	register char *cp;{  if (cp < xbp || cp >= (xbp + x_displen))  {    /* we are heading off screen */    xcp = cp;    x_adjust();  }  else  {    if (cp < xcp)		/* move back */    {      while (cp < xcp)	x_bs(*--xcp);    }    else    {      if (cp > xcp)		/* move forward */      {	while (cp > xcp)	  x_zotc(*xcp++);      }    }  }}static voidx_bs(c)	int c;{	register int i;	i = x_size(c);	while (i--)		x_e_putc('\b');}static intx_size_str(cp)	register char *cp;{	register int size = 0;	while (*cp)		size += x_size(*cp++);	return size;}static intx_size(c)	int c;{	if (c=='\t')		return 4;	/* Kludge, tabs are always four spaces. */	if (iscntrl(c))		/* control char */		return 2;	return 1;}static voidx_zots(str)	register char *str;{  register int	adj = x_adj_done;  x_lastcp();  while (*str && str < xlp && adj == x_adj_done)    x_zotc(*str++);}static voidx_zotc(c)	int c;{	if (c == '\t')  {		/*  Kludge, tabs are always four spaces.  */		x_e_puts("    ");	} else if (iscntrl(c))  {		x_e_putc('^');		x_e_putc(UNCTRL(c));	} else		x_e_putc(c);}static intx_mv_back(c)	int c;{

⌨️ 快捷键说明

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