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