JBoolean
CBCommand::Add
	(
	const JPtrArray<JString>&	cmdArgs,
	const JPtrArray<JString>&	fullNameList,
	const JArray<JIndex>&		lineIndexList,
	CBFunctionStack*			fnStack
	)
{
	const JString* firstArg = cmdArgs.FirstElement();
	if (firstArg->GetFirstCharacter() == '&')
		{
		assert( fnStack != NULL );

		// check for re-used command name

		const JCharacter* cmdName = firstArg->GetCString()+1;

		const JSize cmdCount = fnStack->GetElementCount();
		for (JIndex j=1; j<=cmdCount; j++)
			{
			if (strcmp(cmdName, fnStack->Peek(j)) == 0)
				{
				ReportInfiniteLoop(*fnStack, j);
				return kJFalse;
				}
			}

		// prepare cmd for execution later

		fnStack->Push(cmdName);

		CBCommandManager* mgr =
			(itsProjDoc != NULL ? itsProjDoc->GetCommandManager() : CBGetCommandManager());
		CBCommand* cmdObj;
		CBCommandManager::CmdInfo* cmdInfo;
		if (mgr->Prepare(cmdName, itsProjDoc, fullNameList, lineIndexList,
						 &cmdObj, &cmdInfo, fnStack))
			{
			cmdObj->SetParent(this);
			itsCmdList->AppendElement(CmdInfo(NULL, cmdObj, cmdInfo, kJFalse));
			}
		else
			{
			return kJFalse;
			}

		fnStack->Pop();
		}
	else
		{
		JPtrArray<JString>* args = jnew JPtrArray<JString>(JPtrArrayT::kDeleteAll);
		assert( args != NULL );
		args->CopyObjects(cmdArgs, JPtrArrayT::kDeleteAll, kJFalse);

		itsCmdList->AppendElement(CmdInfo(args, NULL, NULL, kJFalse));
		}

	return kJTrue;
}