jtag: linuxgpiod: drop extra parenthesis
[openocd.git] / src / helper / command.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * Copyright (C) 2005 by Dominic Rath *
5 * Dominic.Rath@gmx.de *
6 * *
7 * Copyright (C) 2007,2008 Øyvind Harboe *
8 * oyvind.harboe@zylin.com *
9 * *
10 * Copyright (C) 2008, Duane Ellis *
11 * openocd@duaneeellis.com *
12 * *
13 * part of this file is taken from libcli (libcli.sourceforge.net) *
14 * Copyright (C) David Parrish (david@dparrish.com) *
15 ***************************************************************************/
16
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 /* @todo the inclusion of target.h here is a layering violation */
22 #include <jtag/jtag.h>
23 #include <target/target.h>
24 #include "command.h"
25 #include "configuration.h"
26 #include "log.h"
27 #include "time_support.h"
28 #include "jim-eventloop.h"
29
30 /* nice short description of source file */
31 #define __THIS__FILE__ "command.c"
32
33 struct log_capture_state {
34 Jim_Interp *interp;
35 Jim_Obj *output;
36 };
37
38 static int unregister_command(struct command_context *context,
39 const char *cmd_prefix, const char *name);
40 static int jim_command_dispatch(Jim_Interp *interp, int argc, Jim_Obj * const *argv);
41 static int help_add_command(struct command_context *cmd_ctx,
42 const char *cmd_name, const char *help_text, const char *usage_text);
43 static int help_del_command(struct command_context *cmd_ctx, const char *cmd_name);
44
45 /* set of functions to wrap jimtcl internal data */
46 static inline bool jimcmd_is_proc(Jim_Cmd *cmd)
47 {
48 return cmd->isproc;
49 }
50
51 bool jimcmd_is_oocd_command(Jim_Cmd *cmd)
52 {
53 return !cmd->isproc && cmd->u.native.cmdProc == jim_command_dispatch;
54 }
55
56 void *jimcmd_privdata(Jim_Cmd *cmd)
57 {
58 return cmd->isproc ? NULL : cmd->u.native.privData;
59 }
60
61 static void tcl_output(void *privData, const char *file, unsigned line,
62 const char *function, const char *string)
63 {
64 struct log_capture_state *state = privData;
65 Jim_AppendString(state->interp, state->output, string, strlen(string));
66 }
67
68 static struct log_capture_state *command_log_capture_start(Jim_Interp *interp)
69 {
70 /* capture log output and return it. A garbage collect can
71 * happen, so we need a reference count to this object */
72 Jim_Obj *jim_output = Jim_NewStringObj(interp, "", 0);
73 if (!jim_output)
74 return NULL;
75
76 Jim_IncrRefCount(jim_output);
77
78 struct log_capture_state *state = malloc(sizeof(*state));
79 if (!state) {
80 LOG_ERROR("Out of memory");
81 Jim_DecrRefCount(interp, jim_output);
82 return NULL;
83 }
84
85 state->interp = interp;
86 state->output = jim_output;
87
88 log_add_callback(tcl_output, state);
89
90 return state;
91 }
92
93 /* Classic openocd commands provide progress output which we
94 * will capture and return as a Tcl return value.
95 *
96 * However, if a non-openocd command has been invoked, then it
97 * makes sense to return the tcl return value from that command.
98 *
99 * The tcl return value is empty for openocd commands that provide
100 * progress output.
101 *
102 * For other commands, we prepend the logs to the tcl return value.
103 */
104 static void command_log_capture_finish(struct log_capture_state *state)
105 {
106 if (!state)
107 return;
108
109 log_remove_callback(tcl_output, state);
110
111 int loglen;
112 const char *log_result = Jim_GetString(state->output, &loglen);
113 int reslen;
114 const char *cmd_result = Jim_GetString(Jim_GetResult(state->interp), &reslen);
115
116 // Just in case the log doesn't end with a newline, we add it
117 if (loglen != 0 && reslen != 0 && log_result[loglen - 1] != '\n')
118 Jim_AppendString(state->interp, state->output, "\n", 1);
119
120 Jim_AppendString(state->interp, state->output, cmd_result, reslen);
121
122 Jim_SetResult(state->interp, state->output);
123 Jim_DecrRefCount(state->interp, state->output);
124
125 free(state);
126 }
127
128 static int command_retval_set(Jim_Interp *interp, int retval)
129 {
130 int *return_retval = Jim_GetAssocData(interp, "retval");
131 if (return_retval)
132 *return_retval = retval;
133
134 return (retval == ERROR_OK) ? JIM_OK : retval;
135 }
136
137 extern struct command_context *global_cmd_ctx;
138
139 /* dump a single line to the log for the command.
140 * Do nothing in case we are not at debug level 3 */
141 static void script_debug(Jim_Interp *interp, unsigned int argc, Jim_Obj * const *argv)
142 {
143 if (debug_level < LOG_LVL_DEBUG)
144 return;
145
146 char *dbg = alloc_printf("command -");
147 for (unsigned i = 0; i < argc; i++) {
148 const char *w = Jim_GetString(argv[i], NULL);
149 char *t = alloc_printf("%s %s", dbg, w);
150 free(dbg);
151 dbg = t;
152 }
153 LOG_DEBUG("%s", dbg);
154 free(dbg);
155 }
156
157 struct command_context *current_command_context(Jim_Interp *interp)
158 {
159 /* grab the command context from the associated data */
160 struct command_context *cmd_ctx = Jim_GetAssocData(interp, "context");
161 if (!cmd_ctx) {
162 /* Tcl can invoke commands directly instead of via command_run_line(). This would
163 * happen when the Jim Tcl interpreter is provided by eCos or if we are running
164 * commands in a startup script.
165 *
166 * A telnet or gdb server would provide a non-default command context to
167 * handle piping of error output, have a separate current target, etc.
168 */
169 cmd_ctx = global_cmd_ctx;
170 }
171 return cmd_ctx;
172 }
173
174 /**
175 * Find a openocd command from fullname.
176 * @returns Returns the named command if it is registred in interp.
177 * Returns NULL otherwise.
178 */
179 static struct command *command_find_from_name(Jim_Interp *interp, const char *name)
180 {
181 if (!name)
182 return NULL;
183
184 Jim_Obj *jim_name = Jim_NewStringObj(interp, name, -1);
185 Jim_IncrRefCount(jim_name);
186 Jim_Cmd *cmd = Jim_GetCommand(interp, jim_name, JIM_NONE);
187 Jim_DecrRefCount(interp, jim_name);
188 if (!cmd || jimcmd_is_proc(cmd) || !jimcmd_is_oocd_command(cmd))
189 return NULL;
190
191 return jimcmd_privdata(cmd);
192 }
193
194 static struct command *command_new(struct command_context *cmd_ctx,
195 const char *full_name, const struct command_registration *cr)
196 {
197 assert(cr->name);
198
199 /*
200 * If it is a non-jim command with no .usage specified,
201 * log an error.
202 *
203 * strlen(.usage) == 0 means that the command takes no
204 * arguments.
205 */
206 if (!cr->jim_handler && !cr->usage)
207 LOG_ERROR("BUG: command '%s' does not have the "
208 "'.usage' field filled out",
209 full_name);
210
211 struct command *c = calloc(1, sizeof(struct command));
212 if (!c)
213 return NULL;
214
215 c->name = strdup(cr->name);
216 if (!c->name) {
217 free(c);
218 return NULL;
219 }
220
221 c->handler = cr->handler;
222 c->jim_handler = cr->jim_handler;
223 c->mode = cr->mode;
224
225 if (cr->help || cr->usage)
226 help_add_command(cmd_ctx, full_name, cr->help, cr->usage);
227
228 return c;
229 }
230
231 static void command_free(struct Jim_Interp *interp, void *priv)
232 {
233 struct command *c = priv;
234
235 free(c->name);
236 free(c);
237 }
238
239 static struct command *register_command(struct command_context *context,
240 const char *cmd_prefix, const struct command_registration *cr)
241 {
242 char *full_name;
243
244 if (!context || !cr->name)
245 return NULL;
246
247 if (cmd_prefix)
248 full_name = alloc_printf("%s %s", cmd_prefix, cr->name);
249 else
250 full_name = strdup(cr->name);
251 if (!full_name)
252 return NULL;
253
254 struct command *c = command_find_from_name(context->interp, full_name);
255 if (c) {
256 /* TODO: originally we treated attempting to register a cmd twice as an error
257 * Sometimes we need this behaviour, such as with flash banks.
258 * http://www.mail-archive.com/openocd-development@lists.berlios.de/msg11152.html */
259 LOG_DEBUG("command '%s' is already registered", full_name);
260 free(full_name);
261 return c;
262 }
263
264 c = command_new(context, full_name, cr);
265 if (!c) {
266 free(full_name);
267 return NULL;
268 }
269
270 if (false) /* too noisy with debug_level 3 */
271 LOG_DEBUG("registering '%s'...", full_name);
272 int retval = Jim_CreateCommand(context->interp, full_name,
273 jim_command_dispatch, c, command_free);
274 if (retval != JIM_OK) {
275 command_run_linef(context, "del_help_text {%s}", full_name);
276 command_run_linef(context, "del_usage_text {%s}", full_name);
277 free(c);
278 free(full_name);
279 return NULL;
280 }
281
282 free(full_name);
283 return c;
284 }
285
286 int __register_commands(struct command_context *cmd_ctx, const char *cmd_prefix,
287 const struct command_registration *cmds, void *data,
288 struct target *override_target)
289 {
290 int retval = ERROR_OK;
291 unsigned i;
292 for (i = 0; cmds[i].name || cmds[i].chain; i++) {
293 const struct command_registration *cr = cmds + i;
294
295 struct command *c = NULL;
296 if (cr->name) {
297 c = register_command(cmd_ctx, cmd_prefix, cr);
298 if (!c) {
299 retval = ERROR_FAIL;
300 break;
301 }
302 c->jim_handler_data = data;
303 c->jim_override_target = override_target;
304 }
305 if (cr->chain) {
306 if (cr->name) {
307 if (cmd_prefix) {
308 char *new_prefix = alloc_printf("%s %s", cmd_prefix, cr->name);
309 if (!new_prefix) {
310 retval = ERROR_FAIL;
311 break;
312 }
313 retval = __register_commands(cmd_ctx, new_prefix, cr->chain, data, override_target);
314 free(new_prefix);
315 } else {
316 retval = __register_commands(cmd_ctx, cr->name, cr->chain, data, override_target);
317 }
318 } else {
319 retval = __register_commands(cmd_ctx, cmd_prefix, cr->chain, data, override_target);
320 }
321 if (retval != ERROR_OK)
322 break;
323 }
324 }
325 if (retval != ERROR_OK) {
326 for (unsigned j = 0; j < i; j++)
327 unregister_command(cmd_ctx, cmd_prefix, cmds[j].name);
328 }
329 return retval;
330 }
331
332 static __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3)))
333 int unregister_commands_match(struct command_context *cmd_ctx, const char *format, ...)
334 {
335 Jim_Interp *interp = cmd_ctx->interp;
336 va_list ap;
337
338 va_start(ap, format);
339 char *query = alloc_vprintf(format, ap);
340 va_end(ap);
341 if (!query)
342 return ERROR_FAIL;
343
344 char *query_cmd = alloc_printf("info commands {%s}", query);
345 free(query);
346 if (!query_cmd)
347 return ERROR_FAIL;
348
349 int retval = Jim_EvalSource(interp, __THIS__FILE__, __LINE__, query_cmd);
350 free(query_cmd);
351 if (retval != JIM_OK)
352 return ERROR_FAIL;
353
354 Jim_Obj *list = Jim_GetResult(interp);
355 Jim_IncrRefCount(list);
356
357 int len = Jim_ListLength(interp, list);
358 for (int i = 0; i < len; i++) {
359 Jim_Obj *elem = Jim_ListGetIndex(interp, list, i);
360 Jim_IncrRefCount(elem);
361
362 const char *name = Jim_GetString(elem, NULL);
363 struct command *c = command_find_from_name(interp, name);
364 if (!c) {
365 /* not openocd command */
366 Jim_DecrRefCount(interp, elem);
367 continue;
368 }
369 if (false) /* too noisy with debug_level 3 */
370 LOG_DEBUG("delete command \"%s\"", name);
371 #if JIM_VERSION >= 80
372 Jim_DeleteCommand(interp, elem);
373 #else
374 Jim_DeleteCommand(interp, name);
375 #endif
376
377 help_del_command(cmd_ctx, name);
378
379 Jim_DecrRefCount(interp, elem);
380 }
381
382 Jim_DecrRefCount(interp, list);
383 return ERROR_OK;
384 }
385
386 int unregister_all_commands(struct command_context *context,
387 const char *cmd_prefix)
388 {
389 if (!context)
390 return ERROR_OK;
391
392 if (!cmd_prefix || !*cmd_prefix)
393 return unregister_commands_match(context, "*");
394
395 int retval = unregister_commands_match(context, "%s *", cmd_prefix);
396 if (retval != ERROR_OK)
397 return retval;
398
399 return unregister_commands_match(context, "%s", cmd_prefix);
400 }
401
402 static int unregister_command(struct command_context *context,
403 const char *cmd_prefix, const char *name)
404 {
405 if (!context || !name)
406 return ERROR_COMMAND_SYNTAX_ERROR;
407
408 if (!cmd_prefix || !*cmd_prefix)
409 return unregister_commands_match(context, "%s", name);
410
411 return unregister_commands_match(context, "%s %s", cmd_prefix, name);
412 }
413
414 void command_output_text(struct command_context *context, const char *data)
415 {
416 if (context && context->output_handler && data)
417 context->output_handler(context, data);
418 }
419
420 void command_print_sameline(struct command_invocation *cmd, const char *format, ...)
421 {
422 char *string;
423
424 va_list ap;
425 va_start(ap, format);
426
427 string = alloc_vprintf(format, ap);
428 if (string && cmd) {
429 /* we want this collected in the log + we also want to pick it up as a tcl return
430 * value.
431 *
432 * The latter bit isn't precisely neat, but will do for now.
433 */
434 Jim_AppendString(cmd->ctx->interp, cmd->output, string, -1);
435 /* We already printed it above
436 * command_output_text(context, string); */
437 free(string);
438 }
439
440 va_end(ap);
441 }
442
443 void command_print(struct command_invocation *cmd, const char *format, ...)
444 {
445 char *string;
446
447 va_list ap;
448 va_start(ap, format);
449
450 string = alloc_vprintf(format, ap);
451 if (string && cmd) {
452 strcat(string, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one
453 *char longer */
454 /* we want this collected in the log + we also want to pick it up as a tcl return
455 * value.
456 *
457 * The latter bit isn't precisely neat, but will do for now.
458 */
459 Jim_AppendString(cmd->ctx->interp, cmd->output, string, -1);
460 /* We already printed it above
461 * command_output_text(context, string); */
462 free(string);
463 }
464
465 va_end(ap);
466 }
467
468 static bool command_can_run(struct command_context *cmd_ctx, struct command *c, const char *full_name)
469 {
470 if (c->mode == COMMAND_ANY || c->mode == cmd_ctx->mode)
471 return true;
472
473 /* Many commands may be run only before/after 'init' */
474 const char *when;
475 switch (c->mode) {
476 case COMMAND_CONFIG:
477 when = "before";
478 break;
479 case COMMAND_EXEC:
480 when = "after";
481 break;
482 /* handle the impossible with humor; it guarantees a bug report! */
483 default:
484 when = "if Cthulhu is summoned by";
485 break;
486 }
487 LOG_ERROR("The '%s' command must be used %s 'init'.",
488 full_name ? full_name : c->name, when);
489 return false;
490 }
491
492 static int exec_command(Jim_Interp *interp, struct command_context *context,
493 struct command *c, int argc, Jim_Obj * const *argv)
494 {
495 if (c->jim_handler)
496 return c->jim_handler(interp, argc, argv);
497
498 /* use c->handler */
499 const char **words = malloc(argc * sizeof(char *));
500 if (!words) {
501 LOG_ERROR("Out of memory");
502 return JIM_ERR;
503 }
504
505 for (int i = 0; i < argc; i++)
506 words[i] = Jim_GetString(argv[i], NULL);
507
508 struct command_invocation cmd = {
509 .ctx = context,
510 .current = c,
511 .name = c->name,
512 .argc = argc - 1,
513 .argv = words + 1,
514 .jimtcl_argv = argv + 1,
515 };
516
517 cmd.output = Jim_NewEmptyStringObj(context->interp);
518 Jim_IncrRefCount(cmd.output);
519
520 int retval = c->handler(&cmd);
521 if (retval == ERROR_COMMAND_SYNTAX_ERROR) {
522 /* Print help for command */
523 command_run_linef(context, "usage %s", words[0]);
524 } else if (retval == ERROR_COMMAND_CLOSE_CONNECTION) {
525 /* just fall through for a shutdown request */
526 } else {
527 if (retval != ERROR_OK)
528 LOG_DEBUG("Command '%s' failed with error code %d",
529 words[0], retval);
530 /*
531 * Use the command output as the Tcl result.
532 * Drop last '\n' to allow command output concatenation
533 * while keep using command_print() everywhere.
534 */
535 const char *output_txt = Jim_String(cmd.output);
536 int len = strlen(output_txt);
537 if (len && output_txt[len - 1] == '\n')
538 --len;
539 Jim_SetResultString(context->interp, output_txt, len);
540 }
541 Jim_DecrRefCount(context->interp, cmd.output);
542
543 free(words);
544 return command_retval_set(interp, retval);
545 }
546
547 int command_run_line(struct command_context *context, char *line)
548 {
549 /* all the parent commands have been registered with the interpreter
550 * so, can just evaluate the line as a script and check for
551 * results
552 */
553 /* run the line thru a script engine */
554 int retval = ERROR_FAIL;
555 int retcode;
556 /* Beware! This code needs to be reentrant. It is also possible
557 * for OpenOCD commands to be invoked directly from Tcl. This would
558 * happen when the Jim Tcl interpreter is provided by eCos for
559 * instance.
560 */
561 struct target *saved_target_override = context->current_target_override;
562 context->current_target_override = NULL;
563
564 Jim_Interp *interp = context->interp;
565 struct command_context *old_context = Jim_GetAssocData(interp, "context");
566 Jim_DeleteAssocData(interp, "context");
567 retcode = Jim_SetAssocData(interp, "context", NULL, context);
568 if (retcode == JIM_OK) {
569 /* associated the return value */
570 Jim_DeleteAssocData(interp, "retval");
571 retcode = Jim_SetAssocData(interp, "retval", NULL, &retval);
572 if (retcode == JIM_OK) {
573 retcode = Jim_Eval_Named(interp, line, NULL, 0);
574
575 Jim_DeleteAssocData(interp, "retval");
576 }
577 Jim_DeleteAssocData(interp, "context");
578 int inner_retcode = Jim_SetAssocData(interp, "context", NULL, old_context);
579 if (retcode == JIM_OK)
580 retcode = inner_retcode;
581 }
582 context->current_target_override = saved_target_override;
583 if (retcode == JIM_OK) {
584 const char *result;
585 int reslen;
586
587 result = Jim_GetString(Jim_GetResult(interp), &reslen);
588 if (reslen > 0) {
589 command_output_text(context, result);
590 command_output_text(context, "\n");
591 }
592 retval = ERROR_OK;
593 } else if (retcode == JIM_EXIT) {
594 /* ignore.
595 * exit(Jim_GetExitCode(interp)); */
596 } else if (retcode == ERROR_COMMAND_CLOSE_CONNECTION) {
597 return retcode;
598 } else {
599 Jim_MakeErrorMessage(interp);
600 /* error is broadcast */
601 LOG_USER("%s", Jim_GetString(Jim_GetResult(interp), NULL));
602
603 if (retval == ERROR_OK) {
604 /* It wasn't a low level OpenOCD command that failed */
605 return ERROR_FAIL;
606 }
607 return retval;
608 }
609
610 return retval;
611 }
612
613 int command_run_linef(struct command_context *context, const char *format, ...)
614 {
615 int retval = ERROR_FAIL;
616 char *string;
617 va_list ap;
618 va_start(ap, format);
619 string = alloc_vprintf(format, ap);
620 if (string) {
621 retval = command_run_line(context, string);
622 free(string);
623 }
624 va_end(ap);
625 return retval;
626 }
627
628 void command_set_output_handler(struct command_context *context,
629 command_output_handler_t output_handler, void *priv)
630 {
631 context->output_handler = output_handler;
632 context->output_handler_priv = priv;
633 }
634
635 struct command_context *copy_command_context(struct command_context *context)
636 {
637 struct command_context *copy_context = malloc(sizeof(struct command_context));
638
639 *copy_context = *context;
640
641 return copy_context;
642 }
643
644 void command_done(struct command_context *cmd_ctx)
645 {
646 if (!cmd_ctx)
647 return;
648
649 free(cmd_ctx);
650 }
651
652 /* find full path to file */
653 COMMAND_HANDLER(handle_find)
654 {
655 if (CMD_ARGC != 1)
656 return ERROR_COMMAND_SYNTAX_ERROR;
657
658 char *full_path = find_file(CMD_ARGV[0]);
659 if (!full_path)
660 return ERROR_COMMAND_ARGUMENT_INVALID;
661
662 command_print(CMD, "%s", full_path);
663 free(full_path);
664
665 return ERROR_OK;
666 }
667
668 COMMAND_HANDLER(handle_echo)
669 {
670 if (CMD_ARGC == 2 && !strcmp(CMD_ARGV[0], "-n")) {
671 LOG_USER_N("%s", CMD_ARGV[1]);
672 return ERROR_OK;
673 }
674
675 if (CMD_ARGC != 1)
676 return ERROR_FAIL;
677
678 LOG_USER("%s", CMD_ARGV[0]);
679 return ERROR_OK;
680 }
681
682 /* Return both the progress output (LOG_INFO and higher)
683 * and the tcl return value of a command.
684 */
685 static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
686 {
687 if (argc != 2)
688 return JIM_ERR;
689
690 struct log_capture_state *state = command_log_capture_start(interp);
691
692 /* disable polling during capture. This avoids capturing output
693 * from polling.
694 *
695 * This is necessary in order to avoid accidentally getting a non-empty
696 * string for tcl fn's.
697 */
698 bool save_poll_mask = jtag_poll_mask();
699
700 const char *str = Jim_GetString(argv[1], NULL);
701 int retcode = Jim_Eval_Named(interp, str, __THIS__FILE__, __LINE__);
702
703 jtag_poll_unmask(save_poll_mask);
704
705 command_log_capture_finish(state);
706
707 return retcode;
708 }
709
710 struct help_entry {
711 struct list_head lh;
712 char *cmd_name;
713 char *help;
714 char *usage;
715 };
716
717 static COMMAND_HELPER(command_help_show, struct help_entry *c,
718 bool show_help, const char *cmd_match);
719
720 static COMMAND_HELPER(command_help_show_list, bool show_help, const char *cmd_match)
721 {
722 struct help_entry *entry;
723
724 list_for_each_entry(entry, CMD_CTX->help_list, lh)
725 CALL_COMMAND_HANDLER(command_help_show, entry, show_help, cmd_match);
726 return ERROR_OK;
727 }
728
729 #define HELP_LINE_WIDTH(_n) (int)(76 - (2 * _n))
730
731 static void command_help_show_indent(unsigned n)
732 {
733 for (unsigned i = 0; i < n; i++)
734 LOG_USER_N(" ");
735 }
736 static void command_help_show_wrap(const char *str, unsigned n, unsigned n2)
737 {
738 const char *cp = str, *last = str;
739 while (*cp) {
740 const char *next = last;
741 do {
742 cp = next;
743 do {
744 next++;
745 } while (*next != ' ' && *next != '\t' && *next != '\0');
746 } while ((next - last < HELP_LINE_WIDTH(n)) && *next != '\0');
747 if (next - last < HELP_LINE_WIDTH(n))
748 cp = next;
749 command_help_show_indent(n);
750 LOG_USER("%.*s", (int)(cp - last), last);
751 last = cp + 1;
752 n = n2;
753 }
754 }
755
756 static COMMAND_HELPER(command_help_show, struct help_entry *c,
757 bool show_help, const char *cmd_match)
758 {
759 unsigned int n = 0;
760 for (const char *s = strchr(c->cmd_name, ' '); s; s = strchr(s + 1, ' '))
761 n++;
762
763 /* If the match string occurs anywhere, we print out
764 * stuff for this command. */
765 bool is_match = strstr(c->cmd_name, cmd_match) ||
766 (c->usage && strstr(c->usage, cmd_match)) ||
767 (c->help && strstr(c->help, cmd_match));
768
769 if (is_match) {
770 if (c->usage && strlen(c->usage) > 0) {
771 char *msg = alloc_printf("%s %s", c->cmd_name, c->usage);
772 command_help_show_wrap(msg, n, n + 5);
773 free(msg);
774 } else {
775 command_help_show_wrap(c->cmd_name, n, n + 5);
776 }
777 }
778
779 if (is_match && show_help) {
780 char *msg;
781
782 /* TODO: factorize jim_command_mode() to avoid running jim command here */
783 char *request = alloc_printf("command mode %s", c->cmd_name);
784 if (!request) {
785 LOG_ERROR("Out of memory");
786 return ERROR_FAIL;
787 }
788 int retval = Jim_Eval(CMD_CTX->interp, request);
789 free(request);
790 enum command_mode mode = COMMAND_UNKNOWN;
791 if (retval != JIM_ERR) {
792 const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), NULL);
793 if (!strcmp(result, "any"))
794 mode = COMMAND_ANY;
795 else if (!strcmp(result, "config"))
796 mode = COMMAND_CONFIG;
797 else if (!strcmp(result, "exec"))
798 mode = COMMAND_EXEC;
799 }
800
801 /* Normal commands are runtime-only; highlight exceptions */
802 if (mode != COMMAND_EXEC) {
803 const char *stage_msg = "";
804
805 switch (mode) {
806 case COMMAND_CONFIG:
807 stage_msg = " (configuration command)";
808 break;
809 case COMMAND_ANY:
810 stage_msg = " (command valid any time)";
811 break;
812 default:
813 stage_msg = " (?mode error?)";
814 break;
815 }
816 msg = alloc_printf("%s%s", c->help ? c->help : "", stage_msg);
817 } else
818 msg = alloc_printf("%s", c->help ? c->help : "");
819
820 if (msg) {
821 command_help_show_wrap(msg, n + 3, n + 3);
822 free(msg);
823 } else
824 return -ENOMEM;
825 }
826
827 return ERROR_OK;
828 }
829
830 COMMAND_HANDLER(handle_help_command)
831 {
832 bool full = strcmp(CMD_NAME, "help") == 0;
833 int retval;
834 char *cmd_match;
835
836 if (CMD_ARGC <= 0)
837 cmd_match = strdup("");
838
839 else {
840 cmd_match = strdup(CMD_ARGV[0]);
841
842 for (unsigned int i = 1; i < CMD_ARGC && cmd_match; ++i) {
843 char *prev = cmd_match;
844 cmd_match = alloc_printf("%s %s", prev, CMD_ARGV[i]);
845 free(prev);
846 }
847 }
848
849 if (!cmd_match) {
850 LOG_ERROR("unable to build search string");
851 return -ENOMEM;
852 }
853 retval = CALL_COMMAND_HANDLER(command_help_show_list, full, cmd_match);
854
855 free(cmd_match);
856 return retval;
857 }
858
859 static char *alloc_concatenate_strings(int argc, Jim_Obj * const *argv)
860 {
861 char *prev, *all;
862 int i;
863
864 assert(argc >= 1);
865
866 all = strdup(Jim_GetString(argv[0], NULL));
867 if (!all) {
868 LOG_ERROR("Out of memory");
869 return NULL;
870 }
871
872 for (i = 1; i < argc; ++i) {
873 prev = all;
874 all = alloc_printf("%s %s", all, Jim_GetString(argv[i], NULL));
875 free(prev);
876 if (!all) {
877 LOG_ERROR("Out of memory");
878 return NULL;
879 }
880 }
881
882 return all;
883 }
884
885 static int jim_command_dispatch(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
886 {
887 /* check subcommands */
888 if (argc > 1) {
889 char *s = alloc_printf("%s %s", Jim_GetString(argv[0], NULL), Jim_GetString(argv[1], NULL));
890 Jim_Obj *js = Jim_NewStringObj(interp, s, -1);
891 Jim_IncrRefCount(js);
892 free(s);
893 Jim_Cmd *cmd = Jim_GetCommand(interp, js, JIM_NONE);
894 if (cmd) {
895 int retval = Jim_EvalObjPrefix(interp, js, argc - 2, argv + 2);
896 Jim_DecrRefCount(interp, js);
897 return retval;
898 }
899 Jim_DecrRefCount(interp, js);
900 }
901
902 script_debug(interp, argc, argv);
903
904 struct command *c = jim_to_command(interp);
905 if (!c->jim_handler && !c->handler) {
906 Jim_EvalObjPrefix(interp, Jim_NewStringObj(interp, "usage", -1), 1, argv);
907 return JIM_ERR;
908 }
909
910 struct command_context *cmd_ctx = current_command_context(interp);
911
912 if (!command_can_run(cmd_ctx, c, Jim_GetString(argv[0], NULL)))
913 return JIM_ERR;
914
915 target_call_timer_callbacks();
916
917 /*
918 * Black magic of overridden current target:
919 * If the command we are going to handle has a target prefix,
920 * override the current target temporarily for the time
921 * of processing the command.
922 * current_target_override is used also for event handlers
923 * therefore we prevent touching it if command has no prefix.
924 * Previous override is saved and restored back to ensure
925 * correct work when jim_command_dispatch() is re-entered.
926 */
927 struct target *saved_target_override = cmd_ctx->current_target_override;
928 if (c->jim_override_target)
929 cmd_ctx->current_target_override = c->jim_override_target;
930
931 int retval = exec_command(interp, cmd_ctx, c, argc, argv);
932
933 if (c->jim_override_target)
934 cmd_ctx->current_target_override = saved_target_override;
935
936 return retval;
937 }
938
939 static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
940 {
941 struct command_context *cmd_ctx = current_command_context(interp);
942 enum command_mode mode;
943
944 if (argc > 1) {
945 char *full_name = alloc_concatenate_strings(argc - 1, argv + 1);
946 if (!full_name)
947 return JIM_ERR;
948 Jim_Obj *s = Jim_NewStringObj(interp, full_name, -1);
949 Jim_IncrRefCount(s);
950 Jim_Cmd *cmd = Jim_GetCommand(interp, s, JIM_NONE);
951 Jim_DecrRefCount(interp, s);
952 free(full_name);
953 if (!cmd || !(jimcmd_is_proc(cmd) || jimcmd_is_oocd_command(cmd))) {
954 Jim_SetResultString(interp, "unknown", -1);
955 return JIM_OK;
956 }
957
958 if (jimcmd_is_proc(cmd)) {
959 /* tcl proc */
960 mode = COMMAND_ANY;
961 } else {
962 struct command *c = jimcmd_privdata(cmd);
963
964 mode = c->mode;
965 }
966 } else
967 mode = cmd_ctx->mode;
968
969 const char *mode_str;
970 switch (mode) {
971 case COMMAND_ANY:
972 mode_str = "any";
973 break;
974 case COMMAND_CONFIG:
975 mode_str = "config";
976 break;
977 case COMMAND_EXEC:
978 mode_str = "exec";
979 break;
980 default:
981 mode_str = "unknown";
982 break;
983 }
984 Jim_SetResultString(interp, mode_str, -1);
985 return JIM_OK;
986 }
987
988 int help_del_all_commands(struct command_context *cmd_ctx)
989 {
990 struct help_entry *curr, *n;
991
992 list_for_each_entry_safe(curr, n, cmd_ctx->help_list, lh) {
993 list_del(&curr->lh);
994 free(curr->cmd_name);
995 free(curr->help);
996 free(curr->usage);
997 free(curr);
998 }
999 return ERROR_OK;
1000 }
1001
1002 static int help_del_command(struct command_context *cmd_ctx, const char *cmd_name)
1003 {
1004 struct help_entry *curr;
1005
1006 list_for_each_entry(curr, cmd_ctx->help_list, lh) {
1007 if (!strcmp(cmd_name, curr->cmd_name)) {
1008 list_del(&curr->lh);
1009 free(curr->cmd_name);
1010 free(curr->help);
1011 free(curr->usage);
1012 free(curr);
1013 break;
1014 }
1015 }
1016
1017 return ERROR_OK;
1018 }
1019
1020 static int help_add_command(struct command_context *cmd_ctx,
1021 const char *cmd_name, const char *help_text, const char *usage_text)
1022 {
1023 int cmp = -1; /* add after curr */
1024 struct help_entry *curr;
1025
1026 list_for_each_entry_reverse(curr, cmd_ctx->help_list, lh) {
1027 cmp = strcmp(cmd_name, curr->cmd_name);
1028 if (cmp >= 0)
1029 break;
1030 }
1031
1032 struct help_entry *entry;
1033 if (cmp) {
1034 entry = calloc(1, sizeof(*entry));
1035 if (!entry) {
1036 LOG_ERROR("Out of memory");
1037 return ERROR_FAIL;
1038 }
1039 entry->cmd_name = strdup(cmd_name);
1040 if (!entry->cmd_name) {
1041 LOG_ERROR("Out of memory");
1042 free(entry);
1043 return ERROR_FAIL;
1044 }
1045 list_add(&entry->lh, &curr->lh);
1046 } else {
1047 entry = curr;
1048 }
1049
1050 if (help_text) {
1051 char *text = strdup(help_text);
1052 if (!text) {
1053 LOG_ERROR("Out of memory");
1054 return ERROR_FAIL;
1055 }
1056 free(entry->help);
1057 entry->help = text;
1058 }
1059
1060 if (usage_text) {
1061 char *text = strdup(usage_text);
1062 if (!text) {
1063 LOG_ERROR("Out of memory");
1064 return ERROR_FAIL;
1065 }
1066 free(entry->usage);
1067 entry->usage = text;
1068 }
1069
1070 return ERROR_OK;
1071 }
1072
1073 COMMAND_HANDLER(handle_help_add_command)
1074 {
1075 if (CMD_ARGC != 2)
1076 return ERROR_COMMAND_SYNTAX_ERROR;
1077
1078 const char *help = !strcmp(CMD_NAME, "add_help_text") ? CMD_ARGV[1] : NULL;
1079 const char *usage = !strcmp(CMD_NAME, "add_usage_text") ? CMD_ARGV[1] : NULL;
1080 if (!help && !usage) {
1081 LOG_ERROR("command name '%s' is unknown", CMD_NAME);
1082 return ERROR_COMMAND_SYNTAX_ERROR;
1083 }
1084 const char *cmd_name = CMD_ARGV[0];
1085 return help_add_command(CMD_CTX, cmd_name, help, usage);
1086 }
1087
1088 /* sleep command sleeps for <n> milliseconds
1089 * this is useful in target startup scripts
1090 */
1091 COMMAND_HANDLER(handle_sleep_command)
1092 {
1093 bool busy = false;
1094 if (CMD_ARGC == 2) {
1095 if (strcmp(CMD_ARGV[1], "busy") == 0)
1096 busy = true;
1097 else
1098 return ERROR_COMMAND_SYNTAX_ERROR;
1099 } else if (CMD_ARGC < 1 || CMD_ARGC > 2)
1100 return ERROR_COMMAND_SYNTAX_ERROR;
1101
1102 unsigned long duration = 0;
1103 int retval = parse_ulong(CMD_ARGV[0], &duration);
1104 if (retval != ERROR_OK)
1105 return retval;
1106
1107 if (!busy) {
1108 int64_t then = timeval_ms();
1109 while (timeval_ms() - then < (int64_t)duration) {
1110 target_call_timer_callbacks_now();
1111 keep_alive();
1112 usleep(1000);
1113 }
1114 } else
1115 busy_sleep(duration);
1116
1117 return ERROR_OK;
1118 }
1119
1120 static const struct command_registration command_subcommand_handlers[] = {
1121 {
1122 .name = "mode",
1123 .mode = COMMAND_ANY,
1124 .jim_handler = jim_command_mode,
1125 .usage = "[command_name ...]",
1126 .help = "Returns the command modes allowed by a command: "
1127 "'any', 'config', or 'exec'. If no command is "
1128 "specified, returns the current command mode. "
1129 "Returns 'unknown' if an unknown command is given. "
1130 "Command can be multiple tokens.",
1131 },
1132 COMMAND_REGISTRATION_DONE
1133 };
1134
1135 static const struct command_registration command_builtin_handlers[] = {
1136 {
1137 .name = "ocd_find",
1138 .mode = COMMAND_ANY,
1139 .handler = handle_find,
1140 .help = "find full path to file",
1141 .usage = "file",
1142 },
1143 {
1144 .name = "capture",
1145 .mode = COMMAND_ANY,
1146 .jim_handler = jim_capture,
1147 .help = "Capture progress output and return as tcl return value. If the "
1148 "progress output was empty, return tcl return value.",
1149 .usage = "command",
1150 },
1151 {
1152 .name = "echo",
1153 .handler = handle_echo,
1154 .mode = COMMAND_ANY,
1155 .help = "Logs a message at \"user\" priority. "
1156 "Option \"-n\" suppresses trailing newline",
1157 .usage = "[-n] string",
1158 },
1159 {
1160 .name = "add_help_text",
1161 .handler = handle_help_add_command,
1162 .mode = COMMAND_ANY,
1163 .help = "Add new command help text; "
1164 "Command can be multiple tokens.",
1165 .usage = "command_name helptext_string",
1166 },
1167 {
1168 .name = "add_usage_text",
1169 .handler = handle_help_add_command,
1170 .mode = COMMAND_ANY,
1171 .help = "Add new command usage text; "
1172 "command can be multiple tokens.",
1173 .usage = "command_name usage_string",
1174 },
1175 {
1176 .name = "sleep",
1177 .handler = handle_sleep_command,
1178 .mode = COMMAND_ANY,
1179 .help = "Sleep for specified number of milliseconds. "
1180 "\"busy\" will busy wait instead (avoid this).",
1181 .usage = "milliseconds ['busy']",
1182 },
1183 {
1184 .name = "help",
1185 .handler = handle_help_command,
1186 .mode = COMMAND_ANY,
1187 .help = "Show full command help; "
1188 "command can be multiple tokens.",
1189 .usage = "[command_name]",
1190 },
1191 {
1192 .name = "usage",
1193 .handler = handle_help_command,
1194 .mode = COMMAND_ANY,
1195 .help = "Show basic command usage; "
1196 "command can be multiple tokens.",
1197 .usage = "[command_name]",
1198 },
1199 {
1200 .name = "command",
1201 .mode = COMMAND_ANY,
1202 .help = "core command group (introspection)",
1203 .chain = command_subcommand_handlers,
1204 .usage = "",
1205 },
1206 COMMAND_REGISTRATION_DONE
1207 };
1208
1209 struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp)
1210 {
1211 struct command_context *context = calloc(1, sizeof(struct command_context));
1212
1213 context->mode = COMMAND_EXEC;
1214
1215 /* context can be duplicated. Put list head on separate mem-chunk to keep list consistent */
1216 context->help_list = malloc(sizeof(*context->help_list));
1217 INIT_LIST_HEAD(context->help_list);
1218
1219 /* Create a jim interpreter if we were not handed one */
1220 if (!interp) {
1221 /* Create an interpreter */
1222 interp = Jim_CreateInterp();
1223 /* Add all the Jim core commands */
1224 Jim_RegisterCoreCommands(interp);
1225 Jim_InitStaticExtensions(interp);
1226 }
1227
1228 context->interp = interp;
1229
1230 register_commands(context, NULL, command_builtin_handlers);
1231
1232 Jim_SetAssocData(interp, "context", NULL, context);
1233 if (Jim_Eval_Named(interp, startup_tcl, "embedded:startup.tcl", 1) == JIM_ERR) {
1234 LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD)");
1235 Jim_MakeErrorMessage(interp);
1236 LOG_USER_N("%s", Jim_GetString(Jim_GetResult(interp), NULL));
1237 exit(-1);
1238 }
1239 Jim_DeleteAssocData(interp, "context");
1240
1241 return context;
1242 }
1243
1244 void command_exit(struct command_context *context)
1245 {
1246 if (!context)
1247 return;
1248
1249 Jim_FreeInterp(context->interp);
1250 free(context->help_list);
1251 command_done(context);
1252 }
1253
1254 int command_context_mode(struct command_context *cmd_ctx, enum command_mode mode)
1255 {
1256 if (!cmd_ctx)
1257 return ERROR_COMMAND_SYNTAX_ERROR;
1258
1259 cmd_ctx->mode = mode;
1260 return ERROR_OK;
1261 }
1262
1263 void process_jim_events(struct command_context *cmd_ctx)
1264 {
1265 static int recursion;
1266 if (recursion)
1267 return;
1268
1269 recursion++;
1270 Jim_ProcessEvents(cmd_ctx->interp, JIM_ALL_EVENTS | JIM_DONT_WAIT);
1271 recursion--;
1272 }
1273
1274 #define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max) \
1275 int parse ## name(const char *str, type * ul) \
1276 { \
1277 if (!*str) { \
1278 LOG_ERROR("Invalid command argument"); \
1279 return ERROR_COMMAND_ARGUMENT_INVALID; \
1280 } \
1281 char *end; \
1282 errno = 0; \
1283 *ul = func(str, &end, 0); \
1284 if (*end) { \
1285 LOG_ERROR("Invalid command argument"); \
1286 return ERROR_COMMAND_ARGUMENT_INVALID; \
1287 } \
1288 if ((max == *ul) && (errno == ERANGE)) { \
1289 LOG_ERROR("Argument overflow"); \
1290 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
1291 } \
1292 if (min && (min == *ul) && (errno == ERANGE)) { \
1293 LOG_ERROR("Argument underflow"); \
1294 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
1295 } \
1296 return ERROR_OK; \
1297 }
1298 DEFINE_PARSE_NUM_TYPE(_ulong, unsigned long, strtoul, 0, ULONG_MAX)
1299 DEFINE_PARSE_NUM_TYPE(_ullong, unsigned long long, strtoull, 0, ULLONG_MAX)
1300 DEFINE_PARSE_NUM_TYPE(_long, long, strtol, LONG_MIN, LONG_MAX)
1301 DEFINE_PARSE_NUM_TYPE(_llong, long long, strtoll, LLONG_MIN, LLONG_MAX)
1302
1303 #define DEFINE_PARSE_WRAPPER(name, type, min, max, functype, funcname) \
1304 int parse ## name(const char *str, type * ul) \
1305 { \
1306 functype n; \
1307 int retval = parse ## funcname(str, &n); \
1308 if (retval != ERROR_OK) \
1309 return retval; \
1310 if (n > max) \
1311 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
1312 if (min) \
1313 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
1314 *ul = n; \
1315 return ERROR_OK; \
1316 }
1317
1318 #define DEFINE_PARSE_ULONGLONG(name, type, min, max) \
1319 DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long long, _ullong)
1320 DEFINE_PARSE_ULONGLONG(_uint, unsigned, 0, UINT_MAX)
1321 DEFINE_PARSE_ULONGLONG(_u64, uint64_t, 0, UINT64_MAX)
1322 DEFINE_PARSE_ULONGLONG(_u32, uint32_t, 0, UINT32_MAX)
1323 DEFINE_PARSE_ULONGLONG(_u16, uint16_t, 0, UINT16_MAX)
1324 DEFINE_PARSE_ULONGLONG(_u8, uint8_t, 0, UINT8_MAX)
1325
1326 DEFINE_PARSE_ULONGLONG(_target_addr, target_addr_t, 0, TARGET_ADDR_MAX)
1327
1328 #define DEFINE_PARSE_LONGLONG(name, type, min, max) \
1329 DEFINE_PARSE_WRAPPER(name, type, min, max, long long, _llong)
1330 DEFINE_PARSE_LONGLONG(_int, int, n < INT_MIN, INT_MAX)
1331 DEFINE_PARSE_LONGLONG(_s64, int64_t, n < INT64_MIN, INT64_MAX)
1332 DEFINE_PARSE_LONGLONG(_s32, int32_t, n < INT32_MIN, INT32_MAX)
1333 DEFINE_PARSE_LONGLONG(_s16, int16_t, n < INT16_MIN, INT16_MAX)
1334 DEFINE_PARSE_LONGLONG(_s8, int8_t, n < INT8_MIN, INT8_MAX)
1335
1336 static int command_parse_bool(const char *in, bool *out,
1337 const char *on, const char *off)
1338 {
1339 if (strcasecmp(in, on) == 0)
1340 *out = true;
1341 else if (strcasecmp(in, off) == 0)
1342 *out = false;
1343 else
1344 return ERROR_COMMAND_SYNTAX_ERROR;
1345 return ERROR_OK;
1346 }
1347
1348 int command_parse_bool_arg(const char *in, bool *out)
1349 {
1350 if (command_parse_bool(in, out, "on", "off") == ERROR_OK)
1351 return ERROR_OK;
1352 if (command_parse_bool(in, out, "enable", "disable") == ERROR_OK)
1353 return ERROR_OK;
1354 if (command_parse_bool(in, out, "true", "false") == ERROR_OK)
1355 return ERROR_OK;
1356 if (command_parse_bool(in, out, "yes", "no") == ERROR_OK)
1357 return ERROR_OK;
1358 if (command_parse_bool(in, out, "1", "0") == ERROR_OK)
1359 return ERROR_OK;
1360 return ERROR_COMMAND_SYNTAX_ERROR;
1361 }
1362
1363 COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label)
1364 {
1365 switch (CMD_ARGC) {
1366 case 1: {
1367 const char *in = CMD_ARGV[0];
1368 if (command_parse_bool_arg(in, out) != ERROR_OK) {
1369 LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME, in);
1370 return ERROR_COMMAND_SYNTAX_ERROR;
1371 }
1372 }
1373 /* fallthrough */
1374 case 0:
1375 LOG_INFO("%s is %s", label, *out ? "enabled" : "disabled");
1376 break;
1377 default:
1378 return ERROR_COMMAND_SYNTAX_ERROR;
1379 }
1380 return ERROR_OK;
1381 }

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)