+ struct log_capture_state *state = command_log_capture_start(interp);
+
+ /* disable polling during capture. This avoids capturing output
+ * from polling.
+ *
+ * This is necessary in order to avoid accidentally getting a non-empty
+ * string for tcl fn's.
+ */
+ bool save_poll = jtag_poll_get_enabled();
+
+ jtag_poll_set_enabled(false);
+
+ const char *str = Jim_GetString(argv[1], NULL);
+ int retcode = Jim_Eval_Named(interp, str, __THIS__FILE__, __LINE__);
+
+ jtag_poll_set_enabled(save_poll);
+
+ command_log_capture_finish(state);
+
+ return retcode;
+}
+
+static COMMAND_HELPER(command_help_find, struct command *head,
+ struct command **out)
+{
+ if (0 == CMD_ARGC)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ *out = command_find(head, CMD_ARGV[0]);
+ if (NULL == *out && strncmp(CMD_ARGV[0], "ocd_", 4) == 0)
+ *out = command_find(head, CMD_ARGV[0] + 4);
+ if (NULL == *out)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ if (--CMD_ARGC == 0)
+ return ERROR_OK;
+ CMD_ARGV++;
+ return CALL_COMMAND_HANDLER(command_help_find, (*out)->children, out);
+}
+
+static COMMAND_HELPER(command_help_show, struct command *c, unsigned n,
+ bool show_help, const char *cmd_match);
+
+static COMMAND_HELPER(command_help_show_list, struct command *head, unsigned n,
+ bool show_help, const char *cmd_match)
+{
+ for (struct command *c = head; NULL != c; c = c->next)
+ CALL_COMMAND_HANDLER(command_help_show, c, n, show_help, cmd_match);
+ return ERROR_OK;
+}
+
+#define HELP_LINE_WIDTH(_n) (int)(76 - (2 * _n))
+
+static void command_help_show_indent(unsigned n)
+{
+ for (unsigned i = 0; i < n; i++)
+ LOG_USER_N(" ");
+}
+static void command_help_show_wrap(const char *str, unsigned n, unsigned n2)
+{
+ const char *cp = str, *last = str;
+ while (*cp) {
+ const char *next = last;
+ do {
+ cp = next;
+ do {
+ next++;
+ } while (*next != ' ' && *next != '\t' && *next != '\0');
+ } while ((next - last < HELP_LINE_WIDTH(n)) && *next != '\0');
+ if (next - last < HELP_LINE_WIDTH(n))
+ cp = next;
+ command_help_show_indent(n);
+ LOG_USER("%.*s", (int)(cp - last), last);
+ last = cp + 1;
+ n = n2;
+ }
+}
+
+static COMMAND_HELPER(command_help_show, struct command *c, unsigned n,
+ bool show_help, const char *cmd_match)
+{
+ char *cmd_name = command_name(c, ' ');
+ if (NULL == cmd_name)
+ return ERROR_FAIL;
+
+ /* If the match string occurs anywhere, we print out
+ * stuff for this command. */
+ bool is_match = (strstr(cmd_name, cmd_match) != NULL) ||
+ ((c->usage != NULL) && (strstr(c->usage, cmd_match) != NULL)) ||
+ ((c->help != NULL) && (strstr(c->help, cmd_match) != NULL));
+
+ if (is_match) {
+ command_help_show_indent(n);
+ LOG_USER_N("%s", cmd_name);
+ }
+ free(cmd_name);
+
+ if (is_match) {
+ if (c->usage && strlen(c->usage) > 0) {
+ LOG_USER_N(" ");
+ command_help_show_wrap(c->usage, 0, n + 5);
+ } else
+ LOG_USER_N("\n");
+ }
+
+ if (is_match && show_help) {
+ char *msg;
+
+ /* Normal commands are runtime-only; highlight exceptions */
+ if (c->mode != COMMAND_EXEC) {
+ const char *stage_msg = "";
+
+ switch (c->mode) {
+ case COMMAND_CONFIG:
+ stage_msg = " (configuration command)";
+ break;
+ case COMMAND_ANY:
+ stage_msg = " (command valid any time)";
+ break;
+ default:
+ stage_msg = " (?mode error?)";
+ break;