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: }