1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2012 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * David Korn <dgk@research.att.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22 * edit.c - common routines for vi and emacs one line editors in shell
23 *
24 * David Korn P.D. Sullivan
25 * AT&T Labs
26 *
27 * Coded April 1983.
28 */
29
30 #include <ast.h>
31 #include <errno.h>
32 #include <ccode.h>
33 #include "FEATURE/options"
34 #include "FEATURE/time"
35 #include "FEATURE/cmds"
36 #ifdef _hdr_utime
37 # include <utime.h>
38 # include <ls.h>
39 #endif
40
41 #if KSHELL
42 # include "defs.h"
43 # include "variables.h"
44 #else
45 # include <ctype.h>
46 extern char ed_errbuf[];
47 char e_version[] = "\n@(#)$Id: Editlib version 1993-12-28 r $\0\n";
48 #endif /* KSHELL */
49 #include "io.h"
50 #include "terminal.h"
51 #include "history.h"
52 #include "edit.h"
53
54 static char CURSOR_UP[20] = { ESC, '[', 'A', 0 };
55 static char KILL_LINE[20] = { ESC, '[', 'J', 0 };
56
57
58
59 #if SHOPT_MULTIBYTE
60 # define is_cntrl(c) ((c<=STRIP) && iscntrl(c))
61 # define is_print(c) ((c&~STRIP) || isprint(c))
62 #else
63 # define is_cntrl(c) iscntrl(c)
64 # define is_print(c) isprint(c)
65 #endif
66
67 #if (CC_NATIVE == CC_ASCII)
68 # define printchar(c) ((c) ^ ('A'-cntl('A')))
69 #else
printchar(int c)70 static int printchar(int c)
71 {
72 switch(c)
73 {
74
75 case cntl('A'): return('A');
76 case cntl('B'): return('B');
77 case cntl('C'): return('C');
78 case cntl('D'): return('D');
79 case cntl('E'): return('E');
80 case cntl('F'): return('F');
81 case cntl('G'): return('G');
82 case cntl('H'): return('H');
83 case cntl('I'): return('I');
84 case cntl('J'): return('J');
85 case cntl('K'): return('K');
86 case cntl('L'): return('L');
87 case cntl('M'): return('M');
88 case cntl('N'): return('N');
89 case cntl('O'): return('O');
90 case cntl('P'): return('P');
91 case cntl('Q'): return('Q');
92 case cntl('R'): return('R');
93 case cntl('S'): return('S');
94 case cntl('T'): return('T');
95 case cntl('U'): return('U');
96 case cntl('V'): return('V');
97 case cntl('W'): return('W');
98 case cntl('X'): return('X');
99 case cntl('Y'): return('Y');
100 case cntl('Z'): return('Z');
101 case cntl(']'): return(']');
102 case cntl('['): return('[');
103 }
104 return('?');
105 }
106 #endif
107 #define MINWINDOW 15 /* minimum width window */
108 #define DFLTWINDOW 80 /* default window width */
109 #define RAWMODE 1
110 #define ALTMODE 2
111 #define ECHOMODE 3
112 #define SYSERR -1
113
114 #if SHOPT_OLDTERMIO
115 # undef tcgetattr
116 # undef tcsetattr
117 #endif /* SHOPT_OLDTERMIO */
118
119 #ifdef RT
120 # define VENIX 1
121 #endif /* RT */
122
123
124 #ifdef _hdr_sgtty
125 # ifdef TIOCGETP
126 static int l_mask;
127 static struct tchars l_ttychars;
128 static struct ltchars l_chars;
129 static char l_changed; /* set if mode bits changed */
130 # define L_CHARS 4
131 # define T_CHARS 2
132 # define L_MASK 1
133 # endif /* TIOCGETP */
134 #endif /* _hdr_sgtty */
135
136 #if KSHELL
137 static int keytrap(Edit_t *,char*, int, int, int);
138 #else
139 Edit_t editb;
140 #endif /* KSHELL */
141
142
143 #ifndef _POSIX_DISABLE
144 # define _POSIX_DISABLE 0
145 #endif
146
147 #ifdef future
148 static int compare(const char*, const char*, int);
149 #endif /* future */
150 #if SHOPT_VSH || SHOPT_ESH
151 # define ttyparm (ep->e_ttyparm)
152 # define nttyparm (ep->e_nttyparm)
153 static const char bellchr[] = "\a"; /* bell char */
154 #endif /* SHOPT_VSH || SHOPT_ESH */
155
156
157 /*
158 * This routine returns true if fd refers to a terminal
159 * This should be equivalent to isatty
160 */
tty_check(int fd)161 int tty_check(int fd)
162 {
163 register Edit_t *ep = (Edit_t*)(shgd->ed_context);
164 struct termios tty;
165 ep->e_savefd = -1;
166 return(tty_get(fd,&tty)==0);
167 }
168
169 /*
170 * Get the current terminal attributes
171 * This routine remembers the attributes and just returns them if it
172 * is called again without an intervening tty_set()
173 */
174
tty_get(register int fd,register struct termios * tty)175 int tty_get(register int fd, register struct termios *tty)
176 {
177 register Edit_t *ep = (Edit_t*)(shgd->ed_context);
178 if(fd == ep->e_savefd)
179 *tty = ep->e_savetty;
180 else
181 {
182 while(tcgetattr(fd,tty) == SYSERR)
183 {
184 if(errno !=EINTR)
185 return(SYSERR);
186 errno = 0;
187 }
188 /* save terminal settings if in cannonical state */
189 if(ep->e_raw==0)
190 {
191 ep->e_savetty = *tty;
192 ep->e_savefd = fd;
193 }
194 }
195 return(0);
196 }
197
198 /*
199 * Set the terminal attributes
200 * If fd<0, then current attributes are invalidated
201 */
202
tty_set(int fd,int action,struct termios * tty)203 int tty_set(int fd, int action, struct termios *tty)
204 {
205 register Edit_t *ep = (Edit_t*)(shgd->ed_context);
206 if(fd >=0)
207 {
208 #ifdef future
209 if(ep->e_savefd>=0 && compare(&ep->e_savetty,tty,sizeof(struct termios)))
210 return(0);
211 #endif
212 while(tcsetattr(fd, action, tty) == SYSERR)
213 {
214 if(errno !=EINTR)
215 return(SYSERR);
216 errno = 0;
217 }
218 ep->e_savetty = *tty;
219 }
220 ep->e_savefd = fd;
221 return(0);
222 }
223
224 #if SHOPT_ESH || SHOPT_VSH
225 /*{ TTY_COOKED( fd )
226 *
227 * This routine will set the tty in cooked mode.
228 * It is also called by error.done().
229 *
230 }*/
231
tty_cooked(register int fd)232 void tty_cooked(register int fd)
233 {
234 register Edit_t *ep = (Edit_t*)(shgd->ed_context);
235 ep->e_keytrap = 0;
236 if(ep->e_raw==0)
237 return;
238 if(fd < 0)
239 fd = ep->e_savefd;
240 #ifdef L_MASK
241 /* restore flags */
242 if(l_changed&L_MASK)
243 ioctl(fd,TIOCLSET,&l_mask);
244 if(l_changed&T_CHARS)
245 /* restore alternate break character */
246 ioctl(fd,TIOCSETC,&l_ttychars);
247 if(l_changed&L_CHARS)
248 /* restore alternate break character */
249 ioctl(fd,TIOCSLTC,&l_chars);
250 l_changed = 0;
251 #endif /* L_MASK */
252 /*** don't do tty_set unless ttyparm has valid data ***/
253 if(tty_set(fd, TCSANOW, &ttyparm) == SYSERR)
254 return;
255 ep->e_raw = 0;
256 return;
257 }
258
259 /*{ TTY_RAW( fd )
260 *
261 * This routine will set the tty in raw mode.
262 *
263 }*/
264
tty_raw(register int fd,int echomode)265 int tty_raw(register int fd, int echomode)
266 {
267 int echo = echomode;
268 #ifdef L_MASK
269 struct ltchars lchars;
270 #endif /* L_MASK */
271 register Edit_t *ep = (Edit_t*)(shgd->ed_context);
272 if(ep->e_raw==RAWMODE)
273 return(echo?-1:0);
274 else if(ep->e_raw==ECHOMODE)
275 return(echo?0:-1);
276 #if !SHOPT_RAWONLY
277 if(ep->e_raw != ALTMODE)
278 #endif /* SHOPT_RAWONLY */
279 {
280 if(tty_get(fd,&ttyparm) == SYSERR)
281 return(-1);
282 }
283 #if L_MASK || VENIX
284 if(ttyparm.sg_flags&LCASE)
285 return(-1);
286 if(!(ttyparm.sg_flags&ECHO))
287 {
288 if(!echomode)
289 return(-1);
290 echo = 0;
291 }
292 nttyparm = ttyparm;
293 if(!echo)
294 nttyparm.sg_flags &= ~(ECHO | TBDELAY);
295 # ifdef CBREAK
296 nttyparm.sg_flags |= CBREAK;
297 # else
298 nttyparm.sg_flags |= RAW;
299 # endif /* CBREAK */
300 ep->e_erase = ttyparm.sg_erase;
301 ep->e_kill = ttyparm.sg_kill;
302 ep->e_eof = cntl('D');
303 ep->e_werase = cntl('W');
304 ep->e_lnext = cntl('V');
305 if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
306 return(-1);
307 ep->e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW);
308 # ifdef TIOCGLTC
309 /* try to remove effect of ^V and ^Y and ^O */
310 if(ioctl(fd,TIOCGLTC,&l_chars) != SYSERR)
311 {
312 lchars = l_chars;
313 lchars.t_lnextc = -1;
314 lchars.t_flushc = -1;
315 lchars.t_dsuspc = -1; /* no delayed stop process signal */
316 if(ioctl(fd,TIOCSLTC,&lchars) != SYSERR)
317 l_changed |= L_CHARS;
318 }
319 # endif /* TIOCGLTC */
320 #else
321 if (!(ttyparm.c_lflag & ECHO ))
322 {
323 if(!echomode)
324 return(-1);
325 echo = 0;
326 }
327 # ifdef FLUSHO
328 ttyparm.c_lflag &= ~FLUSHO;
329 # endif /* FLUSHO */
330 nttyparm = ttyparm;
331 # ifndef u370
332 nttyparm.c_iflag &= ~(IGNPAR|PARMRK|INLCR|IGNCR|ICRNL);
333 nttyparm.c_iflag |= BRKINT;
334 # else
335 nttyparm.c_iflag &=
336 ~(IGNBRK|PARMRK|INLCR|IGNCR|ICRNL|INPCK);
337 nttyparm.c_iflag |= (BRKINT|IGNPAR);
338 # endif /* u370 */
339 if(echo)
340 nttyparm.c_lflag &= ~(ICANON);
341 else
342 nttyparm.c_lflag &= ~(ICANON|ISIG|ECHO|ECHOK);
343 nttyparm.c_cc[VTIME] = 0;
344 nttyparm.c_cc[VMIN] = 1;
345 # ifdef VREPRINT
346 nttyparm.c_cc[VREPRINT] = _POSIX_DISABLE;
347 # endif /* VREPRINT */
348 # ifdef VDISCARD
349 nttyparm.c_cc[VDISCARD] = _POSIX_DISABLE;
350 # endif /* VDISCARD */
351 # ifdef VDSUSP
352 nttyparm.c_cc[VDSUSP] = _POSIX_DISABLE;
353 # endif /* VDSUSP */
354 # ifdef VWERASE
355 if(ttyparm.c_cc[VWERASE] == _POSIX_DISABLE)
356 ep->e_werase = cntl('W');
357 else
358 ep->e_werase = nttyparm.c_cc[VWERASE];
359 nttyparm.c_cc[VWERASE] = _POSIX_DISABLE;
360 # else
361 ep->e_werase = cntl('W');
362 # endif /* VWERASE */
363 # ifdef VLNEXT
364 if(ttyparm.c_cc[VLNEXT] == _POSIX_DISABLE )
365 ep->e_lnext = cntl('V');
366 else
367 ep->e_lnext = nttyparm.c_cc[VLNEXT];
368 nttyparm.c_cc[VLNEXT] = _POSIX_DISABLE;
369 # else
370 ep->e_lnext = cntl('V');
371 # endif /* VLNEXT */
372 ep->e_intr = ttyparm.c_cc[VINTR];
373 ep->e_eof = ttyparm.c_cc[VEOF];
374 ep->e_erase = ttyparm.c_cc[VERASE];
375 ep->e_kill = ttyparm.c_cc[VKILL];
376 if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
377 return(-1);
378 ep->e_ttyspeed = (cfgetospeed(&ttyparm)>=B1200?FAST:SLOW);
379 #endif
380 ep->e_raw = (echomode?ECHOMODE:RAWMODE);
381 return(0);
382 }
383
384 #if !SHOPT_RAWONLY
385
386 /*
387 *
388 * Get tty parameters and make ESC and '\r' wakeup characters.
389 *
390 */
391
392 # ifdef TIOCGETC
tty_alt(register int fd)393 int tty_alt(register int fd)
394 {
395 register Edit_t *ep = (Edit_t*)(shgd->ed_context);
396 int mask;
397 struct tchars ttychars;
398 switch(ep->e_raw)
399 {
400 case ECHOMODE:
401 return(-1);
402 case ALTMODE:
403 return(0);
404 case RAWMODE:
405 tty_cooked(fd);
406 }
407 l_changed = 0;
408 if( ep->e_ttyspeed == 0)
409 {
410 if((tty_get(fd,&ttyparm) != SYSERR))
411 ep->e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW);
412 ep->e_raw = ALTMODE;
413 }
414 if(ioctl(fd,TIOCGETC,&l_ttychars) == SYSERR)
415 return(-1);
416 if(ioctl(fd,TIOCLGET,&l_mask)==SYSERR)
417 return(-1);
418 ttychars = l_ttychars;
419 mask = LCRTBS|LCRTERA|LCTLECH|LPENDIN|LCRTKIL;
420 if((l_mask|mask) != l_mask)
421 l_changed = L_MASK;
422 if(ioctl(fd,TIOCLBIS,&mask)==SYSERR)
423 return(-1);
424 if(ttychars.t_brkc!=ESC)
425 {
426 ttychars.t_brkc = ESC;
427 l_changed |= T_CHARS;
428 if(ioctl(fd,TIOCSETC,&ttychars) == SYSERR)
429 return(-1);
430 }
431 return(0);
432 }
433 # else
434 # ifndef PENDIN
435 # define PENDIN 0
436 # endif /* PENDIN */
437 # ifndef IEXTEN
438 # define IEXTEN 0
439 # endif /* IEXTEN */
440
tty_alt(register int fd)441 int tty_alt(register int fd)
442 {
443 register Edit_t *ep = (Edit_t*)(shgd->ed_context);
444 switch(ep->e_raw)
445 {
446 case ECHOMODE:
447 return(-1);
448 case ALTMODE:
449 return(0);
450 case RAWMODE:
451 tty_cooked(fd);
452 }
453 if((tty_get(fd, &ttyparm)==SYSERR) || (!(ttyparm.c_lflag&ECHO)))
454 return(-1);
455 # ifdef FLUSHO
456 ttyparm.c_lflag &= ~FLUSHO;
457 # endif /* FLUSHO */
458 nttyparm = ttyparm;
459 ep->e_eof = ttyparm.c_cc[VEOF];
460 # ifdef ECHOCTL
461 /* escape character echos as ^[ */
462 nttyparm.c_lflag |= (ECHOE|ECHOK|ECHOCTL|PENDIN|IEXTEN);
463 nttyparm.c_cc[VEOL] = ESC;
464 # else
465 /* switch VEOL2 and EOF, since EOF isn't echo'd by driver */
466 nttyparm.c_lflag |= (ECHOE|ECHOK);
467 nttyparm.c_cc[VEOF] = ESC; /* make ESC the eof char */
468 # ifdef VEOL2
469 nttyparm.c_iflag &= ~(IGNCR|ICRNL);
470 nttyparm.c_iflag |= INLCR;
471 nttyparm.c_cc[VEOL] = '\r'; /* make CR an eol char */
472 nttyparm.c_cc[VEOL2] = ep->e_eof; /* make EOF an eol char */
473 # else
474 nttyparm.c_cc[VEOL] = ep->e_eof; /* make EOF an eol char */
475 # endif /* VEOL2 */
476 # endif /* ECHOCTL */
477 # ifdef VREPRINT
478 nttyparm.c_cc[VREPRINT] = _POSIX_DISABLE;
479 # endif /* VREPRINT */
480 # ifdef VDISCARD
481 nttyparm.c_cc[VDISCARD] = _POSIX_DISABLE;
482 # endif /* VDISCARD */
483 # ifdef VWERASE
484 if(ttyparm.c_cc[VWERASE] == _POSIX_DISABLE)
485 nttyparm.c_cc[VWERASE] = cntl('W');
486 ep->e_werase = nttyparm.c_cc[VWERASE];
487 # else
488 ep->e_werase = cntl('W');
489 # endif /* VWERASE */
490 # ifdef VLNEXT
491 if(ttyparm.c_cc[VLNEXT] == _POSIX_DISABLE )
492 nttyparm.c_cc[VLNEXT] = cntl('V');
493 ep->e_lnext = nttyparm.c_cc[VLNEXT];
494 # else
495 ep->e_lnext = cntl('V');
496 # endif /* VLNEXT */
497 ep->e_erase = ttyparm.c_cc[VERASE];
498 ep->e_kill = ttyparm.c_cc[VKILL];
499 if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
500 return(-1);
501 ep->e_ttyspeed = (cfgetospeed(&ttyparm)>=B1200?FAST:SLOW);
502 ep->e_raw = ALTMODE;
503 return(0);
504 }
505
506 # endif /* TIOCGETC */
507 #endif /* SHOPT_RAWONLY */
508
509 /*
510 * ED_WINDOW()
511 *
512 * return the window size
513 */
ed_window(void)514 int ed_window(void)
515 {
516 int rows,cols;
517 register char *cp = nv_getval(COLUMNS);
518 if(cp)
519 cols = (int)strtol(cp, (char**)0, 10)-1;
520 else
521 {
522 astwinsize(2,&rows,&cols);
523 if(--cols <0)
524 cols = DFLTWINDOW-1;
525 }
526 if(cols < MINWINDOW)
527 cols = MINWINDOW;
528 else if(cols > MAXWINDOW)
529 cols = MAXWINDOW;
530 return(cols);
531 }
532
533 /* E_FLUSH()
534 *
535 * Flush the output buffer.
536 *
537 */
538
ed_flush(Edit_t * ep)539 void ed_flush(Edit_t *ep)
540 {
541 register int n = ep->e_outptr-ep->e_outbase;
542 register int fd = ERRIO;
543 if(n<=0)
544 return;
545 write(fd,ep->e_outbase,(unsigned)n);
546 ep->e_outptr = ep->e_outbase;
547 }
548
549 /*
550 * send the bell character ^G to the terminal
551 */
552
ed_ringbell(void)553 void ed_ringbell(void)
554 {
555 write(ERRIO,bellchr,1);
556 }
557
558 /*
559 * send a carriage return line feed to the terminal
560 */
561
ed_crlf(register Edit_t * ep)562 void ed_crlf(register Edit_t *ep)
563 {
564 #ifdef cray
565 ed_putchar(ep,'\r');
566 #endif /* cray */
567 #ifdef u370
568 ed_putchar(ep,'\r');
569 #endif /* u370 */
570 #ifdef VENIX
571 ed_putchar(ep,'\r');
572 #endif /* VENIX */
573 ed_putchar(ep,'\n');
574 ed_flush(ep);
575 }
576
577 /* ED_SETUP( max_prompt_size )
578 *
579 * This routine sets up the prompt string
580 * The following is an unadvertised feature.
581 * Escape sequences in the prompt can be excluded from the calculated
582 * prompt length. This is accomplished as follows:
583 * - if the prompt string starts with "%\r, or contains \r%\r", where %
584 * represents any char, then % is taken to be the quote character.
585 * - strings enclosed by this quote character, and the quote character,
586 * are not counted as part of the prompt length.
587 */
588
ed_setup(register Edit_t * ep,int fd,int reedit)589 void ed_setup(register Edit_t *ep, int fd, int reedit)
590 {
591 Shell_t *shp = ep->sh;
592 register char *pp;
593 register char *last, *prev;
594 char *ppmax;
595 int myquote = 0, n;
596 register int qlen = 1, qwid;
597 char inquote = 0;
598 ep->e_fd = fd;
599 ep->e_multiline = sh_isoption(SH_MULTILINE)!=0;
600 #ifdef SIGWINCH
601 if(!(shp->sigflag[SIGWINCH]&SH_SIGFAULT))
602 {
603 signal(SIGWINCH,sh_fault);
604 shp->sigflag[SIGWINCH] |= SH_SIGFAULT;
605 }
606 pp = shp->st.trapcom[SIGWINCH];
607 shp->st.trapcom[SIGWINCH] = 0;
608 sh_fault(SIGWINCH);
609 shp->st.trapcom[SIGWINCH] = pp;
610 ep->sh->winch = 0;
611 #endif
612 #if SHOPT_EDPREDICT
613 ep->hlist = 0;
614 ep->nhlist = 0;
615 ep->hoff = 0;
616 #endif /* SHOPT_EDPREDICT */
617 #if KSHELL
618 ep->e_stkptr = stakptr(0);
619 ep->e_stkoff = staktell();
620 if(!(last = shp->prompt))
621 last = "";
622 shp->prompt = 0;
623 #else
624 last = ep->e_prbuff;
625 #endif /* KSHELL */
626 if(shp->gd->hist_ptr)
627 {
628 register History_t *hp = shp->gd->hist_ptr;
629 ep->e_hismax = hist_max(hp);
630 ep->e_hismin = hist_min(hp);
631 }
632 else
633 {
634 ep->e_hismax = ep->e_hismin = ep->e_hloff = 0;
635 }
636 ep->e_hline = ep->e_hismax;
637 if(!sh_isoption(SH_VI) && !sh_isoption(SH_EMACS) && !sh_isoption(SH_GMACS))
638 ep->e_wsize = MAXLINE;
639 else
640 ep->e_wsize = ed_window()-2;
641 ep->e_winsz = ep->e_wsize+2;
642 ep->e_crlf = 1;
643 ep->e_plen = 0;
644 pp = ep->e_prompt;
645 ppmax = pp+PRSIZE-1;
646 *pp++ = '\r';
647 {
648 register int c;
649 while(prev = last, c = mbchar(last)) switch(c)
650 {
651 case ESC:
652 {
653 int skip=0;
654 ep->e_crlf = 0;
655 if (pp < ppmax)
656 *pp++ = c;
657 for(n=1; c = *last++; n++)
658 {
659 if(pp < ppmax)
660 *pp++ = c;
661 if(c=='\a' || c==ESC || c=='\r')
662 break;
663 if(skip || (c>='0' && c<='9'))
664 {
665 skip = 0;
666 continue;
667 }
668 if(n>1 && c==';')
669 skip = 1;
670 else if(n>2 || (c!= '[' && c!= ']'))
671 break;
672 }
673 if(c==0 || c==ESC || c=='\r')
674 last--;
675 qlen += (n+1);
676 break;
677 }
678 case '\b':
679 if(pp>ep->e_prompt+1)
680 pp--;
681 break;
682 case '\r':
683 if(pp == (ep->e_prompt+2)) /* quote char */
684 myquote = *(pp-1);
685 /*FALLTHROUGH*/
686
687 case '\n':
688 /* start again */
689 ep->e_crlf = 1;
690 qlen = 1;
691 inquote = 0;
692 pp = ep->e_prompt+1;
693 break;
694
695 case '\t':
696 /* expand tabs */
697 while((pp-ep->e_prompt)%TABSIZE)
698 {
699 if(pp >= ppmax)
700 break;
701 *pp++ = ' ';
702 }
703 break;
704
705 case '\a':
706 /* cut out bells */
707 break;
708
709 default:
710 if(c==myquote)
711 {
712 qlen += inquote;
713 inquote ^= 1;
714 }
715 if(pp < ppmax)
716 {
717 if(inquote)
718 qlen++;
719 else if(!is_print(c))
720 ep->e_crlf = 0;
721 if((qwid = last - prev) > 1)
722 qlen += qwid - mbwidth(c);
723 while(prev < last && pp < ppmax)
724 *pp++ = *prev++;
725 }
726 break;
727 }
728 }
729 if(pp-ep->e_prompt > qlen)
730 ep->e_plen = pp - ep->e_prompt - qlen;
731 *pp = 0;
732 if(!ep->e_multiline && (ep->e_wsize -= ep->e_plen) < 7)
733 {
734 register int shift = 7-ep->e_wsize;
735 ep->e_wsize = 7;
736 pp = ep->e_prompt+1;
737 strcpy(pp,pp+shift);
738 ep->e_plen -= shift;
739 last[-ep->e_plen-2] = '\r';
740 }
741 sfsync(sfstderr);
742 if(fd == sffileno(sfstderr))
743 {
744 /* can't use output buffer when reading from stderr */
745 static char *buff;
746 if(!buff)
747 buff = (char*)malloc(MAXLINE);
748 ep->e_outbase = ep->e_outptr = buff;
749 ep->e_outlast = ep->e_outptr + MAXLINE;
750 return;
751 }
752 qlen = sfset(sfstderr,SF_READ,0);
753 /* make sure SF_READ not on */
754 ep->e_outbase = ep->e_outptr = (char*)sfreserve(sfstderr,SF_UNBOUND,SF_LOCKR);
755 ep->e_outlast = ep->e_outptr + sfvalue(sfstderr);
756 if(qlen)
757 sfset(sfstderr,SF_READ,1);
758 sfwrite(sfstderr,ep->e_outptr,0);
759 ep->e_eol = reedit;
760 if(ep->e_multiline)
761 {
762 #ifdef _cmd_tput
763 char *term;
764 if(!ep->e_term)
765 ep->e_term = nv_search("TERM",shp->var_tree,0);
766 if(ep->e_term && (term=nv_getval(ep->e_term)) && strlen(term)<sizeof(ep->e_termname) && strcmp(term,ep->e_termname))
767 {
768 sh_trap(".sh.subscript=$(tput cuu1 2>/dev/null)",0);
769 if(pp=nv_getval(SH_SUBSCRNOD))
770 strncpy(CURSOR_UP,pp,sizeof(CURSOR_UP)-1);
771 nv_unset(SH_SUBSCRNOD);
772 strcpy(ep->e_termname,term);
773 }
774 #endif
775 ep->e_wsize = MAXLINE - (ep->e_plen+1);
776 }
777 if(ep->e_default && (pp = nv_getval(ep->e_default)))
778 {
779 n = strlen(pp);
780 if(n > LOOKAHEAD)
781 n = LOOKAHEAD;
782 ep->e_lookahead = n;
783 while(n-- > 0)
784 ep->e_lbuf[n] = *pp++;
785 ep->e_default = 0;
786 }
787 }
788
ed_putstring(register Edit_t * ep,const char * str)789 static void ed_putstring(register Edit_t *ep, const char *str)
790 {
791 register int c;
792 while(c = *str++)
793 ed_putchar(ep,c);
794 }
795
ed_nputchar(register Edit_t * ep,int n,int c)796 static void ed_nputchar(register Edit_t *ep, int n, int c)
797 {
798 while(n-->0)
799 ed_putchar(ep,c);
800 }
801
802 /*
803 * Do read, restart on interrupt unless SH_SIGSET or SH_SIGTRAP is set
804 * Use sfpkrd() to poll() or select() to wait for input if possible
805 * Unfortunately, systems that get interrupted from slow reads update
806 * this access time for for the terminal (in violation of POSIX).
807 * The fixtime() macro, resets the time to the time at entry in
808 * this case. This is not necessary for systems that can handle
809 * sfpkrd() correctly (i,e., those that support poll() or select()
810 */
ed_read(void * context,int fd,char * buff,int size,int reedit)811 int ed_read(void *context, int fd, char *buff, int size, int reedit)
812 {
813 register Edit_t *ep = (Edit_t*)context;
814 register int rv= -1;
815 register int delim = ((ep->e_raw&RAWMODE)?nttyparm.c_cc[VEOL]:'\n');
816 Shell_t *shp = ep->sh;
817 int mode = -1;
818 int (*waitevent)(int,long,int) = shp->gd->waitevent;
819 if(ep->e_raw==ALTMODE)
820 mode = 1;
821 if(size < 0)
822 {
823 mode = 1;
824 size = -size;
825 }
826 sh_onstate(SH_TTYWAIT);
827 errno = EINTR;
828 shp->gd->waitevent = 0;
829 while(rv<0 && errno==EINTR)
830 {
831 if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP))
832 goto done;
833 if(ep->sh->winch && sh_isstate(SH_INTERACTIVE) && (sh_isoption(SH_VI) || sh_isoption(SH_EMACS)))
834 {
835 Edpos_t lastpos;
836 int n, rows, newsize;
837 /* move cursor to start of first line */
838 ed_putchar(ep,'\r');
839 ed_flush(ep);
840 astwinsize(2,&rows,&newsize);
841 n = (ep->e_plen+ep->e_cur)/++ep->e_winsz;
842 while(n--)
843 ed_putstring(ep,CURSOR_UP);
844 if(ep->e_multiline && newsize>ep->e_winsz && (lastpos.line=(ep->e_plen+ep->e_peol)/ep->e_winsz))
845 {
846 /* clear the current command line */
847 n = lastpos.line;
848 while(lastpos.line--)
849 {
850 ed_nputchar(ep,ep->e_winsz,' ');
851 ed_putchar(ep,'\n');
852 }
853 ed_nputchar(ep,ep->e_winsz,' ');
854 while(n--)
855 ed_putstring(ep,CURSOR_UP);
856 }
857 ep->sh->winch = 0;
858 ed_flush(ep);
859 sh_delay(.05);
860 astwinsize(2,&rows,&newsize);
861 ep->e_winsz = newsize-1;
862 if(ep->e_winsz < MINWINDOW)
863 ep->e_winsz = MINWINDOW;
864 if(!ep->e_multiline && ep->e_wsize < MAXLINE)
865 ep->e_wsize = ep->e_winsz-2;
866 ep->e_nocrnl=1;
867 if(*ep->e_vi_insert)
868 {
869 buff[0] = ESC;
870 buff[1] = cntl('L');
871 buff[2] = 'a';
872 return(3);
873 }
874 if(sh_isoption(SH_EMACS) || sh_isoption(SH_VI))
875 buff[0] = cntl('L');
876 return(1);
877 }
878 else
879 ep->sh->winch = 0;
880 /* an interrupt that should be ignored */
881 errno = 0;
882 if(!waitevent || (rv=(*waitevent)(fd,-1L,0))>=0)
883 rv = sfpkrd(fd,buff,size,delim,-1L,mode);
884 }
885 if(rv < 0)
886 {
887 #ifdef _hdr_utime
888 # define fixtime() if(isdevtty)utime(ep->e_tty,&utimes)
889 int isdevtty=0;
890 struct stat statb;
891 struct utimbuf utimes;
892 if(errno==0 && !ep->e_tty)
893 {
894 if((ep->e_tty=ttyname(fd)) && stat(ep->e_tty,&statb)>=0)
895 {
896 ep->e_tty_ino = statb.st_ino;
897 ep->e_tty_dev = statb.st_dev;
898 }
899 }
900 if(ep->e_tty_ino && fstat(fd,&statb)>=0 && statb.st_ino==ep->e_tty_ino && statb.st_dev==ep->e_tty_dev)
901 {
902 utimes.actime = statb.st_atime;
903 utimes.modtime = statb.st_mtime;
904 isdevtty=1;
905 }
906 #else
907 # define fixtime()
908 #endif /* _hdr_utime */
909 while(1)
910 {
911 rv = read(fd,buff,size);
912 if(rv>=0 || errno!=EINTR)
913 break;
914 if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP))
915 goto done;
916 /* an interrupt that should be ignored */
917 fixtime();
918 }
919 }
920 else if(rv>=0 && mode>0)
921 rv = read(fd,buff,rv>0?rv:1);
922 done:
923 shp->gd->waitevent = waitevent;
924 sh_offstate(SH_TTYWAIT);
925 return(rv);
926 }
927
928
929 /*
930 * put <string> of length <nbyte> onto lookahead stack
931 * if <type> is non-zero, the negation of the character is put
932 * onto the stack so that it can be checked for KEYTRAP
933 * putstack() returns 1 except when in the middle of a multi-byte char
934 */
935 static int putstack(Edit_t *ep,char string[], register int nbyte, int type)
936 {
937 register int c;
938 #if SHOPT_MULTIBYTE
939 char *endp, *p=string;
940 int size, offset = ep->e_lookahead + nbyte;
941 *(endp = &p[nbyte]) = 0;
942 endp = &p[nbyte];
943 do
944 {
945 c = (int)((*p) & STRIP);
946 if(c< 0x80 && c!='<')
947 {
948 if (type)
949 c = -c;
950 # ifndef CBREAK
951 if(c == '\0')
952 {
953 /*** user break key ***/
954 ep->e_lookahead = 0;
955 # if KSHELL
956 sh_fault(SIGINT);
957 siglongjmp(ep->e_env, UINTR);
958 # endif /* KSHELL */
959 }
960 # endif /* CBREAK */
961
962 }
963 else
964 {
965 again:
966 if((c=mbchar(p)) >=0)
967 {
968 p--; /* incremented below */
969 if(type)
970 c = -c;
971 }
972 #ifdef EILSEQ
973 else if(errno == EILSEQ)
974 errno = 0;
975 #endif
976 else if((endp-p) < mbmax())
977 {
978 if ((c=ed_read(ep,ep->e_fd,endp, 1,0)) == 1)
979 {
980 *++endp = 0;
981 goto again;
982 }
983 return(c);
984 }
985 else
986 {
987 ed_ringbell();
988 c = -(int)((*p) & STRIP);
989 offset += mbmax()-1;
990 }
991 }
992 ep->e_lbuf[--offset] = c;
993 p++;
994 }
995 while (p < endp);
996 /* shift lookahead buffer if necessary */
997 if(offset -= ep->e_lookahead)
998 {
999 for(size=offset;size < nbyte;size++)
1000 ep->e_lbuf[ep->e_lookahead+size-offset] = ep->e_lbuf[ep->e_lookahead+size];
1001 }
1002 ep->e_lookahead += nbyte-offset;
1003 #else
1004 while (nbyte > 0)
1005 {
1006 c = string[--nbyte] & STRIP;
1007 ep->e_lbuf[ep->e_lookahead++] = (type?-c:c);
1008 # ifndef CBREAK
1009 if( c == '\0' )
1010 {
1011 /*** user break key ***/
1012 ep->e_lookahead = 0;
1013 # if KSHELL
1014 sh_fault(SIGINT);
1015 siglongjmp(ep->e_env, UINTR);
1016 # endif /* KSHELL */
1017 }
1018 # endif /* CBREAK */
1019 }
1020 #endif /* SHOPT_MULTIBYTE */
1021 return(1);
1022 }
1023
1024 /*
1025 * routine to perform read from terminal for vi and emacs mode
1026 * <mode> can be one of the following:
1027 * -2 vi insert mode - key binding is in effect
1028 * -1 vi control mode - key binding is in effect
1029 * 0 normal command mode - key binding is in effect
1030 * 1 edit keys not mapped
1031 * 2 Next key is literal
1032 */
1033 int ed_getchar(register Edit_t *ep,int mode)
1034 {
1035 register int n, c;
1036 char readin[LOOKAHEAD+1];
1037 if(!ep->e_lookahead)
1038 {
1039 ed_flush(ep);
1040 ep->e_inmacro = 0;
1041 /* The while is necessary for reads of partial multbyte chars */
1042 *ep->e_vi_insert = (mode==-2);
1043 if((n=ed_read(ep,ep->e_fd,readin,-LOOKAHEAD,0)) > 0)
1044 n = putstack(ep,readin,n,1);
1045 *ep->e_vi_insert = 0;
1046 }
1047 if(ep->e_lookahead)
1048 {
1049 /* check for possible key mapping */
1050 if((c = ep->e_lbuf[--ep->e_lookahead]) < 0)
1051 {
1052 if(mode<=0 && -c == ep->e_intr)
1053 {
1054 sh_fault(SIGINT);
1055 siglongjmp(ep->e_env, UINTR);
1056 }
1057 if(mode<=0 && ep->sh->st.trap[SH_KEYTRAP])
1058 {
1059 ep->e_keytrap = 1;
1060 n=1;
1061 if((readin[0]= -c) == ESC)
1062 {
1063 while(1)
1064 {
1065 if(!ep->e_lookahead)
1066 {
1067 if((c=sfpkrd(ep->e_fd,readin+n,1,'\r',(mode?400L:-1L),0))>0)
1068 putstack(ep,readin+n,c,1);
1069 }
1070 if(!ep->e_lookahead)
1071 break;
1072 if((c=ep->e_lbuf[--ep->e_lookahead])>=0)
1073 {
1074 ep->e_lookahead++;
1075 break;
1076 }
1077 c = -c;
1078 readin[n++] = c;
1079 if(c>='0' && c<='9' && n>2)
1080 continue;
1081 if(n>2 || (c!= '[' && c!= 'O'))
1082 break;
1083 }
1084 }
1085 if(n=keytrap(ep,readin,n,LOOKAHEAD-n,mode))
1086 {
1087 putstack(ep,readin,n,0);
1088 c = ep->e_lbuf[--ep->e_lookahead];
1089 }
1090 else
1091 c = ed_getchar(ep,mode);
1092 ep->e_keytrap = 0;
1093 }
1094 else
1095 c = -c;
1096 }
1097 /*** map '\r' to '\n' ***/
1098 if(c == '\r' && mode!=2)
1099 c = '\n';
1100 if(ep->e_tabcount && !(c=='\t'||c==ESC || c=='\\' || c=='=' || c==cntl('L') || isdigit(c)))
1101 ep->e_tabcount = 0;
1102 }
1103 else
1104 siglongjmp(ep->e_env,(n==0?UEOF:UINTR));
1105 return(c);
1106 }
1107
1108 void ed_ungetchar(Edit_t *ep,register int c)
1109 {
1110 if (ep->e_lookahead < LOOKAHEAD)
1111 ep->e_lbuf[ep->e_lookahead++] = c;
1112 return;
1113 }
1114
1115 /*
1116 * put a character into the output buffer
1117 */
1118
1119 void ed_putchar(register Edit_t *ep,register int c)
1120 {
1121 char buf[8];
1122 register char *dp = ep->e_outptr;
1123 register int i,size=1;
1124 if(!dp)
1125 return;
1126 buf[0] = c;
1127 #if SHOPT_MULTIBYTE
1128 /* check for place holder */
1129 if(c == MARKER)
1130 return;
1131 if((size = mbconv(buf, (wchar_t)c)) > 1)
1132 {
1133 for (i = 0; i < (size-1); i++)
1134 *dp++ = buf[i];
1135 c = buf[i];
1136 }
1137 else
1138 {
1139 buf[0] = c;
1140 size = 1;
1141 }
1142 #endif /* SHOPT_MULTIBYTE */
1143 if (buf[0] == '_' && size==1)
1144 {
1145 *dp++ = ' ';
1146 *dp++ = '\b';
1147 }
1148 *dp++ = c;
1149 *dp = '\0';
1150 if(dp >= ep->e_outlast)
1151 ed_flush(ep);
1152 else
1153 ep->e_outptr = dp;
1154 }
1155
1156 /*
1157 * returns the line and column corresponding to offset <off> in the physical buffer
1158 * if <cur> is non-zero and <= <off>, then correspodning <curpos> will start the search
1159 */
1160 Edpos_t ed_curpos(Edit_t *ep,genchar *phys, int off, int cur, Edpos_t curpos)
1161 {
1162 register genchar *sp=phys;
1163 register int c=1, col=ep->e_plen;
1164 Edpos_t pos;
1165 #if SHOPT_MULTIBYTE
1166 char p[16];
1167 #endif /* SHOPT_MULTIBYTE */
1168 if(cur && off>=cur)
1169 {
1170 sp += cur;
1171 off -= cur;
1172 pos = curpos;
1173 col = pos.col;
1174 }
1175 else
1176 {
1177 pos.line = 0;
1178 while(col > ep->e_winsz)
1179 {
1180 pos.line++;
1181 col -= (ep->e_winsz+1);
1182 }
1183 }
1184 while(off-->0)
1185 {
1186 if(c)
1187 c = *sp++;
1188 #if SHOPT_MULTIBYTE
1189 if(c && (mbconv(p, (wchar_t)c))==1 && p[0]=='\n')
1190 #else
1191 if(c=='\n')
1192 #endif /* SHOPT_MULTIBYTE */
1193 col = 0;
1194 else
1195 col++;
1196 if(col > ep->e_winsz)
1197 col = 0;
1198 if(col==0)
1199 pos.line++;
1200 }
1201 pos.col = col;
1202 return(pos);
1203 }
1204
1205 int ed_setcursor(register Edit_t *ep,genchar *physical,register int old,register int new,int first)
1206 {
1207 static int oldline;
1208 register int delta;
1209 int clear = 0;
1210 Edpos_t newpos;
1211
1212 delta = new - old;
1213 if(first < 0)
1214 {
1215 first = 0;
1216 clear = 1;
1217 }
1218 if( delta == 0 && !clear)
1219 return(new);
1220 if(ep->e_multiline)
1221 {
1222 ep->e_curpos = ed_curpos(ep, physical, old,0,ep->e_curpos);
1223 if(clear && old>=ep->e_peol && (clear=ep->e_winsz-ep->e_curpos.col)>0)
1224 {
1225 ed_nputchar(ep,clear,' ');
1226 ed_nputchar(ep,clear,'\b');
1227 return(new);
1228 }
1229 newpos = ed_curpos(ep, physical, new,old,ep->e_curpos);
1230 if(ep->e_curpos.col==0 && ep->e_curpos.line>0 && oldline<ep->e_curpos.line && delta<0)
1231 ed_putstring(ep,"\r\n");
1232 oldline = newpos.line;
1233 if(ep->e_curpos.line > newpos.line)
1234 {
1235 int n,pline,plen=ep->e_plen;
1236 for(;ep->e_curpos.line > newpos.line; ep->e_curpos.line--)
1237 ed_putstring(ep,CURSOR_UP);
1238 pline = plen/(ep->e_winsz+1);
1239 if(newpos.line <= pline)
1240 plen -= pline*(ep->e_winsz+1);
1241 else
1242 plen = 0;
1243 if((n=plen- ep->e_curpos.col)>0)
1244 {
1245 ep->e_curpos.col += n;
1246 ed_putchar(ep,'\r');
1247 if(!ep->e_crlf && pline==0)
1248 ed_putstring(ep,ep->e_prompt);
1249 else
1250 {
1251 int m = ep->e_winsz+1-plen;
1252 ed_putchar(ep,'\n');
1253 n = plen;
1254 if(m < ed_genlen(physical))
1255 {
1256 while(physical[m] && n-->0)
1257 ed_putchar(ep,physical[m++]);
1258 }
1259 ed_nputchar(ep,n,' ');
1260 ed_putstring(ep,CURSOR_UP);
1261 }
1262 }
1263 }
1264 else if(ep->e_curpos.line < newpos.line)
1265 {
1266 ed_nputchar(ep, newpos.line-ep->e_curpos.line,'\n');
1267 ep->e_curpos.line = newpos.line;
1268 ed_putchar(ep,'\r');
1269 ep->e_curpos.col = 0;
1270 }
1271 delta = newpos.col - ep->e_curpos.col;
1272 old = new - delta;
1273 }
1274 else
1275 newpos.line=0;
1276 if(delta<0)
1277 {
1278 int bs= newpos.line && ep->e_plen>ep->e_winsz;
1279 /*** move to left ***/
1280 delta = -delta;
1281 /*** attempt to optimize cursor movement ***/
1282 if(!ep->e_crlf || bs || (2*delta <= ((old-first)+(newpos.line?0:ep->e_plen))) )
1283 {
1284 ed_nputchar(ep,delta,'\b');
1285 delta = 0;
1286 }
1287 else
1288 {
1289 if(newpos.line==0)
1290 ed_putstring(ep,ep->e_prompt);
1291 else
1292 {
1293 first = 1+(newpos.line*ep->e_winsz - ep->e_plen);
1294 ed_putchar(ep,'\r');
1295 }
1296 old = first;
1297 delta = new-first;
1298 }
1299 }
1300 while(delta-->0)
1301 ed_putchar(ep,physical[old++]);
1302 return(new);
1303 }
1304
1305 /*
1306 * copy virtual to physical and return the index for cursor in physical buffer
1307 */
1308 int ed_virt_to_phys(Edit_t *ep,genchar *virt,genchar *phys,int cur,int voff,int poff)
1309 {
1310 register genchar *sp = virt;
1311 register genchar *dp = phys;
1312 register int c;
1313 genchar *curp = sp + cur;
1314 genchar *dpmax = phys+MAXLINE;
1315 int d, r;
1316 sp += voff;
1317 dp += poff;
1318 for(r=poff;c= *sp;sp++)
1319 {
1320 if(curp == sp)
1321 r = dp - phys;
1322 #if SHOPT_MULTIBYTE
1323 d = mbwidth((wchar_t)c);
1324 if(d==1 && is_cntrl(c))
1325 d = -1;
1326 if(d>1)
1327 {
1328 /* multiple width character put in place holders */
1329 *dp++ = c;
1330 while(--d >0)
1331 *dp++ = MARKER;
1332 /* in vi mode the cursor is at the last character */
1333 if(dp>=dpmax)
1334 break;
1335 continue;
1336 }
1337 else
1338 #else
1339 d = (is_cntrl(c)?-1:1);
1340 #endif /* SHOPT_MULTIBYTE */
1341 if(d<0)
1342 {
1343 if(c=='\t')
1344 {
1345 c = dp-phys;
1346 if(sh_isoption(SH_VI))
1347 c += ep->e_plen;
1348 c = TABSIZE - c%TABSIZE;
1349 while(--c>0)
1350 *dp++ = ' ';
1351 c = ' ';
1352 }
1353 else
1354 {
1355 *dp++ = '^';
1356 c = printchar(c);
1357 }
1358 /* in vi mode the cursor is at the last character */
1359 if(curp == sp && sh_isoption(SH_VI))
1360 r = dp - phys;
1361 }
1362 *dp++ = c;
1363 if(dp>=dpmax)
1364 break;
1365 }
1366 *dp = 0;
1367 ep->e_peol = dp-phys;
1368 return(r);
1369 }
1370
1371 #if SHOPT_MULTIBYTE
1372 /*
1373 * convert external representation <src> to an array of genchars <dest>
1374 * <src> and <dest> can be the same
1375 * returns number of chars in dest
1376 */
1377
1378 int ed_internal(const char *src, genchar *dest)
1379 {
1380 register const unsigned char *cp = (unsigned char *)src;
1381 register int c;
1382 register wchar_t *dp = (wchar_t*)dest;
1383 if(dest == (genchar*)roundof(cp-(unsigned char*)0,sizeof(genchar)))
1384 {
1385 genchar buffer[MAXLINE];
1386 c = ed_internal(src,buffer);
1387 ed_gencpy((genchar*)dp,buffer);
1388 return(c);
1389 }
1390 while(*cp)
1391 *dp++ = mbchar(cp);
1392 *dp = 0;
1393 return(dp-(wchar_t*)dest);
1394 }
1395
1396 /*
1397 * convert internal representation <src> into character array <dest>.
1398 * The <src> and <dest> may be the same.
1399 * returns number of chars in dest.
1400 */
1401
1402 int ed_external(const genchar *src, char *dest)
1403 {
1404 register genchar wc;
1405 register int c,size;
1406 register char *dp = dest;
1407 char *dpmax = dp+sizeof(genchar)*MAXLINE-2;
1408 if((char*)src == dp)
1409 {
1410 char buffer[MAXLINE*sizeof(genchar)];
1411 c = ed_external(src,buffer);
1412
1413 #ifdef _lib_wcscpy
1414 wcscpy((wchar_t *)dest,(const wchar_t *)buffer);
1415 #else
1416 strcpy(dest,buffer);
1417 #endif
1418 return(c);
1419 }
1420 while((wc = *src++) && dp<dpmax)
1421 {
1422 if((size = mbconv(dp, wc)) < 0)
1423 {
1424 /* copy the character as is */
1425 size = 1;
1426 *dp = wc;
1427 }
1428 dp += size;
1429 }
1430 *dp = 0;
1431 return(dp-dest);
1432 }
1433
1434 /*
1435 * copy <sp> to <dp>
1436 */
1437
1438 void ed_gencpy(genchar *dp,const genchar *sp)
1439 {
1440 dp = (genchar*)roundof((char*)dp-(char*)0,sizeof(genchar));
1441 sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
1442 while(*dp++ = *sp++);
1443 }
1444
1445 /*
1446 * copy at most <n> items from <sp> to <dp>
1447 */
1448
1449 void ed_genncpy(register genchar *dp,register const genchar *sp, int n)
1450 {
1451 dp = (genchar*)roundof((char*)dp-(char*)0,sizeof(genchar));
1452 sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
1453 while(n-->0 && (*dp++ = *sp++));
1454 }
1455
1456 #endif /* SHOPT_MULTIBYTE */
1457 /*
1458 * find the string length of <str>
1459 */
1460
1461 int ed_genlen(register const genchar *str)
1462 {
1463 register const genchar *sp = str;
1464 sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
1465 while(*sp++);
1466 return(sp-str-1);
1467 }
1468 #endif /* SHOPT_ESH || SHOPT_VSH */
1469
1470 #ifdef future
1471 /*
1472 * returns 1 when <n> bytes starting at <a> and <b> are equal
1473 */
1474 static int compare(register const char *a,register const char *b,register int n)
1475 {
1476 while(n-->0)
1477 {
1478 if(*a++ != *b++)
1479 return(0);
1480 }
1481 return(1);
1482 }
1483 #endif
1484
1485 #if SHOPT_OLDTERMIO
1486
1487 # include <sys/termio.h>
1488
1489 #ifndef ECHOCTL
1490 # define ECHOCTL 0
1491 #endif /* !ECHOCTL */
1492 #define ott ep->e_ott
1493
1494 /*
1495 * For backward compatibility only
1496 * This version will use termios when possible, otherwise termio
1497 */
1498
1499 int tcgetattr(int fd, struct termios *tt)
1500 {
1501 register Edit_t *ep = (Edit_t*)(shgd->ed_context);
1502 register int r,i;
1503 ep->e_tcgeta = 0;
1504 ep->e_echoctl = (ECHOCTL!=0);
1505 if((r=ioctl(fd,TCGETS,tt))>=0 || errno!=EINVAL)
1506 return(r);
1507 if((r=ioctl(fd,TCGETA,&ott)) >= 0)
1508 {
1509 tt->c_lflag = ott.c_lflag;
1510 tt->c_oflag = ott.c_oflag;
1511 tt->c_iflag = ott.c_iflag;
1512 tt->c_cflag = ott.c_cflag;
1513 for(i=0; i<NCC; i++)
1514 tt->c_cc[i] = ott.c_cc[i];
1515 ep->e_tcgeta++;
1516 ep->e_echoctl = 0;
1517 }
1518 return(r);
1519 }
1520
1521 int tcsetattr(int fd,int mode,struct termios *tt)
1522 {
1523 register Edit_t *ep = (Edit_t*)(shgd->ed_context);
1524 register int r;
1525 if(ep->e_tcgeta)
1526 {
1527 register int i;
1528 ott.c_lflag = tt->c_lflag;
1529 ott.c_oflag = tt->c_oflag;
1530 ott.c_iflag = tt->c_iflag;
1531 ott.c_cflag = tt->c_cflag;
1532 for(i=0; i<NCC; i++)
1533 ott.c_cc[i] = tt->c_cc[i];
1534 if(tt->c_lflag&ECHOCTL)
1535 {
1536 ott.c_lflag &= ~(ECHOCTL|IEXTEN);
1537 ott.c_iflag &= ~(IGNCR|ICRNL);
1538 ott.c_iflag |= INLCR;
1539 ott.c_cc[VEOF]= ESC; /* ESC -> eof char */
1540 ott.c_cc[VEOL] = '\r'; /* CR -> eol char */
1541 ott.c_cc[VEOL2] = tt->c_cc[VEOF]; /* EOF -> eol char */
1542 }
1543 switch(mode)
1544 {
1545 case TCSANOW:
1546 mode = TCSETA;
1547 break;
1548 case TCSADRAIN:
1549 mode = TCSETAW;
1550 break;
1551 case TCSAFLUSH:
1552 mode = TCSETAF;
1553 }
1554 return(ioctl(fd,mode,&ott));
1555 }
1556 return(ioctl(fd,mode,tt));
1557 }
1558 #endif /* SHOPT_OLDTERMIO */
1559
1560 #if KSHELL
1561 /*
1562 * Execute keyboard trap on given buffer <inbuff> of given size <isize>
1563 * <mode> < 0 for vi insert mode
1564 */
1565 static int keytrap(Edit_t *ep,char *inbuff,register int insize, int bufsize, int mode)
1566 {
1567 register char *cp;
1568 int savexit;
1569 Shell_t *shp = ep->sh;
1570 #if SHOPT_MULTIBYTE
1571 char buff[MAXLINE];
1572 ed_external(ep->e_inbuf,cp=buff);
1573 #else
1574 cp = ep->e_inbuf;
1575 #endif /* SHOPT_MULTIBYTE */
1576 inbuff[insize] = 0;
1577 ep->e_col = ep->e_cur;
1578 if(mode== -2)
1579 {
1580 ep->e_col++;
1581 *ep->e_vi_insert = ESC;
1582 }
1583 else
1584 *ep->e_vi_insert = 0;
1585 nv_putval(ED_CHRNOD,inbuff,NV_NOFREE);
1586 nv_putval(ED_COLNOD,(char*)&ep->e_col,NV_NOFREE|NV_INTEGER);
1587 nv_putval(ED_TXTNOD,(char*)cp,NV_NOFREE);
1588 nv_putval(ED_MODENOD,ep->e_vi_insert,NV_NOFREE);
1589 savexit = shp->savexit;
1590 sh_trap(shp->st.trap[SH_KEYTRAP],0);
1591 shp->savexit = savexit;
1592 if((cp = nv_getval(ED_CHRNOD)) == inbuff)
1593 nv_unset(ED_CHRNOD);
1594 else if(bufsize>0)
1595 {
1596 strncpy(inbuff,cp,bufsize);
1597 inbuff[bufsize-1]='\0';
1598 insize = strlen(inbuff);
1599 }
1600 else
1601 insize = 0;
1602 nv_unset(ED_TXTNOD);
1603 return(insize);
1604 }
1605 #endif /* KSHELL */
1606
1607 #if SHOPT_EDPREDICT
1608 static int ed_sortdata(const char *s1, const char *s2)
1609 {
1610 Histmatch_t *m1 = (Histmatch_t*)s1;
1611 Histmatch_t *m2 = (Histmatch_t*)s2;
1612 return(strcmp(m1->data,m2->data));
1613 }
1614
1615 static int ed_sortindex(const char *s1, const char *s2)
1616 {
1617 Histmatch_t *m1 = (Histmatch_t*)s1;
1618 Histmatch_t *m2 = (Histmatch_t*)s2;
1619 return(m2->index-m1->index);
1620 }
1621
1622 static int ed_histlencopy(const char *cp, char *dp)
1623 {
1624 int c,n=1,col=1;
1625 const char *oldcp=cp;
1626 for(n=0;c = mbchar(cp);oldcp=cp,col++)
1627 {
1628 if(c=='\n' && *cp)
1629 {
1630 n += 2;
1631 if(dp)
1632 {
1633 *dp++ = '^';
1634 *dp++ = 'J';
1635 col +=2;
1636 }
1637 }
1638 else if(c=='\t')
1639 {
1640 n++;
1641 if(dp)
1642 *dp++ = ' ';
1643 }
1644 else
1645 {
1646 n += cp-oldcp;
1647 if(dp)
1648 {
1649 while(oldcp < cp)
1650 *dp++ = *oldcp++;
1651 }
1652 }
1653
1654 }
1655 return(n);
1656 }
1657
1658 int ed_histgen(Edit_t *ep,const char *pattern)
1659 {
1660 Histmatch_t *mp,*mplast=0;
1661 History_t *hp;
1662 off_t offset;
1663 int ac=0,l,n,index1,index2;
1664 size_t m;
1665 char *cp, **argv=0, **av, **ar;
1666 static int maxmatch;
1667 if(!(hp=ep->sh->gd->hist_ptr) && (!nv_getval(HISTFILE) || !sh_histinit(ep->sh)))
1668 return(0);
1669 if(ep->e_cur <=2)
1670 maxmatch = 0;
1671 else if(maxmatch && ep->e_cur > maxmatch)
1672 {
1673 ep->hlist = 0;
1674 ep->hfirst = 0;
1675 return(0);
1676 }
1677 hp = ep->sh->gd->hist_ptr;
1678 if(*pattern=='#' && *++pattern=='#')
1679 return(0);
1680 cp = stakalloc(m=strlen(pattern)+6);
1681 sfsprintf(cp,m,"@(%s)*%c",pattern,0);
1682 if(ep->hlist)
1683 {
1684 m = strlen(ep->hpat)-4;
1685 if(memcmp(pattern,ep->hpat+2,m)==0)
1686 {
1687 n = strcmp(cp,ep->hpat)==0;
1688 for(argv=av=(char**)ep->hlist,mp=ep->hfirst; mp;mp= mp->next)
1689 {
1690 if(n || strmatch(mp->data,cp))
1691 *av++ = (char*)mp;
1692 }
1693 *av = 0;
1694 ep->hmax = av-argv;
1695 if(ep->hmax==0)
1696 maxmatch = ep->e_cur;
1697 return(ep->hmax=av-argv);
1698 }
1699 stakset(ep->e_stkptr,ep->e_stkoff);
1700 }
1701 if((m=strlen(cp)) >= sizeof(ep->hpat))
1702 m = sizeof(ep->hpat)-1;
1703 memcpy(ep->hpat,cp,m);
1704 ep->hpat[m] = 0;
1705 pattern = cp;
1706 index1 = (int)hp->histind;
1707 for(index2=index1-hp->histsize; index1>index2; index1--)
1708 {
1709 offset = hist_tell(hp,index1);
1710 sfseek(hp->histfp,offset,SEEK_SET);
1711 if(!(cp = sfgetr(hp->histfp,0,0)))
1712 continue;
1713 if(*cp=='#')
1714 continue;
1715 if(strmatch(cp,pattern))
1716 {
1717 l = ed_histlencopy(cp,(char*)0);
1718 mp = (Histmatch_t*)stakalloc(sizeof(Histmatch_t)+l);
1719 mp->next = mplast;
1720 mplast = mp;
1721 mp->len = l;
1722 ed_histlencopy(cp,mp->data);
1723 mp->count = 1;
1724 mp->data[l] = 0;
1725 mp->index = index1;
1726 ac++;
1727 }
1728 }
1729 if(ac>0)
1730 {
1731 l = ac;
1732 argv = av = (char**)stakalloc((ac+1)*sizeof(char*));
1733 for(mplast=0; l>=0 && (*av= (char*)mp); mplast=mp,mp=mp->next,av++)
1734 {
1735 l--;
1736 }
1737 *av = 0;
1738 strsort(argv,ac,ed_sortdata);
1739 mplast = (Histmatch_t*)argv[0];
1740 for(ar= av= &argv[1]; mp=(Histmatch_t*)*av; av++)
1741 {
1742 if(strcmp(mp->data,mplast->data)==0)
1743 {
1744 mplast->count++;
1745 if(mp->index> mplast->index)
1746 mplast->index = mp->index;
1747 continue;
1748 }
1749 *ar++ = (char*)(mplast=mp);
1750 }
1751 *ar = 0;
1752 mplast->next = 0;
1753 ac = ar-argv;
1754 strsort(argv,ac,ed_sortindex);
1755 mplast = (Histmatch_t*)argv[0];
1756 for(av= &argv[1]; mp=(Histmatch_t*)*av; av++, mplast=mp)
1757 mplast->next = mp;
1758 mplast->next = 0;
1759 }
1760 ep->hlist = (Histmatch_t**)argv;
1761 ep->hfirst = ep->hlist?ep->hlist[0]:0;
1762 return(ep->hmax=ac);
1763 }
1764
1765 void ed_histlist(Edit_t *ep,int n)
1766 {
1767 Histmatch_t *mp,**mpp = ep->hlist+ep->hoff;
1768 int i,last=0,save[2];
1769 if(n)
1770 {
1771 /* don't bother updating the screen if there is typeahead */
1772 if(!ep->e_lookahead && sfpkrd(ep->e_fd,save,1,'\r',200L,-1)>0)
1773 ed_ungetchar(ep,save[0]);
1774 if(ep->e_lookahead)
1775 return;
1776 ed_putchar(ep,'\n');
1777 ed_putchar(ep,'\r');
1778 }
1779 else
1780 {
1781 stakset(ep->e_stkptr,ep->e_stkoff);
1782 ep->hlist = 0;
1783 ep->nhlist = 0;
1784 }
1785 ed_putstring(ep,KILL_LINE);
1786 if(n)
1787 {
1788 for(i=1; (mp= *mpp) && i <= 16 ; i++,mpp++)
1789 {
1790 last = 0;
1791 if(mp->len >= ep->e_winsz-4)
1792 {
1793 last = ep->e_winsz-4;
1794 save[0] = mp->data[last-1];
1795 save[1] = mp->data[last];
1796 mp->data[last-1] = '\n';
1797 mp->data[last] = 0;
1798 }
1799 ed_putchar(ep,i<10?' ':'1');
1800 ed_putchar(ep,i<10?'0'+i:'0'+i-10);
1801 ed_putchar(ep,')');
1802 ed_putchar(ep,' ');
1803 ed_putstring(ep,mp->data);
1804 if(last)
1805 {
1806 mp->data[last-1] = save[0];
1807 mp->data[last] = save[1];
1808 }
1809 ep->nhlist = i;
1810 }
1811 last = i-1;
1812 while(i-->0)
1813 ed_putstring(ep,CURSOR_UP);
1814 }
1815 ed_flush(ep);
1816 }
1817 #endif /* SHOPT_EDPREDICT */
1818
1819 void *ed_open(Shell_t *shp)
1820 {
1821 Edit_t *ed = newof(0,Edit_t,1,0);
1822 ed->sh = shp;
1823 strcpy(ed->e_macro,"_??");
1824 return((void*)ed);
1825 }
1826
1827 #undef ioctl
1828 int sh_ioctl(int fd, int cmd, void* val, int sz)
1829 {
1830 int r,err=errno;
1831 if(sz == sizeof(void*))
1832 {
1833 while((r=ioctl(fd,cmd,val)) < 0 && errno==EINTR)
1834 errno = err;
1835 }
1836 else
1837 {
1838 Sflong_t l = (Sflong_t)(uintptr_t)val;
1839 if(sizeof(val)==sizeof(long))
1840 {
1841 while((r=ioctl(fd,cmd,(unsigned long)l)) < 0 && errno==EINTR)
1842 errno = err;
1843 }
1844 else if(sizeof(int)!=sizeof(long))
1845 {
1846 while((r=ioctl(fd,cmd,(unsigned int)l)) < 0 && errno==EINTR)
1847 errno = err;
1848 }
1849 }
1850 return(r);
1851 }
1852
1853 #ifdef _lib_tcgetattr
1854 # undef tcgetattr
1855 int
1856 sh_tcgetattr(int fd, struct termios *tty)
1857 {
1858 int r,err = errno;
1859 while((r=tcgetattr(fd,tty)) < 0 && errno==EINTR)
1860 errno = err;
1861 return(r);
1862 }
1863
1864 # undef tcsetattr
1865 int
1866 sh_tcsetattr(int fd, int cmd, struct termios *tty)
1867 {
1868 int r,err = errno;
1869 while((r=tcsetattr(fd,cmd,tty)) < 0 && errno==EINTR)
1870 errno = err;
1871 return(r);
1872 }
1873 #endif
1874