|
|
1.1 ! root 1: /* cmd1.c */ ! 2: ! 3: /* Author: ! 4: * Steve Kirkendall ! 5: * 16820 SW Tallac Way ! 6: * Beaverton, OR 97006 ! 7: * [email protected], or ...uunet!tektronix!psueea!jove!kirkenda ! 8: */ ! 9: ! 10: ! 11: /* This file contains some of the EX commands - mostly ones that deal with ! 12: * files, options, etc. -- anything except text. ! 13: */ ! 14: ! 15: #include "config.h" ! 16: #include <ctype.h> ! 17: #include "vi.h" ! 18: #include "regexp.h" ! 19: ! 20: #if MSDOS ! 21: #define DATE __DATE__ ! 22: #endif ! 23: ! 24: #ifdef DEBUG ! 25: /* print the selected lines with info on the blocks */ ! 26: /*ARGSUSED*/ ! 27: void cmd_debug(frommark, tomark, cmd, bang, extra) ! 28: MARK frommark; ! 29: MARK tomark; ! 30: CMD cmd; ! 31: int bang; ! 32: char *extra; ! 33: { ! 34: REG char *scan; ! 35: REG long l; ! 36: REG int i; ! 37: int len; ! 38: ! 39: /* scan lnum[] to determine which block its in */ ! 40: l = markline(frommark); ! 41: for (i = 1; l > lnum[i]; i++) ! 42: { ! 43: } ! 44: ! 45: do ! 46: { ! 47: /* fetch text of the block containing that line */ ! 48: scan = blkget(i)->c; ! 49: ! 50: /* calculate its length */ ! 51: if (scan[BLKSIZE - 1]) ! 52: { ! 53: len = BLKSIZE; ! 54: } ! 55: else ! 56: { ! 57: len = strlen(scan); ! 58: } ! 59: ! 60: /* print block stats */ ! 61: msg("##### hdr[%d]=%d, lnum[%d-1]=%ld, lnum[%d]=%ld (%ld lines)", ! 62: i, hdr.n[i], i, lnum[i-1], i, lnum[i], lnum[i] - lnum[i - 1]); ! 63: msg("##### len=%d, buf=0x%lx, %sdirty", ! 64: len, scan, ((int *)scan)[MAXBLKS + 1] ? "" : "not "); ! 65: if (bang) ! 66: { ! 67: while (--len >= 0) ! 68: { ! 69: addch(*scan); ! 70: scan++; ! 71: } ! 72: } ! 73: exrefresh(); ! 74: ! 75: /* next block */ ! 76: i++; ! 77: } while (i < MAXBLKS && lnum[i] && lnum[i - 1] < markline(tomark)); ! 78: } ! 79: ! 80: ! 81: /* This function checks a lot of conditions to make sure they aren't screwy */ ! 82: /*ARGSUSED*/ ! 83: void cmd_validate(frommark, tomark, cmd, bang, extra) ! 84: MARK frommark; ! 85: MARK tomark; ! 86: CMD cmd; ! 87: int bang; ! 88: char *extra; ! 89: { ! 90: char *scan; ! 91: int i; ! 92: int nlcnt; /* used to count newlines */ ! 93: int len; /* counts non-NUL characters */ ! 94: ! 95: /* check lnum[0] */ ! 96: if (lnum[0] != 0L) ! 97: { ! 98: msg("lnum[0] = %ld", lnum[0]); ! 99: } ! 100: ! 101: /* check each block */ ! 102: for (i = 1; lnum[i] <= nlines; i++) ! 103: { ! 104: scan = blkget(i)->c; ! 105: if (scan[BLKSIZE - 1]) ! 106: { ! 107: msg("block %d has no NUL at the end", i); ! 108: } ! 109: else ! 110: { ! 111: for (nlcnt = len = 0; *scan; scan++, len++) ! 112: { ! 113: if (*scan == '\n') ! 114: { ! 115: nlcnt++; ! 116: } ! 117: } ! 118: if (scan[-1] != '\n') ! 119: { ! 120: msg("block %d doesn't end with '\\n' (length %d)", i, len); ! 121: } ! 122: if (bang || nlcnt != lnum[i] - lnum[i - 1]) ! 123: { ! 124: msg("block %d (line %ld?) has %d lines, but should have %ld", ! 125: i, lnum[i - 1] + 1L, nlcnt, lnum[i] - lnum[i - 1]); ! 126: } ! 127: } ! 128: exrefresh(); ! 129: } ! 130: ! 131: /* check lnum again */ ! 132: if (lnum[i] != INFINITY) ! 133: { ! 134: msg("hdr.n[%d] = %d, but lnum[%d] = %ld", ! 135: i, hdr.n[i], i, lnum[i]); ! 136: } ! 137: ! 138: msg("# = \"%s\", %% = \"%s\"", prevorig, origname); ! 139: } ! 140: #endif /* DEBUG */ ! 141: ! 142: ! 143: /*ARGSUSED*/ ! 144: void cmd_mark(frommark, tomark, cmd, bang, extra) ! 145: MARK frommark; ! 146: MARK tomark; ! 147: CMD cmd; ! 148: int bang; ! 149: char *extra; ! 150: { ! 151: /* validate the name of the mark */ ! 152: if (!extra || *extra < 'a' || *extra > 'z' || extra[1]) ! 153: { ! 154: msg("Invalid mark name"); ! 155: return; ! 156: } ! 157: ! 158: mark[*extra - 'a'] = tomark; ! 159: } ! 160: ! 161: /*ARGSUSED*/ ! 162: void cmd_write(frommark, tomark, cmd, bang, extra) ! 163: MARK frommark; ! 164: MARK tomark; ! 165: CMD cmd; ! 166: int bang; ! 167: char *extra; ! 168: { ! 169: int fd; ! 170: int append; /* boolean: write in "append" mode? */ ! 171: REG long l; ! 172: REG char *scan; ! 173: REG int i; ! 174: ! 175: /* if all lines are to be written, use tmpsave() */ ! 176: if (frommark == MARK_FIRST && tomark == MARK_LAST) ! 177: { ! 178: tmpsave(extra, bang); ! 179: return; ! 180: } ! 181: ! 182: /* see if we're going to do this in append mode or not */ ! 183: append = FALSE; ! 184: if (extra[0] == '>' && extra[1] == '>') ! 185: { ! 186: extra += 2; ! 187: append = TRUE; ! 188: } ! 189: ! 190: /* either the file must not exist, or we must have a ! or be appending */ ! 191: if (access(extra, 0) == 0 && !bang && !append) ! 192: { ! 193: msg("File already exists - Use :w! to overwrite"); ! 194: return; ! 195: } ! 196: ! 197: /* else do it line-by-line, like cmd_print() */ ! 198: if (append) ! 199: { ! 200: #ifdef O_APPEND ! 201: fd = open(extra, O_WRONLY|O_APPEND); ! 202: #else ! 203: fd = open(extra, O_WRONLY); ! 204: if (fd >= 0) ! 205: { ! 206: lseek(fd, 0L, 2); ! 207: } ! 208: #endif ! 209: } ! 210: else ! 211: { ! 212: fd = -1; /* so we know the file isn't open yet */ ! 213: } ! 214: ! 215: if (fd < 0) ! 216: { ! 217: fd = creat(extra, FILEPERMS); ! 218: if (fd < 0) ! 219: { ! 220: msg("Can't write to \"%s\"", extra); ! 221: return; ! 222: } ! 223: } ! 224: for (l = markline(frommark); l <= markline(tomark); l++) ! 225: { ! 226: /* get the next line */ ! 227: scan = fetchline(l); ! 228: i = strlen(scan); ! 229: scan[i++] = '\n'; ! 230: ! 231: /* print the line */ ! 232: twrite(fd, scan, i); ! 233: } ! 234: close(fd); ! 235: } ! 236: ! 237: ! 238: /*ARGSUSED*/ ! 239: void cmd_shell(frommark, tomark, cmd, bang, extra) ! 240: MARK frommark, tomark; ! 241: CMD cmd; ! 242: int bang; ! 243: char *extra; ! 244: { ! 245: static char prevextra[80]; ! 246: ! 247: /* special case: ":sh" means ":!sh" */ ! 248: if (cmd == CMD_SHELL) ! 249: { ! 250: extra = o_shell; ! 251: frommark = tomark = 0L; ! 252: } ! 253: ! 254: /* if extra is "!", substute previous command */ ! 255: if (*extra == '!') ! 256: { ! 257: if (!*prevextra) ! 258: { ! 259: msg("No previous shell command to substitute for '!'"); ! 260: return; ! 261: } ! 262: extra = prevextra; ! 263: } ! 264: else if (cmd == CMD_BANG && strlen(extra) < sizeof(prevextra) - 1) ! 265: { ! 266: strcpy(prevextra, extra); ! 267: } ! 268: ! 269: /* if no lines were specified, just run the command */ ! 270: suspend_curses(); ! 271: if (frommark == 0L) ! 272: { ! 273: system(extra); ! 274: } ! 275: else /* pipe lines from the file through the command */ ! 276: { ! 277: filter(frommark, tomark, extra); ! 278: } ! 279: ! 280: /* resume curses quietly for MODE_EX, but noisily otherwise */ ! 281: resume_curses(mode == MODE_EX); ! 282: } ! 283: ! 284: ! 285: /*ARGSUSED*/ ! 286: void cmd_global(frommark, tomark, cmd, bang, extra) ! 287: MARK frommark, tomark; ! 288: CMD cmd; ! 289: int bang; ! 290: char *extra; /* rest of the command line */ ! 291: { ! 292: char *cmdptr; /* the command from the command line */ ! 293: char cmdln[100]; /* copy of the command from the command line */ ! 294: char *line; /* a line from the file */ ! 295: long l; /* used as a counter to move through lines */ ! 296: long lqty; /* quantity of lines to be scanned */ ! 297: long nchanged; /* number of lines changed */ ! 298: regexp *re; /* the compiled search expression */ ! 299: ! 300: /* can't nest global commands */ ! 301: if (doingglobal) ! 302: { ! 303: msg("Can't nest global commands."); ! 304: rptlines = -1L; ! 305: return; ! 306: } ! 307: ! 308: /* ":g! ..." is the same as ":v ..." */ ! 309: if (bang) ! 310: { ! 311: cmd = CMD_VGLOBAL; ! 312: } ! 313: ! 314: /* make sure we got a search pattern */ ! 315: if (*extra != '/' && *extra != '?') ! 316: { ! 317: msg("Usage: %c /regular expression/ command", cmd == CMD_GLOBAL ? 'g' : 'v'); ! 318: return; ! 319: } ! 320: ! 321: /* parse & compile the search pattern */ ! 322: cmdptr = parseptrn(extra); ! 323: if (!extra[1]) ! 324: { ! 325: msg("Can't use empty regular expression with '%c' command", cmd == CMD_GLOBAL ? 'g' : 'v'); ! 326: return; ! 327: } ! 328: re = regcomp(extra + 1); ! 329: if (!re) ! 330: { ! 331: /* regcomp found & described an error */ ! 332: return; ! 333: } ! 334: ! 335: /* for each line in the range */ ! 336: doingglobal = TRUE; ! 337: ChangeText ! 338: { ! 339: /* NOTE: we have to go through the lines in a forward order, ! 340: * otherwise "g/re/p" would look funny. *BUT* for "g/re/d" ! 341: * to work, simply adding 1 to the line# on each loop won't ! 342: * work. The solution: count lines relative to the end of ! 343: * the file. Think about it. ! 344: */ ! 345: for (l = nlines - markline(frommark), ! 346: lqty = markline(tomark) - markline(frommark) + 1L, ! 347: nchanged = 0L; ! 348: lqty > 0 && nlines - l >= 0 && nchanged >= 0L; ! 349: l--, lqty--) ! 350: { ! 351: /* fetch the line */ ! 352: line = fetchline(nlines - l); ! 353: ! 354: /* if it contains the search pattern... */ ! 355: if ((!regexec(re, line, 1)) == (cmd != CMD_GLOBAL)) ! 356: { ! 357: /* move the cursor to that line */ ! 358: cursor = MARK_AT_LINE(nlines - l); ! 359: ! 360: /* do the ex command (without mucking up ! 361: * the original copy of the command line) ! 362: */ ! 363: strcpy(cmdln, cmdptr); ! 364: rptlines = 0L; ! 365: doexcmd(cmdln); ! 366: nchanged += rptlines; ! 367: } ! 368: } ! 369: } ! 370: doingglobal = FALSE; ! 371: ! 372: /* free the regexp */ ! 373: free(re); ! 374: ! 375: /* Reporting...*/ ! 376: rptlines = nchanged; ! 377: } ! 378: ! 379: ! 380: /*ARGSUSED*/ ! 381: void cmd_file(frommark, tomark, cmd, bang, extra) ! 382: MARK frommark, tomark; ! 383: CMD cmd; ! 384: int bang; ! 385: char *extra; ! 386: { ! 387: #ifndef CRUNCH ! 388: /* if we're given a new filename, use it as this file's name */ ! 389: if (extra && *extra) ! 390: { ! 391: strcpy(origname, extra); ! 392: } ! 393: #endif ! 394: if (cmd == CMD_FILE) ! 395: { ! 396: msg("\"%s\" %s%s %ld lines, line %ld [%ld%%]", ! 397: *origname ? origname : "[NO FILE]", ! 398: tstflag(file, MODIFIED) ? "[MODIFIED]" : "", ! 399: tstflag(file, READONLY) ? "[READONLY]" : "", ! 400: nlines, ! 401: markline(frommark), ! 402: markline(frommark) * 100 / nlines); ! 403: } ! 404: else if (markline(frommark) == markline(tomark)) ! 405: { ! 406: msg("%ld", markline(frommark)); ! 407: } ! 408: else ! 409: { ! 410: msg("range \"%ld,%ld\" contains %ld lines", ! 411: markline(frommark), ! 412: markline(tomark), ! 413: markline(tomark) - markline(frommark) + 1L); ! 414: } ! 415: } ! 416: ! 417: ! 418: /*ARGSUSED*/ ! 419: void cmd_edit(frommark, tomark, cmd, bang, extra) ! 420: MARK frommark, tomark; ! 421: CMD cmd; ! 422: int bang; ! 423: char *extra; ! 424: { ! 425: long line = 1L; /* might be set to prevline */ ! 426: ! 427: /* Editing previous file? Then start at previous line */ ! 428: if (!strcmp(extra, prevorig)) ! 429: { ! 430: line = prevline; ! 431: } ! 432: ! 433: #ifndef CRUNCH ! 434: /* if we were given an explicit starting line, then start there */ ! 435: if (*extra == '+') ! 436: { ! 437: for (extra++, line = 0L; *extra >= '0' && *extra <= '9'; extra++) ! 438: { ! 439: line *= 10L; ! 440: line += (*extra - '0'); ! 441: } ! 442: while (isascii(*extra) && isspace(*extra)) ! 443: { ! 444: extra++; ! 445: } ! 446: } ! 447: #endif /* not CRUNCH */ ! 448: ! 449: /* switch files */ ! 450: if (tmpabort(bang)) ! 451: { ! 452: tmpstart(extra); ! 453: if (line <= nlines && line >= 1L) ! 454: { ! 455: cursor = MARK_AT_LINE(line); ! 456: } ! 457: } ! 458: else ! 459: { ! 460: msg("Use edit! to abort changes, or w to save changes"); ! 461: ! 462: /* so we can say ":e!#" next time... */ ! 463: strcpy(prevorig, extra); ! 464: prevline = 1L; ! 465: } ! 466: } ! 467: ! 468: /* This code is also used for rewind -- GB */ ! 469: ! 470: /*ARGSUSED*/ ! 471: void cmd_next(frommark, tomark, cmd, bang, extra) ! 472: MARK frommark, tomark; ! 473: CMD cmd; ! 474: int bang; ! 475: char *extra; ! 476: { ! 477: int i, j; ! 478: char *scan; ! 479: char *build; ! 480: ! 481: /* if extra stuff given, use ":args" to define a new args list */ ! 482: if (cmd == CMD_NEXT && extra && *extra) ! 483: { ! 484: cmd_args(frommark, tomark, cmd, bang, extra); ! 485: } ! 486: ! 487: /* move to the next arg */ ! 488: if (cmd == CMD_NEXT) ! 489: { ! 490: i = argno + 1; ! 491: } ! 492: else if (cmd == CMD_PREVIOUS) ! 493: { ! 494: i = argno - 1; ! 495: } ! 496: else /* cmd == CMD_REWIND */ ! 497: { ! 498: i = 0; ! 499: } ! 500: if (i < 0 || i >= nargs) ! 501: { ! 502: msg("No %sfiles to edit", cmd == CMD_REWIND ? "" : "more "); ! 503: return; ! 504: } ! 505: ! 506: /* find & isolate the name of the file to edit */ ! 507: for (j = i, scan = args; j > 0; j--) ! 508: { ! 509: while(!isascii(*scan) || !isspace(*scan)) ! 510: { ! 511: scan++; ! 512: } ! 513: while (isascii(*scan) && isspace(*scan)) ! 514: { ! 515: scan++; ! 516: } ! 517: } ! 518: for (build = tmpblk.c; *scan && (!isascii(*scan) || !isspace(*scan)); ) ! 519: { ! 520: *build++ = *scan++; ! 521: } ! 522: *build = '\0'; ! 523: ! 524: /* switch to the next file */ ! 525: if (tmpabort(bang)) ! 526: { ! 527: tmpstart(tmpblk.c); ! 528: argno = i; ! 529: } ! 530: else ! 531: { ! 532: msg("Use :%s! to abort changes, or w to save changes", ! 533: cmd == CMD_NEXT ? "next" : ! 534: cmd == CMD_PREVIOUS ? "previous" : ! 535: "rewind"); ! 536: } ! 537: } ! 538: ! 539: /* also called from :wq -- always writes back in this case */ ! 540: ! 541: /*ARGSUSED*/ ! 542: void cmd_xit(frommark, tomark, cmd, bang, extra) ! 543: MARK frommark, tomark; ! 544: CMD cmd; ! 545: int bang; ! 546: char *extra; ! 547: { ! 548: static long whenwarned; /* when the user was last warned of extra files */ ! 549: int oldflag; ! 550: ! 551: /* if there are more files to edit, then warn user */ ! 552: if (argno + 1 < nargs && whenwarned != changes && (!bang || cmd != CMD_QUIT)) ! 553: { ! 554: msg("More files to edit -- Use \":n\" to go to next file"); ! 555: whenwarned = changes; ! 556: return; ! 557: } ! 558: ! 559: if (cmd == CMD_QUIT) ! 560: { ! 561: if (tmpabort(bang)) ! 562: { ! 563: mode = MODE_QUIT; ! 564: } ! 565: else ! 566: { ! 567: msg("Use q! to abort changes, or wq to save changes"); ! 568: } ! 569: } ! 570: else ! 571: { ! 572: /* else try to save this file */ ! 573: oldflag = tstflag(file, MODIFIED); ! 574: if (cmd == CMD_WQUIT) ! 575: setflag(file, MODIFIED); ! 576: if (tmpend(bang)) ! 577: { ! 578: mode = MODE_QUIT; ! 579: } ! 580: else ! 581: { ! 582: msg("Could not save file -- use quit! to abort changes, or w filename"); ! 583: } ! 584: if (!oldflag) ! 585: clrflag(file, MODIFIED); ! 586: } ! 587: } ! 588: ! 589: ! 590: /*ARGSUSED*/ ! 591: void cmd_args(frommark, tomark, cmd, bang, extra) ! 592: MARK frommark, tomark; ! 593: CMD cmd; ! 594: int bang; ! 595: char *extra; ! 596: { ! 597: char *scan; ! 598: char *eow; ! 599: int col; ! 600: int arg; ! 601: int addcols; ! 602: int scrolled = 0; ! 603: ! 604: /* if no extra names given, or just current name, then report the args ! 605: * we have now. ! 606: */ ! 607: if (!extra || !*extra) ! 608: { ! 609: for (scan = args, col=arg=0; *scan; ) ! 610: { ! 611: while (*scan && isascii(*scan) && isspace(*scan)) ! 612: scan++; ! 613: eow = scan; ! 614: while (*eow && (!isascii(*++eow) || !isspace(*eow))) ! 615: ; ! 616: if (arg == argno) ! 617: addcols = 2; ! 618: else ! 619: addcols = 0; ! 620: if (col+addcols+(int)(eow-scan)+1>=COLS) ! 621: { ! 622: addch('\n'); ! 623: scrolled=1; ! 624: col=0; ! 625: } ! 626: else if (arg) ! 627: { qaddch(' '); ! 628: col++; ! 629: } ! 630: if (arg == argno) ! 631: qaddch('['); ! 632: while (scan < eow) ! 633: { qaddch(*scan++); ! 634: col++; ! 635: } ! 636: if (arg == argno) ! 637: qaddch(']'); ! 638: arg++; ! 639: col+=addcols; ! 640: } ! 641: /* write a trailing newline */ ! 642: if ((mode == MODE_EX || mode == MODE_COLON || scrolled) && col) ! 643: addch('\n'); ! 644: exrefresh(); ! 645: } ! 646: else /* new args list given */ ! 647: { ! 648: strcpy(args, extra); ! 649: argno = -1; /* before the first, so :next will go to first */ ! 650: ! 651: /* count the names */ ! 652: for (nargs = 0, scan = args; *scan; nargs++) ! 653: { ! 654: while (*scan && (!isascii(*scan) || !isspace(*scan))) ! 655: { ! 656: scan++; ! 657: } ! 658: while (isascii(*scan) && isspace(*scan)) ! 659: { ! 660: scan++; ! 661: } ! 662: } ! 663: msg("%d files to edit", nargs); ! 664: } ! 665: } ! 666: ! 667: ! 668: /*ARGSUSED*/ ! 669: void cmd_cd(frommark, tomark, cmd, bang, extra) ! 670: MARK frommark, tomark; ! 671: CMD cmd; ! 672: int bang; ! 673: char *extra; ! 674: { ! 675: char *getenv(); ! 676: ! 677: /* default directory name is $HOME */ ! 678: if (!*extra) ! 679: { ! 680: extra = getenv("HOME"); ! 681: if (!extra) ! 682: { ! 683: msg("environment variable $HOME not set"); ! 684: return; ! 685: } ! 686: } ! 687: ! 688: /* go to the directory */ ! 689: if (chdir(extra) < 0) ! 690: { ! 691: perror(extra); ! 692: } ! 693: } ! 694: ! 695: ! 696: /*ARGSUSED*/ ! 697: void cmd_map(frommark, tomark, cmd, bang, extra) ! 698: MARK frommark, tomark; ! 699: CMD cmd; ! 700: int bang; ! 701: char *extra; ! 702: { ! 703: char *mapto; ! 704: ! 705: /* "map" with no extra will dump the map table contents */ ! 706: if (!*extra) ! 707: { ! 708: dumpkey(bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD); ! 709: } ! 710: else ! 711: { ! 712: /* "extra" is key to map, followed my what it maps to */ ! 713: for (mapto = extra; *mapto && *mapto != ' ' && *mapto!= '\t'; mapto++) ! 714: { ! 715: } ! 716: while (*mapto == ' ' || *mapto == '\t') ! 717: { ! 718: *mapto++ = '\0'; ! 719: } ! 720: ! 721: mapkey(extra, mapto, bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD, (char *)0); ! 722: } ! 723: } ! 724: ! 725: ! 726: /*ARGSUSED*/ ! 727: void cmd_set(frommark, tomark, cmd, bang, extra) ! 728: MARK frommark, tomark; ! 729: CMD cmd; ! 730: int bang; ! 731: char *extra; ! 732: { ! 733: if (!*extra) ! 734: { ! 735: dumpopts(FALSE);/* "FALSE" means "don't dump all" - only set */ ! 736: } ! 737: else if (!strcmp(extra, "all")) ! 738: { ! 739: dumpopts(TRUE); /* "TRUE" means "dump all" - even unset vars */ ! 740: } ! 741: else ! 742: { ! 743: setopts(extra); ! 744: ! 745: /* That option may have affected the appearence of text */ ! 746: changes++; ! 747: } ! 748: } ! 749: ! 750: /*ARGSUSED*/ ! 751: void cmd_tag(frommark, tomark, cmd, bang, extra) ! 752: MARK frommark, tomark; ! 753: CMD cmd; ! 754: int bang; ! 755: char *extra; ! 756: { ! 757: char *scan; /* used to scan through the tmpblk.c */ ! 758: char *cmp; /* char of tag name we're comparing, or NULL */ ! 759: char *end; /* marks the end of chars in tmpblk.c */ ! 760: int fd; /* file descriptor used to read the file */ ! 761: #ifndef NO_MAGIC ! 762: char wasmagic; /* preserves the original state of o_magic */ ! 763: #endif ! 764: static char prevtag[30]; ! 765: ! 766: /* if no tag is given, use the previous tag */ ! 767: if (!extra || !*extra) ! 768: { ! 769: if (!*prevtag) ! 770: { ! 771: msg("No previous tag"); ! 772: return; ! 773: } ! 774: extra = prevtag; ! 775: } ! 776: else ! 777: { ! 778: strncpy(prevtag, extra, sizeof prevtag); ! 779: } ! 780: ! 781: /* open the tags file */ ! 782: fd = open(TAGS, O_RDONLY); ! 783: if (fd < 0) ! 784: { ! 785: msg("No tags file"); ! 786: return; ! 787: } ! 788: ! 789: /* Hmmm... this would have been a lot easier with <stdio.h> */ ! 790: ! 791: /* find the line with our tag in it */ ! 792: for(scan = end = tmpblk.c, cmp = extra; ; scan++) ! 793: { ! 794: /* read a block, if necessary */ ! 795: if (scan >= end) ! 796: { ! 797: end = tmpblk.c + tread(fd, tmpblk.c, BLKSIZE); ! 798: scan = tmpblk.c; ! 799: if (scan >= end) ! 800: { ! 801: msg("tag \"%s\" not found", extra); ! 802: close(fd); ! 803: return; ! 804: } ! 805: } ! 806: ! 807: /* if we're comparing, compare... */ ! 808: if (cmp) ! 809: { ! 810: /* matched??? wow! */ ! 811: if (!*cmp && *scan == '\t') ! 812: { ! 813: break; ! 814: } ! 815: if (*cmp++ != *scan) ! 816: { ! 817: /* failed! skip to newline */ ! 818: cmp = (char *)0; ! 819: } ! 820: } ! 821: ! 822: /* if we're skipping to newline, do it fast! */ ! 823: if (!cmp) ! 824: { ! 825: while (scan < end && *scan != '\n') ! 826: { ! 827: scan++; ! 828: } ! 829: if (scan < end) ! 830: { ! 831: cmp = extra; ! 832: } ! 833: } ! 834: } ! 835: ! 836: /* found it! get the rest of the line into memory */ ! 837: for (cmp = tmpblk.c, scan++; scan < end && *scan != '\n'; ) ! 838: { ! 839: *cmp++ = *scan++; ! 840: } ! 841: if (scan == end) ! 842: { ! 843: tread(fd, cmp, BLKSIZE - (cmp - tmpblk.c)); ! 844: } ! 845: ! 846: /* we can close the tags file now */ ! 847: close(fd); ! 848: ! 849: /* extract the filename from the line, and edit the file */ ! 850: for (cmp = tmpblk.c; *cmp != '\t'; cmp++) ! 851: { ! 852: } ! 853: *cmp++ = '\0'; ! 854: if (strcmp(origname, tmpblk.c) != 0) ! 855: { ! 856: if (!tmpabort(bang)) ! 857: { ! 858: msg("Use :tag! to abort changes, or :w to save changes"); ! 859: return; ! 860: } ! 861: tmpstart(tmpblk.c); ! 862: } ! 863: ! 864: /* move to the desired line (or to line 1 if that fails) */ ! 865: #ifndef NO_MAGIC ! 866: wasmagic = *o_magic; ! 867: *o_magic = FALSE; ! 868: #endif ! 869: cursor = MARK_FIRST; ! 870: linespec(cmp, &cursor); ! 871: if (cursor == MARK_UNSET) ! 872: { ! 873: cursor = MARK_FIRST; ! 874: } ! 875: #ifndef NO_MAGIC ! 876: *o_magic = wasmagic; ! 877: #endif ! 878: } ! 879: ! 880: ! 881: ! 882: /*ARGSUSED*/ ! 883: void cmd_visual(frommark, tomark, cmd, bang, extra) ! 884: MARK frommark, tomark; ! 885: CMD cmd; ! 886: int bang; ! 887: char *extra; ! 888: { ! 889: mode = MODE_VI; ! 890: msg(""); ! 891: } ! 892: ! 893: ! 894: ! 895: ! 896: ! 897: /* describe this version of the program */ ! 898: /*ARGSUSED*/ ! 899: void cmd_version(frommark, tomark, cmd, bang, extra) ! 900: MARK frommark; ! 901: MARK tomark; ! 902: CMD cmd; ! 903: int bang; ! 904: char *extra; ! 905: { ! 906: #ifndef DATE ! 907: msg("%s", VERSION); ! 908: #else ! 909: msg("%s (%s)", VERSION, DATE); ! 910: #endif ! 911: #ifdef COMPILED_BY ! 912: msg("Compiled by %s", COMPILED_BY); ! 913: #endif ! 914: #ifdef CREDIT ! 915: msg("%s", CREDIT); ! 916: #endif ! 917: #ifdef COPYING ! 918: msg("%s", COPYING); ! 919: #endif ! 920: } ! 921: ! 922: ! 923: #ifndef NO_MKEXRC ! 924: /* make a .exrc file which describes the current configuration */ ! 925: /*ARGSUSED*/ ! 926: void cmd_mkexrc(frommark, tomark, cmd, bang, extra) ! 927: MARK frommark; ! 928: MARK tomark; ! 929: CMD cmd; ! 930: int bang; ! 931: char *extra; ! 932: { ! 933: int fd; ! 934: ! 935: /* the default name for the .exrc file EXRC */ ! 936: if (!*extra) ! 937: { ! 938: extra = EXRC; ! 939: } ! 940: ! 941: /* create the .exrc file */ ! 942: fd = creat(extra, FILEPERMS); ! 943: if (fd < 0) ! 944: { ! 945: msg("Couldn't create a new \"%s\" file", extra); ! 946: return; ! 947: } ! 948: ! 949: /* save stuff */ ! 950: savekeys(fd); ! 951: saveopts(fd); ! 952: #ifndef NO_DIGRAPH ! 953: savedigs(fd); ! 954: #endif ! 955: #ifndef NO_ABBR ! 956: saveabbr(fd); ! 957: #endif ! 958: ! 959: /* close the file */ ! 960: close(fd); ! 961: msg("Created a new \"%s\" file", extra); ! 962: } ! 963: #endif ! 964: ! 965: #ifndef NO_DIGRAPH ! 966: /*ARGSUSED*/ ! 967: void cmd_digraph(frommark, tomark, cmd, bang, extra) ! 968: MARK frommark; ! 969: MARK tomark; ! 970: CMD cmd; ! 971: int bang; ! 972: char *extra; ! 973: { ! 974: do_digraph(bang, extra); ! 975: } ! 976: #endif ! 977: ! 978: ! 979: #ifndef NO_ERRLIST ! 980: static char errfile[256]; /* the name of a file containing an error */ ! 981: static long errline; /* the line number for an error */ ! 982: ! 983: /* This static function tries to parse an error message. ! 984: * ! 985: * For most compilers, the first word is taken to be the name of the erroneous ! 986: * file, and the first number after that is taken to be the line number where ! 987: * the error was detected. The description of the error follows, possibly ! 988: * preceded by an "error ... :" or "warning ... :" label which is skipped. ! 989: * ! 990: * For Coherent, error messages look like "line#: filename: message". ! 991: * ! 992: * For non-error lines, or unparsable error lines, this function returns NULL. ! 993: * Normally, though, it alters errfile and errline, and returns a pointer to ! 994: * the description. ! 995: */ ! 996: static char *parse_errmsg(text) ! 997: REG char *text; ! 998: { ! 999: REG char *cpy; ! 1000: long atol(); ! 1001: # if COHERENT ! 1002: /* Get the line number. If no line number, then ignore this line. */ ! 1003: errline = atol(text); ! 1004: if (errline == 0L) ! 1005: return (char *)0; ! 1006: ! 1007: /* Skip to the start of the filename */ ! 1008: while (*text && *text++ != ':') ! 1009: { ! 1010: } ! 1011: if (!*text++) ! 1012: return (char *)0; ! 1013: ! 1014: /* copy the filename to errfile */ ! 1015: for (cpy = errfile; *text && (*cpy++ = *text++) != ':'; ) ! 1016: { ! 1017: } ! 1018: if (!*text++) ! 1019: return (char *)0; ! 1020: cpy[-1] = '\0'; ! 1021: ! 1022: return text; ! 1023: # else /* not COHERENT */ ! 1024: char *errmsg; ! 1025: ! 1026: /* the error message is the whole line, by default */ ! 1027: errmsg = text; ! 1028: ! 1029: /* skip leading garbage */ ! 1030: while (*text && !(isascii(*text) && isalnum(*text))) ! 1031: { ! 1032: text++; ! 1033: } ! 1034: ! 1035: /* copy over the filename */ ! 1036: cpy = errfile; ! 1037: while(isascii(*text) && isalnum(*text) || *text == '.') ! 1038: { ! 1039: *cpy++ = *text++; ! 1040: } ! 1041: *cpy = '\0'; ! 1042: ! 1043: /* ignore the name "Error" and filenames that contain a '/' */ ! 1044: if (*text == '/' || !strcmp(errfile + 1, "rror") || access(errfile, 0) < 0) ! 1045: { ! 1046: return (char *)0; ! 1047: } ! 1048: ! 1049: /* skip garbage between filename and line number */ ! 1050: while (*text && !(isascii(*text) && isdigit(*text))) ! 1051: { ! 1052: text++; ! 1053: } ! 1054: ! 1055: /* if the number is part of a larger word, then ignore this line */ ! 1056: if (*text && isascii(text[-1]) && isalpha(text[-1])) ! 1057: { ! 1058: return (char *)0; ! 1059: } ! 1060: ! 1061: /* get the error line */ ! 1062: errline = 0L; ! 1063: while (isascii(*text) && isdigit(*text)) ! 1064: { ! 1065: errline *= 10; ! 1066: errline += (*text - '0'); ! 1067: text++; ! 1068: } ! 1069: ! 1070: /* any line which lacks a filename or line number should be ignored */ ! 1071: if (!errfile[0] || !errline) ! 1072: { ! 1073: return (char *)0; ! 1074: } ! 1075: ! 1076: /* locate the beginning of the error description */ ! 1077: while (*text && isascii(*text) && !isspace(*text)) ! 1078: { ! 1079: text++; ! 1080: } ! 1081: while (*text) ! 1082: { ! 1083: # ifndef CRUNCH ! 1084: /* skip "error #:" and "warning #:" clauses */ ! 1085: if (!strncmp(text + 1, "rror ", 5) ! 1086: || !strncmp(text + 1, "arning ", 7) ! 1087: || !strncmp(text + 1, "atal error", 10)) ! 1088: { ! 1089: do ! 1090: { ! 1091: text++; ! 1092: } while (*text && *text != ':'); ! 1093: continue; ! 1094: } ! 1095: # endif ! 1096: ! 1097: /* anything other than whitespace or a colon is important */ ! 1098: if (!isascii(*text) || (!isspace(*text) && *text != ':')) ! 1099: { ! 1100: errmsg = text; ! 1101: break; ! 1102: } ! 1103: ! 1104: /* else keep looking... */ ! 1105: text++; ! 1106: } ! 1107: ! 1108: return errmsg; ! 1109: # endif /* not COHERENT */ ! 1110: } ! 1111: ! 1112: /*ARGSUSED*/ ! 1113: void cmd_errlist(frommark, tomark, cmd, bang, extra) ! 1114: MARK frommark, tomark; ! 1115: CMD cmd; ! 1116: int bang; ! 1117: char *extra; ! 1118: { ! 1119: static long endline;/* original number of lines in this file */ ! 1120: static long offset; /* offset of the next line in the errlist file */ ! 1121: static int fd = -2;/* fd of the errlist file */ ! 1122: int i; ! 1123: char *errmsg; ! 1124: ! 1125: /* if a new errlist file is named, open it */ ! 1126: if (extra && extra[0]) ! 1127: { ! 1128: /* close the old one */ ! 1129: if (fd >= 0) ! 1130: { ! 1131: close(fd); ! 1132: } ! 1133: ! 1134: fd = open(extra, O_RDONLY); ! 1135: offset = 0L; ! 1136: } ! 1137: else if (fd < 0) ! 1138: { ! 1139: fd = open(ERRLIST, O_RDONLY); ! 1140: offset = 0L; ! 1141: } ! 1142: ! 1143: /* do we have an errlist file now? */ ! 1144: if (fd < 0) ! 1145: { ! 1146: msg("There is no errlist file"); ! 1147: beep(); ! 1148: return; ! 1149: } ! 1150: ! 1151: /* find the next error message in the file */ ! 1152: do ! 1153: { ! 1154: /* read the next line from the errlist */ ! 1155: lseek(fd, offset, 0); ! 1156: if (read(fd, tmpblk.c, (unsigned)BLKSIZE) <= 0) ! 1157: { ! 1158: msg("No more errors"); ! 1159: beep(); ! 1160: close(fd); ! 1161: return; ! 1162: } ! 1163: for (i = 0; tmpblk.c[i] != '\n'; i++) ! 1164: { ! 1165: } ! 1166: tmpblk.c[i++] = 0; ! 1167: ! 1168: /* look for an error message in the line */ ! 1169: errmsg = parse_errmsg(tmpblk.c); ! 1170: if (!errmsg) ! 1171: { ! 1172: offset += i; ! 1173: } ! 1174: ! 1175: } while (!errmsg); ! 1176: ! 1177: /* switch to the file containing the error, if this isn't it */ ! 1178: if (strcmp(origname, errfile)) ! 1179: { ! 1180: if (!tmpabort(bang)) ! 1181: { ! 1182: msg("Use :er! to abort changes, or :w to save changes"); ! 1183: beep(); ! 1184: return; ! 1185: } ! 1186: tmpstart(errfile); ! 1187: endline = nlines; ! 1188: } ! 1189: else if (endline == 0L) ! 1190: { ! 1191: endline = nlines; ! 1192: } ! 1193: ! 1194: /* go to the line where the error was detected */ ! 1195: cursor = MARK_AT_LINE(errline + (nlines - endline)); ! 1196: if (cursor > MARK_LAST) ! 1197: { ! 1198: cursor = MARK_LAST; ! 1199: } ! 1200: if (mode == MODE_VI) ! 1201: { ! 1202: redraw(cursor, FALSE); ! 1203: } ! 1204: ! 1205: /* display the error message */ ! 1206: if (nlines > endline) ! 1207: { ! 1208: msg("line %ld(+%ld): %.60s", errline, nlines - endline, errmsg); ! 1209: } ! 1210: else if (nlines < endline) ! 1211: { ! 1212: msg("line %ld(-%ld): %.60s", errline, endline - nlines, errmsg); ! 1213: } ! 1214: else ! 1215: { ! 1216: msg("line %ld: %.65s", errline, errmsg); ! 1217: } ! 1218: ! 1219: /* remember where the NEXT error line will start */ ! 1220: offset += i; ! 1221: } ! 1222: ! 1223: ! 1224: /*ARGSUSED*/ ! 1225: void cmd_make(frommark, tomark, cmd, bang, extra) ! 1226: MARK frommark, tomark; ! 1227: CMD cmd; ! 1228: int bang; ! 1229: char *extra; ! 1230: { ! 1231: BLK buf; ! 1232: ! 1233: /* if the file hasn't been saved, then complain unless ! */ ! 1234: if (tstflag(file, MODIFIED) && !bang) ! 1235: { ! 1236: msg("\"%s\" not saved yet", origname); ! 1237: return; ! 1238: } ! 1239: ! 1240: /* build the command */ ! 1241: sprintf(buf.c, "%s %s %s%s", (cmd == CMD_CC ? o_cc : o_make), extra, REDIRECT, ERRLIST); ! 1242: qaddstr(buf.c); ! 1243: addch('\n'); ! 1244: ! 1245: /* run the command, with curses temporarily disabled */ ! 1246: suspend_curses(); ! 1247: system(buf.c); ! 1248: resume_curses(mode == MODE_EX); ! 1249: if (mode == MODE_COLON) ! 1250: mode = MODE_VI; ! 1251: ! 1252: /* run the "errlist" command */ ! 1253: cmd_errlist(MARK_UNSET, MARK_UNSET, cmd, bang, ERRLIST); ! 1254: } ! 1255: #endif ! 1256: ! 1257: ! 1258: #ifndef NO_ABBR ! 1259: /*ARGSUSED*/ ! 1260: void cmd_abbr(frommark, tomark, cmd, bang, extra) ! 1261: MARK frommark, tomark; ! 1262: CMD cmd; ! 1263: int bang; ! 1264: char *extra; ! 1265: { ! 1266: do_abbr(extra); ! 1267: } ! 1268: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.