|
|
1.1 ! root 1: /* Copyright (c) 1981 Regents of the University of California */ ! 2: static char *sccsid = "@(#)ex_vops2.c 6.5 7/26/81"; ! 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: extern char *vUA1, *vUA2; /* mjm: extern; also in ex_vops.c */ ! 13: extern char *vUD1, *vUD2; /* mjm: extern; also in ex_vops.c */ ! 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: int ch; /* mjm: char --> int */ ! 108: int cnt, indent; ! 109: { ! 110: register int i; ! 111: register char *gcursor; ! 112: bool escape; ! 113: int repcnt, savedoomed; ! 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, ch); ! 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: savedoomed = doomed; ! 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); ! 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; ! 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: */ ! 338: if (FIXUNDO && vundkind == VCHNG) { ! 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: */ ! 388: back1() ! 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 ! 406: * first time you did it. commch is the command character ! 407: * involved, including the prompt for readline. ! 408: */ ! 409: char * ! 410: vgetline(cnt, gcursor, aescaped, commch) ! 411: int cnt; ! 412: register char *gcursor; ! 413: bool *aescaped; ! 414: char commch; ! 415: { ! 416: register int c, ch; ! 417: register char *cp; ! 418: int x, y, iwhite, backsl=0; ! 419: char *iglobp; ! 420: char cstr[2]; ! 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 (;;) { ! 449: backsl = 0; ! 450: if (gobblebl) ! 451: gobblebl--; ! 452: if (cnt != 0) { ! 453: cnt--; ! 454: if (cnt == 0) ! 455: goto vadone; ! 456: } ! 457: c = getkey(); ! 458: if (c != ATTN) ! 459: c &= (QUOTE|TRIM); ! 460: ch = c; ! 461: maphopcnt = 0; ! 462: if (vglobp == 0 && Peekkey == 0 && commch != 'r') ! 463: while ((ch = map(c, immacs)) != c) { ! 464: c = ch; ! 465: if (!value(REMAP)) ! 466: break; ! 467: if (++maphopcnt > 256) ! 468: error("Infinite macro loop"); ! 469: } ! 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: */ ! 478: #ifndef USG3TTY ! 479: if (c == tty.sg_erase) ! 480: c = CTRL(h); ! 481: else if (c == tty.sg_kill) ! 482: c = -1; ! 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 ! 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): ! 514: bakchar: ! 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; ! 549: vbackup: ! 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(); ! 572: #ifndef USG3TTY ! 573: if (c == tty.sg_erase || c == tty.sg_kill) ! 574: #else ! 575: if (c == tty.c_cc[VERASE] ! 576: || c == tty.c_cc[VKILL]) ! 577: #endif ! 578: { ! 579: vgoto(y, x); ! 580: if (doomed >= 0) ! 581: doomed++; ! 582: goto def; ! 583: } ! 584: ungetkey(c), c = '\\'; ! 585: backsl = 1; ! 586: break; ! 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: */ ! 619: if (c != NL && !splitw) { ! 620: if (c == ' ' && gobblebl) { ! 621: gobbled = 1; ! 622: continue; ! 623: } ! 624: if (value(WRAPMARGIN) && ! 625: (outcol >= OCOLUMNS - value(WRAPMARGIN) || ! 626: backsl && outcol==0) && ! 627: commch != 'r') { ! 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; ! 634: if (backsl) ! 635: *gcursor++ = getkey(); ! 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: ; ! 642: if (outcol+(backsl?OCOLUMNS:0) - (gcursor-cp) >= OCOLUMNS - value(WRAPMARGIN)) { ! 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; ! 675: } ! 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: } ! 700: } ! 701: ! 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(); ! 791: vputchar(' '); ! 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: } ! 808: def: ! 809: if (!backsl) { ! 810: int cnt; ! 811: putchar(c); ! 812: flush(); ! 813: } ! 814: if (gcursor > &genbuf[LBSIZE - 2]) ! 815: error("Line too long"); ! 816: *gcursor++ = c & TRIM; ! 817: vcsync(); ! 818: if (value(SHOWMATCH) && !iglobp) ! 819: if (c == ')' || c == '}') ! 820: lsmatch(gcursor); ! 821: continue; ! 822: } ! 823: } ! 824: vadone: ! 825: *gcursor = 0; ! 826: if (Outchar != termchar) ! 827: Outchar = OO; ! 828: endim(); ! 829: return (gcursor); ! 830: } ! 831: ! 832: int vgetsplit(); ! 833: char *vsplitpt; ! 834: ! 835: /* ! 836: * Append the line in buffer at lp ! 837: * to the buffer after dot. ! 838: */ ! 839: vdoappend(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: */ ! 853: vgetsplit() ! 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 ! 866: * LBSIZE characters and also does hacks for the R command. ! 867: */ ! 868: vmaxrep(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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.