14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1982-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.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" 374887Schin #endif /* KSHELL */ 384887Schin #include <ctype.h> 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 */ 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 { 559*8462SApril.Chin@Sun.COM if(vp->ed->e_multiline) 560*8462SApril.Chin@Sun.COM { 561*8462SApril.Chin@Sun.COM cur_virt = last_virt; 562*8462SApril.Chin@Sun.COM sync_cursor(vp); 563*8462SApril.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) 5844887Schin refresh(vp,INPUT); 5854887Schin if(viraw) 5864887Schin getline(vp,APPEND); 5874887Schin else if(last_virt>=0 && virtual[last_virt]==term_char) 5884887Schin getline(vp,APPEND); 5894887Schin else 5904887Schin getline(vp,ESC); 5914887Schin if(vp->ed->e_multiline) 5924887Schin cursor(vp, last_phys); 5934887Schin /*** add a new line if user typed unescaped \n ***/ 5944887Schin /* to cause the shell to process the line */ 5954887Schin tty_cooked(ERRIO); 5964887Schin if(ed->e_nlist) 5974887Schin { 5984887Schin ed->e_nlist = 0; 5994887Schin stakset(ed->e_stkptr,ed->e_stkoff); 6004887Schin } 6014887Schin if( vp->addnl ) 6024887Schin { 6034887Schin virtual[++last_virt] = '\n'; 6044887Schin ed_crlf(vp->ed); 6054887Schin } 6064887Schin if( ++last_virt >= 0 ) 6074887Schin { 6084887Schin #if SHOPT_MULTIBYTE 6094887Schin if(vp->bigvi) 6104887Schin { 6114887Schin vp->bigvi = 0; 6124887Schin shbuf[last_virt-1] = '\n'; 6134887Schin } 6144887Schin else 6154887Schin { 6164887Schin virtual[last_virt] = 0; 6174887Schin last_virt = ed_external(virtual,shbuf); 6184887Schin } 6194887Schin #endif /* SHOPT_MULTIBYTE */ 6204887Schin return(last_virt); 6214887Schin } 6224887Schin else 6234887Schin return(-1); 6244887Schin } 6254887Schin 6264887Schin 6274887Schin /*{ APPEND( char, mode ) 6284887Schin * 6294887Schin * This routine will append char after cur_virt in the virtual image. 6304887Schin * mode = APPEND, shift chars right before appending 6314887Schin * REPLACE, replace char if possible 6324887Schin * 6334887Schin }*/ 6344887Schin 6354887Schin static void append(Vi_t *vp,int c, int mode) 6364887Schin { 6374887Schin register int i,j; 6384887Schin 6394887Schin if( last_virt<max_col && last_phys<max_col ) 6404887Schin { 6414887Schin if( mode==APPEND || (cur_virt==last_virt && last_virt>=0)) 6424887Schin { 6434887Schin j = (cur_virt>=0?cur_virt:0); 6444887Schin for(i = ++last_virt; i > j; --i) 6454887Schin virtual[i] = virtual[i-1]; 6464887Schin } 6474887Schin virtual[++cur_virt] = c; 6484887Schin } 6494887Schin else 6504887Schin ed_ringbell(); 6514887Schin return; 6524887Schin } 6534887Schin 6544887Schin /*{ BACKWORD( nwords, cmd ) 6554887Schin * 6564887Schin * This routine will position cur_virt at the nth previous word. 6574887Schin * 6584887Schin }*/ 6594887Schin 6604887Schin static void backword(Vi_t *vp,int nwords, register int cmd) 6614887Schin { 6624887Schin register int tcur_virt = cur_virt; 6634887Schin while( nwords-- && tcur_virt > first_virt ) 6644887Schin { 6654887Schin if( !isblank(tcur_virt) && isblank(tcur_virt-1) 6664887Schin && tcur_virt>first_virt ) 6674887Schin --tcur_virt; 6684887Schin else if(cmd != 'B') 6694887Schin { 6704887Schin register int last = isalph(tcur_virt-1); 6714887Schin register int cur = isalph(tcur_virt); 6724887Schin if((!cur && last) || (cur && !last)) 6734887Schin --tcur_virt; 6744887Schin } 6754887Schin while( isblank(tcur_virt) && tcur_virt>=first_virt ) 6764887Schin --tcur_virt; 6774887Schin if( cmd == 'B' ) 6784887Schin { 6794887Schin while( !isblank(tcur_virt) && tcur_virt>=first_virt ) 6804887Schin --tcur_virt; 6814887Schin } 6824887Schin else 6834887Schin { 6844887Schin if(isalph(tcur_virt)) 6854887Schin while( isalph(tcur_virt) && tcur_virt>=first_virt ) 6864887Schin --tcur_virt; 6874887Schin else 6884887Schin while( !isalph(tcur_virt) && !isblank(tcur_virt) 6894887Schin && tcur_virt>=first_virt ) 6904887Schin --tcur_virt; 6914887Schin } 6924887Schin cur_virt = ++tcur_virt; 6934887Schin } 6944887Schin return; 6954887Schin } 6964887Schin 6974887Schin /*{ CNTLMODE() 6984887Schin * 6994887Schin * This routine implements the vi command subset. 7004887Schin * The cursor will always be positioned at the char of interest. 7014887Schin * 7024887Schin }*/ 7034887Schin 7044887Schin static int cntlmode(Vi_t *vp) 7054887Schin { 7064887Schin register int c; 7074887Schin register int i; 7084887Schin genchar tmp_u_space[MAXLINE]; /* temporary u_space */ 7094887Schin genchar *real_u_space; /* points to real u_space */ 7104887Schin int tmp_u_column = INVALID; /* temporary u_column */ 7114887Schin int was_inmacro; 7124887Schin 7134887Schin if(!vp->U_saved) 7144887Schin { 7154887Schin /*** save virtual image if never done before ***/ 7164887Schin virtual[last_virt+1] = '\0'; 7174887Schin gencpy(vp->U_space, virtual); 7184887Schin vp->U_saved = 1; 7194887Schin } 7204887Schin 7214887Schin save_last(vp); 7224887Schin 7234887Schin real_u_space = vp->u_space; 7244887Schin curhline = histmax; 7254887Schin first_virt = 0; 7264887Schin vp->repeat = 1; 7274887Schin if( cur_virt > INVALID ) 7284887Schin { 7294887Schin /*** make sure cursor is at the last char ***/ 7304887Schin sync_cursor(vp); 7314887Schin } 7324887Schin 7334887Schin /*** Read control char until something happens to cause a ***/ 7344887Schin /* return to APPEND/REPLACE mode */ 7354887Schin 7364887Schin while( c=ed_getchar(vp->ed,-1) ) 7374887Schin { 7384887Schin vp->repeat_set = 0; 7394887Schin was_inmacro = inmacro; 7404887Schin if( c == '0' ) 7414887Schin { 7424887Schin /*** move to leftmost column ***/ 7434887Schin cur_virt = 0; 7444887Schin sync_cursor(vp); 7454887Schin continue; 7464887Schin } 7474887Schin 7484887Schin if( digit(c) ) 7494887Schin { 7504887Schin c = getcount(vp,c); 7514887Schin if( c == '.' ) 7524887Schin vp->lastrepeat = vp->repeat; 7534887Schin } 7544887Schin 7554887Schin /*** see if it's a move cursor command ***/ 7564887Schin 7574887Schin if(mvcursor(vp,c)) 7584887Schin { 7594887Schin sync_cursor(vp); 7604887Schin vp->repeat = 1; 7614887Schin continue; 7624887Schin } 7634887Schin 7644887Schin /*** see if it's a repeat of the last command ***/ 7654887Schin 7664887Schin if( c == '.' ) 7674887Schin { 7684887Schin c = vp->last_cmd; 7694887Schin vp->repeat = vp->lastrepeat; 7704887Schin i = textmod(vp,c, c); 7714887Schin } 7724887Schin else 7734887Schin { 7744887Schin i = textmod(vp,c, 0); 7754887Schin } 7764887Schin 7774887Schin /*** see if it's a text modification command ***/ 7784887Schin 7794887Schin switch(i) 7804887Schin { 7814887Schin case BAD: 7824887Schin break; 7834887Schin 7844887Schin default: /** input mode **/ 7854887Schin if(!was_inmacro) 7864887Schin { 7874887Schin vp->last_cmd = c; 7884887Schin vp->lastrepeat = vp->repeat; 7894887Schin } 7904887Schin vp->repeat = 1; 7914887Schin if( i == GOOD ) 7924887Schin continue; 7934887Schin return(i); 7944887Schin } 7954887Schin 7964887Schin switch( c ) 7974887Schin { 7984887Schin /***** Other stuff *****/ 7994887Schin 8004887Schin case cntl('L'): /** Redraw line **/ 8014887Schin /*** print the prompt and ***/ 8024887Schin /* force a total refresh */ 803*8462SApril.Chin@Sun.COM if(vp->nonewline==0 && !vp->ed->e_nocrnl) 8044887Schin putchar('\n'); 8054887Schin vp->nonewline = 0; 8064887Schin pr_string(vp,Prompt); 8074887Schin window[0] = '\0'; 8084887Schin cur_phys = vp->first_wind; 8094887Schin vp->ofirst_wind = INVALID; 8104887Schin vp->long_line = ' '; 8114887Schin break; 8124887Schin 8134887Schin case cntl('V'): 8144887Schin { 8154887Schin register const char *p = fmtident(e_version); 8164887Schin save_v(vp); 8174887Schin del_line(vp,BAD); 8184887Schin while(c = *p++) 8194887Schin append(vp,c,APPEND); 8204887Schin refresh(vp,CONTROL); 8214887Schin ed_getchar(vp->ed,-1); 8224887Schin restore_v(vp); 8234887Schin break; 8244887Schin } 8254887Schin 8264887Schin case '/': /** Search **/ 8274887Schin case '?': 8284887Schin case 'N': 8294887Schin case 'n': 8304887Schin save_v(vp); 8314887Schin switch( search(vp,c) ) 8324887Schin { 8334887Schin case GOOD: 8344887Schin /*** force a total refresh ***/ 8354887Schin window[0] = '\0'; 8364887Schin goto newhist; 8374887Schin 8384887Schin case BAD: 8394887Schin /*** no match ***/ 8404887Schin ed_ringbell(); 8414887Schin 8424887Schin default: 8434887Schin if( vp->u_column == INVALID ) 8444887Schin del_line(vp,BAD); 8454887Schin else 8464887Schin restore_v(vp); 8474887Schin break; 8484887Schin } 8494887Schin break; 8504887Schin 8514887Schin case 'j': /** get next command **/ 8524887Schin case '+': /** get next command **/ 8534887Schin curhline += vp->repeat; 8544887Schin if( curhline > histmax ) 8554887Schin { 8564887Schin curhline = histmax; 8574887Schin goto ringbell; 8584887Schin } 8594887Schin else if(curhline==histmax && tmp_u_column!=INVALID ) 8604887Schin { 8614887Schin vp->u_space = tmp_u_space; 8624887Schin vp->u_column = tmp_u_column; 8634887Schin restore_v(vp); 8644887Schin vp->u_space = real_u_space; 8654887Schin break; 8664887Schin } 8674887Schin save_v(vp); 8684887Schin cur_virt = INVALID; 8694887Schin goto newhist; 8704887Schin 8714887Schin case 'k': /** get previous command **/ 8724887Schin case '-': /** get previous command **/ 8734887Schin if( curhline == histmax ) 8744887Schin { 8754887Schin vp->u_space = tmp_u_space; 8764887Schin i = vp->u_column; 8774887Schin save_v(vp); 8784887Schin vp->u_space = real_u_space; 8794887Schin tmp_u_column = vp->u_column; 8804887Schin vp->u_column = i; 8814887Schin } 8824887Schin 8834887Schin curhline -= vp->repeat; 8844887Schin if( curhline <= histmin ) 8854887Schin { 8864887Schin curhline += vp->repeat; 8874887Schin goto ringbell; 8884887Schin } 8894887Schin save_v(vp); 8904887Schin cur_virt = INVALID; 8914887Schin newhist: 8924887Schin if(curhline!=histmax || cur_virt==INVALID) 8934887Schin hist_copy((char*)virtual, MAXLINE, curhline,-1); 8944887Schin else 8954887Schin { 8964887Schin strcpy((char*)virtual,(char*)vp->u_space); 8974887Schin #if SHOPT_MULTIBYTE 8984887Schin ed_internal((char*)vp->u_space,vp->u_space); 8994887Schin #endif /* SHOPT_MULTIBYTE */ 9004887Schin } 9014887Schin #if SHOPT_MULTIBYTE 9024887Schin ed_internal((char*)virtual,virtual); 9034887Schin #endif /* SHOPT_MULTIBYTE */ 9044887Schin if((last_virt=genlen(virtual)-1) >= 0 && cur_virt == INVALID) 9054887Schin cur_virt = 0; 9064887Schin break; 9074887Schin 9084887Schin 9094887Schin case 'u': /** undo the last thing done **/ 9104887Schin restore_v(vp); 9114887Schin break; 9124887Schin 9134887Schin case 'U': /** Undo everything **/ 9144887Schin save_v(vp); 9154887Schin if( virtual[0] == '\0' ) 9164887Schin goto ringbell; 9174887Schin else 9184887Schin { 9194887Schin gencpy(virtual, vp->U_space); 9204887Schin last_virt = genlen(vp->U_space) - 1; 9214887Schin cur_virt = 0; 9224887Schin } 9234887Schin break; 9244887Schin 9254887Schin #if KSHELL 9264887Schin case 'v': 9274887Schin if(vp->repeat_set==0) 9284887Schin goto vcommand; 9294887Schin #endif /* KSHELL */ 9304887Schin 9314887Schin case 'G': /** goto command repeat **/ 9324887Schin if(vp->repeat_set==0) 9334887Schin vp->repeat = histmin+1; 9344887Schin if( vp->repeat <= histmin || vp->repeat > histmax ) 9354887Schin { 9364887Schin goto ringbell; 9374887Schin } 9384887Schin curhline = vp->repeat; 9394887Schin save_v(vp); 9404887Schin if(c == 'G') 9414887Schin { 9424887Schin cur_virt = INVALID; 9434887Schin goto newhist; 9444887Schin } 9454887Schin 9464887Schin #if KSHELL 9474887Schin vcommand: 9484887Schin if(ed_fulledit(vp->ed)==GOOD) 9494887Schin return(BIGVI); 9504887Schin else 9514887Schin goto ringbell; 9524887Schin #endif /* KSHELL */ 9534887Schin 9544887Schin case '#': /** insert(delete) # to (no)comment command **/ 9554887Schin if( cur_virt != INVALID ) 9564887Schin { 9574887Schin register genchar *p = &virtual[last_virt+1]; 9584887Schin *p = 0; 9594887Schin /*** see whether first char is comment char ***/ 9604887Schin c = (virtual[0]=='#'); 9614887Schin while(p-- >= virtual) 9624887Schin { 9634887Schin if(*p=='\n' || p<virtual) 9644887Schin { 9654887Schin if(c) /* delete '#' */ 9664887Schin { 9674887Schin if(p[1]=='#') 9684887Schin { 9694887Schin last_virt--; 9704887Schin gencpy(p+1,p+2); 9714887Schin } 9724887Schin } 9734887Schin else 9744887Schin { 9754887Schin cur_virt = p-virtual; 9764887Schin append(vp,'#', APPEND); 9774887Schin } 9784887Schin } 9794887Schin } 9804887Schin if(c) 9814887Schin { 9824887Schin curhline = histmax; 9834887Schin cur_virt = 0; 9844887Schin break; 9854887Schin } 9864887Schin refresh(vp,INPUT); 9874887Schin } 9884887Schin 9894887Schin case '\n': /** send to shell **/ 9904887Schin return(ENTER); 9914887Schin 9924887Schin case ESC: 9934887Schin /* don't ring bell if next char is '[' */ 9944887Schin if(!lookahead) 9954887Schin { 9964887Schin char x; 9974887Schin if(sfpkrd(editb.e_fd,&x,1,'\r',400L,-1)>0) 9984887Schin ed_ungetchar(vp->ed,x); 9994887Schin } 10004887Schin if(lookahead) 10014887Schin { 10024887Schin ed_ungetchar(vp->ed,c=ed_getchar(vp->ed,1)); 10034887Schin if(c=='[') 10044887Schin { 10054887Schin vp->repeat = 1; 10064887Schin continue; 10074887Schin } 10084887Schin } 10094887Schin default: 10104887Schin ringbell: 10114887Schin ed_ringbell(); 10124887Schin vp->repeat = 1; 10134887Schin continue; 10144887Schin } 10154887Schin 10164887Schin refresh(vp,CONTROL); 10174887Schin vp->repeat = 1; 10184887Schin } 10194887Schin /* NOTREACHED */ 10204887Schin return(0); 10214887Schin } 10224887Schin 10234887Schin /*{ CURSOR( new_current_physical ) 10244887Schin * 10254887Schin * This routine will position the virtual cursor at 10264887Schin * physical column x in the window. 10274887Schin * 10284887Schin }*/ 10294887Schin 10304887Schin static void cursor(Vi_t *vp,register int x) 10314887Schin { 10324887Schin #if SHOPT_MULTIBYTE 10334887Schin while(physical[x]==MARKER) 10344887Schin x++; 10354887Schin #endif /* SHOPT_MULTIBYTE */ 10364887Schin cur_phys = ed_setcursor(vp->ed, physical, cur_phys,x,vp->first_wind); 10374887Schin } 10384887Schin 10394887Schin /*{ DELETE( nchars, mode ) 10404887Schin * 10414887Schin * Delete nchars from the virtual space and leave cur_virt positioned 10424887Schin * at cur_virt-1. 10434887Schin * 10444887Schin * If mode = 'c', do not save the characters deleted 10454887Schin * = 'd', save them in yankbuf and delete. 10464887Schin * = 'y', save them in yankbuf but do not delete. 10474887Schin * 10484887Schin }*/ 10494887Schin 10504887Schin static void cdelete(Vi_t *vp,register int nchars, int mode) 10514887Schin { 10524887Schin register int i; 10534887Schin register genchar *cp; 10544887Schin 10554887Schin if( cur_virt < first_virt ) 10564887Schin { 10574887Schin ed_ringbell(); 10584887Schin return; 10594887Schin } 10604887Schin if( nchars > 0 ) 10614887Schin { 10624887Schin cp = virtual+cur_virt; 10634887Schin vp->o_v_char = cp[0]; 10644887Schin if( (cur_virt-- + nchars) > last_virt ) 10654887Schin { 10664887Schin /*** set nchars to number actually deleted ***/ 10674887Schin nchars = last_virt - cur_virt; 10684887Schin } 10694887Schin 10704887Schin /*** save characters to be deleted ***/ 10714887Schin 10724887Schin if( mode != 'c' ) 10734887Schin { 10744887Schin i = cp[nchars]; 10754887Schin cp[nchars] = 0; 10764887Schin gencpy(yankbuf,cp); 10774887Schin cp[nchars] = i; 10784887Schin } 10794887Schin 10804887Schin /*** now delete these characters ***/ 10814887Schin 10824887Schin if( mode != 'y' ) 10834887Schin { 10844887Schin gencpy(cp,cp+nchars); 10854887Schin last_virt -= nchars; 10864887Schin } 10874887Schin } 10884887Schin return; 10894887Schin } 10904887Schin 10914887Schin /*{ DEL_LINE( mode ) 10924887Schin * 10934887Schin * This routine will delete the line. 10944887Schin * mode = GOOD, do a save_v() 10954887Schin * 10964887Schin }*/ 10974887Schin static void del_line(register Vi_t *vp, int mode) 10984887Schin { 10994887Schin if( last_virt == INVALID ) 11004887Schin return; 11014887Schin 11024887Schin if( mode == GOOD ) 11034887Schin save_v(vp); 11044887Schin 11054887Schin cur_virt = 0; 11064887Schin first_virt = 0; 11074887Schin cdelete(vp,last_virt+1, BAD); 11084887Schin refresh(vp,CONTROL); 11094887Schin 11104887Schin cur_virt = INVALID; 11114887Schin cur_phys = 0; 11124887Schin vp->findchar = INVALID; 11134887Schin last_phys = INVALID; 11144887Schin last_virt = INVALID; 11154887Schin vp->last_wind = INVALID; 11164887Schin vp->first_wind = 0; 11174887Schin vp->o_v_char = '\0'; 11184887Schin vp->ocur_phys = 0; 11194887Schin vp->ocur_virt = MAXCHAR; 11204887Schin vp->ofirst_wind = 0; 11214887Schin window[0] = '\0'; 11224887Schin return; 11234887Schin } 11244887Schin 11254887Schin /*{ DELMOTION( motion, mode ) 11264887Schin * 11274887Schin * Delete thru motion. 11284887Schin * 11294887Schin * mode = 'd', save deleted characters, delete 11304887Schin * = 'c', do not save characters, change 11314887Schin * = 'y', save characters, yank 11324887Schin * 11334887Schin * Returns 1 if operation successful; else 0. 11344887Schin * 11354887Schin }*/ 11364887Schin 11374887Schin static int delmotion(Vi_t *vp,int motion, int mode) 11384887Schin { 11394887Schin register int begin, end, delta; 11404887Schin /* the following saves a register */ 11414887Schin 11424887Schin if( cur_virt == INVALID ) 11434887Schin return(0); 11444887Schin if( mode != 'y' ) 11454887Schin save_v(vp); 11464887Schin begin = cur_virt; 11474887Schin 11484887Schin /*** fake out the motion routines by appending a blank ***/ 11494887Schin 11504887Schin virtual[++last_virt] = ' '; 11514887Schin end = mvcursor(vp,motion); 11524887Schin virtual[last_virt--] = 0; 11534887Schin if(!end) 11544887Schin return(0); 11554887Schin 11564887Schin end = cur_virt; 11574887Schin if( mode=='c' && end>begin && strchr("wW", motion) ) 11584887Schin { 11594887Schin /*** called by change operation, user really expects ***/ 11604887Schin /* the effect of the eE commands, so back up to end of word */ 11614887Schin while( end>begin && isblank(end-1) ) 11624887Schin --end; 11634887Schin if( end == begin ) 11644887Schin ++end; 11654887Schin } 11664887Schin 11674887Schin delta = end - begin; 11684887Schin if( delta >= 0 ) 11694887Schin { 11704887Schin cur_virt = begin; 11714887Schin if( strchr("eE;,TtFf%", motion) ) 11724887Schin ++delta; 11734887Schin } 11744887Schin else 11754887Schin { 11764887Schin delta = -delta + (motion=='%'); 11774887Schin } 11784887Schin 11794887Schin cdelete(vp,delta, mode); 11804887Schin if( mode == 'y' ) 11814887Schin cur_virt = begin; 11824887Schin return(1); 11834887Schin } 11844887Schin 11854887Schin 11864887Schin /*{ ENDWORD( nwords, cmd ) 11874887Schin * 11884887Schin * This routine will move cur_virt to the end of the nth word. 11894887Schin * 11904887Schin }*/ 11914887Schin 11924887Schin static void endword(Vi_t *vp, int nwords, register int cmd) 11934887Schin { 11944887Schin register int tcur_virt = cur_virt; 11954887Schin while( nwords-- ) 11964887Schin { 11974887Schin if( !isblank(tcur_virt) && tcur_virt<=last_virt ) 11984887Schin ++tcur_virt; 11994887Schin while( isblank(tcur_virt) && tcur_virt<=last_virt ) 12004887Schin ++tcur_virt; 12014887Schin if( cmd == 'E' ) 12024887Schin { 12034887Schin while( !isblank(tcur_virt) && tcur_virt<=last_virt ) 12044887Schin ++tcur_virt; 12054887Schin } 12064887Schin else 12074887Schin { 12084887Schin if( isalph(tcur_virt) ) 12094887Schin while( isalph(tcur_virt) && tcur_virt<=last_virt ) 12104887Schin ++tcur_virt; 12114887Schin else 12124887Schin while( !isalph(tcur_virt) && !isblank(tcur_virt) 12134887Schin && tcur_virt<=last_virt ) 12144887Schin ++tcur_virt; 12154887Schin } 12164887Schin if( tcur_virt > first_virt ) 12174887Schin tcur_virt--; 12184887Schin } 12194887Schin cur_virt = tcur_virt; 12204887Schin return; 12214887Schin } 12224887Schin 12234887Schin /*{ FORWARD( nwords, cmd ) 12244887Schin * 12254887Schin * This routine will move cur_virt forward to the next nth word. 12264887Schin * 12274887Schin }*/ 12284887Schin 12294887Schin static void forward(Vi_t *vp,register int nwords, int cmd) 12304887Schin { 12314887Schin register int tcur_virt = cur_virt; 12324887Schin while( nwords-- ) 12334887Schin { 12344887Schin if( cmd == 'W' ) 12354887Schin { 12364887Schin while( !isblank(tcur_virt) && tcur_virt < last_virt ) 12374887Schin ++tcur_virt; 12384887Schin } 12394887Schin else 12404887Schin { 12414887Schin if( isalph(tcur_virt) ) 12424887Schin { 12434887Schin while( isalph(tcur_virt) && tcur_virt<last_virt ) 12444887Schin ++tcur_virt; 12454887Schin } 12464887Schin else 12474887Schin { 12484887Schin while( !isalph(tcur_virt) && !isblank(tcur_virt) 12494887Schin && tcur_virt < last_virt ) 12504887Schin ++tcur_virt; 12514887Schin } 12524887Schin } 12534887Schin while( isblank(tcur_virt) && tcur_virt < last_virt ) 12544887Schin ++tcur_virt; 12554887Schin } 12564887Schin cur_virt = tcur_virt; 12574887Schin return; 12584887Schin } 12594887Schin 12604887Schin 12614887Schin 12624887Schin /*{ GETCOUNT(c) 12634887Schin * 12644887Schin * Set repeat to the user typed number and return the terminating 12654887Schin * character. 12664887Schin * 12674887Schin }*/ 12684887Schin 12694887Schin static int getcount(register Vi_t *vp,register int c) 12704887Schin { 12714887Schin register int i; 12724887Schin 12734887Schin /*** get any repeat count ***/ 12744887Schin 12754887Schin if( c == '0' ) 12764887Schin return(c); 12774887Schin 12784887Schin vp->repeat_set++; 12794887Schin i = 0; 12804887Schin while( digit(c) ) 12814887Schin { 12824887Schin i = i*10 + c - '0'; 12834887Schin c = ed_getchar(vp->ed,-1); 12844887Schin } 12854887Schin 12864887Schin if( i > 0 ) 12874887Schin vp->repeat *= i; 12884887Schin return(c); 12894887Schin } 12904887Schin 12914887Schin 12924887Schin /*{ GETLINE( mode ) 12934887Schin * 12944887Schin * This routine will fetch a line. 12954887Schin * mode = APPEND, allow escape to cntlmode subroutine 12964887Schin * appending characters. 12974887Schin * = REPLACE, allow escape to cntlmode subroutine 12984887Schin * replacing characters. 12994887Schin * = SEARCH, no escape allowed 13004887Schin * = ESC, enter control mode immediately 13014887Schin * 13024887Schin * The cursor will always be positioned after the last 13034887Schin * char printed. 13044887Schin * 13054887Schin * This routine returns when cr, nl, or (eof in column 0) is 13064887Schin * received (column 0 is the first char position). 13074887Schin * 13084887Schin }*/ 13094887Schin 13104887Schin static void getline(register Vi_t* vp,register int mode) 13114887Schin { 13124887Schin register int c; 13134887Schin register int tmp; 13144887Schin int max_virt=0, last_save=0; 13154887Schin genchar saveline[MAXLINE]; 13164887Schin 13174887Schin vp->addnl = 1; 13184887Schin 13194887Schin if( mode == ESC ) 13204887Schin { 13214887Schin /*** go directly to control mode ***/ 13224887Schin goto escape; 13234887Schin } 13244887Schin 13254887Schin for(;;) 13264887Schin { 13274887Schin if( (c=ed_getchar(vp->ed,mode==SEARCH?1:-2)) == usreof ) 13284887Schin c = UEOF; 13294887Schin else if( c == usrerase ) 13304887Schin c = UERASE; 13314887Schin else if( c == usrkill ) 13324887Schin c = UKILL; 13334887Schin else if( c == editb.e_werase ) 13344887Schin c = UWERASE; 13354887Schin else if( c == usrlnext ) 13364887Schin c = ULNEXT; 13374887Schin 13384887Schin if( c == ULNEXT) 13394887Schin { 13404887Schin /*** implement ^V to escape next char ***/ 13414887Schin c = ed_getchar(vp->ed,2); 13424887Schin append(vp,c, mode); 13434887Schin refresh(vp,INPUT); 13444887Schin continue; 13454887Schin } 13464887Schin 13474887Schin switch( c ) 13484887Schin { 13494887Schin case ESC: /** enter control mode **/ 13504887Schin if(!sh_isoption(SH_VI)) 13514887Schin { 13524887Schin append(vp,c, mode); 13534887Schin break; 13544887Schin } 13554887Schin if( mode == SEARCH ) 13564887Schin { 13574887Schin ed_ringbell(); 13584887Schin continue; 13594887Schin } 13604887Schin else 13614887Schin { 13624887Schin escape: 13634887Schin if( mode == REPLACE ) 13644887Schin { 13654887Schin c = max_virt-cur_virt; 13664887Schin if(c > 0 && last_save>=cur_virt) 13674887Schin { 13684887Schin genncpy((&virtual[cur_virt]),&saveline[cur_virt],c); 13694887Schin if(last_virt>=last_save) 13704887Schin last_virt=last_save-1; 13714887Schin refresh(vp,INPUT); 13724887Schin } 13734887Schin --cur_virt; 13744887Schin } 13754887Schin tmp = cntlmode(vp); 13764887Schin if( tmp == ENTER || tmp == BIGVI ) 13774887Schin { 13784887Schin #if SHOPT_MULTIBYTE 13794887Schin vp->bigvi = (tmp==BIGVI); 13804887Schin #endif /* SHOPT_MULTIBYTE */ 13814887Schin return; 13824887Schin } 13834887Schin if( tmp == INSERT ) 13844887Schin { 13854887Schin mode = APPEND; 13864887Schin continue; 13874887Schin } 13884887Schin mode = tmp; 13894887Schin if(mode==REPLACE) 13904887Schin { 13914887Schin c = last_save = last_virt+1; 13924887Schin if(c >= MAXLINE) 13934887Schin c = MAXLINE-1; 13944887Schin genncpy(saveline, virtual, c); 13954887Schin } 13964887Schin } 13974887Schin break; 13984887Schin 13994887Schin case UERASE: /** user erase char **/ 14004887Schin /*** treat as backspace ***/ 14014887Schin 14024887Schin case '\b': /** backspace **/ 14034887Schin if( virtual[cur_virt] == '\\' ) 14044887Schin { 14054887Schin cdelete(vp,1, BAD); 14064887Schin append(vp,usrerase, mode); 14074887Schin } 14084887Schin else 14094887Schin { 14104887Schin if( mode==SEARCH && cur_virt==0 ) 14114887Schin { 14124887Schin first_virt = 0; 14134887Schin cdelete(vp,1, BAD); 14144887Schin return; 14154887Schin } 14164887Schin if(mode==REPLACE || (last_save>0 && last_virt<=last_save)) 14174887Schin { 14184887Schin if(cur_virt<=first_virt) 14194887Schin ed_ringbell(); 14204887Schin else if(mode==REPLACE) 14214887Schin --cur_virt; 14224887Schin mode = REPLACE; 14234887Schin sync_cursor(vp); 14244887Schin continue; 14254887Schin } 14264887Schin else 14274887Schin cdelete(vp,1, BAD); 14284887Schin } 14294887Schin break; 14304887Schin 14314887Schin case UWERASE: /** delete back word **/ 14324887Schin if( cur_virt > first_virt && 14334887Schin !isblank(cur_virt) && 14344887Schin !ispunct(virtual[cur_virt]) && 14354887Schin isblank(cur_virt-1) ) 14364887Schin { 14374887Schin cdelete(vp,1, BAD); 14384887Schin } 14394887Schin else 14404887Schin { 14414887Schin tmp = cur_virt; 14424887Schin backword(vp,1, 'W'); 14434887Schin cdelete(vp,tmp - cur_virt + 1, BAD); 14444887Schin } 14454887Schin break; 14464887Schin 14474887Schin case UKILL: /** user kill line char **/ 14484887Schin if( virtual[cur_virt] == '\\' ) 14494887Schin { 14504887Schin cdelete(vp,1, BAD); 14514887Schin append(vp,usrkill, mode); 14524887Schin } 14534887Schin else 14544887Schin { 14554887Schin if( mode == SEARCH ) 14564887Schin { 14574887Schin cur_virt = 1; 14584887Schin delmotion(vp, '$', BAD); 14594887Schin } 14604887Schin else if(first_virt) 14614887Schin { 14624887Schin tmp = cur_virt; 14634887Schin cur_virt = first_virt; 14644887Schin cdelete(vp,tmp - cur_virt + 1, BAD); 14654887Schin } 14664887Schin else 14674887Schin del_line(vp,GOOD); 14684887Schin } 14694887Schin break; 14704887Schin 14714887Schin case UEOF: /** eof char **/ 14724887Schin if( cur_virt != INVALID ) 14734887Schin continue; 14744887Schin vp->addnl = 0; 14754887Schin 14764887Schin case '\n': /** newline or return **/ 14774887Schin if( mode != SEARCH ) 14784887Schin save_last(vp); 14794887Schin refresh(vp,INPUT); 1480*8462SApril.Chin@Sun.COM last_phys++; 14814887Schin return; 14824887Schin 14834887Schin case '\t': /** command completion **/ 14844887Schin if(mode!=SEARCH && last_virt>=0 && (vp->ed->e_tabcount|| !isblank(cur_virt)) && vp->ed->sh->nextprompt) 14854887Schin { 14864887Schin if(vp->ed->e_tabcount==0) 14874887Schin { 14884887Schin ed_ungetchar(vp->ed,'\\'); 14894887Schin vp->ed->e_tabcount=1; 14904887Schin goto escape; 14914887Schin } 14924887Schin else if(vp->ed->e_tabcount==1) 14934887Schin { 14944887Schin ed_ungetchar(vp->ed,'='); 14954887Schin goto escape; 14964887Schin } 14974887Schin vp->ed->e_tabcount = 0; 14984887Schin } 14994887Schin /* FALL THRU*/ 15004887Schin default: 15014887Schin if( mode == REPLACE ) 15024887Schin { 15034887Schin if( cur_virt < last_virt ) 15044887Schin { 15054887Schin replace(vp,c, 1); 15064887Schin if(cur_virt>max_virt) 15074887Schin max_virt = cur_virt; 15084887Schin continue; 15094887Schin } 15104887Schin cdelete(vp,1, BAD); 15114887Schin mode = APPEND; 15124887Schin max_virt = last_virt+3; 15134887Schin } 15144887Schin append(vp,c, mode); 15154887Schin break; 15164887Schin } 15174887Schin refresh(vp,INPUT); 15184887Schin 15194887Schin } 15204887Schin } 15214887Schin 15224887Schin /*{ MVCURSOR( motion ) 15234887Schin * 15244887Schin * This routine will move the virtual cursor according to motion 15254887Schin * for repeat times. 15264887Schin * 15274887Schin * It returns GOOD if successful; else BAD. 15284887Schin * 15294887Schin }*/ 15304887Schin 15314887Schin static int mvcursor(register Vi_t* vp,register int motion) 15324887Schin { 15334887Schin register int count; 15344887Schin register int tcur_virt; 15354887Schin register int incr = -1; 15364887Schin register int bound = 0; 15374887Schin 15384887Schin switch(motion) 15394887Schin { 15404887Schin /***** Cursor move commands *****/ 15414887Schin 15424887Schin case '0': /** First column **/ 15434887Schin tcur_virt = 0; 15444887Schin break; 15454887Schin 15464887Schin case '^': /** First nonblank character **/ 15474887Schin tcur_virt = first_virt; 15484887Schin while( isblank(tcur_virt) && tcur_virt < last_virt ) 15494887Schin ++tcur_virt; 15504887Schin break; 15514887Schin 15524887Schin case '|': 15534887Schin tcur_virt = vp->repeat-1; 15544887Schin if(tcur_virt <= last_virt) 15554887Schin break; 15564887Schin /* fall through */ 15574887Schin 15584887Schin case '$': /** End of line **/ 15594887Schin tcur_virt = last_virt; 15604887Schin break; 15614887Schin 15624887Schin case '[': 15634887Schin switch(motion=getcount(vp,ed_getchar(vp->ed,-1))) 15644887Schin { 15654887Schin case 'A': 1566*8462SApril.Chin@Sun.COM if(cur_virt>=0 && cur_virt<(SEARCHSIZE-2) && cur_virt == last_virt) 1567*8462SApril.Chin@Sun.COM { 1568*8462SApril.Chin@Sun.COM virtual[last_virt + 1] = '\0'; 1569*8462SApril.Chin@Sun.COM gencpy(&((genchar*)lsearch)[1], virtual); 1570*8462SApril.Chin@Sun.COM #if SHOPT_MULTIBYTE 1571*8462SApril.Chin@Sun.COM ed_external(&((genchar*)lsearch)[1],lsearch+1); 1572*8462SApril.Chin@Sun.COM #endif /* SHOPT_MULTIBYTE */ 1573*8462SApril.Chin@Sun.COM *lsearch = '^'; 1574*8462SApril.Chin@Sun.COM vp->direction = -2; 1575*8462SApril.Chin@Sun.COM ed_ungetchar(vp->ed,'n'); 1576*8462SApril.Chin@Sun.COM } 1577*8462SApril.Chin@Sun.COM else if(cur_virt==0 && vp->direction == -2) 1578*8462SApril.Chin@Sun.COM ed_ungetchar(vp->ed,'n'); 1579*8462SApril.Chin@Sun.COM else 1580*8462SApril.Chin@Sun.COM ed_ungetchar(vp->ed,'k'); 15814887Schin return(1); 15824887Schin case 'B': 15834887Schin ed_ungetchar(vp->ed,'j'); 15844887Schin return(1); 15854887Schin case 'C': 15864887Schin motion = last_virt; 15874887Schin incr = 1; 15884887Schin goto walk; 15894887Schin case 'D': 15904887Schin motion = first_virt; 15914887Schin goto walk; 15924887Schin case 'H': 15934887Schin tcur_virt = 0; 15944887Schin break; 15954887Schin case 'Y': 15964887Schin tcur_virt = last_virt; 15974887Schin break; 15984887Schin default: 15994887Schin ed_ungetchar(vp->ed,motion); 16004887Schin return(0); 16014887Schin } 16024887Schin break; 16034887Schin 16044887Schin case 'h': /** Left one **/ 16054887Schin case '\b': 16064887Schin motion = first_virt; 16074887Schin goto walk; 16084887Schin 16094887Schin case ' ': 16104887Schin case 'l': /** Right one **/ 16114887Schin motion = last_virt; 16124887Schin incr = 1; 16134887Schin walk: 16144887Schin tcur_virt = cur_virt; 16154887Schin if( incr*tcur_virt < motion) 16164887Schin { 16174887Schin tcur_virt += vp->repeat*incr; 16184887Schin if( incr*tcur_virt > motion) 16194887Schin tcur_virt = motion; 16204887Schin } 16214887Schin else 16224887Schin return(0); 16234887Schin break; 16244887Schin 16254887Schin case 'B': 16264887Schin case 'b': /** back word **/ 16274887Schin tcur_virt = cur_virt; 16284887Schin backword(vp,vp->repeat, motion); 16294887Schin if( cur_virt == tcur_virt ) 16304887Schin return(0); 16314887Schin return(1); 16324887Schin 16334887Schin case 'E': 16344887Schin case 'e': /** end of word **/ 16354887Schin tcur_virt = cur_virt; 16364887Schin if(tcur_virt >=0) 16374887Schin endword(vp, vp->repeat, motion); 16384887Schin if( cur_virt == tcur_virt ) 16394887Schin return(0); 16404887Schin return(1); 16414887Schin 16424887Schin case ',': /** reverse find old char **/ 16434887Schin case ';': /** find old char **/ 16444887Schin switch(vp->last_find) 16454887Schin { 16464887Schin case 't': 16474887Schin case 'f': 16484887Schin if(motion==';') 16494887Schin { 16504887Schin bound = last_virt; 16514887Schin incr = 1; 16524887Schin } 16534887Schin goto find_b; 16544887Schin 16554887Schin case 'T': 16564887Schin case 'F': 16574887Schin if(motion==',') 16584887Schin { 16594887Schin bound = last_virt; 16604887Schin incr = 1; 16614887Schin } 16624887Schin goto find_b; 16634887Schin 16644887Schin default: 16654887Schin return(0); 16664887Schin } 16674887Schin 16684887Schin 16694887Schin case 't': /** find up to new char forward **/ 16704887Schin case 'f': /** find new char forward **/ 16714887Schin bound = last_virt; 16724887Schin incr = 1; 16734887Schin 16744887Schin case 'T': /** find up to new char backward **/ 16754887Schin case 'F': /** find new char backward **/ 16764887Schin vp->last_find = motion; 16774887Schin if((vp->findchar=getrchar(vp))==ESC) 16784887Schin return(1); 16794887Schin find_b: 16804887Schin tcur_virt = cur_virt; 16814887Schin count = vp->repeat; 16824887Schin while( count-- ) 16834887Schin { 16844887Schin while( incr*(tcur_virt+=incr) <= bound 16854887Schin && virtual[tcur_virt] != vp->findchar ); 16864887Schin if( incr*tcur_virt > bound ) 16874887Schin { 16884887Schin return(0); 16894887Schin } 16904887Schin } 16914887Schin if( fold(vp->last_find) == 'T' ) 16924887Schin tcur_virt -= incr; 16934887Schin break; 16944887Schin 16954887Schin case '%': 16964887Schin { 16974887Schin int nextmotion; 16984887Schin int nextc; 16994887Schin tcur_virt = cur_virt; 17004887Schin while( tcur_virt <= last_virt 17014887Schin && strchr(paren_chars,virtual[tcur_virt])==(char*)0) 17024887Schin tcur_virt++; 17034887Schin if(tcur_virt > last_virt ) 17044887Schin return(0); 17054887Schin nextc = virtual[tcur_virt]; 17064887Schin count = strchr(paren_chars,nextc)-paren_chars; 17074887Schin if(count < 3) 17084887Schin { 17094887Schin incr = 1; 17104887Schin bound = last_virt; 17114887Schin nextmotion = paren_chars[count+3]; 17124887Schin } 17134887Schin else 17144887Schin nextmotion = paren_chars[count-3]; 17154887Schin count = 1; 17164887Schin while(count >0 && incr*(tcur_virt+=incr) <= bound) 17174887Schin { 17184887Schin if(virtual[tcur_virt] == nextmotion) 17194887Schin count--; 17204887Schin else if(virtual[tcur_virt]==nextc) 17214887Schin count++; 17224887Schin } 17234887Schin if(count) 17244887Schin return(0); 17254887Schin break; 17264887Schin } 17274887Schin 17284887Schin case 'W': 17294887Schin case 'w': /** forward word **/ 17304887Schin tcur_virt = cur_virt; 17314887Schin forward(vp,vp->repeat, motion); 17324887Schin if( tcur_virt == cur_virt ) 17334887Schin return(0); 17344887Schin return(1); 17354887Schin 17364887Schin default: 17374887Schin return(0); 17384887Schin } 17394887Schin cur_virt = tcur_virt; 17404887Schin 17414887Schin return(1); 17424887Schin } 17434887Schin 17444887Schin /* 17454887Schin * print a string 17464887Schin */ 17474887Schin 17484887Schin static void pr_string(register Vi_t *vp, register const char *sp) 17494887Schin { 17504887Schin /*** copy string sp ***/ 17514887Schin register char *ptr = editb.e_outptr; 17524887Schin while(*sp) 17534887Schin *ptr++ = *sp++; 17544887Schin editb.e_outptr = ptr; 17554887Schin return; 17564887Schin } 17574887Schin 17584887Schin /*{ PUTSTRING( column, nchars ) 17594887Schin * 17604887Schin * Put nchars starting at column of physical into the workspace 17614887Schin * to be printed. 17624887Schin * 17634887Schin }*/ 17644887Schin 17654887Schin static void putstring(register Vi_t *vp,register int col, register int nchars) 17664887Schin { 17674887Schin while( nchars-- ) 17684887Schin putchar(physical[col++]); 17694887Schin return; 17704887Schin } 17714887Schin 17724887Schin /*{ REFRESH( mode ) 17734887Schin * 17744887Schin * This routine will refresh the crt so the physical image matches 17754887Schin * the virtual image and display the proper window. 17764887Schin * 17774887Schin * mode = CONTROL, refresh in control mode, ie. leave cursor 17784887Schin * positioned at last char printed. 17794887Schin * = INPUT, refresh in input mode; leave cursor positioned 17804887Schin * after last char printed. 17814887Schin * = TRANSLATE, perform virtual to physical translation 17824887Schin * and adjust left margin only. 17834887Schin * 17844887Schin * +-------------------------------+ 17854887Schin * | | | virtual | | | 17864887Schin * +-------------------------------+ 17874887Schin * cur_virt last_virt 17884887Schin * 17894887Schin * +-----------------------------------------------+ 17904887Schin * | | | physical | | | 17914887Schin * +-----------------------------------------------+ 17924887Schin * cur_phys last_phys 17934887Schin * 17944887Schin * 0 w_size - 1 17954887Schin * +-----------------------+ 17964887Schin * | | | window | 17974887Schin * +-----------------------+ 17984887Schin * cur_window = cur_phys - first_wind 17994887Schin }*/ 18004887Schin 18014887Schin static void refresh(register Vi_t* vp, int mode) 18024887Schin { 18034887Schin register int p; 18044887Schin register int regb; 18054887Schin register int first_w = vp->first_wind; 18064887Schin int p_differ; 18074887Schin int new_lw; 18084887Schin int ncur_phys; 18094887Schin int opflag; /* search optimize flag */ 18104887Schin 18114887Schin # define w regb 18124887Schin # define v regb 18134887Schin 18144887Schin /*** find out if it's necessary to start translating at beginning ***/ 18154887Schin 18164887Schin if(lookahead>0) 18174887Schin { 18184887Schin p = previous[lookahead-1]; 18194887Schin if(p != ESC && p != '\n' && p != '\r') 18204887Schin mode = TRANSLATE; 18214887Schin } 18224887Schin v = cur_virt; 18234887Schin if( v<vp->ocur_virt || vp->ocur_virt==INVALID 18244887Schin || ( v==vp->ocur_virt 18254887Schin && (!is_print(virtual[v]) || !is_print(vp->o_v_char))) ) 18264887Schin { 18274887Schin opflag = 0; 18284887Schin p = 0; 18294887Schin v = 0; 18304887Schin } 18314887Schin else 18324887Schin { 18334887Schin opflag = 1; 18344887Schin p = vp->ocur_phys; 18354887Schin v = vp->ocur_virt; 18364887Schin if( !is_print(virtual[v]) ) 18374887Schin { 18384887Schin /*** avoid double ^'s ***/ 18394887Schin ++p; 18404887Schin ++v; 18414887Schin } 18424887Schin } 18434887Schin virtual[last_virt+1] = 0; 18444887Schin ncur_phys = ed_virt_to_phys(vp->ed,virtual,physical,cur_virt,v,p); 18454887Schin p = genlen(physical); 18464887Schin if( --p < 0 ) 18474887Schin last_phys = 0; 18484887Schin else 18494887Schin last_phys = p; 18504887Schin 18514887Schin /*** see if this was a translate only ***/ 18524887Schin 18534887Schin if( mode == TRANSLATE ) 18544887Schin return; 18554887Schin 18564887Schin /*** adjust left margin if necessary ***/ 18574887Schin 18584887Schin if( ncur_phys<first_w || ncur_phys>=(first_w + w_size) ) 18594887Schin { 18604887Schin cursor(vp,first_w); 18614887Schin first_w = ncur_phys - (w_size>>1); 18624887Schin if( first_w < 0 ) 18634887Schin first_w = 0; 18644887Schin vp->first_wind = cur_phys = first_w; 18654887Schin } 18664887Schin 18674887Schin /*** attempt to optimize search somewhat to find ***/ 18684887Schin /*** out where physical and window images differ ***/ 18694887Schin 18704887Schin if( first_w==vp->ofirst_wind && ncur_phys>=vp->ocur_phys && opflag==1 ) 18714887Schin { 18724887Schin p = vp->ocur_phys; 18734887Schin w = p - first_w; 18744887Schin } 18754887Schin else 18764887Schin { 18774887Schin p = first_w; 18784887Schin w = 0; 18794887Schin } 18804887Schin 18814887Schin for(; (p<=last_phys && w<=vp->last_wind); ++p, ++w) 18824887Schin { 18834887Schin if( window[w] != physical[p] ) 18844887Schin break; 18854887Schin } 18864887Schin p_differ = p; 18874887Schin 18884887Schin if( (p>last_phys || p>=first_w+w_size) && w>vp->last_wind 18894887Schin && cur_virt==vp->ocur_virt ) 18904887Schin { 18914887Schin /*** images are identical ***/ 18924887Schin return; 18934887Schin } 18944887Schin 18954887Schin /*** copy the physical image to the window image ***/ 18964887Schin 18974887Schin if( last_virt != INVALID ) 18984887Schin { 18994887Schin while( p <= last_phys && w < w_size ) 19004887Schin window[w++] = physical[p++]; 19014887Schin } 19024887Schin new_lw = w; 19034887Schin 19044887Schin /*** erase trailing characters if needed ***/ 19054887Schin 19064887Schin while( w <= vp->last_wind ) 19074887Schin window[w++] = ' '; 19084887Schin vp->last_wind = --w; 19094887Schin 19104887Schin p = p_differ; 19114887Schin 19124887Schin /*** move cursor to start of difference ***/ 19134887Schin 19144887Schin cursor(vp,p); 19154887Schin 19164887Schin /*** and output difference ***/ 19174887Schin 19184887Schin w = p - first_w; 19194887Schin while( w <= vp->last_wind ) 19204887Schin putchar(window[w++]); 19214887Schin 19224887Schin cur_phys = w + first_w; 19234887Schin vp->last_wind = --new_lw; 19244887Schin 19254887Schin if( last_phys >= w_size ) 19264887Schin { 19274887Schin if( first_w == 0 ) 19284887Schin vp->long_char = '>'; 19294887Schin else if( last_phys < (first_w+w_size) ) 19304887Schin vp->long_char = '<'; 19314887Schin else 19324887Schin vp->long_char = '*'; 19334887Schin } 19344887Schin else 19354887Schin vp->long_char = ' '; 19364887Schin 19374887Schin if( vp->long_line != vp->long_char ) 19384887Schin { 19394887Schin /*** indicate lines longer than window ***/ 19404887Schin while( w++ < w_size ) 19414887Schin { 19424887Schin putchar(' '); 19434887Schin ++cur_phys; 19444887Schin } 19454887Schin putchar(vp->long_char); 19464887Schin ++cur_phys; 19474887Schin vp->long_line = vp->long_char; 19484887Schin } 19494887Schin 1950*8462SApril.Chin@Sun.COM if(vp->ed->e_multiline && vp->ofirst_wind==INVALID && !vp->ed->e_nocrnl) 1951*8462SApril.Chin@Sun.COM ed_setcursor(vp->ed, physical, last_phys+1, last_phys+1, -1); 1952*8462SApril.Chin@Sun.COM vp->ed->e_nocrnl = 0; 19534887Schin vp->ocur_phys = ncur_phys; 19544887Schin vp->ocur_virt = cur_virt; 19554887Schin vp->ofirst_wind = first_w; 19564887Schin 19574887Schin if( mode==INPUT && cur_virt>INVALID ) 19584887Schin ++ncur_phys; 19594887Schin 19604887Schin cursor(vp,ncur_phys); 19614887Schin ed_flush(vp->ed); 19624887Schin return; 19634887Schin } 19644887Schin 19654887Schin /*{ REPLACE( char, increment ) 19664887Schin * 19674887Schin * Replace the cur_virt character with char. This routine attempts 19684887Schin * to avoid using refresh(). 19694887Schin * 19704887Schin * increment = 1, increment cur_virt after replacement. 19714887Schin * = 0, leave cur_virt where it is. 19724887Schin * 19734887Schin }*/ 19744887Schin 19754887Schin static void replace(register Vi_t *vp, register int c, register int increment) 19764887Schin { 19774887Schin register int cur_window; 19784887Schin 19794887Schin if( cur_virt == INVALID ) 19804887Schin { 19814887Schin /*** can't replace invalid cursor ***/ 19824887Schin ed_ringbell(); 19834887Schin return; 19844887Schin } 19854887Schin cur_window = cur_phys - vp->first_wind; 19864887Schin if( vp->ocur_virt == INVALID || !is_print(c) 19874887Schin || !is_print(virtual[cur_virt]) 19884887Schin || !is_print(vp->o_v_char) 19894887Schin #if SHOPT_MULTIBYTE 19904887Schin || !iswascii(c) || mbwidth(vp->o_v_char)>1 19914887Schin || !iswascii(virtual[cur_virt]) 19924887Schin #endif /* SHOPT_MULTIBYTE */ 19934887Schin || (increment && (cur_window==w_size-1) 19944887Schin || !is_print(virtual[cur_virt+1])) ) 19954887Schin { 19964887Schin /*** must use standard refresh routine ***/ 19974887Schin 19984887Schin cdelete(vp,1, BAD); 19994887Schin append(vp,c, APPEND); 20004887Schin if( increment && cur_virt<last_virt ) 20014887Schin ++cur_virt; 20024887Schin refresh(vp,CONTROL); 20034887Schin } 20044887Schin else 20054887Schin { 20064887Schin virtual[cur_virt] = c; 20074887Schin physical[cur_phys] = c; 20084887Schin window[cur_window] = c; 20094887Schin putchar(c); 20104887Schin if(increment) 20114887Schin { 20124887Schin c = virtual[++cur_virt]; 20134887Schin ++cur_phys; 20144887Schin } 20154887Schin else 20164887Schin { 20174887Schin putchar('\b'); 20184887Schin } 20194887Schin vp->o_v_char = c; 20204887Schin ed_flush(vp->ed); 20214887Schin } 20224887Schin return; 20234887Schin } 20244887Schin 20254887Schin /*{ RESTORE_V() 20264887Schin * 20274887Schin * Restore the contents of virtual space from u_space. 20284887Schin * 20294887Schin }*/ 20304887Schin 20314887Schin static void restore_v(register Vi_t *vp) 20324887Schin { 20334887Schin register int tmpcol; 20344887Schin genchar tmpspace[MAXLINE]; 20354887Schin 20364887Schin if( vp->u_column == INVALID-1 ) 20374887Schin { 20384887Schin /*** never saved anything ***/ 20394887Schin ed_ringbell(); 20404887Schin return; 20414887Schin } 20424887Schin gencpy(tmpspace, vp->u_space); 20434887Schin tmpcol = vp->u_column; 20444887Schin save_v(vp); 20454887Schin gencpy(virtual, tmpspace); 20464887Schin cur_virt = tmpcol; 20474887Schin last_virt = genlen(tmpspace) - 1; 20484887Schin vp->ocur_virt = MAXCHAR; /** invalidate refresh optimization **/ 20494887Schin return; 20504887Schin } 20514887Schin 20524887Schin /*{ SAVE_LAST() 20534887Schin * 20544887Schin * If the user has typed something, save it in last line. 20554887Schin * 20564887Schin }*/ 20574887Schin 20584887Schin static void save_last(register Vi_t* vp) 20594887Schin { 20604887Schin register int i; 20614887Schin 20624887Schin if( (i = cur_virt - first_virt + 1) > 0 ) 20634887Schin { 20644887Schin /*** save last thing user typed ***/ 20654887Schin if(i >= MAXLINE) 20664887Schin i = MAXLINE-1; 20674887Schin genncpy(vp->lastline, (&virtual[first_virt]), i); 20684887Schin vp->lastline[i] = '\0'; 20694887Schin } 20704887Schin return; 20714887Schin } 20724887Schin 20734887Schin /*{ SAVE_V() 20744887Schin * 20754887Schin * This routine will save the contents of virtual in u_space. 20764887Schin * 20774887Schin }*/ 20784887Schin 20794887Schin static void save_v(register Vi_t *vp) 20804887Schin { 20814887Schin if(!inmacro) 20824887Schin { 20834887Schin virtual[last_virt + 1] = '\0'; 20844887Schin gencpy(vp->u_space, virtual); 20854887Schin vp->u_column = cur_virt; 20864887Schin } 20874887Schin return; 20884887Schin } 20894887Schin 20904887Schin /*{ SEARCH( mode ) 20914887Schin * 20924887Schin * Search history file for regular expression. 20934887Schin * 20944887Schin * mode = '/' require search string and search new to old 20954887Schin * mode = '?' require search string and search old to new 20964887Schin * mode = 'N' repeat last search in reverse direction 20974887Schin * mode = 'n' repeat last search 20984887Schin * 20994887Schin }*/ 21004887Schin 21014887Schin /* 21024887Schin * search for <string> in the current command 21034887Schin */ 21044887Schin static int curline_search(Vi_t *vp, const char *string) 21054887Schin { 21064887Schin register int len=strlen(string); 21074887Schin register const char *dp,*cp=string, *dpmax; 21084887Schin #if SHOPT_MULTIBYTE 21094887Schin ed_external(vp->u_space,(char*)vp->u_space); 21104887Schin #endif /* SHOPT_MULTIBYTE */ 21114887Schin for(dp=(char*)vp->u_space,dpmax=dp+strlen(dp)-len; dp<=dpmax; dp++) 21124887Schin { 21134887Schin if(*dp==*cp && memcmp(cp,dp,len)==0) 21144887Schin return(dp-(char*)vp->u_space); 21154887Schin } 21164887Schin #if SHOPT_MULTIBYTE 21174887Schin ed_internal((char*)vp->u_space,vp->u_space); 21184887Schin #endif /* SHOPT_MULTIBYTE */ 21194887Schin return(-1); 21204887Schin } 21214887Schin 21224887Schin static int search(register Vi_t* vp,register int mode) 21234887Schin { 21244887Schin register int new_direction; 21254887Schin register int oldcurhline; 21264887Schin register int i; 21274887Schin Histloc_t location; 21284887Schin 2129*8462SApril.Chin@Sun.COM if( vp->direction == -2 && mode != 'n') 2130*8462SApril.Chin@Sun.COM vp->direction = -1; 21314887Schin if( mode == '/' || mode == '?') 21324887Schin { 21334887Schin /*** new search expression ***/ 21344887Schin del_line(vp,BAD); 21354887Schin append(vp,mode, APPEND); 21364887Schin refresh(vp,INPUT); 21374887Schin first_virt = 1; 21384887Schin getline(vp,SEARCH); 21394887Schin first_virt = 0; 21404887Schin virtual[last_virt + 1] = '\0'; /*** make null terminated ***/ 21414887Schin vp->direction = mode=='/' ? -1 : 1; 21424887Schin } 21434887Schin 21444887Schin if( cur_virt == INVALID ) 21454887Schin { 21464887Schin /*** no operation ***/ 21474887Schin return(ABORT); 21484887Schin } 21494887Schin 21504887Schin if( cur_virt==0 || fold(mode)=='N' ) 21514887Schin { 21524887Schin /*** user wants repeat of last search ***/ 21534887Schin del_line(vp,BAD); 21544887Schin strcpy( ((char*)virtual)+1, lsearch); 21554887Schin #if SHOPT_MULTIBYTE 21564887Schin *((char*)virtual) = '/'; 21574887Schin ed_internal((char*)virtual,virtual); 21584887Schin #endif /* SHOPT_MULTIBYTE */ 21594887Schin } 21604887Schin 21614887Schin if( mode == 'N' ) 21624887Schin new_direction = -vp->direction; 21634887Schin else 21644887Schin new_direction = vp->direction; 21654887Schin 21664887Schin 21674887Schin /*** now search ***/ 21684887Schin 21694887Schin oldcurhline = curhline; 21704887Schin #if SHOPT_MULTIBYTE 21714887Schin ed_external(virtual,(char*)virtual); 21724887Schin #endif /* SHOPT_MULTIBYTE */ 21734887Schin if(mode=='?' && (i=curline_search(vp,((char*)virtual)+1))>=0) 21744887Schin { 21754887Schin location.hist_command = curhline; 21764887Schin location.hist_char = i; 21774887Schin } 21784887Schin else 21794887Schin { 21804887Schin i = INVALID; 21814887Schin if( new_direction==1 && curhline >= histmax ) 21824887Schin curhline = histmin + 1; 21834887Schin location = hist_find(sh.hist_ptr,((char*)virtual)+1, curhline, 1, new_direction); 21844887Schin } 21854887Schin cur_virt = i; 21864887Schin strncpy(lsearch, ((char*)virtual)+1, SEARCHSIZE); 21874887Schin if( (curhline=location.hist_command) >=0 ) 21884887Schin { 21894887Schin vp->ocur_virt = INVALID; 21904887Schin return(GOOD); 21914887Schin } 21924887Schin 21934887Schin /*** could not find matching line ***/ 21944887Schin 21954887Schin curhline = oldcurhline; 21964887Schin return(BAD); 21974887Schin } 21984887Schin 21994887Schin /*{ SYNC_CURSOR() 22004887Schin * 22014887Schin * This routine will move the physical cursor to the same 22024887Schin * column as the virtual cursor. 22034887Schin * 22044887Schin }*/ 22054887Schin 22064887Schin static void sync_cursor(register Vi_t *vp) 22074887Schin { 22084887Schin register int p; 22094887Schin register int v; 22104887Schin register int c; 22114887Schin int new_phys; 22124887Schin 22134887Schin if( cur_virt == INVALID ) 22144887Schin return; 22154887Schin 22164887Schin /*** find physical col that corresponds to virtual col ***/ 22174887Schin 22184887Schin new_phys = 0; 22194887Schin if(vp->first_wind==vp->ofirst_wind && cur_virt>vp->ocur_virt && vp->ocur_virt!=INVALID) 22204887Schin { 22214887Schin /*** try to optimize search a little ***/ 22224887Schin p = vp->ocur_phys + 1; 22234887Schin #if SHOPT_MULTIBYTE 22244887Schin while(physical[p]==MARKER) 22254887Schin p++; 22264887Schin #endif /* SHOPT_MULTIBYTE */ 22274887Schin v = vp->ocur_virt + 1; 22284887Schin } 22294887Schin else 22304887Schin { 22314887Schin p = 0; 22324887Schin v = 0; 22334887Schin } 22344887Schin for(; v <= last_virt; ++p, ++v) 22354887Schin { 22364887Schin #if SHOPT_MULTIBYTE 22374887Schin int d; 22384887Schin c = virtual[v]; 22394887Schin if((d = mbwidth(c)) > 1) 22404887Schin { 22414887Schin if( v != cur_virt ) 22424887Schin p += (d-1); 22434887Schin } 22444887Schin else if(!iswprint(c)) 22454887Schin #else 22464887Schin c = virtual[v]; 22474887Schin if(!isprint(c)) 22484887Schin #endif /* SHOPT_MULTIBYTE */ 22494887Schin { 22504887Schin if( c == '\t' ) 22514887Schin { 22524887Schin p -= ((p+editb.e_plen)%TABSIZE); 22534887Schin p += (TABSIZE-1); 22544887Schin } 22554887Schin else 22564887Schin { 22574887Schin ++p; 22584887Schin } 22594887Schin } 22604887Schin if( v == cur_virt ) 22614887Schin { 22624887Schin new_phys = p; 22634887Schin break; 22644887Schin } 22654887Schin } 22664887Schin 22674887Schin if( new_phys < vp->first_wind || new_phys >= vp->first_wind + w_size ) 22684887Schin { 22694887Schin /*** asked to move outside of window ***/ 22704887Schin 22714887Schin window[0] = '\0'; 22724887Schin refresh(vp,CONTROL); 22734887Schin return; 22744887Schin } 22754887Schin 22764887Schin cursor(vp,new_phys); 22774887Schin ed_flush(vp->ed); 22784887Schin vp->ocur_phys = cur_phys; 22794887Schin vp->ocur_virt = cur_virt; 22804887Schin vp->o_v_char = virtual[vp->ocur_virt]; 22814887Schin 22824887Schin return; 22834887Schin } 22844887Schin 22854887Schin /*{ TEXTMOD( command, mode ) 22864887Schin * 22874887Schin * Modify text operations. 22884887Schin * 22894887Schin * mode != 0, repeat previous operation 22904887Schin * 22914887Schin }*/ 22924887Schin 22934887Schin static int textmod(register Vi_t *vp,register int c, int mode) 22944887Schin { 22954887Schin register int i; 22964887Schin register genchar *p = vp->lastline; 22974887Schin register int trepeat = vp->repeat; 22984887Schin genchar *savep; 22994887Schin 23004887Schin if(mode && (fold(vp->lastmotion)=='F' || fold(vp->lastmotion)=='T')) 23014887Schin vp->lastmotion = ';'; 23024887Schin 23034887Schin if( fold(c) == 'P' ) 23044887Schin { 23054887Schin /*** change p from lastline to yankbuf ***/ 23064887Schin p = yankbuf; 23074887Schin } 23084887Schin 23094887Schin addin: 23104887Schin switch( c ) 23114887Schin { 23124887Schin /***** Input commands *****/ 23134887Schin 23144887Schin #if KSHELL 23154887Schin case '\t': 23164887Schin if(vp->ed->e_tabcount!=1) 23174887Schin return(BAD); 23184887Schin c = '='; 23194887Schin case '*': /** do file name expansion in place **/ 23204887Schin case '\\': /** do file name completion in place **/ 23214887Schin if( cur_virt == INVALID ) 23224887Schin return(BAD); 23234887Schin case '=': /** list file name expansions **/ 23244887Schin save_v(vp); 23254887Schin i = last_virt; 23264887Schin ++last_virt; 23274887Schin mode = cur_virt-1; 23284887Schin virtual[last_virt] = 0; 23294887Schin if(ed_expand(vp->ed,(char*)virtual, &cur_virt, &last_virt, c, vp->repeat_set?vp->repeat:-1)<0) 23304887Schin { 23314887Schin if(vp->ed->e_tabcount) 23324887Schin { 23334887Schin vp->ed->e_tabcount=2; 23344887Schin ed_ungetchar(vp->ed,'\t'); 23354887Schin --last_virt; 23364887Schin return(APPEND); 23374887Schin } 23384887Schin last_virt = i; 23394887Schin ed_ringbell(); 23404887Schin } 23414887Schin else if(c == '=' && !vp->repeat_set) 23424887Schin { 23434887Schin last_virt = i; 23444887Schin vp->nonewline++; 23454887Schin ed_ungetchar(vp->ed,cntl('L')); 23464887Schin return(GOOD); 23474887Schin } 23484887Schin else 23494887Schin { 23504887Schin --cur_virt; 23514887Schin --last_virt; 23524887Schin vp->ocur_virt = MAXCHAR; 23534887Schin if(c=='=' || (mode<cur_virt && (virtual[cur_virt]==' ' || virtual[cur_virt]=='/'))) 23544887Schin vp->ed->e_tabcount = 0; 23554887Schin return(APPEND); 23564887Schin } 23574887Schin break; 23584887Schin 23594887Schin case '@': /** macro expansion **/ 23604887Schin if( mode ) 23614887Schin c = vp->lastmacro; 23624887Schin else 23634887Schin if((c=getrchar(vp))==ESC) 23644887Schin return(GOOD); 23654887Schin if(!inmacro) 23664887Schin vp->lastmacro = c; 23674887Schin if(ed_macro(vp->ed,c)) 23684887Schin { 23694887Schin save_v(vp); 23704887Schin inmacro++; 23714887Schin return(GOOD); 23724887Schin } 23734887Schin ed_ringbell(); 23744887Schin return(BAD); 23754887Schin 23764887Schin #endif /* KSHELL */ 23774887Schin case '_': /** append last argument of prev command **/ 23784887Schin save_v(vp); 23794887Schin { 23804887Schin genchar tmpbuf[MAXLINE]; 23814887Schin if(vp->repeat_set==0) 23824887Schin vp->repeat = -1; 23834887Schin p = (genchar*)hist_word((char*)tmpbuf,MAXLINE,vp->repeat); 23844887Schin #if !KSHELL 23854887Schin if(p==0) 23864887Schin { 23874887Schin ed_ringbell(); 23884887Schin break; 23894887Schin } 23904887Schin #endif /* KSHELL */ 23914887Schin #if SHOPT_MULTIBYTE 23924887Schin ed_internal((char*)p,tmpbuf); 23934887Schin p = tmpbuf; 23944887Schin #endif /* SHOPT_MULTIBYTE */ 23954887Schin i = ' '; 23964887Schin do 23974887Schin { 23984887Schin append(vp,i,APPEND); 23994887Schin } 24004887Schin while(i = *p++); 24014887Schin return(APPEND); 24024887Schin } 24034887Schin 24044887Schin case 'A': /** append to end of line **/ 24054887Schin cur_virt = last_virt; 24064887Schin sync_cursor(vp); 24074887Schin 24084887Schin case 'a': /** append **/ 24094887Schin if( fold(mode) == 'A' ) 24104887Schin { 24114887Schin c = 'p'; 24124887Schin goto addin; 24134887Schin } 24144887Schin save_v(vp); 24154887Schin if( cur_virt != INVALID ) 24164887Schin { 24174887Schin first_virt = cur_virt + 1; 24184887Schin cursor(vp,cur_phys + 1); 24194887Schin ed_flush(vp->ed); 24204887Schin } 24214887Schin return(APPEND); 24224887Schin 24234887Schin case 'I': /** insert at beginning of line **/ 24244887Schin cur_virt = first_virt; 24254887Schin sync_cursor(vp); 24264887Schin 24274887Schin case 'i': /** insert **/ 24284887Schin if( fold(mode) == 'I' ) 24294887Schin { 24304887Schin c = 'P'; 24314887Schin goto addin; 24324887Schin } 24334887Schin save_v(vp); 24344887Schin if( cur_virt != INVALID ) 24354887Schin { 24364887Schin vp->o_v_char = virtual[cur_virt]; 24374887Schin first_virt = cur_virt--; 24384887Schin } 24394887Schin return(INSERT); 24404887Schin 24414887Schin case 'C': /** change to eol **/ 24424887Schin c = '$'; 24434887Schin goto chgeol; 24444887Schin 24454887Schin case 'c': /** change **/ 24464887Schin if( mode ) 24474887Schin c = vp->lastmotion; 24484887Schin else 24494887Schin c = getcount(vp,ed_getchar(vp->ed,-1)); 24504887Schin chgeol: 24514887Schin vp->lastmotion = c; 24524887Schin if( c == 'c' ) 24534887Schin { 24544887Schin del_line(vp,GOOD); 24554887Schin return(APPEND); 24564887Schin } 24574887Schin 24584887Schin if(!delmotion(vp, c, 'c')) 24594887Schin return(BAD); 24604887Schin 24614887Schin if( mode == 'c' ) 24624887Schin { 24634887Schin c = 'p'; 24644887Schin trepeat = 1; 24654887Schin goto addin; 24664887Schin } 24674887Schin first_virt = cur_virt + 1; 24684887Schin return(APPEND); 24694887Schin 24704887Schin case 'D': /** delete to eol **/ 24714887Schin c = '$'; 24724887Schin goto deleol; 24734887Schin 24744887Schin case 'd': /** delete **/ 24754887Schin if( mode ) 24764887Schin c = vp->lastmotion; 24774887Schin else 24784887Schin c = getcount(vp,ed_getchar(vp->ed,-1)); 24794887Schin deleol: 24804887Schin vp->lastmotion = c; 24814887Schin if( c == 'd' ) 24824887Schin { 24834887Schin del_line(vp,GOOD); 24844887Schin break; 24854887Schin } 24864887Schin if(!delmotion(vp, c, 'd')) 24874887Schin return(BAD); 24884887Schin if( cur_virt < last_virt ) 24894887Schin ++cur_virt; 24904887Schin break; 24914887Schin 24924887Schin case 'P': 24934887Schin if( p[0] == '\0' ) 24944887Schin return(BAD); 24954887Schin if( cur_virt != INVALID ) 24964887Schin { 24974887Schin i = virtual[cur_virt]; 24984887Schin if(!is_print(i)) 24994887Schin vp->ocur_virt = INVALID; 25004887Schin --cur_virt; 25014887Schin } 25024887Schin 25034887Schin case 'p': /** print **/ 25044887Schin if( p[0] == '\0' ) 25054887Schin return(BAD); 25064887Schin 25074887Schin if( mode != 's' && mode != 'c' ) 25084887Schin { 25094887Schin save_v(vp); 25104887Schin if( c == 'P' ) 25114887Schin { 25124887Schin /*** fix stored cur_virt ***/ 25134887Schin ++vp->u_column; 25144887Schin } 25154887Schin } 25164887Schin if( mode == 'R' ) 25174887Schin mode = REPLACE; 25184887Schin else 25194887Schin mode = APPEND; 25204887Schin savep = p; 25214887Schin for(i=0; i<trepeat; ++i) 25224887Schin { 25234887Schin while(c= *p++) 25244887Schin append(vp,c,mode); 25254887Schin p = savep; 25264887Schin } 25274887Schin break; 25284887Schin 25294887Schin case 'R': /* Replace many chars **/ 25304887Schin if( mode == 'R' ) 25314887Schin { 25324887Schin c = 'P'; 25334887Schin goto addin; 25344887Schin } 25354887Schin save_v(vp); 25364887Schin if( cur_virt != INVALID ) 25374887Schin first_virt = cur_virt; 25384887Schin return(REPLACE); 25394887Schin 25404887Schin case 'r': /** replace **/ 25414887Schin if( mode ) 25424887Schin c = *p; 25434887Schin else 25444887Schin if((c=getrchar(vp))==ESC) 25454887Schin return(GOOD); 25464887Schin *p = c; 25474887Schin save_v(vp); 25484887Schin while(trepeat--) 25494887Schin replace(vp,c, trepeat!=0); 25504887Schin return(GOOD); 25514887Schin 25524887Schin case 'S': /** Substitute line - cc **/ 25534887Schin c = 'c'; 25544887Schin goto chgeol; 25554887Schin 25564887Schin case 's': /** substitute **/ 25574887Schin save_v(vp); 25584887Schin cdelete(vp,vp->repeat, BAD); 25594887Schin if( mode ) 25604887Schin { 25614887Schin c = 'p'; 25624887Schin trepeat = 1; 25634887Schin goto addin; 25644887Schin } 25654887Schin first_virt = cur_virt + 1; 25664887Schin return(APPEND); 25674887Schin 25684887Schin case 'Y': /** Yank to end of line **/ 25694887Schin c = '$'; 25704887Schin goto yankeol; 25714887Schin 25724887Schin case 'y': /** yank thru motion **/ 25734887Schin if( mode ) 25744887Schin c = vp->lastmotion; 25754887Schin else 25764887Schin c = getcount(vp,ed_getchar(vp->ed,-1)); 25774887Schin yankeol: 25784887Schin vp->lastmotion = c; 25794887Schin if( c == 'y' ) 25804887Schin { 25814887Schin gencpy(yankbuf, virtual); 25824887Schin } 25834887Schin else if(!delmotion(vp, c, 'y')) 25844887Schin { 25854887Schin return(BAD); 25864887Schin } 25874887Schin break; 25884887Schin 25894887Schin case 'x': /** delete repeat chars forward - dl **/ 25904887Schin c = 'l'; 25914887Schin goto deleol; 25924887Schin 25934887Schin case 'X': /** delete repeat chars backward - dh **/ 25944887Schin c = 'h'; 25954887Schin goto deleol; 25964887Schin 25974887Schin case '~': /** invert case and advance **/ 25984887Schin if( cur_virt != INVALID ) 25994887Schin { 26004887Schin save_v(vp); 26014887Schin i = INVALID; 26024887Schin while(trepeat-->0 && i!=cur_virt) 26034887Schin { 26044887Schin i = cur_virt; 26054887Schin c = virtual[cur_virt]; 26064887Schin #if SHOPT_MULTIBYTE 26074887Schin if((c&~STRIP)==0) 26084887Schin #endif /* SHOPT_MULTIBYTE */ 26094887Schin if( isupper(c) ) 26104887Schin c = tolower(c); 26114887Schin else if( islower(c) ) 26124887Schin c = toupper(c); 26134887Schin replace(vp,c, 1); 26144887Schin } 26154887Schin return(GOOD); 26164887Schin } 26174887Schin else 26184887Schin return(BAD); 26194887Schin 26204887Schin default: 26214887Schin return(BAD); 26224887Schin } 26234887Schin refresh(vp,CONTROL); 26244887Schin return(GOOD); 26254887Schin } 26264887Schin 26274887Schin 26284887Schin #if SHOPT_MULTIBYTE 26294887Schin static int _isalph(register int v) 26304887Schin { 26314887Schin #ifdef _lib_iswalnum 26324887Schin return(iswalnum(v) || v=='_'); 26334887Schin #else 26344887Schin return((v&~STRIP) || isalnum(v) || v=='_'); 26354887Schin #endif 26364887Schin } 26374887Schin 26384887Schin 26394887Schin static int _isblank(register int v) 26404887Schin { 26414887Schin return((v&~STRIP)==0 && isspace(v)); 26424887Schin } 26434887Schin 26444887Schin static int _ismetach(register int v) 26454887Schin { 26464887Schin return((v&~STRIP)==0 && ismeta(v)); 26474887Schin } 26484887Schin 26494887Schin #endif /* SHOPT_MULTIBYTE */ 26504887Schin 26514887Schin /* 26524887Schin * get a character, after ^V processing 26534887Schin */ 26544887Schin static int getrchar(register Vi_t *vp) 26554887Schin { 26564887Schin register int c; 26574887Schin if((c=ed_getchar(vp->ed,1))== usrlnext) 26584887Schin c = ed_getchar(vp->ed,2); 26594887Schin return(c); 26604887Schin } 2661