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