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
53806Scf46844 * Common Development and Distribution License (the "License").
63806Scf46844 * 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 */
21*13093SRoger.Faulkner@Oracle.COM
220Sstevel@tonic-gate /*
23*13093SRoger.Faulkner@Oracle.COM * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
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 #include "ex.h"
330Sstevel@tonic-gate #include "ex_tty.h"
340Sstevel@tonic-gate #include "ex_vis.h"
350Sstevel@tonic-gate #ifndef PRESUNEUC
360Sstevel@tonic-gate #include <wctype.h>
370Sstevel@tonic-gate /* Undef putchar/getchar if they're defined. */
380Sstevel@tonic-gate #ifdef putchar
390Sstevel@tonic-gate # undef putchar
400Sstevel@tonic-gate #endif
410Sstevel@tonic-gate #ifdef getchar
420Sstevel@tonic-gate # undef getchar
430Sstevel@tonic-gate #endif
440Sstevel@tonic-gate #endif /* PRESUNEUC */
450Sstevel@tonic-gate
461406Scf46844 extern size_t strlcpy(char *, const char *, size_t);
471406Scf46844
480Sstevel@tonic-gate /*
490Sstevel@tonic-gate * Low level routines for operations sequences,
500Sstevel@tonic-gate * and mostly, insert mode (and a subroutine
510Sstevel@tonic-gate * to read an input line, including in the echo area.)
520Sstevel@tonic-gate */
530Sstevel@tonic-gate extern unsigned char *vUA1, *vUA2; /* extern; also in ex_vops.c */
540Sstevel@tonic-gate extern unsigned char *vUD1, *vUD2; /* extern; also in ex_vops.c */
550Sstevel@tonic-gate
563806Scf46844 #ifdef XPG6
573806Scf46844 /* XPG6 assertion 313 & 254 [count]r\n : Also used in ex_vmain.c */
583806Scf46844 extern int redisplay;
593806Scf46844 #endif
603806Scf46844
61802Scf46844 int vmaxrep(unsigned char, int);
621406Scf46844 static void imultlinerep(int, line *, int, int);
631406Scf46844 static void omultlinerep(int, line *, int);
643806Scf46844 #ifdef XPG6
653806Scf46844 static void rmultlinerep(int, int);
663806Scf46844 #endif
673806Scf46844 void fixdisplay(void);
68802Scf46844
690Sstevel@tonic-gate /*
700Sstevel@tonic-gate * Obleeperate characters in hardcopy
710Sstevel@tonic-gate * open with \'s.
720Sstevel@tonic-gate */
73802Scf46844 void
bleep(int i,unsigned char * cp)74802Scf46844 bleep(int i, unsigned char *cp)
750Sstevel@tonic-gate {
760Sstevel@tonic-gate
770Sstevel@tonic-gate i -= lcolumn(nextchr(cp));
780Sstevel@tonic-gate do
790Sstevel@tonic-gate putchar('\\' | QUOTE);
800Sstevel@tonic-gate while (--i >= 0);
810Sstevel@tonic-gate rubble = 1;
820Sstevel@tonic-gate }
830Sstevel@tonic-gate
840Sstevel@tonic-gate /*
850Sstevel@tonic-gate * Common code for middle part of delete
860Sstevel@tonic-gate * and change operating on parts of lines.
870Sstevel@tonic-gate */
88802Scf46844 int
vdcMID(void)89802Scf46844 vdcMID(void)
900Sstevel@tonic-gate {
91802Scf46844 unsigned char *cp;
920Sstevel@tonic-gate
930Sstevel@tonic-gate squish();
940Sstevel@tonic-gate setLAST();
950Sstevel@tonic-gate if (FIXUNDO)
960Sstevel@tonic-gate vundkind = VCHNG, CP(vutmp, linebuf);
970Sstevel@tonic-gate if (wcursor < cursor)
980Sstevel@tonic-gate cp = wcursor, wcursor = cursor, cursor = cp;
990Sstevel@tonic-gate vUD1 = vUA1 = vUA2 = cursor; vUD2 = wcursor;
1003806Scf46844 /*
1013806Scf46844 * XPG6 assertion 273: Set vmcurs so that undo positions the
1023806Scf46844 * cursor column correctly when we've moved off the initial line
1033806Scf46844 * that was changed, as with the C, c, and s commands,
1043806Scf46844 * when G has moved us off the line, or when a
1053806Scf46844 * multi-line change was done.
1063806Scf46844 */
1073806Scf46844 fixundo();
1080Sstevel@tonic-gate return (lcolumn(wcursor));
1090Sstevel@tonic-gate }
1100Sstevel@tonic-gate
1110Sstevel@tonic-gate /*
1120Sstevel@tonic-gate * Take text from linebuf and stick it
1130Sstevel@tonic-gate * in the VBSIZE buffer BUF. Used to save
1140Sstevel@tonic-gate * deleted text of part of line.
1150Sstevel@tonic-gate */
116802Scf46844 void
takeout(unsigned char * BUF)117802Scf46844 takeout(unsigned char *BUF)
1180Sstevel@tonic-gate {
119802Scf46844 unsigned char *cp;
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate if (wcursor < linebuf)
1220Sstevel@tonic-gate wcursor = linebuf;
1230Sstevel@tonic-gate if (cursor == wcursor) {
124802Scf46844 (void) beep();
1250Sstevel@tonic-gate return;
1260Sstevel@tonic-gate }
1270Sstevel@tonic-gate if (wcursor < cursor) {
1280Sstevel@tonic-gate cp = wcursor;
1290Sstevel@tonic-gate wcursor = cursor;
1300Sstevel@tonic-gate cursor = cp;
1310Sstevel@tonic-gate }
1320Sstevel@tonic-gate setBUF(BUF);
1330Sstevel@tonic-gate if ((unsigned char)BUF[128] == 0200)
134802Scf46844 (void) beep();
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate
1370Sstevel@tonic-gate /*
1380Sstevel@tonic-gate * Are we at the end of the printed representation of the
1390Sstevel@tonic-gate * line? Used internally in hardcopy open.
1400Sstevel@tonic-gate */
141802Scf46844 int
ateopr(void)142802Scf46844 ateopr(void)
1430Sstevel@tonic-gate {
144802Scf46844 wchar_t i, c;
145802Scf46844 wchar_t *cp = vtube[destline] + destcol;
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate for (i = WCOLS - destcol; i > 0; i--) {
1480Sstevel@tonic-gate c = *cp++;
1490Sstevel@tonic-gate if (c == 0) {
1500Sstevel@tonic-gate /*
1510Sstevel@tonic-gate * Optimization to consider returning early, saving
1520Sstevel@tonic-gate * CPU time. We have to make a special check that
1530Sstevel@tonic-gate * we aren't missing a mode indicator.
1540Sstevel@tonic-gate */
1550Sstevel@tonic-gate if (destline == WECHO && destcol < WCOLS-11 && vtube[WECHO][WCOLS-20])
1560Sstevel@tonic-gate return 0;
1570Sstevel@tonic-gate return (1);
1580Sstevel@tonic-gate }
1590Sstevel@tonic-gate if (c != ' ' && (c & QUOTE) == 0)
1600Sstevel@tonic-gate return (0);
1610Sstevel@tonic-gate }
1620Sstevel@tonic-gate return (1);
1630Sstevel@tonic-gate }
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate /*
1660Sstevel@tonic-gate * Append.
1670Sstevel@tonic-gate *
1680Sstevel@tonic-gate * This routine handles the top level append, doing work
1690Sstevel@tonic-gate * as each new line comes in, and arranging repeatability.
1700Sstevel@tonic-gate * It also handles append with repeat counts, and calculation
1710Sstevel@tonic-gate * of autoindents for new lines.
1720Sstevel@tonic-gate */
1730Sstevel@tonic-gate bool vaifirst;
1740Sstevel@tonic-gate bool gobbled;
1750Sstevel@tonic-gate unsigned char *ogcursor;
1760Sstevel@tonic-gate
1770Sstevel@tonic-gate static int INSCDCNT; /* number of ^D's (backtabs) in insertion buffer */
1780Sstevel@tonic-gate
1790Sstevel@tonic-gate static int inscdcnt; /*
1800Sstevel@tonic-gate * count of ^D's (backtabs) not seen yet when doing
1810Sstevel@tonic-gate * repeat of insertion
1820Sstevel@tonic-gate */
1830Sstevel@tonic-gate
184802Scf46844 void
vappend(int ch,int cnt,int indent)185802Scf46844 vappend(int ch, int cnt, int indent)
1860Sstevel@tonic-gate {
187802Scf46844 int i;
188802Scf46844 unsigned char *gcursor;
1890Sstevel@tonic-gate bool escape;
1900Sstevel@tonic-gate int repcnt, savedoomed;
1910Sstevel@tonic-gate short oldhold = hold;
1921406Scf46844 int savecnt = cnt;
1931406Scf46844 line *startsrcline;
1941406Scf46844 int startsrccol, endsrccol;
1951406Scf46844 int gotNL = 0;
1961406Scf46844 int imultlinecnt = 0;
1971406Scf46844 int omultlinecnt = 0;
1981406Scf46844
1991406Scf46844 if ((savecnt > 1) && (ch == 'o' || ch == 'O')) {
2001406Scf46844 omultlinecnt = 1;
2011406Scf46844 }
2021406Scf46844 #ifdef XPG6
2031406Scf46844 if ((savecnt > 1) && (ch == 'a' || ch == 'A' || ch == 'i' || ch == 'I'))
2041406Scf46844 imultlinecnt = 1;
2051406Scf46844 #endif /* XPG6 */
2060Sstevel@tonic-gate
2070Sstevel@tonic-gate /*
2080Sstevel@tonic-gate * Before a move in hardopen when the line is dirty
2090Sstevel@tonic-gate * or we are in the middle of the printed representation,
2100Sstevel@tonic-gate * we retype the line to the left of the cursor so the
2110Sstevel@tonic-gate * insert looks clean.
2120Sstevel@tonic-gate */
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate if (ch != 'o' && state == HARDOPEN && (rubble || !ateopr())) {
2150Sstevel@tonic-gate rubble = 1;
2160Sstevel@tonic-gate gcursor = cursor;
2170Sstevel@tonic-gate i = *gcursor;
2180Sstevel@tonic-gate *gcursor = ' ';
2190Sstevel@tonic-gate wcursor = gcursor;
220802Scf46844 (void) vmove();
2210Sstevel@tonic-gate *gcursor = i;
2220Sstevel@tonic-gate }
2233806Scf46844 /*
2243806Scf46844 * If vrep() passed indent = 0, this is the 'r' command,
2253806Scf46844 * so don't autoindent until the last char.
2263806Scf46844 */
2270Sstevel@tonic-gate vaifirst = indent == 0;
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate /*
2300Sstevel@tonic-gate * Handle replace character by (eventually)
2310Sstevel@tonic-gate * limiting the number of input characters allowed
2320Sstevel@tonic-gate * in the vgetline routine.
2330Sstevel@tonic-gate */
2340Sstevel@tonic-gate if (ch == 'r')
2350Sstevel@tonic-gate repcnt = 2;
2360Sstevel@tonic-gate else
2370Sstevel@tonic-gate repcnt = 0;
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate /*
2400Sstevel@tonic-gate * If an autoindent is specified, then
2410Sstevel@tonic-gate * generate a mixture of blanks to tabs to implement
2420Sstevel@tonic-gate * it and place the cursor after the indent.
2430Sstevel@tonic-gate * Text read by the vgetline routine will be placed in genbuf,
2440Sstevel@tonic-gate * so the indent is generated there.
2450Sstevel@tonic-gate */
2460Sstevel@tonic-gate if (value(vi_AUTOINDENT) && indent != 0) {
2470Sstevel@tonic-gate unsigned char x;
2480Sstevel@tonic-gate gcursor = genindent(indent);
2490Sstevel@tonic-gate *gcursor = 0;
2500Sstevel@tonic-gate vgotoCL(nqcolumn(lastchr(linebuf, cursor), genbuf));
2510Sstevel@tonic-gate } else {
2520Sstevel@tonic-gate gcursor = genbuf;
2530Sstevel@tonic-gate *gcursor = 0;
2540Sstevel@tonic-gate if (ch == 'o')
2550Sstevel@tonic-gate vfixcurs();
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate /*
2590Sstevel@tonic-gate * Prepare for undo. Pointers delimit inserted portion of line.
2600Sstevel@tonic-gate */
2610Sstevel@tonic-gate vUA1 = vUA2 = cursor;
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate /*
2640Sstevel@tonic-gate * If we are not in a repeated command and a ^@ comes in
2650Sstevel@tonic-gate * then this means the previous inserted text.
2660Sstevel@tonic-gate * If there is none or it was too long to be saved,
2670Sstevel@tonic-gate * then beep() and also arrange to undo any damage done
2680Sstevel@tonic-gate * so far (e.g. if we are a change.)
2690Sstevel@tonic-gate */
2700Sstevel@tonic-gate switch (ch) {
2710Sstevel@tonic-gate case 'r':
2720Sstevel@tonic-gate break;
2730Sstevel@tonic-gate case 'a':
2740Sstevel@tonic-gate /*
2750Sstevel@tonic-gate * TRANSLATION_NOTE
2760Sstevel@tonic-gate * "A" is a terse mode message corresponding to
2770Sstevel@tonic-gate * "APPEND MODE".
2780Sstevel@tonic-gate * Translated message of "A" must be 1 character (not byte).
2790Sstevel@tonic-gate * Or, just leave it.
2800Sstevel@tonic-gate */
2810Sstevel@tonic-gate if (value(vi_TERSE)) {
2820Sstevel@tonic-gate vshowmode(gettext("A"));
2830Sstevel@tonic-gate } else {
2840Sstevel@tonic-gate vshowmode(gettext("APPEND MODE"));
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate break;
2870Sstevel@tonic-gate case 's':
2880Sstevel@tonic-gate /*
2890Sstevel@tonic-gate * TRANSLATION_NOTE
2900Sstevel@tonic-gate * "S" is a terse mode message corresponding to
2910Sstevel@tonic-gate * "SUBSTITUTE MODE".
2920Sstevel@tonic-gate * Translated message of "S" must be 1 character (not byte).
2930Sstevel@tonic-gate * Or, just leave it.
2940Sstevel@tonic-gate */
2950Sstevel@tonic-gate if (value(vi_TERSE)) {
2960Sstevel@tonic-gate vshowmode(gettext("S"));
2970Sstevel@tonic-gate } else {
2980Sstevel@tonic-gate vshowmode(gettext("SUBSTITUTE MODE"));
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate break;
3010Sstevel@tonic-gate case 'c':
3020Sstevel@tonic-gate /*
3030Sstevel@tonic-gate * TRANSLATION_NOTE
3040Sstevel@tonic-gate * "C" is a terse mode message corresponding to
3050Sstevel@tonic-gate * "CHANGE MODE".
3060Sstevel@tonic-gate * Translated message of "C" must be 1 character (not byte).
3070Sstevel@tonic-gate * Or, just leave it.
3080Sstevel@tonic-gate */
3090Sstevel@tonic-gate if (value(vi_TERSE)) {
3100Sstevel@tonic-gate vshowmode(gettext("C"));
3110Sstevel@tonic-gate } else {
3120Sstevel@tonic-gate vshowmode(gettext("CHANGE MODE"));
3130Sstevel@tonic-gate }
3140Sstevel@tonic-gate break;
3150Sstevel@tonic-gate case 'R':
3160Sstevel@tonic-gate /*
3170Sstevel@tonic-gate * TRANSLATION_NOTE
3180Sstevel@tonic-gate * "R" is a terse mode message corresponding to
3190Sstevel@tonic-gate * "REPLACE MODE".
3200Sstevel@tonic-gate * Translated message of "R" must be 1 character (not byte).
3210Sstevel@tonic-gate * Or, just leave it.
3220Sstevel@tonic-gate */
3230Sstevel@tonic-gate if (value(vi_TERSE)) {
3240Sstevel@tonic-gate vshowmode(gettext("R"));
3250Sstevel@tonic-gate } else {
3260Sstevel@tonic-gate vshowmode(gettext("REPLACE MODE"));
3270Sstevel@tonic-gate }
3280Sstevel@tonic-gate break;
3290Sstevel@tonic-gate case 'o':
3300Sstevel@tonic-gate /*
3310Sstevel@tonic-gate * TRANSLATION_NOTE
3320Sstevel@tonic-gate * "O" is a terse mode message corresponding to
3330Sstevel@tonic-gate * "OPEN MODE".
3340Sstevel@tonic-gate * Translated message of "O" must be 1 character (not byte).
3350Sstevel@tonic-gate * Or, just leave it.
3360Sstevel@tonic-gate */
3370Sstevel@tonic-gate if (value(vi_TERSE)) {
3380Sstevel@tonic-gate vshowmode(gettext("O"));
3390Sstevel@tonic-gate } else {
3400Sstevel@tonic-gate vshowmode(gettext("OPEN MODE"));
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate break;
3430Sstevel@tonic-gate case 'i':
3440Sstevel@tonic-gate /*
3450Sstevel@tonic-gate * TRANSLATION_NOTE
3460Sstevel@tonic-gate * "I" is a terse mode message corresponding to
3470Sstevel@tonic-gate * "INSERT MODE" and the following "INPUT MODE".
3480Sstevel@tonic-gate * Translated message of "I" must be 1 character (not byte).
3490Sstevel@tonic-gate * Or, just leave it.
3500Sstevel@tonic-gate */
3510Sstevel@tonic-gate if (value(vi_TERSE)) {
3520Sstevel@tonic-gate vshowmode(gettext("I"));
3530Sstevel@tonic-gate } else {
3540Sstevel@tonic-gate vshowmode(gettext("INSERT MODE"));
3550Sstevel@tonic-gate }
3560Sstevel@tonic-gate break;
3570Sstevel@tonic-gate default:
3580Sstevel@tonic-gate /*
3590Sstevel@tonic-gate * TRANSLATION_NOTE
3600Sstevel@tonic-gate * "I" is a terse mode message corresponding to
3610Sstevel@tonic-gate * "INPUT MODE" and the previous "INSERT MODE".
3620Sstevel@tonic-gate * Translated message of "I" must be 1 character (not byte).
3630Sstevel@tonic-gate * Or, just leave it.
3640Sstevel@tonic-gate */
3650Sstevel@tonic-gate if (value(vi_TERSE)) {
3660Sstevel@tonic-gate vshowmode(gettext("I"));
3670Sstevel@tonic-gate } else {
3680Sstevel@tonic-gate vshowmode(gettext("INPUT MODE"));
3690Sstevel@tonic-gate }
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate ixlatctl(1);
3720Sstevel@tonic-gate if ((vglobp && *vglobp == 0) || peekbr()) {
3730Sstevel@tonic-gate if (INS[128] == 0200) {
374802Scf46844 (void) beep();
3750Sstevel@tonic-gate if (!splitw)
3760Sstevel@tonic-gate ungetkey('u');
3770Sstevel@tonic-gate doomed = 0;
3780Sstevel@tonic-gate hold = oldhold;
3790Sstevel@tonic-gate return;
3800Sstevel@tonic-gate }
3810Sstevel@tonic-gate /*
3820Sstevel@tonic-gate * Unread input from INS.
3830Sstevel@tonic-gate * An escape will be generated at end of string.
3840Sstevel@tonic-gate * Hold off n^^2 type update on dumb terminals.
3850Sstevel@tonic-gate */
3860Sstevel@tonic-gate vglobp = INS;
3870Sstevel@tonic-gate inscdcnt = INSCDCNT;
3880Sstevel@tonic-gate hold |= HOLDQIK;
3890Sstevel@tonic-gate } else if (vglobp == 0) {
3900Sstevel@tonic-gate /*
3910Sstevel@tonic-gate * Not a repeated command, get
3920Sstevel@tonic-gate * a new inserted text for repeat.
3930Sstevel@tonic-gate */
3940Sstevel@tonic-gate INS[0] = 0;
3950Sstevel@tonic-gate INS[128] = 0;
3960Sstevel@tonic-gate INSCDCNT = 0;
3970Sstevel@tonic-gate }
3980Sstevel@tonic-gate
3990Sstevel@tonic-gate /*
4000Sstevel@tonic-gate * For wrapmargin to hack away second space after a '.'
4010Sstevel@tonic-gate * when the first space caused a line break we keep
4020Sstevel@tonic-gate * track that this happened in gobblebl, which says
4030Sstevel@tonic-gate * to gobble up a blank silently.
4040Sstevel@tonic-gate */
4050Sstevel@tonic-gate gobblebl = 0;
4060Sstevel@tonic-gate
4071406Scf46844 startsrcline = dot;
4081406Scf46844 startsrccol = cursor - linebuf;
4091406Scf46844
4100Sstevel@tonic-gate /*
4110Sstevel@tonic-gate * Text gathering loop.
4120Sstevel@tonic-gate * New text goes into genbuf starting at gcursor.
4130Sstevel@tonic-gate * cursor preserves place in linebuf where text will eventually go.
4140Sstevel@tonic-gate */
4150Sstevel@tonic-gate if (*cursor == 0 || state == CRTOPEN)
4160Sstevel@tonic-gate hold |= HOLDROL;
4170Sstevel@tonic-gate for (;;) {
4180Sstevel@tonic-gate if (ch == 'r' && repcnt == 0)
4190Sstevel@tonic-gate escape = 0;
4200Sstevel@tonic-gate else {
4210Sstevel@tonic-gate ixlatctl(1);
4223806Scf46844 /*
4233806Scf46844 * When vgetline() returns, gcursor is
4243806Scf46844 * pointing to '\0' and vgetline() has
4253806Scf46844 * read an ESCAPE or NL.
4263806Scf46844 */
4270Sstevel@tonic-gate gcursor = vgetline(repcnt, gcursor, &escape, ch);
4281406Scf46844 if (escape == '\n') {
4291406Scf46844 gotNL = 1;
4303806Scf46844 #ifdef XPG6
4313806Scf46844 if (ch == 'r') {
4323806Scf46844 /*
4333806Scf46844 * XPG6 assertion 313 [count]r\n :
4343806Scf46844 * Arrange to set cursor correctly.
4353806Scf46844 */
4363806Scf46844 endsrccol = gcursor - genbuf - 1;
4373806Scf46844 }
4383806Scf46844 #endif /* XPG6 */
4391406Scf46844 } else {
4401406Scf46844 /*
4411406Scf46844 * Upon escape, gcursor is pointing to '\0'
4421406Scf46844 * terminating the string in genbuf.
4431406Scf46844 */
4441406Scf46844 endsrccol = gcursor - genbuf - 1;
4451406Scf46844 }
4460Sstevel@tonic-gate ixlatctl(0);
4470Sstevel@tonic-gate
4480Sstevel@tonic-gate /*
4490Sstevel@tonic-gate * After an append, stick information
4500Sstevel@tonic-gate * about the ^D's and ^^D's and 0^D's in
4510Sstevel@tonic-gate * the repeated text buffer so repeated
4520Sstevel@tonic-gate * inserts of stuff indented with ^D as backtab's
4530Sstevel@tonic-gate * can work.
4540Sstevel@tonic-gate */
4550Sstevel@tonic-gate if (HADUP)
4560Sstevel@tonic-gate addtext("^");
4570Sstevel@tonic-gate else if (HADZERO)
4580Sstevel@tonic-gate addtext("0");
4590Sstevel@tonic-gate if(!vglobp)
4600Sstevel@tonic-gate INSCDCNT = CDCNT;
4610Sstevel@tonic-gate while (CDCNT > 0) {
4620Sstevel@tonic-gate addtext("\004");
4630Sstevel@tonic-gate CDCNT--;
4640Sstevel@tonic-gate }
4650Sstevel@tonic-gate if (gobbled)
4660Sstevel@tonic-gate addtext(" ");
4670Sstevel@tonic-gate addtext(ogcursor);
4680Sstevel@tonic-gate }
4690Sstevel@tonic-gate repcnt = 0;
4700Sstevel@tonic-gate
4710Sstevel@tonic-gate /*
4720Sstevel@tonic-gate * Smash the generated and preexisting indents together
4730Sstevel@tonic-gate * and generate one cleanly made out of tabs and spaces
4743806Scf46844 * if we are using autoindent and this isn't 'r' command.
4750Sstevel@tonic-gate */
4760Sstevel@tonic-gate if (!vaifirst && value(vi_AUTOINDENT)) {
4770Sstevel@tonic-gate i = fixindent(indent);
4780Sstevel@tonic-gate if (!HADUP)
4790Sstevel@tonic-gate indent = i;
4800Sstevel@tonic-gate gcursor = strend(genbuf);
4810Sstevel@tonic-gate }
4820Sstevel@tonic-gate
4830Sstevel@tonic-gate /*
4841406Scf46844 * Set cnt to 1 to avoid repeating the text on the same line.
4851406Scf46844 * Do this for commands 'i', 'I', 'a', and 'A', if we're
4861406Scf46844 * inserting anything with a newline for XPG6. Always do this
4871406Scf46844 * for commands 'o' and 'O'.
4881406Scf46844 */
4891406Scf46844 if ((imultlinecnt && gotNL) || omultlinecnt) {
4901406Scf46844 cnt = 1;
4911406Scf46844 }
4921406Scf46844
4931406Scf46844 /*
4940Sstevel@tonic-gate * Limit the repetition count based on maximum
4950Sstevel@tonic-gate * possible line length; do output implied
4960Sstevel@tonic-gate * by further count (> 1) and cons up the new line
4970Sstevel@tonic-gate * in linebuf.
4980Sstevel@tonic-gate */
4990Sstevel@tonic-gate cnt = vmaxrep(ch, cnt);
5003806Scf46844 /*
5013806Scf46844 * cursor points to linebuf
5023806Scf46844 * Copy remaining old text (cursor) in original
5033806Scf46844 * line to after new text (gcursor + 1) in genbuf.
5043806Scf46844 */
5050Sstevel@tonic-gate CP(gcursor + 1, cursor);
5063806Scf46844 /*
5073806Scf46844 * For [count] r \n command, when replacing [count] chars
5083806Scf46844 * with '\n', this loop replaces [count] chars with "".
5093806Scf46844 */
5100Sstevel@tonic-gate do {
5113806Scf46844 /* cp new text (genbuf) into linebuf (cursor) */
5120Sstevel@tonic-gate CP(cursor, genbuf);
5130Sstevel@tonic-gate if (cnt > 1) {
5140Sstevel@tonic-gate int oldhold = hold;
5150Sstevel@tonic-gate
5160Sstevel@tonic-gate Outchar = vinschar;
5170Sstevel@tonic-gate hold |= HOLDQIK;
518802Scf46844 viprintf("%s", genbuf);
5190Sstevel@tonic-gate hold = oldhold;
5200Sstevel@tonic-gate Outchar = vputchar;
5210Sstevel@tonic-gate }
5223806Scf46844 /* point cursor after new text in linebuf */
5230Sstevel@tonic-gate cursor += gcursor - genbuf;
5240Sstevel@tonic-gate } while (--cnt > 0);
5250Sstevel@tonic-gate endim();
5260Sstevel@tonic-gate vUA2 = cursor;
5273806Scf46844 /* add the remaining old text after the cursor */
5280Sstevel@tonic-gate if (escape != '\n')
5290Sstevel@tonic-gate CP(cursor, gcursor + 1);
5300Sstevel@tonic-gate
5310Sstevel@tonic-gate /*
5320Sstevel@tonic-gate * If doomed characters remain, clobber them,
5330Sstevel@tonic-gate * and reopen the line to get the display exact.
5343806Scf46844 * eg. c$ to change to end of line
5350Sstevel@tonic-gate */
5360Sstevel@tonic-gate if (state != HARDOPEN) {
5370Sstevel@tonic-gate DEPTH(vcline) = 0;
5380Sstevel@tonic-gate savedoomed = doomed;
5390Sstevel@tonic-gate if (doomed > 0) {
540802Scf46844 int cind = cindent();
5410Sstevel@tonic-gate
5420Sstevel@tonic-gate physdc(cind, cind + doomed);
5430Sstevel@tonic-gate doomed = 0;
5440Sstevel@tonic-gate }
5450Sstevel@tonic-gate if(MB_CUR_MAX > 1)
5460Sstevel@tonic-gate rewrite = _ON;
5470Sstevel@tonic-gate i = vreopen(LINE(vcline), lineDOT(), vcline);
5480Sstevel@tonic-gate if(MB_CUR_MAX > 1)
5490Sstevel@tonic-gate rewrite = _OFF;
5500Sstevel@tonic-gate #ifdef TRACE
5510Sstevel@tonic-gate if (trace)
5520Sstevel@tonic-gate fprintf(trace, "restoring doomed from %d to %d\n", doomed, savedoomed);
5530Sstevel@tonic-gate #endif
5540Sstevel@tonic-gate if (ch == 'R')
5550Sstevel@tonic-gate doomed = savedoomed;
5560Sstevel@tonic-gate }
5570Sstevel@tonic-gate
5580Sstevel@tonic-gate /*
5593806Scf46844 * Unless we are continuing on to another line
5603806Scf46844 * (got a NL), break out of the for loop (got
5613806Scf46844 * an ESCAPE).
5620Sstevel@tonic-gate */
5630Sstevel@tonic-gate if (escape != '\n') {
5640Sstevel@tonic-gate vshowmode("");
5650Sstevel@tonic-gate break;
5660Sstevel@tonic-gate }
5670Sstevel@tonic-gate
5680Sstevel@tonic-gate /*
5690Sstevel@tonic-gate * Set up for the new line.
5700Sstevel@tonic-gate * First save the current line, then construct a new
5710Sstevel@tonic-gate * first image for the continuation line consisting
5720Sstevel@tonic-gate * of any new autoindent plus the pushed ahead text.
5730Sstevel@tonic-gate */
5740Sstevel@tonic-gate killU();
5750Sstevel@tonic-gate addtext(gobblebl ? " " : "\n");
5763806Scf46844 /* save vutmp (for undo state) into temp file */
5770Sstevel@tonic-gate vsave();
5780Sstevel@tonic-gate cnt = 1;
5790Sstevel@tonic-gate if (value(vi_AUTOINDENT)) {
5800Sstevel@tonic-gate if (value(vi_LISP))
5810Sstevel@tonic-gate indent = lindent(dot + 1);
5820Sstevel@tonic-gate else
5830Sstevel@tonic-gate if (!HADUP && vaifirst)
5840Sstevel@tonic-gate indent = whitecnt(linebuf);
5850Sstevel@tonic-gate vaifirst = 0;
5860Sstevel@tonic-gate strcLIN(vpastwh(gcursor + 1));
5870Sstevel@tonic-gate gcursor = genindent(indent);
5880Sstevel@tonic-gate *gcursor = 0;
5890Sstevel@tonic-gate if (gcursor + strlen(linebuf) > &genbuf[LBSIZE - 2])
5900Sstevel@tonic-gate gcursor = genbuf;
5910Sstevel@tonic-gate CP(gcursor, linebuf);
5920Sstevel@tonic-gate } else {
5933806Scf46844 /*
5943806Scf46844 * Put gcursor at start of genbuf to wipe
5953806Scf46844 * out previous line in preparation for
5963806Scf46844 * the next vgetline() loop.
5973806Scf46844 */
5980Sstevel@tonic-gate CP(genbuf, gcursor + 1);
5990Sstevel@tonic-gate gcursor = genbuf;
6000Sstevel@tonic-gate }
6010Sstevel@tonic-gate
6020Sstevel@tonic-gate /*
6030Sstevel@tonic-gate * If we started out as a single line operation and are now
6040Sstevel@tonic-gate * turning into a multi-line change, then we had better yank
6050Sstevel@tonic-gate * out dot before it changes so that undo will work
6060Sstevel@tonic-gate * correctly later.
6070Sstevel@tonic-gate */
6080Sstevel@tonic-gate if (FIXUNDO && vundkind == VCHNG) {
6090Sstevel@tonic-gate vremote(1, yank, 0);
6100Sstevel@tonic-gate undap1--;
6110Sstevel@tonic-gate }
6120Sstevel@tonic-gate
6130Sstevel@tonic-gate /*
6140Sstevel@tonic-gate * Now do the append of the new line in the buffer,
6153806Scf46844 * and update the display, ie: append genbuf to
6163806Scf46844 * the file after dot. If slowopen
6170Sstevel@tonic-gate * we don't do very much.
6180Sstevel@tonic-gate */
6190Sstevel@tonic-gate vdoappend(genbuf);
6200Sstevel@tonic-gate vundkind = VMANYINS;
6210Sstevel@tonic-gate vcline++;
6220Sstevel@tonic-gate if (state != VISUAL)
6230Sstevel@tonic-gate vshow(dot, NOLINE);
6240Sstevel@tonic-gate else {
6250Sstevel@tonic-gate i += LINE(vcline - 1);
6260Sstevel@tonic-gate vopen(dot, i);
6270Sstevel@tonic-gate if (value(vi_SLOWOPEN))
6280Sstevel@tonic-gate vscrap();
6290Sstevel@tonic-gate else
6300Sstevel@tonic-gate vsync1(LINE(vcline));
6310Sstevel@tonic-gate }
6320Sstevel@tonic-gate switch (ch) {
6330Sstevel@tonic-gate case 'r':
6340Sstevel@tonic-gate break;
6350Sstevel@tonic-gate case 'a':
6360Sstevel@tonic-gate if (value(vi_TERSE)) {
6370Sstevel@tonic-gate vshowmode(gettext("A"));
6380Sstevel@tonic-gate } else {
6390Sstevel@tonic-gate vshowmode(gettext("APPEND MODE"));
6400Sstevel@tonic-gate }
6410Sstevel@tonic-gate break;
6420Sstevel@tonic-gate case 's':
6430Sstevel@tonic-gate if (value(vi_TERSE)) {
6440Sstevel@tonic-gate vshowmode(gettext("S"));
6450Sstevel@tonic-gate } else {
6460Sstevel@tonic-gate vshowmode(gettext("SUBSTITUTE MODE"));
6470Sstevel@tonic-gate }
6480Sstevel@tonic-gate break;
6490Sstevel@tonic-gate case 'c':
6500Sstevel@tonic-gate if (value(vi_TERSE)) {
6510Sstevel@tonic-gate vshowmode(gettext("C"));
6520Sstevel@tonic-gate } else {
6530Sstevel@tonic-gate vshowmode(gettext("CHANGE MODE"));
6540Sstevel@tonic-gate }
6550Sstevel@tonic-gate break;
6560Sstevel@tonic-gate case 'R':
6570Sstevel@tonic-gate if (value(vi_TERSE)) {
6580Sstevel@tonic-gate vshowmode(gettext("R"));
6590Sstevel@tonic-gate } else {
6600Sstevel@tonic-gate vshowmode(gettext("REPLACE MODE"));
6610Sstevel@tonic-gate }
6620Sstevel@tonic-gate break;
6630Sstevel@tonic-gate case 'i':
6640Sstevel@tonic-gate if (value(vi_TERSE)) {
6650Sstevel@tonic-gate vshowmode(gettext("I"));
6660Sstevel@tonic-gate } else {
6670Sstevel@tonic-gate vshowmode(gettext("INSERT MODE"));
6680Sstevel@tonic-gate }
6690Sstevel@tonic-gate break;
6700Sstevel@tonic-gate case 'o':
6710Sstevel@tonic-gate if (value(vi_TERSE)) {
6720Sstevel@tonic-gate vshowmode(gettext("O"));
6730Sstevel@tonic-gate } else {
6740Sstevel@tonic-gate vshowmode(gettext("OPEN MODE"));
6750Sstevel@tonic-gate }
6760Sstevel@tonic-gate break;
6770Sstevel@tonic-gate default:
6780Sstevel@tonic-gate if (value(vi_TERSE)) {
6790Sstevel@tonic-gate vshowmode(gettext("I"));
6800Sstevel@tonic-gate } else {
6810Sstevel@tonic-gate vshowmode(gettext("INPUT MODE"));
6820Sstevel@tonic-gate }
6830Sstevel@tonic-gate }
6840Sstevel@tonic-gate strcLIN(gcursor);
6853806Scf46844 /* zero genbuf */
6860Sstevel@tonic-gate *gcursor = 0;
6870Sstevel@tonic-gate cursor = linebuf;
6880Sstevel@tonic-gate vgotoCL(nqcolumn(cursor - 1, genbuf));
6891406Scf46844 } /* end for (;;) loop in vappend() */
6901406Scf46844
6911406Scf46844 if (imultlinecnt && gotNL) {
6921406Scf46844 imultlinerep(savecnt, startsrcline, startsrccol, endsrccol);
6931406Scf46844 } else if (omultlinecnt) {
6941406Scf46844 omultlinerep(savecnt, startsrcline, endsrccol);
6953806Scf46844 #ifdef XPG6
6963806Scf46844 } else if (savecnt > 1 && ch == 'r' && gotNL) {
6973806Scf46844 /*
6983806Scf46844 * XPG6 assertion 313 & 254 : Position cursor for [count]r\n
6993806Scf46844 * then insert [count -1] newlines.
7003806Scf46844 */
7013806Scf46844 endsrccol = gcursor - genbuf - 1;
7023806Scf46844 rmultlinerep(savecnt, endsrccol);
7033806Scf46844 #endif /* XPG6 */
7040Sstevel@tonic-gate }
7050Sstevel@tonic-gate
7060Sstevel@tonic-gate /*
7070Sstevel@tonic-gate * All done with insertion, position the cursor
7080Sstevel@tonic-gate * and sync the screen.
7090Sstevel@tonic-gate */
7100Sstevel@tonic-gate hold = oldhold;
7111406Scf46844 if ((imultlinecnt && gotNL) || omultlinecnt) {
7121406Scf46844 fixdisplay();
7133806Scf46844 #ifdef XPG6
7143806Scf46844 } else if (savecnt > 1 && ch == 'r' && gotNL) {
7153806Scf46844 fixdisplay();
7163806Scf46844 /*
7173806Scf46844 * XPG6 assertion 313 & 254 [count]r\n : Set flag to call
7183806Scf46844 * fixdisplay() after operate() has finished. To be sure that
7193806Scf46844 * the text (after the last \n followed by an indent) is always
7203806Scf46844 * displayed, fixdisplay() is called right before getting
7213806Scf46844 * the next command.
7223806Scf46844 */
7233806Scf46844 redisplay = 1;
7243806Scf46844 #endif /* XPG6 */
7251406Scf46844 } else if (cursor > linebuf) {
7260Sstevel@tonic-gate cursor = lastchr(linebuf, cursor);
7273806Scf46844 #ifdef XPG6
7283806Scf46844 /*
7293806Scf46844 * XPG6 assertion 313 & 254 [count]r\n :
7303806Scf46844 * For 'r' command, when the replacement char causes new
7313806Scf46844 * lines to be created, point cursor to first non-blank.
7323806Scf46844 * The old code, ie: cursor = lastchr(linebuf, cursor);
7333806Scf46844 * set cursor to the blank before the first non-blank
7343806Scf46844 * for r\n
7353806Scf46844 */
7363806Scf46844 if (ch == 'r' && gotNL && isblank((int)*cursor))
7373806Scf46844 ++cursor;
7383806Scf46844 #endif /* XPG6 */
7391406Scf46844 }
7400Sstevel@tonic-gate if (state != HARDOPEN)
7410Sstevel@tonic-gate vsyncCL();
7420Sstevel@tonic-gate else if (cursor > linebuf)
7430Sstevel@tonic-gate back1();
7440Sstevel@tonic-gate doomed = 0;
7450Sstevel@tonic-gate wcursor = cursor;
746802Scf46844 (void) vmove();
7470Sstevel@tonic-gate }
7480Sstevel@tonic-gate
7490Sstevel@tonic-gate /*
7501406Scf46844 * XPG6
7511406Scf46844 * To repeat multi-line input for [count]a, [count]A, [count]i, [count]I,
7521406Scf46844 * or a subsequent [count]. :
7531406Scf46844 * insert input count-1 more times.
7541406Scf46844 */
7551406Scf46844
7561406Scf46844 static void
imultlinerep(int savecnt,line * startsrcline,int startsrccol,int endsrccol)7571406Scf46844 imultlinerep(int savecnt, line *startsrcline, int startsrccol, int endsrccol)
7581406Scf46844 {
7591406Scf46844 int tmpcnt = 2; /* 1st insert counts as 1 repeat */
7601406Scf46844 line *srcline, *endsrcline;
7611406Scf46844 size_t destsize = LBSIZE - endsrccol - 1;
7621406Scf46844
7631406Scf46844 endsrcline = dot;
7641406Scf46844
7651406Scf46844 /* Save linebuf into temp file before moving off the line. */
7661406Scf46844 vsave();
7671406Scf46844
7681406Scf46844 /*
7691406Scf46844 * At this point the temp file contains the first iteration of
7701406Scf46844 * a multi-line insert, and we need to repeat it savecnt - 1
7711406Scf46844 * more times in the temp file. dot is the last line in the
7721406Scf46844 * first iteration of the insert. Decrement dot so that
7731406Scf46844 * vdoappend() will append each new line before the last line.
7741406Scf46844 */
7751406Scf46844 --dot;
7761406Scf46844 --vcline;
7771406Scf46844 /*
7781406Scf46844 * Use genbuf to rebuild the last line in the 1st iteration
7791406Scf46844 * of the repeated insert, then copy this line to the temp file.
7801406Scf46844 */
7811406Scf46844 (void) strlcpy((char *)genbuf, (char *)linebuf, sizeof (genbuf));
782*13093SRoger.Faulkner@Oracle.COM getaline(*startsrcline);
7831406Scf46844 if (strlcpy((char *)(genbuf + endsrccol + 1),
7841406Scf46844 (char *)(linebuf + startsrccol), destsize) >= destsize) {
7851406Scf46844 error(gettext("Line too long"));
7861406Scf46844 }
7871406Scf46844 vdoappend(genbuf);
7881406Scf46844 vcline++;
7891406Scf46844 /*
7901406Scf46844 * Loop from the second line of the first iteration
7911406Scf46844 * through endsrcline, appending after dot.
7921406Scf46844 */
7931406Scf46844 ++startsrcline;
7941406Scf46844
7951406Scf46844 while (tmpcnt <= savecnt) {
7961406Scf46844 for (srcline = startsrcline; srcline <= endsrcline;
7971406Scf46844 ++srcline) {
7981406Scf46844 if ((tmpcnt == savecnt) &&
7991406Scf46844 (srcline == endsrcline)) {
8001406Scf46844 /*
8011406Scf46844 * The last line is already in place,
8021406Scf46844 * just make it the current line.
8031406Scf46844 */
8041406Scf46844 vcline++;
8051406Scf46844 dot++;
8061406Scf46844 getDOT();
8071406Scf46844 cursor = linebuf + endsrccol;
8081406Scf46844 } else {
809*13093SRoger.Faulkner@Oracle.COM getaline(*srcline);
8101406Scf46844 /* copy linebuf to temp file */
8111406Scf46844 vdoappend(linebuf);
8121406Scf46844 vcline++;
8131406Scf46844 }
8141406Scf46844 }
8151406Scf46844 ++tmpcnt;
8161406Scf46844 }
8171406Scf46844 }
8181406Scf46844
8191406Scf46844 /*
8201406Scf46844 * To repeat input for [count]o, [count]O, or a subsequent [count]. :
8211406Scf46844 * append input count-1 more times to the end of the already added
8221406Scf46844 * text, each time starting on a new line.
8231406Scf46844 */
8241406Scf46844
8251406Scf46844 static void
omultlinerep(int savecnt,line * startsrcline,int endsrccol)8261406Scf46844 omultlinerep(int savecnt, line *startsrcline, int endsrccol)
8271406Scf46844 {
8281406Scf46844 int tmpcnt = 2; /* 1st insert counts as 1 repeat */
8291406Scf46844 line *srcline, *endsrcline;
8301406Scf46844
8311406Scf46844 endsrcline = dot;
8321406Scf46844 /* Save linebuf into temp file before moving off the line. */
8331406Scf46844 vsave();
8341406Scf46844
8351406Scf46844 /*
8361406Scf46844 * Loop from the first line of the first iteration
8371406Scf46844 * through endsrcline, appending after dot.
8381406Scf46844 */
8391406Scf46844 while (tmpcnt <= savecnt) {
8401406Scf46844 for (srcline = startsrcline; srcline <= endsrcline; ++srcline) {
841*13093SRoger.Faulkner@Oracle.COM getaline(*srcline);
8421406Scf46844 /* copy linebuf to temp file */
8431406Scf46844 vdoappend(linebuf);
8441406Scf46844 vcline++;
8451406Scf46844 }
8461406Scf46844 ++tmpcnt;
8471406Scf46844 }
8481406Scf46844 cursor = linebuf + endsrccol;
8491406Scf46844 }
8501406Scf46844
8513806Scf46844 #ifdef XPG6
8523806Scf46844 /*
8533806Scf46844 * XPG6 assertion 313 & 254 : To repeat '\n' for [count]r\n
8543806Scf46844 * insert '\n' savecnt-1 more times before the already added '\n'.
8553806Scf46844 */
8563806Scf46844
8573806Scf46844 static void
rmultlinerep(int savecnt,int endsrccol)8583806Scf46844 rmultlinerep(int savecnt, int endsrccol)
8593806Scf46844 {
8603806Scf46844 int tmpcnt = 2; /* 1st replacement counts as 1 repeat */
8613806Scf46844
8623806Scf46844 /* Save linebuf into temp file before moving off the line. */
8633806Scf46844 vsave();
8643806Scf46844 /*
8653806Scf46844 * At this point the temp file contains the line followed by '\n',
8663806Scf46844 * which is preceded by indentation if autoindent is set.
8673806Scf46844 * '\n' must be repeated [savecnt - 1] more times in the temp file.
8683806Scf46844 * dot is the current line containing the '\n'. Decrement dot so that
8693806Scf46844 * vdoappend() will append each '\n' before the current '\n'.
8703806Scf46844 * This will allow only the last line to contain any autoindent
8713806Scf46844 * characters.
8723806Scf46844 */
8733806Scf46844 --dot;
8743806Scf46844 --vcline;
8753806Scf46844
8763806Scf46844 /*
8773806Scf46844 * Append after dot.
8783806Scf46844 */
8793806Scf46844 while (tmpcnt <= savecnt) {
8803806Scf46844 linebuf[0] = '\0';
8813806Scf46844 /* append linebuf below current line in temp file */
8823806Scf46844 vdoappend(linebuf);
8833806Scf46844 vcline++;
8843806Scf46844 ++tmpcnt;
8853806Scf46844 }
8863806Scf46844 /* set the current line to the line after the last '\n' */
8873806Scf46844 ++dot;
8883806Scf46844 ++vcline;
8893806Scf46844 /* point cursor after (linebuf + endsrccol) */
8903806Scf46844 vcursaft(linebuf + endsrccol);
8913806Scf46844 }
8923806Scf46844 #endif /* XPG6 */
8933806Scf46844
8941406Scf46844 /*
8951406Scf46844 * Similiar to a ctrl-l, however always vrepaint() in case the last line
8961406Scf46844 * of the repeat would exceed the bottom of the screen.
8971406Scf46844 */
8981406Scf46844
8993806Scf46844 void
fixdisplay(void)9001406Scf46844 fixdisplay(void)
9011406Scf46844 {
9021406Scf46844 vclear();
9031406Scf46844 vdirty(0, vcnt);
9041406Scf46844 if (state != VISUAL) {
9051406Scf46844 vclean();
9061406Scf46844 vcnt = 0;
9071406Scf46844 vmoveto(dot, cursor, 0);
9081406Scf46844 } else {
9091406Scf46844 vredraw(WTOP);
9101406Scf46844 vrepaint(cursor);
9111406Scf46844 vfixcurs();
9121406Scf46844 }
9131406Scf46844 }
9141406Scf46844
9151406Scf46844 /*
9160Sstevel@tonic-gate * Subroutine for vgetline to back up a single character position,
9170Sstevel@tonic-gate * backwards around end of lines (vgoto can't hack columns which are
9180Sstevel@tonic-gate * less than 0 in general).
9190Sstevel@tonic-gate */
920802Scf46844 void
back1(void)921802Scf46844 back1(void)
9220Sstevel@tonic-gate {
9230Sstevel@tonic-gate
9240Sstevel@tonic-gate vgoto(destline - 1, WCOLS + destcol - 1);
9250Sstevel@tonic-gate }
9260Sstevel@tonic-gate
9270Sstevel@tonic-gate /*
9280Sstevel@tonic-gate * Get a line into genbuf after gcursor.
9290Sstevel@tonic-gate * Cnt limits the number of input characters
9300Sstevel@tonic-gate * accepted and is used for handling the replace
9310Sstevel@tonic-gate * single character command. Aescaped is the location
9320Sstevel@tonic-gate * where we stick a termination indicator (whether we
9330Sstevel@tonic-gate * ended with an ESCAPE or a newline/return.
9340Sstevel@tonic-gate *
9350Sstevel@tonic-gate * We do erase-kill type processing here and also
9360Sstevel@tonic-gate * are careful about the way we do this so that it is
9370Sstevel@tonic-gate * repeatable. (I.e. so that your kill doesn't happen,
9380Sstevel@tonic-gate * when you repeat an insert if it was escaped with \ the
9390Sstevel@tonic-gate * first time you did it. commch is the command character
9400Sstevel@tonic-gate * involved, including the prompt for readline.
9410Sstevel@tonic-gate */
9420Sstevel@tonic-gate unsigned char *
vgetline(cnt,gcursor,aescaped,commch)9430Sstevel@tonic-gate vgetline(cnt, gcursor, aescaped, commch)
9440Sstevel@tonic-gate int cnt;
945802Scf46844 unsigned char *gcursor;
9460Sstevel@tonic-gate bool *aescaped;
9470Sstevel@tonic-gate unsigned char commch;
9480Sstevel@tonic-gate {
949802Scf46844 int c, ch;
950802Scf46844 unsigned char *cp, *pcp;
9510Sstevel@tonic-gate int x, y, iwhite, backsl=0;
9520Sstevel@tonic-gate unsigned char *iglobp;
9530Sstevel@tonic-gate int (*OO)() = Outchar;
9540Sstevel@tonic-gate int length, width;
9550Sstevel@tonic-gate unsigned char multic[MULTI_BYTE_MAX+1];
9560Sstevel@tonic-gate wchar_t wchar = 0;
9570Sstevel@tonic-gate unsigned char *p;
9580Sstevel@tonic-gate int len;
9590Sstevel@tonic-gate
9600Sstevel@tonic-gate
9610Sstevel@tonic-gate /*
9620Sstevel@tonic-gate * Clear the output state and counters
9630Sstevel@tonic-gate * for autoindent backwards motion (counts of ^D, etc.)
9640Sstevel@tonic-gate * Remember how much white space at beginning of line so
9650Sstevel@tonic-gate * as not to allow backspace over autoindent.
9660Sstevel@tonic-gate */
9670Sstevel@tonic-gate
9680Sstevel@tonic-gate *aescaped = 0;
9690Sstevel@tonic-gate ogcursor = gcursor;
9700Sstevel@tonic-gate flusho();
9710Sstevel@tonic-gate CDCNT = 0;
9720Sstevel@tonic-gate HADUP = 0;
9730Sstevel@tonic-gate HADZERO = 0;
9740Sstevel@tonic-gate gobbled = 0;
9750Sstevel@tonic-gate iwhite = whitecnt(genbuf);
9760Sstevel@tonic-gate iglobp = vglobp;
9770Sstevel@tonic-gate
9780Sstevel@tonic-gate /*
9790Sstevel@tonic-gate * Clear abbreviation recursive-use count
9800Sstevel@tonic-gate */
9810Sstevel@tonic-gate abbrepcnt = 0;
9820Sstevel@tonic-gate /*
9830Sstevel@tonic-gate * Carefully avoid using vinschar in the echo area.
9840Sstevel@tonic-gate */
9850Sstevel@tonic-gate if (splitw)
9860Sstevel@tonic-gate Outchar = vputchar;
9870Sstevel@tonic-gate else {
9880Sstevel@tonic-gate Outchar = vinschar;
9890Sstevel@tonic-gate vprepins();
9900Sstevel@tonic-gate }
9910Sstevel@tonic-gate for (;;) {
9920Sstevel@tonic-gate length = 0;
9930Sstevel@tonic-gate backsl = 0;
9940Sstevel@tonic-gate if (gobblebl)
9950Sstevel@tonic-gate gobblebl--;
9960Sstevel@tonic-gate if (cnt != 0) {
9970Sstevel@tonic-gate cnt--;
9980Sstevel@tonic-gate if (cnt == 0)
9990Sstevel@tonic-gate goto vadone;
10000Sstevel@tonic-gate }
10010Sstevel@tonic-gate c = getkey();
10020Sstevel@tonic-gate if (c != ATTN)
10030Sstevel@tonic-gate c &= 0377;
10040Sstevel@tonic-gate ch = c;
10050Sstevel@tonic-gate maphopcnt = 0;
10060Sstevel@tonic-gate if (vglobp == 0 && Peekkey == 0 && commch != 'r')
10070Sstevel@tonic-gate while ((ch = map(c, immacs, commch)) != c) {
10080Sstevel@tonic-gate c = ch;
10090Sstevel@tonic-gate if (!value(vi_REMAP))
10100Sstevel@tonic-gate break;
10110Sstevel@tonic-gate if (++maphopcnt > 256)
10120Sstevel@tonic-gate error(gettext("Infinite macro loop"));
10130Sstevel@tonic-gate }
10140Sstevel@tonic-gate if (!iglobp) {
10150Sstevel@tonic-gate
10160Sstevel@tonic-gate /*
10170Sstevel@tonic-gate * Erase-kill type processing.
10180Sstevel@tonic-gate * Only happens if we were not reading
10190Sstevel@tonic-gate * from untyped input when we started.
10200Sstevel@tonic-gate * Map users erase to ^H, kill to -1 for switch.
10210Sstevel@tonic-gate */
10220Sstevel@tonic-gate if (c == tty.c_cc[VERASE])
10230Sstevel@tonic-gate c = CTRL('h');
10240Sstevel@tonic-gate else if (c == tty.c_cc[VKILL])
10250Sstevel@tonic-gate c = -1;
10260Sstevel@tonic-gate switch (c) {
10270Sstevel@tonic-gate
10280Sstevel@tonic-gate /*
10290Sstevel@tonic-gate * ^? Interrupt drops you back to visual
10300Sstevel@tonic-gate * command mode with an unread interrupt
10310Sstevel@tonic-gate * still in the input buffer.
10320Sstevel@tonic-gate *
10330Sstevel@tonic-gate * ^\ Quit does the same as interrupt.
10340Sstevel@tonic-gate * If you are a ex command rather than
10350Sstevel@tonic-gate * a vi command this will drop you
10360Sstevel@tonic-gate * back to command mode for sure.
10370Sstevel@tonic-gate */
10380Sstevel@tonic-gate case ATTN:
10390Sstevel@tonic-gate case QUIT:
10400Sstevel@tonic-gate ungetkey(c);
10410Sstevel@tonic-gate goto vadone;
10420Sstevel@tonic-gate
10430Sstevel@tonic-gate /*
10440Sstevel@tonic-gate * ^H Backs up a character in the input.
10450Sstevel@tonic-gate *
10460Sstevel@tonic-gate * BUG: Can't back around line boundaries.
10470Sstevel@tonic-gate * This is hard because stuff has
10480Sstevel@tonic-gate * already been saved for repeat.
10490Sstevel@tonic-gate */
10500Sstevel@tonic-gate case CTRL('h'):
10510Sstevel@tonic-gate bakchar:
10520Sstevel@tonic-gate cp = lastchr(ogcursor, gcursor);
10530Sstevel@tonic-gate if (cp < ogcursor) {
10540Sstevel@tonic-gate if (splitw) {
10550Sstevel@tonic-gate /*
10560Sstevel@tonic-gate * Backspacing over readecho
10570Sstevel@tonic-gate * prompt. Pretend delete but
10580Sstevel@tonic-gate * don't beep.
10590Sstevel@tonic-gate */
10600Sstevel@tonic-gate ungetkey(c);
10610Sstevel@tonic-gate goto vadone;
10620Sstevel@tonic-gate }
1063802Scf46844 (void) beep();
10640Sstevel@tonic-gate continue;
10650Sstevel@tonic-gate }
10660Sstevel@tonic-gate goto vbackup;
10670Sstevel@tonic-gate
10680Sstevel@tonic-gate /*
10690Sstevel@tonic-gate * ^W Back up a white/non-white word.
10700Sstevel@tonic-gate */
10710Sstevel@tonic-gate case CTRL('w'):
10720Sstevel@tonic-gate wdkind = 1;
10730Sstevel@tonic-gate for (cp = gcursor; cp > ogcursor && isspace(cp[-1]); cp--)
10740Sstevel@tonic-gate continue;
10750Sstevel@tonic-gate pcp = lastchr(ogcursor, cp);
10760Sstevel@tonic-gate for (c = wordch(pcp);
10770Sstevel@tonic-gate cp > ogcursor && wordof(c, pcp); cp = pcp, pcp = lastchr(ogcursor, cp))
10780Sstevel@tonic-gate continue;
10790Sstevel@tonic-gate goto vbackup;
10800Sstevel@tonic-gate
10810Sstevel@tonic-gate /*
10820Sstevel@tonic-gate * users kill Kill input on this line, back to
10830Sstevel@tonic-gate * the autoindent.
10840Sstevel@tonic-gate */
10850Sstevel@tonic-gate case -1:
10860Sstevel@tonic-gate cp = ogcursor;
10870Sstevel@tonic-gate vbackup:
10880Sstevel@tonic-gate if (cp == gcursor) {
1089802Scf46844 (void) beep();
10900Sstevel@tonic-gate continue;
10910Sstevel@tonic-gate }
10920Sstevel@tonic-gate endim();
10930Sstevel@tonic-gate *cp = 0;
10940Sstevel@tonic-gate c = cindent();
10950Sstevel@tonic-gate vgotoCL(nqcolumn(lastchr(linebuf, cursor), genbuf));
10960Sstevel@tonic-gate
10970Sstevel@tonic-gate if (doomed >= 0)
10980Sstevel@tonic-gate doomed += c - cindent();
10990Sstevel@tonic-gate gcursor = cp;
11000Sstevel@tonic-gate continue;
11010Sstevel@tonic-gate
11020Sstevel@tonic-gate /*
11030Sstevel@tonic-gate * \ Followed by erase or kill
11040Sstevel@tonic-gate * maps to just the erase or kill.
11050Sstevel@tonic-gate */
11060Sstevel@tonic-gate case '\\':
11070Sstevel@tonic-gate x = destcol, y = destline;
11080Sstevel@tonic-gate putchar('\\');
11090Sstevel@tonic-gate vcsync();
11100Sstevel@tonic-gate c = getkey();
11110Sstevel@tonic-gate if (c == tty.c_cc[VERASE]
11120Sstevel@tonic-gate || c == tty.c_cc[VKILL])
11130Sstevel@tonic-gate {
11140Sstevel@tonic-gate vgoto(y, x);
11150Sstevel@tonic-gate if (doomed >= 0)
11160Sstevel@tonic-gate doomed++;
11170Sstevel@tonic-gate multic[0] = wchar = c;
11180Sstevel@tonic-gate length = 1;
11190Sstevel@tonic-gate goto def;
11200Sstevel@tonic-gate }
11210Sstevel@tonic-gate ungetkey(c), c = '\\';
11220Sstevel@tonic-gate backsl = 1;
11230Sstevel@tonic-gate break;
11240Sstevel@tonic-gate
11250Sstevel@tonic-gate /*
11260Sstevel@tonic-gate * ^Q Super quote following character
11270Sstevel@tonic-gate * Only ^@ is verboten (trapped at
11280Sstevel@tonic-gate * a lower level) and \n forces a line
11290Sstevel@tonic-gate * split so doesn't really go in.
11300Sstevel@tonic-gate *
11310Sstevel@tonic-gate * ^V Synonym for ^Q
11320Sstevel@tonic-gate */
11330Sstevel@tonic-gate case CTRL('q'):
11340Sstevel@tonic-gate case CTRL('v'):
11350Sstevel@tonic-gate x = destcol, y = destline;
11360Sstevel@tonic-gate putchar('^');
11370Sstevel@tonic-gate vgoto(y, x);
11380Sstevel@tonic-gate c = getkey();
11390Sstevel@tonic-gate #ifdef USG
11400Sstevel@tonic-gate if (c == ATTN)
11410Sstevel@tonic-gate c = tty.c_cc[VINTR];
11420Sstevel@tonic-gate #endif
11430Sstevel@tonic-gate if (c != NL) {
11440Sstevel@tonic-gate if (doomed >= 0)
11450Sstevel@tonic-gate doomed++;
11460Sstevel@tonic-gate multic[0] = wchar = c;
11470Sstevel@tonic-gate length = 1;
11480Sstevel@tonic-gate goto def;
11490Sstevel@tonic-gate }
11500Sstevel@tonic-gate break;
11510Sstevel@tonic-gate }
11520Sstevel@tonic-gate }
11530Sstevel@tonic-gate
11540Sstevel@tonic-gate /*
11550Sstevel@tonic-gate * If we get a blank not in the echo area
11560Sstevel@tonic-gate * consider splitting the window in the wrapmargin.
11570Sstevel@tonic-gate */
11580Sstevel@tonic-gate if(!backsl) {
11590Sstevel@tonic-gate ungetkey(c);
11600Sstevel@tonic-gate if((length = _mbftowc((char *)multic, &wchar, getkey, &Peekkey)) <= 0) {
1161802Scf46844 (void) beep();
11620Sstevel@tonic-gate continue;
11630Sstevel@tonic-gate }
11640Sstevel@tonic-gate } else {
11650Sstevel@tonic-gate length = 1;
11660Sstevel@tonic-gate multic[0] = '\\';
11670Sstevel@tonic-gate }
11680Sstevel@tonic-gate
11690Sstevel@tonic-gate if (c != NL && !splitw) {
11700Sstevel@tonic-gate if (c == ' ' && gobblebl) {
11710Sstevel@tonic-gate gobbled = 1;
11720Sstevel@tonic-gate continue;
11730Sstevel@tonic-gate }
11740Sstevel@tonic-gate if ((width = wcwidth(wchar)) <= 0)
11750Sstevel@tonic-gate width = (wchar <= 0177 ? 1 : 4);
11760Sstevel@tonic-gate if (value(vi_WRAPMARGIN) &&
11770Sstevel@tonic-gate (outcol + width - 1 >= OCOLUMNS - value(vi_WRAPMARGIN) ||
11780Sstevel@tonic-gate backsl && outcol==0) &&
11790Sstevel@tonic-gate commch != 'r') {
11800Sstevel@tonic-gate /*
11810Sstevel@tonic-gate * At end of word and hit wrapmargin.
11820Sstevel@tonic-gate * Move the word to next line and keep going.
11830Sstevel@tonic-gate */
11840Sstevel@tonic-gate unsigned char *wp;
11850Sstevel@tonic-gate int bytelength;
11860Sstevel@tonic-gate #ifndef PRESUNEUC
11870Sstevel@tonic-gate unsigned char *tgcursor;
11880Sstevel@tonic-gate wchar_t wc1, wc2;
11890Sstevel@tonic-gate tgcursor = gcursor;
11900Sstevel@tonic-gate #endif /* PRESUNEUC */
11910Sstevel@tonic-gate wdkind = 1;
11920Sstevel@tonic-gate strncpy(gcursor, multic, length);
11930Sstevel@tonic-gate gcursor += length;
11940Sstevel@tonic-gate if (backsl) {
11950Sstevel@tonic-gate #ifdef PRESUNEUC
11960Sstevel@tonic-gate if((length = mbftowc((char *)multic, &wchar, getkey, &Peekkey)) <= 0) {
11970Sstevel@tonic-gate #else
11980Sstevel@tonic-gate if((length = _mbftowc((char *)multic, &wchar, getkey, &Peekkey)) <= 0) {
11990Sstevel@tonic-gate #endif /* PRESUNEUC */
1200802Scf46844 (void) beep();
12010Sstevel@tonic-gate continue;
12020Sstevel@tonic-gate }
12030Sstevel@tonic-gate strncpy(gcursor, multic, length);
12040Sstevel@tonic-gate gcursor += length;
12050Sstevel@tonic-gate }
12060Sstevel@tonic-gate *gcursor = 0;
12070Sstevel@tonic-gate /*
12080Sstevel@tonic-gate * Find end of previous word if we are past it.
12090Sstevel@tonic-gate */
12100Sstevel@tonic-gate for (cp=gcursor; cp>ogcursor && isspace(cp[-1]); cp--)
12110Sstevel@tonic-gate ;
12120Sstevel@tonic-gate #ifdef PRESUNEUC
12130Sstevel@tonic-gate /* find screen width of previous word */
12140Sstevel@tonic-gate width = 0;
12150Sstevel@tonic-gate for(wp = cp; *wp; )
12160Sstevel@tonic-gate #else
12170Sstevel@tonic-gate /* count screen width of pending characters */
12180Sstevel@tonic-gate width = 0;
12190Sstevel@tonic-gate for(wp = tgcursor; wp < cp;)
12200Sstevel@tonic-gate #endif /* PRESUNEUC */
12210Sstevel@tonic-gate if((bytelength = mbtowc(&wchar, (char *)wp, MULTI_BYTE_MAX)) < 0) {
12220Sstevel@tonic-gate width+=4;
12230Sstevel@tonic-gate wp++;
12240Sstevel@tonic-gate } else {
12250Sstevel@tonic-gate int curwidth = wcwidth(wchar);
12260Sstevel@tonic-gate if(curwidth <= 0)
12270Sstevel@tonic-gate width += (*wp < 0200 ? 2 : 4);
12280Sstevel@tonic-gate else
12290Sstevel@tonic-gate width += curwidth;
12300Sstevel@tonic-gate wp += bytelength;
12310Sstevel@tonic-gate }
12320Sstevel@tonic-gate
12330Sstevel@tonic-gate #ifdef PRESUNEUC
12340Sstevel@tonic-gate if (outcol+(backsl?OCOLUMNS:0) - width >= OCOLUMNS - value(vi_WRAPMARGIN)) {
12350Sstevel@tonic-gate #else
12360Sstevel@tonic-gate if (outcol+(backsl?OCOLUMNS:0) + width -1 >= OCOLUMNS - value(vi_WRAPMARGIN)) {
12370Sstevel@tonic-gate #endif /* PRESUNEUC */
12380Sstevel@tonic-gate /*
12390Sstevel@tonic-gate * Find beginning of previous word.
12400Sstevel@tonic-gate */
12410Sstevel@tonic-gate #ifdef PRESUNEUC
12420Sstevel@tonic-gate for (; cp>ogcursor && !isspace(cp[-1]); cp--)
12430Sstevel@tonic-gate ;
12440Sstevel@tonic-gate #else
12450Sstevel@tonic-gate wc1 = wc2 = 0;
12460Sstevel@tonic-gate while (cp>ogcursor) {
12470Sstevel@tonic-gate if (isspace(cp[-1])) {
12480Sstevel@tonic-gate break;
12490Sstevel@tonic-gate }
12500Sstevel@tonic-gate if (!multibyte) {
12510Sstevel@tonic-gate cp--;
12520Sstevel@tonic-gate continue;
12530Sstevel@tonic-gate }
12540Sstevel@tonic-gate wp = (unsigned char *)(cp -
12550Sstevel@tonic-gate MB_CUR_MAX);
12560Sstevel@tonic-gate if (wp < ogcursor)
12570Sstevel@tonic-gate wp = ogcursor;
12580Sstevel@tonic-gate while (cp > wp) {
12590Sstevel@tonic-gate /* 7tabs */if (wc2) {
12600Sstevel@tonic-gate /* 7tabs */ if ((bytelength = mbtowc(&wc1, (char *)wp, cp-wp)) != cp-wp) {
12610Sstevel@tonic-gate /* 7tabs */ wp++;
12620Sstevel@tonic-gate /* 7tabs */ wc1 = 0;
12630Sstevel@tonic-gate /* 7tabs */ continue;
12640Sstevel@tonic-gate /* 7tabs */ }
12650Sstevel@tonic-gate /* 7tabs */} else {
12660Sstevel@tonic-gate /* 7tabs */ if ((bytelength = mbtowc(&wc2, (char *)wp, cp-wp)) != cp-wp) {
12670Sstevel@tonic-gate /* 7tabs */ wp++;
12680Sstevel@tonic-gate /* 7tabs */ wc2 = 0;
12690Sstevel@tonic-gate /* 7tabs */ continue;
12700Sstevel@tonic-gate /* 7tabs */ }
12710Sstevel@tonic-gate /* 7tabs */}
12720Sstevel@tonic-gate /* 7tabs */if (wc1) {
12730Sstevel@tonic-gate /* 7tabs */ if (wdbdg && (!iswascii(wc1) || !iswascii(wc2))) {
12740Sstevel@tonic-gate /* 7tabs */ if ((*wdbdg)(wc1, wc2, 2) < 5) {
12750Sstevel@tonic-gate /* 7tabs */ goto ws;
12760Sstevel@tonic-gate /* 7tabs */ }
12770Sstevel@tonic-gate /* 7tabs */ }
12780Sstevel@tonic-gate /* 7tabs */ wc2 = wc1;
12790Sstevel@tonic-gate /* 7tabs */ wc1 = 0;
12800Sstevel@tonic-gate /* 7tabs */ cp -= bytelength - 1;
12810Sstevel@tonic-gate /* 7tabs */ break;
12820Sstevel@tonic-gate /* 7tabs */} else {
12830Sstevel@tonic-gate /* 7tabs */ cp -= bytelength - 1;
12840Sstevel@tonic-gate /* 7tabs */ break;
12850Sstevel@tonic-gate /* 7tabs */}
12860Sstevel@tonic-gate }
12870Sstevel@tonic-gate cp--;
12880Sstevel@tonic-gate }
12890Sstevel@tonic-gate ws:
12900Sstevel@tonic-gate #endif /* PRESUNEUC */
12910Sstevel@tonic-gate if (cp <= ogcursor) {
12920Sstevel@tonic-gate /*
12930Sstevel@tonic-gate * There is a single word that
12940Sstevel@tonic-gate * is too long to fit. Just
12950Sstevel@tonic-gate * let it pass, but beep for
12960Sstevel@tonic-gate * each new letter to warn
12970Sstevel@tonic-gate * the luser.
12980Sstevel@tonic-gate */
12990Sstevel@tonic-gate gcursor -= length;
13000Sstevel@tonic-gate c = *gcursor;
13010Sstevel@tonic-gate *gcursor = 0;
1302802Scf46844 (void) beep();
13030Sstevel@tonic-gate goto dontbreak;
13040Sstevel@tonic-gate }
13050Sstevel@tonic-gate /*
13060Sstevel@tonic-gate * Save it for next line.
13070Sstevel@tonic-gate */
13080Sstevel@tonic-gate macpush(cp, 0);
13090Sstevel@tonic-gate #ifdef PRESUNEUC
13100Sstevel@tonic-gate cp--;
13110Sstevel@tonic-gate #endif /* PRESUNEUC */
13120Sstevel@tonic-gate }
13130Sstevel@tonic-gate macpush("\n", 0);
13140Sstevel@tonic-gate /*
13150Sstevel@tonic-gate * Erase white space before the word.
13160Sstevel@tonic-gate */
13170Sstevel@tonic-gate while (cp > ogcursor && isspace(cp[-1]))
13180Sstevel@tonic-gate cp--; /* skip blank */
13190Sstevel@tonic-gate gobblebl = 3;
13200Sstevel@tonic-gate goto vbackup;
13210Sstevel@tonic-gate }
13220Sstevel@tonic-gate dontbreak:;
13230Sstevel@tonic-gate }
13240Sstevel@tonic-gate
13250Sstevel@tonic-gate /*
13260Sstevel@tonic-gate * Word abbreviation mode.
13270Sstevel@tonic-gate */
13280Sstevel@tonic-gate if (anyabbrs && gcursor > ogcursor && !wordch(multic) && wordch(lastchr(ogcursor, gcursor))) {
13290Sstevel@tonic-gate int wdtype, abno;
13300Sstevel@tonic-gate
13310Sstevel@tonic-gate multic[length] = 0;
13320Sstevel@tonic-gate wdkind = 1;
13330Sstevel@tonic-gate cp = lastchr(ogcursor, gcursor);
13340Sstevel@tonic-gate pcp = lastchr(ogcursor, cp);
13350Sstevel@tonic-gate for (wdtype = wordch(pcp);
13360Sstevel@tonic-gate cp > ogcursor && wordof(wdtype, pcp); cp = pcp, pcp = lastchr(ogcursor, pcp))
13370Sstevel@tonic-gate ;
13380Sstevel@tonic-gate *gcursor = 0;
13390Sstevel@tonic-gate for (abno=0; abbrevs[abno].mapto; abno++) {
13400Sstevel@tonic-gate if (eq(cp, abbrevs[abno].cap)) {
13410Sstevel@tonic-gate if(abbrepcnt == 0) {
13420Sstevel@tonic-gate if(reccnt(abbrevs[abno].cap, abbrevs[abno].mapto))
13430Sstevel@tonic-gate abbrepcnt = 1;
13440Sstevel@tonic-gate macpush(multic, 0);
13450Sstevel@tonic-gate macpush(abbrevs[abno].mapto);
13460Sstevel@tonic-gate goto vbackup;
13470Sstevel@tonic-gate } else
13480Sstevel@tonic-gate abbrepcnt = 0;
13490Sstevel@tonic-gate }
13500Sstevel@tonic-gate }
13510Sstevel@tonic-gate }
13520Sstevel@tonic-gate
13530Sstevel@tonic-gate switch (c) {
13540Sstevel@tonic-gate
13550Sstevel@tonic-gate /*
13560Sstevel@tonic-gate * ^M Except in repeat maps to \n.
13570Sstevel@tonic-gate */
13580Sstevel@tonic-gate case CR:
13590Sstevel@tonic-gate if (vglobp) {
13600Sstevel@tonic-gate multic[0] = wchar = c;
13610Sstevel@tonic-gate length = 1;
13620Sstevel@tonic-gate goto def;
13630Sstevel@tonic-gate }
13640Sstevel@tonic-gate c = '\n';
13650Sstevel@tonic-gate /* presto chango ... */
13660Sstevel@tonic-gate
13670Sstevel@tonic-gate /*
13680Sstevel@tonic-gate * \n Start new line.
13690Sstevel@tonic-gate */
13700Sstevel@tonic-gate case NL:
13710Sstevel@tonic-gate *aescaped = c;
13720Sstevel@tonic-gate goto vadone;
13730Sstevel@tonic-gate
13740Sstevel@tonic-gate /*
13750Sstevel@tonic-gate * escape End insert unless repeat and more to repeat.
13760Sstevel@tonic-gate */
13770Sstevel@tonic-gate case ESCAPE:
13780Sstevel@tonic-gate if (lastvgk) {
13790Sstevel@tonic-gate multic[0] = wchar = c;
13800Sstevel@tonic-gate length = 1;
13810Sstevel@tonic-gate goto def;
13820Sstevel@tonic-gate }
13830Sstevel@tonic-gate goto vadone;
13840Sstevel@tonic-gate
13850Sstevel@tonic-gate /*
13860Sstevel@tonic-gate * ^D Backtab.
13870Sstevel@tonic-gate * ^T Software forward tab.
13880Sstevel@tonic-gate *
13890Sstevel@tonic-gate * Unless in repeat where this means these
13900Sstevel@tonic-gate * were superquoted in.
13910Sstevel@tonic-gate */
13920Sstevel@tonic-gate case CTRL('t'):
13930Sstevel@tonic-gate if (vglobp) {
13940Sstevel@tonic-gate multic[0] = wchar = c;
13950Sstevel@tonic-gate length = 1;
13960Sstevel@tonic-gate goto def;
13970Sstevel@tonic-gate }
13980Sstevel@tonic-gate /* fall into ... */
13990Sstevel@tonic-gate
14000Sstevel@tonic-gate *gcursor = 0;
14010Sstevel@tonic-gate cp = vpastwh(genbuf);
14020Sstevel@tonic-gate c = whitecnt(genbuf);
14030Sstevel@tonic-gate if (ch == CTRL('t')) {
14040Sstevel@tonic-gate /*
14050Sstevel@tonic-gate * ^t just generates new indent replacing
14060Sstevel@tonic-gate * current white space rounded up to soft
14070Sstevel@tonic-gate * tab stop increment.
14080Sstevel@tonic-gate */
14090Sstevel@tonic-gate if (cp != gcursor)
14100Sstevel@tonic-gate /*
14110Sstevel@tonic-gate * BUG: Don't hack ^T except
14120Sstevel@tonic-gate * right after initial
14130Sstevel@tonic-gate * white space.
14140Sstevel@tonic-gate */
14150Sstevel@tonic-gate continue;
14160Sstevel@tonic-gate cp = genindent(iwhite = backtab(c + value(vi_SHIFTWIDTH) + 1));
14170Sstevel@tonic-gate ogcursor = cp;
14180Sstevel@tonic-gate goto vbackup;
14190Sstevel@tonic-gate }
14200Sstevel@tonic-gate /*
14210Sstevel@tonic-gate * ^D works only if we are at the (end of) the
14220Sstevel@tonic-gate * generated autoindent. We count the ^D for repeat
14230Sstevel@tonic-gate * purposes.
14240Sstevel@tonic-gate */
14250Sstevel@tonic-gate case CTRL('d'):
14260Sstevel@tonic-gate /* check if ^d was superquoted in */
14270Sstevel@tonic-gate if(vglobp && inscdcnt <= 0) {
14280Sstevel@tonic-gate multic[0] = wchar = c;
14290Sstevel@tonic-gate length = 1;
14300Sstevel@tonic-gate goto def;
14310Sstevel@tonic-gate }
14320Sstevel@tonic-gate if(vglobp)
14330Sstevel@tonic-gate inscdcnt--;
14340Sstevel@tonic-gate *gcursor = 0;
14350Sstevel@tonic-gate cp = vpastwh(genbuf);
14360Sstevel@tonic-gate c = whitecnt(genbuf);
14370Sstevel@tonic-gate if (c == iwhite && c != 0)
14380Sstevel@tonic-gate if (cp == gcursor) {
14390Sstevel@tonic-gate iwhite = backtab(c);
14400Sstevel@tonic-gate CDCNT++;
14410Sstevel@tonic-gate ogcursor = cp = genindent(iwhite);
14420Sstevel@tonic-gate goto vbackup;
14430Sstevel@tonic-gate } else if (&cp[1] == gcursor &&
14440Sstevel@tonic-gate (*cp == '^' || *cp == '0')) {
14450Sstevel@tonic-gate /*
14460Sstevel@tonic-gate * ^^D moves to margin, then back
14470Sstevel@tonic-gate * to current indent on next line.
14480Sstevel@tonic-gate *
14490Sstevel@tonic-gate * 0^D moves to margin and then
14500Sstevel@tonic-gate * stays there.
14510Sstevel@tonic-gate */
14520Sstevel@tonic-gate HADZERO = *cp == '0';
14530Sstevel@tonic-gate ogcursor = cp = genbuf;
14540Sstevel@tonic-gate HADUP = 1 - HADZERO;
14550Sstevel@tonic-gate CDCNT = 1;
14560Sstevel@tonic-gate endim();
14570Sstevel@tonic-gate back1();
1458802Scf46844 (void) vputchar(' ');
14590Sstevel@tonic-gate goto vbackup;
14600Sstevel@tonic-gate }
14610Sstevel@tonic-gate
14620Sstevel@tonic-gate if (vglobp && vglobp - iglobp >= 2) {
14630Sstevel@tonic-gate if ((p = vglobp - MB_CUR_MAX) < iglobp)
14640Sstevel@tonic-gate p = iglobp;
14650Sstevel@tonic-gate for ( ; p < &vglobp[-2]; p += len) {
14660Sstevel@tonic-gate if ((len = mblen((char *)p, MB_CUR_MAX)) <= 0)
14670Sstevel@tonic-gate len = 1;
14680Sstevel@tonic-gate }
14690Sstevel@tonic-gate if ((p == &vglobp[-2]) &&
14700Sstevel@tonic-gate (*p == '^' || *p == '0') &&
14710Sstevel@tonic-gate gcursor == ogcursor + 1)
14720Sstevel@tonic-gate goto bakchar;
14730Sstevel@tonic-gate }
14740Sstevel@tonic-gate continue;
14750Sstevel@tonic-gate
14760Sstevel@tonic-gate default:
14770Sstevel@tonic-gate /*
14780Sstevel@tonic-gate * Possibly discard control inputs.
14790Sstevel@tonic-gate */
14800Sstevel@tonic-gate if (!vglobp && junk(c)) {
1481802Scf46844 (void) beep();
14820Sstevel@tonic-gate continue;
14830Sstevel@tonic-gate }
14840Sstevel@tonic-gate def:
14850Sstevel@tonic-gate if (!backsl) {
14860Sstevel@tonic-gate putchar(wchar);
14870Sstevel@tonic-gate flush();
14880Sstevel@tonic-gate }
14890Sstevel@tonic-gate if (gcursor + length - 1 > &genbuf[LBSIZE - 2])
14900Sstevel@tonic-gate error(gettext("Line too long"));
14910Sstevel@tonic-gate (void)strncpy(gcursor, multic, length);
14920Sstevel@tonic-gate gcursor += length;
14930Sstevel@tonic-gate vcsync();
14940Sstevel@tonic-gate if (value(vi_SHOWMATCH) && !iglobp)
14950Sstevel@tonic-gate if (c == ')' || c == '}')
14960Sstevel@tonic-gate lsmatch(gcursor);
14970Sstevel@tonic-gate continue;
14980Sstevel@tonic-gate }
14990Sstevel@tonic-gate }
15000Sstevel@tonic-gate vadone:
15010Sstevel@tonic-gate *gcursor = 0;
15020Sstevel@tonic-gate if (Outchar != termchar)
15030Sstevel@tonic-gate Outchar = OO;
15040Sstevel@tonic-gate endim();
15050Sstevel@tonic-gate return (gcursor);
15060Sstevel@tonic-gate }
15070Sstevel@tonic-gate
15080Sstevel@tonic-gate int vgetsplit();
15090Sstevel@tonic-gate unsigned char *vsplitpt;
15100Sstevel@tonic-gate
15110Sstevel@tonic-gate /*
15120Sstevel@tonic-gate * Append the line in buffer at lp
15130Sstevel@tonic-gate * to the buffer after dot.
15140Sstevel@tonic-gate */
1515802Scf46844 void
vdoappend(unsigned char * lp)1516802Scf46844 vdoappend(unsigned char *lp)
15170Sstevel@tonic-gate {
1518802Scf46844 int oing = inglobal;
15190Sstevel@tonic-gate
15200Sstevel@tonic-gate vsplitpt = lp;
15210Sstevel@tonic-gate inglobal = 1;
15220Sstevel@tonic-gate (void)append(vgetsplit, dot);
15230Sstevel@tonic-gate inglobal = oing;
15240Sstevel@tonic-gate }
15250Sstevel@tonic-gate
15260Sstevel@tonic-gate /*
15270Sstevel@tonic-gate * Subroutine for vdoappend to pass to append.
15280Sstevel@tonic-gate */
1529802Scf46844 int
vgetsplit(void)1530802Scf46844 vgetsplit(void)
15310Sstevel@tonic-gate {
15320Sstevel@tonic-gate
15330Sstevel@tonic-gate if (vsplitpt == 0)
15340Sstevel@tonic-gate return (EOF);
15350Sstevel@tonic-gate strcLIN(vsplitpt);
15360Sstevel@tonic-gate vsplitpt = 0;
15370Sstevel@tonic-gate return (0);
15380Sstevel@tonic-gate }
15390Sstevel@tonic-gate
15400Sstevel@tonic-gate /*
15410Sstevel@tonic-gate * Vmaxrep determines the maximum repetition factor
15420Sstevel@tonic-gate * allowed that will yield total line length less than
15430Sstevel@tonic-gate * LBSIZE characters and also does hacks for the R command.
15440Sstevel@tonic-gate */
1545802Scf46844 int
vmaxrep(unsigned char ch,int cnt)1546802Scf46844 vmaxrep(unsigned char ch, int cnt)
15470Sstevel@tonic-gate {
1548802Scf46844 int len;
15490Sstevel@tonic-gate unsigned char *cp;
15500Sstevel@tonic-gate int repcnt, oldcnt, replen;
15510Sstevel@tonic-gate if (cnt > LBSIZE - 2)
15520Sstevel@tonic-gate cnt = LBSIZE - 2;
15530Sstevel@tonic-gate if (ch == 'R') {
15540Sstevel@tonic-gate len = strlen(cursor);
15550Sstevel@tonic-gate oldcnt = 0;
15560Sstevel@tonic-gate for(cp = cursor; *cp; ) {
15570Sstevel@tonic-gate oldcnt++;
15580Sstevel@tonic-gate cp = nextchr(cp);
15590Sstevel@tonic-gate }
15600Sstevel@tonic-gate repcnt = 0;
15610Sstevel@tonic-gate for(cp = genbuf; *cp; ) {
15620Sstevel@tonic-gate repcnt++;
15630Sstevel@tonic-gate cp = nextchr(cp);
15640Sstevel@tonic-gate }
15650Sstevel@tonic-gate /*
15660Sstevel@tonic-gate * if number of characters in replacement string
15670Sstevel@tonic-gate * (repcnt) is less than number of characters following
15680Sstevel@tonic-gate * cursor (oldcnt), find end of repcnt
15690Sstevel@tonic-gate * characters after cursor
15700Sstevel@tonic-gate */
15710Sstevel@tonic-gate if(repcnt < oldcnt) {
15720Sstevel@tonic-gate for(cp = cursor; repcnt > 0; repcnt--)
15730Sstevel@tonic-gate cp = nextchr(cp);
15740Sstevel@tonic-gate len = cp - cursor;
15750Sstevel@tonic-gate }
15760Sstevel@tonic-gate CP(cursor, cursor + len);
15770Sstevel@tonic-gate vUD2 += len;
15780Sstevel@tonic-gate }
15790Sstevel@tonic-gate len = strlen(linebuf);
15800Sstevel@tonic-gate replen = strlen(genbuf);
15810Sstevel@tonic-gate if (len + cnt * replen <= LBSIZE - 2)
15820Sstevel@tonic-gate return (cnt);
15830Sstevel@tonic-gate cnt = (LBSIZE - 2 - len) / replen;
15840Sstevel@tonic-gate if (cnt == 0) {
15850Sstevel@tonic-gate vsave();
15860Sstevel@tonic-gate error(gettext("Line too long"));
15870Sstevel@tonic-gate }
15880Sstevel@tonic-gate return (cnt);
15890Sstevel@tonic-gate }
15900Sstevel@tonic-gate
15910Sstevel@tonic-gate /*
15920Sstevel@tonic-gate * Determine how many occurrences of word 'CAP' are in 'MAPTO'. To be
15930Sstevel@tonic-gate * considered an occurrence there must be both a nonword-prefix, a
15940Sstevel@tonic-gate * complete match of 'CAP' within 'MAPTO', and a nonword-suffix.
15950Sstevel@tonic-gate * Note that the beginning and end of 'MAPTO' are considered to be
15960Sstevel@tonic-gate * valid nonword delimiters.
15970Sstevel@tonic-gate */
1598802Scf46844 int
reccnt(unsigned char * cap,unsigned char * mapto)1599802Scf46844 reccnt(unsigned char *cap, unsigned char *mapto)
16000Sstevel@tonic-gate {
1601802Scf46844 int i, cnt, final;
16020Sstevel@tonic-gate
16030Sstevel@tonic-gate cnt = 0;
16040Sstevel@tonic-gate final = strlen(mapto) - strlen(cap);
16050Sstevel@tonic-gate
16060Sstevel@tonic-gate for (i=0; i <= final; i++)
16070Sstevel@tonic-gate if ((strncmp(cap, mapto+i, strlen(cap)) == 0) /* match */
16080Sstevel@tonic-gate && (i == 0 || !wordch(&mapto[i-1])) /* prefix ok */
16090Sstevel@tonic-gate && (i == final || !wordch(&mapto[i+strlen(cap)]))) /* suffix ok */
16100Sstevel@tonic-gate cnt++;
16110Sstevel@tonic-gate return (cnt);
16120Sstevel@tonic-gate }
16130Sstevel@tonic-gate
1614