//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
/*
 *    This module contains the definitions for the inline functions used by the
 *    name undecorator.  It is intended that this file should be included
 *    somewhere in the source file for the undecorator to maximise the chance
 *    that they will be truly inlined.
 */

//    The following class heirarchy is a special tree/DAG representation for
//    composing strings.    The tree representation allows fast appending, and
//    allows the tree to contain DNames that are 'filled in' later.  All the
//    'real' string data is in leaf nodes so that those nodes can be shared.


class    DNameNode;            // abstract base class
class      charNode;            // leaf node
class      pcharNode;        // leaf node
class      pDNameNode;        // leaf node, points to DName
class      DNameStatusNode;    // leaf node
class      pairNode;            // tree node

//#define UND_STATS
#ifdef UND_STATS
static int charNode_count;
static int pcharNode_count;
static int pcharNode_literal_count;
static int pDNameNode_count;
static int DNameStatusNode_count;
static int DNameStatusNode_get_count;
static int pairNode_count;
static int pairNode_count_avoided;
static int Replicator_count;
#endif

class    DNameNode
{
protected:

                    DNameNode ();

                    DNameNode ( const DNameNode & );

public:

virtual    int            length () const PURE;
virtual    char        getLastChar () const PURE;
virtual    pchar_t        getString ( _In_z_ pchar_t, _In_ pchar_t ) const PURE;

};


class    charNode        : public DNameNode
{
private:
        char                me;

public:
                    charNode ( char );

virtual    int            length () const;
virtual    char        getLastChar () const;
virtual    pchar_t        getString ( _In_z_ pchar_t, _In_ pchar_t ) const;

};


class    pcharNode        : public DNameNode
{
private:
    pchar_t                me;
    int                    myLen;

public:
    pcharNode ( pcchar_t, int );

    virtual    int            length () const;
    virtual    char        getLastChar () const;
    virtual    pchar_t        getString ( _In_z_ pchar_t, _In_ pchar_t ) const;

};


class    pDNameNode        : public DNameNode
{
private:
    DName *                me;

public:
    pDNameNode ( DName * );

    virtual    int            length () const;
    virtual    char        getLastChar () const;
    virtual    pchar_t        getString ( _In_z_ pchar_t, _In_ pchar_t ) const;
};


class    DNameStatusNode    : public DNameNode
{
private:
#define    TruncationMessage        (" ?? ")
#define    TruncationMessageLength    (4)

    DNameStatus            me;
    int                    myLen;

    DNameStatusNode ( DNameStatus );

public:
    static DNameStatusNode *make(DNameStatus);

    virtual    int            length () const;
    virtual    char        getLastChar () const;
    virtual    pchar_t        getString ( _In_z_ pchar_t, _In_ pchar_t ) const;

};

class    pairNode        : public DNameNode
{
private:
        DNameNode *left;
        DNameNode *right;
        mutable int            myLen;

public:
                    pairNode ( DNameNode*, DNameNode* );

virtual    int            length () const;
virtual    char        getLastChar () const;
virtual    pchar_t        getString ( _In_z_ pchar_t, _In_ pchar_t ) const;

};



//    Memory allocation functions
            
inline    void *    operator new ( size_t sz, _HeapManager &, int noBuffer )
{    return    heap.getMemory ( sz, noBuffer );    }

void *    _HeapManager::getMemory ( size_t sz, int noBuffer )
{
    //    Align the allocation on an appropriate boundary

    sz    = (( sz + PACK_SIZE-1 ) & ~(PACK_SIZE-1) );

    if    ( noBuffer )
        return    ( *pOpNew )( sz );
    else
    {
        //    Handle an invalid request for 0 or negative amount of space.

        DASSERT( sz > 0 );
        if    ( 0 >= sz )
            sz    = PACK_SIZE;

        if    ( blockLeft < sz )
        {
            //    Is the request greater than the largest buffer size ?

            if    ( sz > memBlockSize )
                return    0;        // If it is, there is nothing we can do


            //    Allocate a new block

            Block *    pNewBlock    = rnew Block;


            //    Did the allocation succeed ?  If so connect it up

            if    ( pNewBlock )
            {
                //    Handle the initial state

                if    ( tail )
                    tail    = tail->next    = pNewBlock;
                else
                    head    = tail            = pNewBlock;

                //    Compute the remaining space

                blockLeft    = memBlockSize - sz;

            }    // End of IF then
            else
                return    0;        // Oh-oh!  Memory allocation failure

        }    // End of IF then
        else
            blockLeft    -= sz;    // Deduct the allocated amount

        //    And return the buffer address

        return    &( tail->memBlock[ blockLeft ]);

    }    // End of IF else
}    // End of "_HeapManager" FUNCTION "getMemory(size_t,int)"


inline pchar_t getStringHelper ( _Inout_z_ pchar_t buf, _In_ pchar_t end, _In_count_(len) _Pre_z_ pchar_t str, int len )
{
    int capacity = (int)(end - buf);
    if (len > capacity)
      len = capacity;
    und_memcpy(buf, str, len);
    return    buf + len;
}


//    Friend functions of 'DName'

inline DName    operator + ( char c, const DName & rd )
{    return    DName ( c ) + rd;    }

inline DName    operator + ( DNameStatus st, const DName & rd )
{    return    DName ( st ) + rd;    }

inline DName    operator + ( pcchar_t s, const DName & rd )
{    return    DName ( s ) + rd;    }


//    The 'DName' constructors

inline        DName::DName ()
{
    node        = 0;
    stat        = DN_valid;
    isIndir        = 0;
    isAUDC        = 0;
    isAUDTThunk    = 0;
    isArrayType    = 0;
    NoTE        = 0;
    pinPtr        = 0;
    comArray    = 0;
    vcallThunk    = 0;
}


DName::DName ( char c )
{
    stat        = DN_valid;
    isIndir        = 0;
    isAUDC        = 0;
    isAUDTThunk    = 0;
    isArrayType    = 0;
    node        = 0;
    NoTE        = 0;
    pinPtr        = 0;
    comArray    = 0;
    vcallThunk    = 0;

    //    The NUL character would prematurely terminate the string

    if    ( c )
        doPchar ( &c, 1 );

}    // End of "DName" CONSTRUCTOR '(char)'


#pragma intrinsic(memcpy)  // See below.

inline DName::DName ( const DName & rd )
{
#if 1
    // SRA: the compiler generates terrible code for the assignments below,
    // copying each bit one at a time. I have been complaining about this for
    // years.  See VSWhidbey 2889.
    // Using intrinsic memcpy speeds up the whole undecorator by up to 25%
    // ('testundn.exe -fuzz' time reduced from 390s to 289s).
    memcpy(this, &rd, sizeof(*this));
#else
    stat        = rd.stat;
    isIndir        = rd.isIndir;
    isAUDC        = rd.isAUDC;
    isAUDTThunk    = rd.isAUDTThunk;
    isArrayType    = rd.isArrayType;
    node        = rd.node;
    NoTE        = rd.NoTE;
    pinPtr        = rd.pinPtr;
    comArray    = rd.comArray;
    vcallThunk    = rd.vcallThunk;
#endif
}    // End of "DName" CONSTRUCTOR '(const DName&)'


DName::DName ( DName * pd )
{
    if    ( pd )
    {
        node    = gnew pDNameNode ( pd );
        stat    = ( node ? DN_valid : DN_error );

    }    // End of IF else
    else
    {
        stat    = DN_valid;
        node    = 0;

    }    // End of IF else

    isIndir        = 0;
    isAUDC        = 0;
    isAUDTThunk    = 0;
    isArrayType    = 0;
    NoTE        = 0;
    pinPtr        = 0;
    comArray    = 0;
    vcallThunk    = 0;
}    // End of "DName" CONSTRUCTOR '( DName* )'


DName::DName ( pcchar_t s )
{
    stat        = DN_valid;
    node        = 0;
    isIndir        = 0;
    isAUDC        = 0;
    isAUDTThunk    = 0;
    isArrayType    = 0;
    NoTE        = 0;
    pinPtr        = 0;
    comArray    = 0;
    vcallThunk    = 0;

    // If we have a string that needs copying - then copy it.
    if (s != NULL)
    {
        unsigned int len = und_strlen(s);

        if (len > 0)
        {
            doPchar(s, len);
        }
    }
}    // End of "DName" CONSTRUCTOR '(pcchar_t)'


DName::DName ( pcchar_t & name, char terminator )
{
    stat        = DN_valid;
    isIndir        = 0;
    isAUDC        = 0;
    isAUDTThunk    = 0;
    isArrayType    = 0;
    node        = 0;
    NoTE        = 0;
    pinPtr        = 0;
    comArray    = 0;
    vcallThunk    = 0;

    //    Is there a string ?

    if    ( name )
        if    ( *name )
        {
            int    len    = 0;


            //    How long is the string ?

            pcchar_t s;
            for    ( s = name; *name && ( *name != terminator ); name++ )
                if    ( isValidIdentChar ( *name ) || UnDecorator::doNoIdentCharCheck () )
                    len++;
                else
                {
                    stat    = DN_invalid;

                    return;

                }    // End of IF else

            //    Copy the name string fragment

            doPchar ( s, len );

            //    Now gobble the terminator if present, handle error conditions

            if    ( *name )
            {
                if    ( *name++ != terminator )
                {
                    stat    = DN_error;
                    node    = 0;

                }    // End of IF then
            }    // End of IF then
            elif    ( status () == DN_valid )
                stat    = DN_truncated;

        }    // End of IF then
        else
            stat    = DN_truncated;
    else
        stat    = DN_invalid;

}    // End of "DName" CONSTRUCTOR '(pcchar_t&,char)'


DName::DName ( unsigned __int64 num )
{
    char    buf[ 21 ];
    char *    pBuf    = buf + 20;


    stat        = DN_valid;
    node        = 0;
    isIndir        = 0;
    isAUDC        = 0;
    isAUDTThunk    = 0;
    isArrayType    = 0;
    NoTE        = 0;
    pinPtr        = 0;
    comArray    = 0;
    vcallThunk    = 0;

    //    Essentially, 'ultoa ( num, buf, 10 )' :-

    *pBuf    = 0;

    do
    {
        *( --pBuf )    = (char)(( num % 10ui64 ) + '0' );
        num            /= 10ui64;

    }    while    ( num );

    doPchar ( pBuf, ( 20 - (int) ( pBuf - buf )));

}    // End of "DName" CONSTRUCTOR '(unsigned long)'

DName::DName ( __int64 num )
{
    char    buf[ 22 ];
    char *    pBuf    = buf + 21;

    stat        = DN_valid;
    node        = 0;
    isIndir        = 0;
    isAUDC        = 0;
    isAUDTThunk    = 0;
    isArrayType    = 0;
    NoTE        = 0;
    pinPtr        = 0;
    comArray    = 0;
    vcallThunk    = 0;

    //    Essentially, 'ltoa ( num, buf, 10 )' :-

    *pBuf    = 0;

    bool    fSigned = false;
    if (num < 0) {
        fSigned = true;
        num = -num;
    }

    do
    {
        *( --pBuf )    = (char)(( num % 10ui64 ) + '0' );
        num            /= 10ui64;

    }    while    ( num );

    if (fSigned) {
        *(--pBuf) = '-';
    }

    doPchar ( pBuf, ( 21 - (int) ( pBuf - buf )));
}

DName::DName ( DNameStatus st )
{
    isIndir        = 0;
    isAUDC        = 0;
    isAUDTThunk    = 0;
    isArrayType    = 0;
    NoTE        = 0;
    pinPtr        = 0;
    comArray    = 0;
    vcallThunk    = 0;

    stat        = ((( st == DN_invalid ) || ( st == DN_error )) ? st : DN_valid );
    node        = 0;

    if ( st == DN_truncated )
    {
        node    = DNameStatusNode::make ( st );

        if    ( !node )
            stat    = DN_error;
    }
}    // End of "DName" CONSTRUCTOR '(DNameStatus)'


//    Now the member functions for 'DName'

inline int        DName::isValid () const
{
    // return    (( status () == DN_valid ) || ( status () == DN_truncated ));
    //    equivalent test:
    typedef bool __cassert[DN_valid == 0 && DN_truncated == 1];
    return    stat <= DN_truncated;
}
inline int        DName::isEmpty () const
{
    DASSERT( isValid() || node == 0 );    // i.e. !isValid() implies node==0
    return    ( node == 0 );
}

inline    DNameStatus    DName::status () const    {    return    (DNameStatus)stat;    }    // The cast is to keep Glockenspiel quiet

inline    DName &    DName::setPtrRef ()            {    isIndir    = 1;    return    *this;    }
inline    int        DName::isPtrRef () const    {    return    isIndir;    }
inline    int        DName::isUDC () const        {    return    ( !isEmpty () && isAUDC );    }
inline    void    DName::setIsUDC ()            {    if    ( !isEmpty ())    isAUDC    = TRUE;    }
inline    int        DName::isUDTThunk () const    {    return    ( !isEmpty () && isAUDTThunk );    }
inline    void    DName::setIsUDTThunk ()        {    if    ( !isEmpty ())    isAUDTThunk    = TRUE;    }
inline    void    DName::setIsArray ()        {    isArrayType    = 1;    }
inline    int        DName::isArray () const        {    return    isArrayType;    }
inline    int        DName::isNoTE () const        {    return NoTE;    }
inline    void    DName::setIsNoTE ()            {    NoTE = TRUE;    }
inline    int        DName::isPinPtr() const        {    return pinPtr; }
inline    void    DName::setIsPinPtr()        {    pinPtr = TRUE; }
inline    int        DName::isComArray() const    {    return comArray; }
inline    void    DName::setIsComArray()        {    comArray = true; }
inline    int        DName::isVCallThunk() const    {    return vcallThunk; }
inline    void    DName::setIsVCallThunk()    {    vcallThunk = TRUE; }

inline int    DName::length () const
{
    if    ( isEmpty ())
      return  0;

    return    node->length();
}


inline char    DName::getLastChar () const
{
    if ( isEmpty ())
      return  '\0';

    return    node->getLastChar();
}


inline pchar_t    DName::getString ( _Inout_z_cap_(max) pchar_t buf, int max ) const
{
    if        ( !isEmpty ())
    {
        //    Does the caller want a buffer allocated ?

        if    ( !buf )
        {
            max    = length () + 1;
            buf    = gnew char[ max ];    // Get a buffer big enough

        }    // End of IF then

        //    If memory allocation failure, then return no buffer

        if    ( buf )
        {
            //    Now, go through the process of filling the buffer.    Leave one
            //    character for the NUL terminator.

            pchar_t remaining = getString(buf, buf + max - 1);

            *remaining = 0;    // Always NULL terminate the resulting string

        }    // End of IF
    }    // End of IF then
    elif    ( buf )
        *buf    = 0;

    //    Return the buffer

    return    buf;

}    // End of "DName" FUNCTION "getString(pchar_t,int)"


inline pchar_t    DName::getString ( _In_z_ pchar_t buf, _In_ pchar_t end ) const
{
    if ( isEmpty ())
      return  buf;

    return    node->getString(buf, end);
}


DName    DName::operator + ( char ch ) const
{
    DName    local ( *this );

    local += ch;

    //    And return the newly formed 'DName'
    return    local;
}


DName    DName::operator + ( pcchar_t str ) const
{
    DName    local ( *this );

    local += str;

    return    local;

}    // End of "DName" OPERATOR "+(pcchar_t)"


DName    DName::operator + ( const DName & rd ) const
{
    DName    local ( *this );

    local += rd;

    return    local;

}    // End of "DName" OPERATOR "+(const DName&)"


DName    DName::operator + ( DName * pd ) const
{
    DName    local ( *this );
 
    local += pd;

    return    local;

}    // End of "DName" OPERATOR "+(DName*)"


DName    DName::operator + ( DNameStatus st ) const
{
    DName    local ( *this );

    local += st;

    return    local;

}    // End of "DName" OPERATOR "+(DNameStatus)"


void DName::append (DNameNode *newRight)
{
    if    ( newRight )
    {
        node = gnew pairNode(node, newRight);
        if (!node)
          stat = DN_error;
    }
    else
      stat    = DN_error;
}

DName &    DName::operator += ( char ch )
{
    if ( isValid() )
    {
        if    ( ch )
        {
            if    ( isEmpty ())
                *this    = ch;
            else
            {
                append (gnew charNode (ch));
            }
        }
    }
    //    And return self

    return    *this;

}    // End of "DName" OPERATOR "+=(char)"


DName &    DName::operator += ( pcchar_t str )
{
    if ( isValid() )
    {
        if    ( str && *str )
            if    ( isEmpty ())
                *this    = str;
            else
            {
                append (gnew pcharNode ( str, und_strlen(str) ));
            }
    }
    //    And return self

    return    *this;

}    // End of "DName" OPERATOR "+=(pcchar_t)"


DName &    DName::operator += ( const DName & rd )
{
    if ( isValid() )
    {
        if    ( rd.isEmpty ())
        {
            *this    += rd.status ();
        }
        else
        {
            if    ( isEmpty ())
                *this    = rd;
            else
            {
                append (rd.node);
            }
        }
    }

    //    And return self

    return    *this;

}    // End of "DName" OPERATOR "+=(const DName&)"


DName &    DName::operator += ( DName * pd )
{
    if    ( isValid()     &&     pd )
    {
        if    ( isEmpty ())
            *this    = pd;
        elif    (( pd->status () == DN_valid ) || ( pd->status () == DN_truncated ))
        {
            append ( gnew pDNameNode ( pd ) );
        }
        else
            *this    += pd->status ();
    }
    //    And return self

    return    *this;

}    // End of "DName" OPERATOR "+=(DName*)"


DName &    DName::operator += ( DNameStatus st )
{
    if ( isValid() )
    {
        if    ( isEmpty () || (( st == DN_invalid ) || ( st == DN_error )))
        {
            *this    = st;
        }
        else if (st == DN_valid)
        {
#ifdef UND_STATS
            ++pairNode_count_avoided;
#endif
            // no point in appending a node that has no error content or output
            // text
        }
        else
        {
            append ( DNameStatusNode::make ( st ) );
        }
    }

    //    Return self
    return    *this;

}    // End of "DName" OPERATOR "+=(DNameStatus)"



DName &    DName::operator |= ( const DName & rd )
{
    //    Attenuate the error status.     Always becomes worse.    Don't propogate truncation

    if    (( status () != DN_error ) && !rd.isValid ())
        stat    = rd.status ();

    //    And return self

    return    *this;

}    // End of "DName" OPERATOR '|=(const DName&)'



inline DName &    DName::operator = ( char ch )
{
    stat        = DN_valid;
    node        = 0;
    isIndir        = 0;
    isAUDC        = 0;
    isAUDTThunk    = 0;
    isArrayType    = 0;
    NoTE        = 0;
    pinPtr        = 0;
    comArray    = 0;
    vcallThunk    = 0;

    if (ch)
        doPchar ( &ch, 1 );

    return    *this;

}    // End of "DName" OPERATOR '=(char)'


DName &    DName::operator = ( pcchar_t str )
{
    stat        = DN_valid;
    node        = 0;
    isIndir        = 0;
    isAUDC        = 0;
    isAUDTThunk = 0;
    isArrayType    = 0;
    NoTE        = 0;
    pinPtr        = 0;
    comArray    = 0;
    vcallThunk    = 0;

    doPchar ( str, und_strlen ( str ));

    //    And return self

    return    *this;

}    // End of "DName" OPERATOR '=(pcchar_t)'


DName &    DName::operator = ( const DName & rd )
{
#if 1
    // SRA: see comment in the copy constructor DName::DName(const DName&);
    memcpy(this, &rd, sizeof(*this));
#else
    stat        = rd.stat;

    node        = rd.node;

    isIndir        = rd.isIndir;
    isAUDC        = rd.isAUDC;
    isAUDTThunk = rd.isAUDTThunk;
    isArrayType    = rd.isArrayType;
    NoTE        = rd.NoTE;
    pinPtr        = rd.pinPtr;
    comArray    = rd.comArray;
    vcallThunk    = rd.vcallThunk;
#endif
    //    And return self

    return    *this;

}    // End of "DName" OPERATOR '=(const DName&)'


DName &    DName::operator = ( DName * pd )
{
    stat        = DN_valid;
    node        = 0;
    isIndir        = 0;
    isAUDC        = 0;
    isAUDTThunk    = 0;
    isArrayType    = 0;
    NoTE        = 0;
    pinPtr        = 0;
    comArray    = 0;
    vcallThunk    = 0;

    if    ( pd )
    {
        node        = gnew pDNameNode ( pd );

        if    ( !node )
            stat    = DN_error;

    }    // End of IF then
    else
        stat    = DN_error;

    //    And return self

    return    *this;

}    // End of "DName" OPERATOR '=(DName*)'


DName &    DName::operator = ( DNameStatus st )
{
    isIndir        = 0;
    isAUDC        = 0;
    isAUDTThunk    = 0;
    isArrayType    = 0;
    NoTE        = 0;
    pinPtr        = 0;
    comArray    = 0;
    vcallThunk    = 0;

    stat    = st;

    if ( st == DN_truncated )
    {
        node        = DNameStatusNode::make ( st );
        
        if    ( !node )
            stat    = DN_error;
    }
    else
    {
        node    = 0;
    }

    //    And return self

    return    *this;

}    // End of "DName" OPERATOR '=(DNameStatus)'


//    Private implementation functions for 'DName'

void    DName::doPchar ( pcchar_t str, int len )
{
    if        ( node )
        *this    = DN_error;
    elif    ( str && len )
    {
        //    Allocate as economically as possible

        switch    ( len )
        {
        case 0:
                stat    = DN_error;
            break;

        case 1:
                node    = gnew charNode ( *str );

                if    ( !node )
                    stat    = DN_error;
            break;

        default:
                node    = gnew pcharNode ( str, len );

                if    ( !node )
                    stat    = DN_error;
            break;

        }    // End of SWITCH
    }    // End of ELIF
    else
        stat    = DN_invalid;

}    // End of "DName" FUNCTION "doPchar(pcchar_t,int)"



//    The member functions for the 'Replicator'

inline    int    Replicator::isFull () const        {    return    ( index == 9 );    }
inline        Replicator::Replicator ()
{
    index    = -1;
#ifdef UND_STATS
    ++Replicator_count;
#endif
}



Replicator &    Replicator::operator += ( const DName & rd )
{
    if    ( !isFull () && !rd.isEmpty ())
    {
        DName *    pNew    = gnew DName ( rd );


        //    Don't update if failed

        if    ( pNew )
            dNameBuffer[ ++index ]    = pNew;

    }    // End of IF

    return    *this;

}    // End of "Replicator" OPERATOR '+=(const DName&)'


DName    Replicator::operator [] ( int x ) const
{
    if        (( x < 0 ) || ( x > 9 ))
        return    DN_error;
    elif    (( index == -1 ) || ( x > index ))
        return    DN_invalid;
    else
        return    *dNameBuffer[ x ];

}    // End of "Replicator" OPERATOR '[](int)'



//    The member functions for the 'DNameNode' classes

DNameNode::DNameNode ()
{
}

//    The 'charNode' virtual functions

charNode::charNode ( char ch )
{
    me    = ch;
#ifdef UND_STATS
    ++charNode_count;
#endif
}

inline    int    charNode::length () const        {    return    1;    }

inline    char charNode::getLastChar () const    {    return    me;    }

inline pchar_t    charNode::getString ( _In_z_ pchar_t buf, _In_ pchar_t end ) const
{
    if    ( buf < end )
      *buf++    = me;

    return    buf;
}



//    The 'pcharNode' virtual functions

inline    int    pcharNode::length () const        {    return    myLen;    }

inline    char pcharNode::getLastChar () const    {    return    ( myLen ? me[ myLen - 1 ] : '\0' );    }

pcharNode::pcharNode ( pcchar_t str, int len )
{
#ifdef UND_STATS
    ++pcharNode_count;
#endif

    //    Allocate a new string buffer if valid state

    if    ( len && str )
    {
#ifdef UND_STATS
        if (0 == ((((uintptr_t)"string") ^ ((uintptr_t)str)) & (~(uintptr_t)0xFFFF)))
          ++pcharNode_literal_count;
#endif
        me        = gnew char[ len ];
        myLen    = len;

        if    ( me )
          und_memcpy ( me, str, len );

    }    // End of IF then
    else
    {
        me        = 0;
        myLen    = 0;

    }    // End of IF else
}    // End of "pcharNode" CONSTRUCTOR '(pcchar_t,int)'


inline pchar_t    pcharNode::getString ( _In_z_ pchar_t buf, _In_ pchar_t end ) const
{
    return    getStringHelper(buf, end, me, myLen);
}



//    The 'pDNameNode' virtual functions

pDNameNode::pDNameNode ( DName * pName )
{
    me    = (( pName && (( pName->status () == DN_invalid ) || ( pName->status () == DN_error ))) ? 0 : pName );
#ifdef UND_STATS
    ++pDNameNode_count;
#endif
}

inline    int    pDNameNode::length () const
{
    return    me ? me->length() : 0;
}

inline    char pDNameNode::getLastChar () const            {    return    ( me ? me->getLastChar () : '\0' ); }

inline pchar_t    pDNameNode::getString ( _In_z_ pchar_t buf, _In_ pchar_t end ) const
{
    return    me ? me->getString( buf, end ) : buf;
}



//    The 'DNameStatusNode' virtual functions
DNameStatusNode::DNameStatusNode ( DNameStatus stat )
{
    me    = stat;
    myLen    = (( me == DN_truncated ) ? TruncationMessageLength : 0 );
#ifdef UND_STATS
    ++DNameStatusNode_count;
#endif
}

inline    int    DNameStatusNode::length () const    {    return    myLen;    }

inline    char DNameStatusNode::getLastChar () const
{
    return (( me == DN_truncated ) ? TruncationMessage[ TruncationMessageLength - 1 ] : '\0' );
}

inline pchar_t    DNameStatusNode::getString ( _In_z_ pchar_t buf, _In_ pchar_t end ) const
{
    if (me == DN_truncated)
    {
        return    getStringHelper(buf, end, TruncationMessage, TruncationMessageLength);
    }
    return    buf;
}


inline DNameStatusNode *DNameStatusNode::make(DNameStatus stat)
{
    static DNameStatusNode nodes[4] = {DN_valid, DN_truncated, DN_invalid, DN_error};

#ifdef UND_STATS
    ++DNameStatusNode_get_count;
#endif

    if (stat >= 0 && stat < 4)
      return  &nodes[stat];

    return &nodes[DN_error];

}


//    The 'pairNode' virtual functions

pairNode::pairNode ( DNameNode *left, DNameNode *right )
    : left(left),
      right(right),
      myLen(-1)
{
#ifdef UND_STATS
    ++pairNode_count;
#endif
}

inline    int    pairNode::length () const
{
    if (myLen < 0)
      myLen = left->length() + right->length();
    return    myLen;
}

inline    char pairNode::getLastChar () const
{
    char ch = right->getLastChar();
    if (ch == 0)  // i.e. the right half is empty
      ch = left->getLastChar();
    return    ch;
}

inline pchar_t    pairNode::getString ( _In_z_ pchar_t buf, _In_ pchar_t end ) const
{
    pchar_t remaining = left->getString(buf, end);
    if (remaining < end)
      return  right->getString(remaining, end);
    else
      return  remaining;
}


static    unsigned int    und_strlen ( pcchar_t str )
{
    unsigned int len;

    for    ( len = 0; *str; str++ )
        len++;

    return    len;

}    // End of FUNCTION "und_strlen"


static    void            und_memcpy ( _Out_bytecap_(len) pchar_t dst, pcchar_t src, unsigned int len )
{
    for (unsigned int i = 0;  i < len;    ++i)
    {
        dst[i] = src[i];
    }
}    // End of FUNCTION "und_memcpy"

static    unsigned int    und_strncmp ( pcchar_t first, pcchar_t last, unsigned int count)
{
    if (!count)
        return(0);

    while (--count && *first && *first == *last)
    {
        first++;
        last++;
    }

    return( *(unsigned char *)first - *(unsigned char *)last );
}

#ifdef UND_STATS
struct __unDName_atexit
{
    ~__unDName_atexit()
    {
        printf("charNode           = %d\n", charNode_count);
        printf("pcharNode           = %d\n", pcharNode_count);
        printf("          literals = %d\n", pcharNode_literal_count);
        printf("pDNameNode           = %d\n", pDNameNode_count);
        printf("DNameStatusNode       = %d\n", DNameStatusNode_count);
        printf("               get = %d\n", DNameStatusNode_get_count);
        printf("pairNode           = %d\n", pairNode_count);
        printf("           avoided = %d\n", pairNode_count_avoided);
        printf("Replicator           = %d\n", Replicator_count);

        printf("sizeof DName =    %u\n", sizeof(DName));
    }
} __unDName_atexit_used;
#endif
