home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume16 / less5 / part04 / lesskey.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-09-22  |  6.5 KB  |  319 lines

  1. /*
  2.  *    lesskey [-o output] [input]
  3.  *
  4.  *    Make a .less file.
  5.  *    If no input file is specified, standard input is used.
  6.  *    If no output file is specified, $HOME/.less is used.
  7.  *
  8.  *    The .less file is used to specify (to "less") user-defined
  9.  *    key bindings.  Basically any sequence of 1 to MAX_CMDLEN
  10.  *    keystrokes may be bound to an existing less function.
  11.  *
  12.  *    The input file is an ascii file consisting of a 
  13.  *    sequence of lines of the form:
  14.  *        string <whitespace> action <newline>
  15.  *
  16.  *    "string" is a sequence of command characters which form
  17.  *        the new user-defined command.  The command
  18.  *        characters may be:
  19.  *        1. The actual character itself.
  20.  *        2. A character preceeded by ^ to specify a
  21.  *           control character (e.g. ^X means control-X).
  22.  *        3. Any character (other than an octal digit) preceeded by
  23.  *           a \ to specify the character itself (characters which
  24.  *           must be preceeded by \ include ^, \, and whitespace.
  25.  *        4. A backslash followed by one to three octal digits
  26.  *           to specify a character by its octal value.
  27.  *    "action" is the name of a "less" action, from the table below.
  28.  *
  29.  *    Blank lines and lines which start with # are ignored.
  30.  *
  31.  *
  32.  *    The output file is a non-ascii file, consisting of
  33.  *    zero or more byte sequences of the form:
  34.  *        string <0> <action>
  35.  *
  36.  *    "string" is the command string.
  37.  *    "<0>" is one null byte.
  38.  *    "<action>" is one byte containing the action code (the A_xxx value).
  39.  *
  40.  *
  41.  *        Revision history
  42.  *
  43.  *    v1: Initial version.                    10/13/87  mark
  44.  */
  45.  
  46. #include <stdio.h>
  47. #include "less.h"
  48. #include "cmd.h"
  49.  
  50. char usertable[MAX_USERCMD];
  51.  
  52. struct cmdname
  53. {
  54.     char *cn_name;
  55.     int cn_action;
  56. } cmdnames[] = 
  57. {
  58.     "back-line",        A_B_LINE,
  59.     "back-screen",        A_B_SCREEN,
  60.     "back-scroll",        A_B_SCROLL,
  61.     "back-search",        A_B_SEARCH,
  62.     "debug",        A_DEBUG,
  63.     "display-flag",        A_DISP_OPTION,
  64.     "display-option",    A_DISP_OPTION,
  65.     "end",            A_GOEND,
  66.     "examine",        A_EXAMINE,
  67.     "first-cmd",        A_FIRSTCMD,
  68.     "firstcmd",        A_FIRSTCMD,
  69.     "flush-repaint",    A_FREPAINT,
  70.     "forw-line",        A_F_LINE,
  71.     "forw-screen",        A_F_SCREEN,
  72.     "forw-scroll",        A_F_SCROLL,
  73.     "forw-search",        A_F_SEARCH,
  74.     "goto-end",        A_GOEND,
  75.     "goto-line",        A_GOLINE,
  76.     "goto-mark",        A_GOMARK,
  77.     "help",            A_HELP,
  78.     "invalid",        A_NOACTION,
  79.     "next-file",        A_NEXT_FILE,
  80.     "noaction",        A_NOACTION,
  81.     "percent",        A_PERCENT,
  82.     "prev-file",        A_PREV_FILE,
  83.     "quit",            A_QUIT,
  84.     "repaint",        A_REPAINT,
  85.     "repaint-flush",    A_FREPAINT,
  86.     "repeat-search",    A_AGAIN_SEARCH,
  87.     "set-mark",        A_SETMARK,
  88.     "shell",        A_SHELL,
  89.     "status",        A_STAT,
  90.     "toggle-flag",        A_TOGGLE_OPTION,
  91.     "toggle-option",    A_TOGGLE_OPTION,
  92.     "version",        A_VERSION,
  93.     "visual",        A_VISUAL,
  94.     NULL,            0
  95. };
  96.  
  97. main(argc, argv)
  98.     int argc;
  99.     char *argv[];
  100. {
  101.     char *p;        /* {{ Can't be register since we use &p }} */
  102.     register char *up;    /* Pointer into usertable */
  103.     FILE *desc;        /* Description file (input) */
  104.     FILE *out;        /* Output file */
  105.     int linenum;        /* Line number in input file */
  106.     char *currcmd;        /* Start of current command string */
  107.     int errors;
  108.     int i;
  109.     char line[100];
  110.     char *outfile;
  111.  
  112.     extern char *getenv();
  113.  
  114.     /*
  115.      * Process command line arguments.
  116.      */
  117.     outfile = NULL;
  118.     while (--argc > 0 && **(++argv) == '-')
  119.     {
  120.         switch (argv[0][1])
  121.         {
  122.         case 'o':
  123.             outfile = &argv[0][2];
  124.             if (*outfile == '\0')
  125.             {
  126.                 if (--argc <= 0)
  127.                     usage();
  128.                 outfile = *(++argv);
  129.             }
  130.             break;
  131.         default:
  132.             usage();
  133.         }
  134.     }
  135.     if (argc > 1)
  136.         usage();
  137.  
  138.  
  139.     /*
  140.      * Open the input file, or use standard input if none specified.
  141.      */
  142.     if (argc > 0)
  143.     {
  144.         if ((desc = fopen(*argv, "r")) == NULL)
  145.         {
  146.             perror(*argv);
  147.             exit(1);
  148.         }
  149.     } else
  150.         desc = stdin;
  151.  
  152.     /*
  153.      * Read the input file, one line at a time.
  154.      * Each line consists of a command string,
  155.      * followed by white space, followed by an action name.
  156.      */
  157.     linenum = 0;
  158.     errors = 0;
  159.     up = usertable;
  160.     while (fgets(line, sizeof(line), desc) != NULL)
  161.     {
  162.         ++linenum;
  163.  
  164.         /*
  165.          * Skip leading white space.
  166.          * Replace the final newline with a null byte.
  167.          * Ignore blank lines and comment lines.
  168.          */
  169.         p = line;
  170.         while (*p == ' ' || *p == '\t')
  171.             ++p;
  172.         for (i = 0;  p[i] != '\n' && p[i] != '\0';  i++)
  173.             ;
  174.         p[i] = '\0';
  175.         if (*p == '#' || *p == '\0')
  176.             continue;
  177.  
  178.         /*
  179.          * Parse the command string and store it in the usertable.
  180.          */
  181.         currcmd = up;
  182.         do
  183.         {
  184.             if (up >= usertable + MAX_USERCMD)
  185.             {
  186.                 fprintf(stderr, "too many commands, line %d\n",
  187.                     linenum);
  188.                 exit(1);
  189.             }
  190.             if (up >= currcmd + MAX_CMDLEN)
  191.             {
  192.                 fprintf(stderr, "command too long on line %d\n",
  193.                     linenum);
  194.                 errors++;
  195.                 break;
  196.             }
  197.  
  198.             *up++ = tchar(&p);
  199.  
  200.         } while (*p != ' ' && *p != '\t' && *p != '\0');
  201.  
  202.         /*
  203.          * Terminate the command string with a null byte.
  204.          */
  205.         *up++ = '\0';
  206.  
  207.         /*
  208.          * Skip white space between the command string
  209.          * and the action name.
  210.          * Terminate the action name if it is followed
  211.          * by whitespace or a # comment.
  212.          */
  213.         if (*p == '\0')
  214.         {
  215.             fprintf(stderr, "missing whitespace on line %d\n",
  216.                 linenum);
  217.             errors++;
  218.             continue;
  219.         }
  220.         while (*p == ' ' || *p == '\t')
  221.             ++p;
  222.         for (i = 0;  p[i] != ' ' && p[i] != '\t' && 
  223.                  p[i] != '#' && p[i] != '\0';  i++)
  224.             ;
  225.         p[i] = '\0';
  226.  
  227.         /*
  228.          * Parse the action name and store it in the usertable.
  229.          */
  230.         for (i = 0;  cmdnames[i].cn_name != NULL;  i++)
  231.             if (strcmp(cmdnames[i].cn_name, p) == 0)
  232.                 break;
  233.         if (cmdnames[i].cn_name == NULL)
  234.         {
  235.             fprintf(stderr, "unknown action <%s> on line %d\n",
  236.                 p, linenum);
  237.             errors++;
  238.             continue;
  239.         }
  240.         *up++ = cmdnames[i].cn_action;
  241.     }
  242.  
  243.     if (errors > 0)
  244.     {
  245.         fprintf(stderr, "%d errors; no output produced\n", errors);
  246.         exit(1);
  247.     }
  248.  
  249.     /*
  250.      * Write the output file.
  251.      * If no output file was specified, use "$HOME/.less"
  252.      */
  253.     if (outfile == NULL)
  254.     {
  255.         p = getenv("HOME");
  256.         if (p == NULL)
  257.         {
  258.             fprintf(stderr, "cannot find $HOME\n");
  259.             exit(1);
  260.         }
  261.         strcpy(line, p);
  262.         strcat(line, "/.less");
  263.         outfile = line;
  264.     }
  265.     if ((out = fopen(outfile, "w")) == NULL)
  266.         perror(outfile);
  267.     else
  268.         fwrite((char *)usertable, 1, up-usertable, out);
  269. }
  270.  
  271. /*
  272.  * Parse one character of the command string.
  273.  */
  274. tchar(pp)
  275.     char **pp;
  276. {
  277.     register char *p;
  278.     register char ch;
  279.     register int i;
  280.  
  281.     p = *pp;
  282.     switch (*p)
  283.     {
  284.     case '\\':
  285.         if (*++p >= '0' && *p <= '7')
  286.         {
  287.             /*
  288.              * Parse an octal number.
  289.              */
  290.             ch = 0;
  291.             i = 0;
  292.             do
  293.                 ch = 8*ch + (*p - '0');
  294.             while (*++p >= '0' && *p <= '7' && ++i < 3);
  295.             *pp = p;
  296.             return (ch);
  297.         }
  298.         /*
  299.          * Backslash followed by a char just means that char.
  300.          */
  301.         *pp = p+1;
  302.         return (*p);
  303.     case '^':
  304.         /*
  305.          * Carat means CONTROL.
  306.          */
  307.         *pp = p+2;
  308.         return (CONTROL(p[1]));
  309.     }
  310.     *pp = p+1;
  311.     return (*p);
  312. }
  313.  
  314. usage()
  315. {
  316.     fprintf(stderr, "usage: lesskey [-o output] [input]\n");
  317.     exit(1);
  318. }
  319.