home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / Shells / tcsh / Source / tc.bind.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-02-21  |  20.6 KB  |  968 lines

  1. /* $Header: /u/christos/src/tcsh-6.03/RCS/tc.bind.c,v 3.11 1992/09/18 20:56:35 christos Exp $ */
  2. /*
  3.  * tc.bind.c: Key binding functions
  4.  */
  5. /*-
  6.  * Copyright (c) 1980, 1991 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions
  11.  * are met:
  12.  * 1. Redistributions of source code must retain the above copyright
  13.  *    notice, this list of conditions and the following disclaimer.
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in the
  16.  *    documentation and/or other materials provided with the distribution.
  17.  * 3. All advertising materials mentioning features or use of this software
  18.  *    must display the following acknowledgement:
  19.  *    This product includes software developed by the University of
  20.  *    California, Berkeley and its contributors.
  21.  * 4. Neither the name of the University nor the names of its contributors
  22.  *    may be used to endorse or promote products derived from this software
  23.  *    without specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35.  * SUCH DAMAGE.
  36.  */
  37. #include "sh.h"
  38.  
  39. RCSID("$Id: tc.bind.c,v 3.11 1992/09/18 20:56:35 christos Exp $")
  40.  
  41. #include "ed.h"
  42. #include "ed.defns.h"
  43.  
  44. static    int    tocontrol    __P((int));
  45. static    char  *unparsekey    __P((int));
  46. static    KEYCMD getkeycmd    __P((Char **));
  47. static    int    parsekey        __P((Char **));
  48. static    void   printkey        __P((KEYCMD *, Char *));
  49. static    KEYCMD parsecmd        __P((Char *));
  50. static    Char  *parsestring    __P((Char *, Char *));
  51. static    void   print_all_keys    __P((void));
  52. static    void   printkeys    __P((KEYCMD *, int, int));
  53. static    void   bindkey_usage    __P((void));
  54. static    void   list_functions    __P((void));
  55. static    void   pkeys        __P((int, int));
  56.  
  57. extern int MapsAreInited;
  58.  
  59. /*
  60.  * Unfortunately the apollo optimizer does not like & operations
  61.  * with 0377, and produces illegal instructions. So we make it
  62.  * an unsigned char, and hope for the best.
  63.  * Of-course the compiler is smart enough to produce bad assembly
  64.  * language instructions, but dumb when it comes to fold the constant :-)
  65.  */
  66. #ifdef apollo
  67. static unsigned char APOLLO_0377 = 0377;
  68. #else /* sane */
  69. # define APOLLO_0377    0377
  70. #endif /* apollo */
  71.  
  72.  
  73. static int
  74. tocontrol(c)
  75.     int    c;
  76. {
  77.     c &= CHAR;
  78.     if (Islower(c))
  79.     c = Toupper(c);
  80.     else if (c == ' ')
  81.     c = '@';
  82.     if (c == '?')
  83.     c = 0177;
  84.     else
  85.     c &= 037;
  86.     return (c);
  87. }
  88.  
  89. static char *
  90. unparsekey(c)            /* 'c' -> "c", '^C' -> "^" + "C" */
  91.     register int c;
  92. {
  93.     register char *cp;
  94.     static char tmp[10];
  95.  
  96.     cp = tmp;
  97.  
  98.     if (c & 0400) {
  99.     *cp++ = 'A';
  100.     *cp++ = '-';
  101.     c &= APOLLO_0377;
  102.     }
  103.     if ((c & META) && !(Isprint(c) || (Iscntrl(c) && Isprint(c | 0100)))) {
  104.     *cp++ = 'M';
  105.     *cp++ = '-';
  106.     c &= ASCII;
  107.     }
  108.     if (Isprint(c)) {
  109.     *cp++ = c;
  110.     *cp = '\0';
  111.     return (tmp);
  112.     }
  113.     switch (c) {
  114.     case ' ':
  115.     (void) strcpy(cp, "Spc");
  116.     return (tmp);
  117.     case '\n':
  118.     (void) strcpy(cp, "Lfd");
  119.     return (tmp);
  120.     case '\r':
  121.     (void) strcpy(cp, "Ret");
  122.     return (tmp);
  123.     case '\t':
  124.     (void) strcpy(cp, "Tab");
  125.     return (tmp);
  126.     case '\033':
  127.     (void) strcpy(cp, "Esc");
  128.     return (tmp);
  129.     case '\177':
  130.     (void) strcpy(cp, "Del");
  131.     return (tmp);
  132.     default:
  133.     *cp++ = '^';
  134.     if (c == '\177') {
  135.         *cp++ = '?';
  136.     }
  137.     else {
  138.         *cp++ = c | 0100;
  139.     }
  140.     *cp = '\0';
  141.     return (tmp);
  142.     }
  143. }
  144.  
  145. static  KEYCMD
  146. getkeycmd(sp)
  147.     Char  **sp;
  148. {
  149.     register Char *s = *sp;
  150.     register char c;
  151.     register KEYCMD keycmd = F_UNASSIGNED;
  152.     KEYCMD *map;
  153.     int     meta = 0;
  154.     Char   *ret_sp = s;
  155.  
  156.     map = CcKeyMap;
  157.  
  158.     while (*s) {
  159.     if (*s == '^' && s[1]) {
  160.         s++;
  161.         c = tocontrol(*s++);
  162.     }
  163.     else
  164.         c = *s++;
  165.  
  166.     if (*s == '\0')
  167.         break;
  168.  
  169.     switch (map[c | meta]) {
  170.     case F_METANEXT:
  171.         meta = META;
  172.         keycmd = F_METANEXT;
  173.         ret_sp = s;
  174.         break;
  175.  
  176.     case F_XKEY:
  177.         keycmd = F_XKEY;
  178.         ret_sp = s;
  179.         /* FALLTHROUGH */
  180.  
  181.     default:
  182.         *sp = ret_sp;
  183.         return (keycmd);
  184.  
  185.     }
  186.     }
  187.     *sp = ret_sp;
  188.     return (keycmd);
  189. }
  190.  
  191. static int
  192. parsekey(sp)
  193.     Char  **sp;            /* Return position of first unparsed character
  194.                  * for return value -2 (xkeynext) */
  195. {
  196.     register int c, meta = 0, control = 0, ctrlx = 0;
  197.     Char   *s = *sp;
  198.     KEYCMD  keycmd;
  199.  
  200.     if (s == NULL) {
  201.     xprintf("bad key specification -- null string\n");
  202.     return -1;
  203.     }
  204.     if (*s == 0) {
  205.     xprintf("bad key specification -- empty string\n");
  206.     return -1;
  207.     }
  208.  
  209.     (void) strip(s);        /* trim to 7 bits. */
  210.  
  211.     if (s[1] == 0)        /* single char */
  212.     return (s[0] & APOLLO_0377);
  213.  
  214.     if ((s[0] == 'F' || s[0] == 'f') && s[1] == '-') {
  215.     if (s[2] == 0) {
  216.         xprintf("Bad function-key specification.  Null key not allowed\n");
  217.         return (-1);
  218.     }
  219.     *sp = s + 2;
  220.     return (-2);
  221.     }
  222.  
  223.     if (s[0] == '0' && s[1] == 'x') {    /* if 0xn, then assume number */
  224.     c = 0;
  225.     for (s += 2; *s; s++) {    /* convert to hex; skip the first 0 */
  226.         c *= 16;
  227.         if (!Isxdigit(*s)) {
  228.         xprintf("bad key specification -- malformed hex number\n");
  229.         return -1;    /* error */
  230.         }
  231.         if (Isdigit(*s))
  232.         c += *s - '0';
  233.         else if (*s >= 'a' && *s <= 'f')
  234.         c += *s - 'a' + 0xA;
  235.         else if (*s >= 'F' && *s <= 'F')
  236.         c += *s - 'A' + 0xA;
  237.     }
  238.     }
  239.     else if (s[0] == '0' && Isdigit(s[1])) {    /* if 0n, then assume number */
  240.     c = 0;
  241.     for (s++; *s; s++) {    /* convert to octal; skip the first 0 */
  242.         if (!Isdigit(*s) || *s == '8' || *s == '9') {
  243.         xprintf("bad key specification -- malformed octal number\n");
  244.         return -1;    /* error */
  245.         }
  246.         c = (c * 8) + *s - '0';
  247.     }
  248.     }
  249.     else if (Isdigit(s[0]) && Isdigit(s[1])) {    /* decimal number */
  250.     c = 0;
  251.     for (; *s; s++) {    /* convert to octal; skip the first 0 */
  252.         if (!Isdigit(*s)) {
  253.         xprintf("bad key specification -- malformed decimal number\n");
  254.         return -1;    /* error */
  255.         }
  256.         c = (c * 10) + *s - '0';
  257.     }
  258.     }
  259.     else {
  260.     keycmd = getkeycmd(&s);
  261.  
  262.     if ((s[0] == 'X' || s[0] == 'x') && s[1] == '-') {    /* X- */
  263.         ctrlx++;
  264.         s += 2;
  265.         keycmd = getkeycmd(&s);
  266.     }
  267.     if ((*s == 'm' || *s == 'M') && s[1] == '-') {    /* meta */
  268.         meta++;
  269.         s += 2;
  270.         keycmd = getkeycmd(&s);
  271.     }
  272.     else if (keycmd == F_METANEXT && *s) {    /* meta */
  273.         meta++;
  274.         keycmd = getkeycmd(&s);
  275.     }
  276.     if (*s == '^' && s[1]) {
  277.         control++;
  278.         s++;
  279.         keycmd = getkeycmd(&s);
  280.     }
  281.     else if ((*s == 'c' || *s == 'C') && s[1] == '-') {    /* control */
  282.         control++;
  283.         s += 2;
  284.         keycmd = getkeycmd(&s);
  285.     }
  286.  
  287.     if (keycmd == F_XKEY) {
  288.         if (*s == 0) {
  289.         xprintf("Bad function-key specification.\n");
  290.         xprintf("Null key not allowed\n");
  291.         return (-1);
  292.         }
  293.         *sp = s;
  294.         return (-2);
  295.     }
  296.  
  297.     if (s[1] != 0) {    /* if symbolic name */
  298.         char   *ts;
  299.  
  300.         ts = short2str(s);
  301.         if (!strcmp(ts, "space") || !strcmp(ts, "Spc"))
  302.         c = ' ';
  303.         else if (!strcmp(ts, "return") || !strcmp(ts, "Ret"))
  304.         c = '\r';
  305.         else if (!strcmp(ts, "newline") || !strcmp(ts, "Lfd"))
  306.         c = '\n';
  307.         else if (!strcmp(ts, "linefeed"))
  308.         c = '\n';
  309.         else if (!strcmp(ts, "tab"))
  310.         c = '\t';
  311.         else if (!strcmp(ts, "escape") || !strcmp(ts, "Esc"))
  312.         c = '\033';
  313.         else if (!strcmp(ts, "backspace"))
  314.         c = '\b';
  315.         else if (!strcmp(ts, "delete"))
  316.         c = '\177';
  317.         else {
  318.         xprintf("bad key specification -- unknown name \"%s\"\n", s);
  319.         return -1;    /* error */
  320.         }
  321.     }
  322.     else
  323.         c = *s;        /* just a single char */
  324.  
  325.     if (control)
  326.         c = tocontrol(c);
  327.     if (meta)
  328.         c |= META;
  329.     if (ctrlx)
  330.         c |= 0400;
  331.     }
  332.     return (c & 0777);
  333. }
  334.  
  335.  
  336. /*ARGSUSED*/
  337. void
  338. dobindkey(v, c)
  339.     Char  **v;
  340.     struct command *c;
  341. {
  342.     KEYCMD *map;
  343.     int     ntype, no, remove, key;
  344.     Char   *par;
  345.     Char    p;
  346.     Char    inbuf[200];
  347.     Char    outbuf[200];
  348.     Char   *in;
  349.     Char   *out;
  350.     KEYCMD  cmd;
  351.  
  352.     if (!MapsAreInited)
  353.     ed_InitMaps();
  354.  
  355.     map = CcKeyMap;
  356.     ntype = XK_CMD;
  357.     key = remove = 0;
  358.     for (no = 1, par = v[no]; 
  359.      par != NULL && (*par++ & CHAR) == '-'; no++, par = v[no]) {
  360.     if ((p = (*par & CHAR)) == '-')
  361.         break;
  362.     else 
  363.         switch (p) {
  364.         case 'k':
  365.         key = 1;
  366.         break;
  367.         case 'a':
  368.         map = CcAltMap;
  369.         break;
  370.         case 's':
  371.         ntype = XK_STR;
  372.         break;
  373.         case 'c':
  374.         ntype = XK_EXE;
  375.         break;
  376.         case 'r':
  377.         remove = 1;
  378.         break;
  379.         case 'v':
  380.         ed_InitVIMaps();
  381.         return;
  382.         case 'e':
  383.         ed_InitEmacsMaps();
  384.         return;
  385.         case 'd':
  386. #ifdef VIDEFAULT
  387.         ed_InitVIMaps();
  388. #else /* EMACSDEFAULT */
  389.         ed_InitEmacsMaps();
  390. #endif /* VIDEFAULT */
  391.         return;
  392.         case 'l':
  393.         list_functions();
  394.         return;
  395.         default:
  396.         bindkey_usage();
  397.         return;
  398.         }
  399.     }
  400.  
  401.     if (!v[no]) {
  402.     print_all_keys();
  403.     return;
  404.     }
  405.  
  406.     if (key) 
  407.     in = v[no++];
  408.     else
  409.     if ((in = parsestring(v[no++], inbuf)) == NULL)
  410.         return;
  411.  
  412.     if (remove) {
  413.     if (key) {
  414.         (void) ClearArrowKeys(in);
  415.         return;
  416.     }
  417.     if (in[1]) {
  418.         (void) DeleteXkey(in);
  419.     }
  420.     else if (map[(unsigned char) *in] == F_XKEY) {
  421.         (void) DeleteXkey(in);
  422.         map[(unsigned char) *in] = F_UNASSIGNED;
  423.     }
  424.     else {
  425.         map[(unsigned char) *in] = F_UNASSIGNED;
  426.     }
  427.     return;
  428.     }
  429.     if (!v[no]) {
  430.     if (key)
  431.         PrintArrowKeys(in);
  432.     else
  433.         printkey(map, in);
  434.     return;
  435.     }
  436.     if (v[no + 1]) {
  437.     bindkey_usage();
  438.     return;
  439.     }
  440.     switch (ntype) {
  441.     case XK_STR:
  442.     case XK_EXE:
  443.     if ((out = parsestring(v[no], outbuf)) == NULL)
  444.         return;
  445.     if (key)
  446.         SetArrowKeys(in, XmapStr(out), ntype);
  447.     else
  448.         AddXkey(in, XmapStr(out), ntype);
  449.     map[(unsigned char) *in] = F_XKEY;
  450.     break;
  451.     case XK_CMD:
  452.     if ((cmd = parsecmd(v[no])) == 0)
  453.         return;
  454.     if (key)
  455.         SetArrowKeys(in, XmapCmd((int) cmd), ntype);
  456.     else {
  457.         if (in[1]) {
  458.         AddXkey(in, XmapCmd((int) cmd), ntype);
  459.         map[(unsigned char) *in] = F_XKEY;
  460.         }
  461.         else {
  462.         ClearXkey(map, in);
  463.         map[(unsigned char) *in] = cmd;
  464.         }
  465.     }
  466.     break;
  467.     default:
  468.     abort();
  469.     break;
  470.     }
  471.     if (key)
  472.     BindArrowKeys();
  473. }
  474.  
  475. static void
  476. printkey(map, in)
  477.     KEYCMD *map;
  478.     Char   *in;
  479. {
  480.     unsigned char outbuf[100];
  481.     register struct KeyFuncs *fp;
  482.  
  483.     if (in[0] == 0 || in[1] == 0) {
  484.     (void) unparsestring(in, outbuf, STRQQ);
  485.     for (fp = FuncNames; fp->name; fp++) {
  486.         if (fp->func == map[(unsigned char) *in]) {
  487.         xprintf("%s\t->\t%s\n", outbuf, fp->name);
  488.         }
  489.     }
  490.     }
  491.     else 
  492.     PrintXkey(in);
  493. }
  494.  
  495. static  KEYCMD
  496. parsecmd(str)
  497.     Char   *str;
  498. {
  499.     register struct KeyFuncs *fp;
  500.  
  501.     for (fp = FuncNames; fp->name; fp++) {
  502.     if (strcmp(short2str(str), fp->name) == 0) {
  503.         return fp->func;
  504.     }
  505.     }
  506.     xprintf("Bad command name: %S\n", str);
  507.     return 0;
  508. }
  509.  
  510. int
  511. parseescape(ptr)
  512.     Char  **ptr;
  513. {
  514.     Char   *p, c;
  515.  
  516.     p = *ptr;
  517.  
  518.     if ((p[1] & CHAR) == 0) {
  519.     xprintf("Something must follow: %c\n", *p);
  520.     return 0;
  521.     }
  522.     if ((*p & CHAR) == '\\') {
  523.     p++;
  524.     switch (*p & CHAR) {
  525.     case 'a':
  526.         c = '\007';        /* Bell */
  527.         break;
  528.     case 'b':
  529.         c = '\010';        /* Backspace */
  530.         break;
  531.     case 't':
  532.         c = '\011';        /* Horizontal Tab */
  533.         break;
  534.     case 'n':
  535.         c = '\012';        /* New Line */
  536.         break;
  537.     case 'v':
  538.         c = '\013';        /* Vertical Tab */
  539.         break;
  540.     case 'f':
  541.         c = '\014';        /* Form Feed */
  542.         break;
  543.     case 'r':
  544.         c = '\015';        /* Carriage Return */
  545.         break;
  546.     case 'e':
  547.         c = '\033';        /* Escape */
  548.         break;
  549.     case '0':
  550.     case '1':
  551.     case '2':
  552.     case '3':
  553.     case '4':
  554.     case '5':
  555.     case '6':
  556.     case '7':
  557.         {
  558.         register int cnt, val, ch;
  559.  
  560.         for (cnt = 0, val = 0; cnt < 3; cnt++) {
  561.             ch = *p++ & CHAR;
  562.             if (ch < '0' || ch > '7') {
  563.             p--;
  564.             break;
  565.             }
  566.             val = (val << 3) | (ch - '0');
  567.         }
  568.         if ((val & 0xffffff00) != 0) {
  569.             xprintf("Octal constant does not fit in a char.\n");
  570.             return 0;
  571.         }
  572.         c = (Char) val;
  573.         --p;
  574.         }
  575.         break;
  576.     default:
  577.         c = *p;
  578.         break;
  579.     }
  580.     }
  581.     else if ((*p & CHAR) == '^' && (Isalpha(p[1] & CHAR) || 
  582.                     strchr("@^_?\\|[{]}", p[1] & CHAR))) {
  583.     p++;
  584.     c = (*p == '?') ? '\177' : ((*p & CHAR) & 0237);
  585.     }
  586.     else
  587.     c = *p;
  588.     *ptr = p;
  589.     return (c);
  590. }
  591.  
  592. static Char *
  593. parsestring(str, buf)
  594.     Char   *str;
  595.     Char   *buf;
  596. {
  597.     Char   *b;
  598.     Char   *p;
  599.  
  600.     b = buf;
  601.     if (*str == 0) {
  602.     xprintf("Null string specification\n");
  603.     return 0;
  604.     }
  605.  
  606.     for (p = str; *p != 0; p++) {
  607.     if ((*p & CHAR) == '\\' || (*p & CHAR) == '^') {
  608.         if ((*b++ = parseescape(&p)) == 0)
  609.         return 0;
  610.     }
  611.     else {
  612.         *b++ = *p & CHAR;
  613.     }
  614.     }
  615.     *b = 0;
  616.     return buf;
  617. }
  618.  
  619. unsigned char *
  620. unparsestring(str, buf, sep)
  621.     Char   *str;
  622.     unsigned char *buf;
  623.     Char   *sep;
  624. {
  625.     unsigned char *b;
  626.     Char   *p;
  627.  
  628.     b = buf;
  629.     *b++ = sep[0];
  630.     if (*str == 0) {
  631.     *b++ = '^';
  632.     *b++ = '@';
  633.     *b++ = sep[1];
  634.     *b++ = 0;
  635.     return buf;
  636.     }
  637.  
  638.     for (p = str; *p != 0; p++) {
  639.     if (Iscntrl(*p)) {
  640.         *b++ = '^';
  641.         if (*p == '\177')
  642.         *b++ = '?';
  643.         else
  644.         *b++ = *p | 0100;
  645.     }
  646.     else if (*p == '^' || *p == '\\') {
  647.         *b++ = '\\';
  648.         *b++ = *p;
  649.     }
  650.     else if (*p == ' ' || (Isprint(*p) && !Isspace(*p))) {
  651.         *b++ = *p;
  652.     }
  653.     else {
  654.         *b++ = '\\';
  655.         *b++ = ((*p >> 6) & 7) + '0';
  656.         *b++ = ((*p >> 3) & 7) + '0';
  657.         *b++ = (*p & 7) + '0';
  658.     }
  659.     }
  660.     *b++ = sep[1];
  661.     *b++ = 0;
  662.     return buf;            /* should check for overflow */
  663. }
  664.  
  665. static void
  666. print_all_keys()
  667. {
  668.     int     prev, i;
  669.  
  670.     xprintf("Standard key bindings\n");
  671.     prev = 0;
  672.     for (i = 0; i < 256; i++) {
  673.     if (CcKeyMap[prev] == CcKeyMap[i])
  674.         continue;
  675.     printkeys(CcKeyMap, prev, i - 1);
  676.     prev = i;
  677.     }
  678.     printkeys(CcKeyMap, prev, i - 1);
  679.  
  680.     xprintf("Alternative key bindings\n");
  681.     prev = 0;
  682.     for (i = 0; i < 256; i++) {
  683.     if (CcAltMap[prev] == CcAltMap[i])
  684.         continue;
  685.     printkeys(CcAltMap, prev, i - 1);
  686.     prev = i;
  687.     }
  688.     printkeys(CcAltMap, prev, i - 1);
  689.     xprintf("Multi-character bindings\n");
  690.     PrintXkey(STRNULL);    /* print all Xkey bindings */
  691.     xprintf("Arrow key bindings\n");
  692.     PrintArrowKeys(STRNULL);
  693. }
  694.  
  695. static void
  696. printkeys(map, first, last)
  697.     KEYCMD *map;
  698.     int     first, last;
  699. {
  700.     register struct KeyFuncs *fp;
  701.     Char    firstbuf[2], lastbuf[2];
  702.     unsigned char unparsbuf[10], extrabuf[10];
  703.  
  704.     firstbuf[0] = first;
  705.     firstbuf[1] = 0;
  706.     lastbuf[0] = last;
  707.     lastbuf[1] = 0;
  708.     if (map[first] == F_UNASSIGNED) {
  709.     if (first == last)
  710.         xprintf("%-15s->  is undefined\n",
  711.             unparsestring(firstbuf, unparsbuf, STRQQ));
  712.     return;
  713.     }
  714.  
  715.     for (fp = FuncNames; fp->name; fp++) {
  716.     if (fp->func == map[first]) {
  717.         if (first == last) {
  718.         xprintf("%-15s->  %s\n",
  719.             unparsestring(firstbuf, unparsbuf, STRQQ), fp->name);
  720.         }
  721.         else {
  722.         xprintf("%-4s to %-7s->  %s\n",
  723.             unparsestring(firstbuf, unparsbuf, STRQQ),
  724.             unparsestring(lastbuf, extrabuf, STRQQ), fp->name);
  725.         }
  726.         return;
  727.     }
  728.     }
  729.     if (map == CcKeyMap) {
  730.     xprintf("BUG!!! %s isn't bound to anything.\n",
  731.         unparsestring(firstbuf, unparsbuf, STRQQ));
  732.     xprintf("CcKeyMap[%d] == %d\n", first, CcKeyMap[first]);
  733.     }
  734.     else {
  735.     xprintf("BUG!!! %s isn't bound to anything.\n",
  736.         unparsestring(firstbuf, unparsbuf, STRQQ));
  737.     xprintf("CcAltMap[%d] == %d\n", first, CcAltMap[first]);
  738.     }
  739. }
  740.  
  741. static void
  742. bindkey_usage()
  743. {
  744.     xprintf(
  745.     "Usage: bindkey [options] [--] [in-string [out-string | command]]\n");
  746.     xprintf("    -a   bind key in alternative key binding\n");
  747.     xprintf("    -s   bind an out-string instead of a command\n");
  748.     xprintf("    -c   bind a unix-command instead of a command\n");
  749.     xprintf("    -v   initialized maps to default vi bindings\n");
  750.     xprintf("    -e   initialized maps to default emacs bindings\n");
  751.     xprintf("    -d   initialized maps to default bindings\n");
  752.     xprintf("    -l   list available functions with descriptions\n");
  753.     xprintf("    -r   remove the binding of in-string\n");
  754.     xprintf("    -k   bind arrow key with name in in-string\n");
  755.     xprintf(
  756.        "\nIn no out-string or command is given, the binding for in-string\n");
  757.     xprintf("is printed or all bindings if in-strings is not given.\n");
  758. }
  759.  
  760. static void
  761. list_functions()
  762. {
  763.     register struct KeyFuncs *fp;
  764.  
  765.     for (fp = FuncNames; fp->name; fp++) {
  766.     xprintf("%s\n          %s\n", fp->name, fp->description);
  767.     }
  768. }
  769.  
  770. /*ARGSUSED*/
  771. void
  772. dobind(v, dummy)
  773.     register Char **v;
  774.     struct command *dummy;
  775. {
  776.     register int c;
  777.     register struct KeyFuncs *fp;
  778.     register int i, prev;
  779.     Char   *p, *l;
  780.     Char    buf[1000];
  781.  
  782.     /*
  783.      * Assume at this point that i'm given 2 or 3 args - 'bind', the f-name,
  784.      * and the key; or 'bind' key to print the func for that key.
  785.      */
  786.  
  787.     if (!MapsAreInited)
  788.     ed_InitMaps();
  789.  
  790.     if (v[1] && v[2] && v[3]) {
  791.     xprintf(
  792.        "usage: bind [KEY | COMMAND KEY | \"emacs\" | \"vi\" | \"-a\"]\n");
  793.     return;
  794.     }
  795.  
  796.     if (v[1] && v[2]) {        /* if bind FUNCTION KEY */
  797.     for (fp = FuncNames; fp->name; fp++) {
  798.         if (strcmp(short2str(v[1]), fp->name) == 0) {
  799.         Char   *s = v[2];
  800.  
  801.         if ((c = parsekey(&s)) == -1)
  802.             return;
  803.         if (c == -2) {    /* extented key */
  804.             for (i = 0; i < 256; i++) {
  805.             if (i != 033 && (CcKeyMap[i] == F_XKEY ||
  806.                      CcAltMap[i] == F_XKEY)) {
  807.                 p = buf;
  808.                 if (i > 0177) {
  809.                 *p++ = 033;
  810.                 *p++ = i & ASCII;
  811.                 }
  812.                 else {
  813.                 *p++ = (Char) i;
  814.                 }
  815.                 for (l = s; *l != 0; l++) {
  816.                 *p++ = *l;
  817.                 }
  818.                 *p = 0;
  819.                 AddXkey(buf, XmapCmd(fp->func), XK_CMD);
  820.             }
  821.             }
  822.             return;
  823.         }
  824.         if (c & 0400) {
  825.             if (VImode) {
  826.             CcAltMap[c & APOLLO_0377] = fp->func;    
  827.             /* bind the vi cmd mode key */
  828.             if (c & META) {
  829.                 buf[0] = 033;
  830.                 buf[1] = c & ASCII;
  831.                 buf[2] = 0;
  832.                 AddXkey(buf, XmapCmd(fp->func), XK_CMD);
  833.             }
  834.             }
  835.             else {
  836.             buf[0] = 030;    /* ^X */
  837.             buf[1] = c & APOLLO_0377;
  838.             buf[2] = 0;
  839.             AddXkey(buf, XmapCmd(fp->func), XK_CMD);
  840.             CcKeyMap[030] = F_XKEY;
  841.             }
  842.         }
  843.         else {
  844.             CcKeyMap[c] = fp->func;    /* bind the key */
  845.             if (c & META) {
  846.             buf[0] = 033;
  847.             buf[1] = c & ASCII;
  848.             buf[2] = 0;
  849.             AddXkey(buf, XmapCmd(fp->func), XK_CMD);
  850.             }
  851.         }
  852.         return;
  853.         }
  854.     }
  855.     stderror(ERR_NAME | ERR_STRING, "Invalid function");
  856.     }
  857.     else if (v[1]) {
  858.     char   *cv = short2str(v[1]);
  859.  
  860.     if (strcmp(cv, "list") == 0) {
  861.         for (fp = FuncNames; fp->name; fp++) {
  862.         xprintf("%s\n", fp->name);
  863.         }
  864.         return;
  865.     }
  866.     if ((strcmp(cv, "emacs") == 0) ||
  867. #ifndef VIDEFAULT
  868.         (strcmp(cv, "defaults") == 0) ||
  869.         (strcmp(cv, "default") == 0) ||
  870. #endif
  871.         (strcmp(cv, "mg") == 0) ||
  872.         (strcmp(cv, "gnumacs") == 0)) {
  873.         /* reset keys to default */
  874.         ed_InitEmacsMaps();
  875. #ifdef VIDEFAULT
  876.     }
  877.     else if ((strcmp(cv, "vi") == 0)
  878.          || (strcmp(cv, "default") == 0)
  879.          || (strcmp(cv, "defaults") == 0)) {
  880. #else
  881.     }
  882.     else if (strcmp(cv, "vi") == 0) {
  883. #endif
  884.         ed_InitVIMaps();
  885.     }
  886.     else {            /* want to know what this key does */
  887.         Char   *s = v[1];
  888.  
  889.         if ((c = parsekey(&s)) == -1)
  890.         return;
  891.         if (c == -2) {    /* extended key */
  892.         PrintXkey(s);
  893.         return;
  894.         }
  895.         pkeys(c, c);    /* must be regular key */
  896.     }
  897.     }
  898.     else {            /* list all the bindings */
  899.     prev = 0;
  900.     for (i = 0; i < 256; i++) {
  901.         if (CcKeyMap[prev] == CcKeyMap[i])
  902.         continue;
  903.         pkeys(prev, i - 1);
  904.         prev = i;
  905.     }
  906.     pkeys(prev, i - 1);
  907.     prev = 0;
  908.     for (i = 256; i < 512; i++) {
  909.         if (CcAltMap[prev & APOLLO_0377] == CcAltMap[i & APOLLO_0377])
  910.         continue;
  911.         pkeys(prev, i - 1);
  912.         prev = i;
  913.     }
  914.     pkeys(prev, i - 1);
  915.     PrintXkey(STRNULL);    /* print all Xkey bindings */
  916.     }
  917.     return;
  918. }
  919.  
  920. static void
  921. pkeys(first, last)
  922.     register int first, last;
  923. {
  924.     register struct KeyFuncs *fp;
  925.     register KEYCMD *map;
  926.     int mask;
  927.     char    buf[8];
  928.  
  929.     if (last & 0400) {
  930.     map = CcAltMap;
  931.     first &= APOLLO_0377;
  932.     last &= APOLLO_0377;
  933.     mask = 0400;
  934.     }
  935.     else {
  936.     map = CcKeyMap;
  937.     mask = 0;
  938.     }
  939.     if (map[first] == F_UNASSIGNED) {
  940.     if (first == last)
  941.         xprintf(" %s\t\tis undefined\n", unparsekey(first | mask));
  942.     return;
  943.     }
  944.  
  945.     for (fp = FuncNames; fp->name; fp++) {
  946.     if (fp->func == map[first]) {
  947.         if (first == last) 
  948.         xprintf(" %s\t\t%s\n", 
  949.             unparsekey((first & APOLLO_0377) | mask), fp->name);
  950.         else {
  951.         (void) strcpy(buf, unparsekey((first & APOLLO_0377) | mask));
  952.         xprintf(" %s..%s\t\t%s\n", buf,
  953.                 unparsekey((last & APOLLO_0377) | mask), fp->name);
  954.         }
  955.         return;
  956.     }
  957.     }
  958.     if (map == CcKeyMap) {
  959.     xprintf("BUG!!! %s isn't bound to anything.\n", unparsekey(first));
  960.     xprintf("CcKeyMap[%d] == %d\n", first, CcKeyMap[first]);
  961.     }
  962.     else {
  963.     xprintf("BUG!!! %s isn't bound to anything.\n",
  964.         unparsekey(first & 0400));
  965.     xprintf("CcAltMap[%d] == %d\n", first, CcAltMap[first]);
  966.     }
  967. }
  968.