1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1982-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                  David Korn <dgk@research.att.com>                   *
18*4887Schin *                                                                      *
19*4887Schin ***********************************************************************/
20*4887Schin #pragma prototyped
21*4887Schin /* Original version by Michael T. Veach
22*4887Schin  * Adapted for ksh by David Korn */
23*4887Schin /* EMACS_MODES: c tabstop=4
24*4887Schin 
25*4887Schin One line screen editor for any program
26*4887Schin 
27*4887Schin */
28*4887Schin 
29*4887Schin 
30*4887Schin /*	The following is provided by:
31*4887Schin  *
32*4887Schin  *			Matthijs N. Melchior
33*4887Schin  *			AT&T Network Systems International
34*4887Schin  *			APT Nederland
35*4887Schin  *			HV BZ335 x2962
36*4887Schin  *			hvlpb!mmelchio
37*4887Schin  *
38*4887Schin  *  These are now on by default
39*4887Schin  *
40*4887Schin  *  ESH_NFIRST
41*4887Schin  *	-  A ^N as first history related command after the prompt will move
42*4887Schin  *	   to the next command relative to the last known history position.
43*4887Schin  *	   It will not start at the position where the last command was entered
44*4887Schin  *	   as is done by the ^P command.  Every history related command will
45*4887Schin  *	   set both the current and last position.  Executing a command will
46*4887Schin  *	   only set the current position.
47*4887Schin  *
48*4887Schin  *  ESH_KAPPEND
49*4887Schin  *	-  Successive kill and delete commands will accumulate their data
50*4887Schin  *	   in the kill buffer, by appending or prepending as appropriate.
51*4887Schin  *	   This mode will be reset by any command not adding something to the
52*4887Schin  *	   kill buffer.
53*4887Schin  *
54*4887Schin  *  ESH_BETTER
55*4887Schin  *	-  Some enhancements:
56*4887Schin  *		- argument for a macro is passed to its replacement
57*4887Schin  *		- ^X^H command to find out about history position (debugging)
58*4887Schin  *		- ^X^D command to show any debugging info
59*4887Schin  *
60*4887Schin  *  I do not pretend these for changes are completely independent,
61*4887Schin  *  but you can use them to seperate features.
62*4887Schin  */
63*4887Schin 
64*4887Schin #include	<ast.h>
65*4887Schin #include	<ctype.h>
66*4887Schin #include	"FEATURE/cmds"
67*4887Schin #if KSHELL
68*4887Schin #   include	"defs.h"
69*4887Schin #endif	/* KSHELL */
70*4887Schin #include	"io.h"
71*4887Schin 
72*4887Schin #include	"history.h"
73*4887Schin #include	"edit.h"
74*4887Schin #include	"terminal.h"
75*4887Schin 
76*4887Schin #define ESH_NFIRST
77*4887Schin #define ESH_KAPPEND
78*4887Schin #define ESH_BETTER
79*4887Schin 
80*4887Schin #undef putchar
81*4887Schin #define putchar(ed,c)	ed_putchar(ed,c)
82*4887Schin #define beep()		ed_ringbell()
83*4887Schin 
84*4887Schin 
85*4887Schin #if SHOPT_MULTIBYTE
86*4887Schin #   define gencpy(a,b)	ed_gencpy(a,b)
87*4887Schin #   define genncpy(a,b,n)	ed_genncpy(a,b,n)
88*4887Schin #   define genlen(str)	ed_genlen(str)
89*4887Schin     static int	print(int);
90*4887Schin     static int	_isword(int);
91*4887Schin #   define  isword(c)	_isword(out[c])
92*4887Schin 
93*4887Schin #else
94*4887Schin #   define gencpy(a,b)	strcpy((char*)(a),(char*)(b))
95*4887Schin #   define genncpy(a,b,n)	strncpy((char*)(a),(char*)(b),n)
96*4887Schin #   define genlen(str)	strlen(str)
97*4887Schin #   define print(c)	isprint(c)
98*4887Schin #   define isword(c)	(isalnum(out[c]) || (out[c]=='_'))
99*4887Schin #endif /*SHOPT_MULTIBYTE */
100*4887Schin 
101*4887Schin typedef struct _emacs_
102*4887Schin {
103*4887Schin 	genchar *screen;	/* pointer to window buffer */
104*4887Schin 	genchar *cursor;	/* Cursor in real screen */
105*4887Schin 	int 	mark;
106*4887Schin 	int 	in_mult;
107*4887Schin 	char	cr_ok;
108*4887Schin 	char	CntrlO;
109*4887Schin 	char	overflow;		/* Screen overflow flag set */
110*4887Schin 	char	scvalid;		/* Screen is up to date */
111*4887Schin 	int	offset;		/* Screen offset */
112*4887Schin 	enum
113*4887Schin 	{
114*4887Schin 		CRT=0,	/* Crt terminal */
115*4887Schin 		PAPER	/* Paper terminal */
116*4887Schin 	} terminal;
117*4887Schin 	Histloc_t _location;
118*4887Schin 	int	prevdirection;
119*4887Schin 	Edit_t	*ed;	/* pointer to edit data */
120*4887Schin } Emacs_t;
121*4887Schin 
122*4887Schin #define	editb		(*ep->ed)
123*4887Schin #define eol		editb.e_eol
124*4887Schin #define cur		editb.e_cur
125*4887Schin #define hline		editb.e_hline
126*4887Schin #define hloff		editb.e_hloff
127*4887Schin #define hismin		editb.e_hismin
128*4887Schin #define usrkill		editb.e_kill
129*4887Schin #define usrlnext	editb.e_lnext
130*4887Schin #define usreof		editb.e_eof
131*4887Schin #define usrerase	editb.e_erase
132*4887Schin #define crallowed	editb.e_crlf
133*4887Schin #define Prompt		editb.e_prompt
134*4887Schin #define plen		editb.e_plen
135*4887Schin #define kstack		editb.e_killbuf
136*4887Schin #define lstring		editb.e_search
137*4887Schin #define lookahead	editb.e_lookahead
138*4887Schin #define env		editb.e_env
139*4887Schin #define raw		editb.e_raw
140*4887Schin #define histlines	editb.e_hismax
141*4887Schin #define w_size		editb.e_wsize
142*4887Schin #define drawbuff	editb.e_inbuf
143*4887Schin #define killing		editb.e_mode
144*4887Schin #define location	ep->_location
145*4887Schin 
146*4887Schin #define LBUF	100
147*4887Schin #define KILLCHAR	UKILL
148*4887Schin #define ERASECHAR	UERASE
149*4887Schin #define EOFCHAR		UEOF
150*4887Schin #define LNEXTCHAR		ULNEXT
151*4887Schin #define DELETE		('a'==97?0177:7)
152*4887Schin 
153*4887Schin /**********************
154*4887Schin A large lookahead helps when the user is inserting
155*4887Schin characters in the middle of the line.
156*4887Schin ************************/
157*4887Schin 
158*4887Schin 
159*4887Schin typedef enum
160*4887Schin {
161*4887Schin 	FIRST,		/* First time thru for logical line, prompt on screen */
162*4887Schin 	REFRESH,	/* Redraw entire screen */
163*4887Schin 	APPEND,		/* Append char before cursor to screen */
164*4887Schin 	UPDATE,		/* Update the screen as need be */
165*4887Schin 	FINAL		/* Update screen even if pending look ahead */
166*4887Schin } Draw_t;
167*4887Schin 
168*4887Schin static void draw(Emacs_t*,Draw_t);
169*4887Schin static int escape(Emacs_t*,genchar*, int);
170*4887Schin static void putstring(Emacs_t*,char*);
171*4887Schin static void search(Emacs_t*,genchar*,int);
172*4887Schin static void setcursor(Emacs_t*,int, int);
173*4887Schin static void show_info(Emacs_t*,const char*);
174*4887Schin static void xcommands(Emacs_t*,int);
175*4887Schin 
176*4887Schin int ed_emacsread(void *context, int fd,char *buff,int scend, int reedit)
177*4887Schin {
178*4887Schin 	Edit_t *ed = (Edit_t*)context;
179*4887Schin 	register int c;
180*4887Schin 	register int i;
181*4887Schin 	register genchar *out;
182*4887Schin 	register int count;
183*4887Schin 	register Emacs_t *ep = ed->e_emacs;
184*4887Schin 	int adjust,oadjust;
185*4887Schin 	char backslash;
186*4887Schin 	genchar *kptr;
187*4887Schin 	char prompt[PRSIZE];
188*4887Schin 	genchar Screen[MAXLINE];
189*4887Schin 	if(!ep)
190*4887Schin 	{
191*4887Schin 		ep = ed->e_emacs = newof(0,Emacs_t,1,0);
192*4887Schin 		ep->ed = ed;
193*4887Schin 		ep->prevdirection =  1;
194*4887Schin 		location.hist_command =  -5;
195*4887Schin 	}
196*4887Schin 	Prompt = prompt;
197*4887Schin 	ep->screen = Screen;
198*4887Schin 	if(tty_raw(ERRIO,0) < 0)
199*4887Schin 	{
200*4887Schin 		 return(reedit?reedit:ed_read(context, fd,buff,scend,0));
201*4887Schin 	}
202*4887Schin 	raw = 1;
203*4887Schin 	/* This mess in case the read system call fails */
204*4887Schin 
205*4887Schin 	ed_setup(ep->ed,fd,reedit);
206*4887Schin 	out = (genchar*)buff;
207*4887Schin #if SHOPT_MULTIBYTE
208*4887Schin 	out = (genchar*)roundof((char*)out-(char*)0,sizeof(genchar));
209*4887Schin 	ed_internal(buff,out);
210*4887Schin #endif /* SHOPT_MULTIBYTE */
211*4887Schin 	if(!kstack)
212*4887Schin 	{
213*4887Schin 		kstack = (genchar*)malloc(CHARSIZE*MAXLINE);
214*4887Schin 		kstack[0] = '\0';
215*4887Schin 	}
216*4887Schin 	drawbuff = out;
217*4887Schin #ifdef ESH_NFIRST
218*4887Schin 	if (location.hist_command == -5)		/* to be initialized */
219*4887Schin 	{
220*4887Schin 		kstack[0] = '\0';		/* also clear kstack... */
221*4887Schin 		location.hist_command = hline;
222*4887Schin 		location.hist_line = hloff;
223*4887Schin 	}
224*4887Schin 	if (location.hist_command <= hismin)	/* don't start below minimum */
225*4887Schin 	{
226*4887Schin 		location.hist_command = hismin + 1;
227*4887Schin 		location.hist_line = 0;
228*4887Schin 	}
229*4887Schin 	ep->in_mult = hloff;			/* save pos in last command */
230*4887Schin #endif /* ESH_NFIRST */
231*4887Schin 	i = sigsetjmp(env,0);
232*4887Schin 	if (i !=0)
233*4887Schin 	{
234*4887Schin 		tty_cooked(ERRIO);
235*4887Schin 		if (i == UEOF)
236*4887Schin 		{
237*4887Schin 			return(0); /* EOF */
238*4887Schin 		}
239*4887Schin 		return(-1); /* some other error */
240*4887Schin 	}
241*4887Schin 	out[reedit] = 0;
242*4887Schin 	if(scend+plen > (MAXLINE-2))
243*4887Schin 		scend = (MAXLINE-2)-plen;
244*4887Schin 	ep->mark = 0;
245*4887Schin 	cur = eol;
246*4887Schin 	draw(ep,reedit?REFRESH:FIRST);
247*4887Schin 	adjust = -1;
248*4887Schin 	backslash = 0;
249*4887Schin 	if (ep->CntrlO)
250*4887Schin 	{
251*4887Schin #ifdef ESH_NFIRST
252*4887Schin 		ed_ungetchar(ep->ed,cntl('N'));
253*4887Schin #else
254*4887Schin 		location = hist_locate(sh.hist_ptr,location.hist_command,location.hist_line,1);
255*4887Schin 		if (location.hist_command < histlines)
256*4887Schin 		{
257*4887Schin 			hline = location.hist_command;
258*4887Schin 			hloff = location.hist_line;
259*4887Schin 			hist_copy((char*)kstack,MAXLINE, hline,hloff);
260*4887Schin #   if SHOPT_MULTIBYTE
261*4887Schin 			ed_internal((char*)kstack,kstack);
262*4887Schin #   endif /* SHOPT_MULTIBYTE */
263*4887Schin 			ed_ungetchar(ep->ed,cntl('Y'));
264*4887Schin 		}
265*4887Schin #endif /* ESH_NFIRST */
266*4887Schin 	}
267*4887Schin 	ep->CntrlO = 0;
268*4887Schin 	while ((c = ed_getchar(ep->ed,0)) != (-1))
269*4887Schin 	{
270*4887Schin 		if (backslash)
271*4887Schin 		{
272*4887Schin 			backslash = 0;
273*4887Schin 			if (c==usrerase||c==usrkill||(!print(c) &&
274*4887Schin 				(c!='\r'&&c!='\n')))
275*4887Schin 			{
276*4887Schin 				/* accept a backslashed character */
277*4887Schin 				cur--;
278*4887Schin 				out[cur++] = c;
279*4887Schin 				out[eol] = '\0';
280*4887Schin 				draw(ep,APPEND);
281*4887Schin 				continue;
282*4887Schin 			}
283*4887Schin 		}
284*4887Schin 		if (c == usrkill)
285*4887Schin 		{
286*4887Schin 			c = KILLCHAR ;
287*4887Schin 		}
288*4887Schin 		else if (c == usrerase)
289*4887Schin 		{
290*4887Schin 			c = ERASECHAR ;
291*4887Schin 		}
292*4887Schin 		else if (c == usrlnext)
293*4887Schin 		{
294*4887Schin 			c = LNEXTCHAR ;
295*4887Schin 		}
296*4887Schin 		else if ((c == usreof)&&(eol == 0))
297*4887Schin 		{
298*4887Schin 			c = EOFCHAR;
299*4887Schin 		}
300*4887Schin #ifdef ESH_KAPPEND
301*4887Schin 		if (--killing <= 0)	/* reset killing flag */
302*4887Schin 			killing = 0;
303*4887Schin #endif
304*4887Schin 		oadjust = count = adjust;
305*4887Schin 		if(count<0)
306*4887Schin 			count = 1;
307*4887Schin 		adjust = -1;
308*4887Schin 		i = cur;
309*4887Schin 		switch(c)
310*4887Schin 		{
311*4887Schin 		case LNEXTCHAR:
312*4887Schin 			c = ed_getchar(ep->ed,2);
313*4887Schin 			goto do_default_processing;
314*4887Schin 		case cntl('V'):
315*4887Schin 			show_info(ep,fmtident(e_version));
316*4887Schin 			continue;
317*4887Schin 		case '\0':
318*4887Schin 			ep->mark = i;
319*4887Schin 			continue;
320*4887Schin 		case cntl('X'):
321*4887Schin 			xcommands(ep,count);
322*4887Schin 			continue;
323*4887Schin 		case EOFCHAR:
324*4887Schin 			ed_flush(ep->ed);
325*4887Schin 			tty_cooked(ERRIO);
326*4887Schin 			return(0);
327*4887Schin #ifdef u370
328*4887Schin 		case cntl('S') :
329*4887Schin 		case cntl('Q') :
330*4887Schin 			continue;
331*4887Schin #endif	/* u370 */
332*4887Schin 		case '\t':
333*4887Schin 			if(cur>0  && ep->ed->sh->nextprompt)
334*4887Schin 			{
335*4887Schin 				if(ep->ed->e_tabcount==0)
336*4887Schin 				{
337*4887Schin 					ep->ed->e_tabcount=1;
338*4887Schin 					ed_ungetchar(ep->ed,ESC);
339*4887Schin 					goto do_escape;
340*4887Schin 				}
341*4887Schin 				else if(ep->ed->e_tabcount==1)
342*4887Schin 				{
343*4887Schin 					ed_ungetchar(ep->ed,'=');
344*4887Schin 					goto do_escape;
345*4887Schin 				}
346*4887Schin 				ep->ed->e_tabcount = 0;
347*4887Schin 			}
348*4887Schin 		do_default_processing:
349*4887Schin 		default:
350*4887Schin 
351*4887Schin 			if ((eol+1) >= (scend)) /*  will not fit on line */
352*4887Schin 			{
353*4887Schin 				ed_ungetchar(ep->ed,c); /* save character for next line */
354*4887Schin 				goto process;
355*4887Schin 			}
356*4887Schin 			for(i= ++eol; i>cur; i--)
357*4887Schin 				out[i] = out[i-1];
358*4887Schin 			backslash =  (c == '\\');
359*4887Schin 			out[cur++] = c;
360*4887Schin 			draw(ep,APPEND);
361*4887Schin 			continue;
362*4887Schin 		case cntl('Y') :
363*4887Schin 			{
364*4887Schin 				c = genlen(kstack);
365*4887Schin 				if ((c + eol) > scend)
366*4887Schin 				{
367*4887Schin 					beep();
368*4887Schin 					continue;
369*4887Schin 				}
370*4887Schin 				ep->mark = i;
371*4887Schin 				for(i=eol;i>=cur;i--)
372*4887Schin 					out[c+i] = out[i];
373*4887Schin 				kptr=kstack;
374*4887Schin 				while (i = *kptr++)
375*4887Schin 					out[cur++] = i;
376*4887Schin 				draw(ep,UPDATE);
377*4887Schin 				eol = genlen(out);
378*4887Schin 				continue;
379*4887Schin 			}
380*4887Schin 		case '\n':
381*4887Schin 		case '\r':
382*4887Schin 			c = '\n';
383*4887Schin 			goto process;
384*4887Schin 
385*4887Schin 		case DELETE:	/* delete char 0x7f */
386*4887Schin 		case '\b':	/* backspace, ^h */
387*4887Schin 		case ERASECHAR :
388*4887Schin 			if (count > i)
389*4887Schin 				count = i;
390*4887Schin #ifdef ESH_KAPPEND
391*4887Schin 			kptr = &kstack[count];	/* move old contents here */
392*4887Schin 			if (killing)		/* prepend to killbuf */
393*4887Schin 			{
394*4887Schin 				c = genlen(kstack) + CHARSIZE; /* include '\0' */
395*4887Schin 				while(c--)	/* copy stuff */
396*4887Schin 					kptr[c] = kstack[c];
397*4887Schin 			}
398*4887Schin 			else
399*4887Schin 				*kptr = 0;	/* this is end of data */
400*4887Schin 			killing = 2;		/* we are killing */
401*4887Schin 			i -= count;
402*4887Schin 			eol -= count;
403*4887Schin 			genncpy(kstack,out+i,cur-i);
404*4887Schin #else
405*4887Schin 			while ((count--)&&(i>0))
406*4887Schin 			{
407*4887Schin 				i--;
408*4887Schin 				eol--;
409*4887Schin 			}
410*4887Schin 			genncpy(kstack,out+i,cur-i);
411*4887Schin 			kstack[cur-i] = 0;
412*4887Schin #endif /* ESH_KAPPEND */
413*4887Schin 			gencpy(out+i,out+cur);
414*4887Schin 			ep->mark = i;
415*4887Schin 			goto update;
416*4887Schin 		case cntl('W') :
417*4887Schin #ifdef ESH_KAPPEND
418*4887Schin 			++killing;		/* keep killing flag */
419*4887Schin #endif
420*4887Schin 			if (ep->mark > eol )
421*4887Schin 				ep->mark = eol;
422*4887Schin 			if (ep->mark == i)
423*4887Schin 				continue;
424*4887Schin 			if (ep->mark > i)
425*4887Schin 			{
426*4887Schin 				adjust = ep->mark - i;
427*4887Schin 				ed_ungetchar(ep->ed,cntl('D'));
428*4887Schin 				continue;
429*4887Schin 			}
430*4887Schin 			adjust = i - ep->mark;
431*4887Schin 			ed_ungetchar(ep->ed,usrerase);
432*4887Schin 			continue;
433*4887Schin 		case cntl('D') :
434*4887Schin 			ep->mark = i;
435*4887Schin #ifdef ESH_KAPPEND
436*4887Schin 			if (killing)
437*4887Schin 				kptr = &kstack[genlen(kstack)];	/* append here */
438*4887Schin 			else
439*4887Schin 				kptr = kstack;
440*4887Schin 			killing = 2;			/* we are now killing */
441*4887Schin #else
442*4887Schin 			kptr = kstack;
443*4887Schin #endif /* ESH_KAPPEND */
444*4887Schin 			while ((count--)&&(eol>0)&&(i<eol))
445*4887Schin 			{
446*4887Schin 				*kptr++ = out[i];
447*4887Schin 				eol--;
448*4887Schin 				while(1)
449*4887Schin 				{
450*4887Schin 					if ((out[i] = out[(i+1)])==0)
451*4887Schin 						break;
452*4887Schin 					i++;
453*4887Schin 				}
454*4887Schin 				i = cur;
455*4887Schin 			}
456*4887Schin 			*kptr = '\0';
457*4887Schin 			goto update;
458*4887Schin 		case cntl('C') :
459*4887Schin 		case cntl('F') :
460*4887Schin 		{
461*4887Schin 			int cntlC = (c==cntl('C'));
462*4887Schin 			while (count-- && eol>i)
463*4887Schin 			{
464*4887Schin 				if (cntlC)
465*4887Schin 				{
466*4887Schin 					c = out[i];
467*4887Schin #if SHOPT_MULTIBYTE
468*4887Schin 					if((c&~STRIP)==0 && islower(c))
469*4887Schin #else
470*4887Schin 					if(islower(c))
471*4887Schin #endif /* SHOPT_MULTIBYTE */
472*4887Schin 					{
473*4887Schin 						c += 'A' - 'a';
474*4887Schin 						out[i] = c;
475*4887Schin 					}
476*4887Schin 				}
477*4887Schin 				i++;
478*4887Schin 			}
479*4887Schin 			goto update;
480*4887Schin 		}
481*4887Schin 		case cntl(']') :
482*4887Schin 			c = ed_getchar(ep->ed,1);
483*4887Schin 			if ((count == 0) || (count > eol))
484*4887Schin                         {
485*4887Schin                                 beep();
486*4887Schin                                 continue;
487*4887Schin                         }
488*4887Schin 			if (out[i])
489*4887Schin 				i++;
490*4887Schin 			while (i < eol)
491*4887Schin 			{
492*4887Schin 				if (out[i] == c && --count==0)
493*4887Schin 					goto update;
494*4887Schin 				i++;
495*4887Schin 			}
496*4887Schin 			i = 0;
497*4887Schin 			while (i < cur)
498*4887Schin 			{
499*4887Schin 				if (out[i] == c && --count==0)
500*4887Schin 					break;
501*4887Schin 				i++;
502*4887Schin 			};
503*4887Schin 
504*4887Schin update:
505*4887Schin 			cur = i;
506*4887Schin 			draw(ep,UPDATE);
507*4887Schin 			continue;
508*4887Schin 
509*4887Schin 		case cntl('B') :
510*4887Schin 			if (count > i)
511*4887Schin 				count = i;
512*4887Schin 			i -= count;
513*4887Schin 			goto update;
514*4887Schin 		case cntl('T') :
515*4887Schin 			if ((sh_isoption(SH_EMACS))&& (eol!=i))
516*4887Schin 				i++;
517*4887Schin 			if (i >= 2)
518*4887Schin 			{
519*4887Schin 				c = out[i - 1];
520*4887Schin 				out[i-1] = out[i-2];
521*4887Schin 				out[i-2] = c;
522*4887Schin 			}
523*4887Schin 			else
524*4887Schin 			{
525*4887Schin 				if(sh_isoption(SH_EMACS))
526*4887Schin 					i--;
527*4887Schin 				beep();
528*4887Schin 				continue;
529*4887Schin 			}
530*4887Schin 			goto update;
531*4887Schin 		case cntl('A') :
532*4887Schin 			i = 0;
533*4887Schin 			goto update;
534*4887Schin 		case cntl('E') :
535*4887Schin 			i = eol;
536*4887Schin 			goto update;
537*4887Schin 		case cntl('U') :
538*4887Schin 			adjust = 4*count;
539*4887Schin 			continue;
540*4887Schin 		case KILLCHAR :
541*4887Schin 			cur = 0;
542*4887Schin 			oadjust = -1;
543*4887Schin 		case cntl('K') :
544*4887Schin 			if(oadjust >= 0)
545*4887Schin 			{
546*4887Schin #ifdef ESH_KAPPEND
547*4887Schin 				killing = 2;		/* set killing signal */
548*4887Schin #endif
549*4887Schin 				ep->mark = count;
550*4887Schin 				ed_ungetchar(ep->ed,cntl('W'));
551*4887Schin 				continue;
552*4887Schin 			}
553*4887Schin 			i = cur;
554*4887Schin 			eol = i;
555*4887Schin 			ep->mark = i;
556*4887Schin #ifdef ESH_KAPPEND
557*4887Schin 			if (killing)			/* append to kill buffer */
558*4887Schin 				gencpy(&kstack[genlen(kstack)], &out[i]);
559*4887Schin 			else
560*4887Schin 				gencpy(kstack,&out[i]);
561*4887Schin 			killing = 2;			/* set killing signal */
562*4887Schin #else
563*4887Schin 			gencpy(kstack,&out[i]);
564*4887Schin #endif /* ESH_KAPPEND */
565*4887Schin 			out[i] = 0;
566*4887Schin 			draw(ep,UPDATE);
567*4887Schin 			if (c == KILLCHAR)
568*4887Schin 			{
569*4887Schin 				if (ep->terminal == PAPER)
570*4887Schin 				{
571*4887Schin 					putchar(ep->ed,'\n');
572*4887Schin 					putstring(ep,Prompt);
573*4887Schin 				}
574*4887Schin 				c = ed_getchar(ep->ed,0);
575*4887Schin 				if (c != usrkill)
576*4887Schin 				{
577*4887Schin 					ed_ungetchar(ep->ed,c);
578*4887Schin 					continue;
579*4887Schin 				}
580*4887Schin 				if (ep->terminal == PAPER)
581*4887Schin 					ep->terminal = CRT;
582*4887Schin 				else
583*4887Schin 				{
584*4887Schin 					ep->terminal = PAPER;
585*4887Schin 					putchar(ep->ed,'\n');
586*4887Schin 					putstring(ep,Prompt);
587*4887Schin 				}
588*4887Schin 			}
589*4887Schin 			continue;
590*4887Schin 		case cntl('L'):
591*4887Schin 			ed_crlf(ep->ed);
592*4887Schin 			draw(ep,REFRESH);
593*4887Schin 			continue;
594*4887Schin 		case cntl('[') :
595*4887Schin 		do_escape:
596*4887Schin 			adjust = escape(ep,out,oadjust);
597*4887Schin 			continue;
598*4887Schin 		case cntl('R') :
599*4887Schin 			search(ep,out,count);
600*4887Schin 			goto drawline;
601*4887Schin 		case cntl('P') :
602*4887Schin                         if (count <= hloff)
603*4887Schin                                 hloff -= count;
604*4887Schin                         else
605*4887Schin                         {
606*4887Schin                                 hline -= count - hloff;
607*4887Schin                                 hloff = 0;
608*4887Schin                         }
609*4887Schin #ifdef ESH_NFIRST
610*4887Schin 			if (hline <= hismin)
611*4887Schin #else
612*4887Schin 			if (hline < hismin)
613*4887Schin #endif /* ESH_NFIRST */
614*4887Schin 			{
615*4887Schin 				hline = hismin+1;
616*4887Schin 				beep();
617*4887Schin #ifndef ESH_NFIRST
618*4887Schin 				continue;
619*4887Schin #endif
620*4887Schin 			}
621*4887Schin 			goto common;
622*4887Schin 
623*4887Schin 		case cntl('O') :
624*4887Schin 			location.hist_command = hline;
625*4887Schin 			location.hist_line = hloff;
626*4887Schin 			ep->CntrlO = 1;
627*4887Schin 			c = '\n';
628*4887Schin 			goto process;
629*4887Schin 		case cntl('N') :
630*4887Schin #ifdef ESH_NFIRST
631*4887Schin 			hline = location.hist_command;	/* start at saved position */
632*4887Schin 			hloff = location.hist_line;
633*4887Schin #endif /* ESH_NFIRST */
634*4887Schin 			location = hist_locate(sh.hist_ptr,hline,hloff,count);
635*4887Schin 			if (location.hist_command > histlines)
636*4887Schin 			{
637*4887Schin 				beep();
638*4887Schin #ifdef ESH_NFIRST
639*4887Schin 				location.hist_command = histlines;
640*4887Schin 				location.hist_line = ep->in_mult;
641*4887Schin #else
642*4887Schin 				continue;
643*4887Schin #endif /* ESH_NFIRST */
644*4887Schin 			}
645*4887Schin 			hline = location.hist_command;
646*4887Schin 			hloff = location.hist_line;
647*4887Schin 		common:
648*4887Schin #ifdef ESH_NFIRST
649*4887Schin 			location.hist_command = hline;	/* save current position */
650*4887Schin 			location.hist_line = hloff;
651*4887Schin #endif
652*4887Schin 			hist_copy((char*)out,MAXLINE, hline,hloff);
653*4887Schin #if SHOPT_MULTIBYTE
654*4887Schin 			ed_internal((char*)(out),out);
655*4887Schin #endif /* SHOPT_MULTIBYTE */
656*4887Schin 		drawline:
657*4887Schin 			eol = genlen(out);
658*4887Schin 			cur = eol;
659*4887Schin 			draw(ep,UPDATE);
660*4887Schin 			continue;
661*4887Schin 		}
662*4887Schin 
663*4887Schin 	}
664*4887Schin 
665*4887Schin process:
666*4887Schin 
667*4887Schin 	if (c == (-1))
668*4887Schin 	{
669*4887Schin 		lookahead = 0;
670*4887Schin 		beep();
671*4887Schin 		*out = '\0';
672*4887Schin 	}
673*4887Schin 	draw(ep,FINAL);
674*4887Schin 	tty_cooked(ERRIO);
675*4887Schin 	if(ed->e_nlist)
676*4887Schin 	{
677*4887Schin 		ed->e_nlist = 0;
678*4887Schin 		stakset(ed->e_stkptr,ed->e_stkoff);
679*4887Schin 	}
680*4887Schin 	if(c == '\n')
681*4887Schin 	{
682*4887Schin 		out[eol++] = '\n';
683*4887Schin 		out[eol] = '\0';
684*4887Schin 		ed_crlf(ep->ed);
685*4887Schin 	}
686*4887Schin #if SHOPT_MULTIBYTE
687*4887Schin 	ed_external(out,buff);
688*4887Schin #endif /* SHOPT_MULTIBYTE */
689*4887Schin 	i = strlen(buff);
690*4887Schin 	if (i)
691*4887Schin 		return(i);
692*4887Schin 	return(-1);
693*4887Schin }
694*4887Schin 
695*4887Schin static void show_info(Emacs_t *ep,const char *str)
696*4887Schin {
697*4887Schin 	register genchar *out = drawbuff;
698*4887Schin 	register int c;
699*4887Schin 	genchar string[LBUF];
700*4887Schin 	int sav_cur = cur;
701*4887Schin 	/* save current line */
702*4887Schin 	genncpy(string,out,sizeof(string)/sizeof(*string));
703*4887Schin 	*out = 0;
704*4887Schin 	cur = 0;
705*4887Schin #if SHOPT_MULTIBYTE
706*4887Schin 	ed_internal(str,out);
707*4887Schin #else
708*4887Schin 	gencpy(out,str);
709*4887Schin #endif	/* SHOPT_MULTIBYTE */
710*4887Schin 	draw(ep,UPDATE);
711*4887Schin 	c = ed_getchar(ep->ed,0);
712*4887Schin 	if(c!=' ')
713*4887Schin 		ed_ungetchar(ep->ed,c);
714*4887Schin 	/* restore line */
715*4887Schin 	cur = sav_cur;
716*4887Schin 	genncpy(out,string,sizeof(string)/sizeof(*string));
717*4887Schin 	draw(ep,UPDATE);
718*4887Schin }
719*4887Schin 
720*4887Schin static void putstring(Emacs_t* ep,register char *sp)
721*4887Schin {
722*4887Schin 	register int c;
723*4887Schin 	while (c= *sp++)
724*4887Schin 		 putchar(ep->ed,c);
725*4887Schin }
726*4887Schin 
727*4887Schin 
728*4887Schin static int escape(register Emacs_t* ep,register genchar *out,int count)
729*4887Schin {
730*4887Schin 	register int i,value;
731*4887Schin 	int digit,ch;
732*4887Schin 	digit = 0;
733*4887Schin 	value = 0;
734*4887Schin 	while ((i=ed_getchar(ep->ed,0)),isdigit(i))
735*4887Schin 	{
736*4887Schin 		value *= 10;
737*4887Schin 		value += (i - '0');
738*4887Schin 		digit = 1;
739*4887Schin 	}
740*4887Schin 	if (digit)
741*4887Schin 	{
742*4887Schin 		ed_ungetchar(ep->ed,i) ;
743*4887Schin #ifdef ESH_KAPPEND
744*4887Schin 		++killing;		/* don't modify killing signal */
745*4887Schin #endif
746*4887Schin 		return(value);
747*4887Schin 	}
748*4887Schin 	value = count;
749*4887Schin 	if(value<0)
750*4887Schin 		value = 1;
751*4887Schin 	switch(ch=i)
752*4887Schin 	{
753*4887Schin 		case cntl('V'):
754*4887Schin 			show_info(ep,fmtident(e_version));
755*4887Schin 			return(-1);
756*4887Schin 		case ' ':
757*4887Schin 			ep->mark = cur;
758*4887Schin 			return(-1);
759*4887Schin 
760*4887Schin #ifdef ESH_KAPPEND
761*4887Schin 		case '+':		/* M-+ = append next kill */
762*4887Schin 			killing = 2;
763*4887Schin 			return -1;	/* no argument for next command */
764*4887Schin #endif
765*4887Schin 
766*4887Schin 		case 'p':	/* M-p == ^W^Y (copy stack == kill & yank) */
767*4887Schin 			ed_ungetchar(ep->ed,cntl('Y'));
768*4887Schin 			ed_ungetchar(ep->ed,cntl('W'));
769*4887Schin #ifdef ESH_KAPPEND
770*4887Schin 			killing = 0;	/* start fresh */
771*4887Schin #endif
772*4887Schin 			return(-1);
773*4887Schin 
774*4887Schin 		case 'l':	/* M-l == lower-case */
775*4887Schin 		case 'd':
776*4887Schin 		case 'c':
777*4887Schin 		case 'f':
778*4887Schin 		{
779*4887Schin 			i = cur;
780*4887Schin 			while(value-- && i<eol)
781*4887Schin 			{
782*4887Schin 				while ((out[i])&&(!isword(i)))
783*4887Schin 					i++;
784*4887Schin 				while ((out[i])&&(isword(i)))
785*4887Schin 					i++;
786*4887Schin 			}
787*4887Schin 			if(ch=='l')
788*4887Schin 			{
789*4887Schin 				value = i-cur;
790*4887Schin 				while (value-- > 0)
791*4887Schin 				{
792*4887Schin 					i = out[cur];
793*4887Schin #if SHOPT_MULTIBYTE
794*4887Schin 					if((i&~STRIP)==0 && isupper(i))
795*4887Schin #else
796*4887Schin 					if(isupper(i))
797*4887Schin #endif /* SHOPT_MULTIBYTE */
798*4887Schin 					{
799*4887Schin 						i += 'a' - 'A';
800*4887Schin 						out[cur] = i;
801*4887Schin 					}
802*4887Schin 					cur++;
803*4887Schin 				}
804*4887Schin 				draw(ep,UPDATE);
805*4887Schin 				return(-1);
806*4887Schin 			}
807*4887Schin 
808*4887Schin 			else if(ch=='f')
809*4887Schin 				goto update;
810*4887Schin 			else if(ch=='c')
811*4887Schin 			{
812*4887Schin 				ed_ungetchar(ep->ed,cntl('C'));
813*4887Schin 				return(i-cur);
814*4887Schin 			}
815*4887Schin 			else
816*4887Schin 			{
817*4887Schin 				if (i-cur)
818*4887Schin 				{
819*4887Schin 					ed_ungetchar(ep->ed,cntl('D'));
820*4887Schin #ifdef ESH_KAPPEND
821*4887Schin 					++killing;	/* keep killing signal */
822*4887Schin #endif
823*4887Schin 					return(i-cur);
824*4887Schin 				}
825*4887Schin 				beep();
826*4887Schin 				return(-1);
827*4887Schin 			}
828*4887Schin 		}
829*4887Schin 
830*4887Schin 
831*4887Schin 		case 'b':
832*4887Schin 		case DELETE :
833*4887Schin 		case '\b':
834*4887Schin 		case 'h':
835*4887Schin 		{
836*4887Schin 			i = cur;
837*4887Schin 			while(value-- && i>0)
838*4887Schin 			{
839*4887Schin 				i--;
840*4887Schin 				while ((i>0)&&(!isword(i)))
841*4887Schin 					i--;
842*4887Schin 				while ((i>0)&&(isword(i-1)))
843*4887Schin 					i--;
844*4887Schin 			}
845*4887Schin 			if(ch=='b')
846*4887Schin 				goto update;
847*4887Schin 			else
848*4887Schin 			{
849*4887Schin 				ed_ungetchar(ep->ed,usrerase);
850*4887Schin #ifdef ESH_KAPPEND
851*4887Schin 				++killing;
852*4887Schin #endif
853*4887Schin 				return(cur-i);
854*4887Schin 			}
855*4887Schin 		}
856*4887Schin 
857*4887Schin 		case '>':
858*4887Schin 			ed_ungetchar(ep->ed,cntl('N'));
859*4887Schin #ifdef ESH_NFIRST
860*4887Schin 			if (ep->in_mult)
861*4887Schin 			{
862*4887Schin 				location.hist_command = histlines;
863*4887Schin 				location.hist_line = ep->in_mult - 1;
864*4887Schin 			}
865*4887Schin 			else
866*4887Schin 			{
867*4887Schin 				location.hist_command = histlines - 1;
868*4887Schin 				location.hist_line = 0;
869*4887Schin 			}
870*4887Schin #else
871*4887Schin 			hline = histlines-1;
872*4887Schin 			hloff = 0;
873*4887Schin #endif /* ESH_NFIRST */
874*4887Schin 			return(0);
875*4887Schin 
876*4887Schin 		case '<':
877*4887Schin 			ed_ungetchar(ep->ed,cntl('P'));
878*4887Schin 			hloff = 0;
879*4887Schin #ifdef ESH_NFIRST
880*4887Schin 			hline = hismin + 1;
881*4887Schin 			return 0;
882*4887Schin #else
883*4887Schin 			return(hline-hismin);
884*4887Schin #endif /* ESH_NFIRST */
885*4887Schin 
886*4887Schin 
887*4887Schin 		case '#':
888*4887Schin 			ed_ungetchar(ep->ed,'\n');
889*4887Schin 			ed_ungetchar(ep->ed,(out[0]=='#')?cntl('D'):'#');
890*4887Schin 			ed_ungetchar(ep->ed,cntl('A'));
891*4887Schin 			return(-1);
892*4887Schin 		case '_' :
893*4887Schin 		case '.' :
894*4887Schin 		{
895*4887Schin 			genchar name[MAXLINE];
896*4887Schin 			char buf[MAXLINE];
897*4887Schin 			char *ptr;
898*4887Schin 			ptr = hist_word(buf,MAXLINE,(count?count:-1));
899*4887Schin #if !KSHELL
900*4887Schin 			if(ptr==0)
901*4887Schin 			{
902*4887Schin 				beep();
903*4887Schin 				break;
904*4887Schin 			}
905*4887Schin #endif	/* KSHELL */
906*4887Schin 			if ((eol - cur) >= sizeof(name))
907*4887Schin 			{
908*4887Schin 				beep();
909*4887Schin 				return(-1);
910*4887Schin 			}
911*4887Schin 			ep->mark = cur;
912*4887Schin 			gencpy(name,&out[cur]);
913*4887Schin 			while(*ptr)
914*4887Schin 			{
915*4887Schin 				out[cur++] = *ptr++;
916*4887Schin 				eol++;
917*4887Schin 			}
918*4887Schin 			gencpy(&out[cur],name);
919*4887Schin 			draw(ep,UPDATE);
920*4887Schin 			return(-1);
921*4887Schin 		}
922*4887Schin #if KSHELL
923*4887Schin 
924*4887Schin 		/* file name expansion */
925*4887Schin 		case cntl('[') :	/* filename completion */
926*4887Schin 			i = '\\';
927*4887Schin 		case '*':		/* filename expansion */
928*4887Schin 		case '=':	/* escape = - list all matching file names */
929*4887Schin 			ep->mark = cur;
930*4887Schin 			if(ed_expand(ep->ed,(char*)out,&cur,&eol,i,count) < 0)
931*4887Schin 			{
932*4887Schin 				if(ep->ed->e_tabcount==1)
933*4887Schin 				{
934*4887Schin 					ep->ed->e_tabcount=2;
935*4887Schin 					ed_ungetchar(ep->ed,cntl('\t'));
936*4887Schin 					return(-1);
937*4887Schin 				}
938*4887Schin 				beep();
939*4887Schin 			}
940*4887Schin 			else if(i=='=')
941*4887Schin 			{
942*4887Schin 				draw(ep,REFRESH);
943*4887Schin 				if(count>0)
944*4887Schin 					ep->ed->e_tabcount=0;
945*4887Schin 				else
946*4887Schin 				{
947*4887Schin 					i=ed_getchar(ep->ed,0);
948*4887Schin 					ed_ungetchar(ep->ed,i);
949*4887Schin 					if(isdigit(i))
950*4887Schin 						ed_ungetchar(ep->ed,ESC);
951*4887Schin 				}
952*4887Schin 			}
953*4887Schin 			else
954*4887Schin 			{
955*4887Schin 				if(i=='\\' && cur>ep->mark && (out[cur-1]=='/' || out[cur-1]==' '))
956*4887Schin 					ep->ed->e_tabcount=0;
957*4887Schin 				draw(ep,UPDATE);
958*4887Schin 			}
959*4887Schin 			return(-1);
960*4887Schin 
961*4887Schin 		/* search back for character */
962*4887Schin 		case cntl(']'):	/* feature not in book */
963*4887Schin 		{
964*4887Schin 			int c = ed_getchar(ep->ed,1);
965*4887Schin 			if ((value == 0) || (value > eol))
966*4887Schin 			{
967*4887Schin 				beep();
968*4887Schin 				return(-1);
969*4887Schin 			}
970*4887Schin 			i = cur;
971*4887Schin 			if (i > 0)
972*4887Schin 				i--;
973*4887Schin 			while (i >= 0)
974*4887Schin 			{
975*4887Schin 				if (out[i] == c && --value==0)
976*4887Schin 					goto update;
977*4887Schin 				i--;
978*4887Schin 			}
979*4887Schin 			i = eol;
980*4887Schin 			while (i > cur)
981*4887Schin 			{
982*4887Schin 				if (out[i] == c && --value==0)
983*4887Schin 					break;
984*4887Schin 				i--;
985*4887Schin 			};
986*4887Schin 
987*4887Schin 		}
988*4887Schin 		update:
989*4887Schin 			cur = i;
990*4887Schin 			draw(ep,UPDATE);
991*4887Schin 			return(-1);
992*4887Schin 
993*4887Schin #ifdef _cmd_tput
994*4887Schin 		case cntl('L'): /* clear screen */
995*4887Schin 			sh_trap("tput clear", 0);
996*4887Schin 			draw(ep,REFRESH);
997*4887Schin 			return(-1);
998*4887Schin #endif
999*4887Schin 		case '[':	/* feature not in book */
1000*4887Schin 			switch(i=ed_getchar(ep->ed,1))
1001*4887Schin 			{
1002*4887Schin 			    case 'A':
1003*4887Schin 				ed_ungetchar(ep->ed,cntl('P'));
1004*4887Schin 				return(-1);
1005*4887Schin 			    case 'B':
1006*4887Schin 				ed_ungetchar(ep->ed,cntl('N'));
1007*4887Schin 				return(-1);
1008*4887Schin 			    case 'C':
1009*4887Schin 				ed_ungetchar(ep->ed,cntl('F'));
1010*4887Schin 				return(-1);
1011*4887Schin 			    case 'D':
1012*4887Schin 				ed_ungetchar(ep->ed,cntl('B'));
1013*4887Schin 				return(-1);
1014*4887Schin 			    case 'H':
1015*4887Schin 				ed_ungetchar(ep->ed,cntl('A'));
1016*4887Schin 				return(-1);
1017*4887Schin 			    case 'Y':
1018*4887Schin 				ed_ungetchar(ep->ed,cntl('E'));
1019*4887Schin 				return(-1);
1020*4887Schin 			    default:
1021*4887Schin 				ed_ungetchar(ep->ed,i);
1022*4887Schin 			}
1023*4887Schin 			i = '_';
1024*4887Schin 
1025*4887Schin 		default:
1026*4887Schin 			/* look for user defined macro definitions */
1027*4887Schin 			if(ed_macro(ep->ed,i))
1028*4887Schin #   ifdef ESH_BETTER
1029*4887Schin 				return(count);	/* pass argument to macro */
1030*4887Schin #   else
1031*4887Schin 				return(-1);
1032*4887Schin #   endif /* ESH_BETTER */
1033*4887Schin #else
1034*4887Schin 		update:
1035*4887Schin 			cur = i;
1036*4887Schin 			draw(ep,UPDATE);
1037*4887Schin 			return(-1);
1038*4887Schin 
1039*4887Schin 		default:
1040*4887Schin #endif	/* KSHELL */
1041*4887Schin 		beep();
1042*4887Schin 		return(-1);
1043*4887Schin 	}
1044*4887Schin }
1045*4887Schin 
1046*4887Schin 
1047*4887Schin /*
1048*4887Schin  * This routine process all commands starting with ^X
1049*4887Schin  */
1050*4887Schin 
1051*4887Schin static void xcommands(register Emacs_t *ep,int count)
1052*4887Schin {
1053*4887Schin         register int i = ed_getchar(ep->ed,0);
1054*4887Schin 	NOT_USED(count);
1055*4887Schin         switch(i)
1056*4887Schin         {
1057*4887Schin                 case cntl('X'):	/* exchange dot and mark */
1058*4887Schin                         if (ep->mark > eol)
1059*4887Schin                                 ep->mark = eol;
1060*4887Schin                         i = ep->mark;
1061*4887Schin                         ep->mark = cur;
1062*4887Schin                         cur = i;
1063*4887Schin                         draw(ep,UPDATE);
1064*4887Schin                         return;
1065*4887Schin 
1066*4887Schin #if KSHELL
1067*4887Schin #   ifdef ESH_BETTER
1068*4887Schin                 case cntl('E'):	/* invoke emacs on current command */
1069*4887Schin 			if(ed_fulledit(ep->ed)==-1)
1070*4887Schin 				beep();
1071*4887Schin 			else
1072*4887Schin 			{
1073*4887Schin #if SHOPT_MULTIBYTE
1074*4887Schin 				ed_internal((char*)drawbuff,drawbuff);
1075*4887Schin #endif /* SHOPT_MULTIBYTE */
1076*4887Schin 				ed_ungetchar(ep->ed,'\n');
1077*4887Schin 			}
1078*4887Schin 			return;
1079*4887Schin 
1080*4887Schin #	define itos(i)	fmtbase((long)(i),0,0)/* want signed conversion */
1081*4887Schin 
1082*4887Schin 		case cntl('H'):		/* ^X^H show history info */
1083*4887Schin 			{
1084*4887Schin 				char hbuf[MAXLINE];
1085*4887Schin 
1086*4887Schin 				strcpy(hbuf, "Current command ");
1087*4887Schin 				strcat(hbuf, itos(hline));
1088*4887Schin 				if (hloff)
1089*4887Schin 				{
1090*4887Schin 					strcat(hbuf, " (line ");
1091*4887Schin 					strcat(hbuf, itos(hloff+1));
1092*4887Schin 					strcat(hbuf, ")");
1093*4887Schin 				}
1094*4887Schin 				if ((hline != location.hist_command) ||
1095*4887Schin 				    (hloff != location.hist_line))
1096*4887Schin 				{
1097*4887Schin 					strcat(hbuf, "; Previous command ");
1098*4887Schin 					strcat(hbuf, itos(location.hist_command));
1099*4887Schin 					if (location.hist_line)
1100*4887Schin 					{
1101*4887Schin 						strcat(hbuf, " (line ");
1102*4887Schin 						strcat(hbuf, itos(location.hist_line+1));
1103*4887Schin 						strcat(hbuf, ")");
1104*4887Schin 					}
1105*4887Schin 				}
1106*4887Schin 				show_info(ep,hbuf);
1107*4887Schin 				return;
1108*4887Schin 			}
1109*4887Schin #	if 0	/* debugging, modify as required */
1110*4887Schin 		case cntl('D'):		/* ^X^D show debugging info */
1111*4887Schin 			{
1112*4887Schin 				char debugbuf[MAXLINE];
1113*4887Schin 
1114*4887Schin 				strcpy(debugbuf, "count=");
1115*4887Schin 				strcat(debugbuf, itos(count));
1116*4887Schin 				strcat(debugbuf, " eol=");
1117*4887Schin 				strcat(debugbuf, itos(eol));
1118*4887Schin 				strcat(debugbuf, " cur=");
1119*4887Schin 				strcat(debugbuf, itos(cur));
1120*4887Schin 				strcat(debugbuf, " crallowed=");
1121*4887Schin 				strcat(debugbuf, itos(crallowed));
1122*4887Schin 				strcat(debugbuf, " plen=");
1123*4887Schin 				strcat(debugbuf, itos(plen));
1124*4887Schin 				strcat(debugbuf, " w_size=");
1125*4887Schin 				strcat(debugbuf, itos(w_size));
1126*4887Schin 
1127*4887Schin 				show_info(ep,debugbuf);
1128*4887Schin 				return;
1129*4887Schin 			}
1130*4887Schin #	endif /* debugging code */
1131*4887Schin #   endif /* ESH_BETTER */
1132*4887Schin #endif /* KSHELL */
1133*4887Schin 
1134*4887Schin                 default:
1135*4887Schin                         beep();
1136*4887Schin                         return;
1137*4887Schin 	}
1138*4887Schin }
1139*4887Schin 
1140*4887Schin static void search(Emacs_t* ep,genchar *out,int direction)
1141*4887Schin {
1142*4887Schin #ifndef ESH_NFIRST
1143*4887Schin 	Histloc_t location;
1144*4887Schin #endif
1145*4887Schin 	register int i,sl;
1146*4887Schin 	genchar str_buff[LBUF];
1147*4887Schin 	register genchar *string = drawbuff;
1148*4887Schin 	/* save current line */
1149*4887Schin 	int sav_cur = cur;
1150*4887Schin 	genncpy(str_buff,string,sizeof(str_buff)/sizeof(*str_buff));
1151*4887Schin 	string[0] = '^';
1152*4887Schin 	string[1] = 'R';
1153*4887Schin 	string[2] = '\0';
1154*4887Schin 	sl = 2;
1155*4887Schin 	cur = sl;
1156*4887Schin 	draw(ep,UPDATE);
1157*4887Schin 	while ((i = ed_getchar(ep->ed,1))&&(i != '\r')&&(i != '\n'))
1158*4887Schin 	{
1159*4887Schin 		if (i==usrerase || i==DELETE || i=='\b' || i==ERASECHAR)
1160*4887Schin 		{
1161*4887Schin 			if (sl > 2)
1162*4887Schin 			{
1163*4887Schin 				string[--sl] = '\0';
1164*4887Schin 				cur = sl;
1165*4887Schin 				draw(ep,UPDATE);
1166*4887Schin 			}
1167*4887Schin 			else
1168*4887Schin 				beep();
1169*4887Schin 			continue;
1170*4887Schin 		}
1171*4887Schin 		if (i==usrkill)
1172*4887Schin 		{
1173*4887Schin 			beep();
1174*4887Schin 			goto restore;
1175*4887Schin 		}
1176*4887Schin 		if (i == '\\')
1177*4887Schin 		{
1178*4887Schin 			string[sl++] = '\\';
1179*4887Schin 			string[sl] = '\0';
1180*4887Schin 			cur = sl;
1181*4887Schin 			draw(ep,APPEND);
1182*4887Schin 			i = ed_getchar(ep->ed,1);
1183*4887Schin 			string[--sl] = '\0';
1184*4887Schin 		}
1185*4887Schin 		string[sl++] = i;
1186*4887Schin 		string[sl] = '\0';
1187*4887Schin 		cur = sl;
1188*4887Schin 		draw(ep,APPEND);
1189*4887Schin 	}
1190*4887Schin 	i = genlen(string);
1191*4887Schin 
1192*4887Schin 	if (direction < 1)
1193*4887Schin 	{
1194*4887Schin 		ep->prevdirection = -ep->prevdirection;
1195*4887Schin 		direction = 1;
1196*4887Schin 	}
1197*4887Schin 	else
1198*4887Schin 		direction = -1;
1199*4887Schin 	if (i != 2)
1200*4887Schin 	{
1201*4887Schin #if SHOPT_MULTIBYTE
1202*4887Schin 		ed_external(string,(char*)string);
1203*4887Schin #endif /* SHOPT_MULTIBYTE */
1204*4887Schin 		strncpy(lstring,((char*)string)+2,SEARCHSIZE);
1205*4887Schin 		ep->prevdirection = direction;
1206*4887Schin 	}
1207*4887Schin 	else
1208*4887Schin 		direction = ep->prevdirection ;
1209*4887Schin 	location = hist_find(sh.hist_ptr,(char*)lstring,hline,1,direction);
1210*4887Schin 	i = location.hist_command;
1211*4887Schin 	if(i>0)
1212*4887Schin 	{
1213*4887Schin 		hline = i;
1214*4887Schin #ifdef ESH_NFIRST
1215*4887Schin 		hloff = location.hist_line = 0;	/* display first line of multi line command */
1216*4887Schin #else
1217*4887Schin 		hloff = location.hist_line;
1218*4887Schin #endif /* ESH_NFIRST */
1219*4887Schin 		hist_copy((char*)out,MAXLINE, hline,hloff);
1220*4887Schin #if SHOPT_MULTIBYTE
1221*4887Schin 		ed_internal((char*)out,out);
1222*4887Schin #endif /* SHOPT_MULTIBYTE */
1223*4887Schin 		return;
1224*4887Schin 	}
1225*4887Schin 	if (i < 0)
1226*4887Schin 	{
1227*4887Schin 		beep();
1228*4887Schin #ifdef ESH_NFIRST
1229*4887Schin 		location.hist_command = hline;
1230*4887Schin 		location.hist_line = hloff;
1231*4887Schin #else
1232*4887Schin 		hloff = 0;
1233*4887Schin 		hline = histlines;
1234*4887Schin #endif /* ESH_NFIRST */
1235*4887Schin 	}
1236*4887Schin restore:
1237*4887Schin 	genncpy(string,str_buff,sizeof(str_buff)/sizeof(*str_buff));
1238*4887Schin 	cur = sav_cur;
1239*4887Schin 	return;
1240*4887Schin }
1241*4887Schin 
1242*4887Schin 
1243*4887Schin /* Adjust screen to agree with inputs: logical line and cursor */
1244*4887Schin /* If 'first' assume screen is blank */
1245*4887Schin /* Prompt is always kept on the screen */
1246*4887Schin 
1247*4887Schin static void draw(register Emacs_t *ep,Draw_t option)
1248*4887Schin {
1249*4887Schin #define	NORMAL ' '
1250*4887Schin #define	LOWER  '<'
1251*4887Schin #define	BOTH   '*'
1252*4887Schin #define	UPPER  '>'
1253*4887Schin 
1254*4887Schin 	register genchar *sptr;		/* Pointer within screen */
1255*4887Schin 	genchar nscreen[2*MAXLINE];	/* New entire screen */
1256*4887Schin 	genchar *ncursor;		/* New cursor */
1257*4887Schin 	register genchar *nptr;		/* Pointer to New screen */
1258*4887Schin 	char  longline;			/* Line overflow */
1259*4887Schin 	genchar *logcursor;
1260*4887Schin 	genchar *nscend;		/* end of logical screen */
1261*4887Schin 	register int i;
1262*4887Schin 
1263*4887Schin 	nptr = nscreen;
1264*4887Schin 	sptr = drawbuff;
1265*4887Schin 	logcursor = sptr + cur;
1266*4887Schin 	longline = NORMAL;
1267*4887Schin 
1268*4887Schin 	if (option == FIRST || option == REFRESH)
1269*4887Schin 	{
1270*4887Schin 		ep->overflow = NORMAL;
1271*4887Schin 		ep->cursor = ep->screen;
1272*4887Schin 		ep->offset = 0;
1273*4887Schin 		ep->cr_ok = crallowed;
1274*4887Schin 		if (option == FIRST)
1275*4887Schin 		{
1276*4887Schin 			ep->scvalid = 1;
1277*4887Schin 			return;
1278*4887Schin 		}
1279*4887Schin 		*ep->cursor = '\0';
1280*4887Schin 		putstring(ep,Prompt);	/* start with prompt */
1281*4887Schin 	}
1282*4887Schin 
1283*4887Schin 	/*********************
1284*4887Schin 	 Do not update screen if pending characters
1285*4887Schin 	**********************/
1286*4887Schin 
1287*4887Schin 	if ((lookahead)&&(option != FINAL))
1288*4887Schin 	{
1289*4887Schin 
1290*4887Schin 		ep->scvalid = 0; /* Screen is out of date, APPEND will not work */
1291*4887Schin 
1292*4887Schin 		return;
1293*4887Schin 	}
1294*4887Schin 
1295*4887Schin 	/***************************************
1296*4887Schin 	If in append mode, cursor at end of line, screen up to date,
1297*4887Schin 	the previous character was a 'normal' character,
1298*4887Schin 	and the window has room for another character.
1299*4887Schin 	Then output the character and adjust the screen only.
1300*4887Schin 	*****************************************/
1301*4887Schin 
1302*4887Schin 
1303*4887Schin 	i = *(logcursor-1);	/* last character inserted */
1304*4887Schin 
1305*4887Schin 	if ((option == APPEND)&&(ep->scvalid)&&(*logcursor == '\0')&&
1306*4887Schin 	    print(i)&&((ep->cursor-ep->screen)<(w_size-1)))
1307*4887Schin 	{
1308*4887Schin 		putchar(ep->ed,i);
1309*4887Schin 		*ep->cursor++ = i;
1310*4887Schin 		*ep->cursor = '\0';
1311*4887Schin 		return;
1312*4887Schin 	}
1313*4887Schin 
1314*4887Schin 	/* copy the line */
1315*4887Schin 	ncursor = nptr + ed_virt_to_phys(ep->ed,sptr,nptr,cur,0,0);
1316*4887Schin 	nptr += genlen(nptr);
1317*4887Schin 	sptr += genlen(sptr);
1318*4887Schin 	nscend = nptr - 1;
1319*4887Schin 	if(sptr == logcursor)
1320*4887Schin 		ncursor = nptr;
1321*4887Schin 
1322*4887Schin 	/*********************
1323*4887Schin 	 Does ncursor appear on the screen?
1324*4887Schin 	 If not, adjust the screen offset so it does.
1325*4887Schin 	**********************/
1326*4887Schin 
1327*4887Schin 	i = ncursor - nscreen;
1328*4887Schin 
1329*4887Schin 	if ((ep->offset && i<=ep->offset)||(i >= (ep->offset+w_size)))
1330*4887Schin 	{
1331*4887Schin 		/* Center the cursor on the screen */
1332*4887Schin 		ep->offset = i - (w_size>>1);
1333*4887Schin 		if (--ep->offset < 0)
1334*4887Schin 			ep->offset = 0;
1335*4887Schin 	}
1336*4887Schin 
1337*4887Schin 	/*********************
1338*4887Schin 	 Is the range of screen[0] thru screen[w_size] up-to-date
1339*4887Schin 	 with nscreen[offset] thru nscreen[offset+w_size] ?
1340*4887Schin 	 If not, update as need be.
1341*4887Schin 	***********************/
1342*4887Schin 
1343*4887Schin 	nptr = &nscreen[ep->offset];
1344*4887Schin 	sptr = ep->screen;
1345*4887Schin 
1346*4887Schin 	i = w_size;
1347*4887Schin 
1348*4887Schin 	while (i-- > 0)
1349*4887Schin 	{
1350*4887Schin 
1351*4887Schin 		if (*nptr == '\0')
1352*4887Schin 		{
1353*4887Schin 			*(nptr + 1) = '\0';
1354*4887Schin 			*nptr = ' ';
1355*4887Schin 		}
1356*4887Schin 		if (*sptr == '\0')
1357*4887Schin 		{
1358*4887Schin 			*(sptr + 1) = '\0';
1359*4887Schin 			*sptr = ' ';
1360*4887Schin 		}
1361*4887Schin 		if (*nptr == *sptr)
1362*4887Schin 		{
1363*4887Schin 			nptr++;
1364*4887Schin 			sptr++;
1365*4887Schin 			continue;
1366*4887Schin 		}
1367*4887Schin 		setcursor(ep,sptr-ep->screen,*nptr);
1368*4887Schin 		*sptr++ = *nptr++;
1369*4887Schin #if SHOPT_MULTIBYTE
1370*4887Schin 		while(*nptr==MARKER)
1371*4887Schin 		{
1372*4887Schin 			if(*sptr=='\0')
1373*4887Schin 				*(sptr + 1) = '\0';
1374*4887Schin 			*sptr++ = *nptr++;
1375*4887Schin 			i--;
1376*4887Schin 			ep->cursor++;
1377*4887Schin 		}
1378*4887Schin #endif /* SHOPT_MULTIBYTE */
1379*4887Schin 	}
1380*4887Schin 
1381*4887Schin 	/******************
1382*4887Schin 
1383*4887Schin 	Screen overflow checks
1384*4887Schin 
1385*4887Schin 	********************/
1386*4887Schin 
1387*4887Schin 	if (nscend >= &nscreen[ep->offset+w_size])
1388*4887Schin 	{
1389*4887Schin 		if (ep->offset > 0)
1390*4887Schin 			longline = BOTH;
1391*4887Schin 		else
1392*4887Schin 			longline = UPPER;
1393*4887Schin 	}
1394*4887Schin 	else
1395*4887Schin 	{
1396*4887Schin 		if (ep->offset > 0)
1397*4887Schin 			longline = LOWER;
1398*4887Schin 	}
1399*4887Schin 
1400*4887Schin 	/* Update screen overflow indicator if need be */
1401*4887Schin 
1402*4887Schin 	if (longline != ep->overflow)
1403*4887Schin 	{
1404*4887Schin 		setcursor(ep,w_size,longline);
1405*4887Schin 		ep->overflow = longline;
1406*4887Schin 	}
1407*4887Schin 	i = (ncursor-nscreen) - ep->offset;
1408*4887Schin 	setcursor(ep,i,0);
1409*4887Schin 	if(option==FINAL && ep->ed->e_multiline)
1410*4887Schin 		setcursor(ep,nscend-nscreen,0);
1411*4887Schin 	ep->scvalid = 1;
1412*4887Schin 	return;
1413*4887Schin }
1414*4887Schin 
1415*4887Schin /*
1416*4887Schin  * put the cursor to the <newp> position within screen buffer
1417*4887Schin  * if <c> is non-zero then output this character
1418*4887Schin  * cursor is set to reflect the change
1419*4887Schin  */
1420*4887Schin 
1421*4887Schin static void setcursor(register Emacs_t *ep,register int newp,int c)
1422*4887Schin {
1423*4887Schin 	register int oldp = ep->cursor - ep->screen;
1424*4887Schin 	newp  = ed_setcursor(ep->ed, ep->screen, oldp, newp, 0);
1425*4887Schin 	if(c)
1426*4887Schin 	{
1427*4887Schin 		putchar(ep->ed,c);
1428*4887Schin 		newp++;
1429*4887Schin 	}
1430*4887Schin 	ep->cursor = ep->screen+newp;
1431*4887Schin 	return;
1432*4887Schin }
1433*4887Schin 
1434*4887Schin #if SHOPT_MULTIBYTE
1435*4887Schin static int print(register int c)
1436*4887Schin {
1437*4887Schin 	return((c&~STRIP)==0 && isprint(c));
1438*4887Schin }
1439*4887Schin 
1440*4887Schin static int _isword(register int c)
1441*4887Schin {
1442*4887Schin 	return((c&~STRIP) || isalnum(c) || c=='_');
1443*4887Schin }
1444*4887Schin #endif /* SHOPT_MULTIBYTE */
1445