"SfR Fresh" - the SfR Freeware/Shareware Archive 
Member "less-424/decode.c" of archive less-424.tar.gz:
As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers.
Alternatively you can here view or download the uninterpreted source code file.
That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
1 /*
2 * Copyright (C) 1984-2008 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 about less, or for information on how to
8 * contact the author, see the README file.
9 */
10
11
12 /*
13 * Routines to decode user commands.
14 *
15 * This is all table driven.
16 * A command table is a sequence of command descriptors.
17 * Each command descriptor is a sequence of bytes with the following format:
18 * <c1><c2>...<cN><0><action>
19 * The characters c1,c2,...,cN are the command string; that is,
20 * the characters which the user must type.
21 * It is terminated by a null <0> byte.
22 * The byte after the null byte is the action code associated
23 * with the command string.
24 * If an action byte is OR-ed with A_EXTRA, this indicates
25 * that the option byte is followed by an extra string.
26 *
27 * There may be many command tables.
28 * The first (default) table is built-in.
29 * Other tables are read in from "lesskey" files.
30 * All the tables are linked together and are searched in order.
31 */
32
33 #include "less.h"
34 #include "cmd.h"
35 #include "lesskey.h"
36
37 extern int erase_char, erase2_char, kill_char;
38 extern int secure;
39
40 #define SK(k) \
41 SK_SPECIAL_KEY, (k), 6, 1, 1, 1
42 /*
43 * Command table is ordered roughly according to expected
44 * frequency of use, so the common commands are near the beginning.
45 */
46
47 static unsigned char cmdtable[] =
48 {
49 '\r',0, A_F_LINE,
50 '\n',0, A_F_LINE,
51 'e',0, A_F_LINE,
52 'j',0, A_F_LINE,
53 SK(SK_DOWN_ARROW),0, A_F_LINE,
54 CONTROL('E'),0, A_F_LINE,
55 CONTROL('N'),0, A_F_LINE,
56 'k',0, A_B_LINE,
57 'y',0, A_B_LINE,
58 CONTROL('Y'),0, A_B_LINE,
59 SK(SK_CONTROL_K),0, A_B_LINE,
60 CONTROL('P'),0, A_B_LINE,
61 SK(SK_UP_ARROW),0, A_B_LINE,
62 'J',0, A_FF_LINE,
63 'K',0, A_BF_LINE,
64 'Y',0, A_BF_LINE,
65 'd',0, A_F_SCROLL,
66 CONTROL('D'),0, A_F_SCROLL,
67 'u',0, A_B_SCROLL,
68 CONTROL('U'),0, A_B_SCROLL,
69 ' ',0, A_F_SCREEN,
70 'f',0, A_F_SCREEN,
71 CONTROL('F'),0, A_F_SCREEN,
72 CONTROL('V'),0, A_F_SCREEN,
73 SK(SK_PAGE_DOWN),0, A_F_SCREEN,
74 'b',0, A_B_SCREEN,
75 CONTROL('B'),0, A_B_SCREEN,
76 ESC,'v',0, A_B_SCREEN,
77 SK(SK_PAGE_UP),0, A_B_SCREEN,
78 'z',0, A_F_WINDOW,
79 'w',0, A_B_WINDOW,
80 ESC,' ',0, A_FF_SCREEN,
81 'F',0, A_F_FOREVER,
82 'R',0, A_FREPAINT,
83 'r',0, A_REPAINT,
84 CONTROL('R'),0, A_REPAINT,
85 CONTROL('L'),0, A_REPAINT,
86 ESC,'u',0, A_UNDO_SEARCH,
87 'g',0, A_GOLINE,
88 SK(SK_HOME),0, A_GOLINE,
89 '<',0, A_GOLINE,
90 ESC,'<',0, A_GOLINE,
91 'p',0, A_PERCENT,
92 '%',0, A_PERCENT,
93 ESC,'[',0, A_LSHIFT,
94 ESC,']',0, A_RSHIFT,
95 ESC,'(',0, A_LSHIFT,
96 ESC,')',0, A_RSHIFT,
97 SK(SK_RIGHT_ARROW),0, A_RSHIFT,
98 SK(SK_LEFT_ARROW),0, A_LSHIFT,
99 '{',0, A_F_BRACKET|A_EXTRA, '{','}',0,
100 '}',0, A_B_BRACKET|A_EXTRA, '{','}',0,
101 '(',0, A_F_BRACKET|A_EXTRA, '(',')',0,
102 ')',0, A_B_BRACKET|A_EXTRA, '(',')',0,
103 '[',0, A_F_BRACKET|A_EXTRA, '[',']',0,
104 ']',0, A_B_BRACKET|A_EXTRA, '[',']',0,
105 ESC,CONTROL('F'),0, A_F_BRACKET,
106 ESC,CONTROL('B'),0, A_B_BRACKET,
107 'G',0, A_GOEND,
108 ESC,'>',0, A_GOEND,
109 '>',0, A_GOEND,
110 SK(SK_END),0, A_GOEND,
111 'P',0, A_GOPOS,
112
113 '0',0, A_DIGIT,
114 '1',0, A_DIGIT,
115 '2',0, A_DIGIT,
116 '3',0, A_DIGIT,
117 '4',0, A_DIGIT,
118 '5',0, A_DIGIT,
119 '6',0, A_DIGIT,
120 '7',0, A_DIGIT,
121 '8',0, A_DIGIT,
122 '9',0, A_DIGIT,
123 '.',0, A_DIGIT,
124
125 '=',0, A_STAT,
126 CONTROL('G'),0, A_STAT,
127 ':','f',0, A_STAT,
128 '/',0, A_F_SEARCH,
129 '?',0, A_B_SEARCH,
130 ESC,'/',0, A_F_SEARCH|A_EXTRA, '*',0,
131 ESC,'?',0, A_B_SEARCH|A_EXTRA, '*',0,
132 'n',0, A_AGAIN_SEARCH,
133 ESC,'n',0, A_T_AGAIN_SEARCH,
134 'N',0, A_REVERSE_SEARCH,
135 ESC,'N',0, A_T_REVERSE_SEARCH,
136 '&',0, A_FILTER,
137 'm',0, A_SETMARK,
138 '\'',0, A_GOMARK,
139 CONTROL('X'),CONTROL('X'),0, A_GOMARK,
140 'E',0, A_EXAMINE,
141 ':','e',0, A_EXAMINE,
142 CONTROL('X'),CONTROL('V'),0, A_EXAMINE,
143 ':','n',0, A_NEXT_FILE,
144 ':','p',0, A_PREV_FILE,
145 't',0, A_NEXT_TAG,
146 'T',0, A_PREV_TAG,
147 ':','x',0, A_INDEX_FILE,
148 ':','d',0, A_REMOVE_FILE,
149 '-',0, A_OPT_TOGGLE,
150 ':','t',0, A_OPT_TOGGLE|A_EXTRA, 't',0,
151 's',0, A_OPT_TOGGLE|A_EXTRA, 'o',0,
152 '_',0, A_DISP_OPTION,
153 '|',0, A_PIPE,
154 'v',0, A_VISUAL,
155 '!',0, A_SHELL,
156 '+',0, A_FIRSTCMD,
157
158 'H',0, A_HELP,
159 'h',0, A_HELP,
160 SK(SK_F1),0, A_HELP,
161 'V',0, A_VERSION,
162 'q',0, A_QUIT,
163 'Q',0, A_QUIT,
164 ':','q',0, A_QUIT,
165 ':','Q',0, A_QUIT,
166 'Z','Z',0, A_QUIT
167 };
168
169 static unsigned char edittable[] =
170 {
171 '\t',0, EC_F_COMPLETE, /* TAB */
172 '\17',0, EC_B_COMPLETE, /* BACKTAB */
173 SK(SK_BACKTAB),0, EC_B_COMPLETE, /* BACKTAB */
174 ESC,'\t',0, EC_B_COMPLETE, /* ESC TAB */
175 CONTROL('L'),0, EC_EXPAND, /* CTRL-L */
176 CONTROL('V'),0, EC_LITERAL, /* BACKSLASH */
177 CONTROL('A'),0, EC_LITERAL, /* BACKSLASH */
178 ESC,'l',0, EC_RIGHT, /* ESC l */
179 SK(SK_RIGHT_ARROW),0, EC_RIGHT, /* RIGHTARROW */
180 ESC,'h',0, EC_LEFT, /* ESC h */
181 SK(SK_LEFT_ARROW),0, EC_LEFT, /* LEFTARROW */
182 ESC,'b',0, EC_W_LEFT, /* ESC b */
183 ESC,SK(SK_LEFT_ARROW),0, EC_W_LEFT, /* ESC LEFTARROW */
184 SK(SK_CTL_LEFT_ARROW),0, EC_W_LEFT, /* CTRL-LEFTARROW */
185 ESC,'w',0, EC_W_RIGHT, /* ESC w */
186 ESC,SK(SK_RIGHT_ARROW),0, EC_W_RIGHT, /* ESC RIGHTARROW */
187 SK(SK_CTL_RIGHT_ARROW),0, EC_W_RIGHT, /* CTRL-RIGHTARROW */
188 ESC,'i',0, EC_INSERT, /* ESC i */
189 SK(SK_INSERT),0, EC_INSERT, /* INSERT */
190 ESC,'x',0, EC_DELETE, /* ESC x */
191 SK(SK_DELETE),0, EC_DELETE, /* DELETE */
192 ESC,'X',0, EC_W_DELETE, /* ESC X */
193 ESC,SK(SK_DELETE),0, EC_W_DELETE, /* ESC DELETE */
194 SK(SK_CTL_DELETE),0, EC_W_DELETE, /* CTRL-DELETE */
195 SK(SK_CTL_BACKSPACE),0, EC_W_BACKSPACE, /* CTRL-BACKSPACE */
196 ESC,'\b',0, EC_W_BACKSPACE, /* ESC BACKSPACE */
197 ESC,'0',0, EC_HOME, /* ESC 0 */
198 SK(SK_HOME),0, EC_HOME, /* HOME */
199 ESC,'$',0, EC_END, /* ESC $ */
200 SK(SK_END),0, EC_END, /* END */
201 ESC,'k',0, EC_UP, /* ESC k */
202 SK(SK_UP_ARROW),0, EC_UP, /* UPARROW */
203 ESC,'j',0, EC_DOWN, /* ESC j */
204 SK(SK_DOWN_ARROW),0, EC_DOWN, /* DOWNARROW */
205 };
206
207 /*
208 * Structure to support a list of command tables.
209 */
210 struct tablelist
211 {
212 struct tablelist *t_next;
213 char *t_start;
214 char *t_end;
215 };
216
217 /*
218 * List of command tables and list of line-edit tables.
219 */
220 static struct tablelist *list_fcmd_tables = NULL;
221 static struct tablelist *list_ecmd_tables = NULL;
222 static struct tablelist *list_var_tables = NULL;
223 static struct tablelist *list_sysvar_tables = NULL;
224
225
226 /*
227 * Expand special key abbreviations in a command table.
228 */
229 static void
230 expand_special_keys(table, len)
231 char *table;
232 int len;
233 {
234 register char *fm;
235 register char *to;
236 register int a;
237 char *repl;
238 int klen;
239
240 for (fm = table; fm < table + len; )
241 {
242 /*
243 * Rewrite each command in the table with any
244 * special key abbreviations expanded.
245 */
246 for (to = fm; *fm != '\0'; )
247 {
248 if (*fm != SK_SPECIAL_KEY)
249 {
250 *to++ = *fm++;
251 continue;
252 }
253 /*
254 * After SK_SPECIAL_KEY, next byte is the type
255 * of special key (one of the SK_* contants),
256 * and the byte after that is the number of bytes,
257 * N, reserved by the abbreviation (including the
258 * SK_SPECIAL_KEY and key type bytes).
259 * Replace all N bytes with the actual bytes
260 * output by the special key on this terminal.
261 */
262 repl = special_key_str(fm[1]);
263 klen = fm[2] & 0377;
264 fm += klen;
265 if (repl == NULL || (int) strlen(repl) > klen)
266 repl = "\377";
267 while (*repl != '\0')
268 *to++ = *repl++;
269 }
270 *to++ = '\0';
271 /*
272 * Fill any unused bytes between end of command and
273 * the action byte with A_SKIP.
274 */
275 while (to <= fm)
276 *to++ = A_SKIP;
277 fm++;
278 a = *fm++ & 0377;
279 if (a & A_EXTRA)
280 {
281 while (*fm++ != '\0')
282 continue;
283 }
284 }
285 }
286
287 /*
288 * Initialize the command lists.
289 */
290 public void
291 init_cmds()
292 {
293 /*
294 * Add the default command tables.
295 */
296 add_fcmd_table((char*)cmdtable, sizeof(cmdtable));
297 add_ecmd_table((char*)edittable, sizeof(edittable));
298 #if USERFILE
299 /*
300 * For backwards compatibility,
301 * try to add tables in the OLD system lesskey file.
302 */
303 #ifdef BINDIR
304 add_hometable(NULL, BINDIR "/.sysless", 1);
305 #endif
306 /*
307 * Try to add the tables in the system lesskey file.
308 */
309 add_hometable("LESSKEY_SYSTEM", LESSKEYFILE_SYS, 1);
310 /*
311 * Try to add the tables in the standard lesskey file "$HOME/.less".
312 */
313 add_hometable("LESSKEY", LESSKEYFILE, 0);
314 #endif
315 }
316
317 /*
318 * Add a command table.
319 */
320 static int
321 add_cmd_table(tlist, buf, len)
322 struct tablelist **tlist;
323 char *buf;
324 int len;
325 {
326 register struct tablelist *t;
327
328 if (len == 0)
329 return (0);
330 /*
331 * Allocate a tablelist structure, initialize it,
332 * and link it into the list of tables.
333 */
334 if ((t = (struct tablelist *)
335 calloc(1, sizeof(struct tablelist))) == NULL)
336 {
337 return (-1);
338 }
339 expand_special_keys(buf, len);
340 t->t_start = buf;
341 t->t_end = buf + len;
342 t->t_next = *tlist;
343 *tlist = t;
344 return (0);
345 }
346
347 /*
348 * Add a command table.
349 */
350 public void
351 add_fcmd_table(buf, len)
352 char *buf;
353 int len;
354 {
355 if (add_cmd_table(&list_fcmd_tables, buf, len) < 0)
356 error("Warning: some commands disabled", NULL_PARG);
357 }
358
359 /*
360 * Add an editing command table.
361 */
362 public void
363 add_ecmd_table(buf, len)
364 char *buf;
365 int len;
366 {
367 if (add_cmd_table(&list_ecmd_tables, buf, len) < 0)
368 error("Warning: some edit commands disabled", NULL_PARG);
369 }
370
371 /*
372 * Add an environment variable table.
373 */
374 static void
375 add_var_table(tlist, buf, len)
376 struct tablelist **tlist;
377 char *buf;
378 int len;
379 {
380 if (add_cmd_table(tlist, buf, len) < 0)
381 error("Warning: environment variables from lesskey file unavailable", NULL_PARG);
382 }
383
384 /*
385 * Search a single command table for the command string in cmd.
386 */
387 static int
388 cmd_search(cmd, table, endtable, sp)
389 char *cmd;
390 char *table;
391 char *endtable;
392 char **sp;
393 {
394 register char *p;
395 register char *q;
396 register int a;
397
398 *sp = NULL;
399 for (p = table, q = cmd; p < endtable; p++, q++)
400 {
401 if (*p == *q)
402 {
403 /*
404 * Current characters match.
405 * If we're at the end of the string, we've found it.
406 * Return the action code, which is the character
407 * after the null at the end of the string
408 * in the command table.
409 */
410 if (*p == '\0')
411 {
412 a = *++p & 0377;
413 while (a == A_SKIP)
414 a = *++p & 0377;
415 if (a == A_END_LIST)
416 {
417 /*
418 * We get here only if the original
419 * cmd string passed in was empty ("").
420 * I don't think that can happen,
421 * but just in case ...
422 */
423 return (A_UINVALID);
424 }
425 /*
426 * Check for an "extra" string.
427 */
428 if (a & A_EXTRA)
429 {
430 *sp = ++p;
431 a &= ~A_EXTRA;
432 }
433 return (a);
434 }
435 } else if (*q == '\0')
436 {
437 /*
438 * Hit the end of the user's command,
439 * but not the end of the string in the command table.
440 * The user's command is incomplete.
441 */
442 return (A_PREFIX);
443 } else
444 {
445 /*
446 * Not a match.
447 * Skip ahead to the next command in the
448 * command table, and reset the pointer
449 * to the beginning of the user's command.
450 */
451 if (*p == '\0' && p[1] == A_END_LIST)
452 {
453 /*
454 * A_END_LIST is a special marker that tells
455 * us to abort the cmd search.
456 */
457 return (A_UINVALID);
458 }
459 while (*p++ != '\0')
460 continue;
461 while (*p == A_SKIP)
462 p++;
463 if (*p & A_EXTRA)
464 while (*++p != '\0')
465 continue;
466 q = cmd-1;
467 }
468 }
469 /*
470 * No match found in the entire command table.
471 */
472 return (A_INVALID);
473 }
474
475 /*
476 * Decode a command character and return the associated action.
477 * The "extra" string, if any, is returned in sp.
478 */
479 static int
480 cmd_decode(tlist, cmd, sp)
481 struct tablelist *tlist;
482 char *cmd;
483 char **sp;
484 {
485 register struct tablelist *t;
486 register int action = A_INVALID;
487
488 /*
489 * Search thru all the command tables.
490 * Stop when we find an action which is not A_INVALID.
491 */
492 for (t = tlist; t != NULL; t = t->t_next)
493 {
494 action = cmd_search(cmd, t->t_start, t->t_end, sp);
495 if (action != A_INVALID)
496 break;
497 }
498 if (action == A_UINVALID)
499 action = A_INVALID;
500 return (action);
501 }
502
503 /*
504 * Decode a command from the cmdtables list.
505 */
506 public int
507 fcmd_decode(cmd, sp)
508 char *cmd;
509 char **sp;
510 {
511 return (cmd_decode(list_fcmd_tables, cmd, sp));
512 }
513
514 /*
515 * Decode a command from the edittables list.
516 */
517 public int
518 ecmd_decode(cmd, sp)
519 char *cmd;
520 char **sp;
521 {
522 return (cmd_decode(list_ecmd_tables, cmd, sp));
523 }
524
525 /*
526 * Get the value of an environment variable.
527 * Looks first in the lesskey file, then in the real environment.
528 */
529 public char *
530 lgetenv(var)
531 char *var;
532 {
533 int a;
534 char *s;
535
536 a = cmd_decode(list_var_tables, var, &s);
537 if (a == EV_OK)
538 return (s);
539 s = getenv(var);
540 if (s != NULL && *s != '\0')
541 return (s);
542 a = cmd_decode(list_sysvar_tables, var, &s);
543 if (a == EV_OK)
544 return (s);
545 return (NULL);
546 }
547
548 #if USERFILE
549 /*
550 * Get an "integer" from a lesskey file.
551 * Integers are stored in a funny format:
552 * two bytes, low order first, in radix KRADIX.
553 */
554 static int
555 gint(sp)
556 char **sp;
557 {
558 int n;
559
560 n = *(*sp)++;
561 n += *(*sp)++ * KRADIX;
562 return (n);
563 }
564
565 /*
566 * Process an old (pre-v241) lesskey file.
567 */
568 static int
569 old_lesskey(buf, len)
570 char *buf;
571 int len;
572 {
573 /*
574 * Old-style lesskey file.
575 * The file must end with either
576 * ...,cmd,0,action
577 * or ...,cmd,0,action|A_EXTRA,string,0
578 * So the last byte or the second to last byte must be zero.
579 */
580 if (buf[len-1] != '\0' && buf[len-2] != '\0')
581 return (-1);
582 add_fcmd_table(buf, len);
583 return (0);
584 }
585
586 /*
587 * Process a new (post-v241) lesskey file.
588 */
589 static int
590 new_lesskey(buf, len, sysvar)
591 char *buf;
592 int len;
593 int sysvar;
594 {
595 char *p;
596 register int c;
597 register int n;
598
599 /*
600 * New-style lesskey file.
601 * Extract the pieces.
602 */
603 if (buf[len-3] != C0_END_LESSKEY_MAGIC ||
604 buf[len-2] != C1_END_LESSKEY_MAGIC ||
605 buf[len-1] != C2_END_LESSKEY_MAGIC)
606 return (-1);
607 p = buf + 4;
608 for (;;)
609 {
610 c = *p++;
611 switch (c)
612 {
613 case CMD_SECTION:
614 n = gint(&p);
615 add_fcmd_table(p, n);
616 p += n;
617 break;
618 case EDIT_SECTION:
619 n = gint(&p);
620 add_ecmd_table(p, n);
621 p += n;
622 break;
623 case VAR_SECTION:
624 n = gint(&p);
625 add_var_table((sysvar) ?
626 &list_sysvar_tables : &list_var_tables, p, n);
627 p += n;
628 break;
629 case END_SECTION:
630 return (0);
631 default:
632 /*
633 * Unrecognized section type.
634 */
635 return (-1);
636 }
637 }
638 }
639
640 /*
641 * Set up a user command table, based on a "lesskey" file.
642 */
643 public int
644 lesskey(filename, sysvar)
645 char *filename;
646 int sysvar;
647 {
648 register char *buf;
649 register POSITION len;
650 register long n;
651 register int f;
652
653 if (secure)
654 return (1);
655 /*
656 * Try to open the lesskey file.
657 */
658 filename = shell_unquote(filename);
659 f = open(filename, OPEN_READ);
660 free(filename);
661 if (f < 0)
662 return (1);
663
664 /*
665 * Read the file into a buffer.
666 * We first figure out the size of the file and allocate space for it.
667 * {{ Minimal error checking is done here.
668 * A garbage .less file will produce strange results.
669 * To avoid a large amount of error checking code here, we
670 * rely on the lesskey program to generate a good .less file. }}
671 */
672 len = filesize(f);
673 if (len == NULL_POSITION || len < 3)
674 {
675 /*
676 * Bad file (valid file must have at least 3 chars).
677 */
678 close(f);
679 return (-1);
680 }
681 if ((buf = (char *) calloc((int)len, sizeof(char))) == NULL)
682 {
683 close(f);
684 return (-1);
685 }
686 if (lseek(f, (off_t)0, SEEK_SET) == BAD_LSEEK)
687 {
688 free(buf);
689 close(f);
690 return (-1);
691 }
692 n = read(f, buf, (unsigned int) len);
693 close(f);
694 if (n != len)
695 {
696 free(buf);
697 return (-1);
698 }
699
700 /*
701 * Figure out if this is an old-style (before version 241)
702 * or new-style lesskey file format.
703 */
704 if (buf[0] != C0_LESSKEY_MAGIC || buf[1] != C1_LESSKEY_MAGIC ||
705 buf[2] != C2_LESSKEY_MAGIC || buf[3] != C3_LESSKEY_MAGIC)
706 return (old_lesskey(buf, (int)len));
707 return (new_lesskey(buf, (int)len, sysvar));
708 }
709
710 /*
711 * Add the standard lesskey file "$HOME/.less"
712 */
713 public void
714 add_hometable(envname, def_filename, sysvar)
715 char *envname;
716 char *def_filename;
717 int sysvar;
718 {
719 char *filename;
720 PARG parg;
721
722 if (envname != NULL && (filename = lgetenv(envname)) != NULL)
723 filename = save(filename);
724 else if (sysvar)
725 filename = save(def_filename);
726 else
727 filename = homefile(def_filename);
728 if (filename == NULL)
729 return;
730 if (lesskey(filename, sysvar) < 0)
731 {
732 parg.p_string = filename;
733 error("Cannot use lesskey file \"%s\"", &parg);
734 }
735 free(filename);
736 }
737 #endif
738
739 /*
740 * See if a char is a special line-editing command.
741 */
742 public int
743 editchar(c, flags)
744 int c;
745 int flags;
746 {
747 int action;
748 int nch;
749 char *s;
750 char usercmd[MAX_CMDLEN+1];
751
752 /*
753 * An editing character could actually be a sequence of characters;
754 * for example, an escape sequence sent by pressing the uparrow key.
755 * To match the editing string, we use the command decoder
756 * but give it the edit-commands command table
757 * This table is constructed to match the user's keyboard.
758 */
759 if (c == erase_char || c == erase2_char)
760 return (EC_BACKSPACE);
761 if (c == kill_char)
762 return (EC_LINEKILL);
763
764 /*
765 * Collect characters in a buffer.
766 * Start with the one we have, and get more if we need them.
767 */
768 nch = 0;
769 do {
770 if (nch > 0)
771 c = getcc();
772 usercmd[nch] = c;
773 usercmd[nch+1] = '\0';
774 nch++;
775 action = ecmd_decode(usercmd, &s);
776 } while (action == A_PREFIX);
777
778 if (flags & EC_NORIGHTLEFT)
779 {
780 switch (action)
781 {
782 case EC_RIGHT:
783 case EC_LEFT:
784 action = A_INVALID;
785 break;
786 }
787 }
788 #if CMD_HISTORY
789 if (flags & EC_NOHISTORY)
790 {
791 /*
792 * The caller says there is no history list.
793 * Reject any history-manipulation action.
794 */
795 switch (action)
796 {
797 case EC_UP:
798 case EC_DOWN:
799 action = A_INVALID;
800 break;
801 }
802 }
803 #endif
804 #if TAB_COMPLETE_FILENAME
805 if (flags & EC_NOCOMPLETE)
806 {
807 /*
808 * The caller says we don't want any filename completion cmds.
809 * Reject them.
810 */
811 switch (action)
812 {
813 case EC_F_COMPLETE:
814 case EC_B_COMPLETE:
815 case EC_EXPAND:
816 action = A_INVALID;
817 break;
818 }
819 }
820 #endif
821 if ((flags & EC_PEEK) || action == A_INVALID)
822 {
823 /*
824 * We're just peeking, or we didn't understand the command.
825 * Unget all the characters we read in the loop above.
826 * This does NOT include the original character that was
827 * passed in as a parameter.
828 */
829 while (nch > 1)
830 {
831 ungetcc(usercmd[--nch]);
832 }
833 } else
834 {
835 if (s != NULL)
836 ungetsc(s);
837 }
838 return action;
839 }
840