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

Defined functions

Apropos defined in line 390; used 2 times
BindAKey defined in line 94; used 2 times
BindMac defined in line 99; used 2 times
BindSomething defined in line 205; used 2 times
BindWMap defined in line 183; used 2 times
BufPos defined in line 772; used 2 times
CAutoExec defined in line 38; used 2 times
DefAutoExec defined in line 52; used 2 times
DescBindings defined in line 292; used 2 times
DescCom defined in line 238; used 3 times
DescMap defined in line 301; used 2 times
DescWMap defined in line 218; used 2 times
DoAutoExec defined in line 77; used 1 times
Extend defined in line 446; used 3 times
IsPrefix defined in line 108; used 8 times
KeyDesc defined in line 232; used 2 times
MAutoExec defined in line 45; used 2 times
PrVar defined in line 519; used 2 times
SetVar defined in line 530; used 2 times
Source defined in line 761; used 2 times
UnbindC defined in line 134; used 2 times
addgetc defined in line 154; used 5 times
ask_int defined in line 479; used 1 times
aux_complete defined in line 606; used 1 times
chr_to_int defined in line 459; used 5 times
do_if defined in line 795; used 1 times
fb_aux defined in line 346; used 2 times
find_binds defined in line 332; used 3 times
joverc defined in line 842; used 3 times
match defined in line 727; used 1 times
unbind_aux defined in line 126; used 1 times
vpr_aux defined in line 491; used 2 times

Defined variables

ExecIndex defined in line 34; used 6 times
InJoverc defined in line 20; used 8 times
Possible defined in line 602; used 12 times
comp_flags defined in line 604; used 2 times
comp_value defined in line 603; used 6 times

Defined macros

IF_FALSE defined in line 793; used 2 times
IF_TRUE defined in line 792; used 2 times
IF_UNBOUND defined in line 791; used 6 times
NEXECS defined in line 27; used 3 times
Last modified: 1986-03-31
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2936
Valid CSS Valid XHTML 1.0 Strict