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 *pp++ = c;
656 for(n=1; c = *last++; n++)
657 {
658 if(pp < ppmax)
659 *pp++ = c;
660 if(c=='\a' || c==ESC || c=='\r')
661 break;
662 if(skip || (c>='0' && c<='9'))
663 {
664 skip = 0;
665 continue;
666 }
667 if(n>1 && c==';')
668 skip = 1;
669 else if(n>2 || (c!= '[' && c!= ']'))
670 break;
671 }
672 if(c==0 || c==ESC || c=='\r')
673 last--;
674 qlen += (n+1);
675 break;
676 }
677 case '\b':
678 if(pp>ep->e_prompt+1)
679 pp--;
680 break;
681 case '\r':
682 if(pp == (ep->e_prompt+2)) /* quote char */
683 myquote = *(pp-1);
684 /*FALLTHROUGH*/
685
686 case '\n':
687 /* start again */
688 ep->e_crlf = 1;
689 qlen = 1;
690 inquote = 0;
691 pp = ep->e_prompt+1;
692 break;
693
694 case '\t':
695 /* expand tabs */
696 while((pp-ep->e_prompt)%TABSIZE)
697 {
698 if(pp >= ppmax)
699 break;
700 *pp++ = ' ';
701 }
702 break;
703
704 case '\a':
705 /* cut out bells */
706 break;
707
708 default:
709 if(c==myquote)
710 {
711 qlen += inquote;
712 inquote ^= 1;
713 }
714 if(pp < ppmax)
715 {
716 if(inquote)
717 qlen++;
718 else if(!is_print(c))
719 ep->e_crlf = 0;
720 if((qwid = last - prev) > 1)
721 qlen += qwid - mbwidth(c);
722 while(prev < last && pp < ppmax)
723 *pp++ = *prev++;
724 }
725 break;
726 }
727 }
728 if(pp-ep->e_prompt > qlen)
729 ep->e_plen = pp - ep->e_prompt - qlen;
730 *pp = 0;
731 if(!ep->e_multiline && (ep->e_wsize -= ep->e_plen) < 7)
732 {
733 register int shift = 7-ep->e_wsize;
734 ep->e_wsize = 7;
735 pp = ep->e_prompt+1;
736 strcpy(pp,pp+shift);
737 ep->e_plen -= shift;
738 last[-ep->e_plen-2] = '\r';
739 }
740 sfsync(sfstderr);
741 if(fd == sffileno(sfstderr))
742 {
743 /* can't use output buffer when reading from stderr */
744 static char *buff;
745 if(!buff)
746 buff = (char*)malloc(MAXLINE);
747 ep->e_outbase = ep->e_outptr = buff;
748 ep->e_outlast = ep->e_outptr + MAXLINE;
749 return;
750 }
751 qlen = sfset(sfstderr,SF_READ,0);
752 /* make sure SF_READ not on */
753 ep->e_outbase = ep->e_outptr = (char*)sfreserve(sfstderr,SF_UNBOUND,SF_LOCKR);
754 ep->e_outlast = ep->e_outptr + sfvalue(sfstderr);
755 if(qlen)
756 sfset(sfstderr,SF_READ,1);
757 sfwrite(sfstderr,ep->e_outptr,0);
758 ep->e_eol = reedit;
759 if(ep->e_multiline)
760 {
761 #ifdef _cmd_tput
762 char *term;
763 if(!ep->e_term)
764 ep->e_term = nv_search("TERM",shp->var_tree,0);
765 if(ep->e_term && (term=nv_getval(ep->e_term)) && strlen(term)<sizeof(ep->e_termname) && strcmp(term,ep->e_termname))
766 {
767 sh_trap(".sh.subscript=$(tput cuu1 2>/dev/null)",0);
768 if(pp=nv_getval(SH_SUBSCRNOD))
769 strncpy(CURSOR_UP,pp,sizeof(CURSOR_UP)-1);
770 nv_unset(SH_SUBSCRNOD);
771 strcpy(ep->e_termname,term);
772 }
773 #endif
774 ep->e_wsize = MAXLINE - (ep->e_plen+1);
775 }
776 if(ep->e_default && (pp = nv_getval(ep->e_default)))
777 {
778 n = strlen(pp);
779 if(n > LOOKAHEAD)
780 n = LOOKAHEAD;
781 ep->e_lookahead = n;
782 while(n-- > 0)
783 ep->e_lbuf[n] = *pp++;
784 ep->e_default = 0;
785 }
786 }
787
ed_putstring(register Edit_t * ep,const char * str)788 static void ed_putstring(register Edit_t *ep, const char *str)
789 {
790 register int c;
791 while(c = *str++)
792 ed_putchar(ep,c);
793 }
794
ed_nputchar(register Edit_t * ep,int n,int c)795 static void ed_nputchar(register Edit_t *ep, int n, int c)
796 {
797 while(n-->0)
798 ed_putchar(ep,c);
799 }
800
801 /*
802 * Do read, restart on interrupt unless SH_SIGSET or SH_SIGTRAP is set
803 * Use sfpkrd() to poll() or select() to wait for input if possible
804 * Unfortunately, systems that get interrupted from slow reads update
805 * this access time for for the terminal (in violation of POSIX).
806 * The fixtime() macro, resets the time to the time at entry in
807 * this case. This is not necessary for systems that can handle
808 * sfpkrd() correctly (i,e., those that support poll() or select()
809 */
ed_read(void * context,int fd,char * buff,int size,int reedit)810 int ed_read(void *context, int fd, char *buff, int size, int reedit)
811 {
812 register Edit_t *ep = (Edit_t*)context;
813 register int rv= -1;
814 register int delim = ((ep->e_raw&RAWMODE)?nttyparm.c_cc[VEOL]:'\n');
815 Shell_t *shp = ep->sh;
816 int mode = -1;
817 int (*waitevent)(int,long,int) = shp->gd->waitevent;
818 if(ep->e_raw==ALTMODE)
819 mode = 1;
820 if(size < 0)
821 {
822 mode = 1;
823 size = -size;
824 }
825 sh_onstate(SH_TTYWAIT);
826 errno = EINTR;
827 shp->gd->waitevent = 0;
828 while(rv<0 && errno==EINTR)
829 {
830 if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP))
831 goto done;
832 if(ep->sh->winch && sh_isstate(SH_INTERACTIVE) && (sh_isoption(SH_VI) || sh_isoption(SH_EMACS)))
833 {
834 Edpos_t lastpos;
835 int n, rows, newsize;
836 /* move cursor to start of first line */
837 ed_putchar(ep,'\r');
838 ed_flush(ep);
839 astwinsize(2,&rows,&newsize);
840 n = (ep->e_plen+ep->e_cur)/++ep->e_winsz;
841 while(n--)
842 ed_putstring(ep,CURSOR_UP);
843 if(ep->e_multiline && newsize>ep->e_winsz && (lastpos.line=(ep->e_plen+ep->e_peol)/ep->e_winsz))
844 {
845 /* clear the current command line */
846 n = lastpos.line;
847 while(lastpos.line--)
848 {
849 ed_nputchar(ep,ep->e_winsz,' ');
850 ed_putchar(ep,'\n');
851 }
852 ed_nputchar(ep,ep->e_winsz,' ');
853 while(n--)
854 ed_putstring(ep,CURSOR_UP);
855 }
856 ep->sh->winch = 0;
857 ed_flush(ep);
858 sh_delay(.05);
859 astwinsize(2,&rows,&newsize);
860 ep->e_winsz = newsize-1;
861 if(ep->e_winsz < MINWINDOW)
862 ep->e_winsz = MINWINDOW;
863 if(!ep->e_multiline && ep->e_wsize < MAXLINE)
864 ep->e_wsize = ep->e_winsz-2;
865 ep->e_nocrnl=1;
866 if(*ep->e_vi_insert)
867 {
868 buff[0] = ESC;
869 buff[1] = cntl('L');
870 buff[2] = 'a';
871 return(3);
872 }
873 if(sh_isoption(SH_EMACS) || sh_isoption(SH_VI))
874 buff[0] = cntl('L');
875 return(1);
876 }
877 else
878 ep->sh->winch = 0;
879 /* an interrupt that should be ignored */
880 errno = 0;
881 if(!waitevent || (rv=(*waitevent)(fd,-1L,0))>=0)
882 rv = sfpkrd(fd,buff,size,delim,-1L,mode);
883 }
884 if(rv < 0)
885 {
886 #ifdef _hdr_utime
887 # define fixtime() if(isdevtty)utime(ep->e_tty,&utimes)
888 int isdevtty=0;
889 struct stat statb;
890 struct utimbuf utimes;
891 if(errno==0 && !ep->e_tty)
892 {
893 if((ep->e_tty=ttyname(fd)) && stat(ep->e_tty,&statb)>=0)
894 {
895 ep->e_tty_ino = statb.st_ino;
896 ep->e_tty_dev = statb.st_dev;
897 }
898 }
899 if(ep->e_tty_ino && fstat(fd,&statb)>=0 && statb.st_ino==ep->e_tty_ino && statb.st_dev==ep->e_tty_dev)
900 {
901 utimes.actime = statb.st_atime;
902 utimes.modtime = statb.st_mtime;
903 isdevtty=1;
904 }
905 #else
906 # define fixtime()
907 #endif /* _hdr_utime */
908 while(1)
909 {
910 rv = read(fd,buff,size);
911 if(rv>=0 || errno!=EINTR)
912 break;
913 if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP))
914 goto done;
915 /* an interrupt that should be ignored */
916 fixtime();
917 }
918 }
919 else if(rv>=0 && mode>0)
920 rv = read(fd,buff,rv>0?rv:1);
921 done:
922 shp->gd->waitevent = waitevent;
923 sh_offstate(SH_TTYWAIT);
924 return(rv);
925 }
926
927
928 /*
929 * put <string> of length <nbyte> onto lookahead stack
930 * if <type> is non-zero, the negation of the character is put
931 * onto the stack so that it can be checked for KEYTRAP
932 * putstack() returns 1 except when in the middle of a multi-byte char
933 */
934 static int putstack(Edit_t *ep,char string[], register int nbyte, int type)
935 {
936 register int c;
937 #if SHOPT_MULTIBYTE
938 char *endp, *p=string;
939 int size, offset = ep->e_lookahead + nbyte;
940 *(endp = &p[nbyte]) = 0;
941 endp = &p[nbyte];
942 do
943 {
944 c = (int)((*p) & STRIP);
945 if(c< 0x80 && c!='<')
946 {
947 if (type)
948 c = -c;
949 # ifndef CBREAK
950 if(c == '\0')
951 {
952 /*** user break key ***/
953 ep->e_lookahead = 0;
954 # if KSHELL
955 sh_fault(SIGINT);
956 siglongjmp(ep->e_env, UINTR);
957 # endif /* KSHELL */
958 }
959 # endif /* CBREAK */
960
961 }
962 else
963 {
964 again:
965 if((c=mbchar(p)) >=0)
966 {
967 p--; /* incremented below */
968 if(type)
969 c = -c;
970 }
971 #ifdef EILSEQ
972 else if(errno == EILSEQ)
973 errno = 0;
974 #endif
975 else if((endp-p) < mbmax())
976 {
977 if ((c=ed_read(ep,ep->e_fd,endp, 1,0)) == 1)
978 {
979 *++endp = 0;
980 goto again;
981 }
982 return(c);
983 }
984 else
985 {
986 ed_ringbell();
987 c = -(int)((*p) & STRIP);
988 offset += mbmax()-1;
989 }
990 }
991 ep->e_lbuf[--offset] = c;
992 p++;
993 }
994 while (p < endp);
995 /* shift lookahead buffer if necessary */
996 if(offset -= ep->e_lookahead)
997 {
998 for(size=offset;size < nbyte;size++)
999 ep->e_lbuf[ep->e_lookahead+size-offset] = ep->e_lbuf[ep->e_lookahead+size];
1000 }
1001 ep->e_lookahead += nbyte-offset;
1002 #else
1003 while (nbyte > 0)
1004 {
1005 c = string[--nbyte] & STRIP;
1006 ep->e_lbuf[ep->e_lookahead++] = (type?-c:c);
1007 # ifndef CBREAK
1008 if( c == '\0' )
1009 {
1010 /*** user break key ***/
1011 ep->e_lookahead = 0;
1012 # if KSHELL
1013 sh_fault(SIGINT);
1014 siglongjmp(ep->e_env, UINTR);
1015 # endif /* KSHELL */
1016 }
1017 # endif /* CBREAK */
1018 }
1019 #endif /* SHOPT_MULTIBYTE */
1020 return(1);
1021 }
1022
1023 /*
1024 * routine to perform read from terminal for vi and emacs mode
1025 * <mode> can be one of the following:
1026 * -2 vi insert mode - key binding is in effect
1027 * -1 vi control mode - key binding is in effect
1028 * 0 normal command mode - key binding is in effect
1029 * 1 edit keys not mapped
1030 * 2 Next key is literal
1031 */
1032 int ed_getchar(register Edit_t *ep,int mode)
1033 {
1034 register int n, c;
1035 char readin[LOOKAHEAD+1];
1036 if(!ep->e_lookahead)
1037 {
1038 ed_flush(ep);
1039 ep->e_inmacro = 0;
1040 /* The while is necessary for reads of partial multbyte chars */
1041 *ep->e_vi_insert = (mode==-2);
1042 if((n=ed_read(ep,ep->e_fd,readin,-LOOKAHEAD,0)) > 0)
1043 n = putstack(ep,readin,n,1);
1044 *ep->e_vi_insert = 0;
1045 }
1046 if(ep->e_lookahead)
1047 {
1048 /* check for possible key mapping */
1049 if((c = ep->e_lbuf[--ep->e_lookahead]) < 0)
1050 {
1051 if(mode<=0 && -c == ep->e_intr)
1052 {
1053 sh_fault(SIGINT);
1054 siglongjmp(ep->e_env, UINTR);
1055 }
1056 if(mode<=0 && ep->sh->st.trap[SH_KEYTRAP])
1057 {
1058 ep->e_keytrap = 1;
1059 n=1;
1060 if((readin[0]= -c) == ESC)
1061 {
1062 while(1)
1063 {
1064 if(!ep->e_lookahead)
1065 {
1066 if((c=sfpkrd(ep->e_fd,readin+n,1,'\r',(mode?400L:-1L),0))>0)
1067 putstack(ep,readin+n,c,1);
1068 }
1069 if(!ep->e_lookahead)
1070 break;
1071 if((c=ep->e_lbuf[--ep->e_lookahead])>=0)
1072 {
1073 ep->e_lookahead++;
1074 break;
1075 }
1076 c = -c;
1077 readin[n++] = c;
1078 if(c>='0' && c<='9' && n>2)
1079 continue;
1080 if(n>2 || (c!= '[' && c!= 'O'))
1081 break;
1082 }
1083 }
1084 if(n=keytrap(ep,readin,n,LOOKAHEAD-n,mode))
1085 {
1086 putstack(ep,readin,n,0);
1087 c = ep->e_lbuf[--ep->e_lookahead];
1088 }
1089 else
1090 c = ed_getchar(ep,mode);
1091 ep->e_keytrap = 0;
1092 }
1093 else
1094 c = -c;
1095 }
1096 /*** map '\r' to '\n' ***/
1097 if(c == '\r' && mode!=2)
1098 c = '\n';
1099 if(ep->e_tabcount && !(c=='\t'||c==ESC || c=='\\' || c=='=' || c==cntl('L') || isdigit(c)))
1100 ep->e_tabcount = 0;
1101 }
1102 else
1103 siglongjmp(ep->e_env,(n==0?UEOF:UINTR));
1104 return(c);
1105 }
1106
1107 void ed_ungetchar(Edit_t *ep,register int c)
1108 {
1109 if (ep->e_lookahead < LOOKAHEAD)
1110 ep->e_lbuf[ep->e_lookahead++] = c;
1111 return;
1112 }
1113
1114 /*
1115 * put a character into the output buffer
1116 */
1117
1118 void ed_putchar(register Edit_t *ep,register int c)
1119 {
1120 char buf[8];
1121 register char *dp = ep->e_outptr;
1122 register int i,size=1;
1123 if(!dp)
1124 return;
1125 buf[0] = c;
1126 #if SHOPT_MULTIBYTE
1127 /* check for place holder */
1128 if(c == MARKER)
1129 return;
1130 if((size = mbconv(buf, (wchar_t)c)) > 1)
1131 {
1132 for (i = 0; i < (size-1); i++)
1133 *dp++ = buf[i];
1134 c = buf[i];
1135 }
1136 else
1137 {
1138 buf[0] = c;
1139 size = 1;
1140 }
1141 #endif /* SHOPT_MULTIBYTE */
1142 if (buf[0] == '_' && size==1)
1143 {
1144 *dp++ = ' ';
1145 *dp++ = '\b';
1146 }
1147 *dp++ = c;
1148 *dp = '\0';
1149 if(dp >= ep->e_outlast)
1150 ed_flush(ep);
1151 else
1152 ep->e_outptr = dp;
1153 }
1154
1155 /*
1156 * returns the line and column corresponding to offset <off> in the physical buffer
1157 * if <cur> is non-zero and <= <off>, then correspodning <curpos> will start the search
1158 */
1159 Edpos_t ed_curpos(Edit_t *ep,genchar *phys, int off, int cur, Edpos_t curpos)
1160 {
1161 register genchar *sp=phys;
1162 register int c=1, col=ep->e_plen;
1163 Edpos_t pos;
1164 #if SHOPT_MULTIBYTE
1165 char p[16];
1166 #endif /* SHOPT_MULTIBYTE */
1167 if(cur && off>=cur)
1168 {
1169 sp += cur;
1170 off -= cur;
1171 pos = curpos;
1172 col = pos.col;
1173 }
1174 else
1175 {
1176 pos.line = 0;
1177 while(col > ep->e_winsz)
1178 {
1179 pos.line++;
1180 col -= (ep->e_winsz+1);
1181 }
1182 }
1183 while(off-->0)
1184 {
1185 if(c)
1186 c = *sp++;
1187 #if SHOPT_MULTIBYTE
1188 if(c && (mbconv(p, (wchar_t)c))==1 && p[0]=='\n')
1189 #else
1190 if(c=='\n')
1191 #endif /* SHOPT_MULTIBYTE */
1192 col = 0;
1193 else
1194 col++;
1195 if(col > ep->e_winsz)
1196 col = 0;
1197 if(col==0)
1198 pos.line++;
1199 }
1200 pos.col = col;
1201 return(pos);
1202 }
1203
1204 int ed_setcursor(register Edit_t *ep,genchar *physical,register int old,register int new,int first)
1205 {
1206 static int oldline;
1207 register int delta;
1208 int clear = 0;
1209 Edpos_t newpos;
1210
1211 delta = new - old;
1212 if(first < 0)
1213 {
1214 first = 0;
1215 clear = 1;
1216 }
1217 if( delta == 0 && !clear)
1218 return(new);
1219 if(ep->e_multiline)
1220 {
1221 ep->e_curpos = ed_curpos(ep, physical, old,0,ep->e_curpos);
1222 if(clear && old>=ep->e_peol && (clear=ep->e_winsz-ep->e_curpos.col)>0)
1223 {
1224 ed_nputchar(ep,clear,' ');
1225 ed_nputchar(ep,clear,'\b');
1226 return(new);
1227 }
1228 newpos = ed_curpos(ep, physical, new,old,ep->e_curpos);
1229 if(ep->e_curpos.col==0 && ep->e_curpos.line>0 && oldline<ep->e_curpos.line && delta<0)
1230 ed_putstring(ep,"\r\n");
1231 oldline = newpos.line;
1232 if(ep->e_curpos.line > newpos.line)
1233 {
1234 int n,pline,plen=ep->e_plen;
1235 for(;ep->e_curpos.line > newpos.line; ep->e_curpos.line--)
1236 ed_putstring(ep,CURSOR_UP);
1237 pline = plen/(ep->e_winsz+1);
1238 if(newpos.line <= pline)
1239 plen -= pline*(ep->e_winsz+1);
1240 else
1241 plen = 0;
1242 if((n=plen- ep->e_curpos.col)>0)
1243 {
1244 ep->e_curpos.col += n;
1245 ed_putchar(ep,'\r');
1246 if(!ep->e_crlf && pline==0)
1247 ed_putstring(ep,ep->e_prompt);
1248 else
1249 {
1250 int m = ep->e_winsz+1-plen;
1251 ed_putchar(ep,'\n');
1252 n = plen;
1253 if(m < ed_genlen(physical))
1254 {
1255 while(physical[m] && n-->0)
1256 ed_putchar(ep,physical[m++]);
1257 }
1258 ed_nputchar(ep,n,' ');
1259 ed_putstring(ep,CURSOR_UP);
1260 }
1261 }
1262 }
1263 else if(ep->e_curpos.line < newpos.line)
1264 {
1265 ed_nputchar(ep, newpos.line-ep->e_curpos.line,'\n');
1266 ep->e_curpos.line = newpos.line;
1267 ed_putchar(ep,'\r');
1268 ep->e_curpos.col = 0;
1269 }
1270 delta = newpos.col - ep->e_curpos.col;
1271 old = new - delta;
1272 }
1273 else
1274 newpos.line=0;
1275 if(delta<0)
1276 {
1277 int bs= newpos.line && ep->e_plen>ep->e_winsz;
1278 /*** move to left ***/
1279 delta = -delta;
1280 /*** attempt to optimize cursor movement ***/
1281 if(!ep->e_crlf || bs || (2*delta <= ((old-first)+(newpos.line?0:ep->e_plen))) )
1282 {
1283 ed_nputchar(ep,delta,'\b');
1284 delta = 0;
1285 }
1286 else
1287 {
1288 if(newpos.line==0)
1289 ed_putstring(ep,ep->e_prompt);
1290 else
1291 {
1292 first = 1+(newpos.line*ep->e_winsz - ep->e_plen);
1293 ed_putchar(ep,'\r');
1294 }
1295 old = first;
1296 delta = new-first;
1297 }
1298 }
1299 while(delta-->0)
1300 ed_putchar(ep,physical[old++]);
1301 return(new);
1302 }
1303
1304 /*
1305 * copy virtual to physical and return the index for cursor in physical buffer
1306 */
1307 int ed_virt_to_phys(Edit_t *ep,genchar *virt,genchar *phys,int cur,int voff,int poff)
1308 {
1309 register genchar *sp = virt;
1310 register genchar *dp = phys;
1311 register int c;
1312 genchar *curp = sp + cur;
1313 genchar *dpmax = phys+MAXLINE;
1314 int d, r;
1315 sp += voff;
1316 dp += poff;
1317 for(r=poff;c= *sp;sp++)
1318 {
1319 if(curp == sp)
1320 r = dp - phys;
1321 #if SHOPT_MULTIBYTE
1322 d = mbwidth((wchar_t)c);
1323 if(d==1 && is_cntrl(c))
1324 d = -1;
1325 if(d>1)
1326 {
1327 /* multiple width character put in place holders */
1328 *dp++ = c;
1329 while(--d >0)
1330 *dp++ = MARKER;
1331 /* in vi mode the cursor is at the last character */
1332 if(dp>=dpmax)
1333 break;
1334 continue;
1335 }
1336 else
1337 #else
1338 d = (is_cntrl(c)?-1:1);
1339 #endif /* SHOPT_MULTIBYTE */
1340 if(d<0)
1341 {
1342 if(c=='\t')
1343 {
1344 c = dp-phys;
1345 if(sh_isoption(SH_VI))
1346 c += ep->e_plen;
1347 c = TABSIZE - c%TABSIZE;
1348 while(--c>0)
1349 *dp++ = ' ';
1350 c = ' ';
1351 }
1352 else
1353 {
1354 *dp++ = '^';
1355 c = printchar(c);
1356 }
1357 /* in vi mode the cursor is at the last character */
1358 if(curp == sp && sh_isoption(SH_VI))
1359 r = dp - phys;
1360 }
1361 *dp++ = c;
1362 if(dp>=dpmax)
1363 break;
1364 }
1365 *dp = 0;
1366 ep->e_peol = dp-phys;
1367 return(r);
1368 }
1369
1370 #if SHOPT_MULTIBYTE
1371 /*
1372 * convert external representation <src> to an array of genchars <dest>
1373 * <src> and <dest> can be the same
1374 * returns number of chars in dest
1375 */
1376
1377 int ed_internal(const char *src, genchar *dest)
1378 {
1379 register const unsigned char *cp = (unsigned char *)src;
1380 register int c;
1381 register wchar_t *dp = (wchar_t*)dest;
1382 if(dest == (genchar*)roundof(cp-(unsigned char*)0,sizeof(genchar)))
1383 {
1384 genchar buffer[MAXLINE];
1385 c = ed_internal(src,buffer);
1386 ed_gencpy((genchar*)dp,buffer);
1387 return(c);
1388 }
1389 while(*cp)
1390 *dp++ = mbchar(cp);
1391 *dp = 0;
1392 return(dp-(wchar_t*)dest);
1393 }
1394
1395 /*
1396 * convert internal representation <src> into character array <dest>.
1397 * The <src> and <dest> may be the same.
1398 * returns number of chars in dest.
1399 */
1400
1401 int ed_external(const genchar *src, char *dest)
1402 {
1403 register genchar wc;
1404 register int c,size;
1405 register char *dp = dest;
1406 char *dpmax = dp+sizeof(genchar)*MAXLINE-2;
1407 if((char*)src == dp)
1408 {
1409 char buffer[MAXLINE*sizeof(genchar)];
1410 c = ed_external(src,buffer);
1411
1412 #ifdef _lib_wcscpy
1413 wcscpy((wchar_t *)dest,(const wchar_t *)buffer);
1414 #else
1415 strcpy(dest,buffer);
1416 #endif
1417 return(c);
1418 }
1419 while((wc = *src++) && dp<dpmax)
1420 {
1421 if((size = mbconv(dp, wc)) < 0)
1422 {
1423 /* copy the character as is */
1424 size = 1;
1425 *dp = wc;
1426 }
1427 dp += size;
1428 }
1429 *dp = 0;
1430 return(dp-dest);
1431 }
1432
1433 /*
1434 * copy <sp> to <dp>
1435 */
1436
1437 void ed_gencpy(genchar *dp,const genchar *sp)
1438 {
1439 dp = (genchar*)roundof((char*)dp-(char*)0,sizeof(genchar));
1440 sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
1441 while(*dp++ = *sp++);
1442 }
1443
1444 /*
1445 * copy at most <n> items from <sp> to <dp>
1446 */
1447
1448 void ed_genncpy(register genchar *dp,register const genchar *sp, int n)
1449 {
1450 dp = (genchar*)roundof((char*)dp-(char*)0,sizeof(genchar));
1451 sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
1452 while(n-->0 && (*dp++ = *sp++));
1453 }
1454
1455 #endif /* SHOPT_MULTIBYTE */
1456 /*
1457 * find the string length of <str>
1458 */
1459
1460 int ed_genlen(register const genchar *str)
1461 {
1462 register const genchar *sp = str;
1463 sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
1464 while(*sp++);
1465 return(sp-str-1);
1466 }
1467 #endif /* SHOPT_ESH || SHOPT_VSH */
1468
1469 #ifdef future
1470 /*
1471 * returns 1 when <n> bytes starting at <a> and <b> are equal
1472 */
1473 static int compare(register const char *a,register const char *b,register int n)
1474 {
1475 while(n-->0)
1476 {
1477 if(*a++ != *b++)
1478 return(0);
1479 }
1480 return(1);
1481 }
1482 #endif
1483
1484 #if SHOPT_OLDTERMIO
1485
1486 # include <sys/termio.h>
1487
1488 #ifndef ECHOCTL
1489 # define ECHOCTL 0
1490 #endif /* !ECHOCTL */
1491 #define ott ep->e_ott
1492
1493 /*
1494 * For backward compatibility only
1495 * This version will use termios when possible, otherwise termio
1496 */
1497
1498 int tcgetattr(int fd, struct termios *tt)
1499 {
1500 register Edit_t *ep = (Edit_t*)(shgd->ed_context);
1501 register int r,i;
1502 ep->e_tcgeta = 0;
1503 ep->e_echoctl = (ECHOCTL!=0);
1504 if((r=ioctl(fd,TCGETS,tt))>=0 || errno!=EINVAL)
1505 return(r);
1506 if((r=ioctl(fd,TCGETA,&ott)) >= 0)
1507 {
1508 tt->c_lflag = ott.c_lflag;
1509 tt->c_oflag = ott.c_oflag;
1510 tt->c_iflag = ott.c_iflag;
1511 tt->c_cflag = ott.c_cflag;
1512 for(i=0; i<NCC; i++)
1513 tt->c_cc[i] = ott.c_cc[i];
1514 ep->e_tcgeta++;
1515 ep->e_echoctl = 0;
1516 }
1517 return(r);
1518 }
1519
1520 int tcsetattr(int fd,int mode,struct termios *tt)
1521 {
1522 register Edit_t *ep = (Edit_t*)(shgd->ed_context);
1523 register int r;
1524 if(ep->e_tcgeta)
1525 {
1526 register int i;
1527 ott.c_lflag = tt->c_lflag;
1528 ott.c_oflag = tt->c_oflag;
1529 ott.c_iflag = tt->c_iflag;
1530 ott.c_cflag = tt->c_cflag;
1531 for(i=0; i<NCC; i++)
1532 ott.c_cc[i] = tt->c_cc[i];
1533 if(tt->c_lflag&ECHOCTL)
1534 {
1535 ott.c_lflag &= ~(ECHOCTL|IEXTEN);
1536 ott.c_iflag &= ~(IGNCR|ICRNL);
1537 ott.c_iflag |= INLCR;
1538 ott.c_cc[VEOF]= ESC; /* ESC -> eof char */
1539 ott.c_cc[VEOL] = '\r'; /* CR -> eol char */
1540 ott.c_cc[VEOL2] = tt->c_cc[VEOF]; /* EOF -> eol char */
1541 }
1542 switch(mode)
1543 {
1544 case TCSANOW:
1545 mode = TCSETA;
1546 break;
1547 case TCSADRAIN:
1548 mode = TCSETAW;
1549 break;
1550 case TCSAFLUSH:
1551 mode = TCSETAF;
1552 }
1553 return(ioctl(fd,mode,&ott));
1554 }
1555 return(ioctl(fd,mode,tt));
1556 }
1557 #endif /* SHOPT_OLDTERMIO */
1558
1559 #if KSHELL
1560 /*
1561 * Execute keyboard trap on given buffer <inbuff> of given size <isize>
1562 * <mode> < 0 for vi insert mode
1563 */
1564 static int keytrap(Edit_t *ep,char *inbuff,register int insize, int bufsize, int mode)
1565 {
1566 register char *cp;
1567 int savexit;
1568 Shell_t *shp = ep->sh;
1569 #if SHOPT_MULTIBYTE
1570 char buff[MAXLINE];
1571 ed_external(ep->e_inbuf,cp=buff);
1572 #else
1573 cp = ep->e_inbuf;
1574 #endif /* SHOPT_MULTIBYTE */
1575 inbuff[insize] = 0;
1576 ep->e_col = ep->e_cur;
1577 if(mode== -2)
1578 {
1579 ep->e_col++;
1580 *ep->e_vi_insert = ESC;
1581 }
1582 else
1583 *ep->e_vi_insert = 0;
1584 nv_putval(ED_CHRNOD,inbuff,NV_NOFREE);
1585 nv_putval(ED_COLNOD,(char*)&ep->e_col,NV_NOFREE|NV_INTEGER);
1586 nv_putval(ED_TXTNOD,(char*)cp,NV_NOFREE);
1587 nv_putval(ED_MODENOD,ep->e_vi_insert,NV_NOFREE);
1588 savexit = shp->savexit;
1589 sh_trap(shp->st.trap[SH_KEYTRAP],0);
1590 shp->savexit = savexit;
1591 if((cp = nv_getval(ED_CHRNOD)) == inbuff)
1592 nv_unset(ED_CHRNOD);
1593 else if(bufsize>0)
1594 {
1595 strncpy(inbuff,cp,bufsize);
1596 inbuff[bufsize-1]='\0';
1597 insize = strlen(inbuff);
1598 }
1599 else
1600 insize = 0;
1601 nv_unset(ED_TXTNOD);
1602 return(insize);
1603 }
1604 #endif /* KSHELL */
1605
1606 #if SHOPT_EDPREDICT
1607 static int ed_sortdata(const char *s1, const char *s2)
1608 {
1609 Histmatch_t *m1 = (Histmatch_t*)s1;
1610 Histmatch_t *m2 = (Histmatch_t*)s2;
1611 return(strcmp(m1->data,m2->data));
1612 }
1613
1614 static int ed_sortindex(const char *s1, const char *s2)
1615 {
1616 Histmatch_t *m1 = (Histmatch_t*)s1;
1617 Histmatch_t *m2 = (Histmatch_t*)s2;
1618 return(m2->index-m1->index);
1619 }
1620
1621 static int ed_histlencopy(const char *cp, char *dp)
1622 {
1623 int c,n=1,col=1;
1624 const char *oldcp=cp;
1625 for(n=0;c = mbchar(cp);oldcp=cp,col++)
1626 {
1627 if(c=='\n' && *cp)
1628 {
1629 n += 2;
1630 if(dp)
1631 {
1632 *dp++ = '^';
1633 *dp++ = 'J';
1634 col +=2;
1635 }
1636 }
1637 else if(c=='\t')
1638 {
1639 n++;
1640 if(dp)
1641 *dp++ = ' ';
1642 }
1643 else
1644 {
1645 n += cp-oldcp;
1646 if(dp)
1647 {
1648 while(oldcp < cp)
1649 *dp++ = *oldcp++;
1650 }
1651 }
1652
1653 }
1654 return(n);
1655 }
1656
1657 int ed_histgen(Edit_t *ep,const char *pattern)
1658 {
1659 Histmatch_t *mp,*mplast=0;
1660 History_t *hp;
1661 off_t offset;
1662 int ac=0,l,n,index1,index2;
1663 size_t m;
1664 char *cp, **argv=0, **av, **ar;
1665 static int maxmatch;
1666 if(!(hp=ep->sh->gd->hist_ptr) && (!nv_getval(HISTFILE) || !sh_histinit(ep->sh)))
1667 return(0);
1668 if(ep->e_cur <=2)
1669 maxmatch = 0;
1670 else if(maxmatch && ep->e_cur > maxmatch)
1671 {
1672 ep->hlist = 0;
1673 ep->hfirst = 0;
1674 return(0);
1675 }
1676 hp = ep->sh->gd->hist_ptr;
1677 if(*pattern=='#' && *++pattern=='#')
1678 return(0);
1679 cp = stakalloc(m=strlen(pattern)+6);
1680 sfsprintf(cp,m,"@(%s)*%c",pattern,0);
1681 if(ep->hlist)
1682 {
1683 m = strlen(ep->hpat)-4;
1684 if(memcmp(pattern,ep->hpat+2,m)==0)
1685 {
1686 n = strcmp(cp,ep->hpat)==0;
1687 for(argv=av=(char**)ep->hlist,mp=ep->hfirst; mp;mp= mp->next)
1688 {
1689 if(n || strmatch(mp->data,cp))
1690 *av++ = (char*)mp;
1691 }
1692 *av = 0;
1693 ep->hmax = av-argv;
1694 if(ep->hmax==0)
1695 maxmatch = ep->e_cur;
1696 return(ep->hmax=av-argv);
1697 }
1698 stakset(ep->e_stkptr,ep->e_stkoff);
1699 }
1700 if((m=strlen(cp)) >= sizeof(ep->hpat))
1701 m = sizeof(ep->hpat)-1;
1702 memcpy(ep->hpat,cp,m);
1703 ep->hpat[m] = 0;
1704 pattern = cp;
1705 index1 = (int)hp->histind;
1706 for(index2=index1-hp->histsize; index1>index2; index1--)
1707 {
1708 offset = hist_tell(hp,index1);
1709 sfseek(hp->histfp,offset,SEEK_SET);
1710 if(!(cp = sfgetr(hp->histfp,0,0)))
1711 continue;
1712 if(*cp=='#')
1713 continue;
1714 if(strmatch(cp,pattern))
1715 {
1716 l = ed_histlencopy(cp,(char*)0);
1717 mp = (Histmatch_t*)stakalloc(sizeof(Histmatch_t)+l);
1718 mp->next = mplast;
1719 mplast = mp;
1720 mp->len = l;
1721 ed_histlencopy(cp,mp->data);
1722 mp->count = 1;
1723 mp->data[l] = 0;
1724 mp->index = index1;
1725 ac++;
1726 }
1727 }
1728 if(ac>0)
1729 {
1730 l = ac;
1731 argv = av = (char**)stakalloc((ac+1)*sizeof(char*));
1732 for(mplast=0; l>=0 && (*av= (char*)mp); mplast=mp,mp=mp->next,av++)
1733 {
1734 l--;
1735 }
1736 *av = 0;
1737 strsort(argv,ac,ed_sortdata);
1738 mplast = (Histmatch_t*)argv[0];
1739 for(ar= av= &argv[1]; mp=(Histmatch_t*)*av; av++)
1740 {
1741 if(strcmp(mp->data,mplast->data)==0)
1742 {
1743 mplast->count++;
1744 if(mp->index> mplast->index)
1745 mplast->index = mp->index;
1746 continue;
1747 }
1748 *ar++ = (char*)(mplast=mp);
1749 }
1750 *ar = 0;
1751 mplast->next = 0;
1752 ac = ar-argv;
1753 strsort(argv,ac,ed_sortindex);
1754 mplast = (Histmatch_t*)argv[0];
1755 for(av= &argv[1]; mp=(Histmatch_t*)*av; av++, mplast=mp)
1756 mplast->next = mp;
1757 mplast->next = 0;
1758 }
1759 ep->hlist = (Histmatch_t**)argv;
1760 ep->hfirst = ep->hlist?ep->hlist[0]:0;
1761 return(ep->hmax=ac);
1762 }
1763
1764 void ed_histlist(Edit_t *ep,int n)
1765 {
1766 Histmatch_t *mp,**mpp = ep->hlist+ep->hoff;
1767 int i,last=0,save[2];
1768 if(n)
1769 {
1770 /* don't bother updating the screen if there is typeahead */
1771 if(!ep->e_lookahead && sfpkrd(ep->e_fd,save,1,'\r',200L,-1)>0)
1772 ed_ungetchar(ep,save[0]);
1773 if(ep->e_lookahead)
1774 return;
1775 ed_putchar(ep,'\n');
1776 ed_putchar(ep,'\r');
1777 }
1778 else
1779 {
1780 stakset(ep->e_stkptr,ep->e_stkoff);
1781 ep->hlist = 0;
1782 ep->nhlist = 0;
1783 }
1784 ed_putstring(ep,KILL_LINE);
1785 if(n)
1786 {
1787 for(i=1; (mp= *mpp) && i <= 16 ; i++,mpp++)
1788 {
1789 last = 0;
1790 if(mp->len >= ep->e_winsz-4)
1791 {
1792 last = ep->e_winsz-4;
1793 save[0] = mp->data[last-1];
1794 save[1] = mp->data[last];
1795 mp->data[last-1] = '\n';
1796 mp->data[last] = 0;
1797 }
1798 ed_putchar(ep,i<10?' ':'1');
1799 ed_putchar(ep,i<10?'0'+i:'0'+i-10);
1800 ed_putchar(ep,')');
1801 ed_putchar(ep,' ');
1802 ed_putstring(ep,mp->data);
1803 if(last)
1804 {
1805 mp->data[last-1] = save[0];
1806 mp->data[last] = save[1];
1807 }
1808 ep->nhlist = i;
1809 }
1810 last = i-1;
1811 while(i-->0)
1812 ed_putstring(ep,CURSOR_UP);
1813 }
1814 ed_flush(ep);
1815 }
1816 #endif /* SHOPT_EDPREDICT */
1817
1818 void *ed_open(Shell_t *shp)
1819 {
1820 Edit_t *ed = newof(0,Edit_t,1,0);
1821 ed->sh = shp;
1822 strcpy(ed->e_macro,"_??");
1823 return((void*)ed);
1824 }
1825
1826 #undef ioctl
1827 int sh_ioctl(int fd, int cmd, void* val, int sz)
1828 {
1829 int r,err=errno;
1830 if(sz == sizeof(void*))
1831 {
1832 while((r=ioctl(fd,cmd,val)) < 0 && errno==EINTR)
1833 errno = err;
1834 }
1835 else
1836 {
1837 Sflong_t l = (Sflong_t)val;
1838 if(sizeof(val)==sizeof(long))
1839 {
1840 while((r=ioctl(fd,cmd,(unsigned long)l)) < 0 && errno==EINTR)
1841 errno = err;
1842 }
1843 else if(sizeof(int)!=sizeof(long))
1844 {
1845 while((r=ioctl(fd,cmd,(unsigned int)l)) < 0 && errno==EINTR)
1846 errno = err;
1847 }
1848 }
1849 return(r);
1850 }
1851
1852 #ifdef _lib_tcgetattr
1853 # undef tcgetattr
1854 sh_tcgetattr(int fd, struct termios *tty)
1855 {
1856 int r,err = errno;
1857 while((r=tcgetattr(fd,tty)) < 0 && errno==EINTR)
1858 errno = err;
1859 return(r);
1860 }
1861
1862 # undef tcsetattr
1863 sh_tcsetattr(int fd, int cmd, struct termios *tty)
1864 {
1865 int r,err = errno;
1866 while((r=tcsetattr(fd,cmd,tty)) < 0 && errno==EINTR)
1867 errno = err;
1868 return(r);
1869 }
1870 #endif
1871