1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * part of this file is taken from libcli (libcli.sourceforge.net) *
6 * Copyright (C) David Parrish (david@dparrish.com) *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22 ***************************************************************************/
27 #include "replacements.h"
32 #include "time_support.h"
41 int fast_and_dangerous
= 0;
43 void command_print_help_line(command_context_t
* context
, struct command_s
*command
, int indent
);
45 int handle_sleep_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
);
46 int handle_time_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
);
47 int handle_fast_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
);
49 /* forward declaration of jim_command */
50 extern int jim_command(command_context_t
*context
, char *line
);
52 int build_unique_lengths(command_context_t
*context
, command_t
*commands
)
56 /* iterate through all commands */
57 for (c
= commands
; c
; c
= c
->next
)
59 /* find out how many characters are required to uniquely identify a command */
60 for (c
->unique_len
= 1; c
->unique_len
<= strlen(c
->name
); c
->unique_len
++)
64 /* for every command, see if the current length is enough */
65 for (p
= commands
; p
; p
= p
->next
)
67 /* ignore the command itself */
71 /* compare commands up to the current length */
72 if (strncmp(p
->name
, c
->name
, c
->unique_len
) == 0)
76 /* when none of the commands matched, we've found the minimum length required */
81 /* if the current command has children, build the unique lengths for them */
83 build_unique_lengths(context
, c
->children
);
89 /* Avoid evaluating this each time we add a command. Reduces overhead from O(n^2) to O(n).
90 * Makes a difference on ARM7 types machines and is not observable on GHz machines.
92 static int unique_length_dirty
= 1;
94 command_t
* register_command(command_context_t
*context
, command_t
*parent
, char *name
, int (*handler
)(struct command_context_s
*context
, char* name
, char** args
, int argc
), enum command_mode mode
, char *help
)
97 unique_length_dirty
= 1;
99 if (!context
|| !name
)
102 c
= malloc(sizeof(command_t
));
104 c
->name
= strdup(name
);
107 c
->handler
= handler
;
110 c
->help
= strdup(help
);
116 /* place command in tree */
119 if (parent
->children
)
121 /* find last child */
122 for (p
= parent
->children
; p
&& p
->next
; p
= p
->next
);
128 parent
->children
= c
;
133 if (context
->commands
)
135 /* find last command */
136 for (p
= context
->commands
; p
&& p
->next
; p
= p
->next
);
142 context
->commands
= c
;
149 int unregister_all_commands(command_context_t
*context
)
153 unique_length_dirty
= 1;
159 while(NULL
!= context
->commands
)
161 c
= context
->commands
;
163 while(NULL
!= c
->children
)
166 c
->children
= c
->children
->next
;
175 context
->commands
= context
->commands
->next
;
188 int unregister_command(command_context_t
*context
, char *name
)
190 command_t
*c
, *p
= NULL
, *c2
;
192 unique_length_dirty
= 1;
194 if ((!context
) || (!name
))
195 return ERROR_INVALID_ARGUMENTS
;
198 for (c
= context
->commands
; c
; c
= c
->next
)
200 if (strcmp(name
, c
->name
) == 0)
209 context
->commands
= c
->next
;
212 /* unregister children */
215 for (c2
= c
->children
; c2
; c2
= c2
->next
)
231 /* remember the last command for unlinking */
238 int parse_line(char *line
, char *words
[], int max_words
)
242 char *word_start
= line
;
245 while (nwords
< max_words
- 1)
247 /* check if we reached
249 * a matching closing quote character " or '
250 * we're inside a word but not a quote, and the current character is whitespace
252 if (!*p
|| *p
== inquote
|| (word_start
&& !inquote
&& isspace(*p
)))
254 /* we're inside a word or quote, and reached its end*/
260 /* This will handle extra whitespace within quotes */
261 while (isspace(*word_start
)&&(word_start
<word_end
))
263 while (isspace(*(word_end
-1))&&(word_start
<word_end
))
265 len
= word_end
- word_start
;
270 memcpy(words
[nwords
] = malloc(len
+ 1), word_start
, len
);
271 /* add terminating NUL */
272 words
[nwords
++][len
] = 0;
275 /* we're done parsing the line */
279 /* skip over trailing quote or whitespace*/
280 if (inquote
|| isspace(*p
))
288 else if (*p
== '"' || *p
== '\'')
290 /* we've reached the beginning of a quote */
296 /* we've reached the beginning of a new word */
300 /* normal character, skip */
308 void command_output_text(command_context_t
*context
, const char *data
)
310 if( context
&& context
->output_handler
&& data
){
311 context
->output_handler( context
, data
);
315 void command_print_n(command_context_t
*context
, char *format
, ...)
320 va_start(ap
, format
);
322 string
= alloc_vprintf(format
, ap
);
325 context
->output_handler(context
, string
);
332 void command_print(command_context_t
*context
, char *format
, ...)
337 va_start(ap
, format
);
339 string
= alloc_vprintf(format
, ap
);
342 strcat(string
, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one char longer */
343 context
->output_handler(context
, string
);
350 command_t
*find_command(command_context_t
*context
, command_t
*commands
, char *words
[], int num_words
, int start_word
, int *new_start_word
)
354 if (unique_length_dirty
)
356 unique_length_dirty
= 0;
357 /* update unique lengths */
358 build_unique_lengths(context
, context
->commands
);
361 for (c
= commands
; c
; c
= c
->next
)
363 if (strncasecmp(c
->name
, words
[start_word
], c
->unique_len
))
366 if (strncasecmp(c
->name
, words
[start_word
], strlen(words
[start_word
])))
369 if ((context
->mode
== COMMAND_CONFIG
) || (c
->mode
== COMMAND_ANY
) || (c
->mode
== context
->mode
) )
379 *new_start_word
=start_word
;
385 if (start_word
== num_words
- 1)
389 return find_command(context
, c
->children
, words
, num_words
, start_word
+ 1, new_start_word
);
396 int find_and_run_command(command_context_t
*context
, command_t
*commands
, char *words
[], int num_words
)
400 c
= find_command(context
, commands
, words
, num_words
, start_word
, &start_word
);
403 /* just return command not found */
404 return ERROR_COMMAND_NOTFOUND
;
407 int retval
= c
->handler(context
, c
->name
, words
+ start_word
+ 1, num_words
- start_word
- 1);
408 if (retval
== ERROR_COMMAND_SYNTAX_ERROR
)
410 command_print(context
, "Syntax error:");
411 command_print_help_line(context
, c
, 0);
413 else if (retval
== ERROR_COMMAND_CLOSE_CONNECTION
)
415 /* just fall through for a shutdown request */
417 else if (retval
!= ERROR_OK
)
419 /* we do not print out an error message because the command *should*
420 * have printed out an error
422 LOG_DEBUG("Command failed with error code %d", retval
);
428 int command_run_line_internal(command_context_t
*context
, char *line
)
430 LOG_USER_N("%s", ""); /* Keep GDB connection alive*/
433 char *words
[128] = {0};
437 /* skip preceding whitespace */
438 while (isspace(*line
))
441 /* empty line, ignore */
445 /* ignore comments */
446 if (*line
&& (line
[0] == '#'))
449 LOG_DEBUG("%s", line
);
451 nwords
= parse_line(line
, words
, sizeof(words
) / sizeof(words
[0]));
455 retval
= find_and_run_command(context
, context
->commands
, words
, nwords
);
458 return ERROR_INVALID_ARGUMENTS
;
460 for (i
= 0; i
< nwords
; i
++)
466 int command_run_line(command_context_t
*context
, char *line
)
470 if ((!context
) || (!line
))
471 return ERROR_INVALID_ARGUMENTS
;
473 if ((retval
= command_run_line_internal(context
, line
)) == ERROR_COMMAND_NOTFOUND
)
475 /* If we can't find a command, then try the interpreter.
476 * If there is no interpreter implemented, then this will
477 * simply print a syntax error.
479 * These hooks were left in to reduce patch size for
480 * wip to add scripting language.
483 return jim_command(context
, line
);
489 int command_run_file(command_context_t
*context
, FILE *file
, enum command_mode mode
)
491 int retval
= ERROR_OK
;
492 int old_command_mode
;
493 char *buffer
=malloc(4096);
496 return ERROR_INVALID_ARGUMENTS
;
499 old_command_mode
= context
->mode
;
500 context
->mode
= mode
;
502 while (fgets(buffer
, 4096, file
))
507 /* stop processing line after a comment (#, !) or a LF, CR were encountered */
508 if ((p
= strpbrk(buffer
, "#!\r\n")))
511 /* skip over leading whitespace */
513 while (isspace(*cmd
))
516 /* empty (all whitespace) line? */
520 /* search the end of the current line, ignore trailing whitespace */
521 for (p
= end
= cmd
; *p
; p
++)
527 if (strcasecmp(cmd
, "quit") == 0)
531 if ((retval
= command_run_line(context
, cmd
)) == ERROR_COMMAND_CLOSE_CONNECTION
)
535 context
->mode
= old_command_mode
;
543 int command_run_linef(command_context_t
*context
, char *format
, ...)
545 int retval
=ERROR_FAIL
;
548 va_start(ap
, format
);
549 string
= alloc_vprintf(format
, ap
);
552 retval
=command_run_line(context
, string
);
558 void command_print_help_line(command_context_t
* context
, struct command_s
*command
, int indent
)
561 char *indent_text
=malloc(indent
+ 2);
563 char *help
= "no help available";
568 indent_text
[0] = ' ';
569 memset(indent_text
+ 1, '-', indent
);
570 indent_text
[indent
+ 1] = 0;
574 help
= command
->help
;
576 snprintf(name_buf
, 64, command
->name
);
579 strncat(name_buf
, indent_text
, 64);
581 command_print(context
, "%20s\t%s", name_buf
, help
, indent
);
583 if (command
->children
)
585 for (c
= command
->children
; c
; c
= c
->next
)
587 command_print_help_line(context
, c
, indent
+ 1);
593 int command_print_help_match(command_context_t
* context
, command_t
* c_first
, char* name
, char** args
, int argc
)
597 for (c
= c_first
; c
; c
= c
->next
)
601 if (strncasecmp(c
->name
, args
[0], c
->unique_len
))
604 if (strncasecmp(c
->name
, args
[0], strlen(args
[0])))
609 command_print_help_match(context
, c
->children
, name
, args
+ 1, argc
- 1);
614 command_print_help_line(context
, c
, 0);
620 int command_print_help(command_context_t
* context
, char* name
, char** args
, int argc
)
622 return command_print_help_match(context
, context
->commands
, name
, args
, argc
);
625 void command_set_output_handler(command_context_t
* context
, int (*output_handler
)(struct command_context_s
*context
, const char* line
), void *priv
)
627 context
->output_handler
= output_handler
;
628 context
->output_handler_priv
= priv
;
631 command_context_t
* copy_command_context(command_context_t
* context
)
633 command_context_t
* copy_context
= malloc(sizeof(command_context_t
));
635 *copy_context
= *context
;
640 int command_done(command_context_t
*context
)
648 command_context_t
* command_init()
650 command_context_t
* context
= malloc(sizeof(command_context_t
));
652 context
->mode
= COMMAND_EXEC
;
653 context
->commands
= NULL
;
654 context
->current_target
= 0;
655 context
->output_handler
= NULL
;
656 context
->output_handler_priv
= NULL
;
658 register_command(context
, NULL
, "help", command_print_help
,
659 COMMAND_EXEC
, "display this help");
661 register_command(context
, NULL
, "sleep", handle_sleep_command
,
662 COMMAND_ANY
, "sleep for <n> milliseconds");
664 register_command(context
, NULL
, "time", handle_time_command
,
665 COMMAND_ANY
, "time <cmd + args> - execute <cmd + args> and print time it took");
667 register_command(context
, NULL
, "fast", handle_fast_command
,
668 COMMAND_ANY
, "fast <enable/disable> - place at beginning of config files. Sets defaults to fast and dangerous.");
673 /* sleep command sleeps for <n> miliseconds
674 * this is useful in target startup scripts
676 int handle_sleep_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
678 unsigned long duration
= 0;
682 duration
= strtoul(args
[0], NULL
, 0);
683 usleep(duration
* 1000);
689 int handle_fast_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
692 return ERROR_COMMAND_SYNTAX_ERROR
;
694 fast_and_dangerous
= strcmp("enable", args
[0])==0;
700 int handle_time_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
708 return ERROR_COMMAND_SYNTAX_ERROR
;
710 duration_start_measure(&duration
);
712 retval
= find_and_run_command(cmd_ctx
, cmd_ctx
->commands
, args
, argc
);
713 if (retval
== ERROR_COMMAND_NOTFOUND
)
715 command_print(cmd_ctx
, "Command %s not found", args
[0]);
718 duration_stop_measure(&duration
, &duration_text
);
720 t
=duration
.duration
.tv_sec
;
721 t
+=((float)duration
.duration
.tv_usec
/ 1000000.0);
722 command_print(cmd_ctx
, "%s took %fs", args
[0], t
);