/*
* LappendCmd.java
*
* Copyright (c) 1997 Cornell University.
* Copyright (c) 1997 Sun Microsystems, Inc.
* Copyright (c) 1998-1999 by Scriptics Corporation.
* Copyright (c) 1999 Mo DeJong.
*
* See the file "license.terms" for information on usage and
* redistribution of this file, and for a DISCLAIMER OF ALL
* WARRANTIES.
*
* Included in SQLite3 port to C# for use in testharness only; 2008 Noah B Hart
*
* RCS @(#) $Id: LappendCmd.java,v 1.3 2003/01/09 02:15:39 mdejong Exp $
*
*/
using System;
namespace tcl.lang
{
/// This class implements the built-in "lappend" command in Tcl.
class LappendCmd : Command
{
///
/// Tcl_LappendObjCmd -> LappendCmd.cmdProc
///
/// This procedure is invoked to process the "lappend" Tcl command.
/// See the user documentation for details on what it does.
///
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;
}
}
}