/**********************************************************************/
/**                       Microsoft Windows NT                       **/
/**                Copyright(c) Microsoft Corp., 1991                **/
/**********************************************************************/

/*
    XtndStr.cxx

    OLDNAME: NCPASTRS.CXX:  
    String manipulation routines


    FILE HISTORY:
        DavidHov    10/31/92     Created

*/

#include "pch.hxx"  // Precompiled header
#pragma hdrstop

#define TCHX(a) ((TCHAR)TCH(a))

#define ChZero     TCHX('0')
#define ChLowX     TCHX('x')
#define ChUpX      TCHX('X')
#define ChSpace    TCHX(' ')
#define ChCr       TCHX('\r')
#define ChLf       TCHX('\n')

#define LIST_OPEN  TCHX('{')
#define LIST_CLOSE TCHX('}')
#define QUOTE      TCHX('\"')
#define SPACE      TCHX(' ')
#define COMMA      TCHX(',')

  /*
   *   UNICODE-safe version of "strchr()".
   */
const TCHAR * SafeStrChr ( const TCHAR * pchString, TCHAR chSought )
{
    const TCHAR * pchResult ;

    for ( pchResult = pchString ;
          *pchResult != chSought && *pchResult != 0 ;
          pchResult++ ) ;

    return *pchResult ? pchResult : NULL ;
}

  /*
   *   Convert hex string to binary.  Rather than use strupr(),
   *   the table contains two possibilities for each value, and the
   *   lower-order insertion allows for it by dividing by 2.
   */
DWORD CvtHex ( const TCHAR * pszDword )
{
    static const TCHAR * const pchHex = SZ("00112233445566778899AaBbCcDdEeFf") ;
    const TCHAR * pch ;

    DWORD dwResult = 0 ;

    //  Strip any "0x" prefix

    if ( pszDword[0] == ChZero )
       pszDword++ ;

    if ( pszDword[0] == ChLowX || pszDword[0] == ChUpX )
       pszDword++ ;

    for ( ; *pszDword && (pch = SafeStrChr( pchHex, *pszDword )) && *pch ;
          pszDword++ )
    {
        dwResult *= 16 ;
        dwResult += (pch - pchHex) / 2 ;
    }

    return dwResult ;
}

   /*
    *   Convert decimal string to binary
    */
DWORD CvtDec ( const TCHAR * pszDword )
{
    static const TCHAR * const pchHex = SZ("0123456789") ;
    const TCHAR * pch ;

    DWORD dwResult = 0 ;

    for ( ; *pszDword && (pch = SafeStrChr( pchHex, *pszDword )) && *pch ;
          pszDword++ )
    {
        dwResult *= 10 ;
        dwResult += pch - pchHex ;
    }

    return dwResult ;
}

   /*
    *   Convert decimal or hex to binary
    */
DWORD CvtDecOrHex ( const TCHAR * pszDword )
{
    if (   pszDword[0] == ChZero
        && (pszDword[1] == ChUpX) || (pszDword[1] == ChLowX) )
    {
        return CvtHex( pszDword ) ;
    }
    else
    {
        return CvtDec( pszDword ) ;
    }
}

    //  Return the active length of a buffer of
    //    UNICODE NUL-terminated strings.

LONG ParamBufferSize ( const TCHAR * pszBuff )
{
    LONG cch = 0 ;

    for ( ; *pszBuff ; )
    {
        LONG cchStr = ::strlenf( pszBuff ) + 1 ;
        pszBuff += cchStr ;
        cch += cchStr ;
    }

    return cch + 1 ;
}


  /*
   *   Convert the decimal value given into a character numeric
   *   version at the output  return a pointer to the NUL at the
   *   end of the output string.
   */
TCHAR * IntToStr ( LONG lDec, TCHAR * pszOutput, INT iBase )
{
    TCHAR tchBuffer [20] ;
    TCHAR * psz ;
    static const TCHAR * const pchHex = SZ("0123456789ABCDEF") ;

    psz = tchBuffer ;

    //  Convert to proper base in the temp buffer.

    do {  *psz++  = pchHex[ lDec % iBase ] ;
    } while ( lDec /= iBase ) ;

    //  Write it out in the proper order.

    if ( iBase == 16 )
    {
       *pszOutput++ = ChZero ;
       *pszOutput++ = ChLowX ;
    }

    while ( --psz >= tchBuffer )
    {
        *pszOutput++ = *psz ;
    }

    *pszOutput = 0  ;

    return pszOutput ;
}



  /*
   *   Convert array of CHAR pointers to WCHAR pointers.
   *   If UNICDOE, allocate, convert, etc.; if ! UNICODE,
   *   just return input pointer.
   */
TCHAR * * CvtArgs ( const LPSTR * apszArgs, DWORD nArgs )
{
#ifdef UNICODE
     WCHAR * * ppwszResult = new WCHAR * [nArgs+1] ;
     if ( ppwszResult == NULL )
        return NULL ;
     if ( ::MxAllocUnicodeVector( (LPSTR *) apszArgs, ppwszResult, nArgs ) == 0 )
     {
         ppwszResult[nArgs] = NULL ;
         return ppwszResult ;
     }
     delete ppwszResult ;
     return NULL ;
#else
     UNREFERENCED( nArgs ) ;
     return apszArgs ;  // Deliberately uncasted for error checking
#endif
}

  /*
   *   Destroy array of WCHAR arguments.  If ! UNICODE,
   *   do nothing.
   */
void FreeArgs ( TCHAR * * patchArgs, DWORD nArgs )
{
#ifdef UNICODE
    ::MxFreeUnicodeVector( patchArgs, nArgs ) ;
    delete patchArgs ;
#endif
}

 //
 //  Convert a SETUP-style character string handle to the real
 //  thing.
 //
const TCHAR pszHandlePrefix = TCH('|') ;
const TCHAR pszDoubleQuote  = TCH('\"') ;

PVOID CvtSetupHandle ( const TCHAR * pchSetupHandle )
{
    if ( *pchSetupHandle != pszHandlePrefix )
        return NULL ;

    return (PVOID) CvtDec( pchSetupHandle + 1 ) ;
}

HKEY CvtRegHandle ( const TCHAR * pchSetupHandle )
{
    return (HKEY) CvtSetupHandle( pchSetupHandle ) ;
}

    //  Generate a SETUP-style generic handle at the given location.
    //  Return a pointer to it.
TCHAR * CreateSetupHandle ( PVOID pv, TCHAR * pszBuffer )
{
    TCHAR * psz = pszBuffer ;

    *psz++ = pszDoubleQuote ;
    *psz++ = pszHandlePrefix ;
    psz = IntToStr( (INT) pv, psz, 10 ) ;
    *psz++ = pszDoubleQuote ;
    *psz++ = 0 ;

    return pszBuffer ;
}


   /*
    *    Convert a SETUP INF list into a packed string of strings,
    *      delimited by a double-zero.  For example:
    *
    *         { "string first",  "string second" }
    *
    *      becomes:
    *
    *         string first\0string second\0\0
    *
    *
    *    NOTE:  This function is limited to a flat list; unpredictable
    *           results will occur if the input list is nested.
    *
    */
TCHAR * CvtList (
     const TCHAR * pszList,
     TCHAR * pszBuffer,
     DWORD cchBuffSize )
{
    const TCHAR * pszNext = pszList ;
    TCHAR * pszOut = pszBuffer ;
    TCHAR * pszEnd = pszBuffer + cchBuffSize - 1 ;

    for ( ; *pszNext && *pszNext != LIST_OPEN ; pszNext++ ) ;

    do
    {
        for ( ;    *pszNext
                && (   *pszNext == SPACE
                    || *pszNext == COMMA
                    || *pszNext == LIST_OPEN) ;
                pszNext++ ) ;

        if (    *pszNext == 0
             || *pszNext == LIST_CLOSE
             || *pszNext != QUOTE )
            break ;

        for ( ; *(++pszNext) && *pszNext != QUOTE && pszOut < pszEnd ; )
        {
            *pszOut++ = *pszNext ;
        }

        *pszOut++ = 0 ;
        if ( *pszNext == 0 || pszOut >= pszEnd )
             break ;

        pszNext++ ;  // Skip over the final quote

    } while ( *pszNext ) ;

    *pszOut++ = 0 ;
    *pszOut = 0 ;

    return pszOut >= pszEnd
         ? NULL
         : pszBuffer ;
}



TEXT_BUFFER :: TEXT_BUFFER ( UINT uiInitSize, BOOL fUseCrLf )
    : NLS_STR( uiInitSize ),
      _fUseCrLf( fUseCrLf )
{
}

BOOL TEXT_BUFFER :: Cat ( int i )
{
    DEC_STR dsInt( i ) ;
    return Append( dsInt ) == 0 ;
}

BOOL TEXT_BUFFER :: Cat ( TCHAR bNext )
{
    TCHAR achBuff [2] ;
    achBuff[0] = bNext ;
    achBuff[1] = 0 ;
    return Append( achBuff ) == 0 ;
}

BOOL TEXT_BUFFER :: Cat ( const TCHAR * pbNext )
{
    return Append( pbNext ) == 0 ;
}

BOOL TEXT_BUFFER :: Eol ()
{
    if ( _fUseCrLf )
    {
       return Cat( ChCr ) && Cat( ChLf ) ;
    }
    else
    {
       return Cat( ChSpace ) ;
    }
}


//  End of NCPASTRS.CXX