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