2 * Routines to decode user commands.
4 * This is all table driven.
5 * A command table is a sequence of command descriptors.
6 * Each command descriptor is a sequence of bytes with the following format:
7 * <c1><c2>...<cN><0><action>
8 * The characters c1,c2,...,cN are the command string; that is,
9 * the characters which the user must type.
10 * It is terminated by a null <0> byte.
11 * The byte after the null byte is the action code associated
12 * with the command string.
13 * If an action byte is OR-ed with A_EXTRA, this indicates
14 * that the option byte is followed by an extra string.
16 * There may be many command tables.
17 * The first (default) table is built-in.
18 * Other tables are read in from "lesskey" files.
19 * All the tables are linked together and are searched in order.
30 * Command table is ordered roughly according to expected
31 * frequency of use, so the common commands are near the beginning.
33 static char cmdtable[] =
38 * Note that '\0' is converted to '\200' on input.
40 '\200','\120',0, A_F_LINE, /* down arrow */
41 '\200','\121',0, A_F_SCREEN, /* page down */
42 '\200','\110',0, A_B_LINE, /* up arrow */
43 '\200','\111',0, A_B_SCREEN, /* page up */
44 '\200','\107',0, A_GOLINE, /* home */
45 '\200','\117',0, A_GOEND, /* end */
46 '\200','\073',0, A_HELP, /* F1 */
47 '\200','\104',0, A_MODIFY_WINDOW, /* F10 */
48 '\200','\103',0, A_MODIFY_COLOURS, /* F9 */
54 CONTROL('E'),0, A_F_LINE,
55 CONTROL('N'),0, A_F_LINE,
58 CONTROL('Y'),0, A_B_LINE,
59 CONTROL('K'),0, A_B_LINE,
60 CONTROL('P'),0, A_B_LINE,
65 CONTROL('D'),0, A_F_SCROLL,
67 CONTROL('U'),0, A_B_SCROLL,
70 CONTROL('F'),0, A_F_SCREEN,
71 CONTROL('V'),0, A_F_SCREEN,
73 CONTROL('B'),0, A_B_SCREEN,
74 ESC,'v',0, A_B_SCREEN,
80 CONTROL('R'),0, A_REPAINT,
81 CONTROL('L'),0, A_REPAINT,
87 '{',0, A_F_BRACKET|A_EXTRA, '{','}',0,
88 '}',0, A_B_BRACKET|A_EXTRA, '{','}',0,
89 '(',0, A_F_BRACKET|A_EXTRA, '(',')',0,
90 ')',0, A_B_BRACKET|A_EXTRA, '(',')',0,
91 '[',0, A_F_BRACKET|A_EXTRA, '[',']',0,
92 ']',0, A_B_BRACKET|A_EXTRA, '[',']',0,
93 ESC,CONTROL('F'),0, A_F_BRACKET,
94 ESC,CONTROL('B'),0, A_B_BRACKET,
112 CONTROL('G'),0, A_STAT,
116 ESC,'/',0, A_F_SEARCH|A_EXTRA, '*',0,
117 ESC,'?',0, A_B_SEARCH|A_EXTRA, '*',0,
118 'n',0, A_AGAIN_SEARCH,
119 ESC,'n',0, A_T_AGAIN_SEARCH,
120 'N',0, A_REVERSE_SEARCH,
121 ESC,'N',0, A_T_REVERSE_SEARCH,
124 CONTROL('X'),CONTROL('X'),0, A_GOMARK,
126 ':','e',0, A_EXAMINE,
127 CONTROL('X'),CONTROL('V'),0, A_EXAMINE,
128 ':','n',0, A_NEXT_FILE,
129 ':','p',0, A_PREV_FILE,
130 ':','x',0, A_INDEX_FILE,
132 ':','t',0, A_OPT_TOGGLE|A_EXTRA, 't',0,
133 's',0, A_OPT_TOGGLE|A_EXTRA, 'o',0,
134 '_',0, A_DISP_OPTION,
151 * Structure to support a list of command tables.
155 struct tablelist *t_next;
161 * Structure for the default command table.
163 static struct tablelist deftable =
164 { NULL, cmdtable, cmdtable+sizeof(cmdtable) };
167 * List of tables; initially contains only the default table.
169 static struct tablelist *tables = &deftable;
171 static int cmd_search();
173 extern int erase_char, kill_char;
176 * Decode a command character and return the associated action.
177 * The "extra" string, if any, is returned in sp.
184 register struct tablelist *t;
188 * Search thru all the command tables.
189 * Stop when we find an action which is not A_INVALID.
191 for (t = tables; t != NULL; t = t->t_next)
193 action = cmd_search(cmd, t->t_start, t->t_end, sp);
194 if (action != A_INVALID)
201 * Search a command table for the current command string (in cmd).
204 cmd_search(cmd, table, endtable, sp)
214 for (p = table, q = cmd; p < endtable; p++, q++)
219 * Current characters match.
220 * If we're at the end of the string, we've found it.
221 * Return the action code, which is the character
222 * after the null at the end of the string
223 * in the command table.
229 * Check for an "extra" string.
239 } else if (*q == '\0')
242 * Hit the end of the user's command,
243 * but not the end of the string in the command table.
244 * The user's command is incomplete.
251 * Skip ahead to the next command in the
252 * command table, and reset the pointer
253 * to the beginning of the user's command.
255 while (*p++ != '\0') ;
257 while (*++p != '\0') ;
262 * No match found in the entire command table.
269 * Set up a user command table, based on a "lesskey" file.
272 add_cmdtable(filename)
275 register struct tablelist *t;
276 register POSITION len;
281 * Try to open the lesskey file.
282 * If we can't, return an error.
284 f = open(filename, 0);
289 * Read the file into the user table.
290 * We first figure out the size of the file and allocate space for it.
291 * {{ Minimal error checking is done here.
292 * A garbage .less file will produce strange results.
293 * To avoid a large amount of error checking code here, we
294 * rely on the lesskey program to generate a good .less file. }}
297 if (len == NULL_POSITION || len < 3)
300 * Bad file (valid file must have at least 3 chars).
305 if ((t = (struct tablelist *)
306 calloc(1, sizeof(struct tablelist))) == NULL)
311 if ((t->t_start = (char *) calloc(len, sizeof(char))) == NULL)
317 if (lseek(f, (offset_t)0, 0) == BAD_LSEEK)
324 n = read(f, t->t_start, (unsigned int) len);
328 * In a valid lesskey file, the last byte or
329 * the second to the last byte must be zero.
331 if (n != len || (t->t_start[n-1] != '\0' && t->t_start[n-2] != '\0'))
337 t->t_end = t->t_start + n;
340 * Link it into the list of tables.
348 * Try to add the lesskey file "$HOME/.less"
356 filename = homefile("_less");
358 filename = homefile(".less");
360 if (filename == NULL)
365 (void) add_cmdtable(filename);