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