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 char *name
,
267 command_handler_t handler
, enum command_mode mode
,
270 if (!context
|| !name
)
273 struct command
**head
= command_list_for_parent(context
, parent
);
274 struct command
*c
= command_find(*head
, name
);
277 LOG_ERROR("command '%s' is already registered in '%s' context",
278 name
, parent
? parent
->name
: "<global>");
282 c
= command_new(context
, parent
, name
, handler
, mode
, help
);
283 /* if allocation failed or it is a placeholder (no handler), we're done */
284 if (NULL
== c
|| NULL
== c
->handler
)
287 const char *full_name
= command_name(c
, '_');
289 const char *ocd_name
= alloc_printf("ocd_%s", full_name
);
290 Jim_CreateCommand(interp
, ocd_name
, script_command
, c
, NULL
);
291 free((void *)ocd_name
);
293 /* we now need to add an overrideable proc */
294 const char *override_name
= alloc_printf("proc %s {args} {"
295 "if {[catch {eval ocd_%s $args}] == 0} "
296 "{return \"\"} else {return -code error}}",
297 full_name
, full_name
);
298 Jim_Eval_Named(interp
, override_name
, __THIS__FILE__
, __LINE__
);
299 free((void *)override_name
);
301 free((void *)full_name
);
306 int unregister_all_commands(struct command_context
*context
,
307 struct command
*parent
)
312 struct command
**head
= command_list_for_parent(context
, parent
);
313 while (NULL
!= *head
)
315 struct command
*tmp
= *head
;
323 int unregister_command(struct command_context
*context
,
324 struct command
*parent
, const char *name
)
326 if ((!context
) || (!name
))
327 return ERROR_INVALID_ARGUMENTS
;
329 struct command
*p
= NULL
;
330 struct command
**head
= command_list_for_parent(context
, parent
);
331 for (struct command
*c
= *head
; NULL
!= c
; p
= c
, c
= c
->next
)
333 if (strcmp(name
, c
->name
) != 0)
348 void command_output_text(struct command_context
*context
, const char *data
)
350 if (context
&& context
->output_handler
&& data
) {
351 context
->output_handler(context
, data
);
355 void command_print_sameline(struct command_context
*context
, const char *format
, ...)
360 va_start(ap
, format
);
362 string
= alloc_vprintf(format
, ap
);
365 /* we want this collected in the log + we also want to pick it up as a tcl return
368 * The latter bit isn't precisely neat, but will do for now.
370 LOG_USER_N("%s", string
);
371 /* We already printed it above */
372 /* command_output_text(context, string); */
379 void command_print(struct command_context
*context
, const char *format
, ...)
384 va_start(ap
, format
);
386 string
= alloc_vprintf(format
, ap
);
389 strcat(string
, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one char longer */
390 /* we want this collected in the log + we also want to pick it up as a tcl return
393 * The latter bit isn't precisely neat, but will do for now.
395 LOG_USER_N("%s", string
);
396 /* We already printed it above */
397 /* command_output_text(context, string); */
404 static char *__command_name(struct command
*c
, char delim
, unsigned extra
)
407 unsigned len
= strlen(c
->name
);
408 if (NULL
== c
->parent
) {
409 // allocate enough for the name, child names, and '\0'
410 name
= malloc(len
+ extra
+ 1);
411 strcpy(name
, c
->name
);
413 // parent's extra must include both the space and name
414 name
= __command_name(c
->parent
, delim
, 1 + len
+ extra
);
415 char dstr
[2] = { delim
, 0 };
417 strcat(name
, c
->name
);
421 char *command_name(struct command
*c
, char delim
)
423 return __command_name(c
, delim
, 0);
426 static int run_command(struct command_context
*context
,
427 struct command
*c
, const char *words
[], unsigned num_words
)
429 if (!((context
->mode
== COMMAND_CONFIG
) || (c
->mode
== COMMAND_ANY
) || (c
->mode
== context
->mode
)))
431 /* Config commands can not run after the config stage */
432 LOG_ERROR("Command '%s' only runs during configuration stage", c
->name
);
436 struct command_invocation cmd
= {
439 .argc
= num_words
- 1,
442 int retval
= c
->handler(&cmd
);
443 if (retval
== ERROR_COMMAND_SYNTAX_ERROR
)
445 /* Print help for command */
446 char *full_name
= command_name(c
, ' ');
447 if (NULL
!= full_name
) {
448 command_run_linef(context
, "help %s", full_name
);
453 else if (retval
== ERROR_COMMAND_CLOSE_CONNECTION
)
455 /* just fall through for a shutdown request */
457 else if (retval
!= ERROR_OK
)
459 /* we do not print out an error message because the command *should*
460 * have printed out an error
462 LOG_DEBUG("Command failed with error code %d", retval
);
468 int command_run_line(struct command_context
*context
, char *line
)
470 /* all the parent commands have been registered with the interpreter
471 * so, can just evaluate the line as a script and check for
474 /* run the line thru a script engine */
475 int retval
= ERROR_FAIL
;
477 /* Beware! This code needs to be reentrant. It is also possible
478 * for OpenOCD commands to be invoked directly from Tcl. This would
479 * happen when the Jim Tcl interpreter is provided by eCos for
482 Jim_DeleteAssocData(interp
, "context");
483 retcode
= Jim_SetAssocData(interp
, "context", NULL
, context
);
484 if (retcode
== JIM_OK
)
486 /* associated the return value */
487 Jim_DeleteAssocData(interp
, "retval");
488 retcode
= Jim_SetAssocData(interp
, "retval", NULL
, &retval
);
489 if (retcode
== JIM_OK
)
491 retcode
= Jim_Eval_Named(interp
, line
, __THIS__FILE__
, __LINE__
);
493 Jim_DeleteAssocData(interp
, "retval");
495 Jim_DeleteAssocData(interp
, "context");
497 if (retcode
== JIM_ERR
) {
498 if (retval
!= ERROR_COMMAND_CLOSE_CONNECTION
)
500 /* We do not print the connection closed error message */
501 Jim_PrintErrorMessage(interp
);
503 if (retval
== ERROR_OK
)
505 /* It wasn't a low level OpenOCD command that failed */
509 } else if (retcode
== JIM_EXIT
) {
511 /* exit(Jim_GetExitCode(interp)); */
516 result
= Jim_GetString(Jim_GetResult(interp
), &reslen
);
521 for (i
= 0; i
< reslen
; i
+= 256)
527 strncpy(buff
, result
+ i
, chunk
);
529 LOG_USER_N("%s", buff
);
531 LOG_USER_N("%s", "\n");
538 int command_run_linef(struct command_context
*context
, const char *format
, ...)
540 int retval
= ERROR_FAIL
;
543 va_start(ap
, format
);
544 string
= alloc_vprintf(format
, ap
);
547 retval
= command_run_line(context
, string
);
553 void command_set_output_handler(struct command_context
* context
,
554 command_output_handler_t output_handler
, void *priv
)
556 context
->output_handler
= output_handler
;
557 context
->output_handler_priv
= priv
;
560 struct command_context
* copy_command_context(struct command_context
* context
)
562 struct command_context
* copy_context
= malloc(sizeof(struct command_context
));
564 *copy_context
= *context
;
569 int command_done(struct command_context
*context
)
577 /* find full path to file */
578 static int jim_find(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
582 const char *file
= Jim_GetString(argv
[1], NULL
);
583 char *full_path
= find_file(file
);
584 if (full_path
== NULL
)
586 Jim_Obj
*result
= Jim_NewStringObj(interp
, full_path
, strlen(full_path
));
589 Jim_SetResult(interp
, result
);
593 static int jim_echo(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
597 const char *str
= Jim_GetString(argv
[1], NULL
);
602 static size_t openocd_jim_fwrite(const void *_ptr
, size_t size
, size_t n
, void *cookie
)
608 /* make it a char easier to read code */
612 if (ptr
== NULL
|| interp
== NULL
|| nbytes
== 0) {
616 /* do we have to chunk it? */
617 if (ptr
[nbytes
] == 0)
619 /* no it is a C style string */
620 LOG_USER_N("%s", ptr
);
623 /* GRR we must chunk - not null terminated */
633 memcpy(chunk
, ptr
, x
);
637 LOG_USER_N("%s", chunk
);
645 static size_t openocd_jim_fread(void *ptr
, size_t size
, size_t n
, void *cookie
)
647 /* TCL wants to read... tell him no */
651 static int openocd_jim_vfprintf(void *cookie
, const char *fmt
, va_list ap
)
662 cp
= alloc_vprintf(fmt
, ap
);
665 LOG_USER_N("%s", cp
);
672 static int openocd_jim_fflush(void *cookie
)
674 /* nothing to flush */
678 static char* openocd_jim_fgets(char *s
, int size
, void *cookie
)
685 static int jim_capture(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
690 const char *str
= Jim_GetString(argv
[1], NULL
);
692 /* capture log output and return it */
693 Jim_Obj
*tclOutput
= Jim_NewStringObj(interp
, "", 0);
694 /* a garbage collect can happen, so we need a reference count to this object */
695 Jim_IncrRefCount(tclOutput
);
697 log_add_callback(tcl_output
, tclOutput
);
699 retcode
= Jim_Eval_Named(interp
, str
, __THIS__FILE__
, __LINE__
);
701 log_remove_callback(tcl_output
, tclOutput
);
703 /* We dump output into this local variable */
704 Jim_SetResult(interp
, tclOutput
);
705 Jim_DecrRefCount(interp
, tclOutput
);
710 static COMMAND_HELPER(command_help_find
, struct command
*head
,
711 struct command
**out
)
714 return ERROR_INVALID_ARGUMENTS
;
715 *out
= command_find(head
, CMD_ARGV
[0]);
717 return ERROR_INVALID_ARGUMENTS
;
721 return CALL_COMMAND_HANDLER(command_help_find
, (*out
)->children
, out
);
724 static COMMAND_HELPER(command_help_show
, struct command
*c
, unsigned n
);
726 static COMMAND_HELPER(command_help_show_list
, struct command
*head
, unsigned n
)
728 for (struct command
*c
= head
; NULL
!= c
; c
= c
->next
)
729 CALL_COMMAND_HANDLER(command_help_show
, c
, n
);
732 static COMMAND_HELPER(command_help_show
, struct command
*c
, unsigned n
)
734 command_run_linef(CMD_CTX
, "cmd_help {%s} {%s} %d", command_name(c
, ' '),
735 c
->help
? : "no help available", n
);
740 return CALL_COMMAND_HANDLER(command_help_show_list
, c
->children
, n
);
742 COMMAND_HANDLER(handle_help_command
)
744 struct command
*c
= CMD_CTX
->commands
;
747 return CALL_COMMAND_HANDLER(command_help_show_list
, c
, 0);
749 int retval
= CALL_COMMAND_HANDLER(command_help_find
, c
, &c
);
750 if (ERROR_OK
!= retval
)
753 return CALL_COMMAND_HANDLER(command_help_show
, c
, 0);
757 int help_add_command(struct command_context
*cmd_ctx
, struct command
*parent
,
758 const char *cmd_name
, const char *help_text
)
760 struct command
**head
= command_list_for_parent(cmd_ctx
, parent
);
761 struct command
*nc
= command_find(*head
, cmd_name
);
764 // add a new command with help text
765 nc
= register_command(cmd_ctx
, parent
, cmd_name
,
766 NULL
, COMMAND_ANY
, help_text
);
769 LOG_ERROR("failed to add '%s' help text", cmd_name
);
772 LOG_DEBUG("added '%s' help text", cmd_name
);
776 bool replaced
= false;
779 free((void *)nc
->help
);
782 nc
->help
= strdup(help_text
);
785 LOG_INFO("replaced existing '%s' help", cmd_name
);
787 LOG_DEBUG("added '%s' help text", cmd_name
);
792 COMMAND_HANDLER(handle_help_add_command
)
796 LOG_ERROR("%s: insufficient arguments", CMD_NAME
);
797 return ERROR_INVALID_ARGUMENTS
;
800 // save help text and remove it from argument list
801 const char *help_text
= CMD_ARGV
[--CMD_ARGC
];
802 // likewise for the leaf command name
803 const char *cmd_name
= CMD_ARGV
[--CMD_ARGC
];
805 struct command
*c
= NULL
;
808 c
= CMD_CTX
->commands
;
809 int retval
= CALL_COMMAND_HANDLER(command_help_find
, c
, &c
);
810 if (ERROR_OK
!= retval
)
813 return help_add_command(CMD_CTX
, c
, cmd_name
, help_text
);
816 /* sleep command sleeps for <n> miliseconds
817 * this is useful in target startup scripts
819 COMMAND_HANDLER(handle_sleep_command
)
824 if (strcmp(CMD_ARGV
[1], "busy") == 0)
827 return ERROR_COMMAND_SYNTAX_ERROR
;
829 else if (CMD_ARGC
< 1 || CMD_ARGC
> 2)
830 return ERROR_COMMAND_SYNTAX_ERROR
;
832 unsigned long duration
= 0;
833 int retval
= parse_ulong(CMD_ARGV
[0], &duration
);
834 if (ERROR_OK
!= retval
)
839 long long then
= timeval_ms();
840 while (timeval_ms() - then
< (long long)duration
)
842 target_call_timer_callbacks_now();
847 busy_sleep(duration
);
852 struct command_context
* command_init(const char *startup_tcl
)
854 struct command_context
* context
= malloc(sizeof(struct command_context
));
857 context
->mode
= COMMAND_EXEC
;
858 context
->commands
= NULL
;
859 context
->current_target
= 0;
860 context
->output_handler
= NULL
;
861 context
->output_handler_priv
= NULL
;
865 /* Create an interpreter */
866 interp
= Jim_CreateInterp();
867 /* Add all the Jim core commands */
868 Jim_RegisterCoreCommands(interp
);
871 #if defined(_MSC_VER)
872 /* WinXX - is generic, the forward
873 * looking problem is this:
877 * "winxx" is generic.
880 #elif defined(__linux__)
882 #elif defined(__DARWIN__)
884 #elif defined(__CYGWIN__)
886 #elif defined(__MINGW32__)
888 #elif defined(__ECOS)
891 #warn unrecognized host OS...
894 Jim_SetGlobalVariableStr(interp
, "ocd_HOSTOS",
895 Jim_NewStringObj(interp
, HostOs
, strlen(HostOs
)));
897 Jim_CreateCommand(interp
, "ocd_find", jim_find
, NULL
, NULL
);
898 Jim_CreateCommand(interp
, "echo", jim_echo
, NULL
, NULL
);
899 Jim_CreateCommand(interp
, "capture", jim_capture
, NULL
, NULL
);
901 /* Set Jim's STDIO */
902 interp
->cookie_stdin
= interp
;
903 interp
->cookie_stdout
= interp
;
904 interp
->cookie_stderr
= interp
;
905 interp
->cb_fwrite
= openocd_jim_fwrite
;
906 interp
->cb_fread
= openocd_jim_fread
;
907 interp
->cb_vfprintf
= openocd_jim_vfprintf
;
908 interp
->cb_fflush
= openocd_jim_fflush
;
909 interp
->cb_fgets
= openocd_jim_fgets
;
911 COMMAND_REGISTER(context
, NULL
, "add_help_text",
912 handle_help_add_command
, COMMAND_ANY
,
913 "<command> [...] <help_text>] - "
914 "add new command help text");
917 Jim_EventLoopOnLoad(interp
);
919 Jim_SetAssocData(interp
, "context", NULL
, context
);
920 if (Jim_Eval_Named(interp
, startup_tcl
, "embedded:startup.tcl",1) == JIM_ERR
)
922 LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD)");
923 Jim_PrintErrorMessage(interp
);
926 Jim_DeleteAssocData(interp
, "context");
928 COMMAND_REGISTER(context
, NULL
, "sleep",
929 handle_sleep_command
, COMMAND_ANY
,
930 "<n> [busy] - sleep for n milliseconds. "
931 "\"busy\" means busy wait");
933 COMMAND_REGISTER(context
, NULL
, "help",
934 &handle_help_command
, COMMAND_ANY
,
935 "[<command_name> ...] - show built-in command help");
940 int command_context_mode(struct command_context
*cmd_ctx
, enum command_mode mode
)
943 return ERROR_INVALID_ARGUMENTS
;
945 cmd_ctx
->mode
= mode
;
949 void process_jim_events(void)
952 static int recursion
= 0;
957 Jim_ProcessEvents (interp
, JIM_ALL_EVENTS
| JIM_DONT_WAIT
);
963 void register_jim(struct command_context
*cmd_ctx
, const char *name
,
964 Jim_CmdProc cmd
, const char *help
)
966 Jim_CreateCommand(interp
, name
, cmd
, NULL
, NULL
);
968 Jim_Obj
*cmd_list
= Jim_NewListObj(interp
, NULL
, 0);
969 Jim_ListAppendElement(interp
, cmd_list
,
970 Jim_NewStringObj(interp
, name
, -1));
972 help_add_command(cmd_ctx
, NULL
, name
, help
);
975 #define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max) \
976 int parse##name(const char *str, type *ul) \
980 LOG_ERROR("Invalid command argument"); \
981 return ERROR_COMMAND_ARGUMENT_INVALID; \
984 *ul = func(str, &end, 0); \
987 LOG_ERROR("Invalid command argument"); \
988 return ERROR_COMMAND_ARGUMENT_INVALID; \
990 if ((max == *ul) && (ERANGE == errno)) \
992 LOG_ERROR("Argument overflow"); \
993 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
995 if (min && (min == *ul) && (ERANGE == errno)) \
997 LOG_ERROR("Argument underflow"); \
998 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
1002 DEFINE_PARSE_NUM_TYPE(_ulong
, unsigned long , strtoul
, 0, ULONG_MAX
)
1003 DEFINE_PARSE_NUM_TYPE(_ullong
, unsigned long long, strtoull
, 0, ULLONG_MAX
)
1004 DEFINE_PARSE_NUM_TYPE(_long
, long , strtol
, LONG_MIN
, LONG_MAX
)
1005 DEFINE_PARSE_NUM_TYPE(_llong
, long long, strtoll
, LLONG_MIN
, LLONG_MAX
)
1007 #define DEFINE_PARSE_WRAPPER(name, type, min, max, functype, funcname) \
1008 int parse##name(const char *str, type *ul) \
1011 int retval = parse##funcname(str, &n); \
1012 if (ERROR_OK != retval) \
1015 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
1017 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
1022 #define DEFINE_PARSE_ULONG(name, type, min, max) \
1023 DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long, _ulong)
1024 DEFINE_PARSE_ULONG(_uint
, unsigned, 0, UINT_MAX
)
1025 DEFINE_PARSE_ULONG(_u32
, uint32_t, 0, UINT32_MAX
)
1026 DEFINE_PARSE_ULONG(_u16
, uint16_t, 0, UINT16_MAX
)
1027 DEFINE_PARSE_ULONG(_u8
, uint8_t, 0, UINT8_MAX
)
1029 #define DEFINE_PARSE_LONG(name, type, min, max) \
1030 DEFINE_PARSE_WRAPPER(name, type, min, max, long, _long)
1031 DEFINE_PARSE_LONG(_int
, int, n
< INT_MIN
, INT_MAX
)
1032 DEFINE_PARSE_LONG(_s32
, int32_t, n
< INT32_MIN
, INT32_MAX
)
1033 DEFINE_PARSE_LONG(_s16
, int16_t, n
< INT16_MIN
, INT16_MAX
)
1034 DEFINE_PARSE_LONG(_s8
, int8_t, n
< INT8_MIN
, INT8_MAX
)
1036 static int command_parse_bool(const char *in
, bool *out
,
1037 const char *on
, const char *off
)
1039 if (strcasecmp(in
, on
) == 0)
1041 else if (strcasecmp(in
, off
) == 0)
1044 return ERROR_COMMAND_SYNTAX_ERROR
;
1048 int command_parse_bool_arg(const char *in
, bool *out
)
1050 if (command_parse_bool(in
, out
, "on", "off") == ERROR_OK
)
1052 if (command_parse_bool(in
, out
, "enable", "disable") == ERROR_OK
)
1054 if (command_parse_bool(in
, out
, "true", "false") == ERROR_OK
)
1056 if (command_parse_bool(in
, out
, "yes", "no") == ERROR_OK
)
1058 if (command_parse_bool(in
, out
, "1", "0") == ERROR_OK
)
1060 return ERROR_INVALID_ARGUMENTS
;
1063 COMMAND_HELPER(handle_command_parse_bool
, bool *out
, const char *label
)
1067 const char *in
= CMD_ARGV
[0];
1068 if (command_parse_bool_arg(in
, out
) != ERROR_OK
)
1070 LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME
, in
);
1071 return ERROR_INVALID_ARGUMENTS
;
1076 LOG_INFO("%s is %s", label
, *out
? "enabled" : "disabled");
1079 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)