14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1982-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * David Korn <dgk@research.att.com> *
184887Schin * *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /* Adapted for ksh by David Korn */
224887Schin /*+ VI.C P.D. Sullivan
234887Schin *
244887Schin * One line editor for the shell based on the vi editor.
254887Schin *
264887Schin * Questions to:
274887Schin * P.D. Sullivan
284887Schin * cbosgd!pds
294887Schin -*/
304887Schin
314887Schin
324887Schin #if KSHELL
334887Schin # include "defs.h"
344887Schin #else
354887Schin # include <ast.h>
364887Schin # include "FEATURE/options"
3710898Sroland.mainz@nrubsig.org # include <ctype.h>
384887Schin #endif /* KSHELL */
394887Schin #include "io.h"
404887Schin
414887Schin #include "history.h"
424887Schin #include "edit.h"
434887Schin #include "terminal.h"
444887Schin #include "FEATURE/time"
454887Schin
464887Schin #if SHOPT_OLDTERMIO
474887Schin # undef ECHOCTL
484887Schin # define echoctl (vp->ed->e_echoctl)
494887Schin #else
504887Schin # ifdef ECHOCTL
514887Schin # define echoctl ECHOCTL
524887Schin # else
534887Schin # define echoctl 0
544887Schin # endif /* ECHOCTL */
554887Schin #endif /*SHOPT_OLDTERMIO */
564887Schin
574887Schin #ifndef FIORDCHK
584887Schin # define NTICKS 5 /* number of ticks for typeahead */
594887Schin #endif /* FIORDCHK */
604887Schin
614887Schin #define MAXCHAR MAXLINE-2 /* max char per line */
624887Schin
634887Schin #if SHOPT_MULTIBYTE
644887Schin # include "lexstates.h"
654887Schin # define gencpy(a,b) ed_gencpy(a,b)
664887Schin # define genncpy(a,b,n) ed_genncpy(a,b,n)
674887Schin # define genlen(str) ed_genlen(str)
684887Schin # define digit(c) ((c&~STRIP)==0 && isdigit(c))
694887Schin # define is_print(c) ((c&~STRIP) || isprint(c))
704887Schin # if !_lib_iswprint && !defined(iswprint)
714887Schin # define iswprint(c) ((c&~0177) || isprint(c))
724887Schin # endif
734887Schin static int _isalph(int);
744887Schin static int _ismetach(int);
754887Schin static int _isblank(int);
764887Schin # undef isblank
774887Schin # define isblank(v) _isblank(virtual[v])
784887Schin # define isalph(v) _isalph(virtual[v])
794887Schin # define ismetach(v) _ismetach(virtual[v])
804887Schin #else
814887Schin static genchar _c;
824887Schin # define gencpy(a,b) strcpy((char*)(a),(char*)(b))
834887Schin # define genncpy(a,b,n) strncpy((char*)(a),(char*)(b),n)
844887Schin # define genlen(str) strlen(str)
854887Schin # define isalph(v) ((_c=virtual[v])=='_'||isalnum(_c))
864887Schin # undef isblank
874887Schin # define isblank(v) isspace(virtual[v])
884887Schin # define ismetach(v) ismeta(virtual[v])
894887Schin # define digit(c) isdigit(c)
904887Schin # define is_print(c) isprint(c)
914887Schin #endif /* SHOPT_MULTIBYTE */
924887Schin
934887Schin #if ( 'a' == 97) /* ASCII? */
944887Schin # define fold(c) ((c)&~040) /* lower and uppercase equivalent */
954887Schin #else
964887Schin # define fold(c) ((c)|0100) /* lower and uppercase equivalent */
974887Schin #endif
984887Schin
994887Schin #ifndef iswascii
1004887Schin #define iswascii(c) (!((c)&(~0177)))
1014887Schin #endif
1024887Schin
1034887Schin typedef struct _vi_
1044887Schin {
1054887Schin int direction;
1064887Schin int lastmacro;
1074887Schin char addnl; /* boolean - add newline flag */
1084887Schin char last_find; /* last find command */
1094887Schin char last_cmd; /* last command */
1104887Schin char repeat_set;
1114887Schin char nonewline;
1124887Schin int findchar; /* last find char */
1134887Schin genchar *lastline;
1144887Schin int first_wind; /* first column of window */
1154887Schin int last_wind; /* last column in window */
1164887Schin int lastmotion; /* last motion */
1174887Schin int long_char; /* line bigger than window */
1184887Schin int long_line; /* line bigger than window */
1194887Schin int ocur_phys; /* old current physical position */
1204887Schin int ocur_virt; /* old last virtual position */
1214887Schin int ofirst_wind; /* old window first col */
1224887Schin int o_v_char; /* prev virtual[ocur_virt] */
1234887Schin int repeat; /* repeat count for motion cmds */
1244887Schin int lastrepeat; /* last repeat count for motion cmds */
1254887Schin int u_column; /* undo current column */
1264887Schin int U_saved; /* original virtual saved */
1274887Schin genchar *U_space; /* used for U command */
1284887Schin genchar *u_space; /* used for u command */
1294887Schin #ifdef FIORDCHK
1304887Schin clock_t typeahead; /* typeahead occurred */
1314887Schin #else
1324887Schin int typeahead; /* typeahead occurred */
1334887Schin #endif /* FIORDCHK */
1344887Schin #if SHOPT_MULTIBYTE
1354887Schin int bigvi;
1364887Schin #endif
1374887Schin Edit_t *ed; /* pointer to edit data */
1384887Schin } Vi_t;
1394887Schin
1404887Schin #define editb (*vp->ed)
1414887Schin
1424887Schin #undef putchar
1434887Schin #define putchar(c) ed_putchar(vp->ed,c)
1444887Schin
1454887Schin #define crallowed editb.e_crlf
1464887Schin #define cur_virt editb.e_cur /* current virtual column */
1474887Schin #define cur_phys editb.e_pcur /* current phys column cursor is at */
1484887Schin #define curhline editb.e_hline /* current history line */
1494887Schin #define first_virt editb.e_fcol /* first allowable column */
1504887Schin #define globals editb.e_globals /* local global variables */
1514887Schin #define histmin editb.e_hismin
1524887Schin #define histmax editb.e_hismax
1534887Schin #define last_phys editb.e_peol /* last column in physical */
1544887Schin #define last_virt editb.e_eol /* last column */
1554887Schin #define lsearch editb.e_search /* last search string */
1564887Schin #define lookahead editb.e_lookahead /* characters in buffer */
1574887Schin #define previous editb.e_lbuf /* lookahead buffer */
1584887Schin #define max_col editb.e_llimit /* maximum column */
1594887Schin #define Prompt editb.e_prompt /* pointer to prompt */
1604887Schin #define plen editb.e_plen /* length of prompt */
1614887Schin #define physical editb.e_physbuf /* physical image */
1624887Schin #define usreof editb.e_eof /* user defined eof char */
1634887Schin #define usrerase editb.e_erase /* user defined erase char */
1644887Schin #define usrlnext editb.e_lnext /* user defined next literal */
1654887Schin #define usrkill editb.e_kill /* user defined kill char */
1664887Schin #define virtual editb.e_inbuf /* pointer to virtual image buffer */
1674887Schin #define window editb.e_window /* window buffer */
1684887Schin #define w_size editb.e_wsize /* window size */
1694887Schin #define inmacro editb.e_inmacro /* true when in macro */
1704887Schin #define yankbuf editb.e_killbuf /* yank/delete buffer */
1714887Schin
1724887Schin
1734887Schin #define ABORT -2 /* user abort */
1744887Schin #define APPEND -10 /* append chars */
1754887Schin #define BAD -1 /* failure flag */
1764887Schin #define BIGVI -15 /* user wants real vi */
1774887Schin #define CONTROL -20 /* control mode */
1784887Schin #define ENTER -25 /* enter flag */
1794887Schin #define GOOD 0 /* success flag */
1804887Schin #define INPUT -30 /* input mode */
1814887Schin #define INSERT -35 /* insert mode */
1824887Schin #define REPLACE -40 /* replace chars */
1834887Schin #define SEARCH -45 /* search flag */
1844887Schin #define TRANSLATE -50 /* translate virt to phys only */
1854887Schin
1864887Schin #define INVALID (-1) /* invalid column */
1874887Schin
1884887Schin static const char paren_chars[] = "([{)]}"; /* for % command */
1894887Schin
1904887Schin static void cursor(Vi_t*, int);
1914887Schin static void del_line(Vi_t*,int);
1924887Schin static int getcount(Vi_t*,int);
1934887Schin static void getline(Vi_t*,int);
1944887Schin static int getrchar(Vi_t*);
1954887Schin static int mvcursor(Vi_t*,int);
1964887Schin static void pr_string(Vi_t*,const char*);
1974887Schin static void putstring(Vi_t*,int, int);
1984887Schin static void refresh(Vi_t*,int);
1994887Schin static void replace(Vi_t*,int, int);
2004887Schin static void restore_v(Vi_t*);
2014887Schin static void save_last(Vi_t*);
2024887Schin static void save_v(Vi_t*);
2034887Schin static int search(Vi_t*,int);
2044887Schin static void sync_cursor(Vi_t*);
2054887Schin static int textmod(Vi_t*,int,int);
2064887Schin
2074887Schin /*+ VI_READ( fd, shbuf, nchar )
2084887Schin *
2094887Schin * This routine implements a one line version of vi and is
2104887Schin * called by _filbuf.c
2114887Schin *
2124887Schin -*/
2134887Schin
2144887Schin /*
2154887Schin * if reedit is non-zero, initialize edit buffer with reedit chars
2164887Schin */
ed_viread(void * context,int fd,register char * shbuf,int nchar,int reedit)2174887Schin int ed_viread(void *context, int fd, register char *shbuf, int nchar, int reedit)
2184887Schin {
2194887Schin Edit_t *ed = (Edit_t*)context;
2204887Schin register int i; /* general variable */
2214887Schin register int term_char; /* read() termination character */
2224887Schin register Vi_t *vp = ed->e_vi;
2234887Schin char prompt[PRSIZE+2]; /* prompt */
2244887Schin genchar Physical[2*MAXLINE]; /* physical image */
2254887Schin genchar Ubuf[MAXLINE]; /* used for U command */
2264887Schin genchar ubuf[MAXLINE]; /* used for u command */
2274887Schin genchar Window[MAXLINE]; /* window image */
2284887Schin int Globals[9]; /* local global variables */
2294887Schin int esc_or_hang=0; /* <ESC> or hangup */
2304887Schin char cntl_char=0; /* TRUE if control character present */
2314887Schin #if SHOPT_RAWONLY
2324887Schin # define viraw 1
2334887Schin #else
2344887Schin int viraw = (sh_isoption(SH_VIRAW) || sh.st.trap[SH_KEYTRAP]);
2354887Schin # ifndef FIORDCHK
2364887Schin clock_t oldtime, newtime;
2374887Schin struct tms dummy;
2384887Schin # endif /* FIORDCHK */
2394887Schin #endif /* SHOPT_RAWONLY */
2404887Schin if(!vp)
2414887Schin {
2424887Schin ed->e_vi = vp = newof(0,Vi_t,1,0);
2434887Schin vp->lastline = (genchar*)malloc(MAXLINE*CHARSIZE);
2444887Schin vp->direction = -1;
2454887Schin vp->ed = ed;
2464887Schin }
2474887Schin
2484887Schin /*** setup prompt ***/
2494887Schin
2504887Schin Prompt = prompt;
2514887Schin ed_setup(vp->ed,fd, reedit);
2524887Schin shbuf[reedit] = 0;
2534887Schin
2544887Schin #if !SHOPT_RAWONLY
2554887Schin if(!viraw)
2564887Schin {
2574887Schin /*** Change the eol characters to '\r' and eof ***/
2584887Schin /* in addition to '\n' and make eof an ESC */
2594887Schin if(tty_alt(ERRIO) < 0)
2604887Schin return(reexit?reedit:ed_read(context, fd, shbuf, nchar,0));
2614887Schin
2624887Schin #ifdef FIORDCHK
2634887Schin ioctl(fd,FIORDCHK,&vp->typeahead);
2644887Schin #else
2654887Schin /* time the current line to determine typeahead */
2664887Schin oldtime = times(&dummy);
2674887Schin #endif /* FIORDCHK */
2684887Schin #if KSHELL
2694887Schin /* abort of interrupt has occurred */
2704887Schin if(sh.trapnote&SH_SIGSET)
2714887Schin i = -1;
2724887Schin else
2734887Schin #endif /* KSHELL */
2744887Schin /*** Read the line ***/
2754887Schin i = ed_read(context, fd, shbuf, nchar, 0);
2764887Schin #ifndef FIORDCHK
2774887Schin newtime = times(&dummy);
2784887Schin vp->typeahead = ((newtime-oldtime) < NTICKS);
2794887Schin #endif /* FIORDCHK */
2804887Schin if(echoctl)
2814887Schin {
2824887Schin if( i <= 0 )
2834887Schin {
2844887Schin /*** read error or eof typed ***/
2854887Schin tty_cooked(ERRIO);
2864887Schin return(i);
2874887Schin }
2884887Schin term_char = shbuf[--i];
2894887Schin if( term_char == '\r' )
2904887Schin term_char = '\n';
2914887Schin if( term_char=='\n' || term_char==ESC )
2924887Schin shbuf[i--] = '\0';
2934887Schin else
2944887Schin shbuf[i+1] = '\0';
2954887Schin }
2964887Schin else
2974887Schin {
2984887Schin register int c = shbuf[0];
2994887Schin
3004887Schin /*** Save and remove the last character if its an eol, ***/
3014887Schin /* changing '\r' to '\n' */
3024887Schin
3034887Schin if( i == 0 )
3044887Schin {
3054887Schin /*** ESC was typed as first char of line ***/
3064887Schin esc_or_hang = 1;
3074887Schin term_char = ESC;
3084887Schin shbuf[i--] = '\0'; /* null terminate line */
3094887Schin }
3104887Schin else if( i<0 || c==usreof )
3114887Schin {
3124887Schin /*** read error or eof typed ***/
3134887Schin tty_cooked(ERRIO);
3144887Schin if( c == usreof )
3154887Schin i = 0;
3164887Schin return(i);
3174887Schin }
3184887Schin else
3194887Schin {
3204887Schin term_char = shbuf[--i];
3214887Schin if( term_char == '\r' )
3224887Schin term_char = '\n';
3234887Schin #if !defined(VEOL2) && !defined(ECHOCTL)
3244887Schin if(term_char=='\n')
3254887Schin {
3264887Schin tty_cooked(ERRIO);
3274887Schin return(i+1);
3284887Schin }
3294887Schin #endif
3304887Schin if( term_char=='\n' || term_char==usreof )
3314887Schin {
3324887Schin /*** remove terminator & null terminate ***/
3334887Schin shbuf[i--] = '\0';
3344887Schin }
3354887Schin else
3364887Schin {
3374887Schin /** terminator was ESC, which is not xmitted **/
3384887Schin term_char = ESC;
3394887Schin shbuf[i+1] = '\0';
3404887Schin }
3414887Schin }
3424887Schin }
3434887Schin }
3444887Schin else
3454887Schin #endif /* SHOPT_RAWONLY */
3464887Schin {
3474887Schin /*** Set raw mode ***/
3484887Schin
3494887Schin #if !SHOPT_RAWONLY
3504887Schin if( editb.e_ttyspeed == 0 )
3514887Schin {
3524887Schin /*** never did TCGETA, so do it ***/
3534887Schin /* avoids problem if user does 'sh -o viraw' */
3544887Schin tty_alt(ERRIO);
3554887Schin }
3564887Schin #endif /* SHOPT_RAWONLY */
3574887Schin if(tty_raw(ERRIO,0) < 0 )
3584887Schin return(reedit?reedit:ed_read(context, fd, shbuf, nchar,0));
3594887Schin i = last_virt-1;
3604887Schin }
3614887Schin
3624887Schin /*** Initialize some things ***/
3634887Schin
3644887Schin virtual = (genchar*)shbuf;
3654887Schin #if SHOPT_MULTIBYTE
3664887Schin virtual = (genchar*)roundof((char*)virtual-(char*)0,sizeof(genchar));
3674887Schin shbuf[i+1] = 0;
3684887Schin i = ed_internal(shbuf,virtual)-1;
3694887Schin #endif /* SHOPT_MULTIBYTE */
3704887Schin globals = Globals;
3714887Schin cur_phys = i + 1;
3724887Schin cur_virt = i;
3734887Schin first_virt = 0;
3744887Schin vp->first_wind = 0;
3754887Schin last_virt = i;
3764887Schin last_phys = i;
3774887Schin vp->last_wind = i;
3784887Schin vp->long_line = ' ';
3794887Schin vp->long_char = ' ';
3804887Schin vp->o_v_char = '\0';
3814887Schin vp->ocur_phys = 0;
3824887Schin vp->ocur_virt = MAXCHAR;
3834887Schin vp->ofirst_wind = 0;
3844887Schin physical = Physical;
3854887Schin vp->u_column = INVALID - 1;
3864887Schin vp->U_space = Ubuf;
3874887Schin vp->u_space = ubuf;
3884887Schin window = Window;
3894887Schin window[0] = '\0';
3904887Schin
3914887Schin if(!yankbuf)
3924887Schin yankbuf = (genchar*)malloc(MAXLINE*CHARSIZE);
3934887Schin if( vp->last_cmd == '\0' )
3944887Schin {
3954887Schin /*** first time for this shell ***/
3964887Schin
3974887Schin vp->last_cmd = 'i';
3984887Schin vp->findchar = INVALID;
3994887Schin vp->lastmotion = '\0';
4004887Schin vp->lastrepeat = 1;
4014887Schin vp->repeat = 1;
4024887Schin *yankbuf = 0;
4034887Schin }
4044887Schin
4054887Schin /*** fiddle around with prompt length ***/
4064887Schin if( nchar+plen > MAXCHAR )
4074887Schin nchar = MAXCHAR - plen;
4084887Schin max_col = nchar - 2;
4094887Schin
4104887Schin if( !viraw )
4114887Schin {
4124887Schin int kill_erase = 0;
4134887Schin for(i=(echoctl?last_virt:0); i<last_virt; ++i )
4144887Schin {
4154887Schin /*** change \r to \n, check for control characters, ***/
4164887Schin /* delete appropriate ^Vs, */
4174887Schin /* and estimate last physical column */
4184887Schin
4194887Schin if( virtual[i] == '\r' )
4204887Schin virtual[i] = '\n';
4214887Schin if(!echoctl)
4224887Schin {
4234887Schin register int c = virtual[i];
4244887Schin if( c<=usrerase)
4254887Schin {
4264887Schin /*** user typed escaped erase or kill char ***/
4274887Schin cntl_char = 1;
4284887Schin if(is_print(c))
4294887Schin kill_erase++;
4304887Schin }
4314887Schin else if( !is_print(c) )
4324887Schin {
4334887Schin cntl_char = 1;
4344887Schin
4354887Schin if( c == usrlnext )
4364887Schin {
4374887Schin if( i == last_virt )
4384887Schin {
4394887Schin /*** eol/eof was escaped ***/
4404887Schin /* so replace ^V with it */
4414887Schin virtual[i] = term_char;
4424887Schin break;
4434887Schin }
4444887Schin
4454887Schin /*** delete ^V ***/
4464887Schin gencpy((&virtual[i]), (&virtual[i+1]));
4474887Schin --cur_virt;
4484887Schin --last_virt;
4494887Schin }
4504887Schin }
4514887Schin }
4524887Schin }
4534887Schin
4544887Schin /*** copy virtual image to window ***/
4554887Schin if(last_virt > 0)
4564887Schin last_phys = ed_virt_to_phys(vp->ed,virtual,physical,last_virt,0,0);
4574887Schin if( last_phys >= w_size )
4584887Schin {
4594887Schin /*** line longer than window ***/
4604887Schin vp->last_wind = w_size - 1;
4614887Schin }
4624887Schin else
4634887Schin vp->last_wind = last_phys;
4644887Schin genncpy(window, virtual, vp->last_wind+1);
4654887Schin
4664887Schin if( term_char!=ESC && (last_virt==INVALID
4674887Schin || virtual[last_virt]!=term_char) )
4684887Schin {
4694887Schin /*** Line not terminated with ESC or escaped (^V) ***/
4704887Schin /* eol, so return after doing a total update */
4714887Schin /* if( (speed is greater or equal to 1200 */
4724887Schin /* and something was typed) and */
4734887Schin /* (control character present */
4744887Schin /* or typeahead occurred) ) */
4754887Schin
4764887Schin tty_cooked(ERRIO);
4774887Schin if( editb.e_ttyspeed==FAST && last_virt!=INVALID
4784887Schin && (vp->typeahead || cntl_char) )
4794887Schin {
4804887Schin refresh(vp,TRANSLATE);
4814887Schin pr_string(vp,Prompt);
4824887Schin putstring(vp,0, last_phys+1);
4834887Schin if(echoctl)
4844887Schin ed_crlf(vp->ed);
4854887Schin else
4864887Schin while(kill_erase-- > 0)
4874887Schin putchar(' ');
4884887Schin }
4894887Schin
4904887Schin if( term_char=='\n' )
4914887Schin {
4924887Schin if(!echoctl)
4934887Schin ed_crlf(vp->ed);
4944887Schin virtual[++last_virt] = '\n';
4954887Schin }
4964887Schin vp->last_cmd = 'i';
4974887Schin save_last(vp);
4984887Schin #if SHOPT_MULTIBYTE
4994887Schin virtual[last_virt+1] = 0;
5004887Schin last_virt = ed_external(virtual,shbuf);
5014887Schin return(last_virt);
5024887Schin #else
5034887Schin return(++last_virt);
5044887Schin #endif /* SHOPT_MULTIBYTE */
5054887Schin }
5064887Schin
5074887Schin /*** Line terminated with escape, or escaped eol/eof, ***/
5084887Schin /* so set raw mode */
5094887Schin
5104887Schin if( tty_raw(ERRIO,0) < 0 )
5114887Schin {
5124887Schin tty_cooked(ERRIO);
5134887Schin /*
5144887Schin * The following prevents drivers that return 0 on
5154887Schin * causing an infinite loop
5164887Schin */
5174887Schin if(esc_or_hang)
5184887Schin return(-1);
5194887Schin virtual[++last_virt] = '\n';
5204887Schin #if SHOPT_MULTIBYTE
5214887Schin virtual[last_virt+1] = 0;
5224887Schin last_virt = ed_external(virtual,shbuf);
5234887Schin return(last_virt);
5244887Schin #else
5254887Schin return(++last_virt);
5264887Schin #endif /* SHOPT_MULTIBYTE */
5274887Schin }
5284887Schin
5294887Schin if(echoctl) /*** for cntl-echo erase the ^[ ***/
5304887Schin pr_string(vp,"\b\b\b\b \b\b");
5314887Schin
5324887Schin
5334887Schin if(crallowed)
5344887Schin {
5354887Schin /*** start over since there may be ***/
5364887Schin /*** a control char, or cursor might not ***/
5374887Schin /*** be at left margin (this lets us know ***/
5384887Schin /*** where we are ***/
5394887Schin cur_phys = 0;
5404887Schin window[0] = '\0';
5414887Schin pr_string(vp,Prompt);
5424887Schin if( term_char==ESC && (last_virt<0 || virtual[last_virt]!=ESC))
5434887Schin refresh(vp,CONTROL);
5444887Schin else
5454887Schin refresh(vp,INPUT);
5464887Schin }
5474887Schin else
5484887Schin {
5494887Schin /*** just update everything internally ***/
5504887Schin refresh(vp,TRANSLATE);
5514887Schin }
5524887Schin }
5534887Schin
5544887Schin /*** Handle usrintr, usrquit, or EOF ***/
5554887Schin
5564887Schin i = sigsetjmp(editb.e_env,0);
5574887Schin if( i != 0 )
5584887Schin {
5598462SApril.Chin@Sun.COM if(vp->ed->e_multiline)
5608462SApril.Chin@Sun.COM {
5618462SApril.Chin@Sun.COM cur_virt = last_virt;
5628462SApril.Chin@Sun.COM sync_cursor(vp);
5638462SApril.Chin@Sun.COM }
5644887Schin virtual[0] = '\0';
5654887Schin tty_cooked(ERRIO);
5664887Schin
5674887Schin switch(i)
5684887Schin {
5694887Schin case UEOF:
5704887Schin /*** EOF ***/
5714887Schin return(0);
5724887Schin
5734887Schin case UINTR:
5744887Schin /** interrupt **/
5754887Schin return(-1);
5764887Schin }
5774887Schin return(-1);
5784887Schin }
5794887Schin
5804887Schin /*** Get a line from the terminal ***/
5814887Schin
5824887Schin vp->U_saved = 0;
5834887Schin if(reedit)
58410898Sroland.mainz@nrubsig.org {
58510898Sroland.mainz@nrubsig.org cur_phys = vp->first_wind;
58610898Sroland.mainz@nrubsig.org vp->ofirst_wind = INVALID;
5874887Schin refresh(vp,INPUT);
58810898Sroland.mainz@nrubsig.org }
5894887Schin if(viraw)
5904887Schin getline(vp,APPEND);
5914887Schin else if(last_virt>=0 && virtual[last_virt]==term_char)
5924887Schin getline(vp,APPEND);
5934887Schin else
5944887Schin getline(vp,ESC);
5954887Schin if(vp->ed->e_multiline)
5964887Schin cursor(vp, last_phys);
5974887Schin /*** add a new line if user typed unescaped \n ***/
5984887Schin /* to cause the shell to process the line */
5994887Schin tty_cooked(ERRIO);
6004887Schin if(ed->e_nlist)
6014887Schin {
6024887Schin ed->e_nlist = 0;
6034887Schin stakset(ed->e_stkptr,ed->e_stkoff);
6044887Schin }
6054887Schin if( vp->addnl )
6064887Schin {
6074887Schin virtual[++last_virt] = '\n';
6084887Schin ed_crlf(vp->ed);
6094887Schin }
6104887Schin if( ++last_virt >= 0 )
6114887Schin {
6124887Schin #if SHOPT_MULTIBYTE
6134887Schin if(vp->bigvi)
6144887Schin {
6154887Schin vp->bigvi = 0;
6164887Schin shbuf[last_virt-1] = '\n';
6174887Schin }
6184887Schin else
6194887Schin {
6204887Schin virtual[last_virt] = 0;
6214887Schin last_virt = ed_external(virtual,shbuf);
6224887Schin }
6234887Schin #endif /* SHOPT_MULTIBYTE */
6244887Schin return(last_virt);
6254887Schin }
6264887Schin else
6274887Schin return(-1);
6284887Schin }
6294887Schin
6304887Schin
6314887Schin /*{ APPEND( char, mode )
6324887Schin *
6334887Schin * This routine will append char after cur_virt in the virtual image.
6344887Schin * mode = APPEND, shift chars right before appending
6354887Schin * REPLACE, replace char if possible
6364887Schin *
6374887Schin }*/
6384887Schin
append(Vi_t * vp,int c,int mode)6394887Schin static void append(Vi_t *vp,int c, int mode)
6404887Schin {
6414887Schin register int i,j;
6424887Schin
6434887Schin if( last_virt<max_col && last_phys<max_col )
6444887Schin {
6454887Schin if( mode==APPEND || (cur_virt==last_virt && last_virt>=0))
6464887Schin {
6474887Schin j = (cur_virt>=0?cur_virt:0);
6484887Schin for(i = ++last_virt; i > j; --i)
6494887Schin virtual[i] = virtual[i-1];
6504887Schin }
6514887Schin virtual[++cur_virt] = c;
6524887Schin }
6534887Schin else
6544887Schin ed_ringbell();
6554887Schin return;
6564887Schin }
6574887Schin
6584887Schin /*{ BACKWORD( nwords, cmd )
6594887Schin *
6604887Schin * This routine will position cur_virt at the nth previous word.
6614887Schin *
6624887Schin }*/
6634887Schin
backword(Vi_t * vp,int nwords,register int cmd)6644887Schin static void backword(Vi_t *vp,int nwords, register int cmd)
6654887Schin {
6664887Schin register int tcur_virt = cur_virt;
6674887Schin while( nwords-- && tcur_virt > first_virt )
6684887Schin {
6694887Schin if( !isblank(tcur_virt) && isblank(tcur_virt-1)
6704887Schin && tcur_virt>first_virt )
6714887Schin --tcur_virt;
6724887Schin else if(cmd != 'B')
6734887Schin {
6744887Schin register int last = isalph(tcur_virt-1);
6754887Schin register int cur = isalph(tcur_virt);
6764887Schin if((!cur && last) || (cur && !last))
6774887Schin --tcur_virt;
6784887Schin }
6794887Schin while( isblank(tcur_virt) && tcur_virt>=first_virt )
6804887Schin --tcur_virt;
6814887Schin if( cmd == 'B' )
6824887Schin {
6834887Schin while( !isblank(tcur_virt) && tcur_virt>=first_virt )
6844887Schin --tcur_virt;
6854887Schin }
6864887Schin else
6874887Schin {
6884887Schin if(isalph(tcur_virt))
6894887Schin while( isalph(tcur_virt) && tcur_virt>=first_virt )
6904887Schin --tcur_virt;
6914887Schin else
6924887Schin while( !isalph(tcur_virt) && !isblank(tcur_virt)
6934887Schin && tcur_virt>=first_virt )
6944887Schin --tcur_virt;
6954887Schin }
6964887Schin cur_virt = ++tcur_virt;
6974887Schin }
6984887Schin return;
6994887Schin }
7004887Schin
7014887Schin /*{ CNTLMODE()
7024887Schin *
7034887Schin * This routine implements the vi command subset.
7044887Schin * The cursor will always be positioned at the char of interest.
7054887Schin *
7064887Schin }*/
7074887Schin
cntlmode(Vi_t * vp)7084887Schin static int cntlmode(Vi_t *vp)
7094887Schin {
7104887Schin register int c;
7114887Schin register int i;
7124887Schin genchar tmp_u_space[MAXLINE]; /* temporary u_space */
7134887Schin genchar *real_u_space; /* points to real u_space */
7144887Schin int tmp_u_column = INVALID; /* temporary u_column */
7154887Schin int was_inmacro;
7164887Schin
7174887Schin if(!vp->U_saved)
7184887Schin {
7194887Schin /*** save virtual image if never done before ***/
7204887Schin virtual[last_virt+1] = '\0';
7214887Schin gencpy(vp->U_space, virtual);
7224887Schin vp->U_saved = 1;
7234887Schin }
7244887Schin
7254887Schin save_last(vp);
7264887Schin
7274887Schin real_u_space = vp->u_space;
7284887Schin curhline = histmax;
7294887Schin first_virt = 0;
7304887Schin vp->repeat = 1;
7314887Schin if( cur_virt > INVALID )
7324887Schin {
7334887Schin /*** make sure cursor is at the last char ***/
7344887Schin sync_cursor(vp);
7354887Schin }
7364887Schin
7374887Schin /*** Read control char until something happens to cause a ***/
7384887Schin /* return to APPEND/REPLACE mode */
7394887Schin
7404887Schin while( c=ed_getchar(vp->ed,-1) )
7414887Schin {
7424887Schin vp->repeat_set = 0;
7434887Schin was_inmacro = inmacro;
7444887Schin if( c == '0' )
7454887Schin {
7464887Schin /*** move to leftmost column ***/
7474887Schin cur_virt = 0;
7484887Schin sync_cursor(vp);
7494887Schin continue;
7504887Schin }
7514887Schin
7524887Schin if( digit(c) )
7534887Schin {
7544887Schin c = getcount(vp,c);
7554887Schin if( c == '.' )
7564887Schin vp->lastrepeat = vp->repeat;
7574887Schin }
7584887Schin
7594887Schin /*** see if it's a move cursor command ***/
7604887Schin
7614887Schin if(mvcursor(vp,c))
7624887Schin {
7634887Schin sync_cursor(vp);
7644887Schin vp->repeat = 1;
7654887Schin continue;
7664887Schin }
7674887Schin
7684887Schin /*** see if it's a repeat of the last command ***/
7694887Schin
7704887Schin if( c == '.' )
7714887Schin {
7724887Schin c = vp->last_cmd;
7734887Schin vp->repeat = vp->lastrepeat;
7744887Schin i = textmod(vp,c, c);
7754887Schin }
7764887Schin else
7774887Schin {
7784887Schin i = textmod(vp,c, 0);
7794887Schin }
7804887Schin
7814887Schin /*** see if it's a text modification command ***/
7824887Schin
7834887Schin switch(i)
7844887Schin {
7854887Schin case BAD:
7864887Schin break;
7874887Schin
7884887Schin default: /** input mode **/
7894887Schin if(!was_inmacro)
7904887Schin {
7914887Schin vp->last_cmd = c;
7924887Schin vp->lastrepeat = vp->repeat;
7934887Schin }
7944887Schin vp->repeat = 1;
7954887Schin if( i == GOOD )
7964887Schin continue;
7974887Schin return(i);
7984887Schin }
7994887Schin
8004887Schin switch( c )
8014887Schin {
8024887Schin /***** Other stuff *****/
8034887Schin
8044887Schin case cntl('L'): /** Redraw line **/
8054887Schin /*** print the prompt and ***/
8064887Schin /* force a total refresh */
8078462SApril.Chin@Sun.COM if(vp->nonewline==0 && !vp->ed->e_nocrnl)
8084887Schin putchar('\n');
8094887Schin vp->nonewline = 0;
8104887Schin pr_string(vp,Prompt);
8114887Schin window[0] = '\0';
8124887Schin cur_phys = vp->first_wind;
8134887Schin vp->ofirst_wind = INVALID;
8144887Schin vp->long_line = ' ';
8154887Schin break;
8164887Schin
8174887Schin case cntl('V'):
8184887Schin {
8194887Schin register const char *p = fmtident(e_version);
8204887Schin save_v(vp);
8214887Schin del_line(vp,BAD);
8224887Schin while(c = *p++)
8234887Schin append(vp,c,APPEND);
8244887Schin refresh(vp,CONTROL);
8254887Schin ed_getchar(vp->ed,-1);
8264887Schin restore_v(vp);
8274887Schin break;
8284887Schin }
8294887Schin
8304887Schin case '/': /** Search **/
8314887Schin case '?':
8324887Schin case 'N':
8334887Schin case 'n':
8344887Schin save_v(vp);
8354887Schin switch( search(vp,c) )
8364887Schin {
8374887Schin case GOOD:
8384887Schin /*** force a total refresh ***/
8394887Schin window[0] = '\0';
8404887Schin goto newhist;
8414887Schin
8424887Schin case BAD:
8434887Schin /*** no match ***/
8444887Schin ed_ringbell();
8454887Schin
8464887Schin default:
8474887Schin if( vp->u_column == INVALID )
8484887Schin del_line(vp,BAD);
8494887Schin else
8504887Schin restore_v(vp);
8514887Schin break;
8524887Schin }
8534887Schin break;
8544887Schin
8554887Schin case 'j': /** get next command **/
8564887Schin case '+': /** get next command **/
8574887Schin curhline += vp->repeat;
8584887Schin if( curhline > histmax )
8594887Schin {
8604887Schin curhline = histmax;
8614887Schin goto ringbell;
8624887Schin }
8634887Schin else if(curhline==histmax && tmp_u_column!=INVALID )
8644887Schin {
8654887Schin vp->u_space = tmp_u_space;
8664887Schin vp->u_column = tmp_u_column;
8674887Schin restore_v(vp);
8684887Schin vp->u_space = real_u_space;
8694887Schin break;
8704887Schin }
8714887Schin save_v(vp);
8724887Schin cur_virt = INVALID;
8734887Schin goto newhist;
8744887Schin
8754887Schin case 'k': /** get previous command **/
8764887Schin case '-': /** get previous command **/
8774887Schin if( curhline == histmax )
8784887Schin {
8794887Schin vp->u_space = tmp_u_space;
8804887Schin i = vp->u_column;
8814887Schin save_v(vp);
8824887Schin vp->u_space = real_u_space;
8834887Schin tmp_u_column = vp->u_column;
8844887Schin vp->u_column = i;
8854887Schin }
8864887Schin
8874887Schin curhline -= vp->repeat;
8884887Schin if( curhline <= histmin )
8894887Schin {
8904887Schin curhline += vp->repeat;
8914887Schin goto ringbell;
8924887Schin }
8934887Schin save_v(vp);
8944887Schin cur_virt = INVALID;
8954887Schin newhist:
8964887Schin if(curhline!=histmax || cur_virt==INVALID)
8974887Schin hist_copy((char*)virtual, MAXLINE, curhline,-1);
8984887Schin else
8994887Schin {
9004887Schin strcpy((char*)virtual,(char*)vp->u_space);
9014887Schin #if SHOPT_MULTIBYTE
9024887Schin ed_internal((char*)vp->u_space,vp->u_space);
9034887Schin #endif /* SHOPT_MULTIBYTE */
9044887Schin }
9054887Schin #if SHOPT_MULTIBYTE
9064887Schin ed_internal((char*)virtual,virtual);
9074887Schin #endif /* SHOPT_MULTIBYTE */
9084887Schin if((last_virt=genlen(virtual)-1) >= 0 && cur_virt == INVALID)
9094887Schin cur_virt = 0;
9104887Schin break;
9114887Schin
9124887Schin
9134887Schin case 'u': /** undo the last thing done **/
9144887Schin restore_v(vp);
9154887Schin break;
9164887Schin
9174887Schin case 'U': /** Undo everything **/
9184887Schin save_v(vp);
9194887Schin if( virtual[0] == '\0' )
9204887Schin goto ringbell;
9214887Schin else
9224887Schin {
9234887Schin gencpy(virtual, vp->U_space);
9244887Schin last_virt = genlen(vp->U_space) - 1;
9254887Schin cur_virt = 0;
9264887Schin }
9274887Schin break;
9284887Schin
9294887Schin #if KSHELL
9304887Schin case 'v':
9314887Schin if(vp->repeat_set==0)
9324887Schin goto vcommand;
9334887Schin #endif /* KSHELL */
9344887Schin
9354887Schin case 'G': /** goto command repeat **/
9364887Schin if(vp->repeat_set==0)
9374887Schin vp->repeat = histmin+1;
9384887Schin if( vp->repeat <= histmin || vp->repeat > histmax )
9394887Schin {
9404887Schin goto ringbell;
9414887Schin }
9424887Schin curhline = vp->repeat;
9434887Schin save_v(vp);
9444887Schin if(c == 'G')
9454887Schin {
9464887Schin cur_virt = INVALID;
9474887Schin goto newhist;
9484887Schin }
9494887Schin
9504887Schin #if KSHELL
9514887Schin vcommand:
9524887Schin if(ed_fulledit(vp->ed)==GOOD)
9534887Schin return(BIGVI);
9544887Schin else
9554887Schin goto ringbell;
9564887Schin #endif /* KSHELL */
9574887Schin
9584887Schin case '#': /** insert(delete) # to (no)comment command **/
9594887Schin if( cur_virt != INVALID )
9604887Schin {
9614887Schin register genchar *p = &virtual[last_virt+1];
9624887Schin *p = 0;
9634887Schin /*** see whether first char is comment char ***/
9644887Schin c = (virtual[0]=='#');
9654887Schin while(p-- >= virtual)
9664887Schin {
9674887Schin if(*p=='\n' || p<virtual)
9684887Schin {
9694887Schin if(c) /* delete '#' */
9704887Schin {
9714887Schin if(p[1]=='#')
9724887Schin {
9734887Schin last_virt--;
9744887Schin gencpy(p+1,p+2);
9754887Schin }
9764887Schin }
9774887Schin else
9784887Schin {
9794887Schin cur_virt = p-virtual;
9804887Schin append(vp,'#', APPEND);
9814887Schin }
9824887Schin }
9834887Schin }
9844887Schin if(c)
9854887Schin {
9864887Schin curhline = histmax;
9874887Schin cur_virt = 0;
9884887Schin break;
9894887Schin }
9904887Schin refresh(vp,INPUT);
9914887Schin }
9924887Schin
9934887Schin case '\n': /** send to shell **/
9944887Schin return(ENTER);
9954887Schin
9964887Schin case ESC:
9974887Schin /* don't ring bell if next char is '[' */
9984887Schin if(!lookahead)
9994887Schin {
10004887Schin char x;
10014887Schin if(sfpkrd(editb.e_fd,&x,1,'\r',400L,-1)>0)
10024887Schin ed_ungetchar(vp->ed,x);
10034887Schin }
10044887Schin if(lookahead)
10054887Schin {
10064887Schin ed_ungetchar(vp->ed,c=ed_getchar(vp->ed,1));
10074887Schin if(c=='[')
10084887Schin {
10094887Schin vp->repeat = 1;
10104887Schin continue;
10114887Schin }
10124887Schin }
10134887Schin default:
10144887Schin ringbell:
10154887Schin ed_ringbell();
10164887Schin vp->repeat = 1;
10174887Schin continue;
10184887Schin }
10194887Schin
10204887Schin refresh(vp,CONTROL);
10214887Schin vp->repeat = 1;
10224887Schin }
10234887Schin /* NOTREACHED */
10244887Schin return(0);
10254887Schin }
10264887Schin
10274887Schin /*{ CURSOR( new_current_physical )
10284887Schin *
10294887Schin * This routine will position the virtual cursor at
10304887Schin * physical column x in the window.
10314887Schin *
10324887Schin }*/
10334887Schin
cursor(Vi_t * vp,register int x)10344887Schin static void cursor(Vi_t *vp,register int x)
10354887Schin {
10364887Schin #if SHOPT_MULTIBYTE
10374887Schin while(physical[x]==MARKER)
10384887Schin x++;
10394887Schin #endif /* SHOPT_MULTIBYTE */
10404887Schin cur_phys = ed_setcursor(vp->ed, physical, cur_phys,x,vp->first_wind);
10414887Schin }
10424887Schin
10434887Schin /*{ DELETE( nchars, mode )
10444887Schin *
10454887Schin * Delete nchars from the virtual space and leave cur_virt positioned
10464887Schin * at cur_virt-1.
10474887Schin *
10484887Schin * If mode = 'c', do not save the characters deleted
10494887Schin * = 'd', save them in yankbuf and delete.
10504887Schin * = 'y', save them in yankbuf but do not delete.
10514887Schin *
10524887Schin }*/
10534887Schin
cdelete(Vi_t * vp,register int nchars,int mode)10544887Schin static void cdelete(Vi_t *vp,register int nchars, int mode)
10554887Schin {
10564887Schin register int i;
10574887Schin register genchar *cp;
10584887Schin
10594887Schin if( cur_virt < first_virt )
10604887Schin {
10614887Schin ed_ringbell();
10624887Schin return;
10634887Schin }
10644887Schin if( nchars > 0 )
10654887Schin {
10664887Schin cp = virtual+cur_virt;
10674887Schin vp->o_v_char = cp[0];
10684887Schin if( (cur_virt-- + nchars) > last_virt )
10694887Schin {
10704887Schin /*** set nchars to number actually deleted ***/
10714887Schin nchars = last_virt - cur_virt;
10724887Schin }
10734887Schin
10744887Schin /*** save characters to be deleted ***/
10754887Schin
10764887Schin if( mode != 'c' )
10774887Schin {
10784887Schin i = cp[nchars];
10794887Schin cp[nchars] = 0;
10804887Schin gencpy(yankbuf,cp);
10814887Schin cp[nchars] = i;
10824887Schin }
10834887Schin
10844887Schin /*** now delete these characters ***/
10854887Schin
10864887Schin if( mode != 'y' )
10874887Schin {
10884887Schin gencpy(cp,cp+nchars);
10894887Schin last_virt -= nchars;
10904887Schin }
10914887Schin }
10924887Schin return;
10934887Schin }
10944887Schin
10954887Schin /*{ DEL_LINE( mode )
10964887Schin *
10974887Schin * This routine will delete the line.
10984887Schin * mode = GOOD, do a save_v()
10994887Schin *
11004887Schin }*/
del_line(register Vi_t * vp,int mode)11014887Schin static void del_line(register Vi_t *vp, int mode)
11024887Schin {
11034887Schin if( last_virt == INVALID )
11044887Schin return;
11054887Schin
11064887Schin if( mode == GOOD )
11074887Schin save_v(vp);
11084887Schin
11094887Schin cur_virt = 0;
11104887Schin first_virt = 0;
11114887Schin cdelete(vp,last_virt+1, BAD);
11124887Schin refresh(vp,CONTROL);
11134887Schin
11144887Schin cur_virt = INVALID;
11154887Schin cur_phys = 0;
11164887Schin vp->findchar = INVALID;
11174887Schin last_phys = INVALID;
11184887Schin last_virt = INVALID;
11194887Schin vp->last_wind = INVALID;
11204887Schin vp->first_wind = 0;
11214887Schin vp->o_v_char = '\0';
11224887Schin vp->ocur_phys = 0;
11234887Schin vp->ocur_virt = MAXCHAR;
11244887Schin vp->ofirst_wind = 0;
11254887Schin window[0] = '\0';
11264887Schin return;
11274887Schin }
11284887Schin
11294887Schin /*{ DELMOTION( motion, mode )
11304887Schin *
11314887Schin * Delete thru motion.
11324887Schin *
11334887Schin * mode = 'd', save deleted characters, delete
11344887Schin * = 'c', do not save characters, change
11354887Schin * = 'y', save characters, yank
11364887Schin *
11374887Schin * Returns 1 if operation successful; else 0.
11384887Schin *
11394887Schin }*/
11404887Schin
delmotion(Vi_t * vp,int motion,int mode)11414887Schin static int delmotion(Vi_t *vp,int motion, int mode)
11424887Schin {
11434887Schin register int begin, end, delta;
11444887Schin /* the following saves a register */
11454887Schin
11464887Schin if( cur_virt == INVALID )
11474887Schin return(0);
11484887Schin if( mode != 'y' )
11494887Schin save_v(vp);
11504887Schin begin = cur_virt;
11514887Schin
11524887Schin /*** fake out the motion routines by appending a blank ***/
11534887Schin
11544887Schin virtual[++last_virt] = ' ';
11554887Schin end = mvcursor(vp,motion);
11564887Schin virtual[last_virt--] = 0;
11574887Schin if(!end)
11584887Schin return(0);
11594887Schin
11604887Schin end = cur_virt;
11614887Schin if( mode=='c' && end>begin && strchr("wW", motion) )
11624887Schin {
11634887Schin /*** called by change operation, user really expects ***/
11644887Schin /* the effect of the eE commands, so back up to end of word */
11654887Schin while( end>begin && isblank(end-1) )
11664887Schin --end;
11674887Schin if( end == begin )
11684887Schin ++end;
11694887Schin }
11704887Schin
11714887Schin delta = end - begin;
11724887Schin if( delta >= 0 )
11734887Schin {
11744887Schin cur_virt = begin;
11754887Schin if( strchr("eE;,TtFf%", motion) )
11764887Schin ++delta;
11774887Schin }
11784887Schin else
11794887Schin {
11804887Schin delta = -delta + (motion=='%');
11814887Schin }
11824887Schin
11834887Schin cdelete(vp,delta, mode);
11844887Schin if( mode == 'y' )
11854887Schin cur_virt = begin;
11864887Schin return(1);
11874887Schin }
11884887Schin
11894887Schin
11904887Schin /*{ ENDWORD( nwords, cmd )
11914887Schin *
11924887Schin * This routine will move cur_virt to the end of the nth word.
11934887Schin *
11944887Schin }*/
11954887Schin
endword(Vi_t * vp,int nwords,register int cmd)11964887Schin static void endword(Vi_t *vp, int nwords, register int cmd)
11974887Schin {
11984887Schin register int tcur_virt = cur_virt;
11994887Schin while( nwords-- )
12004887Schin {
12014887Schin if( !isblank(tcur_virt) && tcur_virt<=last_virt )
12024887Schin ++tcur_virt;
12034887Schin while( isblank(tcur_virt) && tcur_virt<=last_virt )
12044887Schin ++tcur_virt;
12054887Schin if( cmd == 'E' )
12064887Schin {
12074887Schin while( !isblank(tcur_virt) && tcur_virt<=last_virt )
12084887Schin ++tcur_virt;
12094887Schin }
12104887Schin else
12114887Schin {
12124887Schin if( isalph(tcur_virt) )
12134887Schin while( isalph(tcur_virt) && tcur_virt<=last_virt )
12144887Schin ++tcur_virt;
12154887Schin else
12164887Schin while( !isalph(tcur_virt) && !isblank(tcur_virt)
12174887Schin && tcur_virt<=last_virt )
12184887Schin ++tcur_virt;
12194887Schin }
12204887Schin if( tcur_virt > first_virt )
12214887Schin tcur_virt--;
12224887Schin }
12234887Schin cur_virt = tcur_virt;
12244887Schin return;
12254887Schin }
12264887Schin
12274887Schin /*{ FORWARD( nwords, cmd )
12284887Schin *
12294887Schin * This routine will move cur_virt forward to the next nth word.
12304887Schin *
12314887Schin }*/
12324887Schin
forward(Vi_t * vp,register int nwords,int cmd)12334887Schin static void forward(Vi_t *vp,register int nwords, int cmd)
12344887Schin {
12354887Schin register int tcur_virt = cur_virt;
12364887Schin while( nwords-- )
12374887Schin {
12384887Schin if( cmd == 'W' )
12394887Schin {
12404887Schin while( !isblank(tcur_virt) && tcur_virt < last_virt )
12414887Schin ++tcur_virt;
12424887Schin }
12434887Schin else
12444887Schin {
12454887Schin if( isalph(tcur_virt) )
12464887Schin {
12474887Schin while( isalph(tcur_virt) && tcur_virt<last_virt )
12484887Schin ++tcur_virt;
12494887Schin }
12504887Schin else
12514887Schin {
12524887Schin while( !isalph(tcur_virt) && !isblank(tcur_virt)
12534887Schin && tcur_virt < last_virt )
12544887Schin ++tcur_virt;
12554887Schin }
12564887Schin }
12574887Schin while( isblank(tcur_virt) && tcur_virt < last_virt )
12584887Schin ++tcur_virt;
12594887Schin }
12604887Schin cur_virt = tcur_virt;
12614887Schin return;
12624887Schin }
12634887Schin
12644887Schin
12654887Schin
12664887Schin /*{ GETCOUNT(c)
12674887Schin *
12684887Schin * Set repeat to the user typed number and return the terminating
12694887Schin * character.
12704887Schin *
12714887Schin }*/
12724887Schin
getcount(register Vi_t * vp,register int c)12734887Schin static int getcount(register Vi_t *vp,register int c)
12744887Schin {
12754887Schin register int i;
12764887Schin
12774887Schin /*** get any repeat count ***/
12784887Schin
12794887Schin if( c == '0' )
12804887Schin return(c);
12814887Schin
12824887Schin vp->repeat_set++;
12834887Schin i = 0;
12844887Schin while( digit(c) )
12854887Schin {
12864887Schin i = i*10 + c - '0';
12874887Schin c = ed_getchar(vp->ed,-1);
12884887Schin }
12894887Schin
12904887Schin if( i > 0 )
12914887Schin vp->repeat *= i;
12924887Schin return(c);
12934887Schin }
12944887Schin
12954887Schin
12964887Schin /*{ GETLINE( mode )
12974887Schin *
12984887Schin * This routine will fetch a line.
12994887Schin * mode = APPEND, allow escape to cntlmode subroutine
13004887Schin * appending characters.
13014887Schin * = REPLACE, allow escape to cntlmode subroutine
13024887Schin * replacing characters.
13034887Schin * = SEARCH, no escape allowed
13044887Schin * = ESC, enter control mode immediately
13054887Schin *
13064887Schin * The cursor will always be positioned after the last
13074887Schin * char printed.
13084887Schin *
13094887Schin * This routine returns when cr, nl, or (eof in column 0) is
13104887Schin * received (column 0 is the first char position).
13114887Schin *
13124887Schin }*/
13134887Schin
getline(register Vi_t * vp,register int mode)13144887Schin static void getline(register Vi_t* vp,register int mode)
13154887Schin {
13164887Schin register int c;
13174887Schin register int tmp;
13184887Schin int max_virt=0, last_save=0;
13194887Schin genchar saveline[MAXLINE];
13204887Schin
13214887Schin vp->addnl = 1;
13224887Schin
13234887Schin if( mode == ESC )
13244887Schin {
13254887Schin /*** go directly to control mode ***/
13264887Schin goto escape;
13274887Schin }
13284887Schin
13294887Schin for(;;)
13304887Schin {
13314887Schin if( (c=ed_getchar(vp->ed,mode==SEARCH?1:-2)) == usreof )
13324887Schin c = UEOF;
13334887Schin else if( c == usrerase )
13344887Schin c = UERASE;
13354887Schin else if( c == usrkill )
13364887Schin c = UKILL;
13374887Schin else if( c == editb.e_werase )
13384887Schin c = UWERASE;
13394887Schin else if( c == usrlnext )
13404887Schin c = ULNEXT;
13414887Schin
13424887Schin if( c == ULNEXT)
13434887Schin {
13444887Schin /*** implement ^V to escape next char ***/
13454887Schin c = ed_getchar(vp->ed,2);
13464887Schin append(vp,c, mode);
13474887Schin refresh(vp,INPUT);
13484887Schin continue;
13494887Schin }
13504887Schin
13514887Schin switch( c )
13524887Schin {
13534887Schin case ESC: /** enter control mode **/
13544887Schin if(!sh_isoption(SH_VI))
13554887Schin {
13564887Schin append(vp,c, mode);
13574887Schin break;
13584887Schin }
13594887Schin if( mode == SEARCH )
13604887Schin {
13614887Schin ed_ringbell();
13624887Schin continue;
13634887Schin }
13644887Schin else
13654887Schin {
13664887Schin escape:
13674887Schin if( mode == REPLACE )
13684887Schin {
13694887Schin c = max_virt-cur_virt;
13704887Schin if(c > 0 && last_save>=cur_virt)
13714887Schin {
13724887Schin genncpy((&virtual[cur_virt]),&saveline[cur_virt],c);
13734887Schin if(last_virt>=last_save)
13744887Schin last_virt=last_save-1;
13754887Schin refresh(vp,INPUT);
13764887Schin }
13774887Schin --cur_virt;
13784887Schin }
13794887Schin tmp = cntlmode(vp);
13804887Schin if( tmp == ENTER || tmp == BIGVI )
13814887Schin {
13824887Schin #if SHOPT_MULTIBYTE
13834887Schin vp->bigvi = (tmp==BIGVI);
13844887Schin #endif /* SHOPT_MULTIBYTE */
13854887Schin return;
13864887Schin }
13874887Schin if( tmp == INSERT )
13884887Schin {
13894887Schin mode = APPEND;
13904887Schin continue;
13914887Schin }
13924887Schin mode = tmp;
13934887Schin if(mode==REPLACE)
13944887Schin {
13954887Schin c = last_save = last_virt+1;
13964887Schin if(c >= MAXLINE)
13974887Schin c = MAXLINE-1;
13984887Schin genncpy(saveline, virtual, c);
13994887Schin }
14004887Schin }
14014887Schin break;
14024887Schin
14034887Schin case UERASE: /** user erase char **/
14044887Schin /*** treat as backspace ***/
14054887Schin
14064887Schin case '\b': /** backspace **/
14074887Schin if( virtual[cur_virt] == '\\' )
14084887Schin {
14094887Schin cdelete(vp,1, BAD);
14104887Schin append(vp,usrerase, mode);
14114887Schin }
14124887Schin else
14134887Schin {
14144887Schin if( mode==SEARCH && cur_virt==0 )
14154887Schin {
14164887Schin first_virt = 0;
14174887Schin cdelete(vp,1, BAD);
14184887Schin return;
14194887Schin }
14204887Schin if(mode==REPLACE || (last_save>0 && last_virt<=last_save))
14214887Schin {
14224887Schin if(cur_virt<=first_virt)
14234887Schin ed_ringbell();
14244887Schin else if(mode==REPLACE)
14254887Schin --cur_virt;
14264887Schin mode = REPLACE;
14274887Schin sync_cursor(vp);
14284887Schin continue;
14294887Schin }
14304887Schin else
14314887Schin cdelete(vp,1, BAD);
14324887Schin }
14334887Schin break;
14344887Schin
14354887Schin case UWERASE: /** delete back word **/
14364887Schin if( cur_virt > first_virt &&
14374887Schin !isblank(cur_virt) &&
14384887Schin !ispunct(virtual[cur_virt]) &&
14394887Schin isblank(cur_virt-1) )
14404887Schin {
14414887Schin cdelete(vp,1, BAD);
14424887Schin }
14434887Schin else
14444887Schin {
14454887Schin tmp = cur_virt;
14464887Schin backword(vp,1, 'W');
14474887Schin cdelete(vp,tmp - cur_virt + 1, BAD);
14484887Schin }
14494887Schin break;
14504887Schin
14514887Schin case UKILL: /** user kill line char **/
14524887Schin if( virtual[cur_virt] == '\\' )
14534887Schin {
14544887Schin cdelete(vp,1, BAD);
14554887Schin append(vp,usrkill, mode);
14564887Schin }
14574887Schin else
14584887Schin {
14594887Schin if( mode == SEARCH )
14604887Schin {
14614887Schin cur_virt = 1;
14624887Schin delmotion(vp, '$', BAD);
14634887Schin }
14644887Schin else if(first_virt)
14654887Schin {
14664887Schin tmp = cur_virt;
14674887Schin cur_virt = first_virt;
14684887Schin cdelete(vp,tmp - cur_virt + 1, BAD);
14694887Schin }
14704887Schin else
14714887Schin del_line(vp,GOOD);
14724887Schin }
14734887Schin break;
14744887Schin
14754887Schin case UEOF: /** eof char **/
14764887Schin if( cur_virt != INVALID )
14774887Schin continue;
14784887Schin vp->addnl = 0;
14794887Schin
14804887Schin case '\n': /** newline or return **/
14814887Schin if( mode != SEARCH )
14824887Schin save_last(vp);
14834887Schin refresh(vp,INPUT);
14848462SApril.Chin@Sun.COM last_phys++;
14854887Schin return;
14864887Schin
14874887Schin case '\t': /** command completion **/
14884887Schin if(mode!=SEARCH && last_virt>=0 && (vp->ed->e_tabcount|| !isblank(cur_virt)) && vp->ed->sh->nextprompt)
14894887Schin {
14904887Schin if(vp->ed->e_tabcount==0)
14914887Schin {
14924887Schin ed_ungetchar(vp->ed,'\\');
14934887Schin vp->ed->e_tabcount=1;
14944887Schin goto escape;
14954887Schin }
14964887Schin else if(vp->ed->e_tabcount==1)
14974887Schin {
14984887Schin ed_ungetchar(vp->ed,'=');
14994887Schin goto escape;
15004887Schin }
15014887Schin vp->ed->e_tabcount = 0;
15024887Schin }
15034887Schin /* FALL THRU*/
15044887Schin default:
15054887Schin if( mode == REPLACE )
15064887Schin {
15074887Schin if( cur_virt < last_virt )
15084887Schin {
15094887Schin replace(vp,c, 1);
15104887Schin if(cur_virt>max_virt)
15114887Schin max_virt = cur_virt;
15124887Schin continue;
15134887Schin }
15144887Schin cdelete(vp,1, BAD);
15154887Schin mode = APPEND;
15164887Schin max_virt = last_virt+3;
15174887Schin }
15184887Schin append(vp,c, mode);
15194887Schin break;
15204887Schin }
15214887Schin refresh(vp,INPUT);
15224887Schin
15234887Schin }
15244887Schin }
15254887Schin
15264887Schin /*{ MVCURSOR( motion )
15274887Schin *
15284887Schin * This routine will move the virtual cursor according to motion
15294887Schin * for repeat times.
15304887Schin *
15314887Schin * It returns GOOD if successful; else BAD.
15324887Schin *
15334887Schin }*/
15344887Schin
mvcursor(register Vi_t * vp,register int motion)15354887Schin static int mvcursor(register Vi_t* vp,register int motion)
15364887Schin {
15374887Schin register int count;
15384887Schin register int tcur_virt;
15394887Schin register int incr = -1;
15404887Schin register int bound = 0;
15414887Schin
15424887Schin switch(motion)
15434887Schin {
15444887Schin /***** Cursor move commands *****/
15454887Schin
15464887Schin case '0': /** First column **/
15474887Schin tcur_virt = 0;
15484887Schin break;
15494887Schin
15504887Schin case '^': /** First nonblank character **/
15514887Schin tcur_virt = first_virt;
15524887Schin while( isblank(tcur_virt) && tcur_virt < last_virt )
15534887Schin ++tcur_virt;
15544887Schin break;
15554887Schin
15564887Schin case '|':
15574887Schin tcur_virt = vp->repeat-1;
15584887Schin if(tcur_virt <= last_virt)
15594887Schin break;
15604887Schin /* fall through */
15614887Schin
15624887Schin case '$': /** End of line **/
15634887Schin tcur_virt = last_virt;
15644887Schin break;
15654887Schin
15664887Schin case '[':
15674887Schin switch(motion=getcount(vp,ed_getchar(vp->ed,-1)))
15684887Schin {
15694887Schin case 'A':
15708462SApril.Chin@Sun.COM if(cur_virt>=0 && cur_virt<(SEARCHSIZE-2) && cur_virt == last_virt)
15718462SApril.Chin@Sun.COM {
15728462SApril.Chin@Sun.COM virtual[last_virt + 1] = '\0';
15738462SApril.Chin@Sun.COM #if SHOPT_MULTIBYTE
157410898Sroland.mainz@nrubsig.org ed_external(virtual,lsearch+1);
157510898Sroland.mainz@nrubsig.org #else
157610898Sroland.mainz@nrubsig.org strcpy(lsearch+1,virtual);
15778462SApril.Chin@Sun.COM #endif /* SHOPT_MULTIBYTE */
15788462SApril.Chin@Sun.COM *lsearch = '^';
15798462SApril.Chin@Sun.COM vp->direction = -2;
15808462SApril.Chin@Sun.COM ed_ungetchar(vp->ed,'n');
15818462SApril.Chin@Sun.COM }
15828462SApril.Chin@Sun.COM else if(cur_virt==0 && vp->direction == -2)
15838462SApril.Chin@Sun.COM ed_ungetchar(vp->ed,'n');
15848462SApril.Chin@Sun.COM else
15858462SApril.Chin@Sun.COM ed_ungetchar(vp->ed,'k');
15864887Schin return(1);
15874887Schin case 'B':
15884887Schin ed_ungetchar(vp->ed,'j');
15894887Schin return(1);
15904887Schin case 'C':
15914887Schin motion = last_virt;
15924887Schin incr = 1;
15934887Schin goto walk;
15944887Schin case 'D':
15954887Schin motion = first_virt;
15964887Schin goto walk;
15974887Schin case 'H':
15984887Schin tcur_virt = 0;
15994887Schin break;
16004887Schin case 'Y':
16014887Schin tcur_virt = last_virt;
16024887Schin break;
16034887Schin default:
16044887Schin ed_ungetchar(vp->ed,motion);
16054887Schin return(0);
16064887Schin }
16074887Schin break;
16084887Schin
16094887Schin case 'h': /** Left one **/
16104887Schin case '\b':
16114887Schin motion = first_virt;
16124887Schin goto walk;
16134887Schin
16144887Schin case ' ':
16154887Schin case 'l': /** Right one **/
16164887Schin motion = last_virt;
16174887Schin incr = 1;
16184887Schin walk:
16194887Schin tcur_virt = cur_virt;
16204887Schin if( incr*tcur_virt < motion)
16214887Schin {
16224887Schin tcur_virt += vp->repeat*incr;
16234887Schin if( incr*tcur_virt > motion)
16244887Schin tcur_virt = motion;
16254887Schin }
16264887Schin else
16274887Schin return(0);
16284887Schin break;
16294887Schin
16304887Schin case 'B':
16314887Schin case 'b': /** back word **/
16324887Schin tcur_virt = cur_virt;
16334887Schin backword(vp,vp->repeat, motion);
16344887Schin if( cur_virt == tcur_virt )
16354887Schin return(0);
16364887Schin return(1);
16374887Schin
16384887Schin case 'E':
16394887Schin case 'e': /** end of word **/
16404887Schin tcur_virt = cur_virt;
16414887Schin if(tcur_virt >=0)
16424887Schin endword(vp, vp->repeat, motion);
16434887Schin if( cur_virt == tcur_virt )
16444887Schin return(0);
16454887Schin return(1);
16464887Schin
16474887Schin case ',': /** reverse find old char **/
16484887Schin case ';': /** find old char **/
16494887Schin switch(vp->last_find)
16504887Schin {
16514887Schin case 't':
16524887Schin case 'f':
16534887Schin if(motion==';')
16544887Schin {
16554887Schin bound = last_virt;
16564887Schin incr = 1;
16574887Schin }
16584887Schin goto find_b;
16594887Schin
16604887Schin case 'T':
16614887Schin case 'F':
16624887Schin if(motion==',')
16634887Schin {
16644887Schin bound = last_virt;
16654887Schin incr = 1;
16664887Schin }
16674887Schin goto find_b;
16684887Schin
16694887Schin default:
16704887Schin return(0);
16714887Schin }
16724887Schin
16734887Schin
16744887Schin case 't': /** find up to new char forward **/
16754887Schin case 'f': /** find new char forward **/
16764887Schin bound = last_virt;
16774887Schin incr = 1;
16784887Schin
16794887Schin case 'T': /** find up to new char backward **/
16804887Schin case 'F': /** find new char backward **/
16814887Schin vp->last_find = motion;
16824887Schin if((vp->findchar=getrchar(vp))==ESC)
16834887Schin return(1);
16844887Schin find_b:
16854887Schin tcur_virt = cur_virt;
16864887Schin count = vp->repeat;
16874887Schin while( count-- )
16884887Schin {
16894887Schin while( incr*(tcur_virt+=incr) <= bound
16904887Schin && virtual[tcur_virt] != vp->findchar );
16914887Schin if( incr*tcur_virt > bound )
16924887Schin {
16934887Schin return(0);
16944887Schin }
16954887Schin }
16964887Schin if( fold(vp->last_find) == 'T' )
16974887Schin tcur_virt -= incr;
16984887Schin break;
16994887Schin
17004887Schin case '%':
17014887Schin {
17024887Schin int nextmotion;
17034887Schin int nextc;
17044887Schin tcur_virt = cur_virt;
17054887Schin while( tcur_virt <= last_virt
17064887Schin && strchr(paren_chars,virtual[tcur_virt])==(char*)0)
17074887Schin tcur_virt++;
17084887Schin if(tcur_virt > last_virt )
17094887Schin return(0);
17104887Schin nextc = virtual[tcur_virt];
17114887Schin count = strchr(paren_chars,nextc)-paren_chars;
17124887Schin if(count < 3)
17134887Schin {
17144887Schin incr = 1;
17154887Schin bound = last_virt;
17164887Schin nextmotion = paren_chars[count+3];
17174887Schin }
17184887Schin else
17194887Schin nextmotion = paren_chars[count-3];
17204887Schin count = 1;
17214887Schin while(count >0 && incr*(tcur_virt+=incr) <= bound)
17224887Schin {
17234887Schin if(virtual[tcur_virt] == nextmotion)
17244887Schin count--;
17254887Schin else if(virtual[tcur_virt]==nextc)
17264887Schin count++;
17274887Schin }
17284887Schin if(count)
17294887Schin return(0);
17304887Schin break;
17314887Schin }
17324887Schin
17334887Schin case 'W':
17344887Schin case 'w': /** forward word **/
17354887Schin tcur_virt = cur_virt;
17364887Schin forward(vp,vp->repeat, motion);
17374887Schin if( tcur_virt == cur_virt )
17384887Schin return(0);
17394887Schin return(1);
17404887Schin
17414887Schin default:
17424887Schin return(0);
17434887Schin }
17444887Schin cur_virt = tcur_virt;
17454887Schin
17464887Schin return(1);
17474887Schin }
17484887Schin
17494887Schin /*
17504887Schin * print a string
17514887Schin */
17524887Schin
pr_string(register Vi_t * vp,register const char * sp)17534887Schin static void pr_string(register Vi_t *vp, register const char *sp)
17544887Schin {
17554887Schin /*** copy string sp ***/
17564887Schin register char *ptr = editb.e_outptr;
17574887Schin while(*sp)
17584887Schin *ptr++ = *sp++;
17594887Schin editb.e_outptr = ptr;
17604887Schin return;
17614887Schin }
17624887Schin
17634887Schin /*{ PUTSTRING( column, nchars )
17644887Schin *
17654887Schin * Put nchars starting at column of physical into the workspace
17664887Schin * to be printed.
17674887Schin *
17684887Schin }*/
17694887Schin
putstring(register Vi_t * vp,register int col,register int nchars)17704887Schin static void putstring(register Vi_t *vp,register int col, register int nchars)
17714887Schin {
17724887Schin while( nchars-- )
17734887Schin putchar(physical[col++]);
17744887Schin return;
17754887Schin }
17764887Schin
17774887Schin /*{ REFRESH( mode )
17784887Schin *
17794887Schin * This routine will refresh the crt so the physical image matches
17804887Schin * the virtual image and display the proper window.
17814887Schin *
17824887Schin * mode = CONTROL, refresh in control mode, ie. leave cursor
17834887Schin * positioned at last char printed.
17844887Schin * = INPUT, refresh in input mode; leave cursor positioned
17854887Schin * after last char printed.
17864887Schin * = TRANSLATE, perform virtual to physical translation
17874887Schin * and adjust left margin only.
17884887Schin *
17894887Schin * +-------------------------------+
17904887Schin * | | | virtual | | |
17914887Schin * +-------------------------------+
17924887Schin * cur_virt last_virt
17934887Schin *
17944887Schin * +-----------------------------------------------+
17954887Schin * | | | physical | | |
17964887Schin * +-----------------------------------------------+
17974887Schin * cur_phys last_phys
17984887Schin *
17994887Schin * 0 w_size - 1
18004887Schin * +-----------------------+
18014887Schin * | | | window |
18024887Schin * +-----------------------+
18034887Schin * cur_window = cur_phys - first_wind
18044887Schin }*/
18054887Schin
refresh(register Vi_t * vp,int mode)18064887Schin static void refresh(register Vi_t* vp, int mode)
18074887Schin {
18084887Schin register int p;
18094887Schin register int regb;
18104887Schin register int first_w = vp->first_wind;
18114887Schin int p_differ;
18124887Schin int new_lw;
18134887Schin int ncur_phys;
18144887Schin int opflag; /* search optimize flag */
18154887Schin
18164887Schin # define w regb
18174887Schin # define v regb
18184887Schin
18194887Schin /*** find out if it's necessary to start translating at beginning ***/
18204887Schin
18214887Schin if(lookahead>0)
18224887Schin {
18234887Schin p = previous[lookahead-1];
18244887Schin if(p != ESC && p != '\n' && p != '\r')
18254887Schin mode = TRANSLATE;
18264887Schin }
18274887Schin v = cur_virt;
18284887Schin if( v<vp->ocur_virt || vp->ocur_virt==INVALID
18294887Schin || ( v==vp->ocur_virt
18304887Schin && (!is_print(virtual[v]) || !is_print(vp->o_v_char))) )
18314887Schin {
18324887Schin opflag = 0;
18334887Schin p = 0;
18344887Schin v = 0;
18354887Schin }
18364887Schin else
18374887Schin {
18384887Schin opflag = 1;
18394887Schin p = vp->ocur_phys;
18404887Schin v = vp->ocur_virt;
18414887Schin if( !is_print(virtual[v]) )
18424887Schin {
18434887Schin /*** avoid double ^'s ***/
18444887Schin ++p;
18454887Schin ++v;
18464887Schin }
18474887Schin }
18484887Schin virtual[last_virt+1] = 0;
18494887Schin ncur_phys = ed_virt_to_phys(vp->ed,virtual,physical,cur_virt,v,p);
18504887Schin p = genlen(physical);
18514887Schin if( --p < 0 )
18524887Schin last_phys = 0;
18534887Schin else
18544887Schin last_phys = p;
18554887Schin
18564887Schin /*** see if this was a translate only ***/
18574887Schin
18584887Schin if( mode == TRANSLATE )
18594887Schin return;
18604887Schin
18614887Schin /*** adjust left margin if necessary ***/
18624887Schin
18634887Schin if( ncur_phys<first_w || ncur_phys>=(first_w + w_size) )
18644887Schin {
18654887Schin cursor(vp,first_w);
18664887Schin first_w = ncur_phys - (w_size>>1);
18674887Schin if( first_w < 0 )
18684887Schin first_w = 0;
18694887Schin vp->first_wind = cur_phys = first_w;
18704887Schin }
18714887Schin
18724887Schin /*** attempt to optimize search somewhat to find ***/
18734887Schin /*** out where physical and window images differ ***/
18744887Schin
18754887Schin if( first_w==vp->ofirst_wind && ncur_phys>=vp->ocur_phys && opflag==1 )
18764887Schin {
18774887Schin p = vp->ocur_phys;
18784887Schin w = p - first_w;
18794887Schin }
18804887Schin else
18814887Schin {
18824887Schin p = first_w;
18834887Schin w = 0;
18844887Schin }
18854887Schin
18864887Schin for(; (p<=last_phys && w<=vp->last_wind); ++p, ++w)
18874887Schin {
18884887Schin if( window[w] != physical[p] )
18894887Schin break;
18904887Schin }
18914887Schin p_differ = p;
18924887Schin
18934887Schin if( (p>last_phys || p>=first_w+w_size) && w>vp->last_wind
18944887Schin && cur_virt==vp->ocur_virt )
18954887Schin {
18964887Schin /*** images are identical ***/
18974887Schin return;
18984887Schin }
18994887Schin
19004887Schin /*** copy the physical image to the window image ***/
19014887Schin
19024887Schin if( last_virt != INVALID )
19034887Schin {
19044887Schin while( p <= last_phys && w < w_size )
19054887Schin window[w++] = physical[p++];
19064887Schin }
19074887Schin new_lw = w;
19084887Schin
19094887Schin /*** erase trailing characters if needed ***/
19104887Schin
19114887Schin while( w <= vp->last_wind )
19124887Schin window[w++] = ' ';
19134887Schin vp->last_wind = --w;
19144887Schin
19154887Schin p = p_differ;
19164887Schin
19174887Schin /*** move cursor to start of difference ***/
19184887Schin
19194887Schin cursor(vp,p);
19204887Schin
19214887Schin /*** and output difference ***/
19224887Schin
19234887Schin w = p - first_w;
19244887Schin while( w <= vp->last_wind )
19254887Schin putchar(window[w++]);
19264887Schin
19274887Schin cur_phys = w + first_w;
19284887Schin vp->last_wind = --new_lw;
19294887Schin
19304887Schin if( last_phys >= w_size )
19314887Schin {
19324887Schin if( first_w == 0 )
19334887Schin vp->long_char = '>';
19344887Schin else if( last_phys < (first_w+w_size) )
19354887Schin vp->long_char = '<';
19364887Schin else
19374887Schin vp->long_char = '*';
19384887Schin }
19394887Schin else
19404887Schin vp->long_char = ' ';
19414887Schin
19424887Schin if( vp->long_line != vp->long_char )
19434887Schin {
19444887Schin /*** indicate lines longer than window ***/
19454887Schin while( w++ < w_size )
19464887Schin {
19474887Schin putchar(' ');
19484887Schin ++cur_phys;
19494887Schin }
19504887Schin putchar(vp->long_char);
19514887Schin ++cur_phys;
19524887Schin vp->long_line = vp->long_char;
19534887Schin }
19544887Schin
19558462SApril.Chin@Sun.COM if(vp->ed->e_multiline && vp->ofirst_wind==INVALID && !vp->ed->e_nocrnl)
19568462SApril.Chin@Sun.COM ed_setcursor(vp->ed, physical, last_phys+1, last_phys+1, -1);
19578462SApril.Chin@Sun.COM vp->ed->e_nocrnl = 0;
19584887Schin vp->ocur_phys = ncur_phys;
19594887Schin vp->ocur_virt = cur_virt;
19604887Schin vp->ofirst_wind = first_w;
19614887Schin
19624887Schin if( mode==INPUT && cur_virt>INVALID )
19634887Schin ++ncur_phys;
19644887Schin
19654887Schin cursor(vp,ncur_phys);
19664887Schin ed_flush(vp->ed);
19674887Schin return;
19684887Schin }
19694887Schin
19704887Schin /*{ REPLACE( char, increment )
19714887Schin *
19724887Schin * Replace the cur_virt character with char. This routine attempts
19734887Schin * to avoid using refresh().
19744887Schin *
19754887Schin * increment = 1, increment cur_virt after replacement.
19764887Schin * = 0, leave cur_virt where it is.
19774887Schin *
19784887Schin }*/
19794887Schin
replace(register Vi_t * vp,register int c,register int increment)19804887Schin static void replace(register Vi_t *vp, register int c, register int increment)
19814887Schin {
19824887Schin register int cur_window;
19834887Schin
19844887Schin if( cur_virt == INVALID )
19854887Schin {
19864887Schin /*** can't replace invalid cursor ***/
19874887Schin ed_ringbell();
19884887Schin return;
19894887Schin }
19904887Schin cur_window = cur_phys - vp->first_wind;
19914887Schin if( vp->ocur_virt == INVALID || !is_print(c)
19924887Schin || !is_print(virtual[cur_virt])
19934887Schin || !is_print(vp->o_v_char)
19944887Schin #if SHOPT_MULTIBYTE
19954887Schin || !iswascii(c) || mbwidth(vp->o_v_char)>1
19964887Schin || !iswascii(virtual[cur_virt])
19974887Schin #endif /* SHOPT_MULTIBYTE */
19984887Schin || (increment && (cur_window==w_size-1)
19994887Schin || !is_print(virtual[cur_virt+1])) )
20004887Schin {
20014887Schin /*** must use standard refresh routine ***/
20024887Schin
20034887Schin cdelete(vp,1, BAD);
20044887Schin append(vp,c, APPEND);
20054887Schin if( increment && cur_virt<last_virt )
20064887Schin ++cur_virt;
20074887Schin refresh(vp,CONTROL);
20084887Schin }
20094887Schin else
20104887Schin {
20114887Schin virtual[cur_virt] = c;
20124887Schin physical[cur_phys] = c;
20134887Schin window[cur_window] = c;
20144887Schin putchar(c);
20154887Schin if(increment)
20164887Schin {
20174887Schin c = virtual[++cur_virt];
20184887Schin ++cur_phys;
20194887Schin }
20204887Schin else
20214887Schin {
20224887Schin putchar('\b');
20234887Schin }
20244887Schin vp->o_v_char = c;
20254887Schin ed_flush(vp->ed);
20264887Schin }
20274887Schin return;
20284887Schin }
20294887Schin
20304887Schin /*{ RESTORE_V()
20314887Schin *
20324887Schin * Restore the contents of virtual space from u_space.
20334887Schin *
20344887Schin }*/
20354887Schin
restore_v(register Vi_t * vp)20364887Schin static void restore_v(register Vi_t *vp)
20374887Schin {
20384887Schin register int tmpcol;
20394887Schin genchar tmpspace[MAXLINE];
20404887Schin
20414887Schin if( vp->u_column == INVALID-1 )
20424887Schin {
20434887Schin /*** never saved anything ***/
20444887Schin ed_ringbell();
20454887Schin return;
20464887Schin }
20474887Schin gencpy(tmpspace, vp->u_space);
20484887Schin tmpcol = vp->u_column;
20494887Schin save_v(vp);
20504887Schin gencpy(virtual, tmpspace);
20514887Schin cur_virt = tmpcol;
20524887Schin last_virt = genlen(tmpspace) - 1;
20534887Schin vp->ocur_virt = MAXCHAR; /** invalidate refresh optimization **/
20544887Schin return;
20554887Schin }
20564887Schin
20574887Schin /*{ SAVE_LAST()
20584887Schin *
20594887Schin * If the user has typed something, save it in last line.
20604887Schin *
20614887Schin }*/
20624887Schin
save_last(register Vi_t * vp)20634887Schin static void save_last(register Vi_t* vp)
20644887Schin {
20654887Schin register int i;
20664887Schin
20674887Schin if( (i = cur_virt - first_virt + 1) > 0 )
20684887Schin {
20694887Schin /*** save last thing user typed ***/
20704887Schin if(i >= MAXLINE)
20714887Schin i = MAXLINE-1;
20724887Schin genncpy(vp->lastline, (&virtual[first_virt]), i);
20734887Schin vp->lastline[i] = '\0';
20744887Schin }
20754887Schin return;
20764887Schin }
20774887Schin
20784887Schin /*{ SAVE_V()
20794887Schin *
20804887Schin * This routine will save the contents of virtual in u_space.
20814887Schin *
20824887Schin }*/
20834887Schin
save_v(register Vi_t * vp)20844887Schin static void save_v(register Vi_t *vp)
20854887Schin {
20864887Schin if(!inmacro)
20874887Schin {
20884887Schin virtual[last_virt + 1] = '\0';
20894887Schin gencpy(vp->u_space, virtual);
20904887Schin vp->u_column = cur_virt;
20914887Schin }
20924887Schin return;
20934887Schin }
20944887Schin
20954887Schin /*{ SEARCH( mode )
20964887Schin *
20974887Schin * Search history file for regular expression.
20984887Schin *
20994887Schin * mode = '/' require search string and search new to old
21004887Schin * mode = '?' require search string and search old to new
21014887Schin * mode = 'N' repeat last search in reverse direction
21024887Schin * mode = 'n' repeat last search
21034887Schin *
21044887Schin }*/
21054887Schin
21064887Schin /*
21074887Schin * search for <string> in the current command
21084887Schin */
curline_search(Vi_t * vp,const char * string)21094887Schin static int curline_search(Vi_t *vp, const char *string)
21104887Schin {
21114887Schin register int len=strlen(string);
21124887Schin register const char *dp,*cp=string, *dpmax;
21134887Schin #if SHOPT_MULTIBYTE
21144887Schin ed_external(vp->u_space,(char*)vp->u_space);
21154887Schin #endif /* SHOPT_MULTIBYTE */
21164887Schin for(dp=(char*)vp->u_space,dpmax=dp+strlen(dp)-len; dp<=dpmax; dp++)
21174887Schin {
21184887Schin if(*dp==*cp && memcmp(cp,dp,len)==0)
21194887Schin return(dp-(char*)vp->u_space);
21204887Schin }
21214887Schin #if SHOPT_MULTIBYTE
21224887Schin ed_internal((char*)vp->u_space,vp->u_space);
21234887Schin #endif /* SHOPT_MULTIBYTE */
21244887Schin return(-1);
21254887Schin }
21264887Schin
search(register Vi_t * vp,register int mode)21274887Schin static int search(register Vi_t* vp,register int mode)
21284887Schin {
21294887Schin register int new_direction;
21304887Schin register int oldcurhline;
21314887Schin register int i;
21324887Schin Histloc_t location;
21334887Schin
21348462SApril.Chin@Sun.COM if( vp->direction == -2 && mode != 'n')
21358462SApril.Chin@Sun.COM vp->direction = -1;
21364887Schin if( mode == '/' || mode == '?')
21374887Schin {
21384887Schin /*** new search expression ***/
21394887Schin del_line(vp,BAD);
21404887Schin append(vp,mode, APPEND);
21414887Schin refresh(vp,INPUT);
21424887Schin first_virt = 1;
21434887Schin getline(vp,SEARCH);
21444887Schin first_virt = 0;
21454887Schin virtual[last_virt + 1] = '\0'; /*** make null terminated ***/
21464887Schin vp->direction = mode=='/' ? -1 : 1;
21474887Schin }
21484887Schin
21494887Schin if( cur_virt == INVALID )
21504887Schin {
21514887Schin /*** no operation ***/
21524887Schin return(ABORT);
21534887Schin }
21544887Schin
21554887Schin if( cur_virt==0 || fold(mode)=='N' )
21564887Schin {
21574887Schin /*** user wants repeat of last search ***/
21584887Schin del_line(vp,BAD);
21594887Schin strcpy( ((char*)virtual)+1, lsearch);
21604887Schin #if SHOPT_MULTIBYTE
21614887Schin *((char*)virtual) = '/';
21624887Schin ed_internal((char*)virtual,virtual);
21634887Schin #endif /* SHOPT_MULTIBYTE */
21644887Schin }
21654887Schin
21664887Schin if( mode == 'N' )
21674887Schin new_direction = -vp->direction;
21684887Schin else
21694887Schin new_direction = vp->direction;
21704887Schin
21714887Schin
21724887Schin /*** now search ***/
21734887Schin
21744887Schin oldcurhline = curhline;
21754887Schin #if SHOPT_MULTIBYTE
21764887Schin ed_external(virtual,(char*)virtual);
21774887Schin #endif /* SHOPT_MULTIBYTE */
21784887Schin if(mode=='?' && (i=curline_search(vp,((char*)virtual)+1))>=0)
21794887Schin {
21804887Schin location.hist_command = curhline;
21814887Schin location.hist_char = i;
21824887Schin }
21834887Schin else
21844887Schin {
21854887Schin i = INVALID;
21864887Schin if( new_direction==1 && curhline >= histmax )
21874887Schin curhline = histmin + 1;
21884887Schin location = hist_find(sh.hist_ptr,((char*)virtual)+1, curhline, 1, new_direction);
21894887Schin }
21904887Schin cur_virt = i;
21914887Schin strncpy(lsearch, ((char*)virtual)+1, SEARCHSIZE);
21924887Schin if( (curhline=location.hist_command) >=0 )
21934887Schin {
21944887Schin vp->ocur_virt = INVALID;
21954887Schin return(GOOD);
21964887Schin }
21974887Schin
21984887Schin /*** could not find matching line ***/
21994887Schin
22004887Schin curhline = oldcurhline;
22014887Schin return(BAD);
22024887Schin }
22034887Schin
22044887Schin /*{ SYNC_CURSOR()
22054887Schin *
22064887Schin * This routine will move the physical cursor to the same
22074887Schin * column as the virtual cursor.
22084887Schin *
22094887Schin }*/
22104887Schin
sync_cursor(register Vi_t * vp)22114887Schin static void sync_cursor(register Vi_t *vp)
22124887Schin {
22134887Schin register int p;
22144887Schin register int v;
22154887Schin register int c;
22164887Schin int new_phys;
22174887Schin
22184887Schin if( cur_virt == INVALID )
22194887Schin return;
22204887Schin
22214887Schin /*** find physical col that corresponds to virtual col ***/
22224887Schin
22234887Schin new_phys = 0;
22244887Schin if(vp->first_wind==vp->ofirst_wind && cur_virt>vp->ocur_virt && vp->ocur_virt!=INVALID)
22254887Schin {
22264887Schin /*** try to optimize search a little ***/
22274887Schin p = vp->ocur_phys + 1;
22284887Schin #if SHOPT_MULTIBYTE
22294887Schin while(physical[p]==MARKER)
22304887Schin p++;
22314887Schin #endif /* SHOPT_MULTIBYTE */
22324887Schin v = vp->ocur_virt + 1;
22334887Schin }
22344887Schin else
22354887Schin {
22364887Schin p = 0;
22374887Schin v = 0;
22384887Schin }
22394887Schin for(; v <= last_virt; ++p, ++v)
22404887Schin {
22414887Schin #if SHOPT_MULTIBYTE
22424887Schin int d;
22434887Schin c = virtual[v];
22444887Schin if((d = mbwidth(c)) > 1)
22454887Schin {
22464887Schin if( v != cur_virt )
22474887Schin p += (d-1);
22484887Schin }
22494887Schin else if(!iswprint(c))
22504887Schin #else
22514887Schin c = virtual[v];
22524887Schin if(!isprint(c))
22534887Schin #endif /* SHOPT_MULTIBYTE */
22544887Schin {
22554887Schin if( c == '\t' )
22564887Schin {
22574887Schin p -= ((p+editb.e_plen)%TABSIZE);
22584887Schin p += (TABSIZE-1);
22594887Schin }
22604887Schin else
22614887Schin {
22624887Schin ++p;
22634887Schin }
22644887Schin }
22654887Schin if( v == cur_virt )
22664887Schin {
22674887Schin new_phys = p;
22684887Schin break;
22694887Schin }
22704887Schin }
22714887Schin
22724887Schin if( new_phys < vp->first_wind || new_phys >= vp->first_wind + w_size )
22734887Schin {
22744887Schin /*** asked to move outside of window ***/
22754887Schin
22764887Schin window[0] = '\0';
22774887Schin refresh(vp,CONTROL);
22784887Schin return;
22794887Schin }
22804887Schin
22814887Schin cursor(vp,new_phys);
22824887Schin ed_flush(vp->ed);
22834887Schin vp->ocur_phys = cur_phys;
22844887Schin vp->ocur_virt = cur_virt;
22854887Schin vp->o_v_char = virtual[vp->ocur_virt];
22864887Schin
22874887Schin return;
22884887Schin }
22894887Schin
22904887Schin /*{ TEXTMOD( command, mode )
22914887Schin *
22924887Schin * Modify text operations.
22934887Schin *
22944887Schin * mode != 0, repeat previous operation
22954887Schin *
22964887Schin }*/
22974887Schin
textmod(register Vi_t * vp,register int c,int mode)22984887Schin static int textmod(register Vi_t *vp,register int c, int mode)
22994887Schin {
23004887Schin register int i;
23014887Schin register genchar *p = vp->lastline;
23024887Schin register int trepeat = vp->repeat;
23034887Schin genchar *savep;
23044887Schin
23054887Schin if(mode && (fold(vp->lastmotion)=='F' || fold(vp->lastmotion)=='T'))
23064887Schin vp->lastmotion = ';';
23074887Schin
23084887Schin if( fold(c) == 'P' )
23094887Schin {
23104887Schin /*** change p from lastline to yankbuf ***/
23114887Schin p = yankbuf;
23124887Schin }
23134887Schin
23144887Schin addin:
23154887Schin switch( c )
23164887Schin {
23174887Schin /***** Input commands *****/
23184887Schin
23194887Schin #if KSHELL
23204887Schin case '\t':
23214887Schin if(vp->ed->e_tabcount!=1)
23224887Schin return(BAD);
23234887Schin c = '=';
23244887Schin case '*': /** do file name expansion in place **/
23254887Schin case '\\': /** do file name completion in place **/
23264887Schin if( cur_virt == INVALID )
23274887Schin return(BAD);
23284887Schin case '=': /** list file name expansions **/
23294887Schin save_v(vp);
23304887Schin i = last_virt;
23314887Schin ++last_virt;
23324887Schin mode = cur_virt-1;
23334887Schin virtual[last_virt] = 0;
23344887Schin if(ed_expand(vp->ed,(char*)virtual, &cur_virt, &last_virt, c, vp->repeat_set?vp->repeat:-1)<0)
23354887Schin {
23364887Schin if(vp->ed->e_tabcount)
23374887Schin {
23384887Schin vp->ed->e_tabcount=2;
23394887Schin ed_ungetchar(vp->ed,'\t');
23404887Schin --last_virt;
23414887Schin return(APPEND);
23424887Schin }
23434887Schin last_virt = i;
23444887Schin ed_ringbell();
23454887Schin }
23464887Schin else if(c == '=' && !vp->repeat_set)
23474887Schin {
23484887Schin last_virt = i;
23494887Schin vp->nonewline++;
23504887Schin ed_ungetchar(vp->ed,cntl('L'));
23514887Schin return(GOOD);
23524887Schin }
23534887Schin else
23544887Schin {
23554887Schin --cur_virt;
23564887Schin --last_virt;
23574887Schin vp->ocur_virt = MAXCHAR;
23584887Schin if(c=='=' || (mode<cur_virt && (virtual[cur_virt]==' ' || virtual[cur_virt]=='/')))
23594887Schin vp->ed->e_tabcount = 0;
23604887Schin return(APPEND);
23614887Schin }
23624887Schin break;
23634887Schin
23644887Schin case '@': /** macro expansion **/
23654887Schin if( mode )
23664887Schin c = vp->lastmacro;
23674887Schin else
23684887Schin if((c=getrchar(vp))==ESC)
23694887Schin return(GOOD);
23704887Schin if(!inmacro)
23714887Schin vp->lastmacro = c;
23724887Schin if(ed_macro(vp->ed,c))
23734887Schin {
23744887Schin save_v(vp);
23754887Schin inmacro++;
23764887Schin return(GOOD);
23774887Schin }
23784887Schin ed_ringbell();
23794887Schin return(BAD);
23804887Schin
23814887Schin #endif /* KSHELL */
23824887Schin case '_': /** append last argument of prev command **/
23834887Schin save_v(vp);
23844887Schin {
23854887Schin genchar tmpbuf[MAXLINE];
23864887Schin if(vp->repeat_set==0)
23874887Schin vp->repeat = -1;
23884887Schin p = (genchar*)hist_word((char*)tmpbuf,MAXLINE,vp->repeat);
23894887Schin if(p==0)
23904887Schin {
23914887Schin ed_ringbell();
23924887Schin break;
23934887Schin }
23944887Schin #if SHOPT_MULTIBYTE
23954887Schin ed_internal((char*)p,tmpbuf);
23964887Schin p = tmpbuf;
23974887Schin #endif /* SHOPT_MULTIBYTE */
23984887Schin i = ' ';
23994887Schin do
24004887Schin {
24014887Schin append(vp,i,APPEND);
24024887Schin }
24034887Schin while(i = *p++);
24044887Schin return(APPEND);
24054887Schin }
24064887Schin
24074887Schin case 'A': /** append to end of line **/
24084887Schin cur_virt = last_virt;
24094887Schin sync_cursor(vp);
24104887Schin
24114887Schin case 'a': /** append **/
24124887Schin if( fold(mode) == 'A' )
24134887Schin {
24144887Schin c = 'p';
24154887Schin goto addin;
24164887Schin }
24174887Schin save_v(vp);
24184887Schin if( cur_virt != INVALID )
24194887Schin {
24204887Schin first_virt = cur_virt + 1;
24214887Schin cursor(vp,cur_phys + 1);
24224887Schin ed_flush(vp->ed);
24234887Schin }
24244887Schin return(APPEND);
24254887Schin
24264887Schin case 'I': /** insert at beginning of line **/
24274887Schin cur_virt = first_virt;
24284887Schin sync_cursor(vp);
24294887Schin
24304887Schin case 'i': /** insert **/
24314887Schin if( fold(mode) == 'I' )
24324887Schin {
24334887Schin c = 'P';
24344887Schin goto addin;
24354887Schin }
24364887Schin save_v(vp);
24374887Schin if( cur_virt != INVALID )
24384887Schin {
24394887Schin vp->o_v_char = virtual[cur_virt];
24404887Schin first_virt = cur_virt--;
24414887Schin }
24424887Schin return(INSERT);
24434887Schin
24444887Schin case 'C': /** change to eol **/
24454887Schin c = '$';
24464887Schin goto chgeol;
24474887Schin
24484887Schin case 'c': /** change **/
24494887Schin if( mode )
24504887Schin c = vp->lastmotion;
24514887Schin else
24524887Schin c = getcount(vp,ed_getchar(vp->ed,-1));
24534887Schin chgeol:
24544887Schin vp->lastmotion = c;
24554887Schin if( c == 'c' )
24564887Schin {
24574887Schin del_line(vp,GOOD);
24584887Schin return(APPEND);
24594887Schin }
24604887Schin
24614887Schin if(!delmotion(vp, c, 'c'))
24624887Schin return(BAD);
24634887Schin
24644887Schin if( mode == 'c' )
24654887Schin {
24664887Schin c = 'p';
24674887Schin trepeat = 1;
24684887Schin goto addin;
24694887Schin }
24704887Schin first_virt = cur_virt + 1;
24714887Schin return(APPEND);
24724887Schin
24734887Schin case 'D': /** delete to eol **/
24744887Schin c = '$';
24754887Schin goto deleol;
24764887Schin
24774887Schin case 'd': /** delete **/
24784887Schin if( mode )
24794887Schin c = vp->lastmotion;
24804887Schin else
24814887Schin c = getcount(vp,ed_getchar(vp->ed,-1));
24824887Schin deleol:
24834887Schin vp->lastmotion = c;
24844887Schin if( c == 'd' )
24854887Schin {
24864887Schin del_line(vp,GOOD);
24874887Schin break;
24884887Schin }
24894887Schin if(!delmotion(vp, c, 'd'))
24904887Schin return(BAD);
24914887Schin if( cur_virt < last_virt )
24924887Schin ++cur_virt;
24934887Schin break;
24944887Schin
24954887Schin case 'P':
24964887Schin if( p[0] == '\0' )
24974887Schin return(BAD);
24984887Schin if( cur_virt != INVALID )
24994887Schin {
25004887Schin i = virtual[cur_virt];
25014887Schin if(!is_print(i))
25024887Schin vp->ocur_virt = INVALID;
25034887Schin --cur_virt;
25044887Schin }
25054887Schin
25064887Schin case 'p': /** print **/
25074887Schin if( p[0] == '\0' )
25084887Schin return(BAD);
25094887Schin
25104887Schin if( mode != 's' && mode != 'c' )
25114887Schin {
25124887Schin save_v(vp);
25134887Schin if( c == 'P' )
25144887Schin {
25154887Schin /*** fix stored cur_virt ***/
25164887Schin ++vp->u_column;
25174887Schin }
25184887Schin }
25194887Schin if( mode == 'R' )
25204887Schin mode = REPLACE;
25214887Schin else
25224887Schin mode = APPEND;
25234887Schin savep = p;
25244887Schin for(i=0; i<trepeat; ++i)
25254887Schin {
25264887Schin while(c= *p++)
25274887Schin append(vp,c,mode);
25284887Schin p = savep;
25294887Schin }
25304887Schin break;
25314887Schin
25324887Schin case 'R': /* Replace many chars **/
25334887Schin if( mode == 'R' )
25344887Schin {
25354887Schin c = 'P';
25364887Schin goto addin;
25374887Schin }
25384887Schin save_v(vp);
25394887Schin if( cur_virt != INVALID )
25404887Schin first_virt = cur_virt;
25414887Schin return(REPLACE);
25424887Schin
25434887Schin case 'r': /** replace **/
25444887Schin if( mode )
25454887Schin c = *p;
25464887Schin else
25474887Schin if((c=getrchar(vp))==ESC)
25484887Schin return(GOOD);
25494887Schin *p = c;
25504887Schin save_v(vp);
25514887Schin while(trepeat--)
25524887Schin replace(vp,c, trepeat!=0);
25534887Schin return(GOOD);
25544887Schin
25554887Schin case 'S': /** Substitute line - cc **/
25564887Schin c = 'c';
25574887Schin goto chgeol;
25584887Schin
25594887Schin case 's': /** substitute **/
25604887Schin save_v(vp);
25614887Schin cdelete(vp,vp->repeat, BAD);
25624887Schin if( mode )
25634887Schin {
25644887Schin c = 'p';
25654887Schin trepeat = 1;
25664887Schin goto addin;
25674887Schin }
25684887Schin first_virt = cur_virt + 1;
25694887Schin return(APPEND);
25704887Schin
25714887Schin case 'Y': /** Yank to end of line **/
25724887Schin c = '$';
25734887Schin goto yankeol;
25744887Schin
25754887Schin case 'y': /** yank thru motion **/
25764887Schin if( mode )
25774887Schin c = vp->lastmotion;
25784887Schin else
25794887Schin c = getcount(vp,ed_getchar(vp->ed,-1));
25804887Schin yankeol:
25814887Schin vp->lastmotion = c;
25824887Schin if( c == 'y' )
25834887Schin {
25844887Schin gencpy(yankbuf, virtual);
25854887Schin }
25864887Schin else if(!delmotion(vp, c, 'y'))
25874887Schin {
25884887Schin return(BAD);
25894887Schin }
25904887Schin break;
25914887Schin
25924887Schin case 'x': /** delete repeat chars forward - dl **/
25934887Schin c = 'l';
25944887Schin goto deleol;
25954887Schin
25964887Schin case 'X': /** delete repeat chars backward - dh **/
25974887Schin c = 'h';
25984887Schin goto deleol;
25994887Schin
26004887Schin case '~': /** invert case and advance **/
26014887Schin if( cur_virt != INVALID )
26024887Schin {
26034887Schin save_v(vp);
26044887Schin i = INVALID;
26054887Schin while(trepeat-->0 && i!=cur_virt)
26064887Schin {
26074887Schin i = cur_virt;
26084887Schin c = virtual[cur_virt];
26094887Schin #if SHOPT_MULTIBYTE
26104887Schin if((c&~STRIP)==0)
26114887Schin #endif /* SHOPT_MULTIBYTE */
26124887Schin if( isupper(c) )
26134887Schin c = tolower(c);
26144887Schin else if( islower(c) )
26154887Schin c = toupper(c);
26164887Schin replace(vp,c, 1);
26174887Schin }
26184887Schin return(GOOD);
26194887Schin }
26204887Schin else
26214887Schin return(BAD);
26224887Schin
26234887Schin default:
26244887Schin return(BAD);
26254887Schin }
26264887Schin refresh(vp,CONTROL);
26274887Schin return(GOOD);
26284887Schin }
26294887Schin
26304887Schin
26314887Schin #if SHOPT_MULTIBYTE
_isalph(register int v)26324887Schin static int _isalph(register int v)
26334887Schin {
26344887Schin #ifdef _lib_iswalnum
26354887Schin return(iswalnum(v) || v=='_');
26364887Schin #else
26374887Schin return((v&~STRIP) || isalnum(v) || v=='_');
26384887Schin #endif
26394887Schin }
26404887Schin
26414887Schin
_isblank(register int v)26424887Schin static int _isblank(register int v)
26434887Schin {
26444887Schin return((v&~STRIP)==0 && isspace(v));
26454887Schin }
26464887Schin
_ismetach(register int v)26474887Schin static int _ismetach(register int v)
26484887Schin {
26494887Schin return((v&~STRIP)==0 && ismeta(v));
26504887Schin }
26514887Schin
26524887Schin #endif /* SHOPT_MULTIBYTE */
26534887Schin
26544887Schin /*
26554887Schin * get a character, after ^V processing
26564887Schin */
getrchar(register Vi_t * vp)26574887Schin static int getrchar(register Vi_t *vp)
26584887Schin {
26594887Schin register int c;
26604887Schin if((c=ed_getchar(vp->ed,1))== usrlnext)
26614887Schin c = ed_getchar(vp->ed,2);
26624887Schin return(c);
26634887Schin }
2664