1 /* ----------------------------------------------------------------------- *
3 * Copyright 2009 Erwan Velu - All Rights Reserved
5 * Permission is hereby granted, free of charge, to any person
6 * obtaining a copy of this software and associated documentation
7 * files (the "Software"), to deal in the Software without
8 * restriction, including without limitation the rights to use,
9 * copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom
11 * the Software is furnished to do so, subject to the following
14 * The above copyright notice and this permission notice shall
15 * be included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 * OTHER DEALINGS IN THE SOFTWARE.
26 * -----------------------------------------------------------------------
31 #include <syslinux/config.h>
34 #include "hdt-common.h"
36 struct cli_mode_descr
*list_modes
[] = {
52 * .aliases = {"q", "quit"} won't work since it is an array of pointers, not an
53 * array of variables. There is no easy way around it besides declaring the arrays of
56 const char *exit_aliases
[] = { "q", "quit" };
57 const char *help_aliases
[] = { "h", "?" };
60 struct cli_alias hdt_aliases
[] = {
64 .aliases
= exit_aliases
,
69 .aliases
= help_aliases
,
73 struct cli_mode_descr
*current_mode
;
74 int autocomplete_backlog
;
76 struct autocomplete_list
{
77 char autocomplete_token
[MAX_LINE_SIZE
];
78 struct autocomplete_list
*next
;
80 struct autocomplete_list
*autocomplete_head
= NULL
;
81 struct autocomplete_list
*autocomplete_tail
= NULL
;
82 struct autocomplete_list
*autocomplete_last_seen
= NULL
;
84 static void autocomplete_add_token_to_list(const char *token
)
86 struct autocomplete_list
*new = malloc(sizeof(struct autocomplete_list
));
88 strlcpy(new->autocomplete_token
, token
, sizeof(new->autocomplete_token
));
90 autocomplete_backlog
++;
92 if (autocomplete_tail
!= NULL
)
93 autocomplete_tail
->next
= new;
94 if (autocomplete_head
== NULL
)
95 autocomplete_head
= new;
96 autocomplete_tail
= new;
99 static void autocomplete_destroy_list(void)
101 struct autocomplete_list
*tmp
= NULL
;
103 while (autocomplete_head
!= NULL
) {
104 tmp
= autocomplete_head
->next
;
105 free(autocomplete_head
);
106 autocomplete_head
= tmp
;
108 autocomplete_backlog
= 0;
109 autocomplete_tail
= NULL
;
110 autocomplete_last_seen
= NULL
;
114 * set_mode - set the current mode of the cli
117 * Unlike cli_set_mode, this function is not used by the cli directly.
119 void set_mode(cli_mode_t mode
, struct s_hardware
*hardware
)
129 snprintf(hdt_cli
.prompt
, sizeof(hdt_cli
.prompt
), "%s> ", CLI_HDT
);
132 if (hardware
->sv
->filesystem
!= SYSLINUX_FS_PXELINUX
) {
133 printf("You are not currently using PXELINUX\n");
137 snprintf(hdt_cli
.prompt
, sizeof(hdt_cli
.prompt
), "%s> ", CLI_PXE
);
140 detect_pci(hardware
);
142 snprintf(hdt_cli
.prompt
, sizeof(hdt_cli
.prompt
), "%s> ", CLI_KERNEL
);
146 snprintf(hdt_cli
.prompt
, sizeof(hdt_cli
.prompt
), "%s> ", CLI_SYSLINUX
);
150 snprintf(hdt_cli
.prompt
, sizeof(hdt_cli
.prompt
), "%s> ", CLI_VESA
);
154 snprintf(hdt_cli
.prompt
, sizeof(hdt_cli
.prompt
), "%s> ", CLI_PCI
);
155 if (!hardware
->pci_detection
)
156 cli_detect_pci(hardware
);
160 snprintf(hdt_cli
.prompt
, sizeof(hdt_cli
.prompt
), "%s> ", CLI_CPU
);
161 if (!hardware
->dmi_detection
)
162 detect_dmi(hardware
);
163 if (!hardware
->cpu_detection
)
164 cpu_detect(hardware
);
167 detect_dmi(hardware
);
168 if (!hardware
->is_dmi_valid
) {
169 printf("No valid DMI table found, exiting.\n");
173 snprintf(hdt_cli
.prompt
, sizeof(hdt_cli
.prompt
), "%s> ", CLI_DMI
);
176 detect_disks(hardware
);
178 snprintf(hdt_cli
.prompt
, sizeof(hdt_cli
.prompt
), "%s> ", CLI_DISK
);
181 detect_vpd(hardware
);
182 if (!hardware
->is_vpd_valid
) {
183 printf("No valid VPD table found, exiting.\n");
187 snprintf(hdt_cli
.prompt
, sizeof(hdt_cli
.prompt
), "%s> ", CLI_VPD
);
191 snprintf(hdt_cli
.prompt
, sizeof(hdt_cli
.prompt
), "%s> ", CLI_MEMORY
);
195 printf("Unknown mode, please choose among:\n");
196 while (list_modes
[i
]) {
197 printf("\t%s\n", list_modes
[i
]->name
);
202 find_cli_mode_descr(hdt_cli
.mode
, ¤t_mode
);
203 /* There is not cli_mode_descr struct for the exit mode */
204 if (current_mode
== NULL
&& hdt_cli
.mode
!= EXIT_MODE
) {
205 /* Shouldn't get here... */
206 printf("!!! BUG: Mode '%d' unknown.\n", hdt_cli
.mode
);
211 * mode_s_to_mode_t - given a mode string, return the cli_mode_t representation
213 cli_mode_t
mode_s_to_mode_t(char *name
)
217 while (list_modes
[i
]) {
218 if (!strncmp(name
, list_modes
[i
]->name
, sizeof(list_modes
[i
]->name
)))
226 return list_modes
[i
]->mode
;
230 * find_cli_mode_descr - find the cli_mode_descr struct associated to a mode
231 * @mode: mode to look for
232 * @mode_found: store the mode if found, NULL otherwise
234 * Given a mode name, return a pointer to the associated cli_mode_descr
236 * Note: the current mode name is stored in hdt_cli.mode.
238 void find_cli_mode_descr(cli_mode_t mode
, struct cli_mode_descr
**mode_found
)
242 while (list_modes
[i
] && list_modes
[i
]->mode
!= mode
)
245 /* Shouldn't get here... */
249 *mode_found
= list_modes
[i
];
253 * expand_aliases - resolve aliases mapping
254 * @line: command line to parse
255 * @command: first token in the line
256 * @module: second token in the line
257 * @argc: number of arguments
258 * @argv: array of arguments
260 * We maintain a small list of static alises to enhance user experience.
261 * Only commands can be aliased (first token). Otherwise it can become really hairy...
263 static void expand_aliases(char *line __unused
, char **command
, char **module
,
264 int *argc
, char **argv
)
266 struct cli_mode_descr
*mode
;
269 find_cli_mode_descr(mode_s_to_mode_t(*command
), &mode
);
270 if (mode
!= NULL
&& *module
== NULL
) {
272 * The user specified a mode instead of `set mode...', e.g.
273 * `dmi' instead of `set mode dmi'
276 /* *argv is NULL since *module is NULL */
278 *argv
= malloc(*argc
* sizeof(char *));
279 argv
[0] = malloc((sizeof(*command
) + 1) * sizeof(char));
280 strlcpy(argv
[0], *command
, sizeof(*command
) + 1);
281 dprintf("CLI DEBUG: ALIAS %s ", *command
);
283 strlcpy(*command
, CLI_SET
, sizeof(CLI_SET
)); /* set */
285 *module
= malloc(sizeof(CLI_MODE
) * sizeof(char));
286 strlcpy(*module
, CLI_MODE
, sizeof(CLI_MODE
)); /* mode */
288 dprintf("--> %s %s %s\n", *command
, *module
, argv
[0]);
292 /* Simple aliases mapping a single command to another one */
293 for (i
= 0; i
< MAX_ALIASES
; i
++) {
294 for (j
= 0; j
< hdt_aliases
[i
].nb_aliases
; j
++) {
295 if (!strncmp(*command
, hdt_aliases
[i
].aliases
[j
],
296 sizeof(hdt_aliases
[i
].aliases
[j
]))) {
297 dprintf("CLI DEBUG: ALIAS %s ", *command
);
298 strlcpy(*command
, hdt_aliases
[i
].command
,
299 sizeof(hdt_aliases
[i
].command
) + 1);
300 dprintf("--> %s\n", *command
);
301 goto out
; /* Don't allow chaining aliases */
308 dprintf("CLI DEBUG: New parameters:\n");
309 dprintf("CLI DEBUG: command = %s\n", *command
);
310 dprintf("CLI DEBUG: module = %s\n", *module
);
311 dprintf("CLI DEBUG: argc = %d\n", *argc
);
312 for (i
= 0; i
< *argc
; i
++)
313 dprintf("CLI DEBUG: argv[%d] = %s\n", i
, argv
[0]);
318 * parse_command_line - low level parser for the command line
319 * @line: command line to parse
320 * @command: first token in the line
321 * @module: second token in the line
322 * @argc: number of arguments
323 * @argv: array of arguments
325 * The format of the command line is:
326 * <main command> [<module on which to operate> [<args>]]
327 * command is always malloc'ed (even for an empty line)
329 static void parse_command_line(char *line
, char **command
, char **module
,
330 int *argc
, char **argv
)
332 int argc_iter
= 0, args_pos
= 0, token_found
= 0, token_len
= 0;
334 char *pch
= NULL
, *pch_next
= NULL
, *tmp_pch_next
= NULL
;
341 while (pch
!= NULL
) {
342 pch_next
= strchr(pch
+ 1, ' ');
343 tmp_pch_next
= pch_next
;
346 * Skip whitespaces if the user entered
347 * 'set mode foo' for 'set mode foo'
350 * |___ pch_next <- wrong!
352 * We still keep the position into tmp_pch_next to compute
353 * the lenght of the current token.
355 while (pch_next
!= NULL
&& !strncmp(pch_next
, CLI_SPACE
, 1))
358 /* End of line guaranteed to be zeroed */
359 if (pch_next
== NULL
) {
360 token_len
= (int)(strchr(pch
+ 1, '\0') - pch
);
361 args_len
= token_len
;
363 token_len
= (int)(tmp_pch_next
- pch
);
364 args_len
= (int)(pch_next
- pch
);
367 if (token_found
== 0) {
368 /* Main command to execute */
369 *command
= malloc((token_len
+ 1) * sizeof(char));
370 strlcpy(*command
, pch
, token_len
);
371 (*command
)[token_len
] = '\0';
372 dprintf("CLI DEBUG: command = %s\n", *command
);
373 args_pos
+= args_len
;
374 } else if (token_found
== 1) {
376 *module
= malloc((token_len
+ 1) * sizeof(char));
377 strlcpy(*module
, pch
, token_len
);
378 (*module
)[token_len
] = '\0';
379 dprintf("CLI DEBUG: module = %s\n", *module
);
380 args_pos
+= args_len
;
387 dprintf("CLI DEBUG: argc = %d\n", *argc
);
389 /* Skip arguments handling if none is supplied */
393 /* Transform the arguments string into an array */
394 *argv
= malloc(*argc
* sizeof(char *));
395 pch
= strtok(line
+ args_pos
, CLI_SPACE
);
396 while (pch
!= NULL
) {
397 dprintf("CLI DEBUG: argv[%d] = %s\n", argc_iter
, pch
);
398 argv
[argc_iter
] = malloc(sizeof(pch
) * sizeof(char));
399 strlcpy(argv
[argc_iter
], pch
, sizeof(pch
));
401 pch
= strtok(NULL
, CLI_SPACE
);
403 * strtok(NULL, CLI_SPACE) over a stream of spaces
404 * will return an empty string
406 while (pch
!= NULL
&& !strncmp(pch
, "", 1))
407 pch
= strtok(NULL
, CLI_SPACE
);
412 * find_cli_callback_descr - find a callback in a list of modules
413 * @module_name: Name of the module to find
414 * @modules_list: Lits of modules among which to find @module_name
415 * @module_found: Pointer to the matched module, NULL if not found
417 * Given a module name and a list of possible modules, find the corresponding
418 * module structure that matches the module name and store it in @module_found.
420 void find_cli_callback_descr(const char *module_name
,
421 struct cli_module_descr
*modules_list
,
422 struct cli_callback_descr
**module_found
)
424 int modules_iter
= 0;
426 if (modules_list
== NULL
)
429 /* Find the callback to execute */
430 while (modules_list
->modules
[modules_iter
].name
&&
431 strcmp(module_name
, modules_list
->modules
[modules_iter
].name
) != 0)
434 if (modules_list
->modules
[modules_iter
].name
) {
435 *module_found
= &(modules_list
->modules
[modules_iter
]);
436 dprintf("CLI DEBUG: module %s found\n", (*module_found
)->name
);
441 *module_found
= NULL
;
446 * autocomplete_command - print matching commands
447 * @command: Beginning of the command
449 * Given a string @command, print all availables commands starting with
450 * @command. Commands are found within the list of commands for the current
451 * mode and the hdt mode (if the current mode is not hdt).
453 static void autocomplete_command(char *command
)
456 struct cli_callback_descr
*associated_module
= NULL
;
458 /* First take care of the two special commands: 'show' and 'set' */
459 if (strncmp(CLI_SHOW
, command
, strlen(command
)) == 0) {
460 printf("%s\n", CLI_SHOW
);
461 autocomplete_add_token_to_list(CLI_SHOW
);
463 if (strncmp(CLI_SET
, command
, strlen(command
)) == 0) {
464 printf("%s\n", CLI_SET
);
465 autocomplete_add_token_to_list(CLI_SET
);
469 * Then, go through the modes for the special case
470 * '<mode>' -> 'set mode <mode>'
472 while (list_modes
[j
]) {
473 if (strncmp(list_modes
[j
]->name
, command
, strlen(command
)) == 0) {
474 printf("%s\n", list_modes
[j
]->name
);
475 autocomplete_add_token_to_list(list_modes
[j
]->name
);
481 * Let's go now through the list of default_modules for the current mode
482 * (single token commands for the current_mode)
485 if (current_mode
->default_modules
&& current_mode
->default_modules
->modules
) {
486 while (current_mode
->default_modules
->modules
[j
].name
) {
487 if (strncmp(current_mode
->default_modules
->modules
[j
].name
,
488 command
, strlen(command
)) == 0) {
489 printf("%s\n", current_mode
->default_modules
->modules
[j
].name
);
490 autocomplete_add_token_to_list(current_mode
->default_modules
->
498 * Finally, if the current_mode is not hdt, list the available
499 * default_modules of hdt (these are always available from any mode).
501 if (current_mode
->mode
== HDT_MODE
)
504 if (!hdt_mode
.default_modules
|| !hdt_mode
.default_modules
->modules
)
508 while (hdt_mode
.default_modules
&&
509 hdt_mode
.default_modules
->modules
[j
].name
) {
511 * Any default command that is present in hdt mode but
512 * not in the current mode is available. A default
513 * command can be redefined in the current mode though.
514 * This next call tests this use case: if it is
515 * overwritten, do not print it again.
517 find_cli_callback_descr(hdt_mode
.default_modules
->modules
[j
].name
,
518 current_mode
->default_modules
,
520 if (associated_module
== NULL
&&
522 hdt_mode
.default_modules
->modules
[j
].name
,
523 strlen(command
)) == 0) {
524 printf("%s\n", hdt_mode
.default_modules
->modules
[j
].name
);
525 autocomplete_add_token_to_list(hdt_mode
.default_modules
->modules
[j
].
533 * autocomplete_module - print matching modules
534 * @command: Command on the command line (not NULL)
535 * @module: Beginning of the module
537 * Given a command @command and a string @module, print all availables modules
538 * starting with @module for command @command. Commands are found within the
539 * list of commands for the current mode and the hdt mode (if the current mode
542 static void autocomplete_module(char *command
, char *module
)
545 char autocomplete_full_line
[MAX_LINE_SIZE
];
547 if (strncmp(CLI_SHOW
, command
, strlen(command
)) == 0) {
548 if (!current_mode
->show_modules
|| !current_mode
->show_modules
->modules
)
551 while (current_mode
->show_modules
->modules
[j
].name
) {
552 if (strncmp(current_mode
->show_modules
->modules
[j
].name
,
553 module
, strlen(module
)) == 0) {
554 printf("%s\n", current_mode
->show_modules
->modules
[j
].name
);
555 sprintf(autocomplete_full_line
, "%s %s",
556 CLI_SHOW
, current_mode
->show_modules
->modules
[j
].name
);
557 autocomplete_add_token_to_list(autocomplete_full_line
);
561 } else if (strncmp(CLI_SET
, command
, strlen(command
)) == 0) {
563 if (!current_mode
->set_modules
|| !current_mode
->set_modules
->modules
)
566 while (current_mode
->set_modules
->modules
[j
].name
) {
567 if (strncmp(current_mode
->set_modules
->modules
[j
].name
,
568 module
, strlen(module
)) == 0) {
569 printf("%s\n", current_mode
->set_modules
->modules
[j
].name
);
570 sprintf(autocomplete_full_line
, "%s %s",
571 CLI_SET
, current_mode
->set_modules
->modules
[j
].name
);
572 autocomplete_add_token_to_list(autocomplete_full_line
);
580 * autocomplete - find possible matches for a command line
581 * @line: command line to parse
583 static void autocomplete(char *line
)
587 char *command
= NULL
, *module
= NULL
;
590 parse_command_line(line
, &command
, &module
, &argc
, argv
);
592 /* If the user specified arguments, there is nothing we can complete */
596 /* No argument, (the start of) a module has been specified */
597 if (module
!= NULL
) {
598 autocomplete_module(command
, module
);
603 /* No argument, no module, (the start of) a command has been specified */
604 if (command
!= NULL
) {
605 autocomplete_command(command
);
611 /* Let's not forget to clean ourselves */
612 for (i
= 0; i
< argc
; i
++)
620 * exec_command - main logic to map the command line to callbacks
622 static void exec_command(char *line
, struct s_hardware
*hardware
)
625 char *command
= NULL
, *module
= NULL
;
627 struct cli_callback_descr
*current_module
= NULL
;
629 /* This will allocate memory for command and module */
630 parse_command_line(line
, &command
, &module
, &argc
, argv
);
633 * Expand shortcuts, if needed
634 * This will allocate memory for argc/argv
636 expand_aliases(line
, &command
, &module
, &argc
, argv
);
638 if (module
== NULL
) {
639 dprintf("CLI DEBUG: single command detected\n");
641 * A single word was specified: look at the list of default
642 * commands in the current mode to see if there is a match.
643 * If not, it may be a generic function (exit, help, ...). These
644 * are stored in the list of default commands of the hdt mode.
646 find_cli_callback_descr(command
, current_mode
->default_modules
,
648 if (current_module
!= NULL
)
649 current_module
->exec(argc
, argv
, hardware
);
650 else if (!strncmp(command
, CLI_SHOW
, sizeof(CLI_SHOW
) - 1) &&
651 current_mode
->show_modules
!= NULL
&&
652 current_mode
->show_modules
->default_callback
!= NULL
)
653 current_mode
->show_modules
->default_callback(argc
, argv
, hardware
);
654 else if (!strncmp(command
, CLI_SET
, sizeof(CLI_SET
) - 1) &&
655 current_mode
->set_modules
!= NULL
&&
656 current_mode
->set_modules
->default_callback
!= NULL
)
657 current_mode
->set_modules
->default_callback(argc
, argv
, hardware
);
659 find_cli_callback_descr(command
, hdt_mode
.default_modules
,
661 if (current_module
!= NULL
)
662 current_module
->exec(argc
, argv
, hardware
);
664 printf("unknown command: '%s'\n", command
);
668 * A module has been specified! We now need to find the type of command.
670 * The syntax of the cli is the following:
671 * <type of command> <module on which to operate> <args>
675 * dmi> show memory 0 1
676 * pci> show device 12
679 if (!strncmp(command
, CLI_SHOW
, sizeof(CLI_SHOW
) - 1)) {
680 dprintf("CLI DEBUG: %s command detected\n", CLI_SHOW
);
681 /* Look first for a 'show' callback in the current mode */
682 find_cli_callback_descr(module
, current_mode
->show_modules
,
684 /* Execute the callback, if found */
685 if (current_module
!= NULL
)
686 current_module
->exec(argc
, argv
, hardware
);
688 /* Look now for a 'show' callback in the hdt mode */
689 find_cli_callback_descr(module
, hdt_mode
.show_modules
,
691 /* Execute the callback, if found */
692 if (current_module
!= NULL
)
693 current_module
->exec(argc
, argv
, hardware
);
695 printf("unknown module: '%s'\n", module
);
697 } else if (!strncmp(command
, CLI_SET
, sizeof(CLI_SET
) - 1)) {
698 dprintf("CLI DEBUG: %s command detected\n", CLI_SET
);
699 /* Look now for a 'set' callback in the hdt mode */
700 find_cli_callback_descr(module
, current_mode
->set_modules
,
702 /* Execute the callback, if found */
703 if (current_module
!= NULL
)
704 current_module
->exec(argc
, argv
, hardware
);
706 /* Look now for a 'set' callback in the hdt mode */
707 find_cli_callback_descr(module
, hdt_mode
.set_modules
,
709 /* Execute the callback, if found */
710 if (current_module
!= NULL
)
711 current_module
->exec(argc
, argv
, hardware
);
713 printf("unknown module: '%s'\n", module
);
718 /* Let's not forget to clean ourselves */
723 for (i
= 0; i
< argc
; i
++)
729 static void reset_prompt(void)
731 /* No need to display the prompt if we exit */
732 if (hdt_cli
.mode
!= EXIT_MODE
) {
733 printf("%s", hdt_cli
.prompt
);
735 hdt_cli
.cursor_pos
= 0;
739 void start_auto_mode(struct s_hardware
*hardware
)
743 char *commands
[MAX_NB_AUTO_COMMANDS
];
746 more_printf("\nEntering Auto mode\n");
748 /* Protecting the auto_label from the strtok modifications */
749 char *temp
= strdup(hardware
->auto_label
);
751 /* Searching & saving all commands */
752 mypch
= strtok(temp
, AUTO_SEPARATOR
);
753 while (mypch
!= NULL
) {
754 if ((strlen(remove_spaces(mypch
)) > 0) &&
755 (remove_spaces(mypch
)[0] != AUTO_SEPARATOR
[0])) {
757 if ((commands
[nb_commands
] = malloc(AUTO_COMMAND_SIZE
)) != NULL
) {
758 sprintf(commands
[nb_commands
], "%s", remove_spaces(mypch
));
762 mypch
= strtok(NULL
, AUTO_SEPARATOR
);
765 /* Executing found commands */
766 for (int i
= 1; i
<= nb_commands
; i
++) {
769 more_printf("%s%s\n", hdt_cli
.prompt
, commands
[i
]);
770 exec_command(commands
[i
], hardware
);
776 more_printf("\nExiting Auto mode\n");
781 void print_history(int argc
, char **argv
, struct s_hardware
* hardware
)
788 for (int i
= 1; i
<= MAX_HISTORY_SIZE
; i
++) {
789 if (i
== hdt_cli
.history_pos
) {
790 more_printf("*%d:'%s'\n", i
, hdt_cli
.history
[i
]);
793 if (strlen(hdt_cli
.history
[i
]) == 0)
795 more_printf(" %d:'%s'\n", i
, hdt_cli
.history
[i
]);
799 /* Code that manages the cli mode */
800 void start_cli_mode(struct s_hardware
*hardware
)
803 int future_history_pos
= 1; /* position of the next position in the history */
804 int current_future_history_pos
= 1; /* Temp variable */
805 bool display_history
= true; /* Temp Variable */
806 char temp_command
[MAX_LINE_SIZE
];
808 hdt_cli
.cursor_pos
= 0;
809 memset(hdt_cli
.history
, 0, sizeof(hdt_cli
.history
));
810 hdt_cli
.history_pos
= 1;
811 hdt_cli
.max_history_pos
= 1;
813 /* Find the mode selected */
814 set_mode(HDT_MODE
, hardware
);
815 find_cli_mode_descr(hdt_cli
.mode
, ¤t_mode
);
816 if (current_mode
== NULL
) {
817 /* Shouldn't get here... */
818 printf("!!! BUG: Mode '%d' unknown.\n", hdt_cli
.mode
);
822 /* Start the auto mode if the command line is set */
823 if (strlen(hardware
->auto_label
) > 0) {
824 start_auto_mode(hardware
);
827 printf("Entering CLI mode\n");
831 while (hdt_cli
.mode
!= EXIT_MODE
) {
833 /* Display the cursor */
834 display_cursor(true);
836 /* Let's put the cursor blinking until we get an input */
837 set_cursor_blink(true);
839 /* We wait endlessly for a keyboard input */
840 current_key
= get_key(stdin
, 0);
842 /* We have to cancel the blinking mode to prevent
843 * input text to blink */
844 set_cursor_blink(false);
846 /* Reset autocomplete buffer unless TAB is pressed */
847 if (current_key
!= KEY_TAB
)
848 autocomplete_destroy_list();
850 switch (current_key
) {
851 /* clear until then end of line */
853 /* Clear the end of the line */
855 memset(&INPUT
[hdt_cli
.cursor_pos
], 0,
856 strlen(INPUT
) - hdt_cli
.cursor_pos
);
865 if (hdt_cli
.cursor_pos
> 0) {
867 hdt_cli
.cursor_pos
--;
872 if (hdt_cli
.cursor_pos
< (int)strlen(INPUT
)) {
873 move_cursor_right(1);
874 hdt_cli
.cursor_pos
++;
880 /* Calling with a 0 value will make the cursor move */
881 /* So, let's move the cursor only if needed */
882 if ((strlen(INPUT
) - hdt_cli
.cursor_pos
) > 0) {
883 /* Return to the begining of line */
884 move_cursor_right(strlen(INPUT
) - hdt_cli
.cursor_pos
);
885 hdt_cli
.cursor_pos
= strlen(INPUT
);
891 /* Calling with a 0 value will make the cursor move */
892 /* So, let's move the cursor only if needed */
893 if (hdt_cli
.cursor_pos
> 0) {
894 /* Return to the begining of line */
895 move_cursor_left(hdt_cli
.cursor_pos
);
896 hdt_cli
.cursor_pos
= 0;
902 /* Saving future position */
903 current_future_history_pos
= future_history_pos
;
905 /* We have to compute the next position */
906 if (future_history_pos
== 1) {
907 future_history_pos
= MAX_HISTORY_SIZE
;
909 future_history_pos
--;
912 /* Does the next position is valid */
913 if (strlen(hdt_cli
.history
[future_history_pos
]) == 0) {
914 /* Position is invalid, restoring position */
915 future_history_pos
= current_future_history_pos
;
919 /* Let's make that future position the one we use */
920 memset(INPUT
, 0, sizeof(INPUT
));
921 strlcpy(INPUT
, hdt_cli
.history
[future_history_pos
], sizeof(INPUT
));
926 /* Move to the begining of line */
927 move_cursor_to_column(0);
931 hdt_cli
.cursor_pos
= strlen(INPUT
);
935 display_history
= true;
937 /* Saving future position */
938 current_future_history_pos
= future_history_pos
;
940 if (future_history_pos
== MAX_HISTORY_SIZE
) {
941 future_history_pos
= 1;
943 future_history_pos
++;
946 /* Does the next position is valid */
947 if (strlen(hdt_cli
.history
[future_history_pos
]) == 0)
948 display_history
= false;
950 /* An exception is made to reach the last empty line */
951 if (future_history_pos
== hdt_cli
.max_history_pos
)
952 display_history
= true;
954 if (display_history
== false) {
955 /* Position is invalid, restoring position */
956 future_history_pos
= current_future_history_pos
;
960 /* Let's make that future position the one we use */
961 memset(INPUT
, 0, sizeof(INPUT
));
962 strlcpy(INPUT
, hdt_cli
.history
[future_history_pos
], sizeof(INPUT
));
967 /* Move to the begining of line */
968 move_cursor_to_column(0);
972 hdt_cli
.cursor_pos
= strlen(INPUT
);
976 if (autocomplete_backlog
) {
978 /* Move to the begining of line */
979 move_cursor_to_column(0);
981 printf("%s", autocomplete_last_seen
->autocomplete_token
);
983 autocomplete_last_seen
->autocomplete_token
,
985 hdt_cli
.cursor_pos
= strlen(INPUT
);
987 /* Cycle through the list */
988 autocomplete_last_seen
= autocomplete_last_seen
->next
;
989 if (autocomplete_last_seen
== NULL
)
990 autocomplete_last_seen
= autocomplete_head
;
993 autocomplete(skip_spaces(INPUT
));
994 autocomplete_last_seen
= autocomplete_head
;
996 printf("%s%s", hdt_cli
.prompt
, INPUT
);
1002 if (strlen(remove_spaces(INPUT
)) < 1) {
1006 exec_command(remove_spaces(INPUT
), hardware
);
1007 hdt_cli
.history_pos
++;
1009 /* Did we reach the end of the history ?*/
1010 if (hdt_cli
.history_pos
> MAX_HISTORY_SIZE
) {
1011 /* Let's return at the beginning */
1012 hdt_cli
.history_pos
= 1;
1015 /* Does the next position is already used ?
1016 * If yes, we are cycling in history */
1017 if (strlen(INPUT
) > 0) {
1018 /* Let's clean that entry */
1019 memset(&INPUT
,0,sizeof(INPUT
));
1022 future_history_pos
= hdt_cli
.history_pos
;
1023 if (hdt_cli
.history_pos
> hdt_cli
.max_history_pos
)
1024 hdt_cli
.max_history_pos
= hdt_cli
.history_pos
;
1030 /* No need to delete when input is empty */
1031 if (strlen(INPUT
) == 0)
1033 /* Don't delete when cursor is at the end of the line */
1034 if (hdt_cli
.cursor_pos
>= strlen(INPUT
))
1037 for (int c
= hdt_cli
.cursor_pos
; c
< (int)strlen(INPUT
) - 1; c
++)
1038 INPUT
[c
] = INPUT
[c
+ 1];
1039 INPUT
[strlen(INPUT
) - 1] = '\0';
1041 /* Clear the end of the line */
1042 clear_end_of_line();
1044 /* Print the resulting buffer */
1045 printf("%s", INPUT
+ hdt_cli
.cursor_pos
);
1047 /* Replace the cursor at the proper place */
1048 if (strlen(INPUT
+ hdt_cli
.cursor_pos
) > 0)
1049 move_cursor_left(strlen(INPUT
+ hdt_cli
.cursor_pos
));
1054 /* Don't delete prompt */
1055 if (hdt_cli
.cursor_pos
== 0)
1058 for (int c
= hdt_cli
.cursor_pos
- 1;
1059 c
< (int)strlen(INPUT
) - 1; c
++)
1060 INPUT
[c
] = INPUT
[c
+ 1];
1061 INPUT
[strlen(INPUT
) - 1] = '\0';
1063 /* Get one char back */
1064 move_cursor_left(1);
1066 /* Clear the end of the line */
1067 clear_end_of_line();
1069 /* Print the resulting buffer */
1070 printf("%s", INPUT
+ hdt_cli
.cursor_pos
- 1);
1072 /* Realing to a char before the place we were */
1073 hdt_cli
.cursor_pos
--;
1074 move_cursor_to_column(strlen(hdt_cli
.prompt
) + hdt_cli
.cursor_pos
+
1081 exec_command(CLI_HELP
, hardware
);
1086 if ((current_key
< 0x20) || (current_key
> 0x7e))
1088 /* Prevent overflow */
1089 if (hdt_cli
.cursor_pos
> MAX_LINE_SIZE
- 2)
1091 /* If we aren't at the end of the input line, let's insert */
1092 if (hdt_cli
.cursor_pos
< (int)strlen(INPUT
)) {
1094 int trailing_chars
= strlen(INPUT
) - hdt_cli
.cursor_pos
;
1095 memset(temp_command
, 0, sizeof(temp_command
));
1096 strlcpy(temp_command
, INPUT
, hdt_cli
.cursor_pos
);
1097 sprintf(key
, "%c", current_key
);
1098 strncat(temp_command
, key
, 1);
1099 strncat(temp_command
,
1100 INPUT
+ hdt_cli
.cursor_pos
, trailing_chars
);
1101 memset(INPUT
, 0, sizeof(INPUT
));
1102 snprintf(INPUT
, sizeof(INPUT
), "%s", temp_command
);
1104 /* Clear the end of the line */
1105 clear_end_of_line();
1107 /* Print the resulting buffer */
1108 printf("%s", INPUT
+ hdt_cli
.cursor_pos
);
1110 /* Return where we must put the new char */
1111 move_cursor_left(trailing_chars
);
1114 putchar(current_key
);
1115 INPUT
[hdt_cli
.cursor_pos
] = current_key
;
1117 hdt_cli
.cursor_pos
++;