xref: /original-bsd/local/toolchest/ksh/sh/emacs.c (revision 50dd0bba)
1 /*
2 
3  *      Copyright (c) 1984, 1985, 1986 AT&T
4  *      All Rights Reserved
5 
6  *      THIS IS UNPUBLISHED PROPRIETARY SOURCE
7  *      CODE OF AT&T.
8  *      The copyright notice above does not
9  *      evidence any actual or intended
10  *      publication of such source code.
11 
12  */
13 /* @(#)emacs.c	1.1 */
14 /* Adapted for ksh by David Korn */
15 /* EMACS_MODES: c tabstop=4
16 
17 One line screen editor for any program
18 
19 
20 Questions and comments should be
21 directed to
22 
23 	Michael T. Veach
24 	IX 1C-341 X1614
25 	ihuxl!veach
26 
27 */
28 #ifdef	DMERT	/* 3bcc #undefs RT */
29 #define	RT
30 #endif
31 
32 #ifdef KSHELL
33 #include	"defs.h"
34 #include	"io.h"
35 #include	"shtype.h"
36 
37 #else
38 #include	<setjmp.h>
39 #include	<stdio.h>
40 #include	<signal.h>
41 #include	<ctype.h>
42 #endif	/* KSHELL */
43 
44 #include	"history.h"
45 #include	"edit.h"
46 
47 #undef blank
48 #undef putchar
49 #define putchar(c)	e_putchar(c)
50 #define beep()		e_ringbell()
51 
52 
53 #ifdef KSHELL
54 extern void p_flush();
55 extern char *valup();
56 
57 #else
58 static char version[] = "@(#)Editlib version 06/03/86";
59 extern unsigned char *_sobuf;
60 #define p_flush()	fflush(stderr)
61 #define output		stderr
62 #endif	/* KSHELL */
63 
64 #ifdef MULTIBYTE
65 #define gencpy(a,b)	e_gencpy(a,b)
66 #define genncpy(a,b,n)	e_genncpy(a,b,n)
67 #define genlen(str)	e_genlen(str)
68 static int	print();
69 static int	isword();
70 
71 #else
72 #define gencpy(a,b)	strcpy((char*)(a),(char*)(b))
73 #define genncpy(a,b,n)	strncpy((char*)(a),(char*)(b),n)
74 #define genlen(str)	strlen(str)
75 #define print(c)	isprint(c)
76 #define isword(c)	isalnum(out[c])
77 #endif /*MULTIBYTE */
78 
79 extern histloc hist_find();
80 extern histloc hist_locate();
81 extern char	*hist_word();
82 extern char	*itos();
83 extern char	*strcpy();
84 extern char	*strncpy();
85 extern void	e_flush();
86 extern int	e_getchar();
87 extern void	e_putchar();
88 extern void	ungetchar();
89 
90 #define eol		editb.e_eol
91 #define cur		editb.e_cur
92 #define mark		editb.e_fchar
93 #define hline		editb.e_hline
94 #define hloff		editb.e_hloff
95 #define hismin		editb.e_hismin
96 #define usrkill		editb.e_kill
97 #define usreof		editb.e_eof
98 #define usrerase	editb.e_erase
99 #define crallowed	editb.e_crlf
100 #define llimit		editb.e_llimit
101 #define Prompt		editb.e_prompt
102 #define plen		editb.e_plen
103 #define kstack		editb.e_tmp
104 #define lstring		editb.e_search
105 #define lookahead	editb.e_index
106 #define env		editb.e_env
107 #define raw		editb.e_raw
108 #define histlines	editb.e_hismax
109 #define w_size		editb.e_wsize
110 #define drawbuff	editb.e_inbuf
111 #define NO	0
112 #define YES	1
113 #define LBUF	100
114 #define KILLCHAR	UKILL
115 #define ERASECHAR	UERASE
116 #define EOFCHAR		UEOF
117 
118 /**********************
119 A large lookahead helps when the user is inserting
120 characters in the middle of the line.
121 ************************/
122 
123 
124 static genchar *screen;		/* pointer to window buffer */
125 static genchar *cursor;		/* Cursor in real screen */
126 static enum
127 {
128 	CRT=0,	/* Crt terminal */
129 	PAPER	/* Paper terminal */
130 } terminal ;
131 
132 typedef enum
133 {
134 	FIRST,		/* First time thru for logical line, prompt on screen */
135 	REFRESH,	/* Redraw entire screen */
136 	APPEND,		/* Append char before cursor to screen */
137 	UPDATE,		/* Update the screen as need be */
138 	FINAL		/* Update screen even if pending look ahead */
139 } DRAWTYPE;
140 
141 static void draw();
142 static int escape();
143 static void putstring();
144 static int search();
145 static void setcursor();
146 
147 static int cr_ok;
148 
149 hread(fd,buff,scend)
150 char *buff;
151 int fd,scend;
152 {
153 	register int c;
154 	register int i;
155 	register genchar *out;
156 	register int count;
157 	int adjust,oadjust;
158 	char backslash;
159 	genchar *kptr;
160 static	histloc location;
161 static int CntrlO;
162 	char prompt[LBUF];
163 	genchar stack[MAXLINE];
164 	char string[LBUF*CHARSIZE];
165 	genchar Screen[MAXWINDOW];
166 	Prompt = prompt;
167 	kstack = stack;
168 	lstring = string;
169 	screen = Screen;
170 	drawbuff = out = (genchar*)buff;
171 	kstack[0] = '\0';
172 	if(setraw(fd) < 0)
173 	{
174 		 p_flush();
175 		 return(read(fd,buff,scend));
176 	}
177 	raw = 1;
178 	/* This mess in case the read system call fails */
179 
180 	e_setup(fd,LBUF);
181 	if ((i=setjmp(env))!=0)
182 	{
183 		setcooked(fd);
184 		if (i == UEOF)
185 		{
186 			return(0); /* EOF */
187 		}
188 		return(-1); /* some other error */
189 	}
190 #ifdef MULTIBYTE
191 	plen = e_internal(&Prompt[1],out);  /* Skip the leading \r */
192 #else
193 	gencpy(buff,&Prompt[1]);  /* Skip the leading \r */
194 #endif	/* MULTIBYTE */
195 	scend -= plen;
196 	llimit = scend;
197 	mark = eol = cur = plen;
198 	draw(FIRST);
199 	adjust = -1;
200 	backslash = 0;
201 	if (CntrlO)
202 	{
203 		location = hist_locate(location.his_command,location.his_line,1);
204 		if (location.his_command < histlines)
205 		{
206 			hline = location.his_command;
207 			hloff = location.his_line;
208 			hist_copy((char*)kstack,hline,hloff);
209 #ifdef MULTIBYTE
210 			e_internal((char*)kstack,kstack);
211 #endif	/* MULTIBYTE */
212 			ungetchar(cntl(Y));
213 		}
214 	}
215 	CntrlO = 0;
216 	while ((c = e_getchar()) != (-1))
217 	{
218 		if (backslash)
219 		{
220 			backslash = 0;
221 			if (c==usrerase||c==usrkill||(!print(c) &&
222 				(c!='\r'&&c!='\n')))
223 			{
224 				/* accept a backslashed character */
225 				cur--;
226 				out[cur++] = c;
227 				out[eol] = '\0';
228 				draw(APPEND);
229 				continue;
230 			}
231 		}
232 		if (c == usrkill)
233 		{
234 			c = KILLCHAR ;
235 		}
236 		else if (c == usrerase)
237 		{
238 			c = ERASECHAR ;
239 		}
240 		else if ((c == usreof)&&(eol == plen))
241 		{
242 			c = EOFCHAR;
243 		}
244 		oadjust = count = adjust;
245 		if(count<0)
246 			count = 1;
247 		adjust = -1;
248 		i = cur;
249 		switch(c)
250 		{
251 		case cntl(V):
252 			{
253 				genchar string[100];
254 				/* save current line */
255 				genncpy(string,out,sizeof(string)/CHARSIZE-1);
256 				out[plen] = '\0';
257 				cur = plen;
258 #ifdef MULTIBYTE
259 				e_internal(&version[4],out+plen);
260 #else
261 				gencpy(buff+plen,&version[4]);
262 #endif	/* MULTIBYTE */
263 				draw(UPDATE);
264 				c = e_getchar();
265 				ungetchar(c);
266 				/* restore line */
267 				cur = i;
268 				genncpy(out,string,sizeof(string)/CHARSIZE-1);
269 				draw(UPDATE);
270 			}
271 			continue;
272 		case '\0':
273 			mark = i;
274 			continue;
275 		case cntl(X):
276 			i = e_getchar();
277 			if (i != cntl(X))
278 			{
279 				beep();
280 				continue;
281 			}
282 			if (mark > eol)
283 				mark = eol;
284 			i = mark;
285 			mark = cur;
286 			goto update;
287 		case EOFCHAR:
288 			e_flush();
289 			setcooked(fd);
290 			return(0);
291 #ifdef u370
292 		case cntl(S) :
293 		case cntl(Q) :
294 			continue;
295 #endif	/* u370 */
296 		default:
297 			i = ++eol;
298 			if (i >= (scend)) /*  will not fit on line */
299 			{
300 				eol--;
301 				ungetchar(c); /* save character for next line */
302 				draw(FINAL);
303 				goto process;
304 			}
305 			for(i=eol;i>=cur;i--)
306 			{
307 				out[i] = out[i-1];
308 			}
309 			backslash =  (c == '\\');
310 			out[cur++] = c;
311 			draw(APPEND);
312 			continue;
313 		case cntl(Y) :
314 			{
315 				c = genlen(kstack);
316 				if ((c + eol) > scend)
317 				{
318 					beep();
319 					continue;
320 				}
321 				mark = i;
322 				for(i=eol;i>=cur;i--)
323 					out[c+i] = out[i];
324 				kptr=kstack;
325 				while (i = *kptr++)
326 					out[cur++] = i;
327 				draw(UPDATE);
328 				eol = genlen(out);
329 				continue;
330 			}
331 		case '\n':
332 		case '\r':
333 			draw(FINAL);
334 			out[eol++] = '\n';
335 			out[eol] = '\0';
336 			e_crlf();
337 			goto process;
338 		case ERASECHAR :
339 			if (count > (i-plen))
340 				count = i-plen;
341 			while ((count--)&&(i>plen))
342 			{
343 				i--;
344 				eol--;
345 			}
346 			genncpy(kstack,out+i,cur-i);
347 			kstack[cur-i] = 0;
348 			gencpy(out+i,out+cur);
349 			mark = i;
350 			goto update;
351 		case cntl(W) :
352 			if (mark > eol )
353 				mark = eol;
354 			if (mark == i)
355 				continue;
356 			if (mark > i)
357 			{
358 				adjust = mark - i;
359 				ungetchar(cntl(D));
360 				continue;
361 			}
362 			adjust = i - mark;
363 			ungetchar('\b');
364 			continue;
365 		case cntl(D) :
366 			mark = i;
367 			kptr = kstack;
368 			while ((count--)&&(eol>plen)&&(i<eol))
369 			{
370 				*kptr++ = out[i];
371 				eol--;
372 				while(1)
373 				{
374 					if ((out[i] = out[(i+1)])==0)
375 						break;
376 					i++;
377 				}
378 				i = cur;
379 			}
380 			*kptr = '\0';
381 			goto update;
382 		case cntl(C) :
383 		case cntl(F) :
384 		{
385 			int cntlC = (c==cntl(C));
386 			while (count-- && eol>i)
387 			{
388 				if (cntlC)
389 				{
390 					c = out[i];
391 #ifdef MULTIBYTE
392 					if((c&~STRIP)==0 && islower(c))
393 #else
394 					if(islower(c))
395 #endif /* MULTIBYTE */
396 					{
397 						c += 'A' - 'a';
398 						out[i] = c;
399 					}
400 				}
401 				i++;
402 			}
403 			goto update;
404 		}
405 		case cntl(]) :
406 			c = e_getchar();
407 			if (out[i])
408 				i++;
409 			while (i < eol)
410 			{
411 				if (out[i] == c)
412 					goto update;
413 				i++;
414 			}
415 			i = plen;
416 			while (i < cur)
417 			{
418 				if (out[i] == c)
419 					break;
420 				i++;
421 			};
422 
423 update:
424 			cur = i;
425 			draw(UPDATE);
426 			continue;
427 
428 		case cntl(B) :
429 			if (count > (i-plen))
430 				count = i - plen;
431 			i -= count;
432 			goto update;
433 		case cntl(T) :
434 			if ((is_option(GMACS))||(eol==i))
435 			{
436 				if (i >= plen + 2)
437 				{
438 					c = out[i - 1];
439 					out[i-1] = out[i-2];
440 					out[i-2] = c;
441 				}
442 				else
443 				{
444 					beep();
445 					continue;
446 				}
447 			}
448 			else
449 			{
450 				if (eol>(i+1))
451 				{
452 					c = out[i];
453 					out[i] = out[i+1];
454 					out[i+1] = c;
455 					i++;
456 				}
457 				else
458 				{
459 					beep();
460 					continue;
461 				}
462 			}
463 			goto update;
464 		case cntl(A) :
465 			i = plen;
466 			goto update;
467 		case cntl(E) :
468 			i = eol;
469 			goto update;
470 		case cntl(U) :
471 			adjust = 4*count;
472 			continue;
473 		case KILLCHAR :
474 			cur = plen;
475 			oadjust = -1;
476 		case cntl(K) :
477 			if(oadjust >= 0)
478 			{
479 				mark = plen+count;
480 				ungetchar(cntl(W));
481 				continue;
482 			}
483 			i = cur;
484 			eol = i;
485 			mark = i;
486 			gencpy(kstack,&out[i]);
487 			out[i] = 0;
488 			draw(UPDATE);
489 			if (c == KILLCHAR)
490 			{
491 				if (terminal == PAPER)
492 					putstring("\r\n");
493 				c = e_getchar();
494 				if (c != usrkill)
495 				{
496 					ungetchar(c);
497 					continue;
498 				}
499 				if (terminal == PAPER)
500 					terminal = CRT;
501 				else
502 				{
503 					terminal = PAPER;
504 					putstring("\r\n");
505 				}
506 			}
507 			continue;
508 		case cntl(L):
509 			e_crlf();
510 			draw(REFRESH);
511 			continue;
512 		case cntl([) :
513 			adjust = escape(out,oadjust);
514 			continue;
515 		case cntl(R) :
516 			search(out,count);
517 			goto drawline;
518 		case cntl(P) :
519 			location = hist_locate(hline,hloff,-count);
520 			hline = location.his_command;
521 			if (hline < hismin)
522 			{
523 				hline = hismin;
524 				beep();
525 			}
526 			goto common;
527 
528 		case cntl(O) :
529 			location.his_command = hline;
530 			location.his_line = hloff;
531 			CntrlO = 1;
532 			draw(FINAL);
533 			out[eol++] = '\n';
534 			out[eol] = '\0';
535 			e_crlf();
536 			goto process;
537 		case cntl(N) :
538 			location = hist_locate(hline,hloff,count);
539 			if (location.his_command > histlines)
540 			{
541 				beep();
542 				continue;
543 			}
544 			hline = location.his_command;
545 		common:
546 			hloff = location.his_line;
547 			hist_copy(&out[plen],hline,hloff);
548 #ifdef MULTIBYTE
549 			e_internal((char*)(&out[plen]),&out[plen]);
550 #endif /* MULTIBYTE */
551 		drawline:
552 			eol = genlen(out);
553 			cur = eol;
554 			draw(UPDATE);
555 			continue;
556 		}
557 
558 	}
559 
560 process:
561 
562 	if (c == (-1))
563 	{
564 		lookahead = 0;
565 		beep();
566 		out[plen] = '\0';
567 	}
568 	gencpy(out,&out[plen]);
569 #ifdef MULTIBYTE
570 	e_external(out,buff);
571 #endif /* MULTIBYTE */
572 #ifdef u370
573 	putchar('\0');
574 #endif	/* u370 */
575 	e_flush();
576 	setcooked(fd);
577 	i = strlen(buff);
578 	if (i)
579 		return(i);
580 	return(-1);
581 }
582 
583 
584 static void
585 putstring(s)
586 register char *s;
587 {
588 	register int c;
589 	while (c= *s++)
590 		 putchar(c);
591 }
592 
593 
594 static int
595 escape(out,count)
596 register genchar *out;
597 {
598 	register int i,value;
599 	int digit,ch;
600 	digit = 0;
601 	value = 0;
602 	while ((i=e_getchar()),isdigit(i))
603 	{
604 		value *= 10;
605 		value += (i - '0');
606 		digit = 1;
607 	}
608 	if (digit)
609 	{
610 		ungetchar(i) ;
611 		return(value);
612 	}
613 	value = count;
614 	if(value<0)
615 		value = 1;
616 	switch(ch=i)
617 	{
618 		case ' ':
619 			mark = cur;
620 			return(-1);
621 
622 		case 'p':	/* M-p == ^W^Y (copy stack == kill & yank) */
623 			ungetchar(cntl(Y));
624 			ungetchar(cntl(W));
625 			return(-1);
626 
627 		case 'l':	/* M-l == lower-case */
628 		case 'd':
629 		case 'c':
630 		case 'f':
631 		{
632 			i = cur;
633 			while(value-- && i<eol)
634 			{
635 				while (!isword(i))
636 					i++;
637 				while ((out[i])&&(isword(i)))
638 					i++;
639 			}
640 			if(ch=='l')
641 			{
642 				value = i-cur;
643 				while (value-- > 0)
644 				{
645 					i = out[cur];
646 #ifdef MULTIBYTE
647 					if((i&~STRIP)==0 && isupper(i))
648 #else
649 					if(isupper(i))
650 #endif /* MULTIBYTE */
651 					{
652 						i += 'a' - 'A';
653 						out[cur] = i;
654 					}
655 					cur++;
656 				}
657 				draw(UPDATE);
658 				return(-1);
659 			}
660 
661 			else if(ch=='f')
662 			{
663 				cur = i;
664 				draw(UPDATE);
665 				return(-1);
666 			}
667 			else if(ch=='c')
668 			{
669 				ungetchar(cntl(C));
670 				return(i-cur);
671 			}
672 			else
673 			{
674 				if (i-cur)
675 				{
676 					ungetchar(cntl(D));
677 					return(i-cur);
678 				}
679 				beep();
680 				return(-1);
681 			}
682 		}
683 
684 
685 		case 'b':
686 		case DELETE :
687 		case '\b':
688 		case 'h':
689 		{
690 			i = cur;
691 			while(value-- && i>plen)
692 			{
693 				i--;
694 				while ((i>plen)&&(!isword(i)))
695 					i--;
696 				while ((i>plen)&&(isword(i-1)))
697 					i--;
698 			}
699 			if(ch=='b')
700 			{
701 				cur = i;
702 				draw(UPDATE);
703 				return(-1);
704 			}
705 			else
706 			{
707 				ungetchar(ERASECHAR);
708 				return(cur-i);
709 			}
710 		}
711 
712 		case '>':
713 			ungetchar(cntl(N));
714 			return(histlines-(hline+1));
715 
716 		case '<':
717 			ungetchar(cntl(P));
718 			return(hline);
719 
720 
721 #ifdef KSHELL
722 		case '_' :
723 		case '.' :
724 		{
725 			genchar name[MAXLINE];
726 			char buf[MAXLINE];
727 			char *ptr;
728 			ptr = hist_word(buf,(count?count:-1));
729 #ifndef KSHELL
730 			if(ptr==NULL)
731 			{
732 				beep();
733 				break;
734 			}
735 #endif	/* KSHELL */
736 			if ((eol - cur) >= sizeof(name))
737 			{
738 				beep();
739 				return(-1);
740 			}
741 			mark = cur;
742 			gencpy(name,&out[cur]);
743 			while(*ptr)
744 			{
745 				out[cur++] = *ptr++;
746 				eol++;
747 			}
748 			gencpy(&out[cur],name);
749 			draw(UPDATE);
750 			return(-1);
751 		}
752 
753 		/* file name expansion */
754 		case cntl([) :	/* easier to type */
755 			i = '*';
756 		case '*':
757 		case '=':	/* escape = - list all matching file names */
758 			mark = cur;
759 			if(q_expand(out,&cur,&eol,plen,i) < 0)
760 				beep();
761 			else if(i=='*')
762 				draw(UPDATE);
763 			else
764 				draw(REFRESH);
765 			return(-1);
766 
767 		default:
768 			/* look for user defined macro definitions */
769 			if(e_macro(i))
770 				return(-1);
771 #else
772 		default:
773 #endif	/* KSHELL */
774 		ungetchar(i);
775 		ungetchar(cntl([));
776 		ungetchar('\\');
777 		return(-1);
778 	}
779 }
780 
781 
782 static int
783 search(out,direction)
784 genchar out[];
785 {
786 	static int prevdirection =  1 ;
787 	histloc location;
788 	register int i,sl;
789 	genchar str_buff[100];
790 	register genchar *string = drawbuff;
791 	/* save current line */
792 	char sav_cur = cur;
793 	genncpy(str_buff,string,sizeof(str_buff)/CHARSIZE-1);
794 	string[plen] = '^';
795 	string[plen+1] = 'R';
796 	string[plen+2] = '\0';
797 	sl = 2+plen;
798 	cur = sl;
799 	draw(UPDATE);
800 	while ((i = e_getchar())&&(i != '\r')&&(i != '\n'))
801 	{
802 		if (i==usrerase)
803 		{
804 			if (sl > 2+plen)
805 			{
806 				string[--sl] = '\0';
807 				cur = sl;
808 				draw(UPDATE);
809 			}
810 			else
811 				beep();
812 			continue;
813 		}
814 		if (i==usrkill)
815 		{
816 			beep();
817 			goto restore;
818 		}
819 		if (i == '\\')
820 		{
821 			string[sl++] = '\\';
822 			string[sl] = '\0';
823 			cur = sl;
824 			draw(APPEND);
825 			i = e_getchar();
826 			string[--sl] = '\0';
827 		}
828 		string[sl++] = i;
829 		string[sl] = '\0';
830 		cur = sl;
831 		draw(APPEND);
832 	}
833 	i = genlen(string);
834 
835 	if (direction < 1)
836 	{
837 		prevdirection = -prevdirection;
838 		direction = 1;
839 	}
840 	else
841 		direction = -1;
842 	if (i != 2+plen)
843 	{
844 		gencpy(lstring,&string[2+plen]);
845 #ifdef MULTIBYTE
846 		e_external(lstring,(char*)lstring);
847 #endif /* MULTIBYTE */
848 		prevdirection = direction;
849 	}
850 	else
851 		direction = prevdirection ;
852 	location = hist_find((char*)lstring,hline,1,direction);
853 	i = location.his_command;
854 	if(i>0)
855 	{
856 		hline = i;
857 		hloff = location.his_line;
858 		hist_copy((char*)&out[plen],hline,hloff);
859 #ifdef MULTIBYTE
860 		e_internal((char*)&out[plen],&out[plen]);
861 #endif /* MULTIBYTE */
862 		return;
863 	}
864 	if (i < 0)
865 	{
866 		beep();
867 		hloff = (fc_fix?fc_fix->fixline:0);
868 		hline = histlines;
869 	}
870 restore:
871 	genncpy(string,str_buff,sizeof(str_buff)/CHARSIZE-1);
872 	cur = sav_cur;
873 	return;
874 }
875 
876 
877 /* Adjust screen to agree with inputs: logical line and cursor */
878 /* If 'first' assume screen is blank */
879 
880 static void
881 draw(option)
882 DRAWTYPE option;
883 {
884 #define	NORMAL ' '
885 #define	LOWER  '<'
886 #define	BOTH   '*'
887 #define	UPPER  '>'
888 #define UNDEF	0
889 
890 	static char overflow;		/* Screen overflow flag set */
891 	register genchar *sptr;		/* Pointer within screen */
892 
893 	static int offset;		/* Screen offset */
894 	static char scvalid;	/* Screen is up to date */
895 
896 	genchar nscreen[2*MAXLINE];  /* New entire screen */
897 	genchar *ncursor;	    /* New cursor */
898 	register genchar *nptr;	    /* Pointer to New screen */
899 	char  longline;	    /* Line overflow */
900 	genchar *logcursor;
901 	genchar *nscend;		/* end of logical screen */
902 	register int i;
903 
904 	nptr = nscreen;
905 	sptr = drawbuff;
906 	logcursor = sptr + cur;
907 	ncursor = nscreen;
908 	longline = NORMAL;
909 
910 	if (option == FIRST || option == REFRESH)
911 	{
912 		overflow = NORMAL;
913 		cursor = screen;
914 		offset = 0;
915 		cr_ok = crallowed;
916 		if (option == FIRST)
917 		{
918 			scvalid = 1;
919 			gencpy(cursor,sptr);
920 			cursor += plen;
921 			return;
922 		}
923 		*cursor = '\0';
924 	}
925 
926 	/*********************
927 	 Do not update screen if pending characters
928 	**********************/
929 
930 	if ((lookahead)&&(option != FINAL))
931 	{
932 
933 		scvalid = 0; /* Screen is out of date, APPEND will not work */
934 
935 		return;
936 	}
937 
938 	/***************************************
939 	If in append mode, cursor at end of line, screen up to date,
940 	the previous character was a 'normal' character,
941 	and the window has room for another character.
942 	Then output the character and adjust the screen only.
943 	*****************************************/
944 
945 
946 	i = *(logcursor-1);
947 
948 	if ((option == APPEND)&&(scvalid)&&(*logcursor == '\0')&&
949 	    print(i)&&((cursor-screen)<(w_size-1)))
950 	{
951 		putchar(i);
952 		*cursor++ = i;
953 		*cursor = '\0';
954 		return;
955 	}
956 
957 	/* copy the prompt */
958 	i = plen;
959 	while(--i >=0)
960 		nptr[i] = sptr[i];
961 	/* now the rest of the line */
962 	ncursor = nptr + e_virt_to_phys(sptr,nptr,cur,plen,plen);
963 	nptr += genlen(nptr);
964 	sptr += genlen(sptr);
965 	nscend = nptr - 1;
966 	if(sptr == logcursor)
967 		ncursor = nptr;
968 
969 	/*********************
970 	 Does ncursor appear on the screen?
971 	 If not, adjust the screen offset so it does.
972 	**********************/
973 
974 	i = ncursor - nscreen;
975 
976 	if ((i <= offset)||(i >= (offset+w_size)))
977 	{
978 		offset = i - (w_size>>1);
979 		if (offset < plen)
980 		{
981 			offset = (crallowed == YES) ? 0 : plen;
982 		}
983 		if ((offset >= plen)&&(cr_ok == NO))
984 		{
985 
986 			/*********************************
987 			 Don't really know whats on the screen
988 			 because of strange characters in the prompt.
989 
990 			 Mark entire screen as unknow.
991 			***********************************/
992 
993 			cursor = screen;
994 			*cursor = '\0';
995 			putchar('\r');
996 			overflow =  UNDEF;
997 			cr_ok = YES;
998 		}
999 	}
1000 	/*********************
1001 	 Is the range of screen[0] thru screen[w_size] up-to-date
1002 	 with nscreen[offset] thru nscreen[offset+w_size] ?
1003 	 If not, update as need be.
1004 	***********************/
1005 
1006 	nptr = &nscreen[offset];
1007 	sptr = screen;
1008 
1009 	i = w_size;
1010 
1011 	while (i-- > 0)
1012 	{
1013 
1014 		if (*nptr == '\0')
1015 		{
1016 			*(nptr + 1) = '\0';
1017 			*nptr = ' ';
1018 		}
1019 		if (*sptr == '\0')
1020 		{
1021 			*(sptr + 1) = '\0';
1022 			*sptr = ' ';
1023 		}
1024 		if (*nptr == *sptr)
1025 		{
1026 			nptr++;
1027 			sptr++;
1028 			continue;
1029 		}
1030 		setcursor(sptr-screen,*nptr);
1031 		*sptr++ = *nptr++;
1032 #ifdef MULTIBYTE
1033 		while(*nptr==MARKER)
1034 		{
1035 			*sptr++ = *nptr++;
1036 			i--;
1037 			cursor++;
1038 		}
1039 #endif /* MULTIBYTE */
1040 	}
1041 
1042 	/******************
1043 
1044 	Screen overflow checks
1045 
1046 	********************/
1047 
1048 	if (nscend >= &nscreen[offset+w_size])
1049 	{
1050 		if (offset > plen)
1051 			longline = BOTH;
1052 		else
1053 			longline = UPPER;
1054 	}
1055 	else
1056 	{
1057 		if (offset > plen)
1058 			longline = LOWER;
1059 	}
1060 
1061 	/* Update screen overflow indicator if need be */
1062 
1063 	if (longline != overflow)
1064 	{
1065 		setcursor(w_size,longline);
1066 		overflow = longline;
1067 	}
1068 	i = (ncursor-nscreen) - offset;
1069 	setcursor(i,0);
1070 	scvalid = 1;
1071 	return;
1072 }
1073 
1074 /*
1075  * put the cursor to the <new> position within screen buffer
1076  * if <c> is non-zero then output this character
1077  * cursor is set to reflect the change
1078  */
1079 
1080 static void
1081 setcursor(new,c)
1082 register int new,c;
1083 {
1084 	register int old = cursor - screen;
1085 	if (old > new)
1086 	{
1087 		if ((cr_ok == NO) || ((new*2)>old))
1088 		{
1089 			while (old > new)
1090 			{
1091 				putchar('\b');
1092 				old--;
1093 			}
1094 			goto skip;
1095 		}
1096 		putchar('\r');
1097 		old = 0;
1098 	}
1099 	while (new > old)
1100 		putchar(screen[old++]);
1101 skip:
1102 	if(c)
1103 	{
1104 		putchar(c);
1105 		new++;
1106 	}
1107 	cursor = screen+new;
1108 	return;
1109 }
1110 
1111 #ifdef MULTIBYTE
1112 static int print(c)
1113 register int c;
1114 {
1115 	return((c&~STRIP)==0 && isprint(c));
1116 }
1117 
1118 static int isword(i)
1119 register int i;
1120 {
1121 	register int c = drawbuff[i];
1122 	return((c&~STRIP) || isalnum(c));
1123 }
1124 #endif /* MULTIBYTE */
1125