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 #include <openocd_tcl.h>
43 int fast_and_dangerous = 0;
45 void command_print_help_line(command_context_t* context, struct command_s *command, int indent);
47 int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
48 int handle_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
49 int handle_fast_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
51 /* forward declaration of jim_command */
52 extern int jim_command(command_context_t *context, char *line);
56 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)
60 if (!context || !name)
63 c = malloc(sizeof(command_t));
65 c->name = strdup(name);
72 c->help = strdup(help);
75 /* place command in tree */
81 for (p = parent->children; p && p->next; p = p->next);
92 if (context->commands)
94 /* find last command */
95 for (p = context->commands; p && p->next; p = p->next);
101 context->commands = c;
104 /* accumulate help text in Tcl helptext list. */
105 Jim_Obj *helptext=Jim_GetGlobalVariableStr(interp, "ocd_helptext", JIM_ERRMSG);
106 Jim_Obj *cmd_entry=Jim_NewListObj(interp, NULL, 0);
108 Jim_Obj *cmd_list=Jim_NewListObj(interp, NULL, 0);
110 /* maximum of two levels :-) */
113 Jim_ListAppendElement(interp, cmd_list, Jim_NewStringObj(interp, c->parent->name, -1));
115 Jim_ListAppendElement(interp, cmd_list, Jim_NewStringObj(interp, c->name, -1));
117 Jim_ListAppendElement(interp, cmd_entry, cmd_list);
118 Jim_ListAppendElement(interp, cmd_entry, Jim_NewStringObj(interp, c->help, -1));
119 Jim_ListAppendElement(interp, helptext, cmd_entry);
123 int unregister_all_commands(command_context_t *context)
131 while(NULL != context->commands)
133 c = context->commands;
135 while(NULL != c->children)
138 c->children = c->children->next;
147 context->commands = context->commands->next;
160 int unregister_command(command_context_t *context, char *name)
162 command_t *c, *p = NULL, *c2;
164 if ((!context) || (!name))
165 return ERROR_INVALID_ARGUMENTS;
168 for (c = context->commands; c; c = c->next)
170 if (strcmp(name, c->name) == 0)
179 context->commands = c->next;
182 /* unregister children */
185 for (c2 = c->children; c2; c2 = c2->next)
201 /* remember the last command for unlinking */
208 int parse_line(char *line, char *words[], int max_words)
212 char *word_start = line;
215 while (nwords < max_words - 1)
217 /* check if we reached
219 * a matching closing quote character " or '
220 * we're inside a word but not a quote, and the current character is whitespace
222 if (!*p || *p == inquote || (word_start && !inquote && isspace(*p)))
224 /* we're inside a word or quote, and reached its end*/
230 /* This will handle extra whitespace within quotes */
231 while (isspace(*word_start)&&(word_start<word_end))
233 while (isspace(*(word_end-1))&&(word_start<word_end))
235 len = word_end - word_start;
240 memcpy(words[nwords] = malloc(len + 1), word_start, len);
241 /* add terminating NUL */
242 words[nwords++][len] = 0;
245 /* we're done parsing the line */
249 /* skip over trailing quote or whitespace*/
250 if (inquote || isspace(*p))
258 else if (*p == '"' || *p == '\'')
260 /* we've reached the beginning of a quote */
266 /* we've reached the beginning of a new word */
270 /* normal character, skip */
278 void command_output_text(command_context_t *context, const char *data)
280 if( context && context->output_handler && data ){
281 context->output_handler( context, data );
285 void command_print_n(command_context_t *context, char *format, ...)
290 va_start(ap, format);
292 string = alloc_vprintf(format, ap);
295 context->output_handler(context, string);
302 void command_print(command_context_t *context, char *format, ...)
307 va_start(ap, format);
309 string = alloc_vprintf(format, ap);
312 strcat(string, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one char longer */
313 context->output_handler(context, string);
320 command_t *find_command(command_context_t *context, command_t *commands, char *words[], int num_words, int start_word, int *new_start_word)
324 for (c = commands; c; c = c->next)
326 if (strcasecmp(c->name, words[start_word]))
329 if ((context->mode == COMMAND_CONFIG) || (c->mode == COMMAND_ANY) || (c->mode == context->mode) )
339 *new_start_word=start_word;
345 if (start_word == num_words - 1)
349 return find_command(context, c->children, words, num_words, start_word + 1, new_start_word);
356 int find_and_run_command(command_context_t *context, command_t *commands, char *words[], int num_words)
360 c = find_command(context, commands, words, num_words, start_word, &start_word);
363 /* just return command not found */
364 return ERROR_COMMAND_NOTFOUND;
367 int retval = c->handler(context, c->name, words + start_word + 1, num_words - start_word - 1);
368 if (retval == ERROR_COMMAND_SYNTAX_ERROR)
370 command_print(context, "Syntax error:");
371 command_print_help_line(context, c, 0);
373 else if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
375 /* just fall through for a shutdown request */
377 else if (retval != ERROR_OK)
379 /* we do not print out an error message because the command *should*
380 * have printed out an error
382 LOG_DEBUG("Command failed with error code %d", retval);
388 int command_run_line_internal(command_context_t *context, char *line)
390 LOG_USER_N("%s", ""); /* Keep GDB connection alive*/
393 char *words[128] = {0};
397 /* skip preceding whitespace */
398 while (isspace(*line))
401 /* empty line, ignore */
405 /* ignore comments */
406 if (*line && (line[0] == '#'))
409 LOG_DEBUG("%s", line);
411 nwords = parse_line(line, words, sizeof(words) / sizeof(words[0]));
415 retval = find_and_run_command(context, context->commands, words, nwords);
418 return ERROR_INVALID_ARGUMENTS;
420 for (i = 0; i < nwords; i++)
426 int command_run_line(command_context_t *context, char *line)
428 /* if a command is unknown to the "unknown" proc in tcl/commands.tcl will
429 * redirect it to OpenOCD.
431 * This avoids having to type the "openocd" prefix and makes OpenOCD
432 * commands "native" to Tcl.
434 return jim_command(context, line);
438 int command_run_linef(command_context_t *context, char *format, ...)
440 int retval=ERROR_FAIL;
443 va_start(ap, format);
444 string = alloc_vprintf(format, ap);
447 retval=command_run_line(context, string);
453 void command_print_help_line(command_context_t* context, struct command_s *command, int indent)
456 char *indent_text=malloc(indent + 2);
458 char *help = "no help available";
463 indent_text[0] = ' ';
464 memset(indent_text + 1, '-', indent);
465 indent_text[indent + 1] = 0;
469 help = command->help;
471 snprintf(name_buf, 64, command->name);
474 strncat(name_buf, indent_text, 64);
476 command_print(context, "%20s\t%s", name_buf, help, indent);
478 if (command->children)
480 for (c = command->children; c; c = c->next)
482 command_print_help_line(context, c, indent + 1);
488 int command_print_help_match(command_context_t* context, command_t* c_first, char* name, char** args, int argc)
492 for (c = c_first; c; c = c->next)
496 if (strcasecmp(c->name, args[0]))
501 command_print_help_match(context, c->children, name, args + 1, argc - 1);
506 command_print_help_line(context, c, 0);
512 int command_print_help(command_context_t* context, char* name, char** args, int argc)
514 return command_print_help_match(context, context->commands, name, args, argc);
517 void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, const char* line), void *priv)
519 context->output_handler = output_handler;
520 context->output_handler_priv = priv;
523 command_context_t* copy_command_context(command_context_t* context)
525 command_context_t* copy_context = malloc(sizeof(command_context_t));
527 *copy_context = *context;
532 int command_done(command_context_t *context)
540 command_context_t* command_init()
542 command_context_t* context = malloc(sizeof(command_context_t));
544 context->mode = COMMAND_EXEC;
545 context->commands = NULL;
546 context->current_target = 0;
547 context->output_handler = NULL;
548 context->output_handler_priv = NULL;
550 register_command(context, NULL, "help", command_print_help,
551 COMMAND_EXEC, "display this help");
553 register_command(context, NULL, "sleep", handle_sleep_command,
554 COMMAND_ANY, "sleep for <n> milliseconds");
556 register_command(context, NULL, "time", handle_time_command,
557 COMMAND_ANY, "time <cmd + args> - execute <cmd + args> and print time it took");
559 register_command(context, NULL, "fast", handle_fast_command,
560 COMMAND_ANY, "fast <enable/disable> - place at beginning of config files. Sets defaults to fast and dangerous.");
565 /* sleep command sleeps for <n> miliseconds
566 * this is useful in target startup scripts
568 int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
570 unsigned long duration = 0;
574 duration = strtoul(args[0], NULL, 0);
575 usleep(duration * 1000);
581 int handle_fast_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
584 return ERROR_COMMAND_SYNTAX_ERROR;
586 fast_and_dangerous = strcmp("enable", args[0])==0;
592 int handle_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
600 return ERROR_COMMAND_SYNTAX_ERROR;
602 duration_start_measure(&duration);
604 retval = find_and_run_command(cmd_ctx, cmd_ctx->commands, args, argc);
605 if (retval == ERROR_COMMAND_NOTFOUND)
607 command_print(cmd_ctx, "Command %s not found", args[0]);
610 duration_stop_measure(&duration, &duration_text);
612 t=duration.duration.tv_sec;
613 t+=((float)duration.duration.tv_usec / 1000000.0);
614 command_print(cmd_ctx, "%s took %fs", args[0], t);