add error checking in command_new
[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 char *cmd_name = command_name(c, ' ');
876 if (NULL == cmd_name)
877 return -ENOMEM;
878
879 command_help_show_indent(n);
880 LOG_USER_N("%s", cmd_name);
881 free(cmd_name);
882
883 if (c->usage) {
884 LOG_USER_N(" ");
885 command_help_show_wrap(c->usage, 0, n + 5);
886 }
887 else
888 LOG_USER_N("\n");
889
890 if (show_help)
891 {
892 const char *stage_msg;
893 switch (c->mode) {
894 case COMMAND_CONFIG: stage_msg = "CONFIG"; break;
895 case COMMAND_EXEC: stage_msg = "EXEC"; break;
896 case COMMAND_ANY: stage_msg = "CONFIG or EXEC"; break;
897 default: stage_msg = "***UNKNOWN***"; break;
898 }
899 char *msg = alloc_printf("%s%sValid Modes: %s",
900 c->help ? : "", c->help ? " " : "", stage_msg);
901 if (NULL != msg)
902 {
903 command_help_show_wrap(msg, n + 3, n + 3);
904 free(msg);
905 } else
906 return -ENOMEM;
907 }
908
909 if (++n >= 2)
910 return ERROR_OK;
911
912 return CALL_COMMAND_HANDLER(command_help_show_list,
913 c->children, n, show_help);
914 }
915 COMMAND_HANDLER(handle_help_command)
916 {
917 bool full = strcmp(CMD_NAME, "help") == 0;
918
919 struct command *c = CMD_CTX->commands;
920
921 if (0 == CMD_ARGC)
922 return CALL_COMMAND_HANDLER(command_help_show_list, c, 0, full);
923
924 int retval = CALL_COMMAND_HANDLER(command_help_find, c, &c);
925 if (ERROR_OK != retval)
926 return retval;
927
928 return CALL_COMMAND_HANDLER(command_help_show, c, 0, full);
929 }
930
931 static int command_unknown_find(unsigned argc, Jim_Obj *const *argv,
932 struct command *head, struct command **out, bool top_level)
933 {
934 if (0 == argc)
935 return argc;
936 const char *cmd_name = Jim_GetString(argv[0], NULL);
937 struct command *c = command_find(head, cmd_name);
938 if (NULL == c && top_level && strncmp(cmd_name, "ocd_", 4) == 0)
939 c = command_find(head, cmd_name + 4);
940 if (NULL == c)
941 return argc;
942 *out = c;
943 return command_unknown_find(--argc, ++argv, (*out)->children, out, false);
944 }
945
946 static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
947 {
948 const char *cmd_name = Jim_GetString(argv[0], NULL);
949 if (strcmp(cmd_name, "unknown") == 0)
950 {
951 if (argc == 1)
952 return JIM_OK;
953 argc--;
954 argv++;
955 }
956 script_debug(interp, cmd_name, argc, argv);
957
958 struct command_context *cmd_ctx = current_command_context();
959 struct command *c = cmd_ctx->commands;
960 int remaining = command_unknown_find(argc, argv, c, &c, true);
961 // if nothing could be consumed, then it's really an unknown command
962 if (remaining == argc)
963 {
964 const char *cmd = Jim_GetString(argv[0], NULL);
965 LOG_ERROR("Unknown command:\n %s", cmd);
966 return JIM_OK;
967 }
968
969 bool found = true;
970 Jim_Obj *const *start;
971 unsigned count;
972 if (c->handler || c->jim_handler)
973 {
974 // include the command name in the list
975 count = remaining + 1;
976 start = argv + (argc - remaining - 1);
977 }
978 else
979 {
980 c = command_find(cmd_ctx->commands, "help");
981 if (NULL == c)
982 {
983 LOG_ERROR("unknown command, but help is missing too");
984 return JIM_ERR;
985 }
986 count = argc - remaining;
987 start = argv;
988 found = false;
989 }
990 // pass the command through to the intended handler
991 if (c->jim_handler)
992 {
993 interp->cmdPrivData = c->jim_handler_data;
994 return (*c->jim_handler)(interp, count, start);
995 }
996
997 return script_command_run(interp, count, start, c, found);
998 }
999
1000 static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
1001 {
1002 struct command_context *cmd_ctx = current_command_context();
1003 enum command_mode mode;
1004 if (argc > 1)
1005 {
1006 struct command *c = cmd_ctx->commands;
1007 int remaining = command_unknown_find(argc - 1, argv + 1, c, &c, true);
1008 // if nothing could be consumed, then it's an unknown command
1009 if (remaining == argc - 1)
1010 {
1011 Jim_SetResultString(interp, "unknown", -1);
1012 return JIM_OK;
1013 }
1014 mode = c->mode;
1015 }
1016 else
1017 mode = cmd_ctx->mode;
1018
1019 const char *mode_str;
1020 switch (mode) {
1021 case COMMAND_ANY: mode_str = "any"; break;
1022 case COMMAND_CONFIG: mode_str = "config"; break;
1023 case COMMAND_EXEC: mode_str = "exec"; break;
1024 default: mode_str = "unknown"; break;
1025 }
1026 Jim_SetResultString(interp, mode_str, -1);
1027 return JIM_OK;
1028 }
1029
1030 static int jim_command_type(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
1031 {
1032 if (1 == argc)
1033 return JIM_ERR;
1034
1035 struct command_context *cmd_ctx = current_command_context();
1036 struct command *c = cmd_ctx->commands;
1037 int remaining = command_unknown_find(argc - 1, argv + 1, c, &c, true);
1038 // if nothing could be consumed, then it's an unknown command
1039 if (remaining == argc - 1)
1040 {
1041 Jim_SetResultString(interp, "unknown", -1);
1042 return JIM_OK;
1043 }
1044
1045 if (c->jim_handler)
1046 Jim_SetResultString(interp, "native", -1);
1047 else if (c->handler)
1048 Jim_SetResultString(interp, "simple", -1);
1049 else
1050 Jim_SetResultString(interp, "group", -1);
1051
1052 return JIM_OK;
1053 }
1054
1055 int help_add_command(struct command_context *cmd_ctx, struct command *parent,
1056 const char *cmd_name, const char *help_text, const char *usage)
1057 {
1058 struct command **head = command_list_for_parent(cmd_ctx, parent);
1059 struct command *nc = command_find(*head, cmd_name);
1060 if (NULL == nc)
1061 {
1062 // add a new command with help text
1063 struct command_registration cr = {
1064 .name = cmd_name,
1065 .mode = COMMAND_ANY,
1066 .help = help_text,
1067 .usage = usage,
1068 };
1069 nc = register_command(cmd_ctx, parent, &cr);
1070 if (NULL == nc)
1071 {
1072 LOG_ERROR("failed to add '%s' help text", cmd_name);
1073 return ERROR_FAIL;
1074 }
1075 LOG_DEBUG("added '%s' help text", cmd_name);
1076 return ERROR_OK;
1077 }
1078 if (help_text)
1079 {
1080 bool replaced = false;
1081 if (nc->help)
1082 {
1083 free((void *)nc->help);
1084 replaced = true;
1085 }
1086 nc->help = strdup(help_text);
1087 if (replaced)
1088 LOG_INFO("replaced existing '%s' help", cmd_name);
1089 else
1090 LOG_DEBUG("added '%s' help text", cmd_name);
1091 }
1092 if (usage)
1093 {
1094 bool replaced = false;
1095 if (nc->usage)
1096 {
1097 free((void *)nc->usage);
1098 replaced = true;
1099 }
1100 nc->usage = strdup(usage);
1101 if (replaced)
1102 LOG_INFO("replaced existing '%s' usage", cmd_name);
1103 else
1104 LOG_DEBUG("added '%s' usage text", cmd_name);
1105 }
1106 return ERROR_OK;
1107 }
1108
1109 COMMAND_HANDLER(handle_help_add_command)
1110 {
1111 if (CMD_ARGC < 2)
1112 {
1113 LOG_ERROR("%s: insufficient arguments", CMD_NAME);
1114 return ERROR_INVALID_ARGUMENTS;
1115 }
1116
1117 // save help text and remove it from argument list
1118 const char *str = CMD_ARGV[--CMD_ARGC];
1119 const char *help = !strcmp(CMD_NAME, "add_help_text") ? str : NULL;
1120 const char *usage = !strcmp(CMD_NAME, "add_usage_text") ? str : NULL;
1121 if (!help && !usage)
1122 {
1123 LOG_ERROR("command name '%s' is unknown", CMD_NAME);
1124 return ERROR_INVALID_ARGUMENTS;
1125 }
1126 // likewise for the leaf command name
1127 const char *cmd_name = CMD_ARGV[--CMD_ARGC];
1128
1129 struct command *c = NULL;
1130 if (CMD_ARGC > 0)
1131 {
1132 c = CMD_CTX->commands;
1133 int retval = CALL_COMMAND_HANDLER(command_help_find, c, &c);
1134 if (ERROR_OK != retval)
1135 return retval;
1136 }
1137 return help_add_command(CMD_CTX, c, cmd_name, help, usage);
1138 }
1139
1140 /* sleep command sleeps for <n> miliseconds
1141 * this is useful in target startup scripts
1142 */
1143 COMMAND_HANDLER(handle_sleep_command)
1144 {
1145 bool busy = false;
1146 if (CMD_ARGC == 2)
1147 {
1148 if (strcmp(CMD_ARGV[1], "busy") == 0)
1149 busy = true;
1150 else
1151 return ERROR_COMMAND_SYNTAX_ERROR;
1152 }
1153 else if (CMD_ARGC < 1 || CMD_ARGC > 2)
1154 return ERROR_COMMAND_SYNTAX_ERROR;
1155
1156 unsigned long duration = 0;
1157 int retval = parse_ulong(CMD_ARGV[0], &duration);
1158 if (ERROR_OK != retval)
1159 return retval;
1160
1161 if (!busy)
1162 {
1163 long long then = timeval_ms();
1164 while (timeval_ms() - then < (long long)duration)
1165 {
1166 target_call_timer_callbacks_now();
1167 usleep(1000);
1168 }
1169 }
1170 else
1171 busy_sleep(duration);
1172
1173 return ERROR_OK;
1174 }
1175
1176 static const struct command_registration command_subcommand_handlers[] = {
1177 {
1178 .name = "mode",
1179 .mode = COMMAND_ANY,
1180 .jim_handler = &jim_command_mode,
1181 .usage = "[<name> ...]",
1182 .help = "Returns the command modes allowed by a command:"
1183 "'any', 'config', or 'exec'. If no command is"
1184 "specified, returns the current command mode.",
1185 },
1186 {
1187 .name = "type",
1188 .mode = COMMAND_ANY,
1189 .jim_handler = &jim_command_type,
1190 .usage = "<name> ...",
1191 .help = "Returns the type of built-in command:"
1192 "'native', 'simple', 'group', or 'unknown'",
1193 },
1194 COMMAND_REGISTRATION_DONE
1195 };
1196
1197 static const struct command_registration command_builtin_handlers[] = {
1198 {
1199 .name = "add_help_text",
1200 .handler = &handle_help_add_command,
1201 .mode = COMMAND_ANY,
1202 .help = "add new command help text",
1203 .usage = "<command> [...] <help_text>]",
1204 },
1205 {
1206 .name = "add_usage_text",
1207 .handler = &handle_help_add_command,
1208 .mode = COMMAND_ANY,
1209 .help = "add new command usage text",
1210 .usage = "<command> [...] <usage_text>]",
1211 },
1212 {
1213 .name = "sleep",
1214 .handler = &handle_sleep_command,
1215 .mode = COMMAND_ANY,
1216 .help = "sleep for n milliseconds. "
1217 "\"busy\" will busy wait",
1218 .usage = "<n> [busy]",
1219 },
1220 {
1221 .name = "help",
1222 .handler = &handle_help_command,
1223 .mode = COMMAND_ANY,
1224 .help = "show full command help",
1225 .usage = "[<command> ...]",
1226 },
1227 {
1228 .name = "usage",
1229 .handler = &handle_help_command,
1230 .mode = COMMAND_ANY,
1231 .help = "show basic command usage",
1232 .usage = "[<command> ...]",
1233 },
1234 {
1235 .name = "command",
1236 .mode= COMMAND_ANY,
1237 .help = "core command group (introspection)",
1238 .chain = command_subcommand_handlers,
1239 },
1240 COMMAND_REGISTRATION_DONE
1241 };
1242
1243 struct command_context* command_init(const char *startup_tcl)
1244 {
1245 struct command_context* context = malloc(sizeof(struct command_context));
1246 const char *HostOs;
1247
1248 context->mode = COMMAND_EXEC;
1249 context->commands = NULL;
1250 context->current_target = 0;
1251 context->output_handler = NULL;
1252 context->output_handler_priv = NULL;
1253
1254 #if !BUILD_ECOSBOARD
1255 Jim_InitEmbedded();
1256 /* Create an interpreter */
1257 interp = Jim_CreateInterp();
1258 /* Add all the Jim core commands */
1259 Jim_RegisterCoreCommands(interp);
1260 #endif
1261
1262 #if defined(_MSC_VER)
1263 /* WinXX - is generic, the forward
1264 * looking problem is this:
1265 *
1266 * "win32" or "win64"
1267 *
1268 * "winxx" is generic.
1269 */
1270 HostOs = "winxx";
1271 #elif defined(__linux__)
1272 HostOs = "linux";
1273 #elif defined(__DARWIN__)
1274 HostOs = "darwin";
1275 #elif defined(__CYGWIN__)
1276 HostOs = "cygwin";
1277 #elif defined(__MINGW32__)
1278 HostOs = "mingw32";
1279 #elif defined(__ECOS)
1280 HostOs = "ecos";
1281 #else
1282 #warn unrecognized host OS...
1283 HostOs = "other";
1284 #endif
1285 Jim_SetGlobalVariableStr(interp, "ocd_HOSTOS",
1286 Jim_NewStringObj(interp, HostOs , strlen(HostOs)));
1287
1288 Jim_CreateCommand(interp, "ocd_find", jim_find, NULL, NULL);
1289 Jim_CreateCommand(interp, "echo", jim_echo, NULL, NULL);
1290 Jim_CreateCommand(interp, "capture", jim_capture, NULL, NULL);
1291
1292 /* Set Jim's STDIO */
1293 interp->cookie_stdin = interp;
1294 interp->cookie_stdout = interp;
1295 interp->cookie_stderr = interp;
1296 interp->cb_fwrite = openocd_jim_fwrite;
1297 interp->cb_fread = openocd_jim_fread ;
1298 interp->cb_vfprintf = openocd_jim_vfprintf;
1299 interp->cb_fflush = openocd_jim_fflush;
1300 interp->cb_fgets = openocd_jim_fgets;
1301
1302 register_commands(context, NULL, command_builtin_handlers);
1303
1304 #if !BUILD_ECOSBOARD
1305 Jim_EventLoopOnLoad(interp);
1306 #endif
1307 Jim_SetAssocData(interp, "context", NULL, context);
1308 if (Jim_Eval_Named(interp, startup_tcl, "embedded:startup.tcl",1) == JIM_ERR)
1309 {
1310 LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD)");
1311 Jim_PrintErrorMessage(interp);
1312 exit(-1);
1313 }
1314 Jim_DeleteAssocData(interp, "context");
1315
1316 return context;
1317 }
1318
1319 int command_context_mode(struct command_context *cmd_ctx, enum command_mode mode)
1320 {
1321 if (!cmd_ctx)
1322 return ERROR_INVALID_ARGUMENTS;
1323
1324 cmd_ctx->mode = mode;
1325 return ERROR_OK;
1326 }
1327
1328 void process_jim_events(void)
1329 {
1330 #if !BUILD_ECOSBOARD
1331 static int recursion = 0;
1332
1333 if (!recursion)
1334 {
1335 recursion++;
1336 Jim_ProcessEvents (interp, JIM_ALL_EVENTS | JIM_DONT_WAIT);
1337 recursion--;
1338 }
1339 #endif
1340 }
1341
1342 #define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max) \
1343 int parse##name(const char *str, type *ul) \
1344 { \
1345 if (!*str) \
1346 { \
1347 LOG_ERROR("Invalid command argument"); \
1348 return ERROR_COMMAND_ARGUMENT_INVALID; \
1349 } \
1350 char *end; \
1351 *ul = func(str, &end, 0); \
1352 if (*end) \
1353 { \
1354 LOG_ERROR("Invalid command argument"); \
1355 return ERROR_COMMAND_ARGUMENT_INVALID; \
1356 } \
1357 if ((max == *ul) && (ERANGE == errno)) \
1358 { \
1359 LOG_ERROR("Argument overflow"); \
1360 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
1361 } \
1362 if (min && (min == *ul) && (ERANGE == errno)) \
1363 { \
1364 LOG_ERROR("Argument underflow"); \
1365 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
1366 } \
1367 return ERROR_OK; \
1368 }
1369 DEFINE_PARSE_NUM_TYPE(_ulong, unsigned long , strtoul, 0, ULONG_MAX)
1370 DEFINE_PARSE_NUM_TYPE(_ullong, unsigned long long, strtoull, 0, ULLONG_MAX)
1371 DEFINE_PARSE_NUM_TYPE(_long, long , strtol, LONG_MIN, LONG_MAX)
1372 DEFINE_PARSE_NUM_TYPE(_llong, long long, strtoll, LLONG_MIN, LLONG_MAX)
1373
1374 #define DEFINE_PARSE_WRAPPER(name, type, min, max, functype, funcname) \
1375 int parse##name(const char *str, type *ul) \
1376 { \
1377 functype n; \
1378 int retval = parse##funcname(str, &n); \
1379 if (ERROR_OK != retval) \
1380 return retval; \
1381 if (n > max) \
1382 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
1383 if (min) \
1384 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
1385 *ul = n; \
1386 return ERROR_OK; \
1387 }
1388
1389 #define DEFINE_PARSE_ULONG(name, type, min, max) \
1390 DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long, _ulong)
1391 DEFINE_PARSE_ULONG(_uint, unsigned, 0, UINT_MAX)
1392 DEFINE_PARSE_ULONG(_u32, uint32_t, 0, UINT32_MAX)
1393 DEFINE_PARSE_ULONG(_u16, uint16_t, 0, UINT16_MAX)
1394 DEFINE_PARSE_ULONG(_u8, uint8_t, 0, UINT8_MAX)
1395
1396 #define DEFINE_PARSE_LONG(name, type, min, max) \
1397 DEFINE_PARSE_WRAPPER(name, type, min, max, long, _long)
1398 DEFINE_PARSE_LONG(_int, int, n < INT_MIN, INT_MAX)
1399 DEFINE_PARSE_LONG(_s32, int32_t, n < INT32_MIN, INT32_MAX)
1400 DEFINE_PARSE_LONG(_s16, int16_t, n < INT16_MIN, INT16_MAX)
1401 DEFINE_PARSE_LONG(_s8, int8_t, n < INT8_MIN, INT8_MAX)
1402
1403 static int command_parse_bool(const char *in, bool *out,
1404 const char *on, const char *off)
1405 {
1406 if (strcasecmp(in, on) == 0)
1407 *out = true;
1408 else if (strcasecmp(in, off) == 0)
1409 *out = false;
1410 else
1411 return ERROR_COMMAND_SYNTAX_ERROR;
1412 return ERROR_OK;
1413 }
1414
1415 int command_parse_bool_arg(const char *in, bool *out)
1416 {
1417 if (command_parse_bool(in, out, "on", "off") == ERROR_OK)
1418 return ERROR_OK;
1419 if (command_parse_bool(in, out, "enable", "disable") == ERROR_OK)
1420 return ERROR_OK;
1421 if (command_parse_bool(in, out, "true", "false") == ERROR_OK)
1422 return ERROR_OK;
1423 if (command_parse_bool(in, out, "yes", "no") == ERROR_OK)
1424 return ERROR_OK;
1425 if (command_parse_bool(in, out, "1", "0") == ERROR_OK)
1426 return ERROR_OK;
1427 return ERROR_INVALID_ARGUMENTS;
1428 }
1429
1430 COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label)
1431 {
1432 switch (CMD_ARGC) {
1433 case 1: {
1434 const char *in = CMD_ARGV[0];
1435 if (command_parse_bool_arg(in, out) != ERROR_OK)
1436 {
1437 LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME, in);
1438 return ERROR_INVALID_ARGUMENTS;
1439 }
1440 // fall through
1441 }
1442 case 0:
1443 LOG_INFO("%s is %s", label, *out ? "enabled" : "disabled");
1444 break;
1445 default:
1446 return ERROR_INVALID_ARGUMENTS;
1447 }
1448 return ERROR_OK;
1449 }

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)