decode.c revision 161475
160786Sps/* 2161475Sdelphij * Copyright (C) 1984-2004 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 * Routines to decode user commands. 1460786Sps * 1560786Sps * This is all table driven. 1660786Sps * A command table is a sequence of command descriptors. 1760786Sps * Each command descriptor is a sequence of bytes with the following format: 1860786Sps * <c1><c2>...<cN><0><action> 1960786Sps * The characters c1,c2,...,cN are the command string; that is, 2060786Sps * the characters which the user must type. 2160786Sps * It is terminated by a null <0> byte. 2260786Sps * The byte after the null byte is the action code associated 2360786Sps * with the command string. 2460786Sps * If an action byte is OR-ed with A_EXTRA, this indicates 2560786Sps * that the option byte is followed by an extra string. 2660786Sps * 2760786Sps * There may be many command tables. 2860786Sps * The first (default) table is built-in. 2960786Sps * Other tables are read in from "lesskey" files. 3060786Sps * All the tables are linked together and are searched in order. 3160786Sps */ 3260786Sps 3360786Sps#include "less.h" 3460786Sps#include "cmd.h" 3560786Sps#include "lesskey.h" 3660786Sps 37161475Sdelphijextern int erase_char, erase2_char, kill_char; 3860786Spsextern int secure; 3960786Sps 4060786Sps#define SK(k) \ 4160786Sps SK_SPECIAL_KEY, (k), 6, 1, 1, 1 4260786Sps/* 4360786Sps * Command table is ordered roughly according to expected 4460786Sps * frequency of use, so the common commands are near the beginning. 4560786Sps */ 4660786Sps 4760786Spsstatic unsigned char cmdtable[] = 4860786Sps{ 4960786Sps '\r',0, A_F_LINE, 5060786Sps '\n',0, A_F_LINE, 5160786Sps 'e',0, A_F_LINE, 5260786Sps 'j',0, A_F_LINE, 5360786Sps SK(SK_DOWN_ARROW),0, A_F_LINE, 5460786Sps CONTROL('E'),0, A_F_LINE, 5560786Sps CONTROL('N'),0, A_F_LINE, 5660786Sps 'k',0, A_B_LINE, 5760786Sps 'y',0, A_B_LINE, 5860786Sps CONTROL('Y'),0, A_B_LINE, 5960786Sps SK(SK_CONTROL_K),0, A_B_LINE, 6060786Sps CONTROL('P'),0, A_B_LINE, 6160786Sps SK(SK_UP_ARROW),0, A_B_LINE, 6260786Sps 'J',0, A_FF_LINE, 6360786Sps 'K',0, A_BF_LINE, 6460786Sps 'Y',0, A_BF_LINE, 6560786Sps 'd',0, A_F_SCROLL, 6660786Sps CONTROL('D'),0, A_F_SCROLL, 6760786Sps 'u',0, A_B_SCROLL, 6860786Sps CONTROL('U'),0, A_B_SCROLL, 6960786Sps ' ',0, A_F_SCREEN, 7060786Sps 'f',0, A_F_SCREEN, 7160786Sps CONTROL('F'),0, A_F_SCREEN, 7260786Sps CONTROL('V'),0, A_F_SCREEN, 7360786Sps SK(SK_PAGE_DOWN),0, A_F_SCREEN, 7460786Sps 'b',0, A_B_SCREEN, 7560786Sps CONTROL('B'),0, A_B_SCREEN, 7660786Sps ESC,'v',0, A_B_SCREEN, 7760786Sps SK(SK_PAGE_UP),0, A_B_SCREEN, 7860786Sps 'z',0, A_F_WINDOW, 7960786Sps 'w',0, A_B_WINDOW, 8060786Sps ESC,' ',0, A_FF_SCREEN, 8160786Sps 'F',0, A_F_FOREVER, 8260786Sps 'R',0, A_FREPAINT, 8360786Sps 'r',0, A_REPAINT, 8460786Sps CONTROL('R'),0, A_REPAINT, 8560786Sps CONTROL('L'),0, A_REPAINT, 8660786Sps ESC,'u',0, A_UNDO_SEARCH, 8760786Sps 'g',0, A_GOLINE, 8860786Sps SK(SK_HOME),0, A_GOLINE, 8960786Sps '<',0, A_GOLINE, 9060786Sps ESC,'<',0, A_GOLINE, 9160786Sps 'p',0, A_PERCENT, 9260786Sps '%',0, A_PERCENT, 9360786Sps ESC,'[',0, A_LSHIFT, 9460786Sps ESC,']',0, A_RSHIFT, 9560786Sps ESC,'(',0, A_LSHIFT, 9660786Sps ESC,')',0, A_RSHIFT, 9760786Sps SK(SK_RIGHT_ARROW),0, A_RSHIFT, 9860786Sps SK(SK_LEFT_ARROW),0, A_LSHIFT, 9960786Sps '{',0, A_F_BRACKET|A_EXTRA, '{','}',0, 10060786Sps '}',0, A_B_BRACKET|A_EXTRA, '{','}',0, 10160786Sps '(',0, A_F_BRACKET|A_EXTRA, '(',')',0, 10260786Sps ')',0, A_B_BRACKET|A_EXTRA, '(',')',0, 10360786Sps '[',0, A_F_BRACKET|A_EXTRA, '[',']',0, 10460786Sps ']',0, A_B_BRACKET|A_EXTRA, '[',']',0, 10560786Sps ESC,CONTROL('F'),0, A_F_BRACKET, 10660786Sps ESC,CONTROL('B'),0, A_B_BRACKET, 10760786Sps 'G',0, A_GOEND, 10860786Sps ESC,'>',0, A_GOEND, 10960786Sps '>',0, A_GOEND, 11060786Sps SK(SK_END),0, A_GOEND, 11160786Sps 'P',0, A_GOPOS, 11260786Sps 11360786Sps '0',0, A_DIGIT, 11460786Sps '1',0, A_DIGIT, 11560786Sps '2',0, A_DIGIT, 11660786Sps '3',0, A_DIGIT, 11760786Sps '4',0, A_DIGIT, 11860786Sps '5',0, A_DIGIT, 11960786Sps '6',0, A_DIGIT, 12060786Sps '7',0, A_DIGIT, 12160786Sps '8',0, A_DIGIT, 12260786Sps '9',0, A_DIGIT, 12360786Sps 12460786Sps '=',0, A_STAT, 12560786Sps CONTROL('G'),0, A_STAT, 12660786Sps ':','f',0, A_STAT, 12760786Sps '/',0, A_F_SEARCH, 12860786Sps '?',0, A_B_SEARCH, 12960786Sps ESC,'/',0, A_F_SEARCH|A_EXTRA, '*',0, 13060786Sps ESC,'?',0, A_B_SEARCH|A_EXTRA, '*',0, 13160786Sps 'n',0, A_AGAIN_SEARCH, 13260786Sps ESC,'n',0, A_T_AGAIN_SEARCH, 13360786Sps 'N',0, A_REVERSE_SEARCH, 13460786Sps ESC,'N',0, A_T_REVERSE_SEARCH, 13560786Sps 'm',0, A_SETMARK, 13660786Sps '\'',0, A_GOMARK, 13760786Sps CONTROL('X'),CONTROL('X'),0, A_GOMARK, 13860786Sps 'E',0, A_EXAMINE, 13960786Sps ':','e',0, A_EXAMINE, 14060786Sps CONTROL('X'),CONTROL('V'),0, A_EXAMINE, 14160786Sps ':','n',0, A_NEXT_FILE, 14260786Sps ':','p',0, A_PREV_FILE, 14389019Sps 't',0, A_NEXT_TAG, 14489019Sps 'T',0, A_PREV_TAG, 14560786Sps ':','x',0, A_INDEX_FILE, 14660786Sps ':','d',0, A_REMOVE_FILE, 14760786Sps '-',0, A_OPT_TOGGLE, 14860786Sps ':','t',0, A_OPT_TOGGLE|A_EXTRA, 't',0, 14960786Sps 's',0, A_OPT_TOGGLE|A_EXTRA, 'o',0, 15060786Sps '_',0, A_DISP_OPTION, 15160786Sps '|',0, A_PIPE, 15260786Sps 'v',0, A_VISUAL, 15360786Sps '!',0, A_SHELL, 15460786Sps '+',0, A_FIRSTCMD, 15560786Sps 15660786Sps 'H',0, A_HELP, 15760786Sps 'h',0, A_HELP, 15860786Sps SK(SK_F1),0, A_HELP, 15960786Sps 'V',0, A_VERSION, 16060786Sps 'q',0, A_QUIT, 16160786Sps 'Q',0, A_QUIT, 16260786Sps ':','q',0, A_QUIT, 16360786Sps ':','Q',0, A_QUIT, 16460786Sps 'Z','Z',0, A_QUIT 16560786Sps}; 16660786Sps 16760786Spsstatic unsigned char edittable[] = 16860786Sps{ 16960786Sps '\t',0, EC_F_COMPLETE, /* TAB */ 17060786Sps '\17',0, EC_B_COMPLETE, /* BACKTAB */ 17160786Sps SK(SK_BACKTAB),0, EC_B_COMPLETE, /* BACKTAB */ 17260786Sps ESC,'\t',0, EC_B_COMPLETE, /* ESC TAB */ 17360786Sps CONTROL('L'),0, EC_EXPAND, /* CTRL-L */ 17460786Sps CONTROL('V'),0, EC_LITERAL, /* BACKSLASH */ 17560786Sps CONTROL('A'),0, EC_LITERAL, /* BACKSLASH */ 17660786Sps ESC,'l',0, EC_RIGHT, /* ESC l */ 17760786Sps SK(SK_RIGHT_ARROW),0, EC_RIGHT, /* RIGHTARROW */ 17860786Sps ESC,'h',0, EC_LEFT, /* ESC h */ 17960786Sps SK(SK_LEFT_ARROW),0, EC_LEFT, /* LEFTARROW */ 18060786Sps ESC,'b',0, EC_W_LEFT, /* ESC b */ 18160786Sps ESC,SK(SK_LEFT_ARROW),0, EC_W_LEFT, /* ESC LEFTARROW */ 18260786Sps SK(SK_CTL_LEFT_ARROW),0, EC_W_LEFT, /* CTRL-LEFTARROW */ 18360786Sps ESC,'w',0, EC_W_RIGHT, /* ESC w */ 18460786Sps ESC,SK(SK_RIGHT_ARROW),0, EC_W_RIGHT, /* ESC RIGHTARROW */ 18560786Sps SK(SK_CTL_RIGHT_ARROW),0, EC_W_RIGHT, /* CTRL-RIGHTARROW */ 18660786Sps ESC,'i',0, EC_INSERT, /* ESC i */ 18760786Sps SK(SK_INSERT),0, EC_INSERT, /* INSERT */ 18860786Sps ESC,'x',0, EC_DELETE, /* ESC x */ 18960786Sps SK(SK_DELETE),0, EC_DELETE, /* DELETE */ 19060786Sps ESC,'X',0, EC_W_DELETE, /* ESC X */ 19160786Sps ESC,SK(SK_DELETE),0, EC_W_DELETE, /* ESC DELETE */ 19260786Sps SK(SK_CTL_DELETE),0, EC_W_DELETE, /* CTRL-DELETE */ 19360786Sps SK(SK_CTL_BACKSPACE),0, EC_W_BACKSPACE, /* CTRL-BACKSPACE */ 19460786Sps ESC,'\b',0, EC_W_BACKSPACE, /* ESC BACKSPACE */ 19560786Sps ESC,'0',0, EC_HOME, /* ESC 0 */ 19660786Sps SK(SK_HOME),0, EC_HOME, /* HOME */ 19760786Sps ESC,'$',0, EC_END, /* ESC $ */ 19860786Sps SK(SK_END),0, EC_END, /* END */ 19960786Sps ESC,'k',0, EC_UP, /* ESC k */ 20060786Sps SK(SK_UP_ARROW),0, EC_UP, /* UPARROW */ 20160786Sps ESC,'j',0, EC_DOWN, /* ESC j */ 20260786Sps SK(SK_DOWN_ARROW),0, EC_DOWN, /* DOWNARROW */ 20360786Sps}; 20460786Sps 20560786Sps/* 20660786Sps * Structure to support a list of command tables. 20760786Sps */ 20860786Spsstruct tablelist 20960786Sps{ 21060786Sps struct tablelist *t_next; 21160786Sps char *t_start; 21260786Sps char *t_end; 21360786Sps}; 21460786Sps 21560786Sps/* 21660786Sps * List of command tables and list of line-edit tables. 21760786Sps */ 21860786Spsstatic struct tablelist *list_fcmd_tables = NULL; 21960786Spsstatic struct tablelist *list_ecmd_tables = NULL; 22060786Spsstatic struct tablelist *list_var_tables = NULL; 22160786Spsstatic struct tablelist *list_sysvar_tables = NULL; 22260786Sps 22360786Sps 22460786Sps/* 22560786Sps * Expand special key abbreviations in a command table. 22660786Sps */ 22760786Sps static void 22860786Spsexpand_special_keys(table, len) 22960786Sps char *table; 23060786Sps int len; 23160786Sps{ 23260786Sps register char *fm; 23360786Sps register char *to; 23460786Sps register int a; 23560786Sps char *repl; 23660786Sps int klen; 23760786Sps 23860786Sps for (fm = table; fm < table + len; ) 23960786Sps { 24060786Sps /* 24160786Sps * Rewrite each command in the table with any 24260786Sps * special key abbreviations expanded. 24360786Sps */ 24460786Sps for (to = fm; *fm != '\0'; ) 24560786Sps { 24660786Sps if (*fm != SK_SPECIAL_KEY) 24760786Sps { 24860786Sps *to++ = *fm++; 24960786Sps continue; 25060786Sps } 25160786Sps /* 25260786Sps * After SK_SPECIAL_KEY, next byte is the type 25360786Sps * of special key (one of the SK_* contants), 25460786Sps * and the byte after that is the number of bytes, 25560786Sps * N, reserved by the abbreviation (including the 25660786Sps * SK_SPECIAL_KEY and key type bytes). 25760786Sps * Replace all N bytes with the actual bytes 25860786Sps * output by the special key on this terminal. 25960786Sps */ 26060786Sps repl = special_key_str(fm[1]); 26160786Sps klen = fm[2] & 0377; 26260786Sps fm += klen; 263128345Stjr if (repl == NULL || (int) strlen(repl) > klen) 26460786Sps repl = "\377"; 26560786Sps while (*repl != '\0') 26660786Sps *to++ = *repl++; 26760786Sps } 26860786Sps *to++ = '\0'; 26960786Sps /* 27060786Sps * Fill any unused bytes between end of command and 27160786Sps * the action byte with A_SKIP. 27260786Sps */ 27360786Sps while (to <= fm) 27460786Sps *to++ = A_SKIP; 27560786Sps fm++; 27660786Sps a = *fm++ & 0377; 27760786Sps if (a & A_EXTRA) 27860786Sps { 27960786Sps while (*fm++ != '\0') 28060786Sps continue; 28160786Sps } 28260786Sps } 28360786Sps} 28460786Sps 28560786Sps/* 28660786Sps * Initialize the command lists. 28760786Sps */ 28860786Sps public void 28960786Spsinit_cmds() 29060786Sps{ 29160786Sps /* 29260786Sps * Add the default command tables. 29360786Sps */ 29460786Sps add_fcmd_table((char*)cmdtable, sizeof(cmdtable)); 29560786Sps add_ecmd_table((char*)edittable, sizeof(edittable)); 29660786Sps#if USERFILE 29760786Sps /* 29889019Sps * For backwards compatibility, 29989019Sps * try to add tables in the OLD system lesskey file. 30089019Sps */ 30189019Sps#ifdef BINDIR 30289019Sps add_hometable(NULL, BINDIR "/.sysless", 1); 30389019Sps#endif 30489019Sps /* 30560786Sps * Try to add the tables in the system lesskey file. 30660786Sps */ 30760786Sps add_hometable("LESSKEY_SYSTEM", LESSKEYFILE_SYS, 1); 30860786Sps /* 30960786Sps * Try to add the tables in the standard lesskey file "$HOME/.less". 31060786Sps */ 31160786Sps add_hometable("LESSKEY", LESSKEYFILE, 0); 31260786Sps#endif 31360786Sps} 31460786Sps 31560786Sps/* 31660786Sps * Add a command table. 31760786Sps */ 31860786Sps static int 31960786Spsadd_cmd_table(tlist, buf, len) 32060786Sps struct tablelist **tlist; 32160786Sps char *buf; 32260786Sps int len; 32360786Sps{ 32460786Sps register struct tablelist *t; 32560786Sps 32660786Sps if (len == 0) 32760786Sps return (0); 32860786Sps /* 32960786Sps * Allocate a tablelist structure, initialize it, 33060786Sps * and link it into the list of tables. 33160786Sps */ 33260786Sps if ((t = (struct tablelist *) 33360786Sps calloc(1, sizeof(struct tablelist))) == NULL) 33460786Sps { 33560786Sps return (-1); 33660786Sps } 33760786Sps expand_special_keys(buf, len); 33860786Sps t->t_start = buf; 33960786Sps t->t_end = buf + len; 34060786Sps t->t_next = *tlist; 34160786Sps *tlist = t; 34260786Sps return (0); 34360786Sps} 34460786Sps 34560786Sps/* 34660786Sps * Add a command table. 34760786Sps */ 34860786Sps public void 34960786Spsadd_fcmd_table(buf, len) 35060786Sps char *buf; 35160786Sps int len; 35260786Sps{ 35360786Sps if (add_cmd_table(&list_fcmd_tables, buf, len) < 0) 35460786Sps error("Warning: some commands disabled", NULL_PARG); 35560786Sps} 35660786Sps 35760786Sps/* 35860786Sps * Add an editing command table. 35960786Sps */ 36060786Sps public void 36160786Spsadd_ecmd_table(buf, len) 36260786Sps char *buf; 36360786Sps int len; 36460786Sps{ 36560786Sps if (add_cmd_table(&list_ecmd_tables, buf, len) < 0) 36660786Sps error("Warning: some edit commands disabled", NULL_PARG); 36760786Sps} 36860786Sps 36960786Sps/* 37060786Sps * Add an environment variable table. 37160786Sps */ 37260786Sps static void 37360786Spsadd_var_table(tlist, buf, len) 37460786Sps struct tablelist **tlist; 37560786Sps char *buf; 37660786Sps int len; 37760786Sps{ 37860786Sps if (add_cmd_table(tlist, buf, len) < 0) 37960786Sps error("Warning: environment variables from lesskey file unavailable", NULL_PARG); 38060786Sps} 38160786Sps 38260786Sps/* 38360786Sps * Search a single command table for the command string in cmd. 38460786Sps */ 38563128Sps static int 38660786Spscmd_search(cmd, table, endtable, sp) 38760786Sps char *cmd; 38860786Sps char *table; 38960786Sps char *endtable; 39060786Sps char **sp; 39160786Sps{ 39260786Sps register char *p; 39360786Sps register char *q; 39460786Sps register int a; 39560786Sps 39663128Sps *sp = NULL; 39760786Sps for (p = table, q = cmd; p < endtable; p++, q++) 39860786Sps { 39960786Sps if (*p == *q) 40060786Sps { 40160786Sps /* 40260786Sps * Current characters match. 40360786Sps * If we're at the end of the string, we've found it. 40460786Sps * Return the action code, which is the character 40560786Sps * after the null at the end of the string 40660786Sps * in the command table. 40760786Sps */ 40860786Sps if (*p == '\0') 40960786Sps { 41060786Sps a = *++p & 0377; 41160786Sps while (a == A_SKIP) 41260786Sps a = *++p & 0377; 41360786Sps if (a == A_END_LIST) 41460786Sps { 41560786Sps /* 41660786Sps * We get here only if the original 41760786Sps * cmd string passed in was empty (""). 41860786Sps * I don't think that can happen, 41960786Sps * but just in case ... 42060786Sps */ 42160786Sps return (A_UINVALID); 42260786Sps } 42360786Sps /* 42460786Sps * Check for an "extra" string. 42560786Sps */ 42660786Sps if (a & A_EXTRA) 42760786Sps { 42860786Sps *sp = ++p; 42960786Sps a &= ~A_EXTRA; 43063128Sps } 43160786Sps return (a); 43260786Sps } 43360786Sps } else if (*q == '\0') 43460786Sps { 43560786Sps /* 43660786Sps * Hit the end of the user's command, 43760786Sps * but not the end of the string in the command table. 43860786Sps * The user's command is incomplete. 43960786Sps */ 44060786Sps return (A_PREFIX); 44160786Sps } else 44260786Sps { 44360786Sps /* 44460786Sps * Not a match. 44560786Sps * Skip ahead to the next command in the 44660786Sps * command table, and reset the pointer 44760786Sps * to the beginning of the user's command. 44860786Sps */ 44960786Sps if (*p == '\0' && p[1] == A_END_LIST) 45060786Sps { 45160786Sps /* 45260786Sps * A_END_LIST is a special marker that tells 45360786Sps * us to abort the cmd search. 45460786Sps */ 45560786Sps return (A_UINVALID); 45660786Sps } 45760786Sps while (*p++ != '\0') 45860786Sps continue; 45960786Sps while (*p == A_SKIP) 46060786Sps p++; 46160786Sps if (*p & A_EXTRA) 46260786Sps while (*++p != '\0') 46360786Sps continue; 46460786Sps q = cmd-1; 46560786Sps } 46660786Sps } 46760786Sps /* 46860786Sps * No match found in the entire command table. 46960786Sps */ 47060786Sps return (A_INVALID); 47160786Sps} 47260786Sps 47360786Sps/* 47460786Sps * Decode a command character and return the associated action. 47560786Sps * The "extra" string, if any, is returned in sp. 47660786Sps */ 47760786Sps static int 47860786Spscmd_decode(tlist, cmd, sp) 47960786Sps struct tablelist *tlist; 48060786Sps char *cmd; 48160786Sps char **sp; 48260786Sps{ 48360786Sps register struct tablelist *t; 48460786Sps register int action = A_INVALID; 48560786Sps 48660786Sps /* 48760786Sps * Search thru all the command tables. 48860786Sps * Stop when we find an action which is not A_INVALID. 48960786Sps */ 49060786Sps for (t = tlist; t != NULL; t = t->t_next) 49160786Sps { 49260786Sps action = cmd_search(cmd, t->t_start, t->t_end, sp); 49360786Sps if (action != A_INVALID) 49460786Sps break; 49560786Sps } 49663128Sps if (action == A_UINVALID) 49763128Sps action = A_INVALID; 49860786Sps return (action); 49960786Sps} 50060786Sps 50160786Sps/* 50260786Sps * Decode a command from the cmdtables list. 50360786Sps */ 50460786Sps public int 50560786Spsfcmd_decode(cmd, sp) 50660786Sps char *cmd; 50760786Sps char **sp; 50860786Sps{ 50960786Sps return (cmd_decode(list_fcmd_tables, cmd, sp)); 51060786Sps} 51160786Sps 51260786Sps/* 51360786Sps * Decode a command from the edittables list. 51460786Sps */ 51560786Sps public int 51660786Spsecmd_decode(cmd, sp) 51760786Sps char *cmd; 51860786Sps char **sp; 51960786Sps{ 52060786Sps return (cmd_decode(list_ecmd_tables, cmd, sp)); 52160786Sps} 52260786Sps 52360786Sps/* 52460786Sps * Get the value of an environment variable. 52560786Sps * Looks first in the lesskey file, then in the real environment. 52660786Sps */ 52760786Sps public char * 52860786Spslgetenv(var) 52960786Sps char *var; 53060786Sps{ 53160786Sps int a; 53260786Sps char *s; 53360786Sps 53460786Sps a = cmd_decode(list_var_tables, var, &s); 53560786Sps if (a == EV_OK) 53660786Sps return (s); 53760786Sps s = getenv(var); 53860786Sps if (s != NULL && *s != '\0') 53960786Sps return (s); 54060786Sps a = cmd_decode(list_sysvar_tables, var, &s); 54160786Sps if (a == EV_OK) 54260786Sps return (s); 54360786Sps return (NULL); 54460786Sps} 54560786Sps 54660786Sps#if USERFILE 54760786Sps/* 54860786Sps * Get an "integer" from a lesskey file. 54960786Sps * Integers are stored in a funny format: 55060786Sps * two bytes, low order first, in radix KRADIX. 55160786Sps */ 55260786Sps static int 55360786Spsgint(sp) 55460786Sps char **sp; 55560786Sps{ 55660786Sps int n; 55760786Sps 55860786Sps n = *(*sp)++; 55960786Sps n += *(*sp)++ * KRADIX; 56060786Sps return (n); 56160786Sps} 56260786Sps 56360786Sps/* 56460786Sps * Process an old (pre-v241) lesskey file. 56560786Sps */ 56660786Sps static int 56760786Spsold_lesskey(buf, len) 56860786Sps char *buf; 56960786Sps int len; 57060786Sps{ 57160786Sps /* 57260786Sps * Old-style lesskey file. 57360786Sps * The file must end with either 57460786Sps * ...,cmd,0,action 57560786Sps * or ...,cmd,0,action|A_EXTRA,string,0 57660786Sps * So the last byte or the second to last byte must be zero. 57760786Sps */ 57860786Sps if (buf[len-1] != '\0' && buf[len-2] != '\0') 57960786Sps return (-1); 58060786Sps add_fcmd_table(buf, len); 58160786Sps return (0); 58260786Sps} 58360786Sps 58460786Sps/* 58560786Sps * Process a new (post-v241) lesskey file. 58660786Sps */ 58760786Sps static int 58860786Spsnew_lesskey(buf, len, sysvar) 58960786Sps char *buf; 59060786Sps int len; 59160786Sps int sysvar; 59260786Sps{ 59360786Sps char *p; 59460786Sps register int c; 59560786Sps register int n; 59660786Sps 59760786Sps /* 59860786Sps * New-style lesskey file. 59960786Sps * Extract the pieces. 60060786Sps */ 60160786Sps if (buf[len-3] != C0_END_LESSKEY_MAGIC || 60260786Sps buf[len-2] != C1_END_LESSKEY_MAGIC || 60360786Sps buf[len-1] != C2_END_LESSKEY_MAGIC) 60460786Sps return (-1); 60560786Sps p = buf + 4; 60660786Sps for (;;) 60760786Sps { 60860786Sps c = *p++; 60960786Sps switch (c) 61060786Sps { 61160786Sps case CMD_SECTION: 61260786Sps n = gint(&p); 61360786Sps add_fcmd_table(p, n); 61460786Sps p += n; 61560786Sps break; 61660786Sps case EDIT_SECTION: 61760786Sps n = gint(&p); 61860786Sps add_ecmd_table(p, n); 61960786Sps p += n; 62060786Sps break; 62160786Sps case VAR_SECTION: 62260786Sps n = gint(&p); 62360786Sps add_var_table((sysvar) ? 62460786Sps &list_sysvar_tables : &list_var_tables, p, n); 62560786Sps p += n; 62660786Sps break; 62760786Sps case END_SECTION: 62860786Sps return (0); 62960786Sps default: 63060786Sps /* 63160786Sps * Unrecognized section type. 63260786Sps */ 63360786Sps return (-1); 63460786Sps } 63560786Sps } 63660786Sps} 63760786Sps 63860786Sps/* 63960786Sps * Set up a user command table, based on a "lesskey" file. 64060786Sps */ 64160786Sps public int 64260786Spslesskey(filename, sysvar) 64360786Sps char *filename; 64460786Sps int sysvar; 64560786Sps{ 64660786Sps register char *buf; 64760786Sps register POSITION len; 64860786Sps register long n; 64960786Sps register int f; 65060786Sps 65160786Sps if (secure) 65260786Sps return (1); 65360786Sps /* 65460786Sps * Try to open the lesskey file. 65560786Sps */ 656128345Stjr filename = shell_unquote(filename); 65760786Sps f = open(filename, OPEN_READ); 65860786Sps free(filename); 65960786Sps if (f < 0) 66060786Sps return (1); 66160786Sps 66260786Sps /* 66360786Sps * Read the file into a buffer. 66460786Sps * We first figure out the size of the file and allocate space for it. 66560786Sps * {{ Minimal error checking is done here. 66660786Sps * A garbage .less file will produce strange results. 66760786Sps * To avoid a large amount of error checking code here, we 66860786Sps * rely on the lesskey program to generate a good .less file. }} 66960786Sps */ 67060786Sps len = filesize(f); 67160786Sps if (len == NULL_POSITION || len < 3) 67260786Sps { 67360786Sps /* 67460786Sps * Bad file (valid file must have at least 3 chars). 67560786Sps */ 67660786Sps close(f); 67760786Sps return (-1); 67860786Sps } 67960786Sps if ((buf = (char *) calloc((int)len, sizeof(char))) == NULL) 68060786Sps { 68160786Sps close(f); 68260786Sps return (-1); 68360786Sps } 68460786Sps if (lseek(f, (off_t)0, 0) == BAD_LSEEK) 68560786Sps { 68660786Sps free(buf); 68760786Sps close(f); 68860786Sps return (-1); 68960786Sps } 69060786Sps n = read(f, buf, (unsigned int) len); 69160786Sps close(f); 69260786Sps if (n != len) 69360786Sps { 69460786Sps free(buf); 69560786Sps return (-1); 69660786Sps } 69760786Sps 69860786Sps /* 69960786Sps * Figure out if this is an old-style (before version 241) 70060786Sps * or new-style lesskey file format. 70160786Sps */ 70260786Sps if (buf[0] != C0_LESSKEY_MAGIC || buf[1] != C1_LESSKEY_MAGIC || 70360786Sps buf[2] != C2_LESSKEY_MAGIC || buf[3] != C3_LESSKEY_MAGIC) 70460786Sps return (old_lesskey(buf, (int)len)); 70560786Sps return (new_lesskey(buf, (int)len, sysvar)); 70660786Sps} 70760786Sps 70860786Sps/* 70960786Sps * Add the standard lesskey file "$HOME/.less" 71060786Sps */ 71160786Sps public void 71260786Spsadd_hometable(envname, def_filename, sysvar) 71360786Sps char *envname; 71460786Sps char *def_filename; 71560786Sps int sysvar; 71660786Sps{ 71760786Sps char *filename; 71860786Sps PARG parg; 71960786Sps 72089019Sps if (envname != NULL && (filename = lgetenv(envname)) != NULL) 72160786Sps filename = save(filename); 72260786Sps else if (sysvar) 72360786Sps filename = save(def_filename); 72460786Sps else 72560786Sps filename = homefile(def_filename); 72660786Sps if (filename == NULL) 72760786Sps return; 72860786Sps if (lesskey(filename, sysvar) < 0) 72960786Sps { 73060786Sps parg.p_string = filename; 73160786Sps error("Cannot use lesskey file \"%s\"", &parg); 73260786Sps } 73360786Sps free(filename); 73460786Sps} 73560786Sps#endif 73660786Sps 73760786Sps/* 73860786Sps * See if a char is a special line-editing command. 73960786Sps */ 74060786Sps public int 74160786Spseditchar(c, flags) 74260786Sps int c; 74360786Sps int flags; 74460786Sps{ 74560786Sps int action; 74660786Sps int nch; 74760786Sps char *s; 74860786Sps char usercmd[MAX_CMDLEN+1]; 74960786Sps 75060786Sps /* 75160786Sps * An editing character could actually be a sequence of characters; 75260786Sps * for example, an escape sequence sent by pressing the uparrow key. 75360786Sps * To match the editing string, we use the command decoder 75460786Sps * but give it the edit-commands command table 75560786Sps * This table is constructed to match the user's keyboard. 75660786Sps */ 757161475Sdelphij if (c == erase_char || c == erase2_char) 75860786Sps return (EC_BACKSPACE); 75960786Sps if (c == kill_char) 76060786Sps return (EC_LINEKILL); 76160786Sps 76260786Sps /* 76360786Sps * Collect characters in a buffer. 76460786Sps * Start with the one we have, and get more if we need them. 76560786Sps */ 76660786Sps nch = 0; 76760786Sps do { 76860786Sps if (nch > 0) 76960786Sps c = getcc(); 77060786Sps usercmd[nch] = c; 77160786Sps usercmd[nch+1] = '\0'; 77260786Sps nch++; 77360786Sps action = ecmd_decode(usercmd, &s); 77460786Sps } while (action == A_PREFIX); 77560786Sps 77689019Sps if (flags & EC_NORIGHTLEFT) 77789019Sps { 77889019Sps switch (action) 77989019Sps { 78089019Sps case EC_RIGHT: 78189019Sps case EC_LEFT: 78289019Sps action = A_INVALID; 78389019Sps break; 78489019Sps } 78589019Sps } 78660786Sps#if CMD_HISTORY 78760786Sps if (flags & EC_NOHISTORY) 78860786Sps { 78960786Sps /* 79060786Sps * The caller says there is no history list. 79160786Sps * Reject any history-manipulation action. 79260786Sps */ 79360786Sps switch (action) 79460786Sps { 79560786Sps case EC_UP: 79660786Sps case EC_DOWN: 79760786Sps action = A_INVALID; 79860786Sps break; 79960786Sps } 80060786Sps } 80160786Sps#endif 80260786Sps#if TAB_COMPLETE_FILENAME 80360786Sps if (flags & EC_NOCOMPLETE) 80460786Sps { 80560786Sps /* 80660786Sps * The caller says we don't want any filename completion cmds. 80760786Sps * Reject them. 80860786Sps */ 80960786Sps switch (action) 81060786Sps { 81160786Sps case EC_F_COMPLETE: 81260786Sps case EC_B_COMPLETE: 81360786Sps case EC_EXPAND: 81460786Sps action = A_INVALID; 81560786Sps break; 81660786Sps } 81760786Sps } 81860786Sps#endif 81960786Sps if ((flags & EC_PEEK) || action == A_INVALID) 82060786Sps { 82160786Sps /* 82260786Sps * We're just peeking, or we didn't understand the command. 82360786Sps * Unget all the characters we read in the loop above. 82460786Sps * This does NOT include the original character that was 82560786Sps * passed in as a parameter. 82660786Sps */ 82760786Sps while (nch > 1) 82860786Sps { 82960786Sps ungetcc(usercmd[--nch]); 83060786Sps } 83160786Sps } else 83260786Sps { 83360786Sps if (s != NULL) 83460786Sps ungetsc(s); 83560786Sps } 83660786Sps return action; 83760786Sps} 83860786Sps 839