- Fixes '!=' whitespace
[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 int fast_and_dangerous = 0;
48 Jim_Interp *interp = NULL;
49
50 int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
51 int handle_fast_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
52
53 int run_command(command_context_t *context, command_t *c, char *words[], int num_words);
54
55 static void tcl_output(void *privData, const char *file, int line, const char *function, const char *string)
56 {
57 Jim_Obj *tclOutput=(Jim_Obj *)privData;
58
59 Jim_AppendString(interp, tclOutput, string, strlen(string));
60 }
61
62 extern command_context_t *global_cmd_ctx;
63
64 void script_debug(Jim_Interp *interp, const char *name, int argc, Jim_Obj *const *argv)
65 {
66 int i;
67
68 LOG_DEBUG("command - %s", name);
69 for (i = 0; i < argc; i++) {
70 int len;
71 const char *w = Jim_GetString(argv[i], &len);
72
73 /* end of line comment? */
74 if (*w == '#')
75 break;
76
77 LOG_DEBUG("%s - argv[%d]=%s", name, i, w);
78 }
79 }
80
81 static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
82 {
83 /* the private data is stashed in the interp structure */
84 command_t *c;
85 command_context_t *context;
86 int retval;
87 int i;
88 int nwords;
89 char **words;
90
91 /* DANGER!!!! be careful what we invoke here, since interp->cmdPrivData might
92 * get overwritten by running other Jim commands! Treat it as an
93 * emphemeral global variable that is used in lieu of an argument
94 * to the fn and fish it out manually.
95 */
96 c = interp->cmdPrivData;
97 if (c==NULL)
98 {
99 LOG_ERROR("BUG: interp->cmdPrivData==NULL");
100 return JIM_ERR;
101 }
102 target_call_timer_callbacks_now();
103 LOG_USER_N("%s", ""); /* Keep GDB connection alive*/
104
105 script_debug(interp, c->name, argc, argv);
106
107 words = malloc(sizeof(char *) * argc);
108 for (i = 0; i < argc; i++)
109 {
110 int len;
111 const char *w=Jim_GetString(argv[i], &len);
112 if (*w=='#')
113 {
114 /* hit an end of line comment */
115 break;
116 }
117 words[i] = strdup(w);
118 if (words[i] == NULL)
119 {
120 return JIM_ERR;
121 }
122 }
123 nwords = i;
124
125 /* grab the command context from the associated data */
126 context = Jim_GetAssocData(interp, "context");
127 if (context == NULL)
128 {
129 /* Tcl can invoke commands directly instead of via command_run_line(). This would
130 * happen when the Jim Tcl interpreter is provided by eCos.
131 */
132 context = global_cmd_ctx;
133 }
134
135 /* capture log output and return it */
136 Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
137 /* a garbage collect can happen, so we need a reference count to this object */
138 Jim_IncrRefCount(tclOutput);
139
140 log_add_callback(tcl_output, tclOutput);
141
142 retval = run_command(context, c, words, nwords);
143
144 log_remove_callback(tcl_output, tclOutput);
145
146 /* We dump output into this local variable */
147 Jim_SetResult(interp, tclOutput);
148 Jim_DecrRefCount(interp, tclOutput);
149
150 for (i = 0; i < nwords; i++)
151 free(words[i]);
152 free(words);
153
154 int *return_retval = Jim_GetAssocData(interp, "retval");
155 if (return_retval != NULL)
156 {
157 *return_retval = retval;
158 }
159
160 return (retval==ERROR_OK)?JIM_OK:JIM_ERR;
161 }
162
163 /* nice short description of source file */
164 #define __THIS__FILE__ "command.c"
165
166 command_t* register_command(command_context_t *context, command_t *parent, char *name, int (*handler)(struct command_context_s *context, char* name, char** args, int argc), enum command_mode mode, char *help)
167 {
168 command_t *c, *p;
169
170 if (!context || !name)
171 return NULL;
172
173 c = malloc(sizeof(command_t));
174
175 c->name = strdup(name);
176 c->parent = parent;
177 c->children = NULL;
178 c->handler = handler;
179 c->mode = mode;
180 if (!help)
181 help="";
182 c->next = NULL;
183
184 /* place command in tree */
185 if (parent)
186 {
187 if (parent->children)
188 {
189 /* find last child */
190 for (p = parent->children; p && p->next; p = p->next);
191 if (p)
192 p->next = c;
193 }
194 else
195 {
196 parent->children = c;
197 }
198 }
199 else
200 {
201 if (context->commands)
202 {
203 /* find last command */
204 for (p = context->commands; p && p->next; p = p->next);
205 if (p)
206 p->next = c;
207 }
208 else
209 {
210 context->commands = c;
211 }
212 }
213
214 /* just a placeholder, no handler */
215 if (c->handler==NULL)
216 return c;
217
218 /* If this is a two level command, e.g. "flash banks", then the
219 * "unknown" proc in startup.tcl must redirect to this command.
220 *
221 * "flash banks" is translated by "unknown" to "flash_banks"
222 * if such a proc exists
223 */
224 /* Print help for command */
225 const char *t1="";
226 const char *t2="";
227 const char *t3="";
228 /* maximum of two levels :-) */
229 if (c->parent != NULL)
230 {
231 t1=c->parent->name;
232 t2="_";
233 }
234 t3=c->name;
235 const char *full_name=alloc_printf("ocd_%s%s%s", t1, t2, t3);
236 Jim_CreateCommand(interp, full_name, script_command, c, NULL);
237 free((void *)full_name);
238
239 /* we now need to add an overrideable proc */
240 const char *override_name=alloc_printf("proc %s%s%s {args} {if {[catch {eval ocd_%s%s%s $args}]==0} {return \"\"} else { return -code error }", t1, t2, t3, t1, t2, t3);
241 Jim_Eval_Named(interp, override_name, __THIS__FILE__, __LINE__ );
242 free((void *)override_name);
243
244 /* accumulate help text in Tcl helptext list. */
245 Jim_Obj *helptext=Jim_GetGlobalVariableStr(interp, "ocd_helptext", JIM_ERRMSG);
246 if (Jim_IsShared(helptext))
247 helptext = Jim_DuplicateObj(interp, helptext);
248 Jim_Obj *cmd_entry=Jim_NewListObj(interp, NULL, 0);
249
250 Jim_Obj *cmd_list=Jim_NewListObj(interp, NULL, 0);
251
252 /* maximum of two levels :-) */
253 if (c->parent != NULL)
254 {
255 Jim_ListAppendElement(interp, cmd_list, Jim_NewStringObj(interp, c->parent->name, -1));
256 }
257 Jim_ListAppendElement(interp, cmd_list, Jim_NewStringObj(interp, c->name, -1));
258
259 Jim_ListAppendElement(interp, cmd_entry, cmd_list);
260 Jim_ListAppendElement(interp, cmd_entry, Jim_NewStringObj(interp, help, -1));
261 Jim_ListAppendElement(interp, helptext, cmd_entry);
262 return c;
263 }
264
265 int unregister_all_commands(command_context_t *context)
266 {
267 command_t *c, *c2;
268
269 if (context == NULL)
270 return ERROR_OK;
271
272 while (NULL != context->commands)
273 {
274 c = context->commands;
275
276 while (NULL != c->children)
277 {
278 c2 = c->children;
279 c->children = c->children->next;
280 free(c2->name);
281 c2->name = NULL;
282 free(c2);
283 c2 = NULL;
284 }
285
286 context->commands = context->commands->next;
287
288 free(c->name);
289 c->name = NULL;
290 free(c);
291 c = NULL;
292 }
293
294 return ERROR_OK;
295 }
296
297 int unregister_command(command_context_t *context, char *name)
298 {
299 command_t *c, *p = NULL, *c2;
300
301 if ((!context) || (!name))
302 return ERROR_INVALID_ARGUMENTS;
303
304 /* find command */
305 c = context->commands;
306
307 while (NULL != c)
308 {
309 if (strcmp(name, c->name) == 0)
310 {
311 /* unlink command */
312 if (p)
313 {
314 p->next = c->next;
315 }
316 else
317 {
318 /* first element in command list */
319 context->commands = c->next;
320 }
321
322 /* unregister children */
323 while (NULL != c->children)
324 {
325 c2 = c->children;
326 c->children = c->children->next;
327 free(c2->name);
328 c2->name = NULL;
329 free(c2);
330 c2 = NULL;
331 }
332
333 /* delete command */
334 free(c->name);
335 c->name = NULL;
336 free(c);
337 c = NULL;
338 return ERROR_OK;
339 }
340
341 /* remember the last command for unlinking */
342 p = c;
343 c = c->next;
344 }
345
346 return ERROR_OK;
347 }
348
349 void command_output_text(command_context_t *context, const char *data)
350 {
351 if ( context && context->output_handler && data ){
352 context->output_handler( context, data );
353 }
354 }
355
356 void command_print_sameline(command_context_t *context, const char *format, ...)
357 {
358 char *string;
359
360 va_list ap;
361 va_start(ap, format);
362
363 string = alloc_vprintf(format, ap);
364 if (string != NULL)
365 {
366 /* we want this collected in the log + we also want to pick it up as a tcl return
367 * value.
368 *
369 * The latter bit isn't precisely neat, but will do for now.
370 */
371 LOG_USER_N("%s", string);
372 /* We already printed it above */
373 /* command_output_text(context, string); */
374 free(string);
375 }
376
377 va_end(ap);
378 }
379
380 void command_print(command_context_t *context, const char *format, ...)
381 {
382 char *string;
383
384 va_list ap;
385 va_start(ap, format);
386
387 string = alloc_vprintf(format, ap);
388 if (string != NULL)
389 {
390 strcat(string, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one char longer */
391 /* we want this collected in the log + we also want to pick it up as a tcl return
392 * value.
393 *
394 * The latter bit isn't precisely neat, but will do for now.
395 */
396 LOG_USER_N("%s", string);
397 /* We already printed it above */
398 /* command_output_text(context, string); */
399 free(string);
400 }
401
402 va_end(ap);
403 }
404
405 int run_command(command_context_t *context, command_t *c, char *words[], int num_words)
406 {
407 int start_word=0;
408 if (!((context->mode == COMMAND_CONFIG) || (c->mode == COMMAND_ANY) || (c->mode == context->mode) ))
409 {
410 /* Config commands can not run after the config stage */
411 LOG_ERROR("Command '%s' only runs during configuration stage", c->name);
412 return ERROR_FAIL;
413 }
414
415 int retval = c->handler(context, c->name, words + start_word + 1, num_words - start_word - 1);
416 if (retval == ERROR_COMMAND_SYNTAX_ERROR)
417 {
418 /* Print help for command */
419 const char *t1="";
420 const char *t2="";
421 const char *t3="";
422 /* maximum of two levels :-) */
423 if (c->parent != NULL)
424 {
425 t1=c->parent->name;
426 t2=" ";
427 }
428 t3=c->name;
429 command_run_linef(context, "help {%s%s%s}", t1, t2, t3);
430 }
431 else if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
432 {
433 /* just fall through for a shutdown request */
434 }
435 else if (retval != ERROR_OK)
436 {
437 /* we do not print out an error message because the command *should*
438 * have printed out an error
439 */
440 LOG_DEBUG("Command failed with error code %d", retval);
441 }
442
443 return retval;
444 }
445
446 int command_run_line(command_context_t *context, char *line)
447 {
448 /* all the parent commands have been registered with the interpreter
449 * so, can just evaluate the line as a script and check for
450 * results
451 */
452 /* run the line thru a script engine */
453 int retval=ERROR_FAIL;
454 int retcode;
455 /* Beware! This code needs to be reentrant. It is also possible
456 * for OpenOCD commands to be invoked directly from Tcl. This would
457 * happen when the Jim Tcl interpreter is provided by eCos for
458 * instance.
459 */
460 Jim_DeleteAssocData(interp, "context");
461 retcode = Jim_SetAssocData(interp, "context", NULL, context);
462 if (retcode == JIM_OK)
463 {
464 /* associated the return value */
465 Jim_DeleteAssocData(interp, "retval");
466 retcode = Jim_SetAssocData(interp, "retval", NULL, &retval);
467 if (retcode == JIM_OK)
468 {
469 retcode = Jim_Eval_Named(interp, line, __THIS__FILE__, __LINE__ );
470
471 Jim_DeleteAssocData(interp, "retval");
472 }
473 Jim_DeleteAssocData(interp, "context");
474 }
475 if (retcode == JIM_ERR) {
476 if (retval != ERROR_COMMAND_CLOSE_CONNECTION)
477 {
478 /* We do not print the connection closed error message */
479 Jim_PrintErrorMessage(interp);
480 }
481 if (retval==ERROR_OK)
482 {
483 /* It wasn't a low level OpenOCD command that failed */
484 return ERROR_FAIL;
485 }
486 return retval;
487 } else if (retcode == JIM_EXIT) {
488 /* ignore. */
489 /* exit(Jim_GetExitCode(interp)); */
490 } else {
491 const char *result;
492 int reslen;
493
494 result = Jim_GetString(Jim_GetResult(interp), &reslen);
495 if (reslen>0)
496 {
497 int i;
498 char buff[256+1];
499 for (i = 0; i < reslen; i += 256)
500 {
501 int chunk;
502 chunk = reslen - i;
503 if (chunk > 256)
504 chunk = 256;
505 strncpy(buff, result+i, chunk);
506 buff[chunk] = 0;
507 LOG_USER_N("%s", buff);
508 }
509 LOG_USER_N("%s", "\n");
510 }
511 retval=ERROR_OK;
512 }
513 return retval;
514 }
515
516 int command_run_linef(command_context_t *context, const char *format, ...)
517 {
518 int retval=ERROR_FAIL;
519 char *string;
520 va_list ap;
521 va_start(ap, format);
522 string = alloc_vprintf(format, ap);
523 if (string != NULL)
524 {
525 retval=command_run_line(context, string);
526 }
527 va_end(ap);
528 return retval;
529 }
530
531 void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, const char* line), void *priv)
532 {
533 context->output_handler = output_handler;
534 context->output_handler_priv = priv;
535 }
536
537 command_context_t* copy_command_context(command_context_t* context)
538 {
539 command_context_t* copy_context = malloc(sizeof(command_context_t));
540
541 *copy_context = *context;
542
543 return copy_context;
544 }
545
546 int command_done(command_context_t *context)
547 {
548 free(context);
549 context = NULL;
550
551 return ERROR_OK;
552 }
553
554 /* find full path to file */
555 static int jim_find(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
556 {
557 if (argc != 2)
558 return JIM_ERR;
559 const char *file = Jim_GetString(argv[1], NULL);
560 char *full_path = find_file(file);
561 if (full_path == NULL)
562 return JIM_ERR;
563 Jim_Obj *result = Jim_NewStringObj(interp, full_path, strlen(full_path));
564 free(full_path);
565
566 Jim_SetResult(interp, result);
567 return JIM_OK;
568 }
569
570 static int jim_echo(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
571 {
572 if (argc != 2)
573 return JIM_ERR;
574 const char *str = Jim_GetString(argv[1], NULL);
575 LOG_USER("%s", str);
576 return JIM_OK;
577 }
578
579 static size_t openocd_jim_fwrite(const void *_ptr, size_t size, size_t n, void *cookie)
580 {
581 size_t nbytes;
582 const char *ptr;
583 Jim_Interp *interp;
584
585 /* make it a char easier to read code */
586 ptr = _ptr;
587 interp = cookie;
588 nbytes = size * n;
589 if (ptr == NULL || interp == NULL || nbytes == 0) {
590 return 0;
591 }
592
593 /* do we have to chunk it? */
594 if (ptr[nbytes] == 0)
595 {
596 /* no it is a C style string */
597 LOG_USER_N("%s", ptr);
598 return strlen(ptr);
599 }
600 /* GRR we must chunk - not null terminated */
601 while (nbytes) {
602 char chunk[128+1];
603 int x;
604
605 x = nbytes;
606 if (x > 128) {
607 x = 128;
608 }
609 /* copy it */
610 memcpy(chunk, ptr, x);
611 /* terminate it */
612 chunk[n] = 0;
613 /* output it */
614 LOG_USER_N("%s", chunk);
615 ptr += x;
616 nbytes -= x;
617 }
618
619 return n;
620 }
621
622 static size_t openocd_jim_fread(void *ptr, size_t size, size_t n, void *cookie)
623 {
624 /* TCL wants to read... tell him no */
625 return 0;
626 }
627
628 static int openocd_jim_vfprintf(void *cookie, const char *fmt, va_list ap)
629 {
630 char *cp;
631 int n;
632 Jim_Interp *interp;
633
634 n = -1;
635 interp = cookie;
636 if (interp == NULL)
637 return n;
638
639 cp = alloc_vprintf(fmt, ap);
640 if (cp)
641 {
642 LOG_USER_N("%s", cp);
643 n = strlen(cp);
644 free(cp);
645 }
646 return n;
647 }
648
649 static int openocd_jim_fflush(void *cookie)
650 {
651 /* nothing to flush */
652 return 0;
653 }
654
655 static char* openocd_jim_fgets(char *s, int size, void *cookie)
656 {
657 /* not supported */
658 errno = ENOTSUP;
659 return NULL;
660 }
661
662 static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
663 {
664 if (argc != 2)
665 return JIM_ERR;
666 int retcode;
667 const char *str = Jim_GetString(argv[1], NULL);
668
669 /* capture log output and return it */
670 Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
671 /* a garbage collect can happen, so we need a reference count to this object */
672 Jim_IncrRefCount(tclOutput);
673
674 log_add_callback(tcl_output, tclOutput);
675
676 retcode = Jim_Eval_Named(interp, str, __THIS__FILE__, __LINE__ );
677
678 log_remove_callback(tcl_output, tclOutput);
679
680 /* We dump output into this local variable */
681 Jim_SetResult(interp, tclOutput);
682 Jim_DecrRefCount(interp, tclOutput);
683
684 return retcode;
685 }
686
687 command_context_t* command_init()
688 {
689 command_context_t* context = malloc(sizeof(command_context_t));
690 extern const char startup_tcl[];
691 const char *HostOs;
692
693 context->mode = COMMAND_EXEC;
694 context->commands = NULL;
695 context->current_target = 0;
696 context->output_handler = NULL;
697 context->output_handler_priv = NULL;
698
699 #if !BUILD_ECOSBOARD
700 Jim_InitEmbedded();
701 /* Create an interpreter */
702 interp = Jim_CreateInterp();
703 /* Add all the Jim core commands */
704 Jim_RegisterCoreCommands(interp);
705 #endif
706
707 #if defined( _MSC_VER )
708 /* WinXX - is generic, the forward
709 * looking problem is this:
710 *
711 * "win32" or "win64"
712 *
713 * "winxx" is generic.
714 */
715 HostOs = "winxx";
716 #elif defined( __LINUX__)
717 HostOs = "linux";
718 #elif defined( __DARWIN__ )
719 HostOs = "darwin";
720 #elif defined( __CYGWIN__ )
721 HostOs = "cygwin";
722 #elif defined( __MINGW32__ )
723 HostOs = "mingw32";
724 #else
725 HostOs = "other";
726 #endif
727 Jim_SetGlobalVariableStr( interp, "ocd_HOSTOS", Jim_NewStringObj( interp, HostOs , strlen(HostOs)) );
728
729 Jim_CreateCommand(interp, "ocd_find", jim_find, NULL, NULL);
730 Jim_CreateCommand(interp, "echo", jim_echo, NULL, NULL);
731 Jim_CreateCommand(interp, "capture", jim_capture, NULL, NULL);
732
733 /* Set Jim's STDIO */
734 interp->cookie_stdin = interp;
735 interp->cookie_stdout = interp;
736 interp->cookie_stderr = interp;
737 interp->cb_fwrite = openocd_jim_fwrite;
738 interp->cb_fread = openocd_jim_fread ;
739 interp->cb_vfprintf = openocd_jim_vfprintf;
740 interp->cb_fflush = openocd_jim_fflush;
741 interp->cb_fgets = openocd_jim_fgets;
742
743 add_default_dirs();
744
745 #if !BUILD_ECOSBOARD
746 Jim_EventLoopOnLoad(interp);
747 #endif
748 if (Jim_Eval_Named(interp, startup_tcl, "embedded:startup.tcl",1)==JIM_ERR)
749 {
750 LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD compile time)");
751 Jim_PrintErrorMessage(interp);
752 exit(-1);
753 }
754
755 register_command(context, NULL, "sleep", handle_sleep_command,
756 COMMAND_ANY, "<n> [busy] - sleep for n milliseconds. \"busy\" means busy wait");
757
758 register_command(context, NULL, "fast", handle_fast_command,
759 COMMAND_ANY, "fast <enable/disable> - place at beginning of config files. Sets defaults to fast and dangerous.");
760
761 return context;
762 }
763
764 int command_context_mode(command_context_t *cmd_ctx, enum command_mode mode)
765 {
766 if (!cmd_ctx)
767 return ERROR_INVALID_ARGUMENTS;
768
769 cmd_ctx->mode = mode;
770 return ERROR_OK;
771 }
772
773 /* sleep command sleeps for <n> miliseconds
774 * this is useful in target startup scripts
775 */
776 int handle_sleep_command(struct command_context_s *cmd_ctx,
777 char *cmd, char **args, int argc)
778 {
779 bool busy = false;
780 if (argc == 2)
781 {
782 if (strcmp(args[1], "busy") == 0)
783 busy = true;
784 else
785 return ERROR_COMMAND_SYNTAX_ERROR;
786 }
787 else if (argc < 1 || argc > 2)
788 return ERROR_COMMAND_SYNTAX_ERROR;
789
790 unsigned long duration = 0;
791 int retval = parse_ulong(args[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 int handle_fast_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
811 {
812 if (argc != 1)
813 return ERROR_COMMAND_SYNTAX_ERROR;
814
815 fast_and_dangerous = strcmp("enable", args[0])==0;
816
817 return ERROR_OK;
818 }
819
820 void process_jim_events(void)
821 {
822 #if !BUILD_ECOSBOARD
823 static int recursion = 0;
824
825 if (!recursion)
826 {
827 recursion++;
828 Jim_ProcessEvents (interp, JIM_ALL_EVENTS|JIM_DONT_WAIT);
829 recursion--;
830 }
831 #endif
832 }
833
834 void register_jim(struct command_context_s *cmd_ctx, const char *name, int (*cmd)(Jim_Interp *interp, int argc, Jim_Obj *const *argv), const char *help)
835 {
836 Jim_CreateCommand(interp, name, cmd, NULL, NULL);
837
838 /* FIX!!! it would be prettier to invoke add_help_text...
839 * accumulate help text in Tcl helptext list. */
840 Jim_Obj *helptext=Jim_GetGlobalVariableStr(interp, "ocd_helptext", JIM_ERRMSG);
841 if (Jim_IsShared(helptext))
842 helptext = Jim_DuplicateObj(interp, helptext);
843
844 Jim_Obj *cmd_entry=Jim_NewListObj(interp, NULL, 0);
845
846 Jim_Obj *cmd_list=Jim_NewListObj(interp, NULL, 0);
847 Jim_ListAppendElement(interp, cmd_list, Jim_NewStringObj(interp, name, -1));
848
849 Jim_ListAppendElement(interp, cmd_entry, cmd_list);
850 Jim_ListAppendElement(interp, cmd_entry, Jim_NewStringObj(interp, help, -1));
851 Jim_ListAppendElement(interp, helptext, cmd_entry);
852 }
853
854 /* return global variable long value or 0 upon failure */
855 long jim_global_long(const char *variable)
856 {
857 Jim_Obj *objPtr=Jim_GetGlobalVariableStr(interp, variable, JIM_ERRMSG);
858 long t;
859 if (Jim_GetLong(interp, objPtr, &t)==JIM_OK)
860 {
861 return t;
862 }
863 return 0;
864 }
865
866 #define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max) \
867 int parse##name(const char *str, type *ul) \
868 { \
869 if (!*str) \
870 return ERROR_COMMAND_ARGUMENT_INVALID; \
871 char *end; \
872 *ul = func(str, &end, 0); \
873 if (*end) \
874 return ERROR_COMMAND_ARGUMENT_INVALID; \
875 if ((max == *ul) && (ERANGE == errno)) \
876 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
877 if (min && (min == *ul) && (ERANGE == errno)) \
878 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
879 return ERROR_OK; \
880 }
881 DEFINE_PARSE_NUM_TYPE(_ulong, unsigned long , strtoul, 0, ULONG_MAX)
882 DEFINE_PARSE_NUM_TYPE(_ullong, unsigned long long, strtoull, 0, ULLONG_MAX)
883 DEFINE_PARSE_NUM_TYPE(_long, long , strtol, LONG_MIN, LONG_MAX)
884 DEFINE_PARSE_NUM_TYPE(_llong, long long, strtoll, LLONG_MIN, LLONG_MAX)
885
886 #define DEFINE_PARSE_WRAPPER(name, type, min, max, functype, funcname) \
887 int parse##name(const char *str, type *ul) \
888 { \
889 functype n; \
890 int retval = parse##funcname(str, &n); \
891 if (ERROR_OK != retval) \
892 return retval; \
893 if (n > max) \
894 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
895 if (min) \
896 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
897 *ul = n; \
898 return ERROR_OK; \
899 }
900
901 #define DEFINE_PARSE_ULONG(name, type, min, max) \
902 DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long, _ulong)
903 DEFINE_PARSE_ULONG(_uint, unsigned, 0, UINT_MAX)
904 DEFINE_PARSE_ULONG(_u32, uint32_t, 0, UINT32_MAX)
905 DEFINE_PARSE_ULONG(_u16, uint16_t, 0, UINT16_MAX)
906 DEFINE_PARSE_ULONG(_u8, uint8_t, 0, UINT8_MAX)
907
908 #define DEFINE_PARSE_LONG(name, type, min, max) \
909 DEFINE_PARSE_WRAPPER(name, type, min, max, long, _long)
910 DEFINE_PARSE_LONG(_int, int, n < INT_MIN, INT_MAX)
911 DEFINE_PARSE_LONG(_s32, int32_t, n < INT32_MIN, INT32_MAX)
912 DEFINE_PARSE_LONG(_s16, int16_t, n < INT16_MIN, INT16_MAX)
913 DEFINE_PARSE_LONG(_s8, int8_t, n < INT8_MIN, INT8_MAX)

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)