From: adrianho@barkley.berkeley.edu (Adrian J Ho)
Newsgroups: comp.lang.tcl
Subject: Re: How do I imbed tcl in an application
Date: 29 Jul 92 20:17:30
Organization: University of California, Berkeley
	<ADRIANHO.92Jul27175403@barkley.berkeley.edu>
	<1992Jul28.113922.19882@cas.org>,<156g6sINNnp2@agate.berkeley.edu>
	<1992Jul29.222557.7305@cpu.com>
NNTP-Posting-Host: barkley.berkeley.edu
In-reply-to: gwlester@cpu.com's message of Wed, 29 Jul 1992 22:25:57 GMT

In article <1992Jul29.222557.7305@cpu.com> gwlester@cpu.com (Gerald W. Lester) writes:
>You could also rename string to something else (eg string_org) than add
>a proc called string that sees if the "command" is an extended command (like
>"remove" in your example above), if so it would process it, otherwise it would
>do an uplevel on "string_orig $args".  I know it is "cheating", but it works.

True, but in a very dangerous fashion.  Suppose you and I published
new suboptions to the "canvas" widget that do, say, pixmap and 3D
polygon drawing respectively.  Unless the user (manually) rolls the
two sets of suboptions together into a single suboption package, the
original widget code would become inaccessible from the command level.

Of course, you could do a recursive renaming, but then the overhead of
crawling through 20 different "canvas{_orig}*" suboption wrappers
(mostly at the Tcl level) just to use one of the *original* "canvas"
suboptions could become pretty high.  Suboption namespace collisions
are also next to impossible to handle cleanly in this fashion.

IMHO, a neater way is to modify the Tcl library to allow for the
specification and storage of subcommand descriptors.  Properly done, a
Tcl programmer would be able to create a theoretically infinite tree
of subcommands without changing the programming interface a single
bit, like this:

Tcl_CreateCommand(interp, "string remove", Tcl_StringRemoveCmd,
		  clientData, deleteProc);

Support can also be designed in to handle namespace collisions.
Here's how I'd implement it:
-----
(0) Change the definition of struct Command (in tclInt.h) to:

typedef struct Command {
    Tcl_CmdProc *proc;          /* Procedure to process command. */
    ClientData clientData;      /* Arbitrary value to pass to proc. */
    Tcl_CmdDeleteProc *deleteProc;
                                /* Procedure to invoke when deleting
                                 * command. */
    int is_subproc;             /* Flag to denote subprocs underneath */
    Tcl_HashTable subprocs;     /* Table of Command structs pointing
                                 * to suboptions */
} Command;

(1) Modify Tcl_CreateCommand() to:
    (a) logically divide the cmdName argument (eg. "string remove")
        into space-delimited command words
    (b) create an entry in the main commandTable for the first word if
        it doesn't exist, and an empty Command struct
    (c) while there are command words left, set is_subproc to TRUE and
        insert a pointer to a new Command struct in the subprocs hash
        table with the next command word as key.  (if the key already
        exists, and is_subproc == FALSE, signal a namespace collision,
        else use that struct as the next link in the chain)
    (d) [no more command words] set is_subproc to FALSE and fill in
        the other fields as per normal

(2) Modify Tcl_Eval() to:
    (a) decompose the cmd argument into words and walk down the
        Command tree as far as possible
    (b) when a leaf Command is reached (ie. is_subproc == FALSE),
        execute the proc as per normal
-----
I've left out quite a few details, but there should be enough in there
to enable anyone to patch the sources themselves.
--
-----------------------------------------------------------------------------
Adrian Ho, He With The Embarrassingly *Dead* Passion ** Phone: (510) 642-5563
System Manager, CFD Lab, ME Dept, UC Berkeley * adrianho@barkley.berkeley.edu
Maintainer, Tcl/Tk Contrib Archive ---- barkley.berkeley.edu [128.32.142.237]
  Send all Tcl/Tk Archive-related stuff to tcl-archive@barkley.berkeley.edu
Newsgroups: comp.lang.tcl