1: /*************************************************************************** 2: * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE * 3: * is provided to you without charge, and with no warranty. You may give * 4: * away copies of JOVE, including sources, provided that this notice is * 5: * included in all the files. * 6: ***************************************************************************/ 7: 8: #include "jove.h" 9: #include "io.h" 10: #include "termcap.h" 11: #include "ctype.h" 12: #ifdef JOB_CONTROL 13: # include <signal.h> 14: #endif 15: 16: #ifdef MAC 17: # include "mac.h" 18: #else 19: # include <varargs.h> 20: #endif 21: 22: #ifdef MSDOS 23: #include <process.h> 24: #endif 25: 26: #ifdef MAC 27: # undef private 28: # define private 29: #endif 30: 31: #ifdef LINT_ARGS 32: private void 33: fb_aux(data_obj *, data_obj **, char *, char *), 34: find_binds(data_obj *, char *), 35: vpr_aux(struct variable *, char *); 36: #else 37: private void 38: fb_aux(), 39: find_binds(), 40: vpr_aux(); 41: #endif /* LINT_ARGS */ 42: 43: #ifdef MAC 44: # undef private 45: # define private static 46: #endif 47: 48: 49: int InJoverc = 0; 50: 51: extern int getch(), 52: getchar(); 53: 54: /* Auto execute code */ 55: 56: #define NEXECS 20 57: 58: private struct { 59: char *a_pattern; 60: data_obj *a_cmd; 61: } AutoExecs[NEXECS] = {0}; 62: 63: private int ExecIndex = 0; 64: 65: /* Command auto-execute. */ 66: 67: void 68: CAutoExec() 69: { 70: DefAutoExec(findcom); 71: } 72: 73: /* Macro auto-execute. */ 74: 75: void 76: MAutoExec() 77: { 78: DefAutoExec(findmac); 79: } 80: 81: /* VARARGS0 */ 82: 83: void 84: DefAutoExec(proc) 85: #ifdef LINT_ARGS 86: data_obj *(*proc)(char *); 87: #else 88: data_obj *(*proc)(); 89: #endif 90: { 91: data_obj *d; 92: char *pattern; 93: int i; 94: 95: if (ExecIndex >= NEXECS) 96: complain("Too many auto-executes, max %d.", NEXECS); 97: if ((d = (*proc)(ProcFmt)) == 0) 98: return; 99: pattern = do_ask("\r\n", (int (*)()) 0, (char *) 0, ": %f %s ", d->Name); 100: if (pattern != 0) 101: for (i = 0; i < ExecIndex; i++) 102: if ((AutoExecs[i].a_cmd == d) && 103: (strcmp(pattern, AutoExecs[i].a_pattern) == 0)) 104: return; /* eliminate duplicates */ 105: AutoExecs[ExecIndex].a_pattern = copystr(pattern); 106: AutoExecs[ExecIndex].a_cmd = d; 107: ExecIndex += 1; 108: } 109: 110: /* DoAutoExec: NEW and OLD are file names, and if NEW and OLD aren't the 111: same kind of file (i.e., match the same pattern) or OLD is 0 and it 112: matches, OR if the pattern is 0 (none was specified) then, we execute 113: the command associated with that kind of file. */ 114: 115: void 116: DoAutoExec(new, old) 117: register char *new, 118: *old; 119: { 120: register int i; 121: 122: set_arg_value(1); 123: for (i = 0; i < ExecIndex; i++) 124: if ((AutoExecs[i].a_pattern == 0) || 125: ((new != 0 && LookingAt(AutoExecs[i].a_pattern, new, 0)) && 126: (old == 0 || !LookingAt(AutoExecs[i].a_pattern, old, 0)))) 127: ExecCmd(AutoExecs[i].a_cmd); 128: } 129: 130: void 131: BindAKey() 132: { 133: BindSomething(findcom); 134: } 135: 136: void 137: BindMac() 138: { 139: BindSomething(findmac); 140: } 141: 142: extern void EscPrefix(), 143: CtlxPrefix(), 144: MiscPrefix(); 145: 146: data_obj ** 147: IsPrefix(cp) 148: data_obj *cp; 149: { 150: #ifdef MAC 151: void (*proc)(); 152: #else 153: int (*proc)(); 154: #endif 155: 156: if (cp == 0 || (cp->Type & TYPEMASK) != FUNCTION) 157: return 0; 158: proc = ((struct cmd *) cp)->c_proc; 159: if (proc == EscPrefix) 160: return pref1map; 161: if (proc == CtlxPrefix) 162: return pref2map; 163: if (proc == MiscPrefix) 164: return miscmap; 165: return 0; 166: } 167: 168: void 169: UnbindC() 170: { 171: char *keys; 172: data_obj **map = mainmap; 173: 174: keys = ask((char *) 0, ProcFmt); 175: for (;;) { 176: if (keys[1] == '\0') 177: break; 178: if ((map = IsPrefix(map[*keys])) == 0) 179: break; 180: keys += 1; 181: } 182: if (keys[1] != 0) 183: complain("That's not a legitimate key sequence."); 184: map[keys[0]] = 0; 185: } 186: 187: int 188: addgetc() 189: { 190: int c; 191: 192: if (!InJoverc) { 193: Asking = strlen(mesgbuf); 194: c = getch(); 195: Asking = 0; 196: add_mess("%p ", c); 197: } else { 198: c = getch(); 199: if (c == '\n') 200: return EOF; /* this isn't part of the sequence */ 201: else if (c == '\\') { 202: if ((c = getch()) == LF) 203: complain("[Premature end of line]"); 204: } else if (c == '^') { 205: if ((c = getch()) == '?') 206: c = RUBOUT; 207: else if (isalpha(c) || index("@[\\]^_", c)) 208: c = CTL(c); 209: else 210: complain("[Unknown control character]"); 211: } 212: } 213: return c; 214: } 215: 216: void 217: BindWMap(map, lastkey, cmd) 218: data_obj **map, 219: *cmd; 220: { 221: data_obj **nextmap; 222: int c; 223: 224: c = addgetc(); 225: if (c == EOF) { 226: if (lastkey == EOF) 227: complain("[Empty key sequence]"); 228: complain("[Premature end of key sequence]"); 229: } else { 230: if (nextmap = IsPrefix(map[c])) 231: BindWMap(nextmap, c, cmd); 232: else { 233: map[c] = cmd; 234: #ifdef MAC 235: ((struct cmd *) cmd)->c_key = c; /* see about_j() in mac.c */ 236: if(map == mainmap) ((struct cmd *) cmd)->c_map = F_MAINMAP; 237: else if(map == pref1map) ((struct cmd *) cmd)->c_map = F_PREF1MAP; 238: else if(map == pref2map) ((struct cmd *) cmd)->c_map = F_PREF2MAP; 239: #endif 240: } 241: } 242: } 243: 244: /* VARARGS0 */ 245: 246: void 247: BindSomething(proc) 248: #ifdef LINT_ARGS 249: data_obj *(*proc)(char *); 250: #else 251: data_obj *(*proc)(); 252: #endif 253: { 254: data_obj *d; 255: 256: if ((d = (*proc)(ProcFmt)) == 0) 257: return; 258: s_mess(": %f %s ", d->Name); 259: BindWMap(mainmap, EOF, d); 260: } 261: 262: /* Describe key */ 263: 264: void 265: DescWMap(map, key) 266: data_obj **map; 267: { 268: data_obj *cp = map[key], 269: **prefp; 270: 271: if (cp == 0) 272: add_mess("is unbound."); 273: else if (prefp = IsPrefix(cp)) 274: DescWMap(prefp, addgetc()); 275: else 276: add_mess("is bound to %s.", cp->Name); 277: } 278: 279: void 280: KeyDesc() 281: { 282: s_mess(ProcFmt); 283: DescWMap(mainmap, addgetc()); 284: } 285: 286: void 287: DescCom() 288: { 289: data_obj *dp; 290: char pattern[100], 291: doc_type[40], 292: *the_type, 293: *file = CmdDb; 294: File *fp; 295: int is_var; 296: 297: if (!strcmp(LastCmd->Name, "describe-variable")) { 298: dp = (data_obj *) findvar(ProcFmt); 299: the_type = "Variable"; 300: is_var = YES; 301: } else { 302: dp = (data_obj *) findcom(ProcFmt); 303: the_type = "Command"; 304: is_var = NO; 305: } 306: if (dp == 0) 307: return; 308: fp = open_file(file, iobuff, F_READ, COMPLAIN, QUIET); 309: Placur(ILI, 0); 310: flusho(); 311: sprintf(pattern, "^:entry \"%s\" \"\\([^\"]*\\)\"", dp->Name); 312: TOstart("Help", TRUE); 313: for (;;) { 314: if (f_gets(fp, genbuf, LBSIZE) == EOF) { 315: Typeout("There is no documentation for \"%s\".", dp->Name); 316: goto outahere; 317: } 318: if ((strncmp(genbuf, ":entry", 6) == 0) && 319: (LookingAt(pattern, genbuf, 0))) { 320: char type[64]; 321: 322: putmatch(1, type, sizeof type); 323: if (strcmp(type, the_type) == 0) 324: break; 325: } 326: } 327: /* found it ... let's print it */ 328: putmatch(1, doc_type, sizeof doc_type); 329: if (is_var == YES) 330: Typeout(dp->Name); 331: else { 332: char binding[128]; 333: 334: find_binds(dp, binding); 335: if (blnkp(binding)) 336: Typeout("To invoke %s, type \"ESC X %s<cr>\".", 337: dp->Name, 338: dp->Name); 339: else 340: Typeout("Type \"%s\" to invoke %s.", binding, dp->Name); 341: } 342: Typeout(""); 343: while (f_gets(fp, genbuf, LBSIZE) != EOF) 344: if (strncmp(genbuf, ":entry", 6) == 0) 345: goto outahere; 346: else 347: Typeout("%s", genbuf); 348: outahere: 349: f_close(fp); 350: TOstop(); 351: } 352: 353: void 354: DescBindings() 355: { 356: extern void Typeout(); 357: 358: TOstart("Key Bindings", TRUE); 359: DescMap(mainmap, NullStr); 360: TOstop(); 361: } 362: 363: extern int specialmap; 364: 365: void 366: DescMap(map, pref) 367: data_obj **map; 368: char *pref; 369: { 370: int c1, 371: c2 = 0, 372: numbetween; 373: char keydescbuf[40]; 374: data_obj **prefp; 375: 376: #ifdef IBMPC 377: specialmap = (map == miscmap); 378: #endif 379: 380: for (c1 = 0; c1 < NCHARS && c2 < NCHARS; c1 = c2 + 1) { 381: c2 = c1; 382: if (map[c1] == 0) 383: continue; 384: while (++c2 < NCHARS && map[c1] == map[c2]) 385: ; 386: c2 -= 1; 387: numbetween = c2 - c1; 388: if (numbetween == 1) 389: sprintf(keydescbuf, "%s {%p,%p}", pref, c1, c2); 390: else if (numbetween == 0) 391: sprintf(keydescbuf, "%s %p", pref, c1); 392: else 393: sprintf(keydescbuf, "%s [%p-%p]", pref, c1, c2); 394: if ((prefp = IsPrefix(map[c1])) && (prefp != map)) 395: DescMap(prefp, keydescbuf); 396: else 397: Typeout("%-18s%s", keydescbuf, map[c1]->Name); 398: } 399: } 400: 401: private void 402: find_binds(dp, buf) 403: data_obj *dp; 404: char *buf; 405: { 406: char *endp; 407: 408: buf[0] = '\0'; 409: fb_aux(dp, mainmap, (char *) 0, buf); 410: endp = buf + strlen(buf) - 2; 411: if ((endp > buf) && (strcmp(endp, ", ") == 0)) 412: *endp = '\0'; 413: } 414: 415: private void 416: fb_aux(cp, map, prefix, buf) 417: register data_obj *cp, 418: **map; 419: char *buf, 420: *prefix; 421: { 422: int c1, 423: c2; 424: char *bufp = buf + strlen(buf), 425: prefbuf[20]; 426: data_obj **prefp; 427: 428: #ifdef IBMPC 429: specialmap = (map == miscmap); 430: #endif 431: 432: for (c1 = c2 = 0; c1 < NCHARS && c2 < NCHARS; c1 = c2 + 1) { 433: c2 = c1; 434: if (map[c1] == cp) { 435: while (++c2 < NCHARS && map[c1] == map[c2]) 436: ; 437: c2 -= 1; 438: if (prefix) 439: sprintf(bufp, "%s ", prefix); 440: bufp += strlen(bufp); 441: switch (c2 - c1) { 442: case 0: 443: sprintf(bufp, "%p, ", c1); 444: break; 445: 446: case 1: 447: sprintf(bufp, "{%p,%p}, ", c1, c2); 448: break; 449: 450: default: 451: sprintf(bufp, "[%p-%p], ", c1, c2); 452: break; 453: } 454: } 455: if ((prefp = IsPrefix(map[c1])) && (prefp != map)) { 456: sprintf(prefbuf, "%p", c1); 457: fb_aux(cp, prefp, prefbuf, bufp); 458: } 459: bufp += strlen(bufp); 460: } 461: } 462: 463: void 464: Apropos() 465: { 466: register struct cmd *cp; 467: register struct macro *m; 468: register struct variable *v; 469: char *ans; 470: int anyfs = NO, 471: anyvs = NO, 472: anyms = NO; 473: char buf[256]; 474: 475: ans = ask((char *) 0, ": %f (keyword) "); 476: TOstart("Help", TRUE); 477: for (cp = commands; cp->Name != 0; cp++) 478: if (sindex(ans, cp->Name)) { 479: if (anyfs == 0) { 480: Typeout("Commands"); 481: Typeout("--------"); 482: } 483: find_binds((data_obj *) cp, buf); 484: if (buf[0]) 485: Typeout(": %-35s(%s)", cp->Name, buf); 486: else 487: Typeout(": %s", cp->Name); 488: anyfs = YES; 489: } 490: if (anyfs) 491: Typeout(NullStr); 492: for (v = variables; v->Name != 0; v++) 493: if (sindex(ans, v->Name)) { 494: if (anyvs == 0) { 495: Typeout("Variables"); 496: Typeout("---------"); 497: } 498: anyvs = YES; 499: vpr_aux(v, buf); 500: Typeout(": set %-26s%s", v->Name, buf); 501: } 502: if (anyvs) 503: Typeout(NullStr); 504: for (m = macros; m != 0; m = m->m_nextm) 505: if (sindex(ans, m->Name)) { 506: if (anyms == 0) { 507: Typeout("Macros"); 508: Typeout("------"); 509: } 510: anyms = YES; 511: find_binds((data_obj *) m, buf); 512: if (buf[0]) 513: Typeout(": %-35s(%s)", m->Name, buf); 514: else 515: Typeout(": %-35s%s", "execute-macro", m->Name); 516: } 517: TOstop(); 518: } 519: 520: void 521: Extend() 522: { 523: data_obj *d; 524: 525: if (d = findcom(": ")) 526: ExecCmd(d); 527: } 528: 529: /* Read a positive integer from CP. It must be in base BASE, and 530: complains if it isn't. If allints is nonzero, all the characters 531: in the string must be integers or we return -1; otherwise we stop 532: reading at the first nondigit. */ 533: 534: int 535: chr_to_int(cp, base, allints, result) 536: register char *cp; 537: register int *result; 538: { 539: register int c; 540: int value = 0, 541: sign; 542: 543: if ((c = *cp) == '-') { 544: sign = -1; 545: cp += 1; 546: } else 547: sign = 1; 548: while (c = *cp++) { 549: if (!isdigit(c)) { 550: if (allints == YES) 551: return INT_BAD; 552: break; 553: } 554: c = c - '0'; 555: if (c >= base) 556: complain("You must specify in base %d.", base); 557: value = value * base + c; 558: } 559: *result = value * sign; 560: return INT_OKAY; 561: } 562: 563: int 564: ask_int(prompt, base) 565: char *prompt; 566: int base; 567: { 568: char *val = ask((char *) 0, prompt); 569: int value; 570: 571: if (chr_to_int(val, base, YES, &value) == INT_BAD) 572: complain("That's not a number!"); 573: return value; 574: } 575: 576: private void 577: vpr_aux(vp, buf) 578: register struct variable *vp; 579: char *buf; 580: { 581: switch (vp->v_flags & V_TYPEMASK) { 582: case V_BASE10: 583: sprintf(buf, "%d", *(vp->v_value)); 584: break; 585: 586: case V_BASE8: 587: sprintf(buf, "%o", *(vp->v_value)); 588: break; 589: 590: case V_BOOL: 591: sprintf(buf, (*(vp->v_value)) ? "on" : "off"); 592: break; 593: 594: case V_STRING: 595: case V_FILENAME: 596: sprintf(buf, "%s", (char *) vp->v_value); 597: break; 598: 599: case V_CHAR: 600: sprintf(buf, "%p", *(vp->v_value)); 601: break; 602: } 603: } 604: 605: void 606: PrVar() 607: { 608: struct variable *vp; 609: char prbuf[256]; 610: 611: if ((vp = (struct variable *) findvar(ProcFmt)) == 0) 612: return; 613: vpr_aux(vp, prbuf); 614: s_mess(": %f %s => %s", vp->Name, prbuf); 615: } 616: 617: void 618: SetVar() 619: { 620: struct variable *vp; 621: char *prompt; 622: 623: if ((vp = (struct variable *) findvar(ProcFmt)) == 0) 624: return; 625: prompt = sprint(": %f %s ", vp->Name); 626: 627: switch (vp->v_flags & V_TYPEMASK) { 628: case V_BASE10: 629: case V_BASE8: 630: { 631: int value; 632: 633: value = ask_int(prompt, ((vp->v_flags & V_TYPEMASK) == V_BASE10) 634: ? 10 : 8); 635: *(vp->v_value) = value; 636: break; 637: } 638: 639: case V_BOOL: 640: { 641: char *def = *(vp->v_value) ? "off" : "on", 642: *on_off; 643: int value; 644: 645: on_off = ask(def, prompt); 646: if (casecmp(on_off, "on") == 0) 647: value = ON; 648: else if (casecmp(on_off, "off") == 0) 649: value = OFF; 650: else 651: complain("Boolean variables must be ON or OFF."); 652: *(vp->v_value) = value; 653: #ifdef MAC 654: MarkVar(vp,-1,0); /* mark the menu item */ 655: #endif 656: s_mess("%s%s", prompt, value ? "on" : "off"); 657: break; 658: } 659: 660: case V_FILENAME: 661: { 662: char fbuf[FILESIZE]; 663: 664: (void) ask_file(prompt, (char *) vp->v_value, fbuf); 665: strcpy((char *) vp->v_value, fbuf); 666: break; 667: } 668: 669: case V_STRING: 670: { 671: char *str; 672: 673: /* Do_ask() so you can set string to "" if you so desire. */ 674: str = do_ask("\r\n", (int (*)()) 0, (char *) vp->v_value, prompt); 675: if (str == 0) 676: str = NullStr; 677: strcpy((char *) vp->v_value, str); 678: /* ... and hope there is enough room. */ 679: break; 680: } 681: case V_CHAR: 682: f_mess(prompt); 683: *(vp->v_value) = addgetc(); 684: break; 685: 686: } 687: if (vp->v_flags & V_MODELINE) 688: UpdModLine = YES; 689: if (vp->v_flags & V_CLRSCREEN) { 690: #ifdef IBMPC 691: setcolor(Fgcolor, Bgcolor); 692: #endif /* IBMPC */ 693: ClAndRedraw(); 694: } 695: if (vp->v_flags & V_TTY_RESET) 696: tty_reset(); 697: } 698: 699: /* Command completion - possible is an array of strings, prompt is 700: the prompt to use, and flags are ... well read jove.h. 701: 702: If flags are RET_STATE, and the user hits <return> what they typed 703: so far is in the Minibuf string. */ 704: 705: private char **Possible; 706: private int comp_value, 707: comp_flags; 708: 709: int 710: aux_complete(c) 711: { 712: int command, 713: length, 714: i; 715: 716: if (comp_flags & CASEIND) { 717: char *lp; 718: 719: for (lp = linebuf; *lp != '\0'; lp++) 720: #if (defined(IBMPC) || defined(MAC)) 721: lower(lp); 722: #else 723: if (isupper(*lp)) 724: *lp = tolower(*lp); 725: #endif 726: } 727: switch (c) { 728: case EOF: 729: comp_value = -1; 730: return 0; 731: 732: case '\r': 733: case '\n': 734: command = match(Possible, linebuf); 735: if (command >= 0) { 736: comp_value = command; 737: return 0; /* tells ask to stop */ 738: } 739: if (eolp() && bolp()) { 740: comp_value = NULLSTRING; 741: return 0; 742: } 743: if (comp_flags & RET_STATE) { 744: comp_value = command; 745: return 0; 746: } 747: if (InJoverc) 748: complain("[\"%s\" unknown]", linebuf); 749: rbell(); 750: break; 751: 752: case '\t': 753: case ' ': 754: { 755: int minmatch = 1000, 756: maxmatch = 0, 757: numfound = 0, 758: lastmatch = -1, 759: length = strlen(linebuf); 760: 761: for (i = 0; Possible[i] != 0; i++) { 762: int this_len; 763: 764: this_len = numcomp(Possible[i], linebuf); 765: maxmatch = max(maxmatch, this_len); 766: if (this_len >= length) { 767: if (numfound) 768: minmatch = min(minmatch, numcomp(Possible[lastmatch], Possible[i])); 769: else 770: minmatch = strlen(Possible[i]); 771: numfound += 1; 772: lastmatch = i; 773: if (strcmp(linebuf, Possible[i]) == 0) 774: break; 775: } 776: } 777: 778: if (numfound == 0) { 779: rbell(); 780: if (InJoverc) 781: complain("[\"%s\" unknown]", linebuf); 782: /* If we're not in the .joverc then 783: let's do something helpful for the 784: user. */ 785: if (maxmatch < length) { 786: char *cp; 787: 788: cp = linebuf + maxmatch; 789: *cp = 0; 790: Eol(); 791: } 792: break; 793: } 794: if (c != '\t' && numfound == 1) { 795: comp_value = lastmatch; 796: return 0; 797: } 798: null_ncpy(linebuf, Possible[lastmatch], minmatch); 799: Eol(); 800: if (minmatch == length) /* No difference */ 801: rbell(); 802: break; 803: } 804: 805: case '?': 806: if (InJoverc) 807: complain((char *) 0); 808: /* kludge: in case we're using UseBuffers, in which case 809: linebuf gets written all over */ 810: strcpy(Minibuf, linebuf); 811: length = strlen(Minibuf); 812: TOstart("Completion", TRUE); /* for now ... */ 813: for (i = 0; Possible[i]; i++) 814: if (numcomp(Possible[i], Minibuf) >= length) { 815: Typeout(Possible[i]); 816: if (TOabort != 0) 817: break; 818: } 819: 820: TOstop(); 821: break; 822: } 823: return !FALSE; 824: } 825: 826: int 827: complete(possible, prompt, flags) 828: register char *possible[]; 829: char *prompt; 830: { 831: Possible = possible; 832: comp_flags = flags; 833: (void) do_ask("\r\n \t?", aux_complete, NullStr, prompt); 834: return comp_value; 835: } 836: 837: int 838: match(choices, what) 839: register char **choices, 840: *what; 841: { 842: register int len; 843: int i, 844: found = 0, 845: save, 846: exactmatch = -1; 847: 848: len = strlen(what); 849: if (len == 0) 850: return NULLSTRING; 851: for (i = 0; choices[i]; i++) { 852: if (strncmp(what, choices[i], len) == 0) { 853: if (strcmp(what, choices[i]) == 0) 854: exactmatch = i; 855: save = i; 856: found += 1; /* found one */ 857: } 858: } 859: 860: if (found == 0) 861: save = ORIGINAL; 862: else if (found > 1) { 863: if (exactmatch != -1) 864: save = exactmatch; 865: else 866: save = AMBIGUOUS; 867: } 868: 869: return save; 870: } 871: 872: void 873: Source() 874: { 875: char *com, *getenv(), 876: buf[FILESIZE]; 877: 878: #ifndef MSDOS 879: sprintf(buf, "%s/.joverc", getenv("HOME")); 880: #else /* MSDOS */ 881: if (com = getenv("JOVERC")) 882: strcpy(buf, com); 883: else 884: strcpy(buf, Joverc); 885: #endif /* MSDOS */ 886: com = ask_file((char *) 0, buf, buf); 887: if (joverc(buf) == 0) 888: complain(IOerr("read", com)); 889: } 890: 891: void 892: BufPos() 893: { 894: register Line *lp = curbuf->b_first; 895: register int i, 896: dotline; 897: long dotchar, 898: nchars; 899: 900: for (i = nchars = 0; lp != 0; i++, lp = lp->l_next) { 901: if (lp == curline) { 902: dotchar = nchars + curchar; 903: dotline = i + 1; 904: } 905: nchars += length(lp) + (lp->l_next != 0); /* include the NL */ 906: } 907: 908: s_mess("[\"%s\" line %d/%d, char %D/%D (%d%%), cursor = %d/%d]", 909: filename(curbuf), dotline, i, dotchar, nchars, 910: (nchars == 0) ? 100 : (int) (((long) dotchar * 100) / nchars), 911: calc_pos(linebuf, curchar), 912: calc_pos(linebuf, strlen(linebuf))); 913: } 914: 915: #define IF_UNBOUND -1 916: #define IF_TRUE 1 917: #define IF_FALSE !IF_TRUE 918: 919: #ifndef MAC 920: int 921: do_if(cmd) 922: char *cmd; 923: { 924: #ifdef MSDOS 925: int status; 926: #else 927: int pid, 928: status; 929: #endif /* MSDOS */ 930: #ifndef MSDOS 931: 932: switch (pid = fork()) { 933: case -1: 934: complain("[Fork failed: if]"); 935: 936: case 0: 937: { 938: #endif /* MSDOS */ 939: char *args[12], 940: *cp = cmd, 941: **ap = args; 942: 943: *ap++ = cmd; 944: for (;;) { 945: if ((cp = index(cp, ' ')) == 0) 946: break; 947: *cp++ = '\0'; 948: *ap++ = cp; 949: } 950: *ap = 0; 951: 952: #ifndef MSDOS 953: close(0); /* we want reads to fail */ 954: /* close(1); but not writes or ioctl's 955: close(2); */ 956: #else /* MSDOS */ 957: if ((status = spawnvp(0, args[0], args)) < 0) 958: complain("[Spawn failed: if]"); 959: #endif /* MSDOS */ 960: 961: #ifndef MSDOS 962: (void) execvp(args[0], args); 963: _exit(-10); /* signals exec error (see below) */ 964: } 965: } 966: #ifdef IPROCS 967: sighold(SIGCHLD); 968: #endif 969: dowait(pid, &status); 970: #ifdef IPROCS 971: sigrelse(SIGCHLD); 972: #endif 973: if (status == -10) 974: complain("[Exec failed]"); 975: if (status < 0) 976: complain("[Exit %d]", status); 977: #endif /* MSDOS */ 978: return (status == 0); /* 0 means successful */ 979: } 980: #endif /* MAC */ 981: 982: int 983: joverc(file) 984: char *file; 985: { 986: char buf[LBSIZE], 987: lbuf[LBSIZE]; 988: int lnum = 0, 989: eof = FALSE; 990: jmp_buf savejmp; 991: int IfStatus = IF_UNBOUND; 992: File *fp; 993: 994: fp = open_file(file, buf, F_READ, !COMPLAIN, QUIET); 995: if (fp == NIL) 996: return NO; /* joverc returns an integer */ 997: 998: /* Catch any errors, here, and do the right thing with them, 999: and then restore the error handle to whoever did a setjmp 1000: last. */ 1001: 1002: InJoverc += 1; 1003: push_env(savejmp); 1004: if (setjmp(mainjmp)) { 1005: Buffer *savebuf = curbuf; 1006: 1007: SetBuf(do_select((Window *) 0, "RC errors")); 1008: ins_str(sprint("%s:%d:%s\t%s\n", pr_name(file, YES), lnum, lbuf, mesgbuf), NO); 1009: unmodify(); 1010: SetBuf(savebuf); 1011: Asking = 0; 1012: } 1013: if (!eof) do { 1014: eof = (f_gets(fp, lbuf, sizeof lbuf) == EOF); 1015: lnum += 1; 1016: if (lbuf[0] == '#') /* a comment */ 1017: continue; 1018: #ifndef MAC 1019: if (casencmp(lbuf, "if", 2) == 0) { 1020: char cmd[128]; 1021: 1022: if (IfStatus != IF_UNBOUND) 1023: complain("[Cannot have nested if's]"); 1024: if (LookingAt("if[ \t]*\\(.*\\)$", lbuf, 0) == 0) 1025: complain("[If syntax error]"); 1026: putmatch(1, cmd, sizeof cmd); 1027: IfStatus = do_if(cmd) ? IF_TRUE : IF_FALSE; 1028: continue; 1029: } else if (casencmp(lbuf, "else", 4) == 0) { 1030: if (IfStatus == IF_UNBOUND) 1031: complain("[Unexpected `else']"); 1032: IfStatus = !IfStatus; 1033: continue; 1034: } else if (casencmp(lbuf, "endif", 5) == 0) { 1035: if (IfStatus == IF_UNBOUND) 1036: complain("[Unexpected `endif']"); 1037: IfStatus = IF_UNBOUND; 1038: continue; 1039: } 1040: #endif 1041: if (IfStatus == IF_FALSE) 1042: continue; 1043: (void) strcat(lbuf, "\n"); 1044: Inputp = lbuf; 1045: while (*Inputp == ' ' || *Inputp == '\t') 1046: Inputp += 1; /* skip white space */ 1047: Extend(); 1048: } while (!eof); 1049: 1050: f_close(fp); 1051: pop_env(savejmp); 1052: Inputp = 0; 1053: Asking = 0; 1054: InJoverc -= 1; 1055: if (IfStatus != IF_UNBOUND) 1056: complain("[Missing endif]"); 1057: return 1; 1058: }