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