+ int retval;
+ char *cmd = (char*)Jim_GetString(argv[1], NULL);
+
+ Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
+
+ if (startLoop)
+ {
+ /* We don't know whether or not the telnet/gdb server is running... */
+ target_call_timer_callbacks_now();
+ }
+
+ log_add_callback(tcl_output, tclOutput);
+ retval=command_run_line_internal(active_cmd_ctx, cmd);
+
+ /* we need to be able to get at the retval, so we store in a variable
+ */
+ Jim_Obj *resultvar=Jim_NewIntObj(interp, retval);
+ Jim_IncrRefCount(resultvar);
+ Jim_SetGlobalVariableStr(interp, "openocd_result", resultvar);
+ Jim_DecrRefCount(interp, resultvar);
+
+ if (startLoop)
+ {
+ target_call_timer_callbacks_now();
+ }
+ log_remove_callback(tcl_output, tclOutput);
+
+ Jim_SetResult(interp, tclOutput);
+
+ return (ignore||(retval==ERROR_OK))?JIM_OK:JIM_ERR;
+}
+
+static int Jim_Command_openocd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return Jim_Command_openocd_ignore(interp, argc, argv, 1);
+}
+
+static int Jim_Command_openocd_throw(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return Jim_Command_openocd_ignore(interp, argc, argv, 0);
+}
+
+/* find full path to file */
+static int Jim_Command_find(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 2)
+ return JIM_ERR;
+ char *file = (char*)Jim_GetString(argv[1], NULL);
+ char *full_path = find_file(file);
+ if (full_path == NULL)
+ return JIM_ERR;
+ Jim_Obj *result = Jim_NewStringObj(interp, full_path, strlen(full_path));
+ free(full_path);
+
+ Jim_SetResult(interp, result);
+ return JIM_OK;
+}
+
+static int Jim_Command_echo(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 2)
+ return JIM_ERR;
+ char *str = (char*)Jim_GetString(argv[1], NULL);
+ LOG_USER("%s", str);
+ return JIM_OK;
+}
+
+static size_t openocd_jim_fwrite(const void *_ptr, size_t size, size_t n, void *cookie)
+{
+ size_t nbytes;
+ const char *ptr;
+
+ /* make it a char easier to read code */
+ ptr = _ptr;
+
+ nbytes = size * n;
+ if (nbytes == 0) {
+ return 0;
+ }
+
+ if (!active_cmd_ctx) {
+ /* 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(active_cmd_ctx, ptr);
+ return strlen(ptr);
+ }
+ /* GRR we must chunk - not null terminated */
+ while (nbytes) {
+ char chunk[128+1];
+ int x;
+
+ x = nbytes;
+ if (x > 128) {
+ x = 128;
+ }
+ /* copy it */
+ memcpy(chunk, ptr, x);
+ /* terminate it */
+ chunk[n] = 0;
+ /* output it */
+ command_output_text(active_cmd_ctx, chunk);
+ ptr += x;
+ nbytes -= x;
+ }
+
+ return n;
+}
+
+static size_t openocd_jim_fread(void *ptr, size_t size, size_t n, void *cookie )
+{
+ /* TCL wants to read... tell him no */
+ return 0;
+}
+
+static int openocd_jim_vfprintf(void *cookie, const char *fmt, va_list ap)
+{
+ char *cp;
+ int n;
+
+ n = -1;
+ if (active_cmd_ctx) {
+ cp = alloc_vprintf(fmt, ap);
+ if (cp) {
+ command_output_text(active_cmd_ctx, cp);
+ n = strlen(cp);
+ free(cp);
+ }
+ }
+ return n;
+}
+
+static int openocd_jim_fflush(void *cookie)
+{
+ /* nothing to flush */
+ return 0;
+}
+
+static char* openocd_jim_fgets(char *s, int size, void *cookie)
+{
+ /* not supported */
+ errno = ENOTSUP;
+ return NULL;
+}
+
+void add_jim(const char *name, int (*cmd)(Jim_Interp *interp, int argc, Jim_Obj *const *argv), const char *help)
+{
+ Jim_CreateCommand(interp, name, cmd, NULL, NULL);
+
+ /* FIX!!! it would be prettier to invoke add_help_text...
+ accumulate help text in Tcl helptext list. */
+ Jim_Obj *helptext=Jim_GetGlobalVariableStr(interp, "ocd_helptext", JIM_ERRMSG);
+ Jim_Obj *cmd_entry=Jim_NewListObj(interp, NULL, 0);
+
+ Jim_Obj *cmd_list=Jim_NewListObj(interp, NULL, 0);
+ Jim_ListAppendElement(interp, cmd_list, Jim_NewStringObj(interp, name, -1));
+
+ Jim_ListAppendElement(interp, cmd_entry, cmd_list);
+ Jim_ListAppendElement(interp, cmd_entry, Jim_NewStringObj(interp, help, -1));
+ Jim_ListAppendElement(interp, helptext, cmd_entry);
+}
+
+extern char binary_startup_tcl_start;
+extern char binary_startup_tcl_size;