f135bb03cb2f8dbed1e7d75a2d2ed042e3e424ef
[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 int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
112 {
113 /* the private data is stashed in the interp structure */
114 struct command *c;
115 struct command_context *context;
116 int retval;
117
118 /* DANGER!!!! be careful what we invoke here, since interp->cmdPrivData might
119 * get overwritten by running other Jim commands! Treat it as an
120 * emphemeral global variable that is used in lieu of an argument
121 * to the fn and fish it out manually.
122 */
123 c = interp->cmdPrivData;
124 if (c == NULL)
125 {
126 LOG_ERROR("BUG: interp->cmdPrivData == NULL");
127 return JIM_ERR;
128 }
129 target_call_timer_callbacks_now();
130 LOG_USER_N("%s", ""); /* Keep GDB connection alive*/
131
132 script_debug(interp, c->name, argc, argv);
133
134 unsigned nwords;
135 const char **words = script_command_args_alloc(argc, argv, &nwords);
136 if (NULL == words)
137 return JIM_ERR;
138
139 /* grab the command context from the associated data */
140 context = Jim_GetAssocData(interp, "context");
141 if (context == NULL)
142 {
143 /* Tcl can invoke commands directly instead of via command_run_line(). This would
144 * happen when the Jim Tcl interpreter is provided by eCos.
145 */
146 context = global_cmd_ctx;
147 }
148
149 /* capture log output and return it */
150 Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
151 /* a garbage collect can happen, so we need a reference count to this object */
152 Jim_IncrRefCount(tclOutput);
153
154 log_add_callback(tcl_output, tclOutput);
155
156 retval = run_command(context, c, (const char **)words, nwords);
157
158 log_remove_callback(tcl_output, tclOutput);
159
160 /* We dump output into this local variable */
161 Jim_SetResult(interp, tclOutput);
162 Jim_DecrRefCount(interp, tclOutput);
163
164 script_command_args_free(words, nwords);
165
166 int *return_retval = Jim_GetAssocData(interp, "retval");
167 if (return_retval != NULL)
168 {
169 *return_retval = retval;
170 }
171
172 return (retval == ERROR_OK)?JIM_OK:JIM_ERR;
173 }
174
175 static Jim_Obj *command_name_list(struct command *c)
176 {
177 Jim_Obj *cmd_list = c->parent ?
178 command_name_list(c->parent) :
179 Jim_NewListObj(interp, NULL, 0);
180 Jim_ListAppendElement(interp, cmd_list,
181 Jim_NewStringObj(interp, c->name, -1));
182
183 return cmd_list;
184 }
185
186 static void command_helptext_add(Jim_Obj *cmd_list, const char *help)
187 {
188 Jim_Obj *cmd_entry = Jim_NewListObj(interp, NULL, 0);
189 Jim_ListAppendElement(interp, cmd_entry, cmd_list);
190 Jim_ListAppendElement(interp, cmd_entry,
191 Jim_NewStringObj(interp, help ? : "", -1));
192
193 /* accumulate help text in Tcl helptext list. */
194 Jim_Obj *helptext = Jim_GetGlobalVariableStr(interp,
195 "ocd_helptext", JIM_ERRMSG);
196 if (Jim_IsShared(helptext))
197 helptext = Jim_DuplicateObj(interp, helptext);
198 Jim_ListAppendElement(interp, helptext, cmd_entry);
199 }
200
201 /* nice short description of source file */
202 #define __THIS__FILE__ "command.c"
203
204 /**
205 * Find a command by name from a list of commands.
206 * @returns The named command if found, or NULL.
207 */
208 static struct command *command_find(struct command *head, const char *name)
209 {
210 for (struct command *cc = head; cc; cc = cc->next)
211 {
212 if (strcmp(cc->name, name) == 0)
213 return cc;
214 }
215 return NULL;
216 }
217
218 /**
219 * Add the command to the end of linked list.
220 * @returns Returns false if the named command already exists in the list.
221 * Returns true otherwise.
222 */
223 static void command_add_child(struct command **head, struct command *c)
224 {
225 assert(head);
226 if (NULL == *head)
227 {
228 *head = c;
229 return;
230 }
231 struct command *cc = *head;
232 while (cc->next) cc = cc->next;
233 cc->next = c;
234 }
235
236 static struct command **command_list_for_parent(
237 struct command_context *cmd_ctx, struct command *parent)
238 {
239 return parent ? &parent->children : &cmd_ctx->commands;
240 }
241
242 static struct command *command_new(struct command_context *cmd_ctx,
243 struct command *parent, const char *name,
244 command_handler_t handler, enum command_mode mode,
245 const char *help)
246 {
247 assert(name);
248
249 struct command *c = malloc(sizeof(struct command));
250 memset(c, 0, sizeof(struct command));
251
252 c->name = strdup(name);
253 if (help)
254 c->help = strdup(help);
255 c->parent = parent;
256 c->handler = handler;
257 c->mode = mode;
258
259 command_add_child(command_list_for_parent(cmd_ctx, parent), c);
260
261 command_helptext_add(command_name_list(c), help);
262
263 return c;
264 }
265 static void command_free(struct command *c)
266 {
267 /// @todo if command has a handler, unregister its jim command!
268
269 while (NULL != c->children)
270 {
271 struct command *tmp = c->children;
272 c->children = tmp->next;
273 command_free(tmp);
274 }
275
276 if (c->name)
277 free(c->name);
278 if (c->help)
279 free((void*)c->help);
280 free(c);
281 }
282
283 struct command* register_command(struct command_context *context,
284 struct command *parent, const char *name,
285 command_handler_t handler, enum command_mode mode,
286 const char *help)
287 {
288 if (!context || !name)
289 return NULL;
290
291 struct command **head = command_list_for_parent(context, parent);
292 struct command *c = command_find(*head, name);
293 if (NULL != c)
294 {
295 LOG_ERROR("command '%s' is already registered in '%s' context",
296 name, parent ? parent->name : "<global>");
297 return c;
298 }
299
300 c = command_new(context, parent, name, handler, mode, help);
301 /* if allocation failed or it is a placeholder (no handler), we're done */
302 if (NULL == c || NULL == c->handler)
303 return c;
304
305 const char *full_name = command_name(c, '_');
306
307 const char *ocd_name = alloc_printf("ocd_%s", full_name);
308 Jim_CreateCommand(interp, ocd_name, script_command, c, NULL);
309 free((void *)ocd_name);
310
311 /* we now need to add an overrideable proc */
312 const char *override_name = alloc_printf("proc %s {args} {"
313 "if {[catch {eval ocd_%s $args}] == 0} "
314 "{return \"\"} else {return -code error}}",
315 full_name, full_name);
316 Jim_Eval_Named(interp, override_name, __THIS__FILE__, __LINE__);
317 free((void *)override_name);
318
319 free((void *)full_name);
320
321 return c;
322 }
323
324 int unregister_all_commands(struct command_context *context,
325 struct command *parent)
326 {
327 if (context == NULL)
328 return ERROR_OK;
329
330 struct command **head = command_list_for_parent(context, parent);
331 while (NULL != *head)
332 {
333 struct command *tmp = *head;
334 *head = tmp->next;
335 command_free(tmp);
336 }
337
338 return ERROR_OK;
339 }
340
341 int unregister_command(struct command_context *context,
342 struct command *parent, const char *name)
343 {
344 if ((!context) || (!name))
345 return ERROR_INVALID_ARGUMENTS;
346
347 struct command *p = NULL;
348 struct command **head = command_list_for_parent(context, parent);
349 for (struct command *c = *head; NULL != c; p = c, c = c->next)
350 {
351 if (strcmp(name, c->name) != 0)
352 continue;
353
354 if (p)
355 p->next = c->next;
356 else
357 *head = c->next;
358
359 command_free(c);
360 return ERROR_OK;
361 }
362
363 return ERROR_OK;
364 }
365
366 void command_output_text(struct command_context *context, const char *data)
367 {
368 if (context && context->output_handler && data) {
369 context->output_handler(context, data);
370 }
371 }
372
373 void command_print_sameline(struct command_context *context, const char *format, ...)
374 {
375 char *string;
376
377 va_list ap;
378 va_start(ap, format);
379
380 string = alloc_vprintf(format, ap);
381 if (string != NULL)
382 {
383 /* we want this collected in the log + we also want to pick it up as a tcl return
384 * value.
385 *
386 * The latter bit isn't precisely neat, but will do for now.
387 */
388 LOG_USER_N("%s", string);
389 /* We already printed it above */
390 /* command_output_text(context, string); */
391 free(string);
392 }
393
394 va_end(ap);
395 }
396
397 void command_print(struct command_context *context, const char *format, ...)
398 {
399 char *string;
400
401 va_list ap;
402 va_start(ap, format);
403
404 string = alloc_vprintf(format, ap);
405 if (string != NULL)
406 {
407 strcat(string, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one char longer */
408 /* we want this collected in the log + we also want to pick it up as a tcl return
409 * value.
410 *
411 * The latter bit isn't precisely neat, but will do for now.
412 */
413 LOG_USER_N("%s", string);
414 /* We already printed it above */
415 /* command_output_text(context, string); */
416 free(string);
417 }
418
419 va_end(ap);
420 }
421
422 static char *__command_name(struct command *c, char delim, unsigned extra)
423 {
424 char *name;
425 unsigned len = strlen(c->name);
426 if (NULL == c->parent) {
427 // allocate enough for the name, child names, and '\0'
428 name = malloc(len + extra + 1);
429 strcpy(name, c->name);
430 } else {
431 // parent's extra must include both the space and name
432 name = __command_name(c->parent, delim, 1 + len + extra);
433 char dstr[2] = { delim, 0 };
434 strcat(name, dstr);
435 strcat(name, c->name);
436 }
437 return name;
438 }
439 char *command_name(struct command *c, char delim)
440 {
441 return __command_name(c, delim, 0);
442 }
443
444 static int run_command(struct command_context *context,
445 struct command *c, const char *words[], unsigned num_words)
446 {
447 if (!((context->mode == COMMAND_CONFIG) || (c->mode == COMMAND_ANY) || (c->mode == context->mode)))
448 {
449 /* Config commands can not run after the config stage */
450 LOG_ERROR("Command '%s' only runs during configuration stage", c->name);
451 return ERROR_FAIL;
452 }
453
454 struct command_invocation cmd = {
455 .ctx = context,
456 .name = c->name,
457 .argc = num_words - 1,
458 .argv = words + 1,
459 };
460 int retval = c->handler(&cmd);
461 if (retval == ERROR_COMMAND_SYNTAX_ERROR)
462 {
463 /* Print help for command */
464 char *full_name = command_name(c, ' ');
465 if (NULL != full_name) {
466 command_run_linef(context, "help %s", full_name);
467 free(full_name);
468 } else
469 retval = -ENOMEM;
470 }
471 else if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
472 {
473 /* just fall through for a shutdown request */
474 }
475 else if (retval != ERROR_OK)
476 {
477 /* we do not print out an error message because the command *should*
478 * have printed out an error
479 */
480 LOG_DEBUG("Command failed with error code %d", retval);
481 }
482
483 return retval;
484 }
485
486 int command_run_line(struct command_context *context, char *line)
487 {
488 /* all the parent commands have been registered with the interpreter
489 * so, can just evaluate the line as a script and check for
490 * results
491 */
492 /* run the line thru a script engine */
493 int retval = ERROR_FAIL;
494 int retcode;
495 /* Beware! This code needs to be reentrant. It is also possible
496 * for OpenOCD commands to be invoked directly from Tcl. This would
497 * happen when the Jim Tcl interpreter is provided by eCos for
498 * instance.
499 */
500 Jim_DeleteAssocData(interp, "context");
501 retcode = Jim_SetAssocData(interp, "context", NULL, context);
502 if (retcode == JIM_OK)
503 {
504 /* associated the return value */
505 Jim_DeleteAssocData(interp, "retval");
506 retcode = Jim_SetAssocData(interp, "retval", NULL, &retval);
507 if (retcode == JIM_OK)
508 {
509 retcode = Jim_Eval_Named(interp, line, __THIS__FILE__, __LINE__);
510
511 Jim_DeleteAssocData(interp, "retval");
512 }
513 Jim_DeleteAssocData(interp, "context");
514 }
515 if (retcode == JIM_ERR) {
516 if (retval != ERROR_COMMAND_CLOSE_CONNECTION)
517 {
518 /* We do not print the connection closed error message */
519 Jim_PrintErrorMessage(interp);
520 }
521 if (retval == ERROR_OK)
522 {
523 /* It wasn't a low level OpenOCD command that failed */
524 return ERROR_FAIL;
525 }
526 return retval;
527 } else if (retcode == JIM_EXIT) {
528 /* ignore. */
529 /* exit(Jim_GetExitCode(interp)); */
530 } else {
531 const char *result;
532 int reslen;
533
534 result = Jim_GetString(Jim_GetResult(interp), &reslen);
535 if (reslen > 0)
536 {
537 int i;
538 char buff[256 + 1];
539 for (i = 0; i < reslen; i += 256)
540 {
541 int chunk;
542 chunk = reslen - i;
543 if (chunk > 256)
544 chunk = 256;
545 strncpy(buff, result + i, chunk);
546 buff[chunk] = 0;
547 LOG_USER_N("%s", buff);
548 }
549 LOG_USER_N("%s", "\n");
550 }
551 retval = ERROR_OK;
552 }
553 return retval;
554 }
555
556 int command_run_linef(struct command_context *context, const char *format, ...)
557 {
558 int retval = ERROR_FAIL;
559 char *string;
560 va_list ap;
561 va_start(ap, format);
562 string = alloc_vprintf(format, ap);
563 if (string != NULL)
564 {
565 retval = command_run_line(context, string);
566 }
567 va_end(ap);
568 return retval;
569 }
570
571 void command_set_output_handler(struct command_context* context,
572 command_output_handler_t output_handler, void *priv)
573 {
574 context->output_handler = output_handler;
575 context->output_handler_priv = priv;
576 }
577
578 struct command_context* copy_command_context(struct command_context* context)
579 {
580 struct command_context* copy_context = malloc(sizeof(struct command_context));
581
582 *copy_context = *context;
583
584 return copy_context;
585 }
586
587 int command_done(struct command_context *context)
588 {
589 free(context);
590 context = NULL;
591
592 return ERROR_OK;
593 }
594
595 /* find full path to file */
596 static int jim_find(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
597 {
598 if (argc != 2)
599 return JIM_ERR;
600 const char *file = Jim_GetString(argv[1], NULL);
601 char *full_path = find_file(file);
602 if (full_path == NULL)
603 return JIM_ERR;
604 Jim_Obj *result = Jim_NewStringObj(interp, full_path, strlen(full_path));
605 free(full_path);
606
607 Jim_SetResult(interp, result);
608 return JIM_OK;
609 }
610
611 static int jim_echo(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
612 {
613 if (argc != 2)
614 return JIM_ERR;
615 const char *str = Jim_GetString(argv[1], NULL);
616 LOG_USER("%s", str);
617 return JIM_OK;
618 }
619
620 static size_t openocd_jim_fwrite(const void *_ptr, size_t size, size_t n, void *cookie)
621 {
622 size_t nbytes;
623 const char *ptr;
624 Jim_Interp *interp;
625
626 /* make it a char easier to read code */
627 ptr = _ptr;
628 interp = cookie;
629 nbytes = size * n;
630 if (ptr == NULL || interp == NULL || nbytes == 0) {
631 return 0;
632 }
633
634 /* do we have to chunk it? */
635 if (ptr[nbytes] == 0)
636 {
637 /* no it is a C style string */
638 LOG_USER_N("%s", ptr);
639 return strlen(ptr);
640 }
641 /* GRR we must chunk - not null terminated */
642 while (nbytes) {
643 char chunk[128 + 1];
644 int x;
645
646 x = nbytes;
647 if (x > 128) {
648 x = 128;
649 }
650 /* copy it */
651 memcpy(chunk, ptr, x);
652 /* terminate it */
653 chunk[n] = 0;
654 /* output it */
655 LOG_USER_N("%s", chunk);
656 ptr += x;
657 nbytes -= x;
658 }
659
660 return n;
661 }
662
663 static size_t openocd_jim_fread(void *ptr, size_t size, size_t n, void *cookie)
664 {
665 /* TCL wants to read... tell him no */
666 return 0;
667 }
668
669 static int openocd_jim_vfprintf(void *cookie, const char *fmt, va_list ap)
670 {
671 char *cp;
672 int n;
673 Jim_Interp *interp;
674
675 n = -1;
676 interp = cookie;
677 if (interp == NULL)
678 return n;
679
680 cp = alloc_vprintf(fmt, ap);
681 if (cp)
682 {
683 LOG_USER_N("%s", cp);
684 n = strlen(cp);
685 free(cp);
686 }
687 return n;
688 }
689
690 static int openocd_jim_fflush(void *cookie)
691 {
692 /* nothing to flush */
693 return 0;
694 }
695
696 static char* openocd_jim_fgets(char *s, int size, void *cookie)
697 {
698 /* not supported */
699 errno = ENOTSUP;
700 return NULL;
701 }
702
703 static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
704 {
705 if (argc != 2)
706 return JIM_ERR;
707 int retcode;
708 const char *str = Jim_GetString(argv[1], NULL);
709
710 /* capture log output and return it */
711 Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
712 /* a garbage collect can happen, so we need a reference count to this object */
713 Jim_IncrRefCount(tclOutput);
714
715 log_add_callback(tcl_output, tclOutput);
716
717 retcode = Jim_Eval_Named(interp, str, __THIS__FILE__, __LINE__);
718
719 log_remove_callback(tcl_output, tclOutput);
720
721 /* We dump output into this local variable */
722 Jim_SetResult(interp, tclOutput);
723 Jim_DecrRefCount(interp, tclOutput);
724
725 return retcode;
726 }
727
728 static COMMAND_HELPER(command_help_find, struct command *head,
729 struct command **out)
730 {
731 if (0 == CMD_ARGC)
732 return ERROR_INVALID_ARGUMENTS;
733 *out = command_find(head, CMD_ARGV[0]);
734 if (NULL == *out)
735 return ERROR_INVALID_ARGUMENTS;
736 if (--CMD_ARGC == 0)
737 return ERROR_OK;
738 CMD_ARGV++;
739 return CALL_COMMAND_HANDLER(command_help_find, (*out)->children, out);
740 }
741
742 static COMMAND_HELPER(command_help_show, struct command *c, unsigned n);
743
744 static COMMAND_HELPER(command_help_show_list, struct command *head, unsigned n)
745 {
746 for (struct command *c = head; NULL != c; c = c->next)
747 CALL_COMMAND_HANDLER(command_help_show, c, n);
748 return ERROR_OK;
749 }
750 static COMMAND_HELPER(command_help_show, struct command *c, unsigned n)
751 {
752 command_run_linef(CMD_CTX, "cmd_help {%s} {%s} %d", command_name(c, ' '),
753 c->help ? : "no help available", n);
754
755 if (++n >= 2)
756 return ERROR_OK;
757
758 return CALL_COMMAND_HANDLER(command_help_show_list, c->children, n);
759 }
760 COMMAND_HANDLER(handle_help_command)
761 {
762 struct command *c = CMD_CTX->commands;
763
764 if (0 == CMD_ARGC)
765 return CALL_COMMAND_HANDLER(command_help_show_list, c, 0);
766
767 int retval = CALL_COMMAND_HANDLER(command_help_find, c, &c);
768 if (ERROR_OK != retval)
769 return retval;
770
771 return CALL_COMMAND_HANDLER(command_help_show, c, 0);
772 }
773
774 /* sleep command sleeps for <n> miliseconds
775 * this is useful in target startup scripts
776 */
777 COMMAND_HANDLER(handle_sleep_command)
778 {
779 bool busy = false;
780 if (CMD_ARGC == 2)
781 {
782 if (strcmp(CMD_ARGV[1], "busy") == 0)
783 busy = true;
784 else
785 return ERROR_COMMAND_SYNTAX_ERROR;
786 }
787 else if (CMD_ARGC < 1 || CMD_ARGC > 2)
788 return ERROR_COMMAND_SYNTAX_ERROR;
789
790 unsigned long duration = 0;
791 int retval = parse_ulong(CMD_ARGV[0], &duration);
792 if (ERROR_OK != retval)
793 return retval;
794
795 if (!busy)
796 {
797 long long then = timeval_ms();
798 while (timeval_ms() - then < (long long)duration)
799 {
800 target_call_timer_callbacks_now();
801 usleep(1000);
802 }
803 }
804 else
805 busy_sleep(duration);
806
807 return ERROR_OK;
808 }
809
810 struct command_context* command_init(const char *startup_tcl)
811 {
812 struct command_context* context = malloc(sizeof(struct command_context));
813 const char *HostOs;
814
815 context->mode = COMMAND_EXEC;
816 context->commands = NULL;
817 context->current_target = 0;
818 context->output_handler = NULL;
819 context->output_handler_priv = NULL;
820
821 #if !BUILD_ECOSBOARD
822 Jim_InitEmbedded();
823 /* Create an interpreter */
824 interp = Jim_CreateInterp();
825 /* Add all the Jim core commands */
826 Jim_RegisterCoreCommands(interp);
827 #endif
828
829 #if defined(_MSC_VER)
830 /* WinXX - is generic, the forward
831 * looking problem is this:
832 *
833 * "win32" or "win64"
834 *
835 * "winxx" is generic.
836 */
837 HostOs = "winxx";
838 #elif defined(__linux__)
839 HostOs = "linux";
840 #elif defined(__DARWIN__)
841 HostOs = "darwin";
842 #elif defined(__CYGWIN__)
843 HostOs = "cygwin";
844 #elif defined(__MINGW32__)
845 HostOs = "mingw32";
846 #elif defined(__ECOS)
847 HostOs = "ecos";
848 #else
849 #warn unrecognized host OS...
850 HostOs = "other";
851 #endif
852 Jim_SetGlobalVariableStr(interp, "ocd_HOSTOS",
853 Jim_NewStringObj(interp, HostOs , strlen(HostOs)));
854
855 Jim_CreateCommand(interp, "ocd_find", jim_find, NULL, NULL);
856 Jim_CreateCommand(interp, "echo", jim_echo, NULL, NULL);
857 Jim_CreateCommand(interp, "capture", jim_capture, NULL, NULL);
858
859 /* Set Jim's STDIO */
860 interp->cookie_stdin = interp;
861 interp->cookie_stdout = interp;
862 interp->cookie_stderr = interp;
863 interp->cb_fwrite = openocd_jim_fwrite;
864 interp->cb_fread = openocd_jim_fread ;
865 interp->cb_vfprintf = openocd_jim_vfprintf;
866 interp->cb_fflush = openocd_jim_fflush;
867 interp->cb_fgets = openocd_jim_fgets;
868
869 #if !BUILD_ECOSBOARD
870 Jim_EventLoopOnLoad(interp);
871 #endif
872 if (Jim_Eval_Named(interp, startup_tcl, "embedded:startup.tcl",1) == JIM_ERR)
873 {
874 LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD)");
875 Jim_PrintErrorMessage(interp);
876 exit(-1);
877 }
878
879 register_command(context, NULL, "sleep",
880 handle_sleep_command, COMMAND_ANY,
881 "<n> [busy] - sleep for n milliseconds. "
882 "\"busy\" means busy wait");
883
884 register_command(context, NULL, "help",
885 &handle_help_command, COMMAND_ANY,
886 "[<command_name> ...] - show built-in command help");
887
888 return context;
889 }
890
891 int command_context_mode(struct command_context *cmd_ctx, enum command_mode mode)
892 {
893 if (!cmd_ctx)
894 return ERROR_INVALID_ARGUMENTS;
895
896 cmd_ctx->mode = mode;
897 return ERROR_OK;
898 }
899
900 void process_jim_events(void)
901 {
902 #if !BUILD_ECOSBOARD
903 static int recursion = 0;
904
905 if (!recursion)
906 {
907 recursion++;
908 Jim_ProcessEvents (interp, JIM_ALL_EVENTS | JIM_DONT_WAIT);
909 recursion--;
910 }
911 #endif
912 }
913
914 void register_jim(struct command_context *cmd_ctx, const char *name,
915 Jim_CmdProc cmd, const char *help)
916 {
917 Jim_CreateCommand(interp, name, cmd, NULL, NULL);
918
919 Jim_Obj *cmd_list = Jim_NewListObj(interp, NULL, 0);
920 Jim_ListAppendElement(interp, cmd_list,
921 Jim_NewStringObj(interp, name, -1));
922
923 command_helptext_add(cmd_list, help);
924 }
925
926 #define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max) \
927 int parse##name(const char *str, type *ul) \
928 { \
929 if (!*str) \
930 { \
931 LOG_ERROR("Invalid command argument"); \
932 return ERROR_COMMAND_ARGUMENT_INVALID; \
933 } \
934 char *end; \
935 *ul = func(str, &end, 0); \
936 if (*end) \
937 { \
938 LOG_ERROR("Invalid command argument"); \
939 return ERROR_COMMAND_ARGUMENT_INVALID; \
940 } \
941 if ((max == *ul) && (ERANGE == errno)) \
942 { \
943 LOG_ERROR("Argument overflow"); \
944 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
945 } \
946 if (min && (min == *ul) && (ERANGE == errno)) \
947 { \
948 LOG_ERROR("Argument underflow"); \
949 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
950 } \
951 return ERROR_OK; \
952 }
953 DEFINE_PARSE_NUM_TYPE(_ulong, unsigned long , strtoul, 0, ULONG_MAX)
954 DEFINE_PARSE_NUM_TYPE(_ullong, unsigned long long, strtoull, 0, ULLONG_MAX)
955 DEFINE_PARSE_NUM_TYPE(_long, long , strtol, LONG_MIN, LONG_MAX)
956 DEFINE_PARSE_NUM_TYPE(_llong, long long, strtoll, LLONG_MIN, LLONG_MAX)
957
958 #define DEFINE_PARSE_WRAPPER(name, type, min, max, functype, funcname) \
959 int parse##name(const char *str, type *ul) \
960 { \
961 functype n; \
962 int retval = parse##funcname(str, &n); \
963 if (ERROR_OK != retval) \
964 return retval; \
965 if (n > max) \
966 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
967 if (min) \
968 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
969 *ul = n; \
970 return ERROR_OK; \
971 }
972
973 #define DEFINE_PARSE_ULONG(name, type, min, max) \
974 DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long, _ulong)
975 DEFINE_PARSE_ULONG(_uint, unsigned, 0, UINT_MAX)
976 DEFINE_PARSE_ULONG(_u32, uint32_t, 0, UINT32_MAX)
977 DEFINE_PARSE_ULONG(_u16, uint16_t, 0, UINT16_MAX)
978 DEFINE_PARSE_ULONG(_u8, uint8_t, 0, UINT8_MAX)
979
980 #define DEFINE_PARSE_LONG(name, type, min, max) \
981 DEFINE_PARSE_WRAPPER(name, type, min, max, long, _long)
982 DEFINE_PARSE_LONG(_int, int, n < INT_MIN, INT_MAX)
983 DEFINE_PARSE_LONG(_s32, int32_t, n < INT32_MIN, INT32_MAX)
984 DEFINE_PARSE_LONG(_s16, int16_t, n < INT16_MIN, INT16_MAX)
985 DEFINE_PARSE_LONG(_s8, int8_t, n < INT8_MIN, INT8_MAX)
986
987 static int command_parse_bool(const char *in, bool *out,
988 const char *on, const char *off)
989 {
990 if (strcasecmp(in, on) == 0)
991 *out = true;
992 else if (strcasecmp(in, off) == 0)
993 *out = false;
994 else
995 return ERROR_COMMAND_SYNTAX_ERROR;
996 return ERROR_OK;
997 }
998
999 int command_parse_bool_arg(const char *in, bool *out)
1000 {
1001 if (command_parse_bool(in, out, "on", "off") == ERROR_OK)
1002 return ERROR_OK;
1003 if (command_parse_bool(in, out, "enable", "disable") == ERROR_OK)
1004 return ERROR_OK;
1005 if (command_parse_bool(in, out, "true", "false") == ERROR_OK)
1006 return ERROR_OK;
1007 if (command_parse_bool(in, out, "yes", "no") == ERROR_OK)
1008 return ERROR_OK;
1009 if (command_parse_bool(in, out, "1", "0") == ERROR_OK)
1010 return ERROR_OK;
1011 return ERROR_INVALID_ARGUMENTS;
1012 }
1013
1014 COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label)
1015 {
1016 switch (CMD_ARGC) {
1017 case 1: {
1018 const char *in = CMD_ARGV[0];
1019 if (command_parse_bool_arg(in, out) != ERROR_OK)
1020 {
1021 LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME, in);
1022 return ERROR_INVALID_ARGUMENTS;
1023 }
1024 // fall through
1025 }
1026 case 0:
1027 LOG_INFO("%s is %s", label, *out ? "enabled" : "disabled");
1028 break;
1029 default:
1030 return ERROR_INVALID_ARGUMENTS;
1031 }
1032 return ERROR_OK;
1033 }

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)