10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*3806Scf46844 * Common Development and Distribution License (the "License"). 6*3806Scf46844 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*3806Scf46844 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 270Sstevel@tonic-gate /* All Rights Reserved */ 280Sstevel@tonic-gate 290Sstevel@tonic-gate 300Sstevel@tonic-gate /* Copyright (c) 1981 Regents of the University of California */ 310Sstevel@tonic-gate 320Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 330Sstevel@tonic-gate 340Sstevel@tonic-gate #include "ex.h" 350Sstevel@tonic-gate #include "ex_tty.h" 360Sstevel@tonic-gate #include "ex_vis.h" 370Sstevel@tonic-gate #ifndef PRESUNEUC 380Sstevel@tonic-gate #include <wctype.h> 390Sstevel@tonic-gate /* Undef putchar/getchar if they're defined. */ 400Sstevel@tonic-gate #ifdef putchar 410Sstevel@tonic-gate # undef putchar 420Sstevel@tonic-gate #endif 430Sstevel@tonic-gate #ifdef getchar 440Sstevel@tonic-gate # undef getchar 450Sstevel@tonic-gate #endif 460Sstevel@tonic-gate #endif /* PRESUNEUC */ 470Sstevel@tonic-gate 481406Scf46844 extern size_t strlcpy(char *, const char *, size_t); 491406Scf46844 500Sstevel@tonic-gate /* 510Sstevel@tonic-gate * Low level routines for operations sequences, 520Sstevel@tonic-gate * and mostly, insert mode (and a subroutine 530Sstevel@tonic-gate * to read an input line, including in the echo area.) 540Sstevel@tonic-gate */ 550Sstevel@tonic-gate extern unsigned char *vUA1, *vUA2; /* extern; also in ex_vops.c */ 560Sstevel@tonic-gate extern unsigned char *vUD1, *vUD2; /* extern; also in ex_vops.c */ 570Sstevel@tonic-gate 58*3806Scf46844 #ifdef XPG6 59*3806Scf46844 /* XPG6 assertion 313 & 254 [count]r\n : Also used in ex_vmain.c */ 60*3806Scf46844 extern int redisplay; 61*3806Scf46844 #endif 62*3806Scf46844 63802Scf46844 int vmaxrep(unsigned char, int); 641406Scf46844 static void imultlinerep(int, line *, int, int); 651406Scf46844 static void omultlinerep(int, line *, int); 66*3806Scf46844 #ifdef XPG6 67*3806Scf46844 static void rmultlinerep(int, int); 68*3806Scf46844 #endif 69*3806Scf46844 void fixdisplay(void); 70802Scf46844 710Sstevel@tonic-gate /* 720Sstevel@tonic-gate * Obleeperate characters in hardcopy 730Sstevel@tonic-gate * open with \'s. 740Sstevel@tonic-gate */ 75802Scf46844 void 76802Scf46844 bleep(int i, unsigned char *cp) 770Sstevel@tonic-gate { 780Sstevel@tonic-gate 790Sstevel@tonic-gate i -= lcolumn(nextchr(cp)); 800Sstevel@tonic-gate do 810Sstevel@tonic-gate putchar('\\' | QUOTE); 820Sstevel@tonic-gate while (--i >= 0); 830Sstevel@tonic-gate rubble = 1; 840Sstevel@tonic-gate } 850Sstevel@tonic-gate 860Sstevel@tonic-gate /* 870Sstevel@tonic-gate * Common code for middle part of delete 880Sstevel@tonic-gate * and change operating on parts of lines. 890Sstevel@tonic-gate */ 90802Scf46844 int 91802Scf46844 vdcMID(void) 920Sstevel@tonic-gate { 93802Scf46844 unsigned char *cp; 940Sstevel@tonic-gate 950Sstevel@tonic-gate squish(); 960Sstevel@tonic-gate setLAST(); 970Sstevel@tonic-gate if (FIXUNDO) 980Sstevel@tonic-gate vundkind = VCHNG, CP(vutmp, linebuf); 990Sstevel@tonic-gate if (wcursor < cursor) 1000Sstevel@tonic-gate cp = wcursor, wcursor = cursor, cursor = cp; 1010Sstevel@tonic-gate vUD1 = vUA1 = vUA2 = cursor; vUD2 = wcursor; 102*3806Scf46844 /* 103*3806Scf46844 * XPG6 assertion 273: Set vmcurs so that undo positions the 104*3806Scf46844 * cursor column correctly when we've moved off the initial line 105*3806Scf46844 * that was changed, as with the C, c, and s commands, 106*3806Scf46844 * when G has moved us off the line, or when a 107*3806Scf46844 * multi-line change was done. 108*3806Scf46844 */ 109*3806Scf46844 fixundo(); 1100Sstevel@tonic-gate return (lcolumn(wcursor)); 1110Sstevel@tonic-gate } 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate /* 1140Sstevel@tonic-gate * Take text from linebuf and stick it 1150Sstevel@tonic-gate * in the VBSIZE buffer BUF. Used to save 1160Sstevel@tonic-gate * deleted text of part of line. 1170Sstevel@tonic-gate */ 118802Scf46844 void 119802Scf46844 takeout(unsigned char *BUF) 1200Sstevel@tonic-gate { 121802Scf46844 unsigned char *cp; 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate if (wcursor < linebuf) 1240Sstevel@tonic-gate wcursor = linebuf; 1250Sstevel@tonic-gate if (cursor == wcursor) { 126802Scf46844 (void) beep(); 1270Sstevel@tonic-gate return; 1280Sstevel@tonic-gate } 1290Sstevel@tonic-gate if (wcursor < cursor) { 1300Sstevel@tonic-gate cp = wcursor; 1310Sstevel@tonic-gate wcursor = cursor; 1320Sstevel@tonic-gate cursor = cp; 1330Sstevel@tonic-gate } 1340Sstevel@tonic-gate setBUF(BUF); 1350Sstevel@tonic-gate if ((unsigned char)BUF[128] == 0200) 136802Scf46844 (void) beep(); 1370Sstevel@tonic-gate } 1380Sstevel@tonic-gate 1390Sstevel@tonic-gate /* 1400Sstevel@tonic-gate * Are we at the end of the printed representation of the 1410Sstevel@tonic-gate * line? Used internally in hardcopy open. 1420Sstevel@tonic-gate */ 143802Scf46844 int 144802Scf46844 ateopr(void) 1450Sstevel@tonic-gate { 146802Scf46844 wchar_t i, c; 147802Scf46844 wchar_t *cp = vtube[destline] + destcol; 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate for (i = WCOLS - destcol; i > 0; i--) { 1500Sstevel@tonic-gate c = *cp++; 1510Sstevel@tonic-gate if (c == 0) { 1520Sstevel@tonic-gate /* 1530Sstevel@tonic-gate * Optimization to consider returning early, saving 1540Sstevel@tonic-gate * CPU time. We have to make a special check that 1550Sstevel@tonic-gate * we aren't missing a mode indicator. 1560Sstevel@tonic-gate */ 1570Sstevel@tonic-gate if (destline == WECHO && destcol < WCOLS-11 && vtube[WECHO][WCOLS-20]) 1580Sstevel@tonic-gate return 0; 1590Sstevel@tonic-gate return (1); 1600Sstevel@tonic-gate } 1610Sstevel@tonic-gate if (c != ' ' && (c & QUOTE) == 0) 1620Sstevel@tonic-gate return (0); 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate return (1); 1650Sstevel@tonic-gate } 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate /* 1680Sstevel@tonic-gate * Append. 1690Sstevel@tonic-gate * 1700Sstevel@tonic-gate * This routine handles the top level append, doing work 1710Sstevel@tonic-gate * as each new line comes in, and arranging repeatability. 1720Sstevel@tonic-gate * It also handles append with repeat counts, and calculation 1730Sstevel@tonic-gate * of autoindents for new lines. 1740Sstevel@tonic-gate */ 1750Sstevel@tonic-gate bool vaifirst; 1760Sstevel@tonic-gate bool gobbled; 1770Sstevel@tonic-gate unsigned char *ogcursor; 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate static int INSCDCNT; /* number of ^D's (backtabs) in insertion buffer */ 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate static int inscdcnt; /* 1820Sstevel@tonic-gate * count of ^D's (backtabs) not seen yet when doing 1830Sstevel@tonic-gate * repeat of insertion 1840Sstevel@tonic-gate */ 1850Sstevel@tonic-gate 186802Scf46844 void 187802Scf46844 vappend(int ch, int cnt, int indent) 1880Sstevel@tonic-gate { 189802Scf46844 int i; 190802Scf46844 unsigned char *gcursor; 1910Sstevel@tonic-gate bool escape; 1920Sstevel@tonic-gate int repcnt, savedoomed; 1930Sstevel@tonic-gate short oldhold = hold; 1941406Scf46844 int savecnt = cnt; 1951406Scf46844 line *startsrcline; 1961406Scf46844 int startsrccol, endsrccol; 1971406Scf46844 int gotNL = 0; 1981406Scf46844 int imultlinecnt = 0; 1991406Scf46844 int omultlinecnt = 0; 2001406Scf46844 2011406Scf46844 if ((savecnt > 1) && (ch == 'o' || ch == 'O')) { 2021406Scf46844 omultlinecnt = 1; 2031406Scf46844 } 2041406Scf46844 #ifdef XPG6 2051406Scf46844 if ((savecnt > 1) && (ch == 'a' || ch == 'A' || ch == 'i' || ch == 'I')) 2061406Scf46844 imultlinecnt = 1; 2071406Scf46844 #endif /* XPG6 */ 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate /* 2100Sstevel@tonic-gate * Before a move in hardopen when the line is dirty 2110Sstevel@tonic-gate * or we are in the middle of the printed representation, 2120Sstevel@tonic-gate * we retype the line to the left of the cursor so the 2130Sstevel@tonic-gate * insert looks clean. 2140Sstevel@tonic-gate */ 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate if (ch != 'o' && state == HARDOPEN && (rubble || !ateopr())) { 2170Sstevel@tonic-gate rubble = 1; 2180Sstevel@tonic-gate gcursor = cursor; 2190Sstevel@tonic-gate i = *gcursor; 2200Sstevel@tonic-gate *gcursor = ' '; 2210Sstevel@tonic-gate wcursor = gcursor; 222802Scf46844 (void) vmove(); 2230Sstevel@tonic-gate *gcursor = i; 2240Sstevel@tonic-gate } 225*3806Scf46844 /* 226*3806Scf46844 * If vrep() passed indent = 0, this is the 'r' command, 227*3806Scf46844 * so don't autoindent until the last char. 228*3806Scf46844 */ 2290Sstevel@tonic-gate vaifirst = indent == 0; 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate /* 2320Sstevel@tonic-gate * Handle replace character by (eventually) 2330Sstevel@tonic-gate * limiting the number of input characters allowed 2340Sstevel@tonic-gate * in the vgetline routine. 2350Sstevel@tonic-gate */ 2360Sstevel@tonic-gate if (ch == 'r') 2370Sstevel@tonic-gate repcnt = 2; 2380Sstevel@tonic-gate else 2390Sstevel@tonic-gate repcnt = 0; 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate /* 2420Sstevel@tonic-gate * If an autoindent is specified, then 2430Sstevel@tonic-gate * generate a mixture of blanks to tabs to implement 2440Sstevel@tonic-gate * it and place the cursor after the indent. 2450Sstevel@tonic-gate * Text read by the vgetline routine will be placed in genbuf, 2460Sstevel@tonic-gate * so the indent is generated there. 2470Sstevel@tonic-gate */ 2480Sstevel@tonic-gate if (value(vi_AUTOINDENT) && indent != 0) { 2490Sstevel@tonic-gate unsigned char x; 2500Sstevel@tonic-gate gcursor = genindent(indent); 2510Sstevel@tonic-gate *gcursor = 0; 2520Sstevel@tonic-gate vgotoCL(nqcolumn(lastchr(linebuf, cursor), genbuf)); 2530Sstevel@tonic-gate } else { 2540Sstevel@tonic-gate gcursor = genbuf; 2550Sstevel@tonic-gate *gcursor = 0; 2560Sstevel@tonic-gate if (ch == 'o') 2570Sstevel@tonic-gate vfixcurs(); 2580Sstevel@tonic-gate } 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate /* 2610Sstevel@tonic-gate * Prepare for undo. Pointers delimit inserted portion of line. 2620Sstevel@tonic-gate */ 2630Sstevel@tonic-gate vUA1 = vUA2 = cursor; 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate /* 2660Sstevel@tonic-gate * If we are not in a repeated command and a ^@ comes in 2670Sstevel@tonic-gate * then this means the previous inserted text. 2680Sstevel@tonic-gate * If there is none or it was too long to be saved, 2690Sstevel@tonic-gate * then beep() and also arrange to undo any damage done 2700Sstevel@tonic-gate * so far (e.g. if we are a change.) 2710Sstevel@tonic-gate */ 2720Sstevel@tonic-gate switch (ch) { 2730Sstevel@tonic-gate case 'r': 2740Sstevel@tonic-gate break; 2750Sstevel@tonic-gate case 'a': 2760Sstevel@tonic-gate /* 2770Sstevel@tonic-gate * TRANSLATION_NOTE 2780Sstevel@tonic-gate * "A" is a terse mode message corresponding to 2790Sstevel@tonic-gate * "APPEND MODE". 2800Sstevel@tonic-gate * Translated message of "A" must be 1 character (not byte). 2810Sstevel@tonic-gate * Or, just leave it. 2820Sstevel@tonic-gate */ 2830Sstevel@tonic-gate if (value(vi_TERSE)) { 2840Sstevel@tonic-gate vshowmode(gettext("A")); 2850Sstevel@tonic-gate } else { 2860Sstevel@tonic-gate vshowmode(gettext("APPEND MODE")); 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate break; 2890Sstevel@tonic-gate case 's': 2900Sstevel@tonic-gate /* 2910Sstevel@tonic-gate * TRANSLATION_NOTE 2920Sstevel@tonic-gate * "S" is a terse mode message corresponding to 2930Sstevel@tonic-gate * "SUBSTITUTE MODE". 2940Sstevel@tonic-gate * Translated message of "S" must be 1 character (not byte). 2950Sstevel@tonic-gate * Or, just leave it. 2960Sstevel@tonic-gate */ 2970Sstevel@tonic-gate if (value(vi_TERSE)) { 2980Sstevel@tonic-gate vshowmode(gettext("S")); 2990Sstevel@tonic-gate } else { 3000Sstevel@tonic-gate vshowmode(gettext("SUBSTITUTE MODE")); 3010Sstevel@tonic-gate } 3020Sstevel@tonic-gate break; 3030Sstevel@tonic-gate case 'c': 3040Sstevel@tonic-gate /* 3050Sstevel@tonic-gate * TRANSLATION_NOTE 3060Sstevel@tonic-gate * "C" is a terse mode message corresponding to 3070Sstevel@tonic-gate * "CHANGE MODE". 3080Sstevel@tonic-gate * Translated message of "C" must be 1 character (not byte). 3090Sstevel@tonic-gate * Or, just leave it. 3100Sstevel@tonic-gate */ 3110Sstevel@tonic-gate if (value(vi_TERSE)) { 3120Sstevel@tonic-gate vshowmode(gettext("C")); 3130Sstevel@tonic-gate } else { 3140Sstevel@tonic-gate vshowmode(gettext("CHANGE MODE")); 3150Sstevel@tonic-gate } 3160Sstevel@tonic-gate break; 3170Sstevel@tonic-gate case 'R': 3180Sstevel@tonic-gate /* 3190Sstevel@tonic-gate * TRANSLATION_NOTE 3200Sstevel@tonic-gate * "R" is a terse mode message corresponding to 3210Sstevel@tonic-gate * "REPLACE MODE". 3220Sstevel@tonic-gate * Translated message of "R" must be 1 character (not byte). 3230Sstevel@tonic-gate * Or, just leave it. 3240Sstevel@tonic-gate */ 3250Sstevel@tonic-gate if (value(vi_TERSE)) { 3260Sstevel@tonic-gate vshowmode(gettext("R")); 3270Sstevel@tonic-gate } else { 3280Sstevel@tonic-gate vshowmode(gettext("REPLACE MODE")); 3290Sstevel@tonic-gate } 3300Sstevel@tonic-gate break; 3310Sstevel@tonic-gate case 'o': 3320Sstevel@tonic-gate /* 3330Sstevel@tonic-gate * TRANSLATION_NOTE 3340Sstevel@tonic-gate * "O" is a terse mode message corresponding to 3350Sstevel@tonic-gate * "OPEN MODE". 3360Sstevel@tonic-gate * Translated message of "O" must be 1 character (not byte). 3370Sstevel@tonic-gate * Or, just leave it. 3380Sstevel@tonic-gate */ 3390Sstevel@tonic-gate if (value(vi_TERSE)) { 3400Sstevel@tonic-gate vshowmode(gettext("O")); 3410Sstevel@tonic-gate } else { 3420Sstevel@tonic-gate vshowmode(gettext("OPEN MODE")); 3430Sstevel@tonic-gate } 3440Sstevel@tonic-gate break; 3450Sstevel@tonic-gate case 'i': 3460Sstevel@tonic-gate /* 3470Sstevel@tonic-gate * TRANSLATION_NOTE 3480Sstevel@tonic-gate * "I" is a terse mode message corresponding to 3490Sstevel@tonic-gate * "INSERT MODE" and the following "INPUT MODE". 3500Sstevel@tonic-gate * Translated message of "I" must be 1 character (not byte). 3510Sstevel@tonic-gate * Or, just leave it. 3520Sstevel@tonic-gate */ 3530Sstevel@tonic-gate if (value(vi_TERSE)) { 3540Sstevel@tonic-gate vshowmode(gettext("I")); 3550Sstevel@tonic-gate } else { 3560Sstevel@tonic-gate vshowmode(gettext("INSERT MODE")); 3570Sstevel@tonic-gate } 3580Sstevel@tonic-gate break; 3590Sstevel@tonic-gate default: 3600Sstevel@tonic-gate /* 3610Sstevel@tonic-gate * TRANSLATION_NOTE 3620Sstevel@tonic-gate * "I" is a terse mode message corresponding to 3630Sstevel@tonic-gate * "INPUT MODE" and the previous "INSERT MODE". 3640Sstevel@tonic-gate * Translated message of "I" must be 1 character (not byte). 3650Sstevel@tonic-gate * Or, just leave it. 3660Sstevel@tonic-gate */ 3670Sstevel@tonic-gate if (value(vi_TERSE)) { 3680Sstevel@tonic-gate vshowmode(gettext("I")); 3690Sstevel@tonic-gate } else { 3700Sstevel@tonic-gate vshowmode(gettext("INPUT MODE")); 3710Sstevel@tonic-gate } 3720Sstevel@tonic-gate } 3730Sstevel@tonic-gate ixlatctl(1); 3740Sstevel@tonic-gate if ((vglobp && *vglobp == 0) || peekbr()) { 3750Sstevel@tonic-gate if (INS[128] == 0200) { 376802Scf46844 (void) beep(); 3770Sstevel@tonic-gate if (!splitw) 3780Sstevel@tonic-gate ungetkey('u'); 3790Sstevel@tonic-gate doomed = 0; 3800Sstevel@tonic-gate hold = oldhold; 3810Sstevel@tonic-gate return; 3820Sstevel@tonic-gate } 3830Sstevel@tonic-gate /* 3840Sstevel@tonic-gate * Unread input from INS. 3850Sstevel@tonic-gate * An escape will be generated at end of string. 3860Sstevel@tonic-gate * Hold off n^^2 type update on dumb terminals. 3870Sstevel@tonic-gate */ 3880Sstevel@tonic-gate vglobp = INS; 3890Sstevel@tonic-gate inscdcnt = INSCDCNT; 3900Sstevel@tonic-gate hold |= HOLDQIK; 3910Sstevel@tonic-gate } else if (vglobp == 0) { 3920Sstevel@tonic-gate /* 3930Sstevel@tonic-gate * Not a repeated command, get 3940Sstevel@tonic-gate * a new inserted text for repeat. 3950Sstevel@tonic-gate */ 3960Sstevel@tonic-gate INS[0] = 0; 3970Sstevel@tonic-gate INS[128] = 0; 3980Sstevel@tonic-gate INSCDCNT = 0; 3990Sstevel@tonic-gate } 4000Sstevel@tonic-gate 4010Sstevel@tonic-gate /* 4020Sstevel@tonic-gate * For wrapmargin to hack away second space after a '.' 4030Sstevel@tonic-gate * when the first space caused a line break we keep 4040Sstevel@tonic-gate * track that this happened in gobblebl, which says 4050Sstevel@tonic-gate * to gobble up a blank silently. 4060Sstevel@tonic-gate */ 4070Sstevel@tonic-gate gobblebl = 0; 4080Sstevel@tonic-gate 4091406Scf46844 startsrcline = dot; 4101406Scf46844 startsrccol = cursor - linebuf; 4111406Scf46844 4120Sstevel@tonic-gate /* 4130Sstevel@tonic-gate * Text gathering loop. 4140Sstevel@tonic-gate * New text goes into genbuf starting at gcursor. 4150Sstevel@tonic-gate * cursor preserves place in linebuf where text will eventually go. 4160Sstevel@tonic-gate */ 4170Sstevel@tonic-gate if (*cursor == 0 || state == CRTOPEN) 4180Sstevel@tonic-gate hold |= HOLDROL; 4190Sstevel@tonic-gate for (;;) { 4200Sstevel@tonic-gate if (ch == 'r' && repcnt == 0) 4210Sstevel@tonic-gate escape = 0; 4220Sstevel@tonic-gate else { 4230Sstevel@tonic-gate ixlatctl(1); 424*3806Scf46844 /* 425*3806Scf46844 * When vgetline() returns, gcursor is 426*3806Scf46844 * pointing to '\0' and vgetline() has 427*3806Scf46844 * read an ESCAPE or NL. 428*3806Scf46844 */ 4290Sstevel@tonic-gate gcursor = vgetline(repcnt, gcursor, &escape, ch); 4301406Scf46844 if (escape == '\n') { 4311406Scf46844 gotNL = 1; 432*3806Scf46844 #ifdef XPG6 433*3806Scf46844 if (ch == 'r') { 434*3806Scf46844 /* 435*3806Scf46844 * XPG6 assertion 313 [count]r\n : 436*3806Scf46844 * Arrange to set cursor correctly. 437*3806Scf46844 */ 438*3806Scf46844 endsrccol = gcursor - genbuf - 1; 439*3806Scf46844 } 440*3806Scf46844 #endif /* XPG6 */ 4411406Scf46844 } else { 4421406Scf46844 /* 4431406Scf46844 * Upon escape, gcursor is pointing to '\0' 4441406Scf46844 * terminating the string in genbuf. 4451406Scf46844 */ 4461406Scf46844 endsrccol = gcursor - genbuf - 1; 4471406Scf46844 } 4480Sstevel@tonic-gate ixlatctl(0); 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate /* 4510Sstevel@tonic-gate * After an append, stick information 4520Sstevel@tonic-gate * about the ^D's and ^^D's and 0^D's in 4530Sstevel@tonic-gate * the repeated text buffer so repeated 4540Sstevel@tonic-gate * inserts of stuff indented with ^D as backtab's 4550Sstevel@tonic-gate * can work. 4560Sstevel@tonic-gate */ 4570Sstevel@tonic-gate if (HADUP) 4580Sstevel@tonic-gate addtext("^"); 4590Sstevel@tonic-gate else if (HADZERO) 4600Sstevel@tonic-gate addtext("0"); 4610Sstevel@tonic-gate if(!vglobp) 4620Sstevel@tonic-gate INSCDCNT = CDCNT; 4630Sstevel@tonic-gate while (CDCNT > 0) { 4640Sstevel@tonic-gate addtext("\004"); 4650Sstevel@tonic-gate CDCNT--; 4660Sstevel@tonic-gate } 4670Sstevel@tonic-gate if (gobbled) 4680Sstevel@tonic-gate addtext(" "); 4690Sstevel@tonic-gate addtext(ogcursor); 4700Sstevel@tonic-gate } 4710Sstevel@tonic-gate repcnt = 0; 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate /* 4740Sstevel@tonic-gate * Smash the generated and preexisting indents together 4750Sstevel@tonic-gate * and generate one cleanly made out of tabs and spaces 476*3806Scf46844 * if we are using autoindent and this isn't 'r' command. 4770Sstevel@tonic-gate */ 4780Sstevel@tonic-gate if (!vaifirst && value(vi_AUTOINDENT)) { 4790Sstevel@tonic-gate i = fixindent(indent); 4800Sstevel@tonic-gate if (!HADUP) 4810Sstevel@tonic-gate indent = i; 4820Sstevel@tonic-gate gcursor = strend(genbuf); 4830Sstevel@tonic-gate } 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate /* 4861406Scf46844 * Set cnt to 1 to avoid repeating the text on the same line. 4871406Scf46844 * Do this for commands 'i', 'I', 'a', and 'A', if we're 4881406Scf46844 * inserting anything with a newline for XPG6. Always do this 4891406Scf46844 * for commands 'o' and 'O'. 4901406Scf46844 */ 4911406Scf46844 if ((imultlinecnt && gotNL) || omultlinecnt) { 4921406Scf46844 cnt = 1; 4931406Scf46844 } 4941406Scf46844 4951406Scf46844 /* 4960Sstevel@tonic-gate * Limit the repetition count based on maximum 4970Sstevel@tonic-gate * possible line length; do output implied 4980Sstevel@tonic-gate * by further count (> 1) and cons up the new line 4990Sstevel@tonic-gate * in linebuf. 5000Sstevel@tonic-gate */ 5010Sstevel@tonic-gate cnt = vmaxrep(ch, cnt); 502*3806Scf46844 /* 503*3806Scf46844 * cursor points to linebuf 504*3806Scf46844 * Copy remaining old text (cursor) in original 505*3806Scf46844 * line to after new text (gcursor + 1) in genbuf. 506*3806Scf46844 */ 5070Sstevel@tonic-gate CP(gcursor + 1, cursor); 508*3806Scf46844 /* 509*3806Scf46844 * For [count] r \n command, when replacing [count] chars 510*3806Scf46844 * with '\n', this loop replaces [count] chars with "". 511*3806Scf46844 */ 5120Sstevel@tonic-gate do { 513*3806Scf46844 /* cp new text (genbuf) into linebuf (cursor) */ 5140Sstevel@tonic-gate CP(cursor, genbuf); 5150Sstevel@tonic-gate if (cnt > 1) { 5160Sstevel@tonic-gate int oldhold = hold; 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate Outchar = vinschar; 5190Sstevel@tonic-gate hold |= HOLDQIK; 520802Scf46844 viprintf("%s", genbuf); 5210Sstevel@tonic-gate hold = oldhold; 5220Sstevel@tonic-gate Outchar = vputchar; 5230Sstevel@tonic-gate } 524*3806Scf46844 /* point cursor after new text in linebuf */ 5250Sstevel@tonic-gate cursor += gcursor - genbuf; 5260Sstevel@tonic-gate } while (--cnt > 0); 5270Sstevel@tonic-gate endim(); 5280Sstevel@tonic-gate vUA2 = cursor; 529*3806Scf46844 /* add the remaining old text after the cursor */ 5300Sstevel@tonic-gate if (escape != '\n') 5310Sstevel@tonic-gate CP(cursor, gcursor + 1); 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate /* 5340Sstevel@tonic-gate * If doomed characters remain, clobber them, 5350Sstevel@tonic-gate * and reopen the line to get the display exact. 536*3806Scf46844 * eg. c$ to change to end of line 5370Sstevel@tonic-gate */ 5380Sstevel@tonic-gate if (state != HARDOPEN) { 5390Sstevel@tonic-gate DEPTH(vcline) = 0; 5400Sstevel@tonic-gate savedoomed = doomed; 5410Sstevel@tonic-gate if (doomed > 0) { 542802Scf46844 int cind = cindent(); 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate physdc(cind, cind + doomed); 5450Sstevel@tonic-gate doomed = 0; 5460Sstevel@tonic-gate } 5470Sstevel@tonic-gate if(MB_CUR_MAX > 1) 5480Sstevel@tonic-gate rewrite = _ON; 5490Sstevel@tonic-gate i = vreopen(LINE(vcline), lineDOT(), vcline); 5500Sstevel@tonic-gate if(MB_CUR_MAX > 1) 5510Sstevel@tonic-gate rewrite = _OFF; 5520Sstevel@tonic-gate #ifdef TRACE 5530Sstevel@tonic-gate if (trace) 5540Sstevel@tonic-gate fprintf(trace, "restoring doomed from %d to %d\n", doomed, savedoomed); 5550Sstevel@tonic-gate #endif 5560Sstevel@tonic-gate if (ch == 'R') 5570Sstevel@tonic-gate doomed = savedoomed; 5580Sstevel@tonic-gate } 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate /* 561*3806Scf46844 * Unless we are continuing on to another line 562*3806Scf46844 * (got a NL), break out of the for loop (got 563*3806Scf46844 * an ESCAPE). 5640Sstevel@tonic-gate */ 5650Sstevel@tonic-gate if (escape != '\n') { 5660Sstevel@tonic-gate vshowmode(""); 5670Sstevel@tonic-gate break; 5680Sstevel@tonic-gate } 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate /* 5710Sstevel@tonic-gate * Set up for the new line. 5720Sstevel@tonic-gate * First save the current line, then construct a new 5730Sstevel@tonic-gate * first image for the continuation line consisting 5740Sstevel@tonic-gate * of any new autoindent plus the pushed ahead text. 5750Sstevel@tonic-gate */ 5760Sstevel@tonic-gate killU(); 5770Sstevel@tonic-gate addtext(gobblebl ? " " : "\n"); 578*3806Scf46844 /* save vutmp (for undo state) into temp file */ 5790Sstevel@tonic-gate vsave(); 5800Sstevel@tonic-gate cnt = 1; 5810Sstevel@tonic-gate if (value(vi_AUTOINDENT)) { 5820Sstevel@tonic-gate if (value(vi_LISP)) 5830Sstevel@tonic-gate indent = lindent(dot + 1); 5840Sstevel@tonic-gate else 5850Sstevel@tonic-gate if (!HADUP && vaifirst) 5860Sstevel@tonic-gate indent = whitecnt(linebuf); 5870Sstevel@tonic-gate vaifirst = 0; 5880Sstevel@tonic-gate strcLIN(vpastwh(gcursor + 1)); 5890Sstevel@tonic-gate gcursor = genindent(indent); 5900Sstevel@tonic-gate *gcursor = 0; 5910Sstevel@tonic-gate if (gcursor + strlen(linebuf) > &genbuf[LBSIZE - 2]) 5920Sstevel@tonic-gate gcursor = genbuf; 5930Sstevel@tonic-gate CP(gcursor, linebuf); 5940Sstevel@tonic-gate } else { 595*3806Scf46844 /* 596*3806Scf46844 * Put gcursor at start of genbuf to wipe 597*3806Scf46844 * out previous line in preparation for 598*3806Scf46844 * the next vgetline() loop. 599*3806Scf46844 */ 6000Sstevel@tonic-gate CP(genbuf, gcursor + 1); 6010Sstevel@tonic-gate gcursor = genbuf; 6020Sstevel@tonic-gate } 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate /* 6050Sstevel@tonic-gate * If we started out as a single line operation and are now 6060Sstevel@tonic-gate * turning into a multi-line change, then we had better yank 6070Sstevel@tonic-gate * out dot before it changes so that undo will work 6080Sstevel@tonic-gate * correctly later. 6090Sstevel@tonic-gate */ 6100Sstevel@tonic-gate if (FIXUNDO && vundkind == VCHNG) { 6110Sstevel@tonic-gate vremote(1, yank, 0); 6120Sstevel@tonic-gate undap1--; 6130Sstevel@tonic-gate } 6140Sstevel@tonic-gate 6150Sstevel@tonic-gate /* 6160Sstevel@tonic-gate * Now do the append of the new line in the buffer, 617*3806Scf46844 * and update the display, ie: append genbuf to 618*3806Scf46844 * the file after dot. If slowopen 6190Sstevel@tonic-gate * we don't do very much. 6200Sstevel@tonic-gate */ 6210Sstevel@tonic-gate vdoappend(genbuf); 6220Sstevel@tonic-gate vundkind = VMANYINS; 6230Sstevel@tonic-gate vcline++; 6240Sstevel@tonic-gate if (state != VISUAL) 6250Sstevel@tonic-gate vshow(dot, NOLINE); 6260Sstevel@tonic-gate else { 6270Sstevel@tonic-gate i += LINE(vcline - 1); 6280Sstevel@tonic-gate vopen(dot, i); 6290Sstevel@tonic-gate if (value(vi_SLOWOPEN)) 6300Sstevel@tonic-gate vscrap(); 6310Sstevel@tonic-gate else 6320Sstevel@tonic-gate vsync1(LINE(vcline)); 6330Sstevel@tonic-gate } 6340Sstevel@tonic-gate switch (ch) { 6350Sstevel@tonic-gate case 'r': 6360Sstevel@tonic-gate break; 6370Sstevel@tonic-gate case 'a': 6380Sstevel@tonic-gate if (value(vi_TERSE)) { 6390Sstevel@tonic-gate vshowmode(gettext("A")); 6400Sstevel@tonic-gate } else { 6410Sstevel@tonic-gate vshowmode(gettext("APPEND MODE")); 6420Sstevel@tonic-gate } 6430Sstevel@tonic-gate break; 6440Sstevel@tonic-gate case 's': 6450Sstevel@tonic-gate if (value(vi_TERSE)) { 6460Sstevel@tonic-gate vshowmode(gettext("S")); 6470Sstevel@tonic-gate } else { 6480Sstevel@tonic-gate vshowmode(gettext("SUBSTITUTE MODE")); 6490Sstevel@tonic-gate } 6500Sstevel@tonic-gate break; 6510Sstevel@tonic-gate case 'c': 6520Sstevel@tonic-gate if (value(vi_TERSE)) { 6530Sstevel@tonic-gate vshowmode(gettext("C")); 6540Sstevel@tonic-gate } else { 6550Sstevel@tonic-gate vshowmode(gettext("CHANGE MODE")); 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate break; 6580Sstevel@tonic-gate case 'R': 6590Sstevel@tonic-gate if (value(vi_TERSE)) { 6600Sstevel@tonic-gate vshowmode(gettext("R")); 6610Sstevel@tonic-gate } else { 6620Sstevel@tonic-gate vshowmode(gettext("REPLACE MODE")); 6630Sstevel@tonic-gate } 6640Sstevel@tonic-gate break; 6650Sstevel@tonic-gate case 'i': 6660Sstevel@tonic-gate if (value(vi_TERSE)) { 6670Sstevel@tonic-gate vshowmode(gettext("I")); 6680Sstevel@tonic-gate } else { 6690Sstevel@tonic-gate vshowmode(gettext("INSERT MODE")); 6700Sstevel@tonic-gate } 6710Sstevel@tonic-gate break; 6720Sstevel@tonic-gate case 'o': 6730Sstevel@tonic-gate if (value(vi_TERSE)) { 6740Sstevel@tonic-gate vshowmode(gettext("O")); 6750Sstevel@tonic-gate } else { 6760Sstevel@tonic-gate vshowmode(gettext("OPEN MODE")); 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate break; 6790Sstevel@tonic-gate default: 6800Sstevel@tonic-gate if (value(vi_TERSE)) { 6810Sstevel@tonic-gate vshowmode(gettext("I")); 6820Sstevel@tonic-gate } else { 6830Sstevel@tonic-gate vshowmode(gettext("INPUT MODE")); 6840Sstevel@tonic-gate } 6850Sstevel@tonic-gate } 6860Sstevel@tonic-gate strcLIN(gcursor); 687*3806Scf46844 /* zero genbuf */ 6880Sstevel@tonic-gate *gcursor = 0; 6890Sstevel@tonic-gate cursor = linebuf; 6900Sstevel@tonic-gate vgotoCL(nqcolumn(cursor - 1, genbuf)); 6911406Scf46844 } /* end for (;;) loop in vappend() */ 6921406Scf46844 6931406Scf46844 if (imultlinecnt && gotNL) { 6941406Scf46844 imultlinerep(savecnt, startsrcline, startsrccol, endsrccol); 6951406Scf46844 } else if (omultlinecnt) { 6961406Scf46844 omultlinerep(savecnt, startsrcline, endsrccol); 697*3806Scf46844 #ifdef XPG6 698*3806Scf46844 } else if (savecnt > 1 && ch == 'r' && gotNL) { 699*3806Scf46844 /* 700*3806Scf46844 * XPG6 assertion 313 & 254 : Position cursor for [count]r\n 701*3806Scf46844 * then insert [count -1] newlines. 702*3806Scf46844 */ 703*3806Scf46844 endsrccol = gcursor - genbuf - 1; 704*3806Scf46844 rmultlinerep(savecnt, endsrccol); 705*3806Scf46844 #endif /* XPG6 */ 7060Sstevel@tonic-gate } 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate /* 7090Sstevel@tonic-gate * All done with insertion, position the cursor 7100Sstevel@tonic-gate * and sync the screen. 7110Sstevel@tonic-gate */ 7120Sstevel@tonic-gate hold = oldhold; 7131406Scf46844 if ((imultlinecnt && gotNL) || omultlinecnt) { 7141406Scf46844 fixdisplay(); 715*3806Scf46844 #ifdef XPG6 716*3806Scf46844 } else if (savecnt > 1 && ch == 'r' && gotNL) { 717*3806Scf46844 fixdisplay(); 718*3806Scf46844 /* 719*3806Scf46844 * XPG6 assertion 313 & 254 [count]r\n : Set flag to call 720*3806Scf46844 * fixdisplay() after operate() has finished. To be sure that 721*3806Scf46844 * the text (after the last \n followed by an indent) is always 722*3806Scf46844 * displayed, fixdisplay() is called right before getting 723*3806Scf46844 * the next command. 724*3806Scf46844 */ 725*3806Scf46844 redisplay = 1; 726*3806Scf46844 #endif /* XPG6 */ 7271406Scf46844 } else if (cursor > linebuf) { 7280Sstevel@tonic-gate cursor = lastchr(linebuf, cursor); 729*3806Scf46844 #ifdef XPG6 730*3806Scf46844 /* 731*3806Scf46844 * XPG6 assertion 313 & 254 [count]r\n : 732*3806Scf46844 * For 'r' command, when the replacement char causes new 733*3806Scf46844 * lines to be created, point cursor to first non-blank. 734*3806Scf46844 * The old code, ie: cursor = lastchr(linebuf, cursor); 735*3806Scf46844 * set cursor to the blank before the first non-blank 736*3806Scf46844 * for r\n 737*3806Scf46844 */ 738*3806Scf46844 if (ch == 'r' && gotNL && isblank((int)*cursor)) 739*3806Scf46844 ++cursor; 740*3806Scf46844 #endif /* XPG6 */ 7411406Scf46844 } 7420Sstevel@tonic-gate if (state != HARDOPEN) 7430Sstevel@tonic-gate vsyncCL(); 7440Sstevel@tonic-gate else if (cursor > linebuf) 7450Sstevel@tonic-gate back1(); 7460Sstevel@tonic-gate doomed = 0; 7470Sstevel@tonic-gate wcursor = cursor; 748802Scf46844 (void) vmove(); 7490Sstevel@tonic-gate } 7500Sstevel@tonic-gate 7510Sstevel@tonic-gate /* 7521406Scf46844 * XPG6 7531406Scf46844 * To repeat multi-line input for [count]a, [count]A, [count]i, [count]I, 7541406Scf46844 * or a subsequent [count]. : 7551406Scf46844 * insert input count-1 more times. 7561406Scf46844 */ 7571406Scf46844 7581406Scf46844 static void 7591406Scf46844 imultlinerep(int savecnt, line *startsrcline, int startsrccol, int endsrccol) 7601406Scf46844 { 7611406Scf46844 int tmpcnt = 2; /* 1st insert counts as 1 repeat */ 7621406Scf46844 line *srcline, *endsrcline; 7631406Scf46844 size_t destsize = LBSIZE - endsrccol - 1; 7641406Scf46844 7651406Scf46844 endsrcline = dot; 7661406Scf46844 7671406Scf46844 /* Save linebuf into temp file before moving off the line. */ 7681406Scf46844 vsave(); 7691406Scf46844 7701406Scf46844 /* 7711406Scf46844 * At this point the temp file contains the first iteration of 7721406Scf46844 * a multi-line insert, and we need to repeat it savecnt - 1 7731406Scf46844 * more times in the temp file. dot is the last line in the 7741406Scf46844 * first iteration of the insert. Decrement dot so that 7751406Scf46844 * vdoappend() will append each new line before the last line. 7761406Scf46844 */ 7771406Scf46844 --dot; 7781406Scf46844 --vcline; 7791406Scf46844 /* 7801406Scf46844 * Use genbuf to rebuild the last line in the 1st iteration 7811406Scf46844 * of the repeated insert, then copy this line to the temp file. 7821406Scf46844 */ 7831406Scf46844 (void) strlcpy((char *)genbuf, (char *)linebuf, sizeof (genbuf)); 7841406Scf46844 getline(*startsrcline); 7851406Scf46844 if (strlcpy((char *)(genbuf + endsrccol + 1), 7861406Scf46844 (char *)(linebuf + startsrccol), destsize) >= destsize) { 7871406Scf46844 error(gettext("Line too long")); 7881406Scf46844 } 7891406Scf46844 vdoappend(genbuf); 7901406Scf46844 vcline++; 7911406Scf46844 /* 7921406Scf46844 * Loop from the second line of the first iteration 7931406Scf46844 * through endsrcline, appending after dot. 7941406Scf46844 */ 7951406Scf46844 ++startsrcline; 7961406Scf46844 7971406Scf46844 while (tmpcnt <= savecnt) { 7981406Scf46844 for (srcline = startsrcline; srcline <= endsrcline; 7991406Scf46844 ++srcline) { 8001406Scf46844 if ((tmpcnt == savecnt) && 8011406Scf46844 (srcline == endsrcline)) { 8021406Scf46844 /* 8031406Scf46844 * The last line is already in place, 8041406Scf46844 * just make it the current line. 8051406Scf46844 */ 8061406Scf46844 vcline++; 8071406Scf46844 dot++; 8081406Scf46844 getDOT(); 8091406Scf46844 cursor = linebuf + endsrccol; 8101406Scf46844 } else { 8111406Scf46844 getline(*srcline); 8121406Scf46844 /* copy linebuf to temp file */ 8131406Scf46844 vdoappend(linebuf); 8141406Scf46844 vcline++; 8151406Scf46844 } 8161406Scf46844 } 8171406Scf46844 ++tmpcnt; 8181406Scf46844 } 8191406Scf46844 } 8201406Scf46844 8211406Scf46844 /* 8221406Scf46844 * To repeat input for [count]o, [count]O, or a subsequent [count]. : 8231406Scf46844 * append input count-1 more times to the end of the already added 8241406Scf46844 * text, each time starting on a new line. 8251406Scf46844 */ 8261406Scf46844 8271406Scf46844 static void 8281406Scf46844 omultlinerep(int savecnt, line *startsrcline, int endsrccol) 8291406Scf46844 { 8301406Scf46844 int tmpcnt = 2; /* 1st insert counts as 1 repeat */ 8311406Scf46844 line *srcline, *endsrcline; 8321406Scf46844 8331406Scf46844 endsrcline = dot; 8341406Scf46844 /* Save linebuf into temp file before moving off the line. */ 8351406Scf46844 vsave(); 8361406Scf46844 8371406Scf46844 /* 8381406Scf46844 * Loop from the first line of the first iteration 8391406Scf46844 * through endsrcline, appending after dot. 8401406Scf46844 */ 8411406Scf46844 while (tmpcnt <= savecnt) { 8421406Scf46844 for (srcline = startsrcline; srcline <= endsrcline; ++srcline) { 8431406Scf46844 getline(*srcline); 8441406Scf46844 /* copy linebuf to temp file */ 8451406Scf46844 vdoappend(linebuf); 8461406Scf46844 vcline++; 8471406Scf46844 } 8481406Scf46844 ++tmpcnt; 8491406Scf46844 } 8501406Scf46844 cursor = linebuf + endsrccol; 8511406Scf46844 } 8521406Scf46844 853*3806Scf46844 #ifdef XPG6 854*3806Scf46844 /* 855*3806Scf46844 * XPG6 assertion 313 & 254 : To repeat '\n' for [count]r\n 856*3806Scf46844 * insert '\n' savecnt-1 more times before the already added '\n'. 857*3806Scf46844 */ 858*3806Scf46844 859*3806Scf46844 static void 860*3806Scf46844 rmultlinerep(int savecnt, int endsrccol) 861*3806Scf46844 { 862*3806Scf46844 int tmpcnt = 2; /* 1st replacement counts as 1 repeat */ 863*3806Scf46844 864*3806Scf46844 /* Save linebuf into temp file before moving off the line. */ 865*3806Scf46844 vsave(); 866*3806Scf46844 /* 867*3806Scf46844 * At this point the temp file contains the line followed by '\n', 868*3806Scf46844 * which is preceded by indentation if autoindent is set. 869*3806Scf46844 * '\n' must be repeated [savecnt - 1] more times in the temp file. 870*3806Scf46844 * dot is the current line containing the '\n'. Decrement dot so that 871*3806Scf46844 * vdoappend() will append each '\n' before the current '\n'. 872*3806Scf46844 * This will allow only the last line to contain any autoindent 873*3806Scf46844 * characters. 874*3806Scf46844 */ 875*3806Scf46844 --dot; 876*3806Scf46844 --vcline; 877*3806Scf46844 878*3806Scf46844 /* 879*3806Scf46844 * Append after dot. 880*3806Scf46844 */ 881*3806Scf46844 while (tmpcnt <= savecnt) { 882*3806Scf46844 linebuf[0] = '\0'; 883*3806Scf46844 /* append linebuf below current line in temp file */ 884*3806Scf46844 vdoappend(linebuf); 885*3806Scf46844 vcline++; 886*3806Scf46844 ++tmpcnt; 887*3806Scf46844 } 888*3806Scf46844 /* set the current line to the line after the last '\n' */ 889*3806Scf46844 ++dot; 890*3806Scf46844 ++vcline; 891*3806Scf46844 /* point cursor after (linebuf + endsrccol) */ 892*3806Scf46844 vcursaft(linebuf + endsrccol); 893*3806Scf46844 } 894*3806Scf46844 #endif /* XPG6 */ 895*3806Scf46844 8961406Scf46844 /* 8971406Scf46844 * Similiar to a ctrl-l, however always vrepaint() in case the last line 8981406Scf46844 * of the repeat would exceed the bottom of the screen. 8991406Scf46844 */ 9001406Scf46844 901*3806Scf46844 void 9021406Scf46844 fixdisplay(void) 9031406Scf46844 { 9041406Scf46844 vclear(); 9051406Scf46844 vdirty(0, vcnt); 9061406Scf46844 if (state != VISUAL) { 9071406Scf46844 vclean(); 9081406Scf46844 vcnt = 0; 9091406Scf46844 vmoveto(dot, cursor, 0); 9101406Scf46844 } else { 9111406Scf46844 vredraw(WTOP); 9121406Scf46844 vrepaint(cursor); 9131406Scf46844 vfixcurs(); 9141406Scf46844 } 9151406Scf46844 } 9161406Scf46844 9171406Scf46844 /* 9180Sstevel@tonic-gate * Subroutine for vgetline to back up a single character position, 9190Sstevel@tonic-gate * backwards around end of lines (vgoto can't hack columns which are 9200Sstevel@tonic-gate * less than 0 in general). 9210Sstevel@tonic-gate */ 922802Scf46844 void 923802Scf46844 back1(void) 9240Sstevel@tonic-gate { 9250Sstevel@tonic-gate 9260Sstevel@tonic-gate vgoto(destline - 1, WCOLS + destcol - 1); 9270Sstevel@tonic-gate } 9280Sstevel@tonic-gate 9290Sstevel@tonic-gate /* 9300Sstevel@tonic-gate * Get a line into genbuf after gcursor. 9310Sstevel@tonic-gate * Cnt limits the number of input characters 9320Sstevel@tonic-gate * accepted and is used for handling the replace 9330Sstevel@tonic-gate * single character command. Aescaped is the location 9340Sstevel@tonic-gate * where we stick a termination indicator (whether we 9350Sstevel@tonic-gate * ended with an ESCAPE or a newline/return. 9360Sstevel@tonic-gate * 9370Sstevel@tonic-gate * We do erase-kill type processing here and also 9380Sstevel@tonic-gate * are careful about the way we do this so that it is 9390Sstevel@tonic-gate * repeatable. (I.e. so that your kill doesn't happen, 9400Sstevel@tonic-gate * when you repeat an insert if it was escaped with \ the 9410Sstevel@tonic-gate * first time you did it. commch is the command character 9420Sstevel@tonic-gate * involved, including the prompt for readline. 9430Sstevel@tonic-gate */ 9440Sstevel@tonic-gate unsigned char * 9450Sstevel@tonic-gate vgetline(cnt, gcursor, aescaped, commch) 9460Sstevel@tonic-gate int cnt; 947802Scf46844 unsigned char *gcursor; 9480Sstevel@tonic-gate bool *aescaped; 9490Sstevel@tonic-gate unsigned char commch; 9500Sstevel@tonic-gate { 951802Scf46844 int c, ch; 952802Scf46844 unsigned char *cp, *pcp; 9530Sstevel@tonic-gate int x, y, iwhite, backsl=0; 9540Sstevel@tonic-gate unsigned char *iglobp; 9550Sstevel@tonic-gate int (*OO)() = Outchar; 9560Sstevel@tonic-gate int length, width; 9570Sstevel@tonic-gate unsigned char multic[MULTI_BYTE_MAX+1]; 9580Sstevel@tonic-gate wchar_t wchar = 0; 9590Sstevel@tonic-gate unsigned char *p; 9600Sstevel@tonic-gate int len; 9610Sstevel@tonic-gate 9620Sstevel@tonic-gate 9630Sstevel@tonic-gate /* 9640Sstevel@tonic-gate * Clear the output state and counters 9650Sstevel@tonic-gate * for autoindent backwards motion (counts of ^D, etc.) 9660Sstevel@tonic-gate * Remember how much white space at beginning of line so 9670Sstevel@tonic-gate * as not to allow backspace over autoindent. 9680Sstevel@tonic-gate */ 9690Sstevel@tonic-gate 9700Sstevel@tonic-gate *aescaped = 0; 9710Sstevel@tonic-gate ogcursor = gcursor; 9720Sstevel@tonic-gate flusho(); 9730Sstevel@tonic-gate CDCNT = 0; 9740Sstevel@tonic-gate HADUP = 0; 9750Sstevel@tonic-gate HADZERO = 0; 9760Sstevel@tonic-gate gobbled = 0; 9770Sstevel@tonic-gate iwhite = whitecnt(genbuf); 9780Sstevel@tonic-gate iglobp = vglobp; 9790Sstevel@tonic-gate 9800Sstevel@tonic-gate /* 9810Sstevel@tonic-gate * Clear abbreviation recursive-use count 9820Sstevel@tonic-gate */ 9830Sstevel@tonic-gate abbrepcnt = 0; 9840Sstevel@tonic-gate /* 9850Sstevel@tonic-gate * Carefully avoid using vinschar in the echo area. 9860Sstevel@tonic-gate */ 9870Sstevel@tonic-gate if (splitw) 9880Sstevel@tonic-gate Outchar = vputchar; 9890Sstevel@tonic-gate else { 9900Sstevel@tonic-gate Outchar = vinschar; 9910Sstevel@tonic-gate vprepins(); 9920Sstevel@tonic-gate } 9930Sstevel@tonic-gate for (;;) { 9940Sstevel@tonic-gate length = 0; 9950Sstevel@tonic-gate backsl = 0; 9960Sstevel@tonic-gate if (gobblebl) 9970Sstevel@tonic-gate gobblebl--; 9980Sstevel@tonic-gate if (cnt != 0) { 9990Sstevel@tonic-gate cnt--; 10000Sstevel@tonic-gate if (cnt == 0) 10010Sstevel@tonic-gate goto vadone; 10020Sstevel@tonic-gate } 10030Sstevel@tonic-gate c = getkey(); 10040Sstevel@tonic-gate if (c != ATTN) 10050Sstevel@tonic-gate c &= 0377; 10060Sstevel@tonic-gate ch = c; 10070Sstevel@tonic-gate maphopcnt = 0; 10080Sstevel@tonic-gate if (vglobp == 0 && Peekkey == 0 && commch != 'r') 10090Sstevel@tonic-gate while ((ch = map(c, immacs, commch)) != c) { 10100Sstevel@tonic-gate c = ch; 10110Sstevel@tonic-gate if (!value(vi_REMAP)) 10120Sstevel@tonic-gate break; 10130Sstevel@tonic-gate if (++maphopcnt > 256) 10140Sstevel@tonic-gate error(gettext("Infinite macro loop")); 10150Sstevel@tonic-gate } 10160Sstevel@tonic-gate if (!iglobp) { 10170Sstevel@tonic-gate 10180Sstevel@tonic-gate /* 10190Sstevel@tonic-gate * Erase-kill type processing. 10200Sstevel@tonic-gate * Only happens if we were not reading 10210Sstevel@tonic-gate * from untyped input when we started. 10220Sstevel@tonic-gate * Map users erase to ^H, kill to -1 for switch. 10230Sstevel@tonic-gate */ 10240Sstevel@tonic-gate if (c == tty.c_cc[VERASE]) 10250Sstevel@tonic-gate c = CTRL('h'); 10260Sstevel@tonic-gate else if (c == tty.c_cc[VKILL]) 10270Sstevel@tonic-gate c = -1; 10280Sstevel@tonic-gate switch (c) { 10290Sstevel@tonic-gate 10300Sstevel@tonic-gate /* 10310Sstevel@tonic-gate * ^? Interrupt drops you back to visual 10320Sstevel@tonic-gate * command mode with an unread interrupt 10330Sstevel@tonic-gate * still in the input buffer. 10340Sstevel@tonic-gate * 10350Sstevel@tonic-gate * ^\ Quit does the same as interrupt. 10360Sstevel@tonic-gate * If you are a ex command rather than 10370Sstevel@tonic-gate * a vi command this will drop you 10380Sstevel@tonic-gate * back to command mode for sure. 10390Sstevel@tonic-gate */ 10400Sstevel@tonic-gate case ATTN: 10410Sstevel@tonic-gate case QUIT: 10420Sstevel@tonic-gate ungetkey(c); 10430Sstevel@tonic-gate goto vadone; 10440Sstevel@tonic-gate 10450Sstevel@tonic-gate /* 10460Sstevel@tonic-gate * ^H Backs up a character in the input. 10470Sstevel@tonic-gate * 10480Sstevel@tonic-gate * BUG: Can't back around line boundaries. 10490Sstevel@tonic-gate * This is hard because stuff has 10500Sstevel@tonic-gate * already been saved for repeat. 10510Sstevel@tonic-gate */ 10520Sstevel@tonic-gate case CTRL('h'): 10530Sstevel@tonic-gate bakchar: 10540Sstevel@tonic-gate cp = lastchr(ogcursor, gcursor); 10550Sstevel@tonic-gate if (cp < ogcursor) { 10560Sstevel@tonic-gate if (splitw) { 10570Sstevel@tonic-gate /* 10580Sstevel@tonic-gate * Backspacing over readecho 10590Sstevel@tonic-gate * prompt. Pretend delete but 10600Sstevel@tonic-gate * don't beep. 10610Sstevel@tonic-gate */ 10620Sstevel@tonic-gate ungetkey(c); 10630Sstevel@tonic-gate goto vadone; 10640Sstevel@tonic-gate } 1065802Scf46844 (void) beep(); 10660Sstevel@tonic-gate continue; 10670Sstevel@tonic-gate } 10680Sstevel@tonic-gate goto vbackup; 10690Sstevel@tonic-gate 10700Sstevel@tonic-gate /* 10710Sstevel@tonic-gate * ^W Back up a white/non-white word. 10720Sstevel@tonic-gate */ 10730Sstevel@tonic-gate case CTRL('w'): 10740Sstevel@tonic-gate wdkind = 1; 10750Sstevel@tonic-gate for (cp = gcursor; cp > ogcursor && isspace(cp[-1]); cp--) 10760Sstevel@tonic-gate continue; 10770Sstevel@tonic-gate pcp = lastchr(ogcursor, cp); 10780Sstevel@tonic-gate for (c = wordch(pcp); 10790Sstevel@tonic-gate cp > ogcursor && wordof(c, pcp); cp = pcp, pcp = lastchr(ogcursor, cp)) 10800Sstevel@tonic-gate continue; 10810Sstevel@tonic-gate goto vbackup; 10820Sstevel@tonic-gate 10830Sstevel@tonic-gate /* 10840Sstevel@tonic-gate * users kill Kill input on this line, back to 10850Sstevel@tonic-gate * the autoindent. 10860Sstevel@tonic-gate */ 10870Sstevel@tonic-gate case -1: 10880Sstevel@tonic-gate cp = ogcursor; 10890Sstevel@tonic-gate vbackup: 10900Sstevel@tonic-gate if (cp == gcursor) { 1091802Scf46844 (void) beep(); 10920Sstevel@tonic-gate continue; 10930Sstevel@tonic-gate } 10940Sstevel@tonic-gate endim(); 10950Sstevel@tonic-gate *cp = 0; 10960Sstevel@tonic-gate c = cindent(); 10970Sstevel@tonic-gate vgotoCL(nqcolumn(lastchr(linebuf, cursor), genbuf)); 10980Sstevel@tonic-gate 10990Sstevel@tonic-gate if (doomed >= 0) 11000Sstevel@tonic-gate doomed += c - cindent(); 11010Sstevel@tonic-gate gcursor = cp; 11020Sstevel@tonic-gate continue; 11030Sstevel@tonic-gate 11040Sstevel@tonic-gate /* 11050Sstevel@tonic-gate * \ Followed by erase or kill 11060Sstevel@tonic-gate * maps to just the erase or kill. 11070Sstevel@tonic-gate */ 11080Sstevel@tonic-gate case '\\': 11090Sstevel@tonic-gate x = destcol, y = destline; 11100Sstevel@tonic-gate putchar('\\'); 11110Sstevel@tonic-gate vcsync(); 11120Sstevel@tonic-gate c = getkey(); 11130Sstevel@tonic-gate if (c == tty.c_cc[VERASE] 11140Sstevel@tonic-gate || c == tty.c_cc[VKILL]) 11150Sstevel@tonic-gate { 11160Sstevel@tonic-gate vgoto(y, x); 11170Sstevel@tonic-gate if (doomed >= 0) 11180Sstevel@tonic-gate doomed++; 11190Sstevel@tonic-gate multic[0] = wchar = c; 11200Sstevel@tonic-gate length = 1; 11210Sstevel@tonic-gate goto def; 11220Sstevel@tonic-gate } 11230Sstevel@tonic-gate ungetkey(c), c = '\\'; 11240Sstevel@tonic-gate backsl = 1; 11250Sstevel@tonic-gate break; 11260Sstevel@tonic-gate 11270Sstevel@tonic-gate /* 11280Sstevel@tonic-gate * ^Q Super quote following character 11290Sstevel@tonic-gate * Only ^@ is verboten (trapped at 11300Sstevel@tonic-gate * a lower level) and \n forces a line 11310Sstevel@tonic-gate * split so doesn't really go in. 11320Sstevel@tonic-gate * 11330Sstevel@tonic-gate * ^V Synonym for ^Q 11340Sstevel@tonic-gate */ 11350Sstevel@tonic-gate case CTRL('q'): 11360Sstevel@tonic-gate case CTRL('v'): 11370Sstevel@tonic-gate x = destcol, y = destline; 11380Sstevel@tonic-gate putchar('^'); 11390Sstevel@tonic-gate vgoto(y, x); 11400Sstevel@tonic-gate c = getkey(); 11410Sstevel@tonic-gate #ifdef USG 11420Sstevel@tonic-gate if (c == ATTN) 11430Sstevel@tonic-gate c = tty.c_cc[VINTR]; 11440Sstevel@tonic-gate #endif 11450Sstevel@tonic-gate if (c != NL) { 11460Sstevel@tonic-gate if (doomed >= 0) 11470Sstevel@tonic-gate doomed++; 11480Sstevel@tonic-gate multic[0] = wchar = c; 11490Sstevel@tonic-gate length = 1; 11500Sstevel@tonic-gate goto def; 11510Sstevel@tonic-gate } 11520Sstevel@tonic-gate break; 11530Sstevel@tonic-gate } 11540Sstevel@tonic-gate } 11550Sstevel@tonic-gate 11560Sstevel@tonic-gate /* 11570Sstevel@tonic-gate * If we get a blank not in the echo area 11580Sstevel@tonic-gate * consider splitting the window in the wrapmargin. 11590Sstevel@tonic-gate */ 11600Sstevel@tonic-gate if(!backsl) { 11610Sstevel@tonic-gate ungetkey(c); 11620Sstevel@tonic-gate if((length = _mbftowc((char *)multic, &wchar, getkey, &Peekkey)) <= 0) { 1163802Scf46844 (void) beep(); 11640Sstevel@tonic-gate continue; 11650Sstevel@tonic-gate } 11660Sstevel@tonic-gate } else { 11670Sstevel@tonic-gate length = 1; 11680Sstevel@tonic-gate multic[0] = '\\'; 11690Sstevel@tonic-gate } 11700Sstevel@tonic-gate 11710Sstevel@tonic-gate if (c != NL && !splitw) { 11720Sstevel@tonic-gate if (c == ' ' && gobblebl) { 11730Sstevel@tonic-gate gobbled = 1; 11740Sstevel@tonic-gate continue; 11750Sstevel@tonic-gate } 11760Sstevel@tonic-gate if ((width = wcwidth(wchar)) <= 0) 11770Sstevel@tonic-gate width = (wchar <= 0177 ? 1 : 4); 11780Sstevel@tonic-gate if (value(vi_WRAPMARGIN) && 11790Sstevel@tonic-gate (outcol + width - 1 >= OCOLUMNS - value(vi_WRAPMARGIN) || 11800Sstevel@tonic-gate backsl && outcol==0) && 11810Sstevel@tonic-gate commch != 'r') { 11820Sstevel@tonic-gate /* 11830Sstevel@tonic-gate * At end of word and hit wrapmargin. 11840Sstevel@tonic-gate * Move the word to next line and keep going. 11850Sstevel@tonic-gate */ 11860Sstevel@tonic-gate unsigned char *wp; 11870Sstevel@tonic-gate int bytelength; 11880Sstevel@tonic-gate #ifndef PRESUNEUC 11890Sstevel@tonic-gate unsigned char *tgcursor; 11900Sstevel@tonic-gate wchar_t wc1, wc2; 11910Sstevel@tonic-gate tgcursor = gcursor; 11920Sstevel@tonic-gate #endif /* PRESUNEUC */ 11930Sstevel@tonic-gate wdkind = 1; 11940Sstevel@tonic-gate strncpy(gcursor, multic, length); 11950Sstevel@tonic-gate gcursor += length; 11960Sstevel@tonic-gate if (backsl) { 11970Sstevel@tonic-gate #ifdef PRESUNEUC 11980Sstevel@tonic-gate if((length = mbftowc((char *)multic, &wchar, getkey, &Peekkey)) <= 0) { 11990Sstevel@tonic-gate #else 12000Sstevel@tonic-gate if((length = _mbftowc((char *)multic, &wchar, getkey, &Peekkey)) <= 0) { 12010Sstevel@tonic-gate #endif /* PRESUNEUC */ 1202802Scf46844 (void) beep(); 12030Sstevel@tonic-gate continue; 12040Sstevel@tonic-gate } 12050Sstevel@tonic-gate strncpy(gcursor, multic, length); 12060Sstevel@tonic-gate gcursor += length; 12070Sstevel@tonic-gate } 12080Sstevel@tonic-gate *gcursor = 0; 12090Sstevel@tonic-gate /* 12100Sstevel@tonic-gate * Find end of previous word if we are past it. 12110Sstevel@tonic-gate */ 12120Sstevel@tonic-gate for (cp=gcursor; cp>ogcursor && isspace(cp[-1]); cp--) 12130Sstevel@tonic-gate ; 12140Sstevel@tonic-gate #ifdef PRESUNEUC 12150Sstevel@tonic-gate /* find screen width of previous word */ 12160Sstevel@tonic-gate width = 0; 12170Sstevel@tonic-gate for(wp = cp; *wp; ) 12180Sstevel@tonic-gate #else 12190Sstevel@tonic-gate /* count screen width of pending characters */ 12200Sstevel@tonic-gate width = 0; 12210Sstevel@tonic-gate for(wp = tgcursor; wp < cp;) 12220Sstevel@tonic-gate #endif /* PRESUNEUC */ 12230Sstevel@tonic-gate if((bytelength = mbtowc(&wchar, (char *)wp, MULTI_BYTE_MAX)) < 0) { 12240Sstevel@tonic-gate width+=4; 12250Sstevel@tonic-gate wp++; 12260Sstevel@tonic-gate } else { 12270Sstevel@tonic-gate int curwidth = wcwidth(wchar); 12280Sstevel@tonic-gate if(curwidth <= 0) 12290Sstevel@tonic-gate width += (*wp < 0200 ? 2 : 4); 12300Sstevel@tonic-gate else 12310Sstevel@tonic-gate width += curwidth; 12320Sstevel@tonic-gate wp += bytelength; 12330Sstevel@tonic-gate } 12340Sstevel@tonic-gate 12350Sstevel@tonic-gate #ifdef PRESUNEUC 12360Sstevel@tonic-gate if (outcol+(backsl?OCOLUMNS:0) - width >= OCOLUMNS - value(vi_WRAPMARGIN)) { 12370Sstevel@tonic-gate #else 12380Sstevel@tonic-gate if (outcol+(backsl?OCOLUMNS:0) + width -1 >= OCOLUMNS - value(vi_WRAPMARGIN)) { 12390Sstevel@tonic-gate #endif /* PRESUNEUC */ 12400Sstevel@tonic-gate /* 12410Sstevel@tonic-gate * Find beginning of previous word. 12420Sstevel@tonic-gate */ 12430Sstevel@tonic-gate #ifdef PRESUNEUC 12440Sstevel@tonic-gate for (; cp>ogcursor && !isspace(cp[-1]); cp--) 12450Sstevel@tonic-gate ; 12460Sstevel@tonic-gate #else 12470Sstevel@tonic-gate wc1 = wc2 = 0; 12480Sstevel@tonic-gate while (cp>ogcursor) { 12490Sstevel@tonic-gate if (isspace(cp[-1])) { 12500Sstevel@tonic-gate break; 12510Sstevel@tonic-gate } 12520Sstevel@tonic-gate if (!multibyte) { 12530Sstevel@tonic-gate cp--; 12540Sstevel@tonic-gate continue; 12550Sstevel@tonic-gate } 12560Sstevel@tonic-gate wp = (unsigned char *)(cp - 12570Sstevel@tonic-gate MB_CUR_MAX); 12580Sstevel@tonic-gate if (wp < ogcursor) 12590Sstevel@tonic-gate wp = ogcursor; 12600Sstevel@tonic-gate while (cp > wp) { 12610Sstevel@tonic-gate /* 7tabs */if (wc2) { 12620Sstevel@tonic-gate /* 7tabs */ if ((bytelength = mbtowc(&wc1, (char *)wp, cp-wp)) != cp-wp) { 12630Sstevel@tonic-gate /* 7tabs */ wp++; 12640Sstevel@tonic-gate /* 7tabs */ wc1 = 0; 12650Sstevel@tonic-gate /* 7tabs */ continue; 12660Sstevel@tonic-gate /* 7tabs */ } 12670Sstevel@tonic-gate /* 7tabs */} else { 12680Sstevel@tonic-gate /* 7tabs */ if ((bytelength = mbtowc(&wc2, (char *)wp, cp-wp)) != cp-wp) { 12690Sstevel@tonic-gate /* 7tabs */ wp++; 12700Sstevel@tonic-gate /* 7tabs */ wc2 = 0; 12710Sstevel@tonic-gate /* 7tabs */ continue; 12720Sstevel@tonic-gate /* 7tabs */ } 12730Sstevel@tonic-gate /* 7tabs */} 12740Sstevel@tonic-gate /* 7tabs */if (wc1) { 12750Sstevel@tonic-gate /* 7tabs */ if (wdbdg && (!iswascii(wc1) || !iswascii(wc2))) { 12760Sstevel@tonic-gate /* 7tabs */ if ((*wdbdg)(wc1, wc2, 2) < 5) { 12770Sstevel@tonic-gate /* 7tabs */ goto ws; 12780Sstevel@tonic-gate /* 7tabs */ } 12790Sstevel@tonic-gate /* 7tabs */ } 12800Sstevel@tonic-gate /* 7tabs */ wc2 = wc1; 12810Sstevel@tonic-gate /* 7tabs */ wc1 = 0; 12820Sstevel@tonic-gate /* 7tabs */ cp -= bytelength - 1; 12830Sstevel@tonic-gate /* 7tabs */ break; 12840Sstevel@tonic-gate /* 7tabs */} else { 12850Sstevel@tonic-gate /* 7tabs */ cp -= bytelength - 1; 12860Sstevel@tonic-gate /* 7tabs */ break; 12870Sstevel@tonic-gate /* 7tabs */} 12880Sstevel@tonic-gate } 12890Sstevel@tonic-gate cp--; 12900Sstevel@tonic-gate } 12910Sstevel@tonic-gate ws: 12920Sstevel@tonic-gate #endif /* PRESUNEUC */ 12930Sstevel@tonic-gate if (cp <= ogcursor) { 12940Sstevel@tonic-gate /* 12950Sstevel@tonic-gate * There is a single word that 12960Sstevel@tonic-gate * is too long to fit. Just 12970Sstevel@tonic-gate * let it pass, but beep for 12980Sstevel@tonic-gate * each new letter to warn 12990Sstevel@tonic-gate * the luser. 13000Sstevel@tonic-gate */ 13010Sstevel@tonic-gate gcursor -= length; 13020Sstevel@tonic-gate c = *gcursor; 13030Sstevel@tonic-gate *gcursor = 0; 1304802Scf46844 (void) beep(); 13050Sstevel@tonic-gate goto dontbreak; 13060Sstevel@tonic-gate } 13070Sstevel@tonic-gate /* 13080Sstevel@tonic-gate * Save it for next line. 13090Sstevel@tonic-gate */ 13100Sstevel@tonic-gate macpush(cp, 0); 13110Sstevel@tonic-gate #ifdef PRESUNEUC 13120Sstevel@tonic-gate cp--; 13130Sstevel@tonic-gate #endif /* PRESUNEUC */ 13140Sstevel@tonic-gate } 13150Sstevel@tonic-gate macpush("\n", 0); 13160Sstevel@tonic-gate /* 13170Sstevel@tonic-gate * Erase white space before the word. 13180Sstevel@tonic-gate */ 13190Sstevel@tonic-gate while (cp > ogcursor && isspace(cp[-1])) 13200Sstevel@tonic-gate cp--; /* skip blank */ 13210Sstevel@tonic-gate gobblebl = 3; 13220Sstevel@tonic-gate goto vbackup; 13230Sstevel@tonic-gate } 13240Sstevel@tonic-gate dontbreak:; 13250Sstevel@tonic-gate } 13260Sstevel@tonic-gate 13270Sstevel@tonic-gate /* 13280Sstevel@tonic-gate * Word abbreviation mode. 13290Sstevel@tonic-gate */ 13300Sstevel@tonic-gate if (anyabbrs && gcursor > ogcursor && !wordch(multic) && wordch(lastchr(ogcursor, gcursor))) { 13310Sstevel@tonic-gate int wdtype, abno; 13320Sstevel@tonic-gate 13330Sstevel@tonic-gate multic[length] = 0; 13340Sstevel@tonic-gate wdkind = 1; 13350Sstevel@tonic-gate cp = lastchr(ogcursor, gcursor); 13360Sstevel@tonic-gate pcp = lastchr(ogcursor, cp); 13370Sstevel@tonic-gate for (wdtype = wordch(pcp); 13380Sstevel@tonic-gate cp > ogcursor && wordof(wdtype, pcp); cp = pcp, pcp = lastchr(ogcursor, pcp)) 13390Sstevel@tonic-gate ; 13400Sstevel@tonic-gate *gcursor = 0; 13410Sstevel@tonic-gate for (abno=0; abbrevs[abno].mapto; abno++) { 13420Sstevel@tonic-gate if (eq(cp, abbrevs[abno].cap)) { 13430Sstevel@tonic-gate if(abbrepcnt == 0) { 13440Sstevel@tonic-gate if(reccnt(abbrevs[abno].cap, abbrevs[abno].mapto)) 13450Sstevel@tonic-gate abbrepcnt = 1; 13460Sstevel@tonic-gate macpush(multic, 0); 13470Sstevel@tonic-gate macpush(abbrevs[abno].mapto); 13480Sstevel@tonic-gate goto vbackup; 13490Sstevel@tonic-gate } else 13500Sstevel@tonic-gate abbrepcnt = 0; 13510Sstevel@tonic-gate } 13520Sstevel@tonic-gate } 13530Sstevel@tonic-gate } 13540Sstevel@tonic-gate 13550Sstevel@tonic-gate switch (c) { 13560Sstevel@tonic-gate 13570Sstevel@tonic-gate /* 13580Sstevel@tonic-gate * ^M Except in repeat maps to \n. 13590Sstevel@tonic-gate */ 13600Sstevel@tonic-gate case CR: 13610Sstevel@tonic-gate if (vglobp) { 13620Sstevel@tonic-gate multic[0] = wchar = c; 13630Sstevel@tonic-gate length = 1; 13640Sstevel@tonic-gate goto def; 13650Sstevel@tonic-gate } 13660Sstevel@tonic-gate c = '\n'; 13670Sstevel@tonic-gate /* presto chango ... */ 13680Sstevel@tonic-gate 13690Sstevel@tonic-gate /* 13700Sstevel@tonic-gate * \n Start new line. 13710Sstevel@tonic-gate */ 13720Sstevel@tonic-gate case NL: 13730Sstevel@tonic-gate *aescaped = c; 13740Sstevel@tonic-gate goto vadone; 13750Sstevel@tonic-gate 13760Sstevel@tonic-gate /* 13770Sstevel@tonic-gate * escape End insert unless repeat and more to repeat. 13780Sstevel@tonic-gate */ 13790Sstevel@tonic-gate case ESCAPE: 13800Sstevel@tonic-gate if (lastvgk) { 13810Sstevel@tonic-gate multic[0] = wchar = c; 13820Sstevel@tonic-gate length = 1; 13830Sstevel@tonic-gate goto def; 13840Sstevel@tonic-gate } 13850Sstevel@tonic-gate goto vadone; 13860Sstevel@tonic-gate 13870Sstevel@tonic-gate /* 13880Sstevel@tonic-gate * ^D Backtab. 13890Sstevel@tonic-gate * ^T Software forward tab. 13900Sstevel@tonic-gate * 13910Sstevel@tonic-gate * Unless in repeat where this means these 13920Sstevel@tonic-gate * were superquoted in. 13930Sstevel@tonic-gate */ 13940Sstevel@tonic-gate case CTRL('t'): 13950Sstevel@tonic-gate if (vglobp) { 13960Sstevel@tonic-gate multic[0] = wchar = c; 13970Sstevel@tonic-gate length = 1; 13980Sstevel@tonic-gate goto def; 13990Sstevel@tonic-gate } 14000Sstevel@tonic-gate /* fall into ... */ 14010Sstevel@tonic-gate 14020Sstevel@tonic-gate *gcursor = 0; 14030Sstevel@tonic-gate cp = vpastwh(genbuf); 14040Sstevel@tonic-gate c = whitecnt(genbuf); 14050Sstevel@tonic-gate if (ch == CTRL('t')) { 14060Sstevel@tonic-gate /* 14070Sstevel@tonic-gate * ^t just generates new indent replacing 14080Sstevel@tonic-gate * current white space rounded up to soft 14090Sstevel@tonic-gate * tab stop increment. 14100Sstevel@tonic-gate */ 14110Sstevel@tonic-gate if (cp != gcursor) 14120Sstevel@tonic-gate /* 14130Sstevel@tonic-gate * BUG: Don't hack ^T except 14140Sstevel@tonic-gate * right after initial 14150Sstevel@tonic-gate * white space. 14160Sstevel@tonic-gate */ 14170Sstevel@tonic-gate continue; 14180Sstevel@tonic-gate cp = genindent(iwhite = backtab(c + value(vi_SHIFTWIDTH) + 1)); 14190Sstevel@tonic-gate ogcursor = cp; 14200Sstevel@tonic-gate goto vbackup; 14210Sstevel@tonic-gate } 14220Sstevel@tonic-gate /* 14230Sstevel@tonic-gate * ^D works only if we are at the (end of) the 14240Sstevel@tonic-gate * generated autoindent. We count the ^D for repeat 14250Sstevel@tonic-gate * purposes. 14260Sstevel@tonic-gate */ 14270Sstevel@tonic-gate case CTRL('d'): 14280Sstevel@tonic-gate /* check if ^d was superquoted in */ 14290Sstevel@tonic-gate if(vglobp && inscdcnt <= 0) { 14300Sstevel@tonic-gate multic[0] = wchar = c; 14310Sstevel@tonic-gate length = 1; 14320Sstevel@tonic-gate goto def; 14330Sstevel@tonic-gate } 14340Sstevel@tonic-gate if(vglobp) 14350Sstevel@tonic-gate inscdcnt--; 14360Sstevel@tonic-gate *gcursor = 0; 14370Sstevel@tonic-gate cp = vpastwh(genbuf); 14380Sstevel@tonic-gate c = whitecnt(genbuf); 14390Sstevel@tonic-gate if (c == iwhite && c != 0) 14400Sstevel@tonic-gate if (cp == gcursor) { 14410Sstevel@tonic-gate iwhite = backtab(c); 14420Sstevel@tonic-gate CDCNT++; 14430Sstevel@tonic-gate ogcursor = cp = genindent(iwhite); 14440Sstevel@tonic-gate goto vbackup; 14450Sstevel@tonic-gate } else if (&cp[1] == gcursor && 14460Sstevel@tonic-gate (*cp == '^' || *cp == '0')) { 14470Sstevel@tonic-gate /* 14480Sstevel@tonic-gate * ^^D moves to margin, then back 14490Sstevel@tonic-gate * to current indent on next line. 14500Sstevel@tonic-gate * 14510Sstevel@tonic-gate * 0^D moves to margin and then 14520Sstevel@tonic-gate * stays there. 14530Sstevel@tonic-gate */ 14540Sstevel@tonic-gate HADZERO = *cp == '0'; 14550Sstevel@tonic-gate ogcursor = cp = genbuf; 14560Sstevel@tonic-gate HADUP = 1 - HADZERO; 14570Sstevel@tonic-gate CDCNT = 1; 14580Sstevel@tonic-gate endim(); 14590Sstevel@tonic-gate back1(); 1460802Scf46844 (void) vputchar(' '); 14610Sstevel@tonic-gate goto vbackup; 14620Sstevel@tonic-gate } 14630Sstevel@tonic-gate 14640Sstevel@tonic-gate if (vglobp && vglobp - iglobp >= 2) { 14650Sstevel@tonic-gate if ((p = vglobp - MB_CUR_MAX) < iglobp) 14660Sstevel@tonic-gate p = iglobp; 14670Sstevel@tonic-gate for ( ; p < &vglobp[-2]; p += len) { 14680Sstevel@tonic-gate if ((len = mblen((char *)p, MB_CUR_MAX)) <= 0) 14690Sstevel@tonic-gate len = 1; 14700Sstevel@tonic-gate } 14710Sstevel@tonic-gate if ((p == &vglobp[-2]) && 14720Sstevel@tonic-gate (*p == '^' || *p == '0') && 14730Sstevel@tonic-gate gcursor == ogcursor + 1) 14740Sstevel@tonic-gate goto bakchar; 14750Sstevel@tonic-gate } 14760Sstevel@tonic-gate continue; 14770Sstevel@tonic-gate 14780Sstevel@tonic-gate default: 14790Sstevel@tonic-gate /* 14800Sstevel@tonic-gate * Possibly discard control inputs. 14810Sstevel@tonic-gate */ 14820Sstevel@tonic-gate if (!vglobp && junk(c)) { 1483802Scf46844 (void) beep(); 14840Sstevel@tonic-gate continue; 14850Sstevel@tonic-gate } 14860Sstevel@tonic-gate def: 14870Sstevel@tonic-gate if (!backsl) { 14880Sstevel@tonic-gate putchar(wchar); 14890Sstevel@tonic-gate flush(); 14900Sstevel@tonic-gate } 14910Sstevel@tonic-gate if (gcursor + length - 1 > &genbuf[LBSIZE - 2]) 14920Sstevel@tonic-gate error(gettext("Line too long")); 14930Sstevel@tonic-gate (void)strncpy(gcursor, multic, length); 14940Sstevel@tonic-gate gcursor += length; 14950Sstevel@tonic-gate vcsync(); 14960Sstevel@tonic-gate if (value(vi_SHOWMATCH) && !iglobp) 14970Sstevel@tonic-gate if (c == ')' || c == '}') 14980Sstevel@tonic-gate lsmatch(gcursor); 14990Sstevel@tonic-gate continue; 15000Sstevel@tonic-gate } 15010Sstevel@tonic-gate } 15020Sstevel@tonic-gate vadone: 15030Sstevel@tonic-gate *gcursor = 0; 15040Sstevel@tonic-gate if (Outchar != termchar) 15050Sstevel@tonic-gate Outchar = OO; 15060Sstevel@tonic-gate endim(); 15070Sstevel@tonic-gate return (gcursor); 15080Sstevel@tonic-gate } 15090Sstevel@tonic-gate 15100Sstevel@tonic-gate int vgetsplit(); 15110Sstevel@tonic-gate unsigned char *vsplitpt; 15120Sstevel@tonic-gate 15130Sstevel@tonic-gate /* 15140Sstevel@tonic-gate * Append the line in buffer at lp 15150Sstevel@tonic-gate * to the buffer after dot. 15160Sstevel@tonic-gate */ 1517802Scf46844 void 1518802Scf46844 vdoappend(unsigned char *lp) 15190Sstevel@tonic-gate { 1520802Scf46844 int oing = inglobal; 15210Sstevel@tonic-gate 15220Sstevel@tonic-gate vsplitpt = lp; 15230Sstevel@tonic-gate inglobal = 1; 15240Sstevel@tonic-gate (void)append(vgetsplit, dot); 15250Sstevel@tonic-gate inglobal = oing; 15260Sstevel@tonic-gate } 15270Sstevel@tonic-gate 15280Sstevel@tonic-gate /* 15290Sstevel@tonic-gate * Subroutine for vdoappend to pass to append. 15300Sstevel@tonic-gate */ 1531802Scf46844 int 1532802Scf46844 vgetsplit(void) 15330Sstevel@tonic-gate { 15340Sstevel@tonic-gate 15350Sstevel@tonic-gate if (vsplitpt == 0) 15360Sstevel@tonic-gate return (EOF); 15370Sstevel@tonic-gate strcLIN(vsplitpt); 15380Sstevel@tonic-gate vsplitpt = 0; 15390Sstevel@tonic-gate return (0); 15400Sstevel@tonic-gate } 15410Sstevel@tonic-gate 15420Sstevel@tonic-gate /* 15430Sstevel@tonic-gate * Vmaxrep determines the maximum repetition factor 15440Sstevel@tonic-gate * allowed that will yield total line length less than 15450Sstevel@tonic-gate * LBSIZE characters and also does hacks for the R command. 15460Sstevel@tonic-gate */ 1547802Scf46844 int 1548802Scf46844 vmaxrep(unsigned char ch, int cnt) 15490Sstevel@tonic-gate { 1550802Scf46844 int len; 15510Sstevel@tonic-gate unsigned char *cp; 15520Sstevel@tonic-gate int repcnt, oldcnt, replen; 15530Sstevel@tonic-gate if (cnt > LBSIZE - 2) 15540Sstevel@tonic-gate cnt = LBSIZE - 2; 15550Sstevel@tonic-gate if (ch == 'R') { 15560Sstevel@tonic-gate len = strlen(cursor); 15570Sstevel@tonic-gate oldcnt = 0; 15580Sstevel@tonic-gate for(cp = cursor; *cp; ) { 15590Sstevel@tonic-gate oldcnt++; 15600Sstevel@tonic-gate cp = nextchr(cp); 15610Sstevel@tonic-gate } 15620Sstevel@tonic-gate repcnt = 0; 15630Sstevel@tonic-gate for(cp = genbuf; *cp; ) { 15640Sstevel@tonic-gate repcnt++; 15650Sstevel@tonic-gate cp = nextchr(cp); 15660Sstevel@tonic-gate } 15670Sstevel@tonic-gate /* 15680Sstevel@tonic-gate * if number of characters in replacement string 15690Sstevel@tonic-gate * (repcnt) is less than number of characters following 15700Sstevel@tonic-gate * cursor (oldcnt), find end of repcnt 15710Sstevel@tonic-gate * characters after cursor 15720Sstevel@tonic-gate */ 15730Sstevel@tonic-gate if(repcnt < oldcnt) { 15740Sstevel@tonic-gate for(cp = cursor; repcnt > 0; repcnt--) 15750Sstevel@tonic-gate cp = nextchr(cp); 15760Sstevel@tonic-gate len = cp - cursor; 15770Sstevel@tonic-gate } 15780Sstevel@tonic-gate CP(cursor, cursor + len); 15790Sstevel@tonic-gate vUD2 += len; 15800Sstevel@tonic-gate } 15810Sstevel@tonic-gate len = strlen(linebuf); 15820Sstevel@tonic-gate replen = strlen(genbuf); 15830Sstevel@tonic-gate if (len + cnt * replen <= LBSIZE - 2) 15840Sstevel@tonic-gate return (cnt); 15850Sstevel@tonic-gate cnt = (LBSIZE - 2 - len) / replen; 15860Sstevel@tonic-gate if (cnt == 0) { 15870Sstevel@tonic-gate vsave(); 15880Sstevel@tonic-gate error(gettext("Line too long")); 15890Sstevel@tonic-gate } 15900Sstevel@tonic-gate return (cnt); 15910Sstevel@tonic-gate } 15920Sstevel@tonic-gate 15930Sstevel@tonic-gate /* 15940Sstevel@tonic-gate * Determine how many occurrences of word 'CAP' are in 'MAPTO'. To be 15950Sstevel@tonic-gate * considered an occurrence there must be both a nonword-prefix, a 15960Sstevel@tonic-gate * complete match of 'CAP' within 'MAPTO', and a nonword-suffix. 15970Sstevel@tonic-gate * Note that the beginning and end of 'MAPTO' are considered to be 15980Sstevel@tonic-gate * valid nonword delimiters. 15990Sstevel@tonic-gate */ 1600802Scf46844 int 1601802Scf46844 reccnt(unsigned char *cap, unsigned char *mapto) 16020Sstevel@tonic-gate { 1603802Scf46844 int i, cnt, final; 16040Sstevel@tonic-gate 16050Sstevel@tonic-gate cnt = 0; 16060Sstevel@tonic-gate final = strlen(mapto) - strlen(cap); 16070Sstevel@tonic-gate 16080Sstevel@tonic-gate for (i=0; i <= final; i++) 16090Sstevel@tonic-gate if ((strncmp(cap, mapto+i, strlen(cap)) == 0) /* match */ 16100Sstevel@tonic-gate && (i == 0 || !wordch(&mapto[i-1])) /* prefix ok */ 16110Sstevel@tonic-gate && (i == final || !wordch(&mapto[i+strlen(cap)]))) /* suffix ok */ 16120Sstevel@tonic-gate cnt++; 16130Sstevel@tonic-gate return (cnt); 16140Sstevel@tonic-gate } 16150Sstevel@tonic-gate 1616