/* * InfoCmd.java * * Copyright (c) 1997 Cornell University. * Copyright (c) 1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and * redistribution of this file, and for a DISCLAIMER OF ALL * WARRANTIES. * * Included in SQLite3 port to C# for use in testharness only; 2008 Noah B Hart * * RCS @(#) $Id: InfoCmd.java,v 1.8 2001/11/16 23:57:13 mdejong Exp $ * */ using System; using System.Collections; namespace tcl.lang { /// This class implements the built-in "info" command in Tcl. class InfoCmd : Command { private static readonly string[] validCmds = new string[] { "args", "body", "cmdcount", "commands", "complete", "default", "exists", "globals", "hostname", "level", "library", "loaded", "locals", "nameofexecutable", "patchlevel", "procs", "script", "sharedlibextension", "tclversion", "vars" }; internal const int OPT_ARGS = 0; internal const int OPT_BODY = 1; internal const int OPT_CMDCOUNT = 2; internal const int OPT_COMMANDS = 3; internal const int OPT_COMPLETE = 4; internal const int OPT_DEFAULT = 5; internal const int OPT_EXISTS = 6; internal const int OPT_GLOBALS = 7; internal const int OPT_HOSTNAME = 8; internal const int OPT_LEVEL = 9; internal const int OPT_LIBRARY = 10; internal const int OPT_LOADED = 11; internal const int OPT_LOCALS = 12; internal const int OPT_NAMEOFEXECUTABLE = 13; internal const int OPT_PATCHLEVEL = 14; internal const int OPT_PROCS = 15; internal const int OPT_SCRIPT = 16; internal const int OPT_SHAREDLIBEXTENSION = 17; internal const int OPT_TCLVERSION = 18; internal const int OPT_VARS = 19; /// Tcl_InfoObjCmd -> InfoCmd.cmdProc /// /// This procedure is invoked to process the "info" Tcl command. /// See the user documentation for details on what it does. /// /// /// the current interpreter. /// /// command arguments. /// /// TclException if wrong # of args or invalid argument(s). /// public TCL.CompletionCode cmdProc( Interp interp, TclObject[] objv ) { int index; if ( objv.Length < 2 ) { throw new TclNumArgsException( interp, 1, objv, "option ?arg arg ...?" ); } index = TclIndex.get( interp, objv[1], validCmds, "option", 0 ); switch ( index ) { case OPT_ARGS: InfoArgsCmd( interp, objv ); break; case OPT_BODY: InfoBodyCmd( interp, objv ); break; case OPT_CMDCOUNT: InfoCmdCountCmd( interp, objv ); break; case OPT_COMMANDS: InfoCommandsCmd( interp, objv ); break; case OPT_COMPLETE: InfoCompleteCmd( interp, objv ); break; case OPT_DEFAULT: InfoDefaultCmd( interp, objv ); break; case OPT_EXISTS: InfoExistsCmd( interp, objv ); break; case OPT_GLOBALS: InfoGlobalsCmd( interp, objv ); break; case OPT_HOSTNAME: InfoHostnameCmd( interp, objv ); break; case OPT_LEVEL: InfoLevelCmd( interp, objv ); break; case OPT_LIBRARY: InfoLibraryCmd( interp, objv ); break; case OPT_LOADED: InfoLoadedCmd( interp, objv ); break; case OPT_LOCALS: InfoLocalsCmd( interp, objv ); break; case OPT_NAMEOFEXECUTABLE: InfoNameOfExecutableCmd( interp, objv ); break; case OPT_PATCHLEVEL: InfoPatchLevelCmd( interp, objv ); break; case OPT_PROCS: InfoProcsCmd( interp, objv ); break; case OPT_SCRIPT: InfoScriptCmd( interp, objv ); break; case OPT_SHAREDLIBEXTENSION: InfoSharedlibCmd( interp, objv ); break; case OPT_TCLVERSION: InfoTclVersionCmd( interp, objv ); break; case OPT_VARS: InfoVarsCmd( interp, objv ); break; } return TCL.CompletionCode.RETURN; } /* *---------------------------------------------------------------------- * * InfoArgsCmd -- * * Called to implement the "info args" command that returns the * argument list for a procedure. Handles the following syntax: * * info args procName * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoArgsCmd( Interp interp, TclObject[] objv ) { string name; Procedure proc; TclObject listObj; if ( objv.Length != 3 ) { throw new TclNumArgsException( interp, 2, objv, "procname" ); } name = objv[2].ToString(); proc = Procedure.findProc( interp, name ); if ( proc == null ) { throw new TclException( interp, "\"" + name + "\" isn't a procedure" ); } // Build a return list containing the arguments. listObj = TclList.newInstance(); for ( int i = 0; i < proc.argList.Length; i++ ) { TclObject s = TclString.newInstance( proc.argList[i][0] ); TclList.append( interp, listObj, s ); } interp.setResult( listObj ); return; } /* *---------------------------------------------------------------------- * * InfoBodyCmd -- * * Called to implement the "info body" command that returns the body * for a procedure. Handles the following syntax: * * info body procName * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoBodyCmd( Interp interp, TclObject[] objv ) { string name; Procedure proc; //TclObject body, result; if ( objv.Length != 3 ) { throw new TclNumArgsException( interp, 2, objv, "procname" ); } name = objv[2].ToString(); proc = Procedure.findProc( interp, name ); if ( proc == null ) { throw new TclException( interp, "\"" + name + "\" isn't a procedure" ); } interp.setResult( proc.body.ToString() ); return; } /* *---------------------------------------------------------------------- * * InfoCmdCountCmd -- * * Called to implement the "info cmdcount" command that returns the * number of commands that have been executed. Handles the following * syntax: * * info cmdcount * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoCmdCountCmd( Interp interp, TclObject[] objv ) { if ( objv.Length != 2 ) { throw new TclNumArgsException( interp, 2, objv, null ); } interp.setResult( interp.cmdCount ); return; } /* *---------------------------------------------------------------------- * * InfoCommandsCmd -- * * Called to implement the "info commands" command that returns the * list of commands in the interpreter that match an optional pattern. * The pattern, if any, consists of an optional sequence of namespace * names separated by "::" qualifiers, which is followed by a * glob-style pattern that restricts which commands are returned. * Handles the following syntax: * * info commands ?pattern? * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoCommandsCmd( Interp interp, TclObject[] objv ) { string cmdName, pattern, simplePattern; IDictionaryEnumerator search; NamespaceCmd.Namespace ns; NamespaceCmd.Namespace globalNs = NamespaceCmd.getGlobalNamespace( interp ); NamespaceCmd.Namespace currNs = NamespaceCmd.getCurrentNamespace( interp ); TclObject list, elemObj; bool specificNsInPattern = false; // Init. to avoid compiler warning. WrappedCommand cmd; // Get the pattern and find the "effective namespace" in which to // list commands. if ( objv.Length == 2 ) { simplePattern = null; ns = currNs; specificNsInPattern = false; } else if ( objv.Length == 3 ) { // From the pattern, get the effective namespace and the simple // pattern (no namespace qualifiers or ::'s) at the end. If an // error was found while parsing the pattern, return it. Otherwise, // if the namespace wasn't found, just leave ns NULL: we will // return an empty list since no commands there can be found. pattern = objv[2].ToString(); // Java does not support passing an address so we pass // an array of size 1 and then assign arr[0] to the value NamespaceCmd.Namespace[] nsArr = new NamespaceCmd.Namespace[1]; NamespaceCmd.Namespace[] dummy1Arr = new NamespaceCmd.Namespace[1]; NamespaceCmd.Namespace[] dummy2Arr = new NamespaceCmd.Namespace[1]; string[] simplePatternArr = new string[1]; NamespaceCmd.getNamespaceForQualName( interp, pattern, null, 0, nsArr, dummy1Arr, dummy2Arr, simplePatternArr ); // Get the values out of the arrays! ns = nsArr[0]; simplePattern = simplePatternArr[0]; if ( ns != null ) { // we successfully found the pattern's ns specificNsInPattern = ( simplePattern.CompareTo( pattern ) != 0 ); } } else { throw new TclNumArgsException( interp, 2, objv, "?pattern?" ); } // Scan through the effective namespace's command table and create a // list with all commands that match the pattern. If a specific // namespace was requested in the pattern, qualify the command names // with the namespace name. list = TclList.newInstance(); if ( ns != null ) { search = ns.cmdTable.GetEnumerator(); while ( search.MoveNext() ) { cmdName = ( (string)search.Key ); if ( ( (System.Object)simplePattern == null ) || Util.stringMatch( cmdName, simplePattern ) ) { if ( specificNsInPattern ) { cmd = (WrappedCommand)search.Value; elemObj = TclString.newInstance( interp.getCommandFullName( cmd ) ); } else { elemObj = TclString.newInstance( cmdName ); } TclList.append( interp, list, elemObj ); } } // If the effective namespace isn't the global :: namespace, and a // specific namespace wasn't requested in the pattern, then add in // all global :: commands that match the simple pattern. Of course, // we add in only those commands that aren't hidden by a command in // the effective namespace. if ( ( ns != globalNs ) && !specificNsInPattern ) { search = globalNs.cmdTable.GetEnumerator(); while ( search.MoveNext() ) { cmdName = ( (string)search.Key ); if ( ( (System.Object)simplePattern == null ) || Util.stringMatch( cmdName, simplePattern ) ) { if ( ns.cmdTable[cmdName] == null ) { TclList.append( interp, list, TclString.newInstance( cmdName ) ); } } } } } interp.setResult( list ); return; } /* *---------------------------------------------------------------------- * * InfoCompleteCmd -- * * Called to implement the "info complete" command that determines * whether a string is a complete Tcl command. Handles the following * syntax: * * info complete command * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoCompleteCmd( Interp interp, TclObject[] objv ) { if ( objv.Length != 3 ) { throw new TclNumArgsException( interp, 2, objv, "command" ); } interp.setResult( tcl.lang.Interp.commandComplete( objv[2].ToString() ) ); return; } /* *---------------------------------------------------------------------- * * InfoDefaultCmd -- * * Called to implement the "info default" command that returns the * default value for a procedure argument. Handles the following * syntax: * * info default procName arg varName * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoDefaultCmd( Interp interp, TclObject[] objv ) { string procName, argName, varName; Procedure proc; //TclObject valueObj; if ( objv.Length != 5 ) { throw new TclNumArgsException( interp, 2, objv, "procname arg varname" ); } procName = objv[2].ToString(); argName = objv[3].ToString(); proc = Procedure.findProc( interp, procName ); if ( proc == null ) { throw new TclException( interp, "\"" + procName + "\" isn't a procedure" ); } for ( int i = 0; i < proc.argList.Length; i++ ) { if ( argName.Equals( proc.argList[i][0].ToString() ) ) { varName = objv[4].ToString(); try { if ( proc.argList[i][1] != null ) { interp.setVar( varName, proc.argList[i][1], 0 ); interp.setResult( 1 ); } else { interp.setVar( varName, "", 0 ); interp.setResult( 0 ); } } catch ( TclException excp ) { throw new TclException( interp, "couldn't store default value in variable \"" + varName + "\"" ); } return; } } throw new TclException( interp, "procedure \"" + procName + "\" doesn't have an argument \"" + argName + "\"" ); } /* *---------------------------------------------------------------------- * * InfoExistsCmd -- * * Called to implement the "info exists" command that determines * whether a variable exists. Handles the following syntax: * * info exists varName * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoExistsCmd( Interp interp, TclObject[] objv ) { string varName; Var var = null; if ( objv.Length != 3 ) { throw new TclNumArgsException( interp, 2, objv, "varName" ); } varName = objv[2].ToString(); Var[] result = Var.lookupVar( interp, varName, null, 0, "access", false, false ); if ( result != null ) { var = result[0]; } if ( ( var != null ) && !var.isVarUndefined() ) { interp.setResult( true ); } else { interp.setResult( false ); } return; } /* *---------------------------------------------------------------------- * * InfoGlobalsCmd -- * * Called to implement the "info globals" command that returns the list * of global variables matching an optional pattern. Handles the * following syntax: * * info globals ?pattern?* * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoGlobalsCmd( Interp interp, TclObject[] objv ) { string varName, pattern; NamespaceCmd.Namespace globalNs = NamespaceCmd.getGlobalNamespace( interp ); IDictionaryEnumerator search; Var var; TclObject list; if ( objv.Length == 2 ) { pattern = null; } else if ( objv.Length == 3 ) { pattern = objv[2].ToString(); } else { throw new TclNumArgsException( interp, 2, objv, "?pattern?" ); } // Scan through the global :: namespace's variable table and create a // list of all global variables that match the pattern. list = TclList.newInstance(); for ( search = globalNs.varTable.GetEnumerator(); search.MoveNext(); ) { varName = ( (string)search.Key ); var = (Var)search.Value; if ( var.isVarUndefined() ) { continue; } if ( ( (System.Object)pattern == null ) || Util.stringMatch( varName, pattern ) ) { TclList.append( interp, list, TclString.newInstance( varName ) ); } } interp.setResult( list ); return; } /* *---------------------------------------------------------------------- * * InfoHostnameCmd -- * * Called to implement the "info hostname" command that returns the * host name. Handles the following syntax: * * info hostname * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoHostnameCmd( Interp interp, TclObject[] objv ) { string name; if ( objv.Length != 2 ) { throw new TclNumArgsException( interp, 2, objv, null ); } // FIXME : how can we find the hostname name = null; if ( (System.Object)name != null ) { interp.setResult( name ); return; } else { interp.setResult( "unable to determine name of host" ); return; } } /* *---------------------------------------------------------------------- * * InfoLevelCmd -- * * Called to implement the "info level" command that returns * information about the call stack. Handles the following syntax: * * info level ?number? * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoLevelCmd( Interp interp, TclObject[] objv ) { int level; CallFrame frame; TclObject list; if ( objv.Length == 2 ) { // just "info level" if ( interp.varFrame == null ) { interp.setResult( 0 ); } else { interp.setResult( interp.varFrame.level ); } return; } else if ( objv.Length == 3 ) { level = TclInteger.get( interp, objv[2] ); if ( level <= 0 ) { if ( interp.varFrame == null ) { throw new TclException( interp, "bad level \"" + objv[2].ToString() + "\"" ); } level += interp.varFrame.level; } for ( frame = interp.varFrame; frame != null; frame = frame.callerVar ) { if ( frame.level == level ) { break; } } if ( ( frame == null ) || frame.objv == null ) { throw new TclException( interp, "bad level \"" + objv[2].ToString() + "\"" ); } list = TclList.newInstance(); for ( int i = 0; i < frame.objv.Length; i++ ) { TclList.append( interp, list, TclString.newInstance( frame.objv[i] ) ); } interp.setResult( list ); return; } throw new TclNumArgsException( interp, 2, objv, "?number?" ); } /* *---------------------------------------------------------------------- * * InfoLibraryCmd -- * * Called to implement the "info library" command that returns the * library directory for the Tcl installation. Handles the following * syntax: * * info library * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoLibraryCmd( Interp interp, TclObject[] objv ) { if ( objv.Length != 2 ) { throw new TclNumArgsException( interp, 2, objv, null ); } try { interp.setResult( interp.getVar( "tcl_library", TCL.VarFlag.GLOBAL_ONLY ) ); return; } catch ( TclException e ) { // If the variable has not been defined throw new TclException( interp, "no library has been specified for Tcl" ); } } /* *---------------------------------------------------------------------- * * InfoLoadedCmd -- * * Called to implement the "info loaded" command that returns the * packages that have been loaded into an interpreter. Handles the * following syntax: * * info loaded ?interp? * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoLoadedCmd( Interp interp, TclObject[] objv ) { if ( objv.Length != 2 && objv.Length != 3 ) { throw new TclNumArgsException( interp, 2, objv, "?interp?" ); } // FIXME : what should "info loaded" return? throw new TclException( interp, "info loaded not implemented" ); } /* *---------------------------------------------------------------------- * * InfoLocalsCmd -- * * Called to implement the "info locals" command to return a list of * local variables that match an optional pattern. Handles the * following syntax: * * info locals ?pattern? * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoLocalsCmd( Interp interp, TclObject[] objv ) { string pattern; TclObject list; if ( objv.Length == 2 ) { pattern = null; } else if ( objv.Length == 3 ) { pattern = objv[2].ToString(); } else { throw new TclNumArgsException( interp, 2, objv, "?pattern?" ); } if ( interp.varFrame == null || !interp.varFrame.isProcCallFrame ) { return; } // Return a list containing names of first the compiled locals (i.e. the // ones stored in the call frame), then the variables in the local hash // table (if one exists). list = TclList.newInstance(); AppendLocals( interp, list, pattern, false ); interp.setResult( list ); return; } /* *---------------------------------------------------------------------- * * AppendLocals -- * * Append the local variables for the current frame to the * specified list object. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ private static void AppendLocals( Interp interp, TclObject list, string pattern, bool includeLinks ) { Var var; string varName; Hashtable localVarTable; IDictionaryEnumerator search; localVarTable = interp.varFrame.varTable; // Compiled locals do not exist in Jacl if ( localVarTable != null ) { for ( search = localVarTable.GetEnumerator(); search.MoveNext(); ) { var = (Var)search.Value; varName = (string)search.Key; if ( !var.isVarUndefined() && ( includeLinks || !var.isVarLink() ) ) { if ( ( (System.Object)pattern == null ) || Util.stringMatch( varName, pattern ) ) { TclList.append( interp, list, TclString.newInstance( varName ) ); } } } } } /* *---------------------------------------------------------------------- * * InfoNameOfExecutableCmd -- * * Called to implement the "info nameofexecutable" command that returns * the name of the binary file running this application. Handles the * following syntax: * * info nameofexecutable * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoNameOfExecutableCmd( Interp interp, TclObject[] objv ) { if ( objv.Length != 2 ) { throw new TclNumArgsException( interp, 2, objv, null ); } // We depend on a user defined property named "JAVA" since // the JDK provides no means to learn the name of the executable // that launched the application. string nameOfExecutable = "nacl"; if ( (System.Object)nameOfExecutable != null ) { TclObject result = TclList.newInstance(); TclList.append( interp, result, TclString.newInstance( nameOfExecutable ) ); TclList.append( interp, result, TclString.newInstance( "tcl.lang.Shell" ) ); interp.setResult( result ); } return; } /* *---------------------------------------------------------------------- * * InfoPatchLevelCmd -- * * Called to implement the "info patchlevel" command that returns the * default value for an argument to a procedure. Handles the following * syntax: * * info patchlevel * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoPatchLevelCmd( Interp interp, TclObject[] objv ) { if ( objv.Length != 2 ) { throw new TclNumArgsException( interp, 2, objv, null ); } interp.setResult( interp.getVar( "tcl_patchLevel", TCL.VarFlag.GLOBAL_ONLY ) ); return; } /* *---------------------------------------------------------------------- * * InfoProcsCmd -- * * Called to implement the "info procs" command that returns the * procedures in the current namespace that match an optional pattern. * Handles the following syntax: * * info procs ?pattern? * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoProcsCmd( Interp interp, TclObject[] objv ) { string cmdName, pattern; NamespaceCmd.Namespace currNs = NamespaceCmd.getCurrentNamespace( interp ); IDictionaryEnumerator search; WrappedCommand cmd, realCmd; TclObject list; if ( objv.Length == 2 ) { pattern = null; } else if ( objv.Length == 3 ) { pattern = objv[2].ToString(); } else { throw new TclNumArgsException( interp, 2, objv, "?pattern?" ); } // Scan through the current namespace's command table and return a list // of all procs that match the pattern. list = TclList.newInstance(); for ( search = currNs.cmdTable.GetEnumerator(); search.MoveNext(); ) { cmdName = ( (string)search.Key ); cmd = (WrappedCommand)search.Value; // If the command isn't itself a proc, it still might be an // imported command that points to a "real" proc in a different // namespace. realCmd = NamespaceCmd.getOriginalCommand( cmd ); if ( Procedure.isProc( cmd ) || ( ( realCmd != null ) && Procedure.isProc( realCmd ) ) ) { if ( ( (System.Object)pattern == null ) || Util.stringMatch( cmdName, pattern ) ) { TclList.append( interp, list, TclString.newInstance( cmdName ) ); } } } interp.setResult( list ); return; } /* *---------------------------------------------------------------------- * * InfoScriptCmd -- * * Called to implement the "info script" command that returns the * script file that is currently being evaluated. Handles the * following syntax: * * info script * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoScriptCmd( Interp interp, TclObject[] objv ) { if ( objv.Length != 2 ) { throw new TclNumArgsException( interp, 2, objv, null ); } interp.setResult( interp.scriptFile ); return; } /* *---------------------------------------------------------------------- * * InfoSharedlibCmd -- * * Called to implement the "info sharedlibextension" command that * returns the file extension used for shared libraries. Handles the * following syntax: * * info sharedlibextension * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoSharedlibCmd( Interp interp, TclObject[] objv ) { if ( objv.Length != 2 ) { throw new TclNumArgsException( interp, 2, objv, null ); } interp.setResult( ".jar" ); return; } /* *---------------------------------------------------------------------- * * InfoTclVersionCmd -- * * Called to implement the "info tclversion" command that returns the * version number for this Tcl library. Handles the following syntax: * * info tclversion * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoTclVersionCmd( Interp interp, TclObject[] objv ) { if ( objv.Length != 2 ) { throw new TclNumArgsException( interp, 2, objv, null ); } interp.setResult( interp.getVar( "tcl_version", TCL.VarFlag.GLOBAL_ONLY ) ); return; } /* *---------------------------------------------------------------------- * * InfoVarsCmd -- * * Called to implement the "info vars" command that returns the * list of variables in the interpreter that match an optional pattern. * The pattern, if any, consists of an optional sequence of namespace * names separated by "::" qualifiers, which is followed by a * glob-style pattern that restricts which variables are returned. * Handles the following syntax: * * info vars ?pattern? * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoVarsCmd( Interp interp, TclObject[] objv ) { string varName, pattern, simplePattern; IDictionaryEnumerator search; Var var; NamespaceCmd.Namespace ns; NamespaceCmd.Namespace globalNs = NamespaceCmd.getGlobalNamespace( interp ); NamespaceCmd.Namespace currNs = NamespaceCmd.getCurrentNamespace( interp ); TclObject list, elemObj; bool specificNsInPattern = false; // Init. to avoid compiler warning. // Get the pattern and find the "effective namespace" in which to // list variables. We only use this effective namespace if there's // no active Tcl procedure frame. if ( objv.Length == 2 ) { simplePattern = null; ns = currNs; specificNsInPattern = false; } else if ( objv.Length == 3 ) { // From the pattern, get the effective namespace and the simple // pattern (no namespace qualifiers or ::'s) at the end. If an // error was found while parsing the pattern, return it. Otherwise, // if the namespace wasn't found, just leave ns = null: we will // return an empty list since no variables there can be found. pattern = objv[2].ToString(); // Java does not support passing an address so we pass // an array of size 1 and then assign arr[0] to the value NamespaceCmd.Namespace[] nsArr = new NamespaceCmd.Namespace[1]; NamespaceCmd.Namespace[] dummy1Arr = new NamespaceCmd.Namespace[1]; NamespaceCmd.Namespace[] dummy2Arr = new NamespaceCmd.Namespace[1]; string[] simplePatternArr = new string[1]; NamespaceCmd.getNamespaceForQualName( interp, pattern, null, 0, nsArr, dummy1Arr, dummy2Arr, simplePatternArr ); // Get the values out of the arrays! ns = nsArr[0]; simplePattern = simplePatternArr[0]; if ( ns != null ) { // we successfully found the pattern's ns specificNsInPattern = ( simplePattern.CompareTo( pattern ) != 0 ); } } else { throw new TclNumArgsException( interp, 2, objv, "?pattern?" ); } // If the namespace specified in the pattern wasn't found, just return. if ( ns == null ) { return; } list = TclList.newInstance(); if ( ( interp.varFrame == null ) || !interp.varFrame.isProcCallFrame || specificNsInPattern ) { // There is no frame pointer, the frame pointer was pushed only // to activate a namespace, or we are in a procedure call frame // but a specific namespace was specified. Create a list containing // only the variables in the effective namespace's variable table. search = ns.varTable.GetEnumerator(); while ( search.MoveNext() ) { varName = ( (string)search.Key ); var = (Var)search.Value; if ( !var.isVarUndefined() || ( ( var.flags & VarFlags.NAMESPACE_VAR ) != 0 ) ) { if ( ( (System.Object)simplePattern == null ) || Util.stringMatch( varName, simplePattern ) ) { if ( specificNsInPattern ) { elemObj = TclString.newInstance( Var.getVariableFullName( interp, var ) ); } else { elemObj = TclString.newInstance( varName ); } TclList.append( interp, list, elemObj ); } } } // If the effective namespace isn't the global :: namespace, and a // specific namespace wasn't requested in the pattern (i.e., the // pattern only specifies variable names), then add in all global :: // variables that match the simple pattern. Of course, add in only // those variables that aren't hidden by a variable in the effective // namespace. if ( ( ns != globalNs ) && !specificNsInPattern ) { search = globalNs.varTable.GetEnumerator(); while ( search.MoveNext() ) { varName = ( (string)search.Key ); var = (Var)search.Value; if ( !var.isVarUndefined() || ( ( var.flags & VarFlags.NAMESPACE_VAR ) != 0 ) ) { if ( ( (System.Object)simplePattern == null ) || Util.stringMatch( varName, simplePattern ) ) { // Skip vars defined in current namespace if ( ns.varTable[varName] == null ) { TclList.append( interp, list, TclString.newInstance( varName ) ); } } } } } } else { AppendLocals( interp, list, simplePattern, true ); } interp.setResult( list ); return; } } }