refactor command_new to use command_registration
[openocd.git] / src / helper / command.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * Copyright (C) 2007,2008 Øyvind Harboe *
6 * oyvind.harboe@zylin.com *
7 * *
8 * Copyright (C) 2008, Duane Ellis *
9 * openocd@duaneeellis.com *
10 * *
11 * part of this file is taken from libcli (libcli.sourceforge.net) *
12 * Copyright (C) David Parrish (david@dparrish.com) *
13 * *
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. *
18 * *
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. *
23 * *
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 ***************************************************************************/
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #if !BUILD_ECOSBOARD
34 /* see Embedder-HOWTO.txt in Jim Tcl project hosted on BerliOS*/
35 #define JIM_EMBEDDED
36 #endif
37
38 // @todo the inclusion of target.h here is a layering violation
39 #include "target.h"
40 #include "command.h"
41 #include "configuration.h"
42 #include "log.h"
43 #include "time_support.h"
44 #include "jim-eventloop.h"
45
46
47 Jim_Interp *interp = NULL;
48
49 static int run_command(struct command_context *context,
50 struct command *c, const char *words[], unsigned num_words);
51
52 static void tcl_output(void *privData, const char *file, unsigned line,
53 const char *function, const char *string)
54 {
55 Jim_Obj *tclOutput = (Jim_Obj *)privData;
56 Jim_AppendString(interp, tclOutput, string, strlen(string));
57 }
58
59 extern struct command_context *global_cmd_ctx;
60
61 void script_debug(Jim_Interp *interp, const char *name,
62 unsigned argc, Jim_Obj *const *argv)
63 {
64 LOG_DEBUG("command - %s", name);
65 for (unsigned i = 0; i < argc; i++)
66 {
67 int len;
68 const char *w = Jim_GetString(argv[i], &len);
69
70 /* end of line comment? */
71 if (*w == '#')
72 break;
73
74 LOG_DEBUG("%s - argv[%d]=%s", name, i, w);
75 }
76 }
77
78 static void script_command_args_free(const char **words, unsigned nwords)
79 {
80 for (unsigned i = 0; i < nwords; i++)
81 free((void *)words[i]);
82 free(words);
83 }
84 static const char **script_command_args_alloc(
85 unsigned argc, Jim_Obj *const *argv, unsigned *nwords)
86 {
87 const char **words = malloc(argc * sizeof(char *));
88 if (NULL == words)
89 return NULL;
90
91 unsigned i;
92 for (i = 0; i < argc; i++)
93 {
94 int len;
95 const char *w = Jim_GetString(argv[i], &len);
96 /* a comment may end the line early */
97 if (*w == '#')
98 break;
99
100 words[i] = strdup(w);
101 if (words[i] == NULL)
102 {
103 script_command_args_free(words, i);
104 return NULL;
105 }
106 }
107 *nwords = i;
108 return words;
109 }
110
111 static struct command_context *current_command_context(void)
112 {
113 /* grab the command context from the associated data */
114 struct command_context *cmd_ctx = Jim_GetAssocData(interp, "context");
115 if (NULL == cmd_ctx)
116 {
117 /* Tcl can invoke commands directly instead of via command_run_line(). This would
118 * happen when the Jim Tcl interpreter is provided by eCos.
119 */
120 cmd_ctx = global_cmd_ctx;
121 }
122 return cmd_ctx;
123 }
124
125 static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
126 {
127 /* the private data is stashed in the interp structure */
128 struct command *c;
129 int retval;
130
131 /* DANGER!!!! be careful what we invoke here, since interp->cmdPrivData might
132 * get overwritten by running other Jim commands! Treat it as an
133 * emphemeral global variable that is used in lieu of an argument
134 * to the fn and fish it out manually.
135 */
136 c = interp->cmdPrivData;
137 if (c == NULL)
138 {
139 LOG_ERROR("BUG: interp->cmdPrivData == NULL");
140 return JIM_ERR;
141 }
142 target_call_timer_callbacks_now();
143 LOG_USER_N("%s", ""); /* Keep GDB connection alive*/
144
145 script_debug(interp, c->name, argc, argv);
146
147 unsigned nwords;
148 const char **words = script_command_args_alloc(argc, argv, &nwords);
149 if (NULL == words)
150 return JIM_ERR;
151
152 /* capture log output and return it */
153 Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
154 /* a garbage collect can happen, so we need a reference count to this object */
155 Jim_IncrRefCount(tclOutput);
156
157 log_add_callback(tcl_output, tclOutput);
158
159 struct command_context *cmd_ctx = current_command_context();
160 retval = run_command(cmd_ctx, c, (const char **)words, nwords);
161
162 log_remove_callback(tcl_output, tclOutput);
163
164 /* We dump output into this local variable */
165 Jim_SetResult(interp, tclOutput);
166 Jim_DecrRefCount(interp, tclOutput);
167
168 script_command_args_free(words, nwords);
169
170 int *return_retval = Jim_GetAssocData(interp, "retval");
171 if (return_retval != NULL)
172 {
173 *return_retval = retval;
174 }
175
176 return (retval == ERROR_OK)?JIM_OK:JIM_ERR;
177 }
178
179 /* nice short description of source file */
180 #define __THIS__FILE__ "command.c"
181
182 /**
183 * Find a command by name from a list of commands.
184 * @returns Returns the named command if it exists in the list.
185 * Returns NULL otherwise.
186 */
187 static struct command *command_find(struct command *head, const char *name)
188 {
189 for (struct command *cc = head; cc; cc = cc->next)
190 {
191 if (strcmp(cc->name, name) == 0)
192 return cc;
193 }
194 return NULL;
195 }
196 struct command *command_find_in_context(struct command_context *cmd_ctx,
197 const char *name)
198 {
199 return command_find(cmd_ctx->commands, name);
200 }
201 struct command *command_find_in_parent(struct command *parent,
202 const char *name)
203 {
204 return command_find(parent->children, name);
205 }
206
207 /**
208 * Add the command into the linked list, sorted by name.
209 * @param head Address to head of command list pointer, which may be
210 * updated if @c c gets inserted at the beginning of the list.
211 * @param c The command to add to the list pointed to by @c head.
212 */
213 static void command_add_child(struct command **head, struct command *c)
214 {
215 assert(head);
216 if (NULL == *head)
217 {
218 *head = c;
219 return;
220 }
221
222 while ((*head)->next && (strcmp(c->name, (*head)->name) > 0))
223 head = &(*head)->next;
224
225 if (strcmp(c->name, (*head)->name) > 0) {
226 c->next = (*head)->next;
227 (*head)->next = c;
228 } else {
229 c->next = *head;
230 *head = c;
231 }
232 }
233
234 static struct command **command_list_for_parent(
235 struct command_context *cmd_ctx, struct command *parent)
236 {
237 return parent ? &parent->children : &cmd_ctx->commands;
238 }
239
240 static struct command *command_new(struct command_context *cmd_ctx,
241 struct command *parent, const struct command_registration *cr)
242 {
243 assert(cr->name);
244
245 struct command *c = malloc(sizeof(struct command));
246 memset(c, 0, sizeof(struct command));
247
248 c->name = strdup(cr->name);
249 if (cr->help)
250 c->help = strdup(cr->help);
251 if (cr->usage)
252 c->usage = strdup(cr->usage);
253 c->parent = parent;
254 c->handler = cr->handler;
255 c->mode = cr->mode;
256
257 command_add_child(command_list_for_parent(cmd_ctx, parent), c);
258
259 return c;
260 }
261 static void command_free(struct command *c)
262 {
263 /// @todo if command has a handler, unregister its jim command!
264
265 while (NULL != c->children)
266 {
267 struct command *tmp = c->children;
268 c->children = tmp->next;
269 command_free(tmp);
270 }
271
272 if (c->name)
273 free(c->name);
274 if (c->help)
275 free((void*)c->help);
276 if (c->usage)
277 free((void*)c->usage);
278 free(c);
279 }
280
281 static int register_command_handler(struct command *c)
282 {
283 int retval = -ENOMEM;
284 const char *full_name = command_name(c, '_');
285 if (NULL == full_name)
286 return retval;
287
288 const char *ocd_name = alloc_printf("ocd_%s", full_name);
289 if (NULL == full_name)
290 goto free_full_name;
291
292 Jim_CreateCommand(interp, ocd_name, script_command, c, NULL);
293 free((void *)ocd_name);
294
295 /* we now need to add an overrideable proc */
296 const char *override_name = alloc_printf("proc %s {args} {"
297 "if {[catch {eval ocd_%s $args}] == 0} "
298 "{return \"\"} else {return -code error}}",
299 full_name, full_name);
300 if (NULL == full_name)
301 goto free_full_name;
302
303 Jim_Eval_Named(interp, override_name, __THIS__FILE__, __LINE__);
304 free((void *)override_name);
305
306 retval = ERROR_OK;
307
308 free_full_name:
309 free((void *)full_name);
310 return retval;
311 }
312
313 struct command* register_command(struct command_context *context,
314 struct command *parent, const struct command_registration *cr)
315 {
316 if (!context || !cr->name)
317 return NULL;
318
319 const char *name = cr->name;
320 struct command **head = command_list_for_parent(context, parent);
321 struct command *c = command_find(*head, name);
322 if (NULL != c)
323 {
324 LOG_ERROR("command '%s' is already registered in '%s' context",
325 name, parent ? parent->name : "<global>");
326 return c;
327 }
328
329 c = command_new(context, parent, cr);
330 /* if allocation failed or it is a placeholder (no handler), we're done */
331 if (NULL == c || NULL == c->handler)
332 return c;
333
334 int retval = register_command_handler(c);
335 if (ERROR_OK != retval)
336 {
337 unregister_command(context, parent, name);
338 c = NULL;
339 }
340 return c;
341 }
342
343 int register_commands(struct command_context *cmd_ctx, struct command *parent,
344 const struct command_registration *cmds)
345 {
346 int retval = ERROR_OK;
347 unsigned i;
348 for (i = 0; cmds[i].name || cmds[i].chain; i++)
349 {
350 const struct command_registration *cr = cmds + i;
351
352 struct command *c = NULL;
353 if (NULL != cr->name)
354 {
355 c = register_command(cmd_ctx, parent, cr);
356 if (NULL == c)
357 {
358 retval = ERROR_FAIL;
359 break;
360 }
361 }
362 if (NULL != cr->chain)
363 {
364 struct command *p = c ? : parent;
365 retval = register_commands(cmd_ctx, p, cr->chain);
366 if (ERROR_OK != retval)
367 break;
368 }
369 }
370 if (ERROR_OK != retval)
371 {
372 for (unsigned j = 0; j < i; j++)
373 unregister_command(cmd_ctx, parent, cmds[j].name);
374 }
375 return retval;
376 }
377
378 int unregister_all_commands(struct command_context *context,
379 struct command *parent)
380 {
381 if (context == NULL)
382 return ERROR_OK;
383
384 struct command **head = command_list_for_parent(context, parent);
385 while (NULL != *head)
386 {
387 struct command *tmp = *head;
388 *head = tmp->next;
389 command_free(tmp);
390 }
391
392 return ERROR_OK;
393 }
394
395 int unregister_command(struct command_context *context,
396 struct command *parent, const char *name)
397 {
398 if ((!context) || (!name))
399 return ERROR_INVALID_ARGUMENTS;
400
401 struct command *p = NULL;
402 struct command **head = command_list_for_parent(context, parent);
403 for (struct command *c = *head; NULL != c; p = c, c = c->next)
404 {
405 if (strcmp(name, c->name) != 0)
406 continue;
407
408 if (p)
409 p->next = c->next;
410 else
411 *head = c->next;
412
413 command_free(c);
414 return ERROR_OK;
415 }
416
417 return ERROR_OK;
418 }
419
420 void command_output_text(struct command_context *context, const char *data)
421 {
422 if (context && context->output_handler && data) {
423 context->output_handler(context, data);
424 }
425 }
426
427 void command_print_sameline(struct command_context *context, const char *format, ...)
428 {
429 char *string;
430
431 va_list ap;
432 va_start(ap, format);
433
434 string = alloc_vprintf(format, ap);
435 if (string != NULL)
436 {
437 /* we want this collected in the log + we also want to pick it up as a tcl return
438 * value.
439 *
440 * The latter bit isn't precisely neat, but will do for now.
441 */
442 LOG_USER_N("%s", string);
443 /* We already printed it above */
444 /* command_output_text(context, string); */
445 free(string);
446 }
447
448 va_end(ap);
449 }
450
451 void command_print(struct command_context *context, const char *format, ...)
452 {
453 char *string;
454
455 va_list ap;
456 va_start(ap, format);
457
458 string = alloc_vprintf(format, ap);
459 if (string != NULL)
460 {
461 strcat(string, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one char longer */
462 /* we want this collected in the log + we also want to pick it up as a tcl return
463 * value.
464 *
465 * The latter bit isn't precisely neat, but will do for now.
466 */
467 LOG_USER_N("%s", string);
468 /* We already printed it above */
469 /* command_output_text(context, string); */
470 free(string);
471 }
472
473 va_end(ap);
474 }
475
476 static char *__command_name(struct command *c, char delim, unsigned extra)
477 {
478 char *name;
479 unsigned len = strlen(c->name);
480 if (NULL == c->parent) {
481 // allocate enough for the name, child names, and '\0'
482 name = malloc(len + extra + 1);
483 strcpy(name, c->name);
484 } else {
485 // parent's extra must include both the space and name
486 name = __command_name(c->parent, delim, 1 + len + extra);
487 char dstr[2] = { delim, 0 };
488 strcat(name, dstr);
489 strcat(name, c->name);
490 }
491 return name;
492 }
493 char *command_name(struct command *c, char delim)
494 {
495 return __command_name(c, delim, 0);
496 }
497
498 static int run_command(struct command_context *context,
499 struct command *c, const char *words[], unsigned num_words)
500 {
501 if (!((context->mode == COMMAND_CONFIG) || (c->mode == COMMAND_ANY) || (c->mode == context->mode)))
502 {
503 /* Config commands can not run after the config stage */
504 LOG_ERROR("Command '%s' only runs during configuration stage", c->name);
505 return ERROR_FAIL;
506 }
507
508 struct command_invocation cmd = {
509 .ctx = context,
510 .name = c->name,
511 .argc = num_words - 1,
512 .argv = words + 1,
513 };
514 int retval = c->handler(&cmd);
515 if (retval == ERROR_COMMAND_SYNTAX_ERROR)
516 {
517 /* Print help for command */
518 char *full_name = command_name(c, ' ');
519 if (NULL != full_name) {
520 command_run_linef(context, "help %s", full_name);
521 free(full_name);
522 } else
523 retval = -ENOMEM;
524 }
525 else if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
526 {
527 /* just fall through for a shutdown request */
528 }
529 else if (retval != ERROR_OK)
530 {
531 /* we do not print out an error message because the command *should*
532 * have printed out an error
533 */
534 LOG_DEBUG("Command failed with error code %d", retval);
535 }
536
537 return retval;
538 }
539
540 int command_run_line(struct command_context *context, char *line)
541 {
542 /* all the parent commands have been registered with the interpreter
543 * so, can just evaluate the line as a script and check for
544 * results
545 */
546 /* run the line thru a script engine */
547 int retval = ERROR_FAIL;
548 int retcode;
549 /* Beware! This code needs to be reentrant. It is also possible
550 * for OpenOCD commands to be invoked directly from Tcl. This would
551 * happen when the Jim Tcl interpreter is provided by eCos for
552 * instance.
553 */
554 Jim_DeleteAssocData(interp, "context");
555 retcode = Jim_SetAssocData(interp, "context", NULL, context);
556 if (retcode == JIM_OK)
557 {
558 /* associated the return value */
559 Jim_DeleteAssocData(interp, "retval");
560 retcode = Jim_SetAssocData(interp, "retval", NULL, &retval);
561 if (retcode == JIM_OK)
562 {
563 retcode = Jim_Eval_Named(interp, line, __THIS__FILE__, __LINE__);
564
565 Jim_DeleteAssocData(interp, "retval");
566 }
567 Jim_DeleteAssocData(interp, "context");
568 }
569 if (retcode == JIM_ERR) {
570 if (retval != ERROR_COMMAND_CLOSE_CONNECTION)
571 {
572 /* We do not print the connection closed error message */
573 Jim_PrintErrorMessage(interp);
574 }
575 if (retval == ERROR_OK)
576 {
577 /* It wasn't a low level OpenOCD command that failed */
578 return ERROR_FAIL;
579 }
580 return retval;
581 } else if (retcode == JIM_EXIT) {
582 /* ignore. */
583 /* exit(Jim_GetExitCode(interp)); */
584 } else {
585 const char *result;
586 int reslen;
587
588 result = Jim_GetString(Jim_GetResult(interp), &reslen);
589 if (reslen > 0)
590 {
591 int i;
592 char buff[256 + 1];
593 for (i = 0; i < reslen; i += 256)
594 {
595 int chunk;
596 chunk = reslen - i;
597 if (chunk > 256)
598 chunk = 256;
599 strncpy(buff, result + i, chunk);
600 buff[chunk] = 0;
601 LOG_USER_N("%s", buff);
602 }
603 LOG_USER_N("%s", "\n");
604 }
605 retval = ERROR_OK;
606 }
607 return retval;
608 }
609
610 int command_run_linef(struct command_context *context, const char *format, ...)
611 {
612 int retval = ERROR_FAIL;
613 char *string;
614 va_list ap;
615 va_start(ap, format);
616 string = alloc_vprintf(format, ap);
617 if (string != NULL)
618 {
619 retval = command_run_line(context, string);
620 }
621 va_end(ap);
622 return retval;
623 }
624
625 void command_set_output_handler(struct command_context* context,
626 command_output_handler_t output_handler, void *priv)
627 {
628 context->output_handler = output_handler;
629 context->output_handler_priv = priv;
630 }
631
632 struct command_context* copy_command_context(struct command_context* context)
633 {
634 struct command_context* copy_context = malloc(sizeof(struct command_context));
635
636 *copy_context = *context;
637
638 return copy_context;
639 }
640
641 int command_done(struct command_context *context)
642 {
643 free(context);
644 context = NULL;
645
646 return ERROR_OK;
647 }
648
649 /* find full path to file */
650 static int jim_find(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
651 {
652 if (argc != 2)
653 return JIM_ERR;
654 const char *file = Jim_GetString(argv[1], NULL);
655 char *full_path = find_file(file);
656 if (full_path == NULL)
657 return JIM_ERR;
658 Jim_Obj *result = Jim_NewStringObj(interp, full_path, strlen(full_path));
659 free(full_path);
660
661 Jim_SetResult(interp, result);
662 return JIM_OK;
663 }
664
665 static int jim_echo(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
666 {
667 if (argc != 2)
668 return JIM_ERR;
669 const char *str = Jim_GetString(argv[1], NULL);
670 LOG_USER("%s", str);
671 return JIM_OK;
672 }
673
674 static size_t openocd_jim_fwrite(const void *_ptr, size_t size, size_t n, void *cookie)
675 {
676 size_t nbytes;
677 const char *ptr;
678 Jim_Interp *interp;
679
680 /* make it a char easier to read code */
681 ptr = _ptr;
682 interp = cookie;
683 nbytes = size * n;
684 if (ptr == NULL || interp == NULL || nbytes == 0) {
685 return 0;
686 }
687
688 /* do we have to chunk it? */
689 if (ptr[nbytes] == 0)
690 {
691 /* no it is a C style string */
692 LOG_USER_N("%s", ptr);
693 return strlen(ptr);
694 }
695 /* GRR we must chunk - not null terminated */
696 while (nbytes) {
697 char chunk[128 + 1];
698 int x;
699
700 x = nbytes;
701 if (x > 128) {
702 x = 128;
703 }
704 /* copy it */
705 memcpy(chunk, ptr, x);
706 /* terminate it */
707 chunk[n] = 0;
708 /* output it */
709 LOG_USER_N("%s", chunk);
710 ptr += x;
711 nbytes -= x;
712 }
713
714 return n;
715 }
716
717 static size_t openocd_jim_fread(void *ptr, size_t size, size_t n, void *cookie)
718 {
719 /* TCL wants to read... tell him no */
720 return 0;
721 }
722
723 static int openocd_jim_vfprintf(void *cookie, const char *fmt, va_list ap)
724 {
725 char *cp;
726 int n;
727 Jim_Interp *interp;
728
729 n = -1;
730 interp = cookie;
731 if (interp == NULL)
732 return n;
733
734 cp = alloc_vprintf(fmt, ap);
735 if (cp)
736 {
737 LOG_USER_N("%s", cp);
738 n = strlen(cp);
739 free(cp);
740 }
741 return n;
742 }
743
744 static int openocd_jim_fflush(void *cookie)
745 {
746 /* nothing to flush */
747 return 0;
748 }
749
750 static char* openocd_jim_fgets(char *s, int size, void *cookie)
751 {
752 /* not supported */
753 errno = ENOTSUP;
754 return NULL;
755 }
756
757 static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
758 {
759 if (argc != 2)
760 return JIM_ERR;
761 int retcode;
762 const char *str = Jim_GetString(argv[1], NULL);
763
764 /* capture log output and return it */
765 Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
766 /* a garbage collect can happen, so we need a reference count to this object */
767 Jim_IncrRefCount(tclOutput);
768
769 log_add_callback(tcl_output, tclOutput);
770
771 retcode = Jim_Eval_Named(interp, str, __THIS__FILE__, __LINE__);
772
773 log_remove_callback(tcl_output, tclOutput);
774
775 /* We dump output into this local variable */
776 Jim_SetResult(interp, tclOutput);
777 Jim_DecrRefCount(interp, tclOutput);
778
779 return retcode;
780 }
781
782 static COMMAND_HELPER(command_help_find, struct command *head,
783 struct command **out)
784 {
785 if (0 == CMD_ARGC)
786 return ERROR_INVALID_ARGUMENTS;
787 *out = command_find(head, CMD_ARGV[0]);
788 if (NULL == *out)
789 return ERROR_INVALID_ARGUMENTS;
790 if (--CMD_ARGC == 0)
791 return ERROR_OK;
792 CMD_ARGV++;
793 return CALL_COMMAND_HANDLER(command_help_find, (*out)->children, out);
794 }
795
796 static COMMAND_HELPER(command_help_show, struct command *c, unsigned n,
797 bool show_help);
798
799 static COMMAND_HELPER(command_help_show_list, struct command *head, unsigned n,
800 bool show_help)
801 {
802 for (struct command *c = head; NULL != c; c = c->next)
803 CALL_COMMAND_HANDLER(command_help_show, c, n, show_help);
804 return ERROR_OK;
805 }
806 static COMMAND_HELPER(command_help_show, struct command *c, unsigned n,
807 bool show_help)
808 {
809 const char *usage = c->usage ? : "";
810 const char *help = "";
811 const char *sep = "";
812 if (show_help && c->help)
813 {
814 help = c->help ? : "";
815 sep = c->usage ? " | " : "";
816 }
817 command_run_linef(CMD_CTX, "cmd_help {%s} {%s%s%s} %d",
818 command_name(c, ' '), usage, sep, help, n);
819
820 if (++n >= 2)
821 return ERROR_OK;
822
823 return CALL_COMMAND_HANDLER(command_help_show_list,
824 c->children, n, show_help);
825 }
826 COMMAND_HANDLER(handle_help_command)
827 {
828 struct command *c = CMD_CTX->commands;
829
830 if (0 == CMD_ARGC)
831 return CALL_COMMAND_HANDLER(command_help_show_list, c, 0, true);
832
833 int retval = CALL_COMMAND_HANDLER(command_help_find, c, &c);
834 if (ERROR_OK != retval)
835 return retval;
836
837 return CALL_COMMAND_HANDLER(command_help_show, c, 0, true);
838 }
839
840 COMMAND_HANDLER(handle_usage_command)
841 {
842 struct command *c = CMD_CTX->commands;
843
844 if (0 == CMD_ARGC)
845 return CALL_COMMAND_HANDLER(command_help_show_list, c, 0, false);
846
847 int retval = CALL_COMMAND_HANDLER(command_help_find, c, &c);
848 if (ERROR_OK != retval)
849 return retval;
850
851 return CALL_COMMAND_HANDLER(command_help_show, c, 0, false);
852 }
853
854 static int command_unknown_find(unsigned argc, Jim_Obj *const *argv,
855 struct command *head, struct command **out)
856 {
857 if (0 == argc)
858 return argc;
859 struct command *c = command_find(head, Jim_GetString(argv[0], NULL));
860 if (NULL == c)
861 return argc;
862 *out = c;
863 return command_unknown_find(--argc, ++argv, (*out)->children, out);
864 }
865
866 static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
867 {
868 const char *cmd_name = Jim_GetString(argv[0], NULL);
869 script_debug(interp, cmd_name, argc - 1, argv + 1);
870
871 struct command_context *cmd_ctx = current_command_context();
872 struct command *c = cmd_ctx->commands;
873 int remaining = command_unknown_find(argc - 1, argv + 1, c, &c);
874 // if nothing could be consumed, then it's really an unknown command
875 if (remaining == argc - 1)
876 {
877 const char *cmd = Jim_GetString(argv[1], NULL);
878 LOG_ERROR("Unknown command:\n %s", cmd);
879 return JIM_OK;
880 }
881
882 bool found = true;
883 Jim_Obj *const *start;
884 unsigned count;
885 if (c->handler)
886 {
887 // include the command name in the list
888 count = remaining + 1;
889 start = argv + (argc - remaining - 1);
890 }
891 else
892 {
893 c = command_find(cmd_ctx->commands, "help");
894 if (NULL == c)
895 {
896 LOG_ERROR("unknown command, but help is missing too");
897 return JIM_ERR;
898 }
899 count = argc - remaining;
900 start = argv;
901 found = false;
902 }
903
904 unsigned nwords;
905 const char **words = script_command_args_alloc(count, start, &nwords);
906 if (NULL == words)
907 return JIM_ERR;
908
909 int retval = run_command(cmd_ctx, c, words, nwords);
910
911 script_command_args_free(words, nwords);
912
913 if (!found && ERROR_OK == retval)
914 retval = ERROR_FAIL;
915
916 return retval;
917 }
918
919 int help_add_command(struct command_context *cmd_ctx, struct command *parent,
920 const char *cmd_name, const char *help_text, const char *usage)
921 {
922 struct command **head = command_list_for_parent(cmd_ctx, parent);
923 struct command *nc = command_find(*head, cmd_name);
924 if (NULL == nc)
925 {
926 // add a new command with help text
927 struct command_registration cr = {
928 .name = cmd_name,
929 .mode = COMMAND_ANY,
930 .help = help_text,
931 .usage = usage,
932 };
933 nc = register_command(cmd_ctx, parent, &cr);
934 if (NULL == nc)
935 {
936 LOG_ERROR("failed to add '%s' help text", cmd_name);
937 return ERROR_FAIL;
938 }
939 LOG_DEBUG("added '%s' help text", cmd_name);
940 }
941 else
942 {
943 bool replaced = false;
944 if (nc->help)
945 {
946 free((void *)nc->help);
947 replaced = true;
948 }
949 nc->help = strdup(help_text);
950
951 if (replaced)
952 LOG_INFO("replaced existing '%s' help", cmd_name);
953 else
954 LOG_DEBUG("added '%s' help text", cmd_name);
955 }
956 return ERROR_OK;
957 }
958
959 COMMAND_HANDLER(handle_help_add_command)
960 {
961 if (CMD_ARGC < 2)
962 {
963 LOG_ERROR("%s: insufficient arguments", CMD_NAME);
964 return ERROR_INVALID_ARGUMENTS;
965 }
966
967 // save help text and remove it from argument list
968 const char *help_text = CMD_ARGV[--CMD_ARGC];
969 // likewise for the leaf command name
970 const char *cmd_name = CMD_ARGV[--CMD_ARGC];
971
972 struct command *c = NULL;
973 if (CMD_ARGC > 0)
974 {
975 c = CMD_CTX->commands;
976 int retval = CALL_COMMAND_HANDLER(command_help_find, c, &c);
977 if (ERROR_OK != retval)
978 return retval;
979 }
980 return help_add_command(CMD_CTX, c, cmd_name, help_text, NULL);
981 }
982
983 /* sleep command sleeps for <n> miliseconds
984 * this is useful in target startup scripts
985 */
986 COMMAND_HANDLER(handle_sleep_command)
987 {
988 bool busy = false;
989 if (CMD_ARGC == 2)
990 {
991 if (strcmp(CMD_ARGV[1], "busy") == 0)
992 busy = true;
993 else
994 return ERROR_COMMAND_SYNTAX_ERROR;
995 }
996 else if (CMD_ARGC < 1 || CMD_ARGC > 2)
997 return ERROR_COMMAND_SYNTAX_ERROR;
998
999 unsigned long duration = 0;
1000 int retval = parse_ulong(CMD_ARGV[0], &duration);
1001 if (ERROR_OK != retval)
1002 return retval;
1003
1004 if (!busy)
1005 {
1006 long long then = timeval_ms();
1007 while (timeval_ms() - then < (long long)duration)
1008 {
1009 target_call_timer_callbacks_now();
1010 usleep(1000);
1011 }
1012 }
1013 else
1014 busy_sleep(duration);
1015
1016 return ERROR_OK;
1017 }
1018
1019 static const struct command_registration command_builtin_handlers[] = {
1020 {
1021 .name = "add_help_text",
1022 .handler = &handle_help_add_command,
1023 .mode = COMMAND_ANY,
1024 .help = "add new command help text",
1025 .usage = "<command> [...] <help_text>]",
1026 },
1027 {
1028 .name = "sleep",
1029 .handler = &handle_sleep_command,
1030 .mode = COMMAND_ANY,
1031 .help = "sleep for n milliseconds. "
1032 "\"busy\" will busy wait",
1033 .usage = "<n> [busy]",
1034 },
1035 {
1036 .name = "help",
1037 .handler = &handle_help_command,
1038 .mode = COMMAND_ANY,
1039 .help = "show built-in command help",
1040 .usage = "[<command_name> ...]",
1041 },
1042 {
1043 .name = "usage",
1044 .handler = &handle_usage_command,
1045 .mode = COMMAND_ANY,
1046 .help = "show command usage",
1047 .usage = "[<command_name> ...]",
1048 },
1049 COMMAND_REGISTRATION_DONE
1050 };
1051
1052 struct command_context* command_init(const char *startup_tcl)
1053 {
1054 struct command_context* context = malloc(sizeof(struct command_context));
1055 const char *HostOs;
1056
1057 context->mode = COMMAND_EXEC;
1058 context->commands = NULL;
1059 context->current_target = 0;
1060 context->output_handler = NULL;
1061 context->output_handler_priv = NULL;
1062
1063 #if !BUILD_ECOSBOARD
1064 Jim_InitEmbedded();
1065 /* Create an interpreter */
1066 interp = Jim_CreateInterp();
1067 /* Add all the Jim core commands */
1068 Jim_RegisterCoreCommands(interp);
1069 #endif
1070
1071 #if defined(_MSC_VER)
1072 /* WinXX - is generic, the forward
1073 * looking problem is this:
1074 *
1075 * "win32" or "win64"
1076 *
1077 * "winxx" is generic.
1078 */
1079 HostOs = "winxx";
1080 #elif defined(__linux__)
1081 HostOs = "linux";
1082 #elif defined(__DARWIN__)
1083 HostOs = "darwin";
1084 #elif defined(__CYGWIN__)
1085 HostOs = "cygwin";
1086 #elif defined(__MINGW32__)
1087 HostOs = "mingw32";
1088 #elif defined(__ECOS)
1089 HostOs = "ecos";
1090 #else
1091 #warn unrecognized host OS...
1092 HostOs = "other";
1093 #endif
1094 Jim_SetGlobalVariableStr(interp, "ocd_HOSTOS",
1095 Jim_NewStringObj(interp, HostOs , strlen(HostOs)));
1096
1097 Jim_CreateCommand(interp, "unknown", &command_unknown, NULL, NULL);
1098 Jim_CreateCommand(interp, "ocd_find", jim_find, NULL, NULL);
1099 Jim_CreateCommand(interp, "echo", jim_echo, NULL, NULL);
1100 Jim_CreateCommand(interp, "capture", jim_capture, NULL, NULL);
1101
1102 /* Set Jim's STDIO */
1103 interp->cookie_stdin = interp;
1104 interp->cookie_stdout = interp;
1105 interp->cookie_stderr = interp;
1106 interp->cb_fwrite = openocd_jim_fwrite;
1107 interp->cb_fread = openocd_jim_fread ;
1108 interp->cb_vfprintf = openocd_jim_vfprintf;
1109 interp->cb_fflush = openocd_jim_fflush;
1110 interp->cb_fgets = openocd_jim_fgets;
1111
1112 register_commands(context, NULL, command_builtin_handlers);
1113
1114 #if !BUILD_ECOSBOARD
1115 Jim_EventLoopOnLoad(interp);
1116 #endif
1117 Jim_SetAssocData(interp, "context", NULL, context);
1118 if (Jim_Eval_Named(interp, startup_tcl, "embedded:startup.tcl",1) == JIM_ERR)
1119 {
1120 LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD)");
1121 Jim_PrintErrorMessage(interp);
1122 exit(-1);
1123 }
1124 Jim_DeleteAssocData(interp, "context");
1125
1126 return context;
1127 }
1128
1129 int command_context_mode(struct command_context *cmd_ctx, enum command_mode mode)
1130 {
1131 if (!cmd_ctx)
1132 return ERROR_INVALID_ARGUMENTS;
1133
1134 cmd_ctx->mode = mode;
1135 return ERROR_OK;
1136 }
1137
1138 void process_jim_events(void)
1139 {
1140 #if !BUILD_ECOSBOARD
1141 static int recursion = 0;
1142
1143 if (!recursion)
1144 {
1145 recursion++;
1146 Jim_ProcessEvents (interp, JIM_ALL_EVENTS | JIM_DONT_WAIT);
1147 recursion--;
1148 }
1149 #endif
1150 }
1151
1152 void register_jim(struct command_context *cmd_ctx, const char *name,
1153 Jim_CmdProc cmd, const char *help)
1154 {
1155 Jim_CreateCommand(interp, name, cmd, NULL, NULL);
1156
1157 Jim_Obj *cmd_list = Jim_NewListObj(interp, NULL, 0);
1158 Jim_ListAppendElement(interp, cmd_list,
1159 Jim_NewStringObj(interp, name, -1));
1160
1161 help_add_command(cmd_ctx, NULL, name, help, NULL);
1162 }
1163
1164 #define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max) \
1165 int parse##name(const char *str, type *ul) \
1166 { \
1167 if (!*str) \
1168 { \
1169 LOG_ERROR("Invalid command argument"); \
1170 return ERROR_COMMAND_ARGUMENT_INVALID; \
1171 } \
1172 char *end; \
1173 *ul = func(str, &end, 0); \
1174 if (*end) \
1175 { \
1176 LOG_ERROR("Invalid command argument"); \
1177 return ERROR_COMMAND_ARGUMENT_INVALID; \
1178 } \
1179 if ((max == *ul) && (ERANGE == errno)) \
1180 { \
1181 LOG_ERROR("Argument overflow"); \
1182 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
1183 } \
1184 if (min && (min == *ul) && (ERANGE == errno)) \
1185 { \
1186 LOG_ERROR("Argument underflow"); \
1187 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
1188 } \
1189 return ERROR_OK; \
1190 }
1191 DEFINE_PARSE_NUM_TYPE(_ulong, unsigned long , strtoul, 0, ULONG_MAX)
1192 DEFINE_PARSE_NUM_TYPE(_ullong, unsigned long long, strtoull, 0, ULLONG_MAX)
1193 DEFINE_PARSE_NUM_TYPE(_long, long , strtol, LONG_MIN, LONG_MAX)
1194 DEFINE_PARSE_NUM_TYPE(_llong, long long, strtoll, LLONG_MIN, LLONG_MAX)
1195
1196 #define DEFINE_PARSE_WRAPPER(name, type, min, max, functype, funcname) \
1197 int parse##name(const char *str, type *ul) \
1198 { \
1199 functype n; \
1200 int retval = parse##funcname(str, &n); \
1201 if (ERROR_OK != retval) \
1202 return retval; \
1203 if (n > max) \
1204 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
1205 if (min) \
1206 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
1207 *ul = n; \
1208 return ERROR_OK; \
1209 }
1210
1211 #define DEFINE_PARSE_ULONG(name, type, min, max) \
1212 DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long, _ulong)
1213 DEFINE_PARSE_ULONG(_uint, unsigned, 0, UINT_MAX)
1214 DEFINE_PARSE_ULONG(_u32, uint32_t, 0, UINT32_MAX)
1215 DEFINE_PARSE_ULONG(_u16, uint16_t, 0, UINT16_MAX)
1216 DEFINE_PARSE_ULONG(_u8, uint8_t, 0, UINT8_MAX)
1217
1218 #define DEFINE_PARSE_LONG(name, type, min, max) \
1219 DEFINE_PARSE_WRAPPER(name, type, min, max, long, _long)
1220 DEFINE_PARSE_LONG(_int, int, n < INT_MIN, INT_MAX)
1221 DEFINE_PARSE_LONG(_s32, int32_t, n < INT32_MIN, INT32_MAX)
1222 DEFINE_PARSE_LONG(_s16, int16_t, n < INT16_MIN, INT16_MAX)
1223 DEFINE_PARSE_LONG(_s8, int8_t, n < INT8_MIN, INT8_MAX)
1224
1225 static int command_parse_bool(const char *in, bool *out,
1226 const char *on, const char *off)
1227 {
1228 if (strcasecmp(in, on) == 0)
1229 *out = true;
1230 else if (strcasecmp(in, off) == 0)
1231 *out = false;
1232 else
1233 return ERROR_COMMAND_SYNTAX_ERROR;
1234 return ERROR_OK;
1235 }
1236
1237 int command_parse_bool_arg(const char *in, bool *out)
1238 {
1239 if (command_parse_bool(in, out, "on", "off") == ERROR_OK)
1240 return ERROR_OK;
1241 if (command_parse_bool(in, out, "enable", "disable") == ERROR_OK)
1242 return ERROR_OK;
1243 if (command_parse_bool(in, out, "true", "false") == ERROR_OK)
1244 return ERROR_OK;
1245 if (command_parse_bool(in, out, "yes", "no") == ERROR_OK)
1246 return ERROR_OK;
1247 if (command_parse_bool(in, out, "1", "0") == ERROR_OK)
1248 return ERROR_OK;
1249 return ERROR_INVALID_ARGUMENTS;
1250 }
1251
1252 COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label)
1253 {
1254 switch (CMD_ARGC) {
1255 case 1: {
1256 const char *in = CMD_ARGV[0];
1257 if (command_parse_bool_arg(in, out) != ERROR_OK)
1258 {
1259 LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME, in);
1260 return ERROR_INVALID_ARGUMENTS;
1261 }
1262 // fall through
1263 }
1264 case 0:
1265 LOG_INFO("%s is %s", label, *out ? "enabled" : "disabled");
1266 break;
1267 default:
1268 return ERROR_INVALID_ARGUMENTS;
1269 }
1270 return ERROR_OK;
1271 }

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)