home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Misc / YADME10.LHA / YADME10 / src / keyboard.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-19  |  17.4 KB  |  622 lines

  1.  
  2. /*
  3.  *  KEYBOARD.C
  4.  *
  5.  *      (C)Copyright 1987 by Matthew Dillon
  6.  *
  7.  *  Handle keyboard related stuff such as keyboard mappings.  Every time
  8.  *  a key is pressed, KEYCTL() is called with the code.  KEYCTL() remembers
  9.  *  which qualifier keys are currently held down, and when a non-qualifier
  10.  *  key is pressed finds the hash entry for the key.  If no hash entry
  11.  *  exists (e.g. you type a normal 'a') the default keymap is used.
  12.  */
  13.  
  14. #include "defs.h"
  15. #include <devices/keymap.h>
  16. #include <devices/console.h>
  17.  
  18.  
  19. typedef struct IOStdReq CIO;
  20.  
  21. #define QUAL_SHIFT   0x01
  22. #define QUAL_CTRL    0x02
  23. #define QUAL_AMIGA   0x04
  24. #define QUAL_ALT     0x08
  25. #define QUAL_LMB     0x10
  26. #define QUAL_MMB     0x20
  27. #define QUAL_RMB     0x40
  28.  
  29. #define HASHSIZE  64                /*  power of 2  */
  30. #define HASHMASK  (HASHSIZE-1)
  31.  
  32. typedef struct _HASH {
  33.     struct _HASH *next;     /* next hash   */
  34.     ubyte code;             /* keycode     */
  35.     ubyte mask;             /* qual. mask  */
  36.     ubyte qual;             /* qual. comp  */
  37.     ubyte stat;             /* string static? */
  38.     char *str;              /* command string */
  39. } HASH;
  40.  
  41. HASH *Hash[HASHSIZE];
  42.  
  43. struct Library *ConsoleDevice;
  44.  
  45. ubyte   ctoa[128];
  46. ubyte   cstoa[128];
  47.  
  48. void keyctl(struct IntuiMessage *im, int code, unsigned short qual)
  49. {
  50.     ubyte buf[256];
  51.     ubyte c2;
  52.     short blen = 0;
  53.  
  54.     code &= 0xFF;
  55.     if (im) {
  56.         uword oldQual = im->Qualifier;
  57.  
  58.         im->Qualifier &= ~IEQUALIFIER_REPEAT;
  59.         blen = DeadKeyConvert(im, buf+1, 254, NULL);
  60.         im->Qualifier = oldQual;
  61.         if (blen < 0)
  62.             return;
  63.     }
  64.     c2 = 0;
  65.     if (qual & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
  66.         c2 |= QUAL_SHIFT;
  67.     if (qual & (IEQUALIFIER_CONTROL))
  68.         c2 |= QUAL_CTRL;
  69.     if (qual & (IEQUALIFIER_LCOMMAND|IEQUALIFIER_RCOMMAND))
  70.         c2 |= QUAL_AMIGA;
  71.     if (qual & (IEQUALIFIER_LALT|IEQUALIFIER_RALT))
  72.         c2 |= QUAL_ALT;
  73.     if ((qual & IEQUALIFIER_CAPSLOCK) && blen == 1 && buf[1] >= 'a' && buf[1] <= 'z')
  74.         c2 |= QUAL_SHIFT;
  75.     if (qual & IEQUALIFIER_LEFTBUTTON)
  76.         c2 |= QUAL_LMB;
  77.     if (qual & IEQUALIFIER_MIDBUTTON)
  78.         c2 |= QUAL_MMB;
  79.     if (qual & (IEQUALIFIER_RBUTTON))
  80.         c2 |= QUAL_RMB;
  81.  
  82.     {
  83.         HASH *hash;
  84.         for (hash = Hash[code&HASHMASK]; hash; hash = hash->next) {
  85.             if (hash->code == code && (c2 & hash->mask) == hash->qual)
  86.                 break;
  87.         }
  88.  
  89.         /*
  90.          *  Use hash entry only if not in command line mode, or if the
  91.          *  entry does not correspond to an alpha key.
  92.          */
  93.  
  94.  
  95.      /* Problem with rawkey-code 0 fixed: Wasn't able to enter `-sign */
  96.      /* was: if (hash) {                                              */
  97.  
  98.         if (hash && code > 0) {
  99.             if (c2 || !Comlinemode || blen > 1 || !ctoa[code]) {
  100.                 strcpy(buf, hash->str);
  101.                 do_command(buf);
  102.                 return;
  103.             }
  104.         }
  105.     }
  106.  
  107.     /*
  108.      *  No hash entry
  109.      */
  110.  
  111.     if (blen == 1) {
  112.         buf[0] = '\'';
  113.         buf[2] = 0;
  114.     } else {
  115.         buf[0] = '\`';
  116.         buf[blen+1] = '\'';
  117.     }
  118.     if (blen)
  119.         do_command(buf);
  120. }
  121.  
  122. void dealloc_hash(void)
  123. {
  124.     HASH *hash, *hnext = NULL;
  125.     short i;
  126.  
  127.     for (i = 0; i < HASHSIZE; ++i) {
  128.         for (hash = Hash[i]; hash; hash = hnext) {
  129.             hnext = hash->next;
  130.             if (!hash->stat)
  131.                 FreeMem(hash->str, strlen(hash->str)+1);
  132.             FreeMem(hash, sizeof(HASH));
  133.         }
  134.         Hash[i] = NULL;
  135.     }
  136. }
  137.  
  138. void resethash(void)
  139. {
  140.     short i;
  141.     CIO cio;
  142.     static const struct {
  143.         char *from, *to;   /* const char *from,*to; */
  144.     } defmap[] = {
  145.         "esc",      "esc",
  146.         "c-esc",    "recall",
  147.         "return",   "split return set oldcol \$(colno)",
  148.         "enter",    "firstnb downadd insline set oldcol \$(colno)",
  149.         "up",       "up col \$(oldcol) if r (last)",
  150.         "down",     "down col \$(oldcol) if r (last)",
  151.         "right",    "ifelse r (down first) (right) set oldcol \$(colno)",
  152.         "left",     "ifelse l (up last) (left) set oldcol \$(colno)",
  153.         "bs",       "ifelse l (up last join2) (bs) set oldcol \$(colno)",
  154.         "del",      "ifelse r (join2) (del) set oldcol \$(colno)",
  155.         "tab",      "tab",
  156.         "a-up",     "upfast col \$(oldcol) if r (last)",
  157.         "a-down",   "downfast col \$(oldcol) if r (last)",
  158.         "a-r",      "nextr",
  159.         "a-u",      "while cl (tlate -32 right)",
  160.         "a-l",      "while cu (tlate +32 right)",
  161.         "s-up",     "pageup col \$(oldcol) if r (last)",
  162.         "s-down",   "pagedown col \$(oldcol) if r (last)",
  163.         "s-right",  "wright set oldcol \$(colno)",
  164.         "s-left",   "wleft set oldcol \$(colno)",
  165.         "s-tab",    "backtab",
  166.         "s-del",    "deline",
  167.         "s- ",      "( )",              /* shift space to space */
  168.         "c-1",      "goto block",
  169.         "c-c",      "",                 /* break.. map to a nop */
  170.         "c-l",      "wleft",
  171.         "c-r",      "wright",
  172.         "c-i",      "insertmode on",
  173.         "c-o",      "insertmode off",
  174.         "c-j",      "join",
  175.         "c-s",      "split first down",
  176.         "c-del",    "remeol",
  177.         "c-n",      "next",
  178.         "c-p",      "prev",
  179.         "c-/",      "escimm (find )",
  180.         "c-]",      "ref",
  181.         "c-[",      "ctags",
  182.         "c-g",      "escimm (goto )",
  183.         "c-up",     "top first set oldcol \$(colno)",
  184.         "c-down",   "bottom last set oldcol \$(colno)",
  185.         "c-right",  "last set oldcol \$(colno)",
  186.         "c-left",   "firstnb set oldcol \$(colno)",
  187.         "c-q",      "quit",
  188.         "c-f",      "reformat",
  189.         "c-w",      "wordwrap toggle",
  190.         "f1",       "escimm (insfile )",
  191.         "f2",       "escimm (newfile )",
  192.         "f3",       "escimm (newwindow newfile )",
  193.         "f6",       "saveold iconify",
  194.         "f7",       "escimm (bsave )",
  195.         "f8",       "saveold escimm (newfile )",
  196.         "f9",       "saveold",
  197.    /*     "f10",      "saveold quit", */
  198.         "c-b",      "block",
  199.         "c-u",      "unblock",
  200.         "a-d",      "bdelete",
  201.         "a-c",      "bcopy",
  202.         "a-m",      "bmove",
  203.         "a-s",      "bsource",
  204.         "a-S",      "unblock block block bsource",
  205.         "L-lmb",    "tomouse if r (last) set oldcol \$(colno)",
  206.         "L-mmo",    "tomouse if r (last) set oldcol \$(colno)",
  207.         "R-rmb",    "iconify",      /*  right button                */
  208.         NULL, NULL
  209.     };
  210.  
  211.     dealloc_hash();
  212.     OpenDevice("console.device", -1, (struct IORequest *)&cio, 0);
  213.     ConsoleDevice = (struct Library *)cio.io_Device;
  214.     keyboard_init();
  215.     for (i = 0; defmap[i].from; ++i)
  216.     {
  217.         ubyte code, qual;
  218.         if (get_codequal(defmap[i].from, &code, &qual))
  219.             addhash(code, 1, 0xFF, qual, defmap[i].to);
  220.     }
  221. }
  222.  
  223. int returnoveride(int n)
  224. {
  225.     HASH *hash;
  226.     static ubyte *str;
  227.     static int stat;
  228.  
  229.     for (hash = Hash[0x44&HASHMASK]; hash; hash = hash->next) {
  230.         if (hash->code == 0x44 && hash->qual == 0) {
  231.             if (n) {
  232.                 str = (ubyte *)hash->str;
  233.                 stat= hash->stat;
  234.                 hash->str = "return";
  235.                 hash->stat = 1;
  236.             } else {
  237.                 if (str == NULL) {
  238.                     remhash(0x44, (ubyte)-1, 0);
  239.                 } else {
  240.                     hash->str = (char *)str;
  241.                     hash->stat= stat;
  242.                 }
  243.             }
  244.             return(0);
  245.         }
  246.     }
  247.     if (n) {
  248.         addhash(0x44, 1, 0xFF, 0, "return");
  249.         str = NULL;
  250.     }
  251. }
  252.  
  253. void addhash(ubyte code, ubyte stat, ubyte mask, ubyte qual, ubyte *str)
  254. {
  255.     HASH **p, *hash;
  256.  
  257.     hash = *(p = &Hash[code&HASHMASK]);
  258.     while (hash) {
  259.         if (hash->code == code && hash->qual == qual && hash->mask == mask) {
  260.             if (!hash->stat)
  261.                 FreeMem(hash->str, strlen(hash->str)+1);
  262.             goto newstr;
  263.         }
  264.         hash = *(p = &hash->next);
  265.     }
  266.     *p = hash = (HASH *)AllocMem(sizeof(HASH), 0);
  267.     hash->next = NULL;
  268. newstr:
  269.     hash->code = code;
  270.     hash->stat = stat;
  271.     hash->mask = mask;
  272.     hash->qual = qual;
  273.     hash->str = (char *)str;
  274.     if (!stat)                  /* if not static */
  275.         hash->str = (char *)strcpy((char *)AllocMem(strlen(str)+1, MEMF_PUBLIC), str);
  276. }
  277.  
  278.  
  279. remhash(ubyte code, ubyte mask, ubyte qual)
  280. {
  281.     HASH *hash, **p;
  282.  
  283.     hash = *(p = &Hash[code&HASHMASK]);
  284.     while (hash) {
  285.         if (hash->code == code && hash->qual == qual && hash->mask == mask) {
  286.             if (!hash->stat)
  287.                 FreeMem(hash->str, strlen(hash->str)+1);
  288.             *p = hash->next;
  289.             FreeMem(hash, sizeof(HASH));
  290.             return(1);
  291.         }
  292.         hash = *(p = &hash->next);
  293.     }
  294.     return(0);
  295. }
  296.  
  297. char *keyspectomacro(char *str)
  298. {
  299.     HASH *hash;
  300.     ubyte code, qual;
  301.  
  302.     if (get_codequal(str, &code, &qual)) {
  303.         for (hash = Hash[code&HASHMASK]; hash; hash = hash->next) {
  304.             if (hash->code == code) {
  305.                 if (hash->qual == (qual & hash->mask)) {
  306.                     return(hash->str);
  307.                 }
  308.             }
  309.         }
  310.     }
  311.     return(NULL);
  312. }
  313.  
  314. void do_map(void)
  315. {
  316.     ubyte code, qual;
  317.  
  318.     if (get_codequal(av[1], &code, &qual)) {
  319.         addhash(code, 0, 0xFF, qual, av[2]);
  320.     } else {
  321.         title("Unknown Key");
  322.     }
  323. }
  324.  
  325. void do_unmap(void)        /* key   */
  326. {
  327.     ubyte code, qual;
  328.  
  329.     if (get_codequal(av[1], &code, &qual)) {
  330.         remhash(code, (ubyte)-1, qual);
  331.     } else {
  332.         title("Unknown Command");
  333.     }
  334. }
  335.  
  336. void do_clearmap(void)
  337. {
  338.     resethash();
  339. }
  340.  
  341. /*
  342.  * SAVEMAP  file
  343.  * SAVESMAP file
  344.  */
  345.  
  346. void do_savemap(void)
  347. {
  348.     char sysalso;
  349.     char err = 0;
  350.     char buf[256];
  351.     FILE *fi;
  352.     int i;
  353.     HASH *hash;
  354.     ubyte *ptr;
  355.  
  356.     fi = fopen(av[1], "w");
  357.     if (fi) {
  358.         sysalso = av[0][4] == 's';
  359.         for (i = 0; i < HASHSIZE; ++i) {
  360.             for (hash = Hash[i]; hash; hash = hash->next) {
  361.                 if (hash->stat == 0 || sysalso) {
  362.                     char soc = '(';
  363.                     char eoc = ')';
  364.                     char ksoc = '(';
  365.                     char keoc = ')';
  366.                     short len;
  367.  
  368.                     for (ptr = (ubyte *)hash->str; *ptr; ++ptr) {
  369.                         if (*ptr == '(')
  370.                             break;
  371.                         if (*ptr == '\`') {
  372.                             soc = '\`';
  373.                             eoc = '\'';
  374.                             break;
  375.                         }
  376.                     }
  377.                     len = strlen(ptr = cqtoa(hash->code, hash->qual)) - 1;
  378.                     if (ptr[len] == '(' || ptr[len] == ')') {
  379.                         ksoc = '\`';
  380.                         keoc = '\'';
  381.                     }
  382.                     sprintf(buf, "map %c%s%c %c%s%c\n", ksoc, cqtoa(hash->code, hash->qual), keoc, soc, hash->str, eoc);
  383.                     fputs(buf, fi);
  384.                 }
  385.             }
  386.         }
  387.         fclose(fi);
  388.         if (err)
  389.             title ("Unable to Write");
  390.         else
  391.             title ("OK");
  392.     } else {
  393.         title("Unable to open file");
  394.     }
  395. }
  396.  
  397. /*
  398.  *  Nitty Gritty.
  399.  *
  400.  *  keyboard_init:  initialize for get_codequal() and cqtoa()
  401.  *  get_codequal:   convert a qualifier-string combo to a keycode and qual.
  402.  *  cqtoa:          convert a keycode and qual to a qual & string
  403.  */
  404.  
  405. #define LN(a,b,c,d)  ((a<<24)|(b<<16)|(c<<8)|d)
  406.  
  407. static long lname[] = {
  408.     LN('e','s','c', 0  ), LN('f','1', 0 , 0  ), LN('f','2', 0 , 0  ),
  409.     LN('f','3', 0 , 0  ), LN('f','4', 0 , 0  ), LN('f','5', 0 , 0  ),
  410.     LN('f','6', 0 , 0  ), LN('f','7', 0 , 0  ), LN('f','8', 0 , 0  ),
  411.     LN('f','9', 0 , 0  ), LN('f','1','0', 0  ), LN('d','e','l', 0  ),
  412.     LN('b','a','c', 0  ), LN('b','s', 0 , 0  ), LN('t','a','b', 0  ),
  413.     LN('h','e','l', 0  ), LN('r','e','t', 0  ), LN('u','p', 0 , 0  ),
  414.     LN('d','o','w', 0  ), LN('r','i','g', 0  ), LN('l','e','f', 0  ),
  415.     LN('e','n','t', 0  ), LN('n','k','-', 0  ), LN('n','k','.', 0  ),
  416.     LN('n','k','0', 0  ),   /* 24 */
  417.     LN('n','k','1', 0  ), LN('n','k','2', 0  ), LN('n','k','3', 0  ),
  418.     LN('n','k','4', 0  ), LN('n','k','5', 0  ), LN('n','k','6', 0  ),
  419.     LN('n','k','7', 0  ), LN('n','k','8', 0  ), LN('n','k','9', 0  ),
  420.     LN('n','k','(', 0  ), LN('n','k',')', 0  ), LN('n','k','/', 0  ), /*34-36*/
  421.     LN('n','k','*', 0  ), LN('n','k','+', 0  ),
  422.     LN('l','m','b',0xE8), LN('m','m','b',0xEA), LN('r','m','b',0xE9),
  423.     LN('m','m','o',QMOVE),
  424.     0
  425. };
  426.  
  427.  
  428. /*
  429.  *  ESC:        x1B
  430.  *  FUNCKEYS:   x9B 30 7E to x9B 39 7E
  431.  *  DEL:        x7E
  432.  *  BS:         x08
  433.  *  TAB:        x09
  434.  *  RETURN:     x0D
  435.  *  HELP        x9B 3F 7E
  436.  *  UP/D/L/R    x9B 41/42/44/43
  437.  *  NK0-9,-,.,ENTER
  438.  *
  439.  *  Mouse buttons
  440.  */
  441.  
  442. void keyboard_init(void)
  443. {
  444.     static struct InputEvent ievent = { NULL, IECLASS_RAWKEY };
  445.     ubyte buf[32];
  446.     short i, len;
  447.  
  448.     lname[16] |= 0x44;
  449.     lname[21] |= 0x43;
  450.  
  451.     for (i = 0; i < 128; ++i) {
  452.         ievent.ie_Code = i;
  453.         ievent.ie_Qualifier = 0;
  454.         ievent.ie_position.ie_addr = NULL;
  455.         len = RawKeyConvert(&ievent,buf,32,NULL);
  456.         switch(len) {
  457.         case 1:     /*  ESC/DEL/BS/TAB/NKx  */
  458.             if ((buf[0] & 0x7F) >= 32 && (buf[0] & 0x7F) < 127)
  459.                 ctoa[i] = buf[0];
  460.             switch(buf[0]) {
  461.             case 0x1B:  lname[ 0] |= i; break;
  462.             case 0x7F:  lname[11] |= i; break;
  463.             case 0x09:  lname[14] |= i; break;
  464.             case 0x08:  lname[12] |= i; lname[13] |= i; break;
  465.             case '(': if (i > 0x3A) lname[34] |= i; break;
  466.             case ')': if (i > 0x3A) lname[35] |= i; break;
  467.             case '/': if (i > 0x3A) lname[36] |= i; break;
  468.             case '*': if (i > 0x3A) lname[37] |= i; break;
  469.             case '-': if (i > 0x3A) lname[22] |= i; break;
  470.             case '+': if (i > 0x3A) lname[38] |= i; break;
  471.             case '.': if (i > 0x3A) lname[23] |= i; break;
  472.             default:
  473.                 if (i >= 0x0F && buf[0] >= '0' && buf[0] <= '9')
  474.                     lname[24+buf[0]-'0'] |= i;
  475.             }
  476.             break;
  477.         case 2:     /*  cursor              */
  478.             if (buf[0] == 0x9B) {
  479.                 switch(buf[1]) {
  480.                 case 0x41:  lname[17] |= i;  break;
  481.                 case 0x42:  lname[18] |= i;  break;
  482.                 case 0x43:  lname[19] |= i;  break;
  483.                 case 0x44:  lname[20] |= i;  break;
  484.                 }
  485.             }
  486.             break;
  487.         case 3:     /*  function/help       */
  488.             if (buf[0] == 0x9B && buf[2] == 0x7E) {
  489.                 if (buf[1] == 0x3F)
  490.                     lname[15] |= i;
  491.                 if (buf[1] >= 0x30 && buf[1] <= 0x39)
  492.                     lname[buf[1]-0x30+1] |= i;
  493.             }
  494.             break;
  495.         }
  496.     }
  497.     for (i = 0; i < 128; ++i) {
  498.         ievent.ie_Code = i;
  499.         ievent.ie_Qualifier = IEQUALIFIER_LSHIFT;
  500.         ievent.ie_position.ie_addr = NULL;
  501.         len = RawKeyConvert(&ievent,buf,32,NULL);
  502.         if (len == 1)
  503.             cstoa[i] = buf[0];
  504.     }
  505.     {
  506.         ubyte code, qual;
  507.         get_codequal("c", &code, &qual);
  508.         CtlC = code;
  509.     }
  510. }
  511.  
  512.  
  513. ubyte *cqtoa(int code, int qual)
  514. {
  515.     static ubyte buf[32];
  516.     ubyte *ptr = buf;
  517.     int i;
  518.  
  519.     if (qual & QUAL_SHIFT)
  520.         *ptr++ = 's';
  521.     if (qual & QUAL_CTRL)
  522.         *ptr++ = 'c';
  523.     if (qual & QUAL_ALT)
  524.         *ptr++ = 'a';
  525.     if (qual & QUAL_AMIGA)
  526.         *ptr++ = 'A';
  527.     if (qual & QUAL_LMB)
  528.         *ptr++ = 'L';
  529.     if (qual & QUAL_MMB)
  530.         *ptr++ = 'M';
  531.     if (qual & QUAL_RMB)
  532.         *ptr++ = 'R';
  533.     if (qual)
  534.         *ptr++ = '-';
  535.     for (i = 0; i < sizeof(lname)/sizeof(lname[0]); ++i) {
  536.         if ((lname[i]&0xFF) == code) {
  537.             *ptr++ = (lname[i]>>24);
  538.             *ptr++ = (lname[i]>>16);
  539.             *ptr++ = (lname[i]>>8);
  540.             break;
  541.         }
  542.     }
  543.     if (i == sizeof(lname)/sizeof(lname[0]))
  544.         *ptr++ = ctoa[code];
  545.     *ptr++ = 0;
  546.     return(buf);
  547. }
  548.  
  549.  
  550. int get_codequal(ubyte *str, ubyte *pcode, ubyte *pqual)
  551. {
  552.     char *base = str;
  553.     ubyte qual;
  554.     short i;
  555.  
  556.     qual = 0;
  557.     if (strlen(str) > 1) {
  558.         for (; *str && *str != '-'; ++str) {
  559.             if (*str == 's')
  560.                 qual |= QUAL_SHIFT;
  561.             if (*str == 'c')
  562.                 qual |= QUAL_CTRL;
  563.             if (*str == 'a')
  564.                 qual |= QUAL_ALT;
  565.             if (*str == 'A')
  566.                 qual |= QUAL_AMIGA;
  567.             if (*str == 'L')
  568.                 qual |= QUAL_LMB;
  569.             if (*str == 'M')
  570.                 qual |= QUAL_MMB;
  571.             if (*str == 'R')
  572.                 qual |= QUAL_RMB;
  573.             if (!qual)
  574.                 goto notqual;
  575.         }
  576.         if (*str == 0) {
  577.             qual = 0;
  578.             str = base;
  579.         } else {
  580.             ++str;
  581.         }
  582.     }
  583. notqual:
  584.     if (strlen(str) != 1) {           /* long name   */
  585.         short shift = 24;
  586.         long mult = 0;
  587.         ubyte c;
  588.  
  589.         *pqual = qual;
  590.         while ((c = *str) && shift >= 8) {
  591.             if (c >= 'A' && c <= 'Z')
  592.                 c = c - 'A' + 'a';
  593.             mult |= c << shift;
  594.             shift -= 8;
  595.             ++str;
  596.         }
  597.         for (i = 0; lname[i]; ++i) {
  598.             if (mult == (lname[i] & 0xFFFFFF00)) {
  599.                 *pcode = lname[i] & 0xFF;
  600.                 return(1);
  601.             }
  602.         }
  603.     } else {                /*  single character keycap */
  604.         for (i = 0; i < sizeof(ctoa); ++i) {
  605.             if (*str == ctoa[i]) {
  606.                 *pcode = i;
  607.                 *pqual = qual;
  608.                 return(1);
  609.             }
  610.         }
  611.         for (i = 0; i < sizeof(cstoa); ++i) {
  612.             if (*str == cstoa[i]) {
  613.                 *pcode = i;
  614.                 *pqual = qual|QUAL_SHIFT;
  615.                 return(1);
  616.             }
  617.         }
  618.     }
  619.     return(0);
  620. }
  621.  
  622.