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 /* nice short description of source file */
176 #define __THIS__FILE__ "command.c"
179 * Find a command by name from a list of commands.
180 * @returns Returns the named command if it exists in the list.
181 * Returns NULL otherwise.
183 static struct command
*command_find(struct command
*head
, const char *name
)
185 for (struct command
*cc
= head
; cc
; cc
= cc
->next
)
187 if (strcmp(cc
->name
, name
) == 0)
194 * Add the command into the linked list, sorted by name.
195 * @param head Address to head of command list pointer, which may be
196 * updated if @c c gets inserted at the beginning of the list.
197 * @param c The command to add to the list pointed to by @c head.
199 static void command_add_child(struct command
**head
, struct command
*c
)
208 while ((*head
)->next
&& (strcmp(c
->name
, (*head
)->name
) > 0))
209 head
= &(*head
)->next
;
211 if (strcmp(c
->name
, (*head
)->name
) > 0) {
212 c
->next
= (*head
)->next
;
220 static struct command
**command_list_for_parent(
221 struct command_context
*cmd_ctx
, struct command
*parent
)
223 return parent
? &parent
->children
: &cmd_ctx
->commands
;
226 static struct command
*command_new(struct command_context
*cmd_ctx
,
227 struct command
*parent
, const char *name
,
228 command_handler_t handler
, enum command_mode mode
,
233 struct command
*c
= malloc(sizeof(struct command
));
234 memset(c
, 0, sizeof(struct command
));
236 c
->name
= strdup(name
);
238 c
->help
= strdup(help
);
240 c
->handler
= handler
;
243 command_add_child(command_list_for_parent(cmd_ctx
, parent
), c
);
247 static void command_free(struct command
*c
)
249 /// @todo if command has a handler, unregister its jim command!
251 while (NULL
!= c
->children
)
253 struct command
*tmp
= c
->children
;
254 c
->children
= tmp
->next
;
261 free((void*)c
->help
);
265 struct command
* register_command(struct command_context
*context
,
266 struct command
*parent
, const struct command_registration
*cr
)
268 if (!context
|| !cr
->name
)
271 const char *name
= cr
->name
;
272 struct command
**head
= command_list_for_parent(context
, parent
);
273 struct command
*c
= command_find(*head
, name
);
276 LOG_ERROR("command '%s' is already registered in '%s' context",
277 name
, parent
? parent
->name
: "<global>");
281 c
= command_new(context
, parent
, name
, cr
->handler
, cr
->mode
, cr
->help
);
282 /* if allocation failed or it is a placeholder (no handler), we're done */
283 if (NULL
== c
|| NULL
== c
->handler
)
286 const char *full_name
= command_name(c
, '_');
288 const char *ocd_name
= alloc_printf("ocd_%s", full_name
);
289 Jim_CreateCommand(interp
, ocd_name
, script_command
, c
, NULL
);
290 free((void *)ocd_name
);
292 /* we now need to add an overrideable proc */
293 const char *override_name
= alloc_printf("proc %s {args} {"
294 "if {[catch {eval ocd_%s $args}] == 0} "
295 "{return \"\"} else {return -code error}}",
296 full_name
, full_name
);
297 Jim_Eval_Named(interp
, override_name
, __THIS__FILE__
, __LINE__
);
298 free((void *)override_name
);
300 free((void *)full_name
);
305 int unregister_all_commands(struct command_context
*context
,
306 struct command
*parent
)
311 struct command
**head
= command_list_for_parent(context
, parent
);
312 while (NULL
!= *head
)
314 struct command
*tmp
= *head
;
322 int unregister_command(struct command_context
*context
,
323 struct command
*parent
, const char *name
)
325 if ((!context
) || (!name
))
326 return ERROR_INVALID_ARGUMENTS
;
328 struct command
*p
= NULL
;
329 struct command
**head
= command_list_for_parent(context
, parent
);
330 for (struct command
*c
= *head
; NULL
!= c
; p
= c
, c
= c
->next
)
332 if (strcmp(name
, c
->name
) != 0)
347 void command_output_text(struct command_context
*context
, const char *data
)
349 if (context
&& context
->output_handler
&& data
) {
350 context
->output_handler(context
, data
);
354 void command_print_sameline(struct command_context
*context
, const char *format
, ...)
359 va_start(ap
, format
);
361 string
= alloc_vprintf(format
, ap
);
364 /* we want this collected in the log + we also want to pick it up as a tcl return
367 * The latter bit isn't precisely neat, but will do for now.
369 LOG_USER_N("%s", string
);
370 /* We already printed it above */
371 /* command_output_text(context, string); */
378 void command_print(struct command_context
*context
, const char *format
, ...)
383 va_start(ap
, format
);
385 string
= alloc_vprintf(format
, ap
);
388 strcat(string
, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one char longer */
389 /* we want this collected in the log + we also want to pick it up as a tcl return
392 * The latter bit isn't precisely neat, but will do for now.
394 LOG_USER_N("%s", string
);
395 /* We already printed it above */
396 /* command_output_text(context, string); */
403 static char *__command_name(struct command
*c
, char delim
, unsigned extra
)
406 unsigned len
= strlen(c
->name
);
407 if (NULL
== c
->parent
) {
408 // allocate enough for the name, child names, and '\0'
409 name
= malloc(len
+ extra
+ 1);
410 strcpy(name
, c
->name
);
412 // parent's extra must include both the space and name
413 name
= __command_name(c
->parent
, delim
, 1 + len
+ extra
);
414 char dstr
[2] = { delim
, 0 };
416 strcat(name
, c
->name
);
420 char *command_name(struct command
*c
, char delim
)
422 return __command_name(c
, delim
, 0);
425 static int run_command(struct command_context
*context
,
426 struct command
*c
, const char *words
[], unsigned num_words
)
428 if (!((context
->mode
== COMMAND_CONFIG
) || (c
->mode
== COMMAND_ANY
) || (c
->mode
== context
->mode
)))
430 /* Config commands can not run after the config stage */
431 LOG_ERROR("Command '%s' only runs during configuration stage", c
->name
);
435 struct command_invocation cmd
= {
438 .argc
= num_words
- 1,
441 int retval
= c
->handler(&cmd
);
442 if (retval
== ERROR_COMMAND_SYNTAX_ERROR
)
444 /* Print help for command */
445 char *full_name
= command_name(c
, ' ');
446 if (NULL
!= full_name
) {
447 command_run_linef(context
, "help %s", full_name
);
452 else if (retval
== ERROR_COMMAND_CLOSE_CONNECTION
)
454 /* just fall through for a shutdown request */
456 else if (retval
!= ERROR_OK
)
458 /* we do not print out an error message because the command *should*
459 * have printed out an error
461 LOG_DEBUG("Command failed with error code %d", retval
);
467 int command_run_line(struct command_context
*context
, char *line
)
469 /* all the parent commands have been registered with the interpreter
470 * so, can just evaluate the line as a script and check for
473 /* run the line thru a script engine */
474 int retval
= ERROR_FAIL
;
476 /* Beware! This code needs to be reentrant. It is also possible
477 * for OpenOCD commands to be invoked directly from Tcl. This would
478 * happen when the Jim Tcl interpreter is provided by eCos for
481 Jim_DeleteAssocData(interp
, "context");
482 retcode
= Jim_SetAssocData(interp
, "context", NULL
, context
);
483 if (retcode
== JIM_OK
)
485 /* associated the return value */
486 Jim_DeleteAssocData(interp
, "retval");
487 retcode
= Jim_SetAssocData(interp
, "retval", NULL
, &retval
);
488 if (retcode
== JIM_OK
)
490 retcode
= Jim_Eval_Named(interp
, line
, __THIS__FILE__
, __LINE__
);
492 Jim_DeleteAssocData(interp
, "retval");
494 Jim_DeleteAssocData(interp
, "context");
496 if (retcode
== JIM_ERR
) {
497 if (retval
!= ERROR_COMMAND_CLOSE_CONNECTION
)
499 /* We do not print the connection closed error message */
500 Jim_PrintErrorMessage(interp
);
502 if (retval
== ERROR_OK
)
504 /* It wasn't a low level OpenOCD command that failed */
508 } else if (retcode
== JIM_EXIT
) {
510 /* exit(Jim_GetExitCode(interp)); */
515 result
= Jim_GetString(Jim_GetResult(interp
), &reslen
);
520 for (i
= 0; i
< reslen
; i
+= 256)
526 strncpy(buff
, result
+ i
, chunk
);
528 LOG_USER_N("%s", buff
);
530 LOG_USER_N("%s", "\n");
537 int command_run_linef(struct command_context
*context
, const char *format
, ...)
539 int retval
= ERROR_FAIL
;
542 va_start(ap
, format
);
543 string
= alloc_vprintf(format
, ap
);
546 retval
= command_run_line(context
, string
);
552 void command_set_output_handler(struct command_context
* context
,
553 command_output_handler_t output_handler
, void *priv
)
555 context
->output_handler
= output_handler
;
556 context
->output_handler_priv
= priv
;
559 struct command_context
* copy_command_context(struct command_context
* context
)
561 struct command_context
* copy_context
= malloc(sizeof(struct command_context
));
563 *copy_context
= *context
;
568 int command_done(struct command_context
*context
)
576 /* find full path to file */
577 static int jim_find(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
581 const char *file
= Jim_GetString(argv
[1], NULL
);
582 char *full_path
= find_file(file
);
583 if (full_path
== NULL
)
585 Jim_Obj
*result
= Jim_NewStringObj(interp
, full_path
, strlen(full_path
));
588 Jim_SetResult(interp
, result
);
592 static int jim_echo(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
596 const char *str
= Jim_GetString(argv
[1], NULL
);
601 static size_t openocd_jim_fwrite(const void *_ptr
, size_t size
, size_t n
, void *cookie
)
607 /* make it a char easier to read code */
611 if (ptr
== NULL
|| interp
== NULL
|| nbytes
== 0) {
615 /* do we have to chunk it? */
616 if (ptr
[nbytes
] == 0)
618 /* no it is a C style string */
619 LOG_USER_N("%s", ptr
);
622 /* GRR we must chunk - not null terminated */
632 memcpy(chunk
, ptr
, x
);
636 LOG_USER_N("%s", chunk
);
644 static size_t openocd_jim_fread(void *ptr
, size_t size
, size_t n
, void *cookie
)
646 /* TCL wants to read... tell him no */
650 static int openocd_jim_vfprintf(void *cookie
, const char *fmt
, va_list ap
)
661 cp
= alloc_vprintf(fmt
, ap
);
664 LOG_USER_N("%s", cp
);
671 static int openocd_jim_fflush(void *cookie
)
673 /* nothing to flush */
677 static char* openocd_jim_fgets(char *s
, int size
, void *cookie
)
684 static int jim_capture(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
689 const char *str
= Jim_GetString(argv
[1], NULL
);
691 /* capture log output and return it */
692 Jim_Obj
*tclOutput
= Jim_NewStringObj(interp
, "", 0);
693 /* a garbage collect can happen, so we need a reference count to this object */
694 Jim_IncrRefCount(tclOutput
);
696 log_add_callback(tcl_output
, tclOutput
);
698 retcode
= Jim_Eval_Named(interp
, str
, __THIS__FILE__
, __LINE__
);
700 log_remove_callback(tcl_output
, tclOutput
);
702 /* We dump output into this local variable */
703 Jim_SetResult(interp
, tclOutput
);
704 Jim_DecrRefCount(interp
, tclOutput
);
709 static COMMAND_HELPER(command_help_find
, struct command
*head
,
710 struct command
**out
)
713 return ERROR_INVALID_ARGUMENTS
;
714 *out
= command_find(head
, CMD_ARGV
[0]);
716 return ERROR_INVALID_ARGUMENTS
;
720 return CALL_COMMAND_HANDLER(command_help_find
, (*out
)->children
, out
);
723 static COMMAND_HELPER(command_help_show
, struct command
*c
, unsigned n
);
725 static COMMAND_HELPER(command_help_show_list
, struct command
*head
, unsigned n
)
727 for (struct command
*c
= head
; NULL
!= c
; c
= c
->next
)
728 CALL_COMMAND_HANDLER(command_help_show
, c
, n
);
731 static COMMAND_HELPER(command_help_show
, struct command
*c
, unsigned n
)
733 command_run_linef(CMD_CTX
, "cmd_help {%s} {%s} %d", command_name(c
, ' '),
734 c
->help
? : "no help available", n
);
739 return CALL_COMMAND_HANDLER(command_help_show_list
, c
->children
, n
);
741 COMMAND_HANDLER(handle_help_command
)
743 struct command
*c
= CMD_CTX
->commands
;
746 return CALL_COMMAND_HANDLER(command_help_show_list
, c
, 0);
748 int retval
= CALL_COMMAND_HANDLER(command_help_find
, c
, &c
);
749 if (ERROR_OK
!= retval
)
752 return CALL_COMMAND_HANDLER(command_help_show
, c
, 0);
756 int help_add_command(struct command_context
*cmd_ctx
, struct command
*parent
,
757 const char *cmd_name
, const char *help_text
)
759 struct command
**head
= command_list_for_parent(cmd_ctx
, parent
);
760 struct command
*nc
= command_find(*head
, cmd_name
);
763 // add a new command with help text
764 struct command_registration cr
= {
769 nc
= register_command(cmd_ctx
, parent
, &cr
);
772 LOG_ERROR("failed to add '%s' help text", cmd_name
);
775 LOG_DEBUG("added '%s' help text", cmd_name
);
779 bool replaced
= false;
782 free((void *)nc
->help
);
785 nc
->help
= strdup(help_text
);
788 LOG_INFO("replaced existing '%s' help", cmd_name
);
790 LOG_DEBUG("added '%s' help text", cmd_name
);
795 COMMAND_HANDLER(handle_help_add_command
)
799 LOG_ERROR("%s: insufficient arguments", CMD_NAME
);
800 return ERROR_INVALID_ARGUMENTS
;
803 // save help text and remove it from argument list
804 const char *help_text
= CMD_ARGV
[--CMD_ARGC
];
805 // likewise for the leaf command name
806 const char *cmd_name
= CMD_ARGV
[--CMD_ARGC
];
808 struct command
*c
= NULL
;
811 c
= CMD_CTX
->commands
;
812 int retval
= CALL_COMMAND_HANDLER(command_help_find
, c
, &c
);
813 if (ERROR_OK
!= retval
)
816 return help_add_command(CMD_CTX
, c
, cmd_name
, help_text
);
819 /* sleep command sleeps for <n> miliseconds
820 * this is useful in target startup scripts
822 COMMAND_HANDLER(handle_sleep_command
)
827 if (strcmp(CMD_ARGV
[1], "busy") == 0)
830 return ERROR_COMMAND_SYNTAX_ERROR
;
832 else if (CMD_ARGC
< 1 || CMD_ARGC
> 2)
833 return ERROR_COMMAND_SYNTAX_ERROR
;
835 unsigned long duration
= 0;
836 int retval
= parse_ulong(CMD_ARGV
[0], &duration
);
837 if (ERROR_OK
!= retval
)
842 long long then
= timeval_ms();
843 while (timeval_ms() - then
< (long long)duration
)
845 target_call_timer_callbacks_now();
850 busy_sleep(duration
);
855 struct command_context
* command_init(const char *startup_tcl
)
857 struct command_context
* context
= malloc(sizeof(struct command_context
));
860 context
->mode
= COMMAND_EXEC
;
861 context
->commands
= NULL
;
862 context
->current_target
= 0;
863 context
->output_handler
= NULL
;
864 context
->output_handler_priv
= NULL
;
868 /* Create an interpreter */
869 interp
= Jim_CreateInterp();
870 /* Add all the Jim core commands */
871 Jim_RegisterCoreCommands(interp
);
874 #if defined(_MSC_VER)
875 /* WinXX - is generic, the forward
876 * looking problem is this:
880 * "winxx" is generic.
883 #elif defined(__linux__)
885 #elif defined(__DARWIN__)
887 #elif defined(__CYGWIN__)
889 #elif defined(__MINGW32__)
891 #elif defined(__ECOS)
894 #warn unrecognized host OS...
897 Jim_SetGlobalVariableStr(interp
, "ocd_HOSTOS",
898 Jim_NewStringObj(interp
, HostOs
, strlen(HostOs
)));
900 Jim_CreateCommand(interp
, "ocd_find", jim_find
, NULL
, NULL
);
901 Jim_CreateCommand(interp
, "echo", jim_echo
, NULL
, NULL
);
902 Jim_CreateCommand(interp
, "capture", jim_capture
, NULL
, NULL
);
904 /* Set Jim's STDIO */
905 interp
->cookie_stdin
= interp
;
906 interp
->cookie_stdout
= interp
;
907 interp
->cookie_stderr
= interp
;
908 interp
->cb_fwrite
= openocd_jim_fwrite
;
909 interp
->cb_fread
= openocd_jim_fread
;
910 interp
->cb_vfprintf
= openocd_jim_vfprintf
;
911 interp
->cb_fflush
= openocd_jim_fflush
;
912 interp
->cb_fgets
= openocd_jim_fgets
;
914 COMMAND_REGISTER(context
, NULL
, "add_help_text",
915 handle_help_add_command
, COMMAND_ANY
,
916 "<command> [...] <help_text>] - "
917 "add new command help text");
920 Jim_EventLoopOnLoad(interp
);
922 Jim_SetAssocData(interp
, "context", NULL
, context
);
923 if (Jim_Eval_Named(interp
, startup_tcl
, "embedded:startup.tcl",1) == JIM_ERR
)
925 LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD)");
926 Jim_PrintErrorMessage(interp
);
929 Jim_DeleteAssocData(interp
, "context");
931 COMMAND_REGISTER(context
, NULL
, "sleep",
932 handle_sleep_command
, COMMAND_ANY
,
933 "<n> [busy] - sleep for n milliseconds. "
934 "\"busy\" means busy wait");
936 COMMAND_REGISTER(context
, NULL
, "help",
937 &handle_help_command
, COMMAND_ANY
,
938 "[<command_name> ...] - show built-in command help");
943 int command_context_mode(struct command_context
*cmd_ctx
, enum command_mode mode
)
946 return ERROR_INVALID_ARGUMENTS
;
948 cmd_ctx
->mode
= mode
;
952 void process_jim_events(void)
955 static int recursion
= 0;
960 Jim_ProcessEvents (interp
, JIM_ALL_EVENTS
| JIM_DONT_WAIT
);
966 void register_jim(struct command_context
*cmd_ctx
, const char *name
,
967 Jim_CmdProc cmd
, const char *help
)
969 Jim_CreateCommand(interp
, name
, cmd
, NULL
, NULL
);
971 Jim_Obj
*cmd_list
= Jim_NewListObj(interp
, NULL
, 0);
972 Jim_ListAppendElement(interp
, cmd_list
,
973 Jim_NewStringObj(interp
, name
, -1));
975 help_add_command(cmd_ctx
, NULL
, name
, help
);
978 #define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max) \
979 int parse##name(const char *str, type *ul) \
983 LOG_ERROR("Invalid command argument"); \
984 return ERROR_COMMAND_ARGUMENT_INVALID; \
987 *ul = func(str, &end, 0); \
990 LOG_ERROR("Invalid command argument"); \
991 return ERROR_COMMAND_ARGUMENT_INVALID; \
993 if ((max == *ul) && (ERANGE == errno)) \
995 LOG_ERROR("Argument overflow"); \
996 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
998 if (min && (min == *ul) && (ERANGE == errno)) \
1000 LOG_ERROR("Argument underflow"); \
1001 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
1005 DEFINE_PARSE_NUM_TYPE(_ulong
, unsigned long , strtoul
, 0, ULONG_MAX
)
1006 DEFINE_PARSE_NUM_TYPE(_ullong
, unsigned long long, strtoull
, 0, ULLONG_MAX
)
1007 DEFINE_PARSE_NUM_TYPE(_long
, long , strtol
, LONG_MIN
, LONG_MAX
)
1008 DEFINE_PARSE_NUM_TYPE(_llong
, long long, strtoll
, LLONG_MIN
, LLONG_MAX
)
1010 #define DEFINE_PARSE_WRAPPER(name, type, min, max, functype, funcname) \
1011 int parse##name(const char *str, type *ul) \
1014 int retval = parse##funcname(str, &n); \
1015 if (ERROR_OK != retval) \
1018 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
1020 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
1025 #define DEFINE_PARSE_ULONG(name, type, min, max) \
1026 DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long, _ulong)
1027 DEFINE_PARSE_ULONG(_uint
, unsigned, 0, UINT_MAX
)
1028 DEFINE_PARSE_ULONG(_u32
, uint32_t, 0, UINT32_MAX
)
1029 DEFINE_PARSE_ULONG(_u16
, uint16_t, 0, UINT16_MAX
)
1030 DEFINE_PARSE_ULONG(_u8
, uint8_t, 0, UINT8_MAX
)
1032 #define DEFINE_PARSE_LONG(name, type, min, max) \
1033 DEFINE_PARSE_WRAPPER(name, type, min, max, long, _long)
1034 DEFINE_PARSE_LONG(_int
, int, n
< INT_MIN
, INT_MAX
)
1035 DEFINE_PARSE_LONG(_s32
, int32_t, n
< INT32_MIN
, INT32_MAX
)
1036 DEFINE_PARSE_LONG(_s16
, int16_t, n
< INT16_MIN
, INT16_MAX
)
1037 DEFINE_PARSE_LONG(_s8
, int8_t, n
< INT8_MIN
, INT8_MAX
)
1039 static int command_parse_bool(const char *in
, bool *out
,
1040 const char *on
, const char *off
)
1042 if (strcasecmp(in
, on
) == 0)
1044 else if (strcasecmp(in
, off
) == 0)
1047 return ERROR_COMMAND_SYNTAX_ERROR
;
1051 int command_parse_bool_arg(const char *in
, bool *out
)
1053 if (command_parse_bool(in
, out
, "on", "off") == ERROR_OK
)
1055 if (command_parse_bool(in
, out
, "enable", "disable") == ERROR_OK
)
1057 if (command_parse_bool(in
, out
, "true", "false") == ERROR_OK
)
1059 if (command_parse_bool(in
, out
, "yes", "no") == ERROR_OK
)
1061 if (command_parse_bool(in
, out
, "1", "0") == ERROR_OK
)
1063 return ERROR_INVALID_ARGUMENTS
;
1066 COMMAND_HELPER(handle_command_parse_bool
, bool *out
, const char *label
)
1070 const char *in
= CMD_ARGV
[0];
1071 if (command_parse_bool_arg(in
, out
) != ERROR_OK
)
1073 LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME
, in
);
1074 return ERROR_INVALID_ARGUMENTS
;
1079 LOG_INFO("%s is %s", label
, *out
? "enabled" : "disabled");
1082 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)