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