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*/
38 // @todo the inclusion of target.h here is a layering violation
41 #include "configuration.h"
43 #include "time_support.h"
44 #include "jim-eventloop.h"
47 /* nice short description of source file */
48 #define __THIS__FILE__ "command.c"
50 Jim_Interp
*interp
= NULL
;
52 static int run_command(struct command_context
*context
,
53 struct command
*c
, const char *words
[], unsigned num_words
);
55 static void tcl_output(void *privData
, const char *file
, unsigned line
,
56 const char *function
, const char *string
)
58 Jim_Obj
*tclOutput
= (Jim_Obj
*)privData
;
59 Jim_AppendString(interp
, tclOutput
, string
, strlen(string
));
62 static Jim_Obj
*command_log_capture_start(Jim_Interp
*interp
)
64 /* capture log output and return it. A garbage collect can
65 * happen, so we need a reference count to this object */
66 Jim_Obj
*tclOutput
= Jim_NewStringObj(interp
, "", 0);
67 if (NULL
== tclOutput
)
69 Jim_IncrRefCount(tclOutput
);
70 log_add_callback(tcl_output
, tclOutput
);
74 static void command_log_capture_finish(Jim_Interp
*interp
, Jim_Obj
*tclOutput
)
76 log_remove_callback(tcl_output
, tclOutput
);
77 Jim_SetResult(interp
, tclOutput
);
78 Jim_DecrRefCount(interp
, tclOutput
);
81 static int command_retval_set(Jim_Interp
*interp
, int retval
)
83 int *return_retval
= Jim_GetAssocData(interp
, "retval");
84 if (return_retval
!= NULL
)
85 *return_retval
= retval
;
87 return (retval
== ERROR_OK
) ? JIM_OK
: JIM_ERR
;
90 extern struct command_context
*global_cmd_ctx
;
92 void script_debug(Jim_Interp
*interp
, const char *name
,
93 unsigned argc
, Jim_Obj
*const *argv
)
95 LOG_DEBUG("command - %s", name
);
96 for (unsigned i
= 0; i
< argc
; i
++)
99 const char *w
= Jim_GetString(argv
[i
], &len
);
101 /* end of line comment? */
105 LOG_DEBUG("%s - argv[%d]=%s", name
, i
, w
);
109 static void script_command_args_free(const char **words
, unsigned nwords
)
111 for (unsigned i
= 0; i
< nwords
; i
++)
112 free((void *)words
[i
]);
115 static const char **script_command_args_alloc(
116 unsigned argc
, Jim_Obj
*const *argv
, unsigned *nwords
)
118 const char **words
= malloc(argc
* sizeof(char *));
123 for (i
= 0; i
< argc
; i
++)
126 const char *w
= Jim_GetString(argv
[i
], &len
);
127 /* a comment may end the line early */
131 words
[i
] = strdup(w
);
132 if (words
[i
] == NULL
)
134 script_command_args_free(words
, i
);
142 static struct command_context
*current_command_context(void)
144 /* grab the command context from the associated data */
145 struct command_context
*cmd_ctx
= Jim_GetAssocData(interp
, "context");
148 /* Tcl can invoke commands directly instead of via command_run_line(). This would
149 * happen when the Jim Tcl interpreter is provided by eCos.
151 cmd_ctx
= global_cmd_ctx
;
156 static int script_command_run(Jim_Interp
*interp
,
157 int argc
, Jim_Obj
*const *argv
, struct command
*c
, bool capture
)
159 target_call_timer_callbacks_now();
160 LOG_USER_N("%s", ""); /* Keep GDB connection alive*/
163 const char **words
= script_command_args_alloc(argc
, argv
, &nwords
);
167 Jim_Obj
*tclOutput
= NULL
;
169 tclOutput
= command_log_capture_start(interp
);
171 struct command_context
*cmd_ctx
= current_command_context();
172 int retval
= run_command(cmd_ctx
, c
, (const char **)words
, nwords
);
175 command_log_capture_finish(interp
, tclOutput
);
177 script_command_args_free(words
, nwords
);
178 return command_retval_set(interp
, retval
);
181 static int script_command(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
183 /* the private data is stashed in the interp structure */
185 struct command
*c
= interp
->cmdPrivData
;
187 script_debug(interp
, c
->name
, argc
, argv
);
188 return script_command_run(interp
, argc
, argv
, c
, true);
191 static struct command
*command_root(struct command
*c
)
193 while (NULL
!= c
->parent
)
199 * Find a command by name from a list of commands.
200 * @returns Returns the named command if it exists in the list.
201 * Returns NULL otherwise.
203 static struct command
*command_find(struct command
*head
, const char *name
)
205 for (struct command
*cc
= head
; cc
; cc
= cc
->next
)
207 if (strcmp(cc
->name
, name
) == 0)
212 struct command
*command_find_in_context(struct command_context
*cmd_ctx
,
215 return command_find(cmd_ctx
->commands
, name
);
217 struct command
*command_find_in_parent(struct command
*parent
,
220 return command_find(parent
->children
, name
);
224 * Add the command into the linked list, sorted by name.
225 * @param head Address to head of command list pointer, which may be
226 * updated if @c c gets inserted at the beginning of the list.
227 * @param c The command to add to the list pointed to by @c head.
229 static void command_add_child(struct command
**head
, struct command
*c
)
238 while ((*head
)->next
&& (strcmp(c
->name
, (*head
)->name
) > 0))
239 head
= &(*head
)->next
;
241 if (strcmp(c
->name
, (*head
)->name
) > 0) {
242 c
->next
= (*head
)->next
;
250 static struct command
**command_list_for_parent(
251 struct command_context
*cmd_ctx
, struct command
*parent
)
253 return parent
? &parent
->children
: &cmd_ctx
->commands
;
256 static void command_free(struct command
*c
)
258 /// @todo if command has a handler, unregister its jim command!
260 while (NULL
!= c
->children
)
262 struct command
*tmp
= c
->children
;
263 c
->children
= tmp
->next
;
270 free((void*)c
->help
);
272 free((void*)c
->usage
);
276 static struct command
*command_new(struct command_context
*cmd_ctx
,
277 struct command
*parent
, const struct command_registration
*cr
)
281 struct command
*c
= calloc(1, sizeof(struct command
));
285 c
->name
= strdup(cr
->name
);
287 c
->help
= strdup(cr
->help
);
289 c
->usage
= strdup(cr
->usage
);
291 if (!c
->name
|| (cr
->help
&& !c
->help
) || (cr
->usage
&& !c
->usage
))
292 goto command_new_error
;
295 c
->handler
= cr
->handler
;
296 c
->jim_handler
= cr
->jim_handler
;
297 c
->jim_handler_data
= cr
->jim_handler_data
;
300 command_add_child(command_list_for_parent(cmd_ctx
, parent
), c
);
309 static int command_unknown(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
);
311 static int register_command_handler(struct command
*c
)
313 const char *ocd_name
= alloc_printf("ocd_%s", c
->name
);
314 if (NULL
== ocd_name
)
317 LOG_DEBUG("registering '%s'...", ocd_name
);
319 Jim_CmdProc func
= c
->handler
? &script_command
: &command_unknown
;
320 int retval
= Jim_CreateCommand(interp
, ocd_name
, func
, c
, NULL
);
321 free((void *)ocd_name
);
322 if (JIM_OK
!= retval
)
325 /* we now need to add an overrideable proc */
326 const char *override_name
= alloc_printf(
327 "proc %s {args} {eval ocd_bouncer %s $args}",
329 if (NULL
== override_name
)
332 retval
= Jim_Eval_Named(interp
, override_name
, __FILE__
, __LINE__
);
333 free((void *)override_name
);
338 struct command
* register_command(struct command_context
*context
,
339 struct command
*parent
, const struct command_registration
*cr
)
341 if (!context
|| !cr
->name
)
344 const char *name
= cr
->name
;
345 struct command
**head
= command_list_for_parent(context
, parent
);
346 struct command
*c
= command_find(*head
, name
);
349 LOG_ERROR("command '%s' is already registered in '%s' context",
350 name
, parent
? parent
->name
: "<global>");
354 c
= command_new(context
, parent
, cr
);
358 int retval
= ERROR_OK
;
359 if (NULL
!= cr
->jim_handler
&& NULL
== parent
)
361 retval
= Jim_CreateCommand(interp
, cr
->name
,
362 cr
->jim_handler
, cr
->jim_handler_data
, NULL
);
364 else if (NULL
!= cr
->handler
|| NULL
!= parent
)
365 retval
= register_command_handler(command_root(c
));
367 if (ERROR_OK
!= retval
)
369 unregister_command(context
, parent
, name
);
375 int register_commands(struct command_context
*cmd_ctx
, struct command
*parent
,
376 const struct command_registration
*cmds
)
378 int retval
= ERROR_OK
;
380 for (i
= 0; cmds
[i
].name
|| cmds
[i
].chain
; i
++)
382 const struct command_registration
*cr
= cmds
+ i
;
384 struct command
*c
= NULL
;
385 if (NULL
!= cr
->name
)
387 c
= register_command(cmd_ctx
, parent
, cr
);
394 if (NULL
!= cr
->chain
)
396 struct command
*p
= c
? : parent
;
397 retval
= register_commands(cmd_ctx
, p
, cr
->chain
);
398 if (ERROR_OK
!= retval
)
402 if (ERROR_OK
!= retval
)
404 for (unsigned j
= 0; j
< i
; j
++)
405 unregister_command(cmd_ctx
, parent
, cmds
[j
].name
);
410 int unregister_all_commands(struct command_context
*context
,
411 struct command
*parent
)
416 struct command
**head
= command_list_for_parent(context
, parent
);
417 while (NULL
!= *head
)
419 struct command
*tmp
= *head
;
427 int unregister_command(struct command_context
*context
,
428 struct command
*parent
, const char *name
)
430 if ((!context
) || (!name
))
431 return ERROR_INVALID_ARGUMENTS
;
433 struct command
*p
= NULL
;
434 struct command
**head
= command_list_for_parent(context
, parent
);
435 for (struct command
*c
= *head
; NULL
!= c
; p
= c
, c
= c
->next
)
437 if (strcmp(name
, c
->name
) != 0)
452 void command_set_handler_data(struct command
*c
, void *p
)
454 if (NULL
!= c
->handler
|| NULL
!= c
->jim_handler
)
455 c
->jim_handler_data
= p
;
456 for (struct command
*cc
= c
->children
; NULL
!= cc
; cc
= cc
->next
)
457 command_set_handler_data(cc
, p
);
460 void command_output_text(struct command_context
*context
, const char *data
)
462 if (context
&& context
->output_handler
&& data
) {
463 context
->output_handler(context
, data
);
467 void command_print_sameline(struct command_context
*context
, const char *format
, ...)
472 va_start(ap
, format
);
474 string
= alloc_vprintf(format
, ap
);
477 /* we want this collected in the log + we also want to pick it up as a tcl return
480 * The latter bit isn't precisely neat, but will do for now.
482 LOG_USER_N("%s", string
);
483 /* We already printed it above */
484 /* command_output_text(context, string); */
491 void command_print(struct command_context
*context
, const char *format
, ...)
496 va_start(ap
, format
);
498 string
= alloc_vprintf(format
, ap
);
501 strcat(string
, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one char longer */
502 /* we want this collected in the log + we also want to pick it up as a tcl return
505 * The latter bit isn't precisely neat, but will do for now.
507 LOG_USER_N("%s", string
);
508 /* We already printed it above */
509 /* command_output_text(context, string); */
516 static char *__command_name(struct command
*c
, char delim
, unsigned extra
)
519 unsigned len
= strlen(c
->name
);
520 if (NULL
== c
->parent
) {
521 // allocate enough for the name, child names, and '\0'
522 name
= malloc(len
+ extra
+ 1);
523 strcpy(name
, c
->name
);
525 // parent's extra must include both the space and name
526 name
= __command_name(c
->parent
, delim
, 1 + len
+ extra
);
527 char dstr
[2] = { delim
, 0 };
529 strcat(name
, c
->name
);
533 char *command_name(struct command
*c
, char delim
)
535 return __command_name(c
, delim
, 0);
538 static bool command_can_run(struct command_context
*cmd_ctx
, struct command
*c
)
540 return c
->mode
== COMMAND_ANY
|| c
->mode
== cmd_ctx
->mode
;
543 static int run_command(struct command_context
*context
,
544 struct command
*c
, const char *words
[], unsigned num_words
)
546 if (!command_can_run(context
, c
))
548 /* Config commands can not run after the config stage */
549 LOG_ERROR("The '%s' command must be used before 'init'.", c
->name
);
553 struct command_invocation cmd
= {
556 .argc
= num_words
- 1,
559 int retval
= c
->handler(&cmd
);
560 if (retval
== ERROR_COMMAND_SYNTAX_ERROR
)
562 /* Print help for command */
563 char *full_name
= command_name(c
, ' ');
564 if (NULL
!= full_name
) {
565 command_run_linef(context
, "help %s", full_name
);
570 else if (retval
== ERROR_COMMAND_CLOSE_CONNECTION
)
572 /* just fall through for a shutdown request */
574 else if (retval
!= ERROR_OK
)
576 /* we do not print out an error message because the command *should*
577 * have printed out an error
579 LOG_DEBUG("Command failed with error code %d", retval
);
585 int command_run_line(struct command_context
*context
, char *line
)
587 /* all the parent commands have been registered with the interpreter
588 * so, can just evaluate the line as a script and check for
591 /* run the line thru a script engine */
592 int retval
= ERROR_FAIL
;
594 /* Beware! This code needs to be reentrant. It is also possible
595 * for OpenOCD commands to be invoked directly from Tcl. This would
596 * happen when the Jim Tcl interpreter is provided by eCos for
599 Jim_DeleteAssocData(interp
, "context");
600 retcode
= Jim_SetAssocData(interp
, "context", NULL
, context
);
601 if (retcode
== JIM_OK
)
603 /* associated the return value */
604 Jim_DeleteAssocData(interp
, "retval");
605 retcode
= Jim_SetAssocData(interp
, "retval", NULL
, &retval
);
606 if (retcode
== JIM_OK
)
608 retcode
= Jim_Eval_Named(interp
, line
, __THIS__FILE__
, __LINE__
);
610 Jim_DeleteAssocData(interp
, "retval");
612 Jim_DeleteAssocData(interp
, "context");
614 if (retcode
== JIM_ERR
) {
615 if (retval
!= ERROR_COMMAND_CLOSE_CONNECTION
)
617 /* We do not print the connection closed error message */
618 Jim_PrintErrorMessage(interp
);
620 if (retval
== ERROR_OK
)
622 /* It wasn't a low level OpenOCD command that failed */
626 } else if (retcode
== JIM_EXIT
) {
628 /* exit(Jim_GetExitCode(interp)); */
633 result
= Jim_GetString(Jim_GetResult(interp
), &reslen
);
638 for (i
= 0; i
< reslen
; i
+= 256)
644 strncpy(buff
, result
+ i
, chunk
);
646 LOG_USER_N("%s", buff
);
648 LOG_USER_N("%s", "\n");
655 int command_run_linef(struct command_context
*context
, const char *format
, ...)
657 int retval
= ERROR_FAIL
;
660 va_start(ap
, format
);
661 string
= alloc_vprintf(format
, ap
);
664 retval
= command_run_line(context
, string
);
670 void command_set_output_handler(struct command_context
* context
,
671 command_output_handler_t output_handler
, void *priv
)
673 context
->output_handler
= output_handler
;
674 context
->output_handler_priv
= priv
;
677 struct command_context
* copy_command_context(struct command_context
* context
)
679 struct command_context
* copy_context
= malloc(sizeof(struct command_context
));
681 *copy_context
= *context
;
686 int command_done(struct command_context
*context
)
694 /* find full path to file */
695 static int jim_find(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
699 const char *file
= Jim_GetString(argv
[1], NULL
);
700 char *full_path
= find_file(file
);
701 if (full_path
== NULL
)
703 Jim_Obj
*result
= Jim_NewStringObj(interp
, full_path
, strlen(full_path
));
706 Jim_SetResult(interp
, result
);
710 static int jim_echo(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
714 const char *str
= Jim_GetString(argv
[1], NULL
);
719 static size_t openocd_jim_fwrite(const void *_ptr
, size_t size
, size_t n
, void *cookie
)
725 /* make it a char easier to read code */
729 if (ptr
== NULL
|| interp
== NULL
|| nbytes
== 0) {
733 /* do we have to chunk it? */
734 if (ptr
[nbytes
] == 0)
736 /* no it is a C style string */
737 LOG_USER_N("%s", ptr
);
740 /* GRR we must chunk - not null terminated */
750 memcpy(chunk
, ptr
, x
);
754 LOG_USER_N("%s", chunk
);
762 static size_t openocd_jim_fread(void *ptr
, size_t size
, size_t n
, void *cookie
)
764 /* TCL wants to read... tell him no */
768 static int openocd_jim_vfprintf(void *cookie
, const char *fmt
, va_list ap
)
779 cp
= alloc_vprintf(fmt
, ap
);
782 LOG_USER_N("%s", cp
);
789 static int openocd_jim_fflush(void *cookie
)
791 /* nothing to flush */
795 static char* openocd_jim_fgets(char *s
, int size
, void *cookie
)
802 static int jim_capture(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
807 Jim_Obj
*tclOutput
= command_log_capture_start(interp
);
809 const char *str
= Jim_GetString(argv
[1], NULL
);
810 int retcode
= Jim_Eval_Named(interp
, str
, __THIS__FILE__
, __LINE__
);
812 command_log_capture_finish(interp
, tclOutput
);
817 static COMMAND_HELPER(command_help_find
, struct command
*head
,
818 struct command
**out
)
821 return ERROR_INVALID_ARGUMENTS
;
822 *out
= command_find(head
, CMD_ARGV
[0]);
823 if (NULL
== *out
&& strncmp(CMD_ARGV
[0], "ocd_", 4) == 0)
824 *out
= command_find(head
, CMD_ARGV
[0] + 4);
826 return ERROR_INVALID_ARGUMENTS
;
830 return CALL_COMMAND_HANDLER(command_help_find
, (*out
)->children
, out
);
833 static COMMAND_HELPER(command_help_show
, struct command
*c
, unsigned n
,
836 static COMMAND_HELPER(command_help_show_list
, struct command
*head
, unsigned n
,
839 for (struct command
*c
= head
; NULL
!= c
; c
= c
->next
)
840 CALL_COMMAND_HANDLER(command_help_show
, c
, n
, show_help
);
844 #define HELP_LINE_WIDTH(_n) (int)(76 - (2 * _n))
846 static void command_help_show_indent(unsigned n
)
848 for (unsigned i
= 0; i
< n
; i
++)
851 static void command_help_show_wrap(const char *str
, unsigned n
, unsigned n2
)
853 const char *cp
= str
, *last
= str
;
856 const char *next
= last
;
861 } while (*next
!= ' ' && *next
!= '\t' && *next
!= '\0');
862 } while ((next
- last
< HELP_LINE_WIDTH(n
)) && *next
!= '\0');
863 if (next
- last
< HELP_LINE_WIDTH(n
))
865 command_help_show_indent(n
);
866 LOG_USER_N("%.*s", (int)(cp
- last
), last
);
872 static COMMAND_HELPER(command_help_show
, struct command
*c
, unsigned n
,
875 char *cmd_name
= command_name(c
, ' ');
876 if (NULL
== cmd_name
)
879 command_help_show_indent(n
);
880 LOG_USER_N("%s", cmd_name
);
885 command_help_show_wrap(c
->usage
, 0, n
+ 5);
892 const char *stage_msg
;
894 case COMMAND_CONFIG
: stage_msg
= "CONFIG"; break;
895 case COMMAND_EXEC
: stage_msg
= "EXEC"; break;
896 case COMMAND_ANY
: stage_msg
= "CONFIG or EXEC"; break;
897 default: stage_msg
= "***UNKNOWN***"; break;
899 char *msg
= alloc_printf("%s%sValid Modes: %s",
900 c
->help
? : "", c
->help
? " " : "", stage_msg
);
903 command_help_show_wrap(msg
, n
+ 3, n
+ 3);
912 return CALL_COMMAND_HANDLER(command_help_show_list
,
913 c
->children
, n
, show_help
);
915 COMMAND_HANDLER(handle_help_command
)
917 bool full
= strcmp(CMD_NAME
, "help") == 0;
919 struct command
*c
= CMD_CTX
->commands
;
922 return CALL_COMMAND_HANDLER(command_help_show_list
, c
, 0, full
);
924 int retval
= CALL_COMMAND_HANDLER(command_help_find
, c
, &c
);
925 if (ERROR_OK
!= retval
)
928 return CALL_COMMAND_HANDLER(command_help_show
, c
, 0, full
);
931 static int command_unknown_find(unsigned argc
, Jim_Obj
*const *argv
,
932 struct command
*head
, struct command
**out
, bool top_level
)
936 const char *cmd_name
= Jim_GetString(argv
[0], NULL
);
937 struct command
*c
= command_find(head
, cmd_name
);
938 if (NULL
== c
&& top_level
&& strncmp(cmd_name
, "ocd_", 4) == 0)
939 c
= command_find(head
, cmd_name
+ 4);
943 return command_unknown_find(--argc
, ++argv
, (*out
)->children
, out
, false);
946 static int command_unknown(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
948 const char *cmd_name
= Jim_GetString(argv
[0], NULL
);
949 if (strcmp(cmd_name
, "unknown") == 0)
956 script_debug(interp
, cmd_name
, argc
, argv
);
958 struct command_context
*cmd_ctx
= current_command_context();
959 struct command
*c
= cmd_ctx
->commands
;
960 int remaining
= command_unknown_find(argc
, argv
, c
, &c
, true);
961 // if nothing could be consumed, then it's really an unknown command
962 if (remaining
== argc
)
964 const char *cmd
= Jim_GetString(argv
[0], NULL
);
965 LOG_ERROR("Unknown command:\n %s", cmd
);
970 Jim_Obj
*const *start
;
972 if (c
->handler
|| c
->jim_handler
)
974 // include the command name in the list
975 count
= remaining
+ 1;
976 start
= argv
+ (argc
- remaining
- 1);
980 c
= command_find(cmd_ctx
->commands
, "help");
983 LOG_ERROR("unknown command, but help is missing too");
986 count
= argc
- remaining
;
990 // pass the command through to the intended handler
993 interp
->cmdPrivData
= c
->jim_handler_data
;
994 return (*c
->jim_handler
)(interp
, count
, start
);
997 return script_command_run(interp
, count
, start
, c
, found
);
1000 static int jim_command_mode(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1002 struct command_context
*cmd_ctx
= current_command_context();
1003 enum command_mode mode
;
1006 struct command
*c
= cmd_ctx
->commands
;
1007 int remaining
= command_unknown_find(argc
- 1, argv
+ 1, c
, &c
, true);
1008 // if nothing could be consumed, then it's an unknown command
1009 if (remaining
== argc
- 1)
1011 Jim_SetResultString(interp
, "unknown", -1);
1017 mode
= cmd_ctx
->mode
;
1019 const char *mode_str
;
1021 case COMMAND_ANY
: mode_str
= "any"; break;
1022 case COMMAND_CONFIG
: mode_str
= "config"; break;
1023 case COMMAND_EXEC
: mode_str
= "exec"; break;
1024 default: mode_str
= "unknown"; break;
1026 Jim_SetResultString(interp
, mode_str
, -1);
1030 static int jim_command_type(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1035 struct command_context
*cmd_ctx
= current_command_context();
1036 struct command
*c
= cmd_ctx
->commands
;
1037 int remaining
= command_unknown_find(argc
- 1, argv
+ 1, c
, &c
, true);
1038 // if nothing could be consumed, then it's an unknown command
1039 if (remaining
== argc
- 1)
1041 Jim_SetResultString(interp
, "unknown", -1);
1046 Jim_SetResultString(interp
, "native", -1);
1047 else if (c
->handler
)
1048 Jim_SetResultString(interp
, "simple", -1);
1050 Jim_SetResultString(interp
, "group", -1);
1055 int help_add_command(struct command_context
*cmd_ctx
, struct command
*parent
,
1056 const char *cmd_name
, const char *help_text
, const char *usage
)
1058 struct command
**head
= command_list_for_parent(cmd_ctx
, parent
);
1059 struct command
*nc
= command_find(*head
, cmd_name
);
1062 // add a new command with help text
1063 struct command_registration cr
= {
1065 .mode
= COMMAND_ANY
,
1069 nc
= register_command(cmd_ctx
, parent
, &cr
);
1072 LOG_ERROR("failed to add '%s' help text", cmd_name
);
1075 LOG_DEBUG("added '%s' help text", cmd_name
);
1080 bool replaced
= false;
1083 free((void *)nc
->help
);
1086 nc
->help
= strdup(help_text
);
1088 LOG_INFO("replaced existing '%s' help", cmd_name
);
1090 LOG_DEBUG("added '%s' help text", cmd_name
);
1094 bool replaced
= false;
1097 free((void *)nc
->usage
);
1100 nc
->usage
= strdup(usage
);
1102 LOG_INFO("replaced existing '%s' usage", cmd_name
);
1104 LOG_DEBUG("added '%s' usage text", cmd_name
);
1109 COMMAND_HANDLER(handle_help_add_command
)
1113 LOG_ERROR("%s: insufficient arguments", CMD_NAME
);
1114 return ERROR_INVALID_ARGUMENTS
;
1117 // save help text and remove it from argument list
1118 const char *str
= CMD_ARGV
[--CMD_ARGC
];
1119 const char *help
= !strcmp(CMD_NAME
, "add_help_text") ? str
: NULL
;
1120 const char *usage
= !strcmp(CMD_NAME
, "add_usage_text") ? str
: NULL
;
1121 if (!help
&& !usage
)
1123 LOG_ERROR("command name '%s' is unknown", CMD_NAME
);
1124 return ERROR_INVALID_ARGUMENTS
;
1126 // likewise for the leaf command name
1127 const char *cmd_name
= CMD_ARGV
[--CMD_ARGC
];
1129 struct command
*c
= NULL
;
1132 c
= CMD_CTX
->commands
;
1133 int retval
= CALL_COMMAND_HANDLER(command_help_find
, c
, &c
);
1134 if (ERROR_OK
!= retval
)
1137 return help_add_command(CMD_CTX
, c
, cmd_name
, help
, usage
);
1140 /* sleep command sleeps for <n> miliseconds
1141 * this is useful in target startup scripts
1143 COMMAND_HANDLER(handle_sleep_command
)
1148 if (strcmp(CMD_ARGV
[1], "busy") == 0)
1151 return ERROR_COMMAND_SYNTAX_ERROR
;
1153 else if (CMD_ARGC
< 1 || CMD_ARGC
> 2)
1154 return ERROR_COMMAND_SYNTAX_ERROR
;
1156 unsigned long duration
= 0;
1157 int retval
= parse_ulong(CMD_ARGV
[0], &duration
);
1158 if (ERROR_OK
!= retval
)
1163 long long then
= timeval_ms();
1164 while (timeval_ms() - then
< (long long)duration
)
1166 target_call_timer_callbacks_now();
1171 busy_sleep(duration
);
1176 static const struct command_registration command_subcommand_handlers
[] = {
1179 .mode
= COMMAND_ANY
,
1180 .jim_handler
= &jim_command_mode
,
1181 .usage
= "[<name> ...]",
1182 .help
= "Returns the command modes allowed by a command:"
1183 "'any', 'config', or 'exec'. If no command is"
1184 "specified, returns the current command mode.",
1188 .mode
= COMMAND_ANY
,
1189 .jim_handler
= &jim_command_type
,
1190 .usage
= "<name> ...",
1191 .help
= "Returns the type of built-in command:"
1192 "'native', 'simple', 'group', or 'unknown'",
1194 COMMAND_REGISTRATION_DONE
1197 static const struct command_registration command_builtin_handlers
[] = {
1199 .name
= "add_help_text",
1200 .handler
= &handle_help_add_command
,
1201 .mode
= COMMAND_ANY
,
1202 .help
= "add new command help text",
1203 .usage
= "<command> [...] <help_text>]",
1206 .name
= "add_usage_text",
1207 .handler
= &handle_help_add_command
,
1208 .mode
= COMMAND_ANY
,
1209 .help
= "add new command usage text",
1210 .usage
= "<command> [...] <usage_text>]",
1214 .handler
= &handle_sleep_command
,
1215 .mode
= COMMAND_ANY
,
1216 .help
= "sleep for n milliseconds. "
1217 "\"busy\" will busy wait",
1218 .usage
= "<n> [busy]",
1222 .handler
= &handle_help_command
,
1223 .mode
= COMMAND_ANY
,
1224 .help
= "show full command help",
1225 .usage
= "[<command> ...]",
1229 .handler
= &handle_help_command
,
1230 .mode
= COMMAND_ANY
,
1231 .help
= "show basic command usage",
1232 .usage
= "[<command> ...]",
1237 .help
= "core command group (introspection)",
1238 .chain
= command_subcommand_handlers
,
1240 COMMAND_REGISTRATION_DONE
1243 struct command_context
* command_init(const char *startup_tcl
)
1245 struct command_context
* context
= malloc(sizeof(struct command_context
));
1248 context
->mode
= COMMAND_EXEC
;
1249 context
->commands
= NULL
;
1250 context
->current_target
= 0;
1251 context
->output_handler
= NULL
;
1252 context
->output_handler_priv
= NULL
;
1254 #if !BUILD_ECOSBOARD
1256 /* Create an interpreter */
1257 interp
= Jim_CreateInterp();
1258 /* Add all the Jim core commands */
1259 Jim_RegisterCoreCommands(interp
);
1262 #if defined(_MSC_VER)
1263 /* WinXX - is generic, the forward
1264 * looking problem is this:
1266 * "win32" or "win64"
1268 * "winxx" is generic.
1271 #elif defined(__linux__)
1273 #elif defined(__DARWIN__)
1275 #elif defined(__CYGWIN__)
1277 #elif defined(__MINGW32__)
1279 #elif defined(__ECOS)
1282 #warn unrecognized host OS...
1285 Jim_SetGlobalVariableStr(interp
, "ocd_HOSTOS",
1286 Jim_NewStringObj(interp
, HostOs
, strlen(HostOs
)));
1288 Jim_CreateCommand(interp
, "ocd_find", jim_find
, NULL
, NULL
);
1289 Jim_CreateCommand(interp
, "echo", jim_echo
, NULL
, NULL
);
1290 Jim_CreateCommand(interp
, "capture", jim_capture
, NULL
, NULL
);
1292 /* Set Jim's STDIO */
1293 interp
->cookie_stdin
= interp
;
1294 interp
->cookie_stdout
= interp
;
1295 interp
->cookie_stderr
= interp
;
1296 interp
->cb_fwrite
= openocd_jim_fwrite
;
1297 interp
->cb_fread
= openocd_jim_fread
;
1298 interp
->cb_vfprintf
= openocd_jim_vfprintf
;
1299 interp
->cb_fflush
= openocd_jim_fflush
;
1300 interp
->cb_fgets
= openocd_jim_fgets
;
1302 register_commands(context
, NULL
, command_builtin_handlers
);
1304 #if !BUILD_ECOSBOARD
1305 Jim_EventLoopOnLoad(interp
);
1307 Jim_SetAssocData(interp
, "context", NULL
, context
);
1308 if (Jim_Eval_Named(interp
, startup_tcl
, "embedded:startup.tcl",1) == JIM_ERR
)
1310 LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD)");
1311 Jim_PrintErrorMessage(interp
);
1314 Jim_DeleteAssocData(interp
, "context");
1319 int command_context_mode(struct command_context
*cmd_ctx
, enum command_mode mode
)
1322 return ERROR_INVALID_ARGUMENTS
;
1324 cmd_ctx
->mode
= mode
;
1328 void process_jim_events(void)
1330 #if !BUILD_ECOSBOARD
1331 static int recursion
= 0;
1336 Jim_ProcessEvents (interp
, JIM_ALL_EVENTS
| JIM_DONT_WAIT
);
1342 #define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max) \
1343 int parse##name(const char *str, type *ul) \
1347 LOG_ERROR("Invalid command argument"); \
1348 return ERROR_COMMAND_ARGUMENT_INVALID; \
1351 *ul = func(str, &end, 0); \
1354 LOG_ERROR("Invalid command argument"); \
1355 return ERROR_COMMAND_ARGUMENT_INVALID; \
1357 if ((max == *ul) && (ERANGE == errno)) \
1359 LOG_ERROR("Argument overflow"); \
1360 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
1362 if (min && (min == *ul) && (ERANGE == errno)) \
1364 LOG_ERROR("Argument underflow"); \
1365 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
1369 DEFINE_PARSE_NUM_TYPE(_ulong
, unsigned long , strtoul
, 0, ULONG_MAX
)
1370 DEFINE_PARSE_NUM_TYPE(_ullong
, unsigned long long, strtoull
, 0, ULLONG_MAX
)
1371 DEFINE_PARSE_NUM_TYPE(_long
, long , strtol
, LONG_MIN
, LONG_MAX
)
1372 DEFINE_PARSE_NUM_TYPE(_llong
, long long, strtoll
, LLONG_MIN
, LLONG_MAX
)
1374 #define DEFINE_PARSE_WRAPPER(name, type, min, max, functype, funcname) \
1375 int parse##name(const char *str, type *ul) \
1378 int retval = parse##funcname(str, &n); \
1379 if (ERROR_OK != retval) \
1382 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
1384 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
1389 #define DEFINE_PARSE_ULONG(name, type, min, max) \
1390 DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long, _ulong)
1391 DEFINE_PARSE_ULONG(_uint
, unsigned, 0, UINT_MAX
)
1392 DEFINE_PARSE_ULONG(_u32
, uint32_t, 0, UINT32_MAX
)
1393 DEFINE_PARSE_ULONG(_u16
, uint16_t, 0, UINT16_MAX
)
1394 DEFINE_PARSE_ULONG(_u8
, uint8_t, 0, UINT8_MAX
)
1396 #define DEFINE_PARSE_LONG(name, type, min, max) \
1397 DEFINE_PARSE_WRAPPER(name, type, min, max, long, _long)
1398 DEFINE_PARSE_LONG(_int
, int, n
< INT_MIN
, INT_MAX
)
1399 DEFINE_PARSE_LONG(_s32
, int32_t, n
< INT32_MIN
, INT32_MAX
)
1400 DEFINE_PARSE_LONG(_s16
, int16_t, n
< INT16_MIN
, INT16_MAX
)
1401 DEFINE_PARSE_LONG(_s8
, int8_t, n
< INT8_MIN
, INT8_MAX
)
1403 static int command_parse_bool(const char *in
, bool *out
,
1404 const char *on
, const char *off
)
1406 if (strcasecmp(in
, on
) == 0)
1408 else if (strcasecmp(in
, off
) == 0)
1411 return ERROR_COMMAND_SYNTAX_ERROR
;
1415 int command_parse_bool_arg(const char *in
, bool *out
)
1417 if (command_parse_bool(in
, out
, "on", "off") == ERROR_OK
)
1419 if (command_parse_bool(in
, out
, "enable", "disable") == ERROR_OK
)
1421 if (command_parse_bool(in
, out
, "true", "false") == ERROR_OK
)
1423 if (command_parse_bool(in
, out
, "yes", "no") == ERROR_OK
)
1425 if (command_parse_bool(in
, out
, "1", "0") == ERROR_OK
)
1427 return ERROR_INVALID_ARGUMENTS
;
1430 COMMAND_HELPER(handle_command_parse_bool
, bool *out
, const char *label
)
1434 const char *in
= CMD_ARGV
[0];
1435 if (command_parse_bool_arg(in
, out
) != ERROR_OK
)
1437 LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME
, in
);
1438 return ERROR_INVALID_ARGUMENTS
;
1443 LOG_INFO("%s is %s", label
, *out
? "enabled" : "disabled");
1446 return ERROR_INVALID_ARGUMENTS
;
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)