/***********************************************************************
* *
* 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
/* Adapted for ksh by David Korn */
/*+ VI.C P.D. Sullivan
*
* One line editor for the shell based on the vi editor.
*
* Questions to:
* P.D. Sullivan
* cbosgd!pds
-*/
#if KSHELL
# include "defs.h"
#else
# include <ast.h>
# include <ctype.h>
#endif /* KSHELL */
#include "io.h"
#include "history.h"
#include "edit.h"
#include "terminal.h"
#ifdef ECHOCTL
#else
# define echoctl 0
#endif /* ECHOCTL */
#ifndef FIORDCHK
#endif /* FIORDCHK */
#if SHOPT_MULTIBYTE
# include "lexstates.h"
# if !_lib_iswprint && !defined(iswprint)
# endif
static int _isalph(int);
static int _ismetach(int);
static int _isblank(int);
#else
#endif /* SHOPT_MULTIBYTE */
#if ( 'a' == 97) /* ASCII? */
#else
#endif
#ifndef iswascii
#endif
typedef struct _vi_
{
int direction;
int lastmacro;
char repeat_set;
char nonewline;
#ifdef FIORDCHK
#else
#endif /* FIORDCHK */
#if SHOPT_MULTIBYTE
int bigvi;
#endif
} Vi_t;
static void sync_cursor(Vi_t*);
/*+ VI_READ( fd, shbuf, nchar )
*
* This routine implements a one line version of vi and is
* called by _filbuf.c
*
-*/
/*
* if reedit is non-zero, initialize edit buffer with reedit chars
*/
{
register int i; /* general variable */
#if SHOPT_RAWONLY
#else
# ifndef FIORDCHK
# endif /* FIORDCHK */
#endif /* SHOPT_RAWONLY */
if(!vp)
{
}
/*** setup prompt ***/
#if !SHOPT_RAWONLY
if(!viraw)
{
/*** Change the eol characters to '\r' and eof ***/
/* in addition to '\n' and make eof an ESC */
#ifdef FIORDCHK
#else
/* time the current line to determine typeahead */
#endif /* FIORDCHK */
#if KSHELL
/* abort of interrupt has occurred */
i = -1;
else
#endif /* KSHELL */
/*** Read the line ***/
#ifndef FIORDCHK
#endif /* FIORDCHK */
if(echoctl)
{
if( i <= 0 )
{
/*** read error or eof typed ***/
return(i);
}
if( term_char == '\r' )
term_char = '\n';
shbuf[i--] = '\0';
else
}
else
{
register int c = shbuf[0];
/*** Save and remove the last character if its an eol, ***/
/* changing '\r' to '\n' */
if( i == 0 )
{
/*** ESC was typed as first char of line ***/
esc_or_hang = 1;
}
else if( i<0 || c==usreof )
{
/*** read error or eof typed ***/
if( c == usreof )
i = 0;
return(i);
}
else
{
if( term_char == '\r' )
term_char = '\n';
if(term_char=='\n')
{
return(i+1);
}
#endif
{
/*** remove terminator & null terminate ***/
shbuf[i--] = '\0';
}
else
{
/** terminator was ESC, which is not xmitted **/
}
}
}
}
else
#endif /* SHOPT_RAWONLY */
{
/*** Set raw mode ***/
#if !SHOPT_RAWONLY
if( editb.e_ttyspeed == 0 )
{
/*** never did TCGETA, so do it ***/
/* avoids problem if user does 'sh -o viraw' */
}
#endif /* SHOPT_RAWONLY */
i = last_virt-1;
}
/*** Initialize some things ***/
#if SHOPT_MULTIBYTE
shbuf[i+1] = 0;
#endif /* SHOPT_MULTIBYTE */
cur_phys = i + 1;
cur_virt = i;
first_virt = 0;
vp->first_wind = 0;
last_virt = i;
last_phys = i;
vp->ofirst_wind = 0;
window[0] = '\0';
if(!yankbuf)
{
/*** first time for this shell ***/
*yankbuf = 0;
}
/*** fiddle around with prompt length ***/
if( !viraw )
{
int kill_erase = 0;
{
/*** change \r to \n, check for control characters, ***/
/* delete appropriate ^Vs, */
/* and estimate last physical column */
if( virtual[i] == '\r' )
virtual[i] = '\n';
if(!echoctl)
{
register int c = virtual[i];
if( c<=usrerase)
{
/*** user typed escaped erase or kill char ***/
cntl_char = 1;
if(is_print(c))
kill_erase++;
}
else if( !is_print(c) )
{
cntl_char = 1;
if( c == usrlnext )
{
if( i == last_virt )
{
/* so replace ^V with it */
break;
}
/*** delete ^V ***/
--cur_virt;
--last_virt;
}
}
}
}
/*** copy virtual image to window ***/
if(last_virt > 0)
{
/*** line longer than window ***/
}
else
{
/*** Line not terminated with ESC or escaped (^V) ***/
/* eol, so return after doing a total update */
/* if( (speed is greater or equal to 1200 */
/* and something was typed) and */
/* (control character present */
/* or typeahead occurred) ) */
{
if(echoctl)
else
while(kill_erase-- > 0)
putchar(' ');
}
if( term_char=='\n' )
{
if(!echoctl)
}
#if SHOPT_MULTIBYTE
return(last_virt);
#else
return(++last_virt);
#endif /* SHOPT_MULTIBYTE */
}
/* so set raw mode */
{
/*
* The following prevents drivers that return 0 on
* causing an infinite loop
*/
if(esc_or_hang)
return(-1);
#if SHOPT_MULTIBYTE
return(last_virt);
#else
return(++last_virt);
#endif /* SHOPT_MULTIBYTE */
}
if(echoctl) /*** for cntl-echo erase the ^[ ***/
if(crallowed)
{
/*** start over since there may be ***/
/*** a control char, or cursor might not ***/
/*** be at left margin (this lets us know ***/
/*** where we are ***/
cur_phys = 0;
window[0] = '\0';
else
}
else
{
/*** just update everything internally ***/
}
}
/*** Handle usrintr, usrquit, or EOF ***/
if( i != 0 )
{
{
}
virtual[0] = '\0';
switch(i)
{
case UEOF:
/*** EOF ***/
return(0);
case UINTR:
/** interrupt **/
return(-1);
}
return(-1);
}
/*** Get a line from the terminal ***/
if(reedit)
{
}
if(viraw)
else
/*** add a new line if user typed unescaped \n ***/
/* to cause the shell to process the line */
{
}
{
}
if( ++last_virt >= 0 )
{
#if SHOPT_MULTIBYTE
{
}
else
{
}
#endif /* SHOPT_MULTIBYTE */
#if SHOPT_EDPREDICT
#endif /* SHOPT_EDPREDICT */
return(last_virt);
}
else
return(-1);
}
/*{ APPEND( char, mode )
*
* This routine will append char after cur_virt in the virtual image.
* mode = APPEND, shift chars right before appending
* REPLACE, replace char if possible
*
}*/
{
register int i,j;
{
{
for(i = ++last_virt; i > j; --i)
}
}
else
ed_ringbell();
return;
}
/*{ BACKWORD( nwords, cmd )
*
* This routine will position cur_virt at the nth previous word.
*
}*/
{
{
&& tcur_virt>first_virt )
--tcur_virt;
else if(cmd != 'B')
{
--tcur_virt;
}
--tcur_virt;
if( cmd == 'B' )
{
--tcur_virt;
}
else
{
--tcur_virt;
else
&& tcur_virt>=first_virt )
--tcur_virt;
}
}
return;
}
/*{ CNTLMODE()
*
* This routine implements the vi command subset.
* The cursor will always be positioned at the char of interest.
*
}*/
{
register int c;
register int i;
int was_inmacro;
{
/*** save virtual image if never done before ***/
}
first_virt = 0;
{
/*** make sure cursor is at the last char ***/
}
cur_virt++;
/*** Read control char until something happens to cause a ***/
{
vp->repeat_set = 0;
if( c == '0' )
{
/*** move to leftmost column ***/
cur_virt = 0;
continue;
}
if( digit(c) )
{
if( c == '.' )
}
/*** see if it's a move cursor command ***/
{
continue;
}
/*** see if it's a repeat of the last command ***/
if( c == '.' )
{
}
else
{
}
/*** see if it's a text modification command ***/
switch(i)
{
case BAD:
break;
default: /** input mode **/
if(!was_inmacro)
{
}
if( i == GOOD )
continue;
return(i);
}
switch( c )
{
/***** Other stuff *****/
/*** print the prompt and ***/
/* force a total refresh */
putchar('\n');
window[0] = '\0';
break;
case cntl('V'):
{
while(c = *p++)
break;
}
case '/': /** Search **/
case '?':
case 'N':
case 'n':
{
case GOOD:
/*** force a total refresh ***/
window[0] = '\0';
goto newhist;
case BAD:
/*** no match ***/
ed_ringbell();
default:
else
break;
}
break;
case 'j': /** get next command **/
case '+': /** get next command **/
#if SHOPT_EDPREDICT
{
goto ringbell;
goto hupdate;
}
#endif /* SHOPT_EDPREDICT */
{
goto ringbell;
}
{
break;
}
goto newhist;
case 'k': /** get previous command **/
case '-': /** get previous command **/
#if SHOPT_EDPREDICT
{
goto ringbell;
continue;
}
#endif /* SHOPT_EDPREDICT */
{
}
{
goto ringbell;
}
else
{
#if SHOPT_MULTIBYTE
#endif /* SHOPT_MULTIBYTE */
}
#if SHOPT_MULTIBYTE
#endif /* SHOPT_MULTIBYTE */
cur_virt = 0;
#if SHOPT_EDPREDICT
{
if(c=='\n')
cur_virt = 0;
}
#endif /*SHOPT_EDPREDICT */
break;
case 'u': /** undo the last thing done **/
break;
case 'U': /** Undo everything **/
if( virtual[0] == '\0' )
goto ringbell;
else
{
cur_virt = 0;
}
break;
#if KSHELL
case 'v':
if(vp->repeat_set==0)
goto vcommand;
#endif /* KSHELL */
case 'G': /** goto command repeat **/
if(vp->repeat_set==0)
{
goto ringbell;
}
if(c == 'G')
{
goto newhist;
}
#if KSHELL
return(BIGVI);
else
goto ringbell;
#endif /* KSHELL */
case '#': /** insert(delete) # to (no)comment command **/
{
*p = 0;
/*** see whether first char is comment char ***/
c = (virtual[0]=='#');
while(p-- >= virtual)
{
if(*p=='\n' || p<virtual)
{
if(c) /* delete '#' */
{
if(p[1]=='#')
{
last_virt--;
}
}
else
{
}
}
}
if(c)
{
cur_virt = 0;
break;
}
}
case '\n': /** send to shell **/
#if SHOPT_EDPREDICT
return(ENTER);
case '\t': /** bring choice to edit **/
{
goto ringbell;
goto newhist;
}
goto ringbell;
#else
return(ENTER);
#endif /* SHOPT_EDPREDICT */
case ESC:
/* don't ring bell if next char is '[' */
if(!lookahead)
{
char x;
}
if(lookahead)
{
if(c=='[')
{
continue;
}
}
default:
ed_ringbell();
continue;
}
}
/* NOTREACHED */
return(0);
}
/*{ CURSOR( new_current_physical )
*
* This routine will position the virtual cursor at
* physical column x in the window.
*
}*/
{
#if SHOPT_MULTIBYTE
x++;
#endif /* SHOPT_MULTIBYTE */
}
/*{ DELETE( nchars, mode )
*
* Delete nchars from the virtual space and leave cur_virt positioned
* at cur_virt-1.
*
* If mode = 'c', do not save the characters deleted
* = 'd', save them in yankbuf and delete.
* = 'y', save them in yankbuf but do not delete.
*
}*/
{
register int i;
if( cur_virt < first_virt )
{
ed_ringbell();
return;
}
if( nchars > 0 )
{
{
/*** set nchars to number actually deleted ***/
}
/*** save characters to be deleted ***/
if( mode != 'c' )
{
}
/*** now delete these characters ***/
if( mode != 'y' )
{
}
}
return;
}
/*{ DEL_LINE( mode )
*
* This routine will delete the line.
* mode = GOOD, do a save_v()
*
}*/
{
return;
cur_virt = 0;
first_virt = 0;
cur_phys = 0;
vp->first_wind = 0;
vp->ofirst_wind = 0;
window[0] = '\0';
return;
}
/*{ DELMOTION( motion, mode )
*
* Delete thru motion.
*
* mode = 'd', save deleted characters, delete
* = 'c', do not save characters, change
* = 'y', save characters, yank
*
* Returns 1 if operation successful; else 0.
*
}*/
{
/* the following saves a register */
return(0);
if( mode != 'y' )
/*** fake out the motion routines by appending a blank ***/
if(!end)
return(0);
{
/*** called by change operation, user really expects ***/
/* the effect of the eE commands, so back up to end of word */
--end;
++end;
}
if( delta >= 0 )
{
++delta;
}
else
{
}
if( mode == 'y' )
return(1);
}
/*{ ENDWORD( nwords, cmd )
*
* This routine will move cur_virt to the end of the nth word.
*
}*/
{
while( nwords-- )
{
++tcur_virt;
++tcur_virt;
if( cmd == 'E' )
{
++tcur_virt;
}
else
{
++tcur_virt;
else
++tcur_virt;
}
if( tcur_virt > first_virt )
tcur_virt--;
}
return;
}
/*{ FORWARD( nwords, cmd )
*
* This routine will move cur_virt forward to the next nth word.
*
}*/
{
while( nwords-- )
{
if( cmd == 'W' )
{
++tcur_virt;
}
else
{
{
++tcur_virt;
}
else
{
++tcur_virt;
}
}
++tcur_virt;
}
return;
}
/*{ GETCOUNT(c)
*
* Set repeat to the user typed number and return the terminating
* character.
*
}*/
{
register int i;
/*** get any repeat count ***/
if( c == '0' )
return(c);
vp->repeat_set++;
i = 0;
while( digit(c) )
{
i = i*10 + c - '0';
}
if( i > 0 )
return(c);
}
/*{ GETLINE( mode )
*
* This routine will fetch a line.
* mode = APPEND, allow escape to cntlmode subroutine
* appending characters.
* = REPLACE, allow escape to cntlmode subroutine
* replacing characters.
* = SEARCH, no escape allowed
* = ESC, enter control mode immediately
*
* The cursor will always be positioned after the last
* char printed.
*
* This routine returns when cr, nl, or (eof in column 0) is
* received (column 0 is the first char position).
*
}*/
{
register int c;
register int tmp;
{
/*** go directly to control mode ***/
goto escape;
}
for(;;)
{
c = UEOF;
else if( c == usrerase )
c = UERASE;
else if( c == usrkill )
c = UKILL;
c = UWERASE;
else if( c == usrlnext )
c = ULNEXT;
c = UINTR;
if( c == ULNEXT)
{
/*** implement ^V to escape next char ***/
continue;
}
if(c!='\t')
switch( c )
{
case ESC: /** enter control mode **/
if(!sh_isoption(SH_VI))
{
break;
}
{
ed_ringbell();
continue;
}
else
{
{
{
}
--cur_virt;
}
{
#if SHOPT_MULTIBYTE
#endif /* SHOPT_MULTIBYTE */
return;
}
{
continue;
}
{
if(c >= MAXLINE)
c = MAXLINE-1;
}
}
break;
case UINTR:
first_virt = 0;
cur_virt = -1;
return;
case UERASE: /** user erase char **/
/*** treat as backspace ***/
case '\b': /** backspace **/
{
}
else
{
{
first_virt = 0;
return;
}
{
if(cur_virt<=first_virt)
ed_ringbell();
--cur_virt;
continue;
}
else
}
break;
case UWERASE: /** delete back word **/
if( cur_virt > first_virt &&
{
}
else
{
}
break;
case UKILL: /** user kill line char **/
{
}
else
{
{
cur_virt = 1;
}
else if(first_virt)
{
}
else
}
break;
case UEOF: /** eof char **/
continue;
case '\n': /** newline or return **/
return;
case '\t': /** command completion **/
if(mode!=SEARCH && last_virt>=0 && (vp->ed->e_tabcount|| !isblank(cur_virt)) && vp->ed->sh->nextprompt)
{
{
break;
}
{
goto escape;
}
{
goto escape;
}
}
/* FALL THRU*/
default:
{
{
continue;
}
}
break;
}
}
}
/*{ MVCURSOR( motion )
*
* This routine will move the virtual cursor according to motion
* for repeat times.
*
* It returns GOOD if successful; else BAD.
*
}*/
{
register int count;
register int tcur_virt;
register int bound = 0;
switch(motion)
{
/***** Cursor move commands *****/
case '0': /** First column **/
tcur_virt = 0;
break;
case '^': /** First nonblank character **/
++tcur_virt;
break;
case '|':
break;
/* fall through */
case '$': /** End of line **/
break;
case '[':
{
case 'A':
#if SHOPT_EDPREDICT
#else
#endif /* SHOPT_EDPREDICT */
{
#if SHOPT_MULTIBYTE
#else
#endif /* SHOPT_MULTIBYTE */
*lsearch = '^';
}
else
return(1);
case 'B':
return(1);
case 'C':
incr = 1;
goto walk;
case 'D':
motion = first_virt;
goto walk;
case 'H':
tcur_virt = 0;
break;
case 'Y':
break;
default:
return(0);
}
break;
case 'h': /** Left one **/
case '\b':
motion = first_virt;
goto walk;
case ' ':
case 'l': /** Right one **/
incr = 1;
walk:
{
}
else
return(0);
break;
case 'B':
case 'b': /** back word **/
return(0);
return(1);
case 'E':
case 'e': /** end of word **/
if(tcur_virt >=0)
return(0);
return(1);
case ',': /** reverse find old char **/
case ';': /** find old char **/
{
case 't':
case 'f':
if(motion==';')
{
incr = 1;
}
goto find_b;
case 'T':
case 'F':
if(motion==',')
{
incr = 1;
}
goto find_b;
default:
return(0);
}
case 't': /** find up to new char forward **/
case 'f': /** find new char forward **/
incr = 1;
case 'T': /** find up to new char backward **/
case 'F': /** find new char backward **/
return(1);
while( count-- )
{
{
return(0);
}
}
break;
case '%':
{
int nextmotion;
int nextc;
tcur_virt++;
return(0);
if(count < 3)
{
incr = 1;
}
else
count = 1;
{
count--;
count++;
}
if(count)
return(0);
break;
}
case 'W':
case 'w': /** forward word **/
return(0);
return(1);
default:
return(0);
}
return(1);
}
/*
* print a string
*/
{
/*** copy string sp ***/
while(*sp)
return;
}
/*{ PUTSTRING( column, nchars )
*
* Put nchars starting at column of physical into the workspace
* to be printed.
*
}*/
{
while( nchars-- )
return;
}
/*{ REFRESH( mode )
*
* This routine will refresh the crt so the physical image matches
* the virtual image and display the proper window.
*
* mode = CONTROL, refresh in control mode, ie. leave cursor
* positioned at last char printed.
* = INPUT, refresh in input mode; leave cursor positioned
* after last char printed.
* = TRANSLATE, perform virtual to physical translation
* and adjust left margin only.
*
* +-------------------------------+
* | | | virtual | | |
* +-------------------------------+
* cur_virt last_virt
*
* +-----------------------------------------------+
* | | | physical | | |
* +-----------------------------------------------+
* cur_phys last_phys
*
* 0 w_size - 1
* +-----------------------+
* | | | window |
* +-----------------------+
* cur_window = cur_phys - first_wind
}*/
{
register int p;
register int v;
int p_differ;
int new_lw;
int ncur_phys;
# define w v
/*** find out if it's necessary to start translating at beginning ***/
if(lookahead>0)
{
}
v = cur_virt;
#if SHOPT_EDPREDICT
{
int n;
# if SHOPT_MULTIBYTE
# endif /* SHOPT_MULTIBYTE */
# if SHOPT_MULTIBYTE
# endif /* SHOPT_MULTIBYTE */
{
}
else
ed_ringbell();
}
#endif /* SHOPT_EDPREDICT */
{
opflag = 0;
p = 0;
v = 0;
}
else
{
opflag = 1;
{
/*** avoid double ^'s ***/
++p;
++v;
}
}
if( --p < 0 )
last_phys = 0;
else
last_phys = p;
/*** see if this was a translate only ***/
return;
/*** adjust left margin if necessary ***/
{
if( first_w < 0 )
first_w = 0;
}
/*** attempt to optimize search somewhat to find ***/
/*** out where physical and window images differ ***/
{
w = p - first_w;
}
else
{
p = first_w;
w = 0;
}
{
break;
}
p_differ = p;
{
/*** images are identical ***/
return;
}
/*** copy the physical image to the window image ***/
{
}
new_lw = w;
/*** erase trailing characters if needed ***/
window[w++] = ' ';
p = p_differ;
/*** move cursor to start of difference ***/
/*** and output difference ***/
w = p - first_w;
{
if( first_w == 0 )
else
}
else
{
/*** indicate lines longer than window ***/
while( w++ < w_size )
{
putchar(' ');
++cur_phys;
}
++cur_phys;
}
++ncur_phys;
return;
}
/*{ REPLACE( char, increment )
*
* Replace the cur_virt character with char. This routine attempts
* to avoid using refresh().
*
* increment = 1, increment cur_virt after replacement.
* = 0, leave cur_virt where it is.
*
}*/
{
register int cur_window;
{
/*** can't replace invalid cursor ***/
ed_ringbell();
return;
}
#if SHOPT_MULTIBYTE
#endif /* SHOPT_MULTIBYTE */
{
/*** must use standard refresh routine ***/
++cur_virt;
}
else
{
window[cur_window] = c;
putchar(c);
if(increment)
{
++cur_phys;
}
else
{
putchar('\b');
}
}
return;
}
/*{ RESTORE_V()
*
* Restore the contents of virtual space from u_space.
*
}*/
{
register int tmpcol;
{
/*** never saved anything ***/
ed_ringbell();
return;
}
return;
}
/*{ SAVE_LAST()
*
* If the user has typed something, save it in last line.
*
}*/
{
register int i;
{
/*** save last thing user typed ***/
if(i >= MAXLINE)
i = MAXLINE-1;
}
return;
}
/*{ SAVE_V()
*
* This routine will save the contents of virtual in u_space.
*
}*/
{
if(!inmacro)
{
}
return;
}
/*{ SEARCH( mode )
*
* Search history file for regular expression.
*
* mode = '/' require search string and search new to old
* mode = '?' require search string and search old to new
* mode = 'N' repeat last search in reverse direction
* mode = 'n' repeat last search
*
}*/
/*
* search for <string> in the current command
*/
{
#if SHOPT_MULTIBYTE
#endif /* SHOPT_MULTIBYTE */
{
}
#if SHOPT_MULTIBYTE
#endif /* SHOPT_MULTIBYTE */
return(-1);
}
{
register int new_direction;
register int oldcurhline;
register int i;
{
/*** new search expression ***/
first_virt = 1;
first_virt = 0;
}
{
/*** no operation ***/
return(ABORT);
}
{
/*** user wants repeat of last search ***/
#if SHOPT_MULTIBYTE
*((char*)virtual) = '/';
#endif /* SHOPT_MULTIBYTE */
}
if( mode == 'N' )
else
/*** now search ***/
#if SHOPT_MULTIBYTE
#endif /* SHOPT_MULTIBYTE */
{
}
else
{
i = INVALID;
}
cur_virt = i;
{
return(GOOD);
}
/*** could not find matching line ***/
return(BAD);
}
/*{ SYNC_CURSOR()
*
* This routine will move the physical cursor to the same
* column as the virtual cursor.
*
}*/
{
register int p;
register int v;
register int c;
int new_phys;
return;
/*** find physical col that corresponds to virtual col ***/
new_phys = 0;
{
/*** try to optimize search a little ***/
#if SHOPT_MULTIBYTE
p++;
#endif /* SHOPT_MULTIBYTE */
}
else
{
p = 0;
v = 0;
}
for(; v <= last_virt; ++p, ++v)
{
#if SHOPT_MULTIBYTE
int d;
c = virtual[v];
if((d = mbwidth(c)) > 1)
{
if( v != cur_virt )
p += (d-1);
}
else if(!iswprint(c))
#else
c = virtual[v];
if(!isprint(c))
#endif /* SHOPT_MULTIBYTE */
{
if( c == '\t' )
{
p += (TABSIZE-1);
}
else
{
++p;
}
}
if( v == cur_virt )
{
new_phys = p;
break;
}
}
{
/*** asked to move outside of window ***/
window[0] = '\0';
return;
}
return;
}
/*{ TEXTMOD( command, mode )
*
* Modify text operations.
*
* mode != 0, repeat previous operation
*
}*/
{
register int i;
if( fold(c) == 'P' )
{
/*** change p from lastline to yankbuf ***/
p = yankbuf;
}
switch( c )
{
/***** Input commands *****/
#if KSHELL
case '\t':
return(BAD);
c = '=';
case '*': /** do file name expansion in place **/
case '\\': /** do file name completion in place **/
return(BAD);
case '=': /** list file name expansions **/
i = last_virt;
++last_virt;
{
{
--last_virt;
return(APPEND);
}
last_virt = i;
ed_ringbell();
}
{
last_virt = i;
return(GOOD);
}
else
{
--cur_virt;
--last_virt;
return(APPEND);
}
break;
case '@': /** macro expansion **/
if( mode )
else
return(GOOD);
if(!inmacro)
{
inmacro++;
return(GOOD);
}
ed_ringbell();
return(BAD);
#endif /* KSHELL */
case '_': /** append last argument of prev command **/
{
if(vp->repeat_set==0)
if(p==0)
{
ed_ringbell();
break;
}
#if SHOPT_MULTIBYTE
ed_internal((char*)p,tmpbuf);
p = tmpbuf;
#endif /* SHOPT_MULTIBYTE */
i = ' ';
do
{
}
while(i = *p++);
return(APPEND);
}
case 'A': /** append to end of line **/
case 'a': /** append **/
{
c = 'p';
goto addin;
}
{
}
return(APPEND);
case 'I': /** insert at beginning of line **/
case 'i': /** insert **/
{
c = 'P';
goto addin;
}
{
first_virt = cur_virt--;
}
return(INSERT);
case 'C': /** change to eol **/
c = '$';
goto chgeol;
case 'c': /** change **/
if( mode )
c = vp->lastmotion;
else
vp->lastmotion = c;
if( c == 'c' )
{
return(APPEND);
}
return(BAD);
if( mode == 'c' )
{
c = 'p';
trepeat = 1;
goto addin;
}
return(APPEND);
case 'D': /** delete to eol **/
c = '$';
goto deleol;
case 'd': /** delete **/
if( mode )
c = vp->lastmotion;
else
vp->lastmotion = c;
if( c == 'd' )
{
break;
}
return(BAD);
++cur_virt;
break;
case 'P':
if( p[0] == '\0' )
return(BAD);
{
if(!is_print(i))
--cur_virt;
}
case 'p': /** print **/
if( p[0] == '\0' )
return(BAD);
{
if( c == 'P' )
{
/*** fix stored cur_virt ***/
}
}
if( mode == 'R' )
else
savep = p;
for(i=0; i<trepeat; ++i)
{
while(c= *p++)
p = savep;
}
break;
case 'R': /* Replace many chars **/
if( mode == 'R' )
{
c = 'P';
goto addin;
}
return(REPLACE);
case 'r': /** replace **/
if( mode )
c = *p;
else
return(GOOD);
*p = c;
while(trepeat--)
return(GOOD);
case 'S': /** Substitute line - cc **/
c = 'c';
goto chgeol;
case 's': /** substitute **/
if( mode )
{
c = 'p';
trepeat = 1;
goto addin;
}
return(APPEND);
case 'Y': /** Yank to end of line **/
c = '$';
goto yankeol;
case 'y': /** yank thru motion **/
if( mode )
c = vp->lastmotion;
else
vp->lastmotion = c;
if( c == 'y' )
{
}
{
return(BAD);
}
break;
case 'x': /** delete repeat chars forward - dl **/
c = 'l';
goto deleol;
case 'X': /** delete repeat chars backward - dh **/
c = 'h';
goto deleol;
case '~': /** invert case and advance **/
{
i = INVALID;
{
i = cur_virt;
#if SHOPT_MULTIBYTE
if((c&~STRIP)==0)
#endif /* SHOPT_MULTIBYTE */
if( isupper(c) )
c = tolower(c);
else if( islower(c) )
c = toupper(c);
}
return(GOOD);
}
else
return(BAD);
default:
return(BAD);
}
return(GOOD);
}
#if SHOPT_MULTIBYTE
static int _isalph(register int v)
{
#ifdef _lib_iswalnum
return(iswalnum(v) || v=='_');
#else
#endif
}
static int _isblank(register int v)
{
}
static int _ismetach(register int v)
{
}
#endif /* SHOPT_MULTIBYTE */
/*
* get a character, after ^V processing
*/
{
register int c;
return(c);
}