* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
+ * Copyright (C) 2007,2008 Øyvind Harboe *
+ * oyvind.harboe@zylin.com *
+ * *
* part of this file is taken from libcli (libcli.sourceforge.net) *
* Copyright (C) David Parrish (david@dparrish.com) *
* *
#include "log.h"
#include "time_support.h"
+#include "jim-eventloop.h"
#include <stdlib.h>
#include <string.h>
Jim_AppendString(interp, tclOutput, string, strlen(string));
}
+extern command_context_t *global_cmd_ctx;
+
+
static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
/* the private data is stashed in the interp structure */
command_t *c;
command_context_t *context;
- int *retval;
+ int retval;
int i;
int nwords;
char **words;
c = interp->cmdPrivData;
LOG_DEBUG("script_command - %s", c->name);
- nwords = argc;
- words = malloc(sizeof(char *) * nwords);
- for (i = 0; i < nwords; i++)
+ words = malloc(sizeof(char *) * argc);
+ for (i = 0; i < argc; i++)
{
int len;
-
- words[i] = strdup(Jim_GetString(argv[i], &len));
+ const char *w=Jim_GetString(argv[i], &len);
+ if (*w=='#')
+ {
+ /* hit an end of line comment */
+ break;
+ }
+ words[i] = strdup(w);
if (words[i] == NULL)
{
return JIM_ERR;
}
LOG_DEBUG("script_command - %s, argv[%u]=%s", c->name, i, words[i]);
}
+ nwords = i;
/* grab the command context from the associated data */
context = Jim_GetAssocData(interp, "context");
- retval = Jim_GetAssocData(interp, "retval");
- if (context != NULL && retval != NULL)
+ if (context == NULL)
{
- /* capture log output and return it */
- Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
- log_add_callback(tcl_output, tclOutput);
-
- *retval = run_command(context, c, words, nwords);
-
- log_remove_callback(tcl_output, tclOutput);
-
- /* We dump output into this local variable */
- Jim_SetVariableStr(interp, "openocd_output", tclOutput);
+ /* Tcl can invoke commands directly instead of via command_run_line(). This would
+ * happen when the Jim Tcl interpreter is provided by eCos.
+ */
+ context = global_cmd_ctx;
}
+
+ /* capture log output and return it */
+ Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
+ /* a garbage collect can happen, so we need a reference count to this object */
+ Jim_IncrRefCount(tclOutput);
+
+ log_add_callback(tcl_output, tclOutput);
+
+ retval = run_command(context, c, words, nwords);
+
+ log_remove_callback(tcl_output, tclOutput);
+
+ /* We dump output into this local variable */
+ Jim_SetResult(interp, tclOutput);
+ Jim_DecrRefCount(interp, tclOutput);
for (i = 0; i < nwords; i++)
free(words[i]);
free(words);
- return (*retval==ERROR_OK)?JIM_OK:JIM_ERR;
+ int *return_retval = Jim_GetAssocData(interp, "retval");
+ if (return_retval != NULL)
+ {
+ *return_retval = retval;
+ }
+
+ return (retval==ERROR_OK)?JIM_OK:JIM_ERR;
}
command_t* register_command(command_context_t *context, command_t *parent, char *name, int (*handler)(struct command_context_s *context, char* name, char** args, int argc), enum command_mode mode, char *help)
t2="_";
}
t3=c->name;
- const char *full_name=alloc_printf("%s%s%s", t1, t2, t3);
+ const char *full_name=alloc_printf("ocd_%s%s%s", t1, t2, t3);
Jim_CreateCommand(interp, full_name, script_command, c, NULL);
free((void *)full_name);
+ /* we now need to add an overrideable proc */
+ const char *override_name=alloc_printf("proc %s%s%s {args} {if {[catch {eval \"ocd_%s%s%s $args\"}]==0} {return \"\"} else { return -code error }", t1, t2, t3, t1, t2, t3);
+ Jim_Eval(interp, override_name);
+ free((void *)override_name);
+
/* accumulate help text in Tcl helptext list. */
Jim_Obj *helptext=Jim_GetGlobalVariableStr(interp, "ocd_helptext", JIM_ERRMSG);
if (Jim_IsShared(helptext))
if (!((context->mode == COMMAND_CONFIG) || (c->mode == COMMAND_ANY) || (c->mode == context->mode) ))
{
/* Config commands can not run after the config stage */
+ LOG_ERROR("Illegal mode for command");
return ERROR_FAIL;
}
* results
*/
/* run the line thru a script engine */
- int retval;
+ int retval=ERROR_FAIL;
int retcode;
- Jim_DeleteAssocData(interp, "context"); /* remove existing */
+ /* Beware! This code needs to be reentrant. It is also possible
+ * for OpenOCD commands to be invoked directly from Tcl. This would
+ * happen when the Jim Tcl interpreter is provided by eCos for
+ * instance.
+ */
+ Jim_DeleteAssocData(interp, "context");
retcode = Jim_SetAssocData(interp, "context", NULL, context);
- if (retcode != JIM_OK)
- return ERROR_FAIL;
-
- /* associated the return value */
- retval = ERROR_OK;
- Jim_DeleteAssocData(interp, "retval"); /* remove existing */
- retcode = Jim_SetAssocData(interp, "retval", NULL, &retval);
- if (retcode != JIM_OK)
- return ERROR_FAIL;
-
- retcode = Jim_Eval(interp, line);
+ if (retcode == JIM_OK)
+ {
+ /* associated the return value */
+ Jim_DeleteAssocData(interp, "retval");
+ retcode = Jim_SetAssocData(interp, "retval", NULL, &retval);
+ if (retcode == JIM_OK)
+ {
+ retcode = Jim_Eval(interp, line);
+
+ Jim_DeleteAssocData(interp, "retval");
+ }
+ Jim_DeleteAssocData(interp, "context");
+ }
if (retcode == JIM_ERR) {
if (retval!=ERROR_COMMAND_CLOSE_CONNECTION)
{
size_t nbytes;
const char *ptr;
Jim_Interp *interp;
- command_context_t *context;
/* make it a char easier to read code */
ptr = _ptr;
return 0;
}
- context = Jim_GetAssocData(interp, "context");
- if (context == NULL)
- {
- LOG_ERROR("openocd_jim_fwrite: no command context");
- /* TODO: Where should this go? */
- return n;
- }
-
/* do we have to chunk it? */
if (ptr[nbytes] == 0)
{
/* no it is a C style string */
- command_output_text(context, ptr);
+ LOG_USER_N("%s", ptr);
return strlen(ptr);
}
/* GRR we must chunk - not null terminated */
/* terminate it */
chunk[n] = 0;
/* output it */
- command_output_text(context, chunk);
+ LOG_USER_N("%s", chunk);
ptr += x;
nbytes -= x;
}
char *cp;
int n;
Jim_Interp *interp;
- command_context_t *context;
n = -1;
interp = cookie;
if (interp == NULL)
return n;
- context = Jim_GetAssocData(interp, "context");
- if (context == NULL)
- {
- LOG_ERROR("openocd_jim_vfprintf: no command context");
- return n;
- }
-
cp = alloc_vprintf(fmt, ap);
if (cp)
{
- command_output_text(context, cp);
+ LOG_USER_N("%s", cp);
n = strlen(cp);
free(cp);
}
Jim_RegisterCoreCommands(interp);
#endif
- Jim_CreateCommand(interp, "openocd_find", jim_find, NULL, NULL);
+ Jim_CreateCommand(interp, "ocd_find", jim_find, NULL, NULL);
Jim_CreateCommand(interp, "echo", jim_echo, NULL, NULL);
/* Set Jim's STDIO */
add_default_dirs();
+#ifdef JIM_EMBEDDED
+ Jim_EventLoopOnLoad(interp);
+#endif
if (Jim_Eval(interp, startup_tcl)==JIM_ERR)
{
LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD compile time)");
return ERROR_OK;
}
+void process_jim_events(void)
+{
+#ifdef JIM_EMBEDDED
+ static int recursion = 0;
+
+ if (!recursion)
+ {
+ recursion++;
+ Jim_ProcessEvents (interp, JIM_ALL_EVENTS|JIM_DONT_WAIT);
+ recursion--;
+ }
+#endif
+}
+
void register_jim(struct command_context_s *cmd_ctx, const char *name, int (*cmd)(Jim_Interp *interp, int argc, Jim_Obj *const *argv), const char *help)
{
Jim_CreateCommand(interp, name, cmd, NULL, NULL);