home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / MISC / GNU / LES177AS.ZIP / LESSKEY.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-12  |  8.2 KB  |  367 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 [chars] <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 preceded by ^ to specify a
  21.  *           control character (e.g. ^X means control-X).
  22.  *        3. Any character (other than an octal digit) preceded by
  23.  *           a \ to specify the character itself (characters which
  24.  *           must be preceded 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.  *    "chars" is an optional sequence of characters which is treated
  29.  *        as keyboard input after the command is executed.
  30.  *
  31.  *    Blank lines and lines which start with # are ignored.
  32.  *
  33.  *
  34.  *    The output file is a non-ascii file, consisting of
  35.  *    zero or more byte sequences of the form:
  36.  *        string <0> <action>
  37.  *    or
  38.  *        string <0> <action|A_EXTRA> chars <0>
  39.  *
  40.  *    "string" is the command string.
  41.  *    "<0>" is one null byte.
  42.  *    "<action>" is one byte containing the action code (the A_xxx value).
  43.  *    If action is ORed with A_EXTRA, the action byte is followed
  44.  *        by the null-terminated "chars" string.
  45.  */
  46.  
  47. #include <stdio.h>
  48. #include "less.h"
  49. #include "cmd.h"
  50.  
  51. char usertable[MAX_USERCMD];
  52.  
  53. struct cmdname
  54. {
  55.     char *cn_name;
  56.     int cn_action;
  57. } cmdnames[] = 
  58. {
  59.     "back-bracket",        A_B_BRACKET,
  60.     "back-line",        A_B_LINE,
  61.     "back-line-force",    A_BF_LINE,
  62.     "back-screen",        A_B_SCREEN,
  63.     "back-scroll",        A_B_SCROLL,
  64.     "back-search",        A_B_SEARCH,
  65.     "back-window",        A_B_WINDOW,
  66.     "debug",        A_DEBUG,
  67.     "display-flag",        A_DISP_OPTION,
  68.     "display-option",    A_DISP_OPTION,
  69.     "end",            A_GOEND,
  70.     "examine",        A_EXAMINE,
  71.     "first-cmd",        A_FIRSTCMD,
  72.     "firstcmd",        A_FIRSTCMD,
  73.     "flush-repaint",    A_FREPAINT,
  74.     "forw-bracket",        A_F_BRACKET,
  75.     "forw-forever",        A_F_FOREVER,
  76.     "forw-line",        A_F_LINE,
  77.     "forw-line-force",    A_FF_LINE,
  78.     "forw-screen",        A_F_SCREEN,
  79.     "forw-scroll",        A_F_SCROLL,
  80.     "forw-search",        A_F_SEARCH,
  81.     "forw-window",        A_F_WINDOW,
  82.     "goto-end",        A_GOEND,
  83.     "goto-line",        A_GOLINE,
  84.     "goto-mark",        A_GOMARK,
  85.     "help",            A_HELP,
  86.     "index-file",        A_INDEX_FILE,
  87.     "invalid",        A_UINVALID,
  88.     "next-file",        A_NEXT_FILE,
  89.     "noaction",        A_NOACTION,
  90.     "percent",        A_PERCENT,
  91.     "pipe",            A_PIPE,
  92.     "prev-file",        A_PREV_FILE,
  93.     "quit",            A_QUIT,
  94.     "repaint",        A_REPAINT,
  95.     "repaint-flush",    A_FREPAINT,
  96.     "repeat-search",    A_AGAIN_SEARCH,
  97.     "repeat-search-all",    A_T_AGAIN_SEARCH,
  98.     "reverse-search",    A_REVERSE_SEARCH,
  99.     "reverse-search-all",    A_T_REVERSE_SEARCH,
  100.     "set-mark",        A_SETMARK,
  101.     "shell",        A_SHELL,
  102.     "status",        A_STAT,
  103.     "toggle-flag",        A_OPT_TOGGLE,
  104.     "toggle-option",    A_OPT_TOGGLE,
  105.     "version",        A_VERSION,
  106.     "visual",        A_VISUAL,
  107.     NULL,            0
  108. };
  109.  
  110. void usage()
  111. {
  112.     fprintf(stderr, "usage: lesskey [-o output] [input]\n");
  113.     exit(1);
  114. }
  115.  
  116. void main(argc, argv)
  117.     int argc;
  118.     char *argv[];
  119. {
  120.     char *p;        /* {{ Can't be register since we use &p }} */
  121.     register char *up;    /* Pointer into usertable */
  122.     FILE *desc;        /* Description file (input) */
  123.     FILE *out;        /* Output file */
  124.     int linenum;        /* Line number in input file */
  125.     char *currcmd;        /* Start of current command string */
  126.     int errors;
  127.     int i, j;
  128.     char line[200];
  129.     char *outfile;
  130.  
  131.     extern char *getenv();
  132.  
  133.     /*
  134.      * Process command line arguments.
  135.      */
  136.     outfile = NULL;
  137.     while (--argc > 0 && **(++argv) == '-')
  138.     {
  139.         switch (argv[0][1])
  140.         {
  141.         case 'o':
  142.             outfile = &argv[0][2];
  143.             if (*outfile == '\0')
  144.             {
  145.                 if (--argc <= 0)
  146.                     usage();
  147.                 outfile = *(++argv);
  148.             }
  149.             break;
  150.         default:
  151.             usage();
  152.         }
  153.     }
  154.     if (argc > 1)
  155.         usage();
  156.  
  157.  
  158.     /*
  159.      * Open the input file, or use standard input if none specified.
  160.      */
  161.     if (argc > 0)
  162.     {
  163.         if ((desc = fopen(*argv, "r")) == NULL)
  164.         {
  165.             perror(*argv);
  166.             exit(1);
  167.         }
  168.     } else
  169.         desc = stdin;
  170.  
  171.     /*
  172.      * Read the input file, one line at a time.
  173.      * Each line consists of a command string,
  174.      * followed by white space, followed by an action name.
  175.      */
  176.     linenum = 0;
  177.     errors = 0;
  178.     up = usertable;
  179.     while (fgets(line, sizeof(line), desc) != NULL)
  180.     {
  181.         ++linenum;
  182.  
  183.         /*
  184.          * Skip leading white space.
  185.          * Replace the final newline with a null byte.
  186.          * Ignore blank lines and comment lines.
  187.          */
  188.         p = line;
  189.         while (*p == ' ' || *p == '\t')
  190.             ++p;
  191.         for (i = 0;  p[i] != '\n' && p[i] != '\0';  i++)
  192.             ;
  193.         p[i] = '\0';
  194.         if (*p == '#' || *p == '\0')
  195.             continue;
  196.  
  197.         /*
  198.          * Parse the command string and store it in the usertable.
  199.          */
  200.         currcmd = up;
  201.         do
  202.         {
  203.             if (up >= usertable + MAX_USERCMD)
  204.             {
  205.                 fprintf(stderr, "too many commands, line %d\n",
  206.                     linenum);
  207.                 exit(1);
  208.             }
  209.             if (up >= currcmd + MAX_CMDLEN)
  210.             {
  211.                 fprintf(stderr, "command too long on line %d\n",
  212.                     linenum);
  213.                 errors++;
  214.                 break;
  215.             }
  216.  
  217.             *up++ = tchar(&p);
  218.  
  219.         } while (*p != ' ' && *p != '\t' && *p != '\0');
  220.  
  221.         /*
  222.          * Terminate the command string with a null byte.
  223.          */
  224.         *up++ = '\0';
  225.  
  226.         /*
  227.          * Skip white space between the command string
  228.          * and the action name.
  229.          * Terminate the action name with a null byte if it 
  230.          * is followed by whitespace or a # comment.
  231.          */
  232.         if (*p == '\0')
  233.         {
  234.             fprintf(stderr, "missing whitespace on line %d\n",
  235.                 linenum);
  236.             errors++;
  237.             continue;
  238.         }
  239.         while (*p == ' ' || *p == '\t')
  240.             ++p;
  241.         for (j = 0;  p[j] != ' ' && p[j] != '\t' && 
  242.                  p[j] != '#' && p[j] != '\0';  j++)
  243.             ;
  244.         p[j] = '\0';
  245.  
  246.         /*
  247.          * Parse the action name and store it in the usertable.
  248.          */
  249.         for (i = 0;  cmdnames[i].cn_name != NULL;  i++)
  250.             if (strcmp(cmdnames[i].cn_name, p) == 0)
  251.                 break;
  252.         if (cmdnames[i].cn_name == NULL)
  253.         {
  254.             fprintf(stderr, "unknown action <%s> on line %d\n",
  255.                 p, linenum);
  256.             errors++;
  257.             continue;
  258.         }
  259.         *up++ = cmdnames[i].cn_action;
  260.  
  261.         /*
  262.          * See if an extra string follows the action name.
  263.          */
  264.         for (j = j+1;  p[j] == ' ' || p[j] == '\t';  j++)
  265.             ;
  266.         p += j;
  267.         if (*p != '\0')
  268.         {
  269.             /*
  270.              * OR the special value A_EXTRA into the action byte.
  271.              * Put the extra string after the action byte.
  272.              */
  273.             up[-1] |= A_EXTRA;
  274.             while (*p != '\0')
  275.                 *up++ = tchar(&p);
  276.             *up++ = '\0';
  277.         }
  278.     }
  279.  
  280.     if (errors > 0)
  281.     {
  282.         fprintf(stderr, "%d errors; no output produced\n", errors);
  283.         exit(1);
  284.     }
  285.  
  286.     /*
  287.      * Write the output file.
  288.      * If no output file was specified, use "$HOME/.less"
  289.      */
  290.     if (outfile == NULL)
  291.     {
  292.         p = getenv("HOME");
  293.         if (p == NULL || *p == '\0')
  294.         {
  295. #if __MSDOS__
  296.             fprintf(stderr, "No %HOME defined - using current directory\n");
  297.             strcpy(line, "_less");
  298. #else
  299.             fprintf(stderr, "cannot find $HOME - using current directory\n");
  300.             strcpy(line, ".less");
  301. #endif
  302.         } else
  303.         {
  304.             strcpy(line, p);
  305. #if __MSDOS__
  306.             if ((line[strlen(line)-1] != '/')
  307.              && (line[strlen(line)-1] != '\\'))
  308.                 strcat(line, "/");
  309.             strcat(line, "_less");
  310. #else
  311.             strcat(line, "/.less");
  312. #endif
  313.         }
  314.         outfile = line;
  315.     }
  316.     if ((out = fopen(outfile, "w")) == NULL)
  317.         perror(outfile);
  318.     else {
  319.         fwrite((char *)usertable, 1, up-usertable, out);
  320.         fprintf(stderr, "Key definitions written to %s\n", outfile);
  321.     }
  322.     exit(0);
  323. }
  324.  
  325. /*
  326.  * Parse one character of a string.
  327.  */
  328. tchar(pp)
  329.     char **pp;
  330. {
  331.     register char *p;
  332.     register char ch;
  333.     register int i;
  334.  
  335.     p = *pp;
  336.     switch (*p)
  337.     {
  338.     case '\\':
  339.         if (*++p >= '0' && *p <= '7')
  340.         {
  341.             /*
  342.              * Parse an octal number.
  343.              */
  344.             ch = 0;
  345.             i = 0;
  346.             do
  347.                 ch = 8*ch + (*p - '0');
  348.             while (*++p >= '0' && *p <= '7' && ++i < 3);
  349.             *pp = p;
  350.             return (ch);
  351.         }
  352.         /*
  353.          * Backslash followed by a char just means that char.
  354.          */
  355.         *pp = p+1;
  356.         return (*p);
  357.     case '^':
  358.         /*
  359.          * Carat means CONTROL.
  360.          */
  361.         *pp = p+2;
  362.         return (CONTROL(p[1]));
  363.     }
  364.     *pp = p+1;
  365.     return (*p);
  366. }
  367.