WCH.CPP

//+----------------------------------------------------------------------- 
//
// Wide Character Routines
// Copyright (C) Microsoft Corporation, 1996, 1997
//
// File: wch.cpp
//
// Contents: Implementation of wide characters routines.
// These routines are being used to avoid dragging in
// the initialization chunk of the C run-time library
// that would be required by library routines such as
// wcsicmp() etc.
//
//------------------------------------------------------------------------

#include "stdafx.h"
#include "shlwapi.h" // Wrapper routines for non-Win95 calls

#pragma comment(lib, "shlwapi.lib")

//------------------------------------------------------------------------
//
// Function: wch_icmp()
//
// Synopsis: Perform a case-insensitive comparison of two strings.
//
// Arguments: pwch1 First string to compare
// pwch2 Second string to compare
// Treats NULLs as empty strings.
//
// Returns: 0 if the strings are lexically equal (allowing for
// case insensitivity)
// -1 if pwch1 lexically less than pwch2
// +1 if pwch1 lexically greater than pwch2
//
//------------------------------------------------------------------------

int wch_icmp(LPWCH pwch1, LPWCH pwch2)
{
USES_CONVERSION;

if (pwch1 == NULL)
pwch1 = L"";
if (pwch2 == NULL)
pwch2 = L"";

return StrCmpIW(pwch1, pwch2);
}

//------------------------------------------------------------------------
//
// Function: wch_incmp()
//
// Synopsis: Perform a case-insensitive comparison of two strings,
// up to a specified maximum number of characters.
//
// Arguments: pwch1 First string to compare
// pwch2 Second string to compare
// dwMaxLen Maximum number of characters to compare.
//
// Treats NULLs as empty strings.
//
// Returns: 0 if the strings are lexically equal (allowing for
// case insensitivity)
// -1 if pwch1 lexically less than pwch2
// +1 if pwch1 lexically greater than pwch2
//
//------------------------------------------------------------------------

int wch_incmp(LPWCH pwch1, LPWCH pwch2, DWORD dwMaxLen)
{

if (pwch1 == NULL)
pwch1 = L"";
if (pwch2 == NULL)
pwch2 = L"";

return StrCmpNIW(pwch1, pwch2, dwMaxLen);
}

//------------------------------------------------------------------------
//
// Function: wch_len()
//
// Synopsis: Calculate the length of a string.
// Treats NULL as an empty string.
//
// Arguments: pwch String to measure
//
// Returns: Length of given string.
//
//------------------------------------------------------------------------

int wch_len(LPWCH pwch)
{
LPWCH pwchOrig = pwch;

if (pwch == NULL)
return 0;
while (*pwch++ != 0)
;
return pwch - pwchOrig - 1;
}

//------------------------------------------------------------------------
//
// Function: wch_cmp()
//
// Synopsis: Perform a case-sensitive comparison of two strings.
// Treats NULLs as empty strings.
//
// Arguments: pwch1 First string to compare
// pwch2 Second string to compare
//
// Returns: 0 if the strings are lexically equal
// -1 if pwch1 lexically less than pwch2
// +1 if pwch1 lexically greater than pwch2
//
//------------------------------------------------------------------------

int wch_cmp(LPWCH pwch1, LPWCH pwch2)
{
if (pwch1 == NULL)
pwch1 = L"";
if (pwch2 == NULL)
pwch2 = L"";
for (; *pwch1 != 0 && *pwch1 == *pwch2; pwch1++, pwch2++)
;
return *pwch1 - *pwch2;
}

//------------------------------------------------------------------------
//
// Function: wch_ncmp()
//
// Synopsis: Perform a case-sensitive comparison of two strings,
// up to a specified maximum number of characters.
//
// Arguments: pwch1 First string to compare
// pwch2 Second string to compare
// dwMaxLen Maximum number of characters to compare.
//
// Treats NULLs as empty strings.
//
// Returns: 0 if the strings are lexically equal (allowing for
// case insensitivity)
// -1 if pwch1 lexically less than pwch2
// +1 if pwch1 lexically greater than pwch2
//
//------------------------------------------------------------------------

int wch_ncmp(LPWCH pwch1, LPWCH pwch2, DWORD dwMaxLen)
{
int cmp;

if (pwch1 == NULL)
pwch1 = L"";
if (pwch2 == NULL)
pwch2 = L"";

for (cmp = 0; cmp == 0 && dwMaxLen-- > 0; pwch1++, pwch2++)
if (*pwch1 == 0)
{
cmp = (*pwch2 == 0) ? 0 : -1;
break;
}
else
cmp = (*pwch2 == 0) ? 1 : (*pwch2 - *pwch1);

return cmp;
}

//------------------------------------------------------------------------
//
// Function: wch_cpy()
//
// Synopsis: Copy a wide-character null-terminated string.
// Treats NULL source as an empty string.
//
// Arguments: pwchDesc Destination buffer.
// pwchSrc Source string.
//
// Returns: Nothing.
//
//------------------------------------------------------------------------

void wch_cpy(LPWCH pwchDest, LPWCH pwchSrc)
{
if (pwchSrc == NULL)
*pwchDest = 0;
else
while ((*pwchDest++ = *pwchSrc++) != 0)
;
}

//------------------------------------------------------------------------
//
// Function: wch_chr()
//
// Synopsis: Searches for a character in a null-terminated wide-character
// string.
// Treats NULL pwch as an empty string.
//
// Arguments: pwch Search string.
// wch Character to search for.copy.
//
// Returns: Pointer to first occurrence of 'wch' in 'pwch' if found.
// NULL if 'wch' does not occur in 'pwch'.
//
//------------------------------------------------------------------------

LPWCH wch_chr(LPWCH pwch, WCHAR wch)
{
if (pwch != NULL)
for (; *pwch != 0; pwch++)
if (*pwch == wch)
return pwch;
return NULL;
}

//------------------------------------------------------------------------
//
// Function: wch_wildcardMatch()
//
// Synopsis: Determines whether the given text matches the given
// pattern, which interprets the character '*' as a match
// for 0-or-more characters.
// Treats NULL pwchText as an empty string.
// Treats NULL pwchPattern as an empty string.
//
// Arguments: pwchText Text to match.
// pwchPattern Pattern to match against.
// fCaseSensitive Flag to indicate whether match should be
// case sensitive.
//
// Returns: TRUE if the text matches the given pattern.
// FALSE otherwise.
//
//------------------------------------------------------------------------

// ;begin_internal
// compiler bug (VC5 with optimise?)
// ;end_internal
boolean wch_wildcardMatch(LPWCH pwchText, LPWCH pwchPattern,
boolean fCaseSensitive)
{
boolean fMatched;
LPWCH pwchStar;
DWORD dwPatternLen;

if (pwchText == NULL || pwchText[0] == 0)
{
// Empty/NULL text. This matches:
// - Empty/NULL patterns
// - Patterns consisting of a string of '*'s
//
// Equivalently, the text FAILS to match if there
// is at least one non-* character in the pattern.
//
fMatched = TRUE;
if (pwchPattern != NULL)
while (fMatched && *pwchPattern != 0)
fMatched = *pwchPattern++ == L'*';
goto Done;
}
if (pwchPattern == NULL || pwchPattern[0] == 0)
{
// NULL pattern can only match empty text.
// Since we've already dealt with the case of empty text above,
// the match must fail
//
fMatched = FALSE;
goto Done;
}

// Find the occurrence of the first '*' in the pattern ...
//
pwchStar = wch_chr(pwchPattern, L'*');

if (pwchStar == NULL)
{
// No '*'s in the pattern - compute an exact match
//
fMatched = fCaseSensitive
? wch_cmp(pwchText, pwchPattern) == 0
: wch_icmp(pwchText, pwchPattern) == 0;
goto Done;
}

int (*pfnBufCmp)(LPWCH pwch1, LPWCH pwch2, DWORD dwMaxCmp);

pfnBufCmp = fCaseSensitive ? wch_ncmp : wch_incmp;

// Ensure an exact match for characters preceding the first '*', if any
//
dwPatternLen = pwchStar - pwchPattern;
fMatched = (*pfnBufCmp)(pwchText, pwchPattern, dwPatternLen) == 0;
if (!fMatched)
goto Done;
pwchText += dwPatternLen;

for (;;)
{
DWORD dwTextLen = wch_len(pwchText);

// Skip over leading '*'s in the pattern
//
_ASSERT(*pwchStar == L'*');
while (*pwchStar == L'*')
pwchStar++;

pwchPattern = pwchStar;

// Find the next occurrence of a '*' in the pattern
//
if (*pwchPattern == 0)
{
// This must be have been a trailing '*' in the pattern.
// It automatically matches what remains of the text.
//
fMatched = TRUE;
goto Done;
}
pwchStar = wch_chr(pwchPattern, L'*');
if (pwchStar == NULL)
{
// No more '*'s - require an exact match of remaining
// pattern text with the end of the text.
//
dwPatternLen = wch_len(pwchPattern);
fMatched = (dwTextLen >= dwPatternLen) &&
(*pfnBufCmp)(pwchText + dwTextLen - dwPatternLen,
pwchPattern, dwPatternLen) == 0;
goto Done;
}

// Locate an exact match for the pattern-up-to-next-*
// within the text buffer
//
dwPatternLen = pwchStar - pwchPattern;
fMatched = FALSE;
while (dwTextLen >= dwPatternLen)
{
fMatched = (*pfnBufCmp)(pwchText, pwchPattern, dwPatternLen) == 0;
if (fMatched)
break;
dwTextLen--;
pwchText++;
}
if (!fMatched)
goto Done;
pwchText += dwPatternLen;
}

Done:
return fMatched;
}