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