lesskey.c revision 60786
160786Sps/* 260786Sps * Copyright (C) 1984-2000 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{ 9660786Sps "back-bracket", A_B_BRACKET, 9760786Sps "back-line", A_B_LINE, 9860786Sps "back-line-force", A_BF_LINE, 9960786Sps "back-screen", A_B_SCREEN, 10060786Sps "back-scroll", A_B_SCROLL, 10160786Sps "back-search", A_B_SEARCH, 10260786Sps "back-window", A_B_WINDOW, 10360786Sps "debug", A_DEBUG, 10460786Sps "display-flag", A_DISP_OPTION, 10560786Sps "display-option", A_DISP_OPTION, 10660786Sps "end", A_GOEND, 10760786Sps "examine", A_EXAMINE, 10860786Sps "first-cmd", A_FIRSTCMD, 10960786Sps "firstcmd", A_FIRSTCMD, 11060786Sps "flush-repaint", A_FREPAINT, 11160786Sps "forw-bracket", A_F_BRACKET, 11260786Sps "forw-forever", A_F_FOREVER, 11360786Sps "forw-line", A_F_LINE, 11460786Sps "forw-line-force", A_FF_LINE, 11560786Sps "forw-screen", A_F_SCREEN, 11660786Sps "forw-screen-force", A_FF_SCREEN, 11760786Sps "forw-scroll", A_F_SCROLL, 11860786Sps "forw-search", A_F_SEARCH, 11960786Sps "forw-window", A_F_WINDOW, 12060786Sps "goto-end", A_GOEND, 12160786Sps "goto-line", A_GOLINE, 12260786Sps "goto-mark", A_GOMARK, 12360786Sps "help", A_HELP, 12460786Sps "index-file", A_INDEX_FILE, 12560786Sps "invalid", A_UINVALID, 12660786Sps "left-scroll", A_LSHIFT, 12760786Sps "next-file", A_NEXT_FILE, 12860786Sps "noaction", A_NOACTION, 12960786Sps "percent", A_PERCENT, 13060786Sps "pipe", A_PIPE, 13160786Sps "prev-file", A_PREV_FILE, 13260786Sps "quit", A_QUIT, 13360786Sps "repaint", A_REPAINT, 13460786Sps "repaint-flush", A_FREPAINT, 13560786Sps "repeat-search", A_AGAIN_SEARCH, 13660786Sps "repeat-search-all", A_T_AGAIN_SEARCH, 13760786Sps "reverse-search", A_REVERSE_SEARCH, 13860786Sps "reverse-search-all", A_T_REVERSE_SEARCH, 13960786Sps "right-scroll", A_RSHIFT, 14060786Sps "set-mark", A_SETMARK, 14160786Sps "shell", A_SHELL, 14260786Sps "status", A_STAT, 14360786Sps "toggle-flag", A_OPT_TOGGLE, 14460786Sps "toggle-option", A_OPT_TOGGLE, 14560786Sps "undo-hilite", A_UNDO_SEARCH, 14660786Sps "version", A_VERSION, 14760786Sps "visual", A_VISUAL, 14860786Sps NULL, 0 14960786Sps}; 15060786Sps 15160786Spsstruct cmdname editnames[] = 15260786Sps{ 15360786Sps "back-complete", EC_B_COMPLETE, 15460786Sps "backspace", EC_BACKSPACE, 15560786Sps "delete", EC_DELETE, 15660786Sps "down", EC_DOWN, 15760786Sps "end", EC_END, 15860786Sps "expand", EC_EXPAND, 15960786Sps "forw-complete", EC_F_COMPLETE, 16060786Sps "home", EC_HOME, 16160786Sps "insert", EC_INSERT, 16260786Sps "invalid", EC_UINVALID, 16360786Sps "kill-line", EC_LINEKILL, 16460786Sps "left", EC_LEFT, 16560786Sps "literal", EC_LITERAL, 16660786Sps "right", EC_RIGHT, 16760786Sps "up", EC_UP, 16860786Sps "word-backspace", EC_W_BACKSPACE, 16960786Sps "word-delete", EC_W_DELETE, 17060786Sps "word-left", EC_W_LEFT, 17160786Sps "word-right", EC_W_RIGHT, 17260786Sps NULL, 0 17360786Sps}; 17460786Sps 17560786Spsstruct table 17660786Sps{ 17760786Sps struct cmdname *names; 17860786Sps char *pbuffer; 17960786Sps char buffer[MAX_USERCMD]; 18060786Sps}; 18160786Sps 18260786Spsstruct table cmdtable; 18360786Spsstruct table edittable; 18460786Spsstruct table vartable; 18560786Spsstruct table *currtable = &cmdtable; 18660786Sps 18760786Spschar fileheader[] = { 18860786Sps C0_LESSKEY_MAGIC, 18960786Sps C1_LESSKEY_MAGIC, 19060786Sps C2_LESSKEY_MAGIC, 19160786Sps C3_LESSKEY_MAGIC 19260786Sps}; 19360786Spschar filetrailer[] = { 19460786Sps C0_END_LESSKEY_MAGIC, 19560786Sps C1_END_LESSKEY_MAGIC, 19660786Sps C2_END_LESSKEY_MAGIC 19760786Sps}; 19860786Spschar cmdsection[1] = { CMD_SECTION }; 19960786Spschar editsection[1] = { EDIT_SECTION }; 20060786Spschar varsection[1] = { VAR_SECTION }; 20160786Spschar endsection[1] = { END_SECTION }; 20260786Sps 20360786Spschar *infile = NULL; 20460786Spschar *outfile = NULL ; 20560786Sps 20660786Spsint linenum; 20760786Spsint errors; 20860786Sps 20960786Spsextern char version[]; 21060786Sps 21160786Sps void 21260786Spsusage() 21360786Sps{ 21460786Sps fprintf(stderr, "usage: lesskey [-o output] [input]\n"); 21560786Sps exit(1); 21660786Sps} 21760786Sps 21860786Sps char * 21960786Spsmkpathname(dirname, filename) 22060786Sps char *dirname; 22160786Sps char *filename; 22260786Sps{ 22360786Sps char *pathname; 22460786Sps 22560786Sps pathname = calloc(strlen(dirname) + strlen(filename) + 2, sizeof(char)); 22660786Sps strcpy(pathname, dirname); 22760786Sps strcat(pathname, PATHNAME_SEP); 22860786Sps strcat(pathname, filename); 22960786Sps return (pathname); 23060786Sps} 23160786Sps 23260786Sps/* 23360786Sps * Figure out the name of a default file (in the user's HOME directory). 23460786Sps */ 23560786Sps char * 23660786Spshomefile(filename) 23760786Sps char *filename; 23860786Sps{ 23960786Sps char *p; 24060786Sps char *pathname; 24160786Sps 24260786Sps if ((p = getenv("HOME")) != NULL && *p != '\0') 24360786Sps pathname = mkpathname(p, filename); 24460786Sps#if OS2 24560786Sps else if ((p = getenv("INIT")) != NULL && *p != '\0') 24660786Sps pathname = mkpathname(p, filename); 24760786Sps#endif 24860786Sps else 24960786Sps { 25060786Sps fprintf(stderr, "cannot find $HOME - using current directory\n"); 25160786Sps pathname = mkpathname(".", filename); 25260786Sps } 25360786Sps return (pathname); 25460786Sps} 25560786Sps 25660786Sps/* 25760786Sps * Parse command line arguments. 25860786Sps */ 25960786Sps void 26060786Spsparse_args(argc, argv) 26160786Sps int argc; 26260786Sps char **argv; 26360786Sps{ 26460786Sps char *arg; 26560786Sps 26660786Sps outfile = NULL; 26760786Sps while (--argc > 0) 26860786Sps { 26960786Sps arg = *++argv; 27060786Sps if (arg[0] != '-') 27160786Sps /* Arg does not start with "-"; it's not an option. */ 27260786Sps break; 27360786Sps if (arg[1] == '\0') 27460786Sps /* "-" means standard input. */ 27560786Sps break; 27660786Sps if (arg[1] == '-' && arg[2] == '\0') 27760786Sps { 27860786Sps /* "--" means end of options. */ 27960786Sps argc--; 28060786Sps argv++; 28160786Sps break; 28260786Sps } 28360786Sps switch (arg[1]) 28460786Sps { 28560786Sps case '-': 28660786Sps if (strncmp(arg, "--output", 8) == 0) 28760786Sps { 28860786Sps if (arg[8] == '\0') 28960786Sps outfile = &arg[8]; 29060786Sps else if (arg[8] == '=') 29160786Sps outfile = &arg[9]; 29260786Sps else 29360786Sps usage(); 29460786Sps goto opt_o; 29560786Sps } 29660786Sps if (strcmp(arg, "--version") == 0) 29760786Sps { 29860786Sps goto opt_V; 29960786Sps } 30060786Sps usage(); 30160786Sps break; 30260786Sps case 'o': 30360786Sps outfile = &argv[0][2]; 30460786Sps opt_o: 30560786Sps if (*outfile == '\0') 30660786Sps { 30760786Sps if (--argc <= 0) 30860786Sps usage(); 30960786Sps outfile = *(++argv); 31060786Sps } 31160786Sps break; 31260786Sps case 'V': 31360786Sps opt_V: 31460786Sps printf("lesskey version %s\n", version); 31560786Sps exit(0); 31660786Sps default: 31760786Sps usage(); 31860786Sps } 31960786Sps } 32060786Sps if (argc > 1) 32160786Sps usage(); 32260786Sps /* 32360786Sps * Open the input file, or use DEF_LESSKEYINFILE if none specified. 32460786Sps */ 32560786Sps if (argc > 0) 32660786Sps infile = *argv; 32760786Sps else 32860786Sps infile = homefile(DEF_LESSKEYINFILE); 32960786Sps} 33060786Sps 33160786Sps/* 33260786Sps * Initialize data structures. 33360786Sps */ 33460786Sps void 33560786Spsinit_tables() 33660786Sps{ 33760786Sps cmdtable.names = cmdnames; 33860786Sps cmdtable.pbuffer = cmdtable.buffer; 33960786Sps 34060786Sps edittable.names = editnames; 34160786Sps edittable.pbuffer = edittable.buffer; 34260786Sps 34360786Sps vartable.names = NULL; 34460786Sps vartable.pbuffer = vartable.buffer; 34560786Sps} 34660786Sps 34760786Sps/* 34860786Sps * Parse one character of a string. 34960786Sps */ 35060786Sps char * 35160786Spststr(pp) 35260786Sps char **pp; 35360786Sps{ 35460786Sps register char *p; 35560786Sps register char ch; 35660786Sps register int i; 35760786Sps static char buf[10]; 35860786Sps static char tstr_control_k[] = 35960786Sps { SK_SPECIAL_KEY, SK_CONTROL_K, 6, 1, 1, 1, '\0' }; 36060786Sps 36160786Sps p = *pp; 36260786Sps switch (*p) 36360786Sps { 36460786Sps case '\\': 36560786Sps ++p; 36660786Sps switch (*p) 36760786Sps { 36860786Sps case '0': case '1': case '2': case '3': 36960786Sps case '4': case '5': case '6': case '7': 37060786Sps /* 37160786Sps * Parse an octal number. 37260786Sps */ 37360786Sps ch = 0; 37460786Sps i = 0; 37560786Sps do 37660786Sps ch = 8*ch + (*p - '0'); 37760786Sps while (*++p >= '0' && *p <= '7' && ++i < 3); 37860786Sps *pp = p; 37960786Sps if (ch == CONTROL('K')) 38060786Sps return tstr_control_k; 38160786Sps buf[0] = ch; 38260786Sps buf[1] = '\0'; 38360786Sps return (buf); 38460786Sps case 'b': 38560786Sps *pp = p+1; 38660786Sps return ("\b"); 38760786Sps case 'e': 38860786Sps *pp = p+1; 38960786Sps buf[0] = ESC; 39060786Sps buf[1] = '\0'; 39160786Sps return (buf); 39260786Sps case 'n': 39360786Sps *pp = p+1; 39460786Sps return ("\n"); 39560786Sps case 'r': 39660786Sps *pp = p+1; 39760786Sps return ("\r"); 39860786Sps case 't': 39960786Sps *pp = p+1; 40060786Sps return ("\t"); 40160786Sps case 'k': 40260786Sps switch (*++p) 40360786Sps { 40460786Sps case 'u': ch = SK_UP_ARROW; break; 40560786Sps case 'd': ch = SK_DOWN_ARROW; break; 40660786Sps case 'r': ch = SK_RIGHT_ARROW; break; 40760786Sps case 'l': ch = SK_LEFT_ARROW; break; 40860786Sps case 'U': ch = SK_PAGE_UP; break; 40960786Sps case 'D': ch = SK_PAGE_DOWN; break; 41060786Sps case 'h': ch = SK_HOME; break; 41160786Sps case 'e': ch = SK_END; break; 41260786Sps case 'x': ch = SK_DELETE; break; 41360786Sps } 41460786Sps *pp = p+1; 41560786Sps buf[0] = SK_SPECIAL_KEY; 41660786Sps buf[1] = ch; 41760786Sps buf[2] = 6; 41860786Sps buf[3] = 1; 41960786Sps buf[4] = 1; 42060786Sps buf[5] = 1; 42160786Sps buf[6] = '\0'; 42260786Sps return (buf); 42360786Sps default: 42460786Sps /* 42560786Sps * Backslash followed by any other char 42660786Sps * just means that char. 42760786Sps */ 42860786Sps *pp = p+1; 42960786Sps buf[0] = *p; 43060786Sps buf[1] = '\0'; 43160786Sps if (buf[0] == CONTROL('K')) 43260786Sps return tstr_control_k; 43360786Sps return (buf); 43460786Sps } 43560786Sps case '^': 43660786Sps /* 43760786Sps * Carat means CONTROL. 43860786Sps */ 43960786Sps *pp = p+2; 44060786Sps buf[0] = CONTROL(p[1]); 44160786Sps buf[1] = '\0'; 44260786Sps if (buf[0] == CONTROL('K')) 44360786Sps return tstr_control_k; 44460786Sps return (buf); 44560786Sps } 44660786Sps *pp = p+1; 44760786Sps buf[0] = *p; 44860786Sps buf[1] = '\0'; 44960786Sps if (buf[0] == CONTROL('K')) 45060786Sps return tstr_control_k; 45160786Sps return (buf); 45260786Sps} 45360786Sps 45460786Sps/* 45560786Sps * Skip leading spaces in a string. 45660786Sps */ 45760786Sps public char * 45860786Spsskipsp(s) 45960786Sps register char *s; 46060786Sps{ 46160786Sps while (*s == ' ' || *s == '\t') 46260786Sps s++; 46360786Sps return (s); 46460786Sps} 46560786Sps 46660786Sps/* 46760786Sps * Skip non-space characters in a string. 46860786Sps */ 46960786Sps public char * 47060786Spsskipnsp(s) 47160786Sps register char *s; 47260786Sps{ 47360786Sps while (*s != '\0' && *s != ' ' && *s != '\t') 47460786Sps s++; 47560786Sps return (s); 47660786Sps} 47760786Sps 47860786Sps/* 47960786Sps * Clean up an input line: 48060786Sps * strip off the trailing newline & any trailing # comment. 48160786Sps */ 48260786Sps char * 48360786Spsclean_line(s) 48460786Sps char *s; 48560786Sps{ 48660786Sps register int i; 48760786Sps 48860786Sps s = skipsp(s); 48960786Sps for (i = 0; s[i] != '\n' && s[i] != '\r' && s[i] != '\0'; i++) 49060786Sps if (s[i] == '#' && (i == 0 || s[i-1] != '\\')) 49160786Sps break; 49260786Sps s[i] = '\0'; 49360786Sps return (s); 49460786Sps} 49560786Sps 49660786Sps/* 49760786Sps * Add a byte to the output command table. 49860786Sps */ 49960786Sps void 50060786Spsadd_cmd_char(c) 50160786Sps int c; 50260786Sps{ 50360786Sps if (currtable->pbuffer >= currtable->buffer + MAX_USERCMD) 50460786Sps { 50560786Sps error("too many commands"); 50660786Sps exit(1); 50760786Sps } 50860786Sps *(currtable->pbuffer)++ = c; 50960786Sps} 51060786Sps 51160786Sps/* 51260786Sps * Add a string to the output command table. 51360786Sps */ 51460786Sps void 51560786Spsadd_cmd_str(s) 51660786Sps char *s; 51760786Sps{ 51860786Sps for ( ; *s != '\0'; s++) 51960786Sps add_cmd_char(*s); 52060786Sps} 52160786Sps 52260786Sps/* 52360786Sps * See if we have a special "control" line. 52460786Sps */ 52560786Sps int 52660786Spscontrol_line(s) 52760786Sps char *s; 52860786Sps{ 52960786Sps#define PREFIX(str,pat) (strncmp(str,pat,strlen(pat)-1) == 0) 53060786Sps 53160786Sps if (PREFIX(s, "#line-edit")) 53260786Sps { 53360786Sps currtable = &edittable; 53460786Sps return (1); 53560786Sps } 53660786Sps if (PREFIX(s, "#command")) 53760786Sps { 53860786Sps currtable = &cmdtable; 53960786Sps return (1); 54060786Sps } 54160786Sps if (PREFIX(s, "#env")) 54260786Sps { 54360786Sps currtable = &vartable; 54460786Sps return (1); 54560786Sps } 54660786Sps if (PREFIX(s, "#stop")) 54760786Sps { 54860786Sps add_cmd_char('\0'); 54960786Sps add_cmd_char(A_END_LIST); 55060786Sps return (1); 55160786Sps } 55260786Sps return (0); 55360786Sps} 55460786Sps 55560786Sps/* 55660786Sps * Output some bytes. 55760786Sps */ 55860786Sps void 55960786Spsfputbytes(fd, buf, len) 56060786Sps FILE *fd; 56160786Sps char *buf; 56260786Sps int len; 56360786Sps{ 56460786Sps while (len-- > 0) 56560786Sps { 56660786Sps fwrite(buf, sizeof(char), 1, fd); 56760786Sps buf++; 56860786Sps } 56960786Sps} 57060786Sps 57160786Sps/* 57260786Sps * Output an integer, in special KRADIX form. 57360786Sps */ 57460786Sps void 57560786Spsfputint(fd, val) 57660786Sps FILE *fd; 57760786Sps unsigned int val; 57860786Sps{ 57960786Sps char c; 58060786Sps 58160786Sps if (val >= KRADIX*KRADIX) 58260786Sps { 58360786Sps fprintf(stderr, "error: integer too big (%d > %d)\n", 58460786Sps val, KRADIX*KRADIX); 58560786Sps exit(1); 58660786Sps } 58760786Sps c = val % KRADIX; 58860786Sps fwrite(&c, sizeof(char), 1, fd); 58960786Sps c = val / KRADIX; 59060786Sps fwrite(&c, sizeof(char), 1, fd); 59160786Sps} 59260786Sps 59360786Sps/* 59460786Sps * Find an action, given the name of the action. 59560786Sps */ 59660786Sps int 59760786Spsfindaction(actname) 59860786Sps char *actname; 59960786Sps{ 60060786Sps int i; 60160786Sps 60260786Sps for (i = 0; currtable->names[i].cn_name != NULL; i++) 60360786Sps if (strcmp(currtable->names[i].cn_name, actname) == 0) 60460786Sps return (currtable->names[i].cn_action); 60560786Sps error("unknown action"); 60660786Sps return (A_INVALID); 60760786Sps} 60860786Sps 60960786Sps void 61060786Spserror(s) 61160786Sps char *s; 61260786Sps{ 61360786Sps fprintf(stderr, "line %d: %s\n", linenum, s); 61460786Sps errors++; 61560786Sps} 61660786Sps 61760786Sps 61860786Sps void 61960786Spsparse_cmdline(p) 62060786Sps char *p; 62160786Sps{ 62260786Sps int cmdlen; 62360786Sps char *actname; 62460786Sps int action; 62560786Sps char *s; 62660786Sps char c; 62760786Sps 62860786Sps /* 62960786Sps * Parse the command string and store it in the current table. 63060786Sps */ 63160786Sps cmdlen = 0; 63260786Sps do 63360786Sps { 63460786Sps s = tstr(&p); 63560786Sps cmdlen += strlen(s); 63660786Sps if (cmdlen > MAX_CMDLEN) 63760786Sps error("command too long"); 63860786Sps else 63960786Sps add_cmd_str(s); 64060786Sps } while (*p != ' ' && *p != '\t' && *p != '\0'); 64160786Sps /* 64260786Sps * Terminate the command string with a null byte. 64360786Sps */ 64460786Sps add_cmd_char('\0'); 64560786Sps 64660786Sps /* 64760786Sps * Skip white space between the command string 64860786Sps * and the action name. 64960786Sps * Terminate the action name with a null byte. 65060786Sps */ 65160786Sps p = skipsp(p); 65260786Sps if (*p == '\0') 65360786Sps { 65460786Sps error("missing action"); 65560786Sps return; 65660786Sps } 65760786Sps actname = p; 65860786Sps p = skipnsp(p); 65960786Sps c = *p; 66060786Sps *p = '\0'; 66160786Sps 66260786Sps /* 66360786Sps * Parse the action name and store it in the current table. 66460786Sps */ 66560786Sps action = findaction(actname); 66660786Sps 66760786Sps /* 66860786Sps * See if an extra string follows the action name. 66960786Sps */ 67060786Sps *p = c; 67160786Sps p = skipsp(p); 67260786Sps if (*p == '\0') 67360786Sps { 67460786Sps add_cmd_char(action); 67560786Sps } else 67660786Sps { 67760786Sps /* 67860786Sps * OR the special value A_EXTRA into the action byte. 67960786Sps * Put the extra string after the action byte. 68060786Sps */ 68160786Sps add_cmd_char(action | A_EXTRA); 68260786Sps while (*p != '\0') 68360786Sps add_cmd_str(tstr(&p)); 68460786Sps add_cmd_char('\0'); 68560786Sps } 68660786Sps} 68760786Sps 68860786Sps void 68960786Spsparse_varline(p) 69060786Sps char *p; 69160786Sps{ 69260786Sps char *s; 69360786Sps 69460786Sps do 69560786Sps { 69660786Sps s = tstr(&p); 69760786Sps add_cmd_str(s); 69860786Sps } while (*p != ' ' && *p != '\t' && *p != '=' && *p != '\0'); 69960786Sps /* 70060786Sps * Terminate the variable name with a null byte. 70160786Sps */ 70260786Sps add_cmd_char('\0'); 70360786Sps 70460786Sps p = skipsp(p); 70560786Sps if (*p++ != '=') 70660786Sps { 70760786Sps error("missing ="); 70860786Sps return; 70960786Sps } 71060786Sps 71160786Sps add_cmd_char(EV_OK|A_EXTRA); 71260786Sps 71360786Sps p = skipsp(p); 71460786Sps while (*p != '\0') 71560786Sps { 71660786Sps s = tstr(&p); 71760786Sps add_cmd_str(s); 71860786Sps } 71960786Sps add_cmd_char('\0'); 72060786Sps} 72160786Sps 72260786Sps/* 72360786Sps * Parse a line from the lesskey file. 72460786Sps */ 72560786Sps void 72660786Spsparse_line(line) 72760786Sps char *line; 72860786Sps{ 72960786Sps char *p; 73060786Sps 73160786Sps /* 73260786Sps * See if it is a control line. 73360786Sps */ 73460786Sps if (control_line(line)) 73560786Sps return; 73660786Sps /* 73760786Sps * Skip leading white space. 73860786Sps * Replace the final newline with a null byte. 73960786Sps * Ignore blank lines and comments. 74060786Sps */ 74160786Sps p = clean_line(line); 74260786Sps if (*p == '\0') 74360786Sps return; 74460786Sps 74560786Sps if (currtable == &vartable) 74660786Sps parse_varline(p); 74760786Sps else 74860786Sps parse_cmdline(p); 74960786Sps} 75060786Sps 75160786Sps int 75260786Spsmain(argc, argv) 75360786Sps int argc; 75460786Sps char *argv[]; 75560786Sps{ 75660786Sps FILE *desc; 75760786Sps FILE *out; 75860786Sps char line[200]; 75960786Sps 76060786Sps#ifdef WIN32 76160786Sps if (getenv("HOME") == NULL) 76260786Sps { 76360786Sps /* 76460786Sps * If there is no HOME environment variable, 76560786Sps * try the concatenation of HOMEDRIVE + HOMEPATH. 76660786Sps */ 76760786Sps char *drive = getenv("HOMEDRIVE"); 76860786Sps char *path = getenv("HOMEPATH"); 76960786Sps if (drive != NULL && path != NULL) 77060786Sps { 77160786Sps char *env = (char *) calloc(strlen(drive) + 77260786Sps strlen(path) + 6, sizeof(char)); 77360786Sps strcpy(env, "HOME="); 77460786Sps strcat(env, drive); 77560786Sps strcat(env, path); 77660786Sps putenv(env); 77760786Sps } 77860786Sps } 77960786Sps#endif /* WIN32 */ 78060786Sps 78160786Sps /* 78260786Sps * Process command line arguments. 78360786Sps */ 78460786Sps parse_args(argc, argv); 78560786Sps init_tables(); 78660786Sps 78760786Sps /* 78860786Sps * Open the input file. 78960786Sps */ 79060786Sps if (strcmp(infile, "-") == 0) 79160786Sps desc = stdin; 79260786Sps else if ((desc = fopen(infile, "r")) == NULL) 79360786Sps { 79460786Sps#if HAVE_PERROR 79560786Sps perror(infile); 79660786Sps#else 79760786Sps fprintf(stderr, "Cannot open %s\n", infile); 79860786Sps#endif 79960786Sps usage(); 80060786Sps } 80160786Sps 80260786Sps /* 80360786Sps * Read and parse the input file, one line at a time. 80460786Sps */ 80560786Sps errors = 0; 80660786Sps linenum = 0; 80760786Sps while (fgets(line, sizeof(line), desc) != NULL) 80860786Sps { 80960786Sps ++linenum; 81060786Sps parse_line(line); 81160786Sps } 81260786Sps 81360786Sps /* 81460786Sps * Write the output file. 81560786Sps * If no output file was specified, use "$HOME/.less" 81660786Sps */ 81760786Sps if (errors > 0) 81860786Sps { 81960786Sps fprintf(stderr, "%d errors; no output produced\n", errors); 82060786Sps exit(1); 82160786Sps } 82260786Sps 82360786Sps if (outfile == NULL) 82460786Sps outfile = getenv("LESSKEY"); 82560786Sps if (outfile == NULL) 82660786Sps outfile = homefile(LESSKEYFILE); 82760786Sps if ((out = fopen(outfile, "wb")) == NULL) 82860786Sps { 82960786Sps#if HAVE_PERROR 83060786Sps perror(outfile); 83160786Sps#else 83260786Sps fprintf(stderr, "Cannot open %s\n", outfile); 83360786Sps#endif 83460786Sps exit(1); 83560786Sps } 83660786Sps 83760786Sps /* File header */ 83860786Sps fputbytes(out, fileheader, sizeof(fileheader)); 83960786Sps 84060786Sps /* Command key section */ 84160786Sps fputbytes(out, cmdsection, sizeof(cmdsection)); 84260786Sps fputint(out, cmdtable.pbuffer - cmdtable.buffer); 84360786Sps fputbytes(out, (char *)cmdtable.buffer, cmdtable.pbuffer-cmdtable.buffer); 84460786Sps /* Edit key section */ 84560786Sps fputbytes(out, editsection, sizeof(editsection)); 84660786Sps fputint(out, edittable.pbuffer - edittable.buffer); 84760786Sps fputbytes(out, (char *)edittable.buffer, edittable.pbuffer-edittable.buffer); 84860786Sps 84960786Sps /* Environment variable section */ 85060786Sps fputbytes(out, varsection, sizeof(varsection)); 85160786Sps fputint(out, vartable.pbuffer - vartable.buffer); 85260786Sps fputbytes(out, (char *)vartable.buffer, vartable.pbuffer-vartable.buffer); 85360786Sps 85460786Sps /* File trailer */ 85560786Sps fputbytes(out, endsection, sizeof(endsection)); 85660786Sps fputbytes(out, filetrailer, sizeof(filetrailer)); 85760786Sps return (0); 85860786Sps} 859