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