BSD 4_4 release
[unix-history] / usr / src / usr.bin / ex / ex_vops2.c
CommitLineData
ad787160
C
1/*-
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This module is believed to contain source code proprietary to AT&T.
6 * Use and redistribution is subject to the Berkeley Software License
7 * Agreement and your Software Agreement with AT&T (Western Electric).
dac571dd
DF
8 */
9
10#ifndef lint
ad787160
C
11static char sccsid[] = "@(#)ex_vops2.c 8.1 (Berkeley) 6/9/93";
12#endif /* not lint */
dac571dd 13
09035cec
MH
14#include "ex.h"
15#include "ex_tty.h"
16#include "ex_vis.h"
17
18/*
19 * Low level routines for operations sequences,
20 * and mostly, insert mode (and a subroutine
21 * to read an input line, including in the echo area.)
22 */
299f2784
MH
23extern char *vUA1, *vUA2; /* mjm: extern; also in ex_vops.c */
24extern char *vUD1, *vUD2; /* mjm: extern; also in ex_vops.c */
09035cec
MH
25
26/*
27 * Obleeperate characters in hardcopy
28 * open with \'s.
29 */
30bleep(i, cp)
31 register int i;
32 char *cp;
33{
34
35 i -= column(cp);
36 do
5a6c967e 37 ex_putchar('\\' | QUOTE);
09035cec
MH
38 while (--i >= 0);
39 rubble = 1;
40}
41
42/*
43 * Common code for middle part of delete
44 * and change operating on parts of lines.
45 */
46vdcMID()
47{
48 register char *cp;
49
50 squish();
51 setLAST();
887e3e0d
MH
52 if (FIXUNDO)
53 vundkind = VCHNG, CP(vutmp, linebuf);
09035cec
MH
54 if (wcursor < cursor)
55 cp = wcursor, wcursor = cursor, cursor = cp;
56 vUD1 = vUA1 = vUA2 = cursor; vUD2 = wcursor;
57 return (column(wcursor - 1));
58}
59
60/*
61 * Take text from linebuf and stick it
62 * in the VBSIZE buffer BUF. Used to save
63 * deleted text of part of line.
64 */
65takeout(BUF)
66 char *BUF;
67{
68 register char *cp;
69
70 if (wcursor < linebuf)
71 wcursor = linebuf;
72 if (cursor == wcursor) {
73 beep();
74 return;
75 }
76 if (wcursor < cursor) {
77 cp = wcursor;
78 wcursor = cursor;
79 cursor = cp;
80 }
5a6c967e 81 ex_setBUF(BUF);
09035cec
MH
82 if ((BUF[0] & (QUOTE|TRIM)) == OVERBUF)
83 beep();
84}
85
86/*
87 * Are we at the end of the printed representation of the
88 * line? Used internally in hardcopy open.
89 */
90ateopr()
91{
92 register int i, c;
93 register char *cp = vtube[destline] + destcol;
94
95 for (i = WCOLS - destcol; i > 0; i--) {
96 c = *cp++;
97 if (c == 0)
98 return (1);
99 if (c != ' ' && (c & QUOTE) == 0)
100 return (0);
101 }
102 return (1);
103}
104
105/*
106 * Append.
107 *
108 * This routine handles the top level append, doing work
109 * as each new line comes in, and arranging repeatability.
110 * It also handles append with repeat counts, and calculation
111 * of autoindents for new lines.
112 */
113bool vaifirst;
114bool gobbled;
115char *ogcursor;
116
117vappend(ch, cnt, indent)
299f2784 118 int ch; /* mjm: char --> int */
09035cec
MH
119 int cnt, indent;
120{
121 register int i;
122 register char *gcursor;
123 bool escape;
04379bab 124 int repcnt, savedoomed;
09035cec 125 short oldhold = hold;
5a6c967e 126#ifdef SIGWINCH
48be689d 127 int oldmask;
5a6c967e 128#endif
09035cec
MH
129
130 /*
131 * Before a move in hardopen when the line is dirty
132 * or we are in the middle of the printed representation,
133 * we retype the line to the left of the cursor so the
134 * insert looks clean.
135 */
136 if (ch != 'o' && state == HARDOPEN && (rubble || !ateopr())) {
137 rubble = 1;
138 gcursor = cursor;
139 i = *gcursor;
140 *gcursor = ' ';
141 wcursor = gcursor;
142 vmove();
143 *gcursor = i;
144 }
145 vaifirst = indent == 0;
146
147 /*
148 * Handle replace character by (eventually)
149 * limiting the number of input characters allowed
150 * in the vgetline routine.
151 */
152 if (ch == 'r')
153 repcnt = 2;
154 else
155 repcnt = 0;
156
157 /*
158 * If an autoindent is specified, then
159 * generate a mixture of blanks to tabs to implement
160 * it and place the cursor after the indent.
161 * Text read by the vgetline routine will be placed in genbuf,
162 * so the indent is generated there.
163 */
164 if (value(AUTOINDENT) && indent != 0) {
165 gcursor = genindent(indent);
166 *gcursor = 0;
167 vgotoCL(qcolumn(cursor - 1, genbuf));
168 } else {
169 gcursor = genbuf;
170 *gcursor = 0;
171 if (ch == 'o')
172 vfixcurs();
173 }
174
175 /*
176 * Prepare for undo. Pointers delimit inserted portion of line.
177 */
178 vUA1 = vUA2 = cursor;
179
180 /*
181 * If we are not in a repeated command and a ^@ comes in
182 * then this means the previous inserted text.
183 * If there is none or it was too long to be saved,
184 * then beep() and also arrange to undo any damage done
185 * so far (e.g. if we are a change.)
186 */
187 if ((vglobp && *vglobp == 0) || peekbr()) {
188 if ((INS[0] & (QUOTE|TRIM)) == OVERBUF) {
189 beep();
190 if (!splitw)
191 ungetkey('u');
192 doomed = 0;
193 hold = oldhold;
194 return;
195 }
196 /*
197 * Unread input from INS.
198 * An escape will be generated at end of string.
199 * Hold off n^^2 type update on dumb terminals.
200 */
201 vglobp = INS;
202 hold |= HOLDQIK;
203 } else if (vglobp == 0)
204 /*
205 * Not a repeated command, get
206 * a new inserted text for repeat.
207 */
208 INS[0] = 0;
209
210 /*
211 * For wrapmargin to hack away second space after a '.'
212 * when the first space caused a line break we keep
213 * track that this happened in gobblebl, which says
214 * to gobble up a blank silently.
215 */
216 gobblebl = 0;
217
5a6c967e 218#ifdef SIGWINCH
48be689d 219 oldmask = sigblock(sigmask(SIGWINCH));
5a6c967e 220#endif
09035cec
MH
221 /*
222 * Text gathering loop.
223 * New text goes into genbuf starting at gcursor.
224 * cursor preserves place in linebuf where text will eventually go.
225 */
226 if (*cursor == 0 || state == CRTOPEN)
227 hold |= HOLDROL;
228 for (;;) {
229 if (ch == 'r' && repcnt == 0)
230 escape = 0;
231 else {
04379bab 232 gcursor = vgetline(repcnt, gcursor, &escape, ch);
09035cec
MH
233
234 /*
235 * After an append, stick information
236 * about the ^D's and ^^D's and 0^D's in
237 * the repeated text buffer so repeated
238 * inserts of stuff indented with ^D as backtab's
239 * can work.
240 */
241 if (HADUP)
242 addtext("^");
243 else if (HADZERO)
244 addtext("0");
245 while (CDCNT > 0)
246 addtext("\204"), CDCNT--;
247 if (gobbled)
248 addtext(" ");
249 addtext(ogcursor);
250 }
251 repcnt = 0;
252
253 /*
254 * Smash the generated and preexisting indents together
255 * and generate one cleanly made out of tabs and spaces
256 * if we are using autoindent.
257 */
258 if (!vaifirst && value(AUTOINDENT)) {
259 i = fixindent(indent);
260 if (!HADUP)
261 indent = i;
262 gcursor = strend(genbuf);
263 }
264
265 /*
266 * Limit the repetition count based on maximum
267 * possible line length; do output implied
268 * by further count (> 1) and cons up the new line
269 * in linebuf.
270 */
271 cnt = vmaxrep(ch, cnt);
272 CP(gcursor + 1, cursor);
273 do {
274 CP(cursor, genbuf);
275 if (cnt > 1) {
276 int oldhold = hold;
277
278 Outchar = vinschar;
279 hold |= HOLDQIK;
5a6c967e 280 ex_printf("%s", genbuf);
09035cec
MH
281 hold = oldhold;
282 Outchar = vputchar;
283 }
284 cursor += gcursor - genbuf;
285 } while (--cnt > 0);
286 endim();
287 vUA2 = cursor;
288 if (escape != '\n')
289 CP(cursor, gcursor + 1);
290
291 /*
292 * If doomed characters remain, clobber them,
293 * and reopen the line to get the display exact.
294 */
295 if (state != HARDOPEN) {
296 DEPTH(vcline) = 0;
04379bab 297 savedoomed = doomed;
09035cec
MH
298 if (doomed > 0) {
299 register int cind = cindent();
300
301 physdc(cind, cind + doomed);
302 doomed = 0;
303 }
304 i = vreopen(LINE(vcline), lineDOT(), vcline);
f0f2d980
MH
305#ifdef TRACE
306 if (trace)
307 fprintf(trace, "restoring doomed from %d to %d\n", doomed, savedoomed);
308#endif
309 if (ch == 'R')
310 doomed = savedoomed;
09035cec
MH
311 }
312
313 /*
314 * All done unless we are continuing on to another line.
315 */
316 if (escape != '\n')
317 break;
318
319 /*
320 * Set up for the new line.
321 * First save the current line, then construct a new
322 * first image for the continuation line consisting
323 * of any new autoindent plus the pushed ahead text.
324 */
325 killU();
326 addtext(gobblebl ? " " : "\n");
327 vsave();
328 cnt = 1;
329 if (value(AUTOINDENT)) {
330#ifdef LISPCODE
331 if (value(LISP))
332 indent = lindent(dot + 1);
333 else
334#endif
335 if (!HADUP && vaifirst)
336 indent = whitecnt(linebuf);
337 vaifirst = 0;
338 strcLIN(vpastwh(gcursor + 1));
339 gcursor = genindent(indent);
340 *gcursor = 0;
341 if (gcursor + strlen(linebuf) > &genbuf[LBSIZE - 2])
342 gcursor = genbuf;
343 CP(gcursor, linebuf);
344 } else {
345 CP(genbuf, gcursor + 1);
346 gcursor = genbuf;
347 }
348
349 /*
350 * If we started out as a single line operation and are now
351 * turning into a multi-line change, then we had better yank
352 * out dot before it changes so that undo will work
353 * correctly later.
354 */
887e3e0d 355 if (FIXUNDO && vundkind == VCHNG) {
09035cec
MH
356 vremote(1, yank, 0);
357 undap1--;
358 }
359
360 /*
361 * Now do the append of the new line in the buffer,
362 * and update the display. If slowopen
363 * we don't do very much.
364 */
365 vdoappend(genbuf);
366 vundkind = VMANYINS;
367 vcline++;
368 if (state != VISUAL)
369 vshow(dot, NOLINE);
370 else {
371 i += LINE(vcline - 1);
372 vopen(dot, i);
373 if (value(SLOWOPEN))
374 vscrap();
375 else
376 vsync1(LINE(vcline));
377 }
378 strcLIN(gcursor);
379 *gcursor = 0;
380 cursor = linebuf;
381 vgotoCL(qcolumn(cursor - 1, genbuf));
382 }
383
384 /*
385 * All done with insertion, position the cursor
386 * and sync the screen.
387 */
388 hold = oldhold;
389 if (cursor > linebuf)
390 cursor--;
391 if (state != HARDOPEN)
392 vsyncCL();
393 else if (cursor > linebuf)
394 back1();
395 doomed = 0;
396 wcursor = cursor;
397 vmove();
5a6c967e 398#ifdef SIGWINCH
48be689d 399 (void)sigsetmask(oldmask);
5a6c967e 400#endif
09035cec
MH
401}
402
403/*
404 * Subroutine for vgetline to back up a single character position,
405 * backwards around end of lines (vgoto can't hack columns which are
406 * less than 0 in general).
407 */
408back1()
409{
410
411 vgoto(destline - 1, WCOLS + destcol - 1);
412}
413
414/*
415 * Get a line into genbuf after gcursor.
416 * Cnt limits the number of input characters
417 * accepted and is used for handling the replace
418 * single character command. Aescaped is the location
419 * where we stick a termination indicator (whether we
420 * ended with an ESCAPE or a newline/return.
421 *
422 * We do erase-kill type processing here and also
423 * are careful about the way we do this so that it is
424 * repeatable. (I.e. so that your kill doesn't happen,
425 * when you repeat an insert if it was escaped with \ the
04379bab
MH
426 * first time you did it. commch is the command character
427 * involved, including the prompt for readline.
09035cec
MH
428 */
429char *
04379bab 430vgetline(cnt, gcursor, aescaped, commch)
09035cec
MH
431 int cnt;
432 register char *gcursor;
433 bool *aescaped;
04379bab 434 char commch;
09035cec
MH
435{
436 register int c, ch;
437 register char *cp;
04379bab 438 int x, y, iwhite, backsl=0;
09035cec 439 char *iglobp;
d266c416 440 char cstr[2];
09035cec
MH
441 int (*OO)() = Outchar;
442
443 /*
444 * Clear the output state and counters
445 * for autoindent backwards motion (counts of ^D, etc.)
446 * Remember how much white space at beginning of line so
447 * as not to allow backspace over autoindent.
448 */
449 *aescaped = 0;
450 ogcursor = gcursor;
451 flusho();
452 CDCNT = 0;
453 HADUP = 0;
454 HADZERO = 0;
455 gobbled = 0;
456 iwhite = whitecnt(genbuf);
457 iglobp = vglobp;
458
459 /*
460 * Carefully avoid using vinschar in the echo area.
461 */
462 if (splitw)
463 Outchar = vputchar;
464 else {
465 Outchar = vinschar;
466 vprepins();
467 }
468 for (;;) {
04379bab 469 backsl = 0;
09035cec
MH
470 if (gobblebl)
471 gobblebl--;
472 if (cnt != 0) {
473 cnt--;
474 if (cnt == 0)
475 goto vadone;
476 }
d266c416
MH
477 c = getkey();
478 if (c != ATTN)
479 c &= (QUOTE|TRIM);
480 ch = c;
481 maphopcnt = 0;
5a6c967e 482 if (vglobp == 0 && Peek_key == 0 && commch != 'r')
887e3e0d 483 while ((ch = map(c, immacs)) != c) {
09035cec 484 c = ch;
887e3e0d
MH
485 if (!value(REMAP))
486 break;
d266c416
MH
487 if (++maphopcnt > 256)
488 error("Infinite macro loop");
887e3e0d 489 }
09035cec
MH
490 if (!iglobp) {
491
492 /*
493 * Erase-kill type processing.
494 * Only happens if we were not reading
495 * from untyped input when we started.
496 * Map users erase to ^H, kill to -1 for switch.
497 */
d266c416 498#ifndef USG3TTY
09035cec 499 if (c == tty.sg_erase)
65bacefd 500 c = CTRL('h');
09035cec
MH
501 else if (c == tty.sg_kill)
502 c = -1;
d266c416
MH
503#else
504 if (c == tty.c_cc[VERASE])
65bacefd 505 c = CTRL('h');
d266c416
MH
506 else if (c == tty.c_cc[VKILL])
507 c = -1;
508#endif
09035cec
MH
509 switch (c) {
510
511 /*
512 * ^? Interrupt drops you back to visual
513 * command mode with an unread interrupt
514 * still in the input buffer.
515 *
516 * ^\ Quit does the same as interrupt.
517 * If you are a ex command rather than
518 * a vi command this will drop you
519 * back to command mode for sure.
520 */
521 case ATTN:
522 case QUIT:
523 ungetkey(c);
524 goto vadone;
525
526 /*
527 * ^H Backs up a character in the input.
528 *
529 * BUG: Can't back around line boundaries.
530 * This is hard because stuff has
531 * already been saved for repeat.
532 */
65bacefd 533 case CTRL('h'):
09035cec
MH
534bakchar:
535 cp = gcursor - 1;
536 if (cp < ogcursor) {
537 if (splitw) {
538 /*
539 * Backspacing over readecho
540 * prompt. Pretend delete but
541 * don't beep.
542 */
543 ungetkey(c);
544 goto vadone;
545 }
546 beep();
547 continue;
548 }
549 goto vbackup;
550
551 /*
552 * ^W Back up a white/non-white word.
553 */
65bacefd 554 case CTRL('w'):
09035cec
MH
555 wdkind = 1;
556 for (cp = gcursor; cp > ogcursor && isspace(cp[-1]); cp--)
557 continue;
558 for (c = wordch(cp - 1);
559 cp > ogcursor && wordof(c, cp - 1); cp--)
560 continue;
561 goto vbackup;
562
563 /*
564 * users kill Kill input on this line, back to
565 * the autoindent.
566 */
567 case -1:
568 cp = ogcursor;
569vbackup:
570 if (cp == gcursor) {
571 beep();
572 continue;
573 }
574 endim();
575 *cp = 0;
576 c = cindent();
577 vgotoCL(qcolumn(cursor - 1, genbuf));
578 if (doomed >= 0)
579 doomed += c - cindent();
580 gcursor = cp;
581 continue;
582
583 /*
584 * \ Followed by erase or kill
585 * maps to just the erase or kill.
586 */
587 case '\\':
588 x = destcol, y = destline;
5a6c967e 589 ex_putchar('\\');
09035cec
MH
590 vcsync();
591 c = getkey();
d266c416 592#ifndef USG3TTY
04379bab 593 if (c == tty.sg_erase || c == tty.sg_kill)
d266c416
MH
594#else
595 if (c == tty.c_cc[VERASE]
04379bab 596 || c == tty.c_cc[VKILL])
d266c416 597#endif
04379bab 598 {
09035cec
MH
599 vgoto(y, x);
600 if (doomed >= 0)
601 doomed++;
602 goto def;
603 }
604 ungetkey(c), c = '\\';
04379bab
MH
605 backsl = 1;
606 break;
09035cec
MH
607
608 /*
609 * ^Q Super quote following character
610 * Only ^@ is verboten (trapped at
611 * a lower level) and \n forces a line
612 * split so doesn't really go in.
613 *
614 * ^V Synonym for ^Q
615 */
65bacefd
KB
616 case CTRL('q'):
617 case CTRL('v'):
09035cec 618 x = destcol, y = destline;
5a6c967e 619 ex_putchar('^');
09035cec
MH
620 vgoto(y, x);
621 c = getkey();
622#ifdef TIOCSETC
623 if (c == ATTN)
624 c = nttyc.t_intrc;
625#endif
626 if (c != NL) {
627 if (doomed >= 0)
628 doomed++;
629 goto def;
630 }
631 break;
632 }
633 }
634
635 /*
636 * If we get a blank not in the echo area
637 * consider splitting the window in the wrapmargin.
638 */
d266c416
MH
639 if (c != NL && !splitw) {
640 if (c == ' ' && gobblebl) {
09035cec
MH
641 gobbled = 1;
642 continue;
643 }
04379bab
MH
644 if (value(WRAPMARGIN) &&
645 (outcol >= OCOLUMNS - value(WRAPMARGIN) ||
646 backsl && outcol==0) &&
647 commch != 'r') {
d266c416
MH
648 /*
649 * At end of word and hit wrapmargin.
650 * Move the word to next line and keep going.
651 */
652 wdkind = 1;
653 *gcursor++ = c;
04379bab
MH
654 if (backsl)
655 *gcursor++ = getkey();
d266c416
MH
656 *gcursor = 0;
657 /*
658 * Find end of previous word if we are past it.
659 */
660 for (cp=gcursor; cp>ogcursor && isspace(cp[-1]); cp--)
661 ;
04379bab 662 if (outcol+(backsl?OCOLUMNS:0) - (gcursor-cp) >= OCOLUMNS - value(WRAPMARGIN)) {
d266c416
MH
663 /*
664 * Find beginning of previous word.
665 */
666 for (; cp>ogcursor && !isspace(cp[-1]); cp--)
667 ;
668 if (cp <= ogcursor) {
669 /*
670 * There is a single word that
671 * is too long to fit. Just
672 * let it pass, but beep for
673 * each new letter to warn
674 * the luser.
675 */
676 c = *--gcursor;
677 *gcursor = 0;
678 beep();
679 goto dontbreak;
680 }
681 /*
682 * Save it for next line.
683 */
684 macpush(cp, 0);
685 cp--;
686 }
687 macpush("\n", 0);
688 /*
689 * Erase white space before the word.
690 */
691 while (cp > ogcursor && isspace(cp[-1]))
692 cp--; /* skip blank */
693 gobblebl = 3;
694 goto vbackup;
09035cec 695 }
d266c416
MH
696 dontbreak:;
697 }
698
699 /*
700 * Word abbreviation mode.
701 */
702 cstr[0] = c;
703 if (anyabbrs && gcursor > ogcursor && !wordch(cstr) && wordch(gcursor-1)) {
5a6c967e
CH
704 int wdtype, abno;
705
706 cstr[1] = 0;
707 wdkind = 1;
708 cp = gcursor - 1;
709 for (wdtype = wordch(cp - 1);
710 cp > ogcursor && wordof(wdtype, cp - 1); cp--)
711 ;
712 *gcursor = 0;
713 for (abno=0; abbrevs[abno].mapto; abno++) {
714 if (eq(cp, abbrevs[abno].cap)) {
715 macpush(cstr, 0);
716 macpush(abbrevs[abno].mapto, 1);
717 goto vbackup;
d266c416 718 }
5a6c967e 719 }
09035cec 720 }
d266c416 721
09035cec
MH
722 switch (c) {
723
724 /*
725 * ^M Except in repeat maps to \n.
726 */
727 case CR:
728 if (vglobp)
729 goto def;
730 c = '\n';
731 /* presto chango ... */
732
733 /*
734 * \n Start new line.
735 */
736 case NL:
737 *aescaped = c;
738 goto vadone;
739
740 /*
741 * escape End insert unless repeat and more to repeat.
742 */
743 case ESCAPE:
744 if (lastvgk)
745 goto def;
746 goto vadone;
747
748 /*
749 * ^D Backtab.
750 * ^T Software forward tab.
751 *
752 * Unless in repeat where this means these
753 * were superquoted in.
754 */
65bacefd
KB
755 case CTRL('d'):
756 case CTRL('t'):
09035cec
MH
757 if (vglobp)
758 goto def;
759 /* fall into ... */
760
761 /*
762 * ^D|QUOTE Is a backtab (in a repeated command).
763 */
65bacefd 764 case CTRL('d') | QUOTE:
09035cec
MH
765 *gcursor = 0;
766 cp = vpastwh(genbuf);
767 c = whitecnt(genbuf);
65bacefd 768 if (ch == CTRL('t')) {
09035cec
MH
769 /*
770 * ^t just generates new indent replacing
771 * current white space rounded up to soft
772 * tab stop increment.
773 */
774 if (cp != gcursor)
775 /*
776 * BUG: Don't hack ^T except
777 * right after initial
778 * white space.
779 */
780 continue;
781 cp = genindent(iwhite = backtab(c + value(SHIFTWIDTH) + 1));
782 ogcursor = cp;
783 goto vbackup;
784 }
785 /*
786 * ^D works only if we are at the (end of) the
787 * generated autoindent. We count the ^D for repeat
788 * purposes.
789 */
790 if (c == iwhite && c != 0)
791 if (cp == gcursor) {
792 iwhite = backtab(c);
793 CDCNT++;
794 ogcursor = cp = genindent(iwhite);
795 goto vbackup;
796 } else if (&cp[1] == gcursor &&
797 (*cp == '^' || *cp == '0')) {
798 /*
799 * ^^D moves to margin, then back
800 * to current indent on next line.
801 *
802 * 0^D moves to margin and then
803 * stays there.
804 */
805 HADZERO = *cp == '0';
806 ogcursor = cp = genbuf;
807 HADUP = 1 - HADZERO;
808 CDCNT = 1;
809 endim();
810 back1();
887e3e0d 811 vputchar(' ');
09035cec
MH
812 goto vbackup;
813 }
814 if (vglobp && vglobp - iglobp >= 2 &&
815 (vglobp[-2] == '^' || vglobp[-2] == '0')
816 && gcursor == ogcursor + 1)
817 goto bakchar;
818 continue;
819
820 default:
821 /*
822 * Possibly discard control inputs.
823 */
824 if (!vglobp && junk(c)) {
825 beep();
826 continue;
827 }
828def:
04379bab 829 if (!backsl) {
5a6c967e 830 ex_putchar(c);
0ab2d2a9 831 flush();
04379bab 832 }
09035cec
MH
833 if (gcursor > &genbuf[LBSIZE - 2])
834 error("Line too long");
835 *gcursor++ = c & TRIM;
836 vcsync();
09035cec
MH
837 if (value(SHOWMATCH) && !iglobp)
838 if (c == ')' || c == '}')
839 lsmatch(gcursor);
09035cec
MH
840 continue;
841 }
842 }
843vadone:
844 *gcursor = 0;
d266c416
MH
845 if (Outchar != termchar)
846 Outchar = OO;
09035cec
MH
847 endim();
848 return (gcursor);
849}
850
851int vgetsplit();
852char *vsplitpt;
853
854/*
855 * Append the line in buffer at lp
856 * to the buffer after dot.
857 */
858vdoappend(lp)
859 char *lp;
860{
861 register int oing = inglobal;
862
863 vsplitpt = lp;
864 inglobal = 1;
865 ignore(append(vgetsplit, dot));
866 inglobal = oing;
867}
868
869/*
870 * Subroutine for vdoappend to pass to append.
871 */
872vgetsplit()
873{
874
875 if (vsplitpt == 0)
876 return (EOF);
877 strcLIN(vsplitpt);
878 vsplitpt = 0;
879 return (0);
880}
881
882/*
883 * Vmaxrep determines the maximum repetitition factor
884 * allowed that will yield total line length less than
44232d5b 885 * LBSIZE characters and also does hacks for the R command.
09035cec
MH
886 */
887vmaxrep(ch, cnt)
888 char ch;
889 register int cnt;
890{
891 register int len, replen;
892
893 if (cnt > LBSIZE - 2)
894 cnt = LBSIZE - 2;
895 replen = strlen(genbuf);
896 if (ch == 'R') {
897 len = strlen(cursor);
898 if (replen < len)
899 len = replen;
900 CP(cursor, cursor + len);
901 vUD2 += len;
902 }
903 len = strlen(linebuf);
904 if (len + cnt * replen <= LBSIZE - 2)
905 return (cnt);
906 cnt = (LBSIZE - 2 - len) / replen;
907 if (cnt == 0) {
908 vsave();
909 error("Line too long");
910 }
911 return (cnt);
912}