|
|
1.1 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.