/// <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 index element ?element ...?"); } int size = TclList.getLength(interp, argv[1]); int index = Util.getIntForIndex(interp, argv[2], size); TclObject list = argv[1]; bool isDuplicate = false; // If the list object is unshared we can modify it directly. Otherwise // we create a copy to modify: this is "copy on write". if (list.Shared) { list = list.duplicate(); isDuplicate = true; } try { TclList.insert(interp, list, index, argv, 3, argv.Length - 1); interp.setResult(list); } catch (TclException e) { if (isDuplicate) { list.release(); } throw; } return(TCL.CompletionCode.RETURN); }
/* *---------------------------------------------------------------------- * * cmdProc -- * * This procedure is invoked as part of the Command interface to * process the "lsort" Tcl command. See the user documentation for * details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ public TCL.CompletionCode cmdProc(Interp interp, TclObject[] argv) { if (argv.Length < 2) { throw new TclNumArgsException(interp, 1, argv, "?options? list"); } string command = null; int sortMode = QSort.ASCII; int sortIndex = -1; bool sortIncreasing = true; bool unique = false; for (int i = 1; i < argv.Length - 1; i++) { int index = TclIndex.get(interp, argv[i], validOpts, "option", 0); switch (index) { case 0: sortMode = QSort.ASCII; break; case 1: if (i == argv.Length - 2) { throw new TclException(interp, "\"-command\" option must be" + " followed by comparison command"); } sortMode = QSort.COMMAND; command = argv[i + 1].ToString(); i++; break; case 2: sortIncreasing = false; break; case 3: sortMode = QSort.DICTIONARY; break; case 4: sortIncreasing = true; break; case 5: if (i == argv.Length - 2) { throw new TclException(interp, "\"-index\" option must be followed by list index"); } sortIndex = Util.getIntForIndex(interp, argv[i + 1], -2); command = argv[i + 1].ToString(); i++; break; case 6: sortMode = QSort.INTEGER; break; case 7: sortMode = QSort.REAL; break; case 8: /* -unique */ unique = true; break; } } TclObject list = argv[argv.Length - 1]; bool isDuplicate = false; // If the list object is unshared we can modify it directly. Otherwise // we create a copy to modify: this is "copy on write". if (list.Shared) { list = list.duplicate(); isDuplicate = true; } try { TclList.sort(interp, list, sortMode, sortIndex, sortIncreasing, command, unique); interp.setResult(list); } catch (TclException e) { if (isDuplicate) { list.release(); } throw; } return(TCL.CompletionCode.RETURN); }
public static TclObject Tcl_DuplicateObj(TclObject to) { return(to.duplicate()); }
/// <summary> TCL.Tcl_SetVar2Ex -> setVar /// /// Given a two-part variable name, which may refer either to a scalar /// variable or an element of an array, change the value of the variable /// to a new Tcl object value. If the named scalar or array or element /// doesn't exist then create one. /// /// </summary> /// <param name="interp">the interp that holds the variable /// </param> /// <param name="part1">1st part of the variable name. /// </param> /// <param name="part2">2nd part of the variable name. /// </param> /// <param name="newValue">the new value for the variable /// </param> /// <param name="flags">misc flags that control the actions of this method /// /// Returns a pointer to the TclObject holding the new value of the /// variable. If the write operation was disallowed because an array was /// expected but not found (or vice versa), then null is returned; if /// the TCL.VarFlag.LEAVE_ERR_MSG flag is set, then an exception will be raised. /// Note that the returned object may not be the same one referenced /// by newValue because variable traces may modify the variable's value. /// The value of the given variable is set. If either the array or the /// entry didn't exist then a new variable is created. /// /// The reference count is decremented for any old value of the variable /// and incremented for its new value. If the new value for the variable /// is not the same one referenced by newValue (perhaps as a result /// of a variable trace), then newValue's ref count is left unchanged /// by TCL.Tcl_SetVar2Ex. newValue's ref count is also left unchanged if /// we are appending it as a string value: that is, if "flags" includes /// TCL.VarFlag.APPEND_VALUE but not TCL.VarFlag.LIST_ELEMENT. /// /// The reference count for the returned object is _not_ incremented: if /// you want to keep a reference to the object you must increment its /// ref count yourself. /// </param> internal static TclObject setVar( Interp interp, string part1, string part2, TclObject newValue, TCL.VarFlag flags ) { Var var; Var array; TclObject oldValue; string bytes; Var[] result = lookupVar( interp, part1, part2, flags, "set", true, true ); if ( result == null ) { return null; } var = result[0]; array = result[1]; // If the variable is in a hashtable and its table field is null, then we // may have an upvar to an array element where the array was deleted // or an upvar to a namespace variable whose namespace was deleted. // Generate an error (allowing the variable to be reset would screw up // our storage allocation and is meaningless anyway). if ( ( ( var.flags & VarFlags.IN_HASHTABLE ) != 0 ) && ( var.table == null ) ) { if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 ) { if ( var.isVarArrayElement() ) { throw new TclVarException( interp, part1, part2, "set", danglingElement ); } else { throw new TclVarException( interp, part1, part2, "set", danglingVar ); } } return null; } // It's an error to try to set an array variable itself. if ( var.isVarArray() && !var.isVarUndefined() ) { if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 ) { throw new TclVarException( interp, part1, part2, "set", isArray ); } return null; } // At this point, if we were appending, we used to call read traces: we // treated append as a read-modify-write. However, it seemed unlikely to // us that a real program would be interested in such reads being done // during a set operation. // Set the variable's new value. If appending, append the new value to // the variable, either as a list element or as a string. Also, if // appending, then if the variable's old value is unshared we can modify // it directly, otherwise we must create a new copy to modify: this is // "copy on write". try { if ( var.isSQLITE3_Link() ) { var.sqlite3_set( newValue ); return var.sqlite3_get(); } else { oldValue = (TclObject)var.value; if ( ( flags & TCL.VarFlag.APPEND_VALUE ) != 0 ) { if ( var.isVarUndefined() && ( oldValue != null ) ) { oldValue.release(); // discard old value var.value = null; oldValue = null; } if ( ( flags & TCL.VarFlag.LIST_ELEMENT ) != 0 ) { // append list element if ( oldValue == null ) { oldValue = TclList.newInstance(); var.value = oldValue; oldValue.preserve(); // since var is referenced } else if ( oldValue.Shared ) { // append to copy var.value = oldValue.duplicate(); oldValue.release(); oldValue = (TclObject)var.value; oldValue.preserve(); // since var is referenced } TclList.append( interp, oldValue, newValue ); } else { // append string // We append newValuePtr's bytes but don't change its ref count. bytes = newValue.ToString(); if ( oldValue == null ) { var.value = TclString.newInstance( bytes ); ( (TclObject)var.value ).preserve(); } else { if ( oldValue.Shared ) { // append to copy var.value = oldValue.duplicate(); oldValue.release(); oldValue = (TclObject)var.value; oldValue.preserve(); // since var is referenced } TclString.append( oldValue, newValue ); } } } else { if ( ( flags & TCL.VarFlag.LIST_ELEMENT ) != 0 ) { // set var to list element int listFlags; // We set the variable to the result of converting newValue's // string rep to a list element. We do not change newValue's // ref count. if ( oldValue != null ) { oldValue.release(); // discard old value } bytes = newValue.ToString(); listFlags = Util.scanElement( interp, bytes ); oldValue = TclString.newInstance( Util.convertElement( bytes, listFlags ) ); var.value = oldValue; ( (TclObject)var.value ).preserve(); } else if ( newValue != oldValue ) { var.value = newValue.duplicate(); ( (TclObject)var.value ).preserve(); // var is another ref if ( oldValue != null ) { oldValue.release(); // discard old value } } } var.setVarScalar(); var.clearVarUndefined(); if ( array != null ) { array.clearVarUndefined(); } // Invoke any write traces for the variable. if ( ( var.traces != null ) || ( ( array != null ) && ( array.traces != null ) ) ) { string msg = callTraces( interp, array, var, part1, part2, ( flags & ( TCL.VarFlag.GLOBAL_ONLY | TCL.VarFlag.NAMESPACE_ONLY ) ) | TCL.VarFlag.TRACE_WRITES ); if ( (System.Object)msg != null ) { if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 ) { throw new TclVarException( interp, part1, part2, "set", msg ); } return null; // Same as "goto cleanup" in C verison } } // Return the variable's value unless the variable was changed in some // gross way by a trace (e.g. it was unset and then recreated as an // array). if ( var.isVarScalar() && !var.isVarUndefined() ) { return (TclObject)var.value; } // A trace changed the value in some gross way. Return an empty string // object. return TclString.newInstance( "" ); } } finally { // If the variable doesn't exist anymore and no-one's using it, // then free up the relevant structures and hash table entries. if ( var.isVarUndefined() ) { cleanupVar( var, array ); } } }
/// <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 ?element element ...?"); } int size = TclList.getLength(interp, argv[1]); int first = Util.getIntForIndex(interp, argv[2], size - 1); int last = Util.getIntForIndex(interp, argv[3], size - 1); int numToDelete; if (first < 0) { first = 0; } // Complain if the user asked for a start element that is greater // than the list length. This won't ever trigger for the "end*" // case as that will be properly constrained by getIntForIndex // because we use size-1 (to allow for replacing the last elem). if ((first >= size) && (size > 0)) { throw new TclException(interp, "list doesn't contain element " + argv[2]); } if (last >= size) { last = size - 1; } if (first <= last) { numToDelete = (last - first + 1); } else { numToDelete = 0; } TclObject list = argv[1]; bool isDuplicate = false; // If the list object is unshared we can modify it directly. Otherwise // we create a copy to modify: this is "copy on write". if (list.Shared) { list = list.duplicate(); isDuplicate = true; } try { TclList.replace(interp, list, first, numToDelete, argv, 4, argv.Length - 1); interp.setResult(list); } catch (TclException e) { if (isDuplicate) { list.release(); } throw; } return(TCL.CompletionCode.RETURN); }