|
|
1.1 ! root 1: /* cmd1.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 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: #ifdef DEBUG ! 21: /* print the selected lines with info on the blocks */ ! 22: /*ARGSUSED*/ ! 23: void cmd_debug(frommark, tomark, cmd, bang, extra) ! 24: MARK frommark; ! 25: MARK tomark; ! 26: CMD cmd; ! 27: int bang; ! 28: char *extra; ! 29: { ! 30: REG char *scan; ! 31: REG long l; ! 32: REG int i; ! 33: int len; ! 34: ! 35: /* scan lnum[] to determine which block its in */ ! 36: l = markline(frommark); ! 37: for (i = 1; l > lnum[i]; i++) ! 38: { ! 39: } ! 40: ! 41: do ! 42: { ! 43: /* fetch text of the block containing that line */ ! 44: scan = blkget(i)->c; ! 45: ! 46: /* calculate its length */ ! 47: if (scan[BLKSIZE - 1]) ! 48: { ! 49: len = BLKSIZE; ! 50: } ! 51: else ! 52: { ! 53: len = strlen(scan); ! 54: } ! 55: ! 56: /* print block stats */ ! 57: msg("##### hdr[%d]=%d, lnum[%d-1]=%ld, lnum[%d]=%ld (%ld lines)", ! 58: i, hdr.n[i], i, lnum[i-1], i, lnum[i], lnum[i] - lnum[i - 1]); ! 59: msg("##### len=%d, buf=0x%lx, %sdirty", ! 60: len, scan, ((int *)scan)[MAXBLKS + 1] ? "" : "not "); ! 61: if (bang) ! 62: { ! 63: while (--len >= 0) ! 64: { ! 65: addch(*scan); ! 66: scan++; ! 67: } ! 68: } ! 69: exrefresh(); ! 70: ! 71: /* next block */ ! 72: i++; ! 73: } while (i < MAXBLKS && lnum[i] && lnum[i - 1] < markline(tomark)); ! 74: } ! 75: ! 76: ! 77: /* This function checks a lot of conditions to make sure they aren't screwy */ ! 78: /*ARGSUSED*/ ! 79: void cmd_validate(frommark, tomark, cmd, bang, extra) ! 80: MARK frommark; ! 81: MARK tomark; ! 82: CMD cmd; ! 83: int bang; ! 84: char *extra; ! 85: { ! 86: char *scan; ! 87: int i; ! 88: int nlcnt; /* used to count newlines */ ! 89: int len; /* counts non-NUL characters */ ! 90: ! 91: /* check lnum[0] */ ! 92: if (lnum[0] != 0L) ! 93: { ! 94: msg("lnum[0] = %ld", lnum[0]); ! 95: } ! 96: ! 97: /* check each block */ ! 98: for (i = 1; lnum[i] <= nlines; i++) ! 99: { ! 100: scan = blkget(i)->c; ! 101: if (scan[BLKSIZE - 1]) ! 102: { ! 103: msg("block %d has no NUL at the end", i); ! 104: } ! 105: else ! 106: { ! 107: for (nlcnt = len = 0; *scan; scan++, len++) ! 108: { ! 109: if (*scan == '\n') ! 110: { ! 111: nlcnt++; ! 112: } ! 113: } ! 114: if (scan[-1] != '\n') ! 115: { ! 116: msg("block %d doesn't end with '\\n' (length %d)", i, len); ! 117: } ! 118: if (bang || nlcnt != lnum[i] - lnum[i - 1]) ! 119: { ! 120: msg("block %d (line %ld?) has %d lines, but should have %ld", ! 121: i, lnum[i - 1] + 1L, nlcnt, lnum[i] - lnum[i - 1]); ! 122: } ! 123: } ! 124: exrefresh(); ! 125: } ! 126: ! 127: /* check lnum again */ ! 128: if (lnum[i] != INFINITY) ! 129: { ! 130: msg("hdr.n[%d] = %d, but lnum[%d] = %ld", ! 131: i, hdr.n[i], i, lnum[i]); ! 132: } ! 133: ! 134: msg("# = \"%s\", %% = \"%s\"", prevorig, origname); ! 135: msg("V_from=%ld.%d, cursor=%ld.%d", markline(V_from), markidx(V_from), markline(cursor), markidx(cursor)); ! 136: } ! 137: #endif /* DEBUG */ ! 138: ! 139: ! 140: /*ARGSUSED*/ ! 141: void cmd_mark(frommark, tomark, cmd, bang, extra) ! 142: MARK frommark; ! 143: MARK tomark; ! 144: CMD cmd; ! 145: int bang; ! 146: char *extra; ! 147: { ! 148: /* validate the name of the mark */ ! 149: if (*extra == '"') ! 150: { ! 151: extra++; ! 152: } ! 153: /* valid mark names are lowercase ascii characters */ ! 154: if (!isascii(*extra) || !islower(*extra) || extra[1]) ! 155: { ! 156: msg("Invalid mark name"); ! 157: return; ! 158: } ! 159: ! 160: mark[*extra - 'a'] = tomark; ! 161: } ! 162: ! 163: /*ARGSUSED*/ ! 164: void cmd_write(frommark, tomark, cmd, bang, extra) ! 165: MARK frommark; ! 166: MARK tomark; ! 167: CMD cmd; ! 168: int bang; ! 169: char *extra; ! 170: { ! 171: int fd; ! 172: int append; /* boolean: write in "append" mode? */ ! 173: REG long l; ! 174: REG char *scan; ! 175: REG int i; ! 176: ! 177: /* if writing to a filter, then let filter() handle it */ ! 178: if (*extra == '!') ! 179: { ! 180: filter(frommark, tomark, extra + 1, FALSE); ! 181: return; ! 182: } ! 183: ! 184: /* if all lines are to be written, use tmpsave() */ ! 185: if (frommark == MARK_FIRST && tomark == MARK_LAST && cmd == CMD_WRITE) ! 186: { ! 187: tmpsave(extra, bang); ! 188: return; ! 189: } ! 190: ! 191: /* see if we're going to do this in append mode or not */ ! 192: append = FALSE; ! 193: if (extra[0] == '>' && extra[1] == '>') ! 194: { ! 195: extra += 2; ! 196: append = TRUE; ! 197: } ! 198: ! 199: /* either the file must not exist, or we must have a ! or be appending */ ! 200: if (access(extra, 0) == 0 && !bang && !append) ! 201: { ! 202: msg("File already exists - Use :w! to overwrite"); ! 203: return; ! 204: } ! 205: ! 206: /* else do it line-by-line, like cmd_print() */ ! 207: if (append) ! 208: { ! 209: #ifdef O_APPEND ! 210: fd = open(extra, O_WRONLY|O_APPEND); ! 211: #else ! 212: fd = open(extra, O_WRONLY); ! 213: if (fd >= 0) ! 214: { ! 215: lseek(fd, 0L, 2); ! 216: } ! 217: #endif ! 218: } ! 219: else ! 220: { ! 221: fd = -1; /* so we know the file isn't open yet */ ! 222: } ! 223: ! 224: if (fd < 0) ! 225: { ! 226: fd = creat(extra, FILEPERMS); ! 227: if (fd < 0) ! 228: { ! 229: msg("Can't write to \"%s\"", extra); ! 230: return; ! 231: } ! 232: } ! 233: for (l = markline(frommark); l <= markline(tomark); l++) ! 234: { ! 235: /* get the next line */ ! 236: scan = fetchline(l); ! 237: i = strlen(scan); ! 238: scan[i++] = '\n'; ! 239: ! 240: /* print the line */ ! 241: if (twrite(fd, scan, i) < i) ! 242: { ! 243: msg("Write failed"); ! 244: break; ! 245: } ! 246: } ! 247: rptlines = markline(tomark) - markline(frommark) + 1; ! 248: rptlabel = "written"; ! 249: close(fd); ! 250: } ! 251: ! 252: ! 253: /*ARGSUSED*/ ! 254: void cmd_shell(frommark, tomark, cmd, bang, extra) ! 255: MARK frommark, tomark; ! 256: CMD cmd; ! 257: int bang; ! 258: char *extra; ! 259: { ! 260: static char prevextra[80]; ! 261: ! 262: /* special case: ":sh" means ":!sh" */ ! 263: if (cmd == CMD_SHELL) ! 264: { ! 265: extra = o_shell; ! 266: frommark = tomark = 0L; ! 267: } ! 268: ! 269: /* if extra is "!", substitute previous command */ ! 270: if (*extra == '!') ! 271: { ! 272: if (!*prevextra) ! 273: { ! 274: msg("No previous shell command to substitute for '!'"); ! 275: return; ! 276: } ! 277: extra = prevextra; ! 278: } ! 279: else if (cmd == CMD_BANG && strlen(extra) < sizeof(prevextra) - 1) ! 280: { ! 281: strcpy(prevextra, extra); ! 282: } ! 283: ! 284: /* warn the user if the file hasn't been saved yet */ ! 285: if (*o_warn && tstflag(file, MODIFIED)) ! 286: { ! 287: if (mode == MODE_VI) ! 288: { ! 289: mode = MODE_COLON; ! 290: } ! 291: msg("Warning: \"%s\" has been modified but not yet saved", origname); ! 292: } ! 293: ! 294: /* if no lines were specified, just run the command */ ! 295: suspend_curses(); ! 296: if (frommark == 0L) ! 297: { ! 298: system(extra); ! 299: } ! 300: else /* pipe lines from the file through the command */ ! 301: { ! 302: filter(frommark, tomark, extra, TRUE); ! 303: } ! 304: ! 305: /* resume curses quietly for MODE_EX, but noisily otherwise */ ! 306: resume_curses(mode == MODE_EX); ! 307: } ! 308: ! 309: ! 310: /*ARGSUSED*/ ! 311: void cmd_global(frommark, tomark, cmd, bang, extra) ! 312: MARK frommark, tomark; ! 313: CMD cmd; ! 314: int bang; ! 315: char *extra; /* rest of the command line */ ! 316: { ! 317: char *cmdptr; /* the command from the command line */ ! 318: char cmdln[100]; /* copy of the command from the command line */ ! 319: char *line; /* a line from the file */ ! 320: long l; /* used as a counter to move through lines */ ! 321: long lqty; /* quantity of lines to be scanned */ ! 322: long nchanged; /* number of lines changed */ ! 323: regexp *re; /* the compiled search expression */ ! 324: ! 325: /* can't nest global commands */ ! 326: if (doingglobal) ! 327: { ! 328: msg("Can't nest global commands."); ! 329: rptlines = -1L; ! 330: return; ! 331: } ! 332: ! 333: /* ":g! ..." is the same as ":v ..." */ ! 334: if (bang) ! 335: { ! 336: cmd = CMD_VGLOBAL; ! 337: } ! 338: ! 339: /* make sure we got a search pattern */ ! 340: if (*extra != '/' && *extra != '?') ! 341: { ! 342: msg("Usage: %c /regular expression/ command", cmd == CMD_GLOBAL ? 'g' : 'v'); ! 343: return; ! 344: } ! 345: ! 346: /* parse & compile the search pattern */ ! 347: cmdptr = parseptrn(extra); ! 348: if (!extra[1]) ! 349: { ! 350: msg("Can't use empty regular expression with '%c' command", cmd == CMD_GLOBAL ? 'g' : 'v'); ! 351: return; ! 352: } ! 353: re = regcomp(extra + 1); ! 354: if (!re) ! 355: { ! 356: /* regcomp found & described an error */ ! 357: return; ! 358: } ! 359: ! 360: /* for each line in the range */ ! 361: doingglobal = TRUE; ! 362: ChangeText ! 363: { ! 364: /* NOTE: we have to go through the lines in a forward order, ! 365: * otherwise "g/re/p" would look funny. *BUT* for "g/re/d" ! 366: * to work, simply adding 1 to the line# on each loop won't ! 367: * work. The solution: count lines relative to the end of ! 368: * the file. Think about it. ! 369: */ ! 370: for (l = nlines - markline(frommark), ! 371: lqty = markline(tomark) - markline(frommark) + 1L, ! 372: nchanged = 0L; ! 373: lqty > 0 && nlines - l >= 0 && nchanged >= 0L; ! 374: l--, lqty--) ! 375: { ! 376: /* fetch the line */ ! 377: line = fetchline(nlines - l); ! 378: ! 379: /* if it contains the search pattern... */ ! 380: if ((!regexec(re, line, 1)) == (cmd != CMD_GLOBAL)) ! 381: { ! 382: /* move the cursor to that line */ ! 383: cursor = MARK_AT_LINE(nlines - l); ! 384: ! 385: /* do the ex command (without mucking up ! 386: * the original copy of the command line) ! 387: */ ! 388: strcpy(cmdln, cmdptr); ! 389: rptlines = 0L; ! 390: doexcmd(cmdln); ! 391: nchanged += rptlines; ! 392: } ! 393: } ! 394: } ! 395: doingglobal = FALSE; ! 396: ! 397: /* free the regexp */ ! 398: _free_(re); ! 399: ! 400: /* Reporting...*/ ! 401: rptlines = nchanged; ! 402: } ! 403: ! 404: ! 405: /*ARGSUSED*/ ! 406: void cmd_file(frommark, tomark, cmd, bang, extra) ! 407: MARK frommark, tomark; ! 408: CMD cmd; ! 409: int bang; ! 410: char *extra; ! 411: { ! 412: #ifndef CRUNCH ! 413: /* if we're given a new filename, use it as this file's name */ ! 414: if (extra && *extra) ! 415: { ! 416: strcpy(origname, extra); ! 417: storename(origname); ! 418: setflag(file, NOTEDITED); ! 419: } ! 420: #endif ! 421: if (cmd == CMD_FILE) ! 422: { ! 423: #ifndef CRUNCH ! 424: msg("\"%s\" %s%s%s %ld lines, line %ld [%ld%%]", ! 425: #else ! 426: msg("\"%s\" %s%s %ld lines, line %ld [%ld%%]", ! 427: #endif ! 428: *origname ? origname : "[NO FILE]", ! 429: tstflag(file, MODIFIED) ? "[MODIFIED]" : "", ! 430: #ifndef CRUNCH ! 431: tstflag(file, NOTEDITED) ?"[NOT EDITED]":"", ! 432: #endif ! 433: tstflag(file, READONLY) ? "[READONLY]" : "", ! 434: nlines, ! 435: markline(frommark), ! 436: markline(frommark) * 100 / nlines); ! 437: } ! 438: #ifndef CRUNCH ! 439: else if (markline(frommark) != markline(tomark)) ! 440: { ! 441: msg("range \"%ld,%ld\" contains %ld lines", ! 442: markline(frommark), ! 443: markline(tomark), ! 444: markline(tomark) - markline(frommark) + 1L); ! 445: } ! 446: #endif ! 447: else ! 448: { ! 449: msg("%ld", markline(frommark)); ! 450: } ! 451: } ! 452: ! 453: ! 454: /*ARGSUSED*/ ! 455: void cmd_edit(frommark, tomark, cmd, bang, extra) ! 456: MARK frommark, tomark; ! 457: CMD cmd; ! 458: int bang; ! 459: char *extra; ! 460: { ! 461: long line = 1L; /* might be set to prevline */ ! 462: #ifndef CRUNCH ! 463: char *init = (char *)0; ! 464: #endif ! 465: ! 466: ! 467: /* if ":vi", then switch to visual mode, and if no file is named ! 468: * then don't switch files. ! 469: */ ! 470: if (cmd == CMD_VISUAL) ! 471: { ! 472: mode = MODE_VI; ! 473: msg(""); ! 474: if (!*extra) ! 475: { ! 476: return; ! 477: } ! 478: } ! 479: ! 480: /* Editing previous file? Then start at previous line */ ! 481: if (!strcmp(extra, prevorig)) ! 482: { ! 483: line = prevline; ! 484: } ! 485: ! 486: #ifndef CRUNCH ! 487: /* if we were given an explicit starting line, then start there */ ! 488: if (*extra == '+') ! 489: { ! 490: for (init = ++extra; !isspace(*extra); extra++) ! 491: { ! 492: } ! 493: while (isspace(*extra)) ! 494: { ! 495: *extra++ = '\0'; ! 496: } ! 497: if (!*init) ! 498: { ! 499: init = "$"; ! 500: } ! 501: if (!extra) ! 502: { ! 503: extra = origname; ! 504: } ! 505: } ! 506: #endif /* not CRUNCH */ ! 507: ! 508: /* switch files */ ! 509: if (tmpabort(bang)) ! 510: { ! 511: tmpstart(extra); ! 512: if (line <= nlines && line >= 1L) ! 513: { ! 514: cursor = MARK_AT_LINE(line); ! 515: } ! 516: #ifndef CRUNCH ! 517: if (init) ! 518: { ! 519: doexcmd(init); ! 520: } ! 521: #endif ! 522: } ! 523: else ! 524: { ! 525: msg("Use edit! to abort changes, or w to save changes"); ! 526: ! 527: /* so we can say ":e!#" next time... */ ! 528: strcpy(prevorig, extra); ! 529: prevline = 1L; ! 530: } ! 531: } ! 532: ! 533: /* This code is also used for rewind -- GB */ ! 534: ! 535: /*ARGSUSED*/ ! 536: void cmd_next(frommark, tomark, cmd, bang, extra) ! 537: MARK frommark, tomark; ! 538: CMD cmd; ! 539: int bang; ! 540: char *extra; ! 541: { ! 542: int i, j; ! 543: char *scan; ! 544: ! 545: /* if extra stuff given, use ":args" to define a new args list */ ! 546: if (cmd == CMD_NEXT && extra && *extra) ! 547: { ! 548: cmd_args(frommark, tomark, cmd, bang, extra); ! 549: } ! 550: ! 551: /* move to the next arg */ ! 552: if (cmd == CMD_NEXT) ! 553: { ! 554: i = argno + 1; ! 555: } ! 556: else if (cmd == CMD_PREVIOUS) ! 557: { ! 558: i = argno - 1; ! 559: } ! 560: else /* cmd == CMD_REWIND */ ! 561: { ! 562: i = 0; ! 563: } ! 564: if (i < 0 || i >= nargs) ! 565: { ! 566: msg("No %sfiles to edit", cmd == CMD_REWIND ? "" : "more "); ! 567: return; ! 568: } ! 569: ! 570: /* find & isolate the name of the file to edit */ ! 571: for (j = i, scan = args; j > 0; j--) ! 572: { ! 573: while(*scan++) ! 574: { ! 575: } ! 576: } ! 577: ! 578: /* switch to the next file */ ! 579: if (tmpabort(bang)) ! 580: { ! 581: tmpstart(scan); ! 582: argno = i; ! 583: } ! 584: else ! 585: { ! 586: msg("Use :%s! to abort changes, or w to save changes", ! 587: cmd == CMD_NEXT ? "next" : ! 588: cmd == CMD_PREVIOUS ? "previous" : ! 589: "rewind"); ! 590: } ! 591: } ! 592: ! 593: /* also called from :wq -- always writes back in this case */ ! 594: ! 595: /*ARGSUSED*/ ! 596: void cmd_xit(frommark, tomark, cmd, bang, extra) ! 597: MARK frommark, tomark; ! 598: CMD cmd; ! 599: int bang; ! 600: char *extra; ! 601: { ! 602: static long whenwarned; /* when the user was last warned of extra files */ ! 603: int oldflag; ! 604: ! 605: /* if there are more files to edit, then warn user */ ! 606: if (argno >= 0 && argno + 1 < nargs && whenwarned != changes && (!bang || cmd != CMD_QUIT)) ! 607: { ! 608: msg("More files to edit -- Use \":n\" to go to next file"); ! 609: whenwarned = changes; ! 610: return; ! 611: } ! 612: ! 613: if (cmd == CMD_QUIT) ! 614: { ! 615: oldflag = *o_autowrite; ! 616: *o_autowrite = FALSE; ! 617: if (tmpabort(bang)) ! 618: { ! 619: mode = MODE_QUIT; ! 620: } ! 621: else ! 622: { ! 623: msg("Use q! to abort changes, or wq to save changes"); ! 624: } ! 625: *o_autowrite = oldflag; ! 626: } ! 627: else ! 628: { ! 629: /* else try to save this file */ ! 630: oldflag = tstflag(file, MODIFIED); ! 631: if (cmd == CMD_WQUIT) ! 632: setflag(file, MODIFIED); ! 633: if (tmpend(bang)) ! 634: { ! 635: mode = MODE_QUIT; ! 636: } ! 637: else ! 638: { ! 639: msg("Could not save file -- use quit! to abort changes, or w filename"); ! 640: } ! 641: if (!oldflag) ! 642: clrflag(file, MODIFIED); ! 643: } ! 644: } ! 645: ! 646: ! 647: /*ARGSUSED*/ ! 648: void cmd_args(frommark, tomark, cmd, bang, extra) ! 649: MARK frommark, tomark; ! 650: CMD cmd; ! 651: int bang; ! 652: char *extra; ! 653: { ! 654: char *scan; ! 655: int col; ! 656: int arg; ! 657: int scrolled = FALSE; ! 658: int width; ! 659: ! 660: /* if no extra names given, or just current name, then report the args ! 661: * we have now. ! 662: */ ! 663: if (!extra || !*extra) ! 664: { ! 665: /* empty args list? */ ! 666: if (nargs == 1 && !*args) ! 667: { ! 668: return; ! 669: } ! 670: ! 671: /* list the arguments */ ! 672: for (scan = args, col = arg = 0; ! 673: arg < nargs; ! 674: scan += width + 1, col += width, arg++) ! 675: { ! 676: width = strlen(scan); ! 677: if (col + width >= COLS - 4) ! 678: { ! 679: addch('\n'); ! 680: col = 0; ! 681: scrolled = TRUE; ! 682: } ! 683: else if (col > 0) ! 684: { ! 685: addch(' '); ! 686: col++; ! 687: } ! 688: if (arg == argno) ! 689: { ! 690: addch('['); ! 691: addstr(scan); ! 692: addch(']'); ! 693: col += 2; ! 694: } ! 695: else ! 696: { ! 697: addstr(scan); ! 698: } ! 699: } ! 700: ! 701: /* write a trailing newline */ ! 702: if ((mode == MODE_EX || mode == MODE_COLON || scrolled) && col) ! 703: { ! 704: addch('\n'); ! 705: } ! 706: exrefresh(); ! 707: } ! 708: else /* new args list given */ ! 709: { ! 710: for (scan = args, nargs = 1; *extra; ) ! 711: { ! 712: if (isspace(*extra)) ! 713: { ! 714: *scan++ = '\0'; ! 715: while (isspace(*extra)) ! 716: { ! 717: extra++; ! 718: } ! 719: if (*extra) ! 720: { ! 721: nargs++; ! 722: } ! 723: } ! 724: else ! 725: { ! 726: *scan++ = *extra++; ! 727: } ! 728: } ! 729: *scan = '\0'; ! 730: ! 731: /* reset argno to before the first, so :next will go to first */ ! 732: argno = -1; ! 733: ! 734: if (nargs != 1) ! 735: { ! 736: msg("%d files to edit", nargs); ! 737: } ! 738: } ! 739: } ! 740: ! 741: ! 742: /*ARGSUSED*/ ! 743: void cmd_cd(frommark, tomark, cmd, bang, extra) ! 744: MARK frommark, tomark; ! 745: CMD cmd; ! 746: int bang; ! 747: char *extra; ! 748: { ! 749: char *getenv(); ! 750: ! 751: #ifndef CRUNCH ! 752: /* if current file is modified, and no '!' was given, then error */ ! 753: if (tstflag(file, MODIFIED) && !bang) ! 754: { ! 755: msg("File modified; use \"cd! %s\" to switch anyway", extra); ! 756: } ! 757: #endif ! 758: ! 759: /* default directory name is $HOME */ ! 760: if (!*extra) ! 761: { ! 762: extra = getenv("HOME"); ! 763: if (!extra) ! 764: { ! 765: msg("environment variable $HOME not set"); ! 766: return; ! 767: } ! 768: } ! 769: ! 770: /* go to the directory */ ! 771: if (chdir(extra) < 0) ! 772: { ! 773: perror(extra); ! 774: } ! 775: } ! 776: ! 777: ! 778: /*ARGSUSED*/ ! 779: void cmd_map(frommark, tomark, cmd, bang, extra) ! 780: MARK frommark, tomark; ! 781: CMD cmd; ! 782: int bang; ! 783: char *extra; ! 784: { ! 785: char *mapto; ! 786: char *build, *scan; ! 787: #ifndef NO_FKEY ! 788: static char *fnames[NFKEYS] = ! 789: { ! 790: "#10", "#1", "#2", "#3", "#4", ! 791: "#5", "#6", "#7", "#8", "#9", ! 792: # ifndef NO_SHIFT_FKEY ! 793: "#10s", "#1s", "#2s", "#3s", "#4s", ! 794: "#5s", "#6s", "#7s", "#8s", "#9s", ! 795: # ifndef NO_CTRL_FKEY ! 796: "#10c", "#1c", "#2c", "#3c", "#4c", ! 797: "#5c", "#6c", "#7c", "#8c", "#9c", ! 798: # ifndef NO_ALT_FKEY ! 799: "#10a", "#1a", "#2a", "#3a", "#4a", ! 800: "#5a", "#6a", "#7a", "#8a", "#9a", ! 801: # endif ! 802: # endif ! 803: # endif ! 804: }; ! 805: int key; ! 806: #endif ! 807: ! 808: /* "map" with no extra will dump the map table contents */ ! 809: if (!*extra) ! 810: { ! 811: #ifndef NO_ABBR ! 812: if (cmd == CMD_ABBR) ! 813: { ! 814: dumpkey(bang ? WHEN_EX|WHEN_VIINP|WHEN_VIREP : WHEN_VIINP|WHEN_VIREP, TRUE); ! 815: } ! 816: else ! 817: #endif ! 818: { ! 819: dumpkey(bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD, FALSE); ! 820: } ! 821: } ! 822: else ! 823: { ! 824: /* "extra" is key to map, followed by what it maps to */ ! 825: ! 826: /* handle quoting inside the "raw" string */ ! 827: for (build = mapto = extra; ! 828: *mapto && (*mapto != ' ' && *mapto != '\t'); ! 829: *build++ = *mapto++) ! 830: { ! 831: if (*mapto == ctrl('V') && mapto[1]) ! 832: { ! 833: mapto++; ! 834: } ! 835: } ! 836: ! 837: /* skip whitespace, and mark the end of the "raw" string */ ! 838: while ((*mapto == ' ' || *mapto == '\t')) ! 839: { ! 840: *mapto++ = '\0'; ! 841: } ! 842: *build = '\0'; ! 843: ! 844: /* strip ^Vs from the "cooked" string */ ! 845: for (scan = build = mapto; *scan; *build++ = *scan++) ! 846: { ! 847: if (*scan == ctrl('V') && scan[1]) ! 848: { ! 849: scan++; ! 850: } ! 851: } ! 852: *build = '\0'; ! 853: ! 854: #ifndef NO_FKEY ! 855: /* if the mapped string is '#' and a number, then assume ! 856: * the user wanted that function key ! 857: */ ! 858: if (extra[0] == '#' && isdigit(extra[1])) ! 859: { ! 860: key = atoi(extra + 1) % 10; ! 861: # ifndef NO_SHIFT_FKEY ! 862: build = extra + strlen(extra) - 1; ! 863: if (*build == 's') ! 864: key += 10; ! 865: # ifndef NO_CTRL_FKEY ! 866: else if (*build == 'c') ! 867: key += 20; ! 868: # ifndef NO_ALT_FKEY ! 869: else if (*build == 'a') ! 870: key += 30; ! 871: # endif ! 872: # endif ! 873: # endif ! 874: if (FKEY[key]) ! 875: mapkey(FKEY[key], mapto, bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD, fnames[key]); ! 876: #if !COHERENT ! 877: else ! 878: msg("This terminal has no %s key", fnames[key]); ! 879: #endif ! 880: } ! 881: else ! 882: #endif ! 883: #ifndef NO_ABBR ! 884: if (cmd == CMD_ABBR || cmd == CMD_UNABBR) ! 885: { ! 886: mapkey(extra, mapto, bang ? WHEN_EX|WHEN_VIINP|WHEN_VIREP : WHEN_VIINP|WHEN_VIREP, "abbr"); ! 887: } ! 888: else ! 889: #endif ! 890: { ! 891: mapkey(extra, mapto, bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD, (char *)0); ! 892: } ! 893: } ! 894: } ! 895: ! 896: ! 897: /*ARGSUSED*/ ! 898: void cmd_set(frommark, tomark, cmd, bang, extra) ! 899: MARK frommark, tomark; ! 900: CMD cmd; ! 901: int bang; ! 902: char *extra; ! 903: { ! 904: if (!*extra) ! 905: { ! 906: dumpopts(FALSE);/* "FALSE" means "don't dump all" - only set */ ! 907: } ! 908: else if (!strcmp(extra, "all")) ! 909: { ! 910: dumpopts(TRUE); /* "TRUE" means "dump all" - even unset vars */ ! 911: } ! 912: else ! 913: { ! 914: setopts(extra); ! 915: ! 916: /* That option may have affected the appearence of text */ ! 917: changes++; ! 918: } ! 919: } ! 920: ! 921: /*ARGSUSED*/ ! 922: void cmd_tag(frommark, tomark, cmd, bang, extra) ! 923: MARK frommark, tomark; ! 924: CMD cmd; ! 925: int bang; ! 926: char *extra; ! 927: { ! 928: int fd; /* file descriptor used to read the file */ ! 929: char *scan; /* used to scan through the tmpblk.c */ ! 930: #ifdef INTERNAL_TAGS ! 931: char *cmp; /* char of tag name we're comparing, or NULL */ ! 932: char *end; /* marks the end of chars in tmpblk.c */ ! 933: #else ! 934: int i; ! 935: #endif ! 936: #ifndef NO_MAGIC ! 937: char wasmagic; /* preserves the original state of o_magic */ ! 938: #endif ! 939: static char prevtag[30]; ! 940: ! 941: /* if no tag is given, use the previous tag */ ! 942: if (!extra || !*extra) ! 943: { ! 944: if (!*prevtag) ! 945: { ! 946: msg("No previous tag"); ! 947: return; ! 948: } ! 949: extra = prevtag; ! 950: } ! 951: else ! 952: { ! 953: strncpy(prevtag, extra, sizeof prevtag); ! 954: prevtag[sizeof prevtag - 1] = '\0'; ! 955: } ! 956: ! 957: #ifndef INTERNAL_TAGS ! 958: /* use "ref" to look up the tag info for this tag */ ! 959: sprintf(tmpblk.c, "ref -t %s%s %s", (*origname ? "-f" : ""),origname, prevtag); ! 960: fd = rpipe(tmpblk.c, 0); ! 961: if (fd < 0) ! 962: { ! 963: msg("Can't run \"%s\"", tmpblk.c); ! 964: return; ! 965: } ! 966: ! 967: /* try to read the tag info */ ! 968: for (scan = tmpblk.c; ! 969: (i = tread(fd, scan, scan - tmpblk.c + BLKSIZE)) > 0; ! 970: scan += i) ! 971: { ! 972: } ! 973: *scan = '\0'; ! 974: ! 975: /* close the pipe. abort if error */ ! 976: if (rpclose(fd) != 0 || scan < tmpblk.c + 3) ! 977: { ! 978: msg("tag \"%s\" not found", extra); ! 979: return; ! 980: } ! 981: ! 982: #else /* use internal code to look up the tag */ ! 983: /* open the tags file */ ! 984: fd = open(TAGS, O_RDONLY); ! 985: if (fd < 0) ! 986: { ! 987: msg("No tags file"); ! 988: return; ! 989: } ! 990: ! 991: /* Hmmm... this would have been a lot easier with <stdio.h> */ ! 992: ! 993: /* find the line with our tag in it */ ! 994: for(scan = end = tmpblk.c, cmp = extra; ; scan++) ! 995: { ! 996: /* read a block, if necessary */ ! 997: if (scan >= end) ! 998: { ! 999: end = tmpblk.c + tread(fd, tmpblk.c, BLKSIZE); ! 1000: scan = tmpblk.c; ! 1001: if (scan >= end) ! 1002: { ! 1003: msg("tag \"%s\" not found", extra); ! 1004: close(fd); ! 1005: return; ! 1006: } ! 1007: } ! 1008: ! 1009: /* if we're comparing, compare... */ ! 1010: if (cmp) ! 1011: { ! 1012: /* matched??? wow! */ ! 1013: if (!*cmp && *scan == '\t') ! 1014: { ! 1015: break; ! 1016: } ! 1017: if (*cmp++ != *scan) ! 1018: { ! 1019: /* failed! skip to newline */ ! 1020: cmp = (char *)0; ! 1021: } ! 1022: } ! 1023: ! 1024: /* if we're skipping to newline, do it fast! */ ! 1025: if (!cmp) ! 1026: { ! 1027: while (scan < end && *scan != '\n') ! 1028: { ! 1029: scan++; ! 1030: } ! 1031: if (scan < end) ! 1032: { ! 1033: cmp = extra; ! 1034: } ! 1035: } ! 1036: } ! 1037: ! 1038: /* found it! get the rest of the line into memory */ ! 1039: for (cmp = tmpblk.c, scan++; scan < end && *scan != '\n'; ) ! 1040: { ! 1041: *cmp++ = *scan++; ! 1042: } ! 1043: if (scan == end) ! 1044: { ! 1045: tread(fd, cmp, BLKSIZE - (int)(cmp - tmpblk.c)); ! 1046: } ! 1047: else ! 1048: *cmp = *scan; ! 1049: ! 1050: /* we can close the tags file now */ ! 1051: close(fd); ! 1052: #endif /* INTERNAL_TAGS */ ! 1053: ! 1054: /* extract the filename from the line, and edit the file */ ! 1055: for (scan = tmpblk.c; *scan != '\t'; scan++) ! 1056: { ! 1057: } ! 1058: *scan++ = '\0'; ! 1059: if (strcmp(origname, tmpblk.c) != 0) ! 1060: { ! 1061: if (!tmpabort(bang)) ! 1062: { ! 1063: msg("Use :tag! to abort changes, or :w to save changes"); ! 1064: return; ! 1065: } ! 1066: tmpstart(tmpblk.c); ! 1067: } ! 1068: ! 1069: /* move to the desired line (or to line 1 if that fails) */ ! 1070: #ifndef NO_MAGIC ! 1071: wasmagic = *o_magic; ! 1072: *o_magic = FALSE; ! 1073: #endif ! 1074: cursor = MARK_FIRST; ! 1075: linespec(scan, &cursor); ! 1076: if (cursor == MARK_UNSET) ! 1077: { ! 1078: cursor = MARK_FIRST; ! 1079: msg("Tag's address is out of date"); ! 1080: } ! 1081: #ifndef NO_MAGIC ! 1082: *o_magic = wasmagic; ! 1083: #endif ! 1084: } ! 1085: ! 1086: ! 1087: ! 1088: ! 1089: ! 1090: /* describe this version of the program */ ! 1091: /*ARGSUSED*/ ! 1092: void cmd_version(frommark, tomark, cmd, bang, extra) ! 1093: MARK frommark; ! 1094: MARK tomark; ! 1095: CMD cmd; ! 1096: int bang; ! 1097: char *extra; ! 1098: { ! 1099: msg("%s", VERSION); ! 1100: #ifdef CREDIT ! 1101: msg("%s", CREDIT); ! 1102: #endif ! 1103: #ifdef CREDIT2 ! 1104: msg("%s", CREDIT2); ! 1105: #endif ! 1106: #ifdef COMPILED_BY ! 1107: msg("Compiled by %s", COMPILED_BY); ! 1108: #endif ! 1109: #ifdef COPYING ! 1110: msg("%s", COPYING); ! 1111: #endif ! 1112: } ! 1113: ! 1114: ! 1115: #ifndef NO_MKEXRC ! 1116: /* make a .exrc file which describes the current configuration */ ! 1117: /*ARGSUSED*/ ! 1118: void cmd_mkexrc(frommark, tomark, cmd, bang, extra) ! 1119: MARK frommark; ! 1120: MARK tomark; ! 1121: CMD cmd; ! 1122: int bang; ! 1123: char *extra; ! 1124: { ! 1125: int fd; ! 1126: ! 1127: /* the default name for the .exrc file EXRC */ ! 1128: if (!*extra) ! 1129: { ! 1130: extra = EXRC; ! 1131: } ! 1132: ! 1133: /* create the .exrc file */ ! 1134: fd = creat(extra, FILEPERMS); ! 1135: if (fd < 0) ! 1136: { ! 1137: msg("Couldn't create a new \"%s\" file", extra); ! 1138: return; ! 1139: } ! 1140: ! 1141: /* save stuff */ ! 1142: saveopts(fd); ! 1143: savemaps(fd, FALSE); ! 1144: #ifndef NO_ABBR ! 1145: savemaps(fd, TRUE); ! 1146: #endif ! 1147: #ifndef NO_DIGRAPH ! 1148: savedigs(fd); ! 1149: #endif ! 1150: #ifndef NO_COLOR ! 1151: savecolor(fd); ! 1152: #endif ! 1153: ! 1154: /* close the file */ ! 1155: close(fd); ! 1156: msg("Configuration saved"); ! 1157: } ! 1158: #endif ! 1159: ! 1160: #ifndef NO_DIGRAPH ! 1161: /*ARGSUSED*/ ! 1162: void cmd_digraph(frommark, tomark, cmd, bang, extra) ! 1163: MARK frommark; ! 1164: MARK tomark; ! 1165: CMD cmd; ! 1166: int bang; ! 1167: char *extra; ! 1168: { ! 1169: do_digraph(bang, extra); ! 1170: } ! 1171: #endif ! 1172: ! 1173: ! 1174: #ifndef NO_ERRLIST ! 1175: static char errfile[256]; /* the name of a file containing an error */ ! 1176: static long errline; /* the line number for an error */ ! 1177: static int errfd = -2; /* fd of the errlist file */ ! 1178: ! 1179: /* This static function tries to parse an error message. ! 1180: * ! 1181: * For most compilers, the first word is taken to be the name of the erroneous ! 1182: * file, and the first number after that is taken to be the line number where ! 1183: * the error was detected. The description of the error follows, possibly ! 1184: * preceded by an "error ... :" or "warning ... :" label which is skipped. ! 1185: * ! 1186: * For Coherent, error messages look like "line#: filename: message". ! 1187: * ! 1188: * For non-error lines, or unparsable error lines, this function returns NULL. ! 1189: * Normally, though, it alters errfile and errline, and returns a pointer to ! 1190: * the description. ! 1191: */ ! 1192: static char *parse_errmsg(text) ! 1193: REG char *text; ! 1194: { ! 1195: REG char *cpy; ! 1196: long atol(); ! 1197: # if COHERENT || TOS /* any Mark Williams compiler */ ! 1198: /* Get the line number. If no line number, then ignore this line. */ ! 1199: errline = atol(text); ! 1200: if (errline == 0L) ! 1201: return (char *)0; ! 1202: ! 1203: /* Skip to the start of the filename */ ! 1204: while (*text && *text++ != ':') ! 1205: { ! 1206: } ! 1207: if (!*text++) ! 1208: return (char *)0; ! 1209: ! 1210: /* copy the filename to errfile */ ! 1211: for (cpy = errfile; *text && (*cpy++ = *text++) != ':'; ) ! 1212: { ! 1213: } ! 1214: if (!*text++) ! 1215: return (char *)0; ! 1216: cpy[-1] = '\0'; ! 1217: ! 1218: return text; ! 1219: # else /* not a Mark Williams compiler */ ! 1220: char *errmsg; ! 1221: ! 1222: /* the error message is the whole line, by default */ ! 1223: errmsg = text; ! 1224: ! 1225: /* skip leading garbage */ ! 1226: while (*text && !isalnum(*text)) ! 1227: { ! 1228: text++; ! 1229: } ! 1230: ! 1231: /* copy over the filename */ ! 1232: cpy = errfile; ! 1233: while(isalnum(*text) || *text == '.') ! 1234: { ! 1235: *cpy++ = *text++; ! 1236: } ! 1237: *cpy = '\0'; ! 1238: ! 1239: /* ignore the name "Error" and filenames that contain a '/' */ ! 1240: if (*text == '/' || !*errfile || !strcmp(errfile + 1, "rror") || access(errfile, 0) < 0) ! 1241: { ! 1242: return (char *)0; ! 1243: } ! 1244: ! 1245: /* skip garbage between filename and line number */ ! 1246: while (*text && !isdigit(*text)) ! 1247: { ! 1248: text++; ! 1249: } ! 1250: ! 1251: /* if the number is part of a larger word, then ignore this line */ ! 1252: if (*text && isalpha(text[-1])) ! 1253: { ! 1254: return (char *)0; ! 1255: } ! 1256: ! 1257: /* get the error line */ ! 1258: errline = 0L; ! 1259: while (isdigit(*text)) ! 1260: { ! 1261: errline *= 10; ! 1262: errline += (*text - '0'); ! 1263: text++; ! 1264: } ! 1265: ! 1266: /* any line which lacks a filename or line number should be ignored */ ! 1267: if (!errfile[0] || !errline) ! 1268: { ! 1269: return (char *)0; ! 1270: } ! 1271: ! 1272: /* locate the beginning of the error description */ ! 1273: while (*text && !isspace(*text)) ! 1274: { ! 1275: text++; ! 1276: } ! 1277: while (*text) ! 1278: { ! 1279: # ifndef CRUNCH ! 1280: /* skip "error #:" and "warning #:" clauses */ ! 1281: if (!strncmp(text + 1, "rror ", 5) ! 1282: || !strncmp(text + 1, "arning ", 7) ! 1283: || !strncmp(text + 1, "atal error", 10)) ! 1284: { ! 1285: do ! 1286: { ! 1287: text++; ! 1288: } while (*text && *text != ':'); ! 1289: continue; ! 1290: } ! 1291: # endif ! 1292: ! 1293: /* anything other than whitespace or a colon is important */ ! 1294: if (!isspace(*text) && *text != ':') ! 1295: { ! 1296: errmsg = text; ! 1297: break; ! 1298: } ! 1299: ! 1300: /* else keep looking... */ ! 1301: text++; ! 1302: } ! 1303: ! 1304: return errmsg; ! 1305: # endif /* not COHERENT */ ! 1306: } ! 1307: ! 1308: /*ARGSUSED*/ ! 1309: void cmd_errlist(frommark, tomark, cmd, bang, extra) ! 1310: MARK frommark, tomark; ! 1311: CMD cmd; ! 1312: int bang; ! 1313: char *extra; ! 1314: { ! 1315: static long endline;/* original number of lines in this file */ ! 1316: static long offset; /* offset of the next line in the errlist file */ ! 1317: int i; ! 1318: char *errmsg; ! 1319: ! 1320: /* if a new errlist file is named, open it */ ! 1321: if (extra && extra[0]) ! 1322: { ! 1323: /* close the old one */ ! 1324: if (errfd >= 0) ! 1325: { ! 1326: close(errfd); ! 1327: } ! 1328: ! 1329: /* open the new one */ ! 1330: errfd = open(extra, O_RDONLY); ! 1331: offset = 0L; ! 1332: endline = nlines; ! 1333: } ! 1334: else if (errfd < 0) ! 1335: { ! 1336: /* open the default file */ ! 1337: errfd = open(ERRLIST, O_RDONLY); ! 1338: offset = 0L; ! 1339: endline = nlines; ! 1340: } ! 1341: ! 1342: /* do we have an errlist file now? */ ! 1343: if (errfd < 0) ! 1344: { ! 1345: msg("There is no errlist file"); ! 1346: beep(); ! 1347: return; ! 1348: } ! 1349: ! 1350: /* find the next error message in the file */ ! 1351: do ! 1352: { ! 1353: /* read the next line from the errlist */ ! 1354: lseek(errfd, offset, 0); ! 1355: if (tread(errfd, tmpblk.c, (unsigned)BLKSIZE) <= 0) ! 1356: { ! 1357: msg("No more errors"); ! 1358: beep(); ! 1359: close(errfd); ! 1360: errfd = -2; ! 1361: return; ! 1362: } ! 1363: for (i = 0; tmpblk.c[i] != '\n'; i++) ! 1364: { ! 1365: } ! 1366: tmpblk.c[i++] = 0; ! 1367: ! 1368: /* look for an error message in the line */ ! 1369: errmsg = parse_errmsg(tmpblk.c); ! 1370: if (!errmsg) ! 1371: { ! 1372: offset += i; ! 1373: } ! 1374: ! 1375: } while (!errmsg); ! 1376: ! 1377: /* switch to the file containing the error, if this isn't it */ ! 1378: if (strcmp(origname, errfile)) ! 1379: { ! 1380: if (!tmpabort(bang)) ! 1381: { ! 1382: msg("Use :er! to abort changes, or :w to save changes"); ! 1383: beep(); ! 1384: return; ! 1385: } ! 1386: tmpstart(errfile); ! 1387: endline = nlines; ! 1388: } ! 1389: else if (endline == 0L) ! 1390: { ! 1391: endline = nlines; ! 1392: } ! 1393: ! 1394: /* go to the line where the error was detected */ ! 1395: cursor = MARK_AT_LINE(errline + (nlines - endline)); ! 1396: if (cursor > MARK_LAST) ! 1397: { ! 1398: cursor = MARK_LAST; ! 1399: } ! 1400: if (mode == MODE_VI) ! 1401: { ! 1402: redraw(cursor, FALSE); ! 1403: } ! 1404: ! 1405: /* display the error message */ ! 1406: #ifdef CRUNCH ! 1407: msg("%.70s", errmsg); ! 1408: #else ! 1409: if (nlines > endline) ! 1410: { ! 1411: msg("line %ld(+%ld): %.60s", errline, nlines - endline, errmsg); ! 1412: } ! 1413: else if (nlines < endline) ! 1414: { ! 1415: msg("line %ld(-%ld): %.60s", errline, endline - nlines, errmsg); ! 1416: } ! 1417: else ! 1418: { ! 1419: msg("line %ld: %.65s", errline, errmsg); ! 1420: } ! 1421: #endif ! 1422: ! 1423: /* remember where the NEXT error line will start */ ! 1424: offset += i; ! 1425: } ! 1426: ! 1427: ! 1428: /*ARGSUSED*/ ! 1429: void cmd_make(frommark, tomark, cmd, bang, extra) ! 1430: MARK frommark, tomark; ! 1431: CMD cmd; ! 1432: int bang; ! 1433: char *extra; ! 1434: { ! 1435: BLK buf; ! 1436: ! 1437: /* if the file hasn't been saved, then complain unless ! */ ! 1438: if (tstflag(file, MODIFIED) && !bang) ! 1439: { ! 1440: msg("\"%s\" not saved yet", origname); ! 1441: return; ! 1442: } ! 1443: ! 1444: /* build the command */ ! 1445: sprintf(buf.c, "%s %s %s%s", (cmd == CMD_CC ? o_cc : o_make), extra, REDIRECT, ERRLIST); ! 1446: qaddstr(buf.c); ! 1447: addch('\n'); ! 1448: ! 1449: /* close the old errlist file, if any */ ! 1450: if (errfd >= 0) ! 1451: { ! 1452: close(errfd); ! 1453: errfd = -3; ! 1454: } ! 1455: ! 1456: /* run the command, with curses temporarily disabled */ ! 1457: suspend_curses(); ! 1458: system(buf.c); ! 1459: resume_curses(mode == MODE_EX); ! 1460: if (mode == MODE_COLON) ! 1461: mode = MODE_VI; ! 1462: ! 1463: /* run the "errlist" command */ ! 1464: cmd_errlist(MARK_UNSET, MARK_UNSET, cmd, bang, ERRLIST); ! 1465: } ! 1466: #endif ! 1467: ! 1468: ! 1469: ! 1470: #ifndef NO_COLOR ! 1471: ! 1472: /* figure out the number of text colors we use with this configuration */ ! 1473: # ifndef NO_POPUP ! 1474: # ifndef NO_VISIBLE ! 1475: # define NCOLORS 7 ! 1476: # else ! 1477: # define NCOLORS 6 ! 1478: # endif ! 1479: # else ! 1480: # ifndef NO_VISIBLE ! 1481: # define NCOLORS 6 ! 1482: # else ! 1483: # define NCOLORS 5 ! 1484: # endif ! 1485: # endif ! 1486: ! 1487: /* the attribute bytes used in each of "when"s */ ! 1488: static char bytes[NCOLORS]; ! 1489: ! 1490: static struct ! 1491: { ! 1492: char *word; /* a legal word */ ! 1493: int type; /* what type of word this is */ ! 1494: int val; /* some other value */ ! 1495: } ! 1496: words[] = ! 1497: { ! 1498: {"normal", 1, A_NORMAL}, /* all "when" names must come */ ! 1499: {"standout", 1, A_STANDOUT}, /* at the top of the list. */ ! 1500: {"bold", 1, A_BOLD}, /* The first 3 must be normal,*/ ! 1501: {"underlined", 1, A_UNDERLINE}, /* standout, and bold; the */ ! 1502: {"italics", 1, A_ALTCHARSET}, /* remaining names follow. */ ! 1503: #ifndef NO_POPUP ! 1504: {"popup", 1, A_POPUP}, ! 1505: #endif ! 1506: #ifndef NO_VISIBLE ! 1507: {"visible", 1, A_VISIBLE}, ! 1508: #endif ! 1509: ! 1510: {"black", 3, 0x00}, /* The color names start right*/ ! 1511: {"blue", 3, 0x01}, /* after the "when" names. */ ! 1512: {"green", 3, 0x02}, ! 1513: {"cyan", 3, 0x03}, ! 1514: {"red", 3, 0x04}, ! 1515: {"magenta", 3, 0x05}, ! 1516: {"brown", 3, 0x06}, ! 1517: {"white", 3, 0x07}, ! 1518: {"yellow", 3, 0x0E}, /* bright brown */ ! 1519: {"gray", 3, 0x08}, /* bright black? of course! */ ! 1520: {"grey", 3, 0x08}, ! 1521: ! 1522: {"bright", 2, 0x08}, ! 1523: {"light", 2, 0x08}, ! 1524: {"blinking", 2, 0x80}, ! 1525: {"on", 0, 0}, ! 1526: {"n", 1, A_NORMAL}, ! 1527: {"s", 1, A_STANDOUT}, ! 1528: {"b", 1, A_BOLD}, ! 1529: {"u", 1, A_UNDERLINE}, ! 1530: {"i", 1, A_ALTCHARSET}, ! 1531: #ifndef NO_POPUP ! 1532: {"p", 1, A_POPUP}, ! 1533: {"menu", 1, A_POPUP}, ! 1534: #endif ! 1535: #ifndef NO_VISIBLE ! 1536: {"v", 1, A_VISIBLE}, ! 1537: #endif ! 1538: {(char *)0, 0, 0} ! 1539: }; ! 1540: ! 1541: /*ARGSUSED*/ ! 1542: void cmd_color(frommark, tomark, cmd, bang, extra) ! 1543: MARK frommark, tomark; ! 1544: CMD cmd; ! 1545: int bang; ! 1546: char *extra; ! 1547: { ! 1548: int attrbyte; ! 1549: int cmode; ! 1550: int nowbg; /* BOOLEAN: is the next color background? */ ! 1551: ! 1552: REG char *scan; ! 1553: REG i; ! 1554: ! 1555: ! 1556: #ifndef CRUNCH ! 1557: /* if no args are given, then report the current colors */ ! 1558: if (!*extra) ! 1559: { ! 1560: /* if no colors are set, then say so */ ! 1561: if (!bytes[0]) ! 1562: { ! 1563: msg("no colors have been set"); ! 1564: return; ! 1565: } ! 1566: ! 1567: /* report all five color combinations */ ! 1568: for (i = 0; i < NCOLORS; i++) ! 1569: { ! 1570: qaddstr("color "); ! 1571: qaddstr(words[i].word); ! 1572: qaddch(' '); ! 1573: if (bytes[i] & 0x80) ! 1574: qaddstr("blinking "); ! 1575: switch (bytes[i] & 0xf) ! 1576: { ! 1577: case 0x08: qaddstr("gray"); break; ! 1578: case 0x0e: qaddstr("yellow"); break; ! 1579: case 0x0f: qaddstr("bright white");break; ! 1580: default: ! 1581: if (bytes[i] & 0x08) ! 1582: qaddstr("light "); ! 1583: qaddstr(words[(bytes[i] & 0x07) + NCOLORS].word); ! 1584: } ! 1585: qaddstr(" on "); ! 1586: qaddstr(words[((bytes[i] >> 4) & 0x07) + NCOLORS].word); ! 1587: addch('\n'); ! 1588: exrefresh(); ! 1589: } ! 1590: return; ! 1591: } ! 1592: #endif ! 1593: ! 1594: /* The default background color is the same as "normal" chars. ! 1595: * There is no default foreground color. ! 1596: */ ! 1597: cmode = A_NORMAL; ! 1598: attrbyte = bytes[0] & 0x70; ! 1599: nowbg = FALSE; ! 1600: ! 1601: /* parse each word in the "extra" text */ ! 1602: for (scan = extra; *extra; extra = scan) ! 1603: { ! 1604: /* locate the end of the word */ ! 1605: while (*scan && *scan != ' ') ! 1606: { ! 1607: scan++; ! 1608: } ! 1609: ! 1610: /* skip whitespace at the end of the word */ ! 1611: while(*scan == ' ') ! 1612: { ! 1613: *scan++ = '\0'; ! 1614: } ! 1615: ! 1616: /* lookup the word */ ! 1617: for (i = 0; words[i].word && strcmp(words[i].word, extra); i++) ! 1618: { ! 1619: } ! 1620: ! 1621: /* if not a word, then complain */ ! 1622: if (!words[i].word) ! 1623: { ! 1624: msg("Invalid color name: %s", extra); ! 1625: return; ! 1626: } ! 1627: ! 1628: /* process the word */ ! 1629: switch (words[i].type) ! 1630: { ! 1631: case 1: ! 1632: cmode = words[i].val; ! 1633: break; ! 1634: ! 1635: case 2: ! 1636: attrbyte |= words[i].val; ! 1637: break; ! 1638: ! 1639: case 3: ! 1640: if (nowbg) ! 1641: attrbyte = ((attrbyte & ~0x70) | ((words[i].val & 0x07) << 4)); ! 1642: else ! 1643: attrbyte |= words[i].val; ! 1644: nowbg = TRUE; ! 1645: break; ! 1646: } ! 1647: } ! 1648: ! 1649: /* if nowbg isn't set now, then we were never given a foreground color */ ! 1650: if (!nowbg) ! 1651: { ! 1652: msg("usage: color [when] [\"bright\"] [\"blinking\"] foreground [background]"); ! 1653: return; ! 1654: } ! 1655: ! 1656: /* the first ":color" command MUST define the "normal" colors */ ! 1657: if (!bytes[0]) ! 1658: cmode = A_NORMAL; ! 1659: ! 1660: /* we should now have a cmode and an attribute byte... */ ! 1661: ! 1662: /* set the color */ ! 1663: setcolor(cmode, attrbyte); ! 1664: ! 1665: /* remember what we just did */ ! 1666: bytes[cmode] = attrbyte; ! 1667: ! 1668: /* if the other colors haven't been set yet, then set them to defaults */ ! 1669: if (!bytes[1]) ! 1670: { ! 1671: /* standout is the opposite of normal */ ! 1672: bytes[1] = ((attrbyte << 4) & 0x70 | (attrbyte >> 4) & 0x07); ! 1673: setcolor(A_STANDOUT, bytes[1]); ! 1674: ! 1675: /* if "normal" isn't bright, then bold defaults to normal+bright ! 1676: * else bold defaults to bright white. ! 1677: */ ! 1678: bytes[2] = attrbyte | ((attrbyte & 0x08) ? 0x0f : 0x08); ! 1679: setcolor(A_BOLD, bytes[2]); ! 1680: ! 1681: /* all others default to the "standout" colors, without blinking */ ! 1682: for (i = 3; i < NCOLORS; i++) ! 1683: { ! 1684: bytes[i] = (bytes[1] & 0x7f); ! 1685: setcolor(words[i].val, bytes[i]); ! 1686: } ! 1687: } ! 1688: ! 1689: /* force a redraw, so we see the new colors */ ! 1690: redraw(MARK_UNSET, FALSE); ! 1691: } ! 1692: ! 1693: ! 1694: ! 1695: void savecolor(fd) ! 1696: int fd; /* file descriptor to write colors to */ ! 1697: { ! 1698: int i; ! 1699: char buf[80]; ! 1700: ! 1701: /* if no colors are set, then return */ ! 1702: if (!bytes[0]) ! 1703: { ! 1704: return; ! 1705: } ! 1706: ! 1707: /* save all five color combinations */ ! 1708: for (i = 0; i < NCOLORS; i++) ! 1709: { ! 1710: strcpy(buf, "color "); ! 1711: strcat(buf, words[i].word); ! 1712: strcat(buf, " "); ! 1713: if (bytes[i] & 0x80) ! 1714: strcat(buf, "blinking "); ! 1715: switch (bytes[i] & 0xf) ! 1716: { ! 1717: case 0x08: strcat(buf, "gray"); break; ! 1718: case 0x0e: strcat(buf, "yellow"); break; ! 1719: case 0x0f: strcat(buf, "bright white");break; ! 1720: default: ! 1721: if (bytes[i] & 0x08) ! 1722: strcat(buf, "light "); ! 1723: strcat(buf, words[(bytes[i] & 0x07) + NCOLORS].word); ! 1724: } ! 1725: strcat(buf, " on "); ! 1726: strcat(buf, words[((bytes[i] >> 4) & 0x07) + NCOLORS].word); ! 1727: strcat(buf, "\n"); ! 1728: twrite(fd, buf, (unsigned)strlen(buf)); ! 1729: } ! 1730: } ! 1731: #endif ! 1732: ! 1733: #ifdef SIGTSTP ! 1734: /* temporarily suspend elvis */ ! 1735: /*ARGSUSED*/ ! 1736: void cmd_suspend(frommark, tomark, cmd, bang, extra) ! 1737: MARK frommark; ! 1738: MARK tomark; ! 1739: CMD cmd; ! 1740: int bang; ! 1741: char *extra; ! 1742: { ! 1743: void (*func)(); /* stores the previous setting of SIGTSTP */ ! 1744: ! 1745: #if ANY_UNIX ! 1746: /* the Bourne shell can't handle ^Z */ ! 1747: if (!strcmp(o_shell, "/bin/sh")) ! 1748: { ! 1749: msg("The /bin/sh shell doesn't support ^Z"); ! 1750: return; ! 1751: } ! 1752: #endif ! 1753: ! 1754: move(LINES - 1, 0); ! 1755: if (tstflag(file, MODIFIED)) ! 1756: { ! 1757: addstr("Warning: \""); ! 1758: addstr(origname); ! 1759: addstr("\" modified but not yet saved"); ! 1760: clrtoeol(); ! 1761: } ! 1762: refresh(); ! 1763: suspend_curses(); ! 1764: func = signal(SIGTSTP, SIG_DFL); ! 1765: kill (0, SIGTSTP); ! 1766: ! 1767: /* the process stops and resumes here */ ! 1768: ! 1769: signal(SIGTSTP, func); ! 1770: resume_curses(TRUE); ! 1771: if (mode == MODE_VI || mode == MODE_COLON) ! 1772: redraw(MARK_UNSET, FALSE); ! 1773: else ! 1774: refresh (); ! 1775: } ! 1776: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.