home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / LESS177.ZIP / src / decode.c < prev    next >
C/C++ Source or Header  |  1992-07-18  |  9KB  |  382 lines

  1. /*
  2.  * Routines to decode user commands.
  3.  *
  4.  * This is all table driven.
  5.  * A command table is a sequence of command descriptors.
  6.  * Each command descriptor is a sequence of bytes with the following format:
  7.  *    <c1><c2>...<cN><0><action>
  8.  * The characters c1,c2,...,cN are the command string; that is,
  9.  * the characters which the user must type.
  10.  * It is terminated by a null <0> byte.
  11.  * The byte after the null byte is the action code associated
  12.  * with the command string.
  13.  * If an action byte is OR-ed with A_EXTRA, this indicates
  14.  * that the option byte is followed by an extra string.
  15.  *
  16.  * There may be many command tables.
  17.  * The first (default) table is built-in.
  18.  * Other tables are read in from "lesskey" files.
  19.  * All the tables are linked together and are searched in order.
  20.  */
  21.  
  22. #include "less.h"
  23. #include "cmd.h"
  24. #if __MSDOS__
  25. #include <io.h>
  26. #include <stdlib.h>
  27. #endif
  28.  
  29. /*
  30.  * Command table is ordered roughly according to expected
  31.  * frequency of use, so the common commands are near the beginning.
  32.  */
  33. static char cmdtable[] =
  34. {
  35. #if __MSDOS__
  36.     /*
  37.      * PC function keys.
  38.      * Note that '\0' is converted to '\200' on input.
  39.      */
  40.     '\200','\120',0,        A_F_LINE,        /* down arrow */
  41.     '\200','\121',0,        A_F_SCREEN,        /* page down */
  42.     '\200','\110',0,        A_B_LINE,        /* up arrow */
  43.     '\200','\111',0,        A_B_SCREEN,        /* page up */
  44.     '\200','\107',0,        A_GOLINE,        /* home */
  45.     '\200','\117',0,        A_GOEND,        /* end */
  46.     '\200','\073',0,        A_HELP,            /* F1 */
  47.     '\200','\104',0,        A_MODIFY_WINDOW,    /* F10 */
  48.     '\200','\103',0,        A_MODIFY_COLOURS,    /* F9 */
  49. #endif
  50. #if OS2
  51.     /*
  52.      * PC function keys.
  53.      * Note that '\0' is converted to '\200' on input.
  54.      */
  55.     '\200','\120',0,        A_F_LINE,        /* down arrow */
  56.     '\200','\121',0,        A_F_SCREEN,        /* page down */
  57.     '\200','\110',0,        A_B_LINE,        /* up arrow */
  58.     '\200','\111',0,        A_B_SCREEN,        /* page up */
  59.     '\200','\107',0,        A_GOLINE,        /* home */
  60.     '\200','\117',0,        A_GOEND,        /* end */
  61.     '\200','\073',0,        A_HELP,            /* F1 */
  62. #endif
  63.     '\r',0,                A_F_LINE,
  64.     '\n',0,                A_F_LINE,
  65.     'e',0,                A_F_LINE,
  66.     'j',0,                A_F_LINE,
  67.     CONTROL('E'),0,            A_F_LINE,
  68.     CONTROL('N'),0,            A_F_LINE,
  69.     'k',0,                A_B_LINE,
  70.     'y',0,                A_B_LINE,
  71.     CONTROL('Y'),0,            A_B_LINE,
  72.     CONTROL('K'),0,            A_B_LINE,
  73.     CONTROL('P'),0,            A_B_LINE,
  74.     'J',0,                A_FF_LINE,
  75.     'K',0,                A_BF_LINE,
  76.     'Y',0,                A_BF_LINE,
  77.     'd',0,                A_F_SCROLL,
  78.     CONTROL('D'),0,            A_F_SCROLL,
  79.     'u',0,                A_B_SCROLL,
  80.     CONTROL('U'),0,            A_B_SCROLL,
  81.     ' ',0,                A_F_SCREEN,
  82.     'f',0,                A_F_SCREEN,
  83.     CONTROL('F'),0,            A_F_SCREEN,
  84.     CONTROL('V'),0,            A_F_SCREEN,
  85.     'b',0,                A_B_SCREEN,
  86.     CONTROL('B'),0,            A_B_SCREEN,
  87.     ESC,'v',0,            A_B_SCREEN,
  88.     'z',0,                A_F_WINDOW,
  89.     'w',0,                A_B_WINDOW,
  90.     'F',0,                A_F_FOREVER,
  91.     'R',0,                A_FREPAINT,
  92.     'r',0,                A_REPAINT,
  93.     CONTROL('R'),0,            A_REPAINT,
  94.     CONTROL('L'),0,            A_REPAINT,
  95.     'g',0,                A_GOLINE,
  96.     '<',0,                A_GOLINE,
  97.     ESC,'<',0,            A_GOLINE,
  98.     'p',0,                A_PERCENT,
  99.     '%',0,                A_PERCENT,
  100.     '{',0,                A_F_BRACKET|A_EXTRA,    '{','}',0,
  101.     '}',0,                A_B_BRACKET|A_EXTRA,    '{','}',0,
  102.     '(',0,                A_F_BRACKET|A_EXTRA,    '(',')',0,
  103.     ')',0,                A_B_BRACKET|A_EXTRA,    '(',')',0,
  104.     '[',0,                A_F_BRACKET|A_EXTRA,    '[',']',0,
  105.     ']',0,                A_B_BRACKET|A_EXTRA,    '[',']',0,
  106.     ESC,CONTROL('F'),0,        A_F_BRACKET,
  107.     ESC,CONTROL('B'),0,        A_B_BRACKET,
  108.     'G',0,                A_GOEND,
  109.     ESC,'>',0,            A_GOEND,
  110.     '>',0,                A_GOEND,
  111.     'P',0,                A_GOPOS,
  112.  
  113.     '0',0,                A_DIGIT,
  114.     '1',0,                A_DIGIT,
  115.     '2',0,                A_DIGIT,
  116.     '3',0,                A_DIGIT,
  117.     '4',0,                A_DIGIT,
  118.     '5',0,                A_DIGIT,
  119.     '6',0,                A_DIGIT,
  120.     '7',0,                A_DIGIT,
  121.     '8',0,                A_DIGIT,
  122.     '9',0,                A_DIGIT,
  123.  
  124.     '=',0,                A_STAT,
  125.     CONTROL('G'),0,            A_STAT,
  126.     ':','f',0,            A_STAT,
  127.     '/',0,                A_F_SEARCH,
  128.     '?',0,                A_B_SEARCH,
  129.     ESC,'/',0,            A_F_SEARCH|A_EXTRA,    '*',0,
  130.     ESC,'?',0,            A_B_SEARCH|A_EXTRA,    '*',0,
  131.     'n',0,                A_AGAIN_SEARCH,
  132.     ESC,'n',0,            A_T_AGAIN_SEARCH,
  133.     'N',0,                A_REVERSE_SEARCH,
  134.     ESC,'N',0,            A_T_REVERSE_SEARCH,
  135.     'm',0,                A_SETMARK,
  136.     '\'',0,                A_GOMARK,
  137.     CONTROL('X'),CONTROL('X'),0,    A_GOMARK,
  138.     'E',0,                A_EXAMINE,
  139.     ':','e',0,            A_EXAMINE,
  140.     CONTROL('X'),CONTROL('V'),0,    A_EXAMINE,
  141.     ':','n',0,            A_NEXT_FILE,
  142.     ':','p',0,            A_PREV_FILE,
  143.     ':','x',0,            A_INDEX_FILE,
  144.     '-',0,                A_OPT_TOGGLE,
  145.     ':','t',0,            A_OPT_TOGGLE|A_EXTRA,    't',0,
  146.     's',0,                A_OPT_TOGGLE|A_EXTRA,    'o',0,
  147.     '_',0,                A_DISP_OPTION,
  148.     '|',0,                A_PIPE,
  149.     'v',0,                A_VISUAL,
  150.     '!',0,                A_SHELL,
  151.     '+',0,                A_FIRSTCMD,
  152.  
  153.     'H',0,                A_HELP,
  154.     'h',0,                A_HELP,
  155.     'V',0,                A_VERSION,
  156.     'q',0,                A_QUIT,
  157.     ':','q',0,            A_QUIT,
  158.     ':','Q',0,            A_QUIT,
  159.     'Z','Z',0,            A_QUIT,
  160.     ESC,ESC,0,            A_QUIT,
  161. };
  162.  
  163. /*
  164.  * Structure to support a list of command tables.
  165.  */
  166. struct tablelist
  167. {
  168.     struct tablelist *t_next;
  169.     char *t_start;
  170.     char *t_end;
  171. };
  172.  
  173. /*
  174.  * Structure for the default command table.
  175.  */
  176. static struct tablelist deftable = 
  177.     { NULL, cmdtable, cmdtable+sizeof(cmdtable) };
  178.  
  179. /*
  180.  * List of tables; initially contains only the default table.
  181.  */
  182. static struct tablelist *tables = &deftable;
  183.  
  184. static int cmd_search();
  185.  
  186. extern int erase_char, kill_char;
  187.  
  188. /*
  189.  * Decode a command character and return the associated action.
  190.  * The "extra" string, if any, is returned in sp.
  191.  */
  192.     public int
  193. cmd_decode(cmd, sp)
  194.     char *cmd;
  195.     char **sp;
  196. {
  197.     register struct tablelist *t;
  198.     register int action;
  199.  
  200.     /*
  201.      * Search thru all the command tables.
  202.      * Stop when we find an action which is not A_INVALID.
  203.      */
  204.     for (t = tables;  t != NULL;  t = t->t_next)
  205.     {
  206.         action = cmd_search(cmd, t->t_start, t->t_end, sp);
  207.         if (action != A_INVALID)
  208.             break;
  209.     }
  210.     return (action);
  211. }
  212.  
  213. /*
  214.  * Search a command table for the current command string (in cmd).
  215.  */
  216.     static int
  217. cmd_search(cmd, table, endtable, sp)
  218.     char *cmd;
  219.     char *table;
  220.     char *endtable;
  221.     char **sp;
  222. {
  223.     register char *p;
  224.     register char *q;
  225.     register int a;
  226.  
  227.     for (p = table, q = cmd;  p < endtable;  p++, q++)
  228.     {
  229.         if (*p == *q)
  230.         {
  231.             /*
  232.              * Current characters match.
  233.              * If we're at the end of the string, we've found it.
  234.              * Return the action code, which is the character
  235.              * after the null at the end of the string
  236.              * in the command table.
  237.              */
  238.             if (*p == '\0')
  239.             {
  240.                 a = *++p & 0377;
  241.                 /*
  242.                  * Check for an "extra" string.
  243.                  */
  244.                 if (a & A_EXTRA)
  245.                 {
  246.                     *sp = ++p;
  247.                     a &= ~A_EXTRA;
  248.                 } else
  249.                     *sp = NULL;
  250.                 return (a);
  251.             }
  252.         } else if (*q == '\0')
  253.         {
  254.             /*
  255.              * Hit the end of the user's command,
  256.              * but not the end of the string in the command table.
  257.              * The user's command is incomplete.
  258.              */
  259.             return (A_PREFIX);
  260.         } else
  261.         {
  262.             /*
  263.              * Not a match.
  264.              * Skip ahead to the next command in the
  265.              * command table, and reset the pointer
  266.              * to the beginning of the user's command.
  267.              */
  268.             while (*p++ != '\0') ;
  269.             if (*p & A_EXTRA)
  270.                 while (*++p != '\0') ;
  271.             q = cmd-1;
  272.         }
  273.     }
  274.     /*
  275.      * No match found in the entire command table.
  276.      */
  277.     return (A_INVALID);
  278. }
  279.  
  280. #if USERFILE
  281. /*
  282.  * Set up a user command table, based on a "lesskey" file.
  283.  */
  284.     public int
  285. add_cmdtable(filename)
  286.     char *filename;
  287. {
  288.     register struct tablelist *t;
  289.     register POSITION len;
  290.     register long n;
  291.     register int f;
  292.  
  293.     /*
  294.      * Try to open the lesskey file.
  295.      * If we can't, return an error.
  296.      */
  297.     f = open(filename, 0);
  298.     if (f < 0)
  299.         return (-1);
  300.  
  301.     /*
  302.      * Read the file into the user table.
  303.      * We first figure out the size of the file and allocate space for it.
  304.      * {{ Minimal error checking is done here.
  305.      *    A garbage .less file will produce strange results.
  306.      *    To avoid a large amount of error checking code here, we
  307.      *    rely on the lesskey program to generate a good .less file. }}
  308.      */
  309.     len = filesize(f);
  310.     if (len == NULL_POSITION || len < 3)
  311.     {
  312.         /*
  313.          * Bad file (valid file must have at least 3 chars).
  314.          */
  315.         close(f);
  316.         return (-1);
  317.     }
  318.     if ((t = (struct tablelist *) 
  319.             calloc(1, sizeof(struct tablelist))) == NULL)
  320.     {
  321.         close(f);
  322.         return (-1);
  323.     }
  324.     if ((t->t_start = (char *) calloc(len, sizeof(char))) == NULL)
  325.     {
  326.         free((char *)t);
  327.         close(f);
  328.         return (-1);
  329.     }
  330.     if (lseek(f, (offset_t)0, 0) == BAD_LSEEK)
  331.     {
  332.         free(t->t_start);
  333.         free((char *)t);
  334.         close(f);
  335.         return (-1);
  336.     }
  337.     n = read(f, t->t_start, (unsigned int) len);
  338.     close(f);
  339.  
  340.     /*
  341.      * In a valid lesskey file, the last byte or 
  342.      * the second to the last byte must be zero.
  343.      */
  344.     if (n != len || (t->t_start[n-1] != '\0' && t->t_start[n-2] != '\0'))
  345.     {
  346.         free(t->t_start);
  347.         free((char *)t);
  348.         return (-1);
  349.     }
  350.     t->t_end = t->t_start + n;
  351.  
  352.     /*
  353.      * Link it into the list of tables.
  354.      */
  355.     t->t_next = tables;
  356.     tables = t;
  357.     return (0);
  358. }
  359.  
  360. /*
  361.  * Try to add the lesskey file "$HOME/.less"
  362.  */
  363.     public void
  364. add_hometable()
  365. {
  366.     char *filename;
  367.  
  368. #if __MSDOS__
  369.     filename = homefile("_less");
  370. #else
  371.     filename = homefile(".less");
  372. #endif
  373.     if (filename == NULL)
  374.         return;
  375.     /*
  376.      * Ignore errors.
  377.      */
  378.     (void) add_cmdtable(filename);
  379.     free(filename);
  380. }
  381. #endif
  382.