001: /*
002: * LappendCmd.java
003: *
004: * Copyright (c) 1997 Cornell University.
005: * Copyright (c) 1997 Sun Microsystems, Inc.
006: * Copyright (c) 1998-1999 by Scriptics Corporation.
007: * Copyright (c) 1999 Mo DeJong.
008: *
009: * See the file "license.terms" for information on usage and
010: * redistribution of this file, and for a DISCLAIMER OF ALL
011: * WARRANTIES.
012: *
013: * RCS: @(#) $Id: LappendCmd.java,v 1.5 2006/01/27 23:39:02 mdejong Exp $
014: *
015: */
016:
017: package tcl.lang;
018:
019: /**
020: * This class implements the built-in "lappend" command in Tcl.
021: */
022: class LappendCmd implements Command {
023: /**
024: *
025: * Tcl_LappendObjCmd -> LappendCmd.cmdProc
026: *
027: * This procedure is invoked to process the "lappend" Tcl command.
028: * See the user documentation for details on what it does.
029: */
030:
031: public void cmdProc(Interp interp, TclObject[] objv)
032: throws TclException {
033: TclObject varValue, newValue = null;
034:
035: if (objv.length < 2) {
036: throw new TclNumArgsException(interp, 1, objv,
037: "varName ?value value ...?");
038: }
039: if (objv.length == 2) {
040: try {
041: newValue = interp.getVar(objv[1], 0);
042: } catch (TclException e) {
043: // The variable doesn't exist yet. Just create it with an empty
044: // initial value.
045: varValue = TclList.newInstance();
046:
047: try {
048: newValue = interp.setVar(objv[1], varValue, 0);
049: } finally {
050: if (newValue == null) {
051: varValue.release(); // free unneeded object
052: }
053: }
054:
055: interp.resetResult();
056: return;
057: }
058: } else {
059: newValue = lappendVar(interp, objv[1].toString(), objv, 2);
060: }
061:
062: // Set the interpreter's object result to refer to the variable's value
063: // object.
064:
065: interp.setResult(newValue);
066: return;
067: }
068:
069: // Append TclObject values to a list value stored
070: // in the named variable. This method is used in
071: // the lappend implementation above when 3 or
072: // more arguments are passed to lappend.
073:
074: static TclObject lappendVar(Interp interp, String varName, // name of variable
075: TclObject[] values, // TclObject values to append
076: int valuesInd) // index of values to start at
077: throws TclException {
078: boolean createdNewObj = false;
079: boolean createVar = true;
080: TclObject varValue, newValue;
081: int i;
082:
083: // We have arguments to append. We used to call Tcl_SetVar2 to
084: // append each argument one at a time to ensure that traces were run
085: // for each append step. We now append the arguments all at once
086: // because it's faster. Note that a read trace and a write trace for
087: // the variable will now each only be called once. Also, if the
088: // variable's old value is unshared we modify it directly, otherwise
089: // we create a new copy to modify: this is "copy on write".
090:
091: try {
092: varValue = interp.getVar(varName, 0);
093: } catch (TclException e) {
094: // We couldn't read the old value: either the var doesn't yet
095: // exist or it's an array element. If it's new, we will try to
096: // create it with Tcl_ObjSetVar2 below.
097:
098: if (Var.isArrayVarname(varName)) {
099: createVar = false;
100: }
101:
102: varValue = TclList.newInstance();
103: createdNewObj = true;
104: }
105:
106: // We only take this branch when the catch branch was not run
107: if (!createdNewObj && varValue.isShared()) {
108: varValue = varValue.duplicate();
109: createdNewObj = true;
110: }
111:
112: // Insert the new elements at the end of the list.
113:
114: final int len = values.length;
115: if ((len - valuesInd) == 1) {
116: TclList.append(interp, varValue, values[valuesInd]);
117: } else {
118: TclList.append(interp, varValue, values, valuesInd, len);
119: }
120:
121: // No need to call varValue.invalidateStringRep() since it
122: // is called during the TclList.append() method.
123:
124: // Now store the list object back into the variable. If there is an
125: // error setting the new value, decrement its ref count if it
126: // was new and we didn't create the variable.
127:
128: try {
129: newValue = interp.setVar(varName, varValue, 0);
130: } catch (TclException e) {
131: if (createdNewObj && !createVar) {
132: varValue.release(); // free unneeded obj
133: }
134: throw e;
135: }
136:
137: return newValue;
138: }
139: }
|