/*****************************************************************/ 
/**                  Microsoft Windows for Workgroups                **/
/**              Copyright (C) Microsoft Corp., 1991-1992            **/
/*****************************************************************/ 

/*
    npstring.h
    String classes: definition

    This file contains the basic string classes for the Thor UI.
    Its requirements are:

        - provide a modestly object-oriented interface to string
          manipulation, the better to work with the rest of our code;

        - encapsulate NLS and DBCS support as much as possible;

        - ensure that apps get correct form of library support,
          particularly with possible interference from intrinsics;

    The current solution consists of two classes: NLS_STR, and ISTR.

    class NLS_STR:      use wherever NLS/DBCS support is needed.
                      Most strings (in the UI, anyway) should be
                      of this class.

    class ISTR:      Indexes an NLS_STR in a DBCS safe manner.  All
                  positioning within an NLS_STR is done with ISTRs

    The class hierarchy looks like:

        BASE
            NLS_STR
                RESOURCE_STR
        ISTR

    This file also contains the STACK_NLS_STR macro and the
    strcpy( CHAR *, const NLS_STR& ) prototype.

    FILE HISTORY:
        beng        10/21/90        Created from email memo of last week
        johnl        11/13/90        Removed references to EB_STRING
        johnl        11/28/90        Release fully functional version
        johnl        12/07/90        Numerous revisions after code review
                                    (Removed SZ_STR, ISTR must associate
                                    w/a string upon decl etc.)
        beng        02/05/91        Replaced PCH with CHAR * for
                                    const-placement
        beng        04/26/91        Expunged of CB, IB types; relocated
                                    inline functions to string/strmisc.cxx
        beng        07/23/91        Added more *_STR types
        gregj        03/22/93        Ported to Chicago environment.
        gregj        03/25/93        Added Party(), DonePartying()
        gregj        03/30/93        Allow assigning NLS_STR to ISTR
        gregj        04/02/93        Added NLS_STR::IsDBCSLeadByte()
        gregj        04/02/93        Added ISTR::operator int
        gregj        04/08/93        Added NLS_STR::strncpy()
        gregj        04/08/93        Added NLS_STR::GetPrivateProfileString()
*/

#define WIN31    /* for certain string and NETLIB stuff */

#ifndef _BASE_HXX_
#include "base.h"
#endif

#ifndef _STRING_HXX_
#define _STRING_HXX_

extern HINSTANCE hInstance;        // for NLS_STR::LoadString

// String class doesn't allocate or deallocate memory
// for STR_OWNERALLOC strings
//
#define STR_OWNERALLOC         0x8000

// Same as owner alloc only the string is initialized with the null string.
//
#define STR_OWNERALLOC_CLEAR 0x8001

// Maximum resource string size, owner alloced strings must be at least
// MAX_RES_STR_LEN, otherwise an error will occur.
//
#define MAX_RES_STR_LEN    255


// The maximum number of insert parameters the InsertParams method can
// handle
//
#define MAX_INSERT_PARAMS    9


/*************************************************************************

    NAME:    ISTR

    SYNOPSIS:    String index object, used in conjunction with NLS_STR

    INTERFACE:
        ISTR()    - this ISTR gets associated with
                  the passed string and can only be used
                  on this string (NOTE:  on non-debug
                  versions this turns into a nop, can still
                  be useful for decl. clarity however).

        ISTR()    - Initialize to passed ISTR;
                  this ISTR will be associated with
                  the same string that the passed ISTR
                  is associated with.

        operator=()   - Copy passed ISTR (see prev.)

        operator=()   - Associate ISTR with a new NLS_STR.

        operator-()   - Returns CB diff. between *this & Param.
                        (must both belong to the same string)

        operator++()  - Advance the ISTR to the next logical
                        character (use only where absolutely
                        necessary).  Stops at end of string

        operator+=()  - Advance the ISTR to the ith logical
                        character (call operator++ i times)
                        Stops at end of string.

        operator==()  - Returns TRUE if the two ISTRs point to
                        the same position in the string (causes
                        an assertion failure if the two ISTRs
                        don't point to the same string).

        operator>()   - Returns true of *this is greater then
                        the passed ISTR (i.e., further along
                        in the string).

        operator<()   - Same as operator>, only less then.

        Reset()       - Resets ISTR to beginning of string and
                        updates the ISTR version number with the
                        string's current version number

    private:
        QueryIB()     - Returns the index in bytes
        QueryPNLS()   - Returns the pointer to the NLS_STR this ISTR
                        references
        SetPNLS()     - Sets the pointer to point to the NLS_STR
                        this ISTR references

    DEBUG ONLY:
        QueryVersion()     - Gets the version number of
                           the string this ISTR is associated with
        SetVersion()     - Sets the version number of this ISTR.

    USES:

    CAVEATS:    Each NLS_STR has a version number associated with it.  When
                an operation is performed that modifies the string, the
                version number is updated.  It is invalid to use an ISTR
                after its associated NLS_STR has been modified (can use
                Reset to resync it with the NLS_STR, the index gets reset
                to zero).

                You must associate an NLS_STR with an ISTR at the
                declaration of the ISTR.

    NOTES:        The version checking and string association checking goes
                away in the non-debug version.

    HISTORY:
        johnl        11/16/90        Created
        johnl        12/07/90        Modified after code review
        gregj        03/30/93        Allow assigning NLS_STR to ISTR

**************************************************************************/

class ISTR
{
friend class NLS_STR;

public:
    ISTR( const ISTR& istr );
    ISTR( const NLS_STR& nls );
    ISTR& operator=( const ISTR& istr );
    ISTR& operator=( const NLS_STR& nls );

    INT operator-( const ISTR& istr ) const;

    ISTR& operator++();
    VOID operator+=( INT iChars );

    BOOL operator==( const ISTR& istr ) const;
    BOOL operator>( const ISTR& istr )  const;
    BOOL operator<( const ISTR& istr )  const;

    operator INT() const { return QueryIB(); }

    VOID Reset();

private:
    INT _ibString;        // Index (in bytes) into an NLS_STR
    NLS_STR *_pnls;        // Pointer to "owner" NLS

    INT QueryIB() const
        { return _ibString; }
    VOID SetIB( INT ib )
        { _ibString = ib; }

    const NLS_STR* QueryPNLS() const
        { return _pnls; }
    VOID SetPNLS( const NLS_STR * pnls )
        { _pnls = (NLS_STR*)pnls; }

#ifdef DEBUG
    // Version number of NLS_STR this ISTR is associated with
    //
    USHORT _usVersion;

    USHORT QueryVersion() const { return _usVersion; }
    VOID SetVersion( USHORT usVers ) { _usVersion = usVers; }
#endif
};


/*************************************************************************

    NAME:        NLS_STR (nls)

    SYNOPSIS:    Provide a better string abstraction than the standard ASCIIZ
                representation offered by C (and C++).  The abstraction is
                better mainly because it handles double-byte characters
                (DBCS) in the string and makes intelligent use of operator
                overloading.

    INTERFACE:    NLS_STR()        Construct a NLS_STR (initialized to a CHAR *,
                                NLS_STR or NULL).  Reports errors via BASE.

                ~NLS_STR()        Destructor

                operator=()        Assign one NLS_STR (or CHAR *) value
                                to another (old string is deleted, new
                                string is allocated and copies source)

                operator+=()    Concatenate with assignment (equivalent to
                                strcat - see strcat).

                operator==()    Compare two NLS_STRs for equality

                operator!=()    Compare two NLS_STRs for inequality

                QueryPch()        Access operator, returning a "char *"
                                aliased to the string.  DO NOT MODIFY
                                THE STRING USING THIS METHOD (or pass
                                it to procedures that might modify it).
                                Synonym: operator const CHAR *().

                operator[]()    Same as QueryPch, except the string
                                is offset by ISTR characters

                IsDBCSLeadByte()    Returns whether a byte is a lead byte,
                                according to the ANSI- or OEM-ness of the
                                string.

        C-runtime-style methods.

                strlen()        Return the length of the string in bytes,
                                less terminator.  Provided only for crt
                                compatibility; please use a Query method
                                if possible.

                strcat()        Append an NLS_STR.  Will cause *this to be
                                reallocated if the appended string is larger
                                then this->QueryCb() and this is not an
                                STR_OWNERALLOC string

                strncpy()        Copy a non-null-terminated string into an
                                NLS_STR.  DBCS-safe.  For similar functionality
                                with an NLS_STR as the source, use the sub-
                                string members.

                strcmp()        Compare two NLS_STRs
                stricmp()        "
                strncmp()        Compare a portion of two NLS_STRs
                strnicmp()        "

                strcspn()        Find first char in *this that is
                                a char in arg
                strspn()        Find first char in *this that is
                                not a char in arg

                strtok()        Returns a token from the string

                strstr()        Search for a NLS_STR.

                strchr()        Search for a CHAR from beginning.
                                Returns offset.
                strrchr()        Search for a CHAR from end.
                strupr()        Convert NLS_STR to upper case.
                atoi()            Returns integer numeric value
                atol()            Returns long value

                realloc()        Resize string preserving its contents

        Other methods.

                QueryAllocSize()    Returns total # of bytes allocated (i.e.,
                                    number new was called with, or size of
                                    memory block if STR_OWNERALLOC
                IsOwnerAlloc()        Returns TRUE if this string is an owner
                                    allocated string
                QuerySubStr()        Return a substring
                InsertStr()            Insert a NLS_STR at given index.
                DelSubStr()            Delete a substring
                ReplSubStr()        Replace a substring (given start and
                                    NLS_STR)

                InsertParams()        Replace %1-%9 params in *this with the
                                    corresponding NLS_STRs contained in the
                                    array of pointers

                LoadString()        Load the string associated with the passed
                                    resource into *this (OWNER_ALLOC strings must
                                    be at least MAX_RES_STR_LEN).  Optionally
                                    calls InsertParams with a passed array of
                                    nls pointers.

                GetPrivateProfileString()    Loads a string from an INI file.

                Reset()                After an operation fails (due to memory
                                    failure), it is invalid to use the string
                                    until Reset has been called.  If the object
                                    wasn't successfully constructed, Reset will
                                    fail.

                QueryTextLength()    Returns the number of CHARS, less
                                    terminator.

                QueryTextSize()        Returns the number of bytes, including
                                    terminator.  Denotes amount of storage
                                    needed to dup string into a bytevector.

                QueryNumChar()        Returns total number of logical characters
                                    within the string.  Rarely needed.

                Append()            Appends a string to the current string,
                                    like strcat.
                AppendChar()        Appends a single character.

                Compare()            As strcmp().

                CopyFrom()            As operator=(), but returns an APIERR.

                ToOEM()                Convert string to OEM character set.

                ToAnsi()            Convert string to ANSI character set.

                Party()                Obtain read-write access to the buffer.
                DonePartying()        Release read-write access.

    PARENT:    BASE

    USES:    ISTR

    CAVEATS:    A NLS_STR object can enter an error state for various
                reasons - typically a memory allocation failure.  Using
                an object in such a state is theoretically an error.
                Since string operations frequently occur in groups,
                we define operations on an erroneous string as no-op,
                so that the check for an error may be postponed until
                the end of the complex operation.  Most member functions
                which calculate a value will treat an erroneous string
                as having zero length; however, clients should not depend
                on this.

                Attempting to use an ISTR that is registered with another
                string will cause an assertion failure.

                Each NLS_STR has a version/modification flag that is also
                stored in the the ISTR.  An attempt to use an ISTR on an
                NLS_STR that has been modified (by calling one of the methods
                listed below) will cause an assertion failure.    To use the
                ISTR after a modifying method, you must first call ISTR::Reset
                which will update the version in the ISTR.  See the
                method definition for more detail.

                List of modifying methods:
                    All NLS::operator= methods
                    NLS::DelSubStr
                    NLS::ReplSubStr
                    NLS::InsertSubStr

                NOTE: The ISTR used as a starting index on the
                Substring methods remains valid after the call.

                Party() and DonePartying() can be used when you need to
                do something that the standard NLS_STR methods don't
                cover.  For example, you might want to tweak the first
                couple of characters in a pathname;  if you know they're
                definitely not double-byte characters, this is safe to
                do with ordinary character assignments.
                
                Calling Party() returns a pointer to the string buffer,
                and places the NLS_STR in an error state to prevent the
                standard methods from operating on it (and thereby getting
                confused by the possibly incorrect cached length).  You
                can still call QueryAllocSize() to find out the maximum
                size of the buffer.  When you've finished, call DonePartying()
                to switch the NLS_STR back to "normal" mode.  There are two
                overloaded forms of DonePartying().  If you know what the
                length of the string is, you can pass it in, and NLS_STR
                will just use that.  Otherwise, it will use strlenf() to
                find out what the new length is.  If you don't plan to
                change the length, call strlen() on the string before you
                Party(), save that length, and pass it to DonePartying().
                The initial strlen() is fast because it's cached.

                If you find yourself constantly Party()ing in order to
                accomplish a particular function, that function should
                be formally added to the NLS_STR definition.

    NOTES:        The lack of a strlwr() method comes from a shortcoming
                in the casemap tables.    Sorry.

                STR_OWNERALLOC strings are a special type of NLS_STR
                You mark a string as STR_OWNERALLOC on
                construction by passing the flag STR_OWNERALLOC and a pointer
                to your memory space where you want the string to reside
                plus the size of the memory block.
                THE POINTER MUST POINT TO A VALID NULL TERMINATED STRING.
                You are guaranteed this pointer will never be
                resized or deleted.  Note that no checking is performed for
                writing beyond the end of the string.  Valid uses include
                static strings, severe optimization, owner controlled
                memory allocation or stack controlled memory allocation.

                CODEWORK: Owner-alloc strings should be a distinct
                class from these normal strings.

                CODEWORK: Should add a fReadOnly flag.

                CODEWORK: Should clean up this mess, and make the
                owner-alloc constructor protected.

                I wish I could clean up this mess...

    HISTORY:
        johnl        11/28/90        First fully functioning version
        johnl        12/07/90        Incorporated code review changes
        terryk        04/05/91        add QueryNumChar method
        beng        07/22/91        Added more methods; separated fOwnerAlloc
                                    from cbData
        gregj        05/22/92        Added ToOEM, ToAnsi methods
        gregj        03/22/93        Ported to Chicago environment
        gregj        04/02/93        Added IsDBCSLeadByte()
        gregj        04/08/93        Added strncpy()

**************************************************************************/

class NLS_STR : public BASE
{
friend class ISTR; // Allow access to CheckIstr

public:
    // Default constructor, creating an empty string.
    //
    NLS_STR();

    // Initialize to "cchInitLen" characters, each "chInit",
    // plus trailing NUL.
    //
    NLS_STR( INT cchInitLen );

    // Initialize from a NUL-terminated character vector.
    //
    NLS_STR( const CHAR *pchInit );

    // Initialize an NLS_STR to memory position passed in achInit
    // No memory allocation of any type will be performed on this string
    // cbSize should be the total memory size of the buffer, if cbSize == -1
    // then the size of the buffer will assumed to be strlen(achInit)+1
    //
    NLS_STR( unsigned stralloc, CHAR *pchInit, INT cbSize = -1 );

    // Initialize from an existing x_STRING.
    //
    NLS_STR( const NLS_STR& nlsInit );

    ~NLS_STR();

    // Number of bytes the string uses (not including terminator)
    // Cf. QueryTextLength and QueryTextSize.
    //
    inline INT strlen() const;

    // Return a read-only CHAR vector, for the APIs.
    //
    const CHAR *QueryPch() const
#ifdef DEBUG
        ;
#else
        { return _pchData; }
#endif

    const CHAR *QueryPch( const ISTR& istr ) const
#ifdef DEBUG
        ;
#else
        { return _pchData + istr.QueryIB(); }
#endif

    WCHAR QueryChar( const ISTR& istr ) const
#ifdef DEBUG
        ;
#else
        { return *(_pchData+istr.QueryIB()); }
#endif

    operator const CHAR *() const
        { return QueryPch(); }

    const CHAR *operator[]( const ISTR& istr ) const
        { return QueryPch(istr); }

    BOOL IsDBCSLeadByte( CHAR ch ) const;

    // Total allocated storage
    //
    inline INT QueryAllocSize() const;

    inline BOOL IsOwnerAlloc() const;

    // Increase the size of a string preserving its contents.
    // Returns TRUE if successful, false otherwise (illegal to
    // call for an owner alloced string).  If you ask for a string smaller
    // then the currently allocated one, the request will be ignored and TRUE
    // will be returned.
    //
    BOOL realloc( INT cbNew );

    // Returns TRUE if error was successfully cleared (string is now in valid
    // state), FALSE otherwise.
    //
    BOOL Reset();

    NLS_STR& operator=( const NLS_STR& nlsSource );
    NLS_STR& operator=( const CHAR *achSource );

    NLS_STR& operator+=( WCHAR wch );        // NEW, replaces AppendChar
    NLS_STR& operator+=( const NLS_STR& nls ) { return strcat(nls); }
    NLS_STR& operator+=( LPCSTR psz ) { return strcat(psz); }

    NLS_STR& strncpy( const CHAR *pchSource, UINT cbSource );

    NLS_STR& strcat( const NLS_STR& nls );
    NLS_STR& strcat( LPCSTR psz );

    BOOL operator== ( const NLS_STR& nls ) const;
    BOOL operator!= ( const NLS_STR& nls ) const;

    INT strcmp( const NLS_STR& nls ) const;
    INT strcmp( const NLS_STR& nls, const ISTR& istrThis ) const;
    INT strcmp( const NLS_STR& nls, const ISTR& istrThis,
                const ISTR& istrStart2 ) const;

    INT stricmp( const NLS_STR& nls ) const;
    INT stricmp( const NLS_STR& nls, const ISTR& istrThis ) const;
    INT stricmp( const NLS_STR& nls, const ISTR& istrThis,
                 const ISTR& istrStart2 ) const;

    INT strncmp( const NLS_STR& nls, const ISTR& istrLen ) const;
    INT strncmp( const NLS_STR& nls, const ISTR& istrLen,
                 const ISTR& istrThis ) const;
    INT strncmp( const NLS_STR& nls, const ISTR& istrLen,
                 const ISTR& istrThis, const ISTR& istrStart2 ) const;

    INT strnicmp( const NLS_STR& nls, const ISTR& istrLen ) const;
    INT strnicmp( const NLS_STR& nls, const ISTR& istrLen,
                  const ISTR& istrThis ) const;
    INT strnicmp( const NLS_STR& nls, const ISTR& istrLen,
                  const ISTR& istrThis, const ISTR& istrStart2 ) const;

    // The following str* functions return TRUE if successful (istrPos has
    // meaningful data), false otherwise.
    //
    BOOL strcspn( ISTR *istrPos, const NLS_STR& nls ) const;
    BOOL strcspn( ISTR *istrPos, const NLS_STR& nls, const ISTR& istrStart ) const;
    BOOL strspn( ISTR *istrPos, const NLS_STR& nls ) const;
    BOOL strspn( ISTR *istrPos, const NLS_STR& nls, const ISTR& istrStart ) const;

    BOOL strstr( ISTR *istrPos, const NLS_STR& nls ) const;
    BOOL strstr( ISTR *istrPos, const NLS_STR& nls, const ISTR& istrStart ) const;

    BOOL stristr( ISTR *istrPos, const NLS_STR& nls ) const;
    BOOL stristr( ISTR *istrPos, const NLS_STR& nls, const ISTR& istrStart ) const;

    BOOL strchr( ISTR *istrPos, const CHAR ch ) const;
    BOOL strchr( ISTR *istrPos, const CHAR ch, const ISTR& istrStart ) const;

    BOOL strrchr( ISTR *istrPos, const CHAR ch ) const;
    BOOL strrchr( ISTR *istrPos, const CHAR ch, const ISTR& istrStart ) const;

    BOOL strtok( ISTR *istrPos, const NLS_STR& nlsBreak, BOOL fFirst = FALSE );

    LONG atol() const;
    LONG atol( const ISTR& istrStart ) const;

    INT atoi() const;
    INT atoi( const ISTR& istrStart ) const;

    NLS_STR& strupr();

    // Return a pointer to a new NLS_STR that contains the contents
    // of *this from istrStart to:
    //        End of string if no istrEnd is passed
    //        istrStart + istrEnd
    //
    NLS_STR *QuerySubStr( const ISTR& istrStart ) const;
    NLS_STR *QuerySubStr( const ISTR& istrStart, const ISTR& istrEnd ) const;

    // Collapse the string by removing the characters from istrStart to:
    //        End of string
    //        istrStart + istrEnd
    // The string is not reallocated
    //
    VOID DelSubStr( ISTR& istrStart );
    VOID DelSubStr( ISTR& istrStart, const ISTR& istrEnd );

    BOOL InsertStr( const NLS_STR& nlsIns, ISTR& istrStart );

    // Replace till End of string of either *this or replacement string
    // (or istrEnd in the 2nd form) starting at istrStart
    //
    VOID ReplSubStr( const NLS_STR& nlsRepl, ISTR& istrStart );
    VOID ReplSubStr( const NLS_STR& nlsRepl, ISTR& istrStart,
                     const ISTR& istrEnd );

    // Replace %1-%9 in *this with corresponding index from apnlsParamStrings
    // Ex. if *this="Error %1" and apnlsParamStrings[0]="Foo" the resultant
    //       string would be "Error Foo"
    //
    USHORT InsertParams( const NLS_STR *apnlsParamStrings[] );

    // Load a message from a resource file into *this (if string is an
    // OWNER_ALLOC string, then must be at least MAX_RES_STR_LEN.  Heap
    // NLS_STRs will be reallocated if necessary
    //
    USHORT LoadString( USHORT usMsgID );

    // Combines functionality of InsertParams & LoadString.  *this gets loaded
    // with the string from the resource file corresponding to usMsgID.
    //
    USHORT LoadString( USHORT usMsgID, const NLS_STR *apnlsParamStrings[] );

    VOID GetPrivateProfileString( const CHAR *pszFile, const CHAR *pszSection,
                                  const CHAR *pszKey, const CHAR *pszDefault = NULL );

    VOID ToOEM();            // convert ANSI to OEM

    VOID ToAnsi();            // convert OEM to ANSI

    VOID SetOEM();            // declare that string was constructed as OEM
    VOID SetAnsi();            // declare that string was constructed as ANSI

    inline BOOL IsOEM() const;

    CHAR *Party();            // get read-write access
    VOID DonePartying( VOID );            // if you don't have the length handy
    VOID DonePartying( INT cchNew );    // if you do

#ifdef EXTENDED_STRINGS
    // Initialize from a NUL-terminated character vector
    // and allocate a minimum of: cbTotalLen+1 bytes or strlen(achInit)+1
    //
    NLS_STR( const CHAR *pchInit, INT iTotalLen );

    // Similar to prev. except the string pointed at by pchInit is copied
    // to pchBuff.  The address of pchBuff is used as the string storage.
    // cbSize is required.  stralloc can only be STR_OWNERALLOC (it makes
    // no sense to use STR_OWNERALLOC_CLEAR).
    //
    NLS_STR( unsigned stralloc, CHAR *pchBuff, INT cbSize,
             const CHAR *pchInit );

    // return the number of logical characters within the string
    //
    INT QueryNumChar() const;

    // Return the number of printing CHARs in the string.
    // This number does not include the termination character.
    //
    // Cf. QueryNumChar, which returns a count of glyphs.
    //
    INT QueryTextLength() const;

    // Return the number of BYTES occupied by the string's representation.
    // Cf. QueryAllocSize, which returns the total amount alloc'd.
    //
    INT QueryTextSize() const;

    APIERR Append( const NLS_STR& nls );

    APIERR AppendChar( WCHAR wch );

    APIERR CopyFrom( const NLS_STR& nlsSource );
    APIERR CopyFrom( const CHAR *achSource );

    INT Compare( const NLS_STR *nls ) const { return strcmp(*nls); }

#endif

private:
    UINT _fsFlags;        // owner-alloc, character set flags
#define SF_OWNERALLOC    0x1
#define SF_OEM            0x2

    INT _cchLen;        // Number of bytes string uses (strlen)
    INT _cbData;        // Total storage allocated
    CHAR *_pchData;        // Pointer to Storage

#ifdef DEBUG
    USHORT _usVersion;    // Version count (inc. after each change)
#endif

    // The following substring functions are used internally (can't be
    // exposed since they take an INT cbLen parameter for an index).
    //
    VOID DelSubStr( ISTR&istrStart, INT cbLen );

    NLS_STR *QuerySubStr( const ISTR& istrStart, INT cbLen ) const;

    VOID ReplSubStr( const NLS_STR& nlsRepl, ISTR& istrStart, INT cbLen );

    BOOL Alloc( INT cchLen );      // Allocate memory for a string

#ifdef DEBUG        // DEBUG is new for these
    // CheckIstr checks whether istr is associated with this, asserts out
    // if it is not.  Also checks version numbers in debug version.
    //
    VOID CheckIstr( const ISTR& istr ) const;

    // UpdateIstr syncs the version number between *this and the passed
    // ISTR.  This is for operations that cause an update to the string
    // but the ISTR that was passed in is still valid (see InsertSubSt).
    //
    VOID UpdateIstr( ISTR *pistr ) const;

    // IncVers adds one to this strings version number because the previous
    // operation caused the contents to change thus possibly rendering
    // ISTRs on this string as invalid.
    //
    VOID IncVers();

    // InitializeVers sets the version number to 0
    //
    VOID InitializeVers();

    // QueryVersion returns the current version number of this string
    //
    USHORT QueryVersion() const;
#else    // DEBUG
    VOID CheckIstr( const ISTR& istr ) const { }
    VOID UpdateIstr( ISTR *pistr ) const { }
    VOID IncVers() { }
    VOID InitializeVers() { }
    USHORT QueryVersion() const { return 0; }
#endif
};


/***********************************************************************/

/***********************************************************************
 *
 *  Macro STACK_NLS_STR(name, len )
 *
 *    Define an NLS string on the stack with the name of "name" and the
 *    length of "len".    The strlen will be 0 and the first character will
 *    be '\0'.    One byte is added for the NULL terminator.  Usage:
 *        STACK_NLS_STR( UncPath, UNCLEN );
 *
 *  Macro ISTACK_NLS_STR(name, len, pchInitString )
 *
 *    Same as STACK_NLS_STR except ISTACK_NLS_STR takes an initializer.
 **********************************************************************/

#define STACK_NLS_STR( name, len )                \
    CHAR _tmp##name[ len+1 ] ;                    \
    *_tmp##name = '\0' ;                    \
    NLS_STR name( STR_OWNERALLOC, _tmp##name, len+1 );

#define ISTACK_NLS_STR( name, len, pchInitString )        \
    STACK_NLS_STR( name, len ) ;                \
    name = pchInitString;

/***********************************************************************/

BOOL NLS_STR::IsOwnerAlloc() const
{
    return _fsFlags & SF_OWNERALLOC;
}

BOOL NLS_STR::IsOEM() const
{
    return _fsFlags & SF_OEM;
}

INT NLS_STR::strlen() const
{
    return _cchLen;
}

INT NLS_STR::QueryAllocSize()  const
{
    return _cbData;
}

#endif // _STRING_HXX_