|
|
1.1 ! root 1: /* cmd2.c */ ! 2: ! 3: /* Author: ! 4: * Steve Kirkendall ! 5: * 14407 SW Teal Blvd. #C ! 6: * Beaverton, OR 97005 ! 7: * [email protected] ! 8: */ ! 9: ! 10: ! 11: /* This file contains some of the commands - mostly ones that change text */ ! 12: ! 13: #include "config.h" ! 14: #include "ctype.h" ! 15: #include "vi.h" ! 16: #include "regexp.h" ! 17: #if TOS ! 18: # include <stat.h> ! 19: #else ! 20: # if OSK ! 21: # include "osk.h" ! 22: # else ! 23: # if AMIGA ! 24: # include "amistat.h" ! 25: # else ! 26: # include <sys/stat.h> ! 27: # endif ! 28: # endif ! 29: #endif ! 30: ! 31: ! 32: /*ARGSUSED*/ ! 33: void cmd_substitute(frommark, tomark, cmd, bang, extra) ! 34: MARK frommark; ! 35: MARK tomark; ! 36: CMD cmd; ! 37: int bang; ! 38: char *extra; /* rest of the command line */ ! 39: { ! 40: char *line; /* a line from the file */ ! 41: regexp *re; /* the compiled search expression */ ! 42: char *subst; /* the substitution string */ ! 43: char *opt; /* substitution options */ ! 44: long l; /* a line number */ ! 45: char *s, *d; /* used during subtitutions */ ! 46: char *conf; /* used during confirmation */ ! 47: long chline; /* # of lines changed */ ! 48: long chsub; /* # of substitutions made */ ! 49: static optp; /* boolean option: print when done? */ ! 50: static optg; /* boolean option: substitute globally in line? */ ! 51: static optc; /* boolean option: confirm before subst? */ ! 52: #ifndef CRUNCH ! 53: long oldnlines; ! 54: #endif ! 55: ! 56: ! 57: /* for now, assume this will fail */ ! 58: rptlines = -1L; ! 59: ! 60: if (cmd == CMD_SUBAGAIN) ! 61: { ! 62: #ifndef NO_MAGIC ! 63: if (*o_magic) ! 64: subst = "~"; ! 65: else ! 66: #endif ! 67: subst = "\\~"; ! 68: re = regcomp(""); ! 69: ! 70: /* if visual "&", then turn off the "p" and "c" options */ ! 71: if (bang) ! 72: { ! 73: optp = optc = FALSE; ! 74: } ! 75: } ! 76: else /* CMD_SUBSTITUTE */ ! 77: { ! 78: /* make sure we got a search pattern */ ! 79: if (*extra != '/' && *extra != '?') ! 80: { ! 81: msg("Usage: s/regular expression/new text/"); ! 82: return; ! 83: } ! 84: ! 85: /* parse & compile the search pattern */ ! 86: subst = parseptrn(extra); ! 87: re = regcomp(extra + 1); ! 88: } ! 89: ! 90: /* abort if RE error -- error message already given by regcomp() */ ! 91: if (!re) ! 92: { ! 93: return; ! 94: } ! 95: ! 96: if (cmd == CMD_SUBSTITUTE) ! 97: { ! 98: /* parse the substitution string & find the option string */ ! 99: for (opt = subst; *opt && *opt != *extra; opt++) ! 100: { ! 101: if (*opt == '\\' && opt[1]) ! 102: { ! 103: opt++; ! 104: } ! 105: } ! 106: if (*opt) ! 107: { ! 108: *opt++ = '\0'; ! 109: } ! 110: ! 111: /* analyse the option string */ ! 112: if (!*o_edcompatible) ! 113: { ! 114: optp = optg = optc = FALSE; ! 115: } ! 116: while (*opt) ! 117: { ! 118: switch (*opt++) ! 119: { ! 120: case 'p': optp = !optp; break; ! 121: case 'g': optg = !optg; break; ! 122: case 'c': optc = !optc; break; ! 123: case ' ': ! 124: case '\t': break; ! 125: default: ! 126: msg("Subst options are p, c, and g -- not %c", opt[-1]); ! 127: return; ! 128: } ! 129: } ! 130: } ! 131: ! 132: /* if "c" or "p" flag was given, and we're in visual mode, then NEWLINE */ ! 133: if ((optc || optp) && mode == MODE_VI) ! 134: { ! 135: addch('\n'); ! 136: exrefresh(); ! 137: } ! 138: ! 139: ChangeText ! 140: { ! 141: /* reset the change counters */ ! 142: chline = chsub = 0L; ! 143: ! 144: /* for each selected line */ ! 145: for (l = markline(frommark); l <= markline(tomark); l++) ! 146: { ! 147: /* fetch the line */ ! 148: line = fetchline(l); ! 149: ! 150: /* if it contains the search pattern... */ ! 151: if (regexec(re, line, TRUE)) ! 152: { ! 153: /* increment the line change counter */ ! 154: chline++; ! 155: ! 156: /* initialize the pointers */ ! 157: s = line; ! 158: d = tmpblk.c; ! 159: ! 160: /* do once or globally ... */ ! 161: do ! 162: { ! 163: #ifndef CRUNCH ! 164: /* confirm, if necessary */ ! 165: if (optc) ! 166: { ! 167: for (conf = line; conf < re->startp[0]; conf++) ! 168: addch(*conf); ! 169: standout(); ! 170: for ( ; conf < re->endp[0]; conf++) ! 171: addch(*conf); ! 172: standend(); ! 173: for (; *conf; conf++) ! 174: addch(*conf); ! 175: addch('\n'); ! 176: exrefresh(); ! 177: if (getkey(0) != 'y') ! 178: { ! 179: /* copy accross the original chars */ ! 180: while (s < re->endp[0]) ! 181: *d++ = *s++; ! 182: ! 183: /* skip to next match on this line, if any */ ! 184: goto Continue; ! 185: } ! 186: } ! 187: #endif /* not CRUNCH */ ! 188: ! 189: /* increment the substitution change counter */ ! 190: chsub++; ! 191: ! 192: /* copy stuff from before the match */ ! 193: while (s < re->startp[0]) ! 194: { ! 195: *d++ = *s++; ! 196: } ! 197: ! 198: /* substitute for the matched part */ ! 199: regsub(re, subst, d); ! 200: s = re->endp[0]; ! 201: d += strlen(d); ! 202: ! 203: Continue: ! 204: /* if this regexp could conceivably match ! 205: * a zero-length string, then require at ! 206: * least 1 unmatched character between ! 207: * matches. ! 208: */ ! 209: if (re->minlen == 0) ! 210: { ! 211: if (!*s) ! 212: break; ! 213: *d++ = *s++; ! 214: } ! 215: ! 216: } while (optg && regexec(re, s, FALSE)); ! 217: ! 218: /* copy stuff from after the match */ ! 219: while (*d++ = *s++) /* yes, ASSIGNMENT! */ ! 220: { ! 221: } ! 222: ! 223: #ifndef CRUNCH ! 224: /* NOTE: since the substitution text is allowed to have ^Ms which are ! 225: * translated into newlines, it is possible that the number of lines ! 226: * in the file will increase after each line has been substituted. ! 227: * we need to adjust for this. ! 228: */ ! 229: oldnlines = nlines; ! 230: #endif ! 231: ! 232: /* replace the old version of the line with the new */ ! 233: d[-1] = '\n'; ! 234: d[0] = '\0'; ! 235: change(MARK_AT_LINE(l), MARK_AT_LINE(l + 1), tmpblk.c); ! 236: ! 237: #ifndef CRUNCH ! 238: l += nlines - oldnlines; ! 239: tomark += MARK_AT_LINE(nlines - oldnlines); ! 240: #endif ! 241: ! 242: /* if supposed to print it, do so */ ! 243: if (optp) ! 244: { ! 245: addstr(tmpblk.c); ! 246: exrefresh(); ! 247: } ! 248: ! 249: /* move the cursor to that line */ ! 250: cursor = MARK_AT_LINE(l); ! 251: } ! 252: } ! 253: } ! 254: ! 255: /* free the regexp */ ! 256: _free_(re); ! 257: ! 258: /* if done from within a ":g" command, then finish silently */ ! 259: if (doingglobal) ! 260: { ! 261: rptlines = chline; ! 262: rptlabel = "changed"; ! 263: return; ! 264: } ! 265: ! 266: /* Reporting */ ! 267: if (chsub == 0) ! 268: { ! 269: msg("Substitution failed"); ! 270: } ! 271: else if (chline >= *o_report) ! 272: { ! 273: msg("%ld substitutions on %ld lines", chsub, chline); ! 274: } ! 275: rptlines = 0L; ! 276: } ! 277: ! 278: ! 279: ! 280: ! 281: /*ARGSUSED*/ ! 282: void cmd_delete(frommark, tomark, cmd, bang, extra) ! 283: MARK frommark; ! 284: MARK tomark; ! 285: CMD cmd; ! 286: int bang; ! 287: char *extra; ! 288: { ! 289: MARK curs2; /* an altered form of the cursor */ ! 290: ! 291: /* choose your cut buffer */ ! 292: if (*extra == '"') ! 293: { ! 294: extra++; ! 295: } ! 296: if (*extra) ! 297: { ! 298: cutname(*extra); ! 299: } ! 300: ! 301: /* make sure we're talking about whole lines here */ ! 302: frommark = frommark & ~(BLKSIZE - 1); ! 303: tomark = (tomark & ~(BLKSIZE - 1)) + BLKSIZE; ! 304: ! 305: /* yank the lines */ ! 306: cut(frommark, tomark); ! 307: ! 308: /* if CMD_DELETE then delete the lines */ ! 309: if (cmd != CMD_YANK) ! 310: { ! 311: curs2 = cursor; ! 312: ChangeText ! 313: { ! 314: /* delete the lines */ ! 315: delete(frommark, tomark); ! 316: } ! 317: if (curs2 > tomark) ! 318: { ! 319: cursor = curs2 - tomark + frommark; ! 320: } ! 321: else if (curs2 > frommark) ! 322: { ! 323: cursor = frommark; ! 324: } ! 325: } ! 326: } ! 327: ! 328: ! 329: /*ARGSUSED*/ ! 330: void cmd_append(frommark, tomark, cmd, bang, extra) ! 331: MARK frommark; ! 332: MARK tomark; ! 333: CMD cmd; ! 334: int bang; ! 335: char *extra; ! 336: { ! 337: long l; /* line counter */ ! 338: ! 339: #ifndef CRUNCH ! 340: /* if '!' then toggle auto-indent */ ! 341: if (bang) ! 342: { ! 343: *o_autoindent = !*o_autoindent; ! 344: } ! 345: #endif ! 346: ! 347: ChangeText ! 348: { ! 349: /* if we're doing a change, delete the old version */ ! 350: if (cmd == CMD_CHANGE) ! 351: { ! 352: /* delete 'em */ ! 353: cmd_delete(frommark, tomark, cmd, bang, extra); ! 354: } ! 355: ! 356: /* new lines start at the frommark line, or after it */ ! 357: l = markline(frommark); ! 358: if (cmd == CMD_APPEND) ! 359: { ! 360: l++; ! 361: } ! 362: ! 363: /* get lines until no more lines, or "." line, and insert them */ ! 364: while (vgets('\0', tmpblk.c, BLKSIZE) >= 0) ! 365: { ! 366: addch('\n'); ! 367: if (!strcmp(tmpblk.c, ".")) ! 368: { ! 369: break; ! 370: } ! 371: ! 372: strcat(tmpblk.c, "\n"); ! 373: add(MARK_AT_LINE(l), tmpblk.c); ! 374: l++; ! 375: } ! 376: } ! 377: ! 378: /* on the odd chance that we're calling this from vi mode ... */ ! 379: redraw(MARK_UNSET, FALSE); ! 380: } ! 381: ! 382: ! 383: /*ARGSUSED*/ ! 384: void cmd_put(frommark, tomark, cmd, bang, extra) ! 385: MARK frommark; ! 386: MARK tomark; ! 387: CMD cmd; ! 388: int bang; ! 389: char *extra; ! 390: { ! 391: /* choose your cut buffer */ ! 392: if (*extra == '"') ! 393: { ! 394: extra++; ! 395: } ! 396: if (*extra) ! 397: { ! 398: cutname(*extra); ! 399: } ! 400: ! 401: /* paste it */ ! 402: ChangeText ! 403: { ! 404: cursor = paste(frommark, TRUE, FALSE); ! 405: } ! 406: } ! 407: ! 408: ! 409: /*ARGSUSED*/ ! 410: void cmd_join(frommark, tomark, cmd, bang, extra) ! 411: MARK frommark; ! 412: MARK tomark; ! 413: CMD cmd; ! 414: int bang; ! 415: char *extra; ! 416: { ! 417: long l; ! 418: char *scan; ! 419: int len; /* length of the new line */ ! 420: ! 421: /* if only one line is specified, assume the following one joins too */ ! 422: if (markline(frommark) == nlines) ! 423: { ! 424: msg("Nothing to join with this line"); ! 425: return; ! 426: } ! 427: if (markline(frommark) == markline(tomark)) ! 428: { ! 429: tomark += BLKSIZE; ! 430: } ! 431: ! 432: /* get the first line */ ! 433: l = markline(frommark); ! 434: strcpy(tmpblk.c, fetchline(l)); ! 435: len = strlen(tmpblk.c); ! 436: ! 437: /* build the longer line */ ! 438: while (++l <= markline(tomark)) ! 439: { ! 440: /* get the next line */ ! 441: scan = fetchline(l); ! 442: ! 443: /* remove any leading whitespace */ ! 444: while (*scan == '\t' || *scan == ' ') ! 445: { ! 446: scan++; ! 447: } ! 448: ! 449: /* see if the line will fit */ ! 450: if (strlen(scan) + len + 3 > BLKSIZE) ! 451: { ! 452: msg("Can't join -- the resulting line would be too long"); ! 453: return; ! 454: } ! 455: ! 456: /* catenate it, with a space (or two) in between */ ! 457: if (!bang) ! 458: { ! 459: if (len >= 1) ! 460: { ! 461: if (tmpblk.c[len - 1] == '.' ! 462: || tmpblk.c[len - 1] == '?' ! 463: || tmpblk.c[len - 1] == '!') ! 464: { ! 465: tmpblk.c[len++] = ' '; ! 466: tmpblk.c[len++] = ' '; ! 467: } ! 468: else if (tmpblk.c[len - 1] != ' ') ! 469: { ! 470: tmpblk.c[len++] = ' '; ! 471: } ! 472: } ! 473: } ! 474: strcpy(tmpblk.c + len, scan); ! 475: len += strlen(scan); ! 476: } ! 477: tmpblk.c[len++] = '\n'; ! 478: tmpblk.c[len] = '\0'; ! 479: ! 480: /* make the change */ ! 481: ChangeText ! 482: { ! 483: frommark &= ~(BLKSIZE - 1); ! 484: tomark &= ~(BLKSIZE - 1); ! 485: tomark += BLKSIZE; ! 486: change(frommark, tomark, tmpblk.c); ! 487: } ! 488: ! 489: /* Reporting... */ ! 490: rptlines = markline(tomark) - markline(frommark) - 1L; ! 491: rptlabel = "joined"; ! 492: } ! 493: ! 494: ! 495: ! 496: /*ARGSUSED*/ ! 497: void cmd_shift(frommark, tomark, cmd, bang, extra) ! 498: MARK frommark; ! 499: MARK tomark; ! 500: CMD cmd; ! 501: int bang; ! 502: char *extra; ! 503: { ! 504: long l; /* line number counter */ ! 505: int oldidx; /* number of chars previously used for indent */ ! 506: int newidx; /* number of chars in the new indent string */ ! 507: int oldcol; /* previous indent amount */ ! 508: int newcol; /* new indent amount */ ! 509: char *text; /* pointer to the old line's text */ ! 510: ! 511: ChangeText ! 512: { ! 513: /* for each line to shift... */ ! 514: for (l = markline(frommark); l <= markline(tomark); l++) ! 515: { ! 516: /* get the line - ignore empty lines unless ! mode */ ! 517: text = fetchline(l); ! 518: if (!*text && !bang) ! 519: continue; ! 520: ! 521: /* calc oldidx and oldcol */ ! 522: for (oldidx = 0, oldcol = 0; ! 523: text[oldidx] == ' ' || text[oldidx] == '\t'; ! 524: oldidx++) ! 525: { ! 526: if (text[oldidx] == ' ') ! 527: { ! 528: oldcol += 1; ! 529: } ! 530: else ! 531: { ! 532: oldcol += *o_tabstop - (oldcol % *o_tabstop); ! 533: } ! 534: } ! 535: ! 536: /* calc newcol */ ! 537: if (cmd == CMD_SHIFTR) ! 538: { ! 539: newcol = oldcol + (*o_shiftwidth & 0xff); ! 540: } ! 541: else ! 542: { ! 543: newcol = oldcol - (*o_shiftwidth & 0xff); ! 544: if (newcol < 0) ! 545: newcol = 0; ! 546: } ! 547: ! 548: /* if no change, then skip to next line */ ! 549: if (oldcol == newcol) ! 550: continue; ! 551: ! 552: /* build a new indent string */ ! 553: newidx = 0; ! 554: if (*o_autotab) ! 555: { ! 556: while (newcol >= *o_tabstop) ! 557: { ! 558: tmpblk.c[newidx++] = '\t'; ! 559: newcol -= *o_tabstop; ! 560: } ! 561: } ! 562: while (newcol > 0) ! 563: { ! 564: tmpblk.c[newidx++] = ' '; ! 565: newcol--; ! 566: } ! 567: tmpblk.c[newidx] = '\0'; ! 568: ! 569: /* change the old indent string into the new */ ! 570: change(MARK_AT_LINE(l), MARK_AT_LINE(l) + oldidx, tmpblk.c); ! 571: } ! 572: } ! 573: ! 574: /* Reporting... */ ! 575: rptlines = markline(tomark) - markline(frommark) + 1L; ! 576: if (cmd == CMD_SHIFTR) ! 577: { ! 578: rptlabel = ">ed"; ! 579: } ! 580: else ! 581: { ! 582: rptlabel = "<ed"; ! 583: } ! 584: } ! 585: ! 586: ! 587: /*ARGSUSED*/ ! 588: void cmd_read(frommark, tomark, cmd, bang, extra) ! 589: MARK frommark; ! 590: MARK tomark; ! 591: CMD cmd; ! 592: int bang; ! 593: char *extra; ! 594: { ! 595: int fd, rc; /* used while reading from the file */ ! 596: char *scan; /* used for finding NUL characters */ ! 597: int hadnul; /* boolean: any NULs found? */ ! 598: int addnl; /* boolean: forced to add newlines? */ ! 599: int len; /* number of chars in current line */ ! 600: long lines; /* number of lines in current block */ ! 601: struct stat statb; ! 602: ! 603: /* special case: if ":r !cmd" then let the filter() function do it */ ! 604: if (extra[0] == '!') ! 605: { ! 606: filter(frommark, MARK_UNSET, extra + 1, TRUE); ! 607: return; ! 608: } ! 609: ! 610: /* open the file */ ! 611: fd = open(extra, O_RDONLY); ! 612: if (fd < 0) ! 613: { ! 614: msg("Can't open \"%s\"", extra); ! 615: return; ! 616: } ! 617: ! 618: #ifndef CRUNCH ! 619: if (stat(extra, &statb) < 0) ! 620: { ! 621: msg("Can't stat \"%s\"", extra); ! 622: } ! 623: # if TOS ! 624: if (statb.st_mode & S_IJDIR) ! 625: # else ! 626: # if OSK ! 627: if (statb.st_mode & S_IFDIR) ! 628: # else ! 629: if ((statb.st_mode & S_IFMT) != S_IFREG) ! 630: # endif ! 631: # endif ! 632: { ! 633: msg("\"%s\" is not a regular file", extra); ! 634: return; ! 635: } ! 636: #endif /* not CRUNCH */ ! 637: ! 638: /* get blocks from the file, and add them */ ! 639: ChangeText ! 640: { ! 641: /* insertion starts at the line following frommark */ ! 642: tomark = frommark = (frommark | (BLKSIZE - 1L)) + 1L; ! 643: len = 0; ! 644: hadnul = addnl = FALSE; ! 645: ! 646: /* add an extra newline, so partial lines at the end of ! 647: * the file don't trip us up ! 648: */ ! 649: add(tomark, "\n"); ! 650: ! 651: /* for each chunk of text... */ ! 652: while ((rc = tread(fd, tmpblk.c, BLKSIZE - 1)) > 0) ! 653: { ! 654: /* count newlines, convert NULs, etc. ... */ ! 655: for (lines = 0, scan = tmpblk.c; rc > 0; rc--, scan++) ! 656: { ! 657: /* break up long lines */ ! 658: if (*scan != '\n' && len + 2 > BLKSIZE) ! 659: { ! 660: *scan = '\n'; ! 661: addnl = TRUE; ! 662: } ! 663: ! 664: /* protect against NUL chars in file */ ! 665: if (!*scan) ! 666: { ! 667: *scan = 0x80; ! 668: hadnul = TRUE; ! 669: } ! 670: ! 671: /* starting a new line? */ ! 672: if (*scan == '\n') ! 673: { ! 674: /* reset length at newline */ ! 675: len = 0; ! 676: lines++; ! 677: } ! 678: else ! 679: { ! 680: len++; ! 681: } ! 682: } ! 683: ! 684: /* add the text */ ! 685: *scan = '\0'; ! 686: add(tomark, tmpblk.c); ! 687: tomark += MARK_AT_LINE(lines) + len - markidx(tomark); ! 688: } ! 689: ! 690: /* if partial last line, then retain that first newline */ ! 691: if (len > 0) ! 692: { ! 693: msg("Last line had no newline"); ! 694: tomark += BLKSIZE; /* <- for the rptlines calc */ ! 695: } ! 696: else /* delete that first newline */ ! 697: { ! 698: delete(tomark, (tomark | (BLKSIZE - 1L)) + 1L); ! 699: } ! 700: } ! 701: ! 702: /* close the file */ ! 703: close(fd); ! 704: ! 705: /* Reporting... */ ! 706: rptlines = markline(tomark) - markline(frommark); ! 707: rptlabel = "read"; ! 708: if (mode == MODE_EX) ! 709: { ! 710: cursor = (tomark & ~BLKSIZE) - BLKSIZE; ! 711: } ! 712: else ! 713: { ! 714: cursor = frommark; ! 715: } ! 716: ! 717: if (addnl) ! 718: msg("Newlines were added to break up long lines"); ! 719: if (hadnul) ! 720: msg("NULs were converted to 0x80"); ! 721: } ! 722: ! 723: ! 724: ! 725: /*ARGSUSED*/ ! 726: void cmd_undo(frommark, tomark, cmd, bang, extra) ! 727: MARK frommark; ! 728: MARK tomark; ! 729: CMD cmd; ! 730: int bang; ! 731: char *extra; ! 732: { ! 733: undo(); ! 734: } ! 735: ! 736: ! 737: /* print the selected lines */ ! 738: /*ARGSUSED*/ ! 739: void cmd_print(frommark, tomark, cmd, bang, extra) ! 740: MARK frommark; ! 741: MARK tomark; ! 742: CMD cmd; ! 743: int bang; ! 744: char *extra; ! 745: { ! 746: REG char *scan; ! 747: REG long l; ! 748: REG int col; ! 749: ! 750: for (l = markline(frommark); l <= markline(tomark); l++) ! 751: { ! 752: /* display a line number, if CMD_NUMBER */ ! 753: if (cmd == CMD_NUMBER) ! 754: { ! 755: sprintf(tmpblk.c, "%6ld ", l); ! 756: qaddstr(tmpblk.c); ! 757: col = 8; ! 758: } ! 759: else ! 760: { ! 761: col = 0; ! 762: } ! 763: ! 764: /* get the next line & display it */ ! 765: for (scan = fetchline(l); *scan; scan++) ! 766: { ! 767: /* expand tabs to the proper width */ ! 768: if (*scan == '\t' && cmd != CMD_LIST) ! 769: { ! 770: do ! 771: { ! 772: qaddch(' '); ! 773: col++; ! 774: } while (col % *o_tabstop != 0); ! 775: } ! 776: else if (*scan > 0 && *scan < ' ' || *scan == '\177') ! 777: { ! 778: qaddch('^'); ! 779: qaddch(*scan ^ 0x40); ! 780: col += 2; ! 781: } ! 782: else if ((*scan & 0x80) && cmd == CMD_LIST) ! 783: { ! 784: sprintf(tmpblk.c, "\\%03o", UCHAR(*scan)); ! 785: qaddstr(tmpblk.c); ! 786: col += 4; ! 787: } ! 788: else ! 789: { ! 790: qaddch(*scan); ! 791: col++; ! 792: } ! 793: ! 794: /* wrap at the edge of the screen */ ! 795: if (!has_AM && col >= COLS) ! 796: { ! 797: addch('\n'); ! 798: col -= COLS; ! 799: } ! 800: } ! 801: if (cmd == CMD_LIST) ! 802: { ! 803: qaddch('$'); ! 804: } ! 805: addch('\n'); ! 806: exrefresh(); ! 807: } ! 808: } ! 809: ! 810: ! 811: /* move or copy selected lines */ ! 812: /*ARGSUSED*/ ! 813: void cmd_move(frommark, tomark, cmd, bang, extra) ! 814: MARK frommark; ! 815: MARK tomark; ! 816: CMD cmd; ! 817: int bang; ! 818: char *extra; ! 819: { ! 820: MARK destmark; ! 821: ! 822: /* parse the destination linespec. No defaults. Line 0 is okay */ ! 823: destmark = cursor; ! 824: if (!strcmp(extra, "0")) ! 825: { ! 826: destmark = 0L; ! 827: } ! 828: else if (linespec(extra, &destmark) == extra || !destmark) ! 829: { ! 830: msg("invalid destination address"); ! 831: return; ! 832: } ! 833: ! 834: /* flesh the marks out to encompass whole lines */ ! 835: frommark &= ~(BLKSIZE - 1); ! 836: tomark = (tomark & ~(BLKSIZE - 1)) + BLKSIZE; ! 837: destmark = (destmark & ~(BLKSIZE - 1)) + BLKSIZE; ! 838: ! 839: /* make sure the destination is valid */ ! 840: if (cmd == CMD_MOVE && destmark >= frommark && destmark < tomark) ! 841: { ! 842: msg("invalid destination address"); ! 843: } ! 844: ! 845: /* Do it */ ! 846: ChangeText ! 847: { ! 848: /* save the text to a cut buffer */ ! 849: cutname('\0'); ! 850: cut(frommark, tomark); ! 851: ! 852: /* if we're not copying, delete the old text & adjust destmark */ ! 853: if (cmd != CMD_COPY) ! 854: { ! 855: delete(frommark, tomark); ! 856: if (destmark >= frommark) ! 857: { ! 858: destmark -= (tomark - frommark); ! 859: } ! 860: } ! 861: ! 862: /* add the new text */ ! 863: paste(destmark, FALSE, FALSE); ! 864: } ! 865: ! 866: /* move the cursor to the last line of the moved text */ ! 867: cursor = destmark + (tomark - frommark) - BLKSIZE; ! 868: if (cursor < MARK_FIRST || cursor >= MARK_LAST + BLKSIZE) ! 869: { ! 870: cursor = MARK_LAST; ! 871: } ! 872: ! 873: /* Reporting... */ ! 874: rptlabel = ( (cmd == CMD_COPY) ? "copied" : "moved" ); ! 875: } ! 876: ! 877: ! 878: ! 879: /* execute EX commands from a file */ ! 880: /*ARGSUSED*/ ! 881: void cmd_source(frommark, tomark, cmd, bang, extra) ! 882: MARK frommark; ! 883: MARK tomark; ! 884: CMD cmd; ! 885: int bang; ! 886: char *extra; ! 887: { ! 888: /* must have a filename */ ! 889: if (!*extra) ! 890: { ! 891: msg("\"source\" requires a filename"); ! 892: return; ! 893: } ! 894: ! 895: doexrc(extra); ! 896: } ! 897: ! 898: ! 899: #ifndef NO_AT ! 900: /*ARGSUSED*/ ! 901: void cmd_at(frommark, tomark, cmd, bang, extra) ! 902: MARK frommark; ! 903: MARK tomark; ! 904: CMD cmd; ! 905: int bang; ! 906: char *extra; ! 907: { ! 908: static nest = FALSE; ! 909: int result; ! 910: char buf[MAXRCLEN]; ! 911: ! 912: /* don't allow nested macros */ ! 913: if (nest) ! 914: { ! 915: msg("@ macros can't be nested"); ! 916: return; ! 917: } ! 918: nest = TRUE; ! 919: ! 920: /* require a buffer name */ ! 921: if (*extra == '"') ! 922: extra++; ! 923: if (!*extra || !isascii(*extra) ||!islower(*extra)) ! 924: { ! 925: msg("@ requires a cut buffer name (a-z)"); ! 926: } ! 927: ! 928: /* get the contents of the buffer */ ! 929: result = cb2str(*extra, buf, (unsigned)(sizeof buf)); ! 930: if (result <= 0) ! 931: { ! 932: msg("buffer \"%c is empty", *extra); ! 933: } ! 934: else if (result >= sizeof buf) ! 935: { ! 936: msg("buffer \"%c is too large to execute", *extra); ! 937: } ! 938: else ! 939: { ! 940: /* execute the contents of the buffer as ex commands */ ! 941: exstring(buf, result, '\\'); ! 942: } ! 943: ! 944: nest = FALSE; ! 945: } ! 946: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.