home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / memacs / ue311c.arc / BIND.C < prev    next >
C/C++ Source or Header  |  1991-03-25  |  23KB  |  1,018 lines

  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    "eproto.h"
  10. #include    "edef.h"
  11. #include    "elang.h"
  12. #include    "epath.h"
  13.  
  14. PASCAL NEAR help(f, n)    /* give me some help!!!!
  15.            bring up a fake buffer and read the help file
  16.            into it with view mode            */
  17.  
  18. int f,n;    /* prefix flag and argument */
  19.  
  20. {
  21.     register BUFFER *bp;    /* buffer pointer to help */
  22.     char *fname;        /* file name of help file */
  23.  
  24.     /* first check if we are already here */
  25.     bp = bfind("emacs.hlp", FALSE, BFINVS);
  26.  
  27.     if (bp == NULL) {
  28. #if SHARED
  29.         strcpy(tname, pathname[1]);
  30.         fname = flook(tname, FALSE);
  31. #else        
  32.         fname = flook(pathname[1], FALSE);
  33. #endif
  34.         if (fname == NULL) {
  35.             mlwrite(TEXT12);
  36. /*                "[Help file is not online]" */
  37.             return(FALSE);
  38.         }
  39.     }
  40.  
  41.     /* split the current window to make room for the help stuff */
  42.     if (splitwind(FALSE, 1) == FALSE)
  43.             return(FALSE);
  44.  
  45.     if (bp == NULL) {
  46.         /* and read the stuff in */
  47.         if (getfile(fname, FALSE) == FALSE)
  48.             return(FALSE);
  49.     } else
  50.         swbuffer(bp);
  51.  
  52.     /* make this window in VIEW mode, update all mode lines */
  53.     curwp->w_bufp->b_mode |= MDVIEW;
  54.     curwp->w_bufp->b_flag |= BFINVS;
  55.     upmode();
  56.     return(TRUE);
  57. }
  58.  
  59. PASCAL NEAR deskey(f, n)    /* describe the command for a certain key */
  60.  
  61. int f,n;    /* prefix flag and argument */
  62.  
  63. {
  64.     register int c;     /* key to describe */
  65.     register char *ptr;    /* string pointer to scan output strings */
  66.     char outseq[NSTRING];    /* output buffer for command sequence */
  67.  
  68.     /* prompt the user to type us a key to describe */
  69.     mlwrite(TEXT13);
  70. /*        ": describe-key " */
  71.  
  72.     /* get the command sequence to describe
  73.        change it to something we can print as well */
  74.     cmdstr(c = getckey(FALSE), &outseq[0]);
  75.  
  76.     /* and dump it out */
  77.     ostring(outseq);
  78.     ostring(" ");
  79.  
  80.     /* find the right ->function */
  81.     if ((ptr = getfname(getbind(c))) == NULL)
  82.         ptr = "Not Bound";
  83.  
  84.     /* output the command sequence */
  85.     ostring(ptr);
  86. }
  87.  
  88. /* bindtokey:    add a new key to the key binding table        */
  89.  
  90. PASCAL NEAR bindtokey(f, n)
  91.  
  92. int f, n;    /* command arguments [IGNORED] */
  93.  
  94. {
  95.     register unsigned int c;/* command key to bind */
  96.     register int (PASCAL NEAR *kfunc)();/* ptr to the requested function to bind to */
  97.     register KEYTAB *ktp;    /* pointer into the command table */
  98.     register int found;    /* matched command flag */
  99.     char outseq[80];    /* output buffer for keystroke sequence */
  100.  
  101.     /* prompt the user to type in a key to bind */
  102.     /* get the function name to bind it to */
  103.     kfunc = getname(TEXT15);
  104. /*            ": bind-to-key " */
  105.     if (kfunc == NULL) {
  106.         mlwrite(TEXT16);
  107. /*            "[No such function]" */
  108.         return(FALSE);
  109.     }
  110.     if (clexec == FALSE) {
  111.         ostring(" ");
  112.         TTflush();
  113.     }
  114.  
  115.     /* get the command sequence to bind */
  116.     c = getckey((kfunc == meta) || (kfunc == cex) ||
  117.             (kfunc == unarg) || (kfunc == ctrlg));
  118.  
  119.     if (clexec == FALSE) {
  120.  
  121.         /* change it to something we can print as well */
  122.         cmdstr(c, &outseq[0]);
  123.  
  124.         /* and dump it out */
  125.         ostring(outseq);
  126.     }
  127.  
  128.     /* if the function is a unique prefix key */
  129.     if (kfunc == unarg || kfunc == ctrlg || kfunc == quote) {
  130.  
  131.         /* search for an existing binding for the prefix key */
  132.         ktp = &keytab[0];
  133.         while (ktp->k_type != BINDNUL) {
  134.             if (ktp->k_ptr.fp == kfunc)
  135.                 unbindchar(ktp->k_code);
  136.             ++ktp;
  137.         }
  138.  
  139.         /* reset the appropriate global prefix variable */
  140.         if (kfunc == unarg)
  141.             reptc = c;
  142.         if (kfunc == ctrlg)
  143.             abortc = c;
  144.         if (kfunc == quote)
  145.             quotec = c;
  146.     }
  147.  
  148.     /* search the table to see if it exists */
  149.     ktp = &keytab[0];
  150.     found = FALSE;
  151.     while (ktp->k_type != BINDNUL) {
  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_ptr.fp = kfunc;
  161.         ktp->k_type = BINDFNC;
  162.     } else {    /* otherwise we need to add it to the end */
  163.         /* if we run out of binding room, bitch */
  164.         if (ktp >= &keytab[NBINDS]) {
  165.             mlwrite(TEXT17);
  166. /*                "Binding table FULL!" */
  167.             return(FALSE);
  168.         }
  169.  
  170.         ktp->k_code = c;    /* add keycode */
  171.         ktp->k_ptr.fp = kfunc;    /* and the function pointer */
  172.         ktp->k_type = BINDFNC;    /* and the binding type */
  173.         ++ktp;            /* and make sure the next is null */
  174.         ktp->k_code = 0;
  175.         ktp->k_type = BINDNUL;
  176.         ktp->k_ptr.fp = NULL;
  177.     }
  178.  
  179.     /* if we have rebound the meta key, make the
  180.        search terminator follow it            */
  181.     if (kfunc == meta)
  182.         sterm = c;
  183.  
  184.     return(TRUE);
  185. }
  186.  
  187. /* macrotokey:    Bind a key to a macro in the key binding table */
  188.  
  189. PASCAL NEAR macrotokey(f, n)
  190.  
  191. int f, n;    /* command arguments [IGNORED] */
  192.  
  193. {
  194.     register unsigned int c;/* command key to bind */
  195.     register BUFFER *kmacro;/* ptr to buffer of macro to bind to key */
  196.     register KEYTAB *ktp;    /* pointer into the command table */
  197.     register int found;    /* matched command flag */
  198.     register int status;    /* error return */
  199.     char outseq[80];    /* output buffer for keystroke sequence */
  200.     char bufn[NBUFN];    /* buffer to hold macro name */
  201.  
  202.     /* get the buffer name to use */
  203.     if ((status=mlreply(TEXT215, &bufn[1], NBUFN-2)) != TRUE)
  204. /*        ": macro-to-key " */
  205.         return(status);
  206.  
  207.     /* build the responce string for later */
  208.     strcpy(outseq, TEXT215);
  209. /*           ": macro-to-key " */
  210.     strcat(outseq, &bufn[1]);
  211.  
  212.     /* translate it to a buffer pointer */
  213.     bufn[0] = '[';
  214.     strcat(bufn, "]");
  215.     if ((kmacro=bfind(bufn, FALSE, 0)) == NULL) {
  216.         mlwrite(TEXT130);
  217. /*        "Macro not defined"*/
  218.         return(FALSE);
  219.     }
  220.  
  221.     strcat(outseq, " ");
  222.     mlwrite(outseq);
  223.  
  224.     /* get the command sequence to bind */
  225.     c = getckey(FALSE);
  226.  
  227.     /* change it to something we can print as well */
  228.     cmdstr(c, &outseq[0]);
  229.  
  230.     /* and dump it out */
  231.     ostring(outseq);
  232.  
  233.     /* search the table to see if it exists */
  234.     ktp = &keytab[0];
  235.     found = FALSE;
  236.     while (ktp->k_type != BINDNUL) {
  237.         if (ktp->k_code == c) {
  238.             found = TRUE;
  239.             break;
  240.         }
  241.         ++ktp;
  242.     }
  243.  
  244.     if (found) {    /* it exists, just change it then */
  245.         ktp->k_ptr.buf = kmacro;
  246.         ktp->k_type = BINDBUF;
  247.     } else {    /* otherwise we need to add it to the end */
  248.         /* if we run out of binding room, bitch */
  249.         if (ktp >= &keytab[NBINDS]) {
  250.             mlwrite(TEXT17);
  251. /*                "Binding table FULL!" */
  252.             return(FALSE);
  253.         }
  254.  
  255.         ktp->k_code = c;    /* add keycode */
  256.         ktp->k_ptr.buf = kmacro;    /* and the function pointer */
  257.         ktp->k_type = BINDBUF;    /* and the binding type */
  258.         ++ktp;            /* and make sure the next is null */
  259.         ktp->k_code = 0;
  260.         ktp->k_type = BINDNUL;
  261.         ktp->k_ptr.fp = NULL;
  262.     }
  263.  
  264.     return(TRUE);
  265. }
  266.  
  267. /* unbindkey:    delete a key from the key binding table */
  268.  
  269. PASCAL NEAR unbindkey(f, n)
  270.  
  271. int f, n;    /* command arguments [IGNORED] */
  272.  
  273. {
  274.     register int c;     /* command key to unbind */
  275.     char outseq[80];    /* output buffer for keystroke sequence */
  276.  
  277.     /* prompt the user to type in a key to unbind */
  278.     mlwrite(TEXT18);
  279. /*        ": unbind-key " */
  280.  
  281.     /* get the command sequence to unbind */
  282.     c = getckey(FALSE);        /* get a command sequence */
  283.  
  284.     /* change it to something we can print as well */
  285.     cmdstr(c, &outseq[0]);
  286.  
  287.     /* and dump it out */
  288.     ostring(outseq);
  289.  
  290.     /* if it isn't bound, bitch */
  291.     if (unbindchar(c) == FALSE) {
  292.         mlwrite(TEXT19);
  293. /*            "[Key not bound]" */
  294.         return(FALSE);
  295.     }
  296.     return(TRUE);
  297. }
  298.  
  299. PASCAL NEAR unbindchar(c)
  300.  
  301. int c;        /* command key to unbind */
  302.  
  303. {
  304.     register KEYTAB *ktp;    /* pointer into the command table */
  305.     register KEYTAB *sktp;    /* saved pointer into the command table */
  306.     register int found;    /* matched command flag */
  307.  
  308.     /* search the table to see if the key exists */
  309.     ktp = &keytab[0];
  310.     found = FALSE;
  311.     while (ktp->k_type != BINDNUL) {
  312.         if (ktp->k_code == c) {
  313.             found = TRUE;
  314.             break;
  315.         }
  316.         ++ktp;
  317.     }
  318.  
  319.     /* if it isn't bound, bitch */
  320.     if (!found)
  321.         return(FALSE);
  322.  
  323.     /* save the pointer and scan to the end of the table */
  324.     sktp = ktp;
  325.     while (ktp->k_type != BINDNUL)
  326.         ++ktp;
  327.     --ktp;        /* backup to the last legit entry */
  328.  
  329.     /* copy the last entry to the current one */
  330.     sktp->k_code = ktp->k_code;
  331.     sktp->k_type = ktp->k_type;
  332.     sktp->k_ptr.fp     = ktp->k_ptr.fp;
  333.  
  334.     /* null out the last one */
  335.     ktp->k_code = 0;
  336.     ktp->k_type = BINDNUL;
  337.     ktp->k_ptr.fp = NULL;
  338.     return(TRUE);
  339. }
  340.  
  341. /* Describe bindings:
  342.  
  343.        bring up a fake buffer and list the key bindings
  344.        into it with view mode
  345. */
  346.  
  347. PASCAL NEAR desbind(f, n)
  348.  
  349. int f,n;    /* prefix flag and argument */
  350.  
  351. {
  352.     return(buildlist(TRUE, ""));
  353. }
  354.  
  355. PASCAL NEAR apro(f, n)    /* Apropos (List functions that match a substring) */
  356.  
  357. int f,n;    /* prefix flag and argument */
  358.  
  359. {
  360.     char mstring[NSTRING];    /* string to match cmd names to */
  361.     int status;        /* status return */
  362.  
  363.     status = mlreply(TEXT20, mstring, NSTRING - 1);
  364. /*             "Apropos string: " */
  365.     if (status != TRUE)
  366.         return(status);
  367.  
  368.     return(buildlist(FALSE, mstring));
  369. }
  370.  
  371. PASCAL NEAR buildlist(type, mstring)  /* build a binding list (limited or full) */
  372.  
  373. int type;    /* true = full list,   false = partial list */
  374. char *mstring;    /* match string if a partial list */
  375.  
  376. {
  377.     register KEYTAB *ktp;    /* pointer into the command table */
  378.     register NBIND *nptr;    /* pointer into the name binding table */
  379.     register BUFFER *listbuf;/* buffer to put binding list into */
  380.     register BUFFER *bp;    /* buffer ptr for function scan */
  381.     int cpos;        /* current position to use in outseq */
  382.     char outseq[80];    /* output buffer for keystroke sequence */
  383.  
  384.     /* get a buffer for the binding list */
  385.     listbuf = bfind(TEXT21, TRUE, 0);
  386. /*           "Binding list" */
  387.     if (listbuf == NULL || bclear(listbuf) == FALSE) {
  388.         mlwrite(TEXT22);
  389. /*            "Can not display binding list" */
  390.         return(FALSE);
  391.     }
  392.  
  393.     /* let us know this is in progress */
  394.     mlwrite(TEXT23);
  395. /*        "[Building binding list]" */
  396.  
  397.     /* build the contents of this window, inserting it line by line */
  398.     nptr = &names[0];
  399.     while (nptr->n_func != NULL) {
  400.  
  401.         /* add in the command name */
  402.         strcpy(outseq, nptr->n_name);
  403.         cpos = strlen(outseq);
  404.  
  405.         /* if we are executing an apropos command..... */
  406.         if (type == FALSE &&
  407.             /* and current string doesn't include the search string */
  408.             strinc(outseq, mstring) == FALSE)
  409.             goto fail;
  410.  
  411.         /* search down any keys bound to this */
  412.         ktp = &keytab[0];
  413.         while (ktp->k_type != BINDNUL) {
  414.             if (ktp->k_type == BINDFNC &&
  415.                 ktp->k_ptr.fp == nptr->n_func) {
  416.                 /* padd out some spaces */
  417.                 while (cpos < 25)
  418.                     outseq[cpos++] = ' ';
  419.  
  420.                 /* add in the command sequence */
  421.                 cmdstr(ktp->k_code, &outseq[cpos]);
  422.  
  423.                 /* and add it as a line into the buffer */
  424.                 if (addline(listbuf, outseq) != TRUE)
  425.                     return(FALSE);
  426.  
  427.                 cpos = 0;    /* and clear the line */
  428.             }
  429.             ++ktp;
  430.         }
  431.  
  432.         /* if no key was bound, we need to dump it anyway */
  433.         if (cpos > 0) {
  434.             outseq[cpos] = 0;
  435.             if (addline(listbuf, outseq) != TRUE)
  436.                 return(FALSE);
  437.         }
  438.  
  439. fail:        /* and on to the next name */
  440.         ++nptr;
  441.     }
  442.  
  443.     /* add a blank line between the key and macro lists */
  444.     if (addline(listbuf, "") != TRUE)
  445.         return(FALSE);
  446.  
  447.     /* scan all buffers looking for macroes and their bindings */
  448.     bp = bheadp;
  449.     while (bp) {
  450.  
  451.         /* is this buffer a macro? */
  452.         if (bp->b_bname[0] != '[')
  453.             goto bfail;
  454.  
  455.         /* add in the command name */
  456.         strcpy(outseq, bp->b_bname);
  457.         cpos = strlen(outseq);
  458.  
  459.         /* if we are executing an apropos command..... */
  460.         if (type == FALSE &&
  461.             /* and current string doesn't include the search string */
  462.             strinc(outseq, mstring) == FALSE)
  463.             goto bfail;
  464.  
  465.         /* search down any keys bound to this macro */
  466.         ktp = &keytab[0];
  467.         while (ktp->k_type != BINDNUL) {
  468.             if (ktp->k_type == BINDBUF &&
  469.                 ktp->k_ptr.buf == bp) {
  470.                 /* padd out some spaces */
  471.                 while (cpos < 25)
  472.                     outseq[cpos++] = ' ';
  473.  
  474.                 /* add in the command sequence */
  475.                 cmdstr(ktp->k_code, &outseq[cpos]);
  476.  
  477.                 /* and add it as a line into the buffer */
  478.                 if (addline(listbuf, outseq) != TRUE)
  479.                     return(FALSE);
  480.  
  481.                 cpos = 0;    /* and clear the line */
  482.             }
  483.             ++ktp;
  484.         }
  485.  
  486.         /* if no key was bound, we need to dump it anyway */
  487.         if (cpos > 0) {
  488.             outseq[cpos] = 0;
  489.             if (addline(listbuf, outseq) != TRUE)
  490.                 return(FALSE);
  491.         }
  492.  
  493. bfail:        /* and on to the next buffer */
  494.         bp = bp->b_bufp;
  495.     }
  496.  
  497.     wpopup(listbuf);
  498.     mlerase();    /* clear the mode line */
  499.     return(TRUE);
  500. }
  501.  
  502. PASCAL NEAR strinc(source, sub) /* does source include sub? */
  503.  
  504. char *source;    /* string to search in */
  505. char *sub;    /* substring to look for */
  506.  
  507. {
  508.     char *sp;    /* ptr into source */
  509.     char *nxtsp;    /* next ptr into source */
  510.     char *tp;    /* ptr into substring */
  511.  
  512.     /* for each character in the source string */
  513.     sp = source;
  514.     while (*sp) {
  515.         tp = sub;
  516.         nxtsp = sp;
  517.  
  518.         /* is the substring here? */
  519.         while (*tp) {
  520.             if (*nxtsp++ != *tp)
  521.                 break;
  522.             else
  523.                 tp++;
  524.         }
  525.  
  526.         /* yes, return a success */
  527.         if (*tp == 0)
  528.             return(TRUE);
  529.  
  530.         /* no, onward */
  531.         sp++;
  532.     }
  533.     return(FALSE);
  534. }
  535.  
  536. /* get a command key sequence from the keyboard */
  537.  
  538. unsigned int PASCAL NEAR getckey(mflag)
  539.  
  540. int mflag;    /* going for a meta sequence? */
  541.  
  542. {
  543.     register unsigned int c;    /* character fetched */
  544.     char tok[NSTRING];        /* command incoming */
  545.  
  546.     /* check to see if we are executing a command line */
  547.     if (clexec) {
  548.         macarg(tok);    /* get the next token */
  549.         return(stock(tok));
  550.     }
  551.  
  552.     /* or the normal way */
  553.     if (mflag)
  554.         c = getkey();
  555.     else
  556.         c = getcmd();
  557.     return(c);
  558. }
  559.  
  560. /* execute the startup file */
  561.  
  562. PASCAL NEAR startup(sfname)
  563.  
  564. char *sfname;    /* name of startup file (null if default) */
  565.  
  566. {
  567.     char *fname;    /* resulting file name to execute */
  568.     char name[NSTRING];    /* name with extention */
  569.  
  570.     /* look up the startup file */
  571.     if (*sfname != 0) {
  572.  
  573.          /* default the extention */
  574.         strcpy(name, sfname);
  575.         if (sindex(name, ".") == 0)
  576.             strcat(name, ".cmd");
  577.  
  578.         fname = flook(name, TRUE);
  579.     } else
  580. #if SHARED
  581.     {
  582.         strcpy(tname, pathname[0]);
  583.         fname = flook(tname, TRUE);
  584.     }
  585. #else
  586.         fname = flook(pathname[0], TRUE);
  587. #endif
  588.  
  589.     /* if it isn't around, don't sweat it */
  590.     if (fname == NULL)
  591.         return(TRUE);
  592.  
  593.     /* otherwise, execute the sucker */
  594.     return(dofile(fname));
  595. }
  596.  
  597. /*    Look up the existance of a file along the normal or PATH
  598.     environment variable.
  599.  
  600.     LOOKUP ORDER:
  601.  
  602.         if contains path:
  603.  
  604.             absolute
  605.  
  606.         else
  607.  
  608.             current directory
  609.             HOME environment directory
  610.             all directories along PATH environment
  611.             directories in table from EPATH.H
  612. */
  613.  
  614. char *PASCAL NEAR flook(fname, hflag)
  615.  
  616. char *fname;    /* base file name to search for */
  617. int hflag;    /* Look in the HOME environment variable first? */
  618.  
  619. {
  620.     register char *home;    /* path to home directory */
  621.     register char *path;    /* environmental PATH variable */
  622.     register char *sp;    /* pointer into path spec */
  623.     register int i;     /* index */
  624.     static char fspec[NFILEN];    /* full path spec to search */
  625.     char *getenv();
  626.  
  627.     /* if we have an absolute path.. check only there! */
  628.     sp = fname;
  629.     while (*sp) {
  630.         if (*sp == ':' || *sp == '\\' || *sp == '/') {
  631.             if (ffropen(fname) == FIOSUC) {
  632.                 ffclose();
  633.                 return(fname);
  634.             } else
  635.                 return(NULL);
  636.         }
  637.         ++sp;
  638.     }
  639.  
  640.     /* is it in the current directory? */
  641.     if (ffropen(fname) == FIOSUC) {
  642.         ffclose();
  643.         return(fname);
  644.     }
  645.  
  646. #if    ENVFUNC
  647.  
  648.     if (hflag) {
  649. #if WMCS
  650.         home = getenv("SYS$HOME");
  651. #else
  652.         home = getenv("HOME");
  653. #endif
  654.         if (home != NULL) {
  655.             /* build home dir file spec */
  656.             strcpy(fspec, home);
  657. #if WMCS
  658.             strcat(fspec,fname);
  659. #else
  660.             strcat(fspec, "/");
  661.             strcat(fspec, fname);
  662. #endif
  663.  
  664.             /* and try it out */
  665.             if (ffropen(fspec) == FIOSUC) {
  666.                 ffclose();
  667.                 return(fspec);
  668.             }
  669.         }
  670.     }
  671. #endif
  672.  
  673. #if    ENVFUNC
  674.     /* get the PATH variable */
  675. #if WMCS
  676.     path = getenv("OPT$PATH");
  677. #else
  678.     path = getenv("PATH");
  679. #endif
  680.     if (path != NULL)
  681.         while (*path) {
  682.  
  683.             /* build next possible file spec */
  684.             sp = fspec;
  685. #if    ST520 & MWC
  686.             while (*path && (*path != PATHCHR) && (*path != ','))
  687. #else
  688.             while (*path && (*path != PATHCHR))
  689. #endif
  690.                 *sp++ = *path++;
  691.  
  692.             /* add a terminating dir separator if we need it */
  693.             if (*(sp-1) != DIRSEPCHAR)
  694.                 *sp++ = DIRSEPCHAR;
  695.             *sp = 0;
  696.             strcat(fspec, fname);
  697.  
  698.             /* and try it out */
  699.             if (ffropen(fspec) == FIOSUC) {
  700.                 ffclose();
  701.                 return(fspec);
  702.             }
  703.  
  704. #if    ST520 & MWC
  705.             if ((*path == PATHCHR) || (*path == ','))
  706. #else
  707.             if (*path == PATHCHR)
  708. #endif
  709.                 ++path;
  710.         }
  711. #endif
  712.  
  713.     /* look it up via the old table method */
  714.     for (i=2; i < NPNAMES; i++) {
  715.         strcpy(fspec, pathname[i]);
  716.         strcat(fspec, fname);
  717.  
  718.         /* and try it out */
  719.         if (ffropen(fspec) == FIOSUC) {
  720.             ffclose();
  721.             return(fspec);
  722.         }
  723.     }
  724.  
  725.     return(NULL);    /* no such luck */
  726. }
  727.  
  728. PASCAL NEAR cmdstr(c, seq) /* change a key command to a string we can print out */
  729.  
  730. int c;        /* sequence to translate */
  731. char *seq;    /* destination string for sequence */
  732.  
  733. {
  734.     char *ptr;    /* pointer into current position in sequence */
  735.  
  736.     ptr = seq;
  737.  
  738.     /* apply ^X sequence if needed */
  739.     if (c & CTLX) {
  740.         *ptr++ = '^';
  741.         *ptr++ = 'X';
  742.     }
  743.  
  744.     /* apply ALT key sequence if needed */
  745.     if (c & ALTD) {
  746.         *ptr++ = 'A';
  747.         *ptr++ = '-';
  748.     }
  749.  
  750.     /* apply Shifted sequence if needed */
  751.     if (c & SHFT) {
  752.         *ptr++ = 'S';
  753.         *ptr++ = '-';
  754.     }
  755.  
  756.     /* apply MOUS sequence if needed */
  757.     if (c & MOUS) {
  758.         *ptr++ = 'M';
  759.         *ptr++ = 'S';
  760.     }
  761.  
  762.     /* apply meta sequence if needed */
  763.     if (c & META) {
  764.         *ptr++ = 'M';
  765.         *ptr++ = '-';
  766.     }
  767.  
  768.     /* apply SPEC sequence if needed */
  769.     if (c & SPEC) {
  770.         *ptr++ = 'F';
  771.         *ptr++ = 'N';
  772.     }
  773.  
  774.     /* apply control sequence if needed */
  775.     if (c & CTRL) {
  776.         *ptr++ = '^';
  777.     }
  778.  
  779.     c = c & 255;    /* strip the prefixes */
  780.  
  781.     /* and output the final sequence */
  782.  
  783.     *ptr++ = c;
  784.     *ptr = 0;    /* terminate the string */
  785. }
  786.  
  787. /*    This function looks a key binding up in the binding table    */
  788.  
  789. KEYTAB *getbind(c)
  790.  
  791. int c;    /* key to find what is bound to it */
  792.  
  793. {
  794.     register KEYTAB *ktp;
  795.  
  796.     /* scan through the binding table, looking for the key's entry */
  797.     ktp = &keytab[0];
  798.     while (ktp->k_type != BINDNUL) {
  799.         if (ktp->k_code == c)
  800.             return(ktp);
  801.         ++ktp;
  802.     }
  803.  
  804.     /* no such binding */
  805.     return((KEYTAB *)NULL);
  806. }
  807.  
  808. /* getfname:    This function takes a ptr to KEYTAB entry and gets the name
  809.         associated with it
  810. */
  811.  
  812. char *PASCAL NEAR getfname(key)
  813.  
  814. KEYTAB *key;    /* key binding to return a name of */
  815.  
  816. {
  817.     int (PASCAL NEAR *func)(); /* ptr to the requested function */
  818.     register NBIND *nptr;    /* pointer into the name binding table */
  819.     register BUFFER *bp;    /* ptr to buffer to test */
  820.     register BUFFER *kbuf;    /* ptr to requested buffer */
  821.  
  822.     /* if this isn't a valid key, it has no name */
  823.     if (key == NULL)
  824.         return(NULL);
  825.  
  826.     /* skim through the binding table, looking for a match */
  827.     if (key->k_type == BINDFNC) {
  828.         func = key->k_ptr.fp;
  829.         nptr = &names[0];
  830.         while (nptr->n_func != NULL) {
  831.             if (nptr->n_func == func)
  832.                 return(nptr->n_name);
  833.             ++nptr;
  834.         }
  835.         return(NULL);
  836.     }
  837.  
  838.     /* skim through the buffer list looking for a match */
  839.     kbuf = key->k_ptr.buf;
  840.     bp = bheadp;
  841.     while (bp) {
  842.         if (bp == kbuf)
  843.             return(bp->b_bname);
  844.         bp = bp->b_bufp;
  845.     }
  846.     return(NULL);
  847. }
  848.  
  849. /* fncmatch:    match fname to a function in the names table and return
  850.         any match or NULL if none */
  851.  
  852. #if    MSC
  853. int (PASCAL NEAR *PASCAL NEAR fncmatch(char *fname))(void)
  854. #else
  855. int (PASCAL NEAR *PASCAL NEAR fncmatch(fname))()
  856.  
  857. char *fname;    /* name to attempt to match */
  858. #endif
  859.  
  860. {
  861.     int nval;
  862.  
  863.     if ((nval = binary(fname, namval, numfunc)) == -1)
  864.         return(NULL);
  865.     else
  866.         return(names[nval].n_func);
  867. }
  868.  
  869. char *PASCAL NEAR namval(index)
  870.  
  871. int index;    /* index of name to fetch out of the name table */
  872.  
  873. {
  874.     return(names[index].n_name);
  875. }
  876.  
  877. /*    stock()     String key name TO Command Key
  878.  
  879.     A key binding consists of one or more prefix functions followed by
  880.     a keystroke.  Allowable prefixes must be in the following order:
  881.  
  882.     ^X    preceeding control-X
  883.     A-    simeltaneous ALT key (on PCs mainly)
  884.     S-    shifted function key
  885.     MS    mouse generated keystroke
  886.     M-    Preceding META key
  887.     FN    function key
  888.     ^    control key
  889.  
  890.     Meta and ^X prefix of lower case letters are converted to upper
  891.     case.  Real control characters are automatically converted to
  892.     the ^A form.
  893. */
  894.  
  895. unsigned int PASCAL NEAR stock(keyname)
  896.  
  897. char *keyname;    /* name of key to translate to Command key form */
  898.  
  899. {
  900.     register unsigned int c;    /* key sequence to return */
  901.  
  902.     /* parse it up */
  903.     c = 0;
  904.  
  905.     /* Do ^X prefix */
  906.     if(*keyname == '^' && *(keyname+1) == 'X') {
  907.         if(*(keyname+2) != 0) { /* Key is not bare ^X */
  908.             c |= CTLX;
  909.             keyname += 2;
  910.         }
  911.     }
  912.  
  913.     /* and the ALT key prefix */
  914.     if (*keyname == 'A' && *(keyname+1) == '-') {
  915.         c |= ALTD;
  916.         keyname += 2;
  917.     }
  918.  
  919.     /* and the SHIFTED prefix */
  920.     if (*keyname == 'S' && *(keyname+1) == '-') {
  921.         c |= SHFT;
  922.         keyname += 2;
  923.     }
  924.  
  925.     /* and the mouse (MOUS) prefix */
  926.     if (*keyname == 'M' && *(keyname+1) == 'S') {
  927.         c |= MOUS;
  928.         keyname += 2;
  929.     }
  930.  
  931.     /* then the META prefix */
  932.     if (*keyname == 'M' && *(keyname+1) == '-') {
  933.         c |= META;
  934.         keyname += 2;
  935.     }
  936.  
  937.     /* next the function prefix */
  938.     if (*keyname == 'F' && *(keyname+1) == 'N') {
  939.         c |= SPEC;
  940.         keyname += 2;
  941.     }
  942.  
  943.     /* a control char?  (Always upper case) */
  944.     if (*keyname == '^' && *(keyname+1) != 0) {
  945.         c |= CTRL;
  946.         ++keyname;
  947.         uppercase(keyname);
  948.     }
  949.  
  950.     /* A literal control character? (Boo, hiss) */
  951.     if (*keyname < 32) {
  952.         c |= CTRL;
  953.         *keyname += '@';
  954.     }
  955.  
  956.     /* make sure we are not lower case if used with ^X or M- */
  957.     if(!(c & (MOUS|SPEC|ALTD|SHFT)))    /* If not a special key */
  958.         if( c & (CTLX|META))        /* If is a prefix */
  959.         uppercase(keyname);        /* Then make sure it's upper case */
  960.  
  961.     /* the final sequence... */
  962.     c |= *keyname;
  963.     return(c);
  964. }
  965.  
  966. char *PASCAL NEAR transbind(skey)    /* string key name to binding name.... */
  967.  
  968. char *skey;    /* name of key to get binding for */
  969.  
  970. {
  971.     char *bindname;
  972.  
  973.     bindname = getfname(getbind(stock(skey)));
  974.     if (bindname == NULL)
  975.         bindname = errorm;
  976.  
  977.     return(bindname);
  978. }
  979.  
  980. int PASCAL NEAR execkey(key, f, n)    /* execute a function bound to a key */
  981.  
  982. KEYTAB *key;    /* key to execute */
  983. int f, n;    /* agruments to C function */
  984.  
  985. {
  986.     register int status;    /* error return */
  987.  
  988.     if (key->k_type == BINDFNC)
  989.         return((*(key->k_ptr.fp))(f, n));
  990.     if (key->k_type == BINDBUF) {
  991.         while (n--) {
  992.             status = dobuf(key->k_ptr.buf);
  993.             if (status != TRUE)
  994.                 return(status);
  995.         }
  996.     }
  997.     return(TRUE);
  998. }
  999.  
  1000. /* set a KEYTAB to the given name of the given type */
  1001.  
  1002. #if    PROTO
  1003. int setkey(KEYTAB *key, short type, char *name)
  1004. #else
  1005. setkey(key, type, name)
  1006.  
  1007. KEYTAB *key;        /* ptr to key to set */
  1008. short type;        /* type of binding */
  1009. char *name;        /* name of function or buffer */
  1010. #endif
  1011. {
  1012.     key->k_type = type;
  1013.     if (type == BINDFNC)
  1014.         key->k_ptr.fp = fncmatch(name);
  1015.     else if (type == BINDBUF)
  1016.         /* not quite yet... */;
  1017. }
  1018.