home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / Samples / CSAPE32.ARJ / SOURCE / OWLSCR / DIGKLEX.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-11-01  |  15.6 KB  |  653 lines

  1. /*
  2.     klex.c
  3.  
  4.     % Keyboard scancode lexical scanning code.
  5.  
  6.     VMS OWL DIG
  7.     Copyright (c) 1990 by Oakland Group, Inc.
  8.     ALL RIGHTS RESERVED.
  9.  
  10.     Revision History:
  11.     -----------------
  12.       6/1/90 bkd    Created (on SunOS).
  13.       6/6/90 bkd    Ansi-fied (on VAX/VMS).
  14.      6/12/90 bkd    Renamed from kparse to klex.
  15.      7/12/90 bkd    Removed retro.h include.
  16.      7/19/90 bkd    Undefined KLEX_DEBUG, changed OA_NOTAG to OA_KLEX,
  17.                         changed include "bt.h" to "btree.h"
  18.      9/12/90 bkd    Removed comment that choked de-ansifier.
  19.      9/24/90 jsm    Added cast for C++
  20. */
  21.  
  22. #include "oakhead.h"
  23. #include "disppriv.h"
  24. #include "digutil.h"
  25.  
  26. /* #define KLEXDEBUG */
  27.  
  28. #ifdef KLEXDEBUG
  29. #include <stdio.h>
  30. #endif
  31.  
  32. #define BPB                8        /* Bits per byte */
  33. #define NUMBYTES        0x100    /* How many unique bytes there are */
  34. #define MAXSTACK        10        /* STACK SIZE */
  35.  
  36. #define KEY_SECONDARY    0x01    /* Key has secondaries attached */
  37. #define KEY_TERMINAL    0x02    /* Key can be terminal */
  38.  
  39. struct keyinfo {
  40.     byte in_byte;            /* Byte read */
  41.     byte flags;
  42.     struct keyinfo *previous;    /* Previous key */
  43.     scancode_type scode;        /* Scancode here */
  44.     btree_type secondary;        /* Secondary bytes */
  45. };
  46.  
  47. typedef struct klex {
  48.     /* Front-line map */
  49.     union {
  50.         scancode_type map_scode;
  51.         struct keyinfo *map_kinfo;
  52.     } primary_map[NUMBYTES];
  53.     byte primary_secondary[NUMBYTES/BPB];    /* Bitmap */
  54.     /* Scancode stack: */
  55.     scancode_type scode_stack[MAXSTACK];
  56.     int ss_head;
  57.     int ss_tail;
  58.     int ss_depth;        /* Scancode stack head, tail and depth */
  59.     /* Input state information */
  60.     struct keyinfo *kstate;
  61. } *klexp_type;
  62.  
  63. #define NELEM(x)        (sizeof((x)) / sizeof((x)[0]))
  64.  
  65. #define LOGBPB            3    /* 2 ^ LOGBPB = BPB */
  66. #define MASKBPB            0x7    /* x & MASKBPB = x % BPB */
  67.  
  68. #define ISBITSET(bm, bnum)    ( *((byte *)(bm) + ((bnum) >> LOGBPB)) &    \
  69.                     (byte) (1 << ((bnum) & MASKBPB)))
  70. #define ISBITCLR(bm, bnum)    (( *((byte *)(bm) + ((bnum) >> LOGBPB)) &   \
  71.                     (byte) (1 << ((bnum) & MASKBPB))) == 0)
  72. #define SETBIT(bm, bnum)    ( *((byte *)(bm) + ((bnum) >> LOGBPB)) |=   \
  73.                     (byte) (1 << ((bnum) & MASKBPB)))
  74. #define CLRBIT(bm, bnum)    ( *((byte *)(bm) + ((bnum) >> LOGBPB)) &=   \
  75.                     (byte) ~ ((byte)                \
  76.                           (1 << ((bnum) & MASKBPB))))
  77.  
  78. #define KLEXPSCODE(kl, bn)    ((kl)->primary_map[bn].map_scode)
  79. #define KLEXPKINFO(kl, bn)    ((kl)->primary_map[bn].map_kinfo)
  80.  
  81. OSTATIC btree_nodecomp_func(klex_Compare);
  82. OSTATIC btree_keycomp_func(klex_KeyCompare);
  83. OSTATIC btree_freertn_func(klex_Free);
  84. OSTATIC scancode_type    DIGPRIV klex_MakeScode(byte b);
  85. OSTATIC int                DIGPRIV klex_TreeAddCode(btree_type bt, struct keyinfo *prev,
  86.                                     byte *seq, int seqlen, scancode_type code);
  87. OSTATIC void            DIGPRIV klex_StackAppend(klexp_type kl, scancode_type scode);
  88. OSTATIC scancode_type    DIGPRIV klex_StackPop(klexp_type kl);
  89. OSTATIC void            DIGPRIV klex_TreeUnroll(klexp_type kl, struct keyinfo *ki);
  90.  
  91. /***************************************** ANCILLARY CODE ********************/
  92. /*
  93.     Ancillary code:  None of these routines are called directly.
  94.  
  95.     klex_Compare, klex_KeyCompare and klex_Free are used
  96.      in the btree that stores the lexicon tables.
  97. */
  98.  
  99.  
  100. /*
  101.     These next three routines are used by the btree code.  They
  102.      are associated with the btree in the btree_Open calls in the
  103.      klex_AddCode below.
  104. */
  105.  
  106. static int klex_Compare(VOID *kinfo1, VOID *kinfo2)
  107. {
  108.     return((int) (((struct keyinfo *) kinfo1)->in_byte -
  109.                   ((struct keyinfo *) kinfo2)->in_byte));
  110. }
  111.  
  112. static int klex_KeyCompare(VOID *kinfo, byte *key)
  113. {
  114.     return((int) (((struct keyinfo *) kinfo)->in_byte - *key));
  115. }
  116.  
  117. static void klex_Free(VOID *kinfo)
  118. {
  119.     if ((((struct keyinfo *) kinfo)->flags & KEY_SECONDARY) != 0) {
  120.         btree_Close(((struct keyinfo *) kinfo)->secondary);
  121.     }
  122.     ofree(OA_KLEX, kinfo);
  123. }
  124. /***************************************** INTERNAL CODE *********************/
  125.  
  126. /*
  127.     Default byte->scode mapper.  Used to establish the initial map
  128.      if no default is specified.
  129. */
  130.  
  131. static scancode_type DIGPRIV klex_MakeScode(byte b)
  132. {
  133.     return((scancode_type) b);
  134. }
  135.  
  136.  
  137. static int DIGPRIV klex_TreeAddCode(
  138.     btree_type bt,
  139.     struct keyinfo *prev,
  140.     byte *seq,
  141.     int seqlen,
  142.     scancode_type code)
  143. /*
  144.     This is a recursive subroutine of klex_AddCode. It is used only internally.
  145. */
  146. {
  147.     register struct keyinfo *kinfo;
  148.  
  149.     if (bt == NULL || seq == NULL) {    /* SHOULDN'T HAPPEN */
  150. #ifdef KLEXDEBUG
  151.         fprintf(stderr, "klex_TreeAddCode: bt or seq is NULL.\n");
  152. #endif    /* KLEXDEBUG */
  153.         return(-1);
  154.     }
  155.  
  156.     if (seqlen == 0) {            /* SHOULDN'T HAPPEN */
  157.         return(0);
  158.     }
  159.  
  160.     kinfo = (struct keyinfo *) btree_Get(bt, seq);
  161.  
  162.  
  163.     if (kinfo == NULL) {
  164.         kinfo = (struct keyinfo *) omalloc(OA_KLEX,
  165.                         sizeof(struct keyinfo));
  166.  
  167.         if (kinfo == NULL) {
  168. #ifdef KLEXDEBUG
  169.             fprintf(stderr,
  170.             "klex_TreeAddCode: couldn't allocate kinfo.\n");
  171. #endif    /* KLEXDEBUG */
  172.             return(-1);
  173.         }
  174.  
  175.         kinfo->in_byte = *seq;
  176.         kinfo->previous = prev;
  177.  
  178.         if (btree_Insert(bt, kinfo) != BTREE_OK) {
  179.             ofree(OA_KLEX, kinfo);
  180. #ifdef KLEXDEBUG
  181.             fprintf(stderr,
  182.             "klex_TreeAddCode: error inserting into btree.\n");
  183. #endif    /* KLEXDEBUG */
  184.             return(-1);
  185.         }
  186.  
  187.         if (seqlen == 1) {
  188.             kinfo->scode = code;
  189.             kinfo->flags = KEY_TERMINAL;
  190.  
  191.             return(0);
  192.         }
  193.         else {
  194.             if ((bt = btree_Open(klex_Compare, klex_KeyCompare,
  195.                          klex_Free)) == NULL) {
  196.                 ofree(OA_KLEX, kinfo);
  197. #ifdef KLEXDEBUG
  198.                 fprintf(stderr,
  199.             "klex_TreeAddCode: couldn't open new btree #1.\n");
  200. #endif    /* KLEXDEBUG */
  201.                 return(-1);
  202.             }
  203.  
  204.             kinfo->secondary = bt;
  205.             kinfo->flags = KEY_SECONDARY;
  206.  
  207.             return(klex_TreeAddCode(bt, kinfo, seq + 1, seqlen - 1, code));
  208.         }
  209.  
  210.     }
  211.     else {
  212.         if (seqlen == 1) {
  213.             /* If KEY_TERMINAL is already set, than there is
  214.                   an ambiguity */
  215.             kinfo->scode = code;
  216.             kinfo->flags |= KEY_TERMINAL;
  217.  
  218.             return(0);
  219.         }
  220.         else {
  221.             if ((kinfo->flags & KEY_SECONDARY) != 0) {
  222.                 return(klex_TreeAddCode(
  223.                         kinfo->secondary, kinfo,
  224.                         seq + 1, seqlen - 1, code));
  225.             }
  226.             else {
  227.                 if ((bt = btree_Open(klex_Compare,
  228.                              klex_KeyCompare,
  229.                              klex_Free)) == NULL) {
  230. #ifdef KLEXDEBUG
  231.                     fprintf(stderr,
  232.             "klex_TreeAddCode: couldn't open new btree #2.\n");
  233. #endif    /* KLEXDEBUG */
  234.                     return(-1);
  235.                 }
  236.  
  237.                 kinfo->secondary = bt;
  238.                 kinfo->flags |= KEY_SECONDARY;
  239.  
  240.                 return(klex_TreeAddCode(bt, kinfo,
  241.                           seq + 1, seqlen - 1, code));
  242.             }
  243.         }
  244.     }
  245.     /* NOTREACHED */
  246. }
  247.  
  248.  
  249. static void DIGPRIV klex_StackAppend(klexp_type kl, scancode_type scode)
  250. /*
  251.     Used to manipulate the scancode "stack" (it's really a ring buffer).
  252. */
  253. {
  254.     if (kl->ss_depth >= MAXSTACK) {
  255.         return;        /* ERROR CONDITION UNFLAGGED */
  256.     }
  257.  
  258.     kl->scode_stack[kl->ss_tail++] = scode;
  259.  
  260.     if (kl->ss_tail >= MAXSTACK) {
  261.         kl->ss_tail -= MAXSTACK;
  262.     }
  263.     kl->ss_depth++;
  264. }
  265.  
  266.  
  267. static scancode_type DIGPRIV klex_StackPop(klexp_type kl)
  268. /*
  269.     Used to manipulate the scancode "stack" (it's really a ring buffer).
  270. */
  271. {
  272.     scancode_type scode;
  273.  
  274.     if (kl->ss_depth <= 0) {
  275. #ifdef KLEXDEBUG
  276.         fprintf(stderr, "klex_StacKop: popping from empty stack.\n");
  277. #endif    /* KLEXDEBUG */
  278.         return((scancode_type) 0);    /* ERROR CONDITION UNFLAGGED */
  279.     }
  280.  
  281.     scode = kl->scode_stack[kl->ss_head++];
  282.     kl->ss_depth--;
  283.  
  284.     if (kl->ss_depth == 0) {
  285.         kl->ss_head = kl->ss_tail = 0;
  286.     }
  287.     else {
  288.         if (kl->ss_head >= MAXSTACK) {
  289.             kl->ss_head -= MAXSTACK;
  290.         }
  291.     }
  292.  
  293.     return(scode);
  294. }
  295.  
  296. static void DIGPRIV klex_TreeUnroll(klexp_type kl, struct keyinfo *ki)
  297. /*
  298.     klex_TreeUnroll - This routine will:
  299.     1) Roll backward from the current keyinfo to find the
  300.        first "terminal."  It will then push that scancode
  301.        on the stack.
  302.     2) Reset the state machine to the "base state."
  303.     3) Feed the extra bytes back into the state machine, using
  304.        klex_InByte.
  305.  
  306.     This routine is a little nasty because it calls klex_InByte, which
  307.      can call TreeUnroll.  Totally nasty.
  308. */
  309. {
  310.     if (ki == NULL) {            /* Shouldn't happen */
  311. #ifdef KLEXDEBUG
  312.         fprintf(stderr, "klex_TreeUnroll: ki is NULL.\n");
  313. #endif    /* KLEXDEBUG */
  314.         return;
  315.     }
  316.  
  317.     if ((ki->flags & KEY_TERMINAL) != 0) {
  318.         klex_StackAppend(kl, ki->scode);
  319.         kl->kstate = NULL;
  320.     }
  321.     else {
  322.         klex_TreeUnroll(kl, ki->previous);
  323.         klex_InByte(kl, ki->in_byte);
  324.     }
  325. }
  326.  
  327. /***************************************** PUBLIC CODE ***********************/
  328.  
  329. /*
  330.     klex_Open - Create a new klex object,
  331.      prepare the klex lexicon table to accept definitions,
  332.      initialize the klex state machine and the scancode stack.
  333. */
  334.  
  335. klex_type DIGPRIV klex_Open(scancode_type *def_map)
  336. {
  337.     register int i;
  338.     register klexp_type kl;
  339.  
  340.     if ((kl = (klexp_type) omalloc(OA_KLEX, sizeof(* (klexp_type) 0)))
  341.         == NULL) {
  342. #ifdef KLEXDEBUG
  343.         fprintf(stderr, "klex_Open: couldn't allocate klex.\n");
  344. #endif    /* KLEXDEBUG */
  345.         return(NULL);
  346.     }
  347.  
  348.     if (def_map != NULL) {
  349.         for (i = 0; i < NELEM(kl->primary_map); i++) {
  350.             KLEXPSCODE(kl, i) = *def_map++;
  351.         }
  352.     }
  353.     else {
  354.         for (i = 0; i < NELEM(kl->primary_map); i++) {
  355.             KLEXPSCODE(kl, i) = (scancode_type)
  356.                         klex_MakeScode((byte) i);
  357.         }
  358.     }
  359.  
  360.     /* Reset the bitmap */
  361.     for (i = 0; i < NELEM(kl->primary_secondary); i++) {
  362.         kl->primary_secondary[i] = (byte) 0;
  363.     }
  364.     kl->kstate = NULL;        /* Reset */
  365.  
  366.     kl->ss_head = kl->ss_tail = kl->ss_depth = 0;
  367.  
  368.     return((klex_type) kl);
  369. }
  370.  
  371. void DIGPRIV klex_Close(klex_type klp)
  372. /*
  373.     Closes out a klex and return its storage to the heap.
  374. */
  375. {
  376.     register int i;
  377.     register klexp_type kl;
  378.  
  379.     kl = (klexp_type) klp;
  380.  
  381.     if (kl == NULL) {
  382. #ifdef KLEXDEBUG
  383.         fprintf(stderr, "klex_Close: kl is NULL.\n");
  384. #endif    /* KLEXDEBUG */
  385.         return;
  386.     }
  387.  
  388.     /* Go through the bitmap, find all secondary entries and zap 'em */
  389.  
  390.     for (i = 0; i < NELEM(kl->primary_map); i++) {
  391.         if (ISBITSET(kl->primary_secondary, i)) {
  392.             if ((KLEXPKINFO(kl, i)->flags & KEY_SECONDARY) != 0) {
  393.                 btree_Close(KLEXPKINFO(kl, i)->secondary);
  394.             }
  395.             ofree(OA_KLEX, KLEXPKINFO(kl, i));
  396.         }
  397.     }
  398.  
  399.     /* Now zap the thing itself */
  400.  
  401.     ofree(OA_KLEX, kl);
  402. }
  403.  
  404.  
  405. int DIGPRIV klex_AddCode(klex_type klp, byte *seq, int seqlen, scancode_type code)
  406. /*
  407.     Defines a mapping between a given sequence of bytes and a scancode.
  408. */
  409. {
  410.     register byte firstbyte;
  411.     register struct keyinfo *kinfo;
  412.     register btree_type bt;
  413.     register int retval;
  414.     register klexp_type kl;
  415.  
  416.     kl = (klexp_type) klp;
  417.  
  418.     if (kl == NULL || seq == NULL) {
  419. #ifdef KLEXDEBUG
  420.         fprintf(stderr, "klex_AddCode: kl or seq is NULL.\n");
  421. #endif    /* KLEXDEBUG */
  422.         return(-1);
  423.     }
  424.  
  425.     if (seqlen <= 0) {
  426. #ifdef KLEXDEBUG
  427.         fprintf(stderr, "klex_AddCode: seqlen <= 0.\n");
  428. #endif    /* KLEXDEBUG */
  429.         return(-1);
  430.     }
  431.  
  432.     firstbyte = *seq;
  433.  
  434.     if (ISBITSET(kl->primary_secondary, firstbyte)) {
  435.         kinfo = KLEXPKINFO(kl, firstbyte);
  436.  
  437.         /* kinfo shouldn't be NULL */
  438.  
  439.         /* Single byte sequence */
  440.         if (seqlen == 1) {
  441.             kinfo->scode = code;
  442.             kinfo->flags |= KEY_TERMINAL;
  443.                 /* (SHOULD ALREADY BE SET) */
  444.  
  445.         }
  446.         /* Multi-byte sequence: */
  447.         else {
  448.             return(klex_TreeAddCode(kinfo->secondary, kinfo,
  449.                           seq + 1, seqlen - 1, code));
  450.         }
  451.     }
  452.     else {
  453.         if (seqlen == 1) {
  454.             KLEXPSCODE(kl, firstbyte) = code;
  455.         }
  456.         else {
  457.             if ((kinfo = (struct keyinfo *) omalloc(OA_KLEX,
  458.                         sizeof(struct keyinfo)))
  459.                 == NULL) {
  460. #ifdef KLEXDEBUG
  461.                 fprintf(stderr,
  462.             "klex_AddCode: couldn't allocate new kinfo.\n");
  463. #endif    /* KLEXDEBUG */
  464.                 return(-1);
  465.             }
  466.  
  467.             if ((bt = btree_Open(klex_Compare,
  468.                          klex_KeyCompare,
  469.                          klex_Free)) == NULL) {
  470.                 ofree(OA_KLEX, kinfo);
  471. #ifdef KLEXDEBUG
  472.                 fprintf(stderr,
  473.             "klex_AddCode: couldn't open new btree.\n");
  474. #endif    /* KLEXDEBUG */
  475.                 return(-1);
  476.             }
  477.  
  478.             kinfo->previous = NULL;
  479.             kinfo->in_byte = firstbyte;
  480.             kinfo->secondary = bt;
  481.             kinfo->scode = KLEXPSCODE(kl, firstbyte);
  482.             kinfo->flags = KEY_SECONDARY | KEY_TERMINAL;
  483.  
  484.             retval = klex_TreeAddCode(bt, kinfo,
  485.                           seq + 1, seqlen - 1, code);
  486.             if (retval != 0) {
  487.                 btree_Close(bt);
  488.                 ofree(OA_KLEX, kinfo);
  489.                 return(retval);
  490.             }
  491.  
  492.             KLEXPKINFO(kl, firstbyte) = kinfo;
  493.             SETBIT(kl->primary_secondary, firstbyte);
  494.         }
  495.     }
  496.     return(0);
  497. }
  498.  
  499. /*
  500.     The following three routines: klex_InByte, klex_ShouldTimeOut and
  501.      klex_TimeOut are the extent of interaction with a given OS.
  502.  
  503.     klex_InByte - When a byte is read from the input stream,
  504.         klex_InByte is called to register its receipt.  This
  505.         routine resets the state of the "state machine" and
  506.         (possibly) sticks a scancode on the stack for reading.
  507.     klex_TimeOut - This is called by the OS code after a read
  508.         completed that yielded a timeout.  Note that this
  509.         routine will ALWAYS reset the state machine to its
  510.         base state.
  511.     klex_ShouldTimeOut - This routine should be called by the OS
  512.         specific code before starting a read.  It returns a boolean:
  513.         whether or not to start a timeout timer on the next
  514.         read.  This information is gathered by looking at the
  515.         current state.
  516.  
  517.     So, in short, the routines klex_InByte and klex_TimeOut are used
  518.      for declaring state information from the OS and the klex_ShouldTimeOut
  519.      routine is a question of the current state.
  520. */
  521.  
  522.  
  523. void DIGPRIV klex_InByte(klex_type klp, byte b)
  524. {
  525.     register struct keyinfo *kinfo;
  526.     byte btmp;
  527.     register klexp_type kl;
  528.  
  529.     kl = (klexp_type) klp;
  530.  
  531.     if (kl == NULL) {
  532. #ifdef KLEXDEBUG
  533.         fprintf(stderr, "klex_InByte: kl is NULL.\n");
  534. #endif    /* KLEXDEBUG */
  535.         return;
  536.     }
  537.  
  538.     if (kl->kstate == NULL) {
  539.         if (ISBITCLR(kl->primary_secondary, b)) {
  540.             klex_StackAppend(kl, KLEXPSCODE(kl, b));
  541.         }
  542.         else {
  543.             kl->kstate = KLEXPKINFO(kl, b);
  544.  
  545.             /* BELOW SHOULDN'T HAPPEN */
  546.             if ((kl->kstate->flags & KEY_SECONDARY) == 0) {
  547. #ifdef KLEXDEBUG
  548.                 fprintf(stderr,
  549.         "klex_InByte: warning, kstate is NULL & no secondaries.\n");
  550. #endif    /* KLEXDEBUG */
  551.                 klex_StackAppend(kl, kl->kstate->scode);
  552.                 kl->kstate = NULL;
  553.             }
  554.         }
  555.     }
  556.     else {
  557.         /* kstate->flags should have KEY_SECONDARY set AND
  558.            kstate->secondary should be valid */
  559.         
  560.         btmp = b;
  561.         if ((kinfo = (struct keyinfo *) btree_Get(
  562.                         kl->kstate->secondary,
  563.                         &btmp)) == NULL) {
  564.             /* This is an "error" state.  A byte has been
  565.                received that wasn't on the guest list. */
  566.             klex_TreeUnroll(kl, kl->kstate);
  567.             klex_InByte(kl, b);    /* Try again */
  568.         }
  569.         else {
  570.             if ((kinfo->flags & KEY_SECONDARY) == 0) {
  571.                 klex_StackAppend(kl, kinfo->scode);
  572.                 kl->kstate = NULL;
  573.             }
  574.             else {
  575.                 kl->kstate = kinfo;
  576.             }
  577.         }
  578.     }
  579. }
  580.  
  581. void DIGPRIV klex_TimeOut(klex_type klp)
  582. {
  583.     register klexp_type kl;
  584.  
  585.     kl = (klexp_type) klp;
  586.  
  587.     if (kl == NULL) {
  588. #ifdef KLEXDEBUG
  589.         fprintf(stderr, "klex_TimeOut: kl is NULL.\n");
  590. #endif    /* KLEXDEBUG */
  591.         return;
  592.     }
  593.  
  594.     if (kl->kstate != NULL) {
  595.         if ((kl->kstate->flags & KEY_TERMINAL) != 0) {
  596.             klex_StackAppend(kl, kl->kstate->scode);
  597.             kl->kstate = NULL;
  598.         }
  599.         else {
  600.             klex_TreeUnroll(kl, kl->kstate);
  601.             klex_TimeOut(kl);
  602.         }
  603.     }
  604. }
  605.  
  606. boolean DIGPRIV klex_ShouldTimeOut(klex_type klp)
  607. {
  608.     register klexp_type kl;
  609.  
  610.     kl = (klexp_type) klp;
  611.  
  612.     if (kl == NULL) {
  613. #ifdef KLEXDEBUG
  614.         fprintf(stderr, "klex_ShouldTimeOut: kl is NULL.\n");
  615. #endif    /* KLEXDEBUG */
  616.         return(FALSE);
  617.     }
  618.     else if (kl->kstate == NULL) {
  619.         return(FALSE);
  620.     }
  621.     else {
  622.         if ((kl->kstate->flags & (KEY_SECONDARY | KEY_TERMINAL))
  623.             == (KEY_SECONDARY | KEY_TERMINAL)) {
  624.             return(TRUE);
  625.         }
  626.         else {
  627.             return(FALSE);
  628.         }
  629.     }
  630. }
  631.  
  632.  
  633. /*
  634.     There are two routines provided for getting scancodes.
  635.  
  636.     klex_ScanCodeReady - This routine asks whether or not there is
  637.         scancode ready for reading, either on the stack or
  638.         in the state machine.
  639.     klex_ReadScanCode - This routine pops a scancode off the stack
  640.         or from the state machine.
  641. */
  642.  
  643. scancode_type DIGPRIV klex_ReadScanCode(klex_type klp)
  644. {
  645.     return(klex_StackPop((klexp_type) klp));
  646. }
  647.  
  648. boolean DIGPRIV klex_ScanCodeReady(klex_type klp)
  649. {
  650.     return(((klexp_type) klp)->ss_depth > 0);
  651. }
  652.  
  653.