home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume16 / less5 / part01 / decode.c next >
Encoding:
C/C++ Source or Header  |  1988-09-22  |  5.8 KB  |  265 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.  *
  14.  * The default commands are described by cmdtable.
  15.  * User-defined commands are read into usertable.
  16.  */
  17.  
  18. #include "less.h"
  19. #include "cmd.h"
  20.  
  21. /*
  22.  * Command table is ordered roughly according to expected
  23.  * frequency of use, so the common commands are near the beginning.
  24.  */
  25. static char cmdtable[] =
  26. {
  27.     '\r',0,                A_F_LINE,
  28.     '\n',0,                A_F_LINE,
  29.     'e',0,                A_F_LINE,
  30.     'j',0,                A_F_LINE,
  31.     CONTROL('E'),0,            A_F_LINE,
  32.     CONTROL('N'),0,            A_F_LINE,
  33.     'k',0,                A_B_LINE,
  34.     'y',0,                A_B_LINE,
  35.     CONTROL('Y'),0,            A_B_LINE,
  36.     CONTROL('K'),0,            A_B_LINE,
  37.     CONTROL('P'),0,            A_B_LINE,
  38.     'd',0,                A_F_SCROLL,
  39.     CONTROL('D'),0,            A_F_SCROLL,
  40.     'u',0,                A_B_SCROLL,
  41.     CONTROL('U'),0,            A_B_SCROLL,
  42.     ' ',0,                A_F_SCREEN,
  43.     'f',0,                A_F_SCREEN,
  44.     CONTROL('F'),0,            A_F_SCREEN,
  45.     CONTROL('V'),0,            A_F_SCREEN,
  46.     'b',0,                A_B_SCREEN,
  47.     CONTROL('B'),0,            A_B_SCREEN,
  48.     CONTROL('['),'v',0,        A_B_SCREEN,
  49.     'R',0,                A_FREPAINT,
  50.     'r',0,                A_REPAINT,
  51.     CONTROL('R'),0,            A_REPAINT,
  52.     CONTROL('L'),0,            A_REPAINT,
  53.     'g',0,                A_GOLINE,
  54.     '<',0,                A_GOLINE,
  55.     CONTROL('['),'<',0,        A_GOLINE,
  56.     'p',0,                A_PERCENT,
  57.     '%',0,                A_PERCENT,
  58.     'G',0,                A_GOEND,
  59.     CONTROL('['),'>',0,        A_GOEND,
  60.     '>',0,                A_GOEND,
  61.  
  62.     '0',0,                A_DIGIT,
  63.     '1',0,                A_DIGIT,
  64.     '2',0,                A_DIGIT,
  65.     '3',0,                A_DIGIT,
  66.     '4',0,                A_DIGIT,
  67.     '5',0,                A_DIGIT,
  68.     '6',0,                A_DIGIT,
  69.     '7',0,                A_DIGIT,
  70.     '8',0,                A_DIGIT,
  71.     '9',0,                A_DIGIT,
  72.  
  73.     '=',0,                A_STAT,
  74.     CONTROL('G'),0,            A_STAT,
  75.     '/',0,                A_F_SEARCH,
  76.     '?',0,                A_B_SEARCH,
  77.     'n',0,                A_AGAIN_SEARCH,
  78.     'm',0,                A_SETMARK,
  79.     '\'',0,                A_GOMARK,
  80.     CONTROL('X'),CONTROL('X'),0,    A_GOMARK,
  81.     'E',0,                A_EXAMINE,
  82.     ':','e',0,            A_EXAMINE,
  83.     CONTROL('X'),CONTROL('V'),0,    A_EXAMINE,
  84.     'N',0,                A_NEXT_FILE,
  85.     'P',0,                A_PREV_FILE,
  86.     ':','n',0,            A_NEXT_FILE,
  87.     ':','p',0,            A_PREV_FILE,
  88.     '-',0,                A_TOGGLE_OPTION,
  89.     '_',0,                A_DISP_OPTION,
  90.     'v',0,                A_VISUAL,
  91.     '!',0,                A_SHELL,
  92.     '+',0,                A_FIRSTCMD,
  93.  
  94.     'H',0,                A_HELP,
  95.     'h',0,                A_HELP,
  96.     'V',0,                A_VERSION,
  97.     'q',0,                A_QUIT,
  98.     ':','q',0,            A_QUIT,
  99.     'Z','Z',0,            A_QUIT
  100. };
  101.  
  102. char *cmdendtable = cmdtable + sizeof(cmdtable);
  103.  
  104. static char usertable[MAX_USERCMD];
  105. char *userendtable = usertable;
  106.  
  107. static char kbuf[MAX_CMDLEN+1];
  108. static char *kp = kbuf;
  109.  
  110. /*
  111.  * Decode a command character and return the associated action.
  112.  */
  113.     public int
  114. cmd_decode(c)
  115.     int c;
  116. {
  117.     register int action = A_INVALID;
  118.  
  119.     /*
  120.      * Append the new command character to the command string in kbuf.
  121.      */
  122.     *kp++ = c;
  123.     *kp = '\0';
  124.  
  125. #if USERFILE
  126.     /*
  127.      * Look first for any user-defined commands.
  128.      */
  129.     action = cmd_search(usertable, userendtable);
  130. #endif
  131.     /*
  132.      * If didn't find user-defined command,
  133.      * try the normal default commands.
  134.      */
  135.     if (action == A_INVALID)
  136.         action = cmd_search(cmdtable, cmdendtable);
  137.  
  138.     if (action != A_PREFIX)
  139.         /*
  140.          * This is not a prefix character.
  141.          */
  142.         noprefix();
  143.  
  144.     return (action);
  145. }
  146.  
  147. /*
  148.  * Indicate that we're not in a prefix command
  149.  * by resetting the command buffer pointer.
  150.  */
  151.     public void
  152. noprefix()
  153. {
  154.     kp = kbuf;
  155. }
  156.  
  157. /*
  158.  * Search a command table for the current command string (in kbuf).
  159.  */
  160.     static int
  161. cmd_search(table, endtable)
  162.     char *table;
  163.     char *endtable;
  164. {
  165.     register char *p;
  166.     register char *q;
  167.  
  168.     for (p = table, q = kbuf;  p < endtable;  p++, q++)
  169.     {
  170.         if (*p == *q)
  171.         {
  172.             /*
  173.              * Current characters match.
  174.              * If we're at the end of the string, we've found it.
  175.              * Return the action code, which is the character
  176.              * after the null at the end of the string
  177.              * in the command table.
  178.              */
  179.             if (*p == '\0')
  180.                 return (p[1]);
  181.         } else if (*q == '\0')
  182.         {
  183.             /*
  184.              * Hit the end of the user's command,
  185.              * but not the end of the string in the command table.
  186.              * The user's command is incomplete.
  187.              */
  188.             return (A_PREFIX);
  189.         } else
  190.         {
  191.             /*
  192.              * Not a match.
  193.              * Skip ahead to the next command in the
  194.              * command table, and reset the pointer
  195.              * to the user's command.
  196.              */
  197.             while (*p++ != '\0') ;
  198.             q = kbuf-1;
  199.         }
  200.     }
  201.     /*
  202.      * No match found in the entire command table.
  203.      */
  204.     return (A_INVALID);
  205. }
  206.  
  207. /*
  208.  * Initialize the user command table.
  209.  */
  210.     public void
  211. init_cmd()
  212. {
  213. #if USERFILE
  214.     char *filename;
  215.     char *homedir;
  216.     int f;
  217.     int n;
  218.     extern char *getenv();
  219.  
  220.     /*
  221.      * Try to open "$HOME/.less"
  222.      * If we can't, return without doing anything.
  223.      */
  224.     homedir = getenv("HOME");
  225.     if (homedir == NULL)
  226.         return;
  227.     filename = calloc(strlen(homedir)+7, sizeof(char));
  228.     if (filename == NULL)
  229.         return;
  230.     sprintf(filename, "%s/%s", homedir, ".less");
  231.     f = open(filename, 0);
  232.     free(filename);
  233.     if (f < 0)
  234.         return;
  235.  
  236.     /*
  237.      * Read the file into the user table.
  238.      * {{ Minimal error checking is done here.
  239.      *    A garbage .less file will produce strange results.
  240.      *    To avoid a large amount of error checking code here, we
  241.      *    rely on the lesskey program to generate a good .less file. }}
  242.      */
  243.     n = read(f, (char *)usertable, MAX_USERCMD);
  244.     if (n < 3 || usertable[n-2] != '\0')
  245.     {
  246.         /*
  247.          * Several error cases are lumped together here:
  248.          * - Cannot read user file (n < 0).
  249.          * - User file is too short (a valid file must
  250.          *   have at least 3 chars: one char command string,
  251.          *   the terminating null byte, and the action byte).
  252.          * - The final entry in the user file is bad (it
  253.          *   doesn't have a null byte in the proper place).
  254.          * Many other error cases are not caught, such as
  255.          * invalid format in any except the last entry,
  256.          * invalid action codes, command strings too long, etc.
  257.          */
  258.         error("invalid user key file");
  259.         n = 0;
  260.     }
  261.     userendtable = usertable + n;
  262.     close(f);
  263. #endif
  264. }
  265.