1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
   2: 
   3: /* $Header: getc.c,v 2.5 85/08/22 16:02:44 timo Exp $ */
   4: 
   5: /* B editor -- read key definitions from file */
   6: 
   7: #include "b.h"
   8: #include "feat.h"
   9: #ifdef LINDA
  10: #include "b1mem.h"
  11: #define syserr EDsyserr
  12: #else !LINDA
  13: #define freemem(p) free(p)
  14: #endif !LINDA
  15: #include "file.h"
  16: #include "keys.h"
  17: 
  18: #include <ctype.h>
  19: 
  20: extern bool dflag;
  21: 
  22: #define ESC '\033'
  23: 
  24: /*
  25: This file contains a little parser for key definition files.
  26: To allow sufficient freedom in preparing such a file, a simple
  27: grammar has been defined according to which the file is parsed.
  28: The parsing process is extremely simple, as it can be done
  29: top-down using recursive descent.
  30: 
  31: 
  32: Lexical conventions:
  33: 
  34: - Blanks between lexical symbols are gnored.
  35: - From '#' to end of line is comment (except inside strings).
  36: - Strings are delimited by single or double quotes and
  37:   use the same escape sequences as C strings, plus:
  38:   \e or \E means an ESCape ('\033').
  39: - Command names are like C identifiers ([a-zA-Z_][a-zA-Z0-9_]*).
  40:   Upper/lower case distinction is significant.
  41: - numbers are octal or decimal integers in C-style (leading zero means octal)
  42: - After '^' a character is expected, this must be a letter or one of @^_[]\ .
  43: 
  44: Syntax in modified BNF ([] mean 0 or 1, * means 0 or more, + means 1 or more):
  45: 
  46:    file: line*
  47:    line: [def] [comment]
  48:    def: commandname '=' rhs
  49:    rhs: item+
  50:    item: string | '^' character | number
  51: 
  52: 
  53: Notes:
  54: 
  55: - A definition for command "term_init" defines a string to be sent
  56:   TO the terminal at initialization time, e.g. to set programmable
  57:   function key definitions.  Similar for "term_done" on exiting.
  58: - Command names are  conventional editor commands.
  59: 
  60: */
  61: 
  62: 
  63: #ifndef LINDA
  64: /* Defines subroutine that used to be in the support levels: */
  65: 
  66: Hidden string getmem(nbytes)
  67:     unsigned nbytes;
  68: {
  69:     string malloc();
  70:     string pointer= malloc(nbytes);
  71: 
  72:     if (pointer == NULL)
  73:         syserr("memory full in initkeys");
  74:     return pointer;
  75: }
  76: 
  77: Hidden string regetmem(pp, nbytes)
  78:     string *pp;
  79:     unsigned nbytes;
  80: {
  81:     *pp= realloc(*pp, nbytes);
  82:     if (*pp == NULL)
  83:         syserr("memory full in initkeys (regetmem)");
  84: }
  85: #endif !LINDA
  86: 
  87: 
  88: #define COMMENT '#' /* Not B-like but very UNIX-like */
  89: #define MAXDEFS 100
  90: 
  91: Hidden FILE *fp; /* File from which to read */
  92: Hidden string filename; /* File name for error messages */
  93: Hidden char nextc; /* Next character to be analyzed */
  94: Hidden bool eof; /* EOF seen? */
  95: Hidden int lcount; /* Current line number */
  96: Hidden bool errcount; /* Number of errors detected */
  97: 
  98: 
  99: struct tabent {
 100:     int code;
 101:     string name;
 102:     string def;
 103: };
 104: 
 105: /* Table of key definitions, mostly filled by reading definitions from a file.
 106:    The "I" macro has two arguments: the default for termcap and that for
 107:    the IBM PC.  It expands to either depending on whether IBMPC is defined.
 108:    'def' fields initialized with a string starting with '=' are termcap names,
 109:    and are replaced by the corresponding termcap entry (NULL if none).
 110:    On the IBM PC, 'extended codes' are by convention a null character
 111:    followed by another character (usually the scan code).  Since the null
 112:    character is rather unsuitable for use in C strings, we use \377 (hex FF)
 113:    instead, a code which has no assigned graphic is the extended IBM PC
 114:    character set.  E.g., F1 is 0-59, which we encode as \377\073 (since
 115:    \073 is octal for 59 decimal).  For the exact codes, see for instance the
 116:    BASIC 2.0 manual, appendix G, or the XT Technical Reference, page 2-14.
 117: */
 118: 
 119: #ifdef IBMPC
 120: #define I(tc, ibm) ibm
 121: #else !IBMPC
 122: #define I(tc, ibm) tc
 123: #endif !IBMPC
 124: 
 125: Visible struct tabent deftab[MAXDEFS] = {
 126:     /* General rule:
 127: 	   unix => ctrl-x
 128: 	   IBM  => alt-x
 129: 	   where x is first letter of command name
 130: 	*/
 131:     {0377, "ignore", NULL}, /* Entry to ignore a key */
 132:     {COPY, "copy", I(NULL, "\377\056")},
 133:     {DELETE, "delete", I(NULL, "\377\040")},
 134:     {DELETE, "delete", I(NULL, "\377\123")}, /* IBM DEL key */
 135:     {ACCEPT, "accept", I(NULL, "\377\022")}, /* ^E, alt-E */
 136:     {ACCEPT, "end", I(NULL, "\377\117")}, /* IBM END key */
 137:     {'\t', "tab", NULL}, /* = ACCEPT in Bed, insert tab in Linda */
 138:     {UNDO, "undo"}, /* Always backspace = ^H */
 139:     {REDRAW, "redraw", I(NULL, "\377\046")}, /* ^L, alt-L */
 140:     {REDRAW, "look"},
 141:     {RETURN, "newline"}, /* Always ^M */
 142:     {REDO, "redo", I(NULL, "\177")}, /* IBM ctrl-BS = ASCII 177 (DEL) */
 143:     {EXIT, "exit", I(NULL, "\377\055")}, /* ^X, alt-X */
 144: 
 145: #ifdef RECORDING
 146:     /*
 147: 	 * The IBM-PC has a problem here in ANSI.SYS mode: ctrl-P is
 148: 	 * unusable because it means Print Screen, and alt-R is unusable
 149: 	 * because it transmits 0, 19 but 19 is ctrl-S which means stop
 150: 	 * output :-(.
 151: 	 * The only reasonable place to put the things would then be on
 152: 	 * function keys.  You should do this in the key definitions file. (?)
 153: 	 */
 154:     {PLAYBACK, "play", I(NULL, "\377\031")},
 155:     {PLAYBACK, "playback", I(NULL, "\377\031")},
 156:     {RECORD, "record", I(NULL, "\377\023")},
 157: #endif RECORDING
 158: 
 159: #ifdef LINDA
 160:     {BFIND, "bfind", I(NULL, "\377\060")},
 161:     {FIND, "find", I(NULL, "\377\041")},
 162:     {GLOBAL, "global", I(NULL, "\377\042")},
 163:     {JOIN, "join", I(NULL, "\377\044")},
 164:     {TOGGLE, "toggle", I(NULL, "\377\024")},
 165:     {YANK, "yank", I(NULL, "\377\025")},
 166:     {LITERAL, "literal", I(NULL, "\377\057")}, /* ^V, alt-V */
 167: #endif LINDA
 168: 
 169:     {WIDEN, "widen", I("=k1", "\377\073")}, /* IBM F1 */
 170:     {NARROW, "narrow", I("=k2", "\377\075")}, /* IBM F3 (!!!) */
 171:     {NARROW, "first"},
 172:     {RNARROW, "rnarrow", I("=k3", "\377\076")}, /* IBM F4 (!!!) */
 173:     {RNARROW, "last"},
 174:     {EXTEND, "extend", I("=k4", "\377\074")}, /* IBM F2 (!!!) */
 175:     {UPARROW, "up", I("=ku", "\377\110")},
 176:     {UPLINE, "upline", I("=k5", "\377\110")},
 177:     {LEFTARROW, "left", I("=kl", "\377\113")},
 178:     {PREVIOUS, "previous", I("=k6", NULL)},
 179:     {RITEARROW, "right", I("=kr", "\377\115")},
 180:     {NEXT, "next", I("=k7", NULL)},
 181:     {DOWNARROW, "down", I("=kd", "\377\120")},
 182:     {DOWNLINE, "downline", I("=k8", "\377\120")},
 183: 
 184:     {GOTO, "goto", I("\033g", NULL)}, /* Doesn't exist on IBM */
 185: #ifdef HELPFUL
 186:     {HELP, "help", I("\033?", "\377\104")}, /* ESC ?, IBM F10 */
 187: #endif HELPFUL
 188: 
 189:     {0, "term_init", I("=ks", NULL)},
 190:     {0, "term_done", I("=ke", NULL)},
 191: };
 192: 
 193: #undef I
 194: 
 195: Hidden int ndefs;
 196: 
 197: 
 198: Hidden Procedure err(fmt, arg)
 199:     string fmt, arg;
 200: {
 201:     if (errcount == 0)
 202:         fprintf(stderr, "Errors in key definitions file:\n");
 203:     ++errcount;
 204:     fprintf(stderr, "%s, line %d: ", filename, lcount);
 205:     fprintf(stderr, fmt, arg);
 206:     fprintf(stderr, "\n");
 207: }
 208: 
 209: Hidden Procedure adv()
 210: {
 211:     int c;
 212: 
 213:     if (eof)
 214:         return;
 215:     c= getc(fp);
 216:     if (c == EOF) {
 217:         nextc= '\n';
 218:         eof= Yes;
 219:     }
 220:     else {
 221:         nextc= c;
 222:         if (c == '\n')
 223:             ++lcount;
 224:     }
 225: }
 226: 
 227: Hidden Procedure skipsp()
 228: {
 229:     while (nextc == ' ' || nextc == '\t')
 230:         adv();
 231: }
 232: 
 233: Hidden int lookup(name)
 234:     string name;
 235: {
 236:     int i;
 237: 
 238:     for (i= 0; i < ndefs; ++i) {
 239:         if (deftab[i].name != NULL && strcmp(name, deftab[i].name) == 0)
 240:             return i;
 241:     }
 242:     return -1;
 243: }
 244: 
 245: Hidden Procedure store(code, name, def)
 246:     int code;
 247:     string name;
 248:     string def;
 249: {
 250:     struct tabent *d, *last= deftab+ndefs;
 251:     string p, q;
 252: 
 253:     /* Undefine conflicting definitions.  Conflicts arise
 254: 	   when a command definition is an initial subsequence
 255: 	   of another, or vice versa.  Key definitions (code < 0)
 256: 	   are not undefined. */
 257:     if (code > 0) {
 258:         for (d= deftab; d < last; ++d) {
 259:             if (d->code >= 0 && d->def != NULL) {
 260:                 for (p= def, q= d->def; *p == *q; ++p, ++q) {
 261:                     if (*p == '\0' || *q == '\0') {
 262:                         d->def= NULL;
 263:                         break;
 264:                     }
 265:                 }
 266:             }
 267:         }
 268:     }
 269: 
 270:     /* Find a free slot with the same code and NULL definition */
 271:     /* (For code == 0, the name must match instead of the code,
 272: 	   and the definition need not be NULL) */
 273:     for (d= deftab; d < last; ++d) {
 274:         if (code == 0 ? strcmp(name, d->name) == 0
 275:             : (d->code == code && d->def == NULL))
 276:             break;
 277:     }
 278:     if (d == last) { /* Extend definition table */
 279:         if (ndefs >= MAXDEFS) {
 280:             err("Too many key definitions", "");
 281:             return;
 282:         }
 283:         ++ndefs;
 284:         d->code= code;
 285:         d->name= name;
 286:     }
 287:     d->def= def;
 288: }
 289: 
 290: Hidden string savestr(s)
 291:     string s;
 292: {
 293:     string new;
 294: 
 295:     new= getmem((unsigned) (strlen(s) + 1));
 296:     strcpy(new, s);
 297:     return new;
 298: }
 299: 
 300: Hidden Procedure append(to, item)
 301:     string *to, item;
 302: {
 303:     int len= strlen(*to) + strlen(item) + 1;
 304:     regetmem(to, len);
 305:     strcat(*to, item);
 306: }
 307: 
 308: Hidden string getname()
 309: {
 310:     char buffer[20];
 311:     string bp;
 312: 
 313:     if (!isalpha(nextc) && nextc != '_') {
 314:         err("No name where expected", "");
 315:         return NULL;
 316:     }
 317:     for (bp= buffer; isalnum(nextc) || nextc == '_'; ) {
 318:         if (bp < buffer + sizeof buffer - 1)
 319:             *bp++ = nextc;
 320:         adv();
 321:     }
 322:     *bp= '\0';
 323:     return savestr(buffer);
 324: }
 325: 
 326: Hidden int getnumber()
 327: {
 328:     int base= (nextc == '0') ? 8 : 10;
 329:     int i= 0;
 330:     int d;
 331: 
 332:     for (;; adv()) {
 333:         d= nextc-'0';
 334:         if (d < 0 || d > 9)
 335:             break;
 336:         if (d > base) {
 337:             err("8 or 9 in octal number", "");
 338:             return 0;
 339:         }
 340:         i= i*base + d;
 341:     }
 342:     return i;
 343: }
 344: 
 345: Hidden string getstring()
 346: {
 347:     char buf[256]; /* Arbitrary limit */
 348:     char quote= nextc;
 349:     char c;
 350:     int len= 0;
 351: 
 352:     adv();
 353:     while (nextc != quote) {
 354:         if (nextc == '\n') {
 355:             err("closing string quote not found", "");
 356:             return NULL;
 357:         }
 358:         if (nextc != '\\') {
 359:             c= nextc;
 360:             adv();
 361:         }
 362:         else {
 363:             adv();
 364:             switch (nextc) {
 365: 
 366:             case 'r': c= '\r'; adv(); break;
 367:             case 'n': c= '\n'; adv(); break;
 368:             case 'b': c= '\b'; adv(); break;
 369:             case 't': c= '\t'; adv(); break;
 370:             case 'f': c= '\f'; adv(); break;
 371: 
 372:             case 'E':
 373:             case 'e': c= ESC; adv(); break;
 374: 
 375:             case '0': case '1': case '2': case '3':
 376:             case '4': case '5': case '6': case '7':
 377:                 c= nextc-'0';
 378:                 adv();
 379:                 if (nextc >= '0' && nextc < '8') {
 380:                     c= 8*c + nextc-'0';
 381:                     adv();
 382:                     if (nextc >= '0' && nextc < '8') {
 383:                         c= 8*c + nextc-'0';
 384:                         adv();
 385:                     }
 386:                 }
 387:                 break;
 388: 
 389:             default: c=nextc; adv(); break;
 390: 
 391:             }
 392:         }
 393:         if (len >= sizeof buf) {
 394:             err("string too long", "");
 395:             return NULL;
 396:         }
 397:         buf[len++]= c;
 398:     }
 399:     adv();
 400:     buf[len]= '\0';
 401:     return savestr(buf);
 402: }
 403: 
 404: Hidden string getitem()
 405: {
 406:     char buf[2];
 407:     string keyname;
 408:     int i;
 409: 
 410:     switch (nextc) {
 411:     case '"':
 412:     case '\'':
 413:         return getstring();
 414:     case '^':
 415:         adv();
 416:         if (isalpha(nextc) || index("@^_[]\\?", nextc)) {
 417:             if (nextc == '?')
 418:                 buf[0]= '\177';
 419:             else
 420:                 buf[0]= nextc & 037;
 421:             buf[1]= '\0';
 422:             adv();
 423:             return savestr(buf);
 424:         }
 425:         err("Invalid character after '^'", "");
 426:         return NULL;
 427:     default:
 428:         if (isdigit(nextc)) {
 429:             buf[0]= getnumber();
 430:             buf[1]= '\0';
 431:             return savestr(buf);
 432:         }
 433:         if (isalpha(nextc) || nextc == '_') {
 434:             keyname= getname(); /* Cannot fail */
 435:             if (strlen(keyname) == 1)
 436:                 return savestr(keyname);
 437:                 /* Single letters stand for themselves */
 438:             i= lookup(keyname);
 439:             if (i < 0 || deftab[i].code <= 0) {
 440:                 err("%s: not a key name", keyname);
 441:                 freemem(keyname);
 442:                 return NULL;
 443:             }
 444:             else if (deftab[i].def == NULL) {
 445:                 err("%s: undefined key", keyname);
 446:                 freemem(keyname);
 447:                 return NULL;
 448:             }
 449:             else
 450:                 return savestr(deftab[i].def);
 451:         }
 452:         err("Invalid item", "");
 453:         return NULL;
 454:     }
 455: }
 456: 
 457: Hidden string getrhs()
 458: {
 459:     string first, item;
 460: 
 461:     skipsp();
 462:     first= getitem();
 463:     if (first != NULL) {
 464:         for (;;) {
 465:             skipsp();
 466:             if (nextc == '\n' || nextc == COMMENT)
 467:                 break;
 468:             item= getitem();
 469:             if (item == NULL) {
 470:                 freemem(first);
 471:                 return NULL;
 472:             }
 473:             append(&first, item);
 474:             freemem(item);
 475:         }
 476:     }
 477:     return first;
 478: }
 479: 
 480: Hidden Procedure getdef()
 481: {
 482:     string name;
 483:     int key;
 484:     string rhs;
 485: 
 486:     name= getname();
 487:     if (name == NULL)
 488:         return;
 489:     skipsp();
 490:     if (nextc != '=') {
 491:         err("Command name %s not followed by '='", name);
 492:         return;
 493:     }
 494:     key= lookup(name);
 495:     if (key < 0) {
 496:         err("Unknown command: %s", name);
 497:         return;
 498:     }
 499:     if (deftab[key].code < 0) {
 500:         err("No redefinition of %s allowed", name);
 501:         return;
 502:     }
 503:     adv();
 504:     rhs= getrhs();
 505:     if (rhs != NULL)
 506:         store(deftab[key].code, name, rhs);
 507: }
 508: 
 509: Hidden Procedure getline()
 510: {
 511:     adv();
 512:     skipsp();
 513:     if (nextc != COMMENT && nextc != '\n')
 514:         getdef();
 515:     while (nextc != '\n')
 516:         adv();
 517: }
 518: 
 519: #ifndef NDEBUG
 520: Hidden Procedure dump(where)
 521:     string where;
 522: {
 523:     int i;
 524:     string s;
 525: 
 526:     printf("\nDump of key definitions %s.\n\n", where);
 527:     printf("Code    Name            Definition\n");
 528:     for (i= 0; i < ndefs; ++i) {
 529:         printf("%04o    ", deftab[i].code);
 530:         if (deftab[i].name != NULL)
 531:             printf("%-15s ", deftab[i].name);
 532:         else
 533:             printf("%16s", "");
 534:         s= deftab[i].def;
 535:         if (s != NULL) {
 536:             for (; *s != '\0'; ++s) {
 537:                 if (isascii(*s) && (isprint(*s) || *s == ' '))
 538:                     fputc(*s, stdout);
 539:                 else
 540:                     printf("\\%03o", *s&0377);
 541:             }
 542:         }
 543:         printf("\n");
 544:     }
 545:     fflush(stdout);
 546: }
 547: #endif !NDEBUG
 548: 
 549: Hidden Procedure countdefs()
 550: {
 551:     struct tabent *d;
 552: 
 553:     d= deftab;
 554:     while (d->name != NULL || d->code != 0 || d->def != NULL) {
 555:         ++d;
 556:         if (d >= deftab+MAXDEFS)
 557:             syserr("too many predefined keys");
 558:     }
 559:     ndefs= d-deftab;
 560: }
 561: 
 562: Hidden Procedure process()
 563: {
 564:     errcount= 0;
 565:     lcount= 1;
 566:     eof= No;
 567:     do {
 568:         getline();
 569:     } while (!eof);
 570: }
 571: 
 572: Hidden bool try(dir, file, type)
 573:     string dir, file, type;
 574: {
 575:     char buffer[200];
 576: 
 577: #ifdef IBMPC
 578:     sprintf(buffer, "%.150s\\%.9s%.3s", dir, file, type);
 579: #else !IBMPC
 580:     sprintf(buffer, "%.150s/%.20s%.20s", dir, file, type);
 581: #endif !IBMPC
 582:     fp= fopen(buffer, "r");
 583:     if (fp == NULL)
 584:         return No;
 585:     filename= buffer;
 586:     process();
 587:     fclose(fp);
 588: #ifndef NDEBUG
 589:     if (dflag)
 590:         dump("after try");
 591: #endif NDEBUG
 592:     return Yes;
 593: }
 594: 
 595: #ifndef IBMPC
 596: Hidden Procedure readtermcap()
 597: {
 598:     string tgetstr();
 599:     char buffer[1024]; /* Constant dictated by termcap manual entry */
 600:     static char area[1024];
 601:     string endarea= area;
 602:     string anentry;
 603:     struct tabent *d, *last;
 604: 
 605:     switch (tgetent(buffer, getenv("TERM"))) {
 606: 
 607:     default:
 608:         fprintf(stderr, "*** Bad tgetent() return value.\n");
 609:         /* Fall through */
 610:     case -1:
 611:         fprintf(stderr, "*** Can't read termcap.\n");
 612:         /* Fall through again */
 613:     case 0:
 614:         fprintf(stderr, "*** No description for your terminal.\n");
 615:         exit(1);
 616: 
 617:     case 1:
 618:         break;
 619:     }
 620:     last= deftab+ndefs;
 621:     for (d= deftab; d < last; ++d) {
 622:         if (d->def != NULL && d->def[0] == '=') {
 623:             anentry= tgetstr(d->def+1, &endarea);
 624:             if (anentry != NULL && anentry[0] != '\0')
 625:                 d->def= anentry;
 626:             else
 627:                 d->def= NULL;
 628:         }
 629:     }
 630: }
 631: #endif !IBMPC
 632: 
 633: Visible Procedure initkeys()
 634: {
 635:     string term= NULL;
 636: 
 637:     countdefs();
 638: #ifndef NDEBUG
 639:     if (dflag)
 640:         dump("before termcap");
 641: #endif NDEBUG
 642: #ifndef IBMPC
 643:     readtermcap();
 644: #ifndef NDEBUG
 645:     if (dflag)
 646:         dump("after termcap");
 647: #endif NDEBUG
 648:     term= getenv("TERM");
 649:     if (term != NULL && term[0] == '\0')
 650:         term= NULL;
 651: #endif !IBMPC
 652: #ifdef DEBUG
 653:     /* Try in the current directory. Only for debugging porpoises. */
 654:     if (term != NULL)
 655:         if (try(".", keyfile, term)) return;
 656: #endif DEBUG
 657:     if (term != NULL) {
 658:         if (try(homedir, keyfile, term)) return;
 659:         if (try(libdir, keyfile, term)) return;
 660:     }
 661: #ifdef DEBUG
 662:     if (try(".", keyfile, deftype)) return;
 663: #endif DEBUG
 664:     if (try(homedir, keyfile, deftype)) return;
 665:     if (try(libdir, keyfile, deftype)) return;
 666: #ifndef NDEBUG
 667:     printf("[No key definitions file found, using defaults.]\n");
 668: #endif !NDEBUG
 669: }
 670: 
 671: 
 672: /* Output a named string to the terminal */
 673: 
 674: Hidden Procedure outstring(name)
 675:     string name;
 676: {
 677:     int i= lookup(name);
 678:     string def;
 679: 
 680:     if (i >= 0 && (def= deftab[i].def) != NULL)
 681:         fputs(def, stdout);
 682: }
 683: 
 684: 
 685: /* Output the terminal's initialization sequence, if any. */
 686: 
 687: Visible Procedure
 688: initgetc()
 689: {
 690:     outstring("term_init");
 691: }
 692: 
 693: 
 694: /* Output a sequence, if any, to return the terminal to a 'normal' state. */
 695: 
 696: Visible Procedure endgetc()
 697: {
 698:     outstring("term_done");
 699: }
 700: 
 701: 
 702: /* Read a command from the keyboard, decoding composite key definitions. */
 703: 
 704: #ifndef IBMPC
 705: /* Strip high bit from input characters (matters only on PWB systems?) */
 706: #define getch() (getchar() & 0177)
 707: #endif !IBMPC
 708: 
 709: Visible int inchar()
 710: {
 711:     int c;
 712:     struct tabent *d, *last;
 713:     char buffer[100];
 714:     int len;
 715: 
 716:     c= getch();
 717:     if (c == EOF)
 718:         return c;
 719: #ifdef IBMPC
 720:     if (c == 0)
 721:         c= 0377;
 722: #endif IBMPC
 723:     last= deftab+ndefs;
 724:     for (d= deftab; d < last; ++d) {
 725:         if (d->code > 0 && d->def != NULL && c == (d->def[0] & 0377))
 726:             break;
 727:     }
 728:     if (d == last) {
 729:         if (c == ESC) {
 730:             /* Kludge to make ESC-char by default equal to
 731: 			   char|MASK -- the command definitions do the rest:
 732: 			   e.g. WIDEN is 'w'|MASK, so ESC-w means WIDEN. */
 733:             c= getch();
 734:             if (c == EOF)
 735:                 return EOF;
 736:             return (c&0177) | MASK;
 737:         }
 738:         return c;
 739:     }
 740:     if (d->def[1] == '\0')
 741:         return d->code;
 742:     buffer[0]= c;
 743:     len= 1;
 744:     for (;;) {
 745:         c= getch();
 746:         if (c == EOF)
 747:             return EOF;
 748:         buffer[len]= c;
 749:         if (len < sizeof buffer - 1)
 750:             ++len;
 751:         for (d= deftab; d < last; ++d) {
 752:             if (d->code > 0 && d->def != NULL
 753:                 && strncmp(buffer, d->def, len) == 0)
 754:                 break;
 755:         }
 756:         if (d == last) {
 757:             if (buffer[0] == ESC && len == 2) {
 758:                 /* Same kludge as above */
 759:                 return c&0177 | MASK;
 760:             }
 761:             return 0377; /* Hope this rings a bell */
 762:         }
 763:         if (d->def[len] == '\0')
 764:             return d->code;
 765:     }
 766: }

Defined functions

adv defined in line 209; used 22 times
append defined in line 300; used 1 times
countdefs defined in line 549; used 1 times
dump defined in line 520; used 3 times
endgetc defined in line 696; used 1 times
err defined in line 198; used 12 times
getdef defined in line 480; used 1 times
getitem defined in line 404; used 2 times
getline defined in line 509; used 1 times
getmem defined in line 66; never used
getname defined in line 308; used 2 times
getnumber defined in line 326; used 1 times
getrhs defined in line 457; used 1 times
getstring defined in line 345; used 1 times
inchar defined in line 709; used 1 times
initgetc defined in line 687; used 1 times
initkeys defined in line 633; used 1 times
lookup defined in line 233; used 3 times
outstring defined in line 674; used 2 times
process defined in line 562; used 1 times
readtermcap defined in line 596; used 1 times
regetmem defined in line 77; used 1 times
savestr defined in line 290; used 6 times
skipsp defined in line 227; used 4 times
store defined in line 245; used 1 times
try defined in line 572; used 6 times

Defined variables

Hidden defined in line 520; never used
Procedure defined in line 520; never used
deftab defined in line 125; used 23 times
eof defined in line 94; used 4 times
errcount defined in line 96; used 3 times
filename defined in line 92; used 2 times
lcount defined in line 95; used 3 times
ndefs defined in line 195; used 8 times
nextc defined in line 93; used 39 times

Defined struct's

tabent defined in line 99; used 10 times

Defined macros

COMMENT defined in line 88; used 2 times
ESC defined in line 22; used 3 times
I defined in line 122; used 35 times
MAXDEFS defined in line 89; used 3 times
freemem defined in line 13; used 4 times
getch defined in line 706; used 3 times
syserr defined in line 11; used 3 times
Last modified: 1985-09-13
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 5035
Valid CSS Valid XHTML 1.0 Strict