help: re-implement 'help' independent from tree of struct command
[fw/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, see <http://www.gnu.org/licenses/>. *
26  ***************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 /* see Embedded-HOWTO.txt in Jim Tcl project hosted on BerliOS*/
33 #define JIM_EMBEDDED
34
35 /* @todo the inclusion of target.h here is a layering violation */
36 #include <jtag/jtag.h>
37 #include <target/target.h>
38 #include "command.h"
39 #include "configuration.h"
40 #include "log.h"
41 #include "time_support.h"
42 #include "jim-eventloop.h"
43
44 /* nice short description of source file */
45 #define __THIS__FILE__ "command.c"
46
47 struct log_capture_state {
48         Jim_Interp *interp;
49         Jim_Obj *output;
50 };
51
52 static int unregister_command(struct command_context *context,
53         struct command *parent, const char *name);
54 static char *command_name(struct command *c, char delim);
55 static int help_add_command(struct command_context *cmd_ctx,
56         const char *cmd_name, const char *help_text, const char *usage_text);
57 static int help_del_command(struct command_context *cmd_ctx, const char *cmd_name);
58
59 /* wrap jimtcl internal data */
60 static inline bool jimcmd_is_proc(Jim_Cmd *cmd)
61 {
62         return cmd->isproc;
63 }
64
65 static void tcl_output(void *privData, const char *file, unsigned line,
66         const char *function, const char *string)
67 {
68         struct log_capture_state *state = privData;
69         Jim_AppendString(state->interp, state->output, string, strlen(string));
70 }
71
72 static struct log_capture_state *command_log_capture_start(Jim_Interp *interp)
73 {
74         /* capture log output and return it. A garbage collect can
75          * happen, so we need a reference count to this object */
76         Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
77         if (NULL == tclOutput)
78                 return NULL;
79
80         struct log_capture_state *state = malloc(sizeof(*state));
81         if (NULL == state)
82                 return NULL;
83
84         state->interp = interp;
85         Jim_IncrRefCount(tclOutput);
86         state->output = tclOutput;
87
88         log_add_callback(tcl_output, state);
89
90         return state;
91 }
92
93 /* Classic openocd commands provide progress output which we
94  * will capture and return as a Tcl return value.
95  *
96  * However, if a non-openocd command has been invoked, then it
97  * makes sense to return the tcl return value from that command.
98  *
99  * The tcl return value is empty for openocd commands that provide
100  * progress output.
101  *
102  * Therefore we set the tcl return value only if we actually
103  * captured output.
104  */
105 static void command_log_capture_finish(struct log_capture_state *state)
106 {
107         if (NULL == state)
108                 return;
109
110         log_remove_callback(tcl_output, state);
111
112         int length;
113         Jim_GetString(state->output, &length);
114
115         if (length > 0)
116                 Jim_SetResult(state->interp, state->output);
117         else {
118                 /* No output captured, use tcl return value (which could
119                  * be empty too). */
120         }
121         Jim_DecrRefCount(state->interp, state->output);
122
123         free(state);
124 }
125
126 /*
127  * FIXME: workaround for memory leak in jimtcl 0.80
128  * Jim API Jim_CreateCommand() converts the command name in a Jim object and
129  * does not free the object. Fixed for jimtcl 0.81 by e4416cf86f0b
130  * Use the internal jimtcl API Jim_CreateCommandObj, not exported by jim.h,
131  * and override the bugged API through preprocessor's macro.
132  * This workaround works only when jimtcl is compiled as OpenOCD submodule.
133  * If jimtcl is linked-in from a precompiled library, either static or dynamic,
134  * the symbol Jim_CreateCommandObj is not exported and the build will use the
135  * bugged API.
136  * To be removed when OpenOCD will switch to jimtcl 0.81
137  */
138 #if JIM_VERSION == 80
139 static int workaround_createcommand(Jim_Interp *interp, const char *cmdName,
140         Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc);
141 int Jim_CreateCommandObj(Jim_Interp *interp, Jim_Obj *cmdNameObj,
142         Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc)
143 __attribute__((weak, alias("workaround_createcommand")));
144 static int workaround_createcommand(Jim_Interp *interp, const char *cmdName,
145         Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc)
146 {
147         if ((void *)Jim_CreateCommandObj == (void *)workaround_createcommand)
148                 return Jim_CreateCommand(interp, cmdName, cmdProc, privData, delProc);
149
150         Jim_Obj *cmd_name = Jim_NewStringObj(interp, cmdName, -1);
151         Jim_IncrRefCount(cmd_name);
152         int retval = Jim_CreateCommandObj(interp, cmd_name, cmdProc, privData, delProc);
153         Jim_DecrRefCount(interp, cmd_name);
154         return retval;
155 }
156 #define Jim_CreateCommand workaround_createcommand
157 #endif /* JIM_VERSION == 80 */
158 /* FIXME: end of workaround for memory leak in jimtcl 0.80 */
159
160 static int command_retval_set(Jim_Interp *interp, int retval)
161 {
162         int *return_retval = Jim_GetAssocData(interp, "retval");
163         if (return_retval != NULL)
164                 *return_retval = retval;
165
166         return (retval == ERROR_OK) ? JIM_OK : retval;
167 }
168
169 extern struct command_context *global_cmd_ctx;
170
171 /* dump a single line to the log for the command.
172  * Do nothing in case we are not at debug level 3 */
173 void script_debug(Jim_Interp *interp, unsigned int argc, Jim_Obj * const *argv)
174 {
175         if (debug_level < LOG_LVL_DEBUG)
176                 return;
177
178         char *dbg = alloc_printf("command -");
179         for (unsigned i = 0; i < argc; i++) {
180                 int len;
181                 const char *w = Jim_GetString(argv[i], &len);
182                 char *t = alloc_printf("%s %s", dbg, w);
183                 free(dbg);
184                 dbg = t;
185         }
186         LOG_DEBUG("%s", dbg);
187         free(dbg);
188 }
189
190 static void script_command_args_free(char **words, unsigned nwords)
191 {
192         for (unsigned i = 0; i < nwords; i++)
193                 free(words[i]);
194         free(words);
195 }
196
197 static char **script_command_args_alloc(
198         unsigned argc, Jim_Obj * const *argv, unsigned *nwords)
199 {
200         char **words = malloc(argc * sizeof(char *));
201         if (NULL == words)
202                 return NULL;
203
204         unsigned i;
205         for (i = 0; i < argc; i++) {
206                 int len;
207                 const char *w = Jim_GetString(argv[i], &len);
208                 words[i] = strdup(w);
209                 if (words[i] == NULL) {
210                         script_command_args_free(words, i);
211                         return NULL;
212                 }
213         }
214         *nwords = i;
215         return words;
216 }
217
218 struct command_context *current_command_context(Jim_Interp *interp)
219 {
220         /* grab the command context from the associated data */
221         struct command_context *cmd_ctx = Jim_GetAssocData(interp, "context");
222         if (NULL == cmd_ctx) {
223                 /* Tcl can invoke commands directly instead of via command_run_line(). This would
224                  * happen when the Jim Tcl interpreter is provided by eCos or if we are running
225                  * commands in a startup script.
226                  *
227                  * A telnet or gdb server would provide a non-default command context to
228                  * handle piping of error output, have a separate current target, etc.
229                  */
230                 cmd_ctx = global_cmd_ctx;
231         }
232         return cmd_ctx;
233 }
234
235 static struct command *command_root(struct command *c)
236 {
237         while (NULL != c->parent)
238                 c = c->parent;
239         return c;
240 }
241
242 /**
243  * Find a command by name from a list of commands.
244  * @returns Returns the named command if it exists in the list.
245  * Returns NULL otherwise.
246  */
247 static struct command *command_find(struct command *head, const char *name)
248 {
249         for (struct command *cc = head; cc; cc = cc->next) {
250                 if (strcmp(cc->name, name) == 0)
251                         return cc;
252         }
253         return NULL;
254 }
255
256 /**
257  * Add the command into the linked list, sorted by name.
258  * @param head Address to head of command list pointer, which may be
259  * updated if @c c gets inserted at the beginning of the list.
260  * @param c The command to add to the list pointed to by @c head.
261  */
262 static void command_add_child(struct command **head, struct command *c)
263 {
264         assert(head);
265         if (NULL == *head) {
266                 *head = c;
267                 return;
268         }
269
270         while ((*head)->next && (strcmp(c->name, (*head)->name) > 0))
271                 head = &(*head)->next;
272
273         if (strcmp(c->name, (*head)->name) > 0) {
274                 c->next = (*head)->next;
275                 (*head)->next = c;
276         } else {
277                 c->next = *head;
278                 *head = c;
279         }
280 }
281
282 static struct command **command_list_for_parent(
283         struct command_context *cmd_ctx, struct command *parent)
284 {
285         return parent ? &parent->children : &cmd_ctx->commands;
286 }
287
288 static void command_free(struct command *c)
289 {
290         /** @todo if command has a handler, unregister its jim command! */
291
292         while (NULL != c->children) {
293                 struct command *tmp = c->children;
294                 c->children = tmp->next;
295                 command_free(tmp);
296         }
297
298         free(c->name);
299         free(c);
300 }
301
302 static struct command *command_new(struct command_context *cmd_ctx,
303         struct command *parent, const struct command_registration *cr)
304 {
305         assert(cr->name);
306
307         /*
308          * If it is a non-jim command with no .usage specified,
309          * log an error.
310          *
311          * strlen(.usage) == 0 means that the command takes no
312          * arguments.
313         */
314         if ((cr->jim_handler == NULL) && (cr->usage == NULL)) {
315                 LOG_ERROR("BUG: command '%s%s%s' does not have the "
316                         "'.usage' field filled out",
317                         parent && parent->name ? parent->name : "",
318                         parent && parent->name ? " " : "",
319                         cr->name);
320         }
321
322         struct command *c = calloc(1, sizeof(struct command));
323         if (NULL == c)
324                 return NULL;
325
326         c->name = strdup(cr->name);
327         if (!c->name)
328                 goto command_new_error;
329
330         c->parent = parent;
331         c->handler = cr->handler;
332         c->jim_handler = cr->jim_handler;
333         c->mode = cr->mode;
334
335         command_add_child(command_list_for_parent(cmd_ctx, parent), c);
336
337         if (cr->help || cr->usage) {
338                 char *full_name = command_name(c, ' ');
339                 help_add_command(cmd_ctx, full_name, cr->help, cr->usage);
340                 free(full_name);
341         }
342
343         return c;
344
345 command_new_error:
346         command_free(c);
347         return NULL;
348 }
349
350 static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
351
352 static int register_command_handler(struct command_context *cmd_ctx,
353         struct command *c)
354 {
355         Jim_Interp *interp = cmd_ctx->interp;
356
357 #if 0
358         LOG_DEBUG("registering '%s'...", c->name);
359 #endif
360
361         return Jim_CreateCommand(interp, c->name, command_unknown, c, NULL);
362 }
363
364 static struct command *register_command(struct command_context *context,
365         struct command *parent, const struct command_registration *cr)
366 {
367         if (!context || !cr->name)
368                 return NULL;
369
370         const char *name = cr->name;
371         struct command **head = command_list_for_parent(context, parent);
372         struct command *c = command_find(*head, name);
373         if (NULL != c) {
374                 /* TODO: originally we treated attempting to register a cmd twice as an error
375                  * Sometimes we need this behaviour, such as with flash banks.
376                  * http://www.mail-archive.com/openocd-development@lists.berlios.de/msg11152.html */
377                 LOG_DEBUG("command '%s' is already registered in '%s' context",
378                         name, parent ? parent->name : "<global>");
379                 return c;
380         }
381
382         c = command_new(context, parent, cr);
383         if (NULL == c)
384                 return NULL;
385
386         if (cr->jim_handler || cr->handler) {
387                 int retval = register_command_handler(context, command_root(c));
388                 if (retval != JIM_OK) {
389                         unregister_command(context, parent, name);
390                         return NULL;
391                 }
392         }
393         return c;
394 }
395
396 static int ___register_commands(struct command_context *cmd_ctx, struct command *parent,
397         const struct command_registration *cmds, void *data,
398         struct target *override_target)
399 {
400         int retval = ERROR_OK;
401         unsigned i;
402         for (i = 0; cmds[i].name || cmds[i].chain; i++) {
403                 const struct command_registration *cr = cmds + i;
404
405                 struct command *c = NULL;
406                 if (NULL != cr->name) {
407                         c = register_command(cmd_ctx, parent, cr);
408                         if (NULL == c) {
409                                 retval = ERROR_FAIL;
410                                 break;
411                         }
412                         c->jim_handler_data = data;
413                         c->jim_override_target = override_target;
414                 }
415                 if (NULL != cr->chain) {
416                         struct command *p = c ? : parent;
417                         retval = ___register_commands(cmd_ctx, p, cr->chain, data, override_target);
418                         if (ERROR_OK != retval)
419                                 break;
420                 }
421         }
422         if (ERROR_OK != retval) {
423                 for (unsigned j = 0; j < i; j++)
424                         unregister_command(cmd_ctx, parent, cmds[j].name);
425         }
426         return retval;
427 }
428
429 int __register_commands(struct command_context *cmd_ctx, const char *cmd_prefix,
430         const struct command_registration *cmds, void *data,
431         struct target *override_target)
432 {
433         struct command *parent = NULL;
434
435         if (cmd_prefix)
436                 parent = command_find(cmd_ctx->commands, cmd_prefix);
437
438         return ___register_commands(cmd_ctx, parent, cmds, data, override_target);
439 }
440
441 int unregister_all_commands(struct command_context *context,
442         struct command *parent)
443 {
444         if (context == NULL)
445                 return ERROR_OK;
446
447         struct command **head = command_list_for_parent(context, parent);
448         while (NULL != *head) {
449                 struct command *tmp = *head;
450                 *head = tmp->next;
451                 command_free(tmp);
452         }
453
454         return ERROR_OK;
455 }
456
457 static int unregister_command(struct command_context *context,
458         struct command *parent, const char *name)
459 {
460         if ((!context) || (!name))
461                 return ERROR_COMMAND_SYNTAX_ERROR;
462
463         struct command *p = NULL;
464         struct command **head = command_list_for_parent(context, parent);
465         for (struct command *c = *head; NULL != c; p = c, c = c->next) {
466                 if (strcmp(name, c->name) != 0)
467                         continue;
468
469                 char *full_name = command_name(c, ' ');
470                 help_del_command(context, full_name);
471                 free(full_name);
472
473                 if (p)
474                         p->next = c->next;
475                 else
476                         *head = c->next;
477
478                 command_free(c);
479                 return ERROR_OK;
480         }
481
482         return ERROR_OK;
483 }
484
485 void command_output_text(struct command_context *context, const char *data)
486 {
487         if (context && context->output_handler && data)
488                 context->output_handler(context, data);
489 }
490
491 void command_print_sameline(struct command_invocation *cmd, const char *format, ...)
492 {
493         char *string;
494
495         va_list ap;
496         va_start(ap, format);
497
498         string = alloc_vprintf(format, ap);
499         if (string != NULL && cmd) {
500                 /* we want this collected in the log + we also want to pick it up as a tcl return
501                  * value.
502                  *
503                  * The latter bit isn't precisely neat, but will do for now.
504                  */
505                 Jim_AppendString(cmd->ctx->interp, cmd->output, string, -1);
506                 /* We already printed it above
507                  * command_output_text(context, string); */
508                 free(string);
509         }
510
511         va_end(ap);
512 }
513
514 void command_print(struct command_invocation *cmd, const char *format, ...)
515 {
516         char *string;
517
518         va_list ap;
519         va_start(ap, format);
520
521         string = alloc_vprintf(format, ap);
522         if (string != NULL && cmd) {
523                 strcat(string, "\n");   /* alloc_vprintf guaranteed the buffer to be at least one
524                                          *char longer */
525                 /* we want this collected in the log + we also want to pick it up as a tcl return
526                  * value.
527                  *
528                  * The latter bit isn't precisely neat, but will do for now.
529                  */
530                 Jim_AppendString(cmd->ctx->interp, cmd->output, string, -1);
531                 /* We already printed it above
532                  * command_output_text(context, string); */
533                 free(string);
534         }
535
536         va_end(ap);
537 }
538
539 static char *__command_name(struct command *c, char delim, unsigned extra)
540 {
541         char *name;
542         unsigned len = strlen(c->name);
543         if (NULL == c->parent) {
544                 /* allocate enough for the name, child names, and '\0' */
545                 name = malloc(len + extra + 1);
546                 if (!name) {
547                         LOG_ERROR("Out of memory");
548                         return NULL;
549                 }
550                 strcpy(name, c->name);
551         } else {
552                 /* parent's extra must include both the space and name */
553                 name = __command_name(c->parent, delim, 1 + len + extra);
554                 char dstr[2] = { delim, 0 };
555                 strcat(name, dstr);
556                 strcat(name, c->name);
557         }
558         return name;
559 }
560
561 static char *command_name(struct command *c, char delim)
562 {
563         return __command_name(c, delim, 0);
564 }
565
566 static bool command_can_run(struct command_context *cmd_ctx, struct command *c)
567 {
568         if (c->mode == COMMAND_ANY || c->mode == cmd_ctx->mode)
569                 return true;
570
571         /* Many commands may be run only before/after 'init' */
572         const char *when;
573         switch (c->mode) {
574                 case COMMAND_CONFIG:
575                         when = "before";
576                         break;
577                 case COMMAND_EXEC:
578                         when = "after";
579                         break;
580                 /* handle the impossible with humor; it guarantees a bug report! */
581                 default:
582                         when = "if Cthulhu is summoned by";
583                         break;
584         }
585         char *full_name = command_name(c, ' ');
586         LOG_ERROR("The '%s' command must be used %s 'init'.",
587                         full_name ? full_name : c->name, when);
588         free(full_name);
589         return false;
590 }
591
592 static int run_command(struct command_context *context,
593         struct command *c, const char **words, unsigned num_words)
594 {
595         struct command_invocation cmd = {
596                 .ctx = context,
597                 .current = c,
598                 .name = c->name,
599                 .argc = num_words - 1,
600                 .argv = words + 1,
601         };
602
603         cmd.output = Jim_NewEmptyStringObj(context->interp);
604         Jim_IncrRefCount(cmd.output);
605
606         int retval = c->handler(&cmd);
607         if (retval == ERROR_COMMAND_SYNTAX_ERROR) {
608                 /* Print help for command */
609                 char *full_name = command_name(c, ' ');
610                 if (NULL != full_name) {
611                         command_run_linef(context, "usage %s", full_name);
612                         free(full_name);
613                 }
614         } else if (retval == ERROR_COMMAND_CLOSE_CONNECTION) {
615                 /* just fall through for a shutdown request */
616         } else {
617                 if (retval != ERROR_OK) {
618                         char *full_name = command_name(c, ' ');
619                         LOG_DEBUG("Command '%s' failed with error code %d",
620                                                 full_name ? full_name : c->name, retval);
621                         free(full_name);
622                 }
623                 /* Use the command output as the Tcl result */
624                 Jim_SetResult(context->interp, cmd.output);
625         }
626         Jim_DecrRefCount(context->interp, cmd.output);
627
628         return retval;
629 }
630
631 int command_run_line(struct command_context *context, char *line)
632 {
633         /* all the parent commands have been registered with the interpreter
634          * so, can just evaluate the line as a script and check for
635          * results
636          */
637         /* run the line thru a script engine */
638         int retval = ERROR_FAIL;
639         int retcode;
640         /* Beware! This code needs to be reentrant. It is also possible
641          * for OpenOCD commands to be invoked directly from Tcl. This would
642          * happen when the Jim Tcl interpreter is provided by eCos for
643          * instance.
644          */
645         struct target *saved_target_override = context->current_target_override;
646         context->current_target_override = NULL;
647
648         Jim_Interp *interp = context->interp;
649         struct command_context *old_context = Jim_GetAssocData(interp, "context");
650         Jim_DeleteAssocData(interp, "context");
651         retcode = Jim_SetAssocData(interp, "context", NULL, context);
652         if (retcode == JIM_OK) {
653                 /* associated the return value */
654                 Jim_DeleteAssocData(interp, "retval");
655                 retcode = Jim_SetAssocData(interp, "retval", NULL, &retval);
656                 if (retcode == JIM_OK) {
657                         retcode = Jim_Eval_Named(interp, line, 0, 0);
658
659                         Jim_DeleteAssocData(interp, "retval");
660                 }
661                 Jim_DeleteAssocData(interp, "context");
662                 int inner_retcode = Jim_SetAssocData(interp, "context", NULL, old_context);
663                 if (retcode == JIM_OK)
664                         retcode = inner_retcode;
665         }
666         context->current_target_override = saved_target_override;
667         if (retcode == JIM_OK) {
668                 const char *result;
669                 int reslen;
670
671                 result = Jim_GetString(Jim_GetResult(interp), &reslen);
672                 if (reslen > 0) {
673                         command_output_text(context, result);
674                         command_output_text(context, "\n");
675                 }
676                 retval = ERROR_OK;
677         } else if (retcode == JIM_EXIT) {
678                 /* ignore.
679                  * exit(Jim_GetExitCode(interp)); */
680         } else if (retcode == ERROR_COMMAND_CLOSE_CONNECTION) {
681                 return retcode;
682         } else {
683                 Jim_MakeErrorMessage(interp);
684                 /* error is broadcast */
685                 LOG_USER("%s", Jim_GetString(Jim_GetResult(interp), NULL));
686
687                 if (retval == ERROR_OK) {
688                         /* It wasn't a low level OpenOCD command that failed */
689                         return ERROR_FAIL;
690                 }
691                 return retval;
692         }
693
694         return retval;
695 }
696
697 int command_run_linef(struct command_context *context, const char *format, ...)
698 {
699         int retval = ERROR_FAIL;
700         char *string;
701         va_list ap;
702         va_start(ap, format);
703         string = alloc_vprintf(format, ap);
704         if (string != NULL) {
705                 retval = command_run_line(context, string);
706                 free(string);
707         }
708         va_end(ap);
709         return retval;
710 }
711
712 void command_set_output_handler(struct command_context *context,
713         command_output_handler_t output_handler, void *priv)
714 {
715         context->output_handler = output_handler;
716         context->output_handler_priv = priv;
717 }
718
719 struct command_context *copy_command_context(struct command_context *context)
720 {
721         struct command_context *copy_context = malloc(sizeof(struct command_context));
722
723         *copy_context = *context;
724
725         return copy_context;
726 }
727
728 void command_done(struct command_context *cmd_ctx)
729 {
730         if (NULL == cmd_ctx)
731                 return;
732
733         free(cmd_ctx);
734 }
735
736 /* find full path to file */
737 static int jim_find(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
738 {
739         if (argc != 2)
740                 return JIM_ERR;
741         const char *file = Jim_GetString(argv[1], NULL);
742         char *full_path = find_file(file);
743         if (full_path == NULL)
744                 return JIM_ERR;
745         Jim_Obj *result = Jim_NewStringObj(interp, full_path, strlen(full_path));
746         free(full_path);
747
748         Jim_SetResult(interp, result);
749         return JIM_OK;
750 }
751
752 COMMAND_HANDLER(jim_echo)
753 {
754         if (CMD_ARGC == 2 && !strcmp(CMD_ARGV[0], "-n")) {
755                 LOG_USER_N("%s", CMD_ARGV[1]);
756                 return JIM_OK;
757         }
758         if (CMD_ARGC != 1)
759                 return JIM_ERR;
760         LOG_USER("%s", CMD_ARGV[0]);
761         return JIM_OK;
762 }
763
764 /* Capture progress output and return as tcl return value. If the
765  * progress output was empty, return tcl return value.
766  */
767 static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
768 {
769         if (argc != 2)
770                 return JIM_ERR;
771
772         struct log_capture_state *state = command_log_capture_start(interp);
773
774         /* disable polling during capture. This avoids capturing output
775          * from polling.
776          *
777          * This is necessary in order to avoid accidentally getting a non-empty
778          * string for tcl fn's.
779          */
780         bool save_poll = jtag_poll_get_enabled();
781
782         jtag_poll_set_enabled(false);
783
784         const char *str = Jim_GetString(argv[1], NULL);
785         int retcode = Jim_Eval_Named(interp, str, __THIS__FILE__, __LINE__);
786
787         jtag_poll_set_enabled(save_poll);
788
789         command_log_capture_finish(state);
790
791         return retcode;
792 }
793
794 struct help_entry {
795         struct list_head lh;
796         char *cmd_name;
797         char *help;
798         char *usage;
799 };
800
801 static COMMAND_HELPER(command_help_show, struct help_entry *c,
802         bool show_help, const char *cmd_match);
803
804 static COMMAND_HELPER(command_help_show_list, bool show_help, const char *cmd_match)
805 {
806         struct help_entry *entry;
807
808         list_for_each_entry(entry, CMD_CTX->help_list, lh)
809                 CALL_COMMAND_HANDLER(command_help_show, entry, show_help, cmd_match);
810         return ERROR_OK;
811 }
812
813 #define HELP_LINE_WIDTH(_n) (int)(76 - (2 * _n))
814
815 static void command_help_show_indent(unsigned n)
816 {
817         for (unsigned i = 0; i < n; i++)
818                 LOG_USER_N("  ");
819 }
820 static void command_help_show_wrap(const char *str, unsigned n, unsigned n2)
821 {
822         const char *cp = str, *last = str;
823         while (*cp) {
824                 const char *next = last;
825                 do {
826                         cp = next;
827                         do {
828                                 next++;
829                         } while (*next != ' ' && *next != '\t' && *next != '\0');
830                 } while ((next - last < HELP_LINE_WIDTH(n)) && *next != '\0');
831                 if (next - last < HELP_LINE_WIDTH(n))
832                         cp = next;
833                 command_help_show_indent(n);
834                 LOG_USER("%.*s", (int)(cp - last), last);
835                 last = cp + 1;
836                 n = n2;
837         }
838 }
839
840 static COMMAND_HELPER(command_help_show, struct help_entry *c,
841         bool show_help, const char *cmd_match)
842 {
843         unsigned int n = 0;
844         for (const char *s = strchr(c->cmd_name, ' '); s; s = strchr(s + 1, ' '))
845                 n++;
846
847         /* If the match string occurs anywhere, we print out
848          * stuff for this command. */
849         bool is_match = (strstr(c->cmd_name, cmd_match) != NULL) ||
850                 ((c->usage != NULL) && (strstr(c->usage, cmd_match) != NULL)) ||
851                 ((c->help != NULL) && (strstr(c->help, cmd_match) != NULL));
852
853         if (is_match) {
854                 command_help_show_indent(n);
855                 LOG_USER_N("%s", c->cmd_name);
856
857                 if (c->usage && strlen(c->usage) > 0) {
858                         LOG_USER_N(" ");
859                         command_help_show_wrap(c->usage, 0, n + 5);
860                 } else
861                         LOG_USER_N("\n");
862         }
863
864         if (is_match && show_help) {
865                 char *msg;
866
867                 /* TODO: factorize jim_command_mode() to avoid running jim command here */
868                 char *request = alloc_printf("command mode %s", c->cmd_name);
869                 if (!request) {
870                         LOG_ERROR("Out of memory");
871                         return ERROR_FAIL;
872                 }
873                 int retval = Jim_Eval(CMD_CTX->interp, request);
874                 free(request);
875                 enum command_mode mode = COMMAND_UNKNOWN;
876                 if (retval != JIM_ERR) {
877                         const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), NULL);
878                         if (!strcmp(result, "any"))
879                                 mode = COMMAND_ANY;
880                         else if (!strcmp(result, "config"))
881                                 mode = COMMAND_CONFIG;
882                         else if (!strcmp(result, "exec"))
883                                 mode = COMMAND_EXEC;
884                 }
885
886                 /* Normal commands are runtime-only; highlight exceptions */
887                 if (mode != COMMAND_EXEC) {
888                         const char *stage_msg = "";
889
890                         switch (mode) {
891                                 case COMMAND_CONFIG:
892                                         stage_msg = " (configuration command)";
893                                         break;
894                                 case COMMAND_ANY:
895                                         stage_msg = " (command valid any time)";
896                                         break;
897                                 default:
898                                         stage_msg = " (?mode error?)";
899                                         break;
900                         }
901                         msg = alloc_printf("%s%s", c->help ? : "", stage_msg);
902                 } else
903                         msg = alloc_printf("%s", c->help ? : "");
904
905                 if (NULL != msg) {
906                         command_help_show_wrap(msg, n + 3, n + 3);
907                         free(msg);
908                 } else
909                         return -ENOMEM;
910         }
911
912         return ERROR_OK;
913 }
914
915 COMMAND_HANDLER(handle_help_command)
916 {
917         bool full = strcmp(CMD_NAME, "help") == 0;
918         int retval;
919         char *cmd_match;
920
921         if (CMD_ARGC <= 0)
922                 cmd_match = strdup("");
923
924         else {
925                 cmd_match = strdup(CMD_ARGV[0]);
926
927                 for (unsigned int i = 1; i < CMD_ARGC && cmd_match; ++i) {
928                         char *prev = cmd_match;
929                         cmd_match = alloc_printf("%s %s", prev, CMD_ARGV[i]);
930                         free(prev);
931                 }
932         }
933
934         if (cmd_match == NULL) {
935                 LOG_ERROR("unable to build search string");
936                 return -ENOMEM;
937         }
938         retval = CALL_COMMAND_HANDLER(command_help_show_list, full, cmd_match);
939
940         free(cmd_match);
941         return retval;
942 }
943
944 static int command_unknown_find(unsigned argc, Jim_Obj *const *argv,
945         struct command *head, struct command **out)
946 {
947         if (0 == argc)
948                 return argc;
949         const char *cmd_name = Jim_GetString(argv[0], NULL);
950         struct command *c = command_find(head, cmd_name);
951         if (NULL == c)
952                 return argc;
953         *out = c;
954         return command_unknown_find(--argc, ++argv, (*out)->children, out);
955 }
956
957 static char *alloc_concatenate_strings(int argc, Jim_Obj * const *argv)
958 {
959         char *prev, *all;
960         int i;
961
962         assert(argc >= 1);
963
964         all = strdup(Jim_GetString(argv[0], NULL));
965         if (!all) {
966                 LOG_ERROR("Out of memory");
967                 return NULL;
968         }
969
970         for (i = 1; i < argc; ++i) {
971                 prev = all;
972                 all = alloc_printf("%s %s", all, Jim_GetString(argv[i], NULL));
973                 free(prev);
974                 if (!all) {
975                         LOG_ERROR("Out of memory");
976                         return NULL;
977                 }
978         }
979
980         return all;
981 }
982
983 static int run_usage(Jim_Interp *interp, int argc_valid, int argc, Jim_Obj * const *argv)
984 {
985         struct command_context *cmd_ctx = current_command_context(interp);
986         char *command;
987         int retval;
988
989         assert(argc_valid >= 1);
990         assert(argc >= argc_valid);
991
992         command = alloc_concatenate_strings(argc_valid, argv);
993         if (!command)
994                 return JIM_ERR;
995
996         retval = command_run_linef(cmd_ctx, "usage %s", command);
997         if (retval != ERROR_OK) {
998                 LOG_ERROR("unable to execute command \"usage %s\"", command);
999                 return JIM_ERR;
1000         }
1001
1002         if (argc_valid == argc)
1003                 LOG_ERROR("%s: command requires more arguments", command);
1004         else {
1005                 free(command);
1006                 command = alloc_concatenate_strings(argc - argc_valid, argv + argc_valid);
1007                 if (!command)
1008                         return JIM_ERR;
1009                 LOG_ERROR("invalid subcommand \"%s\"", command);
1010         }
1011
1012         free(command);
1013         return retval;
1014 }
1015
1016 static int exec_command(Jim_Interp *interp, struct command_context *cmd_ctx,
1017                 struct command *c, int argc, Jim_Obj *const *argv)
1018 {
1019         if (c->jim_handler)
1020                 return c->jim_handler(interp, argc, argv);
1021
1022         /* use c->handler */
1023         unsigned int nwords;
1024         char **words = script_command_args_alloc(argc, argv, &nwords);
1025         if (!words)
1026                 return JIM_ERR;
1027
1028         int retval = run_command(cmd_ctx, c, (const char **)words, nwords);
1029         script_command_args_free(words, nwords);
1030         return command_retval_set(interp, retval);
1031 }
1032
1033 static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
1034 {
1035         script_debug(interp, argc, argv);
1036
1037         struct command_context *cmd_ctx = current_command_context(interp);
1038         struct command *c = cmd_ctx->commands;
1039         int remaining = command_unknown_find(argc, argv, c, &c);
1040         /* if nothing could be consumed, then it's really an unknown command */
1041         if (remaining == argc) {
1042                 const char *cmd = Jim_GetString(argv[0], NULL);
1043                 LOG_ERROR("Unknown command:\n  %s", cmd);
1044                 return JIM_OK;
1045         }
1046
1047         Jim_Obj *const *start;
1048         unsigned count;
1049         if (c->handler || c->jim_handler) {
1050                 /* include the command name in the list */
1051                 count = remaining + 1;
1052                 start = argv + (argc - remaining - 1);
1053         } else {
1054                 count = argc - remaining;
1055                 start = argv;
1056                 run_usage(interp, count, argc, start);
1057                 return JIM_ERR;
1058         }
1059
1060         if (!command_can_run(cmd_ctx, c))
1061                 return JIM_ERR;
1062
1063         target_call_timer_callbacks_now();
1064
1065         /*
1066          * Black magic of overridden current target:
1067          * If the command we are going to handle has a target prefix,
1068          * override the current target temporarily for the time
1069          * of processing the command.
1070          * current_target_override is used also for event handlers
1071          * therefore we prevent touching it if command has no prefix.
1072          * Previous override is saved and restored back to ensure
1073          * correct work when command_unknown() is re-entered.
1074          */
1075         struct target *saved_target_override = cmd_ctx->current_target_override;
1076         if (c->jim_override_target)
1077                 cmd_ctx->current_target_override = c->jim_override_target;
1078
1079         int retval = exec_command(interp, cmd_ctx, c, count, start);
1080
1081         if (c->jim_override_target)
1082                 cmd_ctx->current_target_override = saved_target_override;
1083
1084         return retval;
1085 }
1086
1087 static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
1088 {
1089         struct command_context *cmd_ctx = current_command_context(interp);
1090         enum command_mode mode;
1091
1092         if (argc > 1) {
1093                 char *full_name = alloc_concatenate_strings(argc - 1, argv + 1);
1094                 if (!full_name)
1095                         return JIM_ERR;
1096                 Jim_Obj *s = Jim_NewStringObj(interp, full_name, -1);
1097                 Jim_IncrRefCount(s);
1098                 Jim_Cmd *cmd = Jim_GetCommand(interp, s, JIM_NONE);
1099                 Jim_DecrRefCount(interp, s);
1100                 free(full_name);
1101                 if (cmd && jimcmd_is_proc(cmd)) {
1102                         Jim_SetResultString(interp, "any", -1);
1103                         return JIM_OK;
1104                 }
1105                 struct command *c = cmd_ctx->commands;
1106                 int remaining = command_unknown_find(argc - 1, argv + 1, c, &c);
1107                 /* if nothing could be consumed, then it's an unknown command */
1108                 if (remaining == argc - 1) {
1109                         Jim_SetResultString(interp, "unknown", -1);
1110                         return JIM_OK;
1111                 }
1112                 mode = c->mode;
1113         } else
1114                 mode = cmd_ctx->mode;
1115
1116         const char *mode_str;
1117         switch (mode) {
1118                 case COMMAND_ANY:
1119                         mode_str = "any";
1120                         break;
1121                 case COMMAND_CONFIG:
1122                         mode_str = "config";
1123                         break;
1124                 case COMMAND_EXEC:
1125                         mode_str = "exec";
1126                         break;
1127                 default:
1128                         mode_str = "unknown";
1129                         break;
1130         }
1131         Jim_SetResultString(interp, mode_str, -1);
1132         return JIM_OK;
1133 }
1134
1135 int help_del_all_commands(struct command_context *cmd_ctx)
1136 {
1137         struct help_entry *curr, *n;
1138
1139         list_for_each_entry_safe(curr, n, cmd_ctx->help_list, lh) {
1140                 list_del(&curr->lh);
1141                 free(curr->cmd_name);
1142                 free(curr->help);
1143                 free(curr->usage);
1144                 free(curr);
1145         }
1146         return ERROR_OK;
1147 }
1148
1149 static int help_del_command(struct command_context *cmd_ctx, const char *cmd_name)
1150 {
1151         struct help_entry *curr;
1152
1153         list_for_each_entry(curr, cmd_ctx->help_list, lh) {
1154                 if (!strcmp(cmd_name, curr->cmd_name)) {
1155                         list_del(&curr->lh);
1156                         free(curr->cmd_name);
1157                         free(curr->help);
1158                         free(curr->usage);
1159                         free(curr);
1160                         break;
1161                 }
1162         }
1163
1164         return ERROR_OK;
1165 }
1166
1167 static int help_add_command(struct command_context *cmd_ctx,
1168         const char *cmd_name, const char *help_text, const char *usage_text)
1169 {
1170         int cmp = -1; /* add after curr */
1171         struct help_entry *curr;
1172
1173         list_for_each_entry_reverse(curr, cmd_ctx->help_list, lh) {
1174                 cmp = strcmp(cmd_name, curr->cmd_name);
1175                 if (cmp >= 0)
1176                         break;
1177         }
1178
1179         struct help_entry *entry;
1180         if (cmp) {
1181                 entry = calloc(1, sizeof(*entry));
1182                 if (!entry) {
1183                         LOG_ERROR("Out of memory");
1184                         return ERROR_FAIL;
1185                 }
1186                 entry->cmd_name = strdup(cmd_name);
1187                 if (!entry->cmd_name) {
1188                         LOG_ERROR("Out of memory");
1189                         free(entry);
1190                         return ERROR_FAIL;
1191                 }
1192                 list_add(&entry->lh, &curr->lh);
1193         } else {
1194                 entry = curr;
1195         }
1196
1197         if (help_text) {
1198                 char *text = strdup(help_text);
1199                 if (!text) {
1200                         LOG_ERROR("Out of memory");
1201                         return ERROR_FAIL;
1202                 }
1203                 free(entry->help);
1204                 entry->help = text;
1205         }
1206
1207         if (usage_text) {
1208                 char *text = strdup(usage_text);
1209                 if (!text) {
1210                         LOG_ERROR("Out of memory");
1211                         return ERROR_FAIL;
1212                 }
1213                 free(entry->usage);
1214                 entry->usage = text;
1215         }
1216
1217         return ERROR_OK;
1218 }
1219
1220 COMMAND_HANDLER(handle_help_add_command)
1221 {
1222         if (CMD_ARGC != 2)
1223                 return ERROR_COMMAND_SYNTAX_ERROR;
1224
1225         const char *help = !strcmp(CMD_NAME, "add_help_text") ? CMD_ARGV[1] : NULL;
1226         const char *usage = !strcmp(CMD_NAME, "add_usage_text") ? CMD_ARGV[1] : NULL;
1227         if (!help && !usage) {
1228                 LOG_ERROR("command name '%s' is unknown", CMD_NAME);
1229                 return ERROR_COMMAND_SYNTAX_ERROR;
1230         }
1231         const char *cmd_name = CMD_ARGV[0];
1232         return help_add_command(CMD_CTX, cmd_name, help, usage);
1233 }
1234
1235 /* sleep command sleeps for <n> milliseconds
1236  * this is useful in target startup scripts
1237  */
1238 COMMAND_HANDLER(handle_sleep_command)
1239 {
1240         bool busy = false;
1241         if (CMD_ARGC == 2) {
1242                 if (strcmp(CMD_ARGV[1], "busy") == 0)
1243                         busy = true;
1244                 else
1245                         return ERROR_COMMAND_SYNTAX_ERROR;
1246         } else if (CMD_ARGC < 1 || CMD_ARGC > 2)
1247                 return ERROR_COMMAND_SYNTAX_ERROR;
1248
1249         unsigned long duration = 0;
1250         int retval = parse_ulong(CMD_ARGV[0], &duration);
1251         if (ERROR_OK != retval)
1252                 return retval;
1253
1254         if (!busy) {
1255                 int64_t then = timeval_ms();
1256                 while (timeval_ms() - then < (int64_t)duration) {
1257                         target_call_timer_callbacks_now();
1258                         usleep(1000);
1259                 }
1260         } else
1261                 busy_sleep(duration);
1262
1263         return ERROR_OK;
1264 }
1265
1266 static const struct command_registration command_subcommand_handlers[] = {
1267         {
1268                 .name = "mode",
1269                 .mode = COMMAND_ANY,
1270                 .jim_handler = jim_command_mode,
1271                 .usage = "[command_name ...]",
1272                 .help = "Returns the command modes allowed by a command: "
1273                         "'any', 'config', or 'exec'. If no command is "
1274                         "specified, returns the current command mode. "
1275                         "Returns 'unknown' if an unknown command is given. "
1276                         "Command can be multiple tokens.",
1277         },
1278         COMMAND_REGISTRATION_DONE
1279 };
1280
1281 static const struct command_registration command_builtin_handlers[] = {
1282         {
1283                 .name = "ocd_find",
1284                 .mode = COMMAND_ANY,
1285                 .jim_handler = jim_find,
1286                 .help = "find full path to file",
1287                 .usage = "file",
1288         },
1289         {
1290                 .name = "capture",
1291                 .mode = COMMAND_ANY,
1292                 .jim_handler = jim_capture,
1293                 .help = "Capture progress output and return as tcl return value. If the "
1294                                 "progress output was empty, return tcl return value.",
1295                 .usage = "command",
1296         },
1297         {
1298                 .name = "echo",
1299                 .handler = jim_echo,
1300                 .mode = COMMAND_ANY,
1301                 .help = "Logs a message at \"user\" priority. "
1302                         "Output message to stdout. "
1303                         "Option \"-n\" suppresses trailing newline",
1304                 .usage = "[-n] string",
1305         },
1306         {
1307                 .name = "add_help_text",
1308                 .handler = handle_help_add_command,
1309                 .mode = COMMAND_ANY,
1310                 .help = "Add new command help text; "
1311                         "Command can be multiple tokens.",
1312                 .usage = "command_name helptext_string",
1313         },
1314         {
1315                 .name = "add_usage_text",
1316                 .handler = handle_help_add_command,
1317                 .mode = COMMAND_ANY,
1318                 .help = "Add new command usage text; "
1319                         "command can be multiple tokens.",
1320                 .usage = "command_name usage_string",
1321         },
1322         {
1323                 .name = "sleep",
1324                 .handler = handle_sleep_command,
1325                 .mode = COMMAND_ANY,
1326                 .help = "Sleep for specified number of milliseconds.  "
1327                         "\"busy\" will busy wait instead (avoid this).",
1328                 .usage = "milliseconds ['busy']",
1329         },
1330         {
1331                 .name = "help",
1332                 .handler = handle_help_command,
1333                 .mode = COMMAND_ANY,
1334                 .help = "Show full command help; "
1335                         "command can be multiple tokens.",
1336                 .usage = "[command_name]",
1337         },
1338         {
1339                 .name = "usage",
1340                 .handler = handle_help_command,
1341                 .mode = COMMAND_ANY,
1342                 .help = "Show basic command usage; "
1343                         "command can be multiple tokens.",
1344                 .usage = "[command_name]",
1345         },
1346         {
1347                 .name = "command",
1348                 .mode = COMMAND_ANY,
1349                 .help = "core command group (introspection)",
1350                 .chain = command_subcommand_handlers,
1351                 .usage = "",
1352         },
1353         COMMAND_REGISTRATION_DONE
1354 };
1355
1356 struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp)
1357 {
1358         struct command_context *context = calloc(1, sizeof(struct command_context));
1359         const char *HostOs;
1360
1361         context->mode = COMMAND_EXEC;
1362
1363         /* context can be duplicated. Put list head on separate mem-chunk to keep list consistent */
1364         context->help_list = malloc(sizeof(*context->help_list));
1365         INIT_LIST_HEAD(context->help_list);
1366
1367         /* Create a jim interpreter if we were not handed one */
1368         if (interp == NULL) {
1369                 /* Create an interpreter */
1370                 interp = Jim_CreateInterp();
1371                 /* Add all the Jim core commands */
1372                 Jim_RegisterCoreCommands(interp);
1373                 Jim_InitStaticExtensions(interp);
1374         }
1375
1376         context->interp = interp;
1377
1378         /* Stick to lowercase for HostOS strings. */
1379 #if defined(_MSC_VER)
1380         /* WinXX - is generic, the forward
1381          * looking problem is this:
1382          *
1383          *   "win32" or "win64"
1384          *
1385          * "winxx" is generic.
1386          */
1387         HostOs = "winxx";
1388 #elif defined(__linux__)
1389         HostOs = "linux";
1390 #elif defined(__APPLE__) || defined(__DARWIN__)
1391         HostOs = "darwin";
1392 #elif defined(__CYGWIN__)
1393         HostOs = "cygwin";
1394 #elif defined(__MINGW32__)
1395         HostOs = "mingw32";
1396 #elif defined(__ECOS)
1397         HostOs = "ecos";
1398 #elif defined(__FreeBSD__)
1399         HostOs = "freebsd";
1400 #elif defined(__NetBSD__)
1401         HostOs = "netbsd";
1402 #elif defined(__OpenBSD__)
1403         HostOs = "openbsd";
1404 #else
1405 #warning "Unrecognized host OS..."
1406         HostOs = "other";
1407 #endif
1408         Jim_SetGlobalVariableStr(interp, "ocd_HOSTOS",
1409                 Jim_NewStringObj(interp, HostOs, strlen(HostOs)));
1410
1411         register_commands(context, NULL, command_builtin_handlers);
1412
1413         Jim_SetAssocData(interp, "context", NULL, context);
1414         if (Jim_Eval_Named(interp, startup_tcl, "embedded:startup.tcl", 1) == JIM_ERR) {
1415                 LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD)");
1416                 Jim_MakeErrorMessage(interp);
1417                 LOG_USER_N("%s", Jim_GetString(Jim_GetResult(interp), NULL));
1418                 exit(-1);
1419         }
1420         Jim_DeleteAssocData(interp, "context");
1421
1422         return context;
1423 }
1424
1425 void command_exit(struct command_context *context)
1426 {
1427         if (!context)
1428                 return;
1429
1430         Jim_FreeInterp(context->interp);
1431         free(context->help_list);
1432         command_done(context);
1433 }
1434
1435 int command_context_mode(struct command_context *cmd_ctx, enum command_mode mode)
1436 {
1437         if (!cmd_ctx)
1438                 return ERROR_COMMAND_SYNTAX_ERROR;
1439
1440         cmd_ctx->mode = mode;
1441         return ERROR_OK;
1442 }
1443
1444 void process_jim_events(struct command_context *cmd_ctx)
1445 {
1446         static int recursion;
1447         if (recursion)
1448                 return;
1449
1450         recursion++;
1451         Jim_ProcessEvents(cmd_ctx->interp, JIM_ALL_EVENTS | JIM_DONT_WAIT);
1452         recursion--;
1453 }
1454
1455 #define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max) \
1456         int parse ## name(const char *str, type * ul) \
1457         { \
1458                 if (!*str) { \
1459                         LOG_ERROR("Invalid command argument"); \
1460                         return ERROR_COMMAND_ARGUMENT_INVALID; \
1461                 } \
1462                 char *end; \
1463                 errno = 0; \
1464                 *ul = func(str, &end, 0); \
1465                 if (*end) { \
1466                         LOG_ERROR("Invalid command argument"); \
1467                         return ERROR_COMMAND_ARGUMENT_INVALID; \
1468                 } \
1469                 if ((max == *ul) && (ERANGE == errno)) { \
1470                         LOG_ERROR("Argument overflow"); \
1471                         return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
1472                 } \
1473                 if (min && (min == *ul) && (ERANGE == errno)) { \
1474                         LOG_ERROR("Argument underflow"); \
1475                         return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
1476                 } \
1477                 return ERROR_OK; \
1478         }
1479 DEFINE_PARSE_NUM_TYPE(_ulong, unsigned long, strtoul, 0, ULONG_MAX)
1480 DEFINE_PARSE_NUM_TYPE(_ullong, unsigned long long, strtoull, 0, ULLONG_MAX)
1481 DEFINE_PARSE_NUM_TYPE(_long, long, strtol, LONG_MIN, LONG_MAX)
1482 DEFINE_PARSE_NUM_TYPE(_llong, long long, strtoll, LLONG_MIN, LLONG_MAX)
1483
1484 #define DEFINE_PARSE_WRAPPER(name, type, min, max, functype, funcname) \
1485         int parse ## name(const char *str, type * ul) \
1486         { \
1487                 functype n; \
1488                 int retval = parse ## funcname(str, &n); \
1489                 if (ERROR_OK != retval) \
1490                         return retval; \
1491                 if (n > max) \
1492                         return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
1493                 if (min) \
1494                         return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
1495                 *ul = n; \
1496                 return ERROR_OK; \
1497         }
1498
1499 #define DEFINE_PARSE_ULONGLONG(name, type, min, max) \
1500         DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long long, _ullong)
1501 DEFINE_PARSE_ULONGLONG(_uint, unsigned, 0, UINT_MAX)
1502 DEFINE_PARSE_ULONGLONG(_u64,  uint64_t, 0, UINT64_MAX)
1503 DEFINE_PARSE_ULONGLONG(_u32,  uint32_t, 0, UINT32_MAX)
1504 DEFINE_PARSE_ULONGLONG(_u16,  uint16_t, 0, UINT16_MAX)
1505 DEFINE_PARSE_ULONGLONG(_u8,   uint8_t,  0, UINT8_MAX)
1506
1507 DEFINE_PARSE_ULONGLONG(_target_addr, target_addr_t, 0, TARGET_ADDR_MAX)
1508
1509 #define DEFINE_PARSE_LONGLONG(name, type, min, max) \
1510         DEFINE_PARSE_WRAPPER(name, type, min, max, long long, _llong)
1511 DEFINE_PARSE_LONGLONG(_int, int,     n < INT_MIN,   INT_MAX)
1512 DEFINE_PARSE_LONGLONG(_s64, int64_t, n < INT64_MIN, INT64_MAX)
1513 DEFINE_PARSE_LONGLONG(_s32, int32_t, n < INT32_MIN, INT32_MAX)
1514 DEFINE_PARSE_LONGLONG(_s16, int16_t, n < INT16_MIN, INT16_MAX)
1515 DEFINE_PARSE_LONGLONG(_s8,  int8_t,  n < INT8_MIN,  INT8_MAX)
1516
1517 static int command_parse_bool(const char *in, bool *out,
1518         const char *on, const char *off)
1519 {
1520         if (strcasecmp(in, on) == 0)
1521                 *out = true;
1522         else if (strcasecmp(in, off) == 0)
1523                 *out = false;
1524         else
1525                 return ERROR_COMMAND_SYNTAX_ERROR;
1526         return ERROR_OK;
1527 }
1528
1529 int command_parse_bool_arg(const char *in, bool *out)
1530 {
1531         if (command_parse_bool(in, out, "on", "off") == ERROR_OK)
1532                 return ERROR_OK;
1533         if (command_parse_bool(in, out, "enable", "disable") == ERROR_OK)
1534                 return ERROR_OK;
1535         if (command_parse_bool(in, out, "true", "false") == ERROR_OK)
1536                 return ERROR_OK;
1537         if (command_parse_bool(in, out, "yes", "no") == ERROR_OK)
1538                 return ERROR_OK;
1539         if (command_parse_bool(in, out, "1", "0") == ERROR_OK)
1540                 return ERROR_OK;
1541         return ERROR_COMMAND_SYNTAX_ERROR;
1542 }
1543
1544 COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label)
1545 {
1546         switch (CMD_ARGC) {
1547                 case 1: {
1548                         const char *in = CMD_ARGV[0];
1549                         if (command_parse_bool_arg(in, out) != ERROR_OK) {
1550                                 LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME, in);
1551                                 return ERROR_COMMAND_SYNTAX_ERROR;
1552                         }
1553                 }
1554                         /* fallthrough */
1555                 case 0:
1556                         LOG_INFO("%s is %s", label, *out ? "enabled" : "disabled");
1557                         break;
1558                 default:
1559                         return ERROR_COMMAND_SYNTAX_ERROR;
1560         }
1561         return ERROR_OK;
1562 }