Added showdebug command.
Also:
* Added an exported constructor to RChildProcess so the iProcess handle was set to zero on construction.
* Fixed bug in fshell_builddocs script that created HTML relative links with backslashes instead of forward slashes.
// bsymtree.cpp
//
// Copyright (c) 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Accenture - Initial contribution
//
#include "bsymtree.h"
#include <badesca.h>
#include <fshell/descriptorutils.h>
//#include <e32debug.h>
using namespace LtkUtils;
RNode* RNode::NewL()
{
RNode* top = new(ELeave) RNode(0);
CleanupDeletePushL(top);
top->iPtr = new(ELeave) RArray<RNode*>(8);
top->iHasChildArray = 1;
CleanupStack::Pop(top);
return top;
}
RNode::RNode(char aLetter)
: iLetter(aLetter), iHasChildArray(0), iPad(0), iPtr(NULL)
{
}
RNode* RNode::Sprog() const
{
ASSERT(!iHasChildArray);
ASSERT(iLetter != 0);
return reinterpret_cast<RNode*>(iPtr);
}
RArray<RNode*>& RNode::Sprogs() const
{
ASSERT(iHasChildArray);
return *reinterpret_cast<RArray<RNode*>*>(iPtr);
}
RNode* RNode::ChildForLetter(char aChild) const
{
if (iHasChildArray)
{
const TInt count = Sprogs().Count();
for (TInt i = 0; i < count; i++)
{
RNode* node = Sprogs()[i];
if (node->iLetter == aChild) return node;
}
}
else if (iLetter != 0) // null terminators use next for the value
{
RNode* child = Sprog();
if (child && child->iLetter == aChild) return child;
}
return NULL;
}
RNode* RNode::AddChildL(char aChild)
{
RNode* node = new(ELeave) RNode(aChild);
CleanupStack::PushL(node);
if (!iHasChildArray)
{
if (iPtr == NULL)
{
// Easy
CleanupStack::Pop(node);
iPtr = node;
return node;
}
else
{
// Need to upgrade to a childArray
RArray<RNode*>* children = new(ELeave) RArray<RNode*>(8);
CleanupStack::PushL(children);
children->AppendL(reinterpret_cast<RNode*>(iPtr));
iPtr = children;
CleanupStack::Pop(children);
iHasChildArray = 1;
}
}
Sprogs().AppendL(node);
CleanupStack::Pop(node);
return node;
}
void RNode::InsertStringL(const TUint16* aString, TInt aValue)
{
char letter = (char)*aString;
RNode* child = ChildForLetter(letter);
if (!child)
{
child = AddChildL(letter);
}
if (letter == 0)
{
// If the letter was the null termination at the end, we're finished and just need to set the value
//ASSERT(child->iPtr == NULL); // There should never be a child of a null terminator (unless the same string has been inserted twice...)
// ^ Annoyingly there can be duplicate symbols that are only distinguished by information we've actually thrown away in the BSYM.
// We will ignore such duplicate symbols. If this is a problem, someone feel free to fix it.
if (!child->iPtr)
{
child->iPtr = (TAny*)aValue;
}
}
else
{
aString++;
child->InsertStringL(aString, aValue);
}
}
RNode* RNode::WalkToEndOfString(TUint16*& aString)
{
RNode* currentNode = this;
while (*aString)
{
RNode* child = currentNode->ChildForLetter((char)*aString);
if (!child) return currentNode;
currentNode = child;
aString++;
}
return currentNode;
}
RNode* RNode::TabFill(TUint16*& aString, const TUint16* aEnd)
{
// This function completes as far as the next choice point
// aString is a pointer into a buffer with plenty of space in it
//Dump(); // DEBUG
if (!iHasChildArray && iLetter && iPtr && aString+1 < aEnd)
{
*aString = Sprog()->iLetter;
aString++;
*aString = 0;
return Sprog()->TabFill(aString, aEnd);
}
else
{
return this;
}
}
void RNode::CompleteL(TDes& aPrefix, CDesC16Array& aResults)
{
TUint16* ptr = (TUint16*)aPrefix.PtrZ();
TUint16* end = ptr + aPrefix.MaxLength();
RNode* endNode = WalkToEndOfString(ptr);
if (ptr != aPrefix.Ptr() + aPrefix.Length()) return; // We failed to walk the whole of the string so we have nothing to suggest (the string is longer than anything in the tree)
endNode = endNode->TabFill(ptr, end);
TInt newLen = ptr - aPrefix.Ptr();
if (endNode->iLetter == 0 && newLen > 0) newLen--; // If ptr got as far as the null termination, we need to make our length one shorter
//RDebug::Printf("Setting aPrefix len to %d, len=%d maxlen=%d", newLen, aPrefix.Length(), aPrefix.MaxLength());
aPrefix.SetLength(newLen);
// Now that aPrefix has been completed with as much as didn't have any choices, fill aResults with the choices
RLtkBuf current;
current.CreateLC(256);
current.AppendL(aPrefix);
if (current.Length()) current.SetLength(current.Length()-1); // Remove endNode's char as DoCompleteOptionsL expects to do that bit
endNode->DoCompleteOptionsL(aResults, current);
// Make sure last string is included
aResults.AppendL(current);
CleanupStack::PopAndDestroy(¤t);
aResults.Sort();
}
void RNode::DoCompleteOptionsL(CDesC16Array& aResults, RLtkBuf& aCurrent)
{
if (iLetter)
{
aCurrent.ReserveExtraL(1);
aCurrent.Append(TChar(iLetter));
}
TInt currentLen = aCurrent.Length();
if (iHasChildArray)
{
for (int i = 0; i < Sprogs().Count(); i++)
{
RNode* child = Sprogs()[i];
if (i > 0)
{
// A new prefix is in order
aResults.AppendL(aCurrent);
aCurrent.SetLength(currentLen);
}
child->DoCompleteOptionsL(aResults, aCurrent);
}
}
else if (iLetter != 0)
{
if (Sprog()) Sprog()->DoCompleteOptionsL(aResults, aCurrent);
}
}
RNode::~RNode()
{
if (iHasChildArray)
{
RArray<RNode*>& children = Sprogs();
const TInt count = children.Count();
for (TInt i = 0; i < count; i++)
{
RNode* node = children[i];
delete node;
}
children.Close();
delete &children;
}
else if (iLetter != 0)
{
delete Sprog();
}
}
/*
#include <e32debug.h>
void RNode::Dump() const
{
TInt sprogCount = Sprogs().Count();
for (int i = 0; i < sprogCount; i++)
{
RNode* child = Sprogs()[i];
RDebug::Printf("Sprog %i is letter %c", i, child->iLetter);
}
}
*/
TInt RNode::ValueForStringL(const TDesC& aString) const
{
const RNode* node = this;
for (TInt i = 0; i < aString.Length(); i++)
{
node = node->ChildForLetter(aString[i]);
if (!node) User::Leave(KErrNotFound);
}
node = node->ChildForLetter(0); // The null terminator node is the one with the value in
if (!node) User::Leave(KErrNotFound);
ASSERT(!node->iHasChildArray);
return reinterpret_cast<TInt>(node->iPtr);
}