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