1: /* Copyright (c) 1979 Regents of the University of California */
   2: #include "ex.h"
   3: #include "ex_argv.h"
   4: #include "ex_temp.h"
   5: #include "ex_tty.h"
   6: #include "ex_vis.h"
   7: 
   8: /*
   9:  * Command mode subroutines implementing
  10:  *	append, args, copy, delete, join, move, put,
  11:  *	shift, tag, yank, z and undo
  12:  */
  13: 
  14: bool    endline = 1;
  15: line    *tad1;
  16: static  jnoop();
  17: 
  18: /*
  19:  * Append after line a lines returned by function f.
  20:  * Be careful about intermediate states to avoid scramble
  21:  * if an interrupt comes in.
  22:  */
  23: append(f, a)
  24:     int (*f)();
  25:     line *a;
  26: {
  27:     register line *a1, *a2, *rdot;
  28:     int nline;
  29: 
  30:     nline = 0;
  31:     dot = a;
  32:     /*
  33: 	 * This is probably a bug, since it's different than the other tests
  34: 	 * in appendnone, delete, and deletenone. It is known to fail for
  35: 	 * the command :g/foo/r xxx (where there is one foo and the file
  36: 	 * xxx exists) and you try to undo it. I'm leaving it in for now
  37: 	 * because I'm afraid if I change it I'll break something.
  38: 	 */
  39:     if (!inglobal && !inopen && f != getsub) {
  40:         undap1 = undap2 = dot + 1;
  41:         undkind = UNDCHANGE;
  42:     }
  43:     while ((*f)() == 0) {
  44:         if (truedol >= endcore) {
  45:             if (morelines() < 0) {
  46:                 if (!inglobal && f == getsub) {
  47:                     undap1 = addr1;
  48:                     undap2 = addr2 + 1;
  49:                 }
  50:                 error("Out of memory@- too many lines in file");
  51:             }
  52:         }
  53:         nline++;
  54:         a1 = truedol + 1;
  55:         a2 = a1 + 1;
  56:         dot++;
  57:         undap2++;
  58:         dol++;
  59:         unddol++;
  60:         truedol++;
  61:         for (rdot = dot; a1 > rdot;)
  62:             *--a2 = *--a1;
  63:         *rdot = 0;
  64:         putmark(rdot);
  65:         if (f == gettty) {
  66:             dirtcnt++;
  67:             TSYNC();
  68:         }
  69:     }
  70:     return (nline);
  71: }
  72: 
  73: appendnone()
  74: {
  75: 
  76:     if (!inglobal || inopen > 0) {
  77:         undkind = UNDCHANGE;
  78:         undap1 = undap2 = addr1;
  79:     }
  80: }
  81: 
  82: /*
  83:  * Print out the argument list, with []'s around the current name.
  84:  */
  85: pargs()
  86: {
  87:     register char **av = argv0, *as = args0;
  88:     register int ac;
  89: 
  90:     for (ac = 0; ac < argc0; ac++) {
  91:         if (ac != 0)
  92:             putchar(' ');
  93:         if (ac + argc == argc0 - 1)
  94:             printf("[");
  95:         lprintf("%s", as);
  96:         if (ac + argc == argc0 - 1)
  97:             printf("]");
  98:         as = av ? *++av : strend(as) + 1;
  99:     }
 100:     noonl();
 101: }
 102: 
 103: /*
 104:  * Delete lines; two cases are if we are really deleting,
 105:  * more commonly we are just moving lines to the undo save area.
 106:  */
 107: delete(hush)
 108:     bool hush;
 109: {
 110:     register line *a1, *a2;
 111: 
 112:     nonzero();
 113:     if (!inglobal || inopen > 0) {
 114:         register int (*dsavint)();
 115: 
 116:         change();
 117:         dsavint = signal(SIGINT, SIG_IGN);
 118:         undkind = UNDCHANGE;
 119:         a1 = addr1;
 120:         squish();
 121:         a2 = addr2;
 122:         if (a2++ != dol) {
 123:             reverse(a1, a2);
 124:             reverse(a2, dol + 1);
 125:             reverse(a1, dol + 1);
 126:         }
 127:         dol -= a2 - a1;
 128:         unddel = a1 - 1;
 129:         if (a1 > dol)
 130:             a1 = dol;
 131:         dot = a1;
 132:         pkill[0] = pkill[1] = 0;
 133:         signal(SIGINT, dsavint);
 134:     } else {
 135:         register line *a3;
 136:         register int i;
 137: 
 138:         change();
 139:         a1 = addr1;
 140:         a2 = addr2 + 1;
 141:         a3 = truedol;
 142:         i = a2 - a1;
 143:         unddol -= i;
 144:         undap2 -= i;
 145:         dol -= i;
 146:         truedol -= i;
 147:         do
 148:             *a1++ = *a2++;
 149:         while (a2 <= a3);
 150:         a1 = addr1;
 151:         if (a1 > dol)
 152:             a1 = dol;
 153:         dot = a1;
 154:     }
 155:     if (!hush)
 156:         killed();
 157: }
 158: 
 159: deletenone()
 160: {
 161: 
 162:     if (!inglobal || inopen > 0) {
 163:         undkind = UNDCHANGE;
 164:         squish();
 165:         unddel = addr1;
 166:     }
 167: }
 168: 
 169: /*
 170:  * Crush out the undo save area, moving the open/visual
 171:  * save area down in its place.
 172:  */
 173: squish()
 174: {
 175:     register line *a1 = dol + 1, *a2 = unddol + 1, *a3 = truedol + 1;
 176: 
 177:     if (a1 < a2 && a2 < a3)
 178:         do
 179:             *a1++ = *a2++;
 180:         while (a2 < a3);
 181:     truedol -= unddol - dol;
 182:     unddol = dol;
 183: }
 184: 
 185: /*
 186:  * Join lines.  Special hacks put in spaces, two spaces if
 187:  * preceding line ends with '.', or no spaces if next line starts with ).
 188:  */
 189: static  int jcount, jnoop();
 190: 
 191: join(c)
 192:     int c;
 193: {
 194:     register line *a1;
 195:     register char *cp, *cp1;
 196: 
 197:     cp = genbuf;
 198:     *cp = 0;
 199:     for (a1 = addr1; a1 <= addr2; a1++) {
 200:         getline(*a1);
 201:         cp1 = linebuf;
 202:         if (a1 != addr1 && c == 0) {
 203:             while (*cp1 == ' ' || *cp1 == '\t')
 204:                 cp1++;
 205:             if (*cp1 && cp > genbuf && cp[-1] != ' ' && cp[-1] != '\t') {
 206:                 if (*cp1 != ')') {
 207:                     *cp++ = ' ';
 208:                     if (cp[-2] == '.')
 209:                         *cp++ = ' ';
 210:                 }
 211:             }
 212:         }
 213:         while (*cp++ = *cp1++)
 214:             if (cp > &genbuf[LBSIZE-2])
 215:                 error("Line overflow|Result line of join would be too long");
 216:         cp--;
 217:     }
 218:     strcLIN(genbuf);
 219:     delete(0);
 220:     jcount = 1;
 221:     if (FIXUNDO)
 222:         undap1 = undap2 = addr1;
 223:     ignore(append(jnoop, --addr1));
 224:     if (FIXUNDO)
 225:         vundkind = VMANY;
 226: }
 227: 
 228: static
 229: jnoop()
 230: {
 231: 
 232:     return(--jcount);
 233: }
 234: 
 235: /*
 236:  * Move and copy lines.  Hard work is done by move1 which
 237:  * is also called by undo.
 238:  */
 239: int getcopy();
 240: 
 241: move()
 242: {
 243:     register line *adt;
 244:     bool iscopy = 0;
 245: 
 246:     if (Command[0] == 'm') {
 247:         setdot1();
 248:         markpr(addr2 == dot ? addr1 - 1 : addr2 + 1);
 249:     } else {
 250:         iscopy++;
 251:         setdot();
 252:     }
 253:     nonzero();
 254:     adt = address(0);
 255:     if (adt == 0)
 256:         serror("%s where?|%s requires a trailing address", Command);
 257:     newline();
 258:     move1(iscopy, adt);
 259:     killed();
 260: }
 261: 
 262: move1(cflag, addrt)
 263:     int cflag;
 264:     line *addrt;
 265: {
 266:     register line *adt, *ad1, *ad2;
 267:     int lines;
 268: 
 269:     adt = addrt;
 270:     lines = (addr2 - addr1) + 1;
 271:     if (cflag) {
 272:         tad1 = addr1;
 273:         ad1 = dol;
 274:         ignore(append(getcopy, ad1++));
 275:         ad2 = dol;
 276:     } else {
 277:         ad2 = addr2;
 278:         for (ad1 = addr1; ad1 <= ad2;)
 279:             *ad1++ &= ~01;
 280:         ad1 = addr1;
 281:     }
 282:     ad2++;
 283:     if (adt < ad1) {
 284:         if (adt + 1 == ad1 && !cflag && !inglobal)
 285:             error("That move would do nothing!");
 286:         dot = adt + (ad2 - ad1);
 287:         if (++adt != ad1) {
 288:             reverse(adt, ad1);
 289:             reverse(ad1, ad2);
 290:             reverse(adt, ad2);
 291:         }
 292:     } else if (adt >= ad2) {
 293:         dot = adt++;
 294:         reverse(ad1, ad2);
 295:         reverse(ad2, adt);
 296:         reverse(ad1, adt);
 297:     } else
 298:         error("Move to a moved line");
 299:     change();
 300:     if (!inglobal)
 301:         if (cflag) {
 302:             undap1 = addrt + 1;
 303:             undap2 = undap1 + lines;
 304:             deletenone();
 305:         } else {
 306:             undkind = UNDMOVE;
 307:             undap1 = addr1;
 308:             undap2 = addr2;
 309:             unddel = addrt;
 310:             squish();
 311:         }
 312: }
 313: 
 314: getcopy()
 315: {
 316: 
 317:     if (tad1 > addr2)
 318:         return (EOF);
 319:     getline(*tad1++);
 320:     return (0);
 321: }
 322: 
 323: /*
 324:  * Put lines in the buffer from the undo save area.
 325:  */
 326: getput()
 327: {
 328: 
 329:     if (tad1 > unddol)
 330:         return (EOF);
 331:     getline(*tad1++);
 332:     tad1++;
 333:     return (0);
 334: }
 335: 
 336: put()
 337: {
 338:     register int cnt;
 339: 
 340:     cnt = unddol - dol;
 341:     if (cnt && inopen && pkill[0] && pkill[1]) {
 342:         pragged(1);
 343:         return;
 344:     }
 345:     tad1 = dol + 1;
 346:     ignore(append(getput, addr2));
 347:     undkind = UNDPUT;
 348:     notecnt = cnt;
 349:     netchange(cnt);
 350: }
 351: 
 352: /*
 353:  * A tricky put, of a group of lines in the middle
 354:  * of an existing line.  Only from open/visual.
 355:  * Argument says pkills have meaning, e.g. called from
 356:  * put; it is 0 on calls from putreg.
 357:  */
 358: pragged(kill)
 359:     bool kill;
 360: {
 361:     extern char *cursor;
 362:     register char *gp = &genbuf[cursor - linebuf];
 363: 
 364:     /*
 365: 	 * This kind of stuff is TECO's forte.
 366: 	 * We just grunge along, since it cuts
 367: 	 * across our line-oriented model of the world
 368: 	 * almost scrambling our addled brain.
 369: 	 */
 370:     if (!kill)
 371:         getDOT();
 372:     strcpy(genbuf, linebuf);
 373:     getline(*unddol);
 374:     if (kill)
 375:         *pkill[1] = 0;
 376:     strcat(linebuf, gp);
 377:     putmark(unddol);
 378:     getline(dol[1]);
 379:     if (kill)
 380:         strcLIN(pkill[0]);
 381:     strcpy(gp, linebuf);
 382:     strcLIN(genbuf);
 383:     putmark(dol+1);
 384:     undkind = UNDCHANGE;
 385:     undap1 = dot;
 386:     undap2 = dot + 1;
 387:     unddel = dot - 1;
 388:     undo(1);
 389: }
 390: 
 391: /*
 392:  * Shift lines, based on c.
 393:  * If c is neither < nor >, then this is a lisp aligning =.
 394:  */
 395: shift(c, cnt)
 396:     int c;
 397:     int cnt;
 398: {
 399:     register line *addr;
 400:     register char *cp;
 401:     char *dp;
 402:     register int i;
 403: 
 404:     if (!inglobal)
 405:         save12(), undkind = UNDCHANGE;
 406:     cnt *= value(SHIFTWIDTH);
 407:     for (addr = addr1; addr <= addr2; addr++) {
 408:         dot = addr;
 409: #ifdef LISPCODE
 410:         if (c == '=' && addr == addr1 && addr != addr2)
 411:             continue;
 412: #endif
 413:         getDOT();
 414:         i = whitecnt(linebuf);
 415:         switch (c) {
 416: 
 417:         case '>':
 418:             if (linebuf[0] == 0)
 419:                 continue;
 420:             cp = genindent(i + cnt);
 421:             break;
 422: 
 423:         case '<':
 424:             if (i == 0)
 425:                 continue;
 426:             i -= cnt;
 427:             cp = i > 0 ? genindent(i) : genbuf;
 428:             break;
 429: 
 430: #ifdef LISPCODE
 431:         default:
 432:             i = lindent(addr);
 433:             getDOT();
 434:             cp = genindent(i);
 435:             break;
 436: #endif
 437:         }
 438:         if (cp + strlen(dp = vpastwh(linebuf)) >= &genbuf[LBSIZE - 2])
 439:             error("Line too long|Result line after shift would be too long");
 440:         CP(cp, dp);
 441:         strcLIN(genbuf);
 442:         putmark(addr);
 443:     }
 444:     killed();
 445: }
 446: 
 447: #ifdef TAGSCODE
 448: /*
 449:  * Find a tag in the tags file.
 450:  * Most work here is in parsing the tags file itself.
 451:  */
 452: tagfind(quick)
 453:     bool quick;
 454: {
 455:     char cmdbuf[BUFSIZ];
 456:     char filebuf[FNSIZE];
 457:     register int c, d;
 458:     bool samef = 1;
 459:     short omagic;
 460: 
 461:     omagic = value(MAGIC);
 462:     if (!skipend()) {
 463:         register char *lp = lasttag;
 464: 
 465:         while (!iswhite(peekchar()) && !endcmd(peekchar()))
 466:             if (lp < &lasttag[sizeof lasttag - 2])
 467:                 *lp++ = getchar();
 468:             else
 469:                 ignchar();
 470:         *lp++ = 0;
 471:         if (!endcmd(peekchar()))
 472: badtag:
 473:             error("Bad tag|Give one tag per line");
 474:     } else if (lasttag[0] == 0)
 475:         error("No previous tag");
 476:     c = getchar();
 477:     if (!endcmd(c))
 478:         goto badtag;
 479:     if (c == EOF)
 480:         ungetchar(c);
 481:     clrstats();
 482:     io = open("tags", 0);
 483:     if (io < 0)
 484:         error("No tags file");
 485:     while (getfile() == 0) {
 486:         register char *cp = linebuf;
 487:         register char *lp = lasttag;
 488:         char *oglobp;
 489: 
 490:         while (*cp && *lp == *cp)
 491:             cp++, lp++;
 492:         if ((*lp || !iswhite(*cp)) && (value(TAGLENGTH)==0 || lp-lasttag < value(TAGLENGTH)))
 493:             continue;
 494:         close(io);
 495: 
 496:         /* Rest of tag if abbreviated */
 497:         while (*cp && !iswhite(*cp))
 498:             cp++;
 499: 
 500:         while (*cp && iswhite(*cp))
 501:             cp++;
 502:         if (!*cp)
 503: badtags:
 504:             serror("%s: Bad tags file entry", lasttag);
 505:         lp = filebuf;
 506:         while (*cp && *cp != ' ' && *cp != '\t') {
 507:             if (lp < &filebuf[sizeof filebuf - 2])
 508:                 *lp++ = *cp;
 509:             cp++;
 510:         }
 511:         *lp++ = 0;
 512:         if (*cp == 0)
 513:             goto badtags;
 514:         if (dol != zero) {
 515:             /*
 516: 			 * Save current position in 't for ^^ in visual.
 517: 			 */
 518:             names['t'-'a'] = *dot &~ 01;
 519:             if (inopen) {
 520:                 extern char *ncols['z'-'a'+2];
 521:                 extern char *cursor;
 522: 
 523:                 ncols['t'-'a'] = cursor;
 524:             }
 525:         }
 526:         strcpy(cmdbuf, cp);
 527:         if (strcmp(filebuf, savedfile) || !edited) {
 528:             char cmdbuf2[sizeof filebuf + 10];
 529: 
 530:             if (!quick) {
 531:                 ckaw();
 532:                 if (chng && dol > zero)
 533:                     error("No write@since last change (:tag! overrides)");
 534:             }
 535:             oglobp = globp;
 536:             strcpy(cmdbuf2, "e! ");
 537:             strcat(cmdbuf2, filebuf);
 538:             globp = cmdbuf2;
 539:             d = peekc; ungetchar(0);
 540:             commands(1, 1);
 541:             peekc = d;
 542:             globp = oglobp;
 543:             samef = 0;
 544:         }
 545:         oglobp = globp;
 546:         globp = cmdbuf;
 547:         d = peekc; ungetchar(0);
 548:         if (samef)
 549:             markpr(dot);
 550:         value(MAGIC) = 0;   /* force nomagic tags */
 551:         commands(1, 1);
 552:         peekc = d;
 553:         globp = oglobp;
 554:         value(MAGIC) = omagic;
 555:         return;
 556:     }
 557:     serror("%s: No such tag@in tags file", lasttag);
 558: }
 559: #endif
 560: 
 561: /*
 562:  * Save lines from addr1 thru addr2 as though
 563:  * they had been deleted.
 564:  */
 565: yank()
 566: {
 567: 
 568:     save12();
 569:     undkind = UNDNONE;
 570:     killcnt(addr2 - addr1 + 1);
 571: }
 572: 
 573: /*
 574:  * z command; print windows of text in the file.
 575:  *
 576:  * If this seems unreasonably arcane, the reasons
 577:  * are historical.  This is one of the first commands
 578:  * added to the first ex (then called en) and the
 579:  * number of facilities here were the major advantage
 580:  * of en over ed since they allowed more use to be
 581:  * made of fast terminals w/o typing .,.22p all the time.
 582:  */
 583: bool    zhadpr;
 584: bool    znoclear;
 585: short   zweight;
 586: 
 587: zop(hadpr)
 588:     int hadpr;
 589: {
 590:     register int c, lines, op;
 591:     bool excl;
 592: 
 593:     zhadpr = hadpr;
 594:     notempty();
 595:     znoclear = 0;
 596:     zweight = 0;
 597:     excl = exclam();
 598: #ifdef ZCMD
 599:     switch (c = op = getchar()) {
 600: 
 601:     case '^':
 602:         zweight = 1;
 603:     case '-':
 604:     case '+':
 605:         while (peekchar() == op) {
 606:             ignchar();
 607:             zweight++;
 608:         }
 609:     case '=':
 610:     case '.':
 611:         c = getchar();
 612:         break;
 613: 
 614:     case EOF:
 615:         znoclear++;
 616:         break;
 617: 
 618:     default:
 619: #endif
 620:         op = 0;
 621: #ifdef ZCMD
 622:         break;
 623:     }
 624: #endif
 625:     if (isdigit(c)) {
 626:         lines = c - '0';
 627:         for(;;) {
 628:             c = getchar();
 629:             if (!isdigit(c))
 630:                 break;
 631:             lines *= 10;
 632:             lines += c - '0';
 633:         }
 634:         if (lines < LINES)
 635:             znoclear++;
 636:         value(WINDOW) = lines;
 637:         if (op == '=')
 638:             lines += 2;
 639:     } else
 640:         lines = op == EOF ? value(SCROLL) : excl ? LINES - 1 : 2*value(SCROLL);
 641:     if (inopen || c != EOF) {
 642:         ungetchar(c);
 643:         newline();
 644:     }
 645:     addr1 = addr2;
 646:     if (addr2 == 0 && dot < dol && op == 0)
 647:         addr1 = addr2 = dot+1;
 648:     setdot();
 649:     zop2(lines, op);
 650: }
 651: 
 652: zop2(lines, op)
 653:     register int lines;
 654:     register int op;
 655: {
 656:     register line *split;
 657: 
 658:     split = NULL;
 659: #ifdef ZCMD
 660:     switch (op) {
 661: 
 662:     case EOF:
 663:         if (addr2 == dol)
 664:             error("\nAt EOF");
 665:     case '+':
 666:         if (addr2 == dol)
 667:             error("At EOF");
 668:         addr2 += lines * zweight;
 669:         if (addr2 > dol)
 670:             error("Hit BOTTOM");
 671:         addr2++;
 672:     default:
 673: #endif
 674:         addr1 = addr2;
 675:         addr2 += lines-1;
 676:         dot = addr2;
 677: #ifdef ZCMD
 678:         break;
 679: 
 680:     case '=':
 681:     case '.':
 682:         znoclear = 0;
 683:         lines--;
 684:         lines >>= 1;
 685:         if (op == '=')
 686:             lines--;
 687:         addr1 = addr2 - lines;
 688:         if (op == '=')
 689:             dot = split = addr2;
 690:         addr2 += lines;
 691:         if (op == '.') {
 692:             markDOT();
 693:             dot = addr2;
 694:         }
 695:         break;
 696: 
 697:     case '^':
 698:     case '-':
 699:         addr2 -= lines * zweight;
 700:         if (addr2 < one)
 701:             error("Hit TOP");
 702:         lines--;
 703:         addr1 = addr2 - lines;
 704:         dot = addr2;
 705:         break;
 706:     }
 707: #endif
 708:     if (addr1 <= zero)
 709:         addr1 = one;
 710:     if (addr2 > dol)
 711:         addr2 = dol;
 712:     if (dot > dol)
 713:         dot = dol;
 714:     if (addr1 > addr2)
 715:         return;
 716:     if (op == EOF && zhadpr) {
 717:         getline(*addr1);
 718:         putchar('\r' | QUOTE);
 719:         shudclob = 1;
 720:     } else if (znoclear == 0 && CL != NOSTR && !inopen) {
 721:         flush1();
 722:         vclear();
 723:     }
 724:     if (addr2 - addr1 > 1)
 725:         pstart();
 726:     if (split) {
 727:         plines(addr1, split - 1, 0);
 728:         splitit();
 729:         plines(split, split, 0);
 730:         splitit();
 731:         addr1 = split + 1;
 732:     }
 733:     plines(addr1, addr2, 0);
 734: }
 735: 
 736: static
 737: splitit()
 738: {
 739:     register int l;
 740: 
 741:     for (l = COLUMNS > 80 ? 40 : COLUMNS / 2; l > 0; l--)
 742:         putchar('-');
 743:     putnl();
 744: }
 745: 
 746: plines(adr1, adr2, movedot)
 747:     line *adr1;
 748:     register line *adr2;
 749:     bool movedot;
 750: {
 751:     register line *addr;
 752: 
 753:     pofix();
 754:     for (addr = adr1; addr <= adr2; addr++) {
 755:         getline(*addr);
 756:         pline(lineno(addr));
 757:         if (inopen)
 758:             putchar('\n' | QUOTE);
 759:         if (movedot)
 760:             dot = addr;
 761:     }
 762: }
 763: 
 764: pofix()
 765: {
 766: 
 767:     if (inopen && Outchar != termchar) {
 768:         vnfl();
 769:         setoutt();
 770:     }
 771: }
 772: 
 773: /*
 774:  * Dudley doright to the rescue.
 775:  * Undo saves the day again.
 776:  * A tip of the hatlo hat to Warren Teitleman
 777:  * who made undo as useful as do.
 778:  *
 779:  * Command level undo works easily because
 780:  * the editor has a unique temporary file
 781:  * index for every line which ever existed.
 782:  * We don't have to save large blocks of text,
 783:  * only the indices which are small.  We do this
 784:  * by moving them to after the last line in the
 785:  * line buffer array, and marking down info
 786:  * about whence they came.
 787:  *
 788:  * Undo is its own inverse.
 789:  */
 790: undo(c)
 791:     bool c;
 792: {
 793:     register int i;
 794:     register line *jp, *kp;
 795:     line *dolp1, *newdol, *newadot;
 796: 
 797:     if (inglobal && inopen <= 0)
 798:         error("Can't undo in global@commands");
 799:     if (!c)
 800:         somechange();
 801:     pkill[0] = pkill[1] = 0;
 802:     change();
 803:     if (undkind == UNDMOVE) {
 804:         /*
 805: 		 * Command to be undone is a move command.
 806: 		 * This is handled as a special case by noting that
 807: 		 * a move "a,b m c" can be inverted by another move.
 808: 		 */
 809:         if ((i = (jp = unddel) - undap2) > 0) {
 810:             /*
 811: 			 * when c > b inverse is a+(c-b),c m a-1
 812: 			 */
 813:             addr2 = jp;
 814:             addr1 = (jp = undap1) + i;
 815:             unddel = jp-1;
 816:         } else {
 817:             /*
 818: 			 * when b > c inverse is  c+1,c+1+(b-a) m b
 819: 			 */
 820:             addr1 = ++jp;
 821:             addr2 = jp + ((unddel = undap2) - undap1);
 822:         }
 823:         kp = undap1;
 824:         move1(0, unddel);
 825:         dot = kp;
 826:         Command = "move";
 827:         killed();
 828:     } else {
 829:         int cnt;
 830: 
 831:         newadot = dot;
 832:         cnt = lineDOL();
 833:         newdol = dol;
 834:         dolp1 = dol + 1;
 835:         /*
 836: 		 * Command to be undone is a non-move.
 837: 		 * All such commands are treated as a combination of
 838: 		 * a delete command and a append command.
 839: 		 * We first move the lines appended by the last command
 840: 		 * from undap1 to undap2-1 so that they are just before the
 841: 		 * saved deleted lines.
 842: 		 */
 843:         if ((i = (kp = undap2) - (jp = undap1)) > 0) {
 844:             if (kp != dolp1) {
 845:                 reverse(jp, kp);
 846:                 reverse(kp, dolp1);
 847:                 reverse(jp, dolp1);
 848:             }
 849:             /*
 850: 			 * Account for possible backward motion of target
 851: 			 * for restoration of saved deleted lines.
 852: 			 */
 853:             if (unddel >= jp)
 854:                 unddel -= i;
 855:             newdol -= i;
 856:             /*
 857: 			 * For the case where no lines are restored, dot
 858: 			 * is the line before the first line deleted.
 859: 			 */
 860:             dot = jp-1;
 861:         }
 862:         /*
 863: 		 * Now put the deleted lines, if any, back where they were.
 864: 		 * Basic operation is: dol+1,unddol m unddel
 865: 		 */
 866:         if (undkind == UNDPUT) {
 867:             unddel = undap1 - 1;
 868:             squish();
 869:         }
 870:         jp = unddel + 1;
 871:         if ((i = (kp = unddol) - dol) > 0) {
 872:             if (jp != dolp1) {
 873:                 reverse(jp, dolp1);
 874:                 reverse(dolp1, ++kp);
 875:                 reverse(jp, kp);
 876:             }
 877:             /*
 878: 			 * Account for possible forward motion of the target
 879: 			 * for restoration of the deleted lines.
 880: 			 */
 881:             if (undap1 >= jp)
 882:                 undap1 += i;
 883:             /*
 884: 			 * Dot is the first resurrected line.
 885: 			 */
 886:             dot = jp;
 887:             newdol += i;
 888:         }
 889:         /*
 890: 		 * Clean up so we are invertible
 891: 		 */
 892:         unddel = undap1 - 1;
 893:         undap1 = jp;
 894:         undap2 = jp + i;
 895:         dol = newdol;
 896:         netchHAD(cnt);
 897:         if (undkind == UNDALL) {
 898:             dot = undadot;
 899:             undadot = newadot;
 900:         }
 901:         undkind = UNDCHANGE;
 902:     }
 903:     if (dot == zero && dot != dol)
 904:         dot = one;
 905: }
 906: 
 907: /*
 908:  * Be (almost completely) sure there really
 909:  * was a change, before claiming to undo.
 910:  */
 911: somechange()
 912: {
 913:     register line *ip, *jp;
 914: 
 915:     switch (undkind) {
 916: 
 917:     case UNDMOVE:
 918:         return;
 919: 
 920:     case UNDCHANGE:
 921:         if (undap1 == undap2 && dol == unddol)
 922:             break;
 923:         return;
 924: 
 925:     case UNDPUT:
 926:         if (undap1 != undap2)
 927:             return;
 928:         break;
 929: 
 930:     case UNDALL:
 931:         if (unddol - dol != lineDOL())
 932:             return;
 933:         for (ip = one, jp = dol + 1; ip <= dol; ip++, jp++)
 934:             if ((*ip &~ 01) != (*jp &~ 01))
 935:                 return;
 936:         break;
 937: 
 938:     case UNDNONE:
 939:         error("Nothing to undo");
 940:     }
 941:     error("Nothing changed|Last undoable command didn't change anything");
 942: }

Defined functions

delete defined in line 107; used 5 times
getcopy defined in line 314; used 2 times
getput defined in line 326; used 1 times
jnoop defined in line 228; used 3 times
join defined in line 191; used 2 times
move defined in line 241; used 3 times
move1 defined in line 262; used 2 times
pargs defined in line 85; used 1 times
plines defined in line 746; used 5 times
pofix defined in line 764; used 4 times
pragged defined in line 358; used 2 times
put defined in line 336; used 2 times
somechange defined in line 911; used 1 times
splitit defined in line 736; used 2 times
squish defined in line 173; used 7 times
tagfind defined in line 452; used 1 times
undo defined in line 790; used 3 times
yank defined in line 565; used 2 times
zop defined in line 587; used 2 times
zop2 defined in line 652; used 2 times

Defined variables

endline defined in line 14; never used
jcount defined in line 189; used 2 times
tad1 defined in line 15; used 7 times
zhadpr defined in line 583; used 2 times
znoclear defined in line 584; used 5 times
zweight defined in line 585; used 5 times
Last modified: 1980-09-13
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2767
Valid CSS Valid XHTML 1.0 Strict