added PDX constant
[unix-history] / usr / src / usr.bin / ex / ex_vops2.c
CommitLineData
299f2784 1/* Copyright (c) 1981 Regents of the University of California */
cb3ac212 2static char *sccsid = "@(#)ex_vops2.c 6.5 %G%";
09035cec
MH
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 */
299f2784
MH
12extern char *vUA1, *vUA2; /* mjm: extern; also in ex_vops.c */
13extern char *vUD1, *vUD2; /* mjm: extern; also in ex_vops.c */
09035cec
MH
14
15/*
16 * Obleeperate characters in hardcopy
17 * open with \'s.
18 */
19bleep(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 */
35vdcMID()
36{
37 register char *cp;
38
39 squish();
40 setLAST();
887e3e0d
MH
41 if (FIXUNDO)
42 vundkind = VCHNG, CP(vutmp, linebuf);
09035cec
MH
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 */
54takeout(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 */
79ateopr()
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 */
102bool vaifirst;
103bool gobbled;
104char *ogcursor;
105
106vappend(ch, cnt, indent)
299f2784 107 int ch; /* mjm: char --> int */
09035cec
MH
108 int cnt, indent;
109{
110 register int i;
111 register char *gcursor;
112 bool escape;
04379bab 113 int repcnt, savedoomed;
09035cec
MH
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 {
04379bab 215 gcursor = vgetline(repcnt, gcursor, &escape, ch);
09035cec
MH
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;
04379bab 280 savedoomed = doomed;
09035cec
MH
281 if (doomed > 0) {
282 register int cind = cindent();
283
284 physdc(cind, cind + doomed);
285 doomed = 0;
286 }
287 i = vreopen(LINE(vcline), lineDOT(), vcline);
f0f2d980
MH
288#ifdef TRACE
289 if (trace)
290 fprintf(trace, "restoring doomed from %d to %d\n", doomed, savedoomed);
291#endif
292 if (ch == 'R')
293 doomed = savedoomed;
09035cec
MH
294 }
295
296 /*
297 * All done unless we are continuing on to another line.
298 */
299 if (escape != '\n')
300 break;
301
302 /*
303 * Set up for the new line.
304 * First save the current line, then construct a new
305 * first image for the continuation line consisting
306 * of any new autoindent plus the pushed ahead text.
307 */
308 killU();
309 addtext(gobblebl ? " " : "\n");
310 vsave();
311 cnt = 1;
312 if (value(AUTOINDENT)) {
313#ifdef LISPCODE
314 if (value(LISP))
315 indent = lindent(dot + 1);
316 else
317#endif
318 if (!HADUP && vaifirst)
319 indent = whitecnt(linebuf);
320 vaifirst = 0;
321 strcLIN(vpastwh(gcursor + 1));
322 gcursor = genindent(indent);
323 *gcursor = 0;
324 if (gcursor + strlen(linebuf) > &genbuf[LBSIZE - 2])
325 gcursor = genbuf;
326 CP(gcursor, linebuf);
327 } else {
328 CP(genbuf, gcursor + 1);
329 gcursor = genbuf;
330 }
331
332 /*
333 * If we started out as a single line operation and are now
334 * turning into a multi-line change, then we had better yank
335 * out dot before it changes so that undo will work
336 * correctly later.
337 */
887e3e0d 338 if (FIXUNDO && vundkind == VCHNG) {
09035cec
MH
339 vremote(1, yank, 0);
340 undap1--;
341 }
342
343 /*
344 * Now do the append of the new line in the buffer,
345 * and update the display. If slowopen
346 * we don't do very much.
347 */
348 vdoappend(genbuf);
349 vundkind = VMANYINS;
350 vcline++;
351 if (state != VISUAL)
352 vshow(dot, NOLINE);
353 else {
354 i += LINE(vcline - 1);
355 vopen(dot, i);
356 if (value(SLOWOPEN))
357 vscrap();
358 else
359 vsync1(LINE(vcline));
360 }
361 strcLIN(gcursor);
362 *gcursor = 0;
363 cursor = linebuf;
364 vgotoCL(qcolumn(cursor - 1, genbuf));
365 }
366
367 /*
368 * All done with insertion, position the cursor
369 * and sync the screen.
370 */
371 hold = oldhold;
372 if (cursor > linebuf)
373 cursor--;
374 if (state != HARDOPEN)
375 vsyncCL();
376 else if (cursor > linebuf)
377 back1();
378 doomed = 0;
379 wcursor = cursor;
380 vmove();
381}
382
383/*
384 * Subroutine for vgetline to back up a single character position,
385 * backwards around end of lines (vgoto can't hack columns which are
386 * less than 0 in general).
387 */
388back1()
389{
390
391 vgoto(destline - 1, WCOLS + destcol - 1);
392}
393
394/*
395 * Get a line into genbuf after gcursor.
396 * Cnt limits the number of input characters
397 * accepted and is used for handling the replace
398 * single character command. Aescaped is the location
399 * where we stick a termination indicator (whether we
400 * ended with an ESCAPE or a newline/return.
401 *
402 * We do erase-kill type processing here and also
403 * are careful about the way we do this so that it is
404 * repeatable. (I.e. so that your kill doesn't happen,
405 * when you repeat an insert if it was escaped with \ the
04379bab
MH
406 * first time you did it. commch is the command character
407 * involved, including the prompt for readline.
09035cec
MH
408 */
409char *
04379bab 410vgetline(cnt, gcursor, aescaped, commch)
09035cec
MH
411 int cnt;
412 register char *gcursor;
413 bool *aescaped;
04379bab 414 char commch;
09035cec
MH
415{
416 register int c, ch;
417 register char *cp;
04379bab 418 int x, y, iwhite, backsl=0;
09035cec 419 char *iglobp;
d266c416 420 char cstr[2];
09035cec
MH
421 int (*OO)() = Outchar;
422
423 /*
424 * Clear the output state and counters
425 * for autoindent backwards motion (counts of ^D, etc.)
426 * Remember how much white space at beginning of line so
427 * as not to allow backspace over autoindent.
428 */
429 *aescaped = 0;
430 ogcursor = gcursor;
431 flusho();
432 CDCNT = 0;
433 HADUP = 0;
434 HADZERO = 0;
435 gobbled = 0;
436 iwhite = whitecnt(genbuf);
437 iglobp = vglobp;
438
439 /*
440 * Carefully avoid using vinschar in the echo area.
441 */
442 if (splitw)
443 Outchar = vputchar;
444 else {
445 Outchar = vinschar;
446 vprepins();
447 }
448 for (;;) {
04379bab 449 backsl = 0;
09035cec
MH
450 if (gobblebl)
451 gobblebl--;
452 if (cnt != 0) {
453 cnt--;
454 if (cnt == 0)
455 goto vadone;
456 }
d266c416
MH
457 c = getkey();
458 if (c != ATTN)
459 c &= (QUOTE|TRIM);
460 ch = c;
461 maphopcnt = 0;
04379bab 462 if (vglobp == 0 && Peekkey == 0 && commch != 'r')
887e3e0d 463 while ((ch = map(c, immacs)) != c) {
09035cec 464 c = ch;
887e3e0d
MH
465 if (!value(REMAP))
466 break;
d266c416
MH
467 if (++maphopcnt > 256)
468 error("Infinite macro loop");
887e3e0d 469 }
09035cec
MH
470 if (!iglobp) {
471
472 /*
473 * Erase-kill type processing.
474 * Only happens if we were not reading
475 * from untyped input when we started.
476 * Map users erase to ^H, kill to -1 for switch.
477 */
d266c416 478#ifndef USG3TTY
09035cec
MH
479 if (c == tty.sg_erase)
480 c = CTRL(h);
481 else if (c == tty.sg_kill)
482 c = -1;
d266c416
MH
483#else
484 if (c == tty.c_cc[VERASE])
485 c = CTRL(h);
486 else if (c == tty.c_cc[VKILL])
487 c = -1;
488#endif
09035cec
MH
489 switch (c) {
490
491 /*
492 * ^? Interrupt drops you back to visual
493 * command mode with an unread interrupt
494 * still in the input buffer.
495 *
496 * ^\ Quit does the same as interrupt.
497 * If you are a ex command rather than
498 * a vi command this will drop you
499 * back to command mode for sure.
500 */
501 case ATTN:
502 case QUIT:
503 ungetkey(c);
504 goto vadone;
505
506 /*
507 * ^H Backs up a character in the input.
508 *
509 * BUG: Can't back around line boundaries.
510 * This is hard because stuff has
511 * already been saved for repeat.
512 */
513 case CTRL(h):
514bakchar:
515 cp = gcursor - 1;
516 if (cp < ogcursor) {
517 if (splitw) {
518 /*
519 * Backspacing over readecho
520 * prompt. Pretend delete but
521 * don't beep.
522 */
523 ungetkey(c);
524 goto vadone;
525 }
526 beep();
527 continue;
528 }
529 goto vbackup;
530
531 /*
532 * ^W Back up a white/non-white word.
533 */
534 case CTRL(w):
535 wdkind = 1;
536 for (cp = gcursor; cp > ogcursor && isspace(cp[-1]); cp--)
537 continue;
538 for (c = wordch(cp - 1);
539 cp > ogcursor && wordof(c, cp - 1); cp--)
540 continue;
541 goto vbackup;
542
543 /*
544 * users kill Kill input on this line, back to
545 * the autoindent.
546 */
547 case -1:
548 cp = ogcursor;
549vbackup:
550 if (cp == gcursor) {
551 beep();
552 continue;
553 }
554 endim();
555 *cp = 0;
556 c = cindent();
557 vgotoCL(qcolumn(cursor - 1, genbuf));
558 if (doomed >= 0)
559 doomed += c - cindent();
560 gcursor = cp;
561 continue;
562
563 /*
564 * \ Followed by erase or kill
565 * maps to just the erase or kill.
566 */
567 case '\\':
568 x = destcol, y = destline;
569 putchar('\\');
570 vcsync();
571 c = getkey();
d266c416 572#ifndef USG3TTY
04379bab 573 if (c == tty.sg_erase || c == tty.sg_kill)
d266c416
MH
574#else
575 if (c == tty.c_cc[VERASE]
04379bab 576 || c == tty.c_cc[VKILL])
d266c416 577#endif
04379bab 578 {
09035cec
MH
579 vgoto(y, x);
580 if (doomed >= 0)
581 doomed++;
582 goto def;
583 }
584 ungetkey(c), c = '\\';
04379bab
MH
585 backsl = 1;
586 break;
09035cec
MH
587
588 /*
589 * ^Q Super quote following character
590 * Only ^@ is verboten (trapped at
591 * a lower level) and \n forces a line
592 * split so doesn't really go in.
593 *
594 * ^V Synonym for ^Q
595 */
596 case CTRL(q):
597 case CTRL(v):
598 x = destcol, y = destline;
599 putchar('^');
600 vgoto(y, x);
601 c = getkey();
602#ifdef TIOCSETC
603 if (c == ATTN)
604 c = nttyc.t_intrc;
605#endif
606 if (c != NL) {
607 if (doomed >= 0)
608 doomed++;
609 goto def;
610 }
611 break;
612 }
613 }
614
615 /*
616 * If we get a blank not in the echo area
617 * consider splitting the window in the wrapmargin.
618 */
d266c416
MH
619 if (c != NL && !splitw) {
620 if (c == ' ' && gobblebl) {
09035cec
MH
621 gobbled = 1;
622 continue;
623 }
04379bab
MH
624 if (value(WRAPMARGIN) &&
625 (outcol >= OCOLUMNS - value(WRAPMARGIN) ||
626 backsl && outcol==0) &&
627 commch != 'r') {
d266c416
MH
628 /*
629 * At end of word and hit wrapmargin.
630 * Move the word to next line and keep going.
631 */
632 wdkind = 1;
633 *gcursor++ = c;
04379bab
MH
634 if (backsl)
635 *gcursor++ = getkey();
d266c416
MH
636 *gcursor = 0;
637 /*
638 * Find end of previous word if we are past it.
639 */
640 for (cp=gcursor; cp>ogcursor && isspace(cp[-1]); cp--)
641 ;
04379bab 642 if (outcol+(backsl?OCOLUMNS:0) - (gcursor-cp) >= OCOLUMNS - value(WRAPMARGIN)) {
d266c416
MH
643 /*
644 * Find beginning of previous word.
645 */
646 for (; cp>ogcursor && !isspace(cp[-1]); cp--)
647 ;
648 if (cp <= ogcursor) {
649 /*
650 * There is a single word that
651 * is too long to fit. Just
652 * let it pass, but beep for
653 * each new letter to warn
654 * the luser.
655 */
656 c = *--gcursor;
657 *gcursor = 0;
658 beep();
659 goto dontbreak;
660 }
661 /*
662 * Save it for next line.
663 */
664 macpush(cp, 0);
665 cp--;
666 }
667 macpush("\n", 0);
668 /*
669 * Erase white space before the word.
670 */
671 while (cp > ogcursor && isspace(cp[-1]))
672 cp--; /* skip blank */
673 gobblebl = 3;
674 goto vbackup;
09035cec 675 }
d266c416
MH
676 dontbreak:;
677 }
678
679 /*
680 * Word abbreviation mode.
681 */
682 cstr[0] = c;
683 if (anyabbrs && gcursor > ogcursor && !wordch(cstr) && wordch(gcursor-1)) {
684 int wdtype, abno;
685
686 cstr[1] = 0;
687 wdkind = 1;
688 cp = gcursor - 1;
689 for (wdtype = wordch(cp - 1);
690 cp > ogcursor && wordof(wdtype, cp - 1); cp--)
691 ;
692 *gcursor = 0;
693 for (abno=0; abbrevs[abno].mapto; abno++) {
694 if (eq(cp, abbrevs[abno].cap)) {
695 macpush(cstr, 0);
696 macpush(abbrevs[abno].mapto);
697 goto vbackup;
698 }
699 }
09035cec 700 }
d266c416 701
09035cec
MH
702 switch (c) {
703
704 /*
705 * ^M Except in repeat maps to \n.
706 */
707 case CR:
708 if (vglobp)
709 goto def;
710 c = '\n';
711 /* presto chango ... */
712
713 /*
714 * \n Start new line.
715 */
716 case NL:
717 *aescaped = c;
718 goto vadone;
719
720 /*
721 * escape End insert unless repeat and more to repeat.
722 */
723 case ESCAPE:
724 if (lastvgk)
725 goto def;
726 goto vadone;
727
728 /*
729 * ^D Backtab.
730 * ^T Software forward tab.
731 *
732 * Unless in repeat where this means these
733 * were superquoted in.
734 */
735 case CTRL(d):
736 case CTRL(t):
737 if (vglobp)
738 goto def;
739 /* fall into ... */
740
741 /*
742 * ^D|QUOTE Is a backtab (in a repeated command).
743 */
744 case CTRL(d) | QUOTE:
745 *gcursor = 0;
746 cp = vpastwh(genbuf);
747 c = whitecnt(genbuf);
748 if (ch == CTRL(t)) {
749 /*
750 * ^t just generates new indent replacing
751 * current white space rounded up to soft
752 * tab stop increment.
753 */
754 if (cp != gcursor)
755 /*
756 * BUG: Don't hack ^T except
757 * right after initial
758 * white space.
759 */
760 continue;
761 cp = genindent(iwhite = backtab(c + value(SHIFTWIDTH) + 1));
762 ogcursor = cp;
763 goto vbackup;
764 }
765 /*
766 * ^D works only if we are at the (end of) the
767 * generated autoindent. We count the ^D for repeat
768 * purposes.
769 */
770 if (c == iwhite && c != 0)
771 if (cp == gcursor) {
772 iwhite = backtab(c);
773 CDCNT++;
774 ogcursor = cp = genindent(iwhite);
775 goto vbackup;
776 } else if (&cp[1] == gcursor &&
777 (*cp == '^' || *cp == '0')) {
778 /*
779 * ^^D moves to margin, then back
780 * to current indent on next line.
781 *
782 * 0^D moves to margin and then
783 * stays there.
784 */
785 HADZERO = *cp == '0';
786 ogcursor = cp = genbuf;
787 HADUP = 1 - HADZERO;
788 CDCNT = 1;
789 endim();
790 back1();
887e3e0d 791 vputchar(' ');
09035cec
MH
792 goto vbackup;
793 }
794 if (vglobp && vglobp - iglobp >= 2 &&
795 (vglobp[-2] == '^' || vglobp[-2] == '0')
796 && gcursor == ogcursor + 1)
797 goto bakchar;
798 continue;
799
800 default:
801 /*
802 * Possibly discard control inputs.
803 */
804 if (!vglobp && junk(c)) {
805 beep();
806 continue;
807 }
808def:
04379bab 809 if (!backsl) {
299f2784 810 int cnt;
04379bab 811 putchar(c);
0ab2d2a9 812 flush();
04379bab 813 }
09035cec
MH
814 if (gcursor > &genbuf[LBSIZE - 2])
815 error("Line too long");
816 *gcursor++ = c & TRIM;
817 vcsync();
09035cec
MH
818 if (value(SHOWMATCH) && !iglobp)
819 if (c == ')' || c == '}')
820 lsmatch(gcursor);
09035cec
MH
821 continue;
822 }
823 }
824vadone:
825 *gcursor = 0;
d266c416
MH
826 if (Outchar != termchar)
827 Outchar = OO;
09035cec
MH
828 endim();
829 return (gcursor);
830}
831
832int vgetsplit();
833char *vsplitpt;
834
835/*
836 * Append the line in buffer at lp
837 * to the buffer after dot.
838 */
839vdoappend(lp)
840 char *lp;
841{
842 register int oing = inglobal;
843
844 vsplitpt = lp;
845 inglobal = 1;
846 ignore(append(vgetsplit, dot));
847 inglobal = oing;
848}
849
850/*
851 * Subroutine for vdoappend to pass to append.
852 */
853vgetsplit()
854{
855
856 if (vsplitpt == 0)
857 return (EOF);
858 strcLIN(vsplitpt);
859 vsplitpt = 0;
860 return (0);
861}
862
863/*
864 * Vmaxrep determines the maximum repetitition factor
865 * allowed that will yield total line length less than
44232d5b 866 * LBSIZE characters and also does hacks for the R command.
09035cec
MH
867 */
868vmaxrep(ch, cnt)
869 char ch;
870 register int cnt;
871{
872 register int len, replen;
873
874 if (cnt > LBSIZE - 2)
875 cnt = LBSIZE - 2;
876 replen = strlen(genbuf);
877 if (ch == 'R') {
878 len = strlen(cursor);
879 if (replen < len)
880 len = replen;
881 CP(cursor, cursor + len);
882 vUD2 += len;
883 }
884 len = strlen(linebuf);
885 if (len + cnt * replen <= LBSIZE - 2)
886 return (cnt);
887 cnt = (LBSIZE - 2 - len) / replen;
888 if (cnt == 0) {
889 vsave();
890 error("Line too long");
891 }
892 return (cnt);
893}