xref: /onnv-gate/usr/src/lib/libshell/common/edit/emacs.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1982-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                  David Korn <dgk@research.att.com>                   *
184887Schin *                                                                      *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /* Original version by Michael T. Veach
224887Schin  * Adapted for ksh by David Korn */
234887Schin /* EMACS_MODES: c tabstop=4
244887Schin 
254887Schin One line screen editor for any program
264887Schin 
274887Schin */
284887Schin 
294887Schin 
304887Schin /*	The following is provided by:
314887Schin  *
324887Schin  *			Matthijs N. Melchior
334887Schin  *			AT&T Network Systems International
344887Schin  *			APT Nederland
354887Schin  *			HV BZ335 x2962
364887Schin  *			hvlpb!mmelchio
374887Schin  *
384887Schin  *  These are now on by default
394887Schin  *
404887Schin  *  ESH_NFIRST
414887Schin  *	-  A ^N as first history related command after the prompt will move
424887Schin  *	   to the next command relative to the last known history position.
434887Schin  *	   It will not start at the position where the last command was entered
444887Schin  *	   as is done by the ^P command.  Every history related command will
454887Schin  *	   set both the current and last position.  Executing a command will
464887Schin  *	   only set the current position.
474887Schin  *
484887Schin  *  ESH_KAPPEND
494887Schin  *	-  Successive kill and delete commands will accumulate their data
504887Schin  *	   in the kill buffer, by appending or prepending as appropriate.
514887Schin  *	   This mode will be reset by any command not adding something to the
524887Schin  *	   kill buffer.
534887Schin  *
544887Schin  *  ESH_BETTER
554887Schin  *	-  Some enhancements:
564887Schin  *		- argument for a macro is passed to its replacement
574887Schin  *		- ^X^H command to find out about history position (debugging)
584887Schin  *		- ^X^D command to show any debugging info
594887Schin  *
604887Schin  *  I do not pretend these for changes are completely independent,
614887Schin  *  but you can use them to seperate features.
624887Schin  */
634887Schin 
644887Schin #include	<ast.h>
654887Schin #include	"FEATURE/cmds"
664887Schin #if KSHELL
674887Schin #   include	"defs.h"
6810898Sroland.mainz@nrubsig.org #else
6910898Sroland.mainz@nrubsig.org #   include	<ctype.h>
704887Schin #endif	/* KSHELL */
714887Schin #include	"io.h"
724887Schin 
734887Schin #include	"history.h"
744887Schin #include	"edit.h"
754887Schin #include	"terminal.h"
764887Schin 
774887Schin #define ESH_NFIRST
784887Schin #define ESH_KAPPEND
794887Schin #define ESH_BETTER
804887Schin 
814887Schin #undef putchar
824887Schin #define putchar(ed,c)	ed_putchar(ed,c)
834887Schin #define beep()		ed_ringbell()
844887Schin 
854887Schin 
864887Schin #if SHOPT_MULTIBYTE
874887Schin #   define gencpy(a,b)	ed_gencpy(a,b)
884887Schin #   define genncpy(a,b,n)	ed_genncpy(a,b,n)
894887Schin #   define genlen(str)	ed_genlen(str)
904887Schin     static int	print(int);
914887Schin     static int	_isword(int);
924887Schin #   define  isword(c)	_isword(out[c])
934887Schin 
944887Schin #else
954887Schin #   define gencpy(a,b)	strcpy((char*)(a),(char*)(b))
964887Schin #   define genncpy(a,b,n)	strncpy((char*)(a),(char*)(b),n)
974887Schin #   define genlen(str)	strlen(str)
984887Schin #   define print(c)	isprint(c)
994887Schin #   define isword(c)	(isalnum(out[c]) || (out[c]=='_'))
1004887Schin #endif /*SHOPT_MULTIBYTE */
1014887Schin 
1024887Schin typedef struct _emacs_
1034887Schin {
1044887Schin 	genchar *screen;	/* pointer to window buffer */
1054887Schin 	genchar *cursor;	/* Cursor in real screen */
1064887Schin 	int 	mark;
1074887Schin 	int 	in_mult;
1084887Schin 	char	cr_ok;
1094887Schin 	char	CntrlO;
1104887Schin 	char	overflow;		/* Screen overflow flag set */
1114887Schin 	char	scvalid;		/* Screen is up to date */
1128462SApril.Chin@Sun.COM 	char	lastdraw;	/* last update type */
1134887Schin 	int	offset;		/* Screen offset */
1144887Schin 	enum
1154887Schin 	{
1164887Schin 		CRT=0,	/* Crt terminal */
1174887Schin 		PAPER	/* Paper terminal */
1184887Schin 	} terminal;
1194887Schin 	Histloc_t _location;
1204887Schin 	int	prevdirection;
1214887Schin 	Edit_t	*ed;	/* pointer to edit data */
1224887Schin } Emacs_t;
1234887Schin 
1244887Schin #define	editb		(*ep->ed)
1254887Schin #define eol		editb.e_eol
1264887Schin #define cur		editb.e_cur
1274887Schin #define hline		editb.e_hline
1284887Schin #define hloff		editb.e_hloff
1294887Schin #define hismin		editb.e_hismin
1304887Schin #define usrkill		editb.e_kill
1314887Schin #define usrlnext	editb.e_lnext
1324887Schin #define usreof		editb.e_eof
1334887Schin #define usrerase	editb.e_erase
1344887Schin #define crallowed	editb.e_crlf
1354887Schin #define Prompt		editb.e_prompt
1364887Schin #define plen		editb.e_plen
1374887Schin #define kstack		editb.e_killbuf
1384887Schin #define lstring		editb.e_search
1394887Schin #define lookahead	editb.e_lookahead
1404887Schin #define env		editb.e_env
1414887Schin #define raw		editb.e_raw
1424887Schin #define histlines	editb.e_hismax
1434887Schin #define w_size		editb.e_wsize
1444887Schin #define drawbuff	editb.e_inbuf
1454887Schin #define killing		editb.e_mode
1464887Schin #define location	ep->_location
1474887Schin 
1484887Schin #define LBUF	100
1494887Schin #define KILLCHAR	UKILL
1504887Schin #define ERASECHAR	UERASE
1514887Schin #define EOFCHAR		UEOF
1524887Schin #define LNEXTCHAR		ULNEXT
1534887Schin #define DELETE		('a'==97?0177:7)
1544887Schin 
1554887Schin /**********************
1564887Schin A large lookahead helps when the user is inserting
1574887Schin characters in the middle of the line.
1584887Schin ************************/
1594887Schin 
1604887Schin 
1614887Schin typedef enum
1624887Schin {
1634887Schin 	FIRST,		/* First time thru for logical line, prompt on screen */
1644887Schin 	REFRESH,	/* Redraw entire screen */
1654887Schin 	APPEND,		/* Append char before cursor to screen */
1664887Schin 	UPDATE,		/* Update the screen as need be */
1674887Schin 	FINAL		/* Update screen even if pending look ahead */
1684887Schin } Draw_t;
1694887Schin 
1704887Schin static void draw(Emacs_t*,Draw_t);
1714887Schin static int escape(Emacs_t*,genchar*, int);
1724887Schin static void putstring(Emacs_t*,char*);
1734887Schin static void search(Emacs_t*,genchar*,int);
1744887Schin static void setcursor(Emacs_t*,int, int);
1754887Schin static void show_info(Emacs_t*,const char*);
1764887Schin static void xcommands(Emacs_t*,int);
1774887Schin 
ed_emacsread(void * context,int fd,char * buff,int scend,int reedit)1784887Schin int ed_emacsread(void *context, int fd,char *buff,int scend, int reedit)
1794887Schin {
1804887Schin 	Edit_t *ed = (Edit_t*)context;
1814887Schin 	register int c;
1824887Schin 	register int i;
1834887Schin 	register genchar *out;
1844887Schin 	register int count;
1854887Schin 	register Emacs_t *ep = ed->e_emacs;
1864887Schin 	int adjust,oadjust;
1874887Schin 	char backslash;
1884887Schin 	genchar *kptr;
1894887Schin 	char prompt[PRSIZE];
1904887Schin 	genchar Screen[MAXLINE];
1914887Schin 	if(!ep)
1924887Schin 	{
1934887Schin 		ep = ed->e_emacs = newof(0,Emacs_t,1,0);
1944887Schin 		ep->ed = ed;
1954887Schin 		ep->prevdirection =  1;
1964887Schin 		location.hist_command =  -5;
1974887Schin 	}
1984887Schin 	Prompt = prompt;
1994887Schin 	ep->screen = Screen;
2008462SApril.Chin@Sun.COM 	ep->lastdraw = FINAL;
2014887Schin 	if(tty_raw(ERRIO,0) < 0)
2024887Schin 	{
2034887Schin 		 return(reedit?reedit:ed_read(context, fd,buff,scend,0));
2044887Schin 	}
2054887Schin 	raw = 1;
2064887Schin 	/* This mess in case the read system call fails */
2074887Schin 
2084887Schin 	ed_setup(ep->ed,fd,reedit);
2094887Schin 	out = (genchar*)buff;
2104887Schin #if SHOPT_MULTIBYTE
21110898Sroland.mainz@nrubsig.org 	out = (genchar*)roundof(buff-(char*)0,sizeof(genchar));
21210898Sroland.mainz@nrubsig.org 	if(reedit)
21310898Sroland.mainz@nrubsig.org 		ed_internal(buff,out);
2144887Schin #endif /* SHOPT_MULTIBYTE */
2154887Schin 	if(!kstack)
2164887Schin 	{
2174887Schin 		kstack = (genchar*)malloc(CHARSIZE*MAXLINE);
2184887Schin 		kstack[0] = '\0';
2194887Schin 	}
2204887Schin 	drawbuff = out;
2214887Schin #ifdef ESH_NFIRST
2224887Schin 	if (location.hist_command == -5)		/* to be initialized */
2234887Schin 	{
2244887Schin 		kstack[0] = '\0';		/* also clear kstack... */
2254887Schin 		location.hist_command = hline;
2264887Schin 		location.hist_line = hloff;
2274887Schin 	}
2284887Schin 	if (location.hist_command <= hismin)	/* don't start below minimum */
2294887Schin 	{
2304887Schin 		location.hist_command = hismin + 1;
2314887Schin 		location.hist_line = 0;
2324887Schin 	}
2334887Schin 	ep->in_mult = hloff;			/* save pos in last command */
2344887Schin #endif /* ESH_NFIRST */
2354887Schin 	i = sigsetjmp(env,0);
2364887Schin 	if (i !=0)
2374887Schin 	{
2388462SApril.Chin@Sun.COM 		if(ep->ed->e_multiline)
2398462SApril.Chin@Sun.COM 		{
2408462SApril.Chin@Sun.COM 			cur = eol;
2418462SApril.Chin@Sun.COM 			draw(ep,FINAL);
2428462SApril.Chin@Sun.COM 			ed_flush(ep->ed);
2438462SApril.Chin@Sun.COM 		}
2444887Schin 		tty_cooked(ERRIO);
2454887Schin 		if (i == UEOF)
2464887Schin 		{
2474887Schin 			return(0); /* EOF */
2484887Schin 		}
2494887Schin 		return(-1); /* some other error */
2504887Schin 	}
2514887Schin 	out[reedit] = 0;
2524887Schin 	if(scend+plen > (MAXLINE-2))
2534887Schin 		scend = (MAXLINE-2)-plen;
2544887Schin 	ep->mark = 0;
2554887Schin 	cur = eol;
2564887Schin 	draw(ep,reedit?REFRESH:FIRST);
2574887Schin 	adjust = -1;
2584887Schin 	backslash = 0;
2594887Schin 	if (ep->CntrlO)
2604887Schin 	{
2614887Schin #ifdef ESH_NFIRST
2624887Schin 		ed_ungetchar(ep->ed,cntl('N'));
2634887Schin #else
2644887Schin 		location = hist_locate(sh.hist_ptr,location.hist_command,location.hist_line,1);
2654887Schin 		if (location.hist_command < histlines)
2664887Schin 		{
2674887Schin 			hline = location.hist_command;
2684887Schin 			hloff = location.hist_line;
2694887Schin 			hist_copy((char*)kstack,MAXLINE, hline,hloff);
2704887Schin #   if SHOPT_MULTIBYTE
2714887Schin 			ed_internal((char*)kstack,kstack);
2724887Schin #   endif /* SHOPT_MULTIBYTE */
2734887Schin 			ed_ungetchar(ep->ed,cntl('Y'));
2744887Schin 		}
2754887Schin #endif /* ESH_NFIRST */
2764887Schin 	}
2774887Schin 	ep->CntrlO = 0;
2784887Schin 	while ((c = ed_getchar(ep->ed,0)) != (-1))
2794887Schin 	{
2804887Schin 		if (backslash)
2814887Schin 		{
2824887Schin 			backslash = 0;
2834887Schin 			if (c==usrerase||c==usrkill||(!print(c) &&
2844887Schin 				(c!='\r'&&c!='\n')))
2854887Schin 			{
2864887Schin 				/* accept a backslashed character */
2874887Schin 				cur--;
2884887Schin 				out[cur++] = c;
2894887Schin 				out[eol] = '\0';
2904887Schin 				draw(ep,APPEND);
2914887Schin 				continue;
2924887Schin 			}
2934887Schin 		}
2944887Schin 		if (c == usrkill)
2954887Schin 		{
2964887Schin 			c = KILLCHAR ;
2974887Schin 		}
2984887Schin 		else if (c == usrerase)
2994887Schin 		{
3004887Schin 			c = ERASECHAR ;
3014887Schin 		}
3024887Schin 		else if (c == usrlnext)
3034887Schin 		{
3044887Schin 			c = LNEXTCHAR ;
3054887Schin 		}
3064887Schin 		else if ((c == usreof)&&(eol == 0))
3074887Schin 		{
3084887Schin 			c = EOFCHAR;
3094887Schin 		}
3104887Schin #ifdef ESH_KAPPEND
3114887Schin 		if (--killing <= 0)	/* reset killing flag */
3124887Schin 			killing = 0;
3134887Schin #endif
3144887Schin 		oadjust = count = adjust;
3154887Schin 		if(count<0)
3164887Schin 			count = 1;
3174887Schin 		adjust = -1;
3184887Schin 		i = cur;
3194887Schin 		switch(c)
3204887Schin 		{
3214887Schin 		case LNEXTCHAR:
3224887Schin 			c = ed_getchar(ep->ed,2);
3234887Schin 			goto do_default_processing;
3244887Schin 		case cntl('V'):
3254887Schin 			show_info(ep,fmtident(e_version));
3264887Schin 			continue;
3274887Schin 		case '\0':
3284887Schin 			ep->mark = i;
3294887Schin 			continue;
3304887Schin 		case cntl('X'):
3314887Schin 			xcommands(ep,count);
3324887Schin 			continue;
3334887Schin 		case EOFCHAR:
3344887Schin 			ed_flush(ep->ed);
3354887Schin 			tty_cooked(ERRIO);
3364887Schin 			return(0);
3374887Schin #ifdef u370
3384887Schin 		case cntl('S') :
3394887Schin 		case cntl('Q') :
3404887Schin 			continue;
3414887Schin #endif	/* u370 */
3424887Schin 		case '\t':
3434887Schin 			if(cur>0  && ep->ed->sh->nextprompt)
3444887Schin 			{
3454887Schin 				if(ep->ed->e_tabcount==0)
3464887Schin 				{
3474887Schin 					ep->ed->e_tabcount=1;
3484887Schin 					ed_ungetchar(ep->ed,ESC);
3494887Schin 					goto do_escape;
3504887Schin 				}
3514887Schin 				else if(ep->ed->e_tabcount==1)
3524887Schin 				{
3534887Schin 					ed_ungetchar(ep->ed,'=');
3544887Schin 					goto do_escape;
3554887Schin 				}
3564887Schin 				ep->ed->e_tabcount = 0;
3574887Schin 			}
3584887Schin 		do_default_processing:
3594887Schin 		default:
3604887Schin 
3614887Schin 			if ((eol+1) >= (scend)) /*  will not fit on line */
3624887Schin 			{
3634887Schin 				ed_ungetchar(ep->ed,c); /* save character for next line */
3644887Schin 				goto process;
3654887Schin 			}
3664887Schin 			for(i= ++eol; i>cur; i--)
3674887Schin 				out[i] = out[i-1];
3684887Schin 			backslash =  (c == '\\');
3694887Schin 			out[cur++] = c;
3704887Schin 			draw(ep,APPEND);
3714887Schin 			continue;
3724887Schin 		case cntl('Y') :
3734887Schin 			{
3744887Schin 				c = genlen(kstack);
3754887Schin 				if ((c + eol) > scend)
3764887Schin 				{
3774887Schin 					beep();
3784887Schin 					continue;
3794887Schin 				}
3804887Schin 				ep->mark = i;
3814887Schin 				for(i=eol;i>=cur;i--)
3824887Schin 					out[c+i] = out[i];
3834887Schin 				kptr=kstack;
3844887Schin 				while (i = *kptr++)
3854887Schin 					out[cur++] = i;
3864887Schin 				draw(ep,UPDATE);
3874887Schin 				eol = genlen(out);
3884887Schin 				continue;
3894887Schin 			}
3904887Schin 		case '\n':
3914887Schin 		case '\r':
3924887Schin 			c = '\n';
3934887Schin 			goto process;
3944887Schin 
3954887Schin 		case DELETE:	/* delete char 0x7f */
3964887Schin 		case '\b':	/* backspace, ^h */
3974887Schin 		case ERASECHAR :
3984887Schin 			if (count > i)
3994887Schin 				count = i;
4004887Schin #ifdef ESH_KAPPEND
4014887Schin 			kptr = &kstack[count];	/* move old contents here */
4024887Schin 			if (killing)		/* prepend to killbuf */
4034887Schin 			{
4044887Schin 				c = genlen(kstack) + CHARSIZE; /* include '\0' */
4054887Schin 				while(c--)	/* copy stuff */
4064887Schin 					kptr[c] = kstack[c];
4074887Schin 			}
4084887Schin 			else
4094887Schin 				*kptr = 0;	/* this is end of data */
4104887Schin 			killing = 2;		/* we are killing */
4114887Schin 			i -= count;
4124887Schin 			eol -= count;
4134887Schin 			genncpy(kstack,out+i,cur-i);
4144887Schin #else
4154887Schin 			while ((count--)&&(i>0))
4164887Schin 			{
4174887Schin 				i--;
4184887Schin 				eol--;
4194887Schin 			}
4204887Schin 			genncpy(kstack,out+i,cur-i);
4214887Schin 			kstack[cur-i] = 0;
4224887Schin #endif /* ESH_KAPPEND */
4234887Schin 			gencpy(out+i,out+cur);
4244887Schin 			ep->mark = i;
4254887Schin 			goto update;
4264887Schin 		case cntl('W') :
4274887Schin #ifdef ESH_KAPPEND
4284887Schin 			++killing;		/* keep killing flag */
4294887Schin #endif
4304887Schin 			if (ep->mark > eol )
4314887Schin 				ep->mark = eol;
4324887Schin 			if (ep->mark == i)
4334887Schin 				continue;
4344887Schin 			if (ep->mark > i)
4354887Schin 			{
4364887Schin 				adjust = ep->mark - i;
4374887Schin 				ed_ungetchar(ep->ed,cntl('D'));
4384887Schin 				continue;
4394887Schin 			}
4404887Schin 			adjust = i - ep->mark;
4414887Schin 			ed_ungetchar(ep->ed,usrerase);
4424887Schin 			continue;
4434887Schin 		case cntl('D') :
4444887Schin 			ep->mark = i;
4454887Schin #ifdef ESH_KAPPEND
4464887Schin 			if (killing)
4474887Schin 				kptr = &kstack[genlen(kstack)];	/* append here */
4484887Schin 			else
4494887Schin 				kptr = kstack;
4504887Schin 			killing = 2;			/* we are now killing */
4514887Schin #else
4524887Schin 			kptr = kstack;
4534887Schin #endif /* ESH_KAPPEND */
4544887Schin 			while ((count--)&&(eol>0)&&(i<eol))
4554887Schin 			{
4564887Schin 				*kptr++ = out[i];
4574887Schin 				eol--;
4584887Schin 				while(1)
4594887Schin 				{
4604887Schin 					if ((out[i] = out[(i+1)])==0)
4614887Schin 						break;
4624887Schin 					i++;
4634887Schin 				}
4644887Schin 				i = cur;
4654887Schin 			}
4664887Schin 			*kptr = '\0';
4674887Schin 			goto update;
4684887Schin 		case cntl('C') :
4694887Schin 		case cntl('F') :
4704887Schin 		{
4714887Schin 			int cntlC = (c==cntl('C'));
4724887Schin 			while (count-- && eol>i)
4734887Schin 			{
4744887Schin 				if (cntlC)
4754887Schin 				{
4764887Schin 					c = out[i];
4774887Schin #if SHOPT_MULTIBYTE
4784887Schin 					if((c&~STRIP)==0 && islower(c))
4794887Schin #else
4804887Schin 					if(islower(c))
4814887Schin #endif /* SHOPT_MULTIBYTE */
4824887Schin 					{
4834887Schin 						c += 'A' - 'a';
4844887Schin 						out[i] = c;
4854887Schin 					}
4864887Schin 				}
4874887Schin 				i++;
4884887Schin 			}
4894887Schin 			goto update;
4904887Schin 		}
4914887Schin 		case cntl(']') :
4924887Schin 			c = ed_getchar(ep->ed,1);
4934887Schin 			if ((count == 0) || (count > eol))
4944887Schin                         {
4954887Schin                                 beep();
4964887Schin                                 continue;
4974887Schin                         }
4984887Schin 			if (out[i])
4994887Schin 				i++;
5004887Schin 			while (i < eol)
5014887Schin 			{
5024887Schin 				if (out[i] == c && --count==0)
5034887Schin 					goto update;
5044887Schin 				i++;
5054887Schin 			}
5064887Schin 			i = 0;
5074887Schin 			while (i < cur)
5084887Schin 			{
5094887Schin 				if (out[i] == c && --count==0)
5104887Schin 					break;
5114887Schin 				i++;
5124887Schin 			};
5134887Schin 
5144887Schin update:
5154887Schin 			cur = i;
5164887Schin 			draw(ep,UPDATE);
5174887Schin 			continue;
5184887Schin 
5194887Schin 		case cntl('B') :
5204887Schin 			if (count > i)
5214887Schin 				count = i;
5224887Schin 			i -= count;
5234887Schin 			goto update;
5244887Schin 		case cntl('T') :
5254887Schin 			if ((sh_isoption(SH_EMACS))&& (eol!=i))
5264887Schin 				i++;
5274887Schin 			if (i >= 2)
5284887Schin 			{
5294887Schin 				c = out[i - 1];
5304887Schin 				out[i-1] = out[i-2];
5314887Schin 				out[i-2] = c;
5324887Schin 			}
5334887Schin 			else
5344887Schin 			{
5354887Schin 				if(sh_isoption(SH_EMACS))
5364887Schin 					i--;
5374887Schin 				beep();
5384887Schin 				continue;
5394887Schin 			}
5404887Schin 			goto update;
5414887Schin 		case cntl('A') :
5424887Schin 			i = 0;
5434887Schin 			goto update;
5444887Schin 		case cntl('E') :
5454887Schin 			i = eol;
5464887Schin 			goto update;
5474887Schin 		case cntl('U') :
5484887Schin 			adjust = 4*count;
5494887Schin 			continue;
5504887Schin 		case KILLCHAR :
5514887Schin 			cur = 0;
5524887Schin 			oadjust = -1;
5534887Schin 		case cntl('K') :
5544887Schin 			if(oadjust >= 0)
5554887Schin 			{
5564887Schin #ifdef ESH_KAPPEND
5574887Schin 				killing = 2;		/* set killing signal */
5584887Schin #endif
5594887Schin 				ep->mark = count;
5604887Schin 				ed_ungetchar(ep->ed,cntl('W'));
5614887Schin 				continue;
5624887Schin 			}
5634887Schin 			i = cur;
5644887Schin 			eol = i;
5654887Schin 			ep->mark = i;
5664887Schin #ifdef ESH_KAPPEND
5674887Schin 			if (killing)			/* append to kill buffer */
5684887Schin 				gencpy(&kstack[genlen(kstack)], &out[i]);
5694887Schin 			else
5704887Schin 				gencpy(kstack,&out[i]);
5714887Schin 			killing = 2;			/* set killing signal */
5724887Schin #else
5734887Schin 			gencpy(kstack,&out[i]);
5744887Schin #endif /* ESH_KAPPEND */
5754887Schin 			out[i] = 0;
5764887Schin 			draw(ep,UPDATE);
5774887Schin 			if (c == KILLCHAR)
5784887Schin 			{
5794887Schin 				if (ep->terminal == PAPER)
5804887Schin 				{
5814887Schin 					putchar(ep->ed,'\n');
5824887Schin 					putstring(ep,Prompt);
5834887Schin 				}
5844887Schin 				c = ed_getchar(ep->ed,0);
5854887Schin 				if (c != usrkill)
5864887Schin 				{
5874887Schin 					ed_ungetchar(ep->ed,c);
5884887Schin 					continue;
5894887Schin 				}
5904887Schin 				if (ep->terminal == PAPER)
5914887Schin 					ep->terminal = CRT;
5924887Schin 				else
5934887Schin 				{
5944887Schin 					ep->terminal = PAPER;
5954887Schin 					putchar(ep->ed,'\n');
5964887Schin 					putstring(ep,Prompt);
5974887Schin 				}
5984887Schin 			}
5994887Schin 			continue;
6004887Schin 		case cntl('L'):
6018462SApril.Chin@Sun.COM 			if(!ep->ed->e_nocrnl)
6028462SApril.Chin@Sun.COM 				ed_crlf(ep->ed);
6034887Schin 			draw(ep,REFRESH);
6048462SApril.Chin@Sun.COM 			ep->ed->e_nocrnl = 0;
6054887Schin 			continue;
6064887Schin 		case cntl('[') :
6074887Schin 		do_escape:
6084887Schin 			adjust = escape(ep,out,oadjust);
6094887Schin 			continue;
6104887Schin 		case cntl('R') :
6114887Schin 			search(ep,out,count);
6124887Schin 			goto drawline;
6134887Schin 		case cntl('P') :
6144887Schin                         if (count <= hloff)
6154887Schin                                 hloff -= count;
6164887Schin                         else
6174887Schin                         {
6184887Schin                                 hline -= count - hloff;
6194887Schin                                 hloff = 0;
6204887Schin                         }
6214887Schin #ifdef ESH_NFIRST
6224887Schin 			if (hline <= hismin)
6234887Schin #else
6244887Schin 			if (hline < hismin)
6254887Schin #endif /* ESH_NFIRST */
6264887Schin 			{
6274887Schin 				hline = hismin+1;
6284887Schin 				beep();
6294887Schin #ifndef ESH_NFIRST
6304887Schin 				continue;
6314887Schin #endif
6324887Schin 			}
6334887Schin 			goto common;
6344887Schin 
6354887Schin 		case cntl('O') :
6364887Schin 			location.hist_command = hline;
6374887Schin 			location.hist_line = hloff;
6384887Schin 			ep->CntrlO = 1;
6394887Schin 			c = '\n';
6404887Schin 			goto process;
6414887Schin 		case cntl('N') :
6424887Schin #ifdef ESH_NFIRST
6434887Schin 			hline = location.hist_command;	/* start at saved position */
6444887Schin 			hloff = location.hist_line;
6454887Schin #endif /* ESH_NFIRST */
6464887Schin 			location = hist_locate(sh.hist_ptr,hline,hloff,count);
6474887Schin 			if (location.hist_command > histlines)
6484887Schin 			{
6494887Schin 				beep();
6504887Schin #ifdef ESH_NFIRST
6514887Schin 				location.hist_command = histlines;
6524887Schin 				location.hist_line = ep->in_mult;
6534887Schin #else
6544887Schin 				continue;
6554887Schin #endif /* ESH_NFIRST */
6564887Schin 			}
6574887Schin 			hline = location.hist_command;
6584887Schin 			hloff = location.hist_line;
6594887Schin 		common:
6604887Schin #ifdef ESH_NFIRST
6614887Schin 			location.hist_command = hline;	/* save current position */
6624887Schin 			location.hist_line = hloff;
6634887Schin #endif
6648462SApril.Chin@Sun.COM 			cur = 0;
6658462SApril.Chin@Sun.COM 			draw(ep,UPDATE);
6664887Schin 			hist_copy((char*)out,MAXLINE, hline,hloff);
6674887Schin #if SHOPT_MULTIBYTE
6684887Schin 			ed_internal((char*)(out),out);
6694887Schin #endif /* SHOPT_MULTIBYTE */
6704887Schin 		drawline:
6714887Schin 			eol = genlen(out);
6724887Schin 			cur = eol;
6734887Schin 			draw(ep,UPDATE);
6744887Schin 			continue;
6754887Schin 		}
6764887Schin 
6774887Schin 	}
6784887Schin 
6794887Schin process:
6804887Schin 
6814887Schin 	if (c == (-1))
6824887Schin 	{
6834887Schin 		lookahead = 0;
6844887Schin 		beep();
6854887Schin 		*out = '\0';
6864887Schin 	}
6874887Schin 	draw(ep,FINAL);
6884887Schin 	tty_cooked(ERRIO);
6894887Schin 	if(ed->e_nlist)
6904887Schin 	{
6914887Schin 		ed->e_nlist = 0;
6924887Schin 		stakset(ed->e_stkptr,ed->e_stkoff);
6934887Schin 	}
6944887Schin 	if(c == '\n')
6954887Schin 	{
6964887Schin 		out[eol++] = '\n';
6974887Schin 		out[eol] = '\0';
6984887Schin 		ed_crlf(ep->ed);
6994887Schin 	}
7004887Schin #if SHOPT_MULTIBYTE
7014887Schin 	ed_external(out,buff);
7024887Schin #endif /* SHOPT_MULTIBYTE */
7034887Schin 	i = strlen(buff);
7044887Schin 	if (i)
7054887Schin 		return(i);
7064887Schin 	return(-1);
7074887Schin }
7084887Schin 
show_info(Emacs_t * ep,const char * str)7094887Schin static void show_info(Emacs_t *ep,const char *str)
7104887Schin {
7114887Schin 	register genchar *out = drawbuff;
7124887Schin 	register int c;
7134887Schin 	genchar string[LBUF];
7144887Schin 	int sav_cur = cur;
7154887Schin 	/* save current line */
7164887Schin 	genncpy(string,out,sizeof(string)/sizeof(*string));
7174887Schin 	*out = 0;
7184887Schin 	cur = 0;
7194887Schin #if SHOPT_MULTIBYTE
7204887Schin 	ed_internal(str,out);
7214887Schin #else
7224887Schin 	gencpy(out,str);
7234887Schin #endif	/* SHOPT_MULTIBYTE */
7244887Schin 	draw(ep,UPDATE);
7254887Schin 	c = ed_getchar(ep->ed,0);
7264887Schin 	if(c!=' ')
7274887Schin 		ed_ungetchar(ep->ed,c);
7284887Schin 	/* restore line */
7294887Schin 	cur = sav_cur;
7304887Schin 	genncpy(out,string,sizeof(string)/sizeof(*string));
7314887Schin 	draw(ep,UPDATE);
7324887Schin }
7334887Schin 
putstring(Emacs_t * ep,register char * sp)7344887Schin static void putstring(Emacs_t* ep,register char *sp)
7354887Schin {
7364887Schin 	register int c;
7374887Schin 	while (c= *sp++)
7384887Schin 		 putchar(ep->ed,c);
7394887Schin }
7404887Schin 
7414887Schin 
escape(register Emacs_t * ep,register genchar * out,int count)7424887Schin static int escape(register Emacs_t* ep,register genchar *out,int count)
7434887Schin {
7444887Schin 	register int i,value;
7454887Schin 	int digit,ch;
7464887Schin 	digit = 0;
7474887Schin 	value = 0;
7484887Schin 	while ((i=ed_getchar(ep->ed,0)),isdigit(i))
7494887Schin 	{
7504887Schin 		value *= 10;
7514887Schin 		value += (i - '0');
7524887Schin 		digit = 1;
7534887Schin 	}
7544887Schin 	if (digit)
7554887Schin 	{
7564887Schin 		ed_ungetchar(ep->ed,i) ;
7574887Schin #ifdef ESH_KAPPEND
7584887Schin 		++killing;		/* don't modify killing signal */
7594887Schin #endif
7604887Schin 		return(value);
7614887Schin 	}
7624887Schin 	value = count;
7634887Schin 	if(value<0)
7644887Schin 		value = 1;
7654887Schin 	switch(ch=i)
7664887Schin 	{
7674887Schin 		case cntl('V'):
7684887Schin 			show_info(ep,fmtident(e_version));
7694887Schin 			return(-1);
7704887Schin 		case ' ':
7714887Schin 			ep->mark = cur;
7724887Schin 			return(-1);
7734887Schin 
7744887Schin #ifdef ESH_KAPPEND
7754887Schin 		case '+':		/* M-+ = append next kill */
7764887Schin 			killing = 2;
7774887Schin 			return -1;	/* no argument for next command */
7784887Schin #endif
7794887Schin 
7804887Schin 		case 'p':	/* M-p == ^W^Y (copy stack == kill & yank) */
7814887Schin 			ed_ungetchar(ep->ed,cntl('Y'));
7824887Schin 			ed_ungetchar(ep->ed,cntl('W'));
7834887Schin #ifdef ESH_KAPPEND
7844887Schin 			killing = 0;	/* start fresh */
7854887Schin #endif
7864887Schin 			return(-1);
7874887Schin 
7884887Schin 		case 'l':	/* M-l == lower-case */
7894887Schin 		case 'd':
7904887Schin 		case 'c':
7914887Schin 		case 'f':
7924887Schin 		{
7934887Schin 			i = cur;
7944887Schin 			while(value-- && i<eol)
7954887Schin 			{
7964887Schin 				while ((out[i])&&(!isword(i)))
7974887Schin 					i++;
7984887Schin 				while ((out[i])&&(isword(i)))
7994887Schin 					i++;
8004887Schin 			}
8014887Schin 			if(ch=='l')
8024887Schin 			{
8034887Schin 				value = i-cur;
8044887Schin 				while (value-- > 0)
8054887Schin 				{
8064887Schin 					i = out[cur];
8074887Schin #if SHOPT_MULTIBYTE
8084887Schin 					if((i&~STRIP)==0 && isupper(i))
8094887Schin #else
8104887Schin 					if(isupper(i))
8114887Schin #endif /* SHOPT_MULTIBYTE */
8124887Schin 					{
8134887Schin 						i += 'a' - 'A';
8144887Schin 						out[cur] = i;
8154887Schin 					}
8164887Schin 					cur++;
8174887Schin 				}
8184887Schin 				draw(ep,UPDATE);
8194887Schin 				return(-1);
8204887Schin 			}
8214887Schin 
8224887Schin 			else if(ch=='f')
8234887Schin 				goto update;
8244887Schin 			else if(ch=='c')
8254887Schin 			{
8264887Schin 				ed_ungetchar(ep->ed,cntl('C'));
8274887Schin 				return(i-cur);
8284887Schin 			}
8294887Schin 			else
8304887Schin 			{
8314887Schin 				if (i-cur)
8324887Schin 				{
8334887Schin 					ed_ungetchar(ep->ed,cntl('D'));
8344887Schin #ifdef ESH_KAPPEND
8354887Schin 					++killing;	/* keep killing signal */
8364887Schin #endif
8374887Schin 					return(i-cur);
8384887Schin 				}
8394887Schin 				beep();
8404887Schin 				return(-1);
8414887Schin 			}
8424887Schin 		}
8434887Schin 
8444887Schin 
8454887Schin 		case 'b':
8464887Schin 		case DELETE :
8474887Schin 		case '\b':
8484887Schin 		case 'h':
8494887Schin 		{
8504887Schin 			i = cur;
8514887Schin 			while(value-- && i>0)
8524887Schin 			{
8534887Schin 				i--;
8544887Schin 				while ((i>0)&&(!isword(i)))
8554887Schin 					i--;
8564887Schin 				while ((i>0)&&(isword(i-1)))
8574887Schin 					i--;
8584887Schin 			}
8594887Schin 			if(ch=='b')
8604887Schin 				goto update;
8614887Schin 			else
8624887Schin 			{
8634887Schin 				ed_ungetchar(ep->ed,usrerase);
8644887Schin #ifdef ESH_KAPPEND
8654887Schin 				++killing;
8664887Schin #endif
8674887Schin 				return(cur-i);
8684887Schin 			}
8694887Schin 		}
8704887Schin 
8714887Schin 		case '>':
8724887Schin 			ed_ungetchar(ep->ed,cntl('N'));
8734887Schin #ifdef ESH_NFIRST
8744887Schin 			if (ep->in_mult)
8754887Schin 			{
8764887Schin 				location.hist_command = histlines;
8774887Schin 				location.hist_line = ep->in_mult - 1;
8784887Schin 			}
8794887Schin 			else
8804887Schin 			{
8814887Schin 				location.hist_command = histlines - 1;
8824887Schin 				location.hist_line = 0;
8834887Schin 			}
8844887Schin #else
8854887Schin 			hline = histlines-1;
8864887Schin 			hloff = 0;
8874887Schin #endif /* ESH_NFIRST */
8884887Schin 			return(0);
8894887Schin 
8904887Schin 		case '<':
8914887Schin 			ed_ungetchar(ep->ed,cntl('P'));
8924887Schin 			hloff = 0;
8934887Schin #ifdef ESH_NFIRST
8944887Schin 			hline = hismin + 1;
8954887Schin 			return 0;
8964887Schin #else
8974887Schin 			return(hline-hismin);
8984887Schin #endif /* ESH_NFIRST */
8994887Schin 
9004887Schin 
9014887Schin 		case '#':
9024887Schin 			ed_ungetchar(ep->ed,'\n');
9034887Schin 			ed_ungetchar(ep->ed,(out[0]=='#')?cntl('D'):'#');
9044887Schin 			ed_ungetchar(ep->ed,cntl('A'));
9054887Schin 			return(-1);
9064887Schin 		case '_' :
9074887Schin 		case '.' :
9084887Schin 		{
9094887Schin 			genchar name[MAXLINE];
9104887Schin 			char buf[MAXLINE];
9114887Schin 			char *ptr;
9124887Schin 			ptr = hist_word(buf,MAXLINE,(count?count:-1));
9134887Schin 			if(ptr==0)
9144887Schin 			{
9154887Schin 				beep();
9164887Schin 				break;
9174887Schin 			}
9184887Schin 			if ((eol - cur) >= sizeof(name))
9194887Schin 			{
9204887Schin 				beep();
9214887Schin 				return(-1);
9224887Schin 			}
9234887Schin 			ep->mark = cur;
9244887Schin 			gencpy(name,&out[cur]);
9254887Schin 			while(*ptr)
9264887Schin 			{
9274887Schin 				out[cur++] = *ptr++;
9284887Schin 				eol++;
9294887Schin 			}
9304887Schin 			gencpy(&out[cur],name);
9314887Schin 			draw(ep,UPDATE);
9324887Schin 			return(-1);
9334887Schin 		}
9344887Schin #if KSHELL
9354887Schin 
9364887Schin 		/* file name expansion */
9374887Schin 		case cntl('[') :	/* filename completion */
9384887Schin 			i = '\\';
9394887Schin 		case '*':		/* filename expansion */
9404887Schin 		case '=':	/* escape = - list all matching file names */
9414887Schin 			ep->mark = cur;
9424887Schin 			if(ed_expand(ep->ed,(char*)out,&cur,&eol,i,count) < 0)
9434887Schin 			{
9444887Schin 				if(ep->ed->e_tabcount==1)
9454887Schin 				{
9464887Schin 					ep->ed->e_tabcount=2;
9474887Schin 					ed_ungetchar(ep->ed,cntl('\t'));
9484887Schin 					return(-1);
9494887Schin 				}
9504887Schin 				beep();
9514887Schin 			}
9524887Schin 			else if(i=='=')
9534887Schin 			{
9544887Schin 				draw(ep,REFRESH);
9554887Schin 				if(count>0)
9564887Schin 					ep->ed->e_tabcount=0;
9574887Schin 				else
9584887Schin 				{
9594887Schin 					i=ed_getchar(ep->ed,0);
9604887Schin 					ed_ungetchar(ep->ed,i);
9614887Schin 					if(isdigit(i))
9624887Schin 						ed_ungetchar(ep->ed,ESC);
9634887Schin 				}
9644887Schin 			}
9654887Schin 			else
9664887Schin 			{
9674887Schin 				if(i=='\\' && cur>ep->mark && (out[cur-1]=='/' || out[cur-1]==' '))
9684887Schin 					ep->ed->e_tabcount=0;
9694887Schin 				draw(ep,UPDATE);
9704887Schin 			}
9714887Schin 			return(-1);
9724887Schin 
9734887Schin 		/* search back for character */
9744887Schin 		case cntl(']'):	/* feature not in book */
9754887Schin 		{
9764887Schin 			int c = ed_getchar(ep->ed,1);
9774887Schin 			if ((value == 0) || (value > eol))
9784887Schin 			{
9794887Schin 				beep();
9804887Schin 				return(-1);
9814887Schin 			}
9824887Schin 			i = cur;
9834887Schin 			if (i > 0)
9844887Schin 				i--;
9854887Schin 			while (i >= 0)
9864887Schin 			{
9874887Schin 				if (out[i] == c && --value==0)
9884887Schin 					goto update;
9894887Schin 				i--;
9904887Schin 			}
9914887Schin 			i = eol;
9924887Schin 			while (i > cur)
9934887Schin 			{
9944887Schin 				if (out[i] == c && --value==0)
9954887Schin 					break;
9964887Schin 				i--;
9974887Schin 			};
9984887Schin 
9994887Schin 		}
10004887Schin 		update:
10014887Schin 			cur = i;
10024887Schin 			draw(ep,UPDATE);
10034887Schin 			return(-1);
10044887Schin 
10054887Schin #ifdef _cmd_tput
10064887Schin 		case cntl('L'): /* clear screen */
10074887Schin 			sh_trap("tput clear", 0);
10084887Schin 			draw(ep,REFRESH);
10094887Schin 			return(-1);
10104887Schin #endif
10114887Schin 		case '[':	/* feature not in book */
10124887Schin 			switch(i=ed_getchar(ep->ed,1))
10134887Schin 			{
10144887Schin 			    case 'A':
10158462SApril.Chin@Sun.COM 				if(cur>0 && eol==cur && (cur<(SEARCHSIZE-2) || ep->prevdirection == -2))
10168462SApril.Chin@Sun.COM 				{
10178462SApril.Chin@Sun.COM 					if(ep->lastdraw==APPEND && ep->prevdirection != -2)
10188462SApril.Chin@Sun.COM 					{
10198462SApril.Chin@Sun.COM 						out[cur] = 0;
10208462SApril.Chin@Sun.COM 						gencpy(&((genchar*)lstring)[1],out);
10218462SApril.Chin@Sun.COM #if SHOPT_MULTIBYTE
10228462SApril.Chin@Sun.COM 						ed_external(&((genchar*)lstring)[1],lstring+1);
10238462SApril.Chin@Sun.COM #endif /* SHOPT_MULTIBYTE */
10248462SApril.Chin@Sun.COM 						*lstring = '^';
10258462SApril.Chin@Sun.COM 						ep->prevdirection = -2;
10268462SApril.Chin@Sun.COM 					}
10278462SApril.Chin@Sun.COM 					if(*lstring)
10288462SApril.Chin@Sun.COM 					{
10298462SApril.Chin@Sun.COM 						ed_ungetchar(ep->ed,'\r');
10308462SApril.Chin@Sun.COM 						ed_ungetchar(ep->ed,cntl('R'));
10318462SApril.Chin@Sun.COM 						return(-1);
10328462SApril.Chin@Sun.COM 					}
10338462SApril.Chin@Sun.COM 				}
10348462SApril.Chin@Sun.COM 				*lstring = 0;
10354887Schin 				ed_ungetchar(ep->ed,cntl('P'));
10364887Schin 				return(-1);
10374887Schin 			    case 'B':
10384887Schin 				ed_ungetchar(ep->ed,cntl('N'));
10394887Schin 				return(-1);
10404887Schin 			    case 'C':
10414887Schin 				ed_ungetchar(ep->ed,cntl('F'));
10424887Schin 				return(-1);
10434887Schin 			    case 'D':
10444887Schin 				ed_ungetchar(ep->ed,cntl('B'));
10454887Schin 				return(-1);
10464887Schin 			    case 'H':
10474887Schin 				ed_ungetchar(ep->ed,cntl('A'));
10484887Schin 				return(-1);
10494887Schin 			    case 'Y':
10504887Schin 				ed_ungetchar(ep->ed,cntl('E'));
10514887Schin 				return(-1);
10524887Schin 			    default:
10534887Schin 				ed_ungetchar(ep->ed,i);
10544887Schin 			}
10554887Schin 			i = '_';
10564887Schin 
10574887Schin 		default:
10584887Schin 			/* look for user defined macro definitions */
10594887Schin 			if(ed_macro(ep->ed,i))
10604887Schin #   ifdef ESH_BETTER
10614887Schin 				return(count);	/* pass argument to macro */
10624887Schin #   else
10634887Schin 				return(-1);
10644887Schin #   endif /* ESH_BETTER */
10654887Schin #else
10664887Schin 		update:
10674887Schin 			cur = i;
10684887Schin 			draw(ep,UPDATE);
10694887Schin 			return(-1);
10704887Schin 
10714887Schin 		default:
10724887Schin #endif	/* KSHELL */
10734887Schin 		beep();
10744887Schin 		return(-1);
10754887Schin 	}
107610898Sroland.mainz@nrubsig.org 	return(-1);
10774887Schin }
10784887Schin 
10794887Schin 
10804887Schin /*
10814887Schin  * This routine process all commands starting with ^X
10824887Schin  */
10834887Schin 
xcommands(register Emacs_t * ep,int count)10844887Schin static void xcommands(register Emacs_t *ep,int count)
10854887Schin {
10864887Schin         register int i = ed_getchar(ep->ed,0);
10874887Schin 	NOT_USED(count);
10884887Schin         switch(i)
10894887Schin         {
10904887Schin                 case cntl('X'):	/* exchange dot and mark */
10914887Schin                         if (ep->mark > eol)
10924887Schin                                 ep->mark = eol;
10934887Schin                         i = ep->mark;
10944887Schin                         ep->mark = cur;
10954887Schin                         cur = i;
10964887Schin                         draw(ep,UPDATE);
10974887Schin                         return;
10984887Schin 
10994887Schin #if KSHELL
11004887Schin #   ifdef ESH_BETTER
11014887Schin                 case cntl('E'):	/* invoke emacs on current command */
11024887Schin 			if(ed_fulledit(ep->ed)==-1)
11034887Schin 				beep();
11044887Schin 			else
11054887Schin 			{
11064887Schin #if SHOPT_MULTIBYTE
11074887Schin 				ed_internal((char*)drawbuff,drawbuff);
11084887Schin #endif /* SHOPT_MULTIBYTE */
11094887Schin 				ed_ungetchar(ep->ed,'\n');
11104887Schin 			}
11114887Schin 			return;
11124887Schin 
11134887Schin #	define itos(i)	fmtbase((long)(i),0,0)/* want signed conversion */
11144887Schin 
11154887Schin 		case cntl('H'):		/* ^X^H show history info */
11164887Schin 			{
11174887Schin 				char hbuf[MAXLINE];
11184887Schin 
11194887Schin 				strcpy(hbuf, "Current command ");
11204887Schin 				strcat(hbuf, itos(hline));
11214887Schin 				if (hloff)
11224887Schin 				{
11234887Schin 					strcat(hbuf, " (line ");
11244887Schin 					strcat(hbuf, itos(hloff+1));
11254887Schin 					strcat(hbuf, ")");
11264887Schin 				}
11274887Schin 				if ((hline != location.hist_command) ||
11284887Schin 				    (hloff != location.hist_line))
11294887Schin 				{
11304887Schin 					strcat(hbuf, "; Previous command ");
11314887Schin 					strcat(hbuf, itos(location.hist_command));
11324887Schin 					if (location.hist_line)
11334887Schin 					{
11344887Schin 						strcat(hbuf, " (line ");
11354887Schin 						strcat(hbuf, itos(location.hist_line+1));
11364887Schin 						strcat(hbuf, ")");
11374887Schin 					}
11384887Schin 				}
11394887Schin 				show_info(ep,hbuf);
11404887Schin 				return;
11414887Schin 			}
11424887Schin #	if 0	/* debugging, modify as required */
11434887Schin 		case cntl('D'):		/* ^X^D show debugging info */
11444887Schin 			{
11454887Schin 				char debugbuf[MAXLINE];
11464887Schin 
11474887Schin 				strcpy(debugbuf, "count=");
11484887Schin 				strcat(debugbuf, itos(count));
11494887Schin 				strcat(debugbuf, " eol=");
11504887Schin 				strcat(debugbuf, itos(eol));
11514887Schin 				strcat(debugbuf, " cur=");
11524887Schin 				strcat(debugbuf, itos(cur));
11534887Schin 				strcat(debugbuf, " crallowed=");
11544887Schin 				strcat(debugbuf, itos(crallowed));
11554887Schin 				strcat(debugbuf, " plen=");
11564887Schin 				strcat(debugbuf, itos(plen));
11574887Schin 				strcat(debugbuf, " w_size=");
11584887Schin 				strcat(debugbuf, itos(w_size));
11594887Schin 
11604887Schin 				show_info(ep,debugbuf);
11614887Schin 				return;
11624887Schin 			}
11634887Schin #	endif /* debugging code */
11644887Schin #   endif /* ESH_BETTER */
11654887Schin #endif /* KSHELL */
11664887Schin 
11674887Schin                 default:
11684887Schin                         beep();
11694887Schin                         return;
11704887Schin 	}
11714887Schin }
11724887Schin 
search(Emacs_t * ep,genchar * out,int direction)11734887Schin static void search(Emacs_t* ep,genchar *out,int direction)
11744887Schin {
11754887Schin #ifndef ESH_NFIRST
11764887Schin 	Histloc_t location;
11774887Schin #endif
11784887Schin 	register int i,sl;
11794887Schin 	genchar str_buff[LBUF];
11804887Schin 	register genchar *string = drawbuff;
11814887Schin 	/* save current line */
11824887Schin 	int sav_cur = cur;
11834887Schin 	genncpy(str_buff,string,sizeof(str_buff)/sizeof(*str_buff));
11844887Schin 	string[0] = '^';
11854887Schin 	string[1] = 'R';
11864887Schin 	string[2] = '\0';
11874887Schin 	sl = 2;
11884887Schin 	cur = sl;
11894887Schin 	draw(ep,UPDATE);
11904887Schin 	while ((i = ed_getchar(ep->ed,1))&&(i != '\r')&&(i != '\n'))
11914887Schin 	{
11924887Schin 		if (i==usrerase || i==DELETE || i=='\b' || i==ERASECHAR)
11934887Schin 		{
11944887Schin 			if (sl > 2)
11954887Schin 			{
11964887Schin 				string[--sl] = '\0';
11974887Schin 				cur = sl;
11984887Schin 				draw(ep,UPDATE);
11994887Schin 			}
12004887Schin 			else
12014887Schin 				beep();
12024887Schin 			continue;
12034887Schin 		}
12044887Schin 		if (i==usrkill)
12054887Schin 		{
12064887Schin 			beep();
12074887Schin 			goto restore;
12084887Schin 		}
12094887Schin 		if (i == '\\')
12104887Schin 		{
12114887Schin 			string[sl++] = '\\';
12124887Schin 			string[sl] = '\0';
12134887Schin 			cur = sl;
12144887Schin 			draw(ep,APPEND);
12154887Schin 			i = ed_getchar(ep->ed,1);
12164887Schin 			string[--sl] = '\0';
12174887Schin 		}
12184887Schin 		string[sl++] = i;
12194887Schin 		string[sl] = '\0';
12204887Schin 		cur = sl;
12214887Schin 		draw(ep,APPEND);
12224887Schin 	}
12234887Schin 	i = genlen(string);
12244887Schin 
12258462SApril.Chin@Sun.COM 	if(ep->prevdirection == -2 && i!=2 || direction!=1)
12268462SApril.Chin@Sun.COM 		ep->prevdirection = -1;
12274887Schin 	if (direction < 1)
12284887Schin 	{
12294887Schin 		ep->prevdirection = -ep->prevdirection;
12304887Schin 		direction = 1;
12314887Schin 	}
12324887Schin 	else
12334887Schin 		direction = -1;
12344887Schin 	if (i != 2)
12354887Schin 	{
12364887Schin #if SHOPT_MULTIBYTE
12374887Schin 		ed_external(string,(char*)string);
12384887Schin #endif /* SHOPT_MULTIBYTE */
12394887Schin 		strncpy(lstring,((char*)string)+2,SEARCHSIZE);
12404887Schin 		ep->prevdirection = direction;
12414887Schin 	}
12424887Schin 	else
12434887Schin 		direction = ep->prevdirection ;
12444887Schin 	location = hist_find(sh.hist_ptr,(char*)lstring,hline,1,direction);
12454887Schin 	i = location.hist_command;
12464887Schin 	if(i>0)
12474887Schin 	{
12484887Schin 		hline = i;
12494887Schin #ifdef ESH_NFIRST
12504887Schin 		hloff = location.hist_line = 0;	/* display first line of multi line command */
12514887Schin #else
12524887Schin 		hloff = location.hist_line;
12534887Schin #endif /* ESH_NFIRST */
12544887Schin 		hist_copy((char*)out,MAXLINE, hline,hloff);
12554887Schin #if SHOPT_MULTIBYTE
12564887Schin 		ed_internal((char*)out,out);
12574887Schin #endif /* SHOPT_MULTIBYTE */
12584887Schin 		return;
12594887Schin 	}
12604887Schin 	if (i < 0)
12614887Schin 	{
12624887Schin 		beep();
12634887Schin #ifdef ESH_NFIRST
12644887Schin 		location.hist_command = hline;
12654887Schin 		location.hist_line = hloff;
12664887Schin #else
12674887Schin 		hloff = 0;
12684887Schin 		hline = histlines;
12694887Schin #endif /* ESH_NFIRST */
12704887Schin 	}
12714887Schin restore:
12724887Schin 	genncpy(string,str_buff,sizeof(str_buff)/sizeof(*str_buff));
12734887Schin 	cur = sav_cur;
12744887Schin 	return;
12754887Schin }
12764887Schin 
12774887Schin 
12784887Schin /* Adjust screen to agree with inputs: logical line and cursor */
12794887Schin /* If 'first' assume screen is blank */
12804887Schin /* Prompt is always kept on the screen */
12814887Schin 
draw(register Emacs_t * ep,Draw_t option)12824887Schin static void draw(register Emacs_t *ep,Draw_t option)
12834887Schin {
12844887Schin #define	NORMAL ' '
12854887Schin #define	LOWER  '<'
12864887Schin #define	BOTH   '*'
12874887Schin #define	UPPER  '>'
12884887Schin 
12894887Schin 	register genchar *sptr;		/* Pointer within screen */
12904887Schin 	genchar nscreen[2*MAXLINE];	/* New entire screen */
12914887Schin 	genchar *ncursor;		/* New cursor */
12924887Schin 	register genchar *nptr;		/* Pointer to New screen */
12934887Schin 	char  longline;			/* Line overflow */
12944887Schin 	genchar *logcursor;
12954887Schin 	genchar *nscend;		/* end of logical screen */
12964887Schin 	register int i;
12974887Schin 
12984887Schin 	nptr = nscreen;
12994887Schin 	sptr = drawbuff;
13004887Schin 	logcursor = sptr + cur;
13014887Schin 	longline = NORMAL;
13028462SApril.Chin@Sun.COM 	ep->lastdraw = option;
13034887Schin 
13044887Schin 	if (option == FIRST || option == REFRESH)
13054887Schin 	{
13064887Schin 		ep->overflow = NORMAL;
13074887Schin 		ep->cursor = ep->screen;
13084887Schin 		ep->offset = 0;
13094887Schin 		ep->cr_ok = crallowed;
13104887Schin 		if (option == FIRST)
13114887Schin 		{
13124887Schin 			ep->scvalid = 1;
13134887Schin 			return;
13144887Schin 		}
13154887Schin 		*ep->cursor = '\0';
13164887Schin 		putstring(ep,Prompt);	/* start with prompt */
13174887Schin 	}
13184887Schin 
13194887Schin 	/*********************
13204887Schin 	 Do not update screen if pending characters
13214887Schin 	**********************/
13224887Schin 
13234887Schin 	if ((lookahead)&&(option != FINAL))
13244887Schin 	{
13254887Schin 
13264887Schin 		ep->scvalid = 0; /* Screen is out of date, APPEND will not work */
13274887Schin 
13284887Schin 		return;
13294887Schin 	}
13304887Schin 
13314887Schin 	/***************************************
13324887Schin 	If in append mode, cursor at end of line, screen up to date,
13334887Schin 	the previous character was a 'normal' character,
13344887Schin 	and the window has room for another character.
13354887Schin 	Then output the character and adjust the screen only.
13364887Schin 	*****************************************/
13374887Schin 
13384887Schin 
13394887Schin 	i = *(logcursor-1);	/* last character inserted */
13404887Schin 
13414887Schin 	if ((option == APPEND)&&(ep->scvalid)&&(*logcursor == '\0')&&
13424887Schin 	    print(i)&&((ep->cursor-ep->screen)<(w_size-1)))
13434887Schin 	{
13444887Schin 		putchar(ep->ed,i);
13454887Schin 		*ep->cursor++ = i;
13464887Schin 		*ep->cursor = '\0';
13474887Schin 		return;
13484887Schin 	}
13494887Schin 
13504887Schin 	/* copy the line */
13514887Schin 	ncursor = nptr + ed_virt_to_phys(ep->ed,sptr,nptr,cur,0,0);
13524887Schin 	nptr += genlen(nptr);
13534887Schin 	sptr += genlen(sptr);
13544887Schin 	nscend = nptr - 1;
13554887Schin 	if(sptr == logcursor)
13564887Schin 		ncursor = nptr;
13574887Schin 
13584887Schin 	/*********************
13594887Schin 	 Does ncursor appear on the screen?
13604887Schin 	 If not, adjust the screen offset so it does.
13614887Schin 	**********************/
13624887Schin 
13634887Schin 	i = ncursor - nscreen;
13644887Schin 
13654887Schin 	if ((ep->offset && i<=ep->offset)||(i >= (ep->offset+w_size)))
13664887Schin 	{
13674887Schin 		/* Center the cursor on the screen */
13684887Schin 		ep->offset = i - (w_size>>1);
13694887Schin 		if (--ep->offset < 0)
13704887Schin 			ep->offset = 0;
13714887Schin 	}
13724887Schin 
13734887Schin 	/*********************
13744887Schin 	 Is the range of screen[0] thru screen[w_size] up-to-date
13754887Schin 	 with nscreen[offset] thru nscreen[offset+w_size] ?
13764887Schin 	 If not, update as need be.
13774887Schin 	***********************/
13784887Schin 
13794887Schin 	nptr = &nscreen[ep->offset];
13804887Schin 	sptr = ep->screen;
13814887Schin 
13824887Schin 	i = w_size;
13834887Schin 
13844887Schin 	while (i-- > 0)
13854887Schin 	{
13864887Schin 
13874887Schin 		if (*nptr == '\0')
13884887Schin 		{
13894887Schin 			*(nptr + 1) = '\0';
13904887Schin 			*nptr = ' ';
13914887Schin 		}
13924887Schin 		if (*sptr == '\0')
13934887Schin 		{
13944887Schin 			*(sptr + 1) = '\0';
13954887Schin 			*sptr = ' ';
13964887Schin 		}
13974887Schin 		if (*nptr == *sptr)
13984887Schin 		{
13994887Schin 			nptr++;
14004887Schin 			sptr++;
14014887Schin 			continue;
14024887Schin 		}
14034887Schin 		setcursor(ep,sptr-ep->screen,*nptr);
14044887Schin 		*sptr++ = *nptr++;
14054887Schin #if SHOPT_MULTIBYTE
14064887Schin 		while(*nptr==MARKER)
14074887Schin 		{
14084887Schin 			if(*sptr=='\0')
14094887Schin 				*(sptr + 1) = '\0';
14104887Schin 			*sptr++ = *nptr++;
14114887Schin 			i--;
14124887Schin 			ep->cursor++;
14134887Schin 		}
14144887Schin #endif /* SHOPT_MULTIBYTE */
14154887Schin 	}
14168462SApril.Chin@Sun.COM 	if(ep->ed->e_multiline && option == REFRESH && ep->ed->e_nocrnl==0)
14178462SApril.Chin@Sun.COM 		ed_setcursor(ep->ed, ep->screen, ep->cursor-ep->screen, ep->ed->e_peol, -1);
14188462SApril.Chin@Sun.COM 
14194887Schin 
14204887Schin 	/******************
14214887Schin 
14224887Schin 	Screen overflow checks
14234887Schin 
14244887Schin 	********************/
14254887Schin 
14264887Schin 	if (nscend >= &nscreen[ep->offset+w_size])
14274887Schin 	{
14284887Schin 		if (ep->offset > 0)
14294887Schin 			longline = BOTH;
14304887Schin 		else
14314887Schin 			longline = UPPER;
14324887Schin 	}
14334887Schin 	else
14344887Schin 	{
14354887Schin 		if (ep->offset > 0)
14364887Schin 			longline = LOWER;
14374887Schin 	}
14384887Schin 
14394887Schin 	/* Update screen overflow indicator if need be */
14404887Schin 
14414887Schin 	if (longline != ep->overflow)
14424887Schin 	{
14434887Schin 		setcursor(ep,w_size,longline);
14444887Schin 		ep->overflow = longline;
14454887Schin 	}
14464887Schin 	i = (ncursor-nscreen) - ep->offset;
14474887Schin 	setcursor(ep,i,0);
14484887Schin 	if(option==FINAL && ep->ed->e_multiline)
14498462SApril.Chin@Sun.COM 		setcursor(ep,nscend+1-nscreen,0);
14504887Schin 	ep->scvalid = 1;
14514887Schin 	return;
14524887Schin }
14534887Schin 
14544887Schin /*
14554887Schin  * put the cursor to the <newp> position within screen buffer
14564887Schin  * if <c> is non-zero then output this character
14574887Schin  * cursor is set to reflect the change
14584887Schin  */
14594887Schin 
setcursor(register Emacs_t * ep,register int newp,int c)14604887Schin static void setcursor(register Emacs_t *ep,register int newp,int c)
14614887Schin {
14624887Schin 	register int oldp = ep->cursor - ep->screen;
14634887Schin 	newp  = ed_setcursor(ep->ed, ep->screen, oldp, newp, 0);
14644887Schin 	if(c)
14654887Schin 	{
14664887Schin 		putchar(ep->ed,c);
14674887Schin 		newp++;
14684887Schin 	}
14694887Schin 	ep->cursor = ep->screen+newp;
14704887Schin 	return;
14714887Schin }
14724887Schin 
14734887Schin #if SHOPT_MULTIBYTE
print(register int c)14744887Schin static int print(register int c)
14754887Schin {
14764887Schin 	return((c&~STRIP)==0 && isprint(c));
14774887Schin }
14784887Schin 
_isword(register int c)14794887Schin static int _isword(register int c)
14804887Schin {
14814887Schin 	return((c&~STRIP) || isalnum(c) || c=='_');
14824887Schin }
14834887Schin #endif /* SHOPT_MULTIBYTE */
1484