1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * Copyright (C) 2007,2008 Øyvind Harboe *
6 * oyvind.harboe@zylin.com *
8 * Copyright (C) 2008, Duane Ellis *
9 * openocd@duaneeellis.com *
11 * part of this file is taken from libcli (libcli.sourceforge.net) *
12 * Copyright (C) David Parrish (david@dparrish.com) *
14 * This program is free software; you can redistribute it and/or modify *
15 * it under the terms of the GNU General Public License as published by *
16 * the Free Software Foundation; either version 2 of the License, or *
17 * (at your option) any later version. *
19 * This program is distributed in the hope that it will be useful, *
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
22 * GNU General Public License for more details. *
24 * You should have received a copy of the GNU General Public License *
25 * along with this program; if not, write to the *
26 * Free Software Foundation, Inc., *
27 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
28 ***************************************************************************/
34 /* see Embedder-HOWTO.txt in Jim Tcl project hosted on BerliOS*/
37 /* @todo the inclusion of target.h here is a layering violation */
38 #include <jtag/jtag.h>
39 #include <target/target.h>
41 #include "configuration.h"
43 #include "time_support.h"
44 #include "jim-eventloop.h"
46 /* nice short description of source file */
47 #define __THIS__FILE__ "command.c"
49 static int run_command(struct command_context
*context
,
50 struct command
*c
, const char *words
[], unsigned num_words
);
52 struct log_capture_state
{
57 static void tcl_output(void *privData
, const char *file
, unsigned line
,
58 const char *function
, const char *string
)
60 struct log_capture_state
*state
= (struct log_capture_state
*)privData
;
61 Jim_AppendString(state
->interp
, state
->output
, string
, strlen(string
));
64 static struct log_capture_state
*command_log_capture_start(Jim_Interp
*interp
)
66 /* capture log output and return it. A garbage collect can
67 * happen, so we need a reference count to this object */
68 Jim_Obj
*tclOutput
= Jim_NewStringObj(interp
, "", 0);
69 if (NULL
== tclOutput
)
72 struct log_capture_state
*state
= malloc(sizeof(*state
));
76 state
->interp
= interp
;
77 Jim_IncrRefCount(tclOutput
);
78 state
->output
= tclOutput
;
80 log_add_callback(tcl_output
, state
);
85 /* Classic openocd commands provide progress output which we
86 * will capture and return as a Tcl return value.
88 * However, if a non-openocd command has been invoked, then it
89 * makes sense to return the tcl return value from that command.
91 * The tcl return value is empty for openocd commands that provide
94 * Therefore we set the tcl return value only if we actually
97 static void command_log_capture_finish(struct log_capture_state
*state
)
102 log_remove_callback(tcl_output
, state
);
105 Jim_GetString(state
->output
, &length
);
108 Jim_SetResult(state
->interp
, state
->output
);
110 /* No output captured, use tcl return value (which could
113 Jim_DecrRefCount(state
->interp
, state
->output
);
118 static int command_retval_set(Jim_Interp
*interp
, int retval
)
120 int *return_retval
= Jim_GetAssocData(interp
, "retval");
121 if (retval
== ERROR_COMMAND_CLOSE_CONNECTION
) {
122 if (return_retval
!= NULL
)
126 if (return_retval
!= NULL
)
127 *return_retval
= retval
;
128 return (retval
== ERROR_OK
) ? JIM_OK
: JIM_ERR
;
132 extern struct command_context
*global_cmd_ctx
;
134 /* dump a single line to the log for the command.
135 * Do nothing in case we are not at debug level 3 */
136 void script_debug(Jim_Interp
*interp
, const char *name
,
137 unsigned argc
, Jim_Obj
* const *argv
)
139 if (debug_level
< LOG_LVL_DEBUG
)
142 char *dbg
= alloc_printf("command - %s", name
);
143 for (unsigned i
= 0; i
< argc
; i
++) {
145 const char *w
= Jim_GetString(argv
[i
], &len
);
146 char *t
= alloc_printf("%s %s", dbg
, w
);
150 LOG_DEBUG("%s", dbg
);
154 static void script_command_args_free(const char **words
, unsigned nwords
)
156 for (unsigned i
= 0; i
< nwords
; i
++)
157 free((void *)words
[i
]);
160 static const char **script_command_args_alloc(
161 unsigned argc
, Jim_Obj
* const *argv
, unsigned *nwords
)
163 const char **words
= malloc(argc
* sizeof(char *));
168 for (i
= 0; i
< argc
; i
++) {
170 const char *w
= Jim_GetString(argv
[i
], &len
);
171 words
[i
] = strdup(w
);
172 if (words
[i
] == NULL
) {
173 script_command_args_free(words
, i
);
181 struct command_context
*current_command_context(Jim_Interp
*interp
)
183 /* grab the command context from the associated data */
184 struct command_context
*cmd_ctx
= Jim_GetAssocData(interp
, "context");
185 if (NULL
== cmd_ctx
) {
186 /* Tcl can invoke commands directly instead of via command_run_line(). This would
187 * happen when the Jim Tcl interpreter is provided by eCos or if we are running
188 * commands in a startup script.
190 * A telnet or gdb server would provide a non-default command context to
191 * handle piping of error output, have a separate current target, etc.
193 cmd_ctx
= global_cmd_ctx
;
198 static int script_command_run(Jim_Interp
*interp
,
199 int argc
, Jim_Obj
* const *argv
, struct command
*c
, bool capture
)
201 target_call_timer_callbacks_now();
202 LOG_USER_N("%s", ""); /* Keep GDB connection alive*/
205 const char **words
= script_command_args_alloc(argc
, argv
, &nwords
);
209 struct log_capture_state
*state
= NULL
;
211 state
= command_log_capture_start(interp
);
213 struct command_context
*cmd_ctx
= current_command_context(interp
);
214 int retval
= run_command(cmd_ctx
, c
, (const char **)words
, nwords
);
216 command_log_capture_finish(state
);
218 script_command_args_free(words
, nwords
);
219 return command_retval_set(interp
, retval
);
222 static int script_command(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
224 /* the private data is stashed in the interp structure */
226 struct command
*c
= interp
->cmdPrivData
;
228 script_debug(interp
, c
->name
, argc
, argv
);
229 return script_command_run(interp
, argc
, argv
, c
, true);
232 static struct command
*command_root(struct command
*c
)
234 while (NULL
!= c
->parent
)
240 * Find a command by name from a list of commands.
241 * @returns Returns the named command if it exists in the list.
242 * Returns NULL otherwise.
244 static struct command
*command_find(struct command
*head
, const char *name
)
246 for (struct command
*cc
= head
; cc
; cc
= cc
->next
) {
247 if (strcmp(cc
->name
, name
) == 0)
252 struct command
*command_find_in_context(struct command_context
*cmd_ctx
,
255 return command_find(cmd_ctx
->commands
, name
);
257 struct command
*command_find_in_parent(struct command
*parent
,
260 return command_find(parent
->children
, name
);
264 * Add the command into the linked list, sorted by name.
265 * @param head Address to head of command list pointer, which may be
266 * updated if @c c gets inserted at the beginning of the list.
267 * @param c The command to add to the list pointed to by @c head.
269 static void command_add_child(struct command
**head
, struct command
*c
)
277 while ((*head
)->next
&& (strcmp(c
->name
, (*head
)->name
) > 0))
278 head
= &(*head
)->next
;
280 if (strcmp(c
->name
, (*head
)->name
) > 0) {
281 c
->next
= (*head
)->next
;
289 static struct command
**command_list_for_parent(
290 struct command_context
*cmd_ctx
, struct command
*parent
)
292 return parent
? &parent
->children
: &cmd_ctx
->commands
;
295 static void command_free(struct command
*c
)
297 /** @todo if command has a handler, unregister its jim command! */
299 while (NULL
!= c
->children
) {
300 struct command
*tmp
= c
->children
;
301 c
->children
= tmp
->next
;
306 free((void *)c
->name
);
308 free((void *)c
->help
);
310 free((void *)c
->usage
);
314 static struct command
*command_new(struct command_context
*cmd_ctx
,
315 struct command
*parent
, const struct command_registration
*cr
)
320 * If it is a non-jim command with no .usage specified,
323 * strlen(.usage) == 0 means that the command takes no
326 if ((cr
->jim_handler
== NULL
) && (cr
->usage
== NULL
)) {
327 LOG_DEBUG("BUG: command '%s%s%s' does not have the "
328 "'.usage' field filled out",
329 parent
&& parent
->name
? parent
->name
: "",
330 parent
&& parent
->name
? " " : "",
334 struct command
*c
= calloc(1, sizeof(struct command
));
338 c
->name
= strdup(cr
->name
);
340 c
->help
= strdup(cr
->help
);
342 c
->usage
= strdup(cr
->usage
);
344 if (!c
->name
|| (cr
->help
&& !c
->help
) || (cr
->usage
&& !c
->usage
))
345 goto command_new_error
;
348 c
->handler
= cr
->handler
;
349 c
->jim_handler
= cr
->jim_handler
;
350 c
->jim_handler_data
= cr
->jim_handler_data
;
353 command_add_child(command_list_for_parent(cmd_ctx
, parent
), c
);
362 static int command_unknown(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
);
364 static int register_command_handler(struct command_context
*cmd_ctx
,
367 Jim_Interp
*interp
= cmd_ctx
->interp
;
368 const char *ocd_name
= alloc_printf("ocd_%s", c
->name
);
369 if (NULL
== ocd_name
)
372 LOG_DEBUG("registering '%s'...", ocd_name
);
374 Jim_CmdProc func
= c
->handler
? &script_command
: &command_unknown
;
375 int retval
= Jim_CreateCommand(interp
, ocd_name
, func
, c
, NULL
);
376 free((void *)ocd_name
);
377 if (JIM_OK
!= retval
)
380 /* we now need to add an overrideable proc */
381 const char *override_name
= alloc_printf(
382 "proc %s {args} {eval ocd_bouncer %s $args}",
384 if (NULL
== override_name
)
387 retval
= Jim_Eval_Named(interp
, override_name
, 0, 0);
388 free((void *)override_name
);
393 struct command
*register_command(struct command_context
*context
,
394 struct command
*parent
, const struct command_registration
*cr
)
396 if (!context
|| !cr
->name
)
399 const char *name
= cr
->name
;
400 struct command
**head
= command_list_for_parent(context
, parent
);
401 struct command
*c
= command_find(*head
, name
);
403 /* TODO: originally we treated attempting to register a cmd twice as an error
404 * Sometimes we need this behaviour, such as with flash banks.
405 * http://www.mail-archive.com/openocd-development@lists.berlios.de/msg11152.html */
406 LOG_DEBUG("command '%s' is already registered in '%s' context",
407 name
, parent
? parent
->name
: "<global>");
411 c
= command_new(context
, parent
, cr
);
415 int retval
= ERROR_OK
;
416 if (NULL
!= cr
->jim_handler
&& NULL
== parent
) {
417 retval
= Jim_CreateCommand(context
->interp
, cr
->name
,
418 cr
->jim_handler
, cr
->jim_handler_data
, NULL
);
419 } else if (NULL
!= cr
->handler
|| NULL
!= parent
)
420 retval
= register_command_handler(context
, command_root(c
));
422 if (ERROR_OK
!= retval
) {
423 unregister_command(context
, parent
, name
);
429 int register_commands(struct command_context
*cmd_ctx
, struct command
*parent
,
430 const struct command_registration
*cmds
)
432 int retval
= ERROR_OK
;
434 for (i
= 0; cmds
[i
].name
|| cmds
[i
].chain
; i
++) {
435 const struct command_registration
*cr
= cmds
+ i
;
437 struct command
*c
= NULL
;
438 if (NULL
!= cr
->name
) {
439 c
= register_command(cmd_ctx
, parent
, cr
);
445 if (NULL
!= cr
->chain
) {
446 struct command
*p
= c
? : parent
;
447 retval
= register_commands(cmd_ctx
, p
, cr
->chain
);
448 if (ERROR_OK
!= retval
)
452 if (ERROR_OK
!= retval
) {
453 for (unsigned j
= 0; j
< i
; j
++)
454 unregister_command(cmd_ctx
, parent
, cmds
[j
].name
);
459 int unregister_all_commands(struct command_context
*context
,
460 struct command
*parent
)
465 struct command
**head
= command_list_for_parent(context
, parent
);
466 while (NULL
!= *head
) {
467 struct command
*tmp
= *head
;
475 int unregister_command(struct command_context
*context
,
476 struct command
*parent
, const char *name
)
478 if ((!context
) || (!name
))
479 return ERROR_COMMAND_SYNTAX_ERROR
;
481 struct command
*p
= NULL
;
482 struct command
**head
= command_list_for_parent(context
, parent
);
483 for (struct command
*c
= *head
; NULL
!= c
; p
= c
, c
= c
->next
) {
484 if (strcmp(name
, c
->name
) != 0)
499 void command_set_handler_data(struct command
*c
, void *p
)
501 if (NULL
!= c
->handler
|| NULL
!= c
->jim_handler
)
502 c
->jim_handler_data
= p
;
503 for (struct command
*cc
= c
->children
; NULL
!= cc
; cc
= cc
->next
)
504 command_set_handler_data(cc
, p
);
507 void command_output_text(struct command_context
*context
, const char *data
)
509 if (context
&& context
->output_handler
&& data
)
510 context
->output_handler(context
, data
);
513 void command_print_sameline(struct command_context
*context
, const char *format
, ...)
518 va_start(ap
, format
);
520 string
= alloc_vprintf(format
, ap
);
521 if (string
!= NULL
) {
522 /* we want this collected in the log + we also want to pick it up as a tcl return
525 * The latter bit isn't precisely neat, but will do for now.
527 LOG_USER_N("%s", string
);
528 /* We already printed it above
529 * command_output_text(context, string); */
536 void command_print(struct command_context
*context
, const char *format
, ...)
541 va_start(ap
, format
);
543 string
= alloc_vprintf(format
, ap
);
544 if (string
!= NULL
) {
545 strcat(string
, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one
547 /* we want this collected in the log + we also want to pick it up as a tcl return
550 * The latter bit isn't precisely neat, but will do for now.
552 LOG_USER_N("%s", string
);
553 /* We already printed it above
554 * command_output_text(context, string); */
561 static char *__command_name(struct command
*c
, char delim
, unsigned extra
)
564 unsigned len
= strlen(c
->name
);
565 if (NULL
== c
->parent
) {
566 /* allocate enough for the name, child names, and '\0' */
567 name
= malloc(len
+ extra
+ 1);
568 strcpy(name
, c
->name
);
570 /* parent's extra must include both the space and name */
571 name
= __command_name(c
->parent
, delim
, 1 + len
+ extra
);
572 char dstr
[2] = { delim
, 0 };
574 strcat(name
, c
->name
);
578 char *command_name(struct command
*c
, char delim
)
580 return __command_name(c
, delim
, 0);
583 static bool command_can_run(struct command_context
*cmd_ctx
, struct command
*c
)
585 return c
->mode
== COMMAND_ANY
|| c
->mode
== cmd_ctx
->mode
;
588 static int run_command(struct command_context
*context
,
589 struct command
*c
, const char *words
[], unsigned num_words
)
591 if (!command_can_run(context
, c
)) {
592 /* Many commands may be run only before/after 'init' */
601 /* handle the impossible with humor; it guarantees a bug report! */
603 when
= "if Cthulhu is summoned by";
606 LOG_ERROR("The '%s' command must be used %s 'init'.",
611 struct command_invocation cmd
= {
615 .argc
= num_words
- 1,
618 int retval
= c
->handler(&cmd
);
619 if (retval
== ERROR_COMMAND_SYNTAX_ERROR
) {
620 /* Print help for command */
621 char *full_name
= command_name(c
, ' ');
622 if (NULL
!= full_name
) {
623 command_run_linef(context
, "usage %s", full_name
);
627 } else if (retval
== ERROR_COMMAND_CLOSE_CONNECTION
) {
628 /* just fall through for a shutdown request */
629 } else if (retval
!= ERROR_OK
) {
630 /* we do not print out an error message because the command *should*
631 * have printed out an error
633 LOG_DEBUG("Command failed with error code %d", retval
);
639 int command_run_line(struct command_context
*context
, char *line
)
641 /* all the parent commands have been registered with the interpreter
642 * so, can just evaluate the line as a script and check for
645 /* run the line thru a script engine */
646 int retval
= ERROR_FAIL
;
648 /* Beware! This code needs to be reentrant. It is also possible
649 * for OpenOCD commands to be invoked directly from Tcl. This would
650 * happen when the Jim Tcl interpreter is provided by eCos for
653 Jim_Interp
*interp
= context
->interp
;
654 Jim_DeleteAssocData(interp
, "context");
655 retcode
= Jim_SetAssocData(interp
, "context", NULL
, context
);
656 if (retcode
== JIM_OK
) {
657 /* associated the return value */
658 Jim_DeleteAssocData(interp
, "retval");
659 retcode
= Jim_SetAssocData(interp
, "retval", NULL
, &retval
);
660 if (retcode
== JIM_OK
) {
661 retcode
= Jim_Eval_Named(interp
, line
, 0, 0);
663 Jim_DeleteAssocData(interp
, "retval");
665 Jim_DeleteAssocData(interp
, "context");
667 if (retcode
== JIM_ERR
) {
668 if (retval
!= ERROR_COMMAND_CLOSE_CONNECTION
) {
669 /* We do not print the connection closed error message */
670 Jim_MakeErrorMessage(interp
);
671 LOG_USER("%s", Jim_GetString(Jim_GetResult(interp
), NULL
));
673 if (retval
== ERROR_OK
) {
674 /* It wasn't a low level OpenOCD command that failed */
678 } else if (retcode
== JIM_EXIT
) {
679 return ERROR_OK_EXIT
;
684 result
= Jim_GetString(Jim_GetResult(interp
), &reslen
);
688 for (i
= 0; i
< reslen
; i
+= 256) {
693 strncpy(buff
, result
+ i
, chunk
);
695 LOG_USER_N("%s", buff
);
704 int command_run_linef(struct command_context
*context
, const char *format
, ...)
706 int retval
= ERROR_FAIL
;
709 va_start(ap
, format
);
710 string
= alloc_vprintf(format
, ap
);
711 if (string
!= NULL
) {
712 retval
= command_run_line(context
, string
);
719 void command_set_output_handler(struct command_context
*context
,
720 command_output_handler_t output_handler
, void *priv
)
722 context
->output_handler
= output_handler
;
723 context
->output_handler_priv
= priv
;
726 struct command_context
*copy_command_context(struct command_context
*context
)
728 struct command_context
*copy_context
= malloc(sizeof(struct command_context
));
730 *copy_context
= *context
;
735 void command_done(struct command_context
*cmd_ctx
)
743 /* find full path to file */
744 static int jim_find(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
748 const char *file
= Jim_GetString(argv
[1], NULL
);
749 char *full_path
= find_file(file
);
750 if (full_path
== NULL
)
752 Jim_Obj
*result
= Jim_NewStringObj(interp
, full_path
, strlen(full_path
));
755 Jim_SetResult(interp
, result
);
759 COMMAND_HANDLER(jim_echo
)
761 if (CMD_ARGC
== 2 && !strcmp(CMD_ARGV
[0], "-n")) {
762 LOG_USER_N("%s", CMD_ARGV
[1]);
767 LOG_USER("%s", CMD_ARGV
[0]);
771 /* Capture progress output and return as tcl return value. If the
772 * progress output was empty, return tcl return value.
774 static int jim_capture(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
779 struct log_capture_state
*state
= command_log_capture_start(interp
);
781 /* disable polling during capture. This avoids capturing output
784 * This is necessary in order to avoid accidentially getting a non-empty
785 * string for tcl fn's.
787 bool save_poll
= jtag_poll_get_enabled();
789 jtag_poll_set_enabled(false);
791 const char *str
= Jim_GetString(argv
[1], NULL
);
792 int retcode
= Jim_Eval_Named(interp
, str
, __THIS__FILE__
, __LINE__
);
794 jtag_poll_set_enabled(save_poll
);
796 command_log_capture_finish(state
);
801 static COMMAND_HELPER(command_help_find
, struct command
*head
,
802 struct command
**out
)
805 return ERROR_COMMAND_SYNTAX_ERROR
;
806 *out
= command_find(head
, CMD_ARGV
[0]);
807 if (NULL
== *out
&& strncmp(CMD_ARGV
[0], "ocd_", 4) == 0)
808 *out
= command_find(head
, CMD_ARGV
[0] + 4);
810 return ERROR_COMMAND_SYNTAX_ERROR
;
814 return CALL_COMMAND_HANDLER(command_help_find
, (*out
)->children
, out
);
817 static COMMAND_HELPER(command_help_show
, struct command
*c
, unsigned n
,
818 bool show_help
, const char *match
);
820 static COMMAND_HELPER(command_help_show_list
, struct command
*head
, unsigned n
,
821 bool show_help
, const char *match
)
823 for (struct command
*c
= head
; NULL
!= c
; c
= c
->next
)
824 CALL_COMMAND_HANDLER(command_help_show
, c
, n
, show_help
, match
);
828 #define HELP_LINE_WIDTH(_n) (int)(76 - (2 * _n))
830 static void command_help_show_indent(unsigned n
)
832 for (unsigned i
= 0; i
< n
; i
++)
835 static void command_help_show_wrap(const char *str
, unsigned n
, unsigned n2
)
837 const char *cp
= str
, *last
= str
;
839 const char *next
= last
;
844 } while (*next
!= ' ' && *next
!= '\t' && *next
!= '\0');
845 } while ((next
- last
< HELP_LINE_WIDTH(n
)) && *next
!= '\0');
846 if (next
- last
< HELP_LINE_WIDTH(n
))
848 command_help_show_indent(n
);
849 LOG_USER("%.*s", (int)(cp
- last
), last
);
854 static COMMAND_HELPER(command_help_show
, struct command
*c
, unsigned n
,
855 bool show_help
, const char *match
)
857 char *cmd_name
= command_name(c
, ' ');
858 if (NULL
== cmd_name
)
861 /* If the match string occurs anywhere, we print out
862 * stuff for this command. */
863 bool is_match
= (strstr(cmd_name
, match
) != NULL
) ||
864 ((c
->usage
!= NULL
) && (strstr(c
->usage
, match
) != NULL
)) ||
865 ((c
->help
!= NULL
) && (strstr(c
->help
, match
) != NULL
));
868 command_help_show_indent(n
);
869 LOG_USER_N("%s", cmd_name
);
876 command_help_show_wrap(c
->usage
, 0, n
+ 5);
881 if (is_match
&& show_help
) {
884 /* Normal commands are runtime-only; highlight exceptions */
885 if (c
->mode
!= COMMAND_EXEC
) {
886 const char *stage_msg
= "";
890 stage_msg
= " (configuration command)";
893 stage_msg
= " (command valid any time)";
896 stage_msg
= " (?mode error?)";
899 msg
= alloc_printf("%s%s", c
->help
? : "", stage_msg
);
901 msg
= alloc_printf("%s", c
->help
? : "");
904 command_help_show_wrap(msg
, n
+ 3, n
+ 3);
911 LOG_ERROR("command recursion exceeded");
915 return CALL_COMMAND_HANDLER(command_help_show_list
,
916 c
->children
, n
, show_help
, match
);
918 COMMAND_HANDLER(handle_help_command
)
920 bool full
= strcmp(CMD_NAME
, "help") == 0;
922 struct command
*c
= CMD_CTX
->commands
;
927 else if (CMD_ARGC
>= 1) {
930 for (i
= 0; i
< CMD_ARGC
; ++i
) {
934 match
= alloc_printf("%s %s", match
,
938 LOG_ERROR("unable to build "
943 match
= alloc_printf("%s", CMD_ARGV
[i
]);
945 LOG_ERROR("unable to build "
952 return ERROR_COMMAND_SYNTAX_ERROR
;
954 retval
= CALL_COMMAND_HANDLER(command_help_show_list
,
962 static int command_unknown_find(unsigned argc
, Jim_Obj
*const *argv
,
963 struct command
*head
, struct command
**out
, bool top_level
)
967 const char *cmd_name
= Jim_GetString(argv
[0], NULL
);
968 struct command
*c
= command_find(head
, cmd_name
);
969 if (NULL
== c
&& top_level
&& strncmp(cmd_name
, "ocd_", 4) == 0)
970 c
= command_find(head
, cmd_name
+ 4);
974 return command_unknown_find(--argc
, ++argv
, (*out
)->children
, out
, false);
977 static int command_unknown(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
979 const char *cmd_name
= Jim_GetString(argv
[0], NULL
);
980 if (strcmp(cmd_name
, "unknown") == 0) {
986 script_debug(interp
, cmd_name
, argc
, argv
);
988 struct command_context
*cmd_ctx
= current_command_context(interp
);
989 struct command
*c
= cmd_ctx
->commands
;
990 int remaining
= command_unknown_find(argc
, argv
, c
, &c
, true);
991 /* if nothing could be consumed, then it's really an unknown command */
992 if (remaining
== argc
) {
993 const char *cmd
= Jim_GetString(argv
[0], NULL
);
994 LOG_ERROR("Unknown command:\n %s", cmd
);
999 Jim_Obj
*const *start
;
1001 if (c
->handler
|| c
->jim_handler
) {
1002 /* include the command name in the list */
1003 count
= remaining
+ 1;
1004 start
= argv
+ (argc
- remaining
- 1);
1006 c
= command_find(cmd_ctx
->commands
, "usage");
1008 LOG_ERROR("unknown command, but usage is missing too");
1011 count
= argc
- remaining
;
1015 /* pass the command through to the intended handler */
1016 if (c
->jim_handler
) {
1017 interp
->cmdPrivData
= c
->jim_handler_data
;
1018 return (*c
->jim_handler
)(interp
, count
, start
);
1021 return script_command_run(interp
, count
, start
, c
, found
);
1024 static int jim_command_mode(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1026 struct command_context
*cmd_ctx
= current_command_context(interp
);
1027 enum command_mode mode
;
1030 struct command
*c
= cmd_ctx
->commands
;
1031 int remaining
= command_unknown_find(argc
- 1, argv
+ 1, c
, &c
, true);
1032 /* if nothing could be consumed, then it's an unknown command */
1033 if (remaining
== argc
- 1) {
1034 Jim_SetResultString(interp
, "unknown", -1);
1039 mode
= cmd_ctx
->mode
;
1041 const char *mode_str
;
1046 case COMMAND_CONFIG
:
1047 mode_str
= "config";
1053 mode_str
= "unknown";
1056 Jim_SetResultString(interp
, mode_str
, -1);
1060 static int jim_command_type(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1065 struct command_context
*cmd_ctx
= current_command_context(interp
);
1066 struct command
*c
= cmd_ctx
->commands
;
1067 int remaining
= command_unknown_find(argc
- 1, argv
+ 1, c
, &c
, true);
1068 /* if nothing could be consumed, then it's an unknown command */
1069 if (remaining
== argc
- 1) {
1070 Jim_SetResultString(interp
, "unknown", -1);
1075 Jim_SetResultString(interp
, "native", -1);
1076 else if (c
->handler
)
1077 Jim_SetResultString(interp
, "simple", -1);
1079 Jim_SetResultString(interp
, "group", -1);
1084 int help_add_command(struct command_context
*cmd_ctx
, struct command
*parent
,
1085 const char *cmd_name
, const char *help_text
, const char *usage
)
1087 struct command
**head
= command_list_for_parent(cmd_ctx
, parent
);
1088 struct command
*nc
= command_find(*head
, cmd_name
);
1090 /* add a new command with help text */
1091 struct command_registration cr
= {
1093 .mode
= COMMAND_ANY
,
1097 nc
= register_command(cmd_ctx
, parent
, &cr
);
1099 LOG_ERROR("failed to add '%s' help text", cmd_name
);
1102 LOG_DEBUG("added '%s' help text", cmd_name
);
1106 bool replaced
= false;
1108 free((void *)nc
->help
);
1111 nc
->help
= strdup(help_text
);
1113 LOG_INFO("replaced existing '%s' help", cmd_name
);
1115 LOG_DEBUG("added '%s' help text", cmd_name
);
1118 bool replaced
= false;
1120 free((void *)nc
->usage
);
1123 nc
->usage
= strdup(usage
);
1125 LOG_INFO("replaced existing '%s' usage", cmd_name
);
1127 LOG_DEBUG("added '%s' usage text", cmd_name
);
1132 COMMAND_HANDLER(handle_help_add_command
)
1135 LOG_ERROR("%s: insufficient arguments", CMD_NAME
);
1136 return ERROR_COMMAND_SYNTAX_ERROR
;
1139 /* save help text and remove it from argument list */
1140 const char *str
= CMD_ARGV
[--CMD_ARGC
];
1141 const char *help
= !strcmp(CMD_NAME
, "add_help_text") ? str
: NULL
;
1142 const char *usage
= !strcmp(CMD_NAME
, "add_usage_text") ? str
: NULL
;
1143 if (!help
&& !usage
) {
1144 LOG_ERROR("command name '%s' is unknown", CMD_NAME
);
1145 return ERROR_COMMAND_SYNTAX_ERROR
;
1147 /* likewise for the leaf command name */
1148 const char *cmd_name
= CMD_ARGV
[--CMD_ARGC
];
1150 struct command
*c
= NULL
;
1152 c
= CMD_CTX
->commands
;
1153 int retval
= CALL_COMMAND_HANDLER(command_help_find
, c
, &c
);
1154 if (ERROR_OK
!= retval
)
1157 return help_add_command(CMD_CTX
, c
, cmd_name
, help
, usage
);
1160 /* sleep command sleeps for <n> milliseconds
1161 * this is useful in target startup scripts
1163 COMMAND_HANDLER(handle_sleep_command
)
1166 if (CMD_ARGC
== 2) {
1167 if (strcmp(CMD_ARGV
[1], "busy") == 0)
1170 return ERROR_COMMAND_SYNTAX_ERROR
;
1171 } else if (CMD_ARGC
< 1 || CMD_ARGC
> 2)
1172 return ERROR_COMMAND_SYNTAX_ERROR
;
1174 unsigned long duration
= 0;
1175 int retval
= parse_ulong(CMD_ARGV
[0], &duration
);
1176 if (ERROR_OK
!= retval
)
1180 long long then
= timeval_ms();
1181 while (timeval_ms() - then
< (long long)duration
) {
1182 target_call_timer_callbacks_now();
1186 busy_sleep(duration
);
1191 static const struct command_registration command_subcommand_handlers
[] = {
1194 .mode
= COMMAND_ANY
,
1195 .jim_handler
= jim_command_mode
,
1196 .usage
= "[command_name ...]",
1197 .help
= "Returns the command modes allowed by a command:"
1198 "'any', 'config', or 'exec'. If no command is"
1199 "specified, returns the current command mode. "
1200 "Returns 'unknown' if an unknown command is given. "
1201 "Command can be multiple tokens.",
1205 .mode
= COMMAND_ANY
,
1206 .jim_handler
= jim_command_type
,
1207 .usage
= "command_name [...]",
1208 .help
= "Returns the type of built-in command:"
1209 "'native', 'simple', 'group', or 'unknown'. "
1210 "Command can be multiple tokens.",
1212 COMMAND_REGISTRATION_DONE
1215 static const struct command_registration command_builtin_handlers
[] = {
1218 .handler
= jim_echo
,
1219 .mode
= COMMAND_ANY
,
1220 .help
= "Logs a message at \"user\" priority. "
1221 "Output message to stdout. "
1222 "Option \"-n\" suppresses trailing newline",
1223 .usage
= "[-n] string",
1226 .name
= "add_help_text",
1227 .handler
= handle_help_add_command
,
1228 .mode
= COMMAND_ANY
,
1229 .help
= "Add new command help text; "
1230 "Command can be multiple tokens.",
1231 .usage
= "command_name helptext_string",
1234 .name
= "add_usage_text",
1235 .handler
= handle_help_add_command
,
1236 .mode
= COMMAND_ANY
,
1237 .help
= "Add new command usage text; "
1238 "command can be multiple tokens.",
1239 .usage
= "command_name usage_string",
1243 .handler
= handle_sleep_command
,
1244 .mode
= COMMAND_ANY
,
1245 .help
= "Sleep for specified number of milliseconds. "
1246 "\"busy\" will busy wait instead (avoid this).",
1247 .usage
= "milliseconds ['busy']",
1251 .handler
= handle_help_command
,
1252 .mode
= COMMAND_ANY
,
1253 .help
= "Show full command help; "
1254 "command can be multiple tokens.",
1255 .usage
= "[command_name]",
1259 .handler
= handle_help_command
,
1260 .mode
= COMMAND_ANY
,
1261 .help
= "Show basic command usage; "
1262 "command can be multiple tokens.",
1263 .usage
= "[command_name]",
1267 .mode
= COMMAND_ANY
,
1268 .help
= "core command group (introspection)",
1269 .chain
= command_subcommand_handlers
,
1271 COMMAND_REGISTRATION_DONE
1274 struct command_context
*command_init(const char *startup_tcl
, Jim_Interp
*interp
)
1276 struct command_context
*context
= malloc(sizeof(struct command_context
));
1279 context
->mode
= COMMAND_EXEC
;
1280 context
->commands
= NULL
;
1281 context
->current_target
= 0;
1282 context
->output_handler
= NULL
;
1283 context
->output_handler_priv
= NULL
;
1285 /* Create a jim interpreter if we were not handed one */
1286 if (interp
== NULL
) {
1287 /* Create an interpreter */
1288 interp
= Jim_CreateInterp();
1289 /* Add all the Jim core commands */
1290 Jim_RegisterCoreCommands(interp
);
1291 Jim_InitStaticExtensions(interp
);
1294 context
->interp
= interp
;
1296 /* Stick to lowercase for HostOS strings. */
1297 #if defined(_MSC_VER)
1298 /* WinXX - is generic, the forward
1299 * looking problem is this:
1301 * "win32" or "win64"
1303 * "winxx" is generic.
1306 #elif defined(__linux__)
1308 #elif defined(__APPLE__) || defined(__DARWIN__)
1310 #elif defined(__CYGWIN__)
1312 #elif defined(__MINGW32__)
1314 #elif defined(__ECOS)
1316 #elif defined(__FreeBSD__)
1318 #elif defined(__OpenBSD__)
1321 #warning "Unrecognized host OS..."
1324 Jim_SetGlobalVariableStr(interp
, "ocd_HOSTOS",
1325 Jim_NewStringObj(interp
, HostOs
, strlen(HostOs
)));
1327 Jim_CreateCommand(interp
, "ocd_find", jim_find
, NULL
, NULL
);
1328 Jim_CreateCommand(interp
, "capture", jim_capture
, NULL
, NULL
);
1330 register_commands(context
, NULL
, command_builtin_handlers
);
1332 Jim_SetAssocData(interp
, "context", NULL
, context
);
1333 if (Jim_Eval_Named(interp
, startup_tcl
, "embedded:startup.tcl", 1) == JIM_ERR
) {
1334 LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD)");
1335 Jim_MakeErrorMessage(interp
);
1336 LOG_USER_N("%s", Jim_GetString(Jim_GetResult(interp
), NULL
));
1339 Jim_DeleteAssocData(interp
, "context");
1344 int command_context_mode(struct command_context
*cmd_ctx
, enum command_mode mode
)
1347 return ERROR_COMMAND_SYNTAX_ERROR
;
1349 cmd_ctx
->mode
= mode
;
1353 void process_jim_events(struct command_context
*cmd_ctx
)
1355 static int recursion
;
1360 Jim_ProcessEvents(cmd_ctx
->interp
, JIM_ALL_EVENTS
| JIM_DONT_WAIT
);
1364 #define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max) \
1365 int parse ## name(const char *str, type * ul) \
1368 LOG_ERROR("Invalid command argument"); \
1369 return ERROR_COMMAND_ARGUMENT_INVALID; \
1372 *ul = func(str, &end, 0); \
1374 LOG_ERROR("Invalid command argument"); \
1375 return ERROR_COMMAND_ARGUMENT_INVALID; \
1377 if ((max == *ul) && (ERANGE == errno)) { \
1378 LOG_ERROR("Argument overflow"); \
1379 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
1381 if (min && (min == *ul) && (ERANGE == errno)) { \
1382 LOG_ERROR("Argument underflow"); \
1383 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
1387 DEFINE_PARSE_NUM_TYPE(_ulong
, unsigned long, strtoul
, 0, ULONG_MAX
)
1388 DEFINE_PARSE_NUM_TYPE(_ullong
, unsigned long long, strtoull
, 0, ULLONG_MAX
)
1389 DEFINE_PARSE_NUM_TYPE(_long
, long, strtol
, LONG_MIN
, LONG_MAX
)
1390 DEFINE_PARSE_NUM_TYPE(_llong
, long long, strtoll
, LLONG_MIN
, LLONG_MAX
)
1392 #define DEFINE_PARSE_WRAPPER(name, type, min, max, functype, funcname) \
1393 int parse ## name(const char *str, type * ul) \
1396 int retval = parse ## funcname(str, &n); \
1397 if (ERROR_OK != retval) \
1400 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
1402 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
1407 #define DEFINE_PARSE_ULONG(name, type, min, max) \
1408 DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long, _ulong)
1409 DEFINE_PARSE_ULONG(_uint
, unsigned, 0, UINT_MAX
)
1410 DEFINE_PARSE_ULONG(_u32
, uint32_t, 0, UINT32_MAX
)
1411 DEFINE_PARSE_ULONG(_u16
, uint16_t, 0, UINT16_MAX
)
1412 DEFINE_PARSE_ULONG(_u8
, uint8_t, 0, UINT8_MAX
)
1414 #define DEFINE_PARSE_LONG(name, type, min, max) \
1415 DEFINE_PARSE_WRAPPER(name, type, min, max, long, _long)
1416 DEFINE_PARSE_LONG(_int
, int, n
< INT_MIN
, INT_MAX
)
1417 DEFINE_PARSE_LONG(_s32
, int32_t, n
< INT32_MIN
, INT32_MAX
)
1418 DEFINE_PARSE_LONG(_s16
, int16_t, n
< INT16_MIN
, INT16_MAX
)
1419 DEFINE_PARSE_LONG(_s8
, int8_t, n
< INT8_MIN
, INT8_MAX
)
1421 static int command_parse_bool(const char *in
, bool *out
,
1422 const char *on
, const char *off
)
1424 if (strcasecmp(in
, on
) == 0)
1426 else if (strcasecmp(in
, off
) == 0)
1429 return ERROR_COMMAND_SYNTAX_ERROR
;
1433 int command_parse_bool_arg(const char *in
, bool *out
)
1435 if (command_parse_bool(in
, out
, "on", "off") == ERROR_OK
)
1437 if (command_parse_bool(in
, out
, "enable", "disable") == ERROR_OK
)
1439 if (command_parse_bool(in
, out
, "true", "false") == ERROR_OK
)
1441 if (command_parse_bool(in
, out
, "yes", "no") == ERROR_OK
)
1443 if (command_parse_bool(in
, out
, "1", "0") == ERROR_OK
)
1445 return ERROR_COMMAND_SYNTAX_ERROR
;
1448 COMMAND_HELPER(handle_command_parse_bool
, bool *out
, const char *label
)
1452 const char *in
= CMD_ARGV
[0];
1453 if (command_parse_bool_arg(in
, out
) != ERROR_OK
) {
1454 LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME
, in
);
1455 return ERROR_COMMAND_SYNTAX_ERROR
;
1460 LOG_INFO("%s is %s", label
, *out
? "enabled" : "disabled");
1463 return ERROR_COMMAND_SYNTAX_ERROR
;
Linking to existing account procedure
If you already have an account and want to add another login method
you
MUST first sign in with your existing account and
then change URL to read
https://review.openocd.org/login/?link
to get to this page again but this time it'll work for linking. Thank you.
SSH host keys fingerprints
1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=.. |
|+o.. . |
|*.o . . |
|+B . . . |
|Bo. = o S |
|Oo.+ + = |
|oB=.* = . o |
| =+=.+ + E |
|. .=o . o |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)