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

Defined functions

Apropos defined in line 463; used 4 times
BindAKey defined in line 130; used 4 times
BindMac defined in line 136; used 4 times
BindSomething defined in line 246; used 4 times
BindWMap defined in line 216; used 4 times
BufPos defined in line 891; used 4 times
CAutoExec defined in line 67; used 4 times
DefAutoExec defined in line 83; used 4 times
DescBindings defined in line 353; used 4 times
DescCom defined in line 286; used 5 times
DescMap defined in line 365; used 4 times
DescWMap defined in line 264; used 4 times
DoAutoExec defined in line 115; used 3 times
Extend defined in line 520; used 5 times
IsPrefix defined in line 146; used 9 times
KeyDesc defined in line 279; used 4 times
MAutoExec defined in line 75; used 4 times
PrVar defined in line 605; used 4 times
SetVar defined in line 617; used 4 times
Source defined in line 872; used 4 times
UnbindC defined in line 168; used 4 times
addgetc defined in line 187; used 8 times
ask_int defined in line 563; used 6 times
aux_complete defined in line 709; used 3 times
do_if defined in line 920; used 3 times
fb_aux defined in line 415; used 4 times
find_binds defined in line 401; used 5 times
joverc defined in line 982; used 6 times
match defined in line 837; used 3 times
vpr_aux defined in line 576; used 4 times

Defined variables

ExecIndex defined in line 63; used 6 times
InJoverc defined in line 49; used 7 times
Possible defined in line 705; used 12 times
comp_flags defined in line 707; used 3 times
comp_value defined in line 706; used 6 times
private defined in line 705; never used

Defined macros

IF_FALSE defined in line 917; used 2 times
IF_TRUE defined in line 916; used 2 times
IF_UNBOUND defined in line 915; used 6 times
NEXECS defined in line 56; used 3 times
private defined in line 45; used 10 times
Last modified: 1988-08-11
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 6166
Valid CSS Valid XHTML 1.0 Strict