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: }

Defined functions

ateopr defined in line 87; used 4 times
back1 defined in line 399; used 3 times
bleep defined in line 27; used 2 times
takeout defined in line 62; used 1 times
vappend defined in line 114; used 5 times
vdcMID defined in line 43; used 2 times
vdoappend defined in line 850; used 5 times
vgetline defined in line 420; used 3 times
vgetsplit defined in line 864; used 2 times
vmaxrep defined in line 879; used 1 times

Defined variables

gobbled defined in line 111; used 3 times
ogcursor defined in line 112; used 16 times
sccsid defined in line 8; never used
vaifirst defined in line 110; used 4 times
vsplitpt defined in line 844; used 4 times
Last modified: 1985-06-08
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2273
Valid CSS Valid XHTML 1.0 Strict