|
|
1.1 ! root 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 "fp.h" ! 10: #include "termcap.h" ! 11: #include "ctype.h" ! 12: #include "chars.h" ! 13: #include "disp.h" ! 14: #include "re.h" ! 15: ! 16: #if defined(JOB_CONTROL) || defined(IPROCS) ! 17: # include <signal.h> ! 18: #endif ! 19: ! 20: #ifdef MAC ! 21: # include "mac.h" ! 22: #else ! 23: # ifdef STDARGS ! 24: # include <stdarg.h> ! 25: # else ! 26: # include <varargs.h> ! 27: # endif ! 28: #endif ! 29: ! 30: #ifdef MSDOS ! 31: # include <process.h> ! 32: #endif ! 33: ! 34: private void ! 35: DefAutoExec proto((struct data_obj *(*proc)())); ! 36: ! 37: private int ! 38: match proto((char **, char *)); ! 39: ! 40: int InJoverc = 0; ! 41: ! 42: /* Auto execute code */ ! 43: ! 44: #define NEXECS 20 ! 45: ! 46: private struct { ! 47: char *a_pattern; ! 48: data_obj *a_cmd; ! 49: } AutoExecs[NEXECS]; /* must be initialized by system to 0 */ ! 50: ! 51: private int ExecIndex = 0; ! 52: ! 53: /* Command auto-execute. */ ! 54: ! 55: void ! 56: CAutoExec() ! 57: { ! 58: DefAutoExec(findcom); ! 59: } ! 60: ! 61: /* Macro auto-execute. */ ! 62: ! 63: void ! 64: MAutoExec() ! 65: { ! 66: DefAutoExec(findmac); ! 67: } ! 68: ! 69: private void ! 70: DefAutoExec(proc) ! 71: #if defined(MAC) || defined(IBMPC) ! 72: data_obj *(*proc)(); ! 73: #else ! 74: data_obj *(*proc) proto((char *)); ! 75: #endif ! 76: { ! 77: data_obj *d; ! 78: char *pattern; ! 79: int i; ! 80: ! 81: if (ExecIndex >= NEXECS) ! 82: complain("Too many auto-executes, max %d.", NEXECS); ! 83: if ((d = (*proc)(ProcFmt)) == 0) ! 84: return; ! 85: pattern = do_ask("\r\n", (int (*) proto((int))) 0, (char *) 0, ": %f %s ", ! 86: d->Name); ! 87: for (i = 0; i < ExecIndex; i++) { ! 88: if (AutoExecs[i].a_cmd == d) { ! 89: char *ipat = AutoExecs[i].a_pattern; ! 90: ! 91: if ((pattern == NULL || ipat == NULL)? ! 92: (pattern == ipat) : (strcmp(pattern, ipat) == 0)) ! 93: return; /* eliminate duplicates */ ! 94: } ! 95: } ! 96: AutoExecs[ExecIndex].a_pattern = copystr(pattern); ! 97: AutoExecs[ExecIndex].a_cmd = d; ! 98: ExecIndex += 1; ! 99: } ! 100: ! 101: /* DoAutoExec: NEW and OLD are file names, and if NEW and OLD aren't the ! 102: same kind of file (i.e., match the same pattern) or OLD is 0 and it ! 103: matches, OR if the pattern is 0 (none was specified) then, we execute ! 104: the command associated with that kind of file. */ ! 105: ! 106: void ! 107: DoAutoExec(new, old) ! 108: register char *new, ! 109: *old; ! 110: { ! 111: register int i; ! 112: ! 113: set_arg_value(1); ! 114: for (i = 0; i < ExecIndex; i++) ! 115: if ((AutoExecs[i].a_pattern == 0) || ! 116: ((new != 0 && LookingAt(AutoExecs[i].a_pattern, new, 0)) && ! 117: (old == 0 || !LookingAt(AutoExecs[i].a_pattern, old, 0)))) ! 118: ExecCmd(AutoExecs[i].a_cmd); ! 119: } ! 120: ! 121: int ! 122: addgetc() ! 123: { ! 124: int c; ! 125: ! 126: if (!InJoverc) { ! 127: Asking = strlen(mesgbuf); ! 128: c = getch(); ! 129: Asking = 0; ! 130: add_mess("%p ", c); ! 131: } else { ! 132: c = getch(); ! 133: if (c == '\n') ! 134: return EOF; /* this isn't part of the sequence */ ! 135: else if (c == '\\') { ! 136: if ((c = getch()) == LF) ! 137: complain("[Premature end of line]"); ! 138: } else if (c == '^') { ! 139: if ((c = getch()) == '?') ! 140: c = RUBOUT; ! 141: else if (isalpha(c) || strchr("@[\\]^_", c)) ! 142: c = CTL(c); ! 143: else ! 144: complain("[Unknown control character]"); ! 145: } ! 146: } ! 147: return c; ! 148: } ! 149: ! 150: void ! 151: Extend() ! 152: { ! 153: data_obj *d; ! 154: ! 155: if ((d = findcom(": ")) != NULL) ! 156: ExecCmd(d); ! 157: } ! 158: ! 159: /* Read a positive integer from CP. It must be in base BASE, and ! 160: complains if it isn't. If allints is nonzero, all the characters ! 161: in the string must be integers or we return -1; otherwise we stop ! 162: reading at the first nondigit. */ ! 163: ! 164: int ! 165: chr_to_int(cp, base, allints, result) ! 166: register char *cp; ! 167: int base, ! 168: allints; ! 169: register int *result; ! 170: { ! 171: register int c; ! 172: int value = 0, ! 173: sign; ! 174: ! 175: if ((c = *cp) == '-') { ! 176: sign = -1; ! 177: cp += 1; ! 178: } else ! 179: sign = 1; ! 180: while ((c = *cp++) != '\0') { ! 181: if (!isdigit(c)) { ! 182: if (allints == YES) ! 183: return INT_BAD; ! 184: break; ! 185: } ! 186: c = c - '0'; ! 187: if (c >= base) ! 188: complain("You must specify in base %d.", base); ! 189: value = value * base + c; ! 190: } ! 191: *result = value * sign; ! 192: return INT_OKAY; ! 193: } ! 194: ! 195: int ! 196: ask_int(prompt, base) ! 197: char *prompt; ! 198: int base; ! 199: { ! 200: char *val = ask((char *) 0, prompt); ! 201: int value; ! 202: ! 203: if (chr_to_int(val, base, YES, &value) == INT_BAD) ! 204: complain("That's not a number!"); ! 205: return value; ! 206: } ! 207: ! 208: void ! 209: vpr_aux(vp, buf) ! 210: register const struct variable *vp; ! 211: char *buf; ! 212: { ! 213: switch (vp->v_flags & V_TYPEMASK) { ! 214: case V_BASE10: ! 215: swritef(buf, "%d", *((int *) vp->v_value)); ! 216: break; ! 217: ! 218: case V_BASE8: ! 219: swritef(buf, "%o", *((int *) vp->v_value)); ! 220: break; ! 221: ! 222: case V_BOOL: ! 223: swritef(buf, (*((int *) vp->v_value)) ? "on" : "off"); ! 224: break; ! 225: ! 226: case V_STRING: ! 227: case V_FILENAME: ! 228: swritef(buf, "%s", vp->v_value); ! 229: break; ! 230: ! 231: case V_CHAR: ! 232: swritef(buf, "%p", *((int *) vp->v_value)); ! 233: break; ! 234: } ! 235: } ! 236: ! 237: void ! 238: PrVar() ! 239: { ! 240: struct variable *vp; ! 241: char prbuf[256]; ! 242: ! 243: if ((vp = (struct variable *) findvar(ProcFmt)) == 0) ! 244: return; ! 245: vpr_aux(vp, prbuf); ! 246: s_mess(": %f %s => %s", vp->Name, prbuf); ! 247: } ! 248: ! 249: void ! 250: SetVar() ! 251: { ! 252: struct variable *vp; ! 253: char *prompt; ! 254: ! 255: if ((vp = (struct variable *) findvar(ProcFmt)) == 0) ! 256: return; ! 257: prompt = sprint(": %f %s ", vp->Name); ! 258: ! 259: switch (vp->v_flags & V_TYPEMASK) { ! 260: case V_BASE10: ! 261: case V_BASE8: ! 262: { ! 263: int value; ! 264: ! 265: value = ask_int(prompt, ((vp->v_flags & V_TYPEMASK) == V_BASE10) ! 266: ? 10 : 8); ! 267: *((int *) vp->v_value) = value; ! 268: break; ! 269: } ! 270: ! 271: case V_BOOL: ! 272: { ! 273: char *def = *((int *) vp->v_value) ? "off" : "on", ! 274: *on_off; ! 275: int value; ! 276: ! 277: on_off = ask(def, prompt); ! 278: if (casecmp(on_off, "on") == 0) ! 279: value = ON; ! 280: else if (casecmp(on_off, "off") == 0) ! 281: value = OFF; ! 282: else ! 283: complain("Boolean variables must be ON or OFF."); ! 284: *((int *) vp->v_value) = value; ! 285: #ifdef MAC ! 286: MarkVar(vp,-1,0); /* mark the menu item */ ! 287: #endif ! 288: s_mess("%s%s", prompt, value ? "on" : "off"); ! 289: break; ! 290: } ! 291: ! 292: case V_FILENAME: ! 293: { ! 294: char fbuf[FILESIZE]; ! 295: ! 296: (void) ask_file(prompt, (char *) vp->v_value, fbuf); ! 297: strcpy((char *) vp->v_value, fbuf); ! 298: break; ! 299: } ! 300: ! 301: case V_STRING: ! 302: { ! 303: char *str; ! 304: ! 305: /* Do_ask() so you can set string to "" if you so desire. */ ! 306: str = do_ask("\r\n", (int (*) proto((int))) 0, (char *) vp->v_value, ! 307: prompt); ! 308: if (str == 0) ! 309: str = NullStr; ! 310: strcpy(vp->v_value, str); ! 311: /* ... and hope there is enough room. */ ! 312: break; ! 313: } ! 314: case V_CHAR: ! 315: f_mess(prompt); ! 316: *((int *) vp->v_value) = addgetc(); ! 317: break; ! 318: ! 319: } ! 320: if (vp->v_flags & V_MODELINE) ! 321: UpdModLine = YES; ! 322: if (vp->v_flags & V_CLRSCREEN) { ! 323: #ifdef IBMPC ! 324: setcolor(Fgcolor, Bgcolor); ! 325: #endif /* IBMPC */ ! 326: ClAndRedraw(); ! 327: } ! 328: if (vp->v_flags & V_TTY_RESET) ! 329: tty_reset(); ! 330: } ! 331: ! 332: /* Command completion - possible is an array of strings, prompt is ! 333: the prompt to use, and flags are ... well read jove.h. ! 334: ! 335: If flags are RET_STATE, and the user hits <return> what they typed ! 336: so far is in the Minibuf string. */ ! 337: ! 338: private char **Possible; ! 339: private int comp_value, ! 340: comp_flags; ! 341: ! 342: int ! 343: aux_complete(c) ! 344: int c; ! 345: { ! 346: int command, ! 347: i; ! 348: ! 349: if (comp_flags & CASEIND) { ! 350: char *lp; ! 351: ! 352: for (lp = linebuf; *lp != '\0'; lp++) ! 353: #if (defined(IBMPC) || defined(MAC)) ! 354: lower(lp); ! 355: #else ! 356: if (isupper(*lp)) ! 357: *lp = tolower(*lp); ! 358: #endif ! 359: } ! 360: switch (c) { ! 361: case EOF: ! 362: comp_value = -1; ! 363: return 0; ! 364: ! 365: case '\r': ! 366: case '\n': ! 367: command = match(Possible, linebuf); ! 368: if (command >= 0) { ! 369: comp_value = command; ! 370: return 0; /* tells ask to stop */ ! 371: } ! 372: if (eolp() && bolp()) { ! 373: comp_value = NULLSTRING; ! 374: return 0; ! 375: } ! 376: if (comp_flags & RET_STATE) { ! 377: comp_value = command; ! 378: return 0; ! 379: } ! 380: if (InJoverc) ! 381: complain("[\"%s\" unknown]", linebuf); ! 382: rbell(); ! 383: break; ! 384: ! 385: case '\t': ! 386: case ' ': ! 387: { ! 388: int minmatch = 1000, ! 389: maxmatch = 0, ! 390: numfound = 0, ! 391: lastmatch = -1, ! 392: len = strlen(linebuf); ! 393: ! 394: for (i = 0; Possible[i] != 0; i++) { ! 395: int this_len; ! 396: ! 397: this_len = numcomp(Possible[i], linebuf); ! 398: maxmatch = max(maxmatch, this_len); ! 399: if (this_len >= len) { ! 400: if (numfound) ! 401: minmatch = min(minmatch, numcomp(Possible[lastmatch], Possible[i])); ! 402: else ! 403: minmatch = strlen(Possible[i]); ! 404: numfound += 1; ! 405: lastmatch = i; ! 406: if (strcmp(linebuf, Possible[i]) == 0) ! 407: break; ! 408: } ! 409: } ! 410: ! 411: if (numfound == 0) { ! 412: rbell(); ! 413: if (InJoverc) ! 414: complain("[\"%s\" unknown]", linebuf); ! 415: /* If we're not in the .joverc then ! 416: let's do something helpful for the ! 417: user. */ ! 418: if (maxmatch < len) { ! 419: char *cp; ! 420: ! 421: cp = linebuf + maxmatch; ! 422: *cp = 0; ! 423: Eol(); ! 424: } ! 425: break; ! 426: } ! 427: if (c != '\t' && numfound == 1) { ! 428: comp_value = lastmatch; ! 429: return 0; ! 430: } ! 431: null_ncpy(linebuf, Possible[lastmatch], (size_t) minmatch); ! 432: Eol(); ! 433: if (minmatch == len) /* No difference */ ! 434: rbell(); ! 435: break; ! 436: } ! 437: ! 438: case '?': ! 439: { ! 440: int len; ! 441: ! 442: if (InJoverc) ! 443: complain((char *) 0); ! 444: /* kludge: in case we're using UseBuffers, in which case ! 445: linebuf gets written all over */ ! 446: strcpy(Minibuf, linebuf); ! 447: len = strlen(Minibuf); ! 448: TOstart("Completion", TRUE); /* for now ... */ ! 449: for (i = 0; Possible[i]; i++) ! 450: if (numcomp(Possible[i], Minibuf) >= len) { ! 451: Typeout(Possible[i]); ! 452: if (TOabort != 0) ! 453: break; ! 454: } ! 455: ! 456: TOstop(); ! 457: } ! 458: break; ! 459: } ! 460: return !FALSE; ! 461: } ! 462: ! 463: int ! 464: complete(possible, prompt, flags) ! 465: register char *possible[]; ! 466: char *prompt; ! 467: int flags; ! 468: { ! 469: /* protect static "Possible" from being overwritten due to recursion */ ! 470: if (InRealAsk) ! 471: complain((char *) NULL); ! 472: ! 473: Possible = possible; ! 474: comp_flags = flags; ! 475: (void) do_ask("\r\n \t?", aux_complete, NullStr, prompt); ! 476: return comp_value; ! 477: } ! 478: ! 479: private int ! 480: match(choices, what) ! 481: register char **choices, ! 482: *what; ! 483: { ! 484: register size_t len; ! 485: int i, ! 486: found = 0, ! 487: save, ! 488: exactmatch = -1; ! 489: ! 490: len = strlen(what); ! 491: if (len == 0) ! 492: return NULLSTRING; ! 493: for (i = 0; choices[i]; i++) { ! 494: if (strncmp(what, choices[i], len) == 0) { ! 495: if (strcmp(what, choices[i]) == 0) ! 496: exactmatch = i; ! 497: save = i; ! 498: found += 1; /* found one */ ! 499: } ! 500: } ! 501: ! 502: if (found == 0) ! 503: save = ORIGINAL; ! 504: else if (found > 1) { ! 505: if (exactmatch != -1) ! 506: save = exactmatch; ! 507: else ! 508: save = AMBIGUOUS; ! 509: } ! 510: ! 511: return save; ! 512: } ! 513: ! 514: void ! 515: Source() ! 516: { ! 517: extern char *getenv(); ! 518: char *com, ! 519: buf[FILESIZE]; ! 520: ! 521: #ifndef MSDOS ! 522: swritef(buf, "%s/.joverc", HomeDir); ! 523: #else /* MSDOS */ ! 524: if (com = getenv("JOVERC")) ! 525: strcpy(buf, com); ! 526: else ! 527: strcpy(buf, Joverc); ! 528: #endif /* MSDOS */ ! 529: com = ask_file((char *) 0, buf, buf); ! 530: if (joverc(buf) == 0) ! 531: complain(IOerr("read", com)); ! 532: } ! 533: ! 534: void ! 535: BufPos() ! 536: { ! 537: register Line *lp = curbuf->b_first; ! 538: register int i, ! 539: dotline; ! 540: long dotchar, ! 541: nchars; ! 542: ! 543: for (i = nchars = 0; lp != 0; i++, lp = lp->l_next) { ! 544: if (lp == curline) { ! 545: dotchar = nchars + curchar; ! 546: dotline = i + 1; ! 547: } ! 548: nchars += length(lp) + (lp->l_next != 0); /* include the NL */ ! 549: } ! 550: ! 551: s_mess("[\"%s\" line %d/%d, char %D/%D (%d%%), cursor = %d/%d]", ! 552: filename(curbuf), dotline, i, dotchar, nchars, ! 553: (nchars == 0) ? 100 : (int) (((long) dotchar * 100) / nchars), ! 554: calc_pos(linebuf, curchar), ! 555: calc_pos(linebuf, (int)strlen(linebuf))); ! 556: } ! 557: ! 558: #define IF_UNBOUND (-1) ! 559: #define IF_TRUE 1 ! 560: #define IF_FALSE (!IF_TRUE) ! 561: ! 562: #ifndef MAC ! 563: private int ! 564: do_if(cmd) ! 565: char *cmd; ! 566: { ! 567: #ifdef MSDOS ! 568: int status; ! 569: #else ! 570: int pid, ! 571: status; ! 572: #endif /* MSDOS */ ! 573: #ifndef MSDOS ! 574: ! 575: switch (pid = fork()) { ! 576: case -1: ! 577: complain("[Fork failed: if]"); ! 578: /*NOTREACHED*/ ! 579: ! 580: case 0: ! 581: { ! 582: #endif /* MSDOS */ ! 583: char *args[12], ! 584: *cp = cmd, ! 585: **ap = args; ! 586: ! 587: *ap++ = cmd; ! 588: for (;;) { ! 589: if ((cp = strchr(cp, ' ')) == 0) ! 590: break; ! 591: *cp++ = '\0'; ! 592: *ap++ = cp; ! 593: } ! 594: *ap = 0; ! 595: ! 596: #ifndef MSDOS ! 597: close(0); /* we want reads to fail */ ! 598: /* close(1); but not writes or ioctl's ! 599: close(2); */ ! 600: #else /* MSDOS */ ! 601: if ((status = spawnvp(0, args[0], args)) < 0) ! 602: complain("[Spawn failed: if]"); ! 603: #endif /* MSDOS */ ! 604: ! 605: #ifndef MSDOS ! 606: (void) execvp(args[0], (const char **)args); ! 607: _exit(-10); /* signals exec error (see below) */ ! 608: } ! 609: } ! 610: #ifdef IPROCS ! 611: SigHold(SIGCHLD); ! 612: #endif ! 613: dowait(pid, &status); ! 614: #ifdef IPROCS ! 615: SigRelse(SIGCHLD); ! 616: #endif ! 617: if (status == -10) ! 618: complain("[Exec failed]"); ! 619: if (status < 0) ! 620: complain("[Exit %d]", status); ! 621: #endif /* MSDOS */ ! 622: return (status == 0); /* 0 means successful */ ! 623: } ! 624: #endif /* MAC */ ! 625: ! 626: int ! 627: joverc(file) ! 628: char *file; ! 629: { ! 630: char buf[LBSIZE], ! 631: lbuf[LBSIZE]; ! 632: int lnum = 0, ! 633: eof = FALSE; ! 634: jmp_buf savejmp; ! 635: int IfStatus = IF_UNBOUND; ! 636: File *fp; ! 637: ! 638: fp = open_file(file, buf, F_READ, NO, YES); ! 639: if (fp == NIL) ! 640: return NO; /* joverc returns an integer */ ! 641: ! 642: /* Catch any errors, here, and do the right thing with them, ! 643: and then restore the error handle to whoever did a setjmp ! 644: last. */ ! 645: ! 646: InJoverc += 1; ! 647: push_env(savejmp); ! 648: if (setjmp(mainjmp)) { ! 649: Buffer *savebuf = curbuf; ! 650: ! 651: SetBuf(do_select((Window *) 0, "RC errors")); ! 652: ins_str(sprint("%s:%d:%s\t%s\n", pr_name(file, YES), lnum, lbuf, mesgbuf), NO); ! 653: unmodify(); ! 654: SetBuf(savebuf); ! 655: Asking = 0; ! 656: } ! 657: if (!eof) do { ! 658: eof = (f_gets(fp, lbuf, sizeof lbuf) == EOF); ! 659: lnum += 1; ! 660: if (lbuf[0] == '#') /* a comment */ ! 661: continue; ! 662: #ifndef MAC ! 663: if (casencmp(lbuf, "if", (size_t)2) == 0) { ! 664: char cmd[128]; ! 665: ! 666: if (IfStatus != IF_UNBOUND) ! 667: complain("[Cannot have nested if's]"); ! 668: if (LookingAt("if[ \t]*\\(.*\\)$", lbuf, 0) == 0) ! 669: complain("[If syntax error]"); ! 670: putmatch(1, cmd, sizeof cmd); ! 671: IfStatus = do_if(cmd) ? IF_TRUE : IF_FALSE; ! 672: continue; ! 673: } else if (casencmp(lbuf, "else", (size_t)4) == 0) { ! 674: if (IfStatus == IF_UNBOUND) ! 675: complain("[Unexpected `else']"); ! 676: IfStatus = !IfStatus; ! 677: continue; ! 678: } else if (casencmp(lbuf, "endif", (size_t)5) == 0) { ! 679: if (IfStatus == IF_UNBOUND) ! 680: complain("[Unexpected `endif']"); ! 681: IfStatus = IF_UNBOUND; ! 682: continue; ! 683: } ! 684: #endif ! 685: if (IfStatus == IF_FALSE) ! 686: continue; ! 687: (void) strcat(lbuf, "\n"); ! 688: Inputp = lbuf; ! 689: while (*Inputp == ' ' || *Inputp == '\t') ! 690: Inputp += 1; /* skip white space */ ! 691: Extend(); ! 692: } while (!eof); ! 693: ! 694: f_close(fp); ! 695: pop_env(savejmp); ! 696: Inputp = 0; ! 697: Asking = 0; ! 698: InJoverc -= 1; ! 699: if (IfStatus != IF_UNBOUND) ! 700: complain("[Missing endif]"); ! 701: return 1; ! 702: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.