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

  1. /* $Header: /u/christos/src/tcsh-6.03/RCS/ed.xmap.c,v 3.9 1992/10/14 20:19:19 christos Exp $ */
  2. /*
  3.  * ed.xmap.c: This module contains the procedures for maintaining
  4.  *          the extended-key map.
  5.  *
  6.  *           An extended-key (Xkey) is a sequence of keystrokes
  7.  *          introduced with an sequence introducer and consisting
  8.  *          of an arbitrary number of characters.  This module maintains
  9.  *          a map (the Xmap) to convert these extended-key sequences
  10.  *           into input strings (XK_STR), editor functions (XK_CMD), or
  11.  *          unix commands (XK_EXE). It contains the
  12.  *          following externally visible functions.
  13.  *
  14.  *        int GetXkey(ch,val);
  15.  *        Char *ch;
  16.  *        XmapVal *val;
  17.  *
  18.  *          Looks up *ch in map and then reads characters until a
  19.  *          complete match is found or a mismatch occurs. Returns the
  20.  *          type of the match found (XK_STR, XK_CMD, or XK_EXE).
  21.  *          Returns NULL in val.str and XK_STR for no match.  
  22.  *          The last character read is returned in *ch.
  23.  *
  24.  *        void AddXkey(Xkey, val, ntype);
  25.  *        Char *Xkey;
  26.  *        XmapVal *val;
  27.  *        int ntype;
  28.  *
  29.  *          Adds Xkey to the Xmap and associates the value in val with it.
  30.  *          If Xkey is already is in Xmap, the new code is applied to the
  31.  *          existing Xkey. Ntype specifies if code is a command, an
  32.  *          out string or a unix command.
  33.  *
  34.  *            int DeleteXkey(Xkey);
  35.  *            Char *Xkey;
  36.  *
  37.  *          Delete the Xkey and all longer Xkeys staring with Xkey, if
  38.  *          they exists.
  39.  *
  40.  *          Warning:
  41.  *        If Xkey is a substring of some other Xkeys, then the longer
  42.  *        Xkeys are lost!!  That is, if the Xkeys "abcd" and "abcef"
  43.  *        are in Xmap, adding the key "abc" will cause the first two
  44.  *        definitions to be lost.
  45.  *
  46.  *        void ResetXmap();
  47.  *
  48.  *          Removes all entries from Xmap and resets the defaults.
  49.  *
  50.  *        void PrintXkey(Xkey);
  51.  *        Char *Xkey;
  52.  *
  53.  *          Prints all extended keys prefixed by Xkey and their associated
  54.  *          commands.
  55.  *
  56.  *          Restrictions:
  57.  *          -------------
  58.  *            1) It is not possible to have one Xkey that is a
  59.  *           substring of another.
  60.  */
  61. /*-
  62.  * Copyright (c) 1980, 1991 The Regents of the University of California.
  63.  * All rights reserved.
  64.  *
  65.  * Redistribution and use in source and binary forms, with or without
  66.  * modification, are permitted provided that the following conditions
  67.  * are met:
  68.  * 1. Redistributions of source code must retain the above copyright
  69.  *    notice, this list of conditions and the following disclaimer.
  70.  * 2. Redistributions in binary form must reproduce the above copyright
  71.  *    notice, this list of conditions and the following disclaimer in the
  72.  *    documentation and/or other materials provided with the distribution.
  73.  * 3. All advertising materials mentioning features or use of this software
  74.  *    must display the following acknowledgement:
  75.  *    This product includes software developed by the University of
  76.  *    California, Berkeley and its contributors.
  77.  * 4. Neither the name of the University nor the names of its contributors
  78.  *    may be used to endorse or promote products derived from this software
  79.  *    without specific prior written permission.
  80.  *
  81.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  82.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  83.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  84.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  85.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  86.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  87.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  88.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  89.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  90.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  91.  * SUCH DAMAGE.
  92.  */
  93. #include "sh.h"
  94.  
  95. RCSID("$Id: ed.xmap.c,v 3.9 1992/10/14 20:19:19 christos Exp $")
  96.  
  97. #include "ed.h"
  98. #include "ed.defns.h"
  99.  
  100. #ifndef NULL
  101. #define NULL 0
  102. #endif
  103.  
  104. /* Internal Data types and declarations */
  105.  
  106. /* The Nodes of the Xmap.  The Xmap is a linked list of these node
  107.  * elements
  108.  */
  109. typedef struct Xmapnode {
  110.     Char    ch;            /* single character of Xkey */
  111.     int     type;
  112.     XmapVal val;         /* command code or pointer to string, if this
  113.                  * is a leaf */
  114.     struct Xmapnode *next;    /* ptr to next char of this Xkey */
  115.     struct Xmapnode *sibling;    /* ptr to another Xkey with same prefix */
  116. } XmapNode;
  117.  
  118. static XmapNode *Xmap = NULL;    /* the current Xmap */
  119. #define MAXXKEY 100        /* max length of a Xkey for print putposes */
  120. static Char printbuf[MAXXKEY];    /* buffer for printing */
  121.  
  122.  
  123. /* Some declarations of procedures */
  124. static    int       TraverseMap    __P((XmapNode *, Char *, XmapVal *));
  125. static    int       TryNode    __P((XmapNode *, Char *, XmapVal *, int));
  126. static    XmapNode *GetFreeNode    __P((int));
  127. static    void      PutFreeNode    __P((XmapNode *));
  128. static    int      TryDeleteNode    __P((XmapNode **, Char *));
  129. static    int      Lookup    __P((Char *, XmapNode *, int));
  130. static    int      Enumerate    __P((XmapNode *, int));
  131. static    int      unparsech    __P((int, int));
  132.  
  133.  
  134. XmapVal *
  135. XmapCmd(cmd)
  136.     int cmd;
  137. {
  138.     static XmapVal xm;
  139.     xm.cmd = (KEYCMD) cmd;
  140.     return &xm;
  141. }
  142.  
  143. XmapVal *
  144. XmapStr(str)
  145.     Char  *str;
  146. {
  147.     static XmapVal xm;
  148.     xm.str = str;
  149.     return &xm;
  150. }
  151.  
  152. /* ResetXmap():
  153.  *    Takes all nodes on Xmap and puts them on free list.  Then
  154.  *    initializes Xmap with arrow keys
  155.  */
  156. void
  157. ResetXmap()
  158. {
  159.     PutFreeNode(Xmap);
  160.     Xmap = NULL;
  161.  
  162.     DefaultArrowKeys();
  163.     return;
  164. }
  165.  
  166.  
  167. /* GetXkey():
  168.  *    Calls the recursive function with entry point Xmap
  169.  */
  170. int
  171. GetXkey(ch, val)
  172.     Char     *ch;
  173.     XmapVal  *val;
  174. {
  175.     return (TraverseMap(Xmap, ch, val));
  176. }
  177.  
  178. /* TraverseMap():
  179.  *    recursively traverses node in tree until match or mismatch is
  180.  *     found.  May read in more characters.
  181.  */
  182. static int
  183. TraverseMap(ptr, ch, val)
  184.     XmapNode *ptr;
  185.     Char     *ch;
  186.     XmapVal  *val;
  187. {
  188.     Char    tch;
  189.  
  190.     if (ptr->ch == *ch) {
  191.     /* match found */
  192.     if (ptr->next) {
  193.         /* Xkey not complete so get next char */
  194.         if (GetNextChar(&tch) != 1) {    /* if EOF or error */
  195.         val->cmd = F_SEND_EOF;
  196.         return XK_CMD;/* PWP: Pretend we just read an end-of-file */
  197.         }
  198.         *ch = tch;
  199.         return (TraverseMap(ptr->next, ch, val));
  200.     }
  201.     else {
  202.         *val = ptr->val;
  203.         if (ptr->type != XK_CMD)
  204.         *ch = '\0';
  205.         return ptr->type;
  206.     }
  207.     }
  208.     else {
  209.     /* no match found here */
  210.     if (ptr->sibling) {
  211.         /* try next sibling */
  212.         return (TraverseMap(ptr->sibling, ch, val));
  213.     }
  214.     else {
  215.         /* no next sibling -- mismatch */
  216.         val->str = NULL;
  217.         return XK_STR;
  218.     }
  219.     }
  220. }
  221.  
  222. void
  223. AddXkey(Xkey, val, ntype)
  224.     Char    *Xkey;
  225.     XmapVal *val;
  226.     int      ntype;
  227. {
  228.     if (Xkey[0] == '\0') {
  229.     xprintf("AddXkey: Null extended-key not allowed.\n");
  230.     return;
  231.     }
  232.  
  233.     if (ntype == XK_CMD && val->cmd == F_XKEY) {
  234.     xprintf("AddXkey: sequence-lead-in command not allowed\n");
  235.     return;
  236.     }
  237.  
  238.     if (Xmap == NULL)
  239.     /* tree is initially empty.  Set up new node to match Xkey[0] */
  240.     Xmap = GetFreeNode(Xkey[0]);    /* it is properly initialized */
  241.  
  242.     /* Now recurse through Xmap */
  243.     (void) TryNode(Xmap, Xkey, val, ntype);    
  244.     return;
  245. }
  246.  
  247. static int
  248. TryNode(ptr, string, val, ntype)
  249.     XmapNode *ptr;
  250.     Char     *string;
  251.     XmapVal  *val;
  252.     int       ntype;
  253. {
  254.     /*
  255.      * Find a node that matches *string or allocate a new one
  256.      */
  257.     if (ptr->ch != *string) {
  258.     XmapNode *xm;
  259.  
  260.     for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
  261.         if (xm->sibling->ch == *string)
  262.         break;
  263.     if (xm->sibling == NULL)
  264.         xm->sibling = GetFreeNode(*string);    /* setup new node */
  265.     ptr = xm->sibling;
  266.     }
  267.  
  268.     if (*++string == '\0') {
  269.     /* we're there */
  270.     if (ptr->next != NULL) {
  271.         PutFreeNode(ptr->next);    /* lose longer Xkeys with this prefix */
  272.         ptr->next = NULL;
  273.     }
  274.  
  275.     switch (ptr->type) {
  276.     case XK_STR:
  277.     case XK_EXE:
  278.         if (ptr->val.str != NULL)
  279.         xfree((ptr_t) ptr->val.str);
  280.         break;
  281.     case XK_NOD:
  282.     case XK_CMD:
  283.         break;
  284.     default:
  285.         abort();
  286.         break;
  287.     }
  288.  
  289.     switch (ptr->type = ntype) {
  290.     case XK_CMD:
  291.         ptr->val = *val;
  292.         break;
  293.     case XK_STR:
  294.     case XK_EXE:
  295.         ptr->val.str = Strsave(val->str);
  296.         break;
  297.     default:
  298.         abort();
  299.         break;
  300.     }
  301.     }
  302.     else {
  303.     /* still more chars to go */
  304.     if (ptr->next == NULL)
  305.         ptr->next = GetFreeNode(*string);    /* setup new node */
  306.     (void) TryNode(ptr->next, string, val, ntype);
  307.     }
  308.     return (0);
  309. }
  310.  
  311. void
  312. ClearXkey(map, in)
  313.     KEYCMD *map;
  314.     Char   *in;
  315. {
  316.     if ((map[(unsigned char) *in] == F_XKEY) &&
  317.     ((map == CcKeyMap && CcAltMap[(unsigned char) *in] != F_XKEY) ||
  318.      (map == CcAltMap && CcKeyMap[(unsigned char) *in] != F_XKEY)))
  319.     (void) DeleteXkey(in);
  320. }
  321.  
  322. int
  323. DeleteXkey(Xkey)
  324.     Char   *Xkey;
  325. {
  326.     if (Xkey[0] == '\0') {
  327.     xprintf("DeleteXkey: Null extended-key not allowed.\n");
  328.     return (-1);
  329.     }
  330.  
  331.     if (Xmap == NULL)
  332.     return (0);
  333.  
  334.     (void) TryDeleteNode(&Xmap, Xkey);
  335.     return (0);
  336. }
  337.  
  338. static int
  339. TryDeleteNode(inptr, string)
  340.     XmapNode **inptr;
  341.     Char   *string;
  342. {
  343.     XmapNode *ptr;
  344.     XmapNode *prev_ptr = NULL;
  345.  
  346.     ptr = *inptr;
  347.     /*
  348.      * Find a node that matches *string or allocate a new one
  349.      */
  350.     if (ptr->ch != *string) {
  351.     XmapNode *xm;
  352.  
  353.     for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
  354.         if (xm->sibling->ch == *string)
  355.         break;
  356.     if (xm->sibling == NULL)
  357.         return (0);
  358.     prev_ptr = xm;
  359.     ptr = xm->sibling;
  360.     }
  361.  
  362.     if (*++string == '\0') {
  363.     /* we're there */
  364.     if (prev_ptr == NULL)
  365.         *inptr = ptr->sibling;
  366.     else
  367.         prev_ptr->sibling = ptr->sibling;
  368.     ptr->sibling = NULL;
  369.     PutFreeNode(ptr);
  370.     return (1);
  371.     }
  372.     else if (ptr->next != NULL && TryDeleteNode(&ptr->next, string) == 1) {
  373.     if (ptr->next != NULL)
  374.         return (0);
  375.     if (prev_ptr == NULL)
  376.         *inptr = ptr->sibling;
  377.     else
  378.         prev_ptr->sibling = ptr->sibling;
  379.     ptr->sibling = NULL;
  380.     PutFreeNode(ptr);
  381.     return (1);
  382.     }
  383.     else {
  384.     return (0);
  385.     }
  386. }
  387.  
  388. /* PutFreeNode():
  389.  *    Puts a tree of nodes onto free list using free(3).
  390.  */
  391. static void
  392. PutFreeNode(ptr)
  393.     XmapNode *ptr;
  394. {
  395.     if (ptr == NULL)
  396.     return;
  397.  
  398.     if (ptr->next != NULL) {
  399.     PutFreeNode(ptr->next);
  400.     ptr->next = NULL;
  401.     }
  402.  
  403.     PutFreeNode(ptr->sibling);
  404.  
  405.     switch (ptr->type) {
  406.     case XK_CMD:
  407.     case XK_NOD:
  408.     break;
  409.     case XK_EXE:
  410.     case XK_STR:
  411.     if (ptr->val.str != NULL)
  412.         xfree((ptr_t) ptr->val.str);
  413.     break;
  414.     default:
  415.     abort();
  416.     break;
  417.     }
  418.     xfree((ptr_t) ptr);
  419. }
  420.  
  421.  
  422. /* GetFreeNode():
  423.  *    Returns pointer to an XmapNode for ch.
  424.  */
  425. static XmapNode *
  426. GetFreeNode(ch)
  427.     int    ch;
  428. {
  429.     XmapNode *ptr;
  430.  
  431.     ptr = (XmapNode *) xmalloc((size_t) sizeof(XmapNode));
  432.     ptr->ch = ch;
  433.     ptr->type = XK_NOD;
  434.     ptr->val.str = NULL;
  435.     ptr->next = NULL;
  436.     ptr->sibling = NULL;
  437.     return (ptr);
  438. }
  439.  
  440.  
  441. /* PrintXKey():
  442.  *    Print the binding associated with Xkey key.
  443.  *    Print entire Xmap if null
  444.  */
  445. void
  446. PrintXkey(key)
  447.     Char   *key;
  448. {
  449.     /* do nothing if Xmap is empty and null key specified */
  450.     if (Xmap == NULL && *key == 0)
  451.     return;
  452.  
  453.     printbuf[0] =  '"';
  454.     if (Lookup(key, Xmap, 1) <= -1)
  455.     /* key is not bound */
  456.     xprintf("Unbound extended key \"%S\"\n", key);
  457.     return;
  458. }
  459.  
  460. /* Lookup():
  461.  *    look for the string starting at node ptr.
  462.  *    Print if last node
  463.  */
  464. static int
  465. Lookup(string, ptr, cnt)
  466.     Char   *string;
  467.     XmapNode *ptr;
  468.     int     cnt;
  469. {
  470.     int     ncnt;
  471.  
  472.     if (ptr == NULL)
  473.     return (-1);        /* cannot have null ptr */
  474.  
  475.     if (*string == 0) {
  476.     /* no more chars in string.  Enumerate from here. */
  477.     (void) Enumerate(ptr, cnt);
  478.     return (0);
  479.     }
  480.     else {
  481.     /* If match put this char into printbuf.  Recurse */
  482.     if (ptr->ch == *string) {
  483.         /* match found */
  484.         ncnt = unparsech(cnt, ptr->ch);
  485.         if (ptr->next != NULL)
  486.         /* not yet at leaf */
  487.         return (Lookup(string + 1, ptr->next, ncnt + 1));
  488.         else {
  489.         /* next node is null so key should be complete */
  490.         if (string[1] == 0) {
  491.             printbuf[ncnt + 1] = '"';
  492.             printbuf[ncnt + 2] = '\0';
  493.             (void) printOne(printbuf, &ptr->val, ptr->type);
  494.             return (0);
  495.         }
  496.         else
  497.             return (-1);/* mismatch -- string still has chars */
  498.         }
  499.     }
  500.     else {
  501.         /* no match found try sibling */
  502.         if (ptr->sibling)
  503.         return (Lookup(string, ptr->sibling, cnt));
  504.         else
  505.         return (-1);
  506.     }
  507.     }
  508. }
  509.  
  510. static int
  511. Enumerate(ptr, cnt)
  512.     XmapNode *ptr;
  513.     int     cnt;
  514. {
  515.     int     ncnt;
  516.  
  517.     if (cnt >= MAXXKEY - 5) {    /* buffer too small */
  518.     printbuf[++cnt] = '"';
  519.     printbuf[++cnt] = '\0';
  520.     xprintf("Some extended keys too long for internal print buffer");
  521.     xprintf(" \"%S...\"\n", printbuf);
  522.     return (0);
  523.     }
  524.  
  525.     if (ptr == NULL) {
  526. #ifdef DEBUG_EDIT
  527.     xprintf("Enumerate: BUG!! Null ptr passed\n!");
  528. #endif
  529.     return (-1);
  530.     }
  531.  
  532.     ncnt = unparsech(cnt, ptr->ch);    /* put this char at end of string */
  533.     if (ptr->next == NULL) {
  534.     /* print this Xkey and function */
  535.     printbuf[ncnt + 1] = '"';
  536.     printbuf[ncnt + 2] = '\0';
  537.     (void) printOne(printbuf, &ptr->val, ptr->type);
  538.     }
  539.     else
  540.     (void) Enumerate(ptr->next, ncnt + 1);
  541.  
  542.     /* go to sibling if there is one */
  543.     if (ptr->sibling)
  544.     (void) Enumerate(ptr->sibling, cnt);
  545.     return (0);
  546. }
  547.  
  548.  
  549. /* PrintOne():
  550.  *    Print the specified key and its associated
  551.  *    function specified by val
  552.  */
  553. int
  554. printOne(key, val, ntype)
  555.     Char    *key;
  556.     XmapVal *val;
  557.     int      ntype;
  558. {
  559.     struct KeyFuncs *fp;
  560.     unsigned char unparsbuf[200];
  561.     static char *fmt = "%-15S->  %s\n";
  562.  
  563.     if (val != NULL)
  564.     switch (ntype) {
  565.     case XK_STR:
  566.     case XK_EXE:
  567.         xprintf(fmt, key, 
  568.             unparsestring(val->str, unparsbuf, 
  569.                   ntype == XK_STR ? STRQQ : STRBB));
  570.         break;
  571.     case XK_CMD:
  572.         for (fp = FuncNames; fp->name; fp++)
  573.         if (val->cmd == fp->func)
  574.             xprintf(fmt, key, fp->name);
  575.         break;
  576.     default:
  577.         abort();
  578.         break;
  579.     }
  580.     else
  581.     xprintf(fmt, key, "no input");
  582.     return (0);
  583. }
  584.  
  585. static int
  586. unparsech(cnt, ch)
  587.     int     cnt, ch;
  588. {
  589.     if (ch == 0) {
  590.     printbuf[cnt++] = '^';
  591.     printbuf[cnt] = '@';
  592.     return cnt;
  593.     }
  594.  
  595.     if (Iscntrl(ch)) {
  596.     printbuf[cnt++] = '^';
  597.     if (ch == '\177')
  598.         printbuf[cnt] = '?';
  599.     else
  600.         printbuf[cnt] = ch | 0100;
  601.     }
  602.     else if (ch == '^') {
  603.     printbuf[cnt++] = '\\';
  604.     printbuf[cnt] = '^';
  605.     }
  606.     else if (ch == '\\') {
  607.     printbuf[cnt++] = '\\';
  608.     printbuf[cnt] = '\\';
  609.     }
  610.     else if (ch == ' ' || (Isprint(ch) && !Isspace(ch))) {
  611.     printbuf[cnt] = ch;
  612.     }
  613.     else {
  614.     printbuf[cnt++] = '\\';
  615.     printbuf[cnt++] = ((ch >> 6) & 7) + '0';
  616.     printbuf[cnt++] = ((ch >> 3) & 7) + '0';
  617.     printbuf[cnt] = (ch & 7) + '0';
  618.     }
  619.     return cnt;
  620. }
  621.