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