1cd8169f0Sbostic /*-
2*ca303e1fSbostic * Copyright (c) 1980, 1993
3*ca303e1fSbostic * The Regents of the University of California. All rights reserved.
4cd8169f0Sbostic *
5cd8169f0Sbostic * %sccs.include.proprietary.c%
6035a5d32Sdist */
7035a5d32Sdist
8035a5d32Sdist #ifndef lint
9*ca303e1fSbostic static char sccsid[] = "@(#)ex_vops2.c 8.1 (Berkeley) 06/09/93";
10cd8169f0Sbostic #endif /* not lint */
11035a5d32Sdist
1264137b10Smark #include "ex.h"
1364137b10Smark #include "ex_tty.h"
1464137b10Smark #include "ex_vis.h"
1564137b10Smark
1664137b10Smark /*
1764137b10Smark * Low level routines for operations sequences,
1864137b10Smark * and mostly, insert mode (and a subroutine
1964137b10Smark * to read an input line, including in the echo area.)
2064137b10Smark */
21562c8f51Sdist extern char *vUA1, *vUA2; /* mjm: extern; also in ex_vops.c */
22562c8f51Sdist extern char *vUD1, *vUD2; /* mjm: extern; also in ex_vops.c */
2364137b10Smark
2464137b10Smark /*
2564137b10Smark * Obleeperate characters in hardcopy
2664137b10Smark * open with \'s.
2764137b10Smark */
bleep(i,cp)2864137b10Smark bleep(i, cp)
2964137b10Smark register int i;
3064137b10Smark char *cp;
3164137b10Smark {
3264137b10Smark
3364137b10Smark i -= column(cp);
3464137b10Smark do
35c0a5300eSconrad ex_putchar('\\' | QUOTE);
3664137b10Smark while (--i >= 0);
3764137b10Smark rubble = 1;
3864137b10Smark }
3964137b10Smark
4064137b10Smark /*
4164137b10Smark * Common code for middle part of delete
4264137b10Smark * and change operating on parts of lines.
4364137b10Smark */
vdcMID()4464137b10Smark vdcMID()
4564137b10Smark {
4664137b10Smark register char *cp;
4764137b10Smark
4864137b10Smark squish();
4964137b10Smark setLAST();
5025da3ac7Smark if (FIXUNDO)
5164137b10Smark vundkind = VCHNG, CP(vutmp, linebuf);
5264137b10Smark if (wcursor < cursor)
5364137b10Smark cp = wcursor, wcursor = cursor, cursor = cp;
5464137b10Smark vUD1 = vUA1 = vUA2 = cursor; vUD2 = wcursor;
5564137b10Smark return (column(wcursor - 1));
5664137b10Smark }
5764137b10Smark
5864137b10Smark /*
5964137b10Smark * Take text from linebuf and stick it
6064137b10Smark * in the VBSIZE buffer BUF. Used to save
6164137b10Smark * deleted text of part of line.
6264137b10Smark */
takeout(BUF)6364137b10Smark takeout(BUF)
6464137b10Smark char *BUF;
6564137b10Smark {
6664137b10Smark register char *cp;
6764137b10Smark
6864137b10Smark if (wcursor < linebuf)
6964137b10Smark wcursor = linebuf;
7064137b10Smark if (cursor == wcursor) {
7164137b10Smark beep();
7264137b10Smark return;
7364137b10Smark }
7464137b10Smark if (wcursor < cursor) {
7564137b10Smark cp = wcursor;
7664137b10Smark wcursor = cursor;
7764137b10Smark cursor = cp;
7864137b10Smark }
79c0a5300eSconrad ex_setBUF(BUF);
8064137b10Smark if ((BUF[0] & (QUOTE|TRIM)) == OVERBUF)
8164137b10Smark beep();
8264137b10Smark }
8364137b10Smark
8464137b10Smark /*
8564137b10Smark * Are we at the end of the printed representation of the
8664137b10Smark * line? Used internally in hardcopy open.
8764137b10Smark */
ateopr()8864137b10Smark ateopr()
8964137b10Smark {
9064137b10Smark register int i, c;
9164137b10Smark register char *cp = vtube[destline] + destcol;
9264137b10Smark
9364137b10Smark for (i = WCOLS - destcol; i > 0; i--) {
9464137b10Smark c = *cp++;
9564137b10Smark if (c == 0)
9664137b10Smark return (1);
9764137b10Smark if (c != ' ' && (c & QUOTE) == 0)
9864137b10Smark return (0);
9964137b10Smark }
10064137b10Smark return (1);
10164137b10Smark }
10264137b10Smark
10364137b10Smark /*
10464137b10Smark * Append.
10564137b10Smark *
10664137b10Smark * This routine handles the top level append, doing work
10764137b10Smark * as each new line comes in, and arranging repeatability.
10864137b10Smark * It also handles append with repeat counts, and calculation
10964137b10Smark * of autoindents for new lines.
11064137b10Smark */
11164137b10Smark bool vaifirst;
11264137b10Smark bool gobbled;
11364137b10Smark char *ogcursor;
11464137b10Smark
vappend(ch,cnt,indent)11564137b10Smark vappend(ch, cnt, indent)
116562c8f51Sdist int ch; /* mjm: char --> int */
11764137b10Smark int cnt, indent;
11864137b10Smark {
11964137b10Smark register int i;
12064137b10Smark register char *gcursor;
12164137b10Smark bool escape;
122562c8f51Sdist int repcnt, savedoomed;
12364137b10Smark short oldhold = hold;
124c0a5300eSconrad #ifdef SIGWINCH
125562c8f51Sdist int oldmask;
126c0a5300eSconrad #endif
12764137b10Smark
12864137b10Smark /*
12964137b10Smark * Before a move in hardopen when the line is dirty
13064137b10Smark * or we are in the middle of the printed representation,
13164137b10Smark * we retype the line to the left of the cursor so the
13264137b10Smark * insert looks clean.
13364137b10Smark */
13464137b10Smark if (ch != 'o' && state == HARDOPEN && (rubble || !ateopr())) {
13564137b10Smark rubble = 1;
13664137b10Smark gcursor = cursor;
13764137b10Smark i = *gcursor;
13864137b10Smark *gcursor = ' ';
13964137b10Smark wcursor = gcursor;
14064137b10Smark vmove();
14164137b10Smark *gcursor = i;
14264137b10Smark }
14364137b10Smark vaifirst = indent == 0;
14464137b10Smark
14564137b10Smark /*
14664137b10Smark * Handle replace character by (eventually)
14764137b10Smark * limiting the number of input characters allowed
14864137b10Smark * in the vgetline routine.
14964137b10Smark */
15064137b10Smark if (ch == 'r')
15164137b10Smark repcnt = 2;
15264137b10Smark else
15364137b10Smark repcnt = 0;
15464137b10Smark
15564137b10Smark /*
15664137b10Smark * If an autoindent is specified, then
15764137b10Smark * generate a mixture of blanks to tabs to implement
15864137b10Smark * it and place the cursor after the indent.
15964137b10Smark * Text read by the vgetline routine will be placed in genbuf,
16064137b10Smark * so the indent is generated there.
16164137b10Smark */
16264137b10Smark if (value(AUTOINDENT) && indent != 0) {
16364137b10Smark gcursor = genindent(indent);
16464137b10Smark *gcursor = 0;
16564137b10Smark vgotoCL(qcolumn(cursor - 1, genbuf));
16664137b10Smark } else {
16764137b10Smark gcursor = genbuf;
16864137b10Smark *gcursor = 0;
16964137b10Smark if (ch == 'o')
17064137b10Smark vfixcurs();
17164137b10Smark }
17264137b10Smark
17364137b10Smark /*
17464137b10Smark * Prepare for undo. Pointers delimit inserted portion of line.
17564137b10Smark */
17664137b10Smark vUA1 = vUA2 = cursor;
17764137b10Smark
17864137b10Smark /*
17964137b10Smark * If we are not in a repeated command and a ^@ comes in
18064137b10Smark * then this means the previous inserted text.
18164137b10Smark * If there is none or it was too long to be saved,
18264137b10Smark * then beep() and also arrange to undo any damage done
18364137b10Smark * so far (e.g. if we are a change.)
18464137b10Smark */
18564137b10Smark if ((vglobp && *vglobp == 0) || peekbr()) {
18664137b10Smark if ((INS[0] & (QUOTE|TRIM)) == OVERBUF) {
18764137b10Smark beep();
18864137b10Smark if (!splitw)
18964137b10Smark ungetkey('u');
19064137b10Smark doomed = 0;
19164137b10Smark hold = oldhold;
19264137b10Smark return;
19364137b10Smark }
19464137b10Smark /*
19564137b10Smark * Unread input from INS.
19664137b10Smark * An escape will be generated at end of string.
19764137b10Smark * Hold off n^^2 type update on dumb terminals.
19864137b10Smark */
19964137b10Smark vglobp = INS;
20064137b10Smark hold |= HOLDQIK;
20164137b10Smark } else if (vglobp == 0)
20264137b10Smark /*
20364137b10Smark * Not a repeated command, get
20464137b10Smark * a new inserted text for repeat.
20564137b10Smark */
20664137b10Smark INS[0] = 0;
20764137b10Smark
20864137b10Smark /*
20964137b10Smark * For wrapmargin to hack away second space after a '.'
21064137b10Smark * when the first space caused a line break we keep
21164137b10Smark * track that this happened in gobblebl, which says
21264137b10Smark * to gobble up a blank silently.
21364137b10Smark */
21464137b10Smark gobblebl = 0;
21564137b10Smark
216c0a5300eSconrad #ifdef SIGWINCH
217562c8f51Sdist oldmask = sigblock(sigmask(SIGWINCH));
218c0a5300eSconrad #endif
21964137b10Smark /*
22064137b10Smark * Text gathering loop.
22164137b10Smark * New text goes into genbuf starting at gcursor.
22264137b10Smark * cursor preserves place in linebuf where text will eventually go.
22364137b10Smark */
22464137b10Smark if (*cursor == 0 || state == CRTOPEN)
22564137b10Smark hold |= HOLDROL;
22664137b10Smark for (;;) {
22764137b10Smark if (ch == 'r' && repcnt == 0)
22864137b10Smark escape = 0;
22964137b10Smark else {
230562c8f51Sdist gcursor = vgetline(repcnt, gcursor, &escape, ch);
23164137b10Smark
23264137b10Smark /*
23364137b10Smark * After an append, stick information
23464137b10Smark * about the ^D's and ^^D's and 0^D's in
23564137b10Smark * the repeated text buffer so repeated
23664137b10Smark * inserts of stuff indented with ^D as backtab's
23764137b10Smark * can work.
23864137b10Smark */
23964137b10Smark if (HADUP)
24064137b10Smark addtext("^");
24164137b10Smark else if (HADZERO)
24264137b10Smark addtext("0");
24364137b10Smark while (CDCNT > 0)
24464137b10Smark addtext("\204"), CDCNT--;
24564137b10Smark if (gobbled)
24664137b10Smark addtext(" ");
24764137b10Smark addtext(ogcursor);
24864137b10Smark }
24964137b10Smark repcnt = 0;
25064137b10Smark
25164137b10Smark /*
25264137b10Smark * Smash the generated and preexisting indents together
25364137b10Smark * and generate one cleanly made out of tabs and spaces
25464137b10Smark * if we are using autoindent.
25564137b10Smark */
25664137b10Smark if (!vaifirst && value(AUTOINDENT)) {
25764137b10Smark i = fixindent(indent);
25864137b10Smark if (!HADUP)
25964137b10Smark indent = i;
26064137b10Smark gcursor = strend(genbuf);
26164137b10Smark }
26264137b10Smark
26364137b10Smark /*
26464137b10Smark * Limit the repetition count based on maximum
26564137b10Smark * possible line length; do output implied
26664137b10Smark * by further count (> 1) and cons up the new line
26764137b10Smark * in linebuf.
26864137b10Smark */
26964137b10Smark cnt = vmaxrep(ch, cnt);
27064137b10Smark CP(gcursor + 1, cursor);
27164137b10Smark do {
27264137b10Smark CP(cursor, genbuf);
27364137b10Smark if (cnt > 1) {
27464137b10Smark int oldhold = hold;
27564137b10Smark
27664137b10Smark Outchar = vinschar;
27764137b10Smark hold |= HOLDQIK;
278c0a5300eSconrad ex_printf("%s", genbuf);
27964137b10Smark hold = oldhold;
28064137b10Smark Outchar = vputchar;
28164137b10Smark }
28264137b10Smark cursor += gcursor - genbuf;
28364137b10Smark } while (--cnt > 0);
28464137b10Smark endim();
28564137b10Smark vUA2 = cursor;
28664137b10Smark if (escape != '\n')
28764137b10Smark CP(cursor, gcursor + 1);
28864137b10Smark
28964137b10Smark /*
29064137b10Smark * If doomed characters remain, clobber them,
29164137b10Smark * and reopen the line to get the display exact.
29264137b10Smark */
29364137b10Smark if (state != HARDOPEN) {
29464137b10Smark DEPTH(vcline) = 0;
295562c8f51Sdist savedoomed = doomed;
29664137b10Smark if (doomed > 0) {
29764137b10Smark register int cind = cindent();
29864137b10Smark
29964137b10Smark physdc(cind, cind + doomed);
30064137b10Smark doomed = 0;
30164137b10Smark }
30264137b10Smark i = vreopen(LINE(vcline), lineDOT(), vcline);
303562c8f51Sdist #ifdef TRACE
304562c8f51Sdist if (trace)
305562c8f51Sdist fprintf(trace, "restoring doomed from %d to %d\n", doomed, savedoomed);
306562c8f51Sdist #endif
307562c8f51Sdist if (ch == 'R')
308562c8f51Sdist doomed = savedoomed;
30964137b10Smark }
31064137b10Smark
31164137b10Smark /*
31264137b10Smark * All done unless we are continuing on to another line.
31364137b10Smark */
31464137b10Smark if (escape != '\n')
31564137b10Smark break;
31664137b10Smark
31764137b10Smark /*
31864137b10Smark * Set up for the new line.
31964137b10Smark * First save the current line, then construct a new
32064137b10Smark * first image for the continuation line consisting
32164137b10Smark * of any new autoindent plus the pushed ahead text.
32264137b10Smark */
32364137b10Smark killU();
32464137b10Smark addtext(gobblebl ? " " : "\n");
32564137b10Smark vsave();
32664137b10Smark cnt = 1;
32764137b10Smark if (value(AUTOINDENT)) {
32864137b10Smark #ifdef LISPCODE
32964137b10Smark if (value(LISP))
33064137b10Smark indent = lindent(dot + 1);
33164137b10Smark else
33264137b10Smark #endif
33364137b10Smark if (!HADUP && vaifirst)
33464137b10Smark indent = whitecnt(linebuf);
33564137b10Smark vaifirst = 0;
33664137b10Smark strcLIN(vpastwh(gcursor + 1));
33764137b10Smark gcursor = genindent(indent);
33864137b10Smark *gcursor = 0;
33964137b10Smark if (gcursor + strlen(linebuf) > &genbuf[LBSIZE - 2])
34064137b10Smark gcursor = genbuf;
34164137b10Smark CP(gcursor, linebuf);
34264137b10Smark } else {
34364137b10Smark CP(genbuf, gcursor + 1);
34464137b10Smark gcursor = genbuf;
34564137b10Smark }
34664137b10Smark
34764137b10Smark /*
34864137b10Smark * If we started out as a single line operation and are now
34964137b10Smark * turning into a multi-line change, then we had better yank
35064137b10Smark * out dot before it changes so that undo will work
35164137b10Smark * correctly later.
35264137b10Smark */
35325da3ac7Smark if (FIXUNDO && vundkind == VCHNG) {
35464137b10Smark vremote(1, yank, 0);
35564137b10Smark undap1--;
35664137b10Smark }
35764137b10Smark
35864137b10Smark /*
35964137b10Smark * Now do the append of the new line in the buffer,
36064137b10Smark * and update the display. If slowopen
36164137b10Smark * we don't do very much.
36264137b10Smark */
36364137b10Smark vdoappend(genbuf);
36464137b10Smark vundkind = VMANYINS;
36564137b10Smark vcline++;
36664137b10Smark if (state != VISUAL)
36764137b10Smark vshow(dot, NOLINE);
36864137b10Smark else {
36964137b10Smark i += LINE(vcline - 1);
37064137b10Smark vopen(dot, i);
37164137b10Smark if (value(SLOWOPEN))
37264137b10Smark vscrap();
37364137b10Smark else
37464137b10Smark vsync1(LINE(vcline));
37564137b10Smark }
37664137b10Smark strcLIN(gcursor);
37764137b10Smark *gcursor = 0;
37864137b10Smark cursor = linebuf;
37964137b10Smark vgotoCL(qcolumn(cursor - 1, genbuf));
38064137b10Smark }
38164137b10Smark
38264137b10Smark /*
38364137b10Smark * All done with insertion, position the cursor
38464137b10Smark * and sync the screen.
38564137b10Smark */
38664137b10Smark hold = oldhold;
38764137b10Smark if (cursor > linebuf)
38864137b10Smark cursor--;
38964137b10Smark if (state != HARDOPEN)
39064137b10Smark vsyncCL();
39164137b10Smark else if (cursor > linebuf)
39264137b10Smark back1();
39364137b10Smark doomed = 0;
39464137b10Smark wcursor = cursor;
39564137b10Smark vmove();
396c0a5300eSconrad #ifdef SIGWINCH
397562c8f51Sdist (void)sigsetmask(oldmask);
398c0a5300eSconrad #endif
39964137b10Smark }
40064137b10Smark
40164137b10Smark /*
40264137b10Smark * Subroutine for vgetline to back up a single character position,
40364137b10Smark * backwards around end of lines (vgoto can't hack columns which are
40464137b10Smark * less than 0 in general).
40564137b10Smark */
back1()40664137b10Smark back1()
40764137b10Smark {
40864137b10Smark
40964137b10Smark vgoto(destline - 1, WCOLS + destcol - 1);
41064137b10Smark }
41164137b10Smark
41264137b10Smark /*
41364137b10Smark * Get a line into genbuf after gcursor.
41464137b10Smark * Cnt limits the number of input characters
41564137b10Smark * accepted and is used for handling the replace
41664137b10Smark * single character command. Aescaped is the location
41764137b10Smark * where we stick a termination indicator (whether we
41864137b10Smark * ended with an ESCAPE or a newline/return.
41964137b10Smark *
42064137b10Smark * We do erase-kill type processing here and also
42164137b10Smark * are careful about the way we do this so that it is
42264137b10Smark * repeatable. (I.e. so that your kill doesn't happen,
42364137b10Smark * when you repeat an insert if it was escaped with \ the
424562c8f51Sdist * first time you did it. commch is the command character
425562c8f51Sdist * involved, including the prompt for readline.
42664137b10Smark */
42764137b10Smark char *
vgetline(cnt,gcursor,aescaped,commch)428562c8f51Sdist vgetline(cnt, gcursor, aescaped, commch)
42964137b10Smark int cnt;
43064137b10Smark register char *gcursor;
43164137b10Smark bool *aescaped;
432562c8f51Sdist char commch;
43364137b10Smark {
43464137b10Smark register int c, ch;
43564137b10Smark register char *cp;
436562c8f51Sdist int x, y, iwhite, backsl=0;
43764137b10Smark char *iglobp;
438db30859cSmark char cstr[2];
43964137b10Smark int (*OO)() = Outchar;
44064137b10Smark
44164137b10Smark /*
44264137b10Smark * Clear the output state and counters
44364137b10Smark * for autoindent backwards motion (counts of ^D, etc.)
44464137b10Smark * Remember how much white space at beginning of line so
44564137b10Smark * as not to allow backspace over autoindent.
44664137b10Smark */
44764137b10Smark *aescaped = 0;
44864137b10Smark ogcursor = gcursor;
44964137b10Smark flusho();
45064137b10Smark CDCNT = 0;
45164137b10Smark HADUP = 0;
45264137b10Smark HADZERO = 0;
45364137b10Smark gobbled = 0;
45464137b10Smark iwhite = whitecnt(genbuf);
45564137b10Smark iglobp = vglobp;
45664137b10Smark
45764137b10Smark /*
45864137b10Smark * Carefully avoid using vinschar in the echo area.
45964137b10Smark */
46064137b10Smark if (splitw)
46164137b10Smark Outchar = vputchar;
46264137b10Smark else {
46364137b10Smark Outchar = vinschar;
46464137b10Smark vprepins();
46564137b10Smark }
46664137b10Smark for (;;) {
467562c8f51Sdist backsl = 0;
46864137b10Smark if (gobblebl)
46964137b10Smark gobblebl--;
47064137b10Smark if (cnt != 0) {
47164137b10Smark cnt--;
47264137b10Smark if (cnt == 0)
47364137b10Smark goto vadone;
47464137b10Smark }
475db30859cSmark c = getkey();
476db30859cSmark if (c != ATTN)
477db30859cSmark c &= (QUOTE|TRIM);
478db30859cSmark ch = c;
479db30859cSmark maphopcnt = 0;
480c0a5300eSconrad if (vglobp == 0 && Peek_key == 0 && commch != 'r')
48125da3ac7Smark while ((ch = map(c, immacs)) != c) {
48264137b10Smark c = ch;
48325da3ac7Smark if (!value(REMAP))
48425da3ac7Smark break;
485db30859cSmark if (++maphopcnt > 256)
486db30859cSmark error("Infinite macro loop");
48725da3ac7Smark }
48864137b10Smark if (!iglobp) {
48964137b10Smark
49064137b10Smark /*
49164137b10Smark * Erase-kill type processing.
49264137b10Smark * Only happens if we were not reading
49364137b10Smark * from untyped input when we started.
49464137b10Smark * Map users erase to ^H, kill to -1 for switch.
49564137b10Smark */
496db30859cSmark #ifndef USG3TTY
49764137b10Smark if (c == tty.sg_erase)
4982949201cSbostic c = CTRL('h');
49964137b10Smark else if (c == tty.sg_kill)
50064137b10Smark c = -1;
501db30859cSmark #else
502db30859cSmark if (c == tty.c_cc[VERASE])
5032949201cSbostic c = CTRL('h');
504db30859cSmark else if (c == tty.c_cc[VKILL])
505db30859cSmark c = -1;
506db30859cSmark #endif
50764137b10Smark switch (c) {
50864137b10Smark
50964137b10Smark /*
51064137b10Smark * ^? Interrupt drops you back to visual
51164137b10Smark * command mode with an unread interrupt
51264137b10Smark * still in the input buffer.
51364137b10Smark *
51464137b10Smark * ^\ Quit does the same as interrupt.
51564137b10Smark * If you are a ex command rather than
51664137b10Smark * a vi command this will drop you
51764137b10Smark * back to command mode for sure.
51864137b10Smark */
51964137b10Smark case ATTN:
52064137b10Smark case QUIT:
52164137b10Smark ungetkey(c);
52264137b10Smark goto vadone;
52364137b10Smark
52464137b10Smark /*
52564137b10Smark * ^H Backs up a character in the input.
52664137b10Smark *
52764137b10Smark * BUG: Can't back around line boundaries.
52864137b10Smark * This is hard because stuff has
52964137b10Smark * already been saved for repeat.
53064137b10Smark */
5312949201cSbostic case CTRL('h'):
53264137b10Smark bakchar:
53364137b10Smark cp = gcursor - 1;
53464137b10Smark if (cp < ogcursor) {
53564137b10Smark if (splitw) {
53664137b10Smark /*
53764137b10Smark * Backspacing over readecho
53864137b10Smark * prompt. Pretend delete but
53964137b10Smark * don't beep.
54064137b10Smark */
54164137b10Smark ungetkey(c);
54264137b10Smark goto vadone;
54364137b10Smark }
54464137b10Smark beep();
54564137b10Smark continue;
54664137b10Smark }
54764137b10Smark goto vbackup;
54864137b10Smark
54964137b10Smark /*
55064137b10Smark * ^W Back up a white/non-white word.
55164137b10Smark */
5522949201cSbostic case CTRL('w'):
55364137b10Smark wdkind = 1;
55464137b10Smark for (cp = gcursor; cp > ogcursor && isspace(cp[-1]); cp--)
55564137b10Smark continue;
55664137b10Smark for (c = wordch(cp - 1);
55764137b10Smark cp > ogcursor && wordof(c, cp - 1); cp--)
55864137b10Smark continue;
55964137b10Smark goto vbackup;
56064137b10Smark
56164137b10Smark /*
56264137b10Smark * users kill Kill input on this line, back to
56364137b10Smark * the autoindent.
56464137b10Smark */
56564137b10Smark case -1:
56664137b10Smark cp = ogcursor;
56764137b10Smark vbackup:
56864137b10Smark if (cp == gcursor) {
56964137b10Smark beep();
57064137b10Smark continue;
57164137b10Smark }
57264137b10Smark endim();
57364137b10Smark *cp = 0;
57464137b10Smark c = cindent();
57564137b10Smark vgotoCL(qcolumn(cursor - 1, genbuf));
57664137b10Smark if (doomed >= 0)
57764137b10Smark doomed += c - cindent();
57864137b10Smark gcursor = cp;
57964137b10Smark continue;
58064137b10Smark
58164137b10Smark /*
58264137b10Smark * \ Followed by erase or kill
58364137b10Smark * maps to just the erase or kill.
58464137b10Smark */
58564137b10Smark case '\\':
58664137b10Smark x = destcol, y = destline;
587c0a5300eSconrad ex_putchar('\\');
58864137b10Smark vcsync();
58964137b10Smark c = getkey();
590db30859cSmark #ifndef USG3TTY
591562c8f51Sdist if (c == tty.sg_erase || c == tty.sg_kill)
592db30859cSmark #else
593db30859cSmark if (c == tty.c_cc[VERASE]
594562c8f51Sdist || c == tty.c_cc[VKILL])
595db30859cSmark #endif
596562c8f51Sdist {
59764137b10Smark vgoto(y, x);
59864137b10Smark if (doomed >= 0)
59964137b10Smark doomed++;
60064137b10Smark goto def;
60164137b10Smark }
60264137b10Smark ungetkey(c), c = '\\';
603562c8f51Sdist backsl = 1;
604562c8f51Sdist break;
60564137b10Smark
60664137b10Smark /*
60764137b10Smark * ^Q Super quote following character
60864137b10Smark * Only ^@ is verboten (trapped at
60964137b10Smark * a lower level) and \n forces a line
61064137b10Smark * split so doesn't really go in.
61164137b10Smark *
61264137b10Smark * ^V Synonym for ^Q
61364137b10Smark */
6142949201cSbostic case CTRL('q'):
6152949201cSbostic case CTRL('v'):
61664137b10Smark x = destcol, y = destline;
617c0a5300eSconrad ex_putchar('^');
61864137b10Smark vgoto(y, x);
61964137b10Smark c = getkey();
62064137b10Smark #ifdef TIOCSETC
62164137b10Smark if (c == ATTN)
62264137b10Smark c = nttyc.t_intrc;
62364137b10Smark #endif
62464137b10Smark if (c != NL) {
62564137b10Smark if (doomed >= 0)
62664137b10Smark doomed++;
62764137b10Smark goto def;
62864137b10Smark }
62964137b10Smark break;
63064137b10Smark }
63164137b10Smark }
63264137b10Smark
63364137b10Smark /*
63464137b10Smark * If we get a blank not in the echo area
63564137b10Smark * consider splitting the window in the wrapmargin.
63664137b10Smark */
637db30859cSmark if (c != NL && !splitw) {
638db30859cSmark if (c == ' ' && gobblebl) {
63964137b10Smark gobbled = 1;
64064137b10Smark continue;
64164137b10Smark }
642562c8f51Sdist if (value(WRAPMARGIN) &&
643562c8f51Sdist (outcol >= OCOLUMNS - value(WRAPMARGIN) ||
644562c8f51Sdist backsl && outcol==0) &&
645562c8f51Sdist commch != 'r') {
646db30859cSmark /*
647db30859cSmark * At end of word and hit wrapmargin.
648db30859cSmark * Move the word to next line and keep going.
649db30859cSmark */
650db30859cSmark wdkind = 1;
651db30859cSmark *gcursor++ = c;
652562c8f51Sdist if (backsl)
653562c8f51Sdist *gcursor++ = getkey();
654db30859cSmark *gcursor = 0;
655db30859cSmark /*
656db30859cSmark * Find end of previous word if we are past it.
657db30859cSmark */
658db30859cSmark for (cp=gcursor; cp>ogcursor && isspace(cp[-1]); cp--)
659db30859cSmark ;
660562c8f51Sdist if (outcol+(backsl?OCOLUMNS:0) - (gcursor-cp) >= OCOLUMNS - value(WRAPMARGIN)) {
661db30859cSmark /*
662db30859cSmark * Find beginning of previous word.
663db30859cSmark */
664db30859cSmark for (; cp>ogcursor && !isspace(cp[-1]); cp--)
665db30859cSmark ;
666db30859cSmark if (cp <= ogcursor) {
667db30859cSmark /*
668db30859cSmark * There is a single word that
669db30859cSmark * is too long to fit. Just
670db30859cSmark * let it pass, but beep for
671db30859cSmark * each new letter to warn
672db30859cSmark * the luser.
673db30859cSmark */
674db30859cSmark c = *--gcursor;
675db30859cSmark *gcursor = 0;
676db30859cSmark beep();
677db30859cSmark goto dontbreak;
678db30859cSmark }
679db30859cSmark /*
680db30859cSmark * Save it for next line.
681db30859cSmark */
682db30859cSmark macpush(cp, 0);
683db30859cSmark cp--;
684db30859cSmark }
685db30859cSmark macpush("\n", 0);
686db30859cSmark /*
687db30859cSmark * Erase white space before the word.
688db30859cSmark */
689db30859cSmark while (cp > ogcursor && isspace(cp[-1]))
690db30859cSmark cp--; /* skip blank */
691db30859cSmark gobblebl = 3;
692db30859cSmark goto vbackup;
693db30859cSmark }
694db30859cSmark dontbreak:;
695db30859cSmark }
696db30859cSmark
697db30859cSmark /*
698db30859cSmark * Word abbreviation mode.
699db30859cSmark */
700db30859cSmark cstr[0] = c;
701db30859cSmark if (anyabbrs && gcursor > ogcursor && !wordch(cstr) && wordch(gcursor-1)) {
702db30859cSmark int wdtype, abno;
703db30859cSmark
704db30859cSmark cstr[1] = 0;
705db30859cSmark wdkind = 1;
706db30859cSmark cp = gcursor - 1;
707db30859cSmark for (wdtype = wordch(cp - 1);
708db30859cSmark cp > ogcursor && wordof(wdtype, cp - 1); cp--)
709db30859cSmark ;
710db30859cSmark *gcursor = 0;
711db30859cSmark for (abno=0; abbrevs[abno].mapto; abno++) {
712db30859cSmark if (eq(cp, abbrevs[abno].cap)) {
713db30859cSmark macpush(cstr, 0);
714c0a5300eSconrad macpush(abbrevs[abno].mapto, 1);
715db30859cSmark goto vbackup;
71664137b10Smark }
71764137b10Smark }
718db30859cSmark }
719db30859cSmark
72064137b10Smark switch (c) {
72164137b10Smark
72264137b10Smark /*
72364137b10Smark * ^M Except in repeat maps to \n.
72464137b10Smark */
72564137b10Smark case CR:
72664137b10Smark if (vglobp)
72764137b10Smark goto def;
72864137b10Smark c = '\n';
72964137b10Smark /* presto chango ... */
73064137b10Smark
73164137b10Smark /*
73264137b10Smark * \n Start new line.
73364137b10Smark */
73464137b10Smark case NL:
73564137b10Smark *aescaped = c;
73664137b10Smark goto vadone;
73764137b10Smark
73864137b10Smark /*
73964137b10Smark * escape End insert unless repeat and more to repeat.
74064137b10Smark */
74164137b10Smark case ESCAPE:
74264137b10Smark if (lastvgk)
74364137b10Smark goto def;
74464137b10Smark goto vadone;
74564137b10Smark
74664137b10Smark /*
74764137b10Smark * ^D Backtab.
74864137b10Smark * ^T Software forward tab.
74964137b10Smark *
75064137b10Smark * Unless in repeat where this means these
75164137b10Smark * were superquoted in.
75264137b10Smark */
7532949201cSbostic case CTRL('d'):
7542949201cSbostic case CTRL('t'):
75564137b10Smark if (vglobp)
75664137b10Smark goto def;
75764137b10Smark /* fall into ... */
75864137b10Smark
75964137b10Smark /*
76064137b10Smark * ^D|QUOTE Is a backtab (in a repeated command).
76164137b10Smark */
7622949201cSbostic case CTRL('d') | QUOTE:
76364137b10Smark *gcursor = 0;
76464137b10Smark cp = vpastwh(genbuf);
76564137b10Smark c = whitecnt(genbuf);
7662949201cSbostic if (ch == CTRL('t')) {
76764137b10Smark /*
76864137b10Smark * ^t just generates new indent replacing
76964137b10Smark * current white space rounded up to soft
77064137b10Smark * tab stop increment.
77164137b10Smark */
77264137b10Smark if (cp != gcursor)
77364137b10Smark /*
77464137b10Smark * BUG: Don't hack ^T except
77564137b10Smark * right after initial
77664137b10Smark * white space.
77764137b10Smark */
77864137b10Smark continue;
77964137b10Smark cp = genindent(iwhite = backtab(c + value(SHIFTWIDTH) + 1));
78064137b10Smark ogcursor = cp;
78164137b10Smark goto vbackup;
78264137b10Smark }
78364137b10Smark /*
78464137b10Smark * ^D works only if we are at the (end of) the
78564137b10Smark * generated autoindent. We count the ^D for repeat
78664137b10Smark * purposes.
78764137b10Smark */
78864137b10Smark if (c == iwhite && c != 0)
78964137b10Smark if (cp == gcursor) {
79064137b10Smark iwhite = backtab(c);
79164137b10Smark CDCNT++;
79264137b10Smark ogcursor = cp = genindent(iwhite);
79364137b10Smark goto vbackup;
79464137b10Smark } else if (&cp[1] == gcursor &&
79564137b10Smark (*cp == '^' || *cp == '0')) {
79664137b10Smark /*
79764137b10Smark * ^^D moves to margin, then back
79864137b10Smark * to current indent on next line.
79964137b10Smark *
80064137b10Smark * 0^D moves to margin and then
80164137b10Smark * stays there.
80264137b10Smark */
80364137b10Smark HADZERO = *cp == '0';
80464137b10Smark ogcursor = cp = genbuf;
80564137b10Smark HADUP = 1 - HADZERO;
80664137b10Smark CDCNT = 1;
80764137b10Smark endim();
80864137b10Smark back1();
80925da3ac7Smark vputchar(' ');
81064137b10Smark goto vbackup;
81164137b10Smark }
81264137b10Smark if (vglobp && vglobp - iglobp >= 2 &&
81364137b10Smark (vglobp[-2] == '^' || vglobp[-2] == '0')
81464137b10Smark && gcursor == ogcursor + 1)
81564137b10Smark goto bakchar;
81664137b10Smark continue;
81764137b10Smark
81864137b10Smark default:
81964137b10Smark /*
82064137b10Smark * Possibly discard control inputs.
82164137b10Smark */
82264137b10Smark if (!vglobp && junk(c)) {
82364137b10Smark beep();
82464137b10Smark continue;
82564137b10Smark }
82664137b10Smark def:
827562c8f51Sdist if (!backsl) {
828c0a5300eSconrad ex_putchar(c);
829db30859cSmark flush();
830562c8f51Sdist }
83164137b10Smark if (gcursor > &genbuf[LBSIZE - 2])
83264137b10Smark error("Line too long");
83364137b10Smark *gcursor++ = c & TRIM;
83464137b10Smark vcsync();
83564137b10Smark if (value(SHOWMATCH) && !iglobp)
83664137b10Smark if (c == ')' || c == '}')
83764137b10Smark lsmatch(gcursor);
83864137b10Smark continue;
83964137b10Smark }
84064137b10Smark }
84164137b10Smark vadone:
84264137b10Smark *gcursor = 0;
843db30859cSmark if (Outchar != termchar)
84464137b10Smark Outchar = OO;
84564137b10Smark endim();
84664137b10Smark return (gcursor);
84764137b10Smark }
84864137b10Smark
84964137b10Smark int vgetsplit();
85064137b10Smark char *vsplitpt;
85164137b10Smark
85264137b10Smark /*
85364137b10Smark * Append the line in buffer at lp
85464137b10Smark * to the buffer after dot.
85564137b10Smark */
vdoappend(lp)85664137b10Smark vdoappend(lp)
85764137b10Smark char *lp;
85864137b10Smark {
85964137b10Smark register int oing = inglobal;
86064137b10Smark
86164137b10Smark vsplitpt = lp;
86264137b10Smark inglobal = 1;
86364137b10Smark ignore(append(vgetsplit, dot));
86464137b10Smark inglobal = oing;
86564137b10Smark }
86664137b10Smark
86764137b10Smark /*
86864137b10Smark * Subroutine for vdoappend to pass to append.
86964137b10Smark */
vgetsplit()87064137b10Smark vgetsplit()
87164137b10Smark {
87264137b10Smark
87364137b10Smark if (vsplitpt == 0)
87464137b10Smark return (EOF);
87564137b10Smark strcLIN(vsplitpt);
87664137b10Smark vsplitpt = 0;
87764137b10Smark return (0);
87864137b10Smark }
87964137b10Smark
88064137b10Smark /*
88164137b10Smark * Vmaxrep determines the maximum repetitition factor
88264137b10Smark * allowed that will yield total line length less than
883e41600afSmark * LBSIZE characters and also does hacks for the R command.
88464137b10Smark */
vmaxrep(ch,cnt)88564137b10Smark vmaxrep(ch, cnt)
88664137b10Smark char ch;
88764137b10Smark register int cnt;
88864137b10Smark {
88964137b10Smark register int len, replen;
89064137b10Smark
89164137b10Smark if (cnt > LBSIZE - 2)
89264137b10Smark cnt = LBSIZE - 2;
89364137b10Smark replen = strlen(genbuf);
89464137b10Smark if (ch == 'R') {
89564137b10Smark len = strlen(cursor);
89664137b10Smark if (replen < len)
89764137b10Smark len = replen;
89864137b10Smark CP(cursor, cursor + len);
89964137b10Smark vUD2 += len;
90064137b10Smark }
90164137b10Smark len = strlen(linebuf);
90264137b10Smark if (len + cnt * replen <= LBSIZE - 2)
90364137b10Smark return (cnt);
90464137b10Smark cnt = (LBSIZE - 2 - len) / replen;
90564137b10Smark if (cnt == 0) {
90664137b10Smark vsave();
90764137b10Smark error("Line too long");
90864137b10Smark }
90964137b10Smark return (cnt);
91064137b10Smark }
911