/* *---------------------------------------------------------------------- * * 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( "" ); } }
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; }
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; }
/// <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; }
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; }
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; }
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. } }
/// <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; }
/* *---------------------------------------------------------------------- * * 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 + "\"" ); }
/// <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; }
/// <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 ); } }
/* ** 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; }
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; }