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 */ 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 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 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 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 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 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 }*/ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 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 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 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 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 26424887Schin static int _isblank(register int v) 26434887Schin { 26444887Schin return((v&~STRIP)==0 && isspace(v)); 26454887Schin } 26464887Schin 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 */ 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