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

/*
	strassgn.cxx
	NLS/DBCS-aware string class: assignment operator

	This file contains the implementation of the assignment operator
	for the STRING class.  It is separate so that clients of STRING which
	do not use this operator need not link to it.

	FILE HISTORY:
		beng	01/18/91	Separated from original monolithic .cxx
		beng	02/07/91	Uses lmui.hxx
		beng	07/26/91	Replaced min with local inline
		gregj	04/02/93	Do buffer overflow checks for OWNERALLOC strings
							instead of asserting
*/

#include "npcommon.h"

extern "C"
{
	#include <netlib.h>
}

#if defined(DEBUG)
static const CHAR szFileName[] = __FILE__;
#define _FILENAME_DEFINED_ONCE szFileName
#endif
#include <npassert.h>

#include <npstring.h>


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

	NAME:		NLS_STR::operator=

	SYNOPSIS:	Assignment operator

	ENTRY:		Either NLS_STR or CHAR*.

	EXIT:		If successful, contents of string overwritten.
				If failed, the original contents of the string remain.

	RETURNS:	Reference to self.

	HISTORY:
		beng	10/23/90	Created
		johnl	11/13/90	Added UIASSERTion checks for using bad
							strings
		beng	02/05/91	Uses CHAR * instead of PCH
		Johnl	03/06/91	Removed assertion check for *this
							being valid
		johnl	04/12/91	Resets error variable on PCH assignment
							if successful.
		beng	07/22/91	Allow assignment of an erroneous string;
							reset error on nls assignment as well
		gregj	04/02/93	Do buffer overflow checks for OWNERALLOC strings
							instead of asserting

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

NLS_STR& NLS_STR::operator=( const NLS_STR& nlsSource )
{
	if ( this == &nlsSource )
		return *this;

	if (!nlsSource)
	{
		// Assignment of an erroneous string
		//
		ReportError((unsigned short)nlsSource.QueryError());
		return *this;
	}

	INT cbToCopy = nlsSource.strlen();

	if ( !IsOwnerAlloc() )
	{
		if ( QueryAllocSize() < nlsSource.strlen()+1 )
		{
			/* Don't use Realloc because we want to retain the contents
			 * of the string if we fail to get the memory.
			 */
			CHAR * pchNew = new CHAR[nlsSource.strlen()+1];

			if ( pchNew == NULL )
			{
				ReportError( WN_OUT_OF_MEMORY );
				return *this;
			}

			delete _pchData;
			_pchData = pchNew;
			_cbData = nlsSource.strlen()+1;
		}

	}
	else
	{
        if (::fDBCSEnabled) {
    		if (QueryAllocSize() <= cbToCopy) {
    			cbToCopy = QueryAllocSize() - 1;	/* leave room for the null */
    			const CHAR *p = nlsSource.QueryPch();
    			while (p < nlsSource.QueryPch() + cbToCopy)
    				p += nlsSource.IsDBCSLeadByte(*p) ? 2 : 1;
    			if (p - nlsSource.QueryPch() != cbToCopy)	/* last char was DB */
    				cbToCopy--;								/* don't copy lead byte either */
    		}
        }
        else {
    		if (QueryAllocSize() <= cbToCopy)
	    		cbToCopy = QueryAllocSize() - 1;
        }
	}

	if (nlsSource.IsOEM())
		SetOEM();
	else
		SetAnsi();

	::memcpyf( _pchData, nlsSource.QueryPch(), cbToCopy );	/* copy string data */
	_pchData[cbToCopy] = '\0';		/* terminate the string */
	_cchLen = cbToCopy;
	IncVers();

	/* Reset the error state, since the string is now valid.
	 */
	ReportError( WN_SUCCESS );
	return *this;
}


NLS_STR& NLS_STR::operator=( const CHAR *pchSource )
{
	if ( pchSource == NULL )
	{
		if ( !IsOwnerAlloc() && !QueryAllocSize() )
		{
			if ( !Alloc(1) )
				ReportError( WN_OUT_OF_MEMORY );
			return *this;
		}

		UIASSERT( QueryAllocSize() > 0 );

		*_pchData = '\0';
		_cchLen = 0;
	}
	else
	{
		INT iSourceLen = ::strlenf( pchSource );
		INT cbToCopy;

		if ( !IsOwnerAlloc() )
		{
			if ( QueryAllocSize() < iSourceLen + 1 )
			{
				CHAR * pchNew = new CHAR[iSourceLen + 1];

				if ( pchNew == NULL )
				{
					ReportError( WN_OUT_OF_MEMORY );
					return *this;
				}

				delete _pchData;
				_pchData = pchNew;
				_cbData = iSourceLen + 1;
			}
			cbToCopy = iSourceLen;
		}
		else
		{
			if (QueryAllocSize() <= iSourceLen) {
                if (::fDBCSEnabled) {
    				cbToCopy = QueryAllocSize() - 1;	/* leave room for the null */
    				const CHAR *p = pchSource;
    				while (p < pchSource + cbToCopy)
    					p += IsDBCSLeadByte(*p) ? 2 : 1;
    				if (p - pchSource != cbToCopy)		/* last char was DB */
    					cbToCopy--;						/* don't copy lead byte either */
    			}
                else
	    			cbToCopy = QueryAllocSize() - 1;
            }
			else
				cbToCopy = iSourceLen;
		}

		::memcpyf( _pchData, pchSource, cbToCopy );
		_pchData[cbToCopy] = '\0';		/* terminate the string */
		_cchLen = cbToCopy;
	}

	IncVers();

	/* Reset the error state, since the string is now valid.
	 */
	ReportError( WN_SUCCESS );
	return *this;
}


#ifdef EXTENDED_STRINGS
/*******************************************************************

	NAME:		NLS_STR::CopyFrom()

	SYNOPSIS:	Assignment method which returns an error code

	ENTRY:
		nlsSource - source argument, either a nlsstr or char vector.
		achSource

	EXIT:
		Copied argument into this.  Error code of string set.

	RETURNS:
		Error code of string - WN_SUCCESS if successful.

	NOTES:
		If the CopyFrom fails, the current string will retain its
		original contents and error state.

	HISTORY:
		beng	09/18/91	Created
		beng	09/19/91	Added content-preserving behavior

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

APIERR NLS_STR::CopyFrom( const NLS_STR & nlsSource )
{
	if (!nlsSource)
		return nlsSource.QueryError();

	*this = nlsSource;

	APIERR err = QueryError();
	if (err)
		Reset();
	else {
		if (nlsSource.IsOEM())
			SetOEM();
		else
			SetAnsi();
	}
	return err;
}


APIERR NLS_STR::CopyFrom( const CHAR * achSource )
{
	*this = achSource;

	APIERR err = QueryError();
	if (err)
		Reset();
	return err;
}
#endif	// EXTENDED_STRINGS