1a5f0fb15SPaul Saab /* 2*c77c4889SXin LI * Copyright (C) 1984-2024 Mark Nudelman 3a5f0fb15SPaul Saab * 4a5f0fb15SPaul Saab * You may distribute under the terms of either the GNU General Public 5a5f0fb15SPaul Saab * License or the Less License, as specified in the README file. 6a5f0fb15SPaul Saab * 796e55cc7SXin LI * For more information, see the README file. 8a5f0fb15SPaul Saab */ 9a5f0fb15SPaul Saab 10a5f0fb15SPaul Saab 11a5f0fb15SPaul Saab /* 12a5f0fb15SPaul Saab * Routines to decode user commands. 13a5f0fb15SPaul Saab * 14a5f0fb15SPaul Saab * This is all table driven. 15a5f0fb15SPaul Saab * A command table is a sequence of command descriptors. 16a5f0fb15SPaul Saab * Each command descriptor is a sequence of bytes with the following format: 17a5f0fb15SPaul Saab * <c1><c2>...<cN><0><action> 18a5f0fb15SPaul Saab * The characters c1,c2,...,cN are the command string; that is, 19a5f0fb15SPaul Saab * the characters which the user must type. 20a5f0fb15SPaul Saab * It is terminated by a null <0> byte. 21a5f0fb15SPaul Saab * The byte after the null byte is the action code associated 22a5f0fb15SPaul Saab * with the command string. 23a5f0fb15SPaul Saab * If an action byte is OR-ed with A_EXTRA, this indicates 24a5f0fb15SPaul Saab * that the option byte is followed by an extra string. 25a5f0fb15SPaul Saab * 26a5f0fb15SPaul Saab * There may be many command tables. 27a5f0fb15SPaul Saab * The first (default) table is built-in. 28a5f0fb15SPaul Saab * Other tables are read in from "lesskey" files. 29a5f0fb15SPaul Saab * All the tables are linked together and are searched in order. 30a5f0fb15SPaul Saab */ 31a5f0fb15SPaul Saab 32a5f0fb15SPaul Saab #include "less.h" 33a5f0fb15SPaul Saab #include "cmd.h" 34a5f0fb15SPaul Saab #include "lesskey.h" 35a5f0fb15SPaul Saab 366dcb072bSXin LI extern int erase_char, erase2_char, kill_char; 37b7780dbeSXin LI extern int mousecap; 38b7780dbeSXin LI extern int sc_height; 39a5f0fb15SPaul Saab 40*c77c4889SXin LI #if USERFILE 41*c77c4889SXin LI /* "content" is lesskey source, never binary. */ 42*c77c4889SXin LI static void add_content_table(int (*call_lesskey)(constant char *, lbool), constant char *envname, lbool sysvar); 43*c77c4889SXin LI static int add_hometable(int (*call_lesskey)(constant char *, lbool), constant char *envname, constant char *def_filename, lbool sysvar); 44*c77c4889SXin LI #endif /* USERFILE */ 45*c77c4889SXin LI 46a5f0fb15SPaul Saab #define SK(k) \ 47a5f0fb15SPaul Saab SK_SPECIAL_KEY, (k), 6, 1, 1, 1 48a5f0fb15SPaul Saab /* 49a5f0fb15SPaul Saab * Command table is ordered roughly according to expected 50a5f0fb15SPaul Saab * frequency of use, so the common commands are near the beginning. 51a5f0fb15SPaul Saab */ 52a5f0fb15SPaul Saab 53a5f0fb15SPaul Saab static unsigned char cmdtable[] = 54a5f0fb15SPaul Saab { 55a5f0fb15SPaul Saab '\r',0, A_F_LINE, 56a5f0fb15SPaul Saab '\n',0, A_F_LINE, 57a5f0fb15SPaul Saab 'e',0, A_F_LINE, 58a5f0fb15SPaul Saab 'j',0, A_F_LINE, 59a5f0fb15SPaul Saab SK(SK_DOWN_ARROW),0, A_F_LINE, 60a5f0fb15SPaul Saab CONTROL('E'),0, A_F_LINE, 61a5f0fb15SPaul Saab CONTROL('N'),0, A_F_LINE, 62a5f0fb15SPaul Saab 'k',0, A_B_LINE, 63a5f0fb15SPaul Saab 'y',0, A_B_LINE, 64a5f0fb15SPaul Saab CONTROL('Y'),0, A_B_LINE, 65a5f0fb15SPaul Saab SK(SK_CONTROL_K),0, A_B_LINE, 66a5f0fb15SPaul Saab CONTROL('P'),0, A_B_LINE, 67a5f0fb15SPaul Saab SK(SK_UP_ARROW),0, A_B_LINE, 68a5f0fb15SPaul Saab 'J',0, A_FF_LINE, 69a5f0fb15SPaul Saab 'K',0, A_BF_LINE, 70a5f0fb15SPaul Saab 'Y',0, A_BF_LINE, 71a5f0fb15SPaul Saab 'd',0, A_F_SCROLL, 72a5f0fb15SPaul Saab CONTROL('D'),0, A_F_SCROLL, 73a5f0fb15SPaul Saab 'u',0, A_B_SCROLL, 74a5f0fb15SPaul Saab CONTROL('U'),0, A_B_SCROLL, 75b7780dbeSXin LI ESC,'[','M',0, A_X11MOUSE_IN, 76b7780dbeSXin LI ESC,'[','<',0, A_X116MOUSE_IN, 77a5f0fb15SPaul Saab ' ',0, A_F_SCREEN, 78a5f0fb15SPaul Saab 'f',0, A_F_SCREEN, 79a5f0fb15SPaul Saab CONTROL('F'),0, A_F_SCREEN, 80a5f0fb15SPaul Saab CONTROL('V'),0, A_F_SCREEN, 81a5f0fb15SPaul Saab SK(SK_PAGE_DOWN),0, A_F_SCREEN, 82a5f0fb15SPaul Saab 'b',0, A_B_SCREEN, 83a5f0fb15SPaul Saab CONTROL('B'),0, A_B_SCREEN, 84a5f0fb15SPaul Saab ESC,'v',0, A_B_SCREEN, 85a5f0fb15SPaul Saab SK(SK_PAGE_UP),0, A_B_SCREEN, 86a5f0fb15SPaul Saab 'z',0, A_F_WINDOW, 87a5f0fb15SPaul Saab 'w',0, A_B_WINDOW, 88a5f0fb15SPaul Saab ESC,' ',0, A_FF_SCREEN, 89a5f0fb15SPaul Saab 'F',0, A_F_FOREVER, 9096e55cc7SXin LI ESC,'F',0, A_F_UNTIL_HILITE, 91a5f0fb15SPaul Saab 'R',0, A_FREPAINT, 92a5f0fb15SPaul Saab 'r',0, A_REPAINT, 93a5f0fb15SPaul Saab CONTROL('R'),0, A_REPAINT, 94a5f0fb15SPaul Saab CONTROL('L'),0, A_REPAINT, 95a5f0fb15SPaul Saab ESC,'u',0, A_UNDO_SEARCH, 962235c7feSXin LI ESC,'U',0, A_CLR_SEARCH, 97a5f0fb15SPaul Saab 'g',0, A_GOLINE, 98a5f0fb15SPaul Saab SK(SK_HOME),0, A_GOLINE, 99a5f0fb15SPaul Saab '<',0, A_GOLINE, 100a5f0fb15SPaul Saab ESC,'<',0, A_GOLINE, 101a5f0fb15SPaul Saab 'p',0, A_PERCENT, 102a5f0fb15SPaul Saab '%',0, A_PERCENT, 103a5f0fb15SPaul Saab ESC,'(',0, A_LSHIFT, 104a5f0fb15SPaul Saab ESC,')',0, A_RSHIFT, 105f6b74a7dSXin LI ESC,'{',0, A_LLSHIFT, 106f6b74a7dSXin LI ESC,'}',0, A_RRSHIFT, 107a5f0fb15SPaul Saab SK(SK_RIGHT_ARROW),0, A_RSHIFT, 108a5f0fb15SPaul Saab SK(SK_LEFT_ARROW),0, A_LSHIFT, 109f6b74a7dSXin LI SK(SK_CTL_RIGHT_ARROW),0, A_RRSHIFT, 110f6b74a7dSXin LI SK(SK_CTL_LEFT_ARROW),0, A_LLSHIFT, 111a5f0fb15SPaul Saab '{',0, A_F_BRACKET|A_EXTRA, '{','}',0, 112a5f0fb15SPaul Saab '}',0, A_B_BRACKET|A_EXTRA, '{','}',0, 113a5f0fb15SPaul Saab '(',0, A_F_BRACKET|A_EXTRA, '(',')',0, 114a5f0fb15SPaul Saab ')',0, A_B_BRACKET|A_EXTRA, '(',')',0, 115a5f0fb15SPaul Saab '[',0, A_F_BRACKET|A_EXTRA, '[',']',0, 116a5f0fb15SPaul Saab ']',0, A_B_BRACKET|A_EXTRA, '[',']',0, 117a5f0fb15SPaul Saab ESC,CONTROL('F'),0, A_F_BRACKET, 118a5f0fb15SPaul Saab ESC,CONTROL('B'),0, A_B_BRACKET, 119a5f0fb15SPaul Saab 'G',0, A_GOEND, 120a15691bfSXin LI ESC,'G',0, A_GOEND_BUF, 121a5f0fb15SPaul Saab ESC,'>',0, A_GOEND, 122a5f0fb15SPaul Saab '>',0, A_GOEND, 123a5f0fb15SPaul Saab SK(SK_END),0, A_GOEND, 124a5f0fb15SPaul Saab 'P',0, A_GOPOS, 125a5f0fb15SPaul Saab 126a5f0fb15SPaul Saab '0',0, A_DIGIT, 127a5f0fb15SPaul Saab '1',0, A_DIGIT, 128a5f0fb15SPaul Saab '2',0, A_DIGIT, 129a5f0fb15SPaul Saab '3',0, A_DIGIT, 130a5f0fb15SPaul Saab '4',0, A_DIGIT, 131a5f0fb15SPaul Saab '5',0, A_DIGIT, 132a5f0fb15SPaul Saab '6',0, A_DIGIT, 133a5f0fb15SPaul Saab '7',0, A_DIGIT, 134a5f0fb15SPaul Saab '8',0, A_DIGIT, 135a5f0fb15SPaul Saab '9',0, A_DIGIT, 1367f074f9cSXin LI '.',0, A_DIGIT, 137a5f0fb15SPaul Saab 138a5f0fb15SPaul Saab '=',0, A_STAT, 139a5f0fb15SPaul Saab CONTROL('G'),0, A_STAT, 140a5f0fb15SPaul Saab ':','f',0, A_STAT, 141a5f0fb15SPaul Saab '/',0, A_F_SEARCH, 142a5f0fb15SPaul Saab '?',0, A_B_SEARCH, 143a5f0fb15SPaul Saab ESC,'/',0, A_F_SEARCH|A_EXTRA, '*',0, 144a5f0fb15SPaul Saab ESC,'?',0, A_B_SEARCH|A_EXTRA, '*',0, 145a5f0fb15SPaul Saab 'n',0, A_AGAIN_SEARCH, 146a5f0fb15SPaul Saab ESC,'n',0, A_T_AGAIN_SEARCH, 147a5f0fb15SPaul Saab 'N',0, A_REVERSE_SEARCH, 148a5f0fb15SPaul Saab ESC,'N',0, A_T_REVERSE_SEARCH, 1497374caaaSXin LI '&',0, A_FILTER, 150a5f0fb15SPaul Saab 'm',0, A_SETMARK, 151b2ea2440SXin LI 'M',0, A_SETMARKBOT, 152b2ea2440SXin LI ESC,'m',0, A_CLRMARK, 153a5f0fb15SPaul Saab '\'',0, A_GOMARK, 154a5f0fb15SPaul Saab CONTROL('X'),CONTROL('X'),0, A_GOMARK, 155a5f0fb15SPaul Saab 'E',0, A_EXAMINE, 156a5f0fb15SPaul Saab ':','e',0, A_EXAMINE, 157a5f0fb15SPaul Saab CONTROL('X'),CONTROL('V'),0, A_EXAMINE, 158a5f0fb15SPaul Saab ':','n',0, A_NEXT_FILE, 159a5f0fb15SPaul Saab ':','p',0, A_PREV_FILE, 160*c77c4889SXin LI CONTROL('O'),CONTROL('N'),0, A_OSC8_F_SEARCH, 161*c77c4889SXin LI CONTROL('O'),'n',0, A_OSC8_F_SEARCH, 162*c77c4889SXin LI CONTROL('O'),CONTROL('P'),0, A_OSC8_B_SEARCH, 163*c77c4889SXin LI CONTROL('O'),'p',0, A_OSC8_B_SEARCH, 164*c77c4889SXin LI CONTROL('O'),CONTROL('O'),0, A_OSC8_OPEN, 165*c77c4889SXin LI CONTROL('O'),'o',0, A_OSC8_OPEN, 166*c77c4889SXin LI CONTROL('O'),CONTROL('L'),0, A_OSC8_JUMP, 167*c77c4889SXin LI CONTROL('O'),'l',0, A_OSC8_JUMP, 168c9346414SPaul Saab 't',0, A_NEXT_TAG, 169c9346414SPaul Saab 'T',0, A_PREV_TAG, 170a5f0fb15SPaul Saab ':','x',0, A_INDEX_FILE, 171a5f0fb15SPaul Saab ':','d',0, A_REMOVE_FILE, 172a5f0fb15SPaul Saab '-',0, A_OPT_TOGGLE, 173a5f0fb15SPaul Saab ':','t',0, A_OPT_TOGGLE|A_EXTRA, 't',0, 174a5f0fb15SPaul Saab 's',0, A_OPT_TOGGLE|A_EXTRA, 'o',0, 175a5f0fb15SPaul Saab '_',0, A_DISP_OPTION, 176a5f0fb15SPaul Saab '|',0, A_PIPE, 177a5f0fb15SPaul Saab 'v',0, A_VISUAL, 178a5f0fb15SPaul Saab '!',0, A_SHELL, 179d713e089SXin LI '#',0, A_PSHELL, 180a5f0fb15SPaul Saab '+',0, A_FIRSTCMD, 181a5f0fb15SPaul Saab 182a5f0fb15SPaul Saab 'H',0, A_HELP, 183a5f0fb15SPaul Saab 'h',0, A_HELP, 184a5f0fb15SPaul Saab SK(SK_F1),0, A_HELP, 185a5f0fb15SPaul Saab 'V',0, A_VERSION, 186a5f0fb15SPaul Saab 'q',0, A_QUIT, 187a5f0fb15SPaul Saab 'Q',0, A_QUIT, 188a5f0fb15SPaul Saab ':','q',0, A_QUIT, 189a5f0fb15SPaul Saab ':','Q',0, A_QUIT, 190a5f0fb15SPaul Saab 'Z','Z',0, A_QUIT 191a5f0fb15SPaul Saab }; 192a5f0fb15SPaul Saab 193a5f0fb15SPaul Saab static unsigned char edittable[] = 194a5f0fb15SPaul Saab { 195a5f0fb15SPaul Saab '\t',0, EC_F_COMPLETE, /* TAB */ 196a5f0fb15SPaul Saab '\17',0, EC_B_COMPLETE, /* BACKTAB */ 197a5f0fb15SPaul Saab SK(SK_BACKTAB),0, EC_B_COMPLETE, /* BACKTAB */ 198a5f0fb15SPaul Saab ESC,'\t',0, EC_B_COMPLETE, /* ESC TAB */ 199a5f0fb15SPaul Saab CONTROL('L'),0, EC_EXPAND, /* CTRL-L */ 200a5f0fb15SPaul Saab CONTROL('V'),0, EC_LITERAL, /* BACKSLASH */ 201a5f0fb15SPaul Saab CONTROL('A'),0, EC_LITERAL, /* BACKSLASH */ 202a5f0fb15SPaul Saab ESC,'l',0, EC_RIGHT, /* ESC l */ 203a5f0fb15SPaul Saab SK(SK_RIGHT_ARROW),0, EC_RIGHT, /* RIGHTARROW */ 204a5f0fb15SPaul Saab ESC,'h',0, EC_LEFT, /* ESC h */ 205a5f0fb15SPaul Saab SK(SK_LEFT_ARROW),0, EC_LEFT, /* LEFTARROW */ 206a5f0fb15SPaul Saab ESC,'b',0, EC_W_LEFT, /* ESC b */ 207a5f0fb15SPaul Saab ESC,SK(SK_LEFT_ARROW),0, EC_W_LEFT, /* ESC LEFTARROW */ 208a5f0fb15SPaul Saab SK(SK_CTL_LEFT_ARROW),0, EC_W_LEFT, /* CTRL-LEFTARROW */ 209a5f0fb15SPaul Saab ESC,'w',0, EC_W_RIGHT, /* ESC w */ 210a5f0fb15SPaul Saab ESC,SK(SK_RIGHT_ARROW),0, EC_W_RIGHT, /* ESC RIGHTARROW */ 211a5f0fb15SPaul Saab SK(SK_CTL_RIGHT_ARROW),0, EC_W_RIGHT, /* CTRL-RIGHTARROW */ 212a5f0fb15SPaul Saab ESC,'i',0, EC_INSERT, /* ESC i */ 213a5f0fb15SPaul Saab SK(SK_INSERT),0, EC_INSERT, /* INSERT */ 214a5f0fb15SPaul Saab ESC,'x',0, EC_DELETE, /* ESC x */ 215a5f0fb15SPaul Saab SK(SK_DELETE),0, EC_DELETE, /* DELETE */ 216a5f0fb15SPaul Saab ESC,'X',0, EC_W_DELETE, /* ESC X */ 217a5f0fb15SPaul Saab ESC,SK(SK_DELETE),0, EC_W_DELETE, /* ESC DELETE */ 218a5f0fb15SPaul Saab SK(SK_CTL_DELETE),0, EC_W_DELETE, /* CTRL-DELETE */ 219a5f0fb15SPaul Saab SK(SK_CTL_BACKSPACE),0, EC_W_BACKSPACE, /* CTRL-BACKSPACE */ 22095270f73SXin LI ESC,SK(SK_BACKSPACE),0, EC_W_BACKSPACE, /* ESC BACKSPACE */ 221a5f0fb15SPaul Saab ESC,'0',0, EC_HOME, /* ESC 0 */ 222a5f0fb15SPaul Saab SK(SK_HOME),0, EC_HOME, /* HOME */ 223a5f0fb15SPaul Saab ESC,'$',0, EC_END, /* ESC $ */ 224a5f0fb15SPaul Saab SK(SK_END),0, EC_END, /* END */ 225a5f0fb15SPaul Saab ESC,'k',0, EC_UP, /* ESC k */ 226a5f0fb15SPaul Saab SK(SK_UP_ARROW),0, EC_UP, /* UPARROW */ 227a5f0fb15SPaul Saab ESC,'j',0, EC_DOWN, /* ESC j */ 228a5f0fb15SPaul Saab SK(SK_DOWN_ARROW),0, EC_DOWN, /* DOWNARROW */ 22933096f16SXin LI CONTROL('G'),0, EC_ABORT, /* CTRL-G */ 2302235c7feSXin LI ESC,'[','M',0, EC_X11MOUSE, /* X11 mouse report */ 2312235c7feSXin LI ESC,'[','<',0, EC_X116MOUSE, /* X11 1006 mouse report */ 232a5f0fb15SPaul Saab }; 233a5f0fb15SPaul Saab 234*c77c4889SXin LI static unsigned char dflt_vartable[] = 235*c77c4889SXin LI { 236*c77c4889SXin LI 'L','E','S','S','_','O','S','C','8','_','m','a','n', 0, EV_OK|A_EXTRA, 237*c77c4889SXin LI /* echo '%o' | sed -e "s,^man\:\\([^(]*\\)( *\\([^)]*\\)\.*,-man '\\2' '\\1'," -e"t X" -e"s,\.*,-echo Invalid man link," -e"\: X" */ 238*c77c4889SXin LI 'e','c','h','o',' ','\'','%','o','\'',' ','|',' ','s','e','d',' ','-','e',' ','"','s',',','^','m','a','n','\\',':','\\','\\','(','[','^','(',']','*','\\','\\',')','(',' ','*','\\','\\','(','[','^',')',']','*','\\','\\',')','\\','.','*',',','-','m','a','n',' ','\'','\\','\\','2','\'',' ','\'','\\','\\','1','\'',',','"',' ','-','e','"','t',' ','X','"',' ','-','e','"','s',',','\\','.','*',',','-','e','c','h','o',' ','I','n','v','a','l','i','d',' ','m','a','n',' ','l','i','n','k',',','"',' ','-','e','"','\\',':',' ','X','"', 239*c77c4889SXin LI 0, 240*c77c4889SXin LI 241*c77c4889SXin LI 'L','E','S','S','_','O','S','C','8','_','f','i','l','e', 0, EV_OK|A_EXTRA, 242*c77c4889SXin LI /* eval `echo '%o' | sed -e "s,^file://\\([^/]*\\)\\(.*\\),_H=\\1;_P=\\2;_E=0," -e"t X" -e"s,.*,_E=1," -e": X"`; if [ "$_E" = 1 ]; then echo -echo Invalid file link; elif [ -z "$_H" -o "$_H" = localhost -o "$_H" = $HOSTNAME ]; then echo ":e $_P"; else echo -echo Cannot open remote file on "$_H"; fi */ 243*c77c4889SXin LI 'e','v','a','l',' ','`','e','c','h','o',' ','\'','%','o','\'',' ','|',' ','s','e','d',' ','-','e',' ','"','s',',','^','f','i','l','e','\\',':','/','/','\\','\\','(','[','^','/',']','*','\\','\\',')','\\','\\','(','\\','.','*','\\','\\',')',',','_','H','=','\\','\\','1',';','_','P','=','\\','\\','2',';','_','E','=','0',',','"',' ','-','e','"','t',' ','X','"',' ','-','e','"','s',',','\\','.','*',',','_','E','=','1',',','"',' ','-','e','"','\\',':',' ','X','"','`',';',' ','i','f',' ','[',' ','"','$','_','E','"',' ','=',' ','1',' ',']',';',' ','t','h','e','n',' ','e','c','h','o',' ','-','e','c','h','o',' ','I','n','v','a','l','i','d',' ','f','i','l','e',' ','l','i','n','k',';',' ','e','l','i','f',' ','[',' ','-','z',' ','"','$','_','H','"',' ','-','o',' ','"','$','_','H','"',' ','=',' ','l','o','c','a','l','h','o','s','t',' ','-','o',' ','"','$','_','H','"',' ','=',' ','$','H','O','S','T','N','A','M','E',' ',']',';',' ','t','h','e','n',' ','e','c','h','o',' ','"','\\',':','e',' ','$','_','P','"',';',' ','e','l','s','e',' ','e','c','h','o',' ','-','e','c','h','o',' ','C','a','n','n','o','t',' ','o','p','e','n',' ','r','e','m','o','t','e',' ','f','i','l','e',' ','o','n',' ','"','$','_','H','"',';',' ','f','i', 244*c77c4889SXin LI 0, 245*c77c4889SXin LI }; 246*c77c4889SXin LI 247a5f0fb15SPaul Saab /* 248a5f0fb15SPaul Saab * Structure to support a list of command tables. 249a5f0fb15SPaul Saab */ 250a5f0fb15SPaul Saab struct tablelist 251a5f0fb15SPaul Saab { 252a5f0fb15SPaul Saab struct tablelist *t_next; 253*c77c4889SXin LI unsigned char *t_start; 254*c77c4889SXin LI unsigned char *t_end; 255a5f0fb15SPaul Saab }; 256a5f0fb15SPaul Saab 257a5f0fb15SPaul Saab /* 258a5f0fb15SPaul Saab * List of command tables and list of line-edit tables. 259a5f0fb15SPaul Saab */ 260a5f0fb15SPaul Saab static struct tablelist *list_fcmd_tables = NULL; 261a5f0fb15SPaul Saab static struct tablelist *list_ecmd_tables = NULL; 262a5f0fb15SPaul Saab static struct tablelist *list_var_tables = NULL; 263a5f0fb15SPaul Saab static struct tablelist *list_sysvar_tables = NULL; 264a5f0fb15SPaul Saab 265a5f0fb15SPaul Saab 266a5f0fb15SPaul Saab /* 267a5f0fb15SPaul Saab * Expand special key abbreviations in a command table. 268a5f0fb15SPaul Saab */ 269*c77c4889SXin LI static void expand_special_keys(unsigned char *table, size_t len) 270a5f0fb15SPaul Saab { 271*c77c4889SXin LI unsigned char *fm; 272*c77c4889SXin LI unsigned char *to; 2731ea31627SRobert Watson int a; 274*c77c4889SXin LI constant char *repl; 275*c77c4889SXin LI size_t klen; 276a5f0fb15SPaul Saab 277a5f0fb15SPaul Saab for (fm = table; fm < table + len; ) 278a5f0fb15SPaul Saab { 279a5f0fb15SPaul Saab /* 280a5f0fb15SPaul Saab * Rewrite each command in the table with any 281a5f0fb15SPaul Saab * special key abbreviations expanded. 282a5f0fb15SPaul Saab */ 283a5f0fb15SPaul Saab for (to = fm; *fm != '\0'; ) 284a5f0fb15SPaul Saab { 285a5f0fb15SPaul Saab if (*fm != SK_SPECIAL_KEY) 286a5f0fb15SPaul Saab { 287a5f0fb15SPaul Saab *to++ = *fm++; 288a5f0fb15SPaul Saab continue; 289a5f0fb15SPaul Saab } 290a5f0fb15SPaul Saab /* 291a5f0fb15SPaul Saab * After SK_SPECIAL_KEY, next byte is the type 29295270f73SXin LI * of special key (one of the SK_* constants), 293a5f0fb15SPaul Saab * and the byte after that is the number of bytes, 294a5f0fb15SPaul Saab * N, reserved by the abbreviation (including the 295a5f0fb15SPaul Saab * SK_SPECIAL_KEY and key type bytes). 296a5f0fb15SPaul Saab * Replace all N bytes with the actual bytes 297a5f0fb15SPaul Saab * output by the special key on this terminal. 298a5f0fb15SPaul Saab */ 299a5f0fb15SPaul Saab repl = special_key_str(fm[1]); 300a5f0fb15SPaul Saab klen = fm[2] & 0377; 301a5f0fb15SPaul Saab fm += klen; 302*c77c4889SXin LI if (repl == NULL || strlen(repl) > klen) 303a5f0fb15SPaul Saab repl = "\377"; 304a5f0fb15SPaul Saab while (*repl != '\0') 305*c77c4889SXin LI *to++ = (unsigned char) *repl++; /*{{type-issue}}*/ 306a5f0fb15SPaul Saab } 307a5f0fb15SPaul Saab *to++ = '\0'; 308a5f0fb15SPaul Saab /* 309a5f0fb15SPaul Saab * Fill any unused bytes between end of command and 310a5f0fb15SPaul Saab * the action byte with A_SKIP. 311a5f0fb15SPaul Saab */ 312a5f0fb15SPaul Saab while (to <= fm) 313a5f0fb15SPaul Saab *to++ = A_SKIP; 314a5f0fb15SPaul Saab fm++; 315a5f0fb15SPaul Saab a = *fm++ & 0377; 316a5f0fb15SPaul Saab if (a & A_EXTRA) 317a5f0fb15SPaul Saab { 318a5f0fb15SPaul Saab while (*fm++ != '\0') 319a5f0fb15SPaul Saab continue; 320a5f0fb15SPaul Saab } 321a5f0fb15SPaul Saab } 322a5f0fb15SPaul Saab } 323a5f0fb15SPaul Saab 324a5f0fb15SPaul Saab /* 325b2ea2440SXin LI * Expand special key abbreviations in a list of command tables. 326b2ea2440SXin LI */ 327d713e089SXin LI static void expand_cmd_table(struct tablelist *tlist) 328b2ea2440SXin LI { 329b2ea2440SXin LI struct tablelist *t; 330b2ea2440SXin LI for (t = tlist; t != NULL; t = t->t_next) 331b2ea2440SXin LI { 332*c77c4889SXin LI expand_special_keys(t->t_start, ptr_diff(t->t_end, t->t_start)); 333b2ea2440SXin LI } 334b2ea2440SXin LI } 335b2ea2440SXin LI 336b2ea2440SXin LI /* 337b2ea2440SXin LI * Expand special key abbreviations in all command tables. 338b2ea2440SXin LI */ 339d713e089SXin LI public void expand_cmd_tables(void) 340b2ea2440SXin LI { 341b2ea2440SXin LI expand_cmd_table(list_fcmd_tables); 342b2ea2440SXin LI expand_cmd_table(list_ecmd_tables); 343b2ea2440SXin LI expand_cmd_table(list_var_tables); 344b2ea2440SXin LI expand_cmd_table(list_sysvar_tables); 345b2ea2440SXin LI } 346b2ea2440SXin LI 347b2ea2440SXin LI /* 348a5f0fb15SPaul Saab * Initialize the command lists. 349a5f0fb15SPaul Saab */ 350d713e089SXin LI public void init_cmds(void) 351a5f0fb15SPaul Saab { 352a5f0fb15SPaul Saab /* 353a5f0fb15SPaul Saab * Add the default command tables. 354a5f0fb15SPaul Saab */ 355*c77c4889SXin LI add_fcmd_table(cmdtable, sizeof(cmdtable)); 356*c77c4889SXin LI add_ecmd_table(edittable, sizeof(edittable)); 357*c77c4889SXin LI add_sysvar_table(dflt_vartable, sizeof(dflt_vartable)); 358a5f0fb15SPaul Saab #if USERFILE 35930a1828cSXin LI #ifdef BINDIR /* For backwards compatibility */ 36030a1828cSXin LI /* Try to add tables in the OLD system lesskey file. */ 361*c77c4889SXin LI add_hometable(lesskey, NULL, BINDIR "/.sysless", TRUE); 362c9346414SPaul Saab #endif 363c9346414SPaul Saab /* 36430a1828cSXin LI * Try to load lesskey source file or binary file. 36530a1828cSXin LI * If the source file succeeds, don't load binary file. 36630a1828cSXin LI * The binary file is likely to have been generated from 36730a1828cSXin LI * a (possibly out of date) copy of the src file, 36830a1828cSXin LI * so loading it is at best redundant. 369a5f0fb15SPaul Saab */ 370a5f0fb15SPaul Saab /* 37130a1828cSXin LI * Try to add tables in system lesskey src file. 372a5f0fb15SPaul Saab */ 37330a1828cSXin LI #if HAVE_LESSKEYSRC 374*c77c4889SXin LI if (add_hometable(lesskey_src, "LESSKEYIN_SYSTEM", LESSKEYINFILE_SYS, TRUE) != 0) 37530a1828cSXin LI #endif 37630a1828cSXin LI { 37730a1828cSXin LI /* 37830a1828cSXin LI * Try to add the tables in the system lesskey binary file. 37930a1828cSXin LI */ 380*c77c4889SXin LI add_hometable(lesskey, "LESSKEY_SYSTEM", LESSKEYFILE_SYS, TRUE); 38130a1828cSXin LI } 38230a1828cSXin LI /* 38330a1828cSXin LI * Try to add tables in the lesskey src file "$HOME/.lesskey". 38430a1828cSXin LI */ 38530a1828cSXin LI #if HAVE_LESSKEYSRC 386*c77c4889SXin LI if (add_hometable(lesskey_src, "LESSKEYIN", DEF_LESSKEYINFILE, FALSE) != 0) 38730a1828cSXin LI #endif 38830a1828cSXin LI { 38930a1828cSXin LI /* 39030a1828cSXin LI * Try to add the tables in the standard lesskey binary file "$HOME/.less". 39130a1828cSXin LI */ 392*c77c4889SXin LI add_hometable(lesskey, "LESSKEY", LESSKEYFILE, FALSE); 39330a1828cSXin LI } 394*c77c4889SXin LI 395*c77c4889SXin LI add_content_table(lesskey_content, "LESSKEY_CONTENT_SYSTEM", TRUE); 396*c77c4889SXin LI add_content_table(lesskey_content, "LESSKEY_CONTENT", FALSE); 397*c77c4889SXin LI #endif /* USERFILE */ 398a5f0fb15SPaul Saab } 399a5f0fb15SPaul Saab 400a5f0fb15SPaul Saab /* 401a5f0fb15SPaul Saab * Add a command table. 402a5f0fb15SPaul Saab */ 403*c77c4889SXin LI static int add_cmd_table(struct tablelist **tlist, unsigned char *buf, size_t len) 404a5f0fb15SPaul Saab { 4051ea31627SRobert Watson struct tablelist *t; 406a5f0fb15SPaul Saab 407a5f0fb15SPaul Saab if (len == 0) 408a5f0fb15SPaul Saab return (0); 409a5f0fb15SPaul Saab /* 410a5f0fb15SPaul Saab * Allocate a tablelist structure, initialize it, 411a5f0fb15SPaul Saab * and link it into the list of tables. 412a5f0fb15SPaul Saab */ 413a5f0fb15SPaul Saab if ((t = (struct tablelist *) 414a5f0fb15SPaul Saab calloc(1, sizeof(struct tablelist))) == NULL) 415a5f0fb15SPaul Saab { 416a5f0fb15SPaul Saab return (-1); 417a5f0fb15SPaul Saab } 418a5f0fb15SPaul Saab t->t_start = buf; 419a5f0fb15SPaul Saab t->t_end = buf + len; 420*c77c4889SXin LI t->t_next = NULL; 421*c77c4889SXin LI if (*tlist == NULL) 422a5f0fb15SPaul Saab *tlist = t; 423*c77c4889SXin LI else 424*c77c4889SXin LI { 425*c77c4889SXin LI struct tablelist *e; 426*c77c4889SXin LI for (e = *tlist; e->t_next != NULL; e = e->t_next) 427*c77c4889SXin LI continue; 428*c77c4889SXin LI e->t_next = t; 429*c77c4889SXin LI } 430a5f0fb15SPaul Saab return (0); 431a5f0fb15SPaul Saab } 432a5f0fb15SPaul Saab 433a5f0fb15SPaul Saab /* 434*c77c4889SXin LI * Remove the last command table in a list. 435*c77c4889SXin LI */ 436*c77c4889SXin LI static void pop_cmd_table(struct tablelist **tlist) 437*c77c4889SXin LI { 438*c77c4889SXin LI struct tablelist *t; 439*c77c4889SXin LI if (*tlist == NULL) 440*c77c4889SXin LI return; 441*c77c4889SXin LI if ((*tlist)->t_next == NULL) 442*c77c4889SXin LI { 443*c77c4889SXin LI t = *tlist; 444*c77c4889SXin LI *tlist = NULL; 445*c77c4889SXin LI } else 446*c77c4889SXin LI { 447*c77c4889SXin LI struct tablelist *e; 448*c77c4889SXin LI for (e = *tlist; e->t_next->t_next != NULL; e = e->t_next) 449*c77c4889SXin LI continue; 450*c77c4889SXin LI t = e->t_next; 451*c77c4889SXin LI e->t_next = NULL; 452*c77c4889SXin LI } 453*c77c4889SXin LI free(t); 454*c77c4889SXin LI } 455*c77c4889SXin LI 456*c77c4889SXin LI /* 457a5f0fb15SPaul Saab * Add a command table. 458a5f0fb15SPaul Saab */ 459*c77c4889SXin LI public void add_fcmd_table(unsigned char *buf, size_t len) 460a5f0fb15SPaul Saab { 461a5f0fb15SPaul Saab if (add_cmd_table(&list_fcmd_tables, buf, len) < 0) 462a5f0fb15SPaul Saab error("Warning: some commands disabled", NULL_PARG); 463a5f0fb15SPaul Saab } 464a5f0fb15SPaul Saab 465a5f0fb15SPaul Saab /* 466a5f0fb15SPaul Saab * Add an editing command table. 467a5f0fb15SPaul Saab */ 468*c77c4889SXin LI public void add_ecmd_table(unsigned char *buf, size_t len) 469a5f0fb15SPaul Saab { 470a5f0fb15SPaul Saab if (add_cmd_table(&list_ecmd_tables, buf, len) < 0) 471a5f0fb15SPaul Saab error("Warning: some edit commands disabled", NULL_PARG); 472a5f0fb15SPaul Saab } 473a5f0fb15SPaul Saab 474a5f0fb15SPaul Saab /* 475a5f0fb15SPaul Saab * Add an environment variable table. 476a5f0fb15SPaul Saab */ 477*c77c4889SXin LI static void add_var_table(struct tablelist **tlist, unsigned char *buf, size_t len) 478a5f0fb15SPaul Saab { 479*c77c4889SXin LI struct xbuffer xbuf; 480*c77c4889SXin LI 481*c77c4889SXin LI xbuf_init(&xbuf); 482*c77c4889SXin LI expand_evars((char*)buf, len, &xbuf); /*{{unsigned-issue}}*/ 483*c77c4889SXin LI /* {{ We leak the table in buf. expand_evars scribbled in it so it's useless anyway. }} */ 484*c77c4889SXin LI if (add_cmd_table(tlist, xbuf.data, xbuf.end) < 0) 485a5f0fb15SPaul Saab error("Warning: environment variables from lesskey file unavailable", NULL_PARG); 486a5f0fb15SPaul Saab } 487a5f0fb15SPaul Saab 488*c77c4889SXin LI public void add_uvar_table(unsigned char *buf, size_t len) 489*c77c4889SXin LI { 490*c77c4889SXin LI add_var_table(&list_var_tables, buf, len); 491*c77c4889SXin LI } 492*c77c4889SXin LI 493*c77c4889SXin LI public void add_sysvar_table(unsigned char *buf, size_t len) 494*c77c4889SXin LI { 495*c77c4889SXin LI add_var_table(&list_sysvar_tables, buf, len); 496*c77c4889SXin LI } 497*c77c4889SXin LI 498a5f0fb15SPaul Saab /* 499b7780dbeSXin LI * Return action for a mouse wheel down event. 500b7780dbeSXin LI */ 501d713e089SXin LI static int mouse_wheel_down(void) 502b7780dbeSXin LI { 503b7780dbeSXin LI return ((mousecap == OPT_ONPLUS) ? A_B_MOUSE : A_F_MOUSE); 504b7780dbeSXin LI } 505b7780dbeSXin LI 506b7780dbeSXin LI /* 507b7780dbeSXin LI * Return action for a mouse wheel up event. 508b7780dbeSXin LI */ 509d713e089SXin LI static int mouse_wheel_up(void) 510b7780dbeSXin LI { 511b7780dbeSXin LI return ((mousecap == OPT_ONPLUS) ? A_F_MOUSE : A_B_MOUSE); 512b7780dbeSXin LI } 513b7780dbeSXin LI 514b7780dbeSXin LI /* 515*c77c4889SXin LI * Return action for the left mouse button trigger. 516b7780dbeSXin LI */ 517*c77c4889SXin LI static int mouse_button_left(int x, int y) 518b7780dbeSXin LI { 519b7780dbeSXin LI /* 520b7780dbeSXin LI * {{ It would be better to return an action and then do this 521b7780dbeSXin LI * in commands() but it's nontrivial to pass y to it. }} 522b7780dbeSXin LI */ 523*c77c4889SXin LI #if OSC8_LINK 524*c77c4889SXin LI if (osc8_click(y, x)) 525*c77c4889SXin LI return (A_NOACTION); 526*c77c4889SXin LI #else 527*c77c4889SXin LI (void) x; 528*c77c4889SXin LI #endif /* OSC8_LINK */ 529b7780dbeSXin LI if (y < sc_height-1) 530b7780dbeSXin LI { 531b7780dbeSXin LI setmark('#', y); 532*c77c4889SXin LI screen_trashed(); 533*c77c4889SXin LI } 534*c77c4889SXin LI return (A_NOACTION); 535*c77c4889SXin LI } 536*c77c4889SXin LI 537*c77c4889SXin LI /* 538*c77c4889SXin LI * Return action for the right mouse button trigger. 539*c77c4889SXin LI */ 540*c77c4889SXin LI static int mouse_button_right(int x, int y) 541*c77c4889SXin LI { 542*c77c4889SXin LI (void) x; 543*c77c4889SXin LI /* 544*c77c4889SXin LI * {{ unlike mouse_button_left, we could return an action, 545*c77c4889SXin LI * but keep it near mouse_button_left for readability. }} 546*c77c4889SXin LI */ 547*c77c4889SXin LI if (y < sc_height-1) 548*c77c4889SXin LI { 549*c77c4889SXin LI gomark('#'); 550*c77c4889SXin LI screen_trashed(); 551b7780dbeSXin LI } 552b7780dbeSXin LI return (A_NOACTION); 553b7780dbeSXin LI } 554b7780dbeSXin LI 555b7780dbeSXin LI /* 556b7780dbeSXin LI * Read a decimal integer. Return the integer and set *pterm to the terminating char. 557b7780dbeSXin LI */ 558d713e089SXin LI static int getcc_int(char *pterm) 559b7780dbeSXin LI { 560b7780dbeSXin LI int num = 0; 561b7780dbeSXin LI int digits = 0; 562b7780dbeSXin LI for (;;) 563b7780dbeSXin LI { 564b7780dbeSXin LI char ch = getcc(); 565b7780dbeSXin LI if (ch < '0' || ch > '9') 566b7780dbeSXin LI { 567b7780dbeSXin LI if (pterm != NULL) *pterm = ch; 568b7780dbeSXin LI if (digits == 0) 569b7780dbeSXin LI return (-1); 570b7780dbeSXin LI return (num); 571b7780dbeSXin LI } 572d713e089SXin LI if (ckd_mul(&num, num, 10) || ckd_add(&num, num, ch - '0')) 573d713e089SXin LI return -1; 574b7780dbeSXin LI ++digits; 575b7780dbeSXin LI } 576b7780dbeSXin LI } 577b7780dbeSXin LI 578b7780dbeSXin LI /* 579b7780dbeSXin LI * Read suffix of mouse input and return the action to take. 580b7780dbeSXin LI * The prefix ("\e[M") has already been read. 581b7780dbeSXin LI */ 582d713e089SXin LI static int x11mouse_action(int skip) 583b7780dbeSXin LI { 584*c77c4889SXin LI static int prev_b = X11MOUSE_BUTTON_REL; 585b7780dbeSXin LI int b = getcc() - X11MOUSE_OFFSET; 586b7780dbeSXin LI int x = getcc() - X11MOUSE_OFFSET-1; 587b7780dbeSXin LI int y = getcc() - X11MOUSE_OFFSET-1; 5882235c7feSXin LI if (skip) 5892235c7feSXin LI return (A_NOACTION); 590b7780dbeSXin LI switch (b) { 591b7780dbeSXin LI default: 592*c77c4889SXin LI prev_b = b; 593b7780dbeSXin LI return (A_NOACTION); 594b7780dbeSXin LI case X11MOUSE_WHEEL_DOWN: 595b7780dbeSXin LI return mouse_wheel_down(); 596b7780dbeSXin LI case X11MOUSE_WHEEL_UP: 597b7780dbeSXin LI return mouse_wheel_up(); 598b7780dbeSXin LI case X11MOUSE_BUTTON_REL: 599*c77c4889SXin LI /* to trigger on button-up, we check the last button-down */ 600*c77c4889SXin LI switch (prev_b) { 601*c77c4889SXin LI case X11MOUSE_BUTTON1: 602*c77c4889SXin LI return mouse_button_left(x, y); 603*c77c4889SXin LI /* is BUTTON2 the rightmost with 2-buttons mouse? */ 604*c77c4889SXin LI case X11MOUSE_BUTTON2: 605*c77c4889SXin LI case X11MOUSE_BUTTON3: 606*c77c4889SXin LI return mouse_button_right(x, y); 607*c77c4889SXin LI } 608*c77c4889SXin LI return (A_NOACTION); 609b7780dbeSXin LI } 610b7780dbeSXin LI } 611b7780dbeSXin LI 612b7780dbeSXin LI /* 613b7780dbeSXin LI * Read suffix of mouse input and return the action to take. 614b7780dbeSXin LI * The prefix ("\e[<") has already been read. 615b7780dbeSXin LI */ 616d713e089SXin LI static int x116mouse_action(int skip) 617b7780dbeSXin LI { 618b7780dbeSXin LI char ch; 619b7780dbeSXin LI int x, y; 620b7780dbeSXin LI int b = getcc_int(&ch); 621b7780dbeSXin LI if (b < 0 || ch != ';') return (A_NOACTION); 622b7780dbeSXin LI x = getcc_int(&ch) - 1; 623b7780dbeSXin LI if (x < 0 || ch != ';') return (A_NOACTION); 624b7780dbeSXin LI y = getcc_int(&ch) - 1; 625b7780dbeSXin LI if (y < 0) return (A_NOACTION); 6262235c7feSXin LI if (skip) 6272235c7feSXin LI return (A_NOACTION); 628b7780dbeSXin LI switch (b) { 629b7780dbeSXin LI case X11MOUSE_WHEEL_DOWN: 630b7780dbeSXin LI return mouse_wheel_down(); 631b7780dbeSXin LI case X11MOUSE_WHEEL_UP: 632b7780dbeSXin LI return mouse_wheel_up(); 633*c77c4889SXin LI case X11MOUSE_BUTTON1: 634*c77c4889SXin LI if (ch != 'm') return (A_NOACTION); 635*c77c4889SXin LI return mouse_button_left(x, y); 636b7780dbeSXin LI default: 637b7780dbeSXin LI if (ch != 'm') return (A_NOACTION); 638*c77c4889SXin LI /* any other button release */ 639*c77c4889SXin LI return mouse_button_right(x, y); 640b7780dbeSXin LI } 641b7780dbeSXin LI } 642b7780dbeSXin LI 643b7780dbeSXin LI /* 644a5f0fb15SPaul Saab * Search a single command table for the command string in cmd. 645a5f0fb15SPaul Saab */ 646*c77c4889SXin LI static int cmd_search(constant char *cmd, constant char *table, constant char *endtable, constant char **sp) 647a5f0fb15SPaul Saab { 648*c77c4889SXin LI constant char *p; 649*c77c4889SXin LI constant char *q; 650*c77c4889SXin LI int a = A_INVALID; 651a5f0fb15SPaul Saab 6528ed69c6fSPaul Saab *sp = NULL; 653a5f0fb15SPaul Saab for (p = table, q = cmd; p < endtable; p++, q++) 654a5f0fb15SPaul Saab { 655a5f0fb15SPaul Saab if (*p == *q) 656a5f0fb15SPaul Saab { 657a5f0fb15SPaul Saab /* 658a5f0fb15SPaul Saab * Current characters match. 659a5f0fb15SPaul Saab * If we're at the end of the string, we've found it. 660a5f0fb15SPaul Saab * Return the action code, which is the character 661a5f0fb15SPaul Saab * after the null at the end of the string 662a5f0fb15SPaul Saab * in the command table. 663a5f0fb15SPaul Saab */ 664a5f0fb15SPaul Saab if (*p == '\0') 665a5f0fb15SPaul Saab { 666a5f0fb15SPaul Saab a = *++p & 0377; 667a5f0fb15SPaul Saab while (a == A_SKIP) 668a5f0fb15SPaul Saab a = *++p & 0377; 669a5f0fb15SPaul Saab if (a == A_END_LIST) 670a5f0fb15SPaul Saab { 671a5f0fb15SPaul Saab /* 672a5f0fb15SPaul Saab * We get here only if the original 673a5f0fb15SPaul Saab * cmd string passed in was empty (""). 674a5f0fb15SPaul Saab * I don't think that can happen, 675a5f0fb15SPaul Saab * but just in case ... 676a5f0fb15SPaul Saab */ 677a5f0fb15SPaul Saab return (A_UINVALID); 678a5f0fb15SPaul Saab } 679a5f0fb15SPaul Saab /* 680a5f0fb15SPaul Saab * Check for an "extra" string. 681a5f0fb15SPaul Saab */ 682a5f0fb15SPaul Saab if (a & A_EXTRA) 683a5f0fb15SPaul Saab { 684a5f0fb15SPaul Saab *sp = ++p; 685*c77c4889SXin LI while (*p != '\0') 686*c77c4889SXin LI ++p; 687a5f0fb15SPaul Saab a &= ~A_EXTRA; 6888ed69c6fSPaul Saab } 689b7780dbeSXin LI if (a == A_X11MOUSE_IN) 6902235c7feSXin LI a = x11mouse_action(0); 691b7780dbeSXin LI else if (a == A_X116MOUSE_IN) 6922235c7feSXin LI a = x116mouse_action(0); 693*c77c4889SXin LI q = cmd-1; 694a5f0fb15SPaul Saab } 695a5f0fb15SPaul Saab } else if (*q == '\0') 696a5f0fb15SPaul Saab { 697a5f0fb15SPaul Saab /* 698a5f0fb15SPaul Saab * Hit the end of the user's command, 699a5f0fb15SPaul Saab * but not the end of the string in the command table. 700a5f0fb15SPaul Saab * The user's command is incomplete. 701a5f0fb15SPaul Saab */ 702*c77c4889SXin LI if (a == A_INVALID) 703*c77c4889SXin LI a = A_PREFIX; 704*c77c4889SXin LI q = cmd-1; 705a5f0fb15SPaul Saab } else 706a5f0fb15SPaul Saab { 707a5f0fb15SPaul Saab /* 708a5f0fb15SPaul Saab * Not a match. 709a5f0fb15SPaul Saab * Skip ahead to the next command in the 710a5f0fb15SPaul Saab * command table, and reset the pointer 711a5f0fb15SPaul Saab * to the beginning of the user's command. 712a5f0fb15SPaul Saab */ 713a5f0fb15SPaul Saab if (*p == '\0' && p[1] == A_END_LIST) 714a5f0fb15SPaul Saab { 715a5f0fb15SPaul Saab /* 716a5f0fb15SPaul Saab * A_END_LIST is a special marker that tells 717a5f0fb15SPaul Saab * us to abort the cmd search. 718*c77c4889SXin LI * Negative action means accept this action 719*c77c4889SXin LI * without searching any more cmd tables. 720a5f0fb15SPaul Saab */ 721*c77c4889SXin LI return -a; 722a5f0fb15SPaul Saab } 723a5f0fb15SPaul Saab while (*p++ != '\0') 724a5f0fb15SPaul Saab continue; 725a5f0fb15SPaul Saab while (*p == A_SKIP) 726a5f0fb15SPaul Saab p++; 727a5f0fb15SPaul Saab if (*p & A_EXTRA) 728a5f0fb15SPaul Saab while (*++p != '\0') 729a5f0fb15SPaul Saab continue; 730a5f0fb15SPaul Saab q = cmd-1; 731a5f0fb15SPaul Saab } 732a5f0fb15SPaul Saab } 733*c77c4889SXin LI return (a); 734a5f0fb15SPaul Saab } 735a5f0fb15SPaul Saab 736a5f0fb15SPaul Saab /* 737a5f0fb15SPaul Saab * Decode a command character and return the associated action. 738a5f0fb15SPaul Saab * The "extra" string, if any, is returned in sp. 739a5f0fb15SPaul Saab */ 740*c77c4889SXin LI static int cmd_decode(struct tablelist *tlist, constant char *cmd, constant char **sp) 741a5f0fb15SPaul Saab { 7421ea31627SRobert Watson struct tablelist *t; 7431ea31627SRobert Watson int action = A_INVALID; 744a5f0fb15SPaul Saab 745a5f0fb15SPaul Saab /* 746*c77c4889SXin LI * Search for the cmd thru all the command tables. 747*c77c4889SXin LI * If we find it more than once, take the last one. 748a5f0fb15SPaul Saab */ 749*c77c4889SXin LI *sp = NULL; 750a5f0fb15SPaul Saab for (t = tlist; t != NULL; t = t->t_next) 751a5f0fb15SPaul Saab { 752*c77c4889SXin LI constant char *tsp; 753*c77c4889SXin LI int taction = cmd_search(cmd, (char *) t->t_start, (char *) t->t_end, &tsp); 754*c77c4889SXin LI if (taction == A_UINVALID) 755*c77c4889SXin LI taction = A_INVALID; 756*c77c4889SXin LI if (taction != A_INVALID) 757*c77c4889SXin LI { 758*c77c4889SXin LI *sp = tsp; 759*c77c4889SXin LI if (taction < 0) 760*c77c4889SXin LI return (-taction); 761*c77c4889SXin LI action = taction; 762a5f0fb15SPaul Saab } 763*c77c4889SXin LI } 764a5f0fb15SPaul Saab return (action); 765a5f0fb15SPaul Saab } 766a5f0fb15SPaul Saab 767a5f0fb15SPaul Saab /* 768a5f0fb15SPaul Saab * Decode a command from the cmdtables list. 769a5f0fb15SPaul Saab */ 770*c77c4889SXin LI public int fcmd_decode(constant char *cmd, constant char **sp) 771a5f0fb15SPaul Saab { 772a5f0fb15SPaul Saab return (cmd_decode(list_fcmd_tables, cmd, sp)); 773a5f0fb15SPaul Saab } 774a5f0fb15SPaul Saab 775a5f0fb15SPaul Saab /* 776a5f0fb15SPaul Saab * Decode a command from the edittables list. 777a5f0fb15SPaul Saab */ 778*c77c4889SXin LI public int ecmd_decode(constant char *cmd, constant char **sp) 779a5f0fb15SPaul Saab { 780a5f0fb15SPaul Saab return (cmd_decode(list_ecmd_tables, cmd, sp)); 781a5f0fb15SPaul Saab } 782a5f0fb15SPaul Saab 783a5f0fb15SPaul Saab /* 784a5f0fb15SPaul Saab * Get the value of an environment variable. 785a5f0fb15SPaul Saab * Looks first in the lesskey file, then in the real environment. 786a5f0fb15SPaul Saab */ 787*c77c4889SXin LI public constant char * lgetenv(constant char *var) 788a5f0fb15SPaul Saab { 789a5f0fb15SPaul Saab int a; 790*c77c4889SXin LI constant char *s; 791a5f0fb15SPaul Saab 792a5f0fb15SPaul Saab a = cmd_decode(list_var_tables, var, &s); 793a5f0fb15SPaul Saab if (a == EV_OK) 794a5f0fb15SPaul Saab return (s); 795a5f0fb15SPaul Saab s = getenv(var); 796a5f0fb15SPaul Saab if (s != NULL && *s != '\0') 797a5f0fb15SPaul Saab return (s); 798a5f0fb15SPaul Saab a = cmd_decode(list_sysvar_tables, var, &s); 799a5f0fb15SPaul Saab if (a == EV_OK) 800a5f0fb15SPaul Saab return (s); 801a5f0fb15SPaul Saab return (NULL); 802a5f0fb15SPaul Saab } 803a5f0fb15SPaul Saab 804b7780dbeSXin LI /* 805*c77c4889SXin LI * Like lgetenv, but also uses a buffer partially filled with an env table. 806*c77c4889SXin LI */ 807*c77c4889SXin LI public constant char * lgetenv_ext(constant char *var, unsigned char *env_buf, size_t env_buf_len) 808*c77c4889SXin LI { 809*c77c4889SXin LI constant char *r; 810*c77c4889SXin LI size_t e; 811*c77c4889SXin LI size_t env_end = 0; 812*c77c4889SXin LI 813*c77c4889SXin LI for (e = 0;;) 814*c77c4889SXin LI { 815*c77c4889SXin LI for (; e < env_buf_len; e++) 816*c77c4889SXin LI if (env_buf[e] == '\0') 817*c77c4889SXin LI break; 818*c77c4889SXin LI if (e >= env_buf_len) break; 819*c77c4889SXin LI if (env_buf[++e] & A_EXTRA) 820*c77c4889SXin LI { 821*c77c4889SXin LI for (e = e+1; e < env_buf_len; e++) 822*c77c4889SXin LI if (env_buf[e] == '\0') 823*c77c4889SXin LI break; 824*c77c4889SXin LI } 825*c77c4889SXin LI e++; 826*c77c4889SXin LI if (e >= env_buf_len) break; 827*c77c4889SXin LI env_end = e; 828*c77c4889SXin LI } 829*c77c4889SXin LI /* Temporarily add env_buf to var_tables, do the lookup, then remove it. */ 830*c77c4889SXin LI add_uvar_table(env_buf, env_end); 831*c77c4889SXin LI r = lgetenv(var); 832*c77c4889SXin LI pop_cmd_table(&list_var_tables); 833*c77c4889SXin LI return r; 834*c77c4889SXin LI } 835*c77c4889SXin LI 836*c77c4889SXin LI /* 837b7780dbeSXin LI * Is a string null or empty? 838b7780dbeSXin LI */ 839*c77c4889SXin LI public lbool isnullenv(constant char *s) 840b7780dbeSXin LI { 841b7780dbeSXin LI return (s == NULL || *s == '\0'); 842b7780dbeSXin LI } 843b7780dbeSXin LI 844a5f0fb15SPaul Saab #if USERFILE 845a5f0fb15SPaul Saab /* 846a5f0fb15SPaul Saab * Get an "integer" from a lesskey file. 847a5f0fb15SPaul Saab * Integers are stored in a funny format: 848a5f0fb15SPaul Saab * two bytes, low order first, in radix KRADIX. 849a5f0fb15SPaul Saab */ 850*c77c4889SXin LI static size_t gint(unsigned char **sp) 851a5f0fb15SPaul Saab { 852*c77c4889SXin LI size_t n; 853a5f0fb15SPaul Saab 854a5f0fb15SPaul Saab n = *(*sp)++; 855a5f0fb15SPaul Saab n += *(*sp)++ * KRADIX; 856a5f0fb15SPaul Saab return (n); 857a5f0fb15SPaul Saab } 858a5f0fb15SPaul Saab 859a5f0fb15SPaul Saab /* 860a5f0fb15SPaul Saab * Process an old (pre-v241) lesskey file. 861a5f0fb15SPaul Saab */ 862*c77c4889SXin LI static int old_lesskey(unsigned char *buf, size_t len) 863a5f0fb15SPaul Saab { 864a5f0fb15SPaul Saab /* 865a5f0fb15SPaul Saab * Old-style lesskey file. 866a5f0fb15SPaul Saab * The file must end with either 867a5f0fb15SPaul Saab * ...,cmd,0,action 868a5f0fb15SPaul Saab * or ...,cmd,0,action|A_EXTRA,string,0 869a5f0fb15SPaul Saab * So the last byte or the second to last byte must be zero. 870a5f0fb15SPaul Saab */ 871a5f0fb15SPaul Saab if (buf[len-1] != '\0' && buf[len-2] != '\0') 872a5f0fb15SPaul Saab return (-1); 873a5f0fb15SPaul Saab add_fcmd_table(buf, len); 874a5f0fb15SPaul Saab return (0); 875a5f0fb15SPaul Saab } 876a5f0fb15SPaul Saab 877a5f0fb15SPaul Saab /* 878a5f0fb15SPaul Saab * Process a new (post-v241) lesskey file. 879a5f0fb15SPaul Saab */ 880*c77c4889SXin LI static int new_lesskey(unsigned char *buf, size_t len, lbool sysvar) 881a5f0fb15SPaul Saab { 882*c77c4889SXin LI unsigned char *p; 883*c77c4889SXin LI unsigned char *end; 8841ea31627SRobert Watson int c; 885*c77c4889SXin LI size_t n; 886a5f0fb15SPaul Saab 887a5f0fb15SPaul Saab /* 888a5f0fb15SPaul Saab * New-style lesskey file. 889a5f0fb15SPaul Saab * Extract the pieces. 890a5f0fb15SPaul Saab */ 891a5f0fb15SPaul Saab if (buf[len-3] != C0_END_LESSKEY_MAGIC || 892a5f0fb15SPaul Saab buf[len-2] != C1_END_LESSKEY_MAGIC || 893a5f0fb15SPaul Saab buf[len-1] != C2_END_LESSKEY_MAGIC) 894a5f0fb15SPaul Saab return (-1); 895a5f0fb15SPaul Saab p = buf + 4; 89695270f73SXin LI end = buf + len; 897a5f0fb15SPaul Saab for (;;) 898a5f0fb15SPaul Saab { 899a5f0fb15SPaul Saab c = *p++; 900a5f0fb15SPaul Saab switch (c) 901a5f0fb15SPaul Saab { 902a5f0fb15SPaul Saab case CMD_SECTION: 903a5f0fb15SPaul Saab n = gint(&p); 904*c77c4889SXin LI if (p+n >= end) 90595270f73SXin LI return (-1); 906a5f0fb15SPaul Saab add_fcmd_table(p, n); 907a5f0fb15SPaul Saab p += n; 908a5f0fb15SPaul Saab break; 909a5f0fb15SPaul Saab case EDIT_SECTION: 910a5f0fb15SPaul Saab n = gint(&p); 911*c77c4889SXin LI if (p+n >= end) 91295270f73SXin LI return (-1); 913a5f0fb15SPaul Saab add_ecmd_table(p, n); 914a5f0fb15SPaul Saab p += n; 915a5f0fb15SPaul Saab break; 916a5f0fb15SPaul Saab case VAR_SECTION: 917a5f0fb15SPaul Saab n = gint(&p); 918*c77c4889SXin LI if (p+n >= end) 91995270f73SXin LI return (-1); 920*c77c4889SXin LI if (sysvar) 921*c77c4889SXin LI add_sysvar_table(p, n); 922*c77c4889SXin LI else 923*c77c4889SXin LI add_uvar_table(p, n); 924a5f0fb15SPaul Saab p += n; 925a5f0fb15SPaul Saab break; 926a5f0fb15SPaul Saab case END_SECTION: 927a5f0fb15SPaul Saab return (0); 928a5f0fb15SPaul Saab default: 929a5f0fb15SPaul Saab /* 930a5f0fb15SPaul Saab * Unrecognized section type. 931a5f0fb15SPaul Saab */ 932a5f0fb15SPaul Saab return (-1); 933a5f0fb15SPaul Saab } 934a5f0fb15SPaul Saab } 935a5f0fb15SPaul Saab } 936a5f0fb15SPaul Saab 937a5f0fb15SPaul Saab /* 938a5f0fb15SPaul Saab * Set up a user command table, based on a "lesskey" file. 939a5f0fb15SPaul Saab */ 940*c77c4889SXin LI public int lesskey(constant char *filename, lbool sysvar) 941a5f0fb15SPaul Saab { 942*c77c4889SXin LI unsigned char *buf; 9431ea31627SRobert Watson POSITION len; 944*c77c4889SXin LI ssize_t n; 9451ea31627SRobert Watson int f; 946a5f0fb15SPaul Saab 947*c77c4889SXin LI if (!secure_allow(SF_LESSKEY)) 948a5f0fb15SPaul Saab return (1); 949a5f0fb15SPaul Saab /* 950a5f0fb15SPaul Saab * Try to open the lesskey file. 951a5f0fb15SPaul Saab */ 952a5f0fb15SPaul Saab f = open(filename, OPEN_READ); 953a5f0fb15SPaul Saab if (f < 0) 954a5f0fb15SPaul Saab return (1); 955a5f0fb15SPaul Saab 956a5f0fb15SPaul Saab /* 957a5f0fb15SPaul Saab * Read the file into a buffer. 958a5f0fb15SPaul Saab * We first figure out the size of the file and allocate space for it. 959a5f0fb15SPaul Saab * {{ Minimal error checking is done here. 960a5f0fb15SPaul Saab * A garbage .less file will produce strange results. 961a5f0fb15SPaul Saab * To avoid a large amount of error checking code here, we 962a5f0fb15SPaul Saab * rely on the lesskey program to generate a good .less file. }} 963a5f0fb15SPaul Saab */ 964a5f0fb15SPaul Saab len = filesize(f); 965a5f0fb15SPaul Saab if (len == NULL_POSITION || len < 3) 966a5f0fb15SPaul Saab { 967a5f0fb15SPaul Saab /* 968a5f0fb15SPaul Saab * Bad file (valid file must have at least 3 chars). 969a5f0fb15SPaul Saab */ 970a5f0fb15SPaul Saab close(f); 971a5f0fb15SPaul Saab return (-1); 972a5f0fb15SPaul Saab } 973*c77c4889SXin LI if ((buf = (unsigned char *) calloc((size_t)len, sizeof(char))) == NULL) 974a5f0fb15SPaul Saab { 975a5f0fb15SPaul Saab close(f); 976a5f0fb15SPaul Saab return (-1); 977a5f0fb15SPaul Saab } 978*c77c4889SXin LI if (less_lseek(f, (less_off_t)0, SEEK_SET) == BAD_LSEEK) 979a5f0fb15SPaul Saab { 980a5f0fb15SPaul Saab free(buf); 981a5f0fb15SPaul Saab close(f); 982a5f0fb15SPaul Saab return (-1); 983a5f0fb15SPaul Saab } 984*c77c4889SXin LI n = read(f, buf, (size_t) len); 985a5f0fb15SPaul Saab close(f); 986a5f0fb15SPaul Saab if (n != len) 987a5f0fb15SPaul Saab { 988a5f0fb15SPaul Saab free(buf); 989a5f0fb15SPaul Saab return (-1); 990a5f0fb15SPaul Saab } 991a5f0fb15SPaul Saab 992a5f0fb15SPaul Saab /* 993a5f0fb15SPaul Saab * Figure out if this is an old-style (before version 241) 994a5f0fb15SPaul Saab * or new-style lesskey file format. 995a5f0fb15SPaul Saab */ 99695270f73SXin LI if (len < 4 || 99795270f73SXin LI buf[0] != C0_LESSKEY_MAGIC || buf[1] != C1_LESSKEY_MAGIC || 998a5f0fb15SPaul Saab buf[2] != C2_LESSKEY_MAGIC || buf[3] != C3_LESSKEY_MAGIC) 999*c77c4889SXin LI return (old_lesskey(buf, (size_t) len)); 1000*c77c4889SXin LI return (new_lesskey(buf, (size_t) len, sysvar)); 1001a5f0fb15SPaul Saab } 1002a5f0fb15SPaul Saab 100330a1828cSXin LI #if HAVE_LESSKEYSRC 1004*c77c4889SXin LI static int lesskey_text(constant char *filename, lbool sysvar, lbool content) 100530a1828cSXin LI { 100630a1828cSXin LI static struct lesskey_tables tables; 1007*c77c4889SXin LI if (!secure_allow(SF_LESSKEY)) 1008*c77c4889SXin LI return (1); 1009*c77c4889SXin LI int r = content ? parse_lesskey_content(filename, &tables) : parse_lesskey(filename, &tables); 101030a1828cSXin LI if (r != 0) 101130a1828cSXin LI return (r); 1012*c77c4889SXin LI add_fcmd_table(tables.cmdtable.buf.data, tables.cmdtable.buf.end); 1013*c77c4889SXin LI add_ecmd_table(tables.edittable.buf.data, tables.edittable.buf.end); 1014*c77c4889SXin LI if (sysvar) 1015*c77c4889SXin LI add_sysvar_table(tables.vartable.buf.data, tables.vartable.buf.end); 1016*c77c4889SXin LI else 1017*c77c4889SXin LI add_uvar_table(tables.vartable.buf.data, tables.vartable.buf.end); 101830a1828cSXin LI return (0); 101930a1828cSXin LI } 102030a1828cSXin LI 1021*c77c4889SXin LI public int lesskey_src(constant char *filename, lbool sysvar) 1022*c77c4889SXin LI { 1023*c77c4889SXin LI return lesskey_text(filename, sysvar, FALSE); 1024*c77c4889SXin LI } 1025*c77c4889SXin LI 1026*c77c4889SXin LI public int lesskey_content(constant char *content, lbool sysvar) 1027*c77c4889SXin LI { 1028*c77c4889SXin LI return lesskey_text(content, sysvar, TRUE); 1029*c77c4889SXin LI } 1030*c77c4889SXin LI 1031d713e089SXin LI void lesskey_parse_error(char *s) 103230a1828cSXin LI { 103330a1828cSXin LI PARG parg; 103430a1828cSXin LI parg.p_string = s; 103530a1828cSXin LI error("%s", &parg); 103630a1828cSXin LI } 103730a1828cSXin LI #endif /* HAVE_LESSKEYSRC */ 103830a1828cSXin LI 1039a5f0fb15SPaul Saab /* 104030a1828cSXin LI * Add a lesskey file. 1041a5f0fb15SPaul Saab */ 1042*c77c4889SXin LI static int add_hometable(int (*call_lesskey)(constant char *, lbool), constant char *envname, constant char *def_filename, lbool sysvar) 1043a5f0fb15SPaul Saab { 1044*c77c4889SXin LI char *filename = NULL; 1045*c77c4889SXin LI constant char *efilename; 104630a1828cSXin LI int r; 1047a5f0fb15SPaul Saab 1048*c77c4889SXin LI if (envname != NULL && (efilename = lgetenv(envname)) != NULL) 1049*c77c4889SXin LI filename = save(efilename); 105030a1828cSXin LI else if (sysvar) /* def_filename is full path */ 1051a5f0fb15SPaul Saab filename = save(def_filename); 105230a1828cSXin LI else /* def_filename is just basename */ 1053a5f0fb15SPaul Saab { 105495270f73SXin LI /* Remove first char (normally a dot) unless stored in $HOME. */ 1055*c77c4889SXin LI constant char *xdg = lgetenv("XDG_CONFIG_HOME"); 105630a1828cSXin LI if (!isnullenv(xdg)) 105795270f73SXin LI filename = dirfile(xdg, &def_filename[1], 1); 105895270f73SXin LI if (filename == NULL) 105995270f73SXin LI { 1060*c77c4889SXin LI constant char *home = lgetenv("HOME"); 106195270f73SXin LI if (!isnullenv(home)) 106295270f73SXin LI { 106395270f73SXin LI char *cfg_dir = dirfile(home, ".config", 0); 106495270f73SXin LI filename = dirfile(cfg_dir, &def_filename[1], 1); 106595270f73SXin LI free(cfg_dir); 106695270f73SXin LI } 106795270f73SXin LI } 106830a1828cSXin LI if (filename == NULL) 106930a1828cSXin LI filename = homefile(def_filename); 1070a5f0fb15SPaul Saab } 107130a1828cSXin LI if (filename == NULL) 107230a1828cSXin LI return -1; 107330a1828cSXin LI r = (*call_lesskey)(filename, sysvar); 1074a5f0fb15SPaul Saab free(filename); 107530a1828cSXin LI return (r); 1076a5f0fb15SPaul Saab } 1077*c77c4889SXin LI 1078*c77c4889SXin LI /* 1079*c77c4889SXin LI * Add the content of a lesskey source file. 1080*c77c4889SXin LI */ 1081*c77c4889SXin LI static void add_content_table(int (*call_lesskey)(constant char *, lbool), constant char *envname, lbool sysvar) 1082*c77c4889SXin LI { 1083*c77c4889SXin LI (void) call_lesskey; /* not used */ 1084*c77c4889SXin LI constant char *content = lgetenv(envname); 1085*c77c4889SXin LI if (isnullenv(content)) 1086*c77c4889SXin LI return; 1087*c77c4889SXin LI lesskey_content(content, sysvar); 1088*c77c4889SXin LI } 1089*c77c4889SXin LI #endif /* USERFILE */ 1090a5f0fb15SPaul Saab 1091a5f0fb15SPaul Saab /* 1092a5f0fb15SPaul Saab * See if a char is a special line-editing command. 1093a5f0fb15SPaul Saab */ 1094*c77c4889SXin LI public int editchar(char c, int flags) 1095a5f0fb15SPaul Saab { 1096a5f0fb15SPaul Saab int action; 1097a5f0fb15SPaul Saab int nch; 1098*c77c4889SXin LI constant char *s; 1099a5f0fb15SPaul Saab char usercmd[MAX_CMDLEN+1]; 1100a5f0fb15SPaul Saab 1101a5f0fb15SPaul Saab /* 1102a5f0fb15SPaul Saab * An editing character could actually be a sequence of characters; 1103a5f0fb15SPaul Saab * for example, an escape sequence sent by pressing the uparrow key. 1104a5f0fb15SPaul Saab * To match the editing string, we use the command decoder 1105a5f0fb15SPaul Saab * but give it the edit-commands command table 1106a5f0fb15SPaul Saab * This table is constructed to match the user's keyboard. 1107a5f0fb15SPaul Saab */ 11086dcb072bSXin LI if (c == erase_char || c == erase2_char) 1109a5f0fb15SPaul Saab return (EC_BACKSPACE); 1110a5f0fb15SPaul Saab if (c == kill_char) 1111b7780dbeSXin LI { 1112b7780dbeSXin LI #if MSDOS_COMPILER==WIN32C 1113b7780dbeSXin LI if (!win32_kbhit()) 1114b7780dbeSXin LI #endif 1115a5f0fb15SPaul Saab return (EC_LINEKILL); 1116b7780dbeSXin LI } 1117a5f0fb15SPaul Saab 1118a5f0fb15SPaul Saab /* 1119a5f0fb15SPaul Saab * Collect characters in a buffer. 1120a5f0fb15SPaul Saab * Start with the one we have, and get more if we need them. 1121a5f0fb15SPaul Saab */ 1122a5f0fb15SPaul Saab nch = 0; 1123a5f0fb15SPaul Saab do { 1124a5f0fb15SPaul Saab if (nch > 0) 1125a5f0fb15SPaul Saab c = getcc(); 1126a5f0fb15SPaul Saab usercmd[nch] = c; 1127a5f0fb15SPaul Saab usercmd[nch+1] = '\0'; 1128a5f0fb15SPaul Saab nch++; 1129a5f0fb15SPaul Saab action = ecmd_decode(usercmd, &s); 11302235c7feSXin LI } while (action == A_PREFIX && nch < MAX_CMDLEN); 1131a5f0fb15SPaul Saab 11322235c7feSXin LI if (action == EC_X11MOUSE) 11332235c7feSXin LI return (x11mouse_action(1)); 11342235c7feSXin LI if (action == EC_X116MOUSE) 11352235c7feSXin LI return (x116mouse_action(1)); 11362235c7feSXin LI 11372235c7feSXin LI if (flags & ECF_NORIGHTLEFT) 1138c9346414SPaul Saab { 1139c9346414SPaul Saab switch (action) 1140c9346414SPaul Saab { 1141c9346414SPaul Saab case EC_RIGHT: 1142c9346414SPaul Saab case EC_LEFT: 1143c9346414SPaul Saab action = A_INVALID; 1144c9346414SPaul Saab break; 1145c9346414SPaul Saab } 1146c9346414SPaul Saab } 1147a5f0fb15SPaul Saab #if CMD_HISTORY 11482235c7feSXin LI if (flags & ECF_NOHISTORY) 1149a5f0fb15SPaul Saab { 1150a5f0fb15SPaul Saab /* 1151a5f0fb15SPaul Saab * The caller says there is no history list. 1152a5f0fb15SPaul Saab * Reject any history-manipulation action. 1153a5f0fb15SPaul Saab */ 1154a5f0fb15SPaul Saab switch (action) 1155a5f0fb15SPaul Saab { 1156a5f0fb15SPaul Saab case EC_UP: 1157a5f0fb15SPaul Saab case EC_DOWN: 1158a5f0fb15SPaul Saab action = A_INVALID; 1159a5f0fb15SPaul Saab break; 1160a5f0fb15SPaul Saab } 1161a5f0fb15SPaul Saab } 1162a5f0fb15SPaul Saab #endif 1163a5f0fb15SPaul Saab #if TAB_COMPLETE_FILENAME 11642235c7feSXin LI if (flags & ECF_NOCOMPLETE) 1165a5f0fb15SPaul Saab { 1166a5f0fb15SPaul Saab /* 1167a5f0fb15SPaul Saab * The caller says we don't want any filename completion cmds. 1168a5f0fb15SPaul Saab * Reject them. 1169a5f0fb15SPaul Saab */ 1170a5f0fb15SPaul Saab switch (action) 1171a5f0fb15SPaul Saab { 1172a5f0fb15SPaul Saab case EC_F_COMPLETE: 1173a5f0fb15SPaul Saab case EC_B_COMPLETE: 1174a5f0fb15SPaul Saab case EC_EXPAND: 1175a5f0fb15SPaul Saab action = A_INVALID; 1176a5f0fb15SPaul Saab break; 1177a5f0fb15SPaul Saab } 1178a5f0fb15SPaul Saab } 1179a5f0fb15SPaul Saab #endif 11802235c7feSXin LI if ((flags & ECF_PEEK) || action == A_INVALID) 1181a5f0fb15SPaul Saab { 1182a5f0fb15SPaul Saab /* 1183a5f0fb15SPaul Saab * We're just peeking, or we didn't understand the command. 1184a5f0fb15SPaul Saab * Unget all the characters we read in the loop above. 1185a5f0fb15SPaul Saab * This does NOT include the original character that was 1186a5f0fb15SPaul Saab * passed in as a parameter. 1187a5f0fb15SPaul Saab */ 1188a5f0fb15SPaul Saab while (nch > 1) 1189a5f0fb15SPaul Saab { 1190a5f0fb15SPaul Saab ungetcc(usercmd[--nch]); 1191a5f0fb15SPaul Saab } 1192a5f0fb15SPaul Saab } else 1193a5f0fb15SPaul Saab { 1194a5f0fb15SPaul Saab if (s != NULL) 1195a5f0fb15SPaul Saab ungetsc(s); 1196a5f0fb15SPaul Saab } 1197a5f0fb15SPaul Saab return action; 1198a5f0fb15SPaul Saab } 1199a5f0fb15SPaul Saab 1200