You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1469 lines
39 KiB

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