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