edit.c revision 3f54fd611f536639ec30dd53c48e5ec1897cc7d9
/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1982-2012 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* David Korn <dgk@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* edit.c - common routines for vi and emacs one line editors in shell
*
* David Korn P.D. Sullivan
* AT&T Labs
*
* Coded April 1983.
*/
#include <ast.h>
#include <errno.h>
#include <ccode.h>
#ifdef _hdr_utime
# include <utime.h>
# include <ls.h>
#endif
#if KSHELL
# include "defs.h"
# include "variables.h"
#else
# include <ctype.h>
extern char ed_errbuf[];
char e_version[] = "\n@(#)$Id: Editlib version 1993-12-28 r $\0\n";
#endif /* KSHELL */
#include "io.h"
#include "terminal.h"
#include "history.h"
#include "edit.h"
#if SHOPT_MULTIBYTE
#else
#endif
#else
static int printchar(int c)
{
switch(c)
{
}
return('?');
}
#endif
#define RAWMODE 1
#define ALTMODE 2
#define ECHOMODE 3
#define SYSERR -1
#if SHOPT_OLDTERMIO
#endif /* SHOPT_OLDTERMIO */
#ifdef RT
# define VENIX 1
#endif /* RT */
#ifdef _hdr_sgtty
# ifdef TIOCGETP
static int l_mask;
static struct tchars l_ttychars;
static char l_changed; /* set if mode bits changed */
# define L_CHARS 4
# define T_CHARS 2
# define L_MASK 1
# endif /* TIOCGETP */
#endif /* _hdr_sgtty */
#if KSHELL
#else
#endif /* KSHELL */
#ifndef _POSIX_DISABLE
# define _POSIX_DISABLE 0
#endif
#ifdef future
static int compare(const char*, const char*, int);
#endif /* future */
#endif /* SHOPT_VSH || SHOPT_ESH */
/*
* This routine returns true if fd refers to a terminal
* This should be equivalent to isatty
*/
{
}
/*
* Get the current terminal attributes
* This routine remembers the attributes and just returns them if it
* is called again without an intervening tty_set()
*/
{
else
{
{
return(SYSERR);
errno = 0;
}
/* save terminal settings if in cannonical state */
{
}
}
return(0);
}
/*
* Set the terminal attributes
* If fd<0, then current attributes are invalidated
*/
{
if(fd >=0)
{
#ifdef future
return(0);
#endif
{
return(SYSERR);
errno = 0;
}
}
return(0);
}
/*{ TTY_COOKED( fd )
*
* This routine will set the tty in cooked mode.
* It is also called by error.done().
*
}*/
void tty_cooked(register int fd)
{
return;
if(fd < 0)
#ifdef L_MASK
/* restore flags */
/* restore alternate break character */
/* restore alternate break character */
l_changed = 0;
#endif /* L_MASK */
/*** don't do tty_set unless ttyparm has valid data ***/
return;
return;
}
/*{ TTY_RAW( fd )
*
* This routine will set the tty in raw mode.
*
}*/
{
#ifdef L_MASK
#endif /* L_MASK */
return(echo?-1:0);
return(echo?0:-1);
#if !SHOPT_RAWONLY
#endif /* SHOPT_RAWONLY */
{
return(-1);
}
return(-1);
{
if(!echomode)
return(-1);
echo = 0;
}
if(!echo)
# ifdef CBREAK
# else
# endif /* CBREAK */
return(-1);
# ifdef TIOCGLTC
/* try to remove effect of ^V and ^Y and ^O */
{
}
# endif /* TIOCGLTC */
#else
{
if(!echomode)
return(-1);
echo = 0;
}
# ifdef FLUSHO
# endif /* FLUSHO */
# ifndef u370
# else
# endif /* u370 */
if(echo)
else
# ifdef VREPRINT
# endif /* VREPRINT */
# ifdef VDISCARD
# endif /* VDISCARD */
# ifdef VDSUSP
# endif /* VDSUSP */
# ifdef VWERASE
else
# else
# endif /* VWERASE */
# ifdef VLNEXT
else
# else
# endif /* VLNEXT */
return(-1);
#endif
return(0);
}
#if !SHOPT_RAWONLY
/*
*
* Get tty parameters and make ESC and '\r' wakeup characters.
*
*/
# ifdef TIOCGETC
{
int mask;
{
case ECHOMODE:
return(-1);
case ALTMODE:
return(0);
case RAWMODE:
tty_cooked(fd);
}
l_changed = 0;
if( ep->e_ttyspeed == 0)
{
}
return(-1);
return(-1);
return(-1);
{
return(-1);
}
return(0);
}
# else
# ifndef PENDIN
# define PENDIN 0
# endif /* PENDIN */
# ifndef IEXTEN
# define IEXTEN 0
# endif /* IEXTEN */
{
{
case ECHOMODE:
return(-1);
case ALTMODE:
return(0);
case RAWMODE:
tty_cooked(fd);
}
return(-1);
# ifdef FLUSHO
# endif /* FLUSHO */
# ifdef ECHOCTL
/* escape character echos as ^[ */
# else
/* switch VEOL2 and EOF, since EOF isn't echo'd by driver */
# ifdef VEOL2
# else
# endif /* VEOL2 */
# endif /* ECHOCTL */
# ifdef VREPRINT
# endif /* VREPRINT */
# ifdef VDISCARD
# endif /* VDISCARD */
# ifdef VWERASE
# else
# endif /* VWERASE */
# ifdef VLNEXT
# else
# endif /* VLNEXT */
return(-1);
return(0);
}
# endif /* TIOCGETC */
#endif /* SHOPT_RAWONLY */
/*
* ED_WINDOW()
*
* return the window size
*/
int ed_window(void)
{
if(cp)
else
{
if(--cols <0)
}
return(cols);
}
/* E_FLUSH()
*
* Flush the output buffer.
*
*/
{
if(n<=0)
return;
}
/*
* send the bell character ^G to the terminal
*/
void ed_ringbell(void)
{
}
/*
* send a carriage return line feed to the terminal
*/
{
#ifdef cray
#endif /* cray */
#ifdef u370
#endif /* u370 */
#ifdef VENIX
#endif /* VENIX */
}
/* ED_SETUP( max_prompt_size )
*
* This routine sets up the prompt string
* The following is an unadvertised feature.
* Escape sequences in the prompt can be excluded from the calculated
* prompt length. This is accomplished as follows:
* - if the prompt string starts with "%\r, or contains \r%\r", where %
* represents any char, then % is taken to be the quote character.
* - strings enclosed by this quote character, and the quote character,
* are not counted as part of the prompt length.
*/
{
register char *pp;
char *ppmax;
int myquote = 0, n;
char inquote = 0;
#ifdef SIGWINCH
{
}
#endif
#if SHOPT_EDPREDICT
#endif /* SHOPT_EDPREDICT */
#if KSHELL
last = "";
#else
#endif /* KSHELL */
{
}
else
{
}
else
*pp++ = '\r';
{
register int c;
{
case ESC:
{
int skip=0;
*pp++ = c;
for(n=1; c = *last++; n++)
{
*pp++ = c;
break;
{
skip = 0;
continue;
}
if(n>1 && c==';')
skip = 1;
else if(n>2 || (c!= '[' && c!= ']'))
break;
}
if(c==0 || c==ESC || c=='\r')
last--;
qlen += (n+1);
break;
}
case '\b':
pp--;
break;
case '\r':
/*FALLTHROUGH*/
case '\n':
/* start again */
qlen = 1;
inquote = 0;
break;
case '\t':
/* expand tabs */
{
break;
*pp++ = ' ';
}
break;
case '\a':
/* cut out bells */
break;
default:
if(c==myquote)
{
inquote ^= 1;
}
{
if(inquote)
qlen++;
else if(!is_print(c))
}
break;
}
}
*pp = 0;
{
}
{
/* can't use output buffer when reading from stderr */
static char *buff;
if(!buff)
return;
}
/* make sure SF_READ not on */
if(qlen)
if(ep->e_multiline)
{
#ifdef _cmd_tput
char *term;
if(ep->e_term && (term=nv_getval(ep->e_term)) && strlen(term)<sizeof(ep->e_termname) && strcmp(term,ep->e_termname))
{
}
#endif
}
{
if(n > LOOKAHEAD)
n = LOOKAHEAD;
ep->e_lookahead = n;
while(n-- > 0)
}
}
{
register int c;
while(c = *str++)
ed_putchar(ep,c);
}
{
while(n-->0)
ed_putchar(ep,c);
}
/*
* Do read, restart on interrupt unless SH_SIGSET or SH_SIGTRAP is set
* Use sfpkrd() to poll() or select() to wait for input if possible
* Unfortunately, systems that get interrupted from slow reads update
* this access time for for the terminal (in violation of POSIX).
* The fixtime() macro, resets the time to the time at entry in
* this case. This is not necessary for systems that can handle
* sfpkrd() correctly (i,e., those that support poll() or select()
*/
{
register int rv= -1;
int mode = -1;
mode = 1;
if(size < 0)
{
mode = 1;
}
{
goto done;
{
/* move cursor to start of first line */
while(n--)
{
/* clear the current command line */
{
}
while(n--)
}
sh_delay(.05);
if(*ep->e_vi_insert)
{
return(3);
}
return(1);
}
else
/* an interrupt that should be ignored */
errno = 0;
}
if(rv < 0)
{
#ifdef _hdr_utime
int isdevtty=0;
{
{
}
}
if(ep->e_tty_ino && fstat(fd,&statb)>=0 && statb.st_ino==ep->e_tty_ino && statb.st_dev==ep->e_tty_dev)
{
isdevtty=1;
}
#else
# define fixtime()
#endif /* _hdr_utime */
while(1)
{
break;
goto done;
/* an interrupt that should be ignored */
fixtime();
}
}
done:
return(rv);
}
/*
* put <string> of length <nbyte> onto lookahead stack
* if <type> is non-zero, the negation of the character is put
* onto the stack so that it can be checked for KEYTRAP
* putstack() returns 1 except when in the middle of a multi-byte char
*/
{
register int c;
#if SHOPT_MULTIBYTE
do
{
c = (int)((*p) & STRIP);
if(c< 0x80 && c!='<')
{
if (type)
c = -c;
# ifndef CBREAK
if(c == '\0')
{
/*** user break key ***/
ep->e_lookahead = 0;
# if KSHELL
# endif /* KSHELL */
}
# endif /* CBREAK */
}
else
{
if((c=mbchar(p)) >=0)
{
p--; /* incremented below */
if(type)
c = -c;
}
#ifdef EILSEQ
errno = 0;
#endif
{
{
*++endp = 0;
goto again;
}
return(c);
}
else
{
ed_ringbell();
c = -(int)((*p) & STRIP);
}
}
p++;
}
while (p < endp);
/* shift lookahead buffer if necessary */
{
}
#else
while (nbyte > 0)
{
# ifndef CBREAK
if( c == '\0' )
{
/*** user break key ***/
ep->e_lookahead = 0;
# if KSHELL
# endif /* KSHELL */
}
# endif /* CBREAK */
}
#endif /* SHOPT_MULTIBYTE */
return(1);
}
/*
* routine to perform read from terminal for vi and emacs mode
* <mode> can be one of the following:
* -2 vi insert mode - key binding is in effect
* -1 vi control mode - key binding is in effect
* 0 normal command mode - key binding is in effect
* 1 edit keys not mapped
* 2 Next key is literal
*/
{
register int n, c;
if(!ep->e_lookahead)
{
/* The while is necessary for reads of partial multbyte chars */
*ep->e_vi_insert = 0;
}
if(ep->e_lookahead)
{
/* check for possible key mapping */
{
{
}
{
n=1;
{
while(1)
{
if(!ep->e_lookahead)
{
}
if(!ep->e_lookahead)
break;
{
ep->e_lookahead++;
break;
}
c = -c;
readin[n++] = c;
if(c>='0' && c<='9' && n>2)
continue;
if(n>2 || (c!= '[' && c!= 'O'))
break;
}
}
{
}
else
}
else
c = -c;
}
/*** map '\r' to '\n' ***/
c = '\n';
ep->e_tabcount = 0;
}
else
return(c);
}
{
return;
}
/*
* put a character into the output buffer
*/
{
char buf[8];
register int i,size=1;
if(!dp)
return;
buf[0] = c;
#if SHOPT_MULTIBYTE
/* check for place holder */
if(c == MARKER)
return;
{
for (i = 0; i < (size-1); i++)
c = buf[i];
}
else
{
buf[0] = c;
size = 1;
}
#endif /* SHOPT_MULTIBYTE */
{
*dp++ = ' ';
*dp++ = '\b';
}
*dp++ = c;
*dp = '\0';
else
}
/*
* returns the line and column corresponding to offset <off> in the physical buffer
* if <cur> is non-zero and <= <off>, then correspodning <curpos> will start the search
*/
{
#if SHOPT_MULTIBYTE
char p[16];
#endif /* SHOPT_MULTIBYTE */
{
}
else
{
{
}
}
while(off-->0)
{
if(c)
c = *sp++;
#if SHOPT_MULTIBYTE
#else
if(c=='\n')
#endif /* SHOPT_MULTIBYTE */
col = 0;
else
col++;
col = 0;
if(col==0)
}
return(pos);
}
{
static int oldline;
register int delta;
int clear = 0;
if(first < 0)
{
first = 0;
clear = 1;
}
return(new);
if(ep->e_multiline)
{
{
return(new);
}
{
else
plen = 0;
{
else
{
n = plen;
{
while(physical[m] && n-->0)
}
}
}
}
{
}
}
else
if(delta<0)
{
/*** move to left ***/
/*** attempt to optimize cursor movement ***/
{
delta = 0;
}
else
{
else
{
}
}
}
while(delta-->0)
return(new);
}
/*
* copy virtual to physical and return the index for cursor in physical buffer
*/
{
register int c;
int d, r;
{
#if SHOPT_MULTIBYTE
if(d==1 && is_cntrl(c))
d = -1;
if(d>1)
{
/* multiple width character put in place holders */
*dp++ = c;
while(--d >0)
/* in vi mode the cursor is at the last character */
break;
continue;
}
else
#else
#endif /* SHOPT_MULTIBYTE */
if(d<0)
{
if(c=='\t')
{
if(sh_isoption(SH_VI))
while(--c>0)
*dp++ = ' ';
c = ' ';
}
else
{
*dp++ = '^';
c = printchar(c);
}
/* in vi mode the cursor is at the last character */
}
*dp++ = c;
break;
}
*dp = 0;
return(r);
}
#if SHOPT_MULTIBYTE
/*
* convert external representation <src> to an array of genchars <dest>
* <src> and <dest> can be the same
* returns number of chars in dest
*/
{
register int c;
{
return(c);
}
while(*cp)
*dp = 0;
}
/*
* convert internal representation <src> into character array <dest>.
* The <src> and <dest> may be the same.
* returns number of chars in dest.
*/
{
register int c,size;
{
#ifdef _lib_wcscpy
#else
#endif
return(c);
}
{
{
/* copy the character as is */
size = 1;
}
}
*dp = 0;
}
/*
* copy <sp> to <dp>
*/
{
}
/*
* copy at most <n> items from <sp> to <dp>
*/
{
}
#endif /* SHOPT_MULTIBYTE */
/*
* find the string length of <str>
*/
{
while(*sp++);
}
#endif /* SHOPT_ESH || SHOPT_VSH */
#ifdef future
/*
* returns 1 when <n> bytes starting at <a> and <b> are equal
*/
static int compare(register const char *a,register const char *b,register int n)
{
while(n-->0)
{
if(*a++ != *b++)
return(0);
}
return(1);
}
#endif
#if SHOPT_OLDTERMIO
#ifndef ECHOCTL
# define ECHOCTL 0
#endif /* !ECHOCTL */
/*
* For backward compatibility only
* This version will use termios when possible, otherwise termio
*/
{
register int r,i;
return(r);
{
for(i=0; i<NCC; i++)
}
return(r);
}
{
register int r;
{
register int i;
for(i=0; i<NCC; i++)
{
}
switch(mode)
{
case TCSANOW:
break;
case TCSADRAIN:
break;
case TCSAFLUSH:
}
}
}
#endif /* SHOPT_OLDTERMIO */
#if KSHELL
/*
* Execute keyboard trap on given buffer <inbuff> of given size <isize>
* <mode> < 0 for vi insert mode
*/
{
register char *cp;
int savexit;
#if SHOPT_MULTIBYTE
#else
#endif /* SHOPT_MULTIBYTE */
if(mode== -2)
{
}
else
*ep->e_vi_insert = 0;
else if(bufsize>0)
{
}
else
insize = 0;
return(insize);
}
#endif /* KSHELL */
#if SHOPT_EDPREDICT
{
}
{
}
{
{
if(c=='\n' && *cp)
{
n += 2;
if(dp)
{
*dp++ = '^';
*dp++ = 'J';
col +=2;
}
}
else if(c=='\t')
{
n++;
if(dp)
*dp++ = ' ';
}
else
{
if(dp)
{
}
}
}
return(n);
}
{
size_t m;
static int maxmatch;
return(0);
maxmatch = 0;
{
return(0);
}
return(0);
{
{
{
}
*av = 0;
}
}
{
continue;
if(*cp=='#')
continue;
{
l = ed_histlencopy(cp,(char*)0);
ac++;
}
}
if(ac>0)
{
l = ac;
{
l--;
}
*av = 0;
{
{
continue;
}
}
*ar = 0;
}
}
{
if(n)
{
/* don't bother updating the screen if there is typeahead */
if(ep->e_lookahead)
return;
}
else
{
}
if(n)
{
{
last = 0;
{
}
if(last)
{
}
}
last = i-1;
while(i-->0)
}
}
#endif /* SHOPT_EDPREDICT */
{
return((void*)ed);
}
{
if(sz == sizeof(void*))
{
}
else
{
if(sizeof(val)==sizeof(long))
{
}
else if(sizeof(int)!=sizeof(long))
{
}
}
return(r);
}
#ifdef _lib_tcgetattr
{
return(r);
}
{
return(r);
}
#endif