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.
 
 
 
 
 
 

1465 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. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 = (struct log_capture_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 : JIM_ERR;
  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(const char **words, unsigned nwords)
  127. {
  128. for (unsigned i = 0; i < nwords; i++)
  129. free((void *)words[i]);
  130. free(words);
  131. }
  132. static const char **script_command_args_alloc(
  133. unsigned argc, Jim_Obj * const *argv, unsigned *nwords)
  134. {
  135. const 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. const 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. if (c->name)
  259. free((void *)c->name);
  260. if (c->help)
  261. free((void *)c->help);
  262. if (c->usage)
  263. free((void *)c->usage);
  264. free(c);
  265. }
  266. static struct command *command_new(struct command_context *cmd_ctx,
  267. struct command *parent, const struct command_registration *cr)
  268. {
  269. assert(cr->name);
  270. /*
  271. * If it is a non-jim command with no .usage specified,
  272. * log an error.
  273. *
  274. * strlen(.usage) == 0 means that the command takes no
  275. * arguments.
  276. */
  277. if ((cr->jim_handler == NULL) && (cr->usage == NULL)) {
  278. LOG_DEBUG("BUG: command '%s%s%s' does not have the "
  279. "'.usage' field filled out",
  280. parent && parent->name ? parent->name : "",
  281. parent && parent->name ? " " : "",
  282. cr->name);
  283. }
  284. struct command *c = calloc(1, sizeof(struct command));
  285. if (NULL == c)
  286. return NULL;
  287. c->name = strdup(cr->name);
  288. if (cr->help)
  289. c->help = strdup(cr->help);
  290. if (cr->usage)
  291. c->usage = strdup(cr->usage);
  292. if (!c->name || (cr->help && !c->help) || (cr->usage && !c->usage))
  293. goto command_new_error;
  294. c->parent = parent;
  295. c->handler = cr->handler;
  296. c->jim_handler = cr->jim_handler;
  297. c->jim_handler_data = cr->jim_handler_data;
  298. c->mode = cr->mode;
  299. command_add_child(command_list_for_parent(cmd_ctx, parent), c);
  300. return c;
  301. command_new_error:
  302. command_free(c);
  303. return NULL;
  304. }
  305. static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
  306. static int register_command_handler(struct command_context *cmd_ctx,
  307. struct command *c)
  308. {
  309. Jim_Interp *interp = cmd_ctx->interp;
  310. const char *ocd_name = alloc_printf("ocd_%s", c->name);
  311. if (NULL == ocd_name)
  312. return JIM_ERR;
  313. LOG_DEBUG("registering '%s'...", ocd_name);
  314. Jim_CmdProc func = c->handler ? &script_command : &command_unknown;
  315. int retval = Jim_CreateCommand(interp, ocd_name, func, c, NULL);
  316. free((void *)ocd_name);
  317. if (JIM_OK != retval)
  318. return retval;
  319. /* we now need to add an overrideable proc */
  320. const char *override_name = alloc_printf(
  321. "proc %s {args} {eval ocd_bouncer %s $args}",
  322. c->name, c->name);
  323. if (NULL == override_name)
  324. return JIM_ERR;
  325. retval = Jim_Eval_Named(interp, override_name, 0, 0);
  326. free((void *)override_name);
  327. return retval;
  328. }
  329. struct command *register_command(struct command_context *context,
  330. struct command *parent, const struct command_registration *cr)
  331. {
  332. if (!context || !cr->name)
  333. return NULL;
  334. const char *name = cr->name;
  335. struct command **head = command_list_for_parent(context, parent);
  336. struct command *c = command_find(*head, name);
  337. if (NULL != c) {
  338. /* TODO: originally we treated attempting to register a cmd twice as an error
  339. * Sometimes we need this behaviour, such as with flash banks.
  340. * http://www.mail-archive.com/openocd-development@lists.berlios.de/msg11152.html */
  341. LOG_DEBUG("command '%s' is already registered in '%s' context",
  342. name, parent ? parent->name : "<global>");
  343. return c;
  344. }
  345. c = command_new(context, parent, cr);
  346. if (NULL == c)
  347. return NULL;
  348. int retval = ERROR_OK;
  349. if (NULL != cr->jim_handler && NULL == parent) {
  350. retval = Jim_CreateCommand(context->interp, cr->name,
  351. cr->jim_handler, cr->jim_handler_data, NULL);
  352. } else if (NULL != cr->handler || NULL != parent)
  353. retval = register_command_handler(context, command_root(c));
  354. if (ERROR_OK != retval) {
  355. unregister_command(context, parent, name);
  356. c = NULL;
  357. }
  358. return c;
  359. }
  360. int register_commands(struct command_context *cmd_ctx, struct command *parent,
  361. const struct command_registration *cmds)
  362. {
  363. int retval = ERROR_OK;
  364. unsigned i;
  365. for (i = 0; cmds[i].name || cmds[i].chain; i++) {
  366. const struct command_registration *cr = cmds + i;
  367. struct command *c = NULL;
  368. if (NULL != cr->name) {
  369. c = register_command(cmd_ctx, parent, cr);
  370. if (NULL == c) {
  371. retval = ERROR_FAIL;
  372. break;
  373. }
  374. }
  375. if (NULL != cr->chain) {
  376. struct command *p = c ? : parent;
  377. retval = register_commands(cmd_ctx, p, cr->chain);
  378. if (ERROR_OK != retval)
  379. break;
  380. }
  381. }
  382. if (ERROR_OK != retval) {
  383. for (unsigned j = 0; j < i; j++)
  384. unregister_command(cmd_ctx, parent, cmds[j].name);
  385. }
  386. return retval;
  387. }
  388. int unregister_all_commands(struct command_context *context,
  389. struct command *parent)
  390. {
  391. if (context == NULL)
  392. return ERROR_OK;
  393. struct command **head = command_list_for_parent(context, parent);
  394. while (NULL != *head) {
  395. struct command *tmp = *head;
  396. *head = tmp->next;
  397. command_free(tmp);
  398. }
  399. return ERROR_OK;
  400. }
  401. int unregister_command(struct command_context *context,
  402. struct command *parent, const char *name)
  403. {
  404. if ((!context) || (!name))
  405. return ERROR_COMMAND_SYNTAX_ERROR;
  406. struct command *p = NULL;
  407. struct command **head = command_list_for_parent(context, parent);
  408. for (struct command *c = *head; NULL != c; p = c, c = c->next) {
  409. if (strcmp(name, c->name) != 0)
  410. continue;
  411. if (p)
  412. p->next = c->next;
  413. else
  414. *head = c->next;
  415. command_free(c);
  416. return ERROR_OK;
  417. }
  418. return ERROR_OK;
  419. }
  420. void command_set_handler_data(struct command *c, void *p)
  421. {
  422. if (NULL != c->handler || NULL != c->jim_handler)
  423. c->jim_handler_data = p;
  424. for (struct command *cc = c->children; NULL != cc; cc = cc->next)
  425. command_set_handler_data(cc, p);
  426. }
  427. void command_output_text(struct command_context *context, const char *data)
  428. {
  429. if (context && context->output_handler && data)
  430. context->output_handler(context, data);
  431. }
  432. void command_print_sameline(struct command_context *context, const char *format, ...)
  433. {
  434. char *string;
  435. va_list ap;
  436. va_start(ap, format);
  437. string = alloc_vprintf(format, ap);
  438. if (string != NULL) {
  439. /* we want this collected in the log + we also want to pick it up as a tcl return
  440. * value.
  441. *
  442. * The latter bit isn't precisely neat, but will do for now.
  443. */
  444. LOG_USER_N("%s", string);
  445. /* We already printed it above
  446. * command_output_text(context, string); */
  447. free(string);
  448. }
  449. va_end(ap);
  450. }
  451. void command_print(struct command_context *context, const char *format, ...)
  452. {
  453. char *string;
  454. va_list ap;
  455. va_start(ap, format);
  456. string = alloc_vprintf(format, ap);
  457. if (string != NULL) {
  458. strcat(string, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one
  459. *char longer */
  460. /* we want this collected in the log + we also want to pick it up as a tcl return
  461. * value.
  462. *
  463. * The latter bit isn't precisely neat, but will do for now.
  464. */
  465. LOG_USER_N("%s", string);
  466. /* We already printed it above
  467. * command_output_text(context, string); */
  468. free(string);
  469. }
  470. va_end(ap);
  471. }
  472. static char *__command_name(struct command *c, char delim, unsigned extra)
  473. {
  474. char *name;
  475. unsigned len = strlen(c->name);
  476. if (NULL == c->parent) {
  477. /* allocate enough for the name, child names, and '\0' */
  478. name = malloc(len + extra + 1);
  479. strcpy(name, c->name);
  480. } else {
  481. /* parent's extra must include both the space and name */
  482. name = __command_name(c->parent, delim, 1 + len + extra);
  483. char dstr[2] = { delim, 0 };
  484. strcat(name, dstr);
  485. strcat(name, c->name);
  486. }
  487. return name;
  488. }
  489. char *command_name(struct command *c, char delim)
  490. {
  491. return __command_name(c, delim, 0);
  492. }
  493. static bool command_can_run(struct command_context *cmd_ctx, struct command *c)
  494. {
  495. return c->mode == COMMAND_ANY || c->mode == cmd_ctx->mode;
  496. }
  497. static int run_command(struct command_context *context,
  498. struct command *c, const char *words[], unsigned num_words)
  499. {
  500. if (!command_can_run(context, c)) {
  501. /* Many commands may be run only before/after 'init' */
  502. const char *when;
  503. switch (c->mode) {
  504. case COMMAND_CONFIG:
  505. when = "before";
  506. break;
  507. case COMMAND_EXEC:
  508. when = "after";
  509. break;
  510. /* handle the impossible with humor; it guarantees a bug report! */
  511. default:
  512. when = "if Cthulhu is summoned by";
  513. break;
  514. }
  515. LOG_ERROR("The '%s' command must be used %s 'init'.",
  516. c->name, when);
  517. return ERROR_FAIL;
  518. }
  519. struct command_invocation cmd = {
  520. .ctx = context,
  521. .current = c,
  522. .name = c->name,
  523. .argc = num_words - 1,
  524. .argv = words + 1,
  525. };
  526. int retval = c->handler(&cmd);
  527. if (retval == ERROR_COMMAND_SYNTAX_ERROR) {
  528. /* Print help for command */
  529. char *full_name = command_name(c, ' ');
  530. if (NULL != full_name) {
  531. command_run_linef(context, "usage %s", full_name);
  532. free(full_name);
  533. } else
  534. retval = -ENOMEM;
  535. } else if (retval == ERROR_COMMAND_CLOSE_CONNECTION) {
  536. /* just fall through for a shutdown request */
  537. } else if (retval != ERROR_OK) {
  538. /* we do not print out an error message because the command *should*
  539. * have printed out an error
  540. */
  541. LOG_DEBUG("Command failed with error code %d", retval);
  542. }
  543. return retval;
  544. }
  545. int command_run_line(struct command_context *context, char *line)
  546. {
  547. /* all the parent commands have been registered with the interpreter
  548. * so, can just evaluate the line as a script and check for
  549. * results
  550. */
  551. /* run the line thru a script engine */
  552. int retval = ERROR_FAIL;
  553. int retcode;
  554. /* Beware! This code needs to be reentrant. It is also possible
  555. * for OpenOCD commands to be invoked directly from Tcl. This would
  556. * happen when the Jim Tcl interpreter is provided by eCos for
  557. * instance.
  558. */
  559. Jim_Interp *interp = context->interp;
  560. Jim_DeleteAssocData(interp, "context");
  561. retcode = Jim_SetAssocData(interp, "context", NULL, context);
  562. if (retcode == JIM_OK) {
  563. /* associated the return value */
  564. Jim_DeleteAssocData(interp, "retval");
  565. retcode = Jim_SetAssocData(interp, "retval", NULL, &retval);
  566. if (retcode == JIM_OK) {
  567. retcode = Jim_Eval_Named(interp, line, 0, 0);
  568. Jim_DeleteAssocData(interp, "retval");
  569. }
  570. Jim_DeleteAssocData(interp, "context");
  571. }
  572. if (retcode == JIM_ERR) {
  573. if (retval != ERROR_COMMAND_CLOSE_CONNECTION) {
  574. /* We do not print the connection closed error message */
  575. Jim_MakeErrorMessage(interp);
  576. LOG_USER("%s", Jim_GetString(Jim_GetResult(interp), NULL));
  577. }
  578. if (retval == ERROR_OK) {
  579. /* It wasn't a low level OpenOCD command that failed */
  580. return ERROR_FAIL;
  581. }
  582. return retval;
  583. } else if (retcode == JIM_EXIT) {
  584. /* ignore.
  585. * exit(Jim_GetExitCode(interp)); */
  586. } else {
  587. const char *result;
  588. int reslen;
  589. result = Jim_GetString(Jim_GetResult(interp), &reslen);
  590. if (reslen > 0) {
  591. int i;
  592. char buff[256 + 1];
  593. for (i = 0; i < reslen; i += 256) {
  594. int chunk;
  595. chunk = reslen - i;
  596. if (chunk > 256)
  597. chunk = 256;
  598. strncpy(buff, result + i, chunk);
  599. buff[chunk] = 0;
  600. LOG_USER_N("%s", buff);
  601. }
  602. LOG_USER_N("\n");
  603. }
  604. retval = ERROR_OK;
  605. }
  606. return retval;
  607. }
  608. int command_run_linef(struct command_context *context, const char *format, ...)
  609. {
  610. int retval = ERROR_FAIL;
  611. char *string;
  612. va_list ap;
  613. va_start(ap, format);
  614. string = alloc_vprintf(format, ap);
  615. if (string != NULL) {
  616. retval = command_run_line(context, string);
  617. free(string);
  618. }
  619. va_end(ap);
  620. return retval;
  621. }
  622. void command_set_output_handler(struct command_context *context,
  623. command_output_handler_t output_handler, void *priv)
  624. {
  625. context->output_handler = output_handler;
  626. context->output_handler_priv = priv;
  627. }
  628. struct command_context *copy_command_context(struct command_context *context)
  629. {
  630. struct command_context *copy_context = malloc(sizeof(struct command_context));
  631. *copy_context = *context;
  632. return copy_context;
  633. }
  634. void command_done(struct command_context *cmd_ctx)
  635. {
  636. if (NULL == cmd_ctx)
  637. return;
  638. free(cmd_ctx);
  639. }
  640. /* find full path to file */
  641. static int jim_find(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
  642. {
  643. if (argc != 2)
  644. return JIM_ERR;
  645. const char *file = Jim_GetString(argv[1], NULL);
  646. char *full_path = find_file(file);
  647. if (full_path == NULL)
  648. return JIM_ERR;
  649. Jim_Obj *result = Jim_NewStringObj(interp, full_path, strlen(full_path));
  650. free(full_path);
  651. Jim_SetResult(interp, result);
  652. return JIM_OK;
  653. }
  654. COMMAND_HANDLER(jim_echo)
  655. {
  656. if (CMD_ARGC == 2 && !strcmp(CMD_ARGV[0], "-n")) {
  657. LOG_USER_N("%s", CMD_ARGV[1]);
  658. return JIM_OK;
  659. }
  660. if (CMD_ARGC != 1)
  661. return JIM_ERR;
  662. LOG_USER("%s", CMD_ARGV[0]);
  663. return JIM_OK;
  664. }
  665. /* Capture progress output and return as tcl return value. If the
  666. * progress output was empty, return tcl return value.
  667. */
  668. static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
  669. {
  670. if (argc != 2)
  671. return JIM_ERR;
  672. struct log_capture_state *state = command_log_capture_start(interp);
  673. /* disable polling during capture. This avoids capturing output
  674. * from polling.
  675. *
  676. * This is necessary in order to avoid accidentally getting a non-empty
  677. * string for tcl fn's.
  678. */
  679. bool save_poll = jtag_poll_get_enabled();
  680. jtag_poll_set_enabled(false);
  681. const char *str = Jim_GetString(argv[1], NULL);
  682. int retcode = Jim_Eval_Named(interp, str, __THIS__FILE__, __LINE__);
  683. jtag_poll_set_enabled(save_poll);
  684. command_log_capture_finish(state);
  685. return retcode;
  686. }
  687. static COMMAND_HELPER(command_help_find, struct command *head,
  688. struct command **out)
  689. {
  690. if (0 == CMD_ARGC)
  691. return ERROR_COMMAND_SYNTAX_ERROR;
  692. *out = command_find(head, CMD_ARGV[0]);
  693. if (NULL == *out && strncmp(CMD_ARGV[0], "ocd_", 4) == 0)
  694. *out = command_find(head, CMD_ARGV[0] + 4);
  695. if (NULL == *out)
  696. return ERROR_COMMAND_SYNTAX_ERROR;
  697. if (--CMD_ARGC == 0)
  698. return ERROR_OK;
  699. CMD_ARGV++;
  700. return CALL_COMMAND_HANDLER(command_help_find, (*out)->children, out);
  701. }
  702. static COMMAND_HELPER(command_help_show, struct command *c, unsigned n,
  703. bool show_help, const char *match);
  704. static COMMAND_HELPER(command_help_show_list, struct command *head, unsigned n,
  705. bool show_help, const char *match)
  706. {
  707. for (struct command *c = head; NULL != c; c = c->next)
  708. CALL_COMMAND_HANDLER(command_help_show, c, n, show_help, match);
  709. return ERROR_OK;
  710. }
  711. #define HELP_LINE_WIDTH(_n) (int)(76 - (2 * _n))
  712. static void command_help_show_indent(unsigned n)
  713. {
  714. for (unsigned i = 0; i < n; i++)
  715. LOG_USER_N(" ");
  716. }
  717. static void command_help_show_wrap(const char *str, unsigned n, unsigned n2)
  718. {
  719. const char *cp = str, *last = str;
  720. while (*cp) {
  721. const char *next = last;
  722. do {
  723. cp = next;
  724. do {
  725. next++;
  726. } while (*next != ' ' && *next != '\t' && *next != '\0');
  727. } while ((next - last < HELP_LINE_WIDTH(n)) && *next != '\0');
  728. if (next - last < HELP_LINE_WIDTH(n))
  729. cp = next;
  730. command_help_show_indent(n);
  731. LOG_USER("%.*s", (int)(cp - last), last);
  732. last = cp + 1;
  733. n = n2;
  734. }
  735. }
  736. static COMMAND_HELPER(command_help_show, struct command *c, unsigned n,
  737. bool show_help, const char *match)
  738. {
  739. char *cmd_name = command_name(c, ' ');
  740. if (NULL == cmd_name)
  741. return -ENOMEM;
  742. /* If the match string occurs anywhere, we print out
  743. * stuff for this command. */
  744. bool is_match = (strstr(cmd_name, match) != NULL) ||
  745. ((c->usage != NULL) && (strstr(c->usage, match) != NULL)) ||
  746. ((c->help != NULL) && (strstr(c->help, match) != NULL));
  747. if (is_match) {
  748. command_help_show_indent(n);
  749. LOG_USER_N("%s", cmd_name);
  750. }
  751. free(cmd_name);
  752. if (is_match) {
  753. if (c->usage) {
  754. LOG_USER_N(" ");
  755. command_help_show_wrap(c->usage, 0, n + 5);
  756. } else
  757. LOG_USER_N("\n");
  758. }
  759. if (is_match && show_help) {
  760. char *msg;
  761. /* Normal commands are runtime-only; highlight exceptions */
  762. if (c->mode != COMMAND_EXEC) {
  763. const char *stage_msg = "";
  764. switch (c->mode) {
  765. case COMMAND_CONFIG:
  766. stage_msg = " (configuration command)";
  767. break;
  768. case COMMAND_ANY:
  769. stage_msg = " (command valid any time)";
  770. break;
  771. default:
  772. stage_msg = " (?mode error?)";
  773. break;
  774. }
  775. msg = alloc_printf("%s%s", c->help ? : "", stage_msg);
  776. } else
  777. msg = alloc_printf("%s", c->help ? : "");
  778. if (NULL != msg) {
  779. command_help_show_wrap(msg, n + 3, n + 3);
  780. free(msg);
  781. } else
  782. return -ENOMEM;
  783. }
  784. if (++n > 5) {
  785. LOG_ERROR("command recursion exceeded");
  786. return ERROR_FAIL;
  787. }
  788. return CALL_COMMAND_HANDLER(command_help_show_list,
  789. c->children, n, show_help, match);
  790. }
  791. COMMAND_HANDLER(handle_help_command)
  792. {
  793. bool full = strcmp(CMD_NAME, "help") == 0;
  794. int retval;
  795. struct command *c = CMD_CTX->commands;
  796. char *match = NULL;
  797. if (CMD_ARGC == 0)
  798. match = "";
  799. else if (CMD_ARGC >= 1) {
  800. unsigned i;
  801. for (i = 0; i < CMD_ARGC; ++i) {
  802. if (NULL != match) {
  803. char *prev = match;
  804. match = alloc_printf("%s %s", match, CMD_ARGV[i]);
  805. free(prev);
  806. if (NULL == match) {
  807. LOG_ERROR("unable to build search string");
  808. return -ENOMEM;
  809. }
  810. } else {
  811. match = alloc_printf("%s", CMD_ARGV[i]);
  812. if (NULL == match) {
  813. LOG_ERROR("unable to build search string");
  814. return -ENOMEM;
  815. }
  816. }
  817. }
  818. } else
  819. return ERROR_COMMAND_SYNTAX_ERROR;
  820. retval = CALL_COMMAND_HANDLER(command_help_show_list,
  821. c, 0, full, match);
  822. if (CMD_ARGC >= 1)
  823. free(match);
  824. return retval;
  825. }
  826. static int command_unknown_find(unsigned argc, Jim_Obj *const *argv,
  827. struct command *head, struct command **out, bool top_level)
  828. {
  829. if (0 == argc)
  830. return argc;
  831. const char *cmd_name = Jim_GetString(argv[0], NULL);
  832. struct command *c = command_find(head, cmd_name);
  833. if (NULL == c && top_level && strncmp(cmd_name, "ocd_", 4) == 0)
  834. c = command_find(head, cmd_name + 4);
  835. if (NULL == c)
  836. return argc;
  837. *out = c;
  838. return command_unknown_find(--argc, ++argv, (*out)->children, out, false);
  839. }
  840. static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
  841. {
  842. const char *cmd_name = Jim_GetString(argv[0], NULL);
  843. if (strcmp(cmd_name, "unknown") == 0) {
  844. if (argc == 1)
  845. return JIM_OK;
  846. argc--;
  847. argv++;
  848. }
  849. script_debug(interp, cmd_name, argc, argv);
  850. struct command_context *cmd_ctx = current_command_context(interp);
  851. struct command *c = cmd_ctx->commands;
  852. int remaining = command_unknown_find(argc, argv, c, &c, true);
  853. /* if nothing could be consumed, then it's really an unknown command */
  854. if (remaining == argc) {
  855. const char *cmd = Jim_GetString(argv[0], NULL);
  856. LOG_ERROR("Unknown command:\n %s", cmd);
  857. return JIM_OK;
  858. }
  859. bool found = true;
  860. Jim_Obj *const *start;
  861. unsigned count;
  862. if (c->handler || c->jim_handler) {
  863. /* include the command name in the list */
  864. count = remaining + 1;
  865. start = argv + (argc - remaining - 1);
  866. } else {
  867. c = command_find(cmd_ctx->commands, "usage");
  868. if (NULL == c) {
  869. LOG_ERROR("unknown command, but usage is missing too");
  870. return JIM_ERR;
  871. }
  872. count = argc - remaining;
  873. start = argv;
  874. found = false;
  875. }
  876. /* pass the command through to the intended handler */
  877. if (c->jim_handler) {
  878. interp->cmdPrivData = c->jim_handler_data;
  879. return (*c->jim_handler)(interp, count, start);
  880. }
  881. return script_command_run(interp, count, start, c, found);
  882. }
  883. static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
  884. {
  885. struct command_context *cmd_ctx = current_command_context(interp);
  886. enum command_mode mode;
  887. if (argc > 1) {
  888. struct command *c = cmd_ctx->commands;
  889. int remaining = command_unknown_find(argc - 1, argv + 1, c, &c, true);
  890. /* if nothing could be consumed, then it's an unknown command */
  891. if (remaining == argc - 1) {
  892. Jim_SetResultString(interp, "unknown", -1);
  893. return JIM_OK;
  894. }
  895. mode = c->mode;
  896. } else
  897. mode = cmd_ctx->mode;
  898. const char *mode_str;
  899. switch (mode) {
  900. case COMMAND_ANY:
  901. mode_str = "any";
  902. break;
  903. case COMMAND_CONFIG:
  904. mode_str = "config";
  905. break;
  906. case COMMAND_EXEC:
  907. mode_str = "exec";
  908. break;
  909. default:
  910. mode_str = "unknown";
  911. break;
  912. }
  913. Jim_SetResultString(interp, mode_str, -1);
  914. return JIM_OK;
  915. }
  916. static int jim_command_type(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
  917. {
  918. if (1 == argc)
  919. return JIM_ERR;
  920. struct command_context *cmd_ctx = current_command_context(interp);
  921. struct command *c = cmd_ctx->commands;
  922. int remaining = command_unknown_find(argc - 1, argv + 1, c, &c, true);
  923. /* if nothing could be consumed, then it's an unknown command */
  924. if (remaining == argc - 1) {
  925. Jim_SetResultString(interp, "unknown", -1);
  926. return JIM_OK;
  927. }
  928. if (c->jim_handler)
  929. Jim_SetResultString(interp, "native", -1);
  930. else if (c->handler)
  931. Jim_SetResultString(interp, "simple", -1);
  932. else
  933. Jim_SetResultString(interp, "group", -1);
  934. return JIM_OK;
  935. }
  936. int help_add_command(struct command_context *cmd_ctx, struct command *parent,
  937. const char *cmd_name, const char *help_text, const char *usage)
  938. {
  939. struct command **head = command_list_for_parent(cmd_ctx, parent);
  940. struct command *nc = command_find(*head, cmd_name);
  941. if (NULL == nc) {
  942. /* add a new command with help text */
  943. struct command_registration cr = {
  944. .name = cmd_name,
  945. .mode = COMMAND_ANY,
  946. .help = help_text,
  947. .usage = usage,
  948. };
  949. nc = register_command(cmd_ctx, parent, &cr);
  950. if (NULL == nc) {
  951. LOG_ERROR("failed to add '%s' help text", cmd_name);
  952. return ERROR_FAIL;
  953. }
  954. LOG_DEBUG("added '%s' help text", cmd_name);
  955. return ERROR_OK;
  956. }
  957. if (help_text) {
  958. bool replaced = false;
  959. if (nc->help) {
  960. free((void *)nc->help);
  961. replaced = true;
  962. }
  963. nc->help = strdup(help_text);
  964. if (replaced)
  965. LOG_INFO("replaced existing '%s' help", cmd_name);
  966. else
  967. LOG_DEBUG("added '%s' help text", cmd_name);
  968. }
  969. if (usage) {
  970. bool replaced = false;
  971. if (nc->usage) {
  972. free((void *)nc->usage);
  973. replaced = true;
  974. }
  975. nc->usage = strdup(usage);
  976. if (replaced)
  977. LOG_INFO("replaced existing '%s' usage", cmd_name);
  978. else
  979. LOG_DEBUG("added '%s' usage text", cmd_name);
  980. }
  981. return ERROR_OK;
  982. }
  983. COMMAND_HANDLER(handle_help_add_command)
  984. {
  985. if (CMD_ARGC < 2) {
  986. LOG_ERROR("%s: insufficient arguments", CMD_NAME);
  987. return ERROR_COMMAND_SYNTAX_ERROR;
  988. }
  989. /* save help text and remove it from argument list */
  990. const char *str = CMD_ARGV[--CMD_ARGC];
  991. const char *help = !strcmp(CMD_NAME, "add_help_text") ? str : NULL;
  992. const char *usage = !strcmp(CMD_NAME, "add_usage_text") ? str : NULL;
  993. if (!help && !usage) {
  994. LOG_ERROR("command name '%s' is unknown", CMD_NAME);
  995. return ERROR_COMMAND_SYNTAX_ERROR;
  996. }
  997. /* likewise for the leaf command name */
  998. const char *cmd_name = CMD_ARGV[--CMD_ARGC];
  999. struct command *c = NULL;
  1000. if (CMD_ARGC > 0) {
  1001. c = CMD_CTX->commands;
  1002. int retval = CALL_COMMAND_HANDLER(command_help_find, c, &c);
  1003. if (ERROR_OK != retval)
  1004. return retval;
  1005. }
  1006. return help_add_command(CMD_CTX, c, cmd_name, help, usage);
  1007. }
  1008. /* sleep command sleeps for <n> milliseconds
  1009. * this is useful in target startup scripts
  1010. */
  1011. COMMAND_HANDLER(handle_sleep_command)
  1012. {
  1013. bool busy = false;
  1014. if (CMD_ARGC == 2) {
  1015. if (strcmp(CMD_ARGV[1], "busy") == 0)
  1016. busy = true;
  1017. else
  1018. return ERROR_COMMAND_SYNTAX_ERROR;
  1019. } else if (CMD_ARGC < 1 || CMD_ARGC > 2)
  1020. return ERROR_COMMAND_SYNTAX_ERROR;
  1021. unsigned long duration = 0;
  1022. int retval = parse_ulong(CMD_ARGV[0], &duration);
  1023. if (ERROR_OK != retval)
  1024. return retval;
  1025. if (!busy) {
  1026. long long then = timeval_ms();
  1027. while (timeval_ms() - then < (long long)duration) {
  1028. target_call_timer_callbacks_now();
  1029. usleep(1000);
  1030. }
  1031. } else
  1032. busy_sleep(duration);
  1033. return ERROR_OK;
  1034. }
  1035. static const struct command_registration command_subcommand_handlers[] = {
  1036. {
  1037. .name = "mode",
  1038. .mode = COMMAND_ANY,
  1039. .jim_handler = jim_command_mode,
  1040. .usage = "[command_name ...]",
  1041. .help = "Returns the command modes allowed by a command:"
  1042. "'any', 'config', or 'exec'. If no command is"
  1043. "specified, returns the current command mode. "
  1044. "Returns 'unknown' if an unknown command is given. "
  1045. "Command can be multiple tokens.",
  1046. },
  1047. {
  1048. .name = "type",
  1049. .mode = COMMAND_ANY,
  1050. .jim_handler = jim_command_type,
  1051. .usage = "command_name [...]",
  1052. .help = "Returns the type of built-in command:"
  1053. "'native', 'simple', 'group', or 'unknown'. "
  1054. "Command can be multiple tokens.",
  1055. },
  1056. COMMAND_REGISTRATION_DONE
  1057. };
  1058. static const struct command_registration command_builtin_handlers[] = {
  1059. {
  1060. .name = "echo",
  1061. .handler = jim_echo,
  1062. .mode = COMMAND_ANY,
  1063. .help = "Logs a message at \"user\" priority. "
  1064. "Output message to stdout. "
  1065. "Option \"-n\" suppresses trailing newline",
  1066. .usage = "[-n] string",
  1067. },
  1068. {
  1069. .name = "add_help_text",
  1070. .handler = handle_help_add_command,
  1071. .mode = COMMAND_ANY,
  1072. .help = "Add new command help text; "
  1073. "Command can be multiple tokens.",
  1074. .usage = "command_name helptext_string",
  1075. },
  1076. {
  1077. .name = "add_usage_text",
  1078. .handler = handle_help_add_command,
  1079. .mode = COMMAND_ANY,
  1080. .help = "Add new command usage text; "
  1081. "command can be multiple tokens.",
  1082. .usage = "command_name usage_string",
  1083. },
  1084. {
  1085. .name = "sleep",
  1086. .handler = handle_sleep_command,
  1087. .mode = COMMAND_ANY,
  1088. .help = "Sleep for specified number of milliseconds. "
  1089. "\"busy\" will busy wait instead (avoid this).",
  1090. .usage = "milliseconds ['busy']",
  1091. },
  1092. {
  1093. .name = "help",
  1094. .handler = handle_help_command,
  1095. .mode = COMMAND_ANY,
  1096. .help = "Show full command help; "
  1097. "command can be multiple tokens.",
  1098. .usage = "[command_name]",
  1099. },
  1100. {
  1101. .name = "usage",
  1102. .handler = handle_help_command,
  1103. .mode = COMMAND_ANY,
  1104. .help = "Show basic command usage; "
  1105. "command can be multiple tokens.",
  1106. .usage = "[command_name]",
  1107. },
  1108. {
  1109. .name = "command",
  1110. .mode = COMMAND_ANY,
  1111. .help = "core command group (introspection)",
  1112. .chain = command_subcommand_handlers,
  1113. },
  1114. COMMAND_REGISTRATION_DONE
  1115. };
  1116. struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp)
  1117. {
  1118. struct command_context *context = malloc(sizeof(struct command_context));
  1119. const char *HostOs;
  1120. context->mode = COMMAND_EXEC;
  1121. context->commands = NULL;
  1122. context->current_target = 0;
  1123. context->output_handler = NULL;
  1124. context->output_handler_priv = NULL;
  1125. /* Create a jim interpreter if we were not handed one */
  1126. if (interp == NULL) {
  1127. /* Create an interpreter */
  1128. interp = Jim_CreateInterp();
  1129. /* Add all the Jim core commands */
  1130. Jim_RegisterCoreCommands(interp);
  1131. Jim_InitStaticExtensions(interp);
  1132. }
  1133. context->interp = interp;
  1134. /* Stick to lowercase for HostOS strings. */
  1135. #if defined(_MSC_VER)
  1136. /* WinXX - is generic, the forward
  1137. * looking problem is this:
  1138. *
  1139. * "win32" or "win64"
  1140. *
  1141. * "winxx" is generic.
  1142. */
  1143. HostOs = "winxx";
  1144. #elif defined(__linux__)
  1145. HostOs = "linux";
  1146. #elif defined(__APPLE__) || defined(__DARWIN__)
  1147. HostOs = "darwin";
  1148. #elif defined(__CYGWIN__)
  1149. HostOs = "cygwin";
  1150. #elif defined(__MINGW32__)
  1151. HostOs = "mingw32";
  1152. #elif defined(__ECOS)
  1153. HostOs = "ecos";
  1154. #elif defined(__FreeBSD__)
  1155. HostOs = "freebsd";
  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_ULONG(name, type, min, max) \
  1235. DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long, _ulong)
  1236. DEFINE_PARSE_ULONG(_uint, unsigned, 0, UINT_MAX)
  1237. DEFINE_PARSE_ULONG(_u32, uint32_t, 0, UINT32_MAX)
  1238. DEFINE_PARSE_ULONG(_u16, uint16_t, 0, UINT16_MAX)
  1239. DEFINE_PARSE_ULONG(_u8, uint8_t, 0, UINT8_MAX)
  1240. #define DEFINE_PARSE_LONG(name, type, min, max) \
  1241. DEFINE_PARSE_WRAPPER(name, type, min, max, long, _long)
  1242. DEFINE_PARSE_LONG(_int, int, n < INT_MIN, INT_MAX)
  1243. DEFINE_PARSE_LONG(_s32, int32_t, n < INT32_MIN, INT32_MAX)
  1244. DEFINE_PARSE_LONG(_s16, int16_t, n < INT16_MIN, INT16_MAX)
  1245. DEFINE_PARSE_LONG(_s8, int8_t, n < INT8_MIN, INT8_MAX)
  1246. static int command_parse_bool(const char *in, bool *out,
  1247. const char *on, const char *off)
  1248. {
  1249. if (strcasecmp(in, on) == 0)
  1250. *out = true;
  1251. else if (strcasecmp(in, off) == 0)
  1252. *out = false;
  1253. else
  1254. return ERROR_COMMAND_SYNTAX_ERROR;
  1255. return ERROR_OK;
  1256. }
  1257. int command_parse_bool_arg(const char *in, bool *out)
  1258. {
  1259. if (command_parse_bool(in, out, "on", "off") == ERROR_OK)
  1260. return ERROR_OK;
  1261. if (command_parse_bool(in, out, "enable", "disable") == ERROR_OK)
  1262. return ERROR_OK;
  1263. if (command_parse_bool(in, out, "true", "false") == ERROR_OK)
  1264. return ERROR_OK;
  1265. if (command_parse_bool(in, out, "yes", "no") == ERROR_OK)
  1266. return ERROR_OK;
  1267. if (command_parse_bool(in, out, "1", "0") == ERROR_OK)
  1268. return ERROR_OK;
  1269. return ERROR_COMMAND_SYNTAX_ERROR;
  1270. }
  1271. COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label)
  1272. {
  1273. switch (CMD_ARGC) {
  1274. case 1: {
  1275. const char *in = CMD_ARGV[0];
  1276. if (command_parse_bool_arg(in, out) != ERROR_OK) {
  1277. LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME, in);
  1278. return ERROR_COMMAND_SYNTAX_ERROR;
  1279. }
  1280. /* fall through */
  1281. }
  1282. case 0:
  1283. LOG_INFO("%s is %s", label, *out ? "enabled" : "disabled");
  1284. break;
  1285. default:
  1286. return ERROR_COMMAND_SYNTAX_ERROR;
  1287. }
  1288. return ERROR_OK;
  1289. }