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

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)