2 * Shlwapi string functions
4 * Copyright 1998 Juergen Schmied
5 * Copyright 2002 Jon Griffiths
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "wine/port.h"
36 #define NO_SHLWAPI_STREAM
39 #include "wine/unicode.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(shell);
44 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest);
45 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest);
47 /*************************************************************************
48 * SHLWAPI_ChrCmpHelperA
50 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
53 * Both this function and its Unicode counterpart are very inneficient. To
54 * fix this, CompareString must be completely implemented and optimised
55 * first. Then the core character test can be taken out of that function and
56 * placed here, so that it need never be called at all. Until then, do not
57 * attempt to optimise this code unless you are willing to test that it
58 * still performs correctly.
60 static BOOL WINAPI SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
62 char str1[3], str2[3];
64 str1[0] = LOBYTE(ch1);
65 if (IsDBCSLeadByte(ch1))
67 str1[1] = HIBYTE(ch1);
73 str2[0] = LOBYTE(ch2);
74 if (IsDBCSLeadByte(ch2))
76 str2[1] = HIBYTE(ch2);
82 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
85 /*************************************************************************
86 * SHLWAPI_ChrCmpHelperW
88 * Internal helper for SHLWAPI_ChrCmpW/ChrCmpIW.
90 static BOOL WINAPI SHLWAPI_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags)
92 WCHAR str1[2], str2[2];
98 return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2;
101 /*************************************************************************
104 * Internal helper function.
106 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
108 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
111 /*************************************************************************
112 * ChrCmpIA [SHLWAPI.385]
114 * Compare two characters, ignoring case.
117 * ch1 [I] First character to compare
118 * ch2 [I] Second character to compare
121 * FALSE, if the characters are equal.
122 * Non-zero otherwise.
124 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
126 TRACE("(%d,%d)\n", ch1, ch2);
128 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
131 /*************************************************************************
134 * Internal helper function.
136 static BOOL WINAPI SHLWAPI_ChrCmpW(WCHAR ch1, WCHAR ch2)
138 return SHLWAPI_ChrCmpHelperW(ch1, ch2, 0);
141 /*************************************************************************
142 * ChrCmpIW [SHLWAPI.386]
146 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
148 return SHLWAPI_ChrCmpHelperW(ch1, ch2, NORM_IGNORECASE);
151 /*************************************************************************
152 * StrChrA [SHLWAPI.@]
154 * Find a given character in a string.
157 * lpszStr [I] String to search in.
158 * ch [I] Character to search for.
161 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
163 * Failure: NULL, if any arguments are invalid.
165 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
167 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
173 if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
174 return (LPSTR)lpszStr;
175 lpszStr = CharNextA(lpszStr);
181 /*************************************************************************
182 * StrChrW [SHLWAPI.@]
186 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
188 LPWSTR lpszRet = NULL;
190 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
193 lpszRet = strchrW(lpszStr, ch);
197 /*************************************************************************
198 * StrChrIA [SHLWAPI.@]
200 * Find a given character in a string, ignoring case.
203 * lpszStr [I] String to search in.
204 * ch [I] Character to search for.
207 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
209 * Failure: NULL, if any arguments are invalid.
211 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
213 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
219 if (!ChrCmpIA(*lpszStr, ch))
220 return (LPSTR)lpszStr;
221 lpszStr = CharNextA(lpszStr);
227 /*************************************************************************
228 * StrChrIW [SHLWAPI.@]
232 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
234 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
241 if (toupperW(*lpszStr) == ch)
242 return (LPWSTR)lpszStr;
243 lpszStr = CharNextW(lpszStr);
247 return (LPWSTR)lpszStr;
250 /*************************************************************************
251 * StrCmpIW [SHLWAPI.@]
253 * Compare two strings, ignoring case.
256 * lpszStr [I] First string to compare
257 * lpszComp [I] Second string to compare
260 * An integer less than, equal to or greater than 0, indicating that
261 * lpszStr is less than, the same, or greater than lpszComp.
263 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
267 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
269 iRet = strcmpiW(lpszStr, lpszComp);
270 return iRet < 0 ? -1 : iRet ? 1 : 0;
273 /*************************************************************************
274 * SHLWAPI_StrCmpNHelperA
276 * Internal helper for StrCmpNA/StrCmpNIA.
278 static INT WINAPI SHLWAPI_StrCmpNHelperA(LPCSTR lpszStr, LPCSTR lpszComp,
280 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
296 ch1 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
297 ch2 = IsDBCSLeadByte(*lpszComp)? *lpszComp << 8 | lpszComp[1] : *lpszComp;
299 if ((iDiff = pChrCmpFn(ch1, ch2)) < 0)
303 else if (!*lpszStr && !*lpszComp)
306 lpszStr = CharNextA(lpszStr);
307 lpszComp = CharNextA(lpszComp);
312 /*************************************************************************
313 * StrCmpNA [SHLWAPI.@]
315 * Compare two strings, up to a maximum length.
318 * lpszStr [I] First string to compare
319 * lpszComp [I] Second string to compare
320 * iLen [I] Maximum number of chars to compare.
323 * An integer less than, equal to or greater than 0, indicating that
324 * lpszStr is less than, the same, or greater than lpszComp.
326 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
328 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
330 return SHLWAPI_StrCmpNHelperA(lpszStr, lpszComp, iLen, SHLWAPI_ChrCmpA);
333 /*************************************************************************
334 * StrCmpNW [SHLWAPI.@]
338 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
342 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
344 iRet = strncmpW(lpszStr, lpszComp, iLen);
345 return iRet < 0 ? -1 : iRet ? 1 : 0;
348 /*************************************************************************
349 * StrCmpNIA [SHLWAPI.@]
351 * Compare two strings, up to a maximum length, ignoring case.
354 * lpszStr [I] First string to compare
355 * lpszComp [I] Second string to compare
356 * iLen [I] Maximum number of chars to compare.
359 * An integer less than, equal to or greater than 0, indicating that
360 * lpszStr is less than, the same, or greater than lpszComp.
363 * The Win32 version of this function is _completely_ broken for cases
364 * where iLen is greater than the length of lpszComp. Examples:
366 * StrCmpNIA("foo.gif", "foo", 5) is -1 under Win32; Should return 1.
367 * StrCmpNIA("\", "\\", 3) is 0 under Win32; Should return -1.
368 * StrCmpNIA("\", "\..\foo\", 3) is 1 under Win32; Should return -1.
370 * This implementation behaves correctly, since it is unlikely any
371 * applications actually rely on this function being broken.
373 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
375 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
377 return SHLWAPI_StrCmpNHelperA(lpszStr, lpszComp, iLen, ChrCmpIA);
380 /*************************************************************************
381 * StrCmpNIW [SHLWAPI.@]
385 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
389 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
391 iRet = strncmpiW(lpszStr, lpszComp, iLen);
392 return iRet < 0 ? -1 : iRet ? 1 : 0;
395 /*************************************************************************
396 * StrCmpW [SHLWAPI.@]
398 * Compare two strings.
401 * lpszStr [I] First string to compare
402 * lpszComp [I] Second string to compare
405 * An integer less than, equal to or greater than 0, indicating that
406 * lpszStr is less than, the same, or greater than lpszComp.
408 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
412 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
414 iRet = strcmpW(lpszStr, lpszComp);
415 return iRet < 0 ? -1 : iRet ? 1 : 0;
418 /*************************************************************************
419 * StrCatW [SHLWAPI.@]
421 * Concatanate two strings.
424 * lpszStr [O] Initial string
425 * lpszSrc [I] String to concatanate
430 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
432 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
434 strcatW(lpszStr, lpszSrc);
438 /*************************************************************************
439 * StrCpyW [SHLWAPI.@]
441 * Copy a string to another string.
444 * lpszStr [O] Destination string
445 * lpszSrc [I] Source string
450 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
452 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
454 strcpyW(lpszStr, lpszSrc);
458 /*************************************************************************
459 * StrCpyNW [SHLWAPI.@]
461 * Copy a string to another string, up to a maximum number of characters.
464 * lpszStr [O] Destination string
465 * lpszSrc [I] Source string
466 * iLen [I] Maximum number of chars to copy
471 LPWSTR WINAPI StrCpyNW(LPWSTR lpszStr, LPCWSTR lpszSrc, int iLen)
473 TRACE("(%p,%s,%i)\n", lpszStr, debugstr_w(lpszSrc), iLen);
475 lstrcpynW(lpszStr, lpszSrc, iLen);
481 /*************************************************************************
482 * SHLWAPI_StrStrHelperA
484 * Internal implementation of StrStrA/StrStrIA
486 static LPSTR WINAPI SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
487 int (*pStrCmpFn)(LPCSTR,LPCSTR,size_t))
491 if (!lpszStr || !lpszSearch || !*lpszSearch)
494 iLen = strlen(lpszSearch);
498 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
499 return (LPSTR)lpszStr;
500 lpszStr = CharNextA(lpszStr);
505 /*************************************************************************
506 * SHLWAPI_StrStrHelperW
508 * Internal implementation of StrStrW/StrStrIW
510 static LPWSTR WINAPI SHLWAPI_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch,
511 int (*pStrCmpFn)(LPCWSTR,LPCWSTR,int))
515 if (!lpszStr || !lpszSearch || !*lpszSearch)
518 iLen = strlenW(lpszSearch);
522 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
523 return (LPWSTR)lpszStr;
524 lpszStr = CharNextW(lpszStr);
529 /*************************************************************************
530 * StrStrA [SHLWAPI.@]
532 * Find a substring within a string.
535 * lpszStr [I] String to search in
536 * lpszSearch [I] String to look for
539 * The start of lpszSearch within lpszStr, or NULL if not found.
541 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
543 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
545 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncmp);
548 /*************************************************************************
549 * StrStrW [SHLWAPI.@]
553 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
555 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
557 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpW);
560 /*************************************************************************
561 * StrRStrIA [SHLWAPI.@]
563 * Find the last occurence of a substring within a string.
566 * lpszStr [I] String to search in
567 * lpszEnd [I] End of lpszStr
568 * lpszSearch [I] String to look for
571 * The last occurence lpszSearch within lpszStr, or NULL if not found.
573 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
575 LPSTR lpszRet = NULL;
579 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
581 if (!lpszStr || !lpszSearch || !*lpszSearch)
585 lpszEnd = lpszStr + lstrlenA(lpszStr);
587 if (IsDBCSLeadByte(*lpszSearch))
588 ch1 = *lpszSearch << 8 | lpszSearch[1];
591 iLen = lstrlenA(lpszSearch);
593 while (lpszStr <= lpszEnd && *lpszStr)
595 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
596 if (!ChrCmpIA(ch1, ch2))
598 if (!StrCmpNIA(lpszStr, lpszSearch, iLen))
599 lpszRet = (LPSTR)lpszStr;
601 lpszStr = CharNextA(lpszStr);
606 /*************************************************************************
607 * StrRStrIW [SHLWAPI.@]
611 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
613 LPWSTR lpszRet = NULL;
616 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
618 if (!lpszStr || !lpszSearch || !*lpszSearch)
622 lpszEnd = lpszStr + strlenW(lpszStr);
624 iLen = strlenW(lpszSearch);
626 while (lpszStr <= lpszEnd && *lpszStr)
628 if (!ChrCmpIA(*lpszSearch, *lpszStr))
630 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
631 lpszRet = (LPWSTR)lpszStr;
633 lpszStr = CharNextW(lpszStr);
638 /*************************************************************************
639 * StrStrIA [SHLWAPI.@]
641 * Find a substring within a string, ignoring case.
644 * lpszStr [I] String to search in
645 * lpszSearch [I] String to look for
648 * The start of lpszSearch within lpszStr, or NULL if not found.
650 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
652 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
654 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncasecmp);
657 /*************************************************************************
658 * StrStrIW [SHLWAPI.@]
662 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
664 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
666 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpiW);
669 /*************************************************************************
670 * StrToIntA [SHLWAPI.@]
672 * Read an integer from a string.
675 * lpszStr [I] String to read integer from
678 * The integer value represented by the string, or 0 if no integer is
682 * No leading space is allowed before the number, although a leading '-' is.
684 int WINAPI StrToIntA(LPCSTR lpszStr)
688 TRACE("(%s)\n", debugstr_a(lpszStr));
692 WARN("Invalid lpszStr would crash under Win32!\n");
696 if (*lpszStr == '-' || isdigit(*lpszStr))
697 StrToIntExA(lpszStr, 0, &iRet);
701 /*************************************************************************
702 * StrToIntW [SHLWAPI.@]
706 int WINAPI StrToIntW(LPCWSTR lpszStr)
710 TRACE("(%s)\n", debugstr_w(lpszStr));
714 WARN("Invalid lpszStr would crash under Win32!\n");
718 if (*lpszStr == '-' || isdigitW(*lpszStr))
719 StrToIntExW(lpszStr, 0, &iRet);
723 /*************************************************************************
724 * StrToIntExA [SHLWAPI.@]
726 * Read an integer from a string.
729 * lpszStr [I] String to read integer from
730 * dwFlags [I] Flags controlling the conversion
731 * lpiRet [O] Destination for read integer.
734 * Success: TRUE. lpiRet contains the integer value represented by the string.
735 * Failure: FALSE, if the string is invalid, or no number is present.
738 * Leading whitespace, '-' and '+' are allowed before the number. If
739 * dwFlags includes STIF_SUPPORT_HEX, hexidecimal numbers are allowed, if
740 * preceeded by '0x'. If this flag is not set, or there is no '0x' prefix,
741 * the string is treated as a decimal string. A leading '-' is ignored for
742 * hexidecimal numbers.
744 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
746 BOOL bNegative = FALSE;
749 TRACE("(%s,%08lX,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
751 if (!lpszStr || !lpiRet)
753 WARN("Invalid parameter would crash under Win32!\n");
756 if (dwFlags > STIF_SUPPORT_HEX)
758 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
761 /* Skip leading space, '+', '-' */
762 while (isspace(*lpszStr))
763 lpszStr = CharNextA(lpszStr);
770 else if (*lpszStr == '+')
773 if (dwFlags & STIF_SUPPORT_HEX &&
774 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
776 /* Read hex number */
779 if (!isxdigit(*lpszStr))
782 while (isxdigit(*lpszStr))
785 if (isdigit(*lpszStr))
786 iRet += (*lpszStr - '0');
788 iRet += 10 + (tolower(*lpszStr) - 'a');
795 /* Read decimal number */
796 if (!isdigit(*lpszStr))
799 while (isdigit(*lpszStr))
802 iRet += (*lpszStr - '0');
805 *lpiRet = bNegative ? -iRet : iRet;
809 /*************************************************************************
810 * StrToIntExW [SHLWAPI.@]
814 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
816 BOOL bNegative = FALSE;
819 TRACE("(%s,%08lX,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
821 if (!lpszStr || !lpiRet)
823 WARN("Invalid parameter would crash under Win32!\n");
826 if (dwFlags > STIF_SUPPORT_HEX)
828 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
831 /* Skip leading space, '+', '-' */
832 while (isspaceW(*lpszStr))
833 lpszStr = CharNextW(lpszStr);
840 else if (*lpszStr == '+')
843 if (dwFlags & STIF_SUPPORT_HEX &&
844 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
846 /* Read hex number */
849 if (!isxdigitW(*lpszStr))
852 while (isxdigitW(*lpszStr))
855 if (isdigitW(*lpszStr))
856 iRet += (*lpszStr - '0');
858 iRet += 10 + (tolowerW(*lpszStr) - 'a');
865 /* Read decimal number */
866 if (!isdigitW(*lpszStr))
869 while (isdigitW(*lpszStr))
872 iRet += (*lpszStr - '0');
875 *lpiRet = bNegative ? -iRet : iRet;
879 /*************************************************************************
880 * StrDupA [SHLWAPI.@]
882 * Duplicate a string.
885 * lpszStr [I] String to duplicate.
888 * Success: A pointer to a new string containing the contents of lpszStr
889 * Failure: NULL, if memory cannot be allocated
892 * The string memory is allocated with LocalAlloc, and so should be released
893 * by calling LocalFree.
895 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
900 TRACE("(%s)\n",debugstr_a(lpszStr));
902 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
903 lpszRet = (LPSTR)LocalAlloc(LMEM_FIXED, iLen);
908 memcpy(lpszRet, lpszStr, iLen);
915 /*************************************************************************
916 * StrDupW [SHLWAPI.@]
920 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
925 TRACE("(%s)\n",debugstr_w(lpszStr));
927 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
928 lpszRet = (LPWSTR)LocalAlloc(LMEM_FIXED, iLen);
933 memcpy(lpszRet, lpszStr, iLen);
940 /*************************************************************************
941 * SHLWAPI_StrSpnHelperA
943 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
945 static int WINAPI SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
946 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
949 LPCSTR lpszRead = lpszStr;
950 if (lpszStr && *lpszStr && lpszMatch)
954 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
956 if (!bInvert && !lpszTest)
958 if (bInvert && lpszTest)
960 lpszRead = CharNextA(lpszRead);
963 return lpszRead - lpszStr;
966 /*************************************************************************
967 * SHLWAPI_StrSpnHelperW
969 * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW
971 static int WINAPI SHLWAPI_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch,
972 LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR),
975 LPCWSTR lpszRead = lpszStr;
976 if (lpszStr && *lpszStr && lpszMatch)
980 LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
982 if (!bInvert && !lpszTest)
984 if (bInvert && lpszTest)
986 lpszRead = CharNextW(lpszRead);
989 return lpszRead - lpszStr;
992 /*************************************************************************
993 * StrSpnA [SHLWAPI.@]
995 * Find the length of the start of a string that contains only certain
999 * lpszStr [I] String to search
1000 * lpszMatch [I] Characters that can be in the substring
1003 * The length of the part of lpszStr containing only chars from lpszMatch,
1004 * or 0 if any parameter is invalid.
1006 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1008 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1010 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1013 /*************************************************************************
1014 * StrSpnW [SHLWAPI.@]
1018 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1020 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1022 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, FALSE);
1025 /*************************************************************************
1026 * StrCSpnA [SHLWAPI.@]
1028 * Find the length of the start of a string that does not contain certain
1032 * lpszStr [I] String to search
1033 * lpszMatch [I] Characters that cannot be in the substring
1036 * The length of the part of lpszStr containing only chars not in lpszMatch,
1037 * or 0 if any parameter is invalid.
1039 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1041 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1043 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1046 /*************************************************************************
1047 * StrCSpnW [SHLWAPI.@]
1051 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1053 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1055 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE);
1058 /*************************************************************************
1059 * StrCSpnIA [SHLWAPI.@]
1061 * Find the length of the start of a string that does not contain certain
1062 * characters, ignoring case.
1065 * lpszStr [I] String to search
1066 * lpszMatch [I] Characters that cannot be in the substring
1069 * The length of the part of lpszStr containing only chars not in lpszMatch,
1070 * or 0 if any parameter is invalid.
1072 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1074 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1076 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1079 /*************************************************************************
1080 * StrCSpnIW [SHLWAPI.@]
1084 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1086 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1088 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE);
1091 /*************************************************************************
1092 * StrPBrkA [SHLWAPI.@]
1094 * Search a string for any of a group of characters.
1097 * lpszStr [I] String to search
1098 * lpszMatch [I] Characters to match
1101 * A pointer to the first matching character in lpszStr, or NULL if no
1104 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1106 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1108 if (lpszStr && lpszMatch && *lpszMatch)
1112 if (StrChrA(lpszMatch, *lpszStr))
1113 return (LPSTR)lpszStr;
1114 lpszStr = CharNextA(lpszStr);
1120 /*************************************************************************
1121 * StrPBrkW [SHLWAPI.@]
1125 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1127 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1129 if (lpszStr && lpszMatch && *lpszMatch)
1133 if (StrChrW(lpszMatch, *lpszStr))
1134 return (LPWSTR)lpszStr;
1135 lpszStr = CharNextW(lpszStr);
1141 /*************************************************************************
1142 * SHLWAPI_StrRChrHelperA
1144 * Internal implementation of StrRChrA/StrRChrIA.
1146 static LPSTR WINAPI SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1147 LPCSTR lpszEnd, WORD ch,
1148 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1150 LPCSTR lpszRet = NULL;
1157 lpszEnd = lpszStr + lstrlenA(lpszStr);
1159 while (*lpszStr && lpszStr <= lpszEnd)
1161 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1163 if (!pChrCmpFn(ch, ch2))
1165 lpszStr = CharNextA(lpszStr);
1168 return (LPSTR)lpszRet;
1171 /*************************************************************************
1172 * SHLWAPI_StrRChrHelperW
1174 * Internal implementation of StrRChrW/StrRChrIW.
1176 static LPWSTR WINAPI SHLWAPI_StrRChrHelperW(LPCWSTR lpszStr,
1177 LPCWSTR lpszEnd, WCHAR ch,
1178 BOOL (WINAPI *pChrCmpFn)(WCHAR,WCHAR))
1180 LPCWSTR lpszRet = NULL;
1185 lpszEnd = lpszStr + strlenW(lpszStr);
1187 while (*lpszStr && lpszStr <= lpszEnd)
1189 if (!pChrCmpFn(ch, *lpszStr))
1191 lpszStr = CharNextW(lpszStr);
1194 return (LPWSTR)lpszRet;
1197 /**************************************************************************
1198 * StrRChrA [SHLWAPI.@]
1200 * Find the last occurence of a character in string.
1203 * lpszStr [I] String to search in
1204 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1205 * ch [I] Character to search for.
1208 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1209 * or NULL if not found.
1210 * Failure: NULL, if any arguments are invalid.
1212 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1214 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1216 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1219 /**************************************************************************
1220 * StrRChrW [SHLWAPI.@]
1224 LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1226 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1228 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpW);
1231 /**************************************************************************
1232 * StrRChrIA [SHLWAPI.@]
1234 * Find the last occurence of a character in string, ignoring case.
1237 * lpszStr [I] String to search in
1238 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1239 * ch [I] Character to search for.
1242 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1243 * or NULL if not found.
1244 * Failure: NULL, if any arguments are invalid.
1246 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1248 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1250 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1253 /**************************************************************************
1254 * StrRChrIW [SHLWAPI.@]
1258 LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1260 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1262 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, ChrCmpIW);
1265 /*************************************************************************
1266 * StrCatBuffA [SHLWAPI.@]
1268 * Concatenate two strings together.
1271 * lpszStr [O] String to concatenate to
1272 * lpszCat [I] String to add to lpszCat
1273 * cchMax [I] Maximum number of characters for the whole string
1279 * cchMax dtermines the number of characters in the final length of the
1280 * string, not the number appended to lpszStr from lpszCat.
1282 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1286 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1290 WARN("Invalid lpszStr would crash under Win32!\n");
1294 iLen = strlen(lpszStr);
1298 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1302 /*************************************************************************
1303 * StrCatBuffW [SHLWAPI.@]
1307 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1311 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1315 WARN("Invalid lpszStr would crash under Win32!\n");
1319 iLen = strlenW(lpszStr);
1323 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1327 /*************************************************************************
1328 * StrRetToBufA [SHLWAPI.@]
1330 * Convert a STRRET to a normal string.
1333 * lpStrRet [O] STRRET to convert
1334 * pIdl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSETA
1335 * lpszDest [O] Destination for normal string
1336 * dwLen [I] Length of lpszDest
1339 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1340 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1341 * CoTaskMemFree and its type set to STRRET_CSTRA.
1342 * Failure: E_FAIL, if any parameters are invalid.
1344 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, DWORD len)
1347 * This routine is identical to that in dlls/shell32/shellstring.c.
1348 * It was duplicated because not every version of Shlwapi.dll exports
1349 * StrRetToBufA. If you change one routine, change them both.
1351 TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest,len,src,pidl);
1355 WARN("Invalid lpStrRet would crash under Win32!\n");
1369 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1370 CoTaskMemFree(src->u.pOleStr);
1374 lstrcpynA((LPSTR)dest, src->u.cStr, len);
1378 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1382 FIXME("unknown type!\n");
1388 /*************************************************************************
1389 * StrRetToBufW [SHLWAPI.@]
1393 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, DWORD len)
1395 TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest,len,src,pidl);
1399 WARN("Invalid lpStrRet would crash under Win32!\n");
1413 lstrcpynW((LPWSTR)dest, src->u.pOleStr, len);
1414 CoTaskMemFree(src->u.pOleStr);
1418 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
1425 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1432 FIXME("unknown type!\n");
1438 /*************************************************************************
1439 * StrRetToStrA [SHLWAPI.@]
1441 * converts a STRRET to a normal string
1443 HRESULT WINAPI StrRetToStrA(LPSTRRET pstr, const ITEMIDLIST * pidl, LPSTR* ppszName)
1445 HRESULT ret = E_FAIL;
1447 switch (pstr->uType) {
1449 ret = _SHStrDupAW(pstr->u.pOleStr, ppszName);
1450 CoTaskMemFree(pstr->u.pOleStr);
1454 ret = _SHStrDupAA(pstr->u.cStr, ppszName);
1458 ret = _SHStrDupAA(((LPCSTR)&pidl->mkid)+pstr->u.uOffset, ppszName);
1467 /*************************************************************************
1468 * StrRetToStrW [SHLWAPI.@]
1470 * converts a STRRET to a normal string
1472 HRESULT WINAPI StrRetToStrW(LPSTRRET pstr, const ITEMIDLIST * pidl, LPWSTR* ppszName)
1474 HRESULT ret = E_FAIL;
1476 switch (pstr->uType) {
1478 ret = SHStrDupW(pstr->u.pOleStr, ppszName);
1479 CoTaskMemFree(pstr->u.pOleStr);
1483 ret = SHStrDupA(pstr->u.cStr, ppszName);
1487 ret = SHStrDupA(((LPCSTR)&pidl->mkid)+pstr->u.uOffset, ppszName);
1496 /*************************************************************************
1497 * StrFormatByteSizeA [SHLWAPI.@]
1499 LPSTR WINAPI StrFormatByteSizeA ( DWORD dw, LPSTR pszBuf, UINT cchBuf )
1501 TRACE("%lx %p %i\n", dw, pszBuf, cchBuf);
1503 { sprintf (buf,"%ld bytes", dw);
1505 else if ( dw<1048576L)
1506 { sprintf (buf,"%3.1f KB", (FLOAT)dw/1024);
1508 else if ( dw < 1073741824L)
1509 { sprintf (buf,"%3.1f MB", (FLOAT)dw/1048576L);
1512 { sprintf (buf,"%3.1f GB", (FLOAT)dw/1073741824L);
1514 lstrcpynA (pszBuf, buf, cchBuf);
1518 /*************************************************************************
1519 * StrFormatByteSizeW [SHLWAPI.@]
1521 LPWSTR WINAPI StrFormatByteSizeW ( DWORD dw, LPWSTR pszBuf, UINT cchBuf )
1524 StrFormatByteSizeA( dw, buf, sizeof(buf) );
1525 if (!MultiByteToWideChar( CP_ACP, 0, buf, -1, pszBuf, cchBuf ) && cchBuf)
1526 pszBuf[cchBuf-1] = 0;
1530 /*************************************************************************
1531 * StrFormatKBSizeA [SHLWAPI.@]
1533 * Create a formatted string containing a byte count in Kilobytes.
1536 * llBytes [I] Byte size to format
1537 * lpszDest [I] Destination for formatted string
1538 * cchMax [I] Size of lpszDest
1543 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1545 char szBuff[256], *szOut = szBuff + sizeof(szBuff) - 1;
1546 LONGLONG ulKB = (llBytes + 1023) >> 10;
1548 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
1557 LONGLONG ulNextDigit = ulKB % 10;
1558 *szOut-- = '0' + ulNextDigit;
1559 ulKB = (ulKB - ulNextDigit) / 10;
1562 strncpy(lpszDest, szOut + 1, cchMax);
1566 /*************************************************************************
1567 * StrFormatKBSizeW [SHLWAPI.@]
1569 * See StrFormatKBSizeA.
1571 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1573 WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff) - 1;
1574 LONGLONG ulKB = (llBytes + 1023) >> 10;
1576 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
1585 LONGLONG ulNextDigit = ulKB % 10;
1586 *szOut-- = '0' + ulNextDigit;
1587 ulKB = (ulKB - ulNextDigit) / 10;
1590 strncpyW(lpszDest, szOut + 1, cchMax);
1594 /*************************************************************************
1595 * StrNCatA [SHLWAPI.@]
1597 * Concatenate two strings together.
1600 * lpszStr [O] String to concatenate to
1601 * lpszCat [I] String to add to lpszCat
1602 * cchMax [I] Maximum number of characters to concatenate
1608 * cchMax dtermines the number of characters that are appended to lpszStr,
1609 * not the total length of the string.
1611 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1613 LPSTR lpszRet = lpszStr;
1615 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1619 WARN("Invalid lpszStr would crash under Win32!\n");
1623 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1627 /*************************************************************************
1628 * StrNCatW [SHLWAPI.@]
1632 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1634 LPWSTR lpszRet = lpszStr;
1636 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1640 WARN("Invalid lpszStr would crash under Win32\n");
1644 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1648 /*************************************************************************
1649 * StrTrimA [SHLWAPI.@]
1651 * Remove characters from the start and end of a string.
1654 * lpszStr [O] String to remove characters from
1655 * lpszTrim [I] Characters to remove from lpszStr
1658 * TRUE If lpszStr was valid and modified
1661 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1664 LPSTR lpszRead = lpszStr;
1667 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1669 if (lpszRead && *lpszRead)
1671 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1672 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1674 dwLen = strlen(lpszRead);
1676 if (lpszRead != lpszStr)
1678 memmove(lpszStr, lpszRead, dwLen + 1);
1683 lpszRead = lpszStr + dwLen;
1684 while (StrChrA(lpszTrim, lpszRead[-1]))
1685 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1687 if (lpszRead != lpszStr + dwLen)
1697 /*************************************************************************
1698 * StrTrimW [SHLWAPI.@]
1702 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1705 LPWSTR lpszRead = lpszStr;
1708 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1710 if (lpszRead && *lpszRead)
1712 while (*lpszRead && StrChrW(lpszTrim, *lpszRead))
1713 lpszRead = CharNextW(lpszRead); /* Skip leading matches */
1715 dwLen = strlenW(lpszRead);
1717 if (lpszRead != lpszStr)
1719 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1724 lpszRead = lpszStr + dwLen;
1725 while (StrChrW(lpszTrim, lpszRead[-1]))
1726 lpszRead = CharPrevW(lpszStr, lpszRead); /* Skip trailing matches */
1728 if (lpszRead != lpszStr + dwLen)
1738 /*************************************************************************
1739 * _SHStrDupA [INTERNAL]
1741 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1743 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest)
1749 len = lstrlenA(src);
1750 *dest = CoTaskMemAlloc(len);
1756 lstrcpynA(*dest,src, len);
1762 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1766 /*************************************************************************
1769 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc.
1772 * lpszStr [I] String to copy
1773 * lppszDest [O] Destination for the new string copy
1776 * Success: S_OK. lppszDest contains the new string in Unicode format.
1777 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1780 HRESULT WINAPI SHStrDupA(LPCSTR src, LPWSTR * dest)
1786 len = (MultiByteToWideChar(0,0,src,-1,0,0) + 1)* sizeof(WCHAR);
1787 *dest = CoTaskMemAlloc(len);
1793 MultiByteToWideChar(0,0,src,-1,*dest,len);
1799 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1803 /*************************************************************************
1804 * _SHStrDupAW [INTERNAL]
1806 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1808 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1814 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1815 *dest = CoTaskMemAlloc(len);
1821 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1827 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1831 /*************************************************************************
1836 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1842 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1843 *dest = CoTaskMemAlloc(len);
1849 memcpy(*dest, src, len);
1855 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1859 /*************************************************************************
1860 * SHLWAPI_WriteReverseNum
1862 * Internal helper for SHLWAPI_WriteTimeClass.
1864 inline static LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1868 /* Write a decimal number to a string, backwards */
1871 DWORD dwNextDigit = dwNum % 10;
1872 *lpszOut-- = '0' + dwNextDigit;
1873 dwNum = (dwNum - dwNextDigit) / 10;
1874 } while (dwNum > 0);
1879 /*************************************************************************
1880 * SHLWAPI_FormatSignificant
1882 * Internal helper for SHLWAPI_WriteTimeClass.
1884 inline static int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
1886 /* Zero non significant digits, return remaining significant digits */
1890 if (--dwDigits == 0)
1900 /*************************************************************************
1901 * SHLWAPI_WriteTimeClass
1903 * Internal helper for StrFromTimeIntervalW.
1905 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
1906 LPCWSTR lpszClass, int iDigits)
1908 WCHAR szBuff[64], *szOut = szBuff + 32;
1910 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
1911 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
1913 strcpyW(szBuff + 32, lpszClass);
1914 strcatW(lpszOut, szOut);
1918 /*************************************************************************
1919 * StrFromTimeIntervalA [SHLWAPI.@]
1921 * Format a millisecond time interval into a string
1924 * lpszStr [O] Output buffer for formatted time interval
1925 * cchMax [I] Size of lpszStr
1926 * dwMS [I] Number of milliseconds
1927 * iDigits [I] Number of digits to print
1930 * The length of the formatted string, or 0 if any parameter is invalid.
1933 * This implementation mimics the Win32 behaviour of always writing a leading
1934 * space before the time interval begins.
1935 * iDigits is used to provide approximate times if accuracy is not important.
1936 * This number of digits will be written of the first non-zero time class
1937 * (hours/minutes/seconds). If this does not complete the time classification,
1938 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
1939 * If there are digits remaining following the writing of a time class, the
1940 * next time class will be written.
1941 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
1942 * following will result from the given values of iDigits:
1944 * iDigits 1 2 3 4 5 ...
1945 * lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
1947 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
1952 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1954 if (lpszStr && cchMax)
1957 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
1958 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
1964 /*************************************************************************
1965 * StrFromTimeIntervalW [SHLWAPI.@]
1967 * See StrFromTimeIntervalA.
1969 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
1972 static const WCHAR szHr[] = {' ','h','r','\0'};
1973 static const WCHAR szMin[] = {' ','m','i','n','\0'};
1974 static const WCHAR szSec[] = {' ','s','e','c','\0'};
1977 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1979 if (lpszStr && cchMax)
1982 DWORD dwHours, dwMinutes;
1984 if (!iDigits || cchMax == 1)
1990 /* Calculate the time classes */
1991 dwMS = (dwMS + 500) / 1000;
1992 dwHours = dwMS / 3600;
1993 dwMS -= dwHours * 3600;
1994 dwMinutes = dwMS / 60;
1995 dwMS -= dwMinutes * 60;
2000 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, szHr, iDigits);
2002 if (dwMinutes && iDigits)
2003 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, szMin, iDigits);
2005 if (iDigits) /* Always write seconds if we have significant digits */
2006 SHLWAPI_WriteTimeClass(szCopy, dwMS, szSec, iDigits);
2008 strncpyW(lpszStr, szCopy, cchMax);
2009 iRet = strlenW(lpszStr);
2014 /*************************************************************************
2015 * StrIsIntlEqualA [SHLWAPI.@]
2017 * Compare two strings.
2020 * bCase [I] Whether to compare case sensitively
2021 * lpszStr [I] First string to compare
2022 * lpszComp [I] Second string to compare
2023 * iLen [I] Length to compare
2026 * TRUE If the strings are equal.
2029 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2032 DWORD dwFlags = LOCALE_USE_CP_ACP;
2035 TRACE("(%d,%s,%s,%d)\n", bCase,
2036 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2038 /* FIXME: These flags are undocumented and unknown by our CompareString.
2039 * We need defines for them.
2041 dwFlags |= bCase ? 0x10000000 : 0x10000001;
2043 iRet = CompareStringA(GetThreadLocale(),
2044 dwFlags, lpszStr, iLen, lpszComp, iLen);
2047 iRet = CompareStringA(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
2049 return iRet == 2 ? TRUE : FALSE;
2052 /*************************************************************************
2053 * StrIsIntlEqualW [SHLWAPI.@]
2055 * See StrIsIntlEqualA.
2057 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2063 TRACE("(%d,%s,%s,%d)\n", bCase,
2064 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2066 /* FIXME: These flags are undocumented and unknown by our CompareString.
2067 * We need defines for them.
2069 dwFlags = bCase ? 0x10000000 : 0x10000001;
2071 iRet = CompareStringW(GetThreadLocale(),
2072 dwFlags, lpszStr, iLen, lpszComp, iLen);
2075 iRet = CompareStringW(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
2077 return iRet == 2 ? TRUE : FALSE;
2080 /*************************************************************************
2083 * Copy a string to another string, up to a maximum number of characters.
2086 * lpszDest [O] Destination string
2087 * lpszSrc [I] Source string
2088 * iLen [I] Maximum number of chars to copy
2091 * Success: A pointer to the last character written.
2092 * Failure: lpszDest, if any arguments are invalid.
2094 LPSTR WINAPI SHLWAPI_399(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2096 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2098 if (lpszDest && lpszSrc && iLen > 0)
2100 while ((iLen-- > 1) && *lpszSrc)
2101 *lpszDest++ = *lpszSrc++;
2108 /*************************************************************************
2111 * Unicode version of SHLWAPI_399.
2113 LPWSTR WINAPI SHLWAPI_400(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2115 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2117 if (lpszDest && lpszSrc && iLen > 0)
2119 while ((iLen-- > 1) && *lpszSrc)
2120 *lpszDest++ = *lpszSrc++;