home *** CD-ROM | disk | FTP | other *** search
/ Carousel Volume 2 #1 / carousel.iso / mactosh / code / microema.sit / src / bind.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-06-09  |  16.3 KB  |  764 lines  |  [TEXT/Earl]

  1. /*    This file is for functions having to do with key bindings,
  2.     descriptions, help commands and startup file.
  3.  
  4.     written 11-feb-86 by Daniel Lawrence
  5.                                 */
  6.  
  7. #include    <stdio.h>
  8. #include    "estruct.h"
  9. #include    "edef.h"
  10. #include    "epath.h"
  11. #if MPW
  12. #include <OSUtils.h>
  13. #endif
  14. #if LSC
  15. #include <OSUtil.h>
  16. #endif
  17.  
  18. extern int meta(), cex(), unarg(), ctrlg(); /* dummy prefix binding functions */
  19.  
  20. help(f, n)    /* give me some help!!!!
  21.            bring up a fake buffer and read the help file
  22.            into it with view mode            */
  23. {
  24.     register WINDOW *wp;    /* scaning pointer to windows */
  25.     register BUFFER *bp;    /* buffer pointer to help */
  26.     char *fname;        /* ptr to file returned by flook() */
  27.  
  28.     /* first check if we are already here */
  29.     bp = bfind("emacs.hlp", FALSE, BFINVS);
  30.  
  31.     if (bp == NULL) {
  32.         fname = flook(pathname[1], FALSE);
  33.         if (fname == NULL) {
  34.             mlwrite("[Help file is not online]");
  35.             desbind(f,n);    /* Give it to "describe-bindings" */
  36.             return(FALSE);
  37.         }
  38.     }
  39.  
  40.     /* split the current window to make room for the help stuff */
  41.     if (splitwind(FALSE, 1) == FALSE)
  42.             return(FALSE);
  43.  
  44.     if (bp == NULL) {
  45.         /* and read the stuff in */
  46.         if (getfile(fname, FALSE) == FALSE)
  47.             return(FALSE);
  48.     } else
  49.         swbuffer(bp);
  50.  
  51.     /* make this window in VIEW mode, update all mode lines */
  52.     curwp->w_bufp->b_mode |= MDVIEW;
  53.     curwp->w_bufp->b_flag |= BFINVS;
  54.     wp = wheadp;
  55.     while (wp != NULL) {
  56.         wp->w_flag |= WFMODE;
  57.         wp = wp->w_wndp;
  58.     }
  59.     return(TRUE);
  60. }
  61.  
  62. deskey(f, n)    /* describe the command for a certain key */
  63.  
  64. {
  65.     register int c;     /* key to describe */
  66.     register char *ptr;    /* string pointer to scan output strings */
  67.     char outseq[NSTRING];    /* output buffer for command sequence */
  68.     int (*getbind())();
  69.  
  70.     /* prompt the user to type us a key to describe */
  71.     mlwrite(": describe-key ");
  72.  
  73.     /* get the command sequence to describe
  74.        change it to something we can print as well */
  75.     cmdstr(c = getckey(FALSE), &outseq[0]);
  76.  
  77.     /* and dump it out */
  78.     ostring(outseq);
  79.     ostring(" ");
  80.  
  81.     /* find the right ->function */
  82.     if ((ptr = getfname(getbind(c))) == NULL)
  83.         ptr = "Not Bound";
  84.  
  85.     /* output the command sequence */
  86.     ostring(ptr);
  87. }
  88.  
  89. /* bindtokey:    add a new key to the key binding table        */
  90.  
  91. bindtokey(f, n)
  92.  
  93. int f, n;    /* command arguments [IGNORED] */
  94.  
  95. {
  96.     register unsigned int c;/* command key to bind */
  97.     register int (*kfunc)();/* ptr to the requested function to bind to */
  98.     register KEYTAB *ktp;    /* pointer into the command table */
  99.     register int found;    /* matched command flag */
  100.     char outseq[80];    /* output buffer for keystroke sequence */
  101.     int (*getname())();
  102.  
  103.     /* prompt the user to type in a key to bind */
  104.     if(!clexec)mlwrite(": bind-to-key ");
  105.  
  106.     /* get the function name to bind it to */
  107.     kfunc = getname();
  108.     if (kfunc == NULL) {
  109.         mlwrite("[No such function]");
  110.         return(FALSE);
  111.     }
  112.     if(!clexec)ostring(" ");
  113.  
  114.     /* get the command sequence to bind */
  115.     c = getckey((kfunc == meta) || (kfunc == cex) ||
  116.             (kfunc == unarg) || (kfunc == ctrlg));
  117.  
  118.     /* change it to something we can print as well */
  119.     cmdstr(c, &outseq[0]);
  120.  
  121.     /* and dump it out */
  122.     if(!clexec)ostring(outseq);
  123.  
  124.     /* if the function is a prefix key */
  125.     if (kfunc == meta || kfunc == cex ||
  126.         kfunc == unarg || kfunc == ctrlg) {
  127.  
  128.         /* search for an existing binding for the prefix key */
  129.         ktp = &keytab[0];
  130.         found = FALSE;
  131.         while (ktp->k_fp != NULL) {
  132.             if (ktp->k_fp == kfunc)
  133.                 unbindchar(ktp->k_code);
  134.             ++ktp;
  135.         }
  136.  
  137.         /* reset the appropriate global prefix variable */
  138.         if (kfunc == meta)
  139.             metac = c;
  140.         if (kfunc == cex)
  141.             ctlxc = c;
  142.         if (kfunc == unarg)
  143.             reptc = c;
  144.         if (kfunc == ctrlg)
  145.             abortc = c;
  146.     }
  147.  
  148.     /* search the table to see if it exists */
  149.     ktp = &keytab[0];
  150.     found = FALSE;
  151.     while (ktp->k_fp != NULL) {
  152.         if (ktp->k_code == c) {
  153.             found = TRUE;
  154.             break;
  155.         }
  156.         ++ktp;
  157.     }
  158.  
  159.     if (found) {    /* it exists, just change it then */
  160.         ktp->k_fp = kfunc;
  161.     } else {    /* otherwise we need to add it to the end */
  162.         /* if we run out of binding room, bitch */
  163.         if (ktp >= &keytab[NBINDS]) {
  164.             mlwrite("Binding table FULL!");
  165.             return(FALSE);
  166.         }
  167.  
  168.         ktp->k_code = c;    /* add keycode */
  169.         ktp->k_fp = kfunc;    /* and the function pointer */
  170.         ++ktp;            /* and make sure the next is null */
  171.         ktp->k_code = 0;
  172.         ktp->k_fp = NULL;
  173.     }
  174.     return(TRUE);
  175. }
  176.  
  177. /* unbindkey:    delete a key from the key binding table */
  178.  
  179. unbindkey(f, n)
  180.  
  181. int f, n;    /* command arguments [IGNORED] */
  182.  
  183. {
  184.     register int c;     /* command key to unbind */
  185.     char outseq[80];    /* output buffer for keystroke sequence */
  186.  
  187.     /* prompt the user to type in a key to unbind */
  188.     if(!clexec)
  189.         mlwrite(": unbind-key ");
  190.  
  191.     /* get the command sequence to unbind */
  192.     c = getckey(FALSE);        /* get a command sequence */
  193.  
  194.     /* change it to something we can print as well */
  195.     cmdstr(c, &outseq[0]);
  196.  
  197.     /* and dump it out */
  198.     if(!clexec)ostring(outseq);
  199.  
  200.     /* if it isn't bound, bitch */
  201.     if (unbindchar(c) == FALSE) {
  202.         mlwrite("[Key not bound]");
  203.         return(FALSE);
  204.     }
  205.     return(TRUE);
  206. }
  207.  
  208. unbindchar(c)
  209.  
  210. int c;        /* command key to unbind */
  211.  
  212. {
  213.     register KEYTAB *ktp;    /* pointer into the command table */
  214.     register KEYTAB *sktp;    /* saved pointer into the command table */
  215.     register int found;    /* matched command flag */
  216.  
  217.     /* search the table to see if the key exists */
  218.     ktp = &keytab[0];
  219.     found = FALSE;
  220.     while (ktp->k_fp != NULL) {
  221.         if (ktp->k_code == c) {
  222.             found = TRUE;
  223.             break;
  224.         }
  225.         ++ktp;
  226.     }
  227.  
  228.     /* if it isn't bound, bitch */
  229.     if (!found)
  230.         return(FALSE);
  231.  
  232.     /* save the pointer and scan to the end of the table */
  233.     sktp = ktp;
  234.     while (ktp->k_fp != NULL)
  235.         ++ktp;
  236.     --ktp;        /* backup to the last legit entry */
  237.  
  238.     /* copy the last entry to the current one */
  239.     sktp->k_code = ktp->k_code;
  240.     sktp->k_fp   = ktp->k_fp;
  241.  
  242.     /* null out the last one */
  243.     ktp->k_code = 0;
  244.     ktp->k_fp = NULL;
  245.     return(TRUE);
  246. }
  247.  
  248. desbind(f, n)    /* describe bindings
  249.            bring up a fake buffer and list the key bindings
  250.            into it with view mode            */
  251.  
  252. #if    APROP
  253. {
  254.     buildlist(TRUE, "");
  255. }
  256.  
  257. apro(f, n)    /* Apropos (List functions that match a substring) */
  258.  
  259. {
  260.     char mstring[NSTRING];    /* string to match cmd names to */
  261.     int status;        /* status return */
  262.  
  263.     status = mlreply("Apropos string: ", mstring, NSTRING - 1);
  264.     if (status != TRUE)
  265.         return(status);
  266.  
  267.     return(buildlist(FALSE, mstring));
  268. }
  269.  
  270. buildlist(type, mstring)  /* build a binding list (limited or full) */
  271.  
  272. int type;    /* true = full list,   false = partial list */
  273. char *mstring;    /* match string if a partial list */
  274.  
  275. #endif
  276. {
  277. #if    ST520 & LATTICE
  278. #define register        
  279. #endif
  280.     register WINDOW *wp;    /* scanning pointer to windows */
  281.     register KEYTAB *ktp;    /* pointer into the command table */
  282.     register NBIND *nptr;    /* pointer into the name binding table */
  283.     register BUFFER *bp;    /* buffer to put binding list into */
  284.     char *strp;        /* pointer int string to send */
  285.     int cpos;        /* current position to use in outseq */
  286.     char outseq[80];    /* output buffer for keystroke sequence */
  287.  
  288.     /* split the current window to make room for the binding list */
  289.     if (splitwind(FALSE, 1) == FALSE)
  290.             return(FALSE);
  291.  
  292.     /* and get a buffer for it */
  293.     bp = bfind("Binding list", TRUE, 0);
  294.     if (bp == NULL || bclear(bp) == FALSE) {
  295.         mlwrite("Can not display binding list");
  296.         return(FALSE);
  297.     }
  298.  
  299.     /* let us know this is in progress */
  300.     mlwrite("[Building binding list]");
  301.  
  302.     /* disconect the current buffer */
  303.     if (--curbp->b_nwnd == 0) {        /* Last use.        */
  304.         curbp->b_dotp  = curwp->w_dotp;
  305.         curbp->b_doto  = curwp->w_doto;
  306.         curbp->b_markp = curwp->w_markp;
  307.         curbp->b_marko = curwp->w_marko;
  308.     }
  309.  
  310.     /* connect the current window to this buffer */
  311.     curbp = bp;    /* make this buffer current in current window */
  312.     bp->b_mode = 0;     /* no modes active in binding list */
  313.     bp->b_nwnd++;        /* mark us as more in use */
  314.     wp = curwp;
  315.     wp->w_bufp = bp;
  316.     wp->w_linep = bp->b_linep;
  317.     wp->w_flag = WFHARD|WFFORCE;
  318.     wp->w_dotp = bp->b_dotp;
  319.     wp->w_doto = bp->b_doto;
  320.     wp->w_markp = NULL;
  321.     wp->w_marko = 0;
  322.  
  323.     /* build the contents of this window, inserting it line by line */
  324.     nptr = &names[0];
  325.     while (nptr->n_func != NULL) {
  326.  
  327.         /* add in the command name */
  328.         strcpy(outseq, nptr->n_name);
  329.         cpos = strlen(outseq);
  330.         
  331. #if    APROP
  332.         /* if we are executing an apropos command..... */
  333.         if (type == FALSE &&
  334.             /* and current string doesn't include the search string */
  335.             strinc(outseq, mstring) == FALSE)
  336.             goto fail;
  337. #endif
  338.         /* search down any keys bound to this */
  339.         ktp = &keytab[0];
  340.         while (ktp->k_fp != NULL) {
  341.             if (ktp->k_fp == nptr->n_func) {
  342.                 /* padd out some spaces */
  343.                 while (cpos < 25)
  344.                     outseq[cpos++] = ' ';
  345.  
  346.                 /* add in the command sequence */
  347.                 cmdstr(ktp->k_code, &outseq[cpos]);
  348.                 strcat(outseq, EOLSTR);
  349.  
  350.                 /* and add it as a line into the buffer */
  351.                 if (linstr(outseq) != TRUE)
  352.                     return(FALSE);
  353.  
  354.                 cpos = 0;    /* and clear the line */
  355.             }
  356.             ++ktp;
  357.         }
  358.  
  359.         /* if no key was bound, we need to dump it anyway */
  360.         if (cpos > 0) {
  361.             outseq[cpos++] = EOLCHAR;
  362.             outseq[cpos] = 0;
  363.             if (linstr(outseq) != TRUE)
  364.                 return(FALSE);
  365.         }
  366.  
  367. fail:        /* and on to the next name */
  368.         ++nptr;
  369.     }
  370.  
  371.     curwp->w_bufp->b_mode |= MDVIEW;/* put this buffer view mode */
  372.     curbp->b_flag &= ~BFCHG;    /* don't flag this as a change */
  373.     wp->w_dotp = lforw(bp->b_linep);/* back to the beginning */
  374.     wp->w_doto = 0;
  375.     wp = wheadp;            /* and update ALL mode lines */
  376.     while (wp != NULL) {
  377.         wp->w_flag |= WFMODE;
  378.         wp = wp->w_wndp;
  379.     }
  380.     mlwrite("");    /* clear the mode line */
  381.     return(TRUE);
  382. }
  383.  
  384. #if    APROP
  385. strinc(source, sub)    /* does source include sub? */
  386.  
  387. char *source;    /* string to search in */
  388. char *sub;    /* substring to look for */
  389.  
  390. {
  391.     char *sp;    /* ptr into source */
  392.     char *nxtsp;    /* next ptr into source */
  393.     char *tp;    /* ptr into substring */
  394.  
  395.     /* for each character in the source string */
  396.     sp = source;
  397.     while (*sp) {
  398.         tp = sub;
  399.         nxtsp = sp;
  400.  
  401.         /* is the substring here? */
  402.         while (*tp) {
  403.             if (*nxtsp++ != *tp)
  404.                 break;
  405.             else
  406.                 tp++;
  407.         }
  408.  
  409.         /* yes, return a success */
  410.         if (*tp == 0)
  411.             return(TRUE);
  412.  
  413.         /* no, onward */
  414.         sp++;
  415.     }
  416.     return(FALSE);
  417. }
  418. #endif
  419.  
  420. /* get a command key sequence from the keyboard */
  421.  
  422. unsigned int getckey(mflag)
  423.  
  424. int mflag;    /* going for a meta sequence? */
  425.  
  426. {
  427.     register unsigned int c;    /* character fetched */
  428.     char tok[NSTRING];        /* command incoming */
  429.  
  430.     /* check to see if we are executing a command line */
  431.     if (clexec) {
  432.         macarg(tok);    /* get the next token */
  433.         return(stock(tok));
  434.     }
  435.  
  436.     /* or the normal way */
  437.     if (mflag)
  438.         c = get1key();
  439.     else
  440.         c = getcmd();
  441.     return(c);
  442. }
  443.  
  444. /* execute the startup file */
  445. #define __SEG__ INIT
  446. startup(sfname)
  447.  
  448. char *sfname;    /* name of startup file (null if default) */
  449.  
  450. {
  451.     char *fname;    /* resulting file name to execute */
  452.  
  453.     /* look up the startup file */
  454.     if (*sfname != 0)
  455.         fname = flook(sfname, TRUE);
  456.     else
  457.         fname = flook(pathname[0], TRUE);
  458.  
  459.     /* if it isn't around, don't sweat it */
  460.     if (fname == NULL)
  461.         return(TRUE);
  462.  
  463.     /* otherwise, execute the sucker */
  464.     return(dofile(fname));
  465. }
  466. #define __SEG__ bind
  467. /*    Look up the existance of a file along the normal or PATH
  468.     environment variable. Look first in the HOME directory if
  469.     asked and possible
  470. */
  471.  
  472. char *flook(fname, hflag)
  473.  
  474. char *fname;    /* base file name to search for */
  475. int hflag;    /* Look in the HOME environment variable first? */
  476.  
  477. {
  478. #if MAC
  479. /* On the Mac, directories are accessed by Working Directory Reference
  480.  * Numbers, which are set at run time.    In this implementation, we have
  481.  * access to the "current" working directory and to the directory
  482.  * containing MicroEMACS.  These two are searched in that order.  If we
  483.  * get nothing, we use the System Folder.
  484.  */
  485.     int refnum[3];
  486.     int i;
  487.     extern short _iovrefnum;
  488.     SysEnvRec theWorld;
  489.     (void)SysEnvirons(1,&theWorld);
  490.     refnum[2] = theWorld.sysVRefNum;
  491.     if(hflag){
  492.         refnum[0] = ourVRefNum;
  493.         refnum[1] = _iovrefnum;
  494.     }
  495.     else{
  496.         refnum[0] = _iovrefnum;
  497.         refnum[1] = ourVRefNum;
  498.     }
  499.     for(i=0;3-i;i++){
  500.         _iovrefnum = refnum[i];
  501.         if (fexist(fname))return fname;
  502.     }
  503. #else    
  504.     register char *home;    /* path to home directory */
  505.     register char *path;    /* environmental PATH variable */
  506.     register char *sp;    /* pointer into path spec */
  507.     register int i;     /* index */
  508.     static char fspec[NSTRING];    /* full path spec to search */
  509.     char *getenv();
  510.  
  511. #if    ENVFUNC
  512.  
  513.     if (hflag) {
  514.         home = getenv("HOME");
  515.         if (home != NULL) {
  516.             /* build home dir file spec */
  517.             strcpy(fspec, home);
  518.             strcat(fspec, "/");
  519.             strcat(fspec, fname);
  520.  
  521.             /* and try it out */
  522.             if (ffropen(fspec) == FIOSUC) {
  523.                 ffclose();
  524.                 return(fspec);
  525.             }
  526.         }
  527.     }
  528. #endif
  529.  
  530.     /* always try the current directory first */
  531.     if (ffropen(fname) == FIOSUC) {
  532.         ffclose();
  533.         return(fname);
  534.     }
  535.  
  536. #if    ENVFUNC
  537.     /* get the PATH variable */
  538.     path = getenv("PATH");
  539.     if (path != NULL)
  540.         while (*path) {
  541.  
  542.             /* build next possible file spec */
  543.             sp = fspec;
  544. #if    ST520 & MWC
  545.             while (*path && (*path != PATHCHR) && (*path != ','))
  546. #else
  547.             while (*path && (*path != PATHCHR))
  548. #endif
  549.                 *sp++ = *path++;
  550.  
  551.             /* add a terminating dir separator if we need it */
  552.             if (sp != fspec)
  553. #if    ST520
  554.                 *sp++ = '\\';
  555. #else
  556.                 *sp++ = '/';
  557. #endif
  558.             *sp = 0;
  559.             strcat(fspec, fname);
  560.  
  561.             /* and try it out */
  562.             if (ffropen(fspec) == FIOSUC) {
  563.                 ffclose();
  564.                 return(fspec);
  565.             }
  566.  
  567. #if    ST520 & MWC
  568.             if ((*path == PATHCHR) || (*path == ','))
  569. #else
  570.             if (*path == PATHCHR)
  571. #endif
  572.                 ++path;
  573.         }
  574. #endif
  575.  
  576.     /* look it up via the old table method */
  577.     for (i=2; i < NPNAMES; i++) {
  578.         strcpy(fspec, pathname[i]);
  579.         strcat(fspec, fname);
  580.  
  581.         /* and try it out */
  582.         if (ffropen(fspec) == FIOSUC) {
  583.             ffclose();
  584.             return(fspec);
  585.         }
  586.     }
  587. #endif
  588.     return(NULL);    /* no such luck */
  589. }
  590.  
  591. cmdstr(c, seq)    /* change a key command to a string we can print out */
  592.  
  593. int c;        /* sequence to translate */
  594. char *seq;    /* destination string for sequence */
  595.  
  596. {
  597.     char *ptr;    /* pointer into current position in sequence */
  598.  
  599.     ptr = seq;
  600.  
  601.     /* apply meta sequence if needed */
  602.     if (c & META) {
  603.         *ptr++ = 'M';
  604.         *ptr++ = '-';
  605.     }
  606.  
  607.     /* apply ^X sequence if needed */
  608.     if (c & CTLX) {
  609.         *ptr++ = '^';
  610.         *ptr++ = 'X';
  611.     }
  612.  
  613.     /* apply SPEC sequence if needed */
  614.     if (c & SPEC) {
  615.         *ptr++ = 'F';
  616.         *ptr++ = 'N';
  617.     }
  618.  
  619.     /* apply control sequence if needed */
  620.     if (c & CTRL) {
  621.         *ptr++ = '^';
  622.     }
  623.  
  624.     c = c & 255;    /* strip the prefixes */
  625.  
  626.     /* and output the final sequence */
  627.  
  628.     if(c == 0x7F){
  629.         strcpy(ptr,"DEL");    /* Handle special cases. */
  630.     }
  631.     else if(c == ' '){
  632.         strcpy(ptr,"SP");
  633.     }else{
  634.         *ptr++ = c;
  635.         *ptr = 0;    /* terminate the string */
  636.     }
  637.     
  638. }
  639.  
  640. /*    This function looks a key binding up in the binding table    */
  641.  
  642. int (*getbind(c))()
  643.  
  644. int c;    /* key to find what is bound to it */
  645.  
  646. {
  647.     register KEYTAB *ktp;
  648.  
  649.     ktp = &keytab[0];            /* Look in key table.    */
  650.     while (ktp->k_fp != NULL) {
  651.         if (ktp->k_code == c)
  652.             return(ktp->k_fp);
  653.         ++ktp;
  654.     }
  655.  
  656.     /* no such binding */
  657.     return(NULL);
  658. }
  659.  
  660. /* getfname:    This function takes a ptr to function and gets the name
  661.         associated with it
  662. */
  663.  
  664. char *getfname(func)
  665.  
  666. int (*func)();    /* ptr to the requested function to bind to */
  667.  
  668. {
  669.     register NBIND *nptr;    /* pointer into the name binding table */
  670.  
  671.     /* skim through the table, looking for a match */
  672.     nptr = &names[0];
  673.     while (nptr->n_func != NULL) {
  674.         if (nptr->n_func == func)
  675.             return(nptr->n_name);
  676.         ++nptr;
  677.     }
  678.     return(NULL);
  679. }
  680.  
  681. int (*fncmatch(fname))() /* match fname to a function in the names table
  682.                 and return any match or NULL if none        */
  683.  
  684. char *fname;    /* name to attempt to match */
  685.  
  686. {
  687.     register NBIND *ffp;    /* pointer to entry in name binding table */
  688.  
  689.     /* scan through the table, returning any match */
  690.     ffp = &names[0];
  691.     while (ffp->n_func != NULL) {
  692.         if (strcmp(fname, ffp->n_name) == 0)
  693.             return(ffp->n_func);
  694.         ++ffp;
  695.     }
  696.     return(NULL);
  697. }
  698.  
  699. /* stock:    String key name TO Command Key        */
  700.  
  701. unsigned int stock(keyname)
  702.  
  703. char *keyname;        /* name of key to translate to Command key form */
  704.  
  705. {
  706.     register unsigned int c;    /* key sequence to return */
  707.  
  708.     /* parse it up */
  709.     c = 0;
  710.  
  711.     /* first, the META prefix */
  712.     if (*keyname == 'M' && *(keyname+1) == '-') {
  713.         c = META;
  714.         keyname += 2;
  715.     }
  716.  
  717.     /* next the function prefix */
  718.     if (*keyname == 'F' && *(keyname+1) == 'N') {
  719.         c |= SPEC;
  720.         keyname += 2;
  721.     }
  722.  
  723.     /* control-x as well... (but not with FN) */
  724.     if (*keyname == '^' && *(keyname+1) == 'X'&& !(c & SPEC)) {
  725.         c |= CTLX;
  726.         keyname += 2;
  727.     }
  728.  
  729.     /* a control char? */
  730.     if (*keyname == '^' && *(keyname+1) != 0) {
  731.         c |= CTRL;
  732.         ++keyname;
  733.     }
  734.     if (*keyname < 32) {
  735.         c |= CTRL;
  736.         *keyname += 'A';
  737.     }
  738.  
  739.  
  740.     /* make sure we are not lower case (not with function keys)*/
  741.     if (*keyname >= 'a' && *keyname <= 'z' && !(c & SPEC))
  742.         *keyname -= 32;
  743.  
  744.     /* the final sequence... */
  745.     c |= *keyname;
  746.     return(c);
  747. }
  748.  
  749. char *transbind(skey)    /* string key name to binding name.... */
  750.  
  751. char *skey;    /* name of keey to get binding for */
  752.  
  753. {
  754.     char *bindname;
  755.     unsigned int stock();
  756.     int (*getbind())();
  757.  
  758.     bindname = getfname(getbind(stock(skey)));
  759.     if (bindname == NULL)
  760.         bindname = "ERROR";
  761.  
  762.     return(bindname);
  763. }
  764.