Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1253 lines
23 KiB

/*
* 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 is a special node class, used in the implementation
// of the internal chaining mechanism of the 'DName's
class charNode;
class pcharNode;
class pDNameNode;
class DNameStatusNode;
#if ( NO_VIRTUAL )
enum NodeType
{
charNode_t,
pcharNode_t,
pDNameNode_t,
DNameStatusNode_t
};
#endif // NO_VIRTUAL
class DNameNode
{
private:
#if NO_VIRTUAL
NodeType typeIndex;
#endif // NO_VIRTUAL
DNameNode * next;
protected:
#if ( !NO_VIRTUAL )
DNameNode ();
#else // } elif NO_VIRTUAL {
DNameNode ( NodeType );
#endif // NO_VIRTUAL
DNameNode ( const DNameNode & );
public:
virtual int length () const PURE;
virtual char getLastChar () const PURE;
virtual pchar_t getString ( pchar_t, int ) const PURE;
DNameNode * clone ();
DNameNode * nextNode () const;
DNameNode & operator += ( DNameNode * );
};
class charNode : public DNameNode
{
private:
char me;
public:
charNode ( char );
virtual int length () const;
virtual char getLastChar () const;
virtual pchar_t getString ( pchar_t, int ) const;
};
class pcharNode : public DNameNode
{
private:
pchar_t me;
int myLen;
public:
pcharNode ( pcchar_t, int = 0 );
virtual int length () const;
virtual char getLastChar () const;
virtual pchar_t getString ( pchar_t, int ) const;
};
class pDNameNode : public DNameNode
{
private:
DName * me;
public:
pDNameNode ( DName * );
virtual int length () const;
virtual char getLastChar () const;
virtual pchar_t getString ( pchar_t, int ) const;
};
class DNameStatusNode : public DNameNode
{
private:
#define TruncationMessage (" ?? ")
#define TruncationMessageLength (4)
DNameStatus me;
int myLen;
public:
DNameStatusNode ( DNameStatus );
virtual int length () const;
virtual char getLastChar () const;
virtual pchar_t getString ( pchar_t, int ) 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 a potential request for no space
if ( !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)"
// 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; }
inline DName::DName ( DNameNode * pd ) { node = pd; stat = DN_valid; isIndir = 0; isAUDC = 0; isAUDTThunk = 0; isArrayType = 0; NoTE = 0; }
DName::DName ( char c )
{
stat = DN_valid;
isIndir = 0;
isAUDC = 0;
isAUDTThunk = 0;
isArrayType = 0;
node = 0;
NoTE = 0;
// The NULL character is boring, do not copy
if ( c )
doPchar ( &c, 1 );
} // End of "DName" CONSTRUCTOR '(char)'
inline DName::DName ( const DName & rd )
{
stat = rd.stat;
isIndir = rd.isIndir;
isAUDC = rd.isAUDC;
isAUDTThunk = rd.isAUDTThunk;
isArrayType = rd.isArrayType;
node = rd.node;
NoTE = rd.NoTE;
} // 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;
} // 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;
if ( s )
doPchar ( s, und_strlen ( s ));
} // 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;
// 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
else
stat = DN_valid;
} // 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;
// 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;
// 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 )
{
stat = ((( st == DN_invalid ) || ( st == DN_error )) ? st : DN_valid );
node = gnew DNameStatusNode ( st );
isIndir = 0;
isAUDC = 0;
isAUDTThunk = 0;
isArrayType = 0;
NoTE = 0;
if ( !node )
stat = DN_error;
} // End of "DName" CONSTRUCTOR '(DNameStatus)'
// Now the member functions for 'DName'
int DName::isValid () const { return (( status () == DN_valid ) || ( status () == DN_truncated )); }
int DName::isEmpty () const { return (( node == 0 ) || !isValid ()); }
inline DNameStatus DName::status () const { return (DNameStatus)stat; } // The cast is to keep Glockenspiel quiet
inline void DName::clearStatus () { stat = DN_valid; }
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; }
int DName::length () const
{
int len = 0;
if ( !isEmpty ())
for ( DNameNode * pNode = node; pNode; pNode = pNode->nextNode ())
len += pNode->length ();
return len;
} // End of "DName" FUNCTION "length"
char DName::getLastChar () const
{
DNameNode * pLast = 0;
if ( !isEmpty ())
for ( DNameNode * pNode = node; pNode; pNode = pNode->nextNode ())
if ( pNode->length () != 0 )
pLast = pNode;
return pLast != 0 ? pLast->getLastChar () : '\0';
} // End of "DName" FUNCTION "getLastChar"
pchar_t DName::getString ( 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 (until max is reached)
int curLen = max;
DNameNode * curNode = node;
pchar_t curBuf = buf;
while ( curNode && ( curLen > 0 ))
{
int fragLen = curNode->length ();
pchar_t fragBuf = 0;
// Skip empty nodes
if ( fragLen )
{
// Handle buffer overflow
if (( curLen - fragLen ) < 0 )
fragLen = curLen;
// Now copy 'len' number of bytes of the piece to the buffer
fragBuf = curNode->getString ( curBuf, fragLen );
// Should never happen, but handle it anyway
if ( fragBuf )
{
// Update string position
curLen -= fragLen;
curBuf += fragLen;
} // End of IF
} // End of IF
// Move on to the next name fragment
curNode = curNode->nextNode ();
} // End of WHILE
*curBuf = 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)"
DName DName::operator + ( char ch ) const
{
DName local ( *this );
if ( local.isEmpty ())
local = ch;
else
local += ch;
// And return the newly formed 'DName'
return local;
} // End of "DName" OPERATOR "+(char)"
DName DName::operator + ( pcchar_t str ) const
{
DName local ( *this );
if ( local.isEmpty ())
local = str;
else
local += str;
// And return the newly formed 'DName'
return local;
} // End of "DName" OPERATOR "+(pcchar_t)"
DName DName::operator + ( const DName & rd ) const
{
DName local ( *this );
if ( local.isEmpty ())
local = rd;
elif ( rd.isEmpty ())
local += rd.status ();
else
local += rd;
// And return the newly formed 'DName'
return local;
} // End of "DName" OPERATOR "+(const DName&)"
DName DName::operator + ( DName * pd ) const
{
DName local ( *this );
if ( local.isEmpty ())
local = pd;
else
local += pd;
// And return the newly formed 'DName'
return local;
} // End of "DName" OPERATOR "+(DName*)"
DName DName::operator + ( DNameStatus st ) const
{
DName local ( *this );
if ( local.isEmpty ())
local = st;
else
local += st;
// And return the newly formed 'DName'
return local;
} // End of "DName" OPERATOR "+(DNameStatus)"
DName & DName::operator += ( char ch )
{
if ( ch )
if ( isEmpty ())
*this = ch;
else
{
node = node->clone ();
if ( node )
*node += gnew charNode ( ch );
else
stat = DN_error;
} // End of IF
// And return self
return *this;
} // End of "DName" OPERATOR "+=(char)"
DName & DName::operator += ( pcchar_t str )
{
if ( str && *str )
if ( isEmpty ())
*this = str;
else
{
node = node->clone ();
if ( node )
*node += gnew pcharNode ( str );
else
stat = DN_error;
} // End of IF
// And return self
return *this;
} // End of "DName" OPERATOR "+=(pcchar_t)"
DName & DName::operator += ( const DName & rd )
{
if ( rd.isEmpty ())
*this += rd.status ();
else
if ( isEmpty ())
*this = rd;
else
{
node = node->clone ();
if ( node )
*node += rd.node;
else
stat = DN_error;
} // End of IF
// And return self
return *this;
} // End of "DName" OPERATOR "+=(const DName&)"
DName & DName::operator += ( DName * pd )
{
if ( pd )
if ( isEmpty ())
*this = pd;
elif (( pd->status () == DN_valid ) || ( pd->status () == DN_truncated ))
{
DNameNode * pNew = gnew pDNameNode ( pd );
if ( pNew )
{
node = node->clone ();
if ( node )
*node += pNew;
} // End of IF then
else
node = 0;
if ( !node )
stat = DN_error;
} // End of IF then
else
*this += pd->status ();
// And return self
return *this;
} // End of "DName" OPERATOR "+=(DName*)"
DName & DName::operator += ( DNameStatus st )
{
if ( isEmpty () || (( st == DN_invalid ) || ( st == DN_error )))
*this = st;
else
{
DNameNode * pNew = gnew DNameStatusNode ( st );
if ( pNew )
{
node = node->clone ();
if ( node )
*node += pNew;
} // End of IF then
else
node = 0;
if ( !node )
stat = DN_error;
} // End of IF else
// 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&)'
DName & DName::operator = ( char ch )
{
isIndir = 0;
isAUDC = 0;
isAUDTThunk = 0;
isArrayType = 0;
doPchar ( &ch, 1 );
return *this;
} // End of "DName" OPERATOR '=(char)'
DName & DName::operator = ( pcchar_t str )
{
isIndir = 0;
isAUDC = 0;
isAUDTThunk = 0;
isArrayType = 0;
doPchar ( str, und_strlen ( str ));
// And return self
return *this;
} // End of "DName" OPERATOR '=(pcchar_t)'
DName & DName::operator = ( const DName & rd )
{
if (( status () == DN_valid ) || ( status () == DN_truncated ))
{
stat = rd.stat;
isIndir = rd.isIndir;
isAUDC = rd.isAUDC;
isAUDTThunk = rd.isAUDTThunk;
isArrayType = rd.isArrayType;
node = rd.node;
} // End of IF
// And return self
return *this;
} // End of "DName" OPERATOR '=(const DName&)'
DName & DName::operator = ( DName * pd )
{
if (( status () == DN_valid ) || ( status () == DN_truncated ))
if ( pd )
{
isIndir = 0;
isAUDC = 0;
isAUDTThunk = 0;
isArrayType = 0;
node = gnew pDNameNode ( pd );
if ( !node )
stat = DN_error;
} // End of IF then
else
*this = DN_error;
// And return self
return *this;
} // End of "DName" OPERATOR '=(DName*)'
DName & DName::operator = ( DNameStatus st )
{
if (( st == DN_invalid ) || ( st == DN_error ))
{
node = 0;
if ( status () != DN_error )
stat = st;
} // End of IF then
elif (( status () == DN_valid ) || ( status () == DN_truncated ))
{
isIndir = 0;
isAUDC = 0;
isAUDTThunk = 0;
isArrayType = 0;
node = gnew DNameStatusNode ( st );
if ( !node )
stat = DN_error;
} // End of ELIF then
// And return self
return *this;
} // End of "DName" OPERATOR '=(DNameStatus)'
// Private implementation functions for 'DName'
void DName::doPchar ( pcchar_t str, int len )
{
if ( !(( status () == DN_invalid ) || ( status () == DN_error )))
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 ()
: ErrorDName ( DN_error ), InvalidDName ( DN_invalid )
{ index = -1; }
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&)'
const DName & Replicator::operator [] ( int x ) const
{
if (( x < 0 ) || ( x > 9 ))
return ErrorDName;
elif (( index == -1 ) || ( x > index ))
return InvalidDName;
else
return *dNameBuffer[ x ];
} // End of "Replicator" OPERATOR '[](int)'
// The member functions for the 'DNameNode' classes
#if ( !NO_VIRTUAL )
DNameNode::DNameNode ()
#else // } elif NO_VIRTUAL {
DNameNode::DNameNode ( NodeType ndTy )
: typeIndex ( ndTy )
#endif // NO_VIRTUAL
{ next = 0; }
inline DNameNode::DNameNode ( const DNameNode & rd ) { next = (( rd.next ) ? rd.next->clone () : 0 ); }
inline DNameNode * DNameNode::nextNode () const { return next; }
DNameNode * DNameNode::clone ()
{
return gnew pDNameNode ( gnew DName ( this ));
}
#if ( NO_VIRTUAL )
int DNameNode::length () const
{ // Pure function, should not be called
switch ( typeIndex )
{
case charNode_t:
return ((charNode*)this )->length ();
case pcharNode_t:
return ((pcharNode*)this )->length ();
case pDNameNode_t:
return ((pDNameNode*)this )->length ();
case DNameStatusNode_t:
return ((DNameStatusNode*)this )->length ();
} // End of SWITCH
return 0;
}
char DNameNode::getLastChar () const
{ // Pure function, should not be called
switch ( typeIndex )
{
case charNode_t:
return ((charNode*)this )->getLastChar ();
case pcharNode_t:
return ((pcharNode*)this )->getLastChar ();
case pDNameNode_t:
return ((pDNameNode*)this )->getLastChar ();
case DNameStatusNode_t:
return ((DNameStatusNode*)this )->getLastChar ();
} // End of SWITCH
return 0;
}
pchar_t DNameNode::getString ( pchar_t s, int l ) const
{ // Pure function, should not be called
switch ( typeIndex )
{
case charNode_t:
return ((charNode*)this )->getString ( s, l );
case pcharNode_t:
return ((pcharNode*)this )->getString ( s, l );
case pDNameNode_t:
return ((pDNameNode*)this )->getString ( s, l );
case DNameStatusNode_t:
return ((DNameStatusNode*)this )->getString ( s, l );
} // End of SWITCH
return 0;
}
#endif // NO_VIRTUAL
DNameNode & DNameNode::operator += ( DNameNode * pNode )
{
if ( pNode )
{
if ( next )
{
// Skip to the end of the chain
DNameNode* pScan;
for ( pScan = next; pScan->next; pScan = pScan->next )
;
// And append the new node
pScan->next = pNode;
} // End of IF then
else
next = pNode;
} // End of IF
// And return self
return *this;
} // End of "DNameNode" OPERATOR '+=(DNameNode*)'
// The 'charNode' virtual functions
charNode::charNode ( char ch )
#if ( NO_VIRTUAL )
: DNameNode ( charNode_t )
#endif // NO_VIRTUAL
{ me = ch; }
inline int charNode::length () const { return 1; }
inline char charNode::getLastChar () const { return me; }
pchar_t charNode::getString ( pchar_t buf, int len ) const
{
if ( buf && len )
*buf = me;
else
buf = 0;
// Now return the character
return buf;
} // End of "charNode" FUNCTION "getString(pchar_t,int)"
// 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 )
#if ( NO_VIRTUAL )
: DNameNode ( pcharNode_t )
#endif // NO_VIRTUAL
{
// Get length if not supplied
if ( !len && str )
len = und_strlen ( str );
// Allocate a new string buffer if valid state
if ( len && str )
{
me = gnew char[ len ];
myLen = len;
if ( me )
und_strncpy ( me, str, len );
} // End of IF then
else
{
me = 0;
myLen = 0;
} // End of IF else
} // End of "pcharNode" CONSTRUCTOR '(pcchar_t,int)'
pchar_t pcharNode::getString ( pchar_t buf, int len ) const
{
// Use the shorter of the two lengths (may not be NULL terminated)
if ( len > pcharNode::length ())
len = pcharNode::length ();
// Do the copy as appropriate
return (( me && buf && len ) ? und_strncpy ( buf, me, len ) : 0 );
} // End of "pcharNode" FUNCTION "getString(pchar_t,int)"
// The 'pDNameNode' virtual functions
pDNameNode::pDNameNode ( DName * pName )
#if ( NO_VIRTUAL )
: DNameNode ( pDNameNode_t )
#endif // NO_VIRTUAL
{ me = (( pName && (( pName->status () == DN_invalid ) || ( pName->status () == DN_error ))) ? 0 : pName ); }
inline int pDNameNode::length () const { return ( me ? me->length () : 0 ); }
inline char pDNameNode::getLastChar () const { return ( me ? me->getLastChar () : '\0' ); }
pchar_t pDNameNode::getString ( pchar_t buf, int len ) const
{ return (( me && buf && len ) ? me->getString ( buf, len ) : 0 ); }
// The 'DNameStatusNode' virtual functions
DNameStatusNode::DNameStatusNode ( DNameStatus stat )
#if ( NO_VIRTUAL )
: DNameNode ( DNameStatusNode_t )
#endif // NO_VIRTUAL
{ me = stat; myLen = (( me == DN_truncated ) ? TruncationMessageLength : 0 ); }
inline int DNameStatusNode::length () const { return myLen; }
inline char DNameStatusNode::getLastChar () const
{ return (( me == DN_truncated ) ? TruncationMessage[ TruncationMessageLength - 1 ] : '\0' ); }
pchar_t DNameStatusNode::getString ( pchar_t buf, int len ) const
{
// Use the shorter of the two lengths (may not be NULL terminated)
if ( len > DNameStatusNode::length ())
len = DNameStatusNode::length ();
// Do the copy as appropriate
return ((( me == DN_truncated ) && buf && len ) ? und_strncpy ( buf, TruncationMessage, len ) : 0 );
} // End of "DNameStatusNode" FUNCTION "getString(pchar_t,int)"
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 pchar_t und_strncpy ( pchar_t dst, pcchar_t src, unsigned int len )
{
for ( char * d = dst; ( len && ( *d = *src )); d++, src++, len-- )
;
return dst;
} // End of FUNCTION "und_strncpy"
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 );
}