Changing "exit" command in Tcl 
Author Message
 Changing "exit" command in Tcl

Hey all,

I finally got tcl/tk embedded in my application.  I had to hack up the
source code for both tcl and tk for it to work and I'm not sure if what I
did is the best way to do this.  My goal was to keep tcl and tk scripts from
quitting the main application when just the script called "exit" or the use
clicks on the "close window" button.  Basically, I just made the "exit"
command not call exit( ), but instead just return.  Now exit doesn't do
squat, but I can still kill a Tk app with {destroy .}, which as far as my
limited insight and testing can tell, quits the tk script without causing
problems.

(code snippets found below)

So my questions are these:

1) Is there a better way to go about doing this?

2) Will using {destroy .} leak memory if I use that instead of exit to quit
embedded Tk scripts?

I tried redefining the generic Tcl_Exit( ) function to just return a value
like TCL_OK, but I kept getting seg faults, so I switched to hacking the
main functions.  It seems like a lot of other stuff uses that function.

Thanks,

Dana Robinson

Here's what I changed in tcl/tk 8.3.3 on WinNT:

In tclMain.c, at the end of Tcl_Main ( )

    /*
     * Rather than calling exit, invoke the "exit" command so that
     * users can replace "exit" with some other command to do additional
     * cleanup on exit.  The Tcl_Eval call should never return.
     */

    done:
    if (commandPtr != NULL) {
 Tcl_DecrRefCount(commandPtr);
   }

// This line removed by Dana Robinson
// Since I changed the exit command to do nothing
// this really isn't necessary (I think)
//    sprintf(buffer, "exit %d", exitCode);

    Tcl_Eval(interp, buffer);

Quote:
}

In tkMain.c (at the end of Tk_MainEx)

    /*
     * Loop infinitely, waiting for commands to execute.  When there
     * are no windows left, Tk_MainLoop returns and we exit.
     */

    Tk_MainLoop();
    Tcl_DeleteInterp(interp);

    // Removed by DER
    //Tcl_Exit(0);

   // added by DER
    return;

Quote:
}

And in the tclCmdAH.c file

/*
 *----------------------------------------------------------------------
 *
 * Tcl_ExitObjCmd --
 *
 * This procedure is invoked to process the "exit" Tcl command.
 * See the user documentation for details on what it does.
 *
 * Results:
 * A standard Tcl object result.
 *
 * Side effects:
 * See the user documentation.
 *
 *----------------------------------------------------------------------
 */

 /* ARGSUSED */
int
Tcl_ExitObjCmd(dummy, interp, objc, objv)
    ClientData dummy;  /* Not used. */
    Tcl_Interp *interp;  /* Current interpreter. */
    int objc;   /* Number of arguments. */
    Tcl_Obj *CONST objv[]; /* Argument objects. */
{
    int value;

    if ((objc != 1) && (objc != 2)) {
 Tcl_WrongNumArgs(interp, 1, objv, "?returnCode?");
 return TCL_ERROR;
    }

    if (objc == 1) {
 value = 0;
    } else if (Tcl_GetIntFromObj(interp, objv[1], &value) != TCL_OK) {
 return TCL_ERROR;
    }

    //Commented out by DER
    //Tcl_Exit(value);

   // now we reach this part of the code
    /*NOTREACHED*/
    return TCL_OK;   /* Better not ever reach this! */

Quote:
}



Mon, 28 Jun 2004 19:23:02 GMT  
 Changing "exit" command in Tcl

Quote:

>Basically, I just made the "exit"
>command not call exit( ), but instead just return.  Now exit doesn't do
>squat, but I can still kill a Tk app with {destroy .}, which as far as my
>limited insight and testing can tell, quits the tk script without causing
>problems.

I don't know about Tk, but had the same problem with Tcl's "exit" inside
Vim.  I simply defined a new return code TCL_EXIT, then replaced the "exit"
and "catch" commands with custum versions that use this return code, and
used Tcl_AllowExceptions() to stop Tcl_Eval()/Tcl_EvalFile() from
complaining about this "unknown" return code:

                /* replace some standard Tcl commands */
                Tcl_DeleteCommand(interp, "exit");
                Tcl_CreateObjCommand(interp, "exit", exitcmd,
                        (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
                Tcl_DeleteCommand(interp, "catch");
                Tcl_CreateObjCommand(interp, "catch", catchcmd,
                        (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);

                Tcl_AllowExceptions(interp);
                err = Tcl_Eval(interp, script);

/*
 * Replace standard "exit" and "catch" commands.
 *
 * This is a design flaw in Tcl -  the standard "exit" command just calls
 * exit() and kills the application.  It should return TCL_EXIT to the
 * app, which then decides if it wants to terminate or not.  In our case,
 * we just delete the Tcl interpreter (and create a new one with the next
 * :tcl command).
 */
#define TCL_EXIT        5

/* ARGSUSED */
        static int
exitcmd(dummy, interp, objc, objv)
        ClientData dummy;
        Tcl_Interp *interp;
        int objc;
        Tcl_Obj *CONST objv[];
{
        int value = 0;

        switch (objc)
        {
                case 2:
                        if (Tcl_GetIntFromObj(interp, objv[1], &value) != TCL_OK)
                                break;
                        /* FALLTHROUGH */
                case 1:
                        Tcl_SetObjResult(interp, Tcl_NewIntObj(value));
                        return TCL_EXIT;
                default:
                        Tcl_WrongNumArgs(interp, 1, objv, "?returnCode?");
        }
        return TCL_ERROR;

Quote:
}

/* ARGSUSED */
        static int
catchcmd(dummy, interp, objc, objv)
        ClientData      dummy;
        Tcl_Interp      *interp;
        int                     objc;
        Tcl_Obj         *CONST objv[];
{
        char    *varname = NULL;
        int             result;

        switch (objc)
        {
                case 3:
                        varname = Tcl_GetStringFromObj(objv[2], NULL);
                        /* fallthrough */
                case 2:
                        Tcl_ResetResult(interp);
                        Tcl_AllowExceptions(interp);
                        result = Tcl_EvalObj(interp, objv[1]);
                        if (result == TCL_EXIT)
                                return result;
                        if (varname)
                        {
                                if (Tcl_SetVar(interp, varname, Tcl_GetStringResult(interp), 0) == NULL)
                                {
                                        Tcl_SetResult(interp, "couldn't save command result in variable", TCL_STATIC);
                                        return TCL_ERROR;
                                }
                        }
                        Tcl_SetObjResult(interp, Tcl_NewIntObj(result));
                        return TCL_OK;
                default:
                        Tcl_WrongNumArgs(interp, 1, objv, "command ?varName?");
        }
        return TCL_ERROR;

Quote:
}

Regards,
Ingo
--
PGP&GnuPG keys: http://www.informatik.uni-oldenburg.de/~ingo/{pgp|gpg}key.asc
"There's an inverse relationship between how good something is for you,
 and how much fun it is." -- Calvin


Mon, 28 Jun 2004 20:51:26 GMT  
 Changing "exit" command in Tcl

Quote:

> Hey all,
> I finally got tcl/tk embedded in my application. I had to hack up the
> source code for both tcl and tk for it to work and I'm not sure if
> what I did is the best way to do this. My goal was to keep tcl and tk
> scripts from quitting the main application when just the script called
> "exit" or the use clicks on the "close window" button. Basically,
> I just made the "exit" command not call exit( ), but instead just
> return. Now exit doesn't do squat, but I can still kill a Tk app with
> {destroy .}, which as far as my limited insight and testing can tell,
> quits the tk script without causing problems.

Here is simple but working solution:

proc save_and_quit args {
        puts "Do nothing!"

Quote:
}

proc exit {args} {save_and_quit}
wm protocol . WM_DELETE_WINDOW save_and_quit


Mon, 28 Jun 2004 20:56:03 GMT  
 Changing "exit" command in Tcl

Quote:

> I finally got tcl/tk embedded in my application.  I had to hack up the
> source code for both tcl and tk for it to work

That should not have been necessary, but if it got you something
that works, well, a bonus for open source.  I won't argue with
a working solution, but here's some tips on how to revise the
solution to work better with other Tcl-based code.

From your descriptions, it's clear that Tcl_Main() and Tk_Main() do
not suit your needs, so you should not use them.  Instead, you
should copy them to another routine My_Main() and modify that till
it does what you want.

Quote:
> My goal was to keep tcl and tk scripts from
> quitting the main application when just the script called "exit" or the use
> clicks on the "close window" button.  Basically, I just made the "exit"
> command not call exit( ), but instead just return.  

If any Tcl command ([exit], in this example) does something you
don't like, replace it with an implementation that you like
better.  No need to hack the Tcl sources to do that.  Just use
Tcl_CreateCommand(), or even easier [proc].  [*]

As far as cleanup goes, if you are done with the Tcl library
completely, but do not want to exit your program, be sure to
call Tcl_Finalize() to free resources.  More likely, you will
be using Tcl for a while (say to eval one script), then you
won't for a while, then you'll use it again, etc.  In that case,
the best (simplest) approach, is probably to create a new Tcl
interp (Tcl_CreateInterp()) each time you start up again with
Tcl.  Then delete that interp when you are done for a while
(Tcl_DeleteInterp()).  And make use of Tcl_CallWhenDeleted() to be
sure any cleanup routines get called when the interp is deleted.

[*] Do be careful with this.  If you make any use of third-party
code, that code will be expecting Tcl's commands to have their
original meanings, so write your replacements accordingly.

--
| Don Porter          Mathematical and Computational Sciences Division |

| http://math.nist.gov/~DPorter/                                  NIST |
|______________________________________________________________________|



Tue, 29 Jun 2004 00:16:41 GMT  
 
 [ 4 post ] 

 Relevant Pages 

1. Tcl "expr" command change suggestion

2. Embedding Tcl -- "exit" and proper cleanup

3. tcl command "type"

4. Tcl "source" command

5. Tcl command "load" under AIX 4.15

6. Tcl command "load" under AIX 4.15

7. "scope" command in [incr Tcl]

8. Problem with "scan" command in tcl

9. Tcl "autopath" command

10. Questions/problems with Tcl "exec" command

11. string.join(["Tk 4.2p2", "Python 1.4", "Win32", "free"], "for")

12. What replaces "EXIT"?

 

 
Powered by phpBB® Forum Software