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 Jim_Interp
*interp
= NULL
;
49 static int run_command(struct command_context
*context
,
50 struct command
*c
, const char *words
[], unsigned num_words
);
52 static void tcl_output(void *privData
, const char *file
, unsigned line
,
53 const char *function
, const char *string
)
55 Jim_Obj
*tclOutput
= (Jim_Obj
*)privData
;
56 Jim_AppendString(interp
, tclOutput
, string
, strlen(string
));
59 static Jim_Obj
*command_log_capture_start(Jim_Interp
*interp
)
61 /* capture log output and return it. A garbage collect can
62 * happen, so we need a reference count to this object */
63 Jim_Obj
*tclOutput
= Jim_NewStringObj(interp
, "", 0);
64 if (NULL
== tclOutput
)
66 Jim_IncrRefCount(tclOutput
);
67 log_add_callback(tcl_output
, tclOutput
);
71 static void command_log_capture_finish(Jim_Interp
*interp
, Jim_Obj
*tclOutput
)
73 log_remove_callback(tcl_output
, tclOutput
);
74 Jim_SetResult(interp
, tclOutput
);
75 Jim_DecrRefCount(interp
, tclOutput
);
78 static int command_retval_set(Jim_Interp
*interp
, int retval
)
80 int *return_retval
= Jim_GetAssocData(interp
, "retval");
81 if (return_retval
!= NULL
)
82 *return_retval
= retval
;
84 return (retval
== ERROR_OK
) ? JIM_OK
: JIM_ERR
;
87 extern struct command_context
*global_cmd_ctx
;
89 void script_debug(Jim_Interp
*interp
, const char *name
,
90 unsigned argc
, Jim_Obj
*const *argv
)
92 LOG_DEBUG("command - %s", name
);
93 for (unsigned i
= 0; i
< argc
; i
++)
96 const char *w
= Jim_GetString(argv
[i
], &len
);
98 /* end of line comment? */
102 LOG_DEBUG("%s - argv[%d]=%s", name
, i
, w
);
106 static void script_command_args_free(const char **words
, unsigned nwords
)
108 for (unsigned i
= 0; i
< nwords
; i
++)
109 free((void *)words
[i
]);
112 static const char **script_command_args_alloc(
113 unsigned argc
, Jim_Obj
*const *argv
, unsigned *nwords
)
115 const char **words
= malloc(argc
* sizeof(char *));
120 for (i
= 0; i
< argc
; i
++)
123 const char *w
= Jim_GetString(argv
[i
], &len
);
124 /* a comment may end the line early */
128 words
[i
] = strdup(w
);
129 if (words
[i
] == NULL
)
131 script_command_args_free(words
, i
);
139 static struct command_context
*current_command_context(void)
141 /* grab the command context from the associated data */
142 struct command_context
*cmd_ctx
= Jim_GetAssocData(interp
, "context");
145 /* Tcl can invoke commands directly instead of via command_run_line(). This would
146 * happen when the Jim Tcl interpreter is provided by eCos.
148 cmd_ctx
= global_cmd_ctx
;
153 static int script_command_run(Jim_Interp
*interp
,
154 int argc
, Jim_Obj
*const *argv
, struct command
*c
, bool capture
)
156 target_call_timer_callbacks_now();
157 LOG_USER_N("%s", ""); /* Keep GDB connection alive*/
160 const char **words
= script_command_args_alloc(argc
, argv
, &nwords
);
164 Jim_Obj
*tclOutput
= NULL
;
166 tclOutput
= command_log_capture_start(interp
);
168 struct command_context
*cmd_ctx
= current_command_context();
169 int retval
= run_command(cmd_ctx
, c
, (const char **)words
, nwords
);
172 command_log_capture_finish(interp
, tclOutput
);
174 script_command_args_free(words
, nwords
);
175 return command_retval_set(interp
, retval
);
178 static int script_command(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
180 /* the private data is stashed in the interp structure */
182 struct command
*c
= interp
->cmdPrivData
;
184 script_debug(interp
, c
->name
, argc
, argv
);
185 return script_command_run(interp
, argc
, argv
, c
, true);
188 /* nice short description of source file */
189 #define __THIS__FILE__ "command.c"
192 * Find a command by name from a list of commands.
193 * @returns Returns the named command if it exists in the list.
194 * Returns NULL otherwise.
196 static struct command
*command_find(struct command
*head
, const char *name
)
198 for (struct command
*cc
= head
; cc
; cc
= cc
->next
)
200 if (strcmp(cc
->name
, name
) == 0)
205 struct command
*command_find_in_context(struct command_context
*cmd_ctx
,
208 return command_find(cmd_ctx
->commands
, name
);
210 struct command
*command_find_in_parent(struct command
*parent
,
213 return command_find(parent
->children
, name
);
217 * Add the command into the linked list, sorted by name.
218 * @param head Address to head of command list pointer, which may be
219 * updated if @c c gets inserted at the beginning of the list.
220 * @param c The command to add to the list pointed to by @c head.
222 static void command_add_child(struct command
**head
, struct command
*c
)
231 while ((*head
)->next
&& (strcmp(c
->name
, (*head
)->name
) > 0))
232 head
= &(*head
)->next
;
234 if (strcmp(c
->name
, (*head
)->name
) > 0) {
235 c
->next
= (*head
)->next
;
243 static struct command
**command_list_for_parent(
244 struct command_context
*cmd_ctx
, struct command
*parent
)
246 return parent
? &parent
->children
: &cmd_ctx
->commands
;
249 static struct command
*command_new(struct command_context
*cmd_ctx
,
250 struct command
*parent
, const struct command_registration
*cr
)
254 struct command
*c
= malloc(sizeof(struct command
));
255 memset(c
, 0, sizeof(struct command
));
257 c
->name
= strdup(cr
->name
);
259 c
->help
= strdup(cr
->help
);
261 c
->usage
= strdup(cr
->usage
);
263 c
->handler
= cr
->handler
;
264 c
->jim_handler
= cr
->jim_handler
;
265 c
->jim_handler_data
= cr
->jim_handler_data
;
268 command_add_child(command_list_for_parent(cmd_ctx
, parent
), c
);
272 static void command_free(struct command
*c
)
274 /// @todo if command has a handler, unregister its jim command!
276 while (NULL
!= c
->children
)
278 struct command
*tmp
= c
->children
;
279 c
->children
= tmp
->next
;
286 free((void*)c
->help
);
288 free((void*)c
->usage
);
292 static int register_command_handler(struct command
*c
)
294 int retval
= -ENOMEM
;
295 const char *full_name
= command_name(c
, '_');
296 if (NULL
== full_name
)
299 const char *ocd_name
= alloc_printf("ocd_%s", full_name
);
300 if (NULL
== full_name
)
303 Jim_CreateCommand(interp
, ocd_name
, script_command
, c
, NULL
);
304 free((void *)ocd_name
);
306 /* we now need to add an overrideable proc */
307 const char *override_name
= alloc_printf("proc %s {args} {"
308 "if {[catch {eval ocd_%s $args}] == 0} "
309 "{return \"\"} else {return -code error}}",
310 full_name
, full_name
);
311 if (NULL
== full_name
)
314 Jim_Eval_Named(interp
, override_name
, __THIS__FILE__
, __LINE__
);
315 free((void *)override_name
);
320 free((void *)full_name
);
324 struct command
* register_command(struct command_context
*context
,
325 struct command
*parent
, const struct command_registration
*cr
)
327 if (!context
|| !cr
->name
)
330 const char *name
= cr
->name
;
331 struct command
**head
= command_list_for_parent(context
, parent
);
332 struct command
*c
= command_find(*head
, name
);
335 LOG_ERROR("command '%s' is already registered in '%s' context",
336 name
, parent
? parent
->name
: "<global>");
340 c
= command_new(context
, parent
, cr
);
344 if (NULL
!= c
->handler
)
346 int retval
= register_command_handler(c
);
347 if (ERROR_OK
!= retval
)
349 unregister_command(context
, parent
, name
);
354 if (NULL
!= cr
->jim_handler
&& NULL
== parent
)
355 Jim_CreateCommand(interp
, cr
->name
, cr
->jim_handler
, cr
->jim_handler_data
, NULL
);
360 int register_commands(struct command_context
*cmd_ctx
, struct command
*parent
,
361 const struct command_registration
*cmds
)
363 int retval
= ERROR_OK
;
365 for (i
= 0; cmds
[i
].name
|| cmds
[i
].chain
; i
++)
367 const struct command_registration
*cr
= cmds
+ i
;
369 struct command
*c
= NULL
;
370 if (NULL
!= cr
->name
)
372 c
= register_command(cmd_ctx
, parent
, cr
);
379 if (NULL
!= cr
->chain
)
381 struct command
*p
= c
? : parent
;
382 retval
= register_commands(cmd_ctx
, p
, cr
->chain
);
383 if (ERROR_OK
!= retval
)
387 if (ERROR_OK
!= retval
)
389 for (unsigned j
= 0; j
< i
; j
++)
390 unregister_command(cmd_ctx
, parent
, cmds
[j
].name
);
395 int unregister_all_commands(struct command_context
*context
,
396 struct command
*parent
)
401 struct command
**head
= command_list_for_parent(context
, parent
);
402 while (NULL
!= *head
)
404 struct command
*tmp
= *head
;
412 int unregister_command(struct command_context
*context
,
413 struct command
*parent
, const char *name
)
415 if ((!context
) || (!name
))
416 return ERROR_INVALID_ARGUMENTS
;
418 struct command
*p
= NULL
;
419 struct command
**head
= command_list_for_parent(context
, parent
);
420 for (struct command
*c
= *head
; NULL
!= c
; p
= c
, c
= c
->next
)
422 if (strcmp(name
, c
->name
) != 0)
437 void command_output_text(struct command_context
*context
, const char *data
)
439 if (context
&& context
->output_handler
&& data
) {
440 context
->output_handler(context
, data
);
444 void command_print_sameline(struct command_context
*context
, const char *format
, ...)
449 va_start(ap
, format
);
451 string
= alloc_vprintf(format
, ap
);
454 /* we want this collected in the log + we also want to pick it up as a tcl return
457 * The latter bit isn't precisely neat, but will do for now.
459 LOG_USER_N("%s", string
);
460 /* We already printed it above */
461 /* command_output_text(context, string); */
468 void command_print(struct command_context
*context
, const char *format
, ...)
473 va_start(ap
, format
);
475 string
= alloc_vprintf(format
, ap
);
478 strcat(string
, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one char longer */
479 /* we want this collected in the log + we also want to pick it up as a tcl return
482 * The latter bit isn't precisely neat, but will do for now.
484 LOG_USER_N("%s", string
);
485 /* We already printed it above */
486 /* command_output_text(context, string); */
493 static char *__command_name(struct command
*c
, char delim
, unsigned extra
)
496 unsigned len
= strlen(c
->name
);
497 if (NULL
== c
->parent
) {
498 // allocate enough for the name, child names, and '\0'
499 name
= malloc(len
+ extra
+ 1);
500 strcpy(name
, c
->name
);
502 // parent's extra must include both the space and name
503 name
= __command_name(c
->parent
, delim
, 1 + len
+ extra
);
504 char dstr
[2] = { delim
, 0 };
506 strcat(name
, c
->name
);
510 char *command_name(struct command
*c
, char delim
)
512 return __command_name(c
, delim
, 0);
515 static int run_command(struct command_context
*context
,
516 struct command
*c
, const char *words
[], unsigned num_words
)
518 if (!((context
->mode
== COMMAND_CONFIG
) || (c
->mode
== COMMAND_ANY
) || (c
->mode
== context
->mode
)))
520 /* Config commands can not run after the config stage */
521 LOG_ERROR("Command '%s' only runs during configuration stage", c
->name
);
525 struct command_invocation cmd
= {
528 .argc
= num_words
- 1,
531 int retval
= c
->handler(&cmd
);
532 if (retval
== ERROR_COMMAND_SYNTAX_ERROR
)
534 /* Print help for command */
535 char *full_name
= command_name(c
, ' ');
536 if (NULL
!= full_name
) {
537 command_run_linef(context
, "help %s", full_name
);
542 else if (retval
== ERROR_COMMAND_CLOSE_CONNECTION
)
544 /* just fall through for a shutdown request */
546 else if (retval
!= ERROR_OK
)
548 /* we do not print out an error message because the command *should*
549 * have printed out an error
551 LOG_DEBUG("Command failed with error code %d", retval
);
557 int command_run_line(struct command_context
*context
, char *line
)
559 /* all the parent commands have been registered with the interpreter
560 * so, can just evaluate the line as a script and check for
563 /* run the line thru a script engine */
564 int retval
= ERROR_FAIL
;
566 /* Beware! This code needs to be reentrant. It is also possible
567 * for OpenOCD commands to be invoked directly from Tcl. This would
568 * happen when the Jim Tcl interpreter is provided by eCos for
571 Jim_DeleteAssocData(interp
, "context");
572 retcode
= Jim_SetAssocData(interp
, "context", NULL
, context
);
573 if (retcode
== JIM_OK
)
575 /* associated the return value */
576 Jim_DeleteAssocData(interp
, "retval");
577 retcode
= Jim_SetAssocData(interp
, "retval", NULL
, &retval
);
578 if (retcode
== JIM_OK
)
580 retcode
= Jim_Eval_Named(interp
, line
, __THIS__FILE__
, __LINE__
);
582 Jim_DeleteAssocData(interp
, "retval");
584 Jim_DeleteAssocData(interp
, "context");
586 if (retcode
== JIM_ERR
) {
587 if (retval
!= ERROR_COMMAND_CLOSE_CONNECTION
)
589 /* We do not print the connection closed error message */
590 Jim_PrintErrorMessage(interp
);
592 if (retval
== ERROR_OK
)
594 /* It wasn't a low level OpenOCD command that failed */
598 } else if (retcode
== JIM_EXIT
) {
600 /* exit(Jim_GetExitCode(interp)); */
605 result
= Jim_GetString(Jim_GetResult(interp
), &reslen
);
610 for (i
= 0; i
< reslen
; i
+= 256)
616 strncpy(buff
, result
+ i
, chunk
);
618 LOG_USER_N("%s", buff
);
620 LOG_USER_N("%s", "\n");
627 int command_run_linef(struct command_context
*context
, const char *format
, ...)
629 int retval
= ERROR_FAIL
;
632 va_start(ap
, format
);
633 string
= alloc_vprintf(format
, ap
);
636 retval
= command_run_line(context
, string
);
642 void command_set_output_handler(struct command_context
* context
,
643 command_output_handler_t output_handler
, void *priv
)
645 context
->output_handler
= output_handler
;
646 context
->output_handler_priv
= priv
;
649 struct command_context
* copy_command_context(struct command_context
* context
)
651 struct command_context
* copy_context
= malloc(sizeof(struct command_context
));
653 *copy_context
= *context
;
658 int command_done(struct command_context
*context
)
666 /* find full path to file */
667 static int jim_find(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
671 const char *file
= Jim_GetString(argv
[1], NULL
);
672 char *full_path
= find_file(file
);
673 if (full_path
== NULL
)
675 Jim_Obj
*result
= Jim_NewStringObj(interp
, full_path
, strlen(full_path
));
678 Jim_SetResult(interp
, result
);
682 static int jim_echo(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
686 const char *str
= Jim_GetString(argv
[1], NULL
);
691 static size_t openocd_jim_fwrite(const void *_ptr
, size_t size
, size_t n
, void *cookie
)
697 /* make it a char easier to read code */
701 if (ptr
== NULL
|| interp
== NULL
|| nbytes
== 0) {
705 /* do we have to chunk it? */
706 if (ptr
[nbytes
] == 0)
708 /* no it is a C style string */
709 LOG_USER_N("%s", ptr
);
712 /* GRR we must chunk - not null terminated */
722 memcpy(chunk
, ptr
, x
);
726 LOG_USER_N("%s", chunk
);
734 static size_t openocd_jim_fread(void *ptr
, size_t size
, size_t n
, void *cookie
)
736 /* TCL wants to read... tell him no */
740 static int openocd_jim_vfprintf(void *cookie
, const char *fmt
, va_list ap
)
751 cp
= alloc_vprintf(fmt
, ap
);
754 LOG_USER_N("%s", cp
);
761 static int openocd_jim_fflush(void *cookie
)
763 /* nothing to flush */
767 static char* openocd_jim_fgets(char *s
, int size
, void *cookie
)
774 static int jim_capture(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
779 Jim_Obj
*tclOutput
= command_log_capture_start(interp
);
781 const char *str
= Jim_GetString(argv
[1], NULL
);
782 int retcode
= Jim_Eval_Named(interp
, str
, __THIS__FILE__
, __LINE__
);
784 command_log_capture_finish(interp
, tclOutput
);
789 static COMMAND_HELPER(command_help_find
, struct command
*head
,
790 struct command
**out
)
793 return ERROR_INVALID_ARGUMENTS
;
794 *out
= command_find(head
, CMD_ARGV
[0]);
796 return ERROR_INVALID_ARGUMENTS
;
800 return CALL_COMMAND_HANDLER(command_help_find
, (*out
)->children
, out
);
803 static COMMAND_HELPER(command_help_show
, struct command
*c
, unsigned n
,
806 static COMMAND_HELPER(command_help_show_list
, struct command
*head
, unsigned n
,
809 for (struct command
*c
= head
; NULL
!= c
; c
= c
->next
)
810 CALL_COMMAND_HANDLER(command_help_show
, c
, n
, show_help
);
814 #define HELP_LINE_WIDTH(_n) (int)(76 - (2 * _n))
816 static void command_help_show_indent(unsigned n
)
818 for (unsigned i
= 0; i
< n
; i
++)
821 static void command_help_show_wrap(const char *str
, unsigned n
, unsigned n2
)
823 const char *cp
= str
, *last
= str
;
826 const char *next
= last
;
831 } while (*next
!= ' ' && *next
!= '\t' && *next
!= '\0');
832 } while ((next
- last
< HELP_LINE_WIDTH(n
)) && *next
!= '\0');
833 if (next
- last
< HELP_LINE_WIDTH(n
))
835 command_help_show_indent(n
);
836 LOG_USER_N("%.*s", (int)(cp
- last
), last
);
842 static COMMAND_HELPER(command_help_show
, struct command
*c
, unsigned n
,
845 command_help_show_indent(n
);
846 LOG_USER_N("%s", command_name(c
, ' '));
849 command_help_show_wrap(c
->usage
, 0, n
+ 5);
853 if (show_help
&& c
->help
)
854 command_help_show_wrap(c
->help
, n
+ 3, n
+ 3);
858 return CALL_COMMAND_HANDLER(command_help_show_list
,
859 c
->children
, n
, show_help
);
861 COMMAND_HANDLER(handle_help_command
)
863 bool full
= strcmp(CMD_NAME
, "help") == 0;
865 struct command
*c
= CMD_CTX
->commands
;
868 return CALL_COMMAND_HANDLER(command_help_show_list
, c
, 0, full
);
870 int retval
= CALL_COMMAND_HANDLER(command_help_find
, c
, &c
);
871 if (ERROR_OK
!= retval
)
874 return CALL_COMMAND_HANDLER(command_help_show
, c
, 0, full
);
877 static int command_unknown_find(unsigned argc
, Jim_Obj
*const *argv
,
878 struct command
*head
, struct command
**out
)
882 struct command
*c
= command_find(head
, Jim_GetString(argv
[0], NULL
));
886 return command_unknown_find(--argc
, ++argv
, (*out
)->children
, out
);
889 static int command_unknown(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
891 const char *cmd_name
= Jim_GetString(argv
[0], NULL
);
892 script_debug(interp
, cmd_name
, argc
- 1, argv
+ 1);
894 struct command_context
*cmd_ctx
= current_command_context();
895 struct command
*c
= cmd_ctx
->commands
;
896 int remaining
= command_unknown_find(argc
- 1, argv
+ 1, c
, &c
);
897 // if nothing could be consumed, then it's really an unknown command
898 if (remaining
== argc
- 1)
900 const char *cmd
= Jim_GetString(argv
[1], NULL
);
901 LOG_ERROR("Unknown command:\n %s", cmd
);
906 Jim_Obj
*const *start
;
908 if (c
->handler
|| c
->jim_handler
)
910 // include the command name in the list
911 count
= remaining
+ 1;
912 start
= argv
+ (argc
- remaining
- 1);
916 c
= command_find(cmd_ctx
->commands
, "help");
919 LOG_ERROR("unknown command, but help is missing too");
922 count
= argc
- remaining
;
926 // pass the command through to the intended handler
929 interp
->cmdPrivData
= c
->jim_handler_data
;
930 return (*c
->jim_handler
)(interp
, count
, start
);
933 return script_command_run(interp
, count
, start
, c
, found
);
936 int help_add_command(struct command_context
*cmd_ctx
, struct command
*parent
,
937 const char *cmd_name
, const char *help_text
, const char *usage
)
939 struct command
**head
= command_list_for_parent(cmd_ctx
, parent
);
940 struct command
*nc
= command_find(*head
, cmd_name
);
943 // add a new command with help text
944 struct command_registration cr
= {
950 nc
= register_command(cmd_ctx
, parent
, &cr
);
953 LOG_ERROR("failed to add '%s' help text", cmd_name
);
956 LOG_DEBUG("added '%s' help text", cmd_name
);
961 bool replaced
= false;
964 free((void *)nc
->help
);
967 nc
->help
= strdup(help_text
);
969 LOG_INFO("replaced existing '%s' help", cmd_name
);
971 LOG_DEBUG("added '%s' help text", cmd_name
);
975 bool replaced
= false;
978 free((void *)nc
->usage
);
981 nc
->usage
= strdup(usage
);
983 LOG_INFO("replaced existing '%s' usage", cmd_name
);
985 LOG_DEBUG("added '%s' usage text", cmd_name
);
990 COMMAND_HANDLER(handle_help_add_command
)
994 LOG_ERROR("%s: insufficient arguments", CMD_NAME
);
995 return ERROR_INVALID_ARGUMENTS
;
998 // save help text and remove it from argument list
999 const char *str
= CMD_ARGV
[--CMD_ARGC
];
1000 const char *help
= !strcmp(CMD_NAME
, "add_help_text") ? str
: NULL
;
1001 const char *usage
= !strcmp(CMD_NAME
, "add_usage_text") ? str
: NULL
;
1002 if (!help
&& !usage
)
1004 LOG_ERROR("command name '%s' is unknown", CMD_NAME
);
1005 return ERROR_INVALID_ARGUMENTS
;
1007 // likewise for the leaf command name
1008 const char *cmd_name
= CMD_ARGV
[--CMD_ARGC
];
1010 struct command
*c
= NULL
;
1013 c
= CMD_CTX
->commands
;
1014 int retval
= CALL_COMMAND_HANDLER(command_help_find
, c
, &c
);
1015 if (ERROR_OK
!= retval
)
1018 return help_add_command(CMD_CTX
, c
, cmd_name
, help
, usage
);
1021 /* sleep command sleeps for <n> miliseconds
1022 * this is useful in target startup scripts
1024 COMMAND_HANDLER(handle_sleep_command
)
1029 if (strcmp(CMD_ARGV
[1], "busy") == 0)
1032 return ERROR_COMMAND_SYNTAX_ERROR
;
1034 else if (CMD_ARGC
< 1 || CMD_ARGC
> 2)
1035 return ERROR_COMMAND_SYNTAX_ERROR
;
1037 unsigned long duration
= 0;
1038 int retval
= parse_ulong(CMD_ARGV
[0], &duration
);
1039 if (ERROR_OK
!= retval
)
1044 long long then
= timeval_ms();
1045 while (timeval_ms() - then
< (long long)duration
)
1047 target_call_timer_callbacks_now();
1052 busy_sleep(duration
);
1057 static const struct command_registration command_builtin_handlers
[] = {
1059 .name
= "add_help_text",
1060 .handler
= &handle_help_add_command
,
1061 .mode
= COMMAND_ANY
,
1062 .help
= "add new command help text",
1063 .usage
= "<command> [...] <help_text>]",
1066 .name
= "add_usage_text",
1067 .handler
= &handle_help_add_command
,
1068 .mode
= COMMAND_ANY
,
1069 .help
= "add new command usage text",
1070 .usage
= "<command> [...] <usage_text>]",
1074 .handler
= &handle_sleep_command
,
1075 .mode
= COMMAND_ANY
,
1076 .help
= "sleep for n milliseconds. "
1077 "\"busy\" will busy wait",
1078 .usage
= "<n> [busy]",
1082 .handler
= &handle_help_command
,
1083 .mode
= COMMAND_ANY
,
1084 .help
= "show full command help",
1085 .usage
= "[<command> ...]",
1089 .handler
= &handle_help_command
,
1090 .mode
= COMMAND_ANY
,
1091 .help
= "show basic command usage",
1092 .usage
= "[<command> ...]",
1094 COMMAND_REGISTRATION_DONE
1097 struct command_context
* command_init(const char *startup_tcl
)
1099 struct command_context
* context
= malloc(sizeof(struct command_context
));
1102 context
->mode
= COMMAND_EXEC
;
1103 context
->commands
= NULL
;
1104 context
->current_target
= 0;
1105 context
->output_handler
= NULL
;
1106 context
->output_handler_priv
= NULL
;
1108 #if !BUILD_ECOSBOARD
1110 /* Create an interpreter */
1111 interp
= Jim_CreateInterp();
1112 /* Add all the Jim core commands */
1113 Jim_RegisterCoreCommands(interp
);
1116 #if defined(_MSC_VER)
1117 /* WinXX - is generic, the forward
1118 * looking problem is this:
1120 * "win32" or "win64"
1122 * "winxx" is generic.
1125 #elif defined(__linux__)
1127 #elif defined(__DARWIN__)
1129 #elif defined(__CYGWIN__)
1131 #elif defined(__MINGW32__)
1133 #elif defined(__ECOS)
1136 #warn unrecognized host OS...
1139 Jim_SetGlobalVariableStr(interp
, "ocd_HOSTOS",
1140 Jim_NewStringObj(interp
, HostOs
, strlen(HostOs
)));
1142 Jim_CreateCommand(interp
, "unknown", &command_unknown
, NULL
, NULL
);
1143 Jim_CreateCommand(interp
, "ocd_find", jim_find
, NULL
, NULL
);
1144 Jim_CreateCommand(interp
, "echo", jim_echo
, NULL
, NULL
);
1145 Jim_CreateCommand(interp
, "capture", jim_capture
, NULL
, NULL
);
1147 /* Set Jim's STDIO */
1148 interp
->cookie_stdin
= interp
;
1149 interp
->cookie_stdout
= interp
;
1150 interp
->cookie_stderr
= interp
;
1151 interp
->cb_fwrite
= openocd_jim_fwrite
;
1152 interp
->cb_fread
= openocd_jim_fread
;
1153 interp
->cb_vfprintf
= openocd_jim_vfprintf
;
1154 interp
->cb_fflush
= openocd_jim_fflush
;
1155 interp
->cb_fgets
= openocd_jim_fgets
;
1157 register_commands(context
, NULL
, command_builtin_handlers
);
1159 #if !BUILD_ECOSBOARD
1160 Jim_EventLoopOnLoad(interp
);
1162 Jim_SetAssocData(interp
, "context", NULL
, context
);
1163 if (Jim_Eval_Named(interp
, startup_tcl
, "embedded:startup.tcl",1) == JIM_ERR
)
1165 LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD)");
1166 Jim_PrintErrorMessage(interp
);
1169 Jim_DeleteAssocData(interp
, "context");
1174 int command_context_mode(struct command_context
*cmd_ctx
, enum command_mode mode
)
1177 return ERROR_INVALID_ARGUMENTS
;
1179 cmd_ctx
->mode
= mode
;
1183 void process_jim_events(void)
1185 #if !BUILD_ECOSBOARD
1186 static int recursion
= 0;
1191 Jim_ProcessEvents (interp
, JIM_ALL_EVENTS
| JIM_DONT_WAIT
);
1197 #define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max) \
1198 int parse##name(const char *str, type *ul) \
1202 LOG_ERROR("Invalid command argument"); \
1203 return ERROR_COMMAND_ARGUMENT_INVALID; \
1206 *ul = func(str, &end, 0); \
1209 LOG_ERROR("Invalid command argument"); \
1210 return ERROR_COMMAND_ARGUMENT_INVALID; \
1212 if ((max == *ul) && (ERANGE == errno)) \
1214 LOG_ERROR("Argument overflow"); \
1215 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
1217 if (min && (min == *ul) && (ERANGE == errno)) \
1219 LOG_ERROR("Argument underflow"); \
1220 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
1224 DEFINE_PARSE_NUM_TYPE(_ulong
, unsigned long , strtoul
, 0, ULONG_MAX
)
1225 DEFINE_PARSE_NUM_TYPE(_ullong
, unsigned long long, strtoull
, 0, ULLONG_MAX
)
1226 DEFINE_PARSE_NUM_TYPE(_long
, long , strtol
, LONG_MIN
, LONG_MAX
)
1227 DEFINE_PARSE_NUM_TYPE(_llong
, long long, strtoll
, LLONG_MIN
, LLONG_MAX
)
1229 #define DEFINE_PARSE_WRAPPER(name, type, min, max, functype, funcname) \
1230 int parse##name(const char *str, type *ul) \
1233 int retval = parse##funcname(str, &n); \
1234 if (ERROR_OK != retval) \
1237 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
1239 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
1244 #define DEFINE_PARSE_ULONG(name, type, min, max) \
1245 DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long, _ulong)
1246 DEFINE_PARSE_ULONG(_uint
, unsigned, 0, UINT_MAX
)
1247 DEFINE_PARSE_ULONG(_u32
, uint32_t, 0, UINT32_MAX
)
1248 DEFINE_PARSE_ULONG(_u16
, uint16_t, 0, UINT16_MAX
)
1249 DEFINE_PARSE_ULONG(_u8
, uint8_t, 0, UINT8_MAX
)
1251 #define DEFINE_PARSE_LONG(name, type, min, max) \
1252 DEFINE_PARSE_WRAPPER(name, type, min, max, long, _long)
1253 DEFINE_PARSE_LONG(_int
, int, n
< INT_MIN
, INT_MAX
)
1254 DEFINE_PARSE_LONG(_s32
, int32_t, n
< INT32_MIN
, INT32_MAX
)
1255 DEFINE_PARSE_LONG(_s16
, int16_t, n
< INT16_MIN
, INT16_MAX
)
1256 DEFINE_PARSE_LONG(_s8
, int8_t, n
< INT8_MIN
, INT8_MAX
)
1258 static int command_parse_bool(const char *in
, bool *out
,
1259 const char *on
, const char *off
)
1261 if (strcasecmp(in
, on
) == 0)
1263 else if (strcasecmp(in
, off
) == 0)
1266 return ERROR_COMMAND_SYNTAX_ERROR
;
1270 int command_parse_bool_arg(const char *in
, bool *out
)
1272 if (command_parse_bool(in
, out
, "on", "off") == ERROR_OK
)
1274 if (command_parse_bool(in
, out
, "enable", "disable") == ERROR_OK
)
1276 if (command_parse_bool(in
, out
, "true", "false") == ERROR_OK
)
1278 if (command_parse_bool(in
, out
, "yes", "no") == ERROR_OK
)
1280 if (command_parse_bool(in
, out
, "1", "0") == ERROR_OK
)
1282 return ERROR_INVALID_ARGUMENTS
;
1285 COMMAND_HELPER(handle_command_parse_bool
, bool *out
, const char *label
)
1289 const char *in
= CMD_ARGV
[0];
1290 if (command_parse_bool_arg(in
, out
) != ERROR_OK
)
1292 LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME
, in
);
1293 return ERROR_INVALID_ARGUMENTS
;
1298 LOG_INFO("%s is %s", label
, *out
? "enabled" : "disabled");
1301 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)