/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1984-2011 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> *
* Pat Sullivan *
* *
***********************************************************************/
/*
* edit.c - common routines for vi and emacs one line editors in shell
*
* David Korn P.D. Sullivan
* AT&T Bell Laboratories AT&T Bell Laboratories
* Room 3C-526B Room 1B-286
* Murray Hill, N. J. 07974 Columbus, OH 43213
* Tel. x7975 Tel. x 2655
*
* Coded April 1983.
*/
#ifdef KSHELL
# include "defs.h"
# include "terminal.h"
# include "builtins.h"
# include "sym.h"
#else
# include "io.h"
# include "terminal.h"
extern char ed_errbuf[];
#endif /* KSHELL */
#include "history.h"
#include "edit.h"
#include <error.h>
#define GOOD 0
#ifdef OLDTERMIO
#endif /* OLDTERMIO */
#ifdef RT
#endif /* RT */
#ifdef _hdr_sgtty
# ifdef TIOCGETP
static int l_mask;
# endif /* TIOCGETP */
#endif /* _hdr_sgtty */
#ifndef IODELAY
#endif /* IODELAY */
#ifdef _SELECT5_
# ifndef included_sys_time
# endif /* included_sys_time */
static int delay;
# ifndef KSHELL
600,1200,1800,2400,9600,19200,0};
# endif /* KSHELL */
#endif /* _SELECT5_ */
#ifdef KSHELL
extern char *sh_tilde();
#else
# define slowsig() (0)
#endif /* KSHELL */
#ifdef future
static int compare();
#endif
# ifdef tenex
static char *overlay();
# endif /* tenex */
#endif /* VSH || ESH */
/*
* This routine returns true if fd refers to a terminal
* This should be equivalent to isatty
*/
int fd;
{
savefd = -1;
}
/*
* Get the current terminal attributes
* This routine remembers the attributes and just returns them if it
* is called again without an intervening tty_set()
*/
int fd;
{
{
#ifndef SIG_NORESTART
#endif /* SIG_NORESTART */
{
{
#ifndef SIG_NORESTART
#endif /* SIG_NORESTART */
return(SYSERR);
}
errno = 0;
}
#ifndef SIG_NORESTART
#endif /* SIG_NORESTART */
}
if(tty)
return(0);
}
/*
* Set the terminal attributes
* If fd<0, then current attributes are invalidated
*/
/* VARARGS 2 */
{
if(fd >=0)
{
#ifndef SIG_NORESTART
#endif /* SIG_NORESTART */
#ifdef future
return(0);
#endif
#ifndef SIG_NORESTART
#endif /* SIG_NORESTART */
{
{
#ifndef SIG_NORESTART
#endif /* SIG_NORESTART */
return(SYSERR);
}
errno = 0;
}
#ifndef SIG_NORESTART
#endif /* SIG_NORESTART */
}
return(0);
}
/*{ TTY_COOKED( fd )
*
* This routine will set the tty in cooked mode.
* It is also called by error.done().
*
}*/
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.
*
}*/
register int fd;
{
#ifdef L_MASK
#endif /* L_MASK */
return(GOOD);
#ifndef RAWONLY
#endif /* RAWONLY */
{
return(BAD);
}
return(BAD);
# ifdef CBREAK
# else
# endif /* CBREAK */
return(BAD);
# ifdef _SELECT5_
# endif /* _SELECT5_ */
# ifdef TIOCGLTC
/* try to remove effect of ^V and ^Y and ^O */
{
}
# endif /* TIOCGLTC */
#else
return(BAD);
# ifdef FLUSHO
# endif /* FLUSHO */
# ifndef u370
# else
# endif /* u370 */
# ifdef VDISCARD
# endif /* VDISCARD */
# ifdef VWERASE
# endif /* VWERASE */
# ifdef VLNEXT
# endif /* VLNEXT */
return(BAD);
#endif
return(GOOD);
}
#ifndef RAWONLY
/*
*
* Get tty parameters and make ESC and '\r' wakeup characters.
*
*/
# ifdef TIOCGETC
register int fd;
{
int mask;
return(GOOD);
tty_cooked(fd);
l_changed = 0;
if( editb.e_ttyspeed == 0)
{
}
return(BAD);
return(BAD);
return(BAD);
{
return(BAD);
}
return(GOOD);
}
# else
# ifndef PENDIN
# define PENDIN 0
# endif /* PENDIN */
# ifndef IEXTEN
# define IEXTEN 0
# endif /* IEXTEN */
register int fd;
{
return(GOOD);
tty_cooked(fd);
return(BAD);
# ifdef FLUSHO
# endif /* FLUSHO */
# ifdef ECHOCTL
/* escape character echos as ^[ */
# else
/* switch VEOL2 and EOF, since EOF isn't echo'd by driver */
# endif /* ECHOCTL */
# ifdef VWERASE
# endif /* VWERASE */
# ifdef VLNEXT
# endif /* VLNEXT */
return(BAD);
return(GOOD);
}
# endif /* TIOCGETC */
#endif /* RAWONLY */
/*
* ED_WINDOW()
*
* return the window size
*/
#ifdef _sys_stream
#endif /* _sys_stream */
#ifdef _sys_ptem
#endif /* _sys_ptem */
#ifdef _sys_jioctl
# ifdef TIOCGWINSZ
# endif /* TIOCGWINSZ */
#endif /* _sys_jioctl */
int ed_window()
{
register int n = DFLTWINDOW-1;
if(cp)
{
if(n > MAXWINDOW)
n = MAXWINDOW;
}
#ifdef TIOCGWINSZ
else
{
/* for 5620's and 630's */
}
#endif /*TIOCGWINSZ */
if(n < MINWINDOW)
n = MINWINDOW;
return(n);
}
/* E_FLUSH()
*
* Flush the output buffer.
*
*/
void ed_flush()
{
if(n<=0)
return;
#ifdef _SELECT5_
{
/* delay until output drains */
n *= 10;
}
#else
# ifdef IODELAY
# endif /* IODELAY */
#endif /* _SELECT5_ */
}
/*
* send the bell character ^G to the terminal
*/
void ed_ringbell()
{
}
/*
* send a carriage return line feed to the terminal
*/
void ed_crlf()
{
#ifdef cray
ed_putchar('\r');
#endif /* cray */
#ifdef u370
ed_putchar('\r');
#endif /* u370 */
#ifdef VENIX
ed_putchar('\r');
#endif /* VENIX */
ed_putchar('\n');
ed_flush();
}
/* E_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.
*/
int fd;
{
register char *pp;
register char *last;
char *ppmax;
int myquote = 0;
char inquote = 0;
#ifdef KSHELL
#else
#endif /* KSHELL */
if(hist_ptr)
{
}
else
{
}
*pp++ = '\r';
{
register int c;
while(c= *last++) switch(c)
{
case '\r':
/*FALLTHROUGH*/
case '\n':
/* start again */
qlen = 1;
inquote = 0;
break;
case '\t':
/* expand tabs */
{
break;
*pp++ = ' ';
}
break;
case BELL:
/* cut out bells */
break;
default:
if(c==myquote)
{
inquote ^= 1;
}
{
*pp++ = c;
}
}
}
*pp = 0;
{
}
p_flush();
}
#ifdef KSHELL
/*
* look for edit macro named _i
* if found, puts the macro definition into lookahead buffer and returns 1
*/
ed_macro(i)
register int i;
{
register char *out;
if(i != '@')
macro[1] = i;
/* undocumented feature, macros of the form <ESC>[c evoke alias __c */
if(i=='_')
else
macro[2] = 0;
{
#ifdef MULTIBYTE
/* copy to buff in internal representation */
#else
#endif /* MULTIBYTE */
while(i-- > 0)
ed_ungetchar(buff[i]);
return(1);
}
return(0);
}
/*
* file name generation for edit modes
* non-zero exit for error, <0 ring bell
* don't search back past beginning of the buffer
* mode is '*' for inline expansion,
* mode is '\' for filename completion
* mode is '=' cause files to be listed in select format
*/
char outbuff[];
int *cur;
int *eol;
int mode;
{
register char *out;
char *begin;
int addstar;
int istilde = 0;
int rval = 0;
int strip;
#ifdef MULTIBYTE
{
register int c = *cur;
/* adjust cur */
c = *cp;
*cp = 0;
*cp = c;
}
#endif /* MULTIBYTE */
{
register int c;
int chktilde;
char *cp;
{
/* go to beginning of word */
do
{
out--;
c = *(unsigned char*)out;
}
/* copy word into arg */
if(isqmeta(c))
out++;
}
else
/* addstar set to zero if * should not be added */
addstar = '*';
strip = 1;
/* copy word to arg and do ~ expansion */
do
{
c = *(unsigned char*)out;
if(isexp(c))
addstar = 0;
if ((c == '/') && (addstar == 0))
strip = 0;
stakputc(c);
if(chktilde && (c==0 || c == '/'))
{
chktilde=0;
*out = 0;
{
istilde++;
stakputc(c);
if(c==0)
{
addstar = 0;
strip = 0;
}
}
*out = c;
}
out++;
} while (c && !isqmeta(c));
out--;
#ifdef tenex
if(mode=='\\')
addstar = '*';
#endif /* tenex */
stakfreeze(1);
}
if(mode!='*')
{
register char **com;
int narg;
register int size;
/* match? */
{
rval = -1;
goto done;
}
if(mode=='=')
{
if (strip)
{
register char **ptrcom;
/* trim directory prefix */
}
newline();
p_flush();
goto done;
}
/* see if there is enough room */
#ifdef tenex
if(mode=='\\')
{
/* just expand until name is unique */
}
else
#endif
{
{
while (*com)
}
}
/* see if room for expansion */
{
com[1] = 0;
}
/* save remainder of the buffer */
#ifdef tenex
if(mode=='\\')
{
*out++ = ' ';
if(*begin==0)
ed_ringbell();
}
else
#endif
while (*com)
{
*out++ = ' ';
}
/* restore rest of buffer */
}
done:
#ifdef MULTIBYTE
{
register int c;
/* first re-adjust cur */
c = *out;
*out = 0;
*out = c;
}
#endif /* MULTIBYTE */
return(rval);
}
# ifdef tenex
{
str++;
*str = 0;
return(str);
}
# endif
/*
* Enter the fc command on the current history line
*/
{
register char *cp;
return(BAD);
/* use EDITOR on current command */
{
return(BAD);
hist_flush();
}
return(GOOD);
}
#endif /* KSHELL */
/*
* routine to perform read from terminal for vi and emacs mode
*/
int
{
register int i;
register int c;
#ifdef MULTIBYTE
static int curchar;
static int cursize;
#endif /* MULTIBYTE */
if (lookahead)
{
/*** map '\r' to '\n' ***/
if(c == '\r' && !in_raw)
c = '\n';
return(c);
}
ed_flush() ;
/*
* you can't chance read ahead at the end of line
* or when the input is a pipe
*/
#ifdef KSHELL
#else
#endif /* KSHELL */
nchar = 1;
/* Set 'i' to indicate read failed, in case intr set */
#ifdef MULTIBYTE
#endif /* MULTIBYTE */
i = -1;
errno = 0;
{
errno=0;
break;
}
#ifdef MULTIBYTE
i = 0;
while (i < maxtry)
{
next:
if(cursize-- > 0)
{
if(cursize==0)
{
c = curchar;
goto gotit;
}
else if(i>=maxtry)
goto retry;
continue;
}
{
if(curchar != 1)
c = 0;
if(c)
goto next;
else if(i>=maxtry)
goto retry;
continue;
}
#else
while (i > 0)
{
#endif /* MULTIBYTE */
#ifndef CBREAK
if( c == '\0' )
{
/*** user break key ***/
lookahead = 0;
# ifdef KSHELL
# endif /* KSHELL */
}
#endif /* !CBREAK */
}
#ifdef MULTIBYTE
/* shift lookahead buffer if necessary */
if(lookahead)
{
}
#endif /* MULTIBYTE */
if (lookahead > 0)
return(ed_getchar());
return(0);
/* NOTREACHED */
}
void ed_ungetchar(c)
register int c;
{
return;
}
/*
* put a character into the output buffer
*/
void ed_putchar(c)
register int c;
{
#ifdef MULTIBYTE
register int d;
/* check for place holder */
if(c == MARKER)
return;
if(d = icharset(c))
{
if(d == 2)
else if(d == 3)
d = in_csize(d);
while(--d>0)
c |= HIGHBIT;
}
#endif /* MULTIBYTE */
if (c == '_')
{
*dp++ = ' ';
*dp++ = '\b';
}
*dp++ = c;
*dp = '\0';
ed_flush();
else
}
/*
* copy virtual to physical and return the index for cursor in physical buffer
*/
{
register int c;
int r;
#ifdef MULTIBYTE
int d;
#endif /* MULTIBYTE */
{
#ifdef MULTIBYTE
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
#endif /* MULTIBYTE */
if(!isprint(c))
{
if(c=='\t')
{
while(--c>0)
*dp++ = ' ';
c = ' ';
}
else
{
*dp++ = '^';
c ^= TO_PRINT;
}
/* in vi mode the cursor is at the last character */
}
*dp++ = c;
break;
}
*dp = 0;
return(r);
}
#ifdef 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 unsigned char *src;
{
register int c;
register int d;
register int size;
{
return(c);
}
while(c = *src++)
{
{
d = (size==1?c:0);
c = size;
if(d)
{
size--;
c = (c<<7) | (d&~HIGHBIT);
}
while(size-- >0)
}
*dp++ = c;
}
*dp = 0;
}
/*
* convert internal representation <src> into character array <dest>.
* The <src> and <dest> may be the same.
* returns number of chars in dest.
*/
char *dest;
{
register int c;
register int d;
{
return(c);
}
{
if(d = icharset(c))
{
if(d == 2)
else if(d == 3)
d = in_csize(d);
while(--d>0)
c |= HIGHBIT;
}
*dp++ = c;
}
*dp = 0;
}
/*
* copy <sp> to <dp>
*/
{
}
/*
* copy at most <n> items from <sp> to <dp>
*/
register int n;
{
}
/*
* find the string length of <str>
*/
{
while(*sp++);
}
#endif /* MULTIBYTE */
#endif /* ESH || VSH */
#ifdef MULTIBYTE
/*
* set the multibyte widths
* format of string is x1[:y1][,x2[:y2][,x3[:y3]]]
* returns 1 if string in not in this format, 0 otherwise.
*/
extern char int_charsize[];
char *string;
{
register int indx = 0;
register int state = 0;
register int c;
register int n = 0;
while(1) switch(c = *string++)
{
case ':':
if(state!=1)
return(1);
state++;
/* fall through */
case 0:
case ',':
if(state==0)
return(1);
if(state==1)
if(c==0)
{
for(n=1;n<= 3;n++)
{
int_charsize[n] = widths[c++];
}
return(0);
}
else if(c==',')
state = 0;
n = 0;
break;
case '0': case '1': case '2': case '3': case '4':
if(state&1)
return(1);
n = c - '0';
state++;
break;
default:
return(1);
}
/* NOTREACHED */
}
#endif /* MULTIBYTE */
#ifdef future
/*
* returns 1 when <n> bytes starting at <a> and <b> are equal
*/
static int compare(a,b,n)
register char *a;
register char *b;
register int n;
{
while(n-->0)
{
if(*a++ != *b++)
return(0);
}
return(1);
}
#endif
#ifdef OLDTERMIO
#ifndef ECHOCTL
# define ECHOCTL 0
#endif /* !ECHOCTL */
char echoctl;
static char tcgeta;
/*
* For backward compatibility only
* This version will use termios when possible, otherwise termio
*/
{
register int r;
register int i;
tcgeta = 0;
return(r);
{
for(i=0; i<NCC; i++)
tcgeta++;
echoctl = 0;
}
return(r);
}
register int mode;
{
register int r;
if(tcgeta)
{
register int i;
for(i=0; i<NCC; i++)
{
}
switch(mode)
{
case TCSANOW:
break;
case TCSADRAIN:
break;
case TCSAFLUSH:
}
}
}
#endif /* OLDTERMIO */