1*4887Schin /*********************************************************************** 2*4887Schin * * 3*4887Schin * This software is part of the ast package * 4*4887Schin * Copyright (c) 1982-2007 AT&T Knowledge Ventures * 5*4887Schin * and is licensed under the * 6*4887Schin * Common Public License, Version 1.0 * 7*4887Schin * by AT&T Knowledge Ventures * 8*4887Schin * * 9*4887Schin * A copy of the License is available at * 10*4887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 11*4887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12*4887Schin * * 13*4887Schin * Information and Software Systems Research * 14*4887Schin * AT&T Research * 15*4887Schin * Florham Park NJ * 16*4887Schin * * 17*4887Schin * David Korn <dgk@research.att.com> * 18*4887Schin * * 19*4887Schin ***********************************************************************/ 20*4887Schin #pragma prototyped 21*4887Schin /* Adapted for ksh by David Korn */ 22*4887Schin /*+ VI.C P.D. Sullivan 23*4887Schin * 24*4887Schin * One line editor for the shell based on the vi editor. 25*4887Schin * 26*4887Schin * Questions to: 27*4887Schin * P.D. Sullivan 28*4887Schin * cbosgd!pds 29*4887Schin -*/ 30*4887Schin 31*4887Schin 32*4887Schin #if KSHELL 33*4887Schin # include "defs.h" 34*4887Schin #else 35*4887Schin # include <ast.h> 36*4887Schin # include "FEATURE/options" 37*4887Schin #endif /* KSHELL */ 38*4887Schin #include <ctype.h> 39*4887Schin #include "io.h" 40*4887Schin 41*4887Schin #include "history.h" 42*4887Schin #include "edit.h" 43*4887Schin #include "terminal.h" 44*4887Schin #include "FEATURE/time" 45*4887Schin 46*4887Schin #if SHOPT_OLDTERMIO 47*4887Schin # undef ECHOCTL 48*4887Schin # define echoctl (vp->ed->e_echoctl) 49*4887Schin #else 50*4887Schin # ifdef ECHOCTL 51*4887Schin # define echoctl ECHOCTL 52*4887Schin # else 53*4887Schin # define echoctl 0 54*4887Schin # endif /* ECHOCTL */ 55*4887Schin #endif /*SHOPT_OLDTERMIO */ 56*4887Schin 57*4887Schin #ifndef FIORDCHK 58*4887Schin # define NTICKS 5 /* number of ticks for typeahead */ 59*4887Schin #endif /* FIORDCHK */ 60*4887Schin 61*4887Schin #define MAXCHAR MAXLINE-2 /* max char per line */ 62*4887Schin 63*4887Schin #if SHOPT_MULTIBYTE 64*4887Schin # include "lexstates.h" 65*4887Schin # define gencpy(a,b) ed_gencpy(a,b) 66*4887Schin # define genncpy(a,b,n) ed_genncpy(a,b,n) 67*4887Schin # define genlen(str) ed_genlen(str) 68*4887Schin # define digit(c) ((c&~STRIP)==0 && isdigit(c)) 69*4887Schin # define is_print(c) ((c&~STRIP) || isprint(c)) 70*4887Schin # if !_lib_iswprint && !defined(iswprint) 71*4887Schin # define iswprint(c) ((c&~0177) || isprint(c)) 72*4887Schin # endif 73*4887Schin static int _isalph(int); 74*4887Schin static int _ismetach(int); 75*4887Schin static int _isblank(int); 76*4887Schin # undef isblank 77*4887Schin # define isblank(v) _isblank(virtual[v]) 78*4887Schin # define isalph(v) _isalph(virtual[v]) 79*4887Schin # define ismetach(v) _ismetach(virtual[v]) 80*4887Schin #else 81*4887Schin static genchar _c; 82*4887Schin # define gencpy(a,b) strcpy((char*)(a),(char*)(b)) 83*4887Schin # define genncpy(a,b,n) strncpy((char*)(a),(char*)(b),n) 84*4887Schin # define genlen(str) strlen(str) 85*4887Schin # define isalph(v) ((_c=virtual[v])=='_'||isalnum(_c)) 86*4887Schin # undef isblank 87*4887Schin # define isblank(v) isspace(virtual[v]) 88*4887Schin # define ismetach(v) ismeta(virtual[v]) 89*4887Schin # define digit(c) isdigit(c) 90*4887Schin # define is_print(c) isprint(c) 91*4887Schin #endif /* SHOPT_MULTIBYTE */ 92*4887Schin 93*4887Schin #if ( 'a' == 97) /* ASCII? */ 94*4887Schin # define fold(c) ((c)&~040) /* lower and uppercase equivalent */ 95*4887Schin #else 96*4887Schin # define fold(c) ((c)|0100) /* lower and uppercase equivalent */ 97*4887Schin #endif 98*4887Schin 99*4887Schin #ifndef iswascii 100*4887Schin #define iswascii(c) (!((c)&(~0177))) 101*4887Schin #endif 102*4887Schin 103*4887Schin typedef struct _vi_ 104*4887Schin { 105*4887Schin int direction; 106*4887Schin int lastmacro; 107*4887Schin char addnl; /* boolean - add newline flag */ 108*4887Schin char last_find; /* last find command */ 109*4887Schin char last_cmd; /* last command */ 110*4887Schin char repeat_set; 111*4887Schin char nonewline; 112*4887Schin int findchar; /* last find char */ 113*4887Schin genchar *lastline; 114*4887Schin int first_wind; /* first column of window */ 115*4887Schin int last_wind; /* last column in window */ 116*4887Schin int lastmotion; /* last motion */ 117*4887Schin int long_char; /* line bigger than window */ 118*4887Schin int long_line; /* line bigger than window */ 119*4887Schin int ocur_phys; /* old current physical position */ 120*4887Schin int ocur_virt; /* old last virtual position */ 121*4887Schin int ofirst_wind; /* old window first col */ 122*4887Schin int o_v_char; /* prev virtual[ocur_virt] */ 123*4887Schin int repeat; /* repeat count for motion cmds */ 124*4887Schin int lastrepeat; /* last repeat count for motion cmds */ 125*4887Schin int u_column; /* undo current column */ 126*4887Schin int U_saved; /* original virtual saved */ 127*4887Schin genchar *U_space; /* used for U command */ 128*4887Schin genchar *u_space; /* used for u command */ 129*4887Schin #ifdef FIORDCHK 130*4887Schin clock_t typeahead; /* typeahead occurred */ 131*4887Schin #else 132*4887Schin int typeahead; /* typeahead occurred */ 133*4887Schin #endif /* FIORDCHK */ 134*4887Schin #if SHOPT_MULTIBYTE 135*4887Schin int bigvi; 136*4887Schin #endif 137*4887Schin Edit_t *ed; /* pointer to edit data */ 138*4887Schin } Vi_t; 139*4887Schin 140*4887Schin #define editb (*vp->ed) 141*4887Schin 142*4887Schin #undef putchar 143*4887Schin #define putchar(c) ed_putchar(vp->ed,c) 144*4887Schin 145*4887Schin #define crallowed editb.e_crlf 146*4887Schin #define cur_virt editb.e_cur /* current virtual column */ 147*4887Schin #define cur_phys editb.e_pcur /* current phys column cursor is at */ 148*4887Schin #define curhline editb.e_hline /* current history line */ 149*4887Schin #define first_virt editb.e_fcol /* first allowable column */ 150*4887Schin #define globals editb.e_globals /* local global variables */ 151*4887Schin #define histmin editb.e_hismin 152*4887Schin #define histmax editb.e_hismax 153*4887Schin #define last_phys editb.e_peol /* last column in physical */ 154*4887Schin #define last_virt editb.e_eol /* last column */ 155*4887Schin #define lsearch editb.e_search /* last search string */ 156*4887Schin #define lookahead editb.e_lookahead /* characters in buffer */ 157*4887Schin #define previous editb.e_lbuf /* lookahead buffer */ 158*4887Schin #define max_col editb.e_llimit /* maximum column */ 159*4887Schin #define Prompt editb.e_prompt /* pointer to prompt */ 160*4887Schin #define plen editb.e_plen /* length of prompt */ 161*4887Schin #define physical editb.e_physbuf /* physical image */ 162*4887Schin #define usreof editb.e_eof /* user defined eof char */ 163*4887Schin #define usrerase editb.e_erase /* user defined erase char */ 164*4887Schin #define usrlnext editb.e_lnext /* user defined next literal */ 165*4887Schin #define usrkill editb.e_kill /* user defined kill char */ 166*4887Schin #define virtual editb.e_inbuf /* pointer to virtual image buffer */ 167*4887Schin #define window editb.e_window /* window buffer */ 168*4887Schin #define w_size editb.e_wsize /* window size */ 169*4887Schin #define inmacro editb.e_inmacro /* true when in macro */ 170*4887Schin #define yankbuf editb.e_killbuf /* yank/delete buffer */ 171*4887Schin 172*4887Schin 173*4887Schin #define ABORT -2 /* user abort */ 174*4887Schin #define APPEND -10 /* append chars */ 175*4887Schin #define BAD -1 /* failure flag */ 176*4887Schin #define BIGVI -15 /* user wants real vi */ 177*4887Schin #define CONTROL -20 /* control mode */ 178*4887Schin #define ENTER -25 /* enter flag */ 179*4887Schin #define GOOD 0 /* success flag */ 180*4887Schin #define INPUT -30 /* input mode */ 181*4887Schin #define INSERT -35 /* insert mode */ 182*4887Schin #define REPLACE -40 /* replace chars */ 183*4887Schin #define SEARCH -45 /* search flag */ 184*4887Schin #define TRANSLATE -50 /* translate virt to phys only */ 185*4887Schin 186*4887Schin #define INVALID (-1) /* invalid column */ 187*4887Schin 188*4887Schin static const char paren_chars[] = "([{)]}"; /* for % command */ 189*4887Schin 190*4887Schin static void cursor(Vi_t*, int); 191*4887Schin static void del_line(Vi_t*,int); 192*4887Schin static int getcount(Vi_t*,int); 193*4887Schin static void getline(Vi_t*,int); 194*4887Schin static int getrchar(Vi_t*); 195*4887Schin static int mvcursor(Vi_t*,int); 196*4887Schin static void pr_string(Vi_t*,const char*); 197*4887Schin static void putstring(Vi_t*,int, int); 198*4887Schin static void refresh(Vi_t*,int); 199*4887Schin static void replace(Vi_t*,int, int); 200*4887Schin static void restore_v(Vi_t*); 201*4887Schin static void save_last(Vi_t*); 202*4887Schin static void save_v(Vi_t*); 203*4887Schin static int search(Vi_t*,int); 204*4887Schin static void sync_cursor(Vi_t*); 205*4887Schin static int textmod(Vi_t*,int,int); 206*4887Schin 207*4887Schin /*+ VI_READ( fd, shbuf, nchar ) 208*4887Schin * 209*4887Schin * This routine implements a one line version of vi and is 210*4887Schin * called by _filbuf.c 211*4887Schin * 212*4887Schin -*/ 213*4887Schin 214*4887Schin /* 215*4887Schin * if reedit is non-zero, initialize edit buffer with reedit chars 216*4887Schin */ 217*4887Schin int ed_viread(void *context, int fd, register char *shbuf, int nchar, int reedit) 218*4887Schin { 219*4887Schin Edit_t *ed = (Edit_t*)context; 220*4887Schin register int i; /* general variable */ 221*4887Schin register int term_char; /* read() termination character */ 222*4887Schin register Vi_t *vp = ed->e_vi; 223*4887Schin char prompt[PRSIZE+2]; /* prompt */ 224*4887Schin genchar Physical[2*MAXLINE]; /* physical image */ 225*4887Schin genchar Ubuf[MAXLINE]; /* used for U command */ 226*4887Schin genchar ubuf[MAXLINE]; /* used for u command */ 227*4887Schin genchar Window[MAXLINE]; /* window image */ 228*4887Schin int Globals[9]; /* local global variables */ 229*4887Schin int esc_or_hang=0; /* <ESC> or hangup */ 230*4887Schin char cntl_char=0; /* TRUE if control character present */ 231*4887Schin #if SHOPT_RAWONLY 232*4887Schin # define viraw 1 233*4887Schin #else 234*4887Schin int viraw = (sh_isoption(SH_VIRAW) || sh.st.trap[SH_KEYTRAP]); 235*4887Schin # ifndef FIORDCHK 236*4887Schin clock_t oldtime, newtime; 237*4887Schin struct tms dummy; 238*4887Schin # endif /* FIORDCHK */ 239*4887Schin #endif /* SHOPT_RAWONLY */ 240*4887Schin if(!vp) 241*4887Schin { 242*4887Schin ed->e_vi = vp = newof(0,Vi_t,1,0); 243*4887Schin vp->lastline = (genchar*)malloc(MAXLINE*CHARSIZE); 244*4887Schin vp->direction = -1; 245*4887Schin vp->ed = ed; 246*4887Schin } 247*4887Schin 248*4887Schin /*** setup prompt ***/ 249*4887Schin 250*4887Schin Prompt = prompt; 251*4887Schin ed_setup(vp->ed,fd, reedit); 252*4887Schin shbuf[reedit] = 0; 253*4887Schin 254*4887Schin #if !SHOPT_RAWONLY 255*4887Schin if(!viraw) 256*4887Schin { 257*4887Schin /*** Change the eol characters to '\r' and eof ***/ 258*4887Schin /* in addition to '\n' and make eof an ESC */ 259*4887Schin if(tty_alt(ERRIO) < 0) 260*4887Schin return(reexit?reedit:ed_read(context, fd, shbuf, nchar,0)); 261*4887Schin 262*4887Schin #ifdef FIORDCHK 263*4887Schin ioctl(fd,FIORDCHK,&vp->typeahead); 264*4887Schin #else 265*4887Schin /* time the current line to determine typeahead */ 266*4887Schin oldtime = times(&dummy); 267*4887Schin #endif /* FIORDCHK */ 268*4887Schin #if KSHELL 269*4887Schin /* abort of interrupt has occurred */ 270*4887Schin if(sh.trapnote&SH_SIGSET) 271*4887Schin i = -1; 272*4887Schin else 273*4887Schin #endif /* KSHELL */ 274*4887Schin /*** Read the line ***/ 275*4887Schin i = ed_read(context, fd, shbuf, nchar, 0); 276*4887Schin #ifndef FIORDCHK 277*4887Schin newtime = times(&dummy); 278*4887Schin vp->typeahead = ((newtime-oldtime) < NTICKS); 279*4887Schin #endif /* FIORDCHK */ 280*4887Schin if(echoctl) 281*4887Schin { 282*4887Schin if( i <= 0 ) 283*4887Schin { 284*4887Schin /*** read error or eof typed ***/ 285*4887Schin tty_cooked(ERRIO); 286*4887Schin return(i); 287*4887Schin } 288*4887Schin term_char = shbuf[--i]; 289*4887Schin if( term_char == '\r' ) 290*4887Schin term_char = '\n'; 291*4887Schin if( term_char=='\n' || term_char==ESC ) 292*4887Schin shbuf[i--] = '\0'; 293*4887Schin else 294*4887Schin shbuf[i+1] = '\0'; 295*4887Schin } 296*4887Schin else 297*4887Schin { 298*4887Schin register int c = shbuf[0]; 299*4887Schin 300*4887Schin /*** Save and remove the last character if its an eol, ***/ 301*4887Schin /* changing '\r' to '\n' */ 302*4887Schin 303*4887Schin if( i == 0 ) 304*4887Schin { 305*4887Schin /*** ESC was typed as first char of line ***/ 306*4887Schin esc_or_hang = 1; 307*4887Schin term_char = ESC; 308*4887Schin shbuf[i--] = '\0'; /* null terminate line */ 309*4887Schin } 310*4887Schin else if( i<0 || c==usreof ) 311*4887Schin { 312*4887Schin /*** read error or eof typed ***/ 313*4887Schin tty_cooked(ERRIO); 314*4887Schin if( c == usreof ) 315*4887Schin i = 0; 316*4887Schin return(i); 317*4887Schin } 318*4887Schin else 319*4887Schin { 320*4887Schin term_char = shbuf[--i]; 321*4887Schin if( term_char == '\r' ) 322*4887Schin term_char = '\n'; 323*4887Schin #if !defined(VEOL2) && !defined(ECHOCTL) 324*4887Schin if(term_char=='\n') 325*4887Schin { 326*4887Schin tty_cooked(ERRIO); 327*4887Schin return(i+1); 328*4887Schin } 329*4887Schin #endif 330*4887Schin if( term_char=='\n' || term_char==usreof ) 331*4887Schin { 332*4887Schin /*** remove terminator & null terminate ***/ 333*4887Schin shbuf[i--] = '\0'; 334*4887Schin } 335*4887Schin else 336*4887Schin { 337*4887Schin /** terminator was ESC, which is not xmitted **/ 338*4887Schin term_char = ESC; 339*4887Schin shbuf[i+1] = '\0'; 340*4887Schin } 341*4887Schin } 342*4887Schin } 343*4887Schin } 344*4887Schin else 345*4887Schin #endif /* SHOPT_RAWONLY */ 346*4887Schin { 347*4887Schin /*** Set raw mode ***/ 348*4887Schin 349*4887Schin #if !SHOPT_RAWONLY 350*4887Schin if( editb.e_ttyspeed == 0 ) 351*4887Schin { 352*4887Schin /*** never did TCGETA, so do it ***/ 353*4887Schin /* avoids problem if user does 'sh -o viraw' */ 354*4887Schin tty_alt(ERRIO); 355*4887Schin } 356*4887Schin #endif /* SHOPT_RAWONLY */ 357*4887Schin if(tty_raw(ERRIO,0) < 0 ) 358*4887Schin return(reedit?reedit:ed_read(context, fd, shbuf, nchar,0)); 359*4887Schin i = last_virt-1; 360*4887Schin } 361*4887Schin 362*4887Schin /*** Initialize some things ***/ 363*4887Schin 364*4887Schin virtual = (genchar*)shbuf; 365*4887Schin #if SHOPT_MULTIBYTE 366*4887Schin virtual = (genchar*)roundof((char*)virtual-(char*)0,sizeof(genchar)); 367*4887Schin shbuf[i+1] = 0; 368*4887Schin i = ed_internal(shbuf,virtual)-1; 369*4887Schin #endif /* SHOPT_MULTIBYTE */ 370*4887Schin globals = Globals; 371*4887Schin cur_phys = i + 1; 372*4887Schin cur_virt = i; 373*4887Schin first_virt = 0; 374*4887Schin vp->first_wind = 0; 375*4887Schin last_virt = i; 376*4887Schin last_phys = i; 377*4887Schin vp->last_wind = i; 378*4887Schin vp->long_line = ' '; 379*4887Schin vp->long_char = ' '; 380*4887Schin vp->o_v_char = '\0'; 381*4887Schin vp->ocur_phys = 0; 382*4887Schin vp->ocur_virt = MAXCHAR; 383*4887Schin vp->ofirst_wind = 0; 384*4887Schin physical = Physical; 385*4887Schin vp->u_column = INVALID - 1; 386*4887Schin vp->U_space = Ubuf; 387*4887Schin vp->u_space = ubuf; 388*4887Schin window = Window; 389*4887Schin window[0] = '\0'; 390*4887Schin 391*4887Schin if(!yankbuf) 392*4887Schin yankbuf = (genchar*)malloc(MAXLINE*CHARSIZE); 393*4887Schin if( vp->last_cmd == '\0' ) 394*4887Schin { 395*4887Schin /*** first time for this shell ***/ 396*4887Schin 397*4887Schin vp->last_cmd = 'i'; 398*4887Schin vp->findchar = INVALID; 399*4887Schin vp->lastmotion = '\0'; 400*4887Schin vp->lastrepeat = 1; 401*4887Schin vp->repeat = 1; 402*4887Schin *yankbuf = 0; 403*4887Schin } 404*4887Schin 405*4887Schin /*** fiddle around with prompt length ***/ 406*4887Schin if( nchar+plen > MAXCHAR ) 407*4887Schin nchar = MAXCHAR - plen; 408*4887Schin max_col = nchar - 2; 409*4887Schin 410*4887Schin if( !viraw ) 411*4887Schin { 412*4887Schin int kill_erase = 0; 413*4887Schin for(i=(echoctl?last_virt:0); i<last_virt; ++i ) 414*4887Schin { 415*4887Schin /*** change \r to \n, check for control characters, ***/ 416*4887Schin /* delete appropriate ^Vs, */ 417*4887Schin /* and estimate last physical column */ 418*4887Schin 419*4887Schin if( virtual[i] == '\r' ) 420*4887Schin virtual[i] = '\n'; 421*4887Schin if(!echoctl) 422*4887Schin { 423*4887Schin register int c = virtual[i]; 424*4887Schin if( c<=usrerase) 425*4887Schin { 426*4887Schin /*** user typed escaped erase or kill char ***/ 427*4887Schin cntl_char = 1; 428*4887Schin if(is_print(c)) 429*4887Schin kill_erase++; 430*4887Schin } 431*4887Schin else if( !is_print(c) ) 432*4887Schin { 433*4887Schin cntl_char = 1; 434*4887Schin 435*4887Schin if( c == usrlnext ) 436*4887Schin { 437*4887Schin if( i == last_virt ) 438*4887Schin { 439*4887Schin /*** eol/eof was escaped ***/ 440*4887Schin /* so replace ^V with it */ 441*4887Schin virtual[i] = term_char; 442*4887Schin break; 443*4887Schin } 444*4887Schin 445*4887Schin /*** delete ^V ***/ 446*4887Schin gencpy((&virtual[i]), (&virtual[i+1])); 447*4887Schin --cur_virt; 448*4887Schin --last_virt; 449*4887Schin } 450*4887Schin } 451*4887Schin } 452*4887Schin } 453*4887Schin 454*4887Schin /*** copy virtual image to window ***/ 455*4887Schin if(last_virt > 0) 456*4887Schin last_phys = ed_virt_to_phys(vp->ed,virtual,physical,last_virt,0,0); 457*4887Schin if( last_phys >= w_size ) 458*4887Schin { 459*4887Schin /*** line longer than window ***/ 460*4887Schin vp->last_wind = w_size - 1; 461*4887Schin } 462*4887Schin else 463*4887Schin vp->last_wind = last_phys; 464*4887Schin genncpy(window, virtual, vp->last_wind+1); 465*4887Schin 466*4887Schin if( term_char!=ESC && (last_virt==INVALID 467*4887Schin || virtual[last_virt]!=term_char) ) 468*4887Schin { 469*4887Schin /*** Line not terminated with ESC or escaped (^V) ***/ 470*4887Schin /* eol, so return after doing a total update */ 471*4887Schin /* if( (speed is greater or equal to 1200 */ 472*4887Schin /* and something was typed) and */ 473*4887Schin /* (control character present */ 474*4887Schin /* or typeahead occurred) ) */ 475*4887Schin 476*4887Schin tty_cooked(ERRIO); 477*4887Schin if( editb.e_ttyspeed==FAST && last_virt!=INVALID 478*4887Schin && (vp->typeahead || cntl_char) ) 479*4887Schin { 480*4887Schin refresh(vp,TRANSLATE); 481*4887Schin pr_string(vp,Prompt); 482*4887Schin putstring(vp,0, last_phys+1); 483*4887Schin if(echoctl) 484*4887Schin ed_crlf(vp->ed); 485*4887Schin else 486*4887Schin while(kill_erase-- > 0) 487*4887Schin putchar(' '); 488*4887Schin } 489*4887Schin 490*4887Schin if( term_char=='\n' ) 491*4887Schin { 492*4887Schin if(!echoctl) 493*4887Schin ed_crlf(vp->ed); 494*4887Schin virtual[++last_virt] = '\n'; 495*4887Schin } 496*4887Schin vp->last_cmd = 'i'; 497*4887Schin save_last(vp); 498*4887Schin #if SHOPT_MULTIBYTE 499*4887Schin virtual[last_virt+1] = 0; 500*4887Schin last_virt = ed_external(virtual,shbuf); 501*4887Schin return(last_virt); 502*4887Schin #else 503*4887Schin return(++last_virt); 504*4887Schin #endif /* SHOPT_MULTIBYTE */ 505*4887Schin } 506*4887Schin 507*4887Schin /*** Line terminated with escape, or escaped eol/eof, ***/ 508*4887Schin /* so set raw mode */ 509*4887Schin 510*4887Schin if( tty_raw(ERRIO,0) < 0 ) 511*4887Schin { 512*4887Schin tty_cooked(ERRIO); 513*4887Schin /* 514*4887Schin * The following prevents drivers that return 0 on 515*4887Schin * causing an infinite loop 516*4887Schin */ 517*4887Schin if(esc_or_hang) 518*4887Schin return(-1); 519*4887Schin virtual[++last_virt] = '\n'; 520*4887Schin #if SHOPT_MULTIBYTE 521*4887Schin virtual[last_virt+1] = 0; 522*4887Schin last_virt = ed_external(virtual,shbuf); 523*4887Schin return(last_virt); 524*4887Schin #else 525*4887Schin return(++last_virt); 526*4887Schin #endif /* SHOPT_MULTIBYTE */ 527*4887Schin } 528*4887Schin 529*4887Schin if(echoctl) /*** for cntl-echo erase the ^[ ***/ 530*4887Schin pr_string(vp,"\b\b\b\b \b\b"); 531*4887Schin 532*4887Schin 533*4887Schin if(crallowed) 534*4887Schin { 535*4887Schin /*** start over since there may be ***/ 536*4887Schin /*** a control char, or cursor might not ***/ 537*4887Schin /*** be at left margin (this lets us know ***/ 538*4887Schin /*** where we are ***/ 539*4887Schin cur_phys = 0; 540*4887Schin window[0] = '\0'; 541*4887Schin pr_string(vp,Prompt); 542*4887Schin if( term_char==ESC && (last_virt<0 || virtual[last_virt]!=ESC)) 543*4887Schin refresh(vp,CONTROL); 544*4887Schin else 545*4887Schin refresh(vp,INPUT); 546*4887Schin } 547*4887Schin else 548*4887Schin { 549*4887Schin /*** just update everything internally ***/ 550*4887Schin refresh(vp,TRANSLATE); 551*4887Schin } 552*4887Schin } 553*4887Schin 554*4887Schin /*** Handle usrintr, usrquit, or EOF ***/ 555*4887Schin 556*4887Schin i = sigsetjmp(editb.e_env,0); 557*4887Schin if( i != 0 ) 558*4887Schin { 559*4887Schin virtual[0] = '\0'; 560*4887Schin tty_cooked(ERRIO); 561*4887Schin 562*4887Schin switch(i) 563*4887Schin { 564*4887Schin case UEOF: 565*4887Schin /*** EOF ***/ 566*4887Schin return(0); 567*4887Schin 568*4887Schin case UINTR: 569*4887Schin /** interrupt **/ 570*4887Schin return(-1); 571*4887Schin } 572*4887Schin return(-1); 573*4887Schin } 574*4887Schin 575*4887Schin /*** Get a line from the terminal ***/ 576*4887Schin 577*4887Schin vp->U_saved = 0; 578*4887Schin if(reedit) 579*4887Schin refresh(vp,INPUT); 580*4887Schin if(viraw) 581*4887Schin getline(vp,APPEND); 582*4887Schin else if(last_virt>=0 && virtual[last_virt]==term_char) 583*4887Schin getline(vp,APPEND); 584*4887Schin else 585*4887Schin getline(vp,ESC); 586*4887Schin if(vp->ed->e_multiline) 587*4887Schin cursor(vp, last_phys); 588*4887Schin /*** add a new line if user typed unescaped \n ***/ 589*4887Schin /* to cause the shell to process the line */ 590*4887Schin tty_cooked(ERRIO); 591*4887Schin if(ed->e_nlist) 592*4887Schin { 593*4887Schin ed->e_nlist = 0; 594*4887Schin stakset(ed->e_stkptr,ed->e_stkoff); 595*4887Schin } 596*4887Schin if( vp->addnl ) 597*4887Schin { 598*4887Schin virtual[++last_virt] = '\n'; 599*4887Schin ed_crlf(vp->ed); 600*4887Schin } 601*4887Schin if( ++last_virt >= 0 ) 602*4887Schin { 603*4887Schin #if SHOPT_MULTIBYTE 604*4887Schin if(vp->bigvi) 605*4887Schin { 606*4887Schin vp->bigvi = 0; 607*4887Schin shbuf[last_virt-1] = '\n'; 608*4887Schin } 609*4887Schin else 610*4887Schin { 611*4887Schin virtual[last_virt] = 0; 612*4887Schin last_virt = ed_external(virtual,shbuf); 613*4887Schin } 614*4887Schin #endif /* SHOPT_MULTIBYTE */ 615*4887Schin return(last_virt); 616*4887Schin } 617*4887Schin else 618*4887Schin return(-1); 619*4887Schin } 620*4887Schin 621*4887Schin 622*4887Schin /*{ APPEND( char, mode ) 623*4887Schin * 624*4887Schin * This routine will append char after cur_virt in the virtual image. 625*4887Schin * mode = APPEND, shift chars right before appending 626*4887Schin * REPLACE, replace char if possible 627*4887Schin * 628*4887Schin }*/ 629*4887Schin 630*4887Schin static void append(Vi_t *vp,int c, int mode) 631*4887Schin { 632*4887Schin register int i,j; 633*4887Schin 634*4887Schin if( last_virt<max_col && last_phys<max_col ) 635*4887Schin { 636*4887Schin if( mode==APPEND || (cur_virt==last_virt && last_virt>=0)) 637*4887Schin { 638*4887Schin j = (cur_virt>=0?cur_virt:0); 639*4887Schin for(i = ++last_virt; i > j; --i) 640*4887Schin virtual[i] = virtual[i-1]; 641*4887Schin } 642*4887Schin virtual[++cur_virt] = c; 643*4887Schin } 644*4887Schin else 645*4887Schin ed_ringbell(); 646*4887Schin return; 647*4887Schin } 648*4887Schin 649*4887Schin /*{ BACKWORD( nwords, cmd ) 650*4887Schin * 651*4887Schin * This routine will position cur_virt at the nth previous word. 652*4887Schin * 653*4887Schin }*/ 654*4887Schin 655*4887Schin static void backword(Vi_t *vp,int nwords, register int cmd) 656*4887Schin { 657*4887Schin register int tcur_virt = cur_virt; 658*4887Schin while( nwords-- && tcur_virt > first_virt ) 659*4887Schin { 660*4887Schin if( !isblank(tcur_virt) && isblank(tcur_virt-1) 661*4887Schin && tcur_virt>first_virt ) 662*4887Schin --tcur_virt; 663*4887Schin else if(cmd != 'B') 664*4887Schin { 665*4887Schin register int last = isalph(tcur_virt-1); 666*4887Schin register int cur = isalph(tcur_virt); 667*4887Schin if((!cur && last) || (cur && !last)) 668*4887Schin --tcur_virt; 669*4887Schin } 670*4887Schin while( isblank(tcur_virt) && tcur_virt>=first_virt ) 671*4887Schin --tcur_virt; 672*4887Schin if( cmd == 'B' ) 673*4887Schin { 674*4887Schin while( !isblank(tcur_virt) && tcur_virt>=first_virt ) 675*4887Schin --tcur_virt; 676*4887Schin } 677*4887Schin else 678*4887Schin { 679*4887Schin if(isalph(tcur_virt)) 680*4887Schin while( isalph(tcur_virt) && tcur_virt>=first_virt ) 681*4887Schin --tcur_virt; 682*4887Schin else 683*4887Schin while( !isalph(tcur_virt) && !isblank(tcur_virt) 684*4887Schin && tcur_virt>=first_virt ) 685*4887Schin --tcur_virt; 686*4887Schin } 687*4887Schin cur_virt = ++tcur_virt; 688*4887Schin } 689*4887Schin return; 690*4887Schin } 691*4887Schin 692*4887Schin /*{ CNTLMODE() 693*4887Schin * 694*4887Schin * This routine implements the vi command subset. 695*4887Schin * The cursor will always be positioned at the char of interest. 696*4887Schin * 697*4887Schin }*/ 698*4887Schin 699*4887Schin static int cntlmode(Vi_t *vp) 700*4887Schin { 701*4887Schin register int c; 702*4887Schin register int i; 703*4887Schin genchar tmp_u_space[MAXLINE]; /* temporary u_space */ 704*4887Schin genchar *real_u_space; /* points to real u_space */ 705*4887Schin int tmp_u_column = INVALID; /* temporary u_column */ 706*4887Schin int was_inmacro; 707*4887Schin 708*4887Schin if(!vp->U_saved) 709*4887Schin { 710*4887Schin /*** save virtual image if never done before ***/ 711*4887Schin virtual[last_virt+1] = '\0'; 712*4887Schin gencpy(vp->U_space, virtual); 713*4887Schin vp->U_saved = 1; 714*4887Schin } 715*4887Schin 716*4887Schin save_last(vp); 717*4887Schin 718*4887Schin real_u_space = vp->u_space; 719*4887Schin curhline = histmax; 720*4887Schin first_virt = 0; 721*4887Schin vp->repeat = 1; 722*4887Schin if( cur_virt > INVALID ) 723*4887Schin { 724*4887Schin /*** make sure cursor is at the last char ***/ 725*4887Schin sync_cursor(vp); 726*4887Schin } 727*4887Schin 728*4887Schin /*** Read control char until something happens to cause a ***/ 729*4887Schin /* return to APPEND/REPLACE mode */ 730*4887Schin 731*4887Schin while( c=ed_getchar(vp->ed,-1) ) 732*4887Schin { 733*4887Schin vp->repeat_set = 0; 734*4887Schin was_inmacro = inmacro; 735*4887Schin if( c == '0' ) 736*4887Schin { 737*4887Schin /*** move to leftmost column ***/ 738*4887Schin cur_virt = 0; 739*4887Schin sync_cursor(vp); 740*4887Schin continue; 741*4887Schin } 742*4887Schin 743*4887Schin if( digit(c) ) 744*4887Schin { 745*4887Schin c = getcount(vp,c); 746*4887Schin if( c == '.' ) 747*4887Schin vp->lastrepeat = vp->repeat; 748*4887Schin } 749*4887Schin 750*4887Schin /*** see if it's a move cursor command ***/ 751*4887Schin 752*4887Schin if(mvcursor(vp,c)) 753*4887Schin { 754*4887Schin sync_cursor(vp); 755*4887Schin vp->repeat = 1; 756*4887Schin continue; 757*4887Schin } 758*4887Schin 759*4887Schin /*** see if it's a repeat of the last command ***/ 760*4887Schin 761*4887Schin if( c == '.' ) 762*4887Schin { 763*4887Schin c = vp->last_cmd; 764*4887Schin vp->repeat = vp->lastrepeat; 765*4887Schin i = textmod(vp,c, c); 766*4887Schin } 767*4887Schin else 768*4887Schin { 769*4887Schin i = textmod(vp,c, 0); 770*4887Schin } 771*4887Schin 772*4887Schin /*** see if it's a text modification command ***/ 773*4887Schin 774*4887Schin switch(i) 775*4887Schin { 776*4887Schin case BAD: 777*4887Schin break; 778*4887Schin 779*4887Schin default: /** input mode **/ 780*4887Schin if(!was_inmacro) 781*4887Schin { 782*4887Schin vp->last_cmd = c; 783*4887Schin vp->lastrepeat = vp->repeat; 784*4887Schin } 785*4887Schin vp->repeat = 1; 786*4887Schin if( i == GOOD ) 787*4887Schin continue; 788*4887Schin return(i); 789*4887Schin } 790*4887Schin 791*4887Schin switch( c ) 792*4887Schin { 793*4887Schin /***** Other stuff *****/ 794*4887Schin 795*4887Schin case cntl('L'): /** Redraw line **/ 796*4887Schin /*** print the prompt and ***/ 797*4887Schin /* force a total refresh */ 798*4887Schin if(vp->nonewline==0) 799*4887Schin putchar('\n'); 800*4887Schin vp->nonewline = 0; 801*4887Schin pr_string(vp,Prompt); 802*4887Schin window[0] = '\0'; 803*4887Schin cur_phys = vp->first_wind; 804*4887Schin vp->ofirst_wind = INVALID; 805*4887Schin vp->long_line = ' '; 806*4887Schin break; 807*4887Schin 808*4887Schin case cntl('V'): 809*4887Schin { 810*4887Schin register const char *p = fmtident(e_version); 811*4887Schin save_v(vp); 812*4887Schin del_line(vp,BAD); 813*4887Schin while(c = *p++) 814*4887Schin append(vp,c,APPEND); 815*4887Schin refresh(vp,CONTROL); 816*4887Schin ed_getchar(vp->ed,-1); 817*4887Schin restore_v(vp); 818*4887Schin break; 819*4887Schin } 820*4887Schin 821*4887Schin case '/': /** Search **/ 822*4887Schin case '?': 823*4887Schin case 'N': 824*4887Schin case 'n': 825*4887Schin save_v(vp); 826*4887Schin switch( search(vp,c) ) 827*4887Schin { 828*4887Schin case GOOD: 829*4887Schin /*** force a total refresh ***/ 830*4887Schin window[0] = '\0'; 831*4887Schin goto newhist; 832*4887Schin 833*4887Schin case BAD: 834*4887Schin /*** no match ***/ 835*4887Schin ed_ringbell(); 836*4887Schin 837*4887Schin default: 838*4887Schin if( vp->u_column == INVALID ) 839*4887Schin del_line(vp,BAD); 840*4887Schin else 841*4887Schin restore_v(vp); 842*4887Schin break; 843*4887Schin } 844*4887Schin break; 845*4887Schin 846*4887Schin case 'j': /** get next command **/ 847*4887Schin case '+': /** get next command **/ 848*4887Schin curhline += vp->repeat; 849*4887Schin if( curhline > histmax ) 850*4887Schin { 851*4887Schin curhline = histmax; 852*4887Schin goto ringbell; 853*4887Schin } 854*4887Schin else if(curhline==histmax && tmp_u_column!=INVALID ) 855*4887Schin { 856*4887Schin vp->u_space = tmp_u_space; 857*4887Schin vp->u_column = tmp_u_column; 858*4887Schin restore_v(vp); 859*4887Schin vp->u_space = real_u_space; 860*4887Schin break; 861*4887Schin } 862*4887Schin save_v(vp); 863*4887Schin cur_virt = INVALID; 864*4887Schin goto newhist; 865*4887Schin 866*4887Schin case 'k': /** get previous command **/ 867*4887Schin case '-': /** get previous command **/ 868*4887Schin if( curhline == histmax ) 869*4887Schin { 870*4887Schin vp->u_space = tmp_u_space; 871*4887Schin i = vp->u_column; 872*4887Schin save_v(vp); 873*4887Schin vp->u_space = real_u_space; 874*4887Schin tmp_u_column = vp->u_column; 875*4887Schin vp->u_column = i; 876*4887Schin } 877*4887Schin 878*4887Schin curhline -= vp->repeat; 879*4887Schin if( curhline <= histmin ) 880*4887Schin { 881*4887Schin curhline += vp->repeat; 882*4887Schin goto ringbell; 883*4887Schin } 884*4887Schin save_v(vp); 885*4887Schin cur_virt = INVALID; 886*4887Schin newhist: 887*4887Schin if(curhline!=histmax || cur_virt==INVALID) 888*4887Schin hist_copy((char*)virtual, MAXLINE, curhline,-1); 889*4887Schin else 890*4887Schin { 891*4887Schin strcpy((char*)virtual,(char*)vp->u_space); 892*4887Schin #if SHOPT_MULTIBYTE 893*4887Schin ed_internal((char*)vp->u_space,vp->u_space); 894*4887Schin #endif /* SHOPT_MULTIBYTE */ 895*4887Schin } 896*4887Schin #if SHOPT_MULTIBYTE 897*4887Schin ed_internal((char*)virtual,virtual); 898*4887Schin #endif /* SHOPT_MULTIBYTE */ 899*4887Schin if((last_virt=genlen(virtual)-1) >= 0 && cur_virt == INVALID) 900*4887Schin cur_virt = 0; 901*4887Schin break; 902*4887Schin 903*4887Schin 904*4887Schin case 'u': /** undo the last thing done **/ 905*4887Schin restore_v(vp); 906*4887Schin break; 907*4887Schin 908*4887Schin case 'U': /** Undo everything **/ 909*4887Schin save_v(vp); 910*4887Schin if( virtual[0] == '\0' ) 911*4887Schin goto ringbell; 912*4887Schin else 913*4887Schin { 914*4887Schin gencpy(virtual, vp->U_space); 915*4887Schin last_virt = genlen(vp->U_space) - 1; 916*4887Schin cur_virt = 0; 917*4887Schin } 918*4887Schin break; 919*4887Schin 920*4887Schin #if KSHELL 921*4887Schin case 'v': 922*4887Schin if(vp->repeat_set==0) 923*4887Schin goto vcommand; 924*4887Schin #endif /* KSHELL */ 925*4887Schin 926*4887Schin case 'G': /** goto command repeat **/ 927*4887Schin if(vp->repeat_set==0) 928*4887Schin vp->repeat = histmin+1; 929*4887Schin if( vp->repeat <= histmin || vp->repeat > histmax ) 930*4887Schin { 931*4887Schin goto ringbell; 932*4887Schin } 933*4887Schin curhline = vp->repeat; 934*4887Schin save_v(vp); 935*4887Schin if(c == 'G') 936*4887Schin { 937*4887Schin cur_virt = INVALID; 938*4887Schin goto newhist; 939*4887Schin } 940*4887Schin 941*4887Schin #if KSHELL 942*4887Schin vcommand: 943*4887Schin if(ed_fulledit(vp->ed)==GOOD) 944*4887Schin return(BIGVI); 945*4887Schin else 946*4887Schin goto ringbell; 947*4887Schin #endif /* KSHELL */ 948*4887Schin 949*4887Schin case '#': /** insert(delete) # to (no)comment command **/ 950*4887Schin if( cur_virt != INVALID ) 951*4887Schin { 952*4887Schin register genchar *p = &virtual[last_virt+1]; 953*4887Schin *p = 0; 954*4887Schin /*** see whether first char is comment char ***/ 955*4887Schin c = (virtual[0]=='#'); 956*4887Schin while(p-- >= virtual) 957*4887Schin { 958*4887Schin if(*p=='\n' || p<virtual) 959*4887Schin { 960*4887Schin if(c) /* delete '#' */ 961*4887Schin { 962*4887Schin if(p[1]=='#') 963*4887Schin { 964*4887Schin last_virt--; 965*4887Schin gencpy(p+1,p+2); 966*4887Schin } 967*4887Schin } 968*4887Schin else 969*4887Schin { 970*4887Schin cur_virt = p-virtual; 971*4887Schin append(vp,'#', APPEND); 972*4887Schin } 973*4887Schin } 974*4887Schin } 975*4887Schin if(c) 976*4887Schin { 977*4887Schin curhline = histmax; 978*4887Schin cur_virt = 0; 979*4887Schin break; 980*4887Schin } 981*4887Schin refresh(vp,INPUT); 982*4887Schin } 983*4887Schin 984*4887Schin case '\n': /** send to shell **/ 985*4887Schin return(ENTER); 986*4887Schin 987*4887Schin case ESC: 988*4887Schin /* don't ring bell if next char is '[' */ 989*4887Schin if(!lookahead) 990*4887Schin { 991*4887Schin char x; 992*4887Schin if(sfpkrd(editb.e_fd,&x,1,'\r',400L,-1)>0) 993*4887Schin ed_ungetchar(vp->ed,x); 994*4887Schin } 995*4887Schin if(lookahead) 996*4887Schin { 997*4887Schin ed_ungetchar(vp->ed,c=ed_getchar(vp->ed,1)); 998*4887Schin if(c=='[') 999*4887Schin { 1000*4887Schin vp->repeat = 1; 1001*4887Schin continue; 1002*4887Schin } 1003*4887Schin } 1004*4887Schin default: 1005*4887Schin ringbell: 1006*4887Schin ed_ringbell(); 1007*4887Schin vp->repeat = 1; 1008*4887Schin continue; 1009*4887Schin } 1010*4887Schin 1011*4887Schin refresh(vp,CONTROL); 1012*4887Schin vp->repeat = 1; 1013*4887Schin } 1014*4887Schin /* NOTREACHED */ 1015*4887Schin return(0); 1016*4887Schin } 1017*4887Schin 1018*4887Schin /*{ CURSOR( new_current_physical ) 1019*4887Schin * 1020*4887Schin * This routine will position the virtual cursor at 1021*4887Schin * physical column x in the window. 1022*4887Schin * 1023*4887Schin }*/ 1024*4887Schin 1025*4887Schin static void cursor(Vi_t *vp,register int x) 1026*4887Schin { 1027*4887Schin #if SHOPT_MULTIBYTE 1028*4887Schin while(physical[x]==MARKER) 1029*4887Schin x++; 1030*4887Schin #endif /* SHOPT_MULTIBYTE */ 1031*4887Schin cur_phys = ed_setcursor(vp->ed, physical, cur_phys,x,vp->first_wind); 1032*4887Schin } 1033*4887Schin 1034*4887Schin /*{ DELETE( nchars, mode ) 1035*4887Schin * 1036*4887Schin * Delete nchars from the virtual space and leave cur_virt positioned 1037*4887Schin * at cur_virt-1. 1038*4887Schin * 1039*4887Schin * If mode = 'c', do not save the characters deleted 1040*4887Schin * = 'd', save them in yankbuf and delete. 1041*4887Schin * = 'y', save them in yankbuf but do not delete. 1042*4887Schin * 1043*4887Schin }*/ 1044*4887Schin 1045*4887Schin static void cdelete(Vi_t *vp,register int nchars, int mode) 1046*4887Schin { 1047*4887Schin register int i; 1048*4887Schin register genchar *cp; 1049*4887Schin 1050*4887Schin if( cur_virt < first_virt ) 1051*4887Schin { 1052*4887Schin ed_ringbell(); 1053*4887Schin return; 1054*4887Schin } 1055*4887Schin if( nchars > 0 ) 1056*4887Schin { 1057*4887Schin cp = virtual+cur_virt; 1058*4887Schin vp->o_v_char = cp[0]; 1059*4887Schin if( (cur_virt-- + nchars) > last_virt ) 1060*4887Schin { 1061*4887Schin /*** set nchars to number actually deleted ***/ 1062*4887Schin nchars = last_virt - cur_virt; 1063*4887Schin } 1064*4887Schin 1065*4887Schin /*** save characters to be deleted ***/ 1066*4887Schin 1067*4887Schin if( mode != 'c' ) 1068*4887Schin { 1069*4887Schin i = cp[nchars]; 1070*4887Schin cp[nchars] = 0; 1071*4887Schin gencpy(yankbuf,cp); 1072*4887Schin cp[nchars] = i; 1073*4887Schin } 1074*4887Schin 1075*4887Schin /*** now delete these characters ***/ 1076*4887Schin 1077*4887Schin if( mode != 'y' ) 1078*4887Schin { 1079*4887Schin gencpy(cp,cp+nchars); 1080*4887Schin last_virt -= nchars; 1081*4887Schin } 1082*4887Schin } 1083*4887Schin return; 1084*4887Schin } 1085*4887Schin 1086*4887Schin /*{ DEL_LINE( mode ) 1087*4887Schin * 1088*4887Schin * This routine will delete the line. 1089*4887Schin * mode = GOOD, do a save_v() 1090*4887Schin * 1091*4887Schin }*/ 1092*4887Schin static void del_line(register Vi_t *vp, int mode) 1093*4887Schin { 1094*4887Schin if( last_virt == INVALID ) 1095*4887Schin return; 1096*4887Schin 1097*4887Schin if( mode == GOOD ) 1098*4887Schin save_v(vp); 1099*4887Schin 1100*4887Schin cur_virt = 0; 1101*4887Schin first_virt = 0; 1102*4887Schin cdelete(vp,last_virt+1, BAD); 1103*4887Schin refresh(vp,CONTROL); 1104*4887Schin 1105*4887Schin cur_virt = INVALID; 1106*4887Schin cur_phys = 0; 1107*4887Schin vp->findchar = INVALID; 1108*4887Schin last_phys = INVALID; 1109*4887Schin last_virt = INVALID; 1110*4887Schin vp->last_wind = INVALID; 1111*4887Schin vp->first_wind = 0; 1112*4887Schin vp->o_v_char = '\0'; 1113*4887Schin vp->ocur_phys = 0; 1114*4887Schin vp->ocur_virt = MAXCHAR; 1115*4887Schin vp->ofirst_wind = 0; 1116*4887Schin window[0] = '\0'; 1117*4887Schin return; 1118*4887Schin } 1119*4887Schin 1120*4887Schin /*{ DELMOTION( motion, mode ) 1121*4887Schin * 1122*4887Schin * Delete thru motion. 1123*4887Schin * 1124*4887Schin * mode = 'd', save deleted characters, delete 1125*4887Schin * = 'c', do not save characters, change 1126*4887Schin * = 'y', save characters, yank 1127*4887Schin * 1128*4887Schin * Returns 1 if operation successful; else 0. 1129*4887Schin * 1130*4887Schin }*/ 1131*4887Schin 1132*4887Schin static int delmotion(Vi_t *vp,int motion, int mode) 1133*4887Schin { 1134*4887Schin register int begin, end, delta; 1135*4887Schin /* the following saves a register */ 1136*4887Schin 1137*4887Schin if( cur_virt == INVALID ) 1138*4887Schin return(0); 1139*4887Schin if( mode != 'y' ) 1140*4887Schin save_v(vp); 1141*4887Schin begin = cur_virt; 1142*4887Schin 1143*4887Schin /*** fake out the motion routines by appending a blank ***/ 1144*4887Schin 1145*4887Schin virtual[++last_virt] = ' '; 1146*4887Schin end = mvcursor(vp,motion); 1147*4887Schin virtual[last_virt--] = 0; 1148*4887Schin if(!end) 1149*4887Schin return(0); 1150*4887Schin 1151*4887Schin end = cur_virt; 1152*4887Schin if( mode=='c' && end>begin && strchr("wW", motion) ) 1153*4887Schin { 1154*4887Schin /*** called by change operation, user really expects ***/ 1155*4887Schin /* the effect of the eE commands, so back up to end of word */ 1156*4887Schin while( end>begin && isblank(end-1) ) 1157*4887Schin --end; 1158*4887Schin if( end == begin ) 1159*4887Schin ++end; 1160*4887Schin } 1161*4887Schin 1162*4887Schin delta = end - begin; 1163*4887Schin if( delta >= 0 ) 1164*4887Schin { 1165*4887Schin cur_virt = begin; 1166*4887Schin if( strchr("eE;,TtFf%", motion) ) 1167*4887Schin ++delta; 1168*4887Schin } 1169*4887Schin else 1170*4887Schin { 1171*4887Schin delta = -delta + (motion=='%'); 1172*4887Schin } 1173*4887Schin 1174*4887Schin cdelete(vp,delta, mode); 1175*4887Schin if( mode == 'y' ) 1176*4887Schin cur_virt = begin; 1177*4887Schin return(1); 1178*4887Schin } 1179*4887Schin 1180*4887Schin 1181*4887Schin /*{ ENDWORD( nwords, cmd ) 1182*4887Schin * 1183*4887Schin * This routine will move cur_virt to the end of the nth word. 1184*4887Schin * 1185*4887Schin }*/ 1186*4887Schin 1187*4887Schin static void endword(Vi_t *vp, int nwords, register int cmd) 1188*4887Schin { 1189*4887Schin register int tcur_virt = cur_virt; 1190*4887Schin while( nwords-- ) 1191*4887Schin { 1192*4887Schin if( !isblank(tcur_virt) && tcur_virt<=last_virt ) 1193*4887Schin ++tcur_virt; 1194*4887Schin while( isblank(tcur_virt) && tcur_virt<=last_virt ) 1195*4887Schin ++tcur_virt; 1196*4887Schin if( cmd == 'E' ) 1197*4887Schin { 1198*4887Schin while( !isblank(tcur_virt) && tcur_virt<=last_virt ) 1199*4887Schin ++tcur_virt; 1200*4887Schin } 1201*4887Schin else 1202*4887Schin { 1203*4887Schin if( isalph(tcur_virt) ) 1204*4887Schin while( isalph(tcur_virt) && tcur_virt<=last_virt ) 1205*4887Schin ++tcur_virt; 1206*4887Schin else 1207*4887Schin while( !isalph(tcur_virt) && !isblank(tcur_virt) 1208*4887Schin && tcur_virt<=last_virt ) 1209*4887Schin ++tcur_virt; 1210*4887Schin } 1211*4887Schin if( tcur_virt > first_virt ) 1212*4887Schin tcur_virt--; 1213*4887Schin } 1214*4887Schin cur_virt = tcur_virt; 1215*4887Schin return; 1216*4887Schin } 1217*4887Schin 1218*4887Schin /*{ FORWARD( nwords, cmd ) 1219*4887Schin * 1220*4887Schin * This routine will move cur_virt forward to the next nth word. 1221*4887Schin * 1222*4887Schin }*/ 1223*4887Schin 1224*4887Schin static void forward(Vi_t *vp,register int nwords, int cmd) 1225*4887Schin { 1226*4887Schin register int tcur_virt = cur_virt; 1227*4887Schin while( nwords-- ) 1228*4887Schin { 1229*4887Schin if( cmd == 'W' ) 1230*4887Schin { 1231*4887Schin while( !isblank(tcur_virt) && tcur_virt < last_virt ) 1232*4887Schin ++tcur_virt; 1233*4887Schin } 1234*4887Schin else 1235*4887Schin { 1236*4887Schin if( isalph(tcur_virt) ) 1237*4887Schin { 1238*4887Schin while( isalph(tcur_virt) && tcur_virt<last_virt ) 1239*4887Schin ++tcur_virt; 1240*4887Schin } 1241*4887Schin else 1242*4887Schin { 1243*4887Schin while( !isalph(tcur_virt) && !isblank(tcur_virt) 1244*4887Schin && tcur_virt < last_virt ) 1245*4887Schin ++tcur_virt; 1246*4887Schin } 1247*4887Schin } 1248*4887Schin while( isblank(tcur_virt) && tcur_virt < last_virt ) 1249*4887Schin ++tcur_virt; 1250*4887Schin } 1251*4887Schin cur_virt = tcur_virt; 1252*4887Schin return; 1253*4887Schin } 1254*4887Schin 1255*4887Schin 1256*4887Schin 1257*4887Schin /*{ GETCOUNT(c) 1258*4887Schin * 1259*4887Schin * Set repeat to the user typed number and return the terminating 1260*4887Schin * character. 1261*4887Schin * 1262*4887Schin }*/ 1263*4887Schin 1264*4887Schin static int getcount(register Vi_t *vp,register int c) 1265*4887Schin { 1266*4887Schin register int i; 1267*4887Schin 1268*4887Schin /*** get any repeat count ***/ 1269*4887Schin 1270*4887Schin if( c == '0' ) 1271*4887Schin return(c); 1272*4887Schin 1273*4887Schin vp->repeat_set++; 1274*4887Schin i = 0; 1275*4887Schin while( digit(c) ) 1276*4887Schin { 1277*4887Schin i = i*10 + c - '0'; 1278*4887Schin c = ed_getchar(vp->ed,-1); 1279*4887Schin } 1280*4887Schin 1281*4887Schin if( i > 0 ) 1282*4887Schin vp->repeat *= i; 1283*4887Schin return(c); 1284*4887Schin } 1285*4887Schin 1286*4887Schin 1287*4887Schin /*{ GETLINE( mode ) 1288*4887Schin * 1289*4887Schin * This routine will fetch a line. 1290*4887Schin * mode = APPEND, allow escape to cntlmode subroutine 1291*4887Schin * appending characters. 1292*4887Schin * = REPLACE, allow escape to cntlmode subroutine 1293*4887Schin * replacing characters. 1294*4887Schin * = SEARCH, no escape allowed 1295*4887Schin * = ESC, enter control mode immediately 1296*4887Schin * 1297*4887Schin * The cursor will always be positioned after the last 1298*4887Schin * char printed. 1299*4887Schin * 1300*4887Schin * This routine returns when cr, nl, or (eof in column 0) is 1301*4887Schin * received (column 0 is the first char position). 1302*4887Schin * 1303*4887Schin }*/ 1304*4887Schin 1305*4887Schin static void getline(register Vi_t* vp,register int mode) 1306*4887Schin { 1307*4887Schin register int c; 1308*4887Schin register int tmp; 1309*4887Schin int max_virt=0, last_save=0; 1310*4887Schin genchar saveline[MAXLINE]; 1311*4887Schin 1312*4887Schin vp->addnl = 1; 1313*4887Schin 1314*4887Schin if( mode == ESC ) 1315*4887Schin { 1316*4887Schin /*** go directly to control mode ***/ 1317*4887Schin goto escape; 1318*4887Schin } 1319*4887Schin 1320*4887Schin for(;;) 1321*4887Schin { 1322*4887Schin if( (c=ed_getchar(vp->ed,mode==SEARCH?1:-2)) == usreof ) 1323*4887Schin c = UEOF; 1324*4887Schin else if( c == usrerase ) 1325*4887Schin c = UERASE; 1326*4887Schin else if( c == usrkill ) 1327*4887Schin c = UKILL; 1328*4887Schin else if( c == editb.e_werase ) 1329*4887Schin c = UWERASE; 1330*4887Schin else if( c == usrlnext ) 1331*4887Schin c = ULNEXT; 1332*4887Schin 1333*4887Schin if( c == ULNEXT) 1334*4887Schin { 1335*4887Schin /*** implement ^V to escape next char ***/ 1336*4887Schin c = ed_getchar(vp->ed,2); 1337*4887Schin append(vp,c, mode); 1338*4887Schin refresh(vp,INPUT); 1339*4887Schin continue; 1340*4887Schin } 1341*4887Schin 1342*4887Schin switch( c ) 1343*4887Schin { 1344*4887Schin case ESC: /** enter control mode **/ 1345*4887Schin if(!sh_isoption(SH_VI)) 1346*4887Schin { 1347*4887Schin append(vp,c, mode); 1348*4887Schin break; 1349*4887Schin } 1350*4887Schin if( mode == SEARCH ) 1351*4887Schin { 1352*4887Schin ed_ringbell(); 1353*4887Schin continue; 1354*4887Schin } 1355*4887Schin else 1356*4887Schin { 1357*4887Schin escape: 1358*4887Schin if( mode == REPLACE ) 1359*4887Schin { 1360*4887Schin c = max_virt-cur_virt; 1361*4887Schin if(c > 0 && last_save>=cur_virt) 1362*4887Schin { 1363*4887Schin genncpy((&virtual[cur_virt]),&saveline[cur_virt],c); 1364*4887Schin if(last_virt>=last_save) 1365*4887Schin last_virt=last_save-1; 1366*4887Schin refresh(vp,INPUT); 1367*4887Schin } 1368*4887Schin --cur_virt; 1369*4887Schin } 1370*4887Schin tmp = cntlmode(vp); 1371*4887Schin if( tmp == ENTER || tmp == BIGVI ) 1372*4887Schin { 1373*4887Schin #if SHOPT_MULTIBYTE 1374*4887Schin vp->bigvi = (tmp==BIGVI); 1375*4887Schin #endif /* SHOPT_MULTIBYTE */ 1376*4887Schin return; 1377*4887Schin } 1378*4887Schin if( tmp == INSERT ) 1379*4887Schin { 1380*4887Schin mode = APPEND; 1381*4887Schin continue; 1382*4887Schin } 1383*4887Schin mode = tmp; 1384*4887Schin if(mode==REPLACE) 1385*4887Schin { 1386*4887Schin c = last_save = last_virt+1; 1387*4887Schin if(c >= MAXLINE) 1388*4887Schin c = MAXLINE-1; 1389*4887Schin genncpy(saveline, virtual, c); 1390*4887Schin } 1391*4887Schin } 1392*4887Schin break; 1393*4887Schin 1394*4887Schin case UERASE: /** user erase char **/ 1395*4887Schin /*** treat as backspace ***/ 1396*4887Schin 1397*4887Schin case '\b': /** backspace **/ 1398*4887Schin if( virtual[cur_virt] == '\\' ) 1399*4887Schin { 1400*4887Schin cdelete(vp,1, BAD); 1401*4887Schin append(vp,usrerase, mode); 1402*4887Schin } 1403*4887Schin else 1404*4887Schin { 1405*4887Schin if( mode==SEARCH && cur_virt==0 ) 1406*4887Schin { 1407*4887Schin first_virt = 0; 1408*4887Schin cdelete(vp,1, BAD); 1409*4887Schin return; 1410*4887Schin } 1411*4887Schin if(mode==REPLACE || (last_save>0 && last_virt<=last_save)) 1412*4887Schin { 1413*4887Schin if(cur_virt<=first_virt) 1414*4887Schin ed_ringbell(); 1415*4887Schin else if(mode==REPLACE) 1416*4887Schin --cur_virt; 1417*4887Schin mode = REPLACE; 1418*4887Schin sync_cursor(vp); 1419*4887Schin continue; 1420*4887Schin } 1421*4887Schin else 1422*4887Schin cdelete(vp,1, BAD); 1423*4887Schin } 1424*4887Schin break; 1425*4887Schin 1426*4887Schin case UWERASE: /** delete back word **/ 1427*4887Schin if( cur_virt > first_virt && 1428*4887Schin !isblank(cur_virt) && 1429*4887Schin !ispunct(virtual[cur_virt]) && 1430*4887Schin isblank(cur_virt-1) ) 1431*4887Schin { 1432*4887Schin cdelete(vp,1, BAD); 1433*4887Schin } 1434*4887Schin else 1435*4887Schin { 1436*4887Schin tmp = cur_virt; 1437*4887Schin backword(vp,1, 'W'); 1438*4887Schin cdelete(vp,tmp - cur_virt + 1, BAD); 1439*4887Schin } 1440*4887Schin break; 1441*4887Schin 1442*4887Schin case UKILL: /** user kill line char **/ 1443*4887Schin if( virtual[cur_virt] == '\\' ) 1444*4887Schin { 1445*4887Schin cdelete(vp,1, BAD); 1446*4887Schin append(vp,usrkill, mode); 1447*4887Schin } 1448*4887Schin else 1449*4887Schin { 1450*4887Schin if( mode == SEARCH ) 1451*4887Schin { 1452*4887Schin cur_virt = 1; 1453*4887Schin delmotion(vp, '$', BAD); 1454*4887Schin } 1455*4887Schin else if(first_virt) 1456*4887Schin { 1457*4887Schin tmp = cur_virt; 1458*4887Schin cur_virt = first_virt; 1459*4887Schin cdelete(vp,tmp - cur_virt + 1, BAD); 1460*4887Schin } 1461*4887Schin else 1462*4887Schin del_line(vp,GOOD); 1463*4887Schin } 1464*4887Schin break; 1465*4887Schin 1466*4887Schin case UEOF: /** eof char **/ 1467*4887Schin if( cur_virt != INVALID ) 1468*4887Schin continue; 1469*4887Schin vp->addnl = 0; 1470*4887Schin 1471*4887Schin case '\n': /** newline or return **/ 1472*4887Schin if( mode != SEARCH ) 1473*4887Schin save_last(vp); 1474*4887Schin refresh(vp,INPUT); 1475*4887Schin return; 1476*4887Schin 1477*4887Schin case '\t': /** command completion **/ 1478*4887Schin if(mode!=SEARCH && last_virt>=0 && (vp->ed->e_tabcount|| !isblank(cur_virt)) && vp->ed->sh->nextprompt) 1479*4887Schin { 1480*4887Schin if(vp->ed->e_tabcount==0) 1481*4887Schin { 1482*4887Schin ed_ungetchar(vp->ed,'\\'); 1483*4887Schin vp->ed->e_tabcount=1; 1484*4887Schin goto escape; 1485*4887Schin } 1486*4887Schin else if(vp->ed->e_tabcount==1) 1487*4887Schin { 1488*4887Schin ed_ungetchar(vp->ed,'='); 1489*4887Schin goto escape; 1490*4887Schin } 1491*4887Schin vp->ed->e_tabcount = 0; 1492*4887Schin } 1493*4887Schin /* FALL THRU*/ 1494*4887Schin default: 1495*4887Schin if( mode == REPLACE ) 1496*4887Schin { 1497*4887Schin if( cur_virt < last_virt ) 1498*4887Schin { 1499*4887Schin replace(vp,c, 1); 1500*4887Schin if(cur_virt>max_virt) 1501*4887Schin max_virt = cur_virt; 1502*4887Schin continue; 1503*4887Schin } 1504*4887Schin cdelete(vp,1, BAD); 1505*4887Schin mode = APPEND; 1506*4887Schin max_virt = last_virt+3; 1507*4887Schin } 1508*4887Schin append(vp,c, mode); 1509*4887Schin break; 1510*4887Schin } 1511*4887Schin refresh(vp,INPUT); 1512*4887Schin 1513*4887Schin } 1514*4887Schin } 1515*4887Schin 1516*4887Schin /*{ MVCURSOR( motion ) 1517*4887Schin * 1518*4887Schin * This routine will move the virtual cursor according to motion 1519*4887Schin * for repeat times. 1520*4887Schin * 1521*4887Schin * It returns GOOD if successful; else BAD. 1522*4887Schin * 1523*4887Schin }*/ 1524*4887Schin 1525*4887Schin static int mvcursor(register Vi_t* vp,register int motion) 1526*4887Schin { 1527*4887Schin register int count; 1528*4887Schin register int tcur_virt; 1529*4887Schin register int incr = -1; 1530*4887Schin register int bound = 0; 1531*4887Schin 1532*4887Schin switch(motion) 1533*4887Schin { 1534*4887Schin /***** Cursor move commands *****/ 1535*4887Schin 1536*4887Schin case '0': /** First column **/ 1537*4887Schin tcur_virt = 0; 1538*4887Schin break; 1539*4887Schin 1540*4887Schin case '^': /** First nonblank character **/ 1541*4887Schin tcur_virt = first_virt; 1542*4887Schin while( isblank(tcur_virt) && tcur_virt < last_virt ) 1543*4887Schin ++tcur_virt; 1544*4887Schin break; 1545*4887Schin 1546*4887Schin case '|': 1547*4887Schin tcur_virt = vp->repeat-1; 1548*4887Schin if(tcur_virt <= last_virt) 1549*4887Schin break; 1550*4887Schin /* fall through */ 1551*4887Schin 1552*4887Schin case '$': /** End of line **/ 1553*4887Schin tcur_virt = last_virt; 1554*4887Schin break; 1555*4887Schin 1556*4887Schin case '[': 1557*4887Schin switch(motion=getcount(vp,ed_getchar(vp->ed,-1))) 1558*4887Schin { 1559*4887Schin case 'A': 1560*4887Schin ed_ungetchar(vp->ed,'k'); 1561*4887Schin return(1); 1562*4887Schin case 'B': 1563*4887Schin ed_ungetchar(vp->ed,'j'); 1564*4887Schin return(1); 1565*4887Schin case 'C': 1566*4887Schin motion = last_virt; 1567*4887Schin incr = 1; 1568*4887Schin goto walk; 1569*4887Schin case 'D': 1570*4887Schin motion = first_virt; 1571*4887Schin goto walk; 1572*4887Schin case 'H': 1573*4887Schin tcur_virt = 0; 1574*4887Schin break; 1575*4887Schin case 'Y': 1576*4887Schin tcur_virt = last_virt; 1577*4887Schin break; 1578*4887Schin default: 1579*4887Schin ed_ungetchar(vp->ed,motion); 1580*4887Schin return(0); 1581*4887Schin } 1582*4887Schin break; 1583*4887Schin 1584*4887Schin case 'h': /** Left one **/ 1585*4887Schin case '\b': 1586*4887Schin motion = first_virt; 1587*4887Schin goto walk; 1588*4887Schin 1589*4887Schin case ' ': 1590*4887Schin case 'l': /** Right one **/ 1591*4887Schin motion = last_virt; 1592*4887Schin incr = 1; 1593*4887Schin walk: 1594*4887Schin tcur_virt = cur_virt; 1595*4887Schin if( incr*tcur_virt < motion) 1596*4887Schin { 1597*4887Schin tcur_virt += vp->repeat*incr; 1598*4887Schin if( incr*tcur_virt > motion) 1599*4887Schin tcur_virt = motion; 1600*4887Schin } 1601*4887Schin else 1602*4887Schin return(0); 1603*4887Schin break; 1604*4887Schin 1605*4887Schin case 'B': 1606*4887Schin case 'b': /** back word **/ 1607*4887Schin tcur_virt = cur_virt; 1608*4887Schin backword(vp,vp->repeat, motion); 1609*4887Schin if( cur_virt == tcur_virt ) 1610*4887Schin return(0); 1611*4887Schin return(1); 1612*4887Schin 1613*4887Schin case 'E': 1614*4887Schin case 'e': /** end of word **/ 1615*4887Schin tcur_virt = cur_virt; 1616*4887Schin if(tcur_virt >=0) 1617*4887Schin endword(vp, vp->repeat, motion); 1618*4887Schin if( cur_virt == tcur_virt ) 1619*4887Schin return(0); 1620*4887Schin return(1); 1621*4887Schin 1622*4887Schin case ',': /** reverse find old char **/ 1623*4887Schin case ';': /** find old char **/ 1624*4887Schin switch(vp->last_find) 1625*4887Schin { 1626*4887Schin case 't': 1627*4887Schin case 'f': 1628*4887Schin if(motion==';') 1629*4887Schin { 1630*4887Schin bound = last_virt; 1631*4887Schin incr = 1; 1632*4887Schin } 1633*4887Schin goto find_b; 1634*4887Schin 1635*4887Schin case 'T': 1636*4887Schin case 'F': 1637*4887Schin if(motion==',') 1638*4887Schin { 1639*4887Schin bound = last_virt; 1640*4887Schin incr = 1; 1641*4887Schin } 1642*4887Schin goto find_b; 1643*4887Schin 1644*4887Schin default: 1645*4887Schin return(0); 1646*4887Schin } 1647*4887Schin 1648*4887Schin 1649*4887Schin case 't': /** find up to new char forward **/ 1650*4887Schin case 'f': /** find new char forward **/ 1651*4887Schin bound = last_virt; 1652*4887Schin incr = 1; 1653*4887Schin 1654*4887Schin case 'T': /** find up to new char backward **/ 1655*4887Schin case 'F': /** find new char backward **/ 1656*4887Schin vp->last_find = motion; 1657*4887Schin if((vp->findchar=getrchar(vp))==ESC) 1658*4887Schin return(1); 1659*4887Schin find_b: 1660*4887Schin tcur_virt = cur_virt; 1661*4887Schin count = vp->repeat; 1662*4887Schin while( count-- ) 1663*4887Schin { 1664*4887Schin while( incr*(tcur_virt+=incr) <= bound 1665*4887Schin && virtual[tcur_virt] != vp->findchar ); 1666*4887Schin if( incr*tcur_virt > bound ) 1667*4887Schin { 1668*4887Schin return(0); 1669*4887Schin } 1670*4887Schin } 1671*4887Schin if( fold(vp->last_find) == 'T' ) 1672*4887Schin tcur_virt -= incr; 1673*4887Schin break; 1674*4887Schin 1675*4887Schin case '%': 1676*4887Schin { 1677*4887Schin int nextmotion; 1678*4887Schin int nextc; 1679*4887Schin tcur_virt = cur_virt; 1680*4887Schin while( tcur_virt <= last_virt 1681*4887Schin && strchr(paren_chars,virtual[tcur_virt])==(char*)0) 1682*4887Schin tcur_virt++; 1683*4887Schin if(tcur_virt > last_virt ) 1684*4887Schin return(0); 1685*4887Schin nextc = virtual[tcur_virt]; 1686*4887Schin count = strchr(paren_chars,nextc)-paren_chars; 1687*4887Schin if(count < 3) 1688*4887Schin { 1689*4887Schin incr = 1; 1690*4887Schin bound = last_virt; 1691*4887Schin nextmotion = paren_chars[count+3]; 1692*4887Schin } 1693*4887Schin else 1694*4887Schin nextmotion = paren_chars[count-3]; 1695*4887Schin count = 1; 1696*4887Schin while(count >0 && incr*(tcur_virt+=incr) <= bound) 1697*4887Schin { 1698*4887Schin if(virtual[tcur_virt] == nextmotion) 1699*4887Schin count--; 1700*4887Schin else if(virtual[tcur_virt]==nextc) 1701*4887Schin count++; 1702*4887Schin } 1703*4887Schin if(count) 1704*4887Schin return(0); 1705*4887Schin break; 1706*4887Schin } 1707*4887Schin 1708*4887Schin case 'W': 1709*4887Schin case 'w': /** forward word **/ 1710*4887Schin tcur_virt = cur_virt; 1711*4887Schin forward(vp,vp->repeat, motion); 1712*4887Schin if( tcur_virt == cur_virt ) 1713*4887Schin return(0); 1714*4887Schin return(1); 1715*4887Schin 1716*4887Schin default: 1717*4887Schin return(0); 1718*4887Schin } 1719*4887Schin cur_virt = tcur_virt; 1720*4887Schin 1721*4887Schin return(1); 1722*4887Schin } 1723*4887Schin 1724*4887Schin /* 1725*4887Schin * print a string 1726*4887Schin */ 1727*4887Schin 1728*4887Schin static void pr_string(register Vi_t *vp, register const char *sp) 1729*4887Schin { 1730*4887Schin /*** copy string sp ***/ 1731*4887Schin register char *ptr = editb.e_outptr; 1732*4887Schin while(*sp) 1733*4887Schin *ptr++ = *sp++; 1734*4887Schin editb.e_outptr = ptr; 1735*4887Schin return; 1736*4887Schin } 1737*4887Schin 1738*4887Schin /*{ PUTSTRING( column, nchars ) 1739*4887Schin * 1740*4887Schin * Put nchars starting at column of physical into the workspace 1741*4887Schin * to be printed. 1742*4887Schin * 1743*4887Schin }*/ 1744*4887Schin 1745*4887Schin static void putstring(register Vi_t *vp,register int col, register int nchars) 1746*4887Schin { 1747*4887Schin while( nchars-- ) 1748*4887Schin putchar(physical[col++]); 1749*4887Schin return; 1750*4887Schin } 1751*4887Schin 1752*4887Schin /*{ REFRESH( mode ) 1753*4887Schin * 1754*4887Schin * This routine will refresh the crt so the physical image matches 1755*4887Schin * the virtual image and display the proper window. 1756*4887Schin * 1757*4887Schin * mode = CONTROL, refresh in control mode, ie. leave cursor 1758*4887Schin * positioned at last char printed. 1759*4887Schin * = INPUT, refresh in input mode; leave cursor positioned 1760*4887Schin * after last char printed. 1761*4887Schin * = TRANSLATE, perform virtual to physical translation 1762*4887Schin * and adjust left margin only. 1763*4887Schin * 1764*4887Schin * +-------------------------------+ 1765*4887Schin * | | | virtual | | | 1766*4887Schin * +-------------------------------+ 1767*4887Schin * cur_virt last_virt 1768*4887Schin * 1769*4887Schin * +-----------------------------------------------+ 1770*4887Schin * | | | physical | | | 1771*4887Schin * +-----------------------------------------------+ 1772*4887Schin * cur_phys last_phys 1773*4887Schin * 1774*4887Schin * 0 w_size - 1 1775*4887Schin * +-----------------------+ 1776*4887Schin * | | | window | 1777*4887Schin * +-----------------------+ 1778*4887Schin * cur_window = cur_phys - first_wind 1779*4887Schin }*/ 1780*4887Schin 1781*4887Schin static void refresh(register Vi_t* vp, int mode) 1782*4887Schin { 1783*4887Schin register int p; 1784*4887Schin register int regb; 1785*4887Schin register int first_w = vp->first_wind; 1786*4887Schin int p_differ; 1787*4887Schin int new_lw; 1788*4887Schin int ncur_phys; 1789*4887Schin int opflag; /* search optimize flag */ 1790*4887Schin 1791*4887Schin # define w regb 1792*4887Schin # define v regb 1793*4887Schin 1794*4887Schin /*** find out if it's necessary to start translating at beginning ***/ 1795*4887Schin 1796*4887Schin if(lookahead>0) 1797*4887Schin { 1798*4887Schin p = previous[lookahead-1]; 1799*4887Schin if(p != ESC && p != '\n' && p != '\r') 1800*4887Schin mode = TRANSLATE; 1801*4887Schin } 1802*4887Schin v = cur_virt; 1803*4887Schin if( v<vp->ocur_virt || vp->ocur_virt==INVALID 1804*4887Schin || ( v==vp->ocur_virt 1805*4887Schin && (!is_print(virtual[v]) || !is_print(vp->o_v_char))) ) 1806*4887Schin { 1807*4887Schin opflag = 0; 1808*4887Schin p = 0; 1809*4887Schin v = 0; 1810*4887Schin } 1811*4887Schin else 1812*4887Schin { 1813*4887Schin opflag = 1; 1814*4887Schin p = vp->ocur_phys; 1815*4887Schin v = vp->ocur_virt; 1816*4887Schin if( !is_print(virtual[v]) ) 1817*4887Schin { 1818*4887Schin /*** avoid double ^'s ***/ 1819*4887Schin ++p; 1820*4887Schin ++v; 1821*4887Schin } 1822*4887Schin } 1823*4887Schin virtual[last_virt+1] = 0; 1824*4887Schin ncur_phys = ed_virt_to_phys(vp->ed,virtual,physical,cur_virt,v,p); 1825*4887Schin p = genlen(physical); 1826*4887Schin if( --p < 0 ) 1827*4887Schin last_phys = 0; 1828*4887Schin else 1829*4887Schin last_phys = p; 1830*4887Schin 1831*4887Schin /*** see if this was a translate only ***/ 1832*4887Schin 1833*4887Schin if( mode == TRANSLATE ) 1834*4887Schin return; 1835*4887Schin 1836*4887Schin /*** adjust left margin if necessary ***/ 1837*4887Schin 1838*4887Schin if( ncur_phys<first_w || ncur_phys>=(first_w + w_size) ) 1839*4887Schin { 1840*4887Schin cursor(vp,first_w); 1841*4887Schin first_w = ncur_phys - (w_size>>1); 1842*4887Schin if( first_w < 0 ) 1843*4887Schin first_w = 0; 1844*4887Schin vp->first_wind = cur_phys = first_w; 1845*4887Schin } 1846*4887Schin 1847*4887Schin /*** attempt to optimize search somewhat to find ***/ 1848*4887Schin /*** out where physical and window images differ ***/ 1849*4887Schin 1850*4887Schin if( first_w==vp->ofirst_wind && ncur_phys>=vp->ocur_phys && opflag==1 ) 1851*4887Schin { 1852*4887Schin p = vp->ocur_phys; 1853*4887Schin w = p - first_w; 1854*4887Schin } 1855*4887Schin else 1856*4887Schin { 1857*4887Schin p = first_w; 1858*4887Schin w = 0; 1859*4887Schin } 1860*4887Schin 1861*4887Schin for(; (p<=last_phys && w<=vp->last_wind); ++p, ++w) 1862*4887Schin { 1863*4887Schin if( window[w] != physical[p] ) 1864*4887Schin break; 1865*4887Schin } 1866*4887Schin p_differ = p; 1867*4887Schin 1868*4887Schin if( (p>last_phys || p>=first_w+w_size) && w>vp->last_wind 1869*4887Schin && cur_virt==vp->ocur_virt ) 1870*4887Schin { 1871*4887Schin /*** images are identical ***/ 1872*4887Schin return; 1873*4887Schin } 1874*4887Schin 1875*4887Schin /*** copy the physical image to the window image ***/ 1876*4887Schin 1877*4887Schin if( last_virt != INVALID ) 1878*4887Schin { 1879*4887Schin while( p <= last_phys && w < w_size ) 1880*4887Schin window[w++] = physical[p++]; 1881*4887Schin } 1882*4887Schin new_lw = w; 1883*4887Schin 1884*4887Schin /*** erase trailing characters if needed ***/ 1885*4887Schin 1886*4887Schin while( w <= vp->last_wind ) 1887*4887Schin window[w++] = ' '; 1888*4887Schin vp->last_wind = --w; 1889*4887Schin 1890*4887Schin p = p_differ; 1891*4887Schin 1892*4887Schin /*** move cursor to start of difference ***/ 1893*4887Schin 1894*4887Schin cursor(vp,p); 1895*4887Schin 1896*4887Schin /*** and output difference ***/ 1897*4887Schin 1898*4887Schin w = p - first_w; 1899*4887Schin while( w <= vp->last_wind ) 1900*4887Schin putchar(window[w++]); 1901*4887Schin 1902*4887Schin cur_phys = w + first_w; 1903*4887Schin vp->last_wind = --new_lw; 1904*4887Schin 1905*4887Schin if( last_phys >= w_size ) 1906*4887Schin { 1907*4887Schin if( first_w == 0 ) 1908*4887Schin vp->long_char = '>'; 1909*4887Schin else if( last_phys < (first_w+w_size) ) 1910*4887Schin vp->long_char = '<'; 1911*4887Schin else 1912*4887Schin vp->long_char = '*'; 1913*4887Schin } 1914*4887Schin else 1915*4887Schin vp->long_char = ' '; 1916*4887Schin 1917*4887Schin if( vp->long_line != vp->long_char ) 1918*4887Schin { 1919*4887Schin /*** indicate lines longer than window ***/ 1920*4887Schin while( w++ < w_size ) 1921*4887Schin { 1922*4887Schin putchar(' '); 1923*4887Schin ++cur_phys; 1924*4887Schin } 1925*4887Schin putchar(vp->long_char); 1926*4887Schin ++cur_phys; 1927*4887Schin vp->long_line = vp->long_char; 1928*4887Schin } 1929*4887Schin 1930*4887Schin vp->ocur_phys = ncur_phys; 1931*4887Schin vp->ocur_virt = cur_virt; 1932*4887Schin vp->ofirst_wind = first_w; 1933*4887Schin 1934*4887Schin if( mode==INPUT && cur_virt>INVALID ) 1935*4887Schin ++ncur_phys; 1936*4887Schin 1937*4887Schin cursor(vp,ncur_phys); 1938*4887Schin ed_flush(vp->ed); 1939*4887Schin return; 1940*4887Schin } 1941*4887Schin 1942*4887Schin /*{ REPLACE( char, increment ) 1943*4887Schin * 1944*4887Schin * Replace the cur_virt character with char. This routine attempts 1945*4887Schin * to avoid using refresh(). 1946*4887Schin * 1947*4887Schin * increment = 1, increment cur_virt after replacement. 1948*4887Schin * = 0, leave cur_virt where it is. 1949*4887Schin * 1950*4887Schin }*/ 1951*4887Schin 1952*4887Schin static void replace(register Vi_t *vp, register int c, register int increment) 1953*4887Schin { 1954*4887Schin register int cur_window; 1955*4887Schin 1956*4887Schin if( cur_virt == INVALID ) 1957*4887Schin { 1958*4887Schin /*** can't replace invalid cursor ***/ 1959*4887Schin ed_ringbell(); 1960*4887Schin return; 1961*4887Schin } 1962*4887Schin cur_window = cur_phys - vp->first_wind; 1963*4887Schin if( vp->ocur_virt == INVALID || !is_print(c) 1964*4887Schin || !is_print(virtual[cur_virt]) 1965*4887Schin || !is_print(vp->o_v_char) 1966*4887Schin #if SHOPT_MULTIBYTE 1967*4887Schin || !iswascii(c) || mbwidth(vp->o_v_char)>1 1968*4887Schin || !iswascii(virtual[cur_virt]) 1969*4887Schin #endif /* SHOPT_MULTIBYTE */ 1970*4887Schin || (increment && (cur_window==w_size-1) 1971*4887Schin || !is_print(virtual[cur_virt+1])) ) 1972*4887Schin { 1973*4887Schin /*** must use standard refresh routine ***/ 1974*4887Schin 1975*4887Schin cdelete(vp,1, BAD); 1976*4887Schin append(vp,c, APPEND); 1977*4887Schin if( increment && cur_virt<last_virt ) 1978*4887Schin ++cur_virt; 1979*4887Schin refresh(vp,CONTROL); 1980*4887Schin } 1981*4887Schin else 1982*4887Schin { 1983*4887Schin virtual[cur_virt] = c; 1984*4887Schin physical[cur_phys] = c; 1985*4887Schin window[cur_window] = c; 1986*4887Schin putchar(c); 1987*4887Schin if(increment) 1988*4887Schin { 1989*4887Schin c = virtual[++cur_virt]; 1990*4887Schin ++cur_phys; 1991*4887Schin } 1992*4887Schin else 1993*4887Schin { 1994*4887Schin putchar('\b'); 1995*4887Schin } 1996*4887Schin vp->o_v_char = c; 1997*4887Schin ed_flush(vp->ed); 1998*4887Schin } 1999*4887Schin return; 2000*4887Schin } 2001*4887Schin 2002*4887Schin /*{ RESTORE_V() 2003*4887Schin * 2004*4887Schin * Restore the contents of virtual space from u_space. 2005*4887Schin * 2006*4887Schin }*/ 2007*4887Schin 2008*4887Schin static void restore_v(register Vi_t *vp) 2009*4887Schin { 2010*4887Schin register int tmpcol; 2011*4887Schin genchar tmpspace[MAXLINE]; 2012*4887Schin 2013*4887Schin if( vp->u_column == INVALID-1 ) 2014*4887Schin { 2015*4887Schin /*** never saved anything ***/ 2016*4887Schin ed_ringbell(); 2017*4887Schin return; 2018*4887Schin } 2019*4887Schin gencpy(tmpspace, vp->u_space); 2020*4887Schin tmpcol = vp->u_column; 2021*4887Schin save_v(vp); 2022*4887Schin gencpy(virtual, tmpspace); 2023*4887Schin cur_virt = tmpcol; 2024*4887Schin last_virt = genlen(tmpspace) - 1; 2025*4887Schin vp->ocur_virt = MAXCHAR; /** invalidate refresh optimization **/ 2026*4887Schin return; 2027*4887Schin } 2028*4887Schin 2029*4887Schin /*{ SAVE_LAST() 2030*4887Schin * 2031*4887Schin * If the user has typed something, save it in last line. 2032*4887Schin * 2033*4887Schin }*/ 2034*4887Schin 2035*4887Schin static void save_last(register Vi_t* vp) 2036*4887Schin { 2037*4887Schin register int i; 2038*4887Schin 2039*4887Schin if( (i = cur_virt - first_virt + 1) > 0 ) 2040*4887Schin { 2041*4887Schin /*** save last thing user typed ***/ 2042*4887Schin if(i >= MAXLINE) 2043*4887Schin i = MAXLINE-1; 2044*4887Schin genncpy(vp->lastline, (&virtual[first_virt]), i); 2045*4887Schin vp->lastline[i] = '\0'; 2046*4887Schin } 2047*4887Schin return; 2048*4887Schin } 2049*4887Schin 2050*4887Schin /*{ SAVE_V() 2051*4887Schin * 2052*4887Schin * This routine will save the contents of virtual in u_space. 2053*4887Schin * 2054*4887Schin }*/ 2055*4887Schin 2056*4887Schin static void save_v(register Vi_t *vp) 2057*4887Schin { 2058*4887Schin if(!inmacro) 2059*4887Schin { 2060*4887Schin virtual[last_virt + 1] = '\0'; 2061*4887Schin gencpy(vp->u_space, virtual); 2062*4887Schin vp->u_column = cur_virt; 2063*4887Schin } 2064*4887Schin return; 2065*4887Schin } 2066*4887Schin 2067*4887Schin /*{ SEARCH( mode ) 2068*4887Schin * 2069*4887Schin * Search history file for regular expression. 2070*4887Schin * 2071*4887Schin * mode = '/' require search string and search new to old 2072*4887Schin * mode = '?' require search string and search old to new 2073*4887Schin * mode = 'N' repeat last search in reverse direction 2074*4887Schin * mode = 'n' repeat last search 2075*4887Schin * 2076*4887Schin }*/ 2077*4887Schin 2078*4887Schin /* 2079*4887Schin * search for <string> in the current command 2080*4887Schin */ 2081*4887Schin static int curline_search(Vi_t *vp, const char *string) 2082*4887Schin { 2083*4887Schin register int len=strlen(string); 2084*4887Schin register const char *dp,*cp=string, *dpmax; 2085*4887Schin #if SHOPT_MULTIBYTE 2086*4887Schin ed_external(vp->u_space,(char*)vp->u_space); 2087*4887Schin #endif /* SHOPT_MULTIBYTE */ 2088*4887Schin for(dp=(char*)vp->u_space,dpmax=dp+strlen(dp)-len; dp<=dpmax; dp++) 2089*4887Schin { 2090*4887Schin if(*dp==*cp && memcmp(cp,dp,len)==0) 2091*4887Schin return(dp-(char*)vp->u_space); 2092*4887Schin } 2093*4887Schin #if SHOPT_MULTIBYTE 2094*4887Schin ed_internal((char*)vp->u_space,vp->u_space); 2095*4887Schin #endif /* SHOPT_MULTIBYTE */ 2096*4887Schin return(-1); 2097*4887Schin } 2098*4887Schin 2099*4887Schin static int search(register Vi_t* vp,register int mode) 2100*4887Schin { 2101*4887Schin register int new_direction; 2102*4887Schin register int oldcurhline; 2103*4887Schin register int i; 2104*4887Schin Histloc_t location; 2105*4887Schin 2106*4887Schin if( mode == '/' || mode == '?') 2107*4887Schin { 2108*4887Schin /*** new search expression ***/ 2109*4887Schin del_line(vp,BAD); 2110*4887Schin append(vp,mode, APPEND); 2111*4887Schin refresh(vp,INPUT); 2112*4887Schin first_virt = 1; 2113*4887Schin getline(vp,SEARCH); 2114*4887Schin first_virt = 0; 2115*4887Schin virtual[last_virt + 1] = '\0'; /*** make null terminated ***/ 2116*4887Schin vp->direction = mode=='/' ? -1 : 1; 2117*4887Schin } 2118*4887Schin 2119*4887Schin if( cur_virt == INVALID ) 2120*4887Schin { 2121*4887Schin /*** no operation ***/ 2122*4887Schin return(ABORT); 2123*4887Schin } 2124*4887Schin 2125*4887Schin if( cur_virt==0 || fold(mode)=='N' ) 2126*4887Schin { 2127*4887Schin /*** user wants repeat of last search ***/ 2128*4887Schin del_line(vp,BAD); 2129*4887Schin strcpy( ((char*)virtual)+1, lsearch); 2130*4887Schin #if SHOPT_MULTIBYTE 2131*4887Schin *((char*)virtual) = '/'; 2132*4887Schin ed_internal((char*)virtual,virtual); 2133*4887Schin #endif /* SHOPT_MULTIBYTE */ 2134*4887Schin } 2135*4887Schin 2136*4887Schin if( mode == 'N' ) 2137*4887Schin new_direction = -vp->direction; 2138*4887Schin else 2139*4887Schin new_direction = vp->direction; 2140*4887Schin 2141*4887Schin 2142*4887Schin /*** now search ***/ 2143*4887Schin 2144*4887Schin oldcurhline = curhline; 2145*4887Schin #if SHOPT_MULTIBYTE 2146*4887Schin ed_external(virtual,(char*)virtual); 2147*4887Schin #endif /* SHOPT_MULTIBYTE */ 2148*4887Schin if(mode=='?' && (i=curline_search(vp,((char*)virtual)+1))>=0) 2149*4887Schin { 2150*4887Schin location.hist_command = curhline; 2151*4887Schin location.hist_char = i; 2152*4887Schin } 2153*4887Schin else 2154*4887Schin { 2155*4887Schin i = INVALID; 2156*4887Schin if( new_direction==1 && curhline >= histmax ) 2157*4887Schin curhline = histmin + 1; 2158*4887Schin location = hist_find(sh.hist_ptr,((char*)virtual)+1, curhline, 1, new_direction); 2159*4887Schin } 2160*4887Schin cur_virt = i; 2161*4887Schin strncpy(lsearch, ((char*)virtual)+1, SEARCHSIZE); 2162*4887Schin if( (curhline=location.hist_command) >=0 ) 2163*4887Schin { 2164*4887Schin vp->ocur_virt = INVALID; 2165*4887Schin return(GOOD); 2166*4887Schin } 2167*4887Schin 2168*4887Schin /*** could not find matching line ***/ 2169*4887Schin 2170*4887Schin curhline = oldcurhline; 2171*4887Schin return(BAD); 2172*4887Schin } 2173*4887Schin 2174*4887Schin /*{ SYNC_CURSOR() 2175*4887Schin * 2176*4887Schin * This routine will move the physical cursor to the same 2177*4887Schin * column as the virtual cursor. 2178*4887Schin * 2179*4887Schin }*/ 2180*4887Schin 2181*4887Schin static void sync_cursor(register Vi_t *vp) 2182*4887Schin { 2183*4887Schin register int p; 2184*4887Schin register int v; 2185*4887Schin register int c; 2186*4887Schin int new_phys; 2187*4887Schin 2188*4887Schin if( cur_virt == INVALID ) 2189*4887Schin return; 2190*4887Schin 2191*4887Schin /*** find physical col that corresponds to virtual col ***/ 2192*4887Schin 2193*4887Schin new_phys = 0; 2194*4887Schin if(vp->first_wind==vp->ofirst_wind && cur_virt>vp->ocur_virt && vp->ocur_virt!=INVALID) 2195*4887Schin { 2196*4887Schin /*** try to optimize search a little ***/ 2197*4887Schin p = vp->ocur_phys + 1; 2198*4887Schin #if SHOPT_MULTIBYTE 2199*4887Schin while(physical[p]==MARKER) 2200*4887Schin p++; 2201*4887Schin #endif /* SHOPT_MULTIBYTE */ 2202*4887Schin v = vp->ocur_virt + 1; 2203*4887Schin } 2204*4887Schin else 2205*4887Schin { 2206*4887Schin p = 0; 2207*4887Schin v = 0; 2208*4887Schin } 2209*4887Schin for(; v <= last_virt; ++p, ++v) 2210*4887Schin { 2211*4887Schin #if SHOPT_MULTIBYTE 2212*4887Schin int d; 2213*4887Schin c = virtual[v]; 2214*4887Schin if((d = mbwidth(c)) > 1) 2215*4887Schin { 2216*4887Schin if( v != cur_virt ) 2217*4887Schin p += (d-1); 2218*4887Schin } 2219*4887Schin else if(!iswprint(c)) 2220*4887Schin #else 2221*4887Schin c = virtual[v]; 2222*4887Schin if(!isprint(c)) 2223*4887Schin #endif /* SHOPT_MULTIBYTE */ 2224*4887Schin { 2225*4887Schin if( c == '\t' ) 2226*4887Schin { 2227*4887Schin p -= ((p+editb.e_plen)%TABSIZE); 2228*4887Schin p += (TABSIZE-1); 2229*4887Schin } 2230*4887Schin else 2231*4887Schin { 2232*4887Schin ++p; 2233*4887Schin } 2234*4887Schin } 2235*4887Schin if( v == cur_virt ) 2236*4887Schin { 2237*4887Schin new_phys = p; 2238*4887Schin break; 2239*4887Schin } 2240*4887Schin } 2241*4887Schin 2242*4887Schin if( new_phys < vp->first_wind || new_phys >= vp->first_wind + w_size ) 2243*4887Schin { 2244*4887Schin /*** asked to move outside of window ***/ 2245*4887Schin 2246*4887Schin window[0] = '\0'; 2247*4887Schin refresh(vp,CONTROL); 2248*4887Schin return; 2249*4887Schin } 2250*4887Schin 2251*4887Schin cursor(vp,new_phys); 2252*4887Schin ed_flush(vp->ed); 2253*4887Schin vp->ocur_phys = cur_phys; 2254*4887Schin vp->ocur_virt = cur_virt; 2255*4887Schin vp->o_v_char = virtual[vp->ocur_virt]; 2256*4887Schin 2257*4887Schin return; 2258*4887Schin } 2259*4887Schin 2260*4887Schin /*{ TEXTMOD( command, mode ) 2261*4887Schin * 2262*4887Schin * Modify text operations. 2263*4887Schin * 2264*4887Schin * mode != 0, repeat previous operation 2265*4887Schin * 2266*4887Schin }*/ 2267*4887Schin 2268*4887Schin static int textmod(register Vi_t *vp,register int c, int mode) 2269*4887Schin { 2270*4887Schin register int i; 2271*4887Schin register genchar *p = vp->lastline; 2272*4887Schin register int trepeat = vp->repeat; 2273*4887Schin genchar *savep; 2274*4887Schin 2275*4887Schin if(mode && (fold(vp->lastmotion)=='F' || fold(vp->lastmotion)=='T')) 2276*4887Schin vp->lastmotion = ';'; 2277*4887Schin 2278*4887Schin if( fold(c) == 'P' ) 2279*4887Schin { 2280*4887Schin /*** change p from lastline to yankbuf ***/ 2281*4887Schin p = yankbuf; 2282*4887Schin } 2283*4887Schin 2284*4887Schin addin: 2285*4887Schin switch( c ) 2286*4887Schin { 2287*4887Schin /***** Input commands *****/ 2288*4887Schin 2289*4887Schin #if KSHELL 2290*4887Schin case '\t': 2291*4887Schin if(vp->ed->e_tabcount!=1) 2292*4887Schin return(BAD); 2293*4887Schin c = '='; 2294*4887Schin case '*': /** do file name expansion in place **/ 2295*4887Schin case '\\': /** do file name completion in place **/ 2296*4887Schin if( cur_virt == INVALID ) 2297*4887Schin return(BAD); 2298*4887Schin case '=': /** list file name expansions **/ 2299*4887Schin save_v(vp); 2300*4887Schin i = last_virt; 2301*4887Schin ++last_virt; 2302*4887Schin mode = cur_virt-1; 2303*4887Schin virtual[last_virt] = 0; 2304*4887Schin if(ed_expand(vp->ed,(char*)virtual, &cur_virt, &last_virt, c, vp->repeat_set?vp->repeat:-1)<0) 2305*4887Schin { 2306*4887Schin if(vp->ed->e_tabcount) 2307*4887Schin { 2308*4887Schin vp->ed->e_tabcount=2; 2309*4887Schin ed_ungetchar(vp->ed,'\t'); 2310*4887Schin --last_virt; 2311*4887Schin return(APPEND); 2312*4887Schin } 2313*4887Schin last_virt = i; 2314*4887Schin ed_ringbell(); 2315*4887Schin } 2316*4887Schin else if(c == '=' && !vp->repeat_set) 2317*4887Schin { 2318*4887Schin last_virt = i; 2319*4887Schin vp->nonewline++; 2320*4887Schin ed_ungetchar(vp->ed,cntl('L')); 2321*4887Schin return(GOOD); 2322*4887Schin } 2323*4887Schin else 2324*4887Schin { 2325*4887Schin --cur_virt; 2326*4887Schin --last_virt; 2327*4887Schin vp->ocur_virt = MAXCHAR; 2328*4887Schin if(c=='=' || (mode<cur_virt && (virtual[cur_virt]==' ' || virtual[cur_virt]=='/'))) 2329*4887Schin vp->ed->e_tabcount = 0; 2330*4887Schin return(APPEND); 2331*4887Schin } 2332*4887Schin break; 2333*4887Schin 2334*4887Schin case '@': /** macro expansion **/ 2335*4887Schin if( mode ) 2336*4887Schin c = vp->lastmacro; 2337*4887Schin else 2338*4887Schin if((c=getrchar(vp))==ESC) 2339*4887Schin return(GOOD); 2340*4887Schin if(!inmacro) 2341*4887Schin vp->lastmacro = c; 2342*4887Schin if(ed_macro(vp->ed,c)) 2343*4887Schin { 2344*4887Schin save_v(vp); 2345*4887Schin inmacro++; 2346*4887Schin return(GOOD); 2347*4887Schin } 2348*4887Schin ed_ringbell(); 2349*4887Schin return(BAD); 2350*4887Schin 2351*4887Schin #endif /* KSHELL */ 2352*4887Schin case '_': /** append last argument of prev command **/ 2353*4887Schin save_v(vp); 2354*4887Schin { 2355*4887Schin genchar tmpbuf[MAXLINE]; 2356*4887Schin if(vp->repeat_set==0) 2357*4887Schin vp->repeat = -1; 2358*4887Schin p = (genchar*)hist_word((char*)tmpbuf,MAXLINE,vp->repeat); 2359*4887Schin #if !KSHELL 2360*4887Schin if(p==0) 2361*4887Schin { 2362*4887Schin ed_ringbell(); 2363*4887Schin break; 2364*4887Schin } 2365*4887Schin #endif /* KSHELL */ 2366*4887Schin #if SHOPT_MULTIBYTE 2367*4887Schin ed_internal((char*)p,tmpbuf); 2368*4887Schin p = tmpbuf; 2369*4887Schin #endif /* SHOPT_MULTIBYTE */ 2370*4887Schin i = ' '; 2371*4887Schin do 2372*4887Schin { 2373*4887Schin append(vp,i,APPEND); 2374*4887Schin } 2375*4887Schin while(i = *p++); 2376*4887Schin return(APPEND); 2377*4887Schin } 2378*4887Schin 2379*4887Schin case 'A': /** append to end of line **/ 2380*4887Schin cur_virt = last_virt; 2381*4887Schin sync_cursor(vp); 2382*4887Schin 2383*4887Schin case 'a': /** append **/ 2384*4887Schin if( fold(mode) == 'A' ) 2385*4887Schin { 2386*4887Schin c = 'p'; 2387*4887Schin goto addin; 2388*4887Schin } 2389*4887Schin save_v(vp); 2390*4887Schin if( cur_virt != INVALID ) 2391*4887Schin { 2392*4887Schin first_virt = cur_virt + 1; 2393*4887Schin cursor(vp,cur_phys + 1); 2394*4887Schin ed_flush(vp->ed); 2395*4887Schin } 2396*4887Schin return(APPEND); 2397*4887Schin 2398*4887Schin case 'I': /** insert at beginning of line **/ 2399*4887Schin cur_virt = first_virt; 2400*4887Schin sync_cursor(vp); 2401*4887Schin 2402*4887Schin case 'i': /** insert **/ 2403*4887Schin if( fold(mode) == 'I' ) 2404*4887Schin { 2405*4887Schin c = 'P'; 2406*4887Schin goto addin; 2407*4887Schin } 2408*4887Schin save_v(vp); 2409*4887Schin if( cur_virt != INVALID ) 2410*4887Schin { 2411*4887Schin vp->o_v_char = virtual[cur_virt]; 2412*4887Schin first_virt = cur_virt--; 2413*4887Schin } 2414*4887Schin return(INSERT); 2415*4887Schin 2416*4887Schin case 'C': /** change to eol **/ 2417*4887Schin c = '$'; 2418*4887Schin goto chgeol; 2419*4887Schin 2420*4887Schin case 'c': /** change **/ 2421*4887Schin if( mode ) 2422*4887Schin c = vp->lastmotion; 2423*4887Schin else 2424*4887Schin c = getcount(vp,ed_getchar(vp->ed,-1)); 2425*4887Schin chgeol: 2426*4887Schin vp->lastmotion = c; 2427*4887Schin if( c == 'c' ) 2428*4887Schin { 2429*4887Schin del_line(vp,GOOD); 2430*4887Schin return(APPEND); 2431*4887Schin } 2432*4887Schin 2433*4887Schin if(!delmotion(vp, c, 'c')) 2434*4887Schin return(BAD); 2435*4887Schin 2436*4887Schin if( mode == 'c' ) 2437*4887Schin { 2438*4887Schin c = 'p'; 2439*4887Schin trepeat = 1; 2440*4887Schin goto addin; 2441*4887Schin } 2442*4887Schin first_virt = cur_virt + 1; 2443*4887Schin return(APPEND); 2444*4887Schin 2445*4887Schin case 'D': /** delete to eol **/ 2446*4887Schin c = '$'; 2447*4887Schin goto deleol; 2448*4887Schin 2449*4887Schin case 'd': /** delete **/ 2450*4887Schin if( mode ) 2451*4887Schin c = vp->lastmotion; 2452*4887Schin else 2453*4887Schin c = getcount(vp,ed_getchar(vp->ed,-1)); 2454*4887Schin deleol: 2455*4887Schin vp->lastmotion = c; 2456*4887Schin if( c == 'd' ) 2457*4887Schin { 2458*4887Schin del_line(vp,GOOD); 2459*4887Schin break; 2460*4887Schin } 2461*4887Schin if(!delmotion(vp, c, 'd')) 2462*4887Schin return(BAD); 2463*4887Schin if( cur_virt < last_virt ) 2464*4887Schin ++cur_virt; 2465*4887Schin break; 2466*4887Schin 2467*4887Schin case 'P': 2468*4887Schin if( p[0] == '\0' ) 2469*4887Schin return(BAD); 2470*4887Schin if( cur_virt != INVALID ) 2471*4887Schin { 2472*4887Schin i = virtual[cur_virt]; 2473*4887Schin if(!is_print(i)) 2474*4887Schin vp->ocur_virt = INVALID; 2475*4887Schin --cur_virt; 2476*4887Schin } 2477*4887Schin 2478*4887Schin case 'p': /** print **/ 2479*4887Schin if( p[0] == '\0' ) 2480*4887Schin return(BAD); 2481*4887Schin 2482*4887Schin if( mode != 's' && mode != 'c' ) 2483*4887Schin { 2484*4887Schin save_v(vp); 2485*4887Schin if( c == 'P' ) 2486*4887Schin { 2487*4887Schin /*** fix stored cur_virt ***/ 2488*4887Schin ++vp->u_column; 2489*4887Schin } 2490*4887Schin } 2491*4887Schin if( mode == 'R' ) 2492*4887Schin mode = REPLACE; 2493*4887Schin else 2494*4887Schin mode = APPEND; 2495*4887Schin savep = p; 2496*4887Schin for(i=0; i<trepeat; ++i) 2497*4887Schin { 2498*4887Schin while(c= *p++) 2499*4887Schin append(vp,c,mode); 2500*4887Schin p = savep; 2501*4887Schin } 2502*4887Schin break; 2503*4887Schin 2504*4887Schin case 'R': /* Replace many chars **/ 2505*4887Schin if( mode == 'R' ) 2506*4887Schin { 2507*4887Schin c = 'P'; 2508*4887Schin goto addin; 2509*4887Schin } 2510*4887Schin save_v(vp); 2511*4887Schin if( cur_virt != INVALID ) 2512*4887Schin first_virt = cur_virt; 2513*4887Schin return(REPLACE); 2514*4887Schin 2515*4887Schin case 'r': /** replace **/ 2516*4887Schin if( mode ) 2517*4887Schin c = *p; 2518*4887Schin else 2519*4887Schin if((c=getrchar(vp))==ESC) 2520*4887Schin return(GOOD); 2521*4887Schin *p = c; 2522*4887Schin save_v(vp); 2523*4887Schin while(trepeat--) 2524*4887Schin replace(vp,c, trepeat!=0); 2525*4887Schin return(GOOD); 2526*4887Schin 2527*4887Schin case 'S': /** Substitute line - cc **/ 2528*4887Schin c = 'c'; 2529*4887Schin goto chgeol; 2530*4887Schin 2531*4887Schin case 's': /** substitute **/ 2532*4887Schin save_v(vp); 2533*4887Schin cdelete(vp,vp->repeat, BAD); 2534*4887Schin if( mode ) 2535*4887Schin { 2536*4887Schin c = 'p'; 2537*4887Schin trepeat = 1; 2538*4887Schin goto addin; 2539*4887Schin } 2540*4887Schin first_virt = cur_virt + 1; 2541*4887Schin return(APPEND); 2542*4887Schin 2543*4887Schin case 'Y': /** Yank to end of line **/ 2544*4887Schin c = '$'; 2545*4887Schin goto yankeol; 2546*4887Schin 2547*4887Schin case 'y': /** yank thru motion **/ 2548*4887Schin if( mode ) 2549*4887Schin c = vp->lastmotion; 2550*4887Schin else 2551*4887Schin c = getcount(vp,ed_getchar(vp->ed,-1)); 2552*4887Schin yankeol: 2553*4887Schin vp->lastmotion = c; 2554*4887Schin if( c == 'y' ) 2555*4887Schin { 2556*4887Schin gencpy(yankbuf, virtual); 2557*4887Schin } 2558*4887Schin else if(!delmotion(vp, c, 'y')) 2559*4887Schin { 2560*4887Schin return(BAD); 2561*4887Schin } 2562*4887Schin break; 2563*4887Schin 2564*4887Schin case 'x': /** delete repeat chars forward - dl **/ 2565*4887Schin c = 'l'; 2566*4887Schin goto deleol; 2567*4887Schin 2568*4887Schin case 'X': /** delete repeat chars backward - dh **/ 2569*4887Schin c = 'h'; 2570*4887Schin goto deleol; 2571*4887Schin 2572*4887Schin case '~': /** invert case and advance **/ 2573*4887Schin if( cur_virt != INVALID ) 2574*4887Schin { 2575*4887Schin save_v(vp); 2576*4887Schin i = INVALID; 2577*4887Schin while(trepeat-->0 && i!=cur_virt) 2578*4887Schin { 2579*4887Schin i = cur_virt; 2580*4887Schin c = virtual[cur_virt]; 2581*4887Schin #if SHOPT_MULTIBYTE 2582*4887Schin if((c&~STRIP)==0) 2583*4887Schin #endif /* SHOPT_MULTIBYTE */ 2584*4887Schin if( isupper(c) ) 2585*4887Schin c = tolower(c); 2586*4887Schin else if( islower(c) ) 2587*4887Schin c = toupper(c); 2588*4887Schin replace(vp,c, 1); 2589*4887Schin } 2590*4887Schin return(GOOD); 2591*4887Schin } 2592*4887Schin else 2593*4887Schin return(BAD); 2594*4887Schin 2595*4887Schin default: 2596*4887Schin return(BAD); 2597*4887Schin } 2598*4887Schin refresh(vp,CONTROL); 2599*4887Schin return(GOOD); 2600*4887Schin } 2601*4887Schin 2602*4887Schin 2603*4887Schin #if SHOPT_MULTIBYTE 2604*4887Schin static int _isalph(register int v) 2605*4887Schin { 2606*4887Schin #ifdef _lib_iswalnum 2607*4887Schin return(iswalnum(v) || v=='_'); 2608*4887Schin #else 2609*4887Schin return((v&~STRIP) || isalnum(v) || v=='_'); 2610*4887Schin #endif 2611*4887Schin } 2612*4887Schin 2613*4887Schin 2614*4887Schin static int _isblank(register int v) 2615*4887Schin { 2616*4887Schin return((v&~STRIP)==0 && isspace(v)); 2617*4887Schin } 2618*4887Schin 2619*4887Schin static int _ismetach(register int v) 2620*4887Schin { 2621*4887Schin return((v&~STRIP)==0 && ismeta(v)); 2622*4887Schin } 2623*4887Schin 2624*4887Schin #endif /* SHOPT_MULTIBYTE */ 2625*4887Schin 2626*4887Schin /* 2627*4887Schin * get a character, after ^V processing 2628*4887Schin */ 2629*4887Schin static int getrchar(register Vi_t *vp) 2630*4887Schin { 2631*4887Schin register int c; 2632*4887Schin if((c=ed_getchar(vp->ed,1))== usrlnext) 2633*4887Schin c = ed_getchar(vp->ed,2); 2634*4887Schin return(c); 2635*4887Schin } 2636