After I asked the question I had some more time to poke around in the Jacl
src.  No, it was never a feature it just seemed natural to me that it would
be, though.

I'll include some code snippets below to illustrate what I am doing.  This
was my thought:  When a user types a command, say "MyCommand," the interp
first checks internally for a definition.  Not finding it, it calls the
unknown proc.  The unknown proc attempts to resolve the name by first
attempting to load a class of this name.  If found, the class must, of
course, be an extension of Command.  If it's not or the class is not found,
the unknown proc then treats the command as an executable name and attempts
to run it.  (At this point we're in the original unknown proc provided with
Jacl.)

This works out great, by the way.  My application has a interactive command
line (wish-like).  I've named the majority of the commands through the
Extension feature.  However, the user may right their own commands to extend
the functionality of the application.  By removing the need for an Extension
for every Command, a class name becomes a command name.

Here's my unknown proc:

        rename unknown unknown_original

        set tcl_interactive 1

        proc unknown {args} {

           global classpath

           set name [lindex $args 0]
           set rtn [catch {cmdLoad -classpath [set classpath] $name} result]
           if { $rtn == 0 } {
              return [uplevel $name [lrange $args 1 end]]
           } else {
              #return [uplevel [concat unknown_original $args]]
              return -code error $result
           }
        }

Note that the call to unknown_original is commented out simply because of
the exec problems in the past.  I have not tried it w/ 1.2.4.

Here's the relevant source for the 'cmdLoad' command.  In order to get it to
work, I had to copy the entire TclLoadClass file into a local class since it
is not public.  Those are the only changes.  The cmdLoad also has a -reload
option which allows an already-loaded class (or command) to be updated
*while running*.  This is pretty handy during development of the command
itself.  I haven't used it in quite a while, though, so can't vouch for it's
functionality.



import tcl.lang.*;
import java.io.*;
import java.util.*;
import java.util.zip.*;

public class CatLoadCommand implements Command {

   private Argv __argv;
   private ArgvOpt __optReload;
   private ArgvOpt __optPath;
   private ArgvOpt __optClass;
   private ArgvOpt __optCommand;

   public void cmdProc( Interp tclInterp, TclObject[] args )
           throws TclException {

      CatInterp interp = (CatInterp) tclInterp;
      String className;
      String commandName;

      if ( ! parse( interp, args ) ) {
         interp.setResult( false );
         return;
         }

      className = __optClass.value.getString();
      if ( ! __optCommand.found ) {
         commandName = className;
      } else {
         commandName = __optCommand.value.getString();
      }

      try {
         TclObject path;
         if ( __optPath.found ) {
            path = TclList.newInstance();
            try {
               TclList.append( interp, path,



                     TclString.newInstance( __optPath.value.getString() ) );
            } catch ( TclException e ) {
               //empty
            }
         } else {
            path = null;
         }
         LocalTclClassLoader classLoader =
                  new LocalTclClassLoader( interp, path );
         if ( __optReload.found && __optReload.value.getBoolean() ) {
            classLoader.removeCache( className );
         }

         Class c = classLoader.loadClass( className, true );
         interp.createCommand( commandName, (Command) c.newInstance() );
         interp.setResult( true );
      } catch ( ClassNotFoundException e ) {
         interp.setResult( false );
         throw( new TclException( interp, "class not found" ) );
      } catch ( InstantiationException e ) {
         interp.setResult( false );
         throw( new TclException( interp, "instantiation" ) );
      } catch ( IllegalAccessException e ) {
         interp.setResult( false );
         throw( new TclException( interp, "illegal access" ) );
      } catch ( IllegalArgumentException e ) {
         interp.setResult( false );
         throw( new TclException( interp, "illegal argument" ) );
      }

      interp.setResult( true );
      return;
   }


   protected boolean parse( CatInterp interp, TclObject[] args ) {

      if ( __argv == null ) {
         __argv = new Argv( interp.getSystem(),
                  "CatLoadCommand", "$Id: CatLoadCommand.java,v 1.4
1999/09/03 15:20:14 mckay Exp $" );

         __optReload = new ArgvOptNArgsOpt( "Reload", "-reload [on | off]",
                  "Reload", "-reload", new ArgvValueBoolean() );
         __argv.addOpt( __optReload );
         __optPath = new ArgvOptVarArgs( "Class path", "-classpath $path",
                  "Class path", "-classpath", new ArgvValueString() );
         __argv.addOpt( __optPath );
         __optClass = new ArgvOptIsArg( "Class", "$class",
                  "Class name", new ArgvValueString() );
         __argv.addOpt( __optClass );
         __optCommand = new ArgvOptIsArg( "Command", "$command",
                  "Command name", new ArgvValueString() );
         __argv.addOpt( __optCommand );
         }

   __argv.setArgv( true, args );

   try {
      __argv.parse( interp );
   } catch ( ArgvException e ) {
      if ( e.type == ArgvException.OVERRIDE ) {
         __argv.handleStandard();
      } else {
         Catapult.getSystem().writeError( __argv.getName() + ": " +
                  e.getMessage() );
      }
      return( false );
   }
   if ( __argv.handleStandard() ) {
      return( false );
   }

   if ( ! __optClass.found ) {
      if ( __optClass.option != null ) {
         Catapult.getSystem().writeError( __argv.getName() + ": " +
                  "'" + __optClass.option + "' is a required argument" );
      } else if ( __optClass.getOptionDescription() != null ) {
         Catapult.getSystem().writeError( __argv.getName() + ": " +
                  "'" + __optClass.getOptionDescription() +
                  "' is a required argument" );
      }
      return( false );
   }

   /* Since the value is optional for the -reload option, we need to set
    * the value explicitly to true if the user didn't specify a value.
    */
   if ( __optReload.found && __optReload.value.numFound == 0 ) {
      try {
         __optReload.value.set( true );
      } catch ( TclException e ) {
         //empty
      }
   }

   return( true );
   }
}

----------------------------------------------------------------
The TclJava mailing list is sponsored by Scriptics Corporation.
To subscribe:    send mail to [EMAIL PROTECTED]  
                 with the word SUBSCRIBE as the subject.
To unsubscribe:  send mail to [EMAIL PROTECTED] 
                 with the word UNSUBSCRIBE as the subject.
To send to the list, send email to '[EMAIL PROTECTED]'. 

Reply via email to