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