160786Sps/* 2240121Sdelphij * Copyright (C) 1984-2012 Mark Nudelman 360786Sps * 460786Sps * You may distribute under the terms of either the GNU General Public 560786Sps * License or the Less License, as specified in the README file. 660786Sps * 7240121Sdelphij * For more information, see the README file. 860786Sps */ 960786Sps 1060786Sps 1160786Sps/* 1260786Sps * lesskey [-o output] [input] 1360786Sps * 1460786Sps * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1560786Sps * 1660786Sps * Make a .less file. 1760786Sps * If no input file is specified, standard input is used. 1860786Sps * If no output file is specified, $HOME/.less is used. 1960786Sps * 2060786Sps * The .less file is used to specify (to "less") user-defined 2160786Sps * key bindings. Basically any sequence of 1 to MAX_CMDLEN 2260786Sps * keystrokes may be bound to an existing less function. 2360786Sps * 2460786Sps * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2560786Sps * 2660786Sps * The input file is an ascii file consisting of a 2760786Sps * sequence of lines of the form: 2860786Sps * string <whitespace> action [chars] <newline> 2960786Sps * 3060786Sps * "string" is a sequence of command characters which form 3160786Sps * the new user-defined command. The command 3260786Sps * characters may be: 3360786Sps * 1. The actual character itself. 3460786Sps * 2. A character preceded by ^ to specify a 3560786Sps * control character (e.g. ^X means control-X). 3660786Sps * 3. A backslash followed by one to three octal digits 3760786Sps * to specify a character by its octal value. 3860786Sps * 4. A backslash followed by b, e, n, r or t 3960786Sps * to specify \b, ESC, \n, \r or \t, respectively. 4060786Sps * 5. Any character (other than those mentioned above) preceded 4160786Sps * by a \ to specify the character itself (characters which 4260786Sps * must be preceded by \ include ^, \, and whitespace. 4360786Sps * "action" is the name of a "less" action, from the table below. 4460786Sps * "chars" is an optional sequence of characters which is treated 4560786Sps * as keyboard input after the command is executed. 4660786Sps * 4760786Sps * Blank lines and lines which start with # are ignored, 4860786Sps * except for the special control lines: 4960786Sps * #command Signals the beginning of the command 5060786Sps * keys section. 5160786Sps * #line-edit Signals the beginning of the line-editing 5260786Sps * keys section. 5360786Sps * #env Signals the beginning of the environment 5460786Sps * variable section. 5560786Sps * #stop Stops command parsing in less; 5660786Sps * causes all default keys to be disabled. 5760786Sps * 5860786Sps * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 5960786Sps * 6060786Sps * The output file is a non-ascii file, consisting of a header, 6160786Sps * one or more sections, and a trailer. 6260786Sps * Each section begins with a section header, a section length word 6360786Sps * and the section data. Normally there are three sections: 6460786Sps * CMD_SECTION Definition of command keys. 6560786Sps * EDIT_SECTION Definition of editing keys. 6660786Sps * END_SECTION A special section header, with no 6760786Sps * length word or section data. 6860786Sps * 6960786Sps * Section data consists of zero or more byte sequences of the form: 7060786Sps * string <0> <action> 7160786Sps * or 7260786Sps * string <0> <action|A_EXTRA> chars <0> 7360786Sps * 7460786Sps * "string" is the command string. 7560786Sps * "<0>" is one null byte. 7660786Sps * "<action>" is one byte containing the action code (the A_xxx value). 7760786Sps * If action is ORed with A_EXTRA, the action byte is followed 7860786Sps * by the null-terminated "chars" string. 7960786Sps * 8060786Sps * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 8160786Sps */ 8260786Sps 8360786Sps#include "less.h" 8460786Sps#include "lesskey.h" 8560786Sps#include "cmd.h" 8660786Sps 8760786Spsstruct cmdname 8860786Sps{ 8960786Sps char *cn_name; 9060786Sps int cn_action; 9160786Sps}; 9260786Sps 9360786Spsstruct cmdname cmdnames[] = 9460786Sps{ 95191930Sdelphij { "back-bracket", A_B_BRACKET }, 96191930Sdelphij { "back-line", A_B_LINE }, 97191930Sdelphij { "back-line-force", A_BF_LINE }, 98191930Sdelphij { "back-screen", A_B_SCREEN }, 99191930Sdelphij { "back-scroll", A_B_SCROLL }, 100191930Sdelphij { "back-search", A_B_SEARCH }, 101191930Sdelphij { "back-window", A_B_WINDOW }, 102191930Sdelphij { "debug", A_DEBUG }, 103191930Sdelphij { "digit", A_DIGIT }, 104191930Sdelphij { "display-flag", A_DISP_OPTION }, 105191930Sdelphij { "display-option", A_DISP_OPTION }, 106191930Sdelphij { "end", A_GOEND }, 107191930Sdelphij { "examine", A_EXAMINE }, 108191930Sdelphij { "filter", A_FILTER }, 109191930Sdelphij { "first-cmd", A_FIRSTCMD }, 110191930Sdelphij { "firstcmd", A_FIRSTCMD }, 111191930Sdelphij { "flush-repaint", A_FREPAINT }, 112191930Sdelphij { "forw-bracket", A_F_BRACKET }, 113191930Sdelphij { "forw-forever", A_F_FOREVER }, 114240121Sdelphij { "forw-until-hilite", A_F_UNTIL_HILITE }, 115191930Sdelphij { "forw-line", A_F_LINE }, 116191930Sdelphij { "forw-line-force", A_FF_LINE }, 117191930Sdelphij { "forw-screen", A_F_SCREEN }, 118191930Sdelphij { "forw-screen-force", A_FF_SCREEN }, 119191930Sdelphij { "forw-scroll", A_F_SCROLL }, 120191930Sdelphij { "forw-search", A_F_SEARCH }, 121191930Sdelphij { "forw-window", A_F_WINDOW }, 122191930Sdelphij { "goto-end", A_GOEND }, 123191930Sdelphij { "goto-line", A_GOLINE }, 124191930Sdelphij { "goto-mark", A_GOMARK }, 125191930Sdelphij { "help", A_HELP }, 126191930Sdelphij { "index-file", A_INDEX_FILE }, 127191930Sdelphij { "invalid", A_UINVALID }, 128191930Sdelphij { "left-scroll", A_LSHIFT }, 129191930Sdelphij { "next-file", A_NEXT_FILE }, 130191930Sdelphij { "next-tag", A_NEXT_TAG }, 131191930Sdelphij { "noaction", A_NOACTION }, 132191930Sdelphij { "percent", A_PERCENT }, 133191930Sdelphij { "pipe", A_PIPE }, 134191930Sdelphij { "prev-file", A_PREV_FILE }, 135191930Sdelphij { "prev-tag", A_PREV_TAG }, 136191930Sdelphij { "quit", A_QUIT }, 137191930Sdelphij { "remove-file", A_REMOVE_FILE }, 138191930Sdelphij { "repaint", A_REPAINT }, 139191930Sdelphij { "repaint-flush", A_FREPAINT }, 140191930Sdelphij { "repeat-search", A_AGAIN_SEARCH }, 141191930Sdelphij { "repeat-search-all", A_T_AGAIN_SEARCH }, 142191930Sdelphij { "reverse-search", A_REVERSE_SEARCH }, 143191930Sdelphij { "reverse-search-all", A_T_REVERSE_SEARCH }, 144191930Sdelphij { "right-scroll", A_RSHIFT }, 145191930Sdelphij { "set-mark", A_SETMARK }, 146191930Sdelphij { "shell", A_SHELL }, 147191930Sdelphij { "status", A_STAT }, 148191930Sdelphij { "toggle-flag", A_OPT_TOGGLE }, 149191930Sdelphij { "toggle-option", A_OPT_TOGGLE }, 150191930Sdelphij { "undo-hilite", A_UNDO_SEARCH }, 151191930Sdelphij { "version", A_VERSION }, 152191930Sdelphij { "visual", A_VISUAL }, 153191930Sdelphij { NULL, 0 } 15460786Sps}; 15560786Sps 15660786Spsstruct cmdname editnames[] = 15760786Sps{ 158128345Stjr { "back-complete", EC_B_COMPLETE }, 159128345Stjr { "backspace", EC_BACKSPACE }, 160128345Stjr { "delete", EC_DELETE }, 161128345Stjr { "down", EC_DOWN }, 162128345Stjr { "end", EC_END }, 163128345Stjr { "expand", EC_EXPAND }, 164128345Stjr { "forw-complete", EC_F_COMPLETE }, 165128345Stjr { "home", EC_HOME }, 166128345Stjr { "insert", EC_INSERT }, 167128345Stjr { "invalid", EC_UINVALID }, 168128345Stjr { "kill-line", EC_LINEKILL }, 169221715Sdelphij { "abort", EC_ABORT }, 170128345Stjr { "left", EC_LEFT }, 171128345Stjr { "literal", EC_LITERAL }, 172128345Stjr { "right", EC_RIGHT }, 173128345Stjr { "up", EC_UP }, 174128345Stjr { "word-backspace", EC_W_BACKSPACE }, 175128345Stjr { "word-delete", EC_W_DELETE }, 176128345Stjr { "word-left", EC_W_LEFT }, 177128345Stjr { "word-right", EC_W_RIGHT }, 178128345Stjr { NULL, 0 } 17960786Sps}; 18060786Sps 18160786Spsstruct table 18260786Sps{ 18360786Sps struct cmdname *names; 18460786Sps char *pbuffer; 18560786Sps char buffer[MAX_USERCMD]; 18660786Sps}; 18760786Sps 18860786Spsstruct table cmdtable; 18960786Spsstruct table edittable; 19060786Spsstruct table vartable; 19160786Spsstruct table *currtable = &cmdtable; 19260786Sps 19360786Spschar fileheader[] = { 19460786Sps C0_LESSKEY_MAGIC, 19560786Sps C1_LESSKEY_MAGIC, 19660786Sps C2_LESSKEY_MAGIC, 19760786Sps C3_LESSKEY_MAGIC 19860786Sps}; 19960786Spschar filetrailer[] = { 20060786Sps C0_END_LESSKEY_MAGIC, 20160786Sps C1_END_LESSKEY_MAGIC, 20260786Sps C2_END_LESSKEY_MAGIC 20360786Sps}; 20460786Spschar cmdsection[1] = { CMD_SECTION }; 20560786Spschar editsection[1] = { EDIT_SECTION }; 20660786Spschar varsection[1] = { VAR_SECTION }; 20760786Spschar endsection[1] = { END_SECTION }; 20860786Sps 20960786Spschar *infile = NULL; 21060786Spschar *outfile = NULL ; 21160786Sps 21260786Spsint linenum; 21360786Spsint errors; 21460786Sps 21560786Spsextern char version[]; 21660786Sps 21760786Sps void 21860786Spsusage() 21960786Sps{ 22060786Sps fprintf(stderr, "usage: lesskey [-o output] [input]\n"); 22160786Sps exit(1); 22260786Sps} 22360786Sps 22460786Sps char * 22560786Spsmkpathname(dirname, filename) 22660786Sps char *dirname; 22760786Sps char *filename; 22860786Sps{ 22960786Sps char *pathname; 23060786Sps 23160786Sps pathname = calloc(strlen(dirname) + strlen(filename) + 2, sizeof(char)); 23260786Sps strcpy(pathname, dirname); 23360786Sps strcat(pathname, PATHNAME_SEP); 23460786Sps strcat(pathname, filename); 23560786Sps return (pathname); 23660786Sps} 23760786Sps 23860786Sps/* 23960786Sps * Figure out the name of a default file (in the user's HOME directory). 24060786Sps */ 24160786Sps char * 24260786Spshomefile(filename) 24360786Sps char *filename; 24460786Sps{ 24560786Sps char *p; 24660786Sps char *pathname; 24760786Sps 24860786Sps if ((p = getenv("HOME")) != NULL && *p != '\0') 24960786Sps pathname = mkpathname(p, filename); 25060786Sps#if OS2 25160786Sps else if ((p = getenv("INIT")) != NULL && *p != '\0') 25260786Sps pathname = mkpathname(p, filename); 25360786Sps#endif 25460786Sps else 25560786Sps { 25660786Sps fprintf(stderr, "cannot find $HOME - using current directory\n"); 25760786Sps pathname = mkpathname(".", filename); 25860786Sps } 25960786Sps return (pathname); 26060786Sps} 26160786Sps 26260786Sps/* 26360786Sps * Parse command line arguments. 26460786Sps */ 26560786Sps void 26660786Spsparse_args(argc, argv) 26760786Sps int argc; 26860786Sps char **argv; 26960786Sps{ 27060786Sps char *arg; 27160786Sps 27260786Sps outfile = NULL; 27360786Sps while (--argc > 0) 27460786Sps { 27560786Sps arg = *++argv; 27660786Sps if (arg[0] != '-') 27760786Sps /* Arg does not start with "-"; it's not an option. */ 27860786Sps break; 27960786Sps if (arg[1] == '\0') 28060786Sps /* "-" means standard input. */ 28160786Sps break; 28260786Sps if (arg[1] == '-' && arg[2] == '\0') 28360786Sps { 28460786Sps /* "--" means end of options. */ 28560786Sps argc--; 28660786Sps argv++; 28760786Sps break; 28860786Sps } 28960786Sps switch (arg[1]) 29060786Sps { 29160786Sps case '-': 29260786Sps if (strncmp(arg, "--output", 8) == 0) 29360786Sps { 29460786Sps if (arg[8] == '\0') 29560786Sps outfile = &arg[8]; 29660786Sps else if (arg[8] == '=') 29760786Sps outfile = &arg[9]; 29860786Sps else 29960786Sps usage(); 30060786Sps goto opt_o; 30160786Sps } 30260786Sps if (strcmp(arg, "--version") == 0) 30360786Sps { 30460786Sps goto opt_V; 30560786Sps } 30660786Sps usage(); 30760786Sps break; 30860786Sps case 'o': 30960786Sps outfile = &argv[0][2]; 31060786Sps opt_o: 31160786Sps if (*outfile == '\0') 31260786Sps { 31360786Sps if (--argc <= 0) 31460786Sps usage(); 31560786Sps outfile = *(++argv); 31660786Sps } 31760786Sps break; 31860786Sps case 'V': 31960786Sps opt_V: 32060786Sps printf("lesskey version %s\n", version); 32160786Sps exit(0); 32260786Sps default: 32360786Sps usage(); 32460786Sps } 32560786Sps } 32660786Sps if (argc > 1) 32760786Sps usage(); 32860786Sps /* 32960786Sps * Open the input file, or use DEF_LESSKEYINFILE if none specified. 33060786Sps */ 33160786Sps if (argc > 0) 33260786Sps infile = *argv; 33360786Sps else 33460786Sps infile = homefile(DEF_LESSKEYINFILE); 33560786Sps} 33660786Sps 33760786Sps/* 33860786Sps * Initialize data structures. 33960786Sps */ 34060786Sps void 34160786Spsinit_tables() 34260786Sps{ 34360786Sps cmdtable.names = cmdnames; 34460786Sps cmdtable.pbuffer = cmdtable.buffer; 34560786Sps 34660786Sps edittable.names = editnames; 34760786Sps edittable.pbuffer = edittable.buffer; 34860786Sps 34960786Sps vartable.names = NULL; 35060786Sps vartable.pbuffer = vartable.buffer; 35160786Sps} 35260786Sps 35360786Sps/* 35460786Sps * Parse one character of a string. 35560786Sps */ 35660786Sps char * 357128345Stjrtstr(pp, xlate) 35860786Sps char **pp; 359128345Stjr int xlate; 36060786Sps{ 36160786Sps register char *p; 36260786Sps register char ch; 36360786Sps register int i; 36460786Sps static char buf[10]; 36560786Sps static char tstr_control_k[] = 36660786Sps { SK_SPECIAL_KEY, SK_CONTROL_K, 6, 1, 1, 1, '\0' }; 36760786Sps 36860786Sps p = *pp; 36960786Sps switch (*p) 37060786Sps { 37160786Sps case '\\': 37260786Sps ++p; 37360786Sps switch (*p) 37460786Sps { 37560786Sps case '0': case '1': case '2': case '3': 37660786Sps case '4': case '5': case '6': case '7': 37760786Sps /* 37860786Sps * Parse an octal number. 37960786Sps */ 38060786Sps ch = 0; 38160786Sps i = 0; 38260786Sps do 38360786Sps ch = 8*ch + (*p - '0'); 38460786Sps while (*++p >= '0' && *p <= '7' && ++i < 3); 38560786Sps *pp = p; 386128345Stjr if (xlate && ch == CONTROL('K')) 38760786Sps return tstr_control_k; 38860786Sps buf[0] = ch; 38960786Sps buf[1] = '\0'; 39060786Sps return (buf); 39160786Sps case 'b': 39260786Sps *pp = p+1; 39360786Sps return ("\b"); 39460786Sps case 'e': 39560786Sps *pp = p+1; 39660786Sps buf[0] = ESC; 39760786Sps buf[1] = '\0'; 39860786Sps return (buf); 39960786Sps case 'n': 40060786Sps *pp = p+1; 40160786Sps return ("\n"); 40260786Sps case 'r': 40360786Sps *pp = p+1; 40460786Sps return ("\r"); 40560786Sps case 't': 40660786Sps *pp = p+1; 40760786Sps return ("\t"); 40860786Sps case 'k': 409128345Stjr if (xlate) 41060786Sps { 411128345Stjr switch (*++p) 412128345Stjr { 413128345Stjr case 'u': ch = SK_UP_ARROW; break; 414128345Stjr case 'd': ch = SK_DOWN_ARROW; break; 415128345Stjr case 'r': ch = SK_RIGHT_ARROW; break; 416128345Stjr case 'l': ch = SK_LEFT_ARROW; break; 417128345Stjr case 'U': ch = SK_PAGE_UP; break; 418128345Stjr case 'D': ch = SK_PAGE_DOWN; break; 419128345Stjr case 'h': ch = SK_HOME; break; 420128345Stjr case 'e': ch = SK_END; break; 421128345Stjr case 'x': ch = SK_DELETE; break; 422128345Stjr default: 423128345Stjr error("illegal char after \\k"); 424128345Stjr *pp = p+1; 425128345Stjr return (""); 426128345Stjr } 42789019Sps *pp = p+1; 428128345Stjr buf[0] = SK_SPECIAL_KEY; 429128345Stjr buf[1] = ch; 430128345Stjr buf[2] = 6; 431128345Stjr buf[3] = 1; 432128345Stjr buf[4] = 1; 433128345Stjr buf[5] = 1; 434128345Stjr buf[6] = '\0'; 435128345Stjr return (buf); 43660786Sps } 437128345Stjr /* FALLTHRU */ 43860786Sps default: 43960786Sps /* 44060786Sps * Backslash followed by any other char 44160786Sps * just means that char. 44260786Sps */ 44360786Sps *pp = p+1; 44460786Sps buf[0] = *p; 44560786Sps buf[1] = '\0'; 446128345Stjr if (xlate && buf[0] == CONTROL('K')) 44760786Sps return tstr_control_k; 44860786Sps return (buf); 44960786Sps } 45060786Sps case '^': 45160786Sps /* 452240121Sdelphij * Caret means CONTROL. 45360786Sps */ 45460786Sps *pp = p+2; 45560786Sps buf[0] = CONTROL(p[1]); 45660786Sps buf[1] = '\0'; 45760786Sps if (buf[0] == CONTROL('K')) 45860786Sps return tstr_control_k; 45960786Sps return (buf); 46060786Sps } 46160786Sps *pp = p+1; 46260786Sps buf[0] = *p; 46360786Sps buf[1] = '\0'; 464128345Stjr if (xlate && buf[0] == CONTROL('K')) 46560786Sps return tstr_control_k; 46660786Sps return (buf); 46760786Sps} 46860786Sps 46960786Sps/* 47060786Sps * Skip leading spaces in a string. 47160786Sps */ 47260786Sps public char * 47360786Spsskipsp(s) 47460786Sps register char *s; 47560786Sps{ 47660786Sps while (*s == ' ' || *s == '\t') 47760786Sps s++; 47860786Sps return (s); 47960786Sps} 48060786Sps 48160786Sps/* 48260786Sps * Skip non-space characters in a string. 48360786Sps */ 48460786Sps public char * 48560786Spsskipnsp(s) 48660786Sps register char *s; 48760786Sps{ 48860786Sps while (*s != '\0' && *s != ' ' && *s != '\t') 48960786Sps s++; 49060786Sps return (s); 49160786Sps} 49260786Sps 49360786Sps/* 49460786Sps * Clean up an input line: 49560786Sps * strip off the trailing newline & any trailing # comment. 49660786Sps */ 49760786Sps char * 49860786Spsclean_line(s) 49960786Sps char *s; 50060786Sps{ 50160786Sps register int i; 50260786Sps 50360786Sps s = skipsp(s); 50460786Sps for (i = 0; s[i] != '\n' && s[i] != '\r' && s[i] != '\0'; i++) 50560786Sps if (s[i] == '#' && (i == 0 || s[i-1] != '\\')) 50660786Sps break; 50760786Sps s[i] = '\0'; 50860786Sps return (s); 50960786Sps} 51060786Sps 51160786Sps/* 51260786Sps * Add a byte to the output command table. 51360786Sps */ 51460786Sps void 51560786Spsadd_cmd_char(c) 51660786Sps int c; 51760786Sps{ 51860786Sps if (currtable->pbuffer >= currtable->buffer + MAX_USERCMD) 51960786Sps { 52060786Sps error("too many commands"); 52160786Sps exit(1); 52260786Sps } 52360786Sps *(currtable->pbuffer)++ = c; 52460786Sps} 52560786Sps 52660786Sps/* 52760786Sps * Add a string to the output command table. 52860786Sps */ 52960786Sps void 53060786Spsadd_cmd_str(s) 53160786Sps char *s; 53260786Sps{ 53360786Sps for ( ; *s != '\0'; s++) 53460786Sps add_cmd_char(*s); 53560786Sps} 53660786Sps 53760786Sps/* 53860786Sps * See if we have a special "control" line. 53960786Sps */ 54060786Sps int 54160786Spscontrol_line(s) 54260786Sps char *s; 54360786Sps{ 544191930Sdelphij#define PREFIX(str,pat) (strncmp(str,pat,strlen(pat)) == 0) 54560786Sps 54660786Sps if (PREFIX(s, "#line-edit")) 54760786Sps { 54860786Sps currtable = &edittable; 54960786Sps return (1); 55060786Sps } 55160786Sps if (PREFIX(s, "#command")) 55260786Sps { 55360786Sps currtable = &cmdtable; 55460786Sps return (1); 55560786Sps } 55660786Sps if (PREFIX(s, "#env")) 55760786Sps { 55860786Sps currtable = &vartable; 55960786Sps return (1); 56060786Sps } 56160786Sps if (PREFIX(s, "#stop")) 56260786Sps { 56360786Sps add_cmd_char('\0'); 56460786Sps add_cmd_char(A_END_LIST); 56560786Sps return (1); 56660786Sps } 56760786Sps return (0); 56860786Sps} 56960786Sps 57060786Sps/* 57160786Sps * Output some bytes. 57260786Sps */ 57360786Sps void 57460786Spsfputbytes(fd, buf, len) 57560786Sps FILE *fd; 57660786Sps char *buf; 57760786Sps int len; 57860786Sps{ 57960786Sps while (len-- > 0) 58060786Sps { 58160786Sps fwrite(buf, sizeof(char), 1, fd); 58260786Sps buf++; 58360786Sps } 58460786Sps} 58560786Sps 58660786Sps/* 58760786Sps * Output an integer, in special KRADIX form. 58860786Sps */ 58960786Sps void 59060786Spsfputint(fd, val) 59160786Sps FILE *fd; 59260786Sps unsigned int val; 59360786Sps{ 59460786Sps char c; 59560786Sps 59660786Sps if (val >= KRADIX*KRADIX) 59760786Sps { 59860786Sps fprintf(stderr, "error: integer too big (%d > %d)\n", 59960786Sps val, KRADIX*KRADIX); 60060786Sps exit(1); 60160786Sps } 60260786Sps c = val % KRADIX; 60360786Sps fwrite(&c, sizeof(char), 1, fd); 60460786Sps c = val / KRADIX; 60560786Sps fwrite(&c, sizeof(char), 1, fd); 60660786Sps} 60760786Sps 60860786Sps/* 60960786Sps * Find an action, given the name of the action. 61060786Sps */ 61160786Sps int 61260786Spsfindaction(actname) 61360786Sps char *actname; 61460786Sps{ 61560786Sps int i; 61660786Sps 61760786Sps for (i = 0; currtable->names[i].cn_name != NULL; i++) 61860786Sps if (strcmp(currtable->names[i].cn_name, actname) == 0) 61960786Sps return (currtable->names[i].cn_action); 62060786Sps error("unknown action"); 62160786Sps return (A_INVALID); 62260786Sps} 62360786Sps 62460786Sps void 62560786Spserror(s) 62660786Sps char *s; 62760786Sps{ 62860786Sps fprintf(stderr, "line %d: %s\n", linenum, s); 62960786Sps errors++; 63060786Sps} 63160786Sps 63260786Sps 63360786Sps void 63460786Spsparse_cmdline(p) 63560786Sps char *p; 63660786Sps{ 63760786Sps int cmdlen; 63860786Sps char *actname; 63960786Sps int action; 64060786Sps char *s; 64160786Sps char c; 64260786Sps 64360786Sps /* 64460786Sps * Parse the command string and store it in the current table. 64560786Sps */ 64660786Sps cmdlen = 0; 64760786Sps do 64860786Sps { 649128345Stjr s = tstr(&p, 1); 65060786Sps cmdlen += strlen(s); 65160786Sps if (cmdlen > MAX_CMDLEN) 65260786Sps error("command too long"); 65360786Sps else 65460786Sps add_cmd_str(s); 65560786Sps } while (*p != ' ' && *p != '\t' && *p != '\0'); 65660786Sps /* 65760786Sps * Terminate the command string with a null byte. 65860786Sps */ 65960786Sps add_cmd_char('\0'); 66060786Sps 66160786Sps /* 66260786Sps * Skip white space between the command string 66360786Sps * and the action name. 66460786Sps * Terminate the action name with a null byte. 66560786Sps */ 66660786Sps p = skipsp(p); 66760786Sps if (*p == '\0') 66860786Sps { 66960786Sps error("missing action"); 67060786Sps return; 67160786Sps } 67260786Sps actname = p; 67360786Sps p = skipnsp(p); 67460786Sps c = *p; 67560786Sps *p = '\0'; 67660786Sps 67760786Sps /* 67860786Sps * Parse the action name and store it in the current table. 67960786Sps */ 68060786Sps action = findaction(actname); 68160786Sps 68260786Sps /* 68360786Sps * See if an extra string follows the action name. 68460786Sps */ 68560786Sps *p = c; 68660786Sps p = skipsp(p); 68760786Sps if (*p == '\0') 68860786Sps { 68960786Sps add_cmd_char(action); 69060786Sps } else 69160786Sps { 69260786Sps /* 69360786Sps * OR the special value A_EXTRA into the action byte. 69460786Sps * Put the extra string after the action byte. 69560786Sps */ 69660786Sps add_cmd_char(action | A_EXTRA); 69760786Sps while (*p != '\0') 698128345Stjr add_cmd_str(tstr(&p, 0)); 69960786Sps add_cmd_char('\0'); 70060786Sps } 70160786Sps} 70260786Sps 70360786Sps void 70460786Spsparse_varline(p) 70560786Sps char *p; 70660786Sps{ 70760786Sps char *s; 70860786Sps 70960786Sps do 71060786Sps { 711128345Stjr s = tstr(&p, 0); 71260786Sps add_cmd_str(s); 71360786Sps } while (*p != ' ' && *p != '\t' && *p != '=' && *p != '\0'); 71460786Sps /* 71560786Sps * Terminate the variable name with a null byte. 71660786Sps */ 71760786Sps add_cmd_char('\0'); 71860786Sps 71960786Sps p = skipsp(p); 72060786Sps if (*p++ != '=') 72160786Sps { 72260786Sps error("missing ="); 72360786Sps return; 72460786Sps } 72560786Sps 72660786Sps add_cmd_char(EV_OK|A_EXTRA); 72760786Sps 72860786Sps p = skipsp(p); 72960786Sps while (*p != '\0') 73060786Sps { 731128345Stjr s = tstr(&p, 0); 73260786Sps add_cmd_str(s); 73360786Sps } 73460786Sps add_cmd_char('\0'); 73560786Sps} 73660786Sps 73760786Sps/* 73860786Sps * Parse a line from the lesskey file. 73960786Sps */ 74060786Sps void 74160786Spsparse_line(line) 74260786Sps char *line; 74360786Sps{ 74460786Sps char *p; 74560786Sps 74660786Sps /* 74760786Sps * See if it is a control line. 74860786Sps */ 74960786Sps if (control_line(line)) 75060786Sps return; 75160786Sps /* 75260786Sps * Skip leading white space. 75360786Sps * Replace the final newline with a null byte. 75460786Sps * Ignore blank lines and comments. 75560786Sps */ 75660786Sps p = clean_line(line); 75760786Sps if (*p == '\0') 75860786Sps return; 75960786Sps 76060786Sps if (currtable == &vartable) 76160786Sps parse_varline(p); 76260786Sps else 76360786Sps parse_cmdline(p); 76460786Sps} 76560786Sps 76660786Sps int 76760786Spsmain(argc, argv) 76860786Sps int argc; 76960786Sps char *argv[]; 77060786Sps{ 77160786Sps FILE *desc; 77260786Sps FILE *out; 773128345Stjr char line[1024]; 77460786Sps 77560786Sps#ifdef WIN32 77660786Sps if (getenv("HOME") == NULL) 77760786Sps { 77860786Sps /* 77960786Sps * If there is no HOME environment variable, 78060786Sps * try the concatenation of HOMEDRIVE + HOMEPATH. 78160786Sps */ 78260786Sps char *drive = getenv("HOMEDRIVE"); 78360786Sps char *path = getenv("HOMEPATH"); 78460786Sps if (drive != NULL && path != NULL) 78560786Sps { 78660786Sps char *env = (char *) calloc(strlen(drive) + 78760786Sps strlen(path) + 6, sizeof(char)); 78860786Sps strcpy(env, "HOME="); 78960786Sps strcat(env, drive); 79060786Sps strcat(env, path); 79160786Sps putenv(env); 79260786Sps } 79360786Sps } 79460786Sps#endif /* WIN32 */ 79560786Sps 79660786Sps /* 79760786Sps * Process command line arguments. 79860786Sps */ 79960786Sps parse_args(argc, argv); 80060786Sps init_tables(); 80160786Sps 80260786Sps /* 80360786Sps * Open the input file. 80460786Sps */ 80560786Sps if (strcmp(infile, "-") == 0) 80660786Sps desc = stdin; 80760786Sps else if ((desc = fopen(infile, "r")) == NULL) 80860786Sps { 80960786Sps#if HAVE_PERROR 81060786Sps perror(infile); 81160786Sps#else 81260786Sps fprintf(stderr, "Cannot open %s\n", infile); 81360786Sps#endif 81460786Sps usage(); 81560786Sps } 81660786Sps 81760786Sps /* 81860786Sps * Read and parse the input file, one line at a time. 81960786Sps */ 82060786Sps errors = 0; 82160786Sps linenum = 0; 82260786Sps while (fgets(line, sizeof(line), desc) != NULL) 82360786Sps { 82460786Sps ++linenum; 82560786Sps parse_line(line); 82660786Sps } 82760786Sps 82860786Sps /* 82960786Sps * Write the output file. 83060786Sps * If no output file was specified, use "$HOME/.less" 83160786Sps */ 83260786Sps if (errors > 0) 83360786Sps { 83460786Sps fprintf(stderr, "%d errors; no output produced\n", errors); 83560786Sps exit(1); 83660786Sps } 83760786Sps 83860786Sps if (outfile == NULL) 83960786Sps outfile = getenv("LESSKEY"); 84060786Sps if (outfile == NULL) 84160786Sps outfile = homefile(LESSKEYFILE); 84260786Sps if ((out = fopen(outfile, "wb")) == NULL) 84360786Sps { 84460786Sps#if HAVE_PERROR 84560786Sps perror(outfile); 84660786Sps#else 84760786Sps fprintf(stderr, "Cannot open %s\n", outfile); 84860786Sps#endif 84960786Sps exit(1); 85060786Sps } 85160786Sps 85260786Sps /* File header */ 85360786Sps fputbytes(out, fileheader, sizeof(fileheader)); 85460786Sps 85560786Sps /* Command key section */ 85660786Sps fputbytes(out, cmdsection, sizeof(cmdsection)); 85760786Sps fputint(out, cmdtable.pbuffer - cmdtable.buffer); 85860786Sps fputbytes(out, (char *)cmdtable.buffer, cmdtable.pbuffer-cmdtable.buffer); 85960786Sps /* Edit key section */ 86060786Sps fputbytes(out, editsection, sizeof(editsection)); 86160786Sps fputint(out, edittable.pbuffer - edittable.buffer); 86260786Sps fputbytes(out, (char *)edittable.buffer, edittable.pbuffer-edittable.buffer); 86360786Sps 86460786Sps /* Environment variable section */ 86560786Sps fputbytes(out, varsection, sizeof(varsection)); 86660786Sps fputint(out, vartable.pbuffer - vartable.buffer); 86760786Sps fputbytes(out, (char *)vartable.buffer, vartable.pbuffer-vartable.buffer); 86860786Sps 86960786Sps /* File trailer */ 87060786Sps fputbytes(out, endsection, sizeof(endsection)); 87160786Sps fputbytes(out, filetrailer, sizeof(filetrailer)); 87260786Sps return (0); 87360786Sps} 874