Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/less/decode.c
103647 views
1
/*
2
* Copyright (C) 1984-2025 Mark Nudelman
3
*
4
* You may distribute under the terms of either the GNU General Public
5
* License or the Less License, as specified in the README file.
6
*
7
* For more information, see the README file.
8
*/
9
10
11
/*
12
* Routines to decode user commands.
13
*
14
* This is all table driven.
15
* A command table is a sequence of command descriptors.
16
* Each command descriptor is a sequence of bytes with the following format:
17
* <c1><c2>...<cN><0><action>
18
* The characters c1,c2,...,cN are the command string; that is,
19
* the characters which the user must type.
20
* It is terminated by a null <0> byte.
21
* The byte after the null byte is the action code associated
22
* with the command string.
23
* If an action byte is OR-ed with A_EXTRA, this indicates
24
* that the option byte is followed by an extra string.
25
*
26
* There may be many command tables.
27
* The first (default) table is built-in.
28
* Other tables are read in from "lesskey" files.
29
* All the tables are linked together and are searched in order.
30
*/
31
32
#include "less.h"
33
#include "cmd.h"
34
#include "lesskey.h"
35
36
extern int erase_char, erase2_char, kill_char;
37
extern int mousecap;
38
extern int sc_height;
39
extern char *no_config;
40
41
static constant lbool allow_drag = TRUE;
42
43
#if USERFILE
44
/* "content" is lesskey source, never binary. */
45
static void add_content_table(int (*call_lesskey)(constant char *, lbool), constant char *envname, lbool sysvar);
46
static int add_hometable(int (*call_lesskey)(constant char *, lbool), constant char *envname, constant char *def_filename, lbool sysvar);
47
#endif /* USERFILE */
48
49
#define SK(k) \
50
SK_SPECIAL_KEY, (k), 6, 1, 1, 1
51
/*
52
* Command table is ordered roughly according to expected
53
* frequency of use, so the common commands are near the beginning.
54
*/
55
56
static unsigned char cmdtable[] =
57
{
58
'\r',0, A_F_LINE,
59
'\n',0, A_F_LINE,
60
'e',0, A_F_LINE,
61
'j',0, A_F_LINE,
62
SK(SK_DOWN_ARROW),0, A_F_LINE,
63
CONTROL('E'),0, A_F_LINE,
64
CONTROL('N'),0, A_F_LINE,
65
'k',0, A_B_LINE,
66
'y',0, A_B_LINE,
67
CONTROL('Y'),0, A_B_LINE,
68
SK(SK_CONTROL_K),0, A_B_LINE,
69
CONTROL('P'),0, A_B_LINE,
70
SK(SK_UP_ARROW),0, A_B_LINE,
71
'J',0, A_FF_LINE,
72
'K',0, A_BF_LINE,
73
'Y',0, A_BF_LINE,
74
'd',0, A_F_SCROLL,
75
CONTROL('D'),0, A_F_SCROLL,
76
'u',0, A_B_SCROLL,
77
CONTROL('U'),0, A_B_SCROLL,
78
ESC,'[','M',0, A_X11MOUSE_IN,
79
ESC,'[','<',0, A_X116MOUSE_IN,
80
' ',0, A_F_SCREEN,
81
'f',0, A_F_SCREEN,
82
CONTROL('F'),0, A_F_SCREEN,
83
CONTROL('V'),0, A_F_SCREEN,
84
SK(SK_PAGE_DOWN),0, A_F_SCREEN,
85
'b',0, A_B_SCREEN,
86
CONTROL('B'),0, A_B_SCREEN,
87
ESC,'v',0, A_B_SCREEN,
88
SK(SK_PAGE_UP),0, A_B_SCREEN,
89
'z',0, A_F_WINDOW,
90
'w',0, A_B_WINDOW,
91
ESC,' ',0, A_FF_SCREEN,
92
ESC,'b',0, A_BF_SCREEN,
93
ESC,'j',0, A_F_NEWLINE,
94
ESC,'k',0, A_B_NEWLINE,
95
'F',0, A_F_FOREVER,
96
ESC,'f',0, A_F_FOREVER_BELL,
97
ESC,'F',0, A_F_UNTIL_HILITE,
98
'R',0, A_FREPAINT,
99
'r',0, A_REPAINT,
100
CONTROL('R'),0, A_REPAINT,
101
CONTROL('L'),0, A_REPAINT,
102
ESC,'u',0, A_UNDO_SEARCH,
103
ESC,'U',0, A_CLR_SEARCH,
104
'g',0, A_GOLINE,
105
SK(SK_HOME),0, A_LLSHIFT,
106
SK(SK_SHIFT_HOME),0, A_GOLINE|A_EXTRA, ESC,'{',0,
107
SK(SK_CTL_HOME),0, A_GOLINE|A_EXTRA, ESC,'{',0,
108
SK(SK_END),0, A_RRSHIFT,
109
SK(SK_SHIFT_END),0, A_GOEND|A_EXTRA, ESC,'}',0,
110
SK(SK_CTL_END),0, A_GOEND|A_EXTRA, ESC,'}',0,
111
'<',0, A_GOLINE,
112
ESC,'<',0, A_GOLINE,
113
'p',0, A_PERCENT,
114
'%',0, A_PERCENT,
115
ESC,'(',0, A_LSHIFT,
116
ESC,')',0, A_RSHIFT,
117
ESC,'{',0, A_LLSHIFT,
118
ESC,'}',0, A_RRSHIFT,
119
SK(SK_RIGHT_ARROW),0, A_RSHIFT,
120
SK(SK_LEFT_ARROW),0, A_LSHIFT,
121
SK(SK_CTL_RIGHT_ARROW),0, A_RRSHIFT,
122
SK(SK_CTL_LEFT_ARROW),0, A_LLSHIFT,
123
'{',0, A_F_BRACKET|A_EXTRA, '{','}',0,
124
'}',0, A_B_BRACKET|A_EXTRA, '{','}',0,
125
'(',0, A_F_BRACKET|A_EXTRA, '(',')',0,
126
')',0, A_B_BRACKET|A_EXTRA, '(',')',0,
127
'[',0, A_F_BRACKET|A_EXTRA, '[',']',0,
128
']',0, A_B_BRACKET|A_EXTRA, '[',']',0,
129
ESC,CONTROL('F'),0, A_F_BRACKET,
130
ESC,CONTROL('B'),0, A_B_BRACKET,
131
'G',0, A_GOEND,
132
ESC,'G',0, A_GOEND_BUF,
133
ESC,'>',0, A_GOEND,
134
'>',0, A_GOEND,
135
'P',0, A_GOPOS,
136
137
'0',0, A_DIGIT,
138
'1',0, A_DIGIT,
139
'2',0, A_DIGIT,
140
'3',0, A_DIGIT,
141
'4',0, A_DIGIT,
142
'5',0, A_DIGIT,
143
'6',0, A_DIGIT,
144
'7',0, A_DIGIT,
145
'8',0, A_DIGIT,
146
'9',0, A_DIGIT,
147
'.',0, A_DIGIT,
148
149
'=',0, A_STAT,
150
CONTROL('G'),0, A_STAT,
151
':','f',0, A_STAT,
152
'/',0, A_F_SEARCH,
153
'?',0, A_B_SEARCH,
154
ESC,'/',0, A_F_SEARCH|A_EXTRA, '*',0,
155
ESC,'?',0, A_B_SEARCH|A_EXTRA, '*',0,
156
'n',0, A_AGAIN_SEARCH,
157
ESC,'n',0, A_T_AGAIN_SEARCH,
158
'N',0, A_REVERSE_SEARCH,
159
ESC,'N',0, A_T_REVERSE_SEARCH,
160
'&',0, A_FILTER,
161
'm',0, A_SETMARK,
162
'M',0, A_SETMARKBOT,
163
ESC,'m',0, A_CLRMARK,
164
'\'',0, A_GOMARK,
165
CONTROL('X'),CONTROL('X'),0, A_GOMARK,
166
'E',0, A_EXAMINE,
167
':','e',0, A_EXAMINE,
168
CONTROL('X'),CONTROL('V'),0, A_EXAMINE,
169
':','n',0, A_NEXT_FILE,
170
':','p',0, A_PREV_FILE,
171
CONTROL('O'),CONTROL('N'),0, A_OSC8_F_SEARCH,
172
CONTROL('O'),'n',0, A_OSC8_F_SEARCH,
173
CONTROL('O'),CONTROL('P'),0, A_OSC8_B_SEARCH,
174
CONTROL('O'),'p',0, A_OSC8_B_SEARCH,
175
CONTROL('O'),CONTROL('O'),0, A_OSC8_OPEN,
176
CONTROL('O'),'o',0, A_OSC8_OPEN,
177
CONTROL('O'),CONTROL('L'),0, A_OSC8_JUMP,
178
CONTROL('O'),'l',0, A_OSC8_JUMP,
179
't',0, A_NEXT_TAG,
180
'T',0, A_PREV_TAG,
181
':','x',0, A_INDEX_FILE,
182
':','d',0, A_REMOVE_FILE,
183
'-',0, A_OPT_TOGGLE,
184
':','t',0, A_OPT_TOGGLE|A_EXTRA, 't',0,
185
's',0, A_OPT_TOGGLE|A_EXTRA, 'o',0,
186
'_',0, A_DISP_OPTION,
187
'|',0, A_PIPE,
188
'v',0, A_VISUAL,
189
'!',0, A_SHELL,
190
'#',0, A_PSHELL,
191
'+',0, A_FIRSTCMD,
192
193
SK(SK_PAD_U),0, A_B_LINE,
194
SK(SK_PAD_D),0, A_F_LINE,
195
SK(SK_PAD_R),0, A_RSHIFT,
196
SK(SK_PAD_L),0, A_LSHIFT,
197
SK(SK_PAD_UR),0, A_B_SCREEN,
198
SK(SK_PAD_UL),0, A_LLSHIFT,
199
SK(SK_PAD_DR),0, A_RRSHIFT,
200
SK(SK_PAD_DL),0, A_GOEND,
201
SK(SK_PAD_STAR),0, A_NOACTION|A_EXTRA, '*',0,
202
SK(SK_PAD_SLASH),0, A_NOACTION|A_EXTRA, '/',0,
203
SK(SK_PAD_DASH),0, A_NOACTION|A_EXTRA, '-',0,
204
SK(SK_PAD_PLUS),0, A_NOACTION|A_EXTRA, '+',0,
205
SK(SK_PAD_DOT),0, A_NOACTION|A_EXTRA, '.',0,
206
SK(SK_PAD_COMMA),0, A_NOACTION,
207
SK(SK_PAD_ZERO),0, A_NOACTION|A_EXTRA, '0',0,
208
SK(SK_PAD_CENTER),0, A_NOACTION,
209
210
ESC,'[','2','0','0','~',0, A_START_PASTE,
211
ESC,'[','2','0','1','~',0, A_END_PASTE,
212
213
'H',0, A_HELP,
214
'h',0, A_HELP,
215
SK(SK_F1),0, A_HELP,
216
'V',0, A_VERSION,
217
'q',0, A_QUIT,
218
'Q',0, A_QUIT,
219
':','q',0, A_QUIT,
220
':','Q',0, A_QUIT,
221
'Z','Z',0, A_QUIT
222
};
223
224
static unsigned char edittable[] =
225
{
226
'\t',0, EC_F_COMPLETE, /* TAB */
227
'\17',0, EC_B_COMPLETE, /* BACKTAB */
228
SK(SK_BACKTAB),0, EC_B_COMPLETE, /* BACKTAB */
229
ESC,'\t',0, EC_B_COMPLETE, /* ESC TAB */
230
CONTROL('L'),0, EC_EXPAND, /* CTRL-L */
231
CONTROL('V'),0, EC_LITERAL, /* BACKSLASH */
232
CONTROL('A'),0, EC_LITERAL, /* BACKSLASH */
233
ESC,'l',0, EC_RIGHT, /* ESC l */
234
SK(SK_RIGHT_ARROW),0, EC_RIGHT, /* RIGHTARROW */
235
ESC,'h',0, EC_LEFT, /* ESC h */
236
SK(SK_LEFT_ARROW),0, EC_LEFT, /* LEFTARROW */
237
ESC,'b',0, EC_W_LEFT, /* ESC b */
238
ESC,SK(SK_LEFT_ARROW),0, EC_W_LEFT, /* ESC LEFTARROW */
239
SK(SK_CTL_LEFT_ARROW),0, EC_W_LEFT, /* CTRL-LEFTARROW */
240
ESC,'w',0, EC_W_RIGHT, /* ESC w */
241
ESC,SK(SK_RIGHT_ARROW),0, EC_W_RIGHT, /* ESC RIGHTARROW */
242
SK(SK_CTL_RIGHT_ARROW),0, EC_W_RIGHT, /* CTRL-RIGHTARROW */
243
ESC,'i',0, EC_INSERT, /* ESC i */
244
SK(SK_INSERT),0, EC_INSERT, /* INSERT */
245
ESC,'x',0, EC_DELETE, /* ESC x */
246
SK(SK_DELETE),0, EC_DELETE, /* DELETE */
247
ESC,'X',0, EC_W_DELETE, /* ESC X */
248
ESC,SK(SK_DELETE),0, EC_W_DELETE, /* ESC DELETE */
249
SK(SK_CTL_DELETE),0, EC_W_DELETE, /* CTRL-DELETE */
250
SK(SK_CTL_BACKSPACE),0, EC_W_BACKSPACE, /* CTRL-BACKSPACE */
251
ESC,SK(SK_BACKSPACE),0, EC_W_BACKSPACE, /* ESC BACKSPACE */
252
ESC,'0',0, EC_HOME, /* ESC 0 */
253
SK(SK_HOME),0, EC_HOME, /* HOME */
254
SK(SK_SHIFT_HOME),0, EC_HOME, /* SHIFT-HOME */
255
SK(SK_CTL_HOME),0, EC_HOME, /* CTRL-HOME */
256
ESC,'$',0, EC_END, /* ESC $ */
257
SK(SK_END),0, EC_END, /* END */
258
SK(SK_SHIFT_END),0, EC_END, /* SHIFT-END */
259
SK(SK_CTL_END),0, EC_END, /* CTRL-END */
260
ESC,'k',0, EC_UP, /* ESC k */
261
SK(SK_UP_ARROW),0, EC_UP, /* UPARROW */
262
ESC,'j',0, EC_DOWN, /* ESC j */
263
SK(SK_DOWN_ARROW),0, EC_DOWN, /* DOWNARROW */
264
CONTROL('G'),0, EC_ABORT, /* CTRL-G */
265
SK(SK_PAD_U),0, EC_UP,
266
SK(SK_PAD_D),0, EC_DOWN,
267
SK(SK_PAD_R),0, EC_RIGHT,
268
SK(SK_PAD_L),0, EC_LEFT,
269
SK(SK_PAD_UR),0, A_NOACTION,
270
SK(SK_PAD_UL),0, EC_HOME,
271
SK(SK_PAD_DR),0, A_NOACTION,
272
SK(SK_PAD_DL),0, EC_END,
273
SK(SK_PAD_STAR),0, A_NOACTION|A_EXTRA, '*',0,
274
SK(SK_PAD_SLASH),0, A_NOACTION|A_EXTRA, '/',0,
275
SK(SK_PAD_DASH),0, A_NOACTION|A_EXTRA, '-',0,
276
SK(SK_PAD_PLUS),0, A_NOACTION|A_EXTRA, '+',0,
277
SK(SK_PAD_DOT),0, A_NOACTION|A_EXTRA, '.',0,
278
SK(SK_PAD_COMMA),0, A_NOACTION|A_EXTRA, ',',0,
279
SK(SK_PAD_ZERO),0, A_NOACTION|A_EXTRA, '0',0,
280
SK(SK_PAD_CENTER),0, A_NOACTION,
281
ESC,'[','M',0, EC_X11MOUSE, /* X11 mouse report */
282
ESC,'[','<',0, EC_X116MOUSE, /* X11 1006 mouse report */
283
ESC,'[','2','0','0','~',0, A_START_PASTE, /* open paste bracket */
284
ESC,'[','2','0','1','~',0, A_END_PASTE, /* close paste bracket */
285
};
286
287
static unsigned char dflt_vartable[] =
288
{
289
'L','E','S','S','_','O','S','C','8','_','m','a','n', 0, EV_OK|A_EXTRA,
290
/* echo '%o' | sed -e "s,^man\:\\([^(]*\\)( *\\([^)]*\\)\.*,-man '\\2' '\\1'," -e"t X" -e"s,\.*,-echo Invalid man link," -e"\: X" */
291
'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','"',
292
0,
293
294
'L','E','S','S','_','O','S','C','8','_','f','i','l','e', 0, EV_OK|A_EXTRA,
295
/* 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 */
296
'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',
297
0,
298
};
299
300
/*
301
* Structure to support a list of command tables.
302
*/
303
struct tablelist
304
{
305
struct tablelist *t_next;
306
unsigned char *t_start;
307
unsigned char *t_end;
308
};
309
310
/*
311
* List of command tables and list of line-edit tables.
312
*/
313
static struct tablelist *list_fcmd_tables = NULL;
314
static struct tablelist *list_ecmd_tables = NULL;
315
static struct tablelist *list_var_tables = NULL;
316
static struct tablelist *list_sysvar_tables = NULL;
317
318
319
/*
320
* Expand special key abbreviations in a command table.
321
*/
322
static void expand_special_keys(unsigned char *table, size_t len)
323
{
324
unsigned char *fm;
325
unsigned char *to;
326
int a;
327
constant char *repl;
328
size_t klen;
329
330
for (fm = table; fm < table + len; )
331
{
332
/*
333
* Rewrite each command in the table with any
334
* special key abbreviations expanded.
335
*/
336
for (to = fm; *fm != '\0'; )
337
{
338
if (*fm != SK_SPECIAL_KEY)
339
{
340
*to++ = *fm++;
341
continue;
342
}
343
/*
344
* After SK_SPECIAL_KEY, next byte is the type
345
* of special key (one of the SK_* constants),
346
* and the byte after that is the number of bytes,
347
* N, reserved by the abbreviation (including the
348
* SK_SPECIAL_KEY and key type bytes).
349
* Replace all N bytes with the actual bytes
350
* output by the special key on this terminal.
351
*/
352
repl = special_key_str(fm[1]);
353
klen = fm[2] & 0377;
354
fm += klen;
355
if (repl == NULL || strlen(repl) > klen)
356
repl = "\377";
357
while (*repl != '\0')
358
*to++ = (unsigned char) *repl++; /*{{type-issue}}*/
359
}
360
*to++ = '\0';
361
/*
362
* Fill any unused bytes between end of command and
363
* the action byte with A_SKIP.
364
*/
365
while (to <= fm)
366
*to++ = A_SKIP;
367
fm++;
368
a = *fm++ & 0377;
369
if (a & A_EXTRA)
370
{
371
while (*fm++ != '\0')
372
continue;
373
}
374
}
375
}
376
377
/*
378
* Expand special key abbreviations in a list of command tables.
379
*/
380
static void expand_cmd_table(struct tablelist *tlist)
381
{
382
struct tablelist *t;
383
for (t = tlist; t != NULL; t = t->t_next)
384
{
385
expand_special_keys(t->t_start, ptr_diff(t->t_end, t->t_start));
386
}
387
}
388
389
/*
390
* Expand special key abbreviations in all command tables.
391
*/
392
public void expand_cmd_tables(void)
393
{
394
expand_cmd_table(list_fcmd_tables);
395
expand_cmd_table(list_ecmd_tables);
396
expand_cmd_table(list_var_tables);
397
expand_cmd_table(list_sysvar_tables);
398
}
399
400
/*
401
* Initialize the command lists.
402
*/
403
public void init_cmds(void)
404
{
405
/*
406
* Add the default command tables.
407
*/
408
add_fcmd_table(cmdtable, sizeof(cmdtable));
409
add_ecmd_table(edittable, sizeof(edittable));
410
add_sysvar_table(dflt_vartable, sizeof(dflt_vartable));
411
#if USERFILE
412
#ifdef BINDIR /* For backwards compatibility */
413
/* Try to add tables in the OLD system lesskey file. */
414
add_hometable(lesskey, NULL, BINDIR "/.sysless", TRUE);
415
#endif
416
/*
417
* Try to load lesskey source file or binary file.
418
* If the source file succeeds, don't load binary file.
419
* The binary file is likely to have been generated from
420
* a (possibly out of date) copy of the src file,
421
* so loading it is at best redundant.
422
*/
423
/*
424
* Try to add tables in system lesskey src file.
425
*/
426
#if HAVE_LESSKEYSRC
427
if (add_hometable(lesskey_src, "LESSKEYIN_SYSTEM", LESSKEYINFILE_SYS, TRUE) != 0)
428
#endif
429
{
430
/*
431
* Try to add the tables in the system lesskey binary file.
432
*/
433
add_hometable(lesskey, "LESSKEY_SYSTEM", LESSKEYFILE_SYS, TRUE);
434
}
435
/*
436
* Try to add tables in the lesskey src file "$HOME/.lesskey".
437
*/
438
#if HAVE_LESSKEYSRC
439
if (add_hometable(lesskey_src, "LESSKEYIN", DEF_LESSKEYINFILE, FALSE) != 0)
440
#endif
441
{
442
/*
443
* Try to add the tables in the standard lesskey binary file "$HOME/.less".
444
*/
445
add_hometable(lesskey, "LESSKEY", LESSKEYFILE, FALSE);
446
}
447
448
add_content_table(lesskey_content, "LESSKEY_CONTENT_SYSTEM", TRUE);
449
add_content_table(lesskey_content, "LESSKEY_CONTENT", FALSE);
450
#endif /* USERFILE */
451
}
452
453
/*
454
* Add a command table.
455
*/
456
static int add_cmd_table(struct tablelist **tlist, unsigned char *buf, size_t len)
457
{
458
struct tablelist *t;
459
460
if (len == 0)
461
return (0);
462
/*
463
* Allocate a tablelist structure, initialize it,
464
* and link it into the list of tables.
465
*/
466
if ((t = (struct tablelist *)
467
calloc(1, sizeof(struct tablelist))) == NULL)
468
{
469
return (-1);
470
}
471
t->t_start = buf;
472
t->t_end = buf + len;
473
t->t_next = NULL;
474
if (*tlist == NULL)
475
*tlist = t;
476
else
477
{
478
struct tablelist *e;
479
for (e = *tlist; e->t_next != NULL; e = e->t_next)
480
continue;
481
e->t_next = t;
482
}
483
return (0);
484
}
485
486
/*
487
* Remove the last command table in a list.
488
*/
489
static void pop_cmd_table(struct tablelist **tlist)
490
{
491
struct tablelist *t;
492
if (*tlist == NULL)
493
return;
494
if ((*tlist)->t_next == NULL)
495
{
496
t = *tlist;
497
*tlist = NULL;
498
} else
499
{
500
struct tablelist *e;
501
for (e = *tlist; e->t_next->t_next != NULL; e = e->t_next)
502
continue;
503
t = e->t_next;
504
e->t_next = NULL;
505
}
506
free(t);
507
}
508
509
/*
510
* Add a command table.
511
*/
512
public void add_fcmd_table(unsigned char *buf, size_t len)
513
{
514
if (add_cmd_table(&list_fcmd_tables, buf, len) < 0)
515
error("Warning: some commands disabled", NULL_PARG);
516
}
517
518
/*
519
* Add an editing command table.
520
*/
521
public void add_ecmd_table(unsigned char *buf, size_t len)
522
{
523
if (add_cmd_table(&list_ecmd_tables, buf, len) < 0)
524
error("Warning: some edit commands disabled", NULL_PARG);
525
}
526
527
/*
528
* Add an environment variable table.
529
*/
530
static void add_var_table(struct tablelist **tlist, mutable unsigned char *buf, size_t len)
531
{
532
struct xbuffer xbuf;
533
534
xbuf_init(&xbuf);
535
expand_evars((mutable char*)buf, len, &xbuf); /*{{unsigned-issue}}*/
536
/* {{ We leak the table in buf. expand_evars scribbled in it so it's useless anyway. }} */
537
if (add_cmd_table(tlist, xbuf.data, xbuf.end) < 0)
538
error("Warning: environment variables from lesskey file unavailable", NULL_PARG);
539
}
540
541
public void add_uvar_table(unsigned char *buf, size_t len)
542
{
543
add_var_table(&list_var_tables, buf, len);
544
}
545
546
public void add_sysvar_table(unsigned char *buf, size_t len)
547
{
548
add_var_table(&list_sysvar_tables, buf, len);
549
}
550
551
/*
552
* Return action for a mouse wheel down event.
553
*/
554
static int mouse_wheel_down(void)
555
{
556
return ((mousecap == OPT_ONPLUS) ? A_B_MOUSE : A_F_MOUSE);
557
}
558
559
/*
560
* Return action for a mouse wheel up event.
561
*/
562
static int mouse_wheel_up(void)
563
{
564
return ((mousecap == OPT_ONPLUS) ? A_F_MOUSE : A_B_MOUSE);
565
}
566
567
/*
568
* Return action for the left mouse button trigger.
569
*/
570
static int mouse_button_left(int x, int y, lbool down, lbool drag)
571
{
572
static int last_drag_y = -1;
573
static int last_click_y = -1;
574
575
if (down && !drag)
576
{
577
last_drag_y = last_click_y = y;
578
}
579
if (allow_drag && drag && last_drag_y >= 0)
580
{
581
/* Drag text up/down */
582
if (y > last_drag_y)
583
{
584
cmd_exec();
585
backward(y - last_drag_y, FALSE, FALSE, FALSE);
586
last_drag_y = y;
587
} else if (y < last_drag_y)
588
{
589
cmd_exec();
590
forward(last_drag_y - y, FALSE, FALSE, FALSE);
591
last_drag_y = y;
592
}
593
} else if (!down)
594
{
595
#if OSC8_LINK
596
if (secure_allow(SF_OSC8_OPEN))
597
{
598
if (osc8_click(y, x))
599
return (A_NOACTION);
600
}
601
#else
602
(void) x;
603
#endif /* OSC8_LINK */
604
if (y < sc_height-1 && y == last_click_y)
605
{
606
setmark('#', y);
607
screen_trashed();
608
}
609
}
610
return (A_NOACTION);
611
}
612
613
/*
614
* Return action for the right mouse button trigger.
615
*/
616
static int mouse_button_right(int x, int y, lbool down, lbool drag)
617
{
618
(void) x; (void) drag;
619
/*
620
* {{ unlike mouse_button_left, we could return an action,
621
* but keep it near mouse_button_left for readability. }}
622
*/
623
if (!down && y < sc_height-1)
624
{
625
gomark('#');
626
screen_trashed();
627
}
628
return (A_NOACTION);
629
}
630
631
/*
632
* Read a decimal integer. Return the integer and set *pterm to the terminating char.
633
*/
634
static int getcc_int(char *pterm)
635
{
636
int num = 0;
637
int digits = 0;
638
for (;;)
639
{
640
char ch = getcc();
641
if (ch < '0' || ch > '9')
642
{
643
if (pterm != NULL) *pterm = ch;
644
if (digits == 0)
645
return (-1);
646
return (num);
647
}
648
if (ckd_mul(&num, num, 10) || ckd_add(&num, num, ch - '0'))
649
return -1;
650
++digits;
651
}
652
}
653
654
static int x11mouse_button(int btn, int x, int y, lbool down, lbool drag)
655
{
656
switch (btn) {
657
case X11MOUSE_BUTTON1:
658
return mouse_button_left(x, y, down, drag);
659
/* is BUTTON2 the rightmost with 2-buttons mouse? */
660
case X11MOUSE_BUTTON2:
661
case X11MOUSE_BUTTON3:
662
return mouse_button_right(x, y, down, drag);
663
}
664
return (A_NOACTION);
665
}
666
667
/*
668
* Read suffix of mouse input and return the action to take.
669
* The prefix ("\e[M") has already been read.
670
*/
671
static int x11mouse_action(lbool skip)
672
{
673
static int prev_b = X11MOUSE_BUTTON_REL;
674
int x, y;
675
int b = getcc() - X11MOUSE_OFFSET;
676
lbool drag = ((b & X11MOUSE_DRAG) != 0);
677
b &= ~X11MOUSE_DRAG;
678
x = getcc() - X11MOUSE_OFFSET-1;
679
y = getcc() - X11MOUSE_OFFSET-1;
680
if (skip)
681
return (A_NOACTION);
682
switch (b) {
683
case X11MOUSE_WHEEL_DOWN:
684
return mouse_wheel_down();
685
case X11MOUSE_WHEEL_UP:
686
return mouse_wheel_up();
687
case X11MOUSE_BUTTON1:
688
case X11MOUSE_BUTTON2:
689
case X11MOUSE_BUTTON3:
690
prev_b = b;
691
return x11mouse_button(b, x, y, TRUE, drag);
692
case X11MOUSE_BUTTON_REL: /* button up */
693
return x11mouse_button(prev_b, x, y, FALSE, drag);
694
}
695
return (A_NOACTION);
696
}
697
698
/*
699
* Read suffix of mouse input and return the action to take.
700
* The prefix ("\e[<") has already been read.
701
*/
702
static int x116mouse_action(lbool skip)
703
{
704
char ch;
705
int x, y;
706
int b = getcc_int(&ch);
707
lbool drag = ((b & X11MOUSE_DRAG) != 0);
708
b &= ~X11MOUSE_DRAG;
709
if (b < 0 || ch != ';') return (A_NOACTION);
710
x = getcc_int(&ch) - 1;
711
if (x < 0 || ch != ';') return (A_NOACTION);
712
y = getcc_int(&ch) - 1;
713
if (y < 0) return (A_NOACTION);
714
if (skip)
715
return (A_NOACTION);
716
switch (b) {
717
case X11MOUSE_WHEEL_DOWN:
718
return mouse_wheel_down();
719
case X11MOUSE_WHEEL_UP:
720
return mouse_wheel_up();
721
case X11MOUSE_BUTTON1:
722
case X11MOUSE_BUTTON2:
723
case X11MOUSE_BUTTON3: {
724
lbool down = (ch == 'M');
725
lbool up = (ch == 'm');
726
if (up || down)
727
return x11mouse_button(b, x, y, down, drag);
728
break; }
729
}
730
return (A_NOACTION);
731
}
732
733
/*
734
* Return the largest N such that the first N chars of goal
735
* are equal to the last N chars of str.
736
*/
737
static size_t cmd_match(constant char *goal, constant char *str)
738
{
739
size_t slen = strlen(str);
740
size_t len;
741
for (len = slen; len > 0; len--)
742
if (strncmp(str + slen - len, goal, len) == 0)
743
break;
744
return len;
745
}
746
747
/*
748
* Return pointer to next command table entry.
749
* Also return the action and the extra string from the entry.
750
*/
751
static constant unsigned char * cmd_next_entry(constant unsigned char *entry, mutable int *action, mutable constant unsigned char **extra, mutable size_t *cmdlen)
752
{
753
int a;
754
constant unsigned char *oentry = entry;
755
while (*entry != '\0') /* skip cmd */
756
++entry;
757
if (cmdlen != NULL)
758
*cmdlen = ptr_diff(entry, oentry);
759
do
760
a = *++entry; /* get action */
761
while (a == A_SKIP);
762
++entry; /* skip action */
763
if (extra != NULL)
764
*extra = (a & A_EXTRA) ? entry : NULL;
765
if (a & A_EXTRA)
766
{
767
while (*entry++ != '\0') /* skip extra string */
768
continue;
769
a &= ~A_EXTRA;
770
}
771
if (action != NULL)
772
*action = a;
773
return entry;
774
}
775
776
/*
777
* Search a single command table for the command string in cmd.
778
*/
779
static int cmd_search(constant char *cmd, constant unsigned char *table, constant unsigned char *endtable, constant unsigned char **extra, size_t *mlen)
780
{
781
int action = A_INVALID;
782
size_t match_len = 0;
783
if (extra != NULL)
784
*extra = NULL;
785
while (table < endtable)
786
{
787
int taction;
788
constant unsigned char *textra;
789
size_t cmdlen;
790
size_t match = cmd_match((constant char *) table, cmd);
791
table = cmd_next_entry(table, &taction, &textra, &cmdlen);
792
if (taction == A_END_LIST)
793
return (-action);
794
if (match >= match_len)
795
{
796
if (match == cmdlen) /* (last chars of) cmd matches this table entry */
797
{
798
action = taction;
799
if (extra != NULL)
800
*extra = textra;
801
} else if (match > 0 && action == A_INVALID) /* cmd is a prefix of this table entry */
802
{
803
action = A_PREFIX;
804
}
805
match_len = match;
806
}
807
}
808
if (mlen != NULL)
809
*mlen = match_len;
810
return (action);
811
}
812
813
/*
814
* Decode a command character and return the associated action.
815
* The "extra" string, if any, is returned in sp.
816
*/
817
static int cmd_decode(struct tablelist *tlist, constant char *cmd, constant char **sp)
818
{
819
struct tablelist *t;
820
int action = A_INVALID;
821
size_t match_len = 0;
822
823
/*
824
* Search for the cmd thru all the command tables.
825
* If we find it more than once, take the last one.
826
*/
827
*sp = NULL;
828
for (t = tlist; t != NULL; t = t->t_next)
829
{
830
constant unsigned char *tsp;
831
size_t mlen = match_len;
832
int taction = cmd_search(cmd, t->t_start, t->t_end, &tsp, &mlen);
833
if (mlen >= match_len)
834
{
835
match_len = mlen;
836
if (taction != A_INVALID)
837
{
838
*sp = (constant char *) tsp;
839
if (taction < 0)
840
{
841
action = -taction;
842
break;
843
}
844
action = taction;
845
}
846
}
847
}
848
if (action == A_X11MOUSE_IN)
849
action = x11mouse_action(FALSE);
850
else if (action == A_X116MOUSE_IN)
851
action = x116mouse_action(FALSE);
852
return (action);
853
}
854
855
/*
856
* Decode a command from the cmdtables list.
857
*/
858
public int fcmd_decode(constant char *cmd, constant char **sp)
859
{
860
return (cmd_decode(list_fcmd_tables, cmd, sp));
861
}
862
863
/*
864
* Decode a command from the edittables list.
865
*/
866
public int ecmd_decode(constant char *cmd, constant char **sp)
867
{
868
return (cmd_decode(list_ecmd_tables, cmd, sp));
869
}
870
871
/*
872
* Parse a comma-separated list.
873
* Call func repeatedly, passing each item in the list.
874
* Stop and return FALSE if func ever returns FALSE,
875
* otherwise parse the entire list and return TRUE.
876
*/
877
public lbool parse_csl(lbool (*func)(constant char *word, size_t wlen, void *arg), constant char *str, void *arg)
878
{
879
for (;;)
880
{
881
constant char *estr;
882
while (*str == ' ' || *str == ',') ++str; /* skip leading spaces/commas */
883
if (*str == '\0') break;
884
estr = strchr(str, ',');
885
if (estr == NULL) estr = str + strlen(str);
886
while (estr > str && estr[-1] == ' ') --estr; /* trim trailing spaces */
887
if (!(*func)(str, ptr_diff(estr, str), arg))
888
return FALSE;
889
str = estr;
890
}
891
return TRUE;
892
}
893
894
/*
895
* Should we ignore the setting of an environment variable?
896
*/
897
static lbool word_no_match(constant char *word, size_t wlen, void *arg)
898
{
899
constant char *var = (constant char *) arg;
900
return !(wlen == strlen(var) && strncmp(var, word, wlen) == 0);
901
}
902
static lbool ignore_env(constant char *var)
903
{
904
if (isnullenv(no_config))
905
return FALSE; /* no_config is not set; don't ignore anything */
906
/* no_config is set; ignore any var that does not appear in no_config */
907
return parse_csl(word_no_match, no_config, (void*) var);
908
}
909
910
/*
911
* Get the value of an environment variable.
912
* Looks first in the lesskey file, then in the real environment.
913
*/
914
public constant char * lgetenv(constant char *var)
915
{
916
int a;
917
constant char *s;
918
919
if (ignore_env(var))
920
return (NULL);
921
a = cmd_decode(list_var_tables, var, &s);
922
if (a == EV_OK)
923
return (s);
924
s = getenv(var);
925
if (s != NULL && *s != '\0')
926
return (s);
927
a = cmd_decode(list_sysvar_tables, var, &s);
928
if (a == EV_OK)
929
return (s);
930
return (NULL);
931
}
932
933
/*
934
* Like lgetenv, but also uses a buffer partially filled with an env table.
935
*/
936
public constant char * lgetenv_ext(constant char *var, unsigned char *env_buf, size_t env_buf_len)
937
{
938
constant char *r;
939
size_t e;
940
size_t env_end = 0;
941
942
for (e = 0;;)
943
{
944
for (; e < env_buf_len; e++)
945
if (env_buf[e] == '\0')
946
break;
947
if (e >= env_buf_len) break;
948
if (env_buf[++e] & A_EXTRA)
949
{
950
for (e = e+1; e < env_buf_len; e++)
951
if (env_buf[e] == '\0')
952
break;
953
}
954
e++;
955
if (e >= env_buf_len) break;
956
env_end = e;
957
}
958
/* Temporarily add env_buf to var_tables, do the lookup, then remove it. */
959
add_uvar_table(env_buf, env_end);
960
r = lgetenv(var);
961
pop_cmd_table(&list_var_tables);
962
return r;
963
}
964
965
/*
966
* Is a string null or empty?
967
*/
968
public lbool isnullenv(constant char *s)
969
{
970
return (s == NULL || *s == '\0');
971
}
972
973
#if USERFILE
974
/*
975
* Get an "integer" from a lesskey file.
976
* Integers are stored in a funny format:
977
* two bytes, low order first, in radix KRADIX.
978
*/
979
static size_t gint(unsigned char **sp)
980
{
981
size_t n;
982
983
n = *(*sp)++;
984
n += *(*sp)++ * KRADIX;
985
return (n);
986
}
987
988
/*
989
* Process an old (pre-v241) lesskey file.
990
*/
991
static int old_lesskey(unsigned char *buf, size_t len)
992
{
993
/*
994
* Old-style lesskey file.
995
* The file must end with either
996
* ...,cmd,0,action
997
* or ...,cmd,0,action|A_EXTRA,string,0
998
* So the last byte or the second to last byte must be zero.
999
*/
1000
if (buf[len-1] != '\0' && buf[len-2] != '\0')
1001
return (-1);
1002
add_fcmd_table(buf, len);
1003
return (0);
1004
}
1005
1006
/*
1007
* Process a new (post-v241) lesskey file.
1008
*/
1009
static int new_lesskey(unsigned char *buf, size_t len, lbool sysvar)
1010
{
1011
unsigned char *p;
1012
unsigned char *end;
1013
int c;
1014
size_t n;
1015
1016
/*
1017
* New-style lesskey file.
1018
* Extract the pieces.
1019
*/
1020
if (buf[len-3] != C0_END_LESSKEY_MAGIC ||
1021
buf[len-2] != C1_END_LESSKEY_MAGIC ||
1022
buf[len-1] != C2_END_LESSKEY_MAGIC)
1023
return (-1);
1024
p = buf + 4;
1025
end = buf + len;
1026
for (;;)
1027
{
1028
c = *p++;
1029
switch (c)
1030
{
1031
case CMD_SECTION:
1032
n = gint(&p);
1033
if (p+n >= end)
1034
return (-1);
1035
add_fcmd_table(p, n);
1036
p += n;
1037
break;
1038
case EDIT_SECTION:
1039
n = gint(&p);
1040
if (p+n >= end)
1041
return (-1);
1042
add_ecmd_table(p, n);
1043
p += n;
1044
break;
1045
case VAR_SECTION:
1046
n = gint(&p);
1047
if (p+n >= end)
1048
return (-1);
1049
if (sysvar)
1050
add_sysvar_table(p, n);
1051
else
1052
add_uvar_table(p, n);
1053
p += n;
1054
break;
1055
case END_SECTION:
1056
return (0);
1057
default:
1058
/*
1059
* Unrecognized section type.
1060
*/
1061
return (-1);
1062
}
1063
}
1064
}
1065
1066
/*
1067
* Set up a user command table, based on a "lesskey" file.
1068
*/
1069
public int lesskey(constant char *filename, lbool sysvar)
1070
{
1071
unsigned char *buf;
1072
POSITION len;
1073
ssize_t n;
1074
int f;
1075
1076
if (!secure_allow(SF_LESSKEY) || !isnullenv(no_config))
1077
return (1);
1078
/*
1079
* Try to open the lesskey file.
1080
*/
1081
f = open(filename, OPEN_READ);
1082
if (f < 0)
1083
return (1);
1084
1085
/*
1086
* Read the file into a buffer.
1087
* We first figure out the size of the file and allocate space for it.
1088
* {{ Minimal error checking is done here.
1089
* A garbage .less file will produce strange results.
1090
* To avoid a large amount of error checking code here, we
1091
* rely on the lesskey program to generate a good .less file. }}
1092
*/
1093
len = filesize(f);
1094
if (len == NULL_POSITION || len < 3)
1095
{
1096
/*
1097
* Bad file (valid file must have at least 3 chars).
1098
*/
1099
close(f);
1100
return (-1);
1101
}
1102
if ((buf = (unsigned char *) calloc((size_t)len, sizeof(char))) == NULL)
1103
{
1104
close(f);
1105
return (-1);
1106
}
1107
if (less_lseek(f, (less_off_t)0, SEEK_SET) == BAD_LSEEK)
1108
{
1109
free(buf);
1110
close(f);
1111
return (-1);
1112
}
1113
n = read(f, buf, (size_t) len);
1114
close(f);
1115
if (n != len)
1116
{
1117
free(buf);
1118
return (-1);
1119
}
1120
1121
/*
1122
* Figure out if this is an old-style (before version 241)
1123
* or new-style lesskey file format.
1124
*/
1125
if (len < 4 ||
1126
buf[0] != C0_LESSKEY_MAGIC || buf[1] != C1_LESSKEY_MAGIC ||
1127
buf[2] != C2_LESSKEY_MAGIC || buf[3] != C3_LESSKEY_MAGIC)
1128
return (old_lesskey(buf, (size_t) len));
1129
return (new_lesskey(buf, (size_t) len, sysvar));
1130
}
1131
1132
#if HAVE_LESSKEYSRC
1133
static int lesskey_text(constant char *filename, lbool sysvar, lbool content)
1134
{
1135
int r;
1136
static struct lesskey_tables tables;
1137
1138
if (!secure_allow(SF_LESSKEY) || !isnullenv(no_config))
1139
return (1);
1140
r = content ? parse_lesskey_content(filename, &tables) : parse_lesskey(filename, &tables);
1141
if (r != 0)
1142
return (r);
1143
add_fcmd_table(tables.cmdtable.buf.data, tables.cmdtable.buf.end);
1144
add_ecmd_table(tables.edittable.buf.data, tables.edittable.buf.end);
1145
if (sysvar)
1146
add_sysvar_table(tables.vartable.buf.data, tables.vartable.buf.end);
1147
else
1148
add_uvar_table(tables.vartable.buf.data, tables.vartable.buf.end);
1149
return (0);
1150
}
1151
1152
public int lesskey_src(constant char *filename, lbool sysvar)
1153
{
1154
return lesskey_text(filename, sysvar, FALSE);
1155
}
1156
1157
public int lesskey_content(constant char *content, lbool sysvar)
1158
{
1159
return lesskey_text(content, sysvar, TRUE);
1160
}
1161
1162
void lesskey_parse_error(char *s)
1163
{
1164
PARG parg;
1165
parg.p_string = s;
1166
error("%s", &parg);
1167
}
1168
#endif /* HAVE_LESSKEYSRC */
1169
1170
/*
1171
* Add a lesskey file.
1172
*/
1173
static int add_hometable(int (*call_lesskey)(constant char *, lbool), constant char *envname, constant char *def_filename, lbool sysvar)
1174
{
1175
char *filename = NULL;
1176
constant char *efilename;
1177
int r;
1178
1179
if (envname != NULL && (efilename = lgetenv(envname)) != NULL)
1180
filename = save(efilename);
1181
else if (sysvar) /* def_filename is full path */
1182
filename = save(def_filename);
1183
else /* def_filename is just basename */
1184
{
1185
/* Remove first char (normally a dot) unless stored in $HOME. */
1186
constant char *xdg = lgetenv("XDG_CONFIG_HOME");
1187
if (!isnullenv(xdg))
1188
filename = dirfile(xdg, &def_filename[1], 1);
1189
if (filename == NULL)
1190
{
1191
constant char *home = lgetenv("HOME");
1192
if (!isnullenv(home))
1193
{
1194
char *cfg_dir = dirfile(home, ".config", 0);
1195
filename = dirfile(cfg_dir, &def_filename[1], 1);
1196
free(cfg_dir);
1197
}
1198
}
1199
if (filename == NULL)
1200
filename = homefile(def_filename);
1201
}
1202
if (filename == NULL)
1203
return -1;
1204
r = (*call_lesskey)(filename, sysvar);
1205
free(filename);
1206
return (r);
1207
}
1208
1209
/*
1210
* Add the content of a lesskey source file.
1211
*/
1212
static void add_content_table(int (*call_lesskey)(constant char *, lbool), constant char *envname, lbool sysvar)
1213
{
1214
constant char *content;
1215
1216
(void) call_lesskey; /* not used */
1217
content = lgetenv(envname);
1218
if (isnullenv(content))
1219
return;
1220
lesskey_content(content, sysvar);
1221
}
1222
#endif /* USERFILE */
1223
1224
/*
1225
* See if a char is a special line-editing command.
1226
*/
1227
public int editchar(char c, int flags)
1228
{
1229
int action;
1230
int nch;
1231
constant char *s;
1232
char usercmd[MAX_CMDLEN+1];
1233
1234
/*
1235
* An editing character could actually be a sequence of characters;
1236
* for example, an escape sequence sent by pressing the uparrow key.
1237
* To match the editing string, we use the command decoder
1238
* but give it the edit-commands command table
1239
* This table is constructed to match the user's keyboard.
1240
*/
1241
if (c == erase_char || c == erase2_char)
1242
return (EC_BACKSPACE);
1243
if (c == kill_char)
1244
{
1245
#if MSDOS_COMPILER==WIN32C
1246
if (!win32_kbhit())
1247
#endif
1248
return (EC_LINEKILL);
1249
}
1250
1251
/*
1252
* Collect characters in a buffer.
1253
* Start with the one we have, and get more if we need them.
1254
*/
1255
nch = 0;
1256
do {
1257
if (nch > 0)
1258
c = getcc();
1259
usercmd[nch] = c;
1260
usercmd[nch+1] = '\0';
1261
nch++;
1262
action = ecmd_decode(usercmd, &s);
1263
} while (action == A_PREFIX && nch < MAX_CMDLEN);
1264
1265
if (action == EC_X11MOUSE)
1266
return (x11mouse_action(TRUE));
1267
if (action == EC_X116MOUSE)
1268
return (x116mouse_action(TRUE));
1269
1270
if (flags & ECF_NORIGHTLEFT)
1271
{
1272
switch (action)
1273
{
1274
case EC_RIGHT:
1275
case EC_LEFT:
1276
action = A_INVALID;
1277
break;
1278
}
1279
}
1280
#if CMD_HISTORY
1281
if (flags & ECF_NOHISTORY)
1282
{
1283
/*
1284
* The caller says there is no history list.
1285
* Reject any history-manipulation action.
1286
*/
1287
switch (action)
1288
{
1289
case EC_UP:
1290
case EC_DOWN:
1291
action = A_INVALID;
1292
break;
1293
}
1294
}
1295
#endif
1296
if (flags & ECF_NOCOMPLETE)
1297
{
1298
/*
1299
* The caller says we don't want any filename completion cmds.
1300
* Reject them.
1301
*/
1302
switch (action)
1303
{
1304
case EC_F_COMPLETE:
1305
case EC_B_COMPLETE:
1306
case EC_EXPAND:
1307
action = A_INVALID;
1308
break;
1309
}
1310
}
1311
if ((flags & ECF_PEEK) || action == A_INVALID)
1312
{
1313
/*
1314
* We're just peeking, or we didn't understand the command.
1315
* Unget all the characters we read in the loop above.
1316
* This does NOT include the original character that was
1317
* passed in as a parameter.
1318
*/
1319
while (nch > 1)
1320
{
1321
ungetcc(usercmd[--nch]);
1322
}
1323
} else
1324
{
1325
if (s != NULL)
1326
ungetsc(s);
1327
}
1328
return action;
1329
}
1330
1331
1332