|
|
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.