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