📄 string.c
字号:
/*
* Shlwapi string functions
*
* Copyright 1998 Juergen Schmied
* Copyright 2002 Jon Griffiths
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "windef.h"
#include "winbase.h"
#define NO_SHLWAPI_REG
#define NO_SHLWAPI_STREAM
#include "shlwapi.h"
#include "wingdi.h"
#include "winuser.h"
#include "shlobj.h"
#include "mlang.h"
#include "ddeml.h"
#include "wine/unicode.h"
#include "wine/debug.h"
#include "resource.h"
WINE_DEFAULT_DEBUG_CHANNEL(shell);
extern HINSTANCE shlwapi_hInstance;
static HRESULT _SHStrDupAA(LPCSTR,LPSTR*);
static HRESULT _SHStrDupAW(LPCWSTR,LPSTR*);
static void FillNumberFmt(NUMBERFMTW *fmt, LPWSTR decimal_buffer, int decimal_bufwlen,
LPWSTR thousand_buffer, int thousand_bufwlen)
{
WCHAR grouping[64];
WCHAR *c;
GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_ILZERO|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->LeadingZero)/sizeof(WCHAR));
GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_INEGNUMBER|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->NegativeOrder)/sizeof(WCHAR));
fmt->NumDigits = 0;
GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimal_buffer, decimal_bufwlen);
GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thousand_buffer, thousand_bufwlen);
fmt->lpThousandSep = thousand_buffer;
fmt->lpDecimalSep = decimal_buffer;
/*
* Converting grouping string to number as described on
* http://blogs.msdn.com/oldnewthing/archive/2006/04/18/578251.aspx
*/
fmt->Grouping = 0;
GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, grouping, sizeof(grouping)/sizeof(WCHAR));
for (c = grouping; *c; c++)
if (*c >= '0' && *c < '9')
{
fmt->Grouping *= 10;
fmt->Grouping += *c - '0';
}
if (fmt->Grouping % 10 == 0)
fmt->Grouping /= 10;
else
fmt->Grouping *= 10;
}
/*************************************************************************
* FormatInt [internal]
*
* Format an integer according to the current locale
*
* RETURNS
* The number of bytes written on success or 0 on failure
*/
static int FormatInt(LONGLONG qdwValue, LPWSTR pszBuf, int cchBuf)
{
NUMBERFMTW fmt;
WCHAR decimal[8], thousand[8];
WCHAR buf[24];
WCHAR *c;
BOOL neg = (qdwValue < 0);
FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR),
thousand, sizeof thousand / sizeof (WCHAR));
c = &buf[24];
*(--c) = 0;
do
{
*(--c) = '0' + (qdwValue%10);
qdwValue /= 10;
} while (qdwValue > 0);
if (neg)
*(--c) = '-';
return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, c, &fmt, pszBuf, cchBuf);
}
/*************************************************************************
* FormatDouble [internal]
*
* Format an integer according to the current locale. Prints the specified number of digits
* after the decimal point
*
* RETURNS
* The number of bytes written on success or 0 on failure
*/
static int FormatDouble(double value, int decimals, LPWSTR pszBuf, int cchBuf)
{
static const WCHAR flfmt[] = {'%','f',0};
WCHAR buf[64];
NUMBERFMTW fmt;
WCHAR decimal[8], thousand[8];
snprintfW(buf, 64, flfmt, value);
FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR),
thousand, sizeof thousand / sizeof (WCHAR));
fmt.NumDigits = decimals;
return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, buf, &fmt, pszBuf, cchBuf);
}
/*************************************************************************
* SHLWAPI_ChrCmpHelperA
*
* Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
*
* NOTES
* Both this function and its Unicode counterpart are very inefficient. To
* fix this, CompareString must be completely implemented and optimised
* first. Then the core character test can be taken out of that function and
* placed here, so that it need never be called at all. Until then, do not
* attempt to optimise this code unless you are willing to test that it
* still performs correctly.
*/
static BOOL SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
{
char str1[3], str2[3];
str1[0] = LOBYTE(ch1);
if (IsDBCSLeadByte(str1[0]))
{
str1[1] = HIBYTE(ch1);
str1[2] = '\0';
}
else
str1[1] = '\0';
str2[0] = LOBYTE(ch2);
if (IsDBCSLeadByte(str2[0]))
{
str2[1] = HIBYTE(ch2);
str2[2] = '\0';
}
else
str2[1] = '\0';
return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
}
/*************************************************************************
* SHLWAPI_ChrCmpA
*
* Internal helper function.
*/
static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
{
return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
}
/*************************************************************************
* ChrCmpIA (SHLWAPI.385)
*
* Compare two characters, ignoring case.
*
* PARAMS
* ch1 [I] First character to compare
* ch2 [I] Second character to compare
*
* RETURNS
* FALSE, if the characters are equal.
* Non-zero otherwise.
*/
BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
{
TRACE("(%d,%d)\n", ch1, ch2);
return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
}
/*************************************************************************
* ChrCmpIW [SHLWAPI.386]
*
* See ChrCmpIA.
*/
BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
{
return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, &ch1, 1, &ch2, 1) - 2;
}
/*************************************************************************
* StrChrA [SHLWAPI.@]
*
* Find a given character in a string.
*
* PARAMS
* lpszStr [I] String to search in.
* ch [I] Character to search for.
*
* RETURNS
* Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
* not found.
* Failure: NULL, if any arguments are invalid.
*/
LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
{
TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
if (lpszStr)
{
while (*lpszStr)
{
if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
return (LPSTR)lpszStr;
lpszStr = CharNextA(lpszStr);
}
}
return NULL;
}
/*************************************************************************
* StrChrW [SHLWAPI.@]
*
* See StrChrA.
*/
LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
{
LPWSTR lpszRet = NULL;
TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
if (lpszStr)
lpszRet = strchrW(lpszStr, ch);
return lpszRet;
}
/*************************************************************************
* StrChrIA [SHLWAPI.@]
*
* Find a given character in a string, ignoring case.
*
* PARAMS
* lpszStr [I] String to search in.
* ch [I] Character to search for.
*
* RETURNS
* Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
* not found.
* Failure: NULL, if any arguments are invalid.
*/
LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
{
TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
if (lpszStr)
{
while (*lpszStr)
{
if (!ChrCmpIA(*lpszStr, ch))
return (LPSTR)lpszStr;
lpszStr = CharNextA(lpszStr);
}
}
return NULL;
}
/*************************************************************************
* StrChrIW [SHLWAPI.@]
*
* See StrChrA.
*/
LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
{
TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
if (lpszStr)
{
ch = toupperW(ch);
while (*lpszStr)
{
if (toupperW(*lpszStr) == ch)
return (LPWSTR)lpszStr;
lpszStr++;
}
lpszStr = NULL;
}
return (LPWSTR)lpszStr;
}
/*************************************************************************
* StrCmpIW [SHLWAPI.@]
*
* Compare two strings, ignoring case.
*
* PARAMS
* lpszStr [I] First string to compare
* lpszComp [I] Second string to compare
*
* RETURNS
* An integer less than, equal to or greater than 0, indicating that
* lpszStr is less than, the same, or greater than lpszComp.
*/
int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
{
int iRet;
TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, -1, lpszComp, -1);
return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
}
/*************************************************************************
* StrCmpNA [SHLWAPI.@]
*
* Compare two strings, up to a maximum length.
*
* PARAMS
* lpszStr [I] First string to compare
* lpszComp [I] Second string to compare
* iLen [I] Maximum number of chars to compare.
*
* RETURNS
* An integer less than, equal to or greater than 0, indicating that
* lpszStr is less than, the same, or greater than lpszComp.
*/
INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
{
INT iRet;
TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
iRet = CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
}
/*************************************************************************
* StrCmpNW [SHLWAPI.@]
*
* See StrCmpNA.
*/
INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
{
INT iRet;
TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
}
/*************************************************************************
* StrCmpNIA [SHLWAPI.@]
*
* Compare two strings, up to a maximum length, ignoring case.
*
* PARAMS
* lpszStr [I] First string to compare
* lpszComp [I] Second string to compare
* iLen [I] Maximum number of chars to compare.
*
* RETURNS
* An integer less than, equal to or greater than 0, indicating that
* lpszStr is less than, the same, or greater than lpszComp.
*/
int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
{
INT iRet;
TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
iRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
}
/*************************************************************************
* StrCmpNIW [SHLWAPI.@]
*
* See StrCmpNIA.
*/
INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
{
INT iRet;
TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
}
/*************************************************************************
* StrCmpW [SHLWAPI.@]
*
* Compare two strings.
*
* PARAMS
* lpszStr [I] First string to compare
* lpszComp [I] Second string to compare
*
* RETURNS
* An integer less than, equal to or greater than 0, indicating that
* lpszStr is less than, the same, or greater than lpszComp.
*/
int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
{
INT iRet;
TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, -1, lpszComp, -1);
return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
}
/*************************************************************************
* StrCatW [SHLWAPI.@]
*
* Concatanate two strings.
*
* PARAMS
* lpszStr [O] Initial string
* lpszSrc [I] String to concatanate
*
* RETURNS
* lpszStr.
*/
LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
{
TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
strcatW(lpszStr, lpszSrc);
return lpszStr;
}
/*************************************************************************
* StrCpyW [SHLWAPI.@]
*
* Copy a string to another string.
*
* PARAMS
* lpszStr [O] Destination string
* lpszSrc [I] Source string
*
* RETURNS
* lpszStr.
*/
LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
{
TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
strcpyW(lpszStr, lpszSrc);
return lpszStr;
}
/*************************************************************************
* StrCpyNW [SHLWAPI.@]
*
* Copy a string to another string, up to a maximum number of characters.
*
* PARAMS
* lpszStr [O] Destination string
* lpszSrc [I] Source string
* iLen [I] Maximum number of chars to copy
*
* RETURNS
* lpszStr.
*/
LPWSTR WINAPI StrCpyNW(LPWSTR lpszStr, LPCWSTR lpszSrc, int iLen)
{
TRACE("(%p,%s,%i)\n", lpszStr, debugstr_w(lpszSrc), iLen);
lstrcpynW(lpszStr, lpszSrc, iLen);
return lpszStr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -