fix error output a bit: do not repeat output printed during execution in case of...
[openocd.git] / src / helper / command.c
index 12827ecd9c66e15e4a4cb6450e838ea2cd12a25d..7ce7c2245d94768065f4d63470a5f932ef34cdc5 100644 (file)
@@ -2,6 +2,9 @@
  *   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)                      *
  *                                                                         *
@@ -31,6 +34,7 @@
 
 #include "log.h"
 #include "time_support.h"
+#include "jim-eventloop.h"
 
 #include <stdlib.h>
 #include <string.h>
@@ -55,12 +59,15 @@ static void tcl_output(void *privData, const char *file, int line, const char *f
        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;
@@ -71,42 +78,61 @@ static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        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, "ocd_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)
@@ -183,7 +209,7 @@ command_t* register_command(command_context_t *context, command_t *parent, char
        free((void *)full_name);
        
        /* we now need to add an overrideable proc */
-       const char *override_name=alloc_printf("proc %s%s%s {args} {return [eval \"ocd_%s%s%s $args\"]}", t1, t2, t3, t1, t2, t3);
+       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);
        
@@ -346,6 +372,7 @@ int run_command(command_context_t *context, command_t *c, char *words[], int num
        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;
        }
        
@@ -387,21 +414,28 @@ int command_run_line(command_context_t *context, char *line)
         * 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)
                {
@@ -509,7 +543,6 @@ static size_t openocd_jim_fwrite(const void *_ptr, size_t size, size_t n, void *
        size_t nbytes;
        const char *ptr;
        Jim_Interp *interp;
-       command_context_t *context;
 
        /* make it a char easier to read code */
        ptr = _ptr;
@@ -519,19 +552,11 @@ static size_t openocd_jim_fwrite(const void *_ptr, size_t size, size_t n, void *
                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 */
@@ -548,7 +573,7 @@ static size_t openocd_jim_fwrite(const void *_ptr, size_t size, size_t n, void *
                /* terminate it */
                chunk[n] = 0;
                /* output it */
-               command_output_text(context, chunk);
+               LOG_USER_N("%s", chunk);
                ptr += x;
                nbytes -= x;
        }
@@ -567,24 +592,16 @@ static int openocd_jim_vfprintf(void *cookie, const char *fmt, va_list ap)
        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);
        }
@@ -638,6 +655,9 @@ command_context_t* command_init()
        
        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)");
@@ -689,6 +709,20 @@ int handle_fast_command(struct command_context_s *cmd_ctx, char *cmd, char **arg
        return ERROR_OK;
 }
 
+void process_jim_events() 
+{
+#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);

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)