Exemplo n.º 1
0
    /*
    *----------------------------------------------------------------------
    *
    * initialize --
    *
    *	This method is called to initialize an interpreter with it's 
    *	initial values for the env array.
    *
    * Results:
    *	None.
    *
    * Side effects:
    *	The env array in the interpreter is created and populated.
    *
    *----------------------------------------------------------------------
    */

    internal static void initialize( Interp interp )
    {
      // For a few standrad environment vairables that Tcl users 
      // often assume aways exist (even if they shouldn't), we will
      // try to create those expected variables with the common unix
      // names.

      try
      {
        interp.setVar( "env", "HOME", System.Environment.CurrentDirectory, TCL.VarFlag.GLOBAL_ONLY );
      }
      catch ( TclException e )
      {
        // Ignore errors.
      }

      try
      {
        interp.setVar( "env", "USER", System.Environment.UserName, TCL.VarFlag.GLOBAL_ONLY );
      }
      catch ( TclException e )
      {
        // Ignore errors.
      }

      // Now we will populate the rest of the env array with the
      // properties recieved from the System classes.  This makes for 
      // a nice shortcut for getting to these useful values.

      try
      {


        for ( IDictionaryEnumerator search = System.Environment.GetEnvironmentVariables().GetEnumerator(); search.MoveNext(); )
        {
          interp.setVar( "env", search.Key.ToString(), search.Value.ToString(), TCL.VarFlag.GLOBAL_ONLY );
        }
      }
      catch ( System.Security.SecurityException e2 )
      {
        // We are inside a browser and we can't access the list of
        // property names. That's fine. Life goes on ....
      }
      catch ( System.Exception e3 )
      {
        // We are inside a browser and we can't access the list of
        // property names. That's fine. Life goes on ....

        System.Diagnostics.Debug.WriteLine( "Exception while initializing env array" );
        System.Diagnostics.Debug.WriteLine( e3 );
        System.Diagnostics.Debug.WriteLine( "" );
      }
    }
Exemplo n.º 2
0
    public TCL.CompletionCode cmdProc( Interp interp, TclObject[] objv )
    {
      TclObject varValue = null;

      if ( objv.Length < 2 )
      {
        throw new TclNumArgsException( interp, 1, objv, "varName ?value value ...?" );
      }
      else if ( objv.Length == 2 )
      {
        interp.resetResult();
        interp.setResult( interp.getVar( objv[1], 0 ) );
      }
      else
      {
        for ( int i = 2; i < objv.Length; i++ )
        {
          varValue = interp.setVar( objv[1], objv[i], TCL.VarFlag.APPEND_VALUE );
        }

        if ( varValue != null )
        {
          interp.resetResult();
          interp.setResult( varValue );
        }
        else
        {
          interp.resetResult();
        }
      }
      return TCL.CompletionCode.RETURN;
    }
    /// <summary> This procedure is invoked to process the "gets" Tcl command.
    /// See the user documentation for details on what it does.
    /// 
    /// </summary>
    /// <param name="interp">the current interpreter.
    /// </param>
    /// <param name="argv">command arguments.
    /// </param>

    public TCL.CompletionCode cmdProc( Interp interp, TclObject[] argv )
    {

      bool writeToVar = false; // If true write to var passes as arg
      string varName = ""; // The variable to write value to
      Channel chan; // The channel being operated on
      int lineLen;
      TclObject line;

      if ( ( argv.Length < 2 ) || ( argv.Length > 3 ) )
      {
        throw new TclNumArgsException( interp, 1, argv, "channelId ?varName?" );
      }

      if ( argv.Length == 3 )
      {
        writeToVar = true;

        varName = argv[2].ToString();
      }


      chan = TclIO.getChannel( interp, argv[1].ToString() );
      if ( chan == null )
      {

        throw new TclException( interp, "can not find channel named \"" + argv[1].ToString() + "\"" );
      }

      try
      {
        line = TclString.newInstance( new StringBuilder( 64 ) );
        lineLen = chan.read( interp, line, TclIO.READ_LINE, 0 );
        if ( lineLen < 0 )
        {
          // FIXME: Need more specific posix error codes!
          if ( !chan.eof() && !chan.isBlocked( interp ) )
          {

            throw new TclPosixException( interp, TclPosixException.EIO, true, "error reading \"" + argv[1].ToString() + "\"" );
          }
          lineLen = -1;
        }
        if ( writeToVar )
        {
          interp.setVar( varName, line, 0 );
          interp.setResult( lineLen );
        }
        else
        {
          interp.setResult( line );
        }
      }
      catch ( IOException e )
      {
        throw new TclRuntimeError( "GetsCmd.cmdProc() Error: IOException when getting " + chan.ChanName + ": " + e.Message );
      }
      return TCL.CompletionCode.RETURN;
    }
Exemplo n.º 4
0
    public TCL.CompletionCode cmdProc( Interp interp, TclObject[] argv )
    {
      bool debug;

      if ( argv.Length == 2 )
      {
        System.Diagnostics.Debug.WriteLine( "getting value of \"" + argv[1].ToString() + "\"" );

        interp.setResult( interp.getVar( argv[1], 0 ) );
      }
      else if ( argv.Length == 3 )
      {
        System.Diagnostics.Debug.WriteLine( "setting value of \"" + argv[1].ToString() + "\" to \"" + argv[2].ToString() + "\"" );
        interp.setResult( interp.setVar( argv[1], argv[2], 0 ) );
      }
      else
      {
        throw new TclNumArgsException( interp, 1, argv, "varName ?newValue?" );
      }
      return TCL.CompletionCode.RETURN;
    }
Exemplo n.º 5
0
		/// <summary> This procedure is invoked to process the "catch" Tcl command.
		/// See the user documentation for details on what it does.
		/// 
		/// </summary>
		/// <param name="interp">the current interpreter.
		/// </param>
		/// <param name="argv">command arguments.
		/// </param>
		/// <exception cref=""> TclException if wrong number of arguments.
		/// </exception>
		
		public TCL.CompletionCode cmdProc(Interp interp, TclObject[] argv)
		{
			if (argv.Length != 2 && argv.Length != 3)
			{
				throw new TclNumArgsException(interp, 1, argv, "command ?varName?");
			}
			
			TclObject result;
			TCL.CompletionCode code = TCL.CompletionCode.OK;
			
			try
			{
				interp.eval(argv[1], 0);
			}
			catch (TclException e)
			{
				code = e.getCompletionCode();
			}

      result = interp.getResult();

      if ( argv.Length == 3 )
			{
				try
				{
					interp.setVar(argv[2], result, 0);
				}
				catch (TclException e)
				{
					throw new TclException(interp, "couldn't save command result in variable");
				}
			}
			
			interp.resetResult();
			interp.setResult(TclInteger.newInstance((int)code));
      return TCL.CompletionCode.RETURN;
    }
Exemplo n.º 6
0
    public TCL.CompletionCode cmdProc( Interp interp, TclObject[] argv )
    {
      bool all = false;
      bool nocase = false;

      try
      {
        int i = 1;

        while ( argv[i].ToString().StartsWith( "-" ) )
        {
          int index = TclIndex.get( interp, argv[i], validOpts, "switch", 0 );
          i++;
          switch ( index )
          {

            case OPT_ALL:
              {
                all = true;
                break;
              }

            case OPT_NOCASE:
              {
                nocase = true;
                break;
              }

            case OPT_LAST:
              {
                goto opts_brk;
              }
          }
        }

opts_brk:
        ;


        TclObject exp = argv[i++];

        string inString = argv[i++].ToString();

        string subSpec = argv[i++].ToString();

        string varName = null;
        if (i != argv.Length) varName = argv[i++].ToString();
        if ( i != argv.Length )
        {
          throw new System.IndexOutOfRangeException();
        }

        Regexp r = TclRegexp.compile( interp, exp, nocase );

        int count = 0;
        string result;

        if ( all == false )
        {
          result = r.sub( inString, subSpec );
          if ( (System.Object)result == null )
          {
            result = inString;
          }
          else
          {
            count++;
          }
        }
        else
        {
          StringBuilder sb = new StringBuilder();
          Regsub s = new Regsub( r, inString );
          while ( s.nextMatch() )
          {
            count++;
            sb.Append( s.skipped() );
            Regexp.applySubspec( s, subSpec, sb );
          }
          sb.Append( s.rest() );
          result = sb.ToString();
        }

        TclObject obj = TclString.newInstance( result );
        if ( varName == null )
          interp.setResult( result );
        else {
          try
          {
            interp.setVar( varName, obj, 0 );
          }
          catch ( TclException e )
          {
            throw new TclException( interp, "couldn't set variable \"" + varName + "\"" );
          }
          interp.setResult( count );
        }
      }
      catch ( System.IndexOutOfRangeException e )
      {
        throw new TclNumArgsException( interp, 1, argv, "?switches? exp string subSpec ?varName?" );
      }
      return TCL.CompletionCode.RETURN;
    }
Exemplo n.º 7
0
    internal static Interp create( Interp interp, TclObject path, bool safe )
    {
      Interp masterInterp;
      string pathString;

      TclObject[] objv = TclList.getElements( interp, path );

      if ( objv.Length < 2 )
      {
        masterInterp = interp;

        pathString = path.ToString();
      }
      else
      {
        TclObject obj = TclList.newInstance();

        TclList.insert( interp, obj, 0, objv, 0, objv.Length - 2 );
        masterInterp = InterpCmd.getInterp( interp, obj );

        pathString = objv[objv.Length - 1].ToString();
      }
      if ( !safe )
      {
        safe = masterInterp.isSafe;
      }

      if ( masterInterp.slaveTable.ContainsKey( pathString ) )
      {
        throw new TclException( interp, "interpreter named \"" + pathString + "\" already exists, cannot create" );
      }

      Interp slaveInterp = new Interp();
      InterpSlaveCmd slave = new InterpSlaveCmd();

      slaveInterp.slave = slave;
      slaveInterp.setAssocData( "InterpSlaveCmd", slave );

      slave.masterInterp = masterInterp;
      slave.path = pathString;
      slave.slaveInterp = slaveInterp;

      masterInterp.createCommand( pathString, slaveInterp.slave );
      slaveInterp.slave.interpCmd = NamespaceCmd.findCommand( masterInterp, pathString, null, 0 );

      SupportClass.PutElement( masterInterp.slaveTable, pathString, slaveInterp.slave );

      slaveInterp.setVar( "tcl_interactive", "0", TCL.VarFlag.GLOBAL_ONLY );

      // Inherit the recursion limit.

      slaveInterp.maxNestingDepth = masterInterp.maxNestingDepth;

      if ( safe )
      {
        try
        {
          makeSafe( slaveInterp );
        }
        catch ( TclException e )
        {
          SupportClass.WriteStackTrace( e, Console.Error );
        }
      }
      else
      {
        //Tcl_Init(slaveInterp);
      }

      return slaveInterp;
    }
Exemplo n.º 8
0
		public TCL.CompletionCode cmdProc(Interp interp, TclObject[] argv)
		{
			bool nocase = false;
			bool indices = false;
			
			try
			{
				int i = 1;
				
				while (argv[i].ToString().StartsWith("-"))
				{
					int index = TclIndex.get(interp, argv[i], validOpts, "switch", 0);
					i++;
					switch (index)
					{
						
						case OPT_INDICES:  {
								indices = true;
								break;
							}
						
						case OPT_NOCASE:  {
								nocase = true;
								break;
							}
						
						case OPT_LAST:  {
								goto opts_brk;
							}
						}
				}

opts_brk: ;


        TclObject exp = TclString.newInstance( argv[i++].ToString().Replace( "\\d", "[0-9]" ) );
				
				string inString = argv[i++].ToString();
				
				int matches = argv.Length - i;
				
				Regexp r = TclRegexp.compile(interp, exp, nocase);
				
				int[] args = new int[matches * 2];
				bool matched = r.match(inString, args);
				if (matched)
				{
					for (int match = 0; i < argv.Length; i++)
					{
						TclObject obj;
						
						int start = args[match++];
						int end = args[match++];
						if (indices)
						{
							if (end >= 0)
							{
								end--;
							}
							obj = TclList.newInstance();
							TclList.append(interp, obj, TclInteger.newInstance(start));
							TclList.append(interp, obj, TclInteger.newInstance(end));
						}
						else
						{
							string range = (start >= 0)?inString.Substring(start, (end) - (start)):"";
							obj = TclString.newInstance(range);
						}
						try
						{
							
							interp.setVar(argv[i].ToString(), obj, 0);
						}
						catch (TclException e)
						{
							
							throw new TclException(interp, "couldn't set variable \"" + argv[i] + "\"");
						}
					}
				}
				interp.setResult(matched);
			}
			catch (System.IndexOutOfRangeException e)
			{
				throw new TclNumArgsException(interp, 1, argv, "?switches? exp string ?matchVar? ?subMatchVar subMatchVar ...?");
			}
      return TCL.CompletionCode.RETURN;
    }
    private static void getAndStoreStatData( Interp interp, string fileName, string varName )
    {
      FileInfo fileObj = FileUtil.getNewFileObj( interp, fileName );

      bool tmpBool;
      if ( File.Exists( fileObj.FullName ) )
        tmpBool = true;
      else
        tmpBool = Directory.Exists( fileObj.FullName );
      if ( !tmpBool )
      {
        throw new TclPosixException( interp, TclPosixException.ENOENT, true, "could not read \"" + fileName + "\"" );
      }

      try
      {
        int mtime = getMtime( interp, fileName, fileObj );
        TclObject mtimeObj = TclInteger.newInstance( mtime );
        TclObject atimeObj = TclInteger.newInstance( mtime );
        TclObject ctimeObj = TclInteger.newInstance( mtime );
        interp.setVar( varName, "atime", atimeObj, 0 );
        interp.setVar( varName, "ctime", ctimeObj, 0 );
        interp.setVar( varName, "mtime", mtimeObj, 0 );
      }
      catch ( System.Security.SecurityException e )
      {
        throw new TclException( interp, e.Message );
      }
      catch ( TclException e )
      {
        throw new TclException( interp, "can't set \"" + varName + "(dev)\": variable isn't array" );
      }

      try
      {
        TclObject sizeObj = TclInteger.newInstance( (int)SupportClass.FileLength( fileObj ) );
        interp.setVar( varName, "size", sizeObj, 0 );
      }
      catch ( System.Exception e )
      {
        // Do nothing.
      }

      try
      {
        TclObject typeObj = TclString.newInstance( getType( interp, fileName, fileObj ) );
        interp.setVar( varName, "type", typeObj, 0 );
      }
      catch ( System.Exception e )
      {
      }

      try
      {
        TclObject uidObj = TclBoolean.newInstance( isOwner( interp, fileObj ) );
        interp.setVar( varName, "uid", uidObj, 0 );
      }
      catch ( TclException e )
      {
        // Do nothing.
      }
    }
Exemplo n.º 10
0
		/// <summary> 
		/// Tcl_LappendObjCmd -> LappendCmd.cmdProc
		/// 
		/// This procedure is invoked to process the "lappend" Tcl command.
		/// See the user documentation for details on what it does.
		/// </summary>
		
		public TCL.CompletionCode cmdProc(Interp interp, TclObject[] objv)
		{
			TclObject varValue, newValue = null;
      int i;//int numElems, i, j;
			bool createdNewObj, createVar;
			
			if (objv.Length < 2)
			{
				throw new TclNumArgsException(interp, 1, objv, "varName ?value value ...?");
			}
			if (objv.Length == 2)
			{
				try
				{
					newValue = interp.getVar(objv[1], 0);
				}
				catch (TclException e)
				{
					// The variable doesn't exist yet. Just create it with an empty
					// initial value.
					varValue = TclList.newInstance();
					
					try
					{
						newValue = interp.setVar(objv[1], varValue, 0);
					}
					finally
					{
						if (newValue == null)
							varValue.release(); // free unneeded object
					}
					
					interp.resetResult();
          return TCL.CompletionCode.RETURN;
				}
			}
			else
			{
				// We have arguments to append. We used to call Tcl_SetVar2 to
				// append each argument one at a time to ensure that traces were run
				// for each append step. We now append the arguments all at once
				// because it's faster. Note that a read trace and a write trace for
				// the variable will now each only be called once. Also, if the
				// variable's old value is unshared we modify it directly, otherwise
				// we create a new copy to modify: this is "copy on write".
				
				createdNewObj = false;
				createVar = true;
				
				try
				{
					varValue = interp.getVar(objv[1], 0);
				}
				catch (TclException e)
				{
					// We couldn't read the old value: either the var doesn't yet
					// exist or it's an array element. If it's new, we will try to
					// create it with Tcl_ObjSetVar2 below.
					
					// FIXME : not sure we even need this parse for anything!
					// If we do not need to parse could we at least speed it up a bit
					
					string varName;
					int nameBytes;
					
					
					varName = objv[1].ToString();
					nameBytes = varName.Length; // Number of Unicode chars in string
					
					for (i = 0; i < nameBytes; i++)
					{
						if (varName[i] == '(')
						{
							i = nameBytes - 1;
							if (varName[i] == ')')
							{
								// last char is ')' => array ref
								createVar = false;
							}
							break;
						}
					}
					varValue = TclList.newInstance();
					createdNewObj = true;
				}
				
				// We only take this branch when the catch branch was not run
				if (createdNewObj == false && varValue.Shared)
				{
					varValue = varValue.duplicate();
					createdNewObj = true;
				}
				
				// Insert the new elements at the end of the list.
				
				for (i = 2; i < objv.Length; i++)
				{
					TclList.append(interp, varValue, objv[i]);
				}
				
				// No need to call varValue.invalidateStringRep() since it
				// is called during the TclList.append operation.
				
				// Now store the list object back into the variable. If there is an
				// error setting the new value, decrement its ref count if it
				// was new and we didn't create the variable.
				
				try
				{
					
					newValue = interp.setVar(objv[1].ToString(), varValue, 0);
				}
				catch (TclException e)
				{
					if (createdNewObj && !createVar)
					{
						varValue.release(); // free unneeded obj
					}
					throw ;
				}
			}
			
			// Set the interpreter's object result to refer to the variable's value
			// object.
			
			interp.setResult(newValue);
      return TCL.CompletionCode.RETURN;
		}
Exemplo n.º 11
0
    /*
    *----------------------------------------------------------------------
    *
    * 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 + "\"" );
    }
Exemplo n.º 12
0
		/// <summary> Tcl_ForeachObjCmd -> ForeachCmd.cmdProc
		/// 
		/// This procedure is invoked to process the "foreach" Tcl command.
		/// See the user documentation for details on what it does.
		/// 
		/// </summary>
		/// <param name="interp">the current interpreter.
		/// </param>
		/// <param name="objv">command arguments.
		/// </param>
		/// <exception cref=""> TclException if script causes error.
		/// </exception>
		
		public TCL.CompletionCode cmdProc(Interp interp, TclObject[] objv)
		{
			if (objv.Length < 4 || (objv.Length % 2) != 0)
			{
				throw new TclNumArgsException(interp, 1, objv, "varList list ?varList list ...? command");
			}
			
			// foreach {n1 n2} {1 2 3 4} {n3} {1 2} {puts $n1-$n2-$n3}
			//	name[0] = {n1 n2}	value[0] = {1 2 3 4}
			//	name[1] = {n3}		value[0] = {1 2}
			
			TclObject[] name = new TclObject[(objv.Length - 2) / 2];
			TclObject[] value = new TclObject[(objv.Length - 2) / 2];
			
			int c, i, j, base_;
			int maxIter = 0;
			TclObject command = objv[objv.Length - 1];
			bool done = false;
			
			for (i = 0; i < objv.Length - 2; i += 2)
			{
				int x = i / 2;
				name[x] = objv[i + 1];
				value[x] = objv[i + 2];
				
				int nSize = TclList.getLength(interp, name[x]);
				int vSize = TclList.getLength(interp, value[x]);
				
				if (nSize == 0)
				{
					throw new TclException(interp, "foreach varlist is empty");
				}
				
				int iter = (vSize + nSize - 1) / nSize;
				if (maxIter < iter)
				{
					maxIter = iter;
				}
			}
			
			for (c = 0; !done && c < maxIter; c++)
			{
				// Set up the variables
				
				for (i = 0; i < objv.Length - 2; i += 2)
				{
					int x = i / 2;
					int nSize = TclList.getLength(interp, name[x]);
					base_ = nSize * c;
					for (j = 0; j < nSize; j++)
					{
						// Test and see if the name variable is an array.
						
						
						Var[] result = Var.lookupVar(interp, name[x].ToString(), null, 0, null, false, false);
						Var var = null;
						
						if (result != null)
						{
							if (result[1] != null)
							{
								var = result[1];
							}
							else
							{
								var = result[0];
							}
						}
						
						try
						{
							if (base_ + j >= TclList.getLength(interp, value[x]))
							{
								interp.setVar(TclList.index(interp, name[x], j), TclString.newInstance(""), 0);
							}
							else
							{
								interp.setVar(TclList.index(interp, name[x], j), TclList.index(interp, value[x], base_ + j), 0);
							}
						}
						catch (TclException e)
						{
							
							throw new TclException(interp, "couldn't set loop variable: \"" + TclList.index(interp, name[x], j) + "\"");
						}
					}
				}
				
				// Execute the script
				
				try
				{
					interp.eval(command, 0);
				}
				catch (TclException e)
				{
					switch (e.getCompletionCode())
					{
						
						case TCL.CompletionCode.BREAK: 
							done = true;
							break;
						
						
						case TCL.CompletionCode.CONTINUE: 
							continue;
						
						
						case TCL.CompletionCode.ERROR: 
							interp.addErrorInfo("\n    (\"foreach\" body line " + interp.errorLine + ")");
							throw ;
						
						
						default: 
							throw ;
						
					}
				}
			}
			
			interp.resetResult();
      return TCL.CompletionCode.RETURN;
    }
    /// <summary> This procedure is invoked to process the "array" Tcl command.
    /// See the user documentation for details on what it does.
    /// </summary>

    public TCL.CompletionCode cmdProc( Interp interp, TclObject[] objv )
    {
      Var var = null, array = null;
      bool notArray = false;
      string varName, msg;
      int index;//, result;

      if ( objv.Length < 3 )
      {
        throw new TclNumArgsException( interp, 1, objv, "option arrayName ?arg ...?" );
      }

      index = TclIndex.get( interp, objv[1], validCmds, "option", 0 );

      // Locate the array variable (and it better be an array).


      varName = objv[2].ToString();
      Var[] retArray = Var.lookupVar( interp, varName, null, 0, null, false, false );

      // Assign the values returned in the array
      if ( retArray != null )
      {
        var = retArray[0];
        array = retArray[1];
      }

      if ( ( var == null ) || !var.isVarArray() || var.isVarUndefined() )
      {
        notArray = true;
      }

      // Special array trace used to keep the env array in sync for
      // array names, array get, etc.

      if ( var != null && var.traces != null )
      {
        msg = Var.callTraces( interp, array, var, varName, null, ( TCL.VarFlag.LEAVE_ERR_MSG | TCL.VarFlag.NAMESPACE_ONLY | TCL.VarFlag.GLOBAL_ONLY | TCL.VarFlag.TRACE_ARRAY ) );
        if ( (System.Object)msg != null )
        {
          throw new TclVarException( interp, varName, null, "trace array", msg );
        }
      }

      switch ( index )
      {

        case OPT_ANYMORE:
          {
            if ( objv.Length != 4 )
            {
              throw new TclNumArgsException( interp, 2, objv, "arrayName searchId" );
            }
            if ( notArray )
            {

              errorNotArray( interp, objv[2].ToString() );
            }

            if ( var.sidVec == null )
            {

              errorIllegalSearchId( interp, objv[2].ToString(), objv[3].ToString() );
            }


            SearchId e = var.getSearch( objv[3].ToString() );
            if ( e == null )
            {

              errorIllegalSearchId( interp, objv[2].ToString(), objv[3].ToString() );
            }

            if ( e.HasMore )
            {
              interp.setResult( "1" );
            }
            else
            {
              interp.setResult( "0" );
            }
            break;
          }

        case OPT_DONESEARCH:
          {

            if ( objv.Length != 4 )
            {
              throw new TclNumArgsException( interp, 2, objv, "arrayName searchId" );
            }
            if ( notArray )
            {

              errorNotArray( interp, objv[2].ToString() );
            }

            bool rmOK = true;
            if ( var.sidVec != null )
            {

              rmOK = ( var.removeSearch( objv[3].ToString() ) );
            }
            if ( ( var.sidVec == null ) || !rmOK )
            {

              errorIllegalSearchId( interp, objv[2].ToString(), objv[3].ToString() );
            }
            break;
          }

        case OPT_EXISTS:
          {

            if ( objv.Length != 3 )
            {
              throw new TclNumArgsException( interp, 2, objv, "arrayName" );
            }
            interp.setResult( !notArray );
            break;
          }

        case OPT_GET:
          {
            // Due to the differences in the hashtable implementation 
            // from the Tcl core and Java, the output will be rearranged.
            // This is not a negative side effect, however, test results 
            // will differ.

            if ( ( objv.Length != 3 ) && ( objv.Length != 4 ) )
            {
              throw new TclNumArgsException( interp, 2, objv, "arrayName ?pattern?" );
            }
            if ( notArray )
            {
              return TCL.CompletionCode.RETURN;
            }

            string pattern = null;
            if ( objv.Length == 4 )
            {

              pattern = objv[3].ToString();
            }

            Hashtable table = (Hashtable)var.value;
            TclObject tobj = TclList.newInstance();

            string arrayName = objv[2].ToString();
            string key, strValue;
            Var var2;

            // Go through each key in the hash table.  If there is a 
            // pattern, test for a match.  Each valid key and its value 
            // is written into sbuf, which is returned.

            // FIXME : do we need to port over the 8.1 code for this loop?

            for ( IDictionaryEnumerator e = table.GetEnumerator(); e.MoveNext(); )
            {
              key = ( (string)e.Key );
              var2 = (Var)e.Value;
              if ( var2.isVarUndefined() )
              {
                continue;
              }

              if ( (System.Object)pattern != null && !Util.stringMatch( key, pattern ) )
              {
                continue;
              }


              strValue = interp.getVar( arrayName, key, 0 ).ToString();

              TclList.append( interp, tobj, TclString.newInstance( key ) );
              TclList.append( interp, tobj, TclString.newInstance( strValue ) );
            }
            interp.setResult( tobj );
            break;
          }

        case OPT_NAMES:
          {

            if ( ( objv.Length != 3 ) && ( objv.Length != 4 ) )
            {
              throw new TclNumArgsException( interp, 2, objv, "arrayName ?pattern?" );
            }
            if ( notArray )
            {
              return TCL.CompletionCode.RETURN;
            }

            string pattern = null;
            if ( objv.Length == 4 )
            {

              pattern = objv[3].ToString();
            }

            Hashtable table = (Hashtable)var.value;
            TclObject tobj = TclList.newInstance();
            string key;

            // Go through each key in the hash table.  If there is a 
            // pattern, test for a match. Each valid key and its value 
            // is written into sbuf, which is returned.

            for ( IDictionaryEnumerator e = table.GetEnumerator(); e.MoveNext(); )
            {
              key = (string)e.Key;
              Var elem = (Var)e.Value;
              if ( !elem.isVarUndefined() )
              {
                if ( (System.Object)pattern != null )
                {
                  if ( !Util.stringMatch( key, pattern ) )
                  {
                    continue;
                  }
                }
                TclList.append( interp, tobj, TclString.newInstance( key ) );
              }
            }
            interp.setResult( tobj );
            break;
          }

        case OPT_NEXTELEMENT:
          {

            if ( objv.Length != 4 )
            {
              throw new TclNumArgsException( interp, 2, objv, "arrayName searchId" );
            }
            if ( notArray )
            {

              errorNotArray( interp, objv[2].ToString() );
            }

            if ( var.sidVec == null )
            {

              errorIllegalSearchId( interp, objv[2].ToString(), objv[3].ToString() );
            }


            SearchId e = var.getSearch( objv[3].ToString() );
            if ( e == null )
            {

              errorIllegalSearchId( interp, objv[2].ToString(), objv[3].ToString() );
            }
            if ( e.HasMore )
            {
              Hashtable table = (Hashtable)var.value;
              DictionaryEntry entry = e.nextEntry();
              string key = (string)entry.Key;
              Var elem = (Var)entry.Value;
              if ( ( elem.flags & VarFlags.UNDEFINED ) == 0 )
              {
                interp.setResult( key );
              }
              else
              {
                interp.setResult( "" );
              }
            }
            break;
          }

        case OPT_SET:
          {

            if ( objv.Length != 4 )
            {
              throw new TclNumArgsException( interp, 2, objv, "arrayName list" );
            }
            int size = TclList.getLength( interp, objv[3] );
            if ( size % 2 != 0 )
            {
              throw new TclException( interp, "list must have an even number of elements" );
            }

            int i;

            string name1 = objv[2].ToString();
            string name2, strValue;

            // Set each of the array variable names in the interp

            for ( i = 0; i < size; i++ )
            {

              name2 = TclList.index( interp, objv[3], i++ ).ToString();

              strValue = TclList.index( interp, objv[3], i ).ToString();
              interp.setVar( name1, name2, TclString.newInstance( strValue ), 0 );
            }
            break;
          }

        case OPT_SIZE:
          {

            if ( objv.Length != 3 )
            {
              throw new TclNumArgsException( interp, 2, objv, "arrayName" );
            }
            if ( notArray )
            {
              interp.setResult( 0 );
            }
            else
            {
              Hashtable table = (Hashtable)var.value;
              int size = 0;
              for ( IDictionaryEnumerator e = table.GetEnumerator(); e.MoveNext(); )
              {
                Var elem = (Var)e.Value;
                if ( ( elem.flags & VarFlags.UNDEFINED ) == 0 )
                {
                  size++;
                }
              }
              interp.setResult( size );
            }
            break;
          }

        case OPT_STARTSEARCH:
          {

            if ( objv.Length != 3 )
            {
              throw new TclNumArgsException( interp, 2, objv, "arrayName" );
            }
            if ( notArray )
            {

              errorNotArray( interp, objv[2].ToString() );
            }

            if ( var.sidVec == null )
            {
              var.sidVec = new ArrayList( 10 );
            }

            // Create a SearchId Object:
            // To create a new SearchId object, a unique string
            // identifier needs to be composed and we need to
            // create an Enumeration of the array keys.  The
            // unique string identifier is created from three
            // strings:
            //
            //     "s-"   is the default prefix
            //     "i"    is a unique number that is 1+ the greatest
            //	      SearchId index currently on the ArrayVar.
            //     "name" is the name of the array
            //
            // Once the SearchId string is created we construct a
            // new SearchId object using the string and the
            // Enumeration.  From now on the string is used to
            // uniquely identify the SearchId object.

            int i = var.NextIndex;

            string s = "s-" + i + "-" + objv[2].ToString();
            IDictionaryEnumerator e = ( (Hashtable)var.value ).GetEnumerator();
            var.sidVec.Add( new SearchId( e, s, i ) );
            interp.setResult( s );
            break;
          }

        case OPT_UNSET:
          {
            string pattern;
            string name;

            if ( ( objv.Length != 3 ) && ( objv.Length != 4 ) )
            {
              throw new TclNumArgsException( interp, 2, objv, "arrayName ?pattern?" );
            }
            if ( notArray )
            {

              //Ignot this error -- errorNotArray(interp, objv[2].ToString());
              break;
            }
            if ( objv.Length == 3 )
            {
              // When no pattern is given, just unset the whole array

              interp.unsetVar( objv[2], 0 );
            }
            else
            {

              pattern = objv[3].ToString();
              Hashtable table = (Hashtable)( ( (Hashtable)var.value ).Clone() );
              for ( IDictionaryEnumerator e = table.GetEnumerator(); e.MoveNext(); )
              {
                name = (string)e.Key;
                Var elem = (Var)e.Value;
                if ( var.isVarUndefined() )
                {
                  continue;
                }
                if ( Util.stringMatch( name, pattern ) )
                {
                  interp.unsetVar( varName, name, 0 );
                }
              }
            }
            break;
          }
      }
      return TCL.CompletionCode.RETURN;
    }
Exemplo n.º 14
0
    /// <summary> Called whenever the cmdProc wants to set an interp value.  
    /// This method <ol>
    /// <li> verifies that there exisits a varName from the argv array, 
    /// <li> that the variable either dosent exisit or is of type scalar
    /// <li> set the variable in interp if (1) and (2) are OK
    /// </ol>
    /// 
    /// </summary>
    /// <param name="interp">  - the Tcl interpreter
    /// </param>
    /// <param name="argv">    - the argument array
    /// </param>
    /// <param name="argIndex">- the current index into the argv array
    /// </param>
    /// <param name="tobj">    - the TclObject that the varName equals
    /// 
    /// </param>

    private static void testAndSetVar( Interp interp, TclObject[] argv, int argIndex, TclObject tobj )
    {
      if ( argIndex < argv.Length )
      {
        try
        {

          interp.setVar( argv[argIndex].ToString(), tobj, 0 );
        }
        catch ( TclException e )
        {

          throw new TclException( interp, "couldn't set variable \"" + argv[argIndex].ToString() + "\"" );
        }
      }
      else
      {
        errorDiffVars( interp );
      }
    }
Exemplo n.º 15
0
  /*
  ** 2009 July 17
  **
  ** The author disclaims copyright to this source code.  In place of
  ** a legal notice, here is a blessing:
  **
  **    May you do good and not evil.
  **    May you find forgiveness for yourself and forgive others.
  **    May you share freely, never taking more than you give.
  **
  *************************************************************************
  ** This file contains code to implement the "sqlite" test harness
  ** which runs TCL commands for testing the C#-SQLite port.
  **
  ** $Header$
  */
  public static void Main(string[] args)
  {
    // Array of command-line argument strings.
    {
      string fileName = null;

      // Create the interpreter. This will also create the built-in
      // Tcl commands.

      Interp interp = new Interp();

      // Make command-line arguments available in the Tcl variables "argc"
      // and "argv".  If the first argument doesn't start with a "-" then
      // strip it off and use it as the name of a script file to process.
      // We also set the argv0 and TCL.Tcl_interactive vars here.

      if ((args.Length > 0) && !(args[0].StartsWith("-")))
      {
        fileName = args[0];
      }

      TclObject argv = TclList.newInstance();
      argv.preserve();
      try
      {
        int i = 0;
        int argc = args.Length;
        if ((System.Object)fileName == null)
        {
          interp.setVar("argv0", "tcl.lang.Shell", TCL.VarFlag.GLOBAL_ONLY);
          interp.setVar("tcl_interactive", "1", TCL.VarFlag.GLOBAL_ONLY);
        }
        else
        {
          interp.setVar("argv0", fileName, TCL.VarFlag.GLOBAL_ONLY);
          interp.setVar("tcl_interactive", "0", TCL.VarFlag.GLOBAL_ONLY);
          i++;
          argc--;
        }
        for (; i < args.Length; i++)
        {
          TclList.append(interp, argv, TclString.newInstance(args[i]));
        }
        interp.setVar("argv", argv, TCL.VarFlag.GLOBAL_ONLY);
        interp.setVar("argc", System.Convert.ToString(argc), TCL.VarFlag.GLOBAL_ONLY);
      }
      catch (TclException e)
      {
        throw new TclRuntimeError("unexpected TclException: " + e.Message);
      }
      finally
      {
        argv.release();
      }

      // Normally we would do application specific initialization here.
      // However, that feature is not currently supported.
      // If a script file was specified then just source that file
      // and quit.

      Console.WriteLine("C#-TCL version " + Assembly.GetExecutingAssembly().GetName().Version.ToString());
      Console.WriteLine("==============================================================");
      Console.WriteLine("");

      if ((System.Object)fileName != null)
      {
        try
        {
          interp.evalFile(fileName);
        }
        catch (TclException e)
        {
          TCL.CompletionCode code = e.getCompletionCode();
          if (code == TCL.CompletionCode.RETURN)
          {
            code = interp.updateReturnInfo();
            if (code != TCL.CompletionCode.OK)
            {
              System.Console.Error.WriteLine("command returned bad code: " + code);
              if (tcl.lang.ConsoleThread.debug) System.Diagnostics.Debug.WriteLine("command returned bad code: " + code);
            }
          }
          else if (code == TCL.CompletionCode.ERROR)
          {
            System.Console.Error.WriteLine(interp.getResult().ToString());
            if (tcl.lang.ConsoleThread.debug) System.Diagnostics.Debug.WriteLine(interp.getResult().ToString());
            System.Diagnostics.Debug.Assert(false, interp.getResult().ToString());
          }
          else
          {
            System.Console.Error.WriteLine("command returned bad code: " + code);
            if (tcl.lang.ConsoleThread.debug) System.Diagnostics.Debug.WriteLine("command returned bad code: " + code);
          }
        }

        // Note that if the above interp.evalFile() returns the main
        // thread will exit.  This may bring down the VM and stop
        // the execution of Tcl.
        //
        // If the script needs to handle events, it must call
        // vwait or do something similar.
        //
        // Note that the script can create AWT widgets. This will
        // start an AWT event handling thread and keep the VM up. However,
        // the interpreter thread (the same as the main thread) would
        // have exited and no Tcl scripts can be executed.

        interp.dispose();

        System.Environment.Exit(0);
      }

      if ((System.Object)fileName == null)
      {
        // We are running in interactive mode. Start the ConsoleThread
        // that loops, grabbing stdin and passing it to the interp.

        ConsoleThread consoleThread = new ConsoleThread(interp);
        consoleThread.IsBackground = true;
        consoleThread.Start();

        // Loop forever to handle user input events in the command line.

        Notifier notifier = interp.getNotifier();
        while (true)
        {
          // process events until "exit" is called.

          notifier.doOneEvent(TCL.ALL_EVENTS);
        }
      }
    }
  }
    /// <summary>----------------------------------------------------------------------
    /// 
    /// Tcl_StringObjCmd -> StringCmd.cmdProc
    /// 
    /// This procedure is invoked to process the "string" Tcl command.
    /// See the user documentation for details on what it does.
    /// 
    /// Results:
    /// None.
    /// 
    /// Side effects:
    /// See the user documentation.
    /// 
    /// ----------------------------------------------------------------------
    /// </summary>

    public TCL.CompletionCode cmdProc( Interp interp, TclObject[] objv )
    {
      if ( objv.Length < 2 )
      {
        throw new TclNumArgsException( interp, 1, objv, "option arg ?arg ...?" );
      }
      int index = TclIndex.get( interp, objv[1], options, "option", 0 );

      switch ( index )
      {

        case STR_EQUAL:
        case STR_COMPARE:
          {

            if ( objv.Length < 4 || objv.Length > 7 )
            {
              throw new TclNumArgsException( interp, 2, objv, "?-nocase? ?-length int? string1 string2" );
            }

            bool nocase = false;
            int reqlength = -1;
            for ( int i = 2; i < objv.Length - 2; i++ )
            {

              string string2 = objv[i].ToString();
              int length2 = string2.Length;
              if ( ( length2 > 1 ) && "-nocase".StartsWith( string2 ) )
              {
                nocase = true;
              }
              else if ( ( length2 > 1 ) && "-length".StartsWith( string2 ) )
              {
                if ( i + 1 >= objv.Length - 2 )
                {
                  throw new TclNumArgsException( interp, 2, objv, "?-nocase? ?-length int? string1 string2" );
                }
                reqlength = TclInteger.get( interp, objv[++i] );
              }
              else
              {
                throw new TclException( interp, "bad option \"" + string2 + "\": must be -nocase or -length" );
              }
            }


            string string1 = objv[objv.Length - 2].ToString();

            string string3 = objv[objv.Length - 1].ToString();
            int length1 = string1.Length;
            int length3 = string3.Length;

            // This is the min length IN BYTES of the two strings

            int length = ( length1 < length3 ) ? length1 : length3;

            int match;

            if ( reqlength == 0 )
            {
              // Anything matches at 0 chars, right?

              match = 0;
            }
            else if ( nocase || ( ( reqlength > 0 ) && ( reqlength <= length ) ) )
            {
              // In Java, strings are always encoded in unicode, so we do
              // not need to worry about individual char lengths

              // Do the reqlength check again, against 0 as well for
              // the benfit of nocase

              if ( ( reqlength > 0 ) && ( reqlength < length ) )
              {
                length = reqlength;
              }
              else if ( reqlength < 0 )
              {
                // The requested length is negative, so we ignore it by
                // setting it to the longer of the two lengths.

                reqlength = ( length1 > length3 ) ? length1 : length3;
              }
              if ( nocase )
              {
                string1 = string1.ToLower();
                string3 = string3.ToLower();
              }
              match = System.Globalization.CultureInfo.InvariantCulture.CompareInfo.Compare( string1, 0, length, string3, 0, length, System.Globalization.CompareOptions.Ordinal );
              // match = string1.Substring(0, (length) - (0)).CompareTo(string3.Substring(0, (length) - (0)));

              if ( ( match == 0 ) && ( reqlength > length ) )
              {
                match = length1 - length3;
              }
            }
            else
            {
              match = System.Globalization.CultureInfo.InvariantCulture.CompareInfo.Compare( string1, 0, length, string3, 0, length, System.Globalization.CompareOptions.Ordinal );
              // ATK match = string1.Substring(0, (length) - (0)).CompareTo(string3.Substring(0, (length) - (0)));
              if ( match == 0 )
              {
                match = length1 - length3;
              }
            }

            if ( index == STR_EQUAL )
            {
              interp.setResult( ( match != 0 ) ? false : true );
            }
            else
            {
              interp.setResult( ( ( match > 0 ) ? 1 : ( match < 0 ) ? -1 : 0 ) );
            }
            break;
          }


        case STR_FIRST:
          {
            if ( objv.Length < 4 || objv.Length > 5 )
            {
              throw new TclNumArgsException( interp, 2, objv, "subString string ?startIndex?" );
            }

            string string1 = objv[2].ToString();

            string string2 = objv[3].ToString();
            int length2 = string2.Length;

            int start = 0;

            if ( objv.Length == 5 )
            {
              // If a startIndex is specified, we will need to fast
              // forward to that point in the string before we think
              // about a match.

              start = Util.getIntForIndex( interp, objv[4], length2 - 1 );
              if ( start >= length2 )
              {
                interp.setResult( -1 );
                return TCL.CompletionCode.RETURN;
              }
            }

            if ( string1.Length == 0 )
            {
              interp.setResult( -1 );
            }
            else
            {

              interp.setResult( string2.IndexOf( string1, start ) );
            }
            break;
          }


        case STR_INDEX:
          {
            if ( objv.Length != 4 )
            {
              throw new TclNumArgsException( interp, 2, objv, "string charIndex" );
            }


            string string1 = objv[2].ToString();
            int length1 = string1.Length;

            int i = Util.getIntForIndex( interp, objv[3], length1 - 1 );

            if ( ( i >= 0 ) && ( i < length1 ) )
            {
              interp.setResult( string1.Substring( i, ( i + 1 ) - ( i ) ) );
            }
            break;
          }


        case STR_IS:
          {
            if ( objv.Length < 4 || objv.Length > 7 )
            {
              throw new TclNumArgsException( interp, 2, objv, "class ?-strict? ?-failindex var? str" );
            }
            index = TclIndex.get( interp, objv[2], isOptions, "class", 0 );

            bool strict = false;
            TclObject failVarObj = null;

            if ( objv.Length != 4 )
            {
              for ( int i = 3; i < objv.Length - 1; i++ )
              {

                string string2 = objv[i].ToString();
                int length2 = string2.Length;
                if ( ( length2 > 1 ) && "-strict".StartsWith( string2 ) )
                {
                  strict = true;
                }
                else if ( ( length2 > 1 ) && "-failindex".StartsWith( string2 ) )
                {
                  if ( i + 1 >= objv.Length - 1 )
                  {
                    throw new TclNumArgsException( interp, 3, objv, "?-strict? ?-failindex var? str" );
                  }
                  failVarObj = objv[++i];
                }
                else
                {
                  throw new TclException( interp, "bad option \"" + string2 + "\": must be -strict or -failindex" );
                }
              }
            }

            bool result = true;
            int failat = 0;

            // We get the objPtr so that we can short-cut for some classes
            // by checking the object type (int and double), but we need
            // the string otherwise, because we don't want any conversion
            // of type occuring (as, for example, Tcl_Get*FromObj would do

            TclObject obj = objv[objv.Length - 1];

            string string1 = obj.ToString();
            int length1 = string1.Length;
            if ( length1 == 0 )
            {
              if ( strict )
              {
                result = false;
              }
            }

            switch ( index )
            {

              case STR_IS_BOOL:
              case STR_IS_TRUE:
              case STR_IS_FALSE:
                {
                  if ( obj.InternalRep is TclBoolean )
                  {
                    if ( ( ( index == STR_IS_TRUE ) && !TclBoolean.get( interp, obj ) ) || ( ( index == STR_IS_FALSE ) && TclBoolean.get( interp, obj ) ) )
                    {
                      result = false;
                    }
                  }
                  else
                  {
                    try
                    {
                      bool i = TclBoolean.get( null, obj );
                      if ( ( ( index == STR_IS_TRUE ) && !i ) || ( ( index == STR_IS_FALSE ) && i ) )
                      {
                        result = false;
                      }
                    }
                    catch ( TclException e )
                    {
                      result = false;
                    }
                  }
                  break;
                }

              case STR_IS_DOUBLE:
                {
                  if ( ( obj.InternalRep is TclDouble ) || ( obj.InternalRep is TclInteger ) )
                  {
                    break;
                  }

                  // This is adapted from Tcl_GetDouble
                  //
                  // The danger in this function is that
                  // "12345678901234567890" is an acceptable 'double',
                  // but will later be interp'd as an int by something
                  // like [expr].  Therefore, we check to see if it looks
                  // like an int, and if so we do a range check on it.
                  // If strtoul gets to the end, we know we either
                  // received an acceptable int, or over/underflow

                  if ( Expression.looksLikeInt( string1, length1, 0 ) )
                  {
                    char c = string1[0];
                    int signIx = ( c == '-' || c == '+' ) ? 1 : 0;
                    StrtoulResult res = Util.strtoul( string1, signIx, 0 );
                    if ( res.index == length1 )
                    {
                      if ( res.errno == TCL.INTEGER_RANGE )
                      {
                        result = false;
                        failat = -1;
                      }
                      break;
                    }
                  }

                  char c2 = string1[0];
                  int signIx2 = ( c2 == '-' || c2 == '+' ) ? 1 : 0;
                  StrtodResult res2 = Util.strtod( string1, signIx2 );
                  if ( res2.errno == TCL.DOUBLE_RANGE )
                  {
                    // if (errno == ERANGE), then it was an over/underflow
                    // problem, but in this method, we only want to know
                    // yes or no, so bad flow returns 0 (false) and sets
                    // the failVarObj to the string length.

                    result = false;
                    failat = -1;
                  }
                  else if ( res2.index == 0 )
                  {
                    // In this case, nothing like a number was found

                    result = false;
                    failat = 0;
                  }
                  else
                  {
                    // Go onto SPACE, since we are
                    // allowed trailing whitespace

                    failat = res2.index;
                    for ( int i = res2.index; i < length1; i++ )
                    {
                      if ( !System.Char.IsWhiteSpace( string1[i] ) )
                      {
                        result = false;
                        break;
                      }
                    }
                  }
                  break;
                }

              case STR_IS_INT:
                {
                  if ( obj.InternalRep is TclInteger )
                  {
                    break;
                  }
                  bool isInteger = true;
                  try
                  {
                    TclInteger.get( null, obj );
                  }
                  catch ( TclException e )
                  {
                    isInteger = false;
                  }
                  if ( isInteger )
                  {
                    break;
                  }

                  char c = string1[0];
                  int signIx = ( c == '-' || c == '+' ) ? 1 : 0;
                  StrtoulResult res = Util.strtoul( string1, signIx, 0 );
                  if ( res.errno == TCL.INTEGER_RANGE )
                  {
                    // if (errno == ERANGE), then it was an over/underflow
                    // problem, but in this method, we only want to know
                    // yes or no, so bad flow returns false and sets
                    // the failVarObj to the string length.

                    result = false;
                    failat = -1;
                  }
                  else if ( res.index == 0 )
                  {
                    // In this case, nothing like a number was found

                    result = false;
                    failat = 0;
                  }
                  else
                  {
                    // Go onto SPACE, since we are
                    // allowed trailing whitespace

                    failat = res.index;
                    for ( int i = res.index; i < length1; i++ )
                    {
                      if ( !System.Char.IsWhiteSpace( string1[i] ) )
                      {
                        result = false;
                        break;
                      }
                    }
                  }
                  break;
                }

              case STR_IS_WIDE:
                {
                  if ( obj.InternalRep is TclLong )
                  {
                    break;
                  }
                  bool isInteger = true;
                  try
                  {
                    TclLong.get( null, obj );
                  }
                  catch ( TclException e )
                  {
                    isInteger = false;
                  }
                  if ( isInteger )
                  {
                    break;
                  }

                  char c = string1[0];
                  int signIx = ( c == '-' || c == '+' ) ? 1 : 0;
                  StrtoulResult res = Util.strtoul( string1, signIx, 0 );
                  if ( res.errno == TCL.INTEGER_RANGE )
                  {
                    // if (errno == ERANGE), then it was an over/underflow
                    // problem, but in this method, we only want to know
                    // yes or no, so bad flow returns false and sets
                    // the failVarObj to the string length.

                    result = false;
                    failat = -1;
                  }
                  else if ( res.index == 0 )
                  {
                    // In this case, nothing like a number was found

                    result = false;
                    failat = 0;
                  }
                  else
                  {
                    // Go onto SPACE, since we are
                    // allowed trailing whitespace

                    failat = res.index;
                    for ( int i = res.index; i < length1; i++ )
                    {
                      if ( !System.Char.IsWhiteSpace( string1[i] ) )
                      {
                        result = false;
                        break;
                      }
                    }
                  }
                  break;
                }

              default:
                {
                  for ( failat = 0; failat < length1; failat++ )
                  {
                    char c = string1[failat];
                    switch ( index )
                    {

                      case STR_IS_ASCII:

                        result = c < 0x80;
                        break;

                      case STR_IS_ALNUM:
                        result = System.Char.IsLetterOrDigit( c );
                        break;

                      case STR_IS_ALPHA:
                        result = System.Char.IsLetter( c );
                        break;

                      case STR_IS_DIGIT:
                        result = System.Char.IsDigit( c );
                        break;

                      case STR_IS_GRAPH:
                        result = ( ( 1 << (int)System.Char.GetUnicodeCategory( c ) ) & PRINT_BITS ) != 0 && c != ' ';
                        break;

                      case STR_IS_PRINT:
                        result = ( ( 1 << (int)System.Char.GetUnicodeCategory( c ) ) & PRINT_BITS ) != 0;
                        break;

                      case STR_IS_PUNCT:
                        result = ( ( 1 << (int)System.Char.GetUnicodeCategory( c ) ) & PUNCT_BITS ) != 0;
                        break;

                      case STR_IS_UPPER:
                        result = System.Char.IsUpper( c );
                        break;

                      case STR_IS_SPACE:
                        result = System.Char.IsWhiteSpace( c );
                        break;

                      case STR_IS_CONTROL:
                        result = ( System.Char.GetUnicodeCategory( c ) == System.Globalization.UnicodeCategory.Control );
                        break;

                      case STR_IS_LOWER:
                        result = System.Char.IsLower( c );
                        break;

                      case STR_IS_WORD:
                        result = ( ( 1 << (int)System.Char.GetUnicodeCategory( c ) ) & WORD_BITS ) != 0;
                        break;

                      case STR_IS_XDIGIT:
                        result = "0123456789ABCDEFabcdef".IndexOf( c ) >= 0;
                        break;

                      default:
                        throw new TclRuntimeError( "unimplemented" );

                    }
                    if ( !result )
                    {
                      break;
                    }
                  }
                }
                break;

            }

            // Only set the failVarObj when we will return 0
            // and we have indicated a valid fail index (>= 0)

            if ( ( !result ) && ( failVarObj != null ) )
            {
              interp.setVar( failVarObj, TclInteger.newInstance( failat ), 0 );
            }
            interp.setResult( result );
            break;
          }


        case STR_LAST:
          {
            if ( objv.Length < 4 || objv.Length > 5 )
            {
              throw new TclNumArgsException( interp, 2, objv, "subString string ?startIndex?" );
            }

            string string1 = objv[2].ToString();

            string string2 = objv[3].ToString();
            int length2 = string2.Length;

            int start = 0;
            if ( objv.Length == 5 )
            {
              // If a startIndex is specified, we will need to fast
              // forward to that point in the string before we think
              // about a match.

              start = Util.getIntForIndex( interp, objv[4], length2 - 1 );
              if ( start < 0 )
              {
                interp.setResult( -1 );
                break;
              }
              else if ( start < length2 )
              {
                string2 = string2.Substring( 0, ( start + 1 ) - ( 0 ) );
              }
            }

            if ( string1.Length == 0 )
            {
              interp.setResult( -1 );
            }
            else
            {
              interp.setResult( string2.LastIndexOf( string1 ) );
            }
            break;
          }


        case STR_BYTELENGTH:
          if ( objv.Length != 3 )
          {
            throw new TclNumArgsException( interp, 2, objv, "string" );
          }

          interp.setResult( Utf8Count( objv[2].ToString() ) );
          break;


        case STR_LENGTH:
          {
            if ( objv.Length != 3 )
            {
              throw new TclNumArgsException( interp, 2, objv, "string" );
            }

            interp.setResult( objv[2].ToString().Length );
            break;
          }


        case STR_MAP:
          {
            if ( objv.Length < 4 || objv.Length > 5 )
            {
              throw new TclNumArgsException( interp, 2, objv, "?-nocase? charMap string" );
            }

            bool nocase = false;
            if ( objv.Length == 5 )
            {

              string string2 = objv[2].ToString();
              int length2 = string2.Length;
              if ( ( length2 > 1 ) && "-nocase".StartsWith( string2 ) )
              {
                nocase = true;
              }
              else
              {
                throw new TclException( interp, "bad option \"" + string2 + "\": must be -nocase" );
              }
            }

            TclObject[] mapElemv = TclList.getElements( interp, objv[objv.Length - 2] );
            if ( mapElemv.Length == 0 )
            {
              // empty charMap, just return whatever string was given

              interp.setResult( objv[objv.Length - 1] );
            }
            else if ( ( mapElemv.Length % 2 ) != 0 )
            {
              // The charMap must be an even number of key/value items

              throw new TclException( interp, "char map list unbalanced" );
            }

            string string1 = objv[objv.Length - 1].ToString();
            string cmpString1;
            if ( nocase )
            {
              cmpString1 = string1.ToLower();
            }
            else
            {
              cmpString1 = string1;
            }
            int length1 = string1.Length;
            if ( length1 == 0 )
            {
              // Empty input string, just stop now

              break;
            }

            // Precompute pointers to the unicode string and length.
            // This saves us repeated function calls later,
            // significantly speeding up the algorithm.

            string[] mapStrings = new string[mapElemv.Length];
            int[] mapLens = new int[mapElemv.Length];
            for ( int ix = 0; ix < mapElemv.Length; ix++ )
            {

              mapStrings[ix] = mapElemv[ix].ToString();
              mapLens[ix] = mapStrings[ix].Length;
            }
            string[] cmpStrings;
            if ( nocase )
            {
              cmpStrings = new string[mapStrings.Length];
              for ( int ix = 0; ix < mapStrings.Length; ix++ )
              {
                cmpStrings[ix] = mapStrings[ix].ToLower();
              }
            }
            else
            {
              cmpStrings = mapStrings;
            }

            TclObject result = TclString.newInstance( "" );
            int p, str1;
            for ( p = 0, str1 = 0; str1 < length1; str1++ )
            {
              for ( index = 0; index < mapStrings.Length; index += 2 )
              {
                // Get the key string to match on

                string string2 = mapStrings[index];
                int length2 = mapLens[index];
                if ( ( length2 > 0 ) && ( cmpString1.Substring( str1 ).StartsWith( cmpStrings[index] ) ) )
                {
                  if ( p != str1 )
                  {
                    // Put the skipped chars onto the result first

                    TclString.append( result, string1.Substring( p, ( str1 ) - ( p ) ) );
                    p = str1 + length2;
                  }
                  else
                  {
                    p += length2;
                  }

                  // Adjust len to be full length of matched string

                  str1 = p - 1;

                  // Append the map value to the unicode string

                  TclString.append( result, mapStrings[index + 1] );
                  break;
                }
              }
            }

            if ( p != str1 )
            {
              // Put the rest of the unmapped chars onto result

              TclString.append( result, string1.Substring( p, ( str1 ) - ( p ) ) );
            }
            interp.setResult( result );
            break;
          }


        case STR_MATCH:
          {
            if ( objv.Length < 4 || objv.Length > 5 )
            {
              throw new TclNumArgsException( interp, 2, objv, "?-nocase? pattern string" );
            }

            string string1, string2;
            if ( objv.Length == 5 )
            {

              string inString = objv[2].ToString();
              if ( !( ( inString.Length > 1 ) && "-nocase".StartsWith( inString ) ) )
              {
                throw new TclException( interp, "bad option \"" + inString + "\": must be -nocase" );
              }

              string1 = objv[4].ToString().ToLower();

              string2 = objv[3].ToString().ToLower();
            }
            else
            {

              string1 = objv[3].ToString();

              string2 = objv[2].ToString();
            }

            interp.setResult( Util.stringMatch( string1, string2 ) );
            break;
          }


        case STR_RANGE:
          {
            if ( objv.Length != 5 )
            {
              throw new TclNumArgsException( interp, 2, objv, "string first last" );
            }


            string string1 = objv[2].ToString();
            int length1 = string1.Length;

            int first = Util.getIntForIndex( interp, objv[3], length1 - 1 );
            if ( first < 0 )
            {
              first = 0;
            }
            int last = Util.getIntForIndex( interp, objv[4], length1 - 1 );
            if ( last >= length1 )
            {
              last = length1 - 1;
            }

            if ( first > last )
            {
              interp.resetResult();
            }
            else
            {
              interp.setResult( string1.Substring( first, ( last + 1 ) - ( first ) ) );
            }
            break;
          }


        case STR_REPEAT:
          {
            if ( objv.Length != 4 )
            {
              throw new TclNumArgsException( interp, 2, objv, "string count" );
            }

            int count = TclInteger.get( interp, objv[3] );


            string string1 = objv[2].ToString();
            if ( string1.Length > 0 )
            {
              TclObject tstr = TclString.newInstance( "" );
              for ( index = 0; index < count; index++ )
              {
                TclString.append( tstr, string1 );
              }
              interp.setResult( tstr );
            }
            break;
          }


        case STR_REPLACE:
          {
            if ( objv.Length < 5 || objv.Length > 6 )
            {
              throw new TclNumArgsException( interp, 2, objv, "string first last ?string?" );
            }


            string string1 = objv[2].ToString();
            int length1 = string1.Length - 1;

            int first = Util.getIntForIndex( interp, objv[3], length1 );
            int last = Util.getIntForIndex( interp, objv[4], length1 );

            if ( ( last < first ) || ( first > length1 ) || ( last < 0 ) )
            {
              interp.setResult( objv[2] );
            }
            else
            {
              if ( first < 0 )
              {
                first = 0;
              }
              string start = string1.Substring( first );
              int ind = ( ( last > length1 ) ? length1 : last ) - first + 1;
              string end;
              if ( ind <= 0 )
              {
                end = start;
              }
              else if ( ind >= start.Length )
              {
                end = "";
              }
              else
              {
                end = start.Substring( ind );
              }

              TclObject tstr = TclString.newInstance( string1.Substring( 0, ( first ) - ( 0 ) ) );

              if ( objv.Length == 6 )
              {
                TclString.append( tstr, objv[5] );
              }
              if ( last < length1 )
              {
                TclString.append( tstr, end );
              }

              interp.setResult( tstr );
            }
            break;
          }


        case STR_TOLOWER:
        case STR_TOUPPER:
        case STR_TOTITLE:
          {
            if ( objv.Length < 3 || objv.Length > 5 )
            {
              throw new TclNumArgsException( interp, 2, objv, "string ?first? ?last?" );
            }

            string string1 = objv[2].ToString();

            if ( objv.Length == 3 )
            {
              if ( index == STR_TOLOWER )
              {
                interp.setResult( string1.ToLower() );
              }
              else if ( index == STR_TOUPPER )
              {
                interp.setResult( string1.ToUpper() );
              }
              else
              {
                interp.setResult( Util.toTitle( string1 ) );
              }
            }
            else
            {
              int length1 = string1.Length - 1;
              int first = Util.getIntForIndex( interp, objv[3], length1 );
              if ( first < 0 )
              {
                first = 0;
              }
              int last = first;
              if ( objv.Length == 5 )
              {
                last = Util.getIntForIndex( interp, objv[4], length1 );
              }
              if ( last >= length1 )
              {
                last = length1;
              }
              if ( last < first )
              {
                interp.setResult( objv[2] );
                break;
              }

              string string2;
              StringBuilder buf = new StringBuilder();
              buf.Append( string1.Substring( 0, ( first ) - ( 0 ) ) );
              if ( last + 1 > length1 )
              {
                string2 = string1.Substring( first );
              }
              else
              {
                string2 = string1.Substring( first, ( last + 1 ) - ( first ) );
              }
              if ( index == STR_TOLOWER )
              {
                buf.Append( string2.ToLower() );
              }
              else if ( index == STR_TOUPPER )
              {
                buf.Append( string2.ToUpper() );
              }
              else
              {
                buf.Append( Util.toTitle( string2 ) );
              }
              if ( last + 1 <= length1 )
              {
                buf.Append( string1.Substring( last + 1 ) );
              }

              interp.setResult( buf.ToString() );
            }
            break;
          }


        case STR_TRIM:
          {
            if ( objv.Length == 3 )
            {
              // Case 1: "string trim str" --
              // Remove leading and trailing white space


              interp.setResult( objv[2].ToString().Trim() );
            }
            else if ( objv.Length == 4 )
            {

              // Case 2: "string trim str chars" --
              // Remove leading and trailing chars in the chars set


              string tmp = Util.TrimLeft( objv[2].ToString(), objv[3].ToString() );

              interp.setResult( Util.TrimRight( tmp, objv[3].ToString() ) );
            }
            else
            {
              // Case 3: Wrong # of args

              throw new TclNumArgsException( interp, 2, objv, "string ?chars?" );
            }
            break;
          }


        case STR_TRIMLEFT:
          {
            if ( objv.Length == 3 )
            {
              // Case 1: "string trimleft str" --
              // Remove leading and trailing white space


              interp.setResult( Util.TrimLeft( objv[2].ToString() ) );
            }
            else if ( objv.Length == 4 )
            {
              // Case 2: "string trimleft str chars" --
              // Remove leading and trailing chars in the chars set


              interp.setResult( Util.TrimLeft( objv[2].ToString(), objv[3].ToString() ) );
            }
            else
            {
              // Case 3: Wrong # of args

              throw new TclNumArgsException( interp, 2, objv, "string ?chars?" );
            }
            break;
          }


        case STR_TRIMRIGHT:
          {
            if ( objv.Length == 3 )
            {
              // Case 1: "string trimright str" --
              // Remove leading and trailing white space


              interp.setResult( Util.TrimRight( objv[2].ToString() ) );
            }
            else if ( objv.Length == 4 )
            {
              // Case 2: "string trimright str chars" --
              // Remove leading and trailing chars in the chars set


              interp.setResult( Util.TrimRight( objv[2].ToString(), objv[3].ToString() ) );
            }
            else
            {
              // Case 3: Wrong # of args

              throw new TclNumArgsException( interp, 2, objv, "string ?chars?" );
            }
            break;
          }


        case STR_WORDEND:
          {
            if ( objv.Length != 4 )
            {
              throw new TclNumArgsException( interp, 2, objv, "string index" );
            }


            string string1 = objv[2].ToString();
            char[] strArray = string1.ToCharArray();
            int cur;
            int length1 = string1.Length;
            index = Util.getIntForIndex( interp, objv[3], length1 - 1 );

            if ( index < 0 )
            {
              index = 0;
            }
            if ( index >= length1 )
            {
              interp.setResult( length1 );
              return TCL.CompletionCode.RETURN;
            }
            for ( cur = index; cur < length1; cur++ )
            {
              char c = strArray[cur];
              if ( ( ( 1 << (int)System.Char.GetUnicodeCategory( c ) ) & WORD_BITS ) == 0 )
              {
                break;
              }
            }
            if ( cur == index )
            {
              cur = index + 1;
            }
            interp.setResult( cur );
            break;
          }


        case STR_WORDSTART:
          {
            if ( objv.Length != 4 )
            {
              throw new TclNumArgsException( interp, 2, objv, "string index" );
            }


            string string1 = objv[2].ToString();
            char[] strArray = string1.ToCharArray();
            int cur;
            int length1 = string1.Length;
            index = Util.getIntForIndex( interp, objv[3], length1 - 1 );

            if ( index > length1 )
            {
              index = length1 - 1;
            }
            if ( index < 0 )
            {
              interp.setResult( 0 );
              return TCL.CompletionCode.RETURN;
            }
            for ( cur = index; cur >= 0; cur-- )
            {
              char c = strArray[cur];
              if ( ( ( 1 << (int)System.Char.GetUnicodeCategory( c ) ) & WORD_BITS ) == 0 )
              {
                break;
              }
            }
            if ( cur != index )
            {
              cur += 1;
            }
            interp.setResult( cur );
            break;
          }
      }
      return TCL.CompletionCode.RETURN;
    }
Exemplo n.º 17
0
    public void traceProc( Interp interp, string name1, string name2, TCL.VarFlag flags )
    {
      // If the variable is unset, then recreate the trace and restore
      // the default value of the format string.

      if ( ( flags & TCL.VarFlag.TRACE_UNSETS ) != 0 )
      {
        if ( ( ( flags & TCL.VarFlag.TRACE_DESTROYED ) != 0 ) && ( ( flags & TCL.VarFlag.INTERP_DESTROYED ) == 0 ) )
        {
          interp.traceVar( name1, name2, new PrecTraceProc(), TCL.VarFlag.GLOBAL_ONLY | TCL.VarFlag.TRACE_WRITES | TCL.VarFlag.TRACE_READS | TCL.VarFlag.TRACE_UNSETS );
          Util.precision = Util.DEFAULT_PRECISION;
        }
        return;
      }

      // When the variable is read, reset its value from our shared
      // value. This is needed in case the variable was modified in
      // some other interpreter so that this interpreter's value is
      // out of date.

      if ( ( flags & TCL.VarFlag.TRACE_READS ) != 0 )
      {
        interp.setVar( name1, name2, TclInteger.newInstance( Util.precision ), flags & TCL.VarFlag.GLOBAL_ONLY );
        return;
      }

      // The variable is being written. Check the new value and disallow
      // it if it isn't reasonable.
      //
      // (ToDo) Disallow it if this is a safe interpreter (we don't want
      // safe interpreters messing up the precision of other
      // interpreters).

      TclObject tobj = null;
      try
      {
        tobj = interp.getVar( name1, name2, ( flags & TCL.VarFlag.GLOBAL_ONLY ) );
      }
      catch ( TclException e )
      {
        // Do nothing when var does not exist.
      }

      string value;

      if ( tobj != null )
      {

        value = tobj.ToString();
      }
      else
      {
        value = "";
      }

      StrtoulResult r = Util.strtoul( value, 0, 10 );

      if ( ( r == null ) || ( r.value <= 0 ) || ( r.value > TCL_MAX_PREC ) || ( r.value > 100 ) || ( r.index == 0 ) || ( r.index != value.Length ) )
      {
        interp.setVar( name1, name2, TclInteger.newInstance( Util.precision ), TCL.VarFlag.GLOBAL_ONLY );
        throw new TclException( interp, "improper value for precision" );
      }

      Util.precision = (int)r.value;
    }
    public TCL.CompletionCode cmdProc( Interp interp, TclObject[] argv )
    {
      int arg; // Index of next argument to consume.
      char[] format = null; // User specified format string.
      char cmd; // Current format character.
      int cursor; // Current position within result buffer.
      int maxPos; // Greatest position within result buffer that
      // cursor has visited.
      int value = 0; // Current integer value to be packed.
      // Initialized to avoid compiler warning.
      int offset, size = 0, length;//, index;

      if ( argv.Length < 2 )
      {
        throw new TclNumArgsException( interp, 1, argv, "option ?arg arg ...?" );
      }
      int cmdIndex = TclIndex.get( interp, argv[1], validCmds, "option", 0 );

      switch ( cmdIndex )
      {

        case CMD_FORMAT:
          {
            if ( argv.Length < 3 )
            {
              throw new TclNumArgsException( interp, 2, argv, "formatString ?arg arg ...?" );
            }

            // To avoid copying the data, we format the string in two passes.
            // The first pass computes the size of the output buffer.  The
            // second pass places the formatted data into the buffer.

            format = argv[2].ToString().ToCharArray();
            arg = 3;
            length = 0;
            offset = 0;
            System.Int32 parsePos = 0;

            while ( ( cmd = GetFormatSpec( format, ref parsePos ) ) != FORMAT_END )
            {
              int count = GetFormatCount( format, ref parsePos );

              switch ( cmd )
              {

                case 'a':
                case 'A':
                case 'b':
                case 'B':
                case 'h':
                case 'H':
                  {
                    // For string-type specifiers, the count corresponds
                    // to the number of bytes in a single argument.

                    if ( arg >= argv.Length )
                    {
                      missingArg( interp );
                    }
                    if ( count == BINARY_ALL )
                    {
                      count = TclByteArray.getLength( interp, argv[arg] );
                    }
                    else if ( count == BINARY_NOCOUNT )
                    {
                      count = 1;
                    }
                    arg++;
                    switch ( cmd )
                    {

                      case 'a':
                      case 'A':
                        offset += count;
                        break;

                      case 'b':
                      case 'B':
                        offset += ( count + 7 ) / 8;
                        break;

                      case 'h':
                      case 'H':
                        offset += ( count + 1 ) / 2;
                        break;
                    }
                    break;
                  }

                case 'c':
                case 's':
                case 'S':
                case 'i':
                case 'I':
                case 'f':
                case 'd':
                  {
                    if ( arg >= argv.Length )
                    {
                      missingArg( interp );
                    }
                    switch ( cmd )
                    {

                      case 'c':
                        size = 1;
                        break;

                      case 's':
                      case 'S':
                        size = 2;
                        break;

                      case 'i':
                      case 'I':
                        size = 4;
                        break;

                      case 'f':
                        size = 4;
                        break;

                      case 'd':
                        size = 8;
                        break;
                    }

                    // For number-type specifiers, the count corresponds
                    // to the number of elements in the list stored in
                    // a single argument.  If no count is specified, then
                    // the argument is taken as a single non-list value.

                    if ( count == BINARY_NOCOUNT )
                    {
                      arg++;
                      count = 1;
                    }
                    else
                    {
                      int listc = TclList.getLength( interp, argv[arg++] );
                      if ( count == BINARY_ALL )
                      {
                        count = listc;
                      }
                      else if ( count > listc )
                      {
                        throw new TclException( interp, "number of elements in list" + " does not match count" );
                      }
                    }
                    offset += count * size;
                    break;
                  }

                case 'x':
                  {
                    if ( count == BINARY_ALL )
                    {
                      throw new TclException( interp, "cannot use \"*\"" + " in format string with \"x\"" );
                    }
                    if ( count == BINARY_NOCOUNT )
                    {
                      count = 1;
                    }
                    offset += count;
                    break;
                  }

                case 'X':
                  {
                    if ( count == BINARY_NOCOUNT )
                    {
                      count = 1;
                    }
                    if ( ( count > offset ) || ( count == BINARY_ALL ) )
                    {
                      count = offset;
                    }
                    if ( offset > length )
                    {
                      length = offset;
                    }
                    offset -= count;
                    break;
                  }

                case '@':
                  {
                    if ( offset > length )
                    {
                      length = offset;
                    }
                    if ( count == BINARY_ALL )
                    {
                      offset = length;
                    }
                    else if ( count == BINARY_NOCOUNT )
                    {
                      alephWithoutCount( interp );
                    }
                    else
                    {
                      offset = count;
                    }
                    break;
                  }

                default:
                  {
                    badField( interp, cmd );
                  }
                  break;

              }
            }
            if ( offset > length )
            {
              length = offset;
            }
            if ( length == 0 )
            {
              return TCL.CompletionCode.RETURN;
            }

            // Prepare the result object by preallocating the calculated
            // number of bytes and filling with nulls.

            TclObject resultObj = TclByteArray.newInstance();
            byte[] resultBytes = TclByteArray.setLength( interp, resultObj, length );
            interp.setResult( resultObj );

            // Pack the data into the result object.  Note that we can skip
            // the error checking during this pass, since we have already
            // parsed the string once.

            arg = 3;
            cursor = 0;
            maxPos = cursor;
            parsePos = 0;

            while ( ( cmd = GetFormatSpec( format, ref parsePos ) ) != FORMAT_END )
            {
              int count = GetFormatCount( format, ref parsePos );

              if ( ( count == 0 ) && ( cmd != '@' ) )
              {
                arg++;
                continue;
              }

              switch ( cmd )
              {

                case 'a':
                case 'A':
                  {
                    byte pad = ( cmd == 'a' ) ? (byte)0 : (byte)SupportClass.Identity( ' ' );
                    byte[] bytes = TclByteArray.getBytes( interp, argv[arg++] );
                    length = bytes.Length;

                    if ( count == BINARY_ALL )
                    {
                      count = length;
                    }
                    else if ( count == BINARY_NOCOUNT )
                    {
                      count = 1;
                    }
                    if ( length >= count )
                    {
                      Array.Copy( bytes, 0, resultBytes, cursor, count );
                    }
                    else
                    {
                      Array.Copy( bytes, 0, resultBytes, cursor, length );
                      for ( int ix = 0; ix < count - length; ix++ )
                      {
                        resultBytes[cursor + length + ix] = pad;
                      }
                    }
                    cursor += count;
                    break;
                  }

                case 'b':
                case 'B':
                  {
                    char[] str = argv[arg++].ToString().ToCharArray();
                    if ( count == BINARY_ALL )
                    {
                      count = str.Length;
                    }
                    else if ( count == BINARY_NOCOUNT )
                    {
                      count = 1;
                    }
                    int last = cursor + ( ( count + 7 ) / 8 );
                    if ( count > str.Length )
                    {
                      count = str.Length;
                    }
                    if ( cmd == 'B' )
                    {
                      for ( offset = 0; offset < count; offset++ )
                      {
                        value <<= 1;
                        if ( str[offset] == '1' )
                        {
                          value |= 1;
                        }
                        else if ( str[offset] != '0' )
                        {
                          expectedButGot( interp, "binary", new string( str ) );
                        }
                        if ( ( ( offset + 1 ) % 8 ) == 0 )
                        {
                          resultBytes[cursor++] = (byte)value;
                          value = 0;
                        }
                      }
                    }
                    else
                    {
                      for ( offset = 0; offset < count; offset++ )
                      {
                        value >>= 1;
                        if ( str[offset] == '1' )
                        {
                          value |= 128;
                        }
                        else if ( str[offset] != '0' )
                        {
                          expectedButGot( interp, "binary", new string( str ) );
                        }
                        if ( ( ( offset + 1 ) % 8 ) == 0 )
                        {
                          resultBytes[cursor++] = (byte)value;
                          value = 0;
                        }
                      }
                    }
                    if ( ( offset % 8 ) != 0 )
                    {
                      if ( cmd == 'B' )
                      {
                        value <<= 8 - ( offset % 8 );
                      }
                      else
                      {
                        value >>= 8 - ( offset % 8 );
                      }
                      resultBytes[cursor++] = (byte)value;
                    }
                    while ( cursor < last )
                    {
                      resultBytes[cursor++] = 0;
                    }
                    break;
                  }

                case 'h':
                case 'H':
                  {
                    char[] str = argv[arg++].ToString().ToCharArray();
                    if ( count == BINARY_ALL )
                    {
                      count = str.Length;
                    }
                    else if ( count == BINARY_NOCOUNT )
                    {
                      count = 1;
                    }
                    int last = cursor + ( ( count + 1 ) / 2 );
                    if ( count > str.Length )
                    {
                      count = str.Length;
                    }
                    if ( cmd == 'H' )
                    {
                      for ( offset = 0; offset < count; offset++ )
                      {
                        value <<= 4;
                        int c = HEXDIGITS.IndexOf( Char.ToLower( str[offset] ) );
                        if ( c < 0 )
                        {
                          expectedButGot( interp, "hexadecimal", new string( str ) );
                        }
                        value |= ( c & 0xf );
                        if ( ( offset % 2 ) != 0 )
                        {
                          resultBytes[cursor++] = (byte)value;
                          value = 0;
                        }
                      }
                    }
                    else
                    {
                      for ( offset = 0; offset < count; offset++ )
                      {
                        value >>= 4;
                        int c = HEXDIGITS.IndexOf( Char.ToLower( str[offset] ) );
                        if ( c < 0 )
                        {
                          expectedButGot( interp, "hexadecimal", new string( str ) );
                        }
                        value |= ( ( c << 4 ) & 0xf0 );
                        if ( ( offset % 2 ) != 0 )
                        {
                          resultBytes[cursor++] = (byte)value;
                          value = 0;
                        }
                      }
                    }
                    if ( ( offset % 2 ) != 0 )
                    {
                      if ( cmd == 'H' )
                      {
                        value <<= 4;
                      }
                      else
                      {
                        value >>= 4;
                      }
                      resultBytes[cursor++] = (byte)value;
                    }
                    while ( cursor < last )
                    {
                      resultBytes[cursor++] = 0;
                    }
                    break;
                  }

                case 'c':
                case 's':
                case 'S':
                case 'i':
                case 'I':
                case 'f':
                case 'd':
                  {
                    TclObject[] listv;

                    if ( count == BINARY_NOCOUNT )
                    {
                      listv = new TclObject[1];
                      listv[0] = argv[arg++];
                      count = 1;
                    }
                    else
                    {
                      listv = TclList.getElements( interp, argv[arg++] );
                      if ( count == BINARY_ALL )
                      {
                        count = listv.Length;
                      }
                    }
                    for ( int ix = 0; ix < count; ix++ )
                    {
                      cursor = FormatNumber( interp, cmd, listv[ix], resultBytes, cursor );
                    }
                    break;
                  }

                case 'x':
                  {
                    if ( count == BINARY_NOCOUNT )
                    {
                      count = 1;
                    }
                    for ( int ix = 0; ix < count; ix++ )
                    {
                      resultBytes[cursor++] = 0;
                    }
                    break;
                  }

                case 'X':
                  {
                    if ( cursor > maxPos )
                    {
                      maxPos = cursor;
                    }
                    if ( count == BINARY_NOCOUNT )
                    {
                      count = 1;
                    }
                    if ( count == BINARY_ALL || count > cursor )
                    {
                      cursor = 0;
                    }
                    else
                    {
                      cursor -= count;
                    }
                    break;
                  }

                case '@':
                  {
                    if ( cursor > maxPos )
                    {
                      maxPos = cursor;
                    }
                    if ( count == BINARY_ALL )
                    {
                      cursor = maxPos;
                    }
                    else
                    {
                      cursor = count;
                    }
                    break;
                  }
              }
            }
            break;
          }

        case CMD_SCAN:
          {
            if ( argv.Length < 4 )
            {
              throw new TclNumArgsException( interp, 2, argv, "value formatString ?varName varName ...?" );
            }
            byte[] src = TclByteArray.getBytes( interp, argv[2] );
            length = src.Length;
            format = argv[3].ToString().ToCharArray();
            arg = 4;
            cursor = 0;
            offset = 0;
            System.Int32 parsePos = 0;

            while ( ( cmd = GetFormatSpec( format, ref parsePos ) ) != FORMAT_END )
            {
              int count = GetFormatCount( format, ref parsePos );

              switch ( cmd )
              {

                case 'a':
                case 'A':
                  {
                    if ( arg >= argv.Length )
                    {
                      missingArg( interp );
                    }
                    if ( count == BINARY_ALL )
                    {
                      count = length - offset;
                    }
                    else
                    {
                      if ( count == BINARY_NOCOUNT )
                      {
                        count = 1;
                      }
                      if ( count > length - offset )
                      {
                        break;
                      }
                    }

                    size = count;

                    // Trim trailing nulls and spaces, if necessary.

                    if ( cmd == 'A' )
                    {
                      while ( size > 0 )
                      {
                        if ( src[offset + size - 1] != '\x0000' && src[offset + size - 1] != ' ' )
                        {
                          break;
                        }
                        size--;
                      }
                    }

                    interp.setVar( argv[arg++], TclByteArray.newInstance( src, offset, size ), 0 );

                    offset += count;
                    break;
                  }

                case 'b':
                case 'B':
                  {
                    if ( arg >= argv.Length )
                    {
                      missingArg( interp );
                    }
                    if ( count == BINARY_ALL )
                    {
                      count = ( length - offset ) * 8;
                    }
                    else
                    {
                      if ( count == BINARY_NOCOUNT )
                      {
                        count = 1;
                      }
                      if ( count > ( length - offset ) * 8 )
                      {
                        break;
                      }
                    }
                    StringBuilder s = new StringBuilder( count );
                    int thisOffset = offset;

                    if ( cmd == 'b' )
                    {
                      for ( int ix = 0; ix < count; ix++ )
                      {
                        if ( ( ix % 8 ) != 0 )
                        {
                          value >>= 1;
                        }
                        else
                        {
                          value = src[thisOffset++];
                        }
                        s.Append( ( value & 1 ) != 0 ? '1' : '0' );
                      }
                    }
                    else
                    {
                      for ( int ix = 0; ix < count; ix++ )
                      {
                        if ( ( ix % 8 ) != 0 )
                        {
                          value <<= 1;
                        }
                        else
                        {
                          value = src[thisOffset++];
                        }
                        s.Append( ( value & 0x80 ) != 0 ? '1' : '0' );
                      }
                    }

                    interp.setVar( argv[arg++], TclString.newInstance( s.ToString() ), 0 );

                    offset += ( count + 7 ) / 8;
                    break;
                  }

                case 'h':
                case 'H':
                  {
                    if ( arg >= argv.Length )
                    {
                      missingArg( interp );
                    }
                    if ( count == BINARY_ALL )
                    {
                      count = ( length - offset ) * 2;
                    }
                    else
                    {
                      if ( count == BINARY_NOCOUNT )
                      {
                        count = 1;
                      }
                      if ( count > ( length - offset ) * 2 )
                      {
                        break;
                      }
                    }
                    StringBuilder s = new StringBuilder( count );
                    int thisOffset = offset;

                    if ( cmd == 'h' )
                    {
                      for ( int ix = 0; ix < count; ix++ )
                      {
                        if ( ( ix % 2 ) != 0 )
                        {
                          value >>= 4;
                        }
                        else
                        {
                          value = src[thisOffset++];
                        }
                        s.Append( HEXDIGITS[value & 0xf] );
                      }
                    }
                    else
                    {
                      for ( int ix = 0; ix < count; ix++ )
                      {
                        if ( ( ix % 2 ) != 0 )
                        {
                          value <<= 4;
                        }
                        else
                        {
                          value = src[thisOffset++];
                        }
                        s.Append( HEXDIGITS[value >> 4 & 0xf] );
                      }
                    }

                    interp.setVar( argv[arg++], TclString.newInstance( s.ToString() ), 0 );

                    offset += ( count + 1 ) / 2;
                    break;
                  }

                case 'c':
                case 's':
                case 'S':
                case 'i':
                case 'I':
                case 'f':
                case 'd':
                  {
                    if ( arg >= argv.Length )
                    {
                      missingArg( interp );
                    }
                    switch ( cmd )
                    {

                      case 'c':
                        size = 1;
                        break;

                      case 's':
                      case 'S':
                        size = 2;
                        break;

                      case 'i':
                      case 'I':
                        size = 4;
                        break;

                      case 'f':
                        size = 4;
                        break;

                      case 'd':
                        size = 8;
                        break;
                    }
                    TclObject valueObj;
                    if ( count == BINARY_NOCOUNT )
                    {
                      if ( length - offset < size )
                      {
                        break;
                      }
                      valueObj = ScanNumber( src, offset, cmd );
                      offset += size;
                    }
                    else
                    {
                      if ( count == BINARY_ALL )
                      {
                        count = ( length - offset ) / size;
                      }
                      if ( length - offset < count * size )
                      {
                        break;
                      }
                      valueObj = TclList.newInstance();
                      int thisOffset = offset;
                      for ( int ix = 0; ix < count; ix++ )
                      {
                        TclList.append( null, valueObj, ScanNumber( src, thisOffset, cmd ) );
                        thisOffset += size;
                      }
                      offset += count * size;
                    }

                    interp.setVar( argv[arg++], valueObj, 0 );

                    break;
                  }

                case 'x':
                  {
                    if ( count == BINARY_NOCOUNT )
                    {
                      count = 1;
                    }
                    if ( count == BINARY_ALL || count > length - offset )
                    {
                      offset = length;
                    }
                    else
                    {
                      offset += count;
                    }
                    break;
                  }

                case 'X':
                  {
                    if ( count == BINARY_NOCOUNT )
                    {
                      count = 1;
                    }
                    if ( count == BINARY_ALL || count > offset )
                    {
                      offset = 0;
                    }
                    else
                    {
                      offset -= count;
                    }
                    break;
                  }

                case '@':
                  {
                    if ( count == BINARY_NOCOUNT )
                    {
                      alephWithoutCount( interp );
                    }
                    if ( count == BINARY_ALL || count > length )
                    {
                      offset = length;
                    }
                    else
                    {
                      offset = count;
                    }
                    break;
                  }

                default:
                  {
                    badField( interp, cmd );
                  }
                  break;

              }
            }

            // Set the result to the last position of the cursor.

            interp.setResult( arg - 4 );
          }
          break;
      }
      return TCL.CompletionCode.RETURN;
    }