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