xref: /freebsd-src/contrib/less/decode.c (revision c77c488926555ca344ae3a417544cf7a720e1de1)
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