1*35136Smarc /* @(#)edit.c 1.1 */
2*35136Smarc
3*35136Smarc /*
4*35136Smarc * edit.c - common routines for vi and emacs one line editors in shell
5*35136Smarc *
6*35136Smarc * David Korn P.D. Sullivan
7*35136Smarc * AT&T Bell Laboratories AT&T Bell Laboratories
8*35136Smarc * Room 5D-112 Room 1E253
9*35136Smarc * Murray Hill, N. J. 07974 Columbus, OH 43213
10*35136Smarc * Tel. x7975 Tel. x 2655
11*35136Smarc *
12*35136Smarc * Coded April 1983.
13*35136Smarc */
14*35136Smarc
15*35136Smarc #include <errno.h>
16*35136Smarc
17*35136Smarc #ifdef KSHELL
18*35136Smarc #include "shtype.h"
19*35136Smarc #include "flags.h"
20*35136Smarc #include "defs.h"
21*35136Smarc #include "io.h"
22*35136Smarc #include "name.h"
23*35136Smarc #include "sym.h"
24*35136Smarc #include "stak.h"
25*35136Smarc #include "mode.h"
26*35136Smarc #include "builtins.h"
27*35136Smarc #include "brkincr.h"
28*35136Smarc
29*35136Smarc #else
30*35136Smarc #include <stdio.h>
31*35136Smarc #include <signal.h>
32*35136Smarc #include <setjmp.h>
33*35136Smarc #include <ctype.h>
34*35136Smarc #endif /* KSHELL */
35*35136Smarc
36*35136Smarc #include "history.h"
37*35136Smarc #include "edit.h"
38*35136Smarc
39*35136Smarc #define BAD -1
40*35136Smarc #define GOOD 0
41*35136Smarc #define TRUE (-1)
42*35136Smarc #define FALSE 0
43*35136Smarc #define SYSERR -1
44*35136Smarc
45*35136Smarc #ifdef VENIX
46*35136Smarc #define RT 1
47*35136Smarc #endif /* VENIX */
48*35136Smarc
49*35136Smarc void e_crlf();
50*35136Smarc void e_flush();
51*35136Smarc int e_getchar();
52*35136Smarc void e_putchar();
53*35136Smarc void e_ringbell();
54*35136Smarc void e_setup();
55*35136Smarc int e_virt_to_phys();
56*35136Smarc int e_window();
57*35136Smarc void setcooked();
58*35136Smarc void ungetchar();
59*35136Smarc
60*35136Smarc #if BSD || RT
61*35136Smarc #include <sgtty.h>
62*35136Smarc # ifdef BSD_4_2
63*35136Smarc # include <sys/time.h>
64*35136Smarc # endif /* BSD_4_2 */
65*35136Smarc static struct sgttyb ttyparm; /* initial tty parameters */
66*35136Smarc static struct sgttyb nttyparm; /* raw tty parameters */
67*35136Smarc # ifdef BSD
68*35136Smarc extern int tty_speeds[];
69*35136Smarc static int delay;
70*35136Smarc static int l_mask;
71*35136Smarc static struct tchars l_ttychars;
72*35136Smarc static struct ltchars l_chars;
73*35136Smarc static char l_changed; /* set if mode bits changed */
74*35136Smarc #define L_CHARS 4
75*35136Smarc #define T_CHARS 2
76*35136Smarc #define L_MASK 1
77*35136Smarc # endif /* BSD */
78*35136Smarc #else
79*35136Smarc # ifdef XENIX /* avoid symbol table overflows */
80*35136Smarc # define NCC 8
81*35136Smarc struct termio {
82*35136Smarc unsigned short c_iflag; /* input modes */
83*35136Smarc unsigned short c_oflag; /* output modes */
84*35136Smarc unsigned short c_cflag; /* control modes */
85*35136Smarc unsigned short c_lflag; /* line discipline modes */
86*35136Smarc char c_line; /* line discipline */
87*35136Smarc unsigned char c_cc[NCC]; /* control chars */
88*35136Smarc char c_res; /* padding, AFTER the array */
89*35136Smarc };
90*35136Smarc #define TIOC ('T'<<8)
91*35136Smarc #define BRKINT 0000002
92*35136Smarc #define CBAUD 0000017
93*35136Smarc #define ECHO 0000010
94*35136Smarc #define ECHOE 0000020
95*35136Smarc #define ECHOK 0000040
96*35136Smarc #define ECHONL 0000100
97*35136Smarc #define ICANON 0000002
98*35136Smarc #define ICRNL 0000400
99*35136Smarc #define IGNCR 0000200
100*35136Smarc #define IGNPAR 0000004
101*35136Smarc #define INLCR 0000100
102*35136Smarc #define PARMRK 0000010
103*35136Smarc #define TCGETA (TIOC|1)
104*35136Smarc #define TCSETAW (TIOC|3)
105*35136Smarc #define TCXONC (TIOC|6)
106*35136Smarc #define VEOF 4
107*35136Smarc #define VERASE 2
108*35136Smarc #define VKILL 3
109*35136Smarc #define VMIN 4
110*35136Smarc #define VTIME 5
111*35136Smarc #define TM_CECHO 0010
112*35136Smarc # else
113*35136Smarc # include <termio.h>
114*35136Smarc # endif /* XENIX */
115*35136Smarc
116*35136Smarc static struct termio ttyparm; /* initial tty parameters */
117*35136Smarc static struct termio nttyparm; /* raw tty parameters */
118*35136Smarc #endif /* RT */
119*35136Smarc
120*35136Smarc #define lookahead editb.e_index
121*35136Smarc #define env editb.e_env
122*35136Smarc #define previous editb.e_lbuf
123*35136Smarc #define fildes editb.e_fd
124*35136Smarc
125*35136Smarc #ifdef KSHELL
126*35136Smarc extern struct Amemory *alias;
127*35136Smarc extern char **arg_build();
128*35136Smarc extern void failed();
129*35136Smarc extern void fault();
130*35136Smarc extern struct Namnod *findnod();
131*35136Smarc extern int f_complete();
132*35136Smarc extern void gsort();
133*35136Smarc extern char *movstr();
134*35136Smarc extern void p_flush();
135*35136Smarc extern void p_setout();
136*35136Smarc extern char *simple();
137*35136Smarc extern char *tilde();
138*35136Smarc extern char *valup();
139*35136Smarc static char macro[] = "_?";
140*35136Smarc
141*35136Smarc #else
142*35136Smarc static char badcooked[] = "cannot reset tty to cooked mode";
143*35136Smarc struct edit editb;
144*35136Smarc char trapnote;
145*35136Smarc extern char trapnote;
146*35136Smarc extern int errno;
147*35136Smarc #define p_flush() fflush(stderr)
148*35136Smarc #define p_setout(s) fflush(stdout)
149*35136Smarc #define error(s) failed(s,NULL)
150*35136Smarc #define SIGSLOW 1
151*35136Smarc #define output stderr
152*35136Smarc #endif /* KSHELL */
153*35136Smarc
154*35136Smarc extern char *strrchr();
155*35136Smarc extern char *strcpy();
156*35136Smarc
157*35136Smarc static char bellchr[] = "\7"; /* bell char */
158*35136Smarc
159*35136Smarc static int control();
160*35136Smarc /*{ SETCOOKED( fd )
161*35136Smarc *
162*35136Smarc * This routine will set the tty in cooked mode.
163*35136Smarc * It is also called by error.done().
164*35136Smarc *
165*35136Smarc }*/
166*35136Smarc
setcooked(fd)167*35136Smarc void setcooked(fd)
168*35136Smarc register int fd;
169*35136Smarc {
170*35136Smarc /*** don't do ioctl unless ttyparm has valid data ***/
171*35136Smarc /* or in raw mode */
172*35136Smarc
173*35136Smarc if(editb.e_ttyspeed==0 || editb.e_raw==0)
174*35136Smarc return;
175*35136Smarc
176*35136Smarc #ifdef BSD
177*35136Smarc if(editb.e_raw==RAWMODE && ioctl(fd, TIOCSETN, &ttyparm) == SYSERR )
178*35136Smarc {
179*35136Smarc if(errno!=EBADF && errno!=ENOTTY)
180*35136Smarc error(badcooked);
181*35136Smarc return;
182*35136Smarc }
183*35136Smarc /* restore flags */
184*35136Smarc if(l_changed&L_MASK)
185*35136Smarc ioctl(fd,TIOCLSET,&l_mask);
186*35136Smarc if(l_changed&T_CHARS)
187*35136Smarc /* restore alternate break character */
188*35136Smarc ioctl(fd,TIOCSETC,&l_ttychars);
189*35136Smarc if(l_changed&L_CHARS)
190*35136Smarc /* restore alternate break character */
191*35136Smarc ioctl(fd,TIOCSLTC,&l_chars);
192*35136Smarc l_changed = 0;
193*35136Smarc #else
194*35136Smarc # ifdef RT
195*35136Smarc if (stty(fd,&ttyparm) == SYSERR)
196*35136Smarc # else
197*35136Smarc if( editb.e_raw && control(fd, TCSETAW, &ttyparm) == SYSERR )
198*35136Smarc # endif /* RT */
199*35136Smarc {
200*35136Smarc if(errno!=EBADF && errno!=ENOTTY)
201*35136Smarc error(badcooked);
202*35136Smarc return;
203*35136Smarc }
204*35136Smarc #endif /* BSD */
205*35136Smarc editb.e_raw = 0;
206*35136Smarc return;
207*35136Smarc }
208*35136Smarc
209*35136Smarc /*{ SETRAW( fd )
210*35136Smarc *
211*35136Smarc * This routine will set the tty in raw mode.
212*35136Smarc *
213*35136Smarc }*/
214*35136Smarc
setraw(fd)215*35136Smarc setraw(fd)
216*35136Smarc register int fd;
217*35136Smarc {
218*35136Smarc #ifdef BSD
219*35136Smarc struct ltchars lchars;
220*35136Smarc #endif /* BSD */
221*35136Smarc if(editb.e_raw==RAWMODE)
222*35136Smarc return(GOOD);
223*35136Smarc /* characters are echoed on standard error */
224*35136Smarc p_setout(stderr);
225*35136Smarc #if BSD || RT
226*35136Smarc # ifdef BSD
227*35136Smarc if((ioctl(fd,TIOCGETP,&ttyparm) == SYSERR)
228*35136Smarc # else
229*35136Smarc if ((gtty(fd,&ttyparm) == SYSERR)
230*35136Smarc # endif /* BSD */
231*35136Smarc || !(ttyparm.sg_flags & ECHO )
232*35136Smarc || (ttyparm.sg_flags & LCASE ))
233*35136Smarc {
234*35136Smarc return(BAD);
235*35136Smarc }
236*35136Smarc nttyparm = ttyparm;
237*35136Smarc nttyparm.sg_flags &= ~(ECHO | TBDELAY);
238*35136Smarc # ifdef BSD
239*35136Smarc nttyparm.sg_flags |= CBREAK;
240*35136Smarc # else
241*35136Smarc nttyparm.sg_flags |= RAW;
242*35136Smarc # endif /* BSD */
243*35136Smarc editb.e_erase = ttyparm.sg_erase;
244*35136Smarc editb.e_kill = ttyparm.sg_kill;
245*35136Smarc editb.e_eof = cntl(D);
246*35136Smarc # ifdef BSD
247*35136Smarc if( ioctl(fd, TIOCSETN, &nttyparm) == SYSERR )
248*35136Smarc # else
249*35136Smarc if( stty(fd, &nttyparm) == SYSERR )
250*35136Smarc # endif /* BSD */
251*35136Smarc {
252*35136Smarc return(BAD);
253*35136Smarc }
254*35136Smarc editb.e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW);
255*35136Smarc #ifdef BSD
256*35136Smarc delay = tty_speeds[ttyparm.sg_ospeed];
257*35136Smarc /* try to remove effect of ^V and ^Y */
258*35136Smarc if(ioctl(fd,TIOCGLTC,&l_chars) != SYSERR)
259*35136Smarc {
260*35136Smarc lchars = l_chars;
261*35136Smarc lchars.t_lnextc = -1;
262*35136Smarc lchars.t_dsuspc = -1; /* no delayed stop process signal */
263*35136Smarc if(ioctl(fd,TIOCSLTC,&lchars) != SYSERR)
264*35136Smarc l_changed |= L_CHARS;
265*35136Smarc }
266*35136Smarc #endif /* BSD */
267*35136Smarc #else
268*35136Smarc
269*35136Smarc # ifndef RAWONLY
270*35136Smarc if(editb.e_raw != ALTMODE)
271*35136Smarc # endif /* RAWONLY */
272*35136Smarc if( (ioctl(fd, TCGETA, &ttyparm) == SYSERR)
273*35136Smarc || (!(ttyparm.c_lflag & ECHO )))
274*35136Smarc {
275*35136Smarc return(BAD);
276*35136Smarc }
277*35136Smarc
278*35136Smarc nttyparm = ttyparm;
279*35136Smarc #ifndef u370
280*35136Smarc nttyparm.c_iflag &= ~(IGNPAR|PARMRK|INLCR|IGNCR|ICRNL);
281*35136Smarc nttyparm.c_iflag |= BRKINT;
282*35136Smarc nttyparm.c_lflag &= ~(ICANON|ECHO);
283*35136Smarc #else
284*35136Smarc nttyparm.c_iflag &=
285*35136Smarc ~(IGNBRK|PARMRK|INLCR|IGNCR|ICRNL|INPCK);
286*35136Smarc nttyparm.c_iflag |= (BRKINT|IGNPAR);
287*35136Smarc nttyparm.c_lflag &= ~(ICANON|ECHO);
288*35136Smarc #endif /* u370 */
289*35136Smarc nttyparm.c_cc[VTIME] = 0;
290*35136Smarc nttyparm.c_cc[VMIN] = 1;
291*35136Smarc editb.e_eof = ttyparm.c_cc[VEOF];
292*35136Smarc editb.e_erase = ttyparm.c_cc[VERASE];
293*35136Smarc editb.e_kill = ttyparm.c_cc[VKILL];
294*35136Smarc #ifndef u370
295*35136Smarc if( control(fd, TCSETAW, &nttyparm) == SYSERR )
296*35136Smarc #else
297*35136Smarc /* delays are too long, don't wait for output to drain */
298*35136Smarc if( control(fd, TCSETA, &nttyparm) == SYSERR )
299*35136Smarc #endif /* u370 */
300*35136Smarc {
301*35136Smarc return(BAD);
302*35136Smarc }
303*35136Smarc control(fd,TCXONC,1);
304*35136Smarc editb.e_ttyspeed = ttyparm.c_cflag & CBAUD;
305*35136Smarc #endif
306*35136Smarc editb.e_raw = RAWMODE;
307*35136Smarc return(GOOD);
308*35136Smarc }
309*35136Smarc
310*35136Smarc #ifndef BSD
311*35136Smarc /*
312*35136Smarc * give two tries for ioctl
313*35136Smarc * interrupts are ignored
314*35136Smarc */
315*35136Smarc
control(fd,request,arg)316*35136Smarc static int control(fd,request,arg)
317*35136Smarc {
318*35136Smarc register int i;
319*35136Smarc register int k = 2;
320*35136Smarc errno = 0;
321*35136Smarc while(k--)
322*35136Smarc {
323*35136Smarc if((i = ioctl(fd,request,arg)) != SYSERR)
324*35136Smarc return(i);
325*35136Smarc if(errno == EINTR)
326*35136Smarc {
327*35136Smarc errno = 0;
328*35136Smarc k++;
329*35136Smarc }
330*35136Smarc }
331*35136Smarc return(SYSERR);
332*35136Smarc }
333*35136Smarc #endif /* BSD */
334*35136Smarc #ifndef RAWONLY
335*35136Smarc
336*35136Smarc /* SET_TTY( fd )
337*35136Smarc *
338*35136Smarc * Get tty parameters and make ESC and '\r' wakeup characters.
339*35136Smarc *
340*35136Smarc */
341*35136Smarc
342*35136Smarc #ifdef BSD
setalt(fd)343*35136Smarc setalt(fd)
344*35136Smarc register int fd;
345*35136Smarc {
346*35136Smarc int mask;
347*35136Smarc struct tchars ttychars;
348*35136Smarc if(editb.e_raw==ALTMODE)
349*35136Smarc return(GOOD);
350*35136Smarc if(editb.e_raw==RAWMODE)
351*35136Smarc setcooked(fd);
352*35136Smarc l_changed = 0;
353*35136Smarc if( editb.e_ttyspeed == 0)
354*35136Smarc {
355*35136Smarc if((ioctl(fd,TIOCGETP,&ttyparm) != SYSERR))
356*35136Smarc editb.e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW);
357*35136Smarc }
358*35136Smarc if(ioctl(fd,TIOCGETC,&l_ttychars) == SYSERR)
359*35136Smarc return(BAD);
360*35136Smarc if(ioctl(fd,TIOCLGET,&l_mask)==SYSERR)
361*35136Smarc return(BAD);
362*35136Smarc ttychars = l_ttychars;
363*35136Smarc mask = LCRTBS|LCRTERA|LCTLECH|LPENDIN|LCRTKIL;
364*35136Smarc if((l_mask|mask) != l_mask)
365*35136Smarc l_changed = L_MASK;
366*35136Smarc if(ioctl(fd,TIOCLBIS,&mask)==SYSERR)
367*35136Smarc return(BAD);
368*35136Smarc ttychars.t_brkc = ESC;
369*35136Smarc l_changed |= T_CHARS;
370*35136Smarc if(ioctl(fd,TIOCSETC,&ttychars) == SYSERR)
371*35136Smarc return(BAD);
372*35136Smarc editb.e_raw = ALTMODE;
373*35136Smarc return(GOOD);
374*35136Smarc }
375*35136Smarc #else
setalt(fd)376*35136Smarc setalt(fd)
377*35136Smarc register int fd;
378*35136Smarc {
379*35136Smarc if(editb.e_raw==ALTMODE)
380*35136Smarc return(GOOD);
381*35136Smarc if(editb.e_raw==RAWMODE)
382*35136Smarc setcooked(fd);
383*35136Smarc if( (control(fd, TCGETA, &ttyparm) == SYSERR)
384*35136Smarc || (!(ttyparm.c_lflag & ECHO )))
385*35136Smarc {
386*35136Smarc return(BAD);
387*35136Smarc }
388*35136Smarc nttyparm = ttyparm;
389*35136Smarc nttyparm.c_iflag &= ~(IGNCR|ICRNL);
390*35136Smarc nttyparm.c_iflag |= INLCR;
391*35136Smarc nttyparm.c_lflag |= (ECHOE|ECHOK);
392*35136Smarc nttyparm.c_cc[VEOF] = ESC; /* make ESC the eof char */
393*35136Smarc nttyparm.c_cc[VEOL] = '\r'; /* make CR an eol char */
394*35136Smarc editb.e_eof = ttyparm.c_cc[VEOF];
395*35136Smarc nttyparm.c_cc[VEOL2] = editb.e_eof; /* make EOF an eol char */
396*35136Smarc editb.e_erase = ttyparm.c_cc[VERASE];
397*35136Smarc editb.e_kill = ttyparm.c_cc[VKILL];
398*35136Smarc if( control(fd, TCSETAW, &nttyparm) == SYSERR )
399*35136Smarc {
400*35136Smarc return(BAD);
401*35136Smarc }
402*35136Smarc editb.e_ttyspeed = ((ttyparm.c_cflag&CBAUD)>=B1200?FAST:SLOW);
403*35136Smarc editb.e_raw = ALTMODE;
404*35136Smarc return(GOOD);
405*35136Smarc }
406*35136Smarc
407*35136Smarc #endif /* BSD */
408*35136Smarc #endif /* RAWONLY */
409*35136Smarc
410*35136Smarc /*
411*35136Smarc * E_WINDOW()
412*35136Smarc *
413*35136Smarc * return the window size
414*35136Smarc */
415*35136Smarc
e_window()416*35136Smarc int e_window()
417*35136Smarc {
418*35136Smarc register int n = DFLTWINDOW-1;
419*35136Smarc register char *cp = valup(COLUMNS);
420*35136Smarc if(cp)
421*35136Smarc {
422*35136Smarc n = atoi(cp)-1;
423*35136Smarc if(n < MINWINDOW)
424*35136Smarc n = MINWINDOW;
425*35136Smarc if(n > MAXWINDOW)
426*35136Smarc n = MAXWINDOW;
427*35136Smarc }
428*35136Smarc return(n);
429*35136Smarc }
430*35136Smarc
431*35136Smarc /* E_FLUSH()
432*35136Smarc *
433*35136Smarc * Flush the output buffer.
434*35136Smarc *
435*35136Smarc */
436*35136Smarc
e_flush()437*35136Smarc void e_flush()
438*35136Smarc {
439*35136Smarc register unsigned char *buf = (unsigned char*)output->_base;
440*35136Smarc register int n = editb.e_outptr-buf;
441*35136Smarc register int fd = fileno(output);
442*35136Smarc if(n<=0)
443*35136Smarc return;
444*35136Smarc write(fd,(char*)buf,n);
445*35136Smarc editb.e_outptr = buf;
446*35136Smarc #ifdef BSD
447*35136Smarc # ifdef BSD_4_2
448*35136Smarc if(delay && n > delay/100)
449*35136Smarc {
450*35136Smarc /* delay until output drains */
451*35136Smarc struct timeval timeloc;
452*35136Smarc n *= 10;
453*35136Smarc timeloc.tv_sec = n/delay;
454*35136Smarc timeloc.tv_usec = (1000000*(n%delay))/delay;
455*35136Smarc select(0,0,0,0,&timeloc);
456*35136Smarc }
457*35136Smarc # endif /* BSD_4_2 */
458*35136Smarc #else
459*35136Smarc # ifndef RT
460*35136Smarc if(editb.e_raw==RAWMODE && n > 16)
461*35136Smarc ioctl(fd, TCSETAW, &nttyparm);
462*35136Smarc # endif /* RT */
463*35136Smarc #endif /* BSD */
464*35136Smarc }
465*35136Smarc
466*35136Smarc /*
467*35136Smarc * send the bell character ^G to the terminal
468*35136Smarc */
469*35136Smarc
e_ringbell()470*35136Smarc void e_ringbell()
471*35136Smarc {
472*35136Smarc write(fileno(output),bellchr,1);
473*35136Smarc }
474*35136Smarc
475*35136Smarc /*
476*35136Smarc * send a carriage return line feed to the terminal
477*35136Smarc */
478*35136Smarc
e_crlf()479*35136Smarc void e_crlf()
480*35136Smarc {
481*35136Smarc #ifdef u370
482*35136Smarc e_putchar('\r');
483*35136Smarc #endif /* u370 */
484*35136Smarc #ifdef VENIX
485*35136Smarc e_putchar('\r');
486*35136Smarc #endif /* VENIX */
487*35136Smarc e_putchar('\n');
488*35136Smarc e_flush();
489*35136Smarc }
490*35136Smarc
491*35136Smarc /* E_SETUP( max_prompt_size )
492*35136Smarc *
493*35136Smarc * This routine sets up the prompt string
494*35136Smarc */
495*35136Smarc
e_setup(fd,PRSIZE)496*35136Smarc void e_setup(fd,PRSIZE)
497*35136Smarc {
498*35136Smarc register char *last;
499*35136Smarc register char *pp = (char*)(output->_base);
500*35136Smarc char *ppmax;
501*35136Smarc editb.e_fd = fd;
502*35136Smarc if(fc_fix)
503*35136Smarc {
504*35136Smarc register struct fixcmd *fp = fc_fix;
505*35136Smarc editb.e_hismax = fp->fixind;
506*35136Smarc editb.e_hloff = fp->fixline;
507*35136Smarc editb.e_hismin = fp->fixind-fp->fixmax;
508*35136Smarc if(editb.e_hismin<0)
509*35136Smarc editb.e_hismin = 0;
510*35136Smarc }
511*35136Smarc else
512*35136Smarc {
513*35136Smarc editb.e_hismax = editb.e_hismin = editb.e_hloff = 0;
514*35136Smarc }
515*35136Smarc editb.e_hline = editb.e_hismax;
516*35136Smarc editb.e_wsize = e_window()-2;
517*35136Smarc editb.e_outptr = (unsigned char*)pp;
518*35136Smarc editb.e_crlf = YES;
519*35136Smarc *(output->_ptr) = 0;
520*35136Smarc if((last=strrchr(pp,'\n'))==NULL)
521*35136Smarc {
522*35136Smarc if(*(last=pp)==0)
523*35136Smarc editb.e_crlf = NO;
524*35136Smarc }
525*35136Smarc else
526*35136Smarc last++;
527*35136Smarc pp = editb.e_prompt;
528*35136Smarc ppmax = pp+PRSIZE-1;
529*35136Smarc *pp++ = '\r';
530*35136Smarc {
531*35136Smarc register int c;
532*35136Smarc while(c = *last++)
533*35136Smarc {
534*35136Smarc /* cut out bells */
535*35136Smarc if(c!=BELL)
536*35136Smarc {
537*35136Smarc if(pp < ppmax)
538*35136Smarc *pp++ = c;
539*35136Smarc if(!isprint(c))
540*35136Smarc editb.e_crlf = NO;
541*35136Smarc }
542*35136Smarc }
543*35136Smarc }
544*35136Smarc editb.e_plen = pp - editb.e_prompt - 1;
545*35136Smarc *pp = 0;
546*35136Smarc #ifdef u370
547*35136Smarc if (editb.e_raw == RAWMODE)
548*35136Smarc u370fflush(output);
549*35136Smarc else
550*35136Smarc #endif /* u370 */
551*35136Smarc p_flush();
552*35136Smarc }
553*35136Smarc
554*35136Smarc #ifdef u370
555*35136Smarc /* The u370 does not \r before \n in raw mode (known bug).
556*35136Smarc To get around this we will insert a \r before each \n
557*35136Smarc in the output buffer.
558*35136Smarc */
559*35136Smarc
u370fflush(file)560*35136Smarc u370fflush(file)
561*35136Smarc FILE *file;
562*35136Smarc {
563*35136Smarc unsigned char *base,*ptr,buffer[BUFSIZ*2];
564*35136Smarc int icnt,ocnt;
565*35136Smarc ptr = buffer;
566*35136Smarc icnt = file->_ptr - file->_base;
567*35136Smarc ocnt = icnt;
568*35136Smarc base = file->_base ;
569*35136Smarc if (icnt <= 0) return;
570*35136Smarc while (base < file->_ptr)
571*35136Smarc {
572*35136Smarc if (*base == '\n' )
573*35136Smarc {
574*35136Smarc *ptr++ = '\r';
575*35136Smarc ocnt++;
576*35136Smarc }
577*35136Smarc *ptr++ = *base++;
578*35136Smarc }
579*35136Smarc base = file->_base;
580*35136Smarc ptr = buffer;
581*35136Smarc while (ocnt>0)
582*35136Smarc {
583*35136Smarc for(icnt=0;icnt<BUFSIZ;icnt++)
584*35136Smarc {
585*35136Smarc *base++ = *ptr++;
586*35136Smarc if (--ocnt <= 0) break;
587*35136Smarc }
588*35136Smarc file->_ptr = base;
589*35136Smarc p_flush();
590*35136Smarc base = file->_base;
591*35136Smarc }
592*35136Smarc }
593*35136Smarc #endif /* u370 */
594*35136Smarc
595*35136Smarc #ifdef KSHELL
596*35136Smarc /*
597*35136Smarc * look for edit macro named _i
598*35136Smarc * if found, puts the macro definition into lookahead buffer and returns 1
599*35136Smarc */
600*35136Smarc
e_macro(i)601*35136Smarc e_macro(i)
602*35136Smarc register int i;
603*35136Smarc {
604*35136Smarc register char *out;
605*35136Smarc struct Namnod *np;
606*35136Smarc genchar buff[LOOKAHEAD+1];
607*35136Smarc if(i != '@')
608*35136Smarc macro[1] = i;
609*35136Smarc if (isalnum(i)&&(np=findnod(macro,alias,0))&&(out=valup(np)))
610*35136Smarc {
611*35136Smarc #ifdef MULTIBYTE
612*35136Smarc /* copy to buff in internal representation */
613*35136Smarc int c = out[LOOKAHEAD];
614*35136Smarc out[LOOKAHEAD] = 0;
615*35136Smarc i = e_internal(out,buff);
616*35136Smarc out[LOOKAHEAD] = c;
617*35136Smarc #else
618*35136Smarc strncpy((char*)buff,out,LOOKAHEAD);
619*35136Smarc i = strlen((char*)buff);
620*35136Smarc #endif /* MULTIBYTE */
621*35136Smarc while(i-- > 0)
622*35136Smarc ungetchar(buff[i]);
623*35136Smarc return(1);
624*35136Smarc }
625*35136Smarc return(0);
626*35136Smarc }
627*35136Smarc /*
628*35136Smarc * file name generation for edit modes
629*35136Smarc * non-zero exit for error, <0 ring bell
630*35136Smarc * don't search back past <start> character of the buffer
631*35136Smarc * mode is '*' for inline expansion, otherwise files are listed in select format
632*35136Smarc */
633*35136Smarc
q_expand(outbuff,cur,eol,start,mode)634*35136Smarc q_expand(outbuff,cur,eol,start,mode)
635*35136Smarc char outbuff[];
636*35136Smarc int *cur;
637*35136Smarc int *eol;
638*35136Smarc int start;
639*35136Smarc int mode;
640*35136Smarc {
641*35136Smarc STKPTR staksav = stakbot;
642*35136Smarc COMPTR comptr = (COMPTR)getstak(COMTYPE);
643*35136Smarc ARGPTR ap = (ARGPTR)locstak();
644*35136Smarc register char *out;
645*35136Smarc char *outmin = outbuff + start;
646*35136Smarc char *begin;
647*35136Smarc char *last;
648*35136Smarc int rval = 0;
649*35136Smarc int strip;
650*35136Smarc optflag savflags = flags;
651*35136Smarc #ifdef MULTIBYTE
652*35136Smarc {
653*35136Smarc register int c = *cur;
654*35136Smarc register genchar *cp;
655*35136Smarc /* adjust cur */
656*35136Smarc cp = (genchar *)outbuff + *cur;
657*35136Smarc c = *cp;
658*35136Smarc *cp = 0;
659*35136Smarc *cur = e_external((genchar*)outbuff,(char*)stakbot);
660*35136Smarc *cp = c;
661*35136Smarc *eol = e_external((genchar*)outbuff,outbuff);
662*35136Smarc }
663*35136Smarc #endif /* MULTIBYTE */
664*35136Smarc out = outbuff + *cur;
665*35136Smarc comptr->comtyp = COMSCAN;
666*35136Smarc comptr->comarg = ap;
667*35136Smarc ap->argflag = (A_MAC|A_EXP);
668*35136Smarc ap->argnxt = 0;
669*35136Smarc {
670*35136Smarc register int c;
671*35136Smarc register char *ptr = ap->argval;
672*35136Smarc int chktilde = 0;
673*35136Smarc int flag;
674*35136Smarc char *cp;
675*35136Smarc if(out>outmin)
676*35136Smarc {
677*35136Smarc /* go to beginning of word */
678*35136Smarc do
679*35136Smarc {
680*35136Smarc out--;
681*35136Smarc c = *(unsigned char*)out;
682*35136Smarc }
683*35136Smarc while(out>outmin && !isqmeta(c));
684*35136Smarc /* copy word into arg */
685*35136Smarc if(isqmeta(c))
686*35136Smarc out++;
687*35136Smarc }
688*35136Smarc else
689*35136Smarc out = outmin;
690*35136Smarc begin = out;
691*35136Smarc flag = '*';
692*35136Smarc strip = TRUE;
693*35136Smarc /* copy word to arg and do ~ expansion */
694*35136Smarc do
695*35136Smarc {
696*35136Smarc c = *(unsigned char*)out++;
697*35136Smarc if(isexp(c))
698*35136Smarc flag = 0;
699*35136Smarc if ((c == '/') && (flag == 0))
700*35136Smarc strip = FALSE;
701*35136Smarc *ptr++ = c;
702*35136Smarc if(chktilde==0 && (c==0 || c == '/'))
703*35136Smarc {
704*35136Smarc chktilde++;
705*35136Smarc if(cp=tilde(begin))
706*35136Smarc {
707*35136Smarc ptr = movstr(cp,ap->argval);
708*35136Smarc *ptr++ = c;
709*35136Smarc }
710*35136Smarc }
711*35136Smarc
712*35136Smarc } while (c && !isqmeta(c));
713*35136Smarc
714*35136Smarc out--;
715*35136Smarc *(ptr-1) = flag;
716*35136Smarc endstak(ptr);
717*35136Smarc last = ptr-1;
718*35136Smarc }
719*35136Smarc if(mode!='*')
720*35136Smarc on_option(MARKDIR);
721*35136Smarc {
722*35136Smarc register char **com;
723*35136Smarc int narg;
724*35136Smarc register int size;
725*35136Smarc while(1)
726*35136Smarc {
727*35136Smarc com = arg_build(&narg,comptr);
728*35136Smarc /* match? */
729*35136Smarc if (narg > 1 || !eq(ap->argval,*com))
730*35136Smarc break;
731*35136Smarc if (*last == 0)
732*35136Smarc *last = '*';
733*35136Smarc else
734*35136Smarc {
735*35136Smarc rval = -1;
736*35136Smarc goto done;
737*35136Smarc }
738*35136Smarc }
739*35136Smarc if(mode!='*')
740*35136Smarc {
741*35136Smarc if (strip)
742*35136Smarc {
743*35136Smarc register char **ptrcom;
744*35136Smarc for(ptrcom=com;*ptrcom;ptrcom++)
745*35136Smarc /* trim directory prefix */
746*35136Smarc *ptrcom = simple (*ptrcom);
747*35136Smarc }
748*35136Smarc p_setout(stderr);
749*35136Smarc newline();
750*35136Smarc p_list(narg,com);
751*35136Smarc p_flush();
752*35136Smarc goto done;
753*35136Smarc }
754*35136Smarc /* see if there is enough room */
755*35136Smarc size = *eol - (out-begin);
756*35136Smarc size += narg;
757*35136Smarc {
758*35136Smarc char **savcom = com;
759*35136Smarc while (*com)
760*35136Smarc size += strlen(*com++);
761*35136Smarc com = savcom;
762*35136Smarc }
763*35136Smarc /* see if room for expansion */
764*35136Smarc if(outbuff+size >= &outbuff[MAXLINE])
765*35136Smarc {
766*35136Smarc com[0] = ap->argval;
767*35136Smarc com[1] = NULL;
768*35136Smarc }
769*35136Smarc /* save remainder of the buffer */
770*35136Smarc strcpy(stakbot,out);
771*35136Smarc out = begin;
772*35136Smarc while (*com)
773*35136Smarc {
774*35136Smarc out = movstr(*com,out);
775*35136Smarc if (*++com)
776*35136Smarc *out++ = ' ';
777*35136Smarc }
778*35136Smarc *cur = (out-outbuff);
779*35136Smarc /* restore rest of buffer */
780*35136Smarc out = movstr(stakbot,out);
781*35136Smarc *eol = (out-outbuff);
782*35136Smarc }
783*35136Smarc done:
784*35136Smarc tdystak(staksav);
785*35136Smarc flags = savflags;
786*35136Smarc #ifdef MULTIBYTE
787*35136Smarc {
788*35136Smarc register int c;
789*35136Smarc /* first re-adjust cur */
790*35136Smarc out = outbuff + *cur;
791*35136Smarc c = *out;
792*35136Smarc *out = 0;
793*35136Smarc *cur = e_internal(outbuff,(genchar*)stakbot);
794*35136Smarc *out = c;
795*35136Smarc outbuff[*eol+1] = 0;
796*35136Smarc *eol = e_internal(outbuff,(genchar*)outbuff);
797*35136Smarc }
798*35136Smarc #endif /* MULTIBYTE */
799*35136Smarc return(rval);
800*35136Smarc }
801*35136Smarc #endif /* KSHELL */
802*35136Smarc
803*35136Smarc
804*35136Smarc /*
805*35136Smarc * routine to perform read from terminal for vi and emacs mode
806*35136Smarc */
807*35136Smarc
808*35136Smarc
809*35136Smarc int
e_getchar()810*35136Smarc e_getchar()
811*35136Smarc {
812*35136Smarc register int i;
813*35136Smarc register int c;
814*35136Smarc register int maxtry = 100;
815*35136Smarc int nchar; /* number of characters to read at a time */
816*35136Smarc #ifdef MULTIBYTE
817*35136Smarc static int curchar;
818*35136Smarc static int cursize;
819*35136Smarc #endif /* MULTIBYTE */
820*35136Smarc char readin[LOOKAHEAD] ;
821*35136Smarc if (lookahead)
822*35136Smarc {
823*35136Smarc c = previous[--lookahead];
824*35136Smarc /*** map '\r' to '\n' ***/
825*35136Smarc if(c == '\r')
826*35136Smarc c = '\n';
827*35136Smarc return(c);
828*35136Smarc }
829*35136Smarc
830*35136Smarc e_flush() ;
831*35136Smarc /* you can't chance read ahead at the end of line */
832*35136Smarc nchar = (editb.e_cur>=editb.e_eol?1:READAHEAD);
833*35136Smarc /* Set 'i' to indicate read failed, in case intr set */
834*35136Smarc retry:
835*35136Smarc i = -1;
836*35136Smarc errno = 0;
837*35136Smarc editb.e_inmacro = 0;
838*35136Smarc while((trapnote&SIGSLOW)==0 && maxtry--)
839*35136Smarc {
840*35136Smarc errno=0;
841*35136Smarc if ((i = read(fildes,readin, nchar)) != -1)
842*35136Smarc break;
843*35136Smarc }
844*35136Smarc #ifdef MULTIBYTE
845*35136Smarc lookahead = maxtry = i;
846*35136Smarc i = 0;
847*35136Smarc while (i < maxtry)
848*35136Smarc {
849*35136Smarc c = readin[i++] & STRIP;
850*35136Smarc next:
851*35136Smarc if(cursize-- > 0)
852*35136Smarc {
853*35136Smarc curchar = (curchar<<7) | (c&~HIGHBIT);
854*35136Smarc if(cursize==0)
855*35136Smarc {
856*35136Smarc c = curchar;
857*35136Smarc goto gotit;
858*35136Smarc }
859*35136Smarc else if(i>=maxtry)
860*35136Smarc goto retry;
861*35136Smarc continue;
862*35136Smarc }
863*35136Smarc else if(curchar = echarset(c))
864*35136Smarc {
865*35136Smarc cursize = in_csize(curchar);
866*35136Smarc if(curchar != 1)
867*35136Smarc c = 0;
868*35136Smarc curchar <<= 7*(ESS_MAXCHAR-cursize);
869*35136Smarc if(c)
870*35136Smarc goto next;
871*35136Smarc else if(i>=maxtry)
872*35136Smarc goto retry;
873*35136Smarc continue;
874*35136Smarc }
875*35136Smarc gotit:
876*35136Smarc previous[--lookahead] = c;
877*35136Smarc #else
878*35136Smarc while (i > 0)
879*35136Smarc {
880*35136Smarc c = readin[--i] & STRIP;
881*35136Smarc previous[lookahead++] = c;
882*35136Smarc #endif /* MULTIBYTE */
883*35136Smarc #ifndef BSD
884*35136Smarc if( c == '\0' )
885*35136Smarc {
886*35136Smarc /*** user break key ***/
887*35136Smarc lookahead = 0;
888*35136Smarc # ifdef KSHELL
889*35136Smarc fault(SIGINT);
890*35136Smarc longjmp(env, UINTR);
891*35136Smarc # endif /* KSHELL */
892*35136Smarc }
893*35136Smarc #endif /* !BSD */
894*35136Smarc }
895*35136Smarc #ifdef MULTIBYTE
896*35136Smarc /* shift lookahead buffer if necessary */
897*35136Smarc if(lookahead)
898*35136Smarc {
899*35136Smarc for(i=lookahead;i < maxtry;i++)
900*35136Smarc previous[i-lookahead] = previous[i];
901*35136Smarc }
902*35136Smarc lookahead = maxtry-lookahead;
903*35136Smarc #endif /* MULTIBYTE */
904*35136Smarc if (lookahead > 0)
905*35136Smarc return(e_getchar(1));
906*35136Smarc longjmp(env,(i==0?UEOF:UINTR)); /* What a mess! Give up */
907*35136Smarc /* NOTREACHED */
908*35136Smarc }
909*35136Smarc
910*35136Smarc void ungetchar(c)
911*35136Smarc register int c;
912*35136Smarc {
913*35136Smarc if (lookahead < LOOKAHEAD)
914*35136Smarc previous[lookahead++] = c;
915*35136Smarc return;
916*35136Smarc }
917*35136Smarc
918*35136Smarc /*
919*35136Smarc * put a character into the output buffer
920*35136Smarc */
921*35136Smarc
922*35136Smarc void e_putchar(c)
923*35136Smarc register int c;
924*35136Smarc {
925*35136Smarc register unsigned char *dp = editb.e_outptr;
926*35136Smarc #ifdef MULTIBYTE
927*35136Smarc register int d;
928*35136Smarc /* check for place holder */
929*35136Smarc if(c == MARKER)
930*35136Smarc return;
931*35136Smarc if(d = icharset(c))
932*35136Smarc {
933*35136Smarc if(d == 2)
934*35136Smarc *dp++ = ESS2;
935*35136Smarc else if(d == 3)
936*35136Smarc *dp++ = ESS3;
937*35136Smarc d = in_csize(d);
938*35136Smarc while(--d>0)
939*35136Smarc *dp++ = HIGHBIT|(c>>(7*d));
940*35136Smarc c |= HIGHBIT;
941*35136Smarc }
942*35136Smarc #endif /* MULTIBYTE */
943*35136Smarc if (c == '_')
944*35136Smarc {
945*35136Smarc *dp++ = ' ';
946*35136Smarc *dp++ = '\b';
947*35136Smarc }
948*35136Smarc *dp++ = c;
949*35136Smarc *dp = '\0';
950*35136Smarc if ((dp - (unsigned char*)(output->_base))>=(BUFSIZ-3))
951*35136Smarc e_flush();
952*35136Smarc else
953*35136Smarc editb.e_outptr = dp;
954*35136Smarc }
955*35136Smarc
956*35136Smarc /*
957*35136Smarc * copy virtual to physical and return the index for cursor in physical buffer
958*35136Smarc */
959*35136Smarc e_virt_to_phys(virt,phys,cur,voff,poff)
960*35136Smarc genchar *virt;
961*35136Smarc genchar *phys;
962*35136Smarc int cur;
963*35136Smarc {
964*35136Smarc register genchar *sp = virt;
965*35136Smarc register genchar *dp = phys;
966*35136Smarc register int c;
967*35136Smarc genchar *curp = sp + cur;
968*35136Smarc genchar *dpmax = phys+MAXLINE;
969*35136Smarc int r = 0;
970*35136Smarc #ifdef MULTIBYTE
971*35136Smarc int d;
972*35136Smarc #endif /* MULTIBYTE */
973*35136Smarc sp += voff;
974*35136Smarc dp += poff;
975*35136Smarc for(r=poff;c= *sp;sp++)
976*35136Smarc {
977*35136Smarc if(curp == sp)
978*35136Smarc r = dp - phys;
979*35136Smarc #ifdef MULTIBYTE
980*35136Smarc d = out_csize(icharset(c));
981*35136Smarc if(d>1)
982*35136Smarc {
983*35136Smarc /* multiple width character put in place holders */
984*35136Smarc *dp++ = c;
985*35136Smarc while(--d >0)
986*35136Smarc *dp++ = MARKER;
987*35136Smarc /* in vi mode the cursor is at the last character */
988*35136Smarc if(dp>=dpmax)
989*35136Smarc break;
990*35136Smarc continue;
991*35136Smarc }
992*35136Smarc else
993*35136Smarc #endif /* MULTIBYTE */
994*35136Smarc if(!isprint(c))
995*35136Smarc {
996*35136Smarc if(c=='\t')
997*35136Smarc {
998*35136Smarc c = dp-phys;
999*35136Smarc c = ((c+8)&~07) - c;
1000*35136Smarc while(--c>0)
1001*35136Smarc *dp++ = ' ';
1002*35136Smarc c = ' ';
1003*35136Smarc }
1004*35136Smarc else
1005*35136Smarc {
1006*35136Smarc *dp++ = '^';
1007*35136Smarc c ^= TO_PRINT;
1008*35136Smarc }
1009*35136Smarc /* in vi mode the cursor is at the last character */
1010*35136Smarc if(curp == sp && is_option(EDITVI))
1011*35136Smarc r = dp - phys;
1012*35136Smarc }
1013*35136Smarc *dp++ = c;
1014*35136Smarc if(dp>=dpmax)
1015*35136Smarc break;
1016*35136Smarc }
1017*35136Smarc *dp = 0;
1018*35136Smarc return(r);
1019*35136Smarc }
1020*35136Smarc
1021*35136Smarc #ifdef MULTIBYTE
1022*35136Smarc /*
1023*35136Smarc * convert external representation <src> to an array of genchars <dest>
1024*35136Smarc * <src> and <dest> can be the same
1025*35136Smarc * returns number of chars in dest
1026*35136Smarc */
1027*35136Smarc
1028*35136Smarc int e_internal(src,dest)
1029*35136Smarc register unsigned char *src;
1030*35136Smarc genchar *dest;
1031*35136Smarc {
1032*35136Smarc register int c;
1033*35136Smarc register genchar *dp = dest;
1034*35136Smarc register int d;
1035*35136Smarc register int size;
1036*35136Smarc if((unsigned char*)dest == src)
1037*35136Smarc {
1038*35136Smarc genchar buffer[MAXLINE];
1039*35136Smarc c = e_internal(src,buffer);
1040*35136Smarc e_gencpy(dp,buffer);
1041*35136Smarc return(c);
1042*35136Smarc }
1043*35136Smarc while(c = *src++)
1044*35136Smarc {
1045*35136Smarc if(size = echarset(c))
1046*35136Smarc {
1047*35136Smarc d = (size==1?c:0);
1048*35136Smarc c = size;
1049*35136Smarc size = in_csize(c);
1050*35136Smarc c <<= 7*(ESS_MAXCHAR-size);
1051*35136Smarc if(d)
1052*35136Smarc {
1053*35136Smarc size--;
1054*35136Smarc c = (c<<7) | (d&~HIGHBIT);
1055*35136Smarc }
1056*35136Smarc while(size-- >0)
1057*35136Smarc c = (c<<7) | ((*src++)&~HIGHBIT);
1058*35136Smarc }
1059*35136Smarc *dp++ = c;
1060*35136Smarc }
1061*35136Smarc *dp = 0;
1062*35136Smarc return(dp-dest);
1063*35136Smarc }
1064*35136Smarc
1065*35136Smarc /*
1066*35136Smarc * convert internal representation <src> into character array <dest>.
1067*35136Smarc * The <src> and <dest> may be the same.
1068*35136Smarc * returns number of chars in dest.
1069*35136Smarc */
1070*35136Smarc
1071*35136Smarc int e_external(src,dest)
1072*35136Smarc genchar *src;
1073*35136Smarc char *dest;
1074*35136Smarc {
1075*35136Smarc register int c;
1076*35136Smarc register char *dp = dest;
1077*35136Smarc register int d;
1078*35136Smarc char *dpmax = dp+sizeof(genchar)*MAXLINE-2;
1079*35136Smarc if((char*)src == dp)
1080*35136Smarc {
1081*35136Smarc char buffer[MAXLINE*sizeof(genchar)];
1082*35136Smarc c = e_external(src,buffer);
1083*35136Smarc strcpy(dest,buffer);
1084*35136Smarc return(c);
1085*35136Smarc }
1086*35136Smarc while((c = *src++) && dp<dpmax)
1087*35136Smarc {
1088*35136Smarc if(d = icharset(c))
1089*35136Smarc {
1090*35136Smarc if(d == 2)
1091*35136Smarc *dp++ = ESS2;
1092*35136Smarc else if(d == 3)
1093*35136Smarc *dp++ = ESS3;
1094*35136Smarc d = in_csize(d);
1095*35136Smarc while(--d>0)
1096*35136Smarc *dp++ = HIGHBIT|(c>>(7*d));
1097*35136Smarc c |= HIGHBIT;
1098*35136Smarc }
1099*35136Smarc *dp++ = c;
1100*35136Smarc }
1101*35136Smarc *dp = 0;
1102*35136Smarc return(dp-dest);
1103*35136Smarc }
1104*35136Smarc
1105*35136Smarc /*
1106*35136Smarc * copy <sp> to <dp>
1107*35136Smarc */
1108*35136Smarc
1109*35136Smarc int e_gencpy(dp,sp)
1110*35136Smarc register genchar *dp;
1111*35136Smarc register genchar *sp;
1112*35136Smarc {
1113*35136Smarc while(*dp++ = *sp++);
1114*35136Smarc }
1115*35136Smarc
1116*35136Smarc /*
1117*35136Smarc * copy at most <n> items from <sp> to <dp>
1118*35136Smarc */
1119*35136Smarc
1120*35136Smarc int e_genncpy(dp,sp, n)
1121*35136Smarc register genchar *dp;
1122*35136Smarc register genchar *sp;
1123*35136Smarc register int n;
1124*35136Smarc {
1125*35136Smarc while(n-->0 && (*dp++ = *sp++));
1126*35136Smarc }
1127*35136Smarc
1128*35136Smarc /*
1129*35136Smarc * find the string length of <str>
1130*35136Smarc */
1131*35136Smarc
1132*35136Smarc int e_genlen(str)
1133*35136Smarc register genchar *str;
1134*35136Smarc {
1135*35136Smarc register genchar *sp = str;
1136*35136Smarc while(*sp++);
1137*35136Smarc return(sp-str-1);
1138*35136Smarc }
1139*35136Smarc #endif /* MULTIBYTE */
1140