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 extern struct command_context
*global_cmd_ctx
;
61 void script_debug(Jim_Interp
*interp
, const char *name
,
62 unsigned argc
, Jim_Obj
*const *argv
)
64 LOG_DEBUG("command - %s", name
);
65 for (unsigned i
= 0; i
< argc
; i
++)
68 const char *w
= Jim_GetString(argv
[i
], &len
);
70 /* end of line comment? */
74 LOG_DEBUG("%s - argv[%d]=%s", name
, i
, w
);
78 static void script_command_args_free(const char **words
, unsigned nwords
)
80 for (unsigned i
= 0; i
< nwords
; i
++)
81 free((void *)words
[i
]);
84 static const char **script_command_args_alloc(
85 unsigned argc
, Jim_Obj
*const *argv
, unsigned *nwords
)
87 const char **words
= malloc(argc
* sizeof(char *));
92 for (i
= 0; i
< argc
; i
++)
95 const char *w
= Jim_GetString(argv
[i
], &len
);
96 /* a comment may end the line early */
100 words
[i
] = strdup(w
);
101 if (words
[i
] == NULL
)
103 script_command_args_free(words
, i
);
111 static int script_command(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
113 /* the private data is stashed in the interp structure */
115 struct command_context
*context
;
118 /* DANGER!!!! be careful what we invoke here, since interp->cmdPrivData might
119 * get overwritten by running other Jim commands! Treat it as an
120 * emphemeral global variable that is used in lieu of an argument
121 * to the fn and fish it out manually.
123 c
= interp
->cmdPrivData
;
126 LOG_ERROR("BUG: interp->cmdPrivData == NULL");
129 target_call_timer_callbacks_now();
130 LOG_USER_N("%s", ""); /* Keep GDB connection alive*/
132 script_debug(interp
, c
->name
, argc
, argv
);
135 const char **words
= script_command_args_alloc(argc
, argv
, &nwords
);
139 /* grab the command context from the associated data */
140 context
= Jim_GetAssocData(interp
, "context");
143 /* Tcl can invoke commands directly instead of via command_run_line(). This would
144 * happen when the Jim Tcl interpreter is provided by eCos.
146 context
= global_cmd_ctx
;
149 /* capture log output and return it */
150 Jim_Obj
*tclOutput
= Jim_NewStringObj(interp
, "", 0);
151 /* a garbage collect can happen, so we need a reference count to this object */
152 Jim_IncrRefCount(tclOutput
);
154 log_add_callback(tcl_output
, tclOutput
);
156 retval
= run_command(context
, c
, (const char **)words
, nwords
);
158 log_remove_callback(tcl_output
, tclOutput
);
160 /* We dump output into this local variable */
161 Jim_SetResult(interp
, tclOutput
);
162 Jim_DecrRefCount(interp
, tclOutput
);
164 script_command_args_free(words
, nwords
);
166 int *return_retval
= Jim_GetAssocData(interp
, "retval");
167 if (return_retval
!= NULL
)
169 *return_retval
= retval
;
172 return (retval
== ERROR_OK
)?JIM_OK
:JIM_ERR
;
175 static Jim_Obj
*command_name_list(struct command
*c
)
177 Jim_Obj
*cmd_list
= c
->parent
?
178 command_name_list(c
->parent
) :
179 Jim_NewListObj(interp
, NULL
, 0);
180 Jim_ListAppendElement(interp
, cmd_list
,
181 Jim_NewStringObj(interp
, c
->name
, -1));
186 static void command_helptext_add(Jim_Obj
*cmd_list
, const char *help
)
188 Jim_Obj
*cmd_entry
= Jim_NewListObj(interp
, NULL
, 0);
189 Jim_ListAppendElement(interp
, cmd_entry
, cmd_list
);
190 Jim_ListAppendElement(interp
, cmd_entry
,
191 Jim_NewStringObj(interp
, help
? : "", -1));
193 /* accumulate help text in Tcl helptext list. */
194 Jim_Obj
*helptext
= Jim_GetGlobalVariableStr(interp
,
195 "ocd_helptext", JIM_ERRMSG
);
196 if (Jim_IsShared(helptext
))
197 helptext
= Jim_DuplicateObj(interp
, helptext
);
198 Jim_ListAppendElement(interp
, helptext
, cmd_entry
);
201 /* nice short description of source file */
202 #define __THIS__FILE__ "command.c"
205 * Find a command by name from a list of commands.
206 * @returns The named command if found, or NULL.
208 static struct command
*command_find(struct command
*head
, const char *name
)
210 for (struct command
*cc
= head
; cc
; cc
= cc
->next
)
212 if (strcmp(cc
->name
, name
) == 0)
219 * Add the command to the end of linked list.
220 * @returns Returns false if the named command already exists in the list.
221 * Returns true otherwise.
223 static void command_add_child(struct command
**head
, struct command
*c
)
231 struct command
*cc
= *head
;
232 while (cc
->next
) cc
= cc
->next
;
236 static struct command
**command_list_for_parent(
237 struct command_context
*cmd_ctx
, struct command
*parent
)
239 return parent
? &parent
->children
: &cmd_ctx
->commands
;
242 static struct command
*command_new(struct command_context
*cmd_ctx
,
243 struct command
*parent
, const char *name
,
244 command_handler_t handler
, enum command_mode mode
,
249 struct command
*c
= malloc(sizeof(struct command
));
250 memset(c
, 0, sizeof(struct command
));
252 c
->name
= strdup(name
);
254 c
->help
= strdup(help
);
256 c
->handler
= handler
;
259 command_add_child(command_list_for_parent(cmd_ctx
, parent
), c
);
261 command_helptext_add(command_name_list(c
), help
);
265 static void command_free(struct command
*c
)
267 /// @todo if command has a handler, unregister its jim command!
269 while (NULL
!= c
->children
)
271 struct command
*tmp
= c
->children
;
272 c
->children
= tmp
->next
;
279 free((void*)c
->help
);
283 struct command
* register_command(struct command_context
*context
,
284 struct command
*parent
, const char *name
,
285 command_handler_t handler
, enum command_mode mode
,
288 if (!context
|| !name
)
291 struct command
**head
= command_list_for_parent(context
, parent
);
292 struct command
*c
= command_find(*head
, name
);
295 LOG_ERROR("command '%s' is already registered in '%s' context",
296 name
, parent
? parent
->name
: "<global>");
300 c
= command_new(context
, parent
, name
, handler
, mode
, help
);
301 /* if allocation failed or it is a placeholder (no handler), we're done */
302 if (NULL
== c
|| NULL
== c
->handler
)
305 const char *full_name
= command_name(c
, '_');
307 const char *ocd_name
= alloc_printf("ocd_%s", full_name
);
308 Jim_CreateCommand(interp
, ocd_name
, script_command
, c
, NULL
);
309 free((void *)ocd_name
);
311 /* we now need to add an overrideable proc */
312 const char *override_name
= alloc_printf("proc %s {args} {"
313 "if {[catch {eval ocd_%s $args}] == 0} "
314 "{return \"\"} else {return -code error}}",
315 full_name
, full_name
);
316 Jim_Eval_Named(interp
, override_name
, __THIS__FILE__
, __LINE__
);
317 free((void *)override_name
);
319 free((void *)full_name
);
324 int unregister_all_commands(struct command_context
*context
,
325 struct command
*parent
)
330 struct command
**head
= command_list_for_parent(context
, parent
);
331 while (NULL
!= *head
)
333 struct command
*tmp
= *head
;
341 int unregister_command(struct command_context
*context
,
342 struct command
*parent
, const char *name
)
344 if ((!context
) || (!name
))
345 return ERROR_INVALID_ARGUMENTS
;
347 struct command
*p
= NULL
;
348 struct command
**head
= command_list_for_parent(context
, parent
);
349 for (struct command
*c
= *head
; NULL
!= c
; p
= c
, c
= c
->next
)
351 if (strcmp(name
, c
->name
) != 0)
366 void command_output_text(struct command_context
*context
, const char *data
)
368 if (context
&& context
->output_handler
&& data
) {
369 context
->output_handler(context
, data
);
373 void command_print_sameline(struct command_context
*context
, const char *format
, ...)
378 va_start(ap
, format
);
380 string
= alloc_vprintf(format
, ap
);
383 /* we want this collected in the log + we also want to pick it up as a tcl return
386 * The latter bit isn't precisely neat, but will do for now.
388 LOG_USER_N("%s", string
);
389 /* We already printed it above */
390 /* command_output_text(context, string); */
397 void command_print(struct command_context
*context
, const char *format
, ...)
402 va_start(ap
, format
);
404 string
= alloc_vprintf(format
, ap
);
407 strcat(string
, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one char longer */
408 /* we want this collected in the log + we also want to pick it up as a tcl return
411 * The latter bit isn't precisely neat, but will do for now.
413 LOG_USER_N("%s", string
);
414 /* We already printed it above */
415 /* command_output_text(context, string); */
422 static char *__command_name(struct command
*c
, char delim
, unsigned extra
)
425 unsigned len
= strlen(c
->name
);
426 if (NULL
== c
->parent
) {
427 // allocate enough for the name, child names, and '\0'
428 name
= malloc(len
+ extra
+ 1);
429 strcpy(name
, c
->name
);
431 // parent's extra must include both the space and name
432 name
= __command_name(c
->parent
, delim
, 1 + len
+ extra
);
433 char dstr
[2] = { delim
, 0 };
435 strcat(name
, c
->name
);
439 char *command_name(struct command
*c
, char delim
)
441 return __command_name(c
, delim
, 0);
444 static int run_command(struct command_context
*context
,
445 struct command
*c
, const char *words
[], unsigned num_words
)
447 if (!((context
->mode
== COMMAND_CONFIG
) || (c
->mode
== COMMAND_ANY
) || (c
->mode
== context
->mode
)))
449 /* Config commands can not run after the config stage */
450 LOG_ERROR("Command '%s' only runs during configuration stage", c
->name
);
454 struct command_invocation cmd
= {
457 .argc
= num_words
- 1,
460 int retval
= c
->handler(&cmd
);
461 if (retval
== ERROR_COMMAND_SYNTAX_ERROR
)
463 /* Print help for command */
464 char *full_name
= command_name(c
, ' ');
465 if (NULL
!= full_name
) {
466 command_run_linef(context
, "help %s", full_name
);
471 else if (retval
== ERROR_COMMAND_CLOSE_CONNECTION
)
473 /* just fall through for a shutdown request */
475 else if (retval
!= ERROR_OK
)
477 /* we do not print out an error message because the command *should*
478 * have printed out an error
480 LOG_DEBUG("Command failed with error code %d", retval
);
486 int command_run_line(struct command_context
*context
, char *line
)
488 /* all the parent commands have been registered with the interpreter
489 * so, can just evaluate the line as a script and check for
492 /* run the line thru a script engine */
493 int retval
= ERROR_FAIL
;
495 /* Beware! This code needs to be reentrant. It is also possible
496 * for OpenOCD commands to be invoked directly from Tcl. This would
497 * happen when the Jim Tcl interpreter is provided by eCos for
500 Jim_DeleteAssocData(interp
, "context");
501 retcode
= Jim_SetAssocData(interp
, "context", NULL
, context
);
502 if (retcode
== JIM_OK
)
504 /* associated the return value */
505 Jim_DeleteAssocData(interp
, "retval");
506 retcode
= Jim_SetAssocData(interp
, "retval", NULL
, &retval
);
507 if (retcode
== JIM_OK
)
509 retcode
= Jim_Eval_Named(interp
, line
, __THIS__FILE__
, __LINE__
);
511 Jim_DeleteAssocData(interp
, "retval");
513 Jim_DeleteAssocData(interp
, "context");
515 if (retcode
== JIM_ERR
) {
516 if (retval
!= ERROR_COMMAND_CLOSE_CONNECTION
)
518 /* We do not print the connection closed error message */
519 Jim_PrintErrorMessage(interp
);
521 if (retval
== ERROR_OK
)
523 /* It wasn't a low level OpenOCD command that failed */
527 } else if (retcode
== JIM_EXIT
) {
529 /* exit(Jim_GetExitCode(interp)); */
534 result
= Jim_GetString(Jim_GetResult(interp
), &reslen
);
539 for (i
= 0; i
< reslen
; i
+= 256)
545 strncpy(buff
, result
+ i
, chunk
);
547 LOG_USER_N("%s", buff
);
549 LOG_USER_N("%s", "\n");
556 int command_run_linef(struct command_context
*context
, const char *format
, ...)
558 int retval
= ERROR_FAIL
;
561 va_start(ap
, format
);
562 string
= alloc_vprintf(format
, ap
);
565 retval
= command_run_line(context
, string
);
571 void command_set_output_handler(struct command_context
* context
,
572 command_output_handler_t output_handler
, void *priv
)
574 context
->output_handler
= output_handler
;
575 context
->output_handler_priv
= priv
;
578 struct command_context
* copy_command_context(struct command_context
* context
)
580 struct command_context
* copy_context
= malloc(sizeof(struct command_context
));
582 *copy_context
= *context
;
587 int command_done(struct command_context
*context
)
595 /* find full path to file */
596 static int jim_find(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
600 const char *file
= Jim_GetString(argv
[1], NULL
);
601 char *full_path
= find_file(file
);
602 if (full_path
== NULL
)
604 Jim_Obj
*result
= Jim_NewStringObj(interp
, full_path
, strlen(full_path
));
607 Jim_SetResult(interp
, result
);
611 static int jim_echo(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
615 const char *str
= Jim_GetString(argv
[1], NULL
);
620 static size_t openocd_jim_fwrite(const void *_ptr
, size_t size
, size_t n
, void *cookie
)
626 /* make it a char easier to read code */
630 if (ptr
== NULL
|| interp
== NULL
|| nbytes
== 0) {
634 /* do we have to chunk it? */
635 if (ptr
[nbytes
] == 0)
637 /* no it is a C style string */
638 LOG_USER_N("%s", ptr
);
641 /* GRR we must chunk - not null terminated */
651 memcpy(chunk
, ptr
, x
);
655 LOG_USER_N("%s", chunk
);
663 static size_t openocd_jim_fread(void *ptr
, size_t size
, size_t n
, void *cookie
)
665 /* TCL wants to read... tell him no */
669 static int openocd_jim_vfprintf(void *cookie
, const char *fmt
, va_list ap
)
680 cp
= alloc_vprintf(fmt
, ap
);
683 LOG_USER_N("%s", cp
);
690 static int openocd_jim_fflush(void *cookie
)
692 /* nothing to flush */
696 static char* openocd_jim_fgets(char *s
, int size
, void *cookie
)
703 static int jim_capture(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
708 const char *str
= Jim_GetString(argv
[1], NULL
);
710 /* capture log output and return it */
711 Jim_Obj
*tclOutput
= Jim_NewStringObj(interp
, "", 0);
712 /* a garbage collect can happen, so we need a reference count to this object */
713 Jim_IncrRefCount(tclOutput
);
715 log_add_callback(tcl_output
, tclOutput
);
717 retcode
= Jim_Eval_Named(interp
, str
, __THIS__FILE__
, __LINE__
);
719 log_remove_callback(tcl_output
, tclOutput
);
721 /* We dump output into this local variable */
722 Jim_SetResult(interp
, tclOutput
);
723 Jim_DecrRefCount(interp
, tclOutput
);
728 static COMMAND_HELPER(command_help_find
, struct command
*head
,
729 struct command
**out
)
732 return ERROR_INVALID_ARGUMENTS
;
733 *out
= command_find(head
, CMD_ARGV
[0]);
735 return ERROR_INVALID_ARGUMENTS
;
739 return CALL_COMMAND_HANDLER(command_help_find
, (*out
)->children
, out
);
742 static COMMAND_HELPER(command_help_show
, struct command
*c
, unsigned n
);
744 static COMMAND_HELPER(command_help_show_list
, struct command
*head
, unsigned n
)
746 for (struct command
*c
= head
; NULL
!= c
; c
= c
->next
)
747 CALL_COMMAND_HANDLER(command_help_show
, c
, n
);
750 static COMMAND_HELPER(command_help_show
, struct command
*c
, unsigned n
)
752 command_run_linef(CMD_CTX
, "cmd_help {%s} {%s} %d", command_name(c
, ' '),
753 c
->help
? : "no help available", n
);
758 return CALL_COMMAND_HANDLER(command_help_show_list
, c
->children
, n
);
760 COMMAND_HANDLER(handle_help_command
)
762 struct command
*c
= CMD_CTX
->commands
;
765 return CALL_COMMAND_HANDLER(command_help_show_list
, c
, 0);
767 int retval
= CALL_COMMAND_HANDLER(command_help_find
, c
, &c
);
768 if (ERROR_OK
!= retval
)
771 return CALL_COMMAND_HANDLER(command_help_show
, c
, 0);
774 /* sleep command sleeps for <n> miliseconds
775 * this is useful in target startup scripts
777 COMMAND_HANDLER(handle_sleep_command
)
782 if (strcmp(CMD_ARGV
[1], "busy") == 0)
785 return ERROR_COMMAND_SYNTAX_ERROR
;
787 else if (CMD_ARGC
< 1 || CMD_ARGC
> 2)
788 return ERROR_COMMAND_SYNTAX_ERROR
;
790 unsigned long duration
= 0;
791 int retval
= parse_ulong(CMD_ARGV
[0], &duration
);
792 if (ERROR_OK
!= retval
)
797 long long then
= timeval_ms();
798 while (timeval_ms() - then
< (long long)duration
)
800 target_call_timer_callbacks_now();
805 busy_sleep(duration
);
810 struct command_context
* command_init(const char *startup_tcl
)
812 struct command_context
* context
= malloc(sizeof(struct command_context
));
815 context
->mode
= COMMAND_EXEC
;
816 context
->commands
= NULL
;
817 context
->current_target
= 0;
818 context
->output_handler
= NULL
;
819 context
->output_handler_priv
= NULL
;
823 /* Create an interpreter */
824 interp
= Jim_CreateInterp();
825 /* Add all the Jim core commands */
826 Jim_RegisterCoreCommands(interp
);
829 #if defined(_MSC_VER)
830 /* WinXX - is generic, the forward
831 * looking problem is this:
835 * "winxx" is generic.
838 #elif defined(__linux__)
840 #elif defined(__DARWIN__)
842 #elif defined(__CYGWIN__)
844 #elif defined(__MINGW32__)
846 #elif defined(__ECOS)
849 #warn unrecognized host OS...
852 Jim_SetGlobalVariableStr(interp
, "ocd_HOSTOS",
853 Jim_NewStringObj(interp
, HostOs
, strlen(HostOs
)));
855 Jim_CreateCommand(interp
, "ocd_find", jim_find
, NULL
, NULL
);
856 Jim_CreateCommand(interp
, "echo", jim_echo
, NULL
, NULL
);
857 Jim_CreateCommand(interp
, "capture", jim_capture
, NULL
, NULL
);
859 /* Set Jim's STDIO */
860 interp
->cookie_stdin
= interp
;
861 interp
->cookie_stdout
= interp
;
862 interp
->cookie_stderr
= interp
;
863 interp
->cb_fwrite
= openocd_jim_fwrite
;
864 interp
->cb_fread
= openocd_jim_fread
;
865 interp
->cb_vfprintf
= openocd_jim_vfprintf
;
866 interp
->cb_fflush
= openocd_jim_fflush
;
867 interp
->cb_fgets
= openocd_jim_fgets
;
870 Jim_EventLoopOnLoad(interp
);
872 Jim_SetAssocData(interp
, "context", NULL
, context
);
873 if (Jim_Eval_Named(interp
, startup_tcl
, "embedded:startup.tcl",1) == JIM_ERR
)
875 LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD)");
876 Jim_PrintErrorMessage(interp
);
879 Jim_DeleteAssocData(interp
, "context");
881 register_command(context
, NULL
, "sleep",
882 handle_sleep_command
, COMMAND_ANY
,
883 "<n> [busy] - sleep for n milliseconds. "
884 "\"busy\" means busy wait");
886 register_command(context
, NULL
, "help",
887 &handle_help_command
, COMMAND_ANY
,
888 "[<command_name> ...] - show built-in command help");
893 int command_context_mode(struct command_context
*cmd_ctx
, enum command_mode mode
)
896 return ERROR_INVALID_ARGUMENTS
;
898 cmd_ctx
->mode
= mode
;
902 void process_jim_events(void)
905 static int recursion
= 0;
910 Jim_ProcessEvents (interp
, JIM_ALL_EVENTS
| JIM_DONT_WAIT
);
916 void register_jim(struct command_context
*cmd_ctx
, const char *name
,
917 Jim_CmdProc cmd
, const char *help
)
919 Jim_CreateCommand(interp
, name
, cmd
, NULL
, NULL
);
921 Jim_Obj
*cmd_list
= Jim_NewListObj(interp
, NULL
, 0);
922 Jim_ListAppendElement(interp
, cmd_list
,
923 Jim_NewStringObj(interp
, name
, -1));
925 command_helptext_add(cmd_list
, help
);
928 #define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max) \
929 int parse##name(const char *str, type *ul) \
933 LOG_ERROR("Invalid command argument"); \
934 return ERROR_COMMAND_ARGUMENT_INVALID; \
937 *ul = func(str, &end, 0); \
940 LOG_ERROR("Invalid command argument"); \
941 return ERROR_COMMAND_ARGUMENT_INVALID; \
943 if ((max == *ul) && (ERANGE == errno)) \
945 LOG_ERROR("Argument overflow"); \
946 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
948 if (min && (min == *ul) && (ERANGE == errno)) \
950 LOG_ERROR("Argument underflow"); \
951 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
955 DEFINE_PARSE_NUM_TYPE(_ulong
, unsigned long , strtoul
, 0, ULONG_MAX
)
956 DEFINE_PARSE_NUM_TYPE(_ullong
, unsigned long long, strtoull
, 0, ULLONG_MAX
)
957 DEFINE_PARSE_NUM_TYPE(_long
, long , strtol
, LONG_MIN
, LONG_MAX
)
958 DEFINE_PARSE_NUM_TYPE(_llong
, long long, strtoll
, LLONG_MIN
, LLONG_MAX
)
960 #define DEFINE_PARSE_WRAPPER(name, type, min, max, functype, funcname) \
961 int parse##name(const char *str, type *ul) \
964 int retval = parse##funcname(str, &n); \
965 if (ERROR_OK != retval) \
968 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
970 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
975 #define DEFINE_PARSE_ULONG(name, type, min, max) \
976 DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long, _ulong)
977 DEFINE_PARSE_ULONG(_uint
, unsigned, 0, UINT_MAX
)
978 DEFINE_PARSE_ULONG(_u32
, uint32_t, 0, UINT32_MAX
)
979 DEFINE_PARSE_ULONG(_u16
, uint16_t, 0, UINT16_MAX
)
980 DEFINE_PARSE_ULONG(_u8
, uint8_t, 0, UINT8_MAX
)
982 #define DEFINE_PARSE_LONG(name, type, min, max) \
983 DEFINE_PARSE_WRAPPER(name, type, min, max, long, _long)
984 DEFINE_PARSE_LONG(_int
, int, n
< INT_MIN
, INT_MAX
)
985 DEFINE_PARSE_LONG(_s32
, int32_t, n
< INT32_MIN
, INT32_MAX
)
986 DEFINE_PARSE_LONG(_s16
, int16_t, n
< INT16_MIN
, INT16_MAX
)
987 DEFINE_PARSE_LONG(_s8
, int8_t, n
< INT8_MIN
, INT8_MAX
)
989 static int command_parse_bool(const char *in
, bool *out
,
990 const char *on
, const char *off
)
992 if (strcasecmp(in
, on
) == 0)
994 else if (strcasecmp(in
, off
) == 0)
997 return ERROR_COMMAND_SYNTAX_ERROR
;
1001 int command_parse_bool_arg(const char *in
, bool *out
)
1003 if (command_parse_bool(in
, out
, "on", "off") == ERROR_OK
)
1005 if (command_parse_bool(in
, out
, "enable", "disable") == ERROR_OK
)
1007 if (command_parse_bool(in
, out
, "true", "false") == ERROR_OK
)
1009 if (command_parse_bool(in
, out
, "yes", "no") == ERROR_OK
)
1011 if (command_parse_bool(in
, out
, "1", "0") == ERROR_OK
)
1013 return ERROR_INVALID_ARGUMENTS
;
1016 COMMAND_HELPER(handle_command_parse_bool
, bool *out
, const char *label
)
1020 const char *in
= CMD_ARGV
[0];
1021 if (command_parse_bool_arg(in
, out
) != ERROR_OK
)
1023 LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME
, in
);
1024 return ERROR_INVALID_ARGUMENTS
;
1029 LOG_INFO("%s is %s", label
, *out
? "enabled" : "disabled");
1032 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)