1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * David Korn <dgk@research.att.com> *
19 ***********************************************************************/
22 * edit.c - common routines for vi and emacs one line editors in shell
24 * David Korn P.D. Sullivan
33 #include "FEATURE/options"
34 #include "FEATURE/time"
35 #include "FEATURE/cmds"
43 # include "variables.h"
46 extern char ed_errbuf
[];
47 char e_version
[] = "\n@(#)$Id: Editlib version 1993-12-28 r $\0\n";
54 static char CURSOR_UP
[20] = { ESC
, '[', 'A', 0 };
59 # define is_cntrl(c) ((c<=STRIP) && iscntrl(c))
60 # define is_print(c) ((c&~STRIP) || isprint(c))
62 # define is_cntrl(c) iscntrl(c)
63 # define is_print(c) isprint(c)
66 #if (CC_NATIVE == CC_ASCII)
67 # define printchar(c) ((c) ^ ('A'-cntl('A')))
69 static int printchar(int c
)
74 case cntl('A'): return('A');
75 case cntl('B'): return('B');
76 case cntl('C'): return('C');
77 case cntl('D'): return('D');
78 case cntl('E'): return('E');
79 case cntl('F'): return('F');
80 case cntl('G'): return('G');
81 case cntl('H'): return('H');
82 case cntl('I'): return('I');
83 case cntl('J'): return('J');
84 case cntl('K'): return('K');
85 case cntl('L'): return('L');
86 case cntl('M'): return('M');
87 case cntl('N'): return('N');
88 case cntl('O'): return('O');
89 case cntl('P'): return('P');
90 case cntl('Q'): return('Q');
91 case cntl('R'): return('R');
92 case cntl('S'): return('S');
93 case cntl('T'): return('T');
94 case cntl('U'): return('U');
95 case cntl('V'): return('V');
96 case cntl('W'): return('W');
97 case cntl('X'): return('X');
98 case cntl('Y'): return('Y');
99 case cntl('Z'): return('Z');
100 case cntl(']'): return(']');
101 case cntl('['): return('[');
106 #define MINWINDOW 15 /* minimum width window */
107 #define DFLTWINDOW 80 /* default window width */
116 #endif /* SHOPT_OLDTERMIO */
126 static struct tchars l_ttychars
;
127 static struct ltchars l_chars
;
128 static char l_changed
; /* set if mode bits changed */
132 # endif /* TIOCGETP */
133 #endif /* _hdr_sgtty */
136 static int keytrap(Edit_t
*,char*, int, int, int);
142 #ifndef _POSIX_DISABLE
143 # define _POSIX_DISABLE 0
147 static int compare(const char*, const char*, int);
149 #if SHOPT_VSH || SHOPT_ESH
150 # define ttyparm (ep->e_ttyparm)
151 # define nttyparm (ep->e_nttyparm)
152 static const char bellchr
[] = "\a"; /* bell char */
153 #endif /* SHOPT_VSH || SHOPT_ESH */
157 * This routine returns true if fd refers to a terminal
158 * This should be equivalent to isatty
160 int tty_check(int fd
)
162 register Edit_t
*ep
= (Edit_t
*)(sh_getinterp()->ed_context
);
165 return(tty_get(fd
,&tty
)==0);
169 * Get the current terminal attributes
170 * This routine remembers the attributes and just returns them if it
171 * is called again without an intervening tty_set()
174 int tty_get(register int fd
, register struct termios
*tty
)
176 register Edit_t
*ep
= (Edit_t
*)(sh_getinterp()->ed_context
);
177 if(fd
== ep
->e_savefd
)
178 *tty
= ep
->e_savetty
;
181 while(tcgetattr(fd
,tty
) == SYSERR
)
187 /* save terminal settings if in cannonical state */
190 ep
->e_savetty
= *tty
;
198 * Set the terminal attributes
199 * If fd<0, then current attributes are invalidated
202 int tty_set(int fd
, int action
, struct termios
*tty
)
204 register Edit_t
*ep
= (Edit_t
*)(sh_getinterp()->ed_context
);
208 if(ep
->e_savefd
>=0 && compare(&ep
->e_savetty
,tty
,sizeof(struct termios
)))
211 while(tcsetattr(fd
, action
, tty
) == SYSERR
)
217 ep
->e_savetty
= *tty
;
223 #if SHOPT_ESH || SHOPT_VSH
226 * This routine will set the tty in cooked mode.
227 * It is also called by error.done().
231 void tty_cooked(register int fd
)
233 register Edit_t
*ep
= (Edit_t
*)(sh_getinterp()->ed_context
);
241 ioctl(fd
,TIOCLSET
,&l_mask
);
242 if(l_changed
&T_CHARS
)
243 /* restore alternate break character */
244 ioctl(fd
,TIOCSETC
,&l_ttychars
);
245 if(l_changed
&L_CHARS
)
246 /* restore alternate break character */
247 ioctl(fd
,TIOCSLTC
,&l_chars
);
250 /*** don't do tty_set unless ttyparm has valid data ***/
251 if(tty_set(fd
, TCSANOW
, &ttyparm
) == SYSERR
)
259 * This routine will set the tty in raw mode.
263 int tty_raw(register int fd
, int echomode
)
267 struct ltchars lchars
;
269 register Edit_t
*ep
= (Edit_t
*)(sh_getinterp()->ed_context
);
270 if(ep
->e_raw
==RAWMODE
)
272 else if(ep
->e_raw
==ECHOMODE
)
275 if(ep
->e_raw
!= ALTMODE
)
276 #endif /* SHOPT_RAWONLY */
278 if(tty_get(fd
,&ttyparm
) == SYSERR
)
282 if(ttyparm
.sg_flags
&LCASE
)
284 if(!(ttyparm
.sg_flags
&ECHO
))
292 nttyparm
.sg_flags
&= ~(ECHO
| TBDELAY
);
294 nttyparm
.sg_flags
|= CBREAK
;
296 nttyparm
.sg_flags
|= RAW
;
298 ep
->e_erase
= ttyparm
.sg_erase
;
299 ep
->e_kill
= ttyparm
.sg_kill
;
300 ep
->e_eof
= cntl('D');
301 ep
->e_werase
= cntl('W');
302 ep
->e_lnext
= cntl('V');
303 if( tty_set(fd
, TCSADRAIN
, &nttyparm
) == SYSERR
)
305 ep
->e_ttyspeed
= (ttyparm
.sg_ospeed
>=B1200
?FAST
:SLOW
);
307 /* try to remove effect of ^V and ^Y and ^O */
308 if(ioctl(fd
,TIOCGLTC
,&l_chars
) != SYSERR
)
311 lchars
.t_lnextc
= -1;
312 lchars
.t_flushc
= -1;
313 lchars
.t_dsuspc
= -1; /* no delayed stop process signal */
314 if(ioctl(fd
,TIOCSLTC
,&lchars
) != SYSERR
)
315 l_changed
|= L_CHARS
;
317 # endif /* TIOCGLTC */
319 if (!(ttyparm
.c_lflag
& ECHO
))
326 ttyparm
.c_lflag
&= ~FLUSHO
;
330 nttyparm
.c_iflag
&= ~(IGNPAR
|PARMRK
|INLCR
|IGNCR
|ICRNL
);
331 nttyparm
.c_iflag
|= BRKINT
;
334 ~(IGNBRK
|PARMRK
|INLCR
|IGNCR
|ICRNL
|INPCK
);
335 nttyparm
.c_iflag
|= (BRKINT
|IGNPAR
);
338 nttyparm
.c_lflag
&= ~ICANON
;
340 nttyparm
.c_lflag
&= ~(ICANON
|ECHO
|ECHOK
);
341 nttyparm
.c_cc
[VTIME
] = 0;
342 nttyparm
.c_cc
[VMIN
] = 1;
344 nttyparm
.c_cc
[VREPRINT
] = _POSIX_DISABLE
;
345 # endif /* VREPRINT */
347 nttyparm
.c_cc
[VDISCARD
] = _POSIX_DISABLE
;
348 # endif /* VDISCARD */
350 nttyparm
.c_cc
[VDSUSP
] = _POSIX_DISABLE
;
353 if(ttyparm
.c_cc
[VWERASE
] == _POSIX_DISABLE
)
354 ep
->e_werase
= cntl('W');
356 ep
->e_werase
= nttyparm
.c_cc
[VWERASE
];
357 nttyparm
.c_cc
[VWERASE
] = _POSIX_DISABLE
;
359 ep
->e_werase
= cntl('W');
360 # endif /* VWERASE */
362 if(ttyparm
.c_cc
[VLNEXT
] == _POSIX_DISABLE
)
363 ep
->e_lnext
= cntl('V');
365 ep
->e_lnext
= nttyparm
.c_cc
[VLNEXT
];
366 nttyparm
.c_cc
[VLNEXT
] = _POSIX_DISABLE
;
368 ep
->e_lnext
= cntl('V');
370 ep
->e_eof
= ttyparm
.c_cc
[VEOF
];
371 ep
->e_erase
= ttyparm
.c_cc
[VERASE
];
372 ep
->e_kill
= ttyparm
.c_cc
[VKILL
];
373 if( tty_set(fd
, TCSADRAIN
, &nttyparm
) == SYSERR
)
375 ep
->e_ttyspeed
= (cfgetospeed(&ttyparm
)>=B1200
?FAST
:SLOW
);
377 ep
->e_raw
= (echomode
?ECHOMODE
:RAWMODE
);
385 * Get tty parameters and make ESC and '\r' wakeup characters.
390 int tty_alt(register int fd
)
392 register Edit_t
*ep
= (Edit_t
*)(sh_getinterp()->ed_context
);
394 struct tchars ttychars
;
405 if( ep
->e_ttyspeed
== 0)
407 if((tty_get(fd
,&ttyparm
) != SYSERR
))
408 ep
->e_ttyspeed
= (ttyparm
.sg_ospeed
>=B1200
?FAST
:SLOW
);
411 if(ioctl(fd
,TIOCGETC
,&l_ttychars
) == SYSERR
)
413 if(ioctl(fd
,TIOCLGET
,&l_mask
)==SYSERR
)
415 ttychars
= l_ttychars
;
416 mask
= LCRTBS
|LCRTERA
|LCTLECH
|LPENDIN
|LCRTKIL
;
417 if((l_mask
|mask
) != l_mask
)
419 if(ioctl(fd
,TIOCLBIS
,&mask
)==SYSERR
)
421 if(ttychars
.t_brkc
!=ESC
)
423 ttychars
.t_brkc
= ESC
;
424 l_changed
|= T_CHARS
;
425 if(ioctl(fd
,TIOCSETC
,&ttychars
) == SYSERR
)
438 int tty_alt(register int fd
)
440 register Edit_t
*ep
= (Edit_t
*)(sh_getinterp()->ed_context
);
450 if((tty_get(fd
, &ttyparm
)==SYSERR
) || (!(ttyparm
.c_lflag
&ECHO
)))
453 ttyparm
.c_lflag
&= ~FLUSHO
;
456 ep
->e_eof
= ttyparm
.c_cc
[VEOF
];
458 /* escape character echos as ^[ */
459 nttyparm
.c_lflag
|= (ECHOE
|ECHOK
|ECHOCTL
|PENDIN
|IEXTEN
);
460 nttyparm
.c_cc
[VEOL
] = ESC
;
462 /* switch VEOL2 and EOF, since EOF isn't echo'd by driver */
463 nttyparm
.c_lflag
|= (ECHOE
|ECHOK
);
464 nttyparm
.c_cc
[VEOF
] = ESC
; /* make ESC the eof char */
466 nttyparm
.c_iflag
&= ~(IGNCR
|ICRNL
);
467 nttyparm
.c_iflag
|= INLCR
;
468 nttyparm
.c_cc
[VEOL
] = '\r'; /* make CR an eol char */
469 nttyparm
.c_cc
[VEOL2
] = ep
->e_eof
; /* make EOF an eol char */
471 nttyparm
.c_cc
[VEOL
] = ep
->e_eof
; /* make EOF an eol char */
473 # endif /* ECHOCTL */
475 nttyparm
.c_cc
[VREPRINT
] = _POSIX_DISABLE
;
476 # endif /* VREPRINT */
478 nttyparm
.c_cc
[VDISCARD
] = _POSIX_DISABLE
;
479 # endif /* VDISCARD */
481 if(ttyparm
.c_cc
[VWERASE
] == _POSIX_DISABLE
)
482 nttyparm
.c_cc
[VWERASE
] = cntl('W');
483 ep
->e_werase
= nttyparm
.c_cc
[VWERASE
];
485 ep
->e_werase
= cntl('W');
486 # endif /* VWERASE */
488 if(ttyparm
.c_cc
[VLNEXT
] == _POSIX_DISABLE
)
489 nttyparm
.c_cc
[VLNEXT
] = cntl('V');
490 ep
->e_lnext
= nttyparm
.c_cc
[VLNEXT
];
492 ep
->e_lnext
= cntl('V');
494 ep
->e_erase
= ttyparm
.c_cc
[VERASE
];
495 ep
->e_kill
= ttyparm
.c_cc
[VKILL
];
496 if( tty_set(fd
, TCSADRAIN
, &nttyparm
) == SYSERR
)
498 ep
->e_ttyspeed
= (cfgetospeed(&ttyparm
)>=B1200
?FAST
:SLOW
);
503 # endif /* TIOCGETC */
504 #endif /* SHOPT_RAWONLY */
509 * return the window size
514 register char *cp
= nv_getval(COLUMNS
);
516 cols
= (int)strtol(cp
, (char**)0, 10)-1;
519 astwinsize(2,&rows
,&cols
);
525 else if(cols
> MAXWINDOW
)
532 * Flush the output buffer.
536 void ed_flush(Edit_t
*ep
)
538 register int n
= ep
->e_outptr
-ep
->e_outbase
;
539 register int fd
= ERRIO
;
542 write(fd
,ep
->e_outbase
,(unsigned)n
);
543 ep
->e_outptr
= ep
->e_outbase
;
547 * send the bell character ^G to the terminal
550 void ed_ringbell(void)
552 write(ERRIO
,bellchr
,1);
556 * send a carriage return line feed to the terminal
559 void ed_crlf(register Edit_t
*ep
)
574 /* ED_SETUP( max_prompt_size )
576 * This routine sets up the prompt string
577 * The following is an unadvertised feature.
578 * Escape sequences in the prompt can be excluded from the calculated
579 * prompt length. This is accomplished as follows:
580 * - if the prompt string starts with "%\r, or contains \r%\r", where %
581 * represents any char, then % is taken to be the quote character.
582 * - strings enclosed by this quote character, and the quote character,
583 * are not counted as part of the prompt length.
586 void ed_setup(register Edit_t
*ep
, int fd
, int reedit
)
588 Shell_t
*shp
= ep
->sh
;
590 register char *last
, *prev
;
593 register int qlen
= 1, qwid
;
596 ep
->e_multiline
= sh_isoption(SH_MULTILINE
)!=0;
598 if(!(shp
->sigflag
[SIGWINCH
]&SH_SIGFAULT
))
600 signal(SIGWINCH
,sh_fault
);
601 shp
->sigflag
[SIGWINCH
] |= SH_SIGFAULT
;
603 pp
= shp
->st
.trapcom
[SIGWINCH
];
604 shp
->st
.trapcom
[SIGWINCH
] = 0;
606 shp
->st
.trapcom
[SIGWINCH
] = pp
;
610 ep
->e_stkptr
= stakptr(0);
611 ep
->e_stkoff
= staktell();
612 if(!(last
= shp
->prompt
))
620 register History_t
*hp
= shp
->hist_ptr
;
621 ep
->e_hismax
= hist_max(hp
);
622 ep
->e_hismin
= hist_min(hp
);
626 ep
->e_hismax
= ep
->e_hismin
= ep
->e_hloff
= 0;
628 ep
->e_hline
= ep
->e_hismax
;
629 if(!sh_isoption(SH_VI
) && !sh_isoption(SH_EMACS
) && !sh_isoption(SH_GMACS
))
630 ep
->e_wsize
= MAXLINE
;
632 ep
->e_wsize
= ed_window()-2;
633 ep
->e_winsz
= ep
->e_wsize
+2;
641 while(prev
= last
, c
= mbchar(last
)) switch(c
)
648 for(n
=1; c
= *last
++; n
++)
652 if(c
=='\a' || c
==ESC
|| c
=='\r')
654 if(skip
|| (c
>='0' && c
<='9'))
658 else if(n
>2 || (c
!= '[' && c
!= ']'))
661 if(c
==0 || c
==ESC
|| c
=='\r')
667 if(pp
>ep
->e_prompt
+1)
671 if(pp
== (ep
->e_prompt
+2)) /* quote char */
685 while((pp
-ep
->e_prompt
)%TABSIZE
)
707 else if(!is_print(c
))
709 if((qwid
= last
- prev
) > 1)
710 qlen
+= qwid
- mbwidth(c
);
711 while(prev
< last
&& pp
< ppmax
)
717 if(pp
-ep
->e_prompt
> qlen
)
718 ep
->e_plen
= pp
- ep
->e_prompt
- qlen
;
720 if(!ep
->e_multiline
&& (ep
->e_wsize
-= ep
->e_plen
) < 7)
722 register int shift
= 7-ep
->e_wsize
;
727 last
[-ep
->e_plen
-2] = '\r';
730 if(fd
== sffileno(sfstderr
))
732 /* can't use output buffer when reading from stderr */
735 buff
= (char*)malloc(MAXLINE
);
736 ep
->e_outbase
= ep
->e_outptr
= buff
;
737 ep
->e_outlast
= ep
->e_outptr
+ MAXLINE
;
740 qlen
= sfset(sfstderr
,SF_READ
,0);
741 /* make sure SF_READ not on */
742 ep
->e_outbase
= ep
->e_outptr
= (char*)sfreserve(sfstderr
,SF_UNBOUND
,SF_LOCKR
);
743 ep
->e_outlast
= ep
->e_outptr
+ sfvalue(sfstderr
);
745 sfset(sfstderr
,SF_READ
,1);
746 sfwrite(sfstderr
,ep
->e_outptr
,0);
753 ep
->e_term
= nv_search("TERM",shp
->var_tree
,0);
754 if(ep
->e_term
&& (term
=nv_getval(ep
->e_term
)) && strlen(term
)<sizeof(ep
->e_termname
) && strcmp(term
,ep
->e_termname
))
756 sh_trap(".sh.subscript=$(tput cuu1 2>/dev/null)",0);
757 if(pp
=nv_getval(SH_SUBSCRNOD
))
758 strncpy(CURSOR_UP
,pp
,sizeof(CURSOR_UP
)-1);
759 nv_unset(SH_SUBSCRNOD
);
760 strcpy(ep
->e_termname
,term
);
763 ep
->e_wsize
= MAXLINE
- (ep
->e_plen
+1);
765 if(ep
->e_default
&& (pp
= nv_getval(ep
->e_default
)))
772 ep
->e_lbuf
[n
] = *pp
++;
777 static void ed_putstring(register Edit_t
*ep
, const char *str
)
784 static void ed_nputchar(register Edit_t
*ep
, int n
, int c
)
791 * Do read, restart on interrupt unless SH_SIGSET or SH_SIGTRAP is set
792 * Use sfpkrd() to poll() or select() to wait for input if possible
793 * Unfortunately, systems that get interrupted from slow reads update
794 * this access time for for the terminal (in violation of POSIX).
795 * The fixtime() macro, resets the time to the time at entry in
796 * this case. This is not necessary for systems that can handle
797 * sfpkrd() correctly (i,e., those that support poll() or select()
799 int ed_read(void *context
, int fd
, char *buff
, int size
, int reedit
)
801 register Edit_t
*ep
= (Edit_t
*)context
;
803 register int delim
= (ep
->e_raw
==RAWMODE
?'\r':'\n');
804 Shell_t
*shp
= ep
->sh
;
806 int (*waitevent
)(int,long,int) = shp
->waitevent
;
807 if(ep
->e_raw
==ALTMODE
)
814 sh_onstate(SH_TTYWAIT
);
817 while(rv
<0 && errno
==EINTR
)
819 if(shp
->trapnote
&(SH_SIGSET
|SH_SIGTRAP
))
821 if(ep
->sh
->winch
&& sh_isstate(SH_INTERACTIVE
) && (sh_isoption(SH_VI
) || sh_isoption(SH_EMACS
)))
824 int n
, rows
, newsize
;
825 /* move cursor to start of first line */
828 astwinsize(2,&rows
,&newsize
);
829 n
= (ep
->e_plen
+ep
->e_cur
)/++ep
->e_winsz
;
831 ed_putstring(ep
,CURSOR_UP
);
832 if(ep
->e_multiline
&& newsize
>ep
->e_winsz
&& (lastpos
.line
=(ep
->e_plen
+ep
->e_peol
)/ep
->e_winsz
))
834 /* clear the current command line */
836 while(lastpos
.line
--)
838 ed_nputchar(ep
,ep
->e_winsz
,' ');
841 ed_nputchar(ep
,ep
->e_winsz
,' ');
843 ed_putstring(ep
,CURSOR_UP
);
848 astwinsize(2,&rows
,&newsize
);
849 ep
->e_winsz
= newsize
-1;
850 if(!ep
->e_multiline
&& ep
->e_wsize
< MAXLINE
)
851 ep
->e_wsize
= ep
->e_winsz
-2;
860 if(sh_isoption(SH_EMACS
) || sh_isoption(SH_VI
))
866 /* an interrupt that should be ignored */
868 if(!waitevent
|| (rv
=(*waitevent
)(fd
,-1L,0))>=0)
869 rv
= sfpkrd(fd
,buff
,size
,delim
,-1L,mode
);
874 # define fixtime() if(isdevtty)utime(ep->e_tty,&utimes)
877 struct utimbuf utimes
;
878 if(errno
==0 && !ep
->e_tty
)
880 if((ep
->e_tty
=ttyname(fd
)) && stat(ep
->e_tty
,&statb
)>=0)
882 ep
->e_tty_ino
= statb
.st_ino
;
883 ep
->e_tty_dev
= statb
.st_dev
;
886 if(ep
->e_tty_ino
&& fstat(fd
,&statb
)>=0 && statb
.st_ino
==ep
->e_tty_ino
&& statb
.st_dev
==ep
->e_tty_dev
)
888 utimes
.actime
= statb
.st_atime
;
889 utimes
.modtime
= statb
.st_mtime
;
894 #endif /* _hdr_utime */
897 rv
= read(fd
,buff
,size
);
898 if(rv
>=0 || errno
!=EINTR
)
900 if(shp
->trapnote
&(SH_SIGSET
|SH_SIGTRAP
))
902 /* an interrupt that should be ignored */
906 else if(rv
>=0 && mode
>0)
907 rv
= read(fd
,buff
,rv
>0?rv
:1);
909 shp
->waitevent
= waitevent
;
910 sh_offstate(SH_TTYWAIT
);
916 * put <string> of length <nbyte> onto lookahead stack
917 * if <type> is non-zero, the negation of the character is put
918 * onto the stack so that it can be checked for KEYTRAP
919 * putstack() returns 1 except when in the middle of a multi-byte char
921 static int putstack(Edit_t
*ep
,char string
[], register int nbyte
, int type
)
925 char *endp
, *p
=string
;
926 int size
, offset
= ep
->e_lookahead
+ nbyte
;
927 *(endp
= &p
[nbyte
]) = 0;
931 c
= (int)((*p
) & STRIP
);
932 if(c
< 0x80 && c
!='<')
939 /*** user break key ***/
943 siglongjmp(ep
->e_env
, UINTR
);
952 if((c
=mbchar(p
)) >=0)
954 p
--; /* incremented below */
959 else if(errno
== EILSEQ
)
962 else if((endp
-p
) < mbmax())
964 if ((c
=ed_read(ep
,ep
->e_fd
,endp
, 1,0)) == 1)
974 c
= -(int)((*p
) & STRIP
);
978 ep
->e_lbuf
[--offset
] = c
;
982 /* shift lookahead buffer if necessary */
983 if(offset
-= ep
->e_lookahead
)
985 for(size
=offset
;size
< nbyte
;size
++)
986 ep
->e_lbuf
[ep
->e_lookahead
+size
-offset
] = ep
->e_lbuf
[ep
->e_lookahead
+size
];
988 ep
->e_lookahead
+= nbyte
-offset
;
992 c
= string
[--nbyte
] & STRIP
;
993 ep
->e_lbuf
[ep
->e_lookahead
++] = (type
?-c
:c
);
997 /*** user break key ***/
1001 siglongjmp(ep
->e_env
, UINTR
);
1002 # endif /* KSHELL */
1004 # endif /* CBREAK */
1006 #endif /* SHOPT_MULTIBYTE */
1011 * routine to perform read from terminal for vi and emacs mode
1012 * <mode> can be one of the following:
1013 * -2 vi insert mode - key binding is in effect
1014 * -1 vi control mode - key binding is in effect
1015 * 0 normal command mode - key binding is in effect
1016 * 1 edit keys not mapped
1017 * 2 Next key is literal
1019 int ed_getchar(register Edit_t
*ep
,int mode
)
1022 char readin
[LOOKAHEAD
+1];
1023 if(!ep
->e_lookahead
)
1027 /* The while is necessary for reads of partial multbyte chars */
1028 *ep
->e_vi_insert
= (mode
==-2);
1029 if((n
=ed_read(ep
,ep
->e_fd
,readin
,-LOOKAHEAD
,0)) > 0)
1030 n
= putstack(ep
,readin
,n
,1);
1031 *ep
->e_vi_insert
= 0;
1035 /* check for possible key mapping */
1036 if((c
= ep
->e_lbuf
[--ep
->e_lookahead
]) < 0)
1038 if(mode
<=0 && ep
->sh
->st
.trap
[SH_KEYTRAP
])
1041 if((readin
[0]= -c
) == ESC
)
1045 if(!ep
->e_lookahead
)
1047 if((c
=sfpkrd(ep
->e_fd
,readin
+n
,1,'\r',(mode
?400L:-1L),0))>0)
1048 putstack(ep
,readin
+n
,c
,1);
1050 if(!ep
->e_lookahead
)
1052 if((c
=ep
->e_lbuf
[--ep
->e_lookahead
])>=0)
1059 if(c
>='0' && c
<='9' && n
>2)
1061 if(n
>2 || (c
!= '[' && c
!= 'O'))
1065 if(n
=keytrap(ep
,readin
,n
,LOOKAHEAD
-n
,mode
))
1067 putstack(ep
,readin
,n
,0);
1068 c
= ep
->e_lbuf
[--ep
->e_lookahead
];
1071 c
= ed_getchar(ep
,mode
);
1076 /*** map '\r' to '\n' ***/
1077 if(c
== '\r' && mode
!=2)
1079 if(ep
->e_tabcount
&& !(c
=='\t'||c
==ESC
|| c
=='\\' || c
=='=' || c
==cntl('L') || isdigit(c
)))
1083 siglongjmp(ep
->e_env
,(n
==0?UEOF
:UINTR
));
1087 void ed_ungetchar(Edit_t
*ep
,register int c
)
1089 if (ep
->e_lookahead
< LOOKAHEAD
)
1090 ep
->e_lbuf
[ep
->e_lookahead
++] = c
;
1095 * put a character into the output buffer
1098 void ed_putchar(register Edit_t
*ep
,register int c
)
1101 register char *dp
= ep
->e_outptr
;
1102 register int i
,size
=1;
1107 /* check for place holder */
1110 if((size
= mbconv(buf
, (wchar_t)c
)) > 1)
1112 for (i
= 0; i
< (size
-1); i
++)
1121 #endif /* SHOPT_MULTIBYTE */
1122 if (buf
[0] == '_' && size
==1)
1129 if(dp
>= ep
->e_outlast
)
1136 * returns the line and column corresponding to offset <off> in the physical buffer
1137 * if <cur> is non-zero and <= <off>, then correspodning <curpos> will start the search
1139 Edpos_t
ed_curpos(Edit_t
*ep
,genchar
*phys
, int off
, int cur
, Edpos_t curpos
)
1141 register genchar
*sp
=phys
;
1142 register int c
=1, col
=ep
->e_plen
;
1146 #endif /* SHOPT_MULTIBYTE */
1157 while(col
> ep
->e_winsz
)
1160 col
-= (ep
->e_winsz
+1);
1168 if(c
&& (mbconv(p
, (wchar_t)c
))==1 && p
[0]=='\n')
1171 #endif /* SHOPT_MULTIBYTE */
1175 if(col
> ep
->e_winsz
)
1184 int ed_setcursor(register Edit_t
*ep
,genchar
*physical
,register int old
,register int new,int first
)
1197 if( delta
== 0 && !clear
)
1201 ep
->e_curpos
= ed_curpos(ep
, physical
, old
,0,ep
->e_curpos
);
1202 if(clear
&& old
>=ep
->e_peol
&& (clear
=ep
->e_winsz
-ep
->e_curpos
.col
)>0)
1204 ed_nputchar(ep
,clear
,' ');
1205 ed_nputchar(ep
,clear
,'\b');
1208 newpos
= ed_curpos(ep
, physical
, new,old
,ep
->e_curpos
);
1209 if(ep
->e_curpos
.col
==0 && ep
->e_curpos
.line
>0 && oldline
<ep
->e_curpos
.line
&& delta
<0)
1210 ed_putstring(ep
,"\r\n");
1211 oldline
= newpos
.line
;
1212 if(ep
->e_curpos
.line
> newpos
.line
)
1214 int n
,pline
,plen
=ep
->e_plen
;
1215 for(;ep
->e_curpos
.line
> newpos
.line
; ep
->e_curpos
.line
--)
1216 ed_putstring(ep
,CURSOR_UP
);
1217 pline
= plen
/(ep
->e_winsz
+1);
1218 if(newpos
.line
<= pline
)
1219 plen
-= pline
*(ep
->e_winsz
+1);
1222 if((n
=plen
- ep
->e_curpos
.col
)>0)
1224 ep
->e_curpos
.col
+= n
;
1225 ed_putchar(ep
,'\r');
1226 if(!ep
->e_crlf
&& pline
==0)
1227 ed_putstring(ep
,ep
->e_prompt
);
1230 int m
= ep
->e_winsz
+1-plen
;
1231 ed_putchar(ep
,'\n');
1233 if(m
< ed_genlen(physical
))
1235 while(physical
[m
] && n
-->0)
1236 ed_putchar(ep
,physical
[m
++]);
1238 ed_nputchar(ep
,n
,' ');
1239 ed_putstring(ep
,CURSOR_UP
);
1243 else if(ep
->e_curpos
.line
< newpos
.line
)
1245 ed_nputchar(ep
, newpos
.line
-ep
->e_curpos
.line
,'\n');
1246 ep
->e_curpos
.line
= newpos
.line
;
1247 ed_putchar(ep
,'\r');
1248 ep
->e_curpos
.col
= 0;
1250 delta
= newpos
.col
- ep
->e_curpos
.col
;
1257 int bs
= newpos
.line
&& ep
->e_plen
>ep
->e_winsz
;
1258 /*** move to left ***/
1260 /*** attempt to optimize cursor movement ***/
1261 if(!ep
->e_crlf
|| bs
|| (2*delta
<= ((old
-first
)+(newpos
.line
?0:ep
->e_plen
))) )
1263 ed_nputchar(ep
,delta
,'\b');
1269 ed_putstring(ep
,ep
->e_prompt
);
1272 first
= 1+(newpos
.line
*ep
->e_winsz
- ep
->e_plen
);
1273 ed_putchar(ep
,'\r');
1280 ed_putchar(ep
,physical
[old
++]);
1285 * copy virtual to physical and return the index for cursor in physical buffer
1287 int ed_virt_to_phys(Edit_t
*ep
,genchar
*virt
,genchar
*phys
,int cur
,int voff
,int poff
)
1289 register genchar
*sp
= virt
;
1290 register genchar
*dp
= phys
;
1292 genchar
*curp
= sp
+ cur
;
1293 genchar
*dpmax
= phys
+MAXLINE
;
1297 for(r
=poff
;c
= *sp
;sp
++)
1302 d
= mbwidth((wchar_t)c
);
1303 if(d
==1 && is_cntrl(c
))
1307 /* multiple width character put in place holders */
1311 /* in vi mode the cursor is at the last character */
1318 d
= (is_cntrl(c
)?-1:1);
1319 #endif /* SHOPT_MULTIBYTE */
1325 if(sh_isoption(SH_VI
))
1327 c
= TABSIZE
- c
%TABSIZE
;
1337 /* in vi mode the cursor is at the last character */
1338 if(curp
== sp
&& sh_isoption(SH_VI
))
1346 ep
->e_peol
= dp
-phys
;
1352 * convert external representation <src> to an array of genchars <dest>
1353 * <src> and <dest> can be the same
1354 * returns number of chars in dest
1357 int ed_internal(const char *src
, genchar
*dest
)
1359 register const unsigned char *cp
= (unsigned char *)src
;
1361 register wchar_t *dp
= (wchar_t*)dest
;
1362 if(dest
== (genchar
*)roundof(cp
-(unsigned char*)0,sizeof(genchar
)))
1364 genchar buffer
[MAXLINE
];
1365 c
= ed_internal(src
,buffer
);
1366 ed_gencpy((genchar
*)dp
,buffer
);
1372 return(dp
-(wchar_t*)dest
);
1376 * convert internal representation <src> into character array <dest>.
1377 * The <src> and <dest> may be the same.
1378 * returns number of chars in dest.
1381 int ed_external(const genchar
*src
, char *dest
)
1383 register genchar wc
;
1384 register int c
,size
;
1385 register char *dp
= dest
;
1386 char *dpmax
= dp
+sizeof(genchar
)*MAXLINE
-2;
1387 if((char*)src
== dp
)
1389 char buffer
[MAXLINE
*sizeof(genchar
)];
1390 c
= ed_external(src
,buffer
);
1393 wcscpy((wchar_t *)dest
,(const wchar_t *)buffer
);
1395 strcpy(dest
,buffer
);
1399 while((wc
= *src
++) && dp
<dpmax
)
1401 if((size
= mbconv(dp
, wc
)) < 0)
1403 /* copy the character as is */
1417 void ed_gencpy(genchar
*dp
,const genchar
*sp
)
1419 dp
= (genchar
*)roundof((char*)dp
-(char*)0,sizeof(genchar
));
1420 sp
= (const genchar
*)roundof((char*)sp
-(char*)0,sizeof(genchar
));
1421 while(*dp
++ = *sp
++);
1425 * copy at most <n> items from <sp> to <dp>
1428 void ed_genncpy(register genchar
*dp
,register const genchar
*sp
, int n
)
1430 dp
= (genchar
*)roundof((char*)dp
-(char*)0,sizeof(genchar
));
1431 sp
= (const genchar
*)roundof((char*)sp
-(char*)0,sizeof(genchar
));
1432 while(n
-->0 && (*dp
++ = *sp
++));
1436 * find the string length of <str>
1439 int ed_genlen(register const genchar
*str
)
1441 register const genchar
*sp
= str
;
1442 sp
= (const genchar
*)roundof((char*)sp
-(char*)0,sizeof(genchar
));
1446 #endif /* SHOPT_MULTIBYTE */
1447 #endif /* SHOPT_ESH || SHOPT_VSH */
1451 * returns 1 when <n> bytes starting at <a> and <b> are equal
1453 static int compare(register const char *a
,register const char *b
,register int n
)
1466 # include <sys/termio.h>
1470 #endif /* !ECHOCTL */
1471 #define ott ep->e_ott
1474 * For backward compatibility only
1475 * This version will use termios when possible, otherwise termio
1478 int tcgetattr(int fd
, struct termios
*tt
)
1480 register Edit_t
*ep
= (Edit_t
*)(sh_getinterp()->ed_context
);
1483 ep
->e_echoctl
= (ECHOCTL
!=0);
1484 if((r
=ioctl(fd
,TCGETS
,tt
))>=0 || errno
!=EINVAL
)
1486 if((r
=ioctl(fd
,TCGETA
,&ott
)) >= 0)
1488 tt
->c_lflag
= ott
.c_lflag
;
1489 tt
->c_oflag
= ott
.c_oflag
;
1490 tt
->c_iflag
= ott
.c_iflag
;
1491 tt
->c_cflag
= ott
.c_cflag
;
1492 for(i
=0; i
<NCC
; i
++)
1493 tt
->c_cc
[i
] = ott
.c_cc
[i
];
1500 int tcsetattr(int fd
,int mode
,struct termios
*tt
)
1502 register Edit_t
*ep
= (Edit_t
*)(sh_getinterp()->ed_context
);
1507 ott
.c_lflag
= tt
->c_lflag
;
1508 ott
.c_oflag
= tt
->c_oflag
;
1509 ott
.c_iflag
= tt
->c_iflag
;
1510 ott
.c_cflag
= tt
->c_cflag
;
1511 for(i
=0; i
<NCC
; i
++)
1512 ott
.c_cc
[i
] = tt
->c_cc
[i
];
1513 if(tt
->c_lflag
&ECHOCTL
)
1515 ott
.c_lflag
&= ~(ECHOCTL
|IEXTEN
);
1516 ott
.c_iflag
&= ~(IGNCR
|ICRNL
);
1517 ott
.c_iflag
|= INLCR
;
1518 ott
.c_cc
[VEOF
]= ESC
; /* ESC -> eof char */
1519 ott
.c_cc
[VEOL
] = '\r'; /* CR -> eol char */
1520 ott
.c_cc
[VEOL2
] = tt
->c_cc
[VEOF
]; /* EOF -> eol char */
1533 return(ioctl(fd
,mode
,&ott
));
1535 return(ioctl(fd
,mode
,tt
));
1537 #endif /* SHOPT_OLDTERMIO */
1541 * Execute keyboard trap on given buffer <inbuff> of given size <isize>
1542 * <mode> < 0 for vi insert mode
1544 static int keytrap(Edit_t
*ep
,char *inbuff
,register int insize
, int bufsize
, int mode
)
1548 Shell_t
*shp
= ep
->sh
;
1551 ed_external(ep
->e_inbuf
,cp
=buff
);
1554 #endif /* SHOPT_MULTIBYTE */
1556 ep
->e_col
= ep
->e_cur
;
1560 *ep
->e_vi_insert
= ESC
;
1563 *ep
->e_vi_insert
= 0;
1564 nv_putval(ED_CHRNOD
,inbuff
,NV_NOFREE
);
1565 nv_putval(ED_COLNOD
,(char*)&ep
->e_col
,NV_NOFREE
|NV_INTEGER
);
1566 nv_putval(ED_TXTNOD
,(char*)cp
,NV_NOFREE
);
1567 nv_putval(ED_MODENOD
,ep
->e_vi_insert
,NV_NOFREE
);
1568 savexit
= shp
->savexit
;
1569 sh_trap(shp
->st
.trap
[SH_KEYTRAP
],0);
1570 shp
->savexit
= savexit
;
1571 if((cp
= nv_getval(ED_CHRNOD
)) == inbuff
)
1572 nv_unset(ED_CHRNOD
);
1575 strncpy(inbuff
,cp
,bufsize
);
1576 inbuff
[bufsize
-1]='\0';
1577 insize
= strlen(inbuff
);
1581 nv_unset(ED_TXTNOD
);
1586 void *ed_open(Shell_t
*shp
)
1588 Edit_t
*ed
= newof(0,Edit_t
,1,0);
1590 strcpy(ed
->e_macro
,"_??");