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; }
public TCL.CompletionCode cmdProc(Interp interp, TclObject[] argv) { if (argv.Length != 2) { throw new TclNumArgsException(interp, 1, argv, "name"); } VwaitTrace trace = new VwaitTrace(); Var.traceVar(interp, argv[1], TCL.VarFlag.GLOBAL_ONLY | TCL.VarFlag.TRACE_WRITES | TCL.VarFlag.TRACE_UNSETS, trace); int foundEvent = 1; while (!trace.done && (foundEvent != 0)) { foundEvent = interp.getNotifier().doOneEvent(TCL.ALL_EVENTS); } Var.untraceVar(interp, argv[1], TCL.VarFlag.GLOBAL_ONLY | TCL.VarFlag.TRACE_WRITES | TCL.VarFlag.TRACE_UNSETS, trace); // Clear out the interpreter's result, since it may have been set // by event handlers. interp.resetResult(); if (foundEvent == 0) { throw new TclException(interp, "can't wait for variable \"" + argv[1] + "\": would wait forever"); } return TCL.CompletionCode.RETURN; }
/// <summary> Tcl_UpvarObjCmd -> UpvarCmd.cmdProc /// /// This procedure is invoked to process the "upvar" Tcl command. /// See the user documentation for details on what it does. /// </summary> public TCL.CompletionCode cmdProc( Interp interp, TclObject[] objv ) { CallFrame frame; string frameSpec, otherVarName, myVarName; int p; int objc = objv.Length, objv_index; int result; if ( objv.Length < 3 ) { throw new TclNumArgsException( interp, 1, objv, "?level? otherVar localVar ?otherVar localVar ...?" ); } // Find the call frame containing each of the "other variables" to be // linked to. frameSpec = objv[1].ToString(); // Java does not support passing a reference by refernece so use an array CallFrame[] frameArr = new CallFrame[1]; result = CallFrame.getFrame( interp, frameSpec, frameArr ); frame = frameArr[0]; objc -= ( result + 1 ); if ( ( objc & 1 ) != 0 ) { throw new TclNumArgsException( interp, 1, objv, "?level? otherVar localVar ?otherVar localVar ...?" ); } objv_index = result + 1; // Iterate over each (other variable, local variable) pair. // Divide the other variable name into two parts, then call // MakeUpvar to do all the work of linking it to the local variable. for ( ; objc > 0; objc -= 2, objv_index += 2 ) { myVarName = objv[objv_index + 1].ToString(); otherVarName = objv[objv_index].ToString(); int otherLength = otherVarName.Length; p = otherVarName.IndexOf( (System.Char)'(' ); if ( ( p != -1 ) && ( otherVarName[otherLength - 1] == ')' ) ) { // This is an array variable name Var.makeUpvar( interp, frame, otherVarName.Substring( 0, ( p ) - ( 0 ) ), otherVarName.Substring( p + 1, ( otherLength - 1 ) - ( p + 1 ) ), 0, myVarName, 0 ); } else { // This is a scalar variable name Var.makeUpvar( interp, frame, otherVarName, null, 0, myVarName, 0 ); } } interp.resetResult(); return TCL.CompletionCode.RETURN; }
/// <summary> This procedure is invoked to process the "while" 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 script causes error. /// </exception> public TCL.CompletionCode cmdProc( Interp interp, TclObject[] argv ) { if ( argv.Length != 3 ) { throw new TclNumArgsException( interp, 1, argv, "test command" ); } string test = argv[1].ToString(); TclObject command = argv[2]; { while ( interp.expr.evalBoolean( interp, test ) ) { try { interp.eval( command, 0 ); } catch ( TclException e ) { switch ( e.getCompletionCode() ) { case TCL.CompletionCode.BREAK: goto loop_brk; case TCL.CompletionCode.CONTINUE: continue; case TCL.CompletionCode.ERROR: interp.addErrorInfo( "\n (\"while\" body line " + interp.errorLine + ")" ); throw; default: throw; } } } } loop_brk: ; interp.resetResult(); return TCL.CompletionCode.RETURN; }
/// <summary> Creates an exception with the appropiate Tcl error message to /// indicate an error with variable access. /// /// </summary> /// <param name="interp">currrent interpreter. /// </param> /// <param name="name1">first part of a variable name. /// </param> /// <param name="name2">second part of a variable name. May be null. /// </param> /// <param name="operation">either "read" or "set". /// </param> /// <param name="reason">a string message to explain why the operation fails.. /// </param> internal TclVarException(Interp interp, string name1, string name2, string operation, string reason):base(TCL.CompletionCode.ERROR) { if (interp != null) { interp.resetResult(); if ((System.Object) name2 == null) { interp.setResult("can't " + operation + " \"" + name1 + "\": " + reason); } else { interp.setResult("can't " + operation + " \"" + name1 + "(" + name2 + ")\": " + reason); } } }
/// <summary> See Tcl user documentation for details.</summary> public TCL.CompletionCode cmdProc( Interp interp, TclObject[] argv ) { string sep = null; if ( argv.Length == 2 ) { sep = null; } else if ( argv.Length == 3 ) { sep = argv[2].ToString(); } else { throw new TclNumArgsException( interp, 1, argv, "list ?joinString?" ); } TclObject list = argv[1]; int size = TclList.getLength( interp, list ); if ( size == 0 ) { interp.resetResult(); return TCL.CompletionCode.RETURN; } StringBuilder sbuf = new StringBuilder( TclList.index( interp, list, 0 ).ToString() ); for ( int i = 1; i < size; i++ ) { if ( (System.Object)sep == null ) { sbuf.Append( ' ' ); } else { sbuf.Append( sep ); } sbuf.Append( TclList.index( interp, list, i ).ToString() ); } interp.setResult( sbuf.ToString() ); return TCL.CompletionCode.RETURN; }
public TCL.CompletionCode cmdProc( Interp interp, TclObject[] argv ) { if ( argv.Length < 3 ) { throw new TclNumArgsException( interp, 1, argv, "list index" ); } int size = TclList.getLength( interp, argv[1] ); int index = Util.getIntForIndex( interp, argv[2], size - 1 ); TclObject element = TclList.index( interp, argv[1], index ); if ( element != null ) { interp.setResult( element ); } else { interp.resetResult(); } return TCL.CompletionCode.RETURN; }
public TCL.CompletionCode cmdProc( Interp interp, TclObject[] argv ) { int flags; if ( argv.Length == 1 ) { flags = TCL.ALL_EVENTS | TCL.DONT_WAIT; } else if ( argv.Length == 2 ) { TclIndex.get( interp, argv[1], validOpts, "option", 0 ); /* * Since we just have one valid option, if the above call returns * without an exception, we've got "idletasks" (or abreviations). */ flags = TCL.IDLE_EVENTS | TCL.DONT_WAIT; } else { throw new TclNumArgsException( interp, 1, argv, "?idletasks?" ); } while ( interp.getNotifier().doOneEvent( flags ) != 0 ) { /* Empty loop body */ } /* * Must clear the interpreter's result because event handlers could * have executed commands. */ interp.resetResult(); 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; }
/// <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; }
/// <summary> CallTraces -> callTraces /// /// This procedure is invoked to find and invoke relevant /// trace procedures associated with a particular operation on /// a variable. This procedure invokes traces both on the /// variable and on its containing array (where relevant). /// /// </summary> /// <param name="interp">Interpreter containing variable. /// </param> /// <param name="array">array variable that contains the variable, or null /// if the variable isn't an element of an array. /// </param> /// <param name="var">Variable whose traces are to be invoked. /// </param> /// <param name="part1">the first part of a variable name. /// </param> /// <param name="part2">the second part of a variable name. /// </param> /// <param name="flags">Flags to pass to trace procedures: indicates /// what's happening to variable, plus other stuff like /// TCL.VarFlag.GLOBAL_ONLY, TCL.VarFlag.NAMESPACE_ONLY, and TCL.VarFlag.INTERP_DESTROYED. /// </param> /// <returns> null if no trace procedures were invoked, or /// if all the invoked trace procedures returned successfully. /// The return value is non-null if a trace procedure returned an /// error (in this case no more trace procedures were invoked /// after the error was returned). In this case the return value /// is a pointer to a string describing the error. /// </returns> static protected internal string callTraces( Interp interp, Var array, Var var, string part1, string part2, TCL.VarFlag flags ) { TclObject oldResult; int i; // If there are already similar trace procedures active for the // variable, don't call them again. if ( ( var.flags & VarFlags.TRACE_ACTIVE ) != 0 ) { return null; } var.flags |= VarFlags.TRACE_ACTIVE; var.refCount++; // If the variable name hasn't been parsed into array name and // element, do it here. If there really is an array element, // make a copy of the original name so that nulls can be // inserted into it to separate the names (can't modify the name // string in place, because the string might get used by the // callbacks we invoke). // FIXME : come up with parsing code to use for all situations! if ( (System.Object)part2 == null ) { int len = part1.Length; if ( len > 0 ) { if ( part1[len - 1] == ')' ) { for ( i = 0; i < len - 1; i++ ) { if ( part1[i] == '(' ) { break; } } if ( i < len - 1 ) { if ( i < len - 2 ) { part2 = part1.Substring( i + 1, ( len - 1 ) - ( i + 1 ) ); part1 = part1.Substring( 0, ( i ) - ( 0 ) ); } } } } } oldResult = interp.getResult(); oldResult.preserve(); interp.resetResult(); try { // Invoke traces on the array containing the variable, if relevant. if ( array != null ) { array.refCount++; } if ( ( array != null ) && ( array.traces != null ) ) { for ( i = 0; ( array.traces != null ) && ( i < array.traces.Count ); i++ ) { TraceRecord rec = (TraceRecord)array.traces[i]; if ( ( rec.flags & flags ) != 0 ) { try { rec.trace.traceProc( interp, part1, part2, flags ); } catch ( TclException e ) { if ( ( flags & TCL.VarFlag.TRACE_UNSETS ) == 0 ) { return interp.getResult().ToString(); } } } } } // Invoke traces on the variable itself. if ( ( flags & TCL.VarFlag.TRACE_UNSETS ) != 0 ) { flags |= TCL.VarFlag.TRACE_DESTROYED; } for ( i = 0; ( var.traces != null ) && ( i < var.traces.Count ); i++ ) { TraceRecord rec = (TraceRecord)var.traces[i]; if ( ( rec.flags & flags ) != 0 ) { try { rec.trace.traceProc( interp, part1, part2, flags ); } catch ( TclException e ) { if ( ( flags & TCL.VarFlag.TRACE_UNSETS ) == 0 ) { return interp.getResult().ToString(); } } } } return null; } finally { if ( array != null ) { array.refCount--; } var.flags &= ~VarFlags.TRACE_ACTIVE; var.refCount--; interp.setResult( oldResult ); oldResult.release(); } }
public static void eval2( Interp interp, char[] script_array, int script_index, int numBytes, int flags ) { int i; int objUsed = 0; int nextIndex, tokenIndex; int commandLength, bytesLeft; bool nested; TclObject[] objv; TclObject obj; TclParse parse = null; TclToken token; // Saves old copy of interp.varFrame in case TCL.EVAL_GLOBAL was set CallFrame savedVarFrame; // Take into account the trailing '\0' int script_length = script_array.Length - 1; // These are modified instead of script_array and script_index char[] src_array = script_array; int src_index = script_index; #if DEBUG System.Diagnostics.Debug.WriteLine(); System.Diagnostics.Debug.WriteLine("Entered eval2()"); System.Diagnostics.Debug.Write("now to eval2 the string \""); for (int k = script_index; k < script_array.Length; k++) { System.Diagnostics.Debug.Write(script_array[k]); } System.Diagnostics.Debug.WriteLine("\""); #endif if ( numBytes < 0 ) { numBytes = script_length - script_index; } interp.resetResult(); savedVarFrame = interp.varFrame; if ( ( flags & TCL.EVAL_GLOBAL ) != 0 ) { interp.varFrame = null; } // Each iteration through the following loop parses the next // command from the script and then executes it. bytesLeft = numBytes; // Init objv with the most commonly used array size objv = grabObjv( interp, 3 ); if ( ( interp.evalFlags & TCL_BRACKET_TERM ) != 0 ) { nested = true; } else { nested = false; } interp.evalFlags &= ~TCL_BRACKET_TERM; try { do { parse = parseCommand( interp, src_array, src_index, bytesLeft, null, 0, nested ); if ( parse.result != TCL.CompletionCode.OK ) { throw new TclException( parse.result ); } // The test on noEval is temporary. As soon as the new expr // parser is implemented it should be removed. if ( parse.numWords > 0 && interp.noEval == 0 ) { // Generate an array of objects for the words of the command. try { tokenIndex = 0; token = parse.getToken( tokenIndex ); // Test to see if new space needs to be allocated. If objv // is the EXACT size of parse.numWords, then no allocation // needs to be performed. if ( objv.Length != parse.numWords ) { //System.out.println("need new size " + objv.length); releaseObjv( interp, objv ); //let go of resource objv = grabObjv( interp, parse.numWords ); //get new resource } else { //System.out.println("reusing size " + objv.length); } for ( objUsed = 0; objUsed < parse.numWords; objUsed++ ) { obj = evalTokens( interp, parse.tokenList, tokenIndex + 1, token.numComponents ); if ( obj == null ) { throw new TclException( TCL.CompletionCode.ERROR ); } else { objv[objUsed] = obj; if ( token.type == TCL_TOKEN_EXPAND_WORD ) { int numElements; int code; TclList.setListFromAny( null, objv[objUsed] ); TclObject[] elements = TclList.getElements( null, objv[objUsed] ); if ( elements.Length == 0 ) { elements = new TclObject[1]; elements[0] = TclString.newInstance("{}") ; TclList.setListFromAny( null, elements[0] ); } numElements = elements.Length; /* * Some word expansion was requested. Check for objv resize. */ int objIdx = objUsed + numElements - 1; Array.Resize( ref objv, objIdx+1 ); while ( numElements-- != 0 ) { objv[objIdx] = elements[numElements]; objv[objIdx].preserve(); objIdx--; } objUsed = objv.Length-1; } } tokenIndex += ( token.numComponents + 1 ); token = parse.getToken( tokenIndex ); } // Execute the command and free the objects for its words. try { evalObjv( interp, objv, bytesLeft, 0 ); } catch ( System.StackOverflowException e ) { interp.setResult( "too many nested calls" + " to eval (infinite loop?)" ); throw new TclException( TCL.CompletionCode.ERROR ); } } catch ( TclException e ) { // Generate various pieces of error information, such // as the line number where the error occurred and // information to add to the errorInfo variable. Then // free resources that had been allocated // to the command. if ( e.getCompletionCode() == TCL.CompletionCode.ERROR && !( interp.errAlreadyLogged ) ) { commandLength = parse.commandSize; char term = script_array[parse.commandStart + commandLength - 1]; int type = charType( term ); int terminators; if ( nested ) { terminators = TYPE_COMMAND_END | TYPE_CLOSE_BRACK; } else { terminators = TYPE_COMMAND_END; } if ( ( type & terminators ) != 0 ) { // The command where the error occurred didn't end // at the end of the script (i.e. it ended at a // terminator character such as ";". Reduce the // length by one so that the error message // doesn't include the terminator character. commandLength -= 1; } interp.varFrame = savedVarFrame; logCommandInfo( interp, script_array, script_index, parse.commandStart, commandLength, e ); throw e; } else throw; } finally { for ( i = 0; i < objUsed; i++ ) { objv[i].release(); } objUsed = 0; parse.release(); // Cleanup parser resources } } // Advance to the next command in the script. nextIndex = parse.commandStart + parse.commandSize; bytesLeft -= ( nextIndex - src_index ); src_index = nextIndex; if ( nested && ( src_index > 1 ) && ( src_array[src_index - 1] == ']' ) ) { // We get here in the special case where the TCL_BRACKET_TERM // flag was set in the interpreter and we reached a close // bracket in the script. Return immediately. interp.termOffset = ( src_index - 1 ) - script_index; interp.varFrame = savedVarFrame; return; } } while ( bytesLeft > 0 ); } finally { if ( parse != null ) { parse.release(); // Let go of parser resources } releaseObjv( interp, objv ); // Let go of objv buffer } interp.termOffset = src_index - script_index; interp.varFrame = savedVarFrame; return; }
public static void evalObjv( Interp interp, TclObject[] objv, int length, int flags ) { Command cmd; WrappedCommand wCmd = null; TclObject[] newObjv; int i; CallFrame savedVarFrame; //Saves old copy of interp.varFrame // in case TCL.EVAL_GLOBAL was set. interp.resetResult(); if ( objv.Length == 0 ) { return; } // If the interpreter was deleted, return an error. if ( interp.deleted ) { interp.setResult( "attempt to call eval in deleted interpreter" ); interp.setErrorCode( TclString.newInstance( "CORE IDELETE {attempt to call eval in deleted interpreter}" ) ); throw new TclException( TCL.CompletionCode.ERROR ); } // Check depth of nested calls to eval: if this gets too large, // it's probably because of an infinite loop somewhere. if ( interp.nestLevel >= interp.maxNestingDepth ) { throw new TclException( interp, "too many nested calls to eval (infinite loop?)" ); } interp.nestLevel++; try { // Find the procedure to execute this command. If there isn't one, // then see if there is a command "unknown". If so, create a new // word array with "unknown" as the first word and the original // command words as arguments. Then call ourselves recursively // to execute it. cmd = interp.getCommand( objv[0].ToString() ); if ( cmd == null ) wCmd = interp.getObjCommand( objv[0].ToString() ); // See if we are running as a slave interpretor, and this is a windows command if ( cmd == null && wCmd == null && interp.slave != null ) { wCmd = interp.slave.masterInterp.getObjCommand( objv[0].ToString() ); } if ( cmd == null && wCmd == null ) { newObjv = new TclObject[objv.Length + 1]; for ( i = ( objv.Length - 1 ); i >= 0; i-- ) { newObjv[i + 1] = objv[i]; } newObjv[0] = TclString.newInstance( "unknown" ); newObjv[0].preserve(); cmd = interp.getCommand( "unknown" ); if ( cmd == null ) { Debug.Assert( false, "invalid command name \"" + objv[0].ToString() + "\"" ); throw new TclException( interp, "invalid command name \"" + objv[0].ToString() + "\"" ); } else { evalObjv( interp, newObjv, length, 0 ); } newObjv[0].release(); return; } // Finally, invoke the Command's cmdProc. interp.cmdCount++; savedVarFrame = interp.varFrame; if ( ( flags & TCL.EVAL_GLOBAL ) != 0 ) { interp.varFrame = null; } int rc = 0; if ( cmd != null ) { if ( cmd.cmdProc( interp, objv ) == TCL.CompletionCode.EXIT ) throw new TclException( TCL.CompletionCode.EXIT ); } else { rc = wCmd.objProc( wCmd.objClientData, interp, objv.Length, objv ); if ( rc != 0 ) { if ( rc == TCL.TCL_RETURN ) throw new TclException( TCL.CompletionCode.RETURN ); throw new TclException( TCL.CompletionCode.ERROR ); } } interp.varFrame = savedVarFrame; } finally { interp.nestLevel--; } }
/// <summary> See Tcl user documentation for details.</summary> /// <exception cref=""> TclException If incorrect number of arguments. /// </exception> public TCL.CompletionCode cmdProc( Interp interp, TclObject[] argv ) { if ( argv.Length != 4 ) { throw new TclNumArgsException( interp, 1, argv, "list first last" ); } int size = TclList.getLength( interp, argv[1] ); int first; int last; first = Util.getIntForIndex( interp, argv[2], size - 1 ); last = Util.getIntForIndex( interp, argv[3], size - 1 ); if ( last < 0 ) { interp.resetResult(); return TCL.CompletionCode.RETURN; } if ( first >= size ) { interp.resetResult(); return TCL.CompletionCode.RETURN; } if ( first <= 0 && last >= size ) { interp.setResult( argv[1] ); return TCL.CompletionCode.RETURN; } if ( first < 0 ) { first = 0; } if ( first >= size ) { first = size - 1; } if ( last < 0 ) { last = 0; } if ( last >= size ) { last = size - 1; } if ( first > last ) { interp.resetResult(); return TCL.CompletionCode.RETURN; } TclObject list = TclList.newInstance(); list.preserve(); try { for ( int i = first; i <= last; i++ ) { TclList.append( interp, list, TclList.index( interp, argv[1], i ) ); } interp.setResult( list ); } finally { list.release(); } return TCL.CompletionCode.RETURN; }
/* *---------------------------------------------------------------------- * * Tcl_Import -> importList * * Imports all of the commands matching a pattern into the namespace * specified by namespace (or the current namespace if namespace * is null). This is done by creating a new command (the "imported * command") that points to the real command in its original namespace. * * If matching commands are on the autoload path but haven't been * loaded yet, this command forces them to be loaded, then creates * the links to them. * * Results: * Returns if successful, raises TclException if something goes wrong. * * Side effects: * Creates new commands in the importing namespace. These indirect * calls back to the real command and are deleted if the real commands * are deleted. * *---------------------------------------------------------------------- */ internal static void importList(Interp interp, Namespace namespace_Renamed, string pattern, bool allowOverwrite) { Namespace ns, importNs; Namespace currNs = getCurrentNamespace(interp); string simplePattern, cmdName; IEnumerator search; WrappedCommand cmd, realCmd; ImportRef ref_Renamed; WrappedCommand autoCmd, importedCmd; ImportedCmdData data; bool wasExported; int i, result; // If the specified namespace is null, use the current namespace. if (namespace_Renamed == null) { ns = currNs; } else { ns = namespace_Renamed; } // First, invoke the "auto_import" command with the pattern // being imported. This command is part of the Tcl library. // It looks for imported commands in autoloaded libraries and // loads them in. That way, they will be found when we try // to create links below. autoCmd = findCommand(interp, "auto_import", null, TCL.VarFlag.GLOBAL_ONLY); if (autoCmd != null) { TclObject[] objv = new TclObject[2]; objv[0] = TclString.newInstance("auto_import"); objv[0].preserve(); objv[1] = TclString.newInstance(pattern); objv[1].preserve(); cmd = autoCmd; try { // Invoke the command with the arguments cmd.cmd.cmdProc(interp, objv); } finally { objv[0].release(); objv[1].release(); } interp.resetResult(); } // From the pattern, find the namespace from which we are importing // and get the simple pattern (no namespace qualifiers or ::'s) at // the end. if (pattern.Length == 0) { throw new TclException(interp, "empty import pattern"); } // Java does not support passing an address so we pass // an array of size 1 and then assign arr[0] to the value Namespace[] importNsArr = new Namespace[1]; Namespace[] dummyArr = new Namespace[1]; string[] simplePatternArr = new string[1]; getNamespaceForQualName(interp, pattern, ns, TCL.VarFlag.LEAVE_ERR_MSG, importNsArr, dummyArr, dummyArr, simplePatternArr); importNs = importNsArr[0]; simplePattern = simplePatternArr[0]; if (importNs == null) { throw new TclException(interp, "unknown namespace in import pattern \"" + pattern + "\""); } if (importNs == ns) { if ((System.Object) pattern == (System.Object) simplePattern) { throw new TclException(interp, "no namespace specified in import pattern \"" + pattern + "\""); } else { throw new TclException(interp, "import pattern \"" + pattern + "\" tries to import from namespace \"" + importNs.name + "\" into itself"); } } // Scan through the command table in the source namespace and look for // exported commands that match the string pattern. Create an "imported // command" in the current namespace for each imported command; these // commands redirect their invocations to the "real" command. for (search = importNs.cmdTable.Keys.GetEnumerator(); search.MoveNext(); ) { cmdName = ((string) search.Current); if (Util.stringMatch(cmdName, simplePattern)) { // The command cmdName in the source namespace matches the // pattern. Check whether it was exported. If it wasn't, // we ignore it. wasExported = false; for (i = 0; i < importNs.numExportPatterns; i++) { if (Util.stringMatch(cmdName, importNs.exportArray[i])) { wasExported = true; break; } } if (!wasExported) { continue; } // Unless there is a name clash, create an imported command // in the current namespace that refers to cmdPtr. if ((ns.cmdTable[cmdName] == null) || allowOverwrite) { // Create the imported command and its client data. // To create the new command in the current namespace, // generate a fully qualified name for it. System.Text.StringBuilder ds; ds = new System.Text.StringBuilder(); ds.Append(ns.fullName); if (ns != interp.globalNs) { ds.Append("::"); } ds.Append(cmdName); // Check whether creating the new imported command in the // current namespace would create a cycle of imported->real // command references that also would destroy an existing // "real" command already in the current namespace. cmd = (WrappedCommand) importNs.cmdTable[cmdName]; if (cmd.cmd is ImportedCmdData) { // This is actually an imported command, find // the real command it references realCmd = getOriginalCommand(cmd); if ((realCmd != null) && (realCmd.ns == currNs) && (currNs.cmdTable[cmdName] != null)) { throw new TclException(interp, "import pattern \"" + pattern + "\" would create a loop containing command \"" + ds.ToString() + "\""); } } data = new ImportedCmdData(); // Create the imported command inside the interp interp.createCommand(ds.ToString(), data); // Lookup in the namespace for the new WrappedCommand importedCmd = findCommand(interp, ds.ToString(), ns, (TCL.VarFlag.NAMESPACE_ONLY | TCL.VarFlag.LEAVE_ERR_MSG)); data.realCmd = cmd; data.self = importedCmd; // Create an ImportRef structure describing this new import // command and add it to the import ref list in the "real" // command. ref_Renamed = new ImportRef(); ref_Renamed.importedCmd = importedCmd; ref_Renamed.next = cmd.importRef; cmd.importRef = ref_Renamed; } else { throw new TclException(interp, "can't import command \"" + cmdName + "\": already exists"); } } } return ; }
/// <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; }
public TCL.CompletionCode cmdProc( Interp interp, TclObject[] argv ) { int i; Notifier notifier = (Notifier)interp.getNotifier(); Object info; if ( assocData == null ) { /* * Create the "after" information associated for this * interpreter, if it doesn't already exist. */ assocData = (AfterAssocData)interp.getAssocData( "tclAfter" ); if ( assocData == null ) { assocData = new AfterAssocData( this ); interp.setAssocData( "tclAfter", assocData ); } } if ( argv.Length < 2 ) { throw new TclNumArgsException( interp, 1, argv, "option ?arg arg ...?" ); } /* * First lets see if the command was passed a number as the first argument. */ bool isNumber = false; int ms = 0; if ( argv[1].InternalRep is TclInteger ) { ms = TclInteger.get( interp, argv[1] ); isNumber = true; } else { string s = argv[1].ToString(); if ( ( s.Length > 0 ) && ( System.Char.IsDigit( s[0] ) ) ) { ms = TclInteger.get( interp, argv[1] ); isNumber = true; } } if ( isNumber ) { if ( ms < 0 ) { ms = 0; } if ( argv.Length == 2 ) { /* * Sleep for at least the given milliseconds and return. */ long endTime = System.DateTime.Now.Ticks / 10000 + ms; while ( true ) { try { System.Threading.Thread.Sleep( ms ); return TCL.CompletionCode.RETURN; } catch ( System.Threading.ThreadInterruptedException e ) { /* * We got interrupted. Sleep again if we havn't slept * long enough yet. */ long sysTime = System.DateTime.Now.Ticks / 10000; if ( sysTime >= endTime ) { return TCL.CompletionCode.RETURN; } ms = (int)( endTime - sysTime ); continue; } } } TclObject cmd = getCmdObject( argv ); cmd.preserve(); assocData.lastAfterId++; TimerInfo timerInfo = new TimerInfo( this, notifier, ms ); timerInfo.interp = interp; timerInfo.command = cmd; timerInfo.id = assocData.lastAfterId; assocData.handlers.Add( timerInfo ); interp.setResult( "after#" + timerInfo.id ); return TCL.CompletionCode.RETURN; } /* * If it's not a number it must be a subcommand. */ int index; try { index = TclIndex.get( interp, argv[1], validOpts, "option", 0 ); } catch ( TclException e ) { throw new TclException( interp, "bad argument \"" + argv[1] + "\": must be cancel, idle, info, or a number" ); } switch ( index ) { case OPT_CANCEL: if ( argv.Length < 3 ) { throw new TclNumArgsException( interp, 2, argv, "id|command" ); } TclObject arg = getCmdObject( argv ); arg.preserve(); /* * Search the timer/idle handler by id or by command. */ info = null; for ( i = 0; i < assocData.handlers.Count; i++ ) { Object obj = assocData.handlers[i]; if ( obj is TimerInfo ) { TclObject cmd = ( (TimerInfo)obj ).command; if ( ( cmd == arg ) || cmd.ToString().Equals( arg.ToString() ) ) { info = obj; break; } } else { TclObject cmd = ( (IdleInfo)obj ).command; if ( ( cmd == arg ) || cmd.ToString().Equals( arg.ToString() ) ) { info = obj; break; } } } if ( info == null ) { info = getAfterEvent( arg.ToString() ); } arg.release(); /* * Cancel the handler. */ if ( info != null ) { if ( info is TimerInfo ) { ( (TimerInfo)info ).cancel(); ( (TimerInfo)info ).command.release(); } else { ( (IdleInfo)info ).cancel(); ( (IdleInfo)info ).command.release(); } SupportClass.VectorRemoveElement( assocData.handlers, info ); } break; case OPT_IDLE: if ( argv.Length < 3 ) { throw new TclNumArgsException( interp, 2, argv, "script script ..." ); } TclObject cmd2 = getCmdObject( argv ); cmd2.preserve(); assocData.lastAfterId++; IdleInfo idleInfo = new IdleInfo( this, notifier ); idleInfo.interp = interp; idleInfo.command = cmd2; idleInfo.id = assocData.lastAfterId; assocData.handlers.Add( idleInfo ); interp.setResult( "after#" + idleInfo.id ); break; case OPT_INFO: if ( argv.Length == 2 ) { /* * No id is given. Return a list of current after id's. */ TclObject list = TclList.newInstance(); for ( i = 0; i < assocData.handlers.Count; i++ ) { int id; Object obj = assocData.handlers[i]; if ( obj is TimerInfo ) { id = ( (TimerInfo)obj ).id; } else { id = ( (IdleInfo)obj ).id; } TclList.append( interp, list, TclString.newInstance( "after#" + id ) ); } interp.resetResult(); interp.setResult( list ); return TCL.CompletionCode.RETURN; } if ( argv.Length != 3 ) { throw new TclNumArgsException( interp, 2, argv, "?id?" ); } /* * Return command and type of the given after id. */ info = getAfterEvent( argv[2].ToString() ); if ( info == null ) { throw new TclException( interp, "event \"" + argv[2] + "\" doesn't exist" ); } TclObject list2 = TclList.newInstance(); TclList.append( interp, list2, ( ( info is TimerInfo ) ? ( (TimerInfo)info ).command : ( (IdleInfo)info ).command ) ); TclList.append( interp, list2, TclString.newInstance( ( info is TimerInfo ) ? "timer" : "idle" ) ); interp.resetResult(); interp.setResult( list2 ); break; } return TCL.CompletionCode.RETURN; }
/* * This procedure is invoked to process the "for" Tcl command. * See the user documentation for details on what it does. * * @param interp the current interpreter. * @param argv command arguments. * @exception TclException if script causes error. */ public TCL.CompletionCode cmdProc( Interp interp, TclObject[] argv ) { if ( argv.Length != 5 ) { throw new TclNumArgsException( interp, 1, argv, "start test next command" ); } TclObject start = argv[1]; string test = argv[2].ToString(); TclObject next = argv[3]; TclObject command = argv[4]; bool done = false; try { interp.eval( start, 0 ); } catch ( TclException e ) { interp.addErrorInfo( "\n (\"for\" initial command)" ); throw; } while ( !done ) { if ( !interp.expr.evalBoolean( interp, test ) ) { break; } try { interp.eval( command, 0 ); } catch ( TclException e ) { switch ( e.getCompletionCode() ) { case TCL.CompletionCode.BREAK: done = true; break; case TCL.CompletionCode.CONTINUE: break; case TCL.CompletionCode.ERROR: interp.addErrorInfo( "\n (\"for\" body line " + interp.errorLine + ")" ); throw; default: throw; } } if ( !done ) { try { interp.eval( next, 0 ); } catch ( TclException e ) { switch ( e.getCompletionCode() ) { case TCL.CompletionCode.BREAK: done = true; break; case TCL.CompletionCode.CONTINUE: break; default: interp.addErrorInfo( "\n (\"for\" loop-end command)" ); throw; } } } } interp.resetResult(); return TCL.CompletionCode.RETURN; }
internal static string pkgRequire( Interp interp, string pkgName, string version, bool exact ) { VersionSatisfiesResult vsres; Package pkg; PkgAvail avail, best; string script; StringBuilder sbuf; int pass, result; // Do extra check to make sure that version is not // null when the exact flag is set to true. if ( (System.Object)version == null && exact ) { throw new TclException( interp, "conflicting arguments : version == null and exact == true" ); } // Before we can compare versions the version string // must be verified but if it is null we are just looking // for the latest version so skip the check in this case. if ( (System.Object)version != null ) { checkVersion( interp, version ); } // It can take up to three passes to find the package: one pass to // run the "package unknown" script, one to run the "package ifneeded" // script for a specific version, and a final pass to lookup the // package loaded by the "package ifneeded" script. vsres = new VersionSatisfiesResult(); for ( pass = 1; ; pass++ ) { pkg = findPackage( interp, pkgName ); if ( (System.Object)pkg.version != null ) { break; } // The package isn't yet present. Search the list of available // versions and invoke the script for the best available version. best = null; for ( avail = pkg.avail; avail != null; avail = avail.next ) { if ( ( best != null ) && ( compareVersions( avail.version, best.version, null ) <= 0 ) ) { continue; } if ( (System.Object)version != null ) { result = compareVersions( avail.version, version, vsres ); if ( ( result != 0 ) && exact ) { continue; } if ( !vsres.satisfies ) { continue; } } best = avail; } if ( best != null ) { // We found an ifneeded script for the package. Be careful while // executing it: this could cause reentrancy, so (a) protect the // script itself from deletion and (b) don't assume that best // will still exist when the script completes. script = best.script; try { interp.eval( script, TCL.EVAL_GLOBAL ); } catch ( TclException e ) { interp.addErrorInfo( "\n (\"package ifneeded\" script)" ); // Throw the error with new info added to errorInfo. throw; } interp.resetResult(); pkg = findPackage( interp, pkgName ); break; } // Package not in the database. If there is a "package unknown" // command, invoke it (but only on the first pass; after that, // we should not get here in the first place). if ( pass > 1 ) { break; } script = interp.packageUnknown; if ( (System.Object)script != null ) { sbuf = new StringBuilder(); try { Util.appendElement( interp, sbuf, script ); Util.appendElement( interp, sbuf, pkgName ); if ( (System.Object)version == null ) { Util.appendElement( interp, sbuf, "" ); } else { Util.appendElement( interp, sbuf, version ); } if ( exact ) { Util.appendElement( interp, sbuf, "-exact" ); } } catch ( TclException e ) { throw new TclRuntimeError( "unexpected TclException: " + e.Message ); } try { interp.eval( sbuf.ToString(), TCL.EVAL_GLOBAL ); } catch ( TclException e ) { interp.addErrorInfo( "\n (\"package unknown\" script)" ); // Throw the first exception. throw; } interp.resetResult(); } } if ( (System.Object)pkg.version == null ) { sbuf = new StringBuilder(); sbuf.Append( "can't find package " + pkgName ); if ( (System.Object)version != null ) { sbuf.Append( " " + version ); } throw new TclException( interp, sbuf.ToString() ); } // At this point we know that the package is present. Make sure that the // provided version meets the current requirement. if ( (System.Object)version == null ) { return pkg.version; } result = compareVersions( pkg.version, version, vsres ); if ( ( vsres.satisfies && !exact ) || ( result == 0 ) ) { return pkg.version; } // If we have a version conflict we throw a TclException. throw new TclException( interp, "version conflict for package \"" + pkgName + "\": have " + pkg.version + ", need " + version ); }
/// <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; }
internal void transferResult( Interp sourceInterp, TCL.CompletionCode result ) { if ( sourceInterp == this ) { return; } if ( result == TCL.CompletionCode.ERROR ) { TclObject obj; // An error occurred, so transfer error information from the source // interpreter to the target interpreter. Setting the flags tells // the target interp that it has inherited a partial traceback // chain, not just a simple error message. if ( !sourceInterp.errAlreadyLogged ) { sourceInterp.addErrorInfo( "" ); } sourceInterp.errAlreadyLogged = true; resetResult(); obj = sourceInterp.getVar( "errorInfo", TCL.VarFlag.GLOBAL_ONLY ); setVar( "errorInfo", obj, TCL.VarFlag.GLOBAL_ONLY ); obj = sourceInterp.getVar( "errorCode", TCL.VarFlag.GLOBAL_ONLY ); setVar( "errorCode", obj, TCL.VarFlag.GLOBAL_ONLY ); errInProgress = true; errCodeSet = true; } returnCode = result; setResult( sourceInterp.getResult() ); sourceInterp.resetResult(); if ( result != TCL.CompletionCode.OK ) { throw new TclException( this, getResult().ToString(), result ); } }
/// <summary> See Tcl user documentation for details.</summary> /// <exception cref=""> TclException If incorrect number of arguments. /// </exception> public TCL.CompletionCode cmdProc(Interp interp, TclObject[] argv) { int i; bool value; i = 1; while (true) { /* * At this point in the loop, argv and argc refer to an * expression to test, either for the main expression or * an expression following an "elseif". The arguments * after the expression must be "then" (optional) and a * script to execute if the expression is true. */ if (i >= argv.Length) { throw new TclException(interp, "wrong # args: no expression after \"" + argv[i - 1] + "\" argument"); } try { value = interp.expr.evalBoolean(interp, argv[i].ToString()); } catch (TclException e) { switch (e.getCompletionCode()) { case TCL.CompletionCode.ERROR: interp.addErrorInfo("\n (\"if\" test expression)"); break; } throw ; } i++; if ((i < argv.Length) && (argv[i].ToString().Equals("then"))) { i++; } if (i >= argv.Length) { throw new TclException(interp, "wrong # args: no script following \"" + argv[i - 1] + "\" argument"); } if (value) { try { interp.eval(argv[i], 0); } catch (TclException e) { switch (e.getCompletionCode()) { case TCL.CompletionCode.ERROR: interp.addErrorInfo("\n (\"if\" then script line " + interp.errorLine + ")"); break; } throw ; } return TCL.CompletionCode.RETURN; } /* * The expression evaluated to false. Skip the command, then * see if there is an "else" or "elseif" clause. */ i++; if (i >= argv.Length) { interp.resetResult(); return TCL.CompletionCode.RETURN; } if (argv[i].ToString().Equals("elseif")) { i++; continue; } break; } /* * Couldn't find a "then" or "elseif" clause to execute. * Check now for an "else" clause. We know that there's at * least one more argument when we get here. */ if (argv[i].ToString().Equals("else")) { i++; if (i >= argv.Length) { throw new TclException(interp, "wrong # args: no script following \"else\" argument"); } else if (i != (argv.Length - 1)) { throw new TclException(interp, "wrong # args: extra words after \"else\" clause in " + "\"if\" command"); } } try { interp.eval(argv[i], 0); } catch (TclException e) { switch (e.getCompletionCode()) { case TCL.CompletionCode.ERROR: interp.addErrorInfo("\n (\"if\" else script line " + interp.errorLine + ")"); break; } throw ; } return TCL.CompletionCode.RETURN; }