1 /*
2 * Shlwapi string functions
3 *
4 * Copyright 1998 Juergen Schmied
5 * Copyright 2002 Jon Griffiths
6 *
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.
11 *
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.
16 *
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <math.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
32 #include "windef.h"
33 #include "winbase.h"
34 #define NO_SHLWAPI_REG
35 #define NO_SHLWAPI_STREAM
36 #include "shlwapi.h"
37 #include "wingdi.h"
38 #include "winuser.h"
39 #include "shlobj.h"
40 #include "mlang.h"
41 #include "ddeml.h"
42 #include "wine/unicode.h"
43 #include "wine/debug.h"
44
45 #include "resource.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(shell);
48
49 extern HINSTANCE shlwapi_hInstance;
50
51 static HRESULT _SHStrDupAA(LPCSTR,LPSTR*);
52 static HRESULT _SHStrDupAW(LPCWSTR,LPSTR*);
53
54
55 static void FillNumberFmt(NUMBERFMTW *fmt, LPWSTR decimal_buffer, int decimal_bufwlen,
56 LPWSTR thousand_buffer, int thousand_bufwlen)
57 {
58 WCHAR grouping[64];
59 WCHAR *c;
60
61 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_ILZERO|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->LeadingZero)/sizeof(WCHAR));
62 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_INEGNUMBER|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->NegativeOrder)/sizeof(WCHAR));
63 fmt->NumDigits = 0;
64 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimal_buffer, decimal_bufwlen);
65 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thousand_buffer, thousand_bufwlen);
66 fmt->lpThousandSep = thousand_buffer;
67 fmt->lpDecimalSep = decimal_buffer;
68
69 /*
70 * Converting grouping string to number as described on
71 * http://blogs.msdn.com/oldnewthing/archive/2006/04/18/578251.aspx
72 */
73 fmt->Grouping = 0;
74 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, grouping, sizeof(grouping)/sizeof(WCHAR));
75 for (c = grouping; *c; c++)
76 if (*c >= '' && *c < '9')
77 {
78 fmt->Grouping *= 10;
79 fmt->Grouping += *c - '';
80 }
81
82 if (fmt->Grouping % 10 == 0)
83 fmt->Grouping /= 10;
84 else
85 fmt->Grouping *= 10;
86 }
87
88 /*************************************************************************
89 * FormatInt [internal]
90 *
91 * Format an integer according to the current locale
92 *
93 * RETURNS
94 * The number of bytes written on success or 0 on failure
95 */
96 static int FormatInt(LONGLONG qdwValue, LPWSTR pszBuf, int cchBuf)
97 {
98 NUMBERFMTW fmt;
99 WCHAR decimal[8], thousand[8];
100 WCHAR buf[24];
101 WCHAR *c;
102 BOOL neg = (qdwValue < 0);
103
104 FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR),
105 thousand, sizeof thousand / sizeof (WCHAR));
106
107 c = &buf[24];
108 *(--c) = 0;
109 do
110 {
111 *(--c) = '' + (qdwValue%10);
112 qdwValue /= 10;
113 } while (qdwValue > 0);
114 if (neg)
115 *(--c) = '-';
116
117 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, c, &fmt, pszBuf, cchBuf);
118 }
119
120 /*************************************************************************
121 * FormatDouble [internal]
122 *
123 * Format an integer according to the current locale. Prints the specified number of digits
124 * after the decimal point
125 *
126 * RETURNS
127 * The number of bytes written on success or 0 on failure
128 */
129 static int FormatDouble(double value, int decimals, LPWSTR pszBuf, int cchBuf)
130 {
131 static const WCHAR flfmt[] = {'%','f',0};
132 WCHAR buf[64];
133 NUMBERFMTW fmt;
134 WCHAR decimal[8], thousand[8];
135
136 snprintfW(buf, 64, flfmt, value);
137
138 FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR),
139 thousand, sizeof thousand / sizeof (WCHAR));
140 fmt.NumDigits = decimals;
141 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, buf, &fmt, pszBuf, cchBuf);
142 }
143
144 /*************************************************************************
145 * SHLWAPI_ChrCmpHelperA
146 *
147 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
148 *
149 * NOTES
150 * Both this function and its Unicode counterpart are very inefficient. To
151 * fix this, CompareString must be completely implemented and optimised
152 * first. Then the core character test can be taken out of that function and
153 * placed here, so that it need never be called at all. Until then, do not
154 * attempt to optimise this code unless you are willing to test that it
155 * still performs correctly.
156 */
157 static BOOL SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
158 {
159 char str1[3], str2[3];
160
161 str1[0] = LOBYTE(ch1);
162 if (IsDBCSLeadByte(str1[0]))
163 {
164 str1[1] = HIBYTE(ch1);
165 str1[2] = '\0';
166 }
167 else
168 str1[1] = '\0';
169
170 str2[0] = LOBYTE(ch2);
171 if (IsDBCSLeadByte(str2[0]))
172 {
173 str2[1] = HIBYTE(ch2);
174 str2[2] = '\0';
175 }
176 else
177 str2[1] = '\0';
178
179 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
180 }
181
182 /*************************************************************************
183 * SHLWAPI_ChrCmpA
184 *
185 * Internal helper function.
186 */
187 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
188 {
189 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
190 }
191
192 /*************************************************************************
193 * ChrCmpIA (SHLWAPI.385)
194 *
195 * Compare two characters, ignoring case.
196 *
197 * PARAMS
198 * ch1 [I] First character to compare
199 * ch2 [I] Second character to compare
200 *
201 * RETURNS
202 * FALSE, if the characters are equal.
203 * Non-zero otherwise.
204 */
205 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
206 {
207 TRACE("(%d,%d)\n", ch1, ch2);
208
209 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
210 }
211
212 /*************************************************************************
213 * ChrCmpIW [SHLWAPI.386]
214 *
215 * See ChrCmpIA.
216 */
217 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
218 {
219 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, &ch1, 1, &ch2, 1) - 2;
220 }
221
222 /*************************************************************************
223 * StrChrA [SHLWAPI.@]
224 *
225 * Find a given character in a string.
226 *
227 * PARAMS
228 * lpszStr [I] String to search in.
229 * ch [I] Character to search for.
230 *
231 * RETURNS
232 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
233 * not found.
234 * Failure: NULL, if any arguments are invalid.
235 */
236 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
237 {
238 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
239
240 if (lpszStr)
241 {
242 while (*lpszStr)
243 {
244 if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
245 return (LPSTR)lpszStr;
246 lpszStr = CharNextA(lpszStr);
247 }
248 }
249 return NULL;
250 }
251
252 /*************************************************************************
253 * StrChrW [SHLWAPI.@]
254 *
255 * See StrChrA.
256 */
257 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
258 {
259 LPWSTR lpszRet = NULL;
260
261 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
262
263 if (lpszStr)
264 lpszRet = strchrW(lpszStr, ch);
265 return lpszRet;
266 }
267
268 /*************************************************************************
269 * StrChrIA [SHLWAPI.@]
270 *
271 * Find a given character in a string, ignoring case.
272 *
273 * PARAMS
274 * lpszStr [I] String to search in.
275 * ch [I] Character to search for.
276 *
277 * RETURNS
278 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
279 * not found.
280 * Failure: NULL, if any arguments are invalid.
281 */
282 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
283 {
284 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
285
286 if (lpszStr)
287 {
288 while (*lpszStr)
289 {
290 if (!ChrCmpIA(*lpszStr, ch))
291 return (LPSTR)lpszStr;
292 lpszStr = CharNextA(lpszStr);
293 }
294 }
295 return NULL;
296 }
297
298 /*************************************************************************
299 * StrChrIW [SHLWAPI.@]
300 *
301 * See StrChrA.
302 */
303 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
304 {
305 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
306
307 if (lpszStr)
308 {
309 ch = toupperW(ch);
310 while (*lpszStr)
311 {
312 if (toupperW(*lpszStr) == ch)
313 return (LPWSTR)lpszStr;
314 lpszStr++;
315 }
316 lpszStr = NULL;
317 }
318 return (LPWSTR)lpszStr;
319 }
320
321 /*************************************************************************
322 * StrCmpIW [SHLWAPI.@]
323 *
324 * Compare two strings, ignoring case.
325 *
326 * PARAMS
327 * lpszStr [I] First string to compare
328 * lpszComp [I] Second string to compare
329 *
330 * RETURNS
331 * An integer less than, equal to or greater than 0, indicating that
332 * lpszStr is less than, the same, or greater than lpszComp.
333 */
334 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
335 {
336 int iRet;
337
338 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
339
340 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, -1, lpszComp, -1);
341 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
342 }
343
344 /*************************************************************************
345 * StrCmpNA [SHLWAPI.@]
346 *
347 * Compare two strings, up to a maximum length.
348 *
349 * PARAMS
350 * lpszStr [I] First string to compare
351 * lpszComp [I] Second string to compare
352 * iLen [I] Maximum number of chars to compare.
353 *
354 * RETURNS
355 * An integer less than, equal to or greater than 0, indicating that
356 * lpszStr is less than, the same, or greater than lpszComp.
357 */
358 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
359 {
360 INT iRet;
361
362 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
363
364 iRet = CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
365 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
366 }
367
368 /*************************************************************************
369 * StrCmpNW [SHLWAPI.@]
370 *
371 * See StrCmpNA.
372 */
373 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
374 {
375 INT iRet;
376
377 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
378
379 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
380 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
381 }
382
383 /*************************************************************************
384 * StrCmpNIA [SHLWAPI.@]
385 *
386 * Compare two strings, up to a maximum length, ignoring case.
387 *
388 * PARAMS
389 * lpszStr [I] First string to compare
390 * lpszComp [I] Second string to compare
391 * iLen [I] Maximum number of chars to compare.
392 *
393 * RETURNS
394 * An integer less than, equal to or greater than 0, indicating that
395 * lpszStr is less than, the same, or greater than lpszComp.
396 */
397 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
398 {
399 INT iRet;
400
401 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
402
403 iRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
404 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
405 }
406
407 /*************************************************************************
408 * StrCmpNIW [SHLWAPI.@]
409 *
410 * See StrCmpNIA.
411 */
412 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
413 {
414 INT iRet;
415
416 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
417
418 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
419 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
420 }
421
422 /*************************************************************************
423 * StrCmpW [SHLWAPI.@]
424 *
425 * Compare two strings.
426 *
427 * PARAMS
428 * lpszStr [I] First string to compare
429 * lpszComp [I] Second string to compare
430 *
431 * RETURNS
432 * An integer less than, equal to or greater than 0, indicating that
433 * lpszStr is less than, the same, or greater than lpszComp.
434 */
435 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
436 {
437 INT iRet;
438
439 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
440
441 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, -1, lpszComp, -1);
442 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
443 }
444
445 /*************************************************************************
446 * StrCatW [SHLWAPI.@]
447 *
448 * Concatenate two strings.
449 *
450 * PARAMS
451 * lpszStr [O] Initial string
452 * lpszSrc [I] String to concatenate
453 *
454 * RETURNS
455 * lpszStr.
456 */
457 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
458 {
459 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
460
461 strcatW(lpszStr, lpszSrc);
462 return lpszStr;
463 }
464
465 /*************************************************************************
466 * StrCpyW [SHLWAPI.@]
467 *
468 * Copy a string to another string.
469 *
470 * PARAMS
471 * lpszStr [O] Destination string
472 * lpszSrc [I] Source string
473 *
474 * RETURNS
475 * lpszStr.
476 */
477 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
478 {
479 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
480
481 strcpyW(lpszStr, lpszSrc);
482 return lpszStr;
483 }
484
485 /*************************************************************************
486 * StrCpyNW [SHLWAPI.@]
487 *
488 * Copy a string to another string, up to a maximum number of characters.
489 *
490 * PARAMS
491 * lpszStr [O] Destination string
492 * lpszSrc [I] Source string
493 * iLen [I] Maximum number of chars to copy
494 *
495 * RETURNS
496 * lpszStr.
497 */
498 LPWSTR WINAPI StrCpyNW(LPWSTR lpszStr, LPCWSTR lpszSrc, int iLen)
499 {
500 TRACE("(%p,%s,%i)\n", lpszStr, debugstr_w(lpszSrc), iLen);
501
502 lstrcpynW(lpszStr, lpszSrc, iLen);
503 return lpszStr;
504 }
505
506
507
508 /*************************************************************************
509 * SHLWAPI_StrStrHelperA
510 *
511 * Internal implementation of StrStrA/StrStrIA
512 */
513 static LPSTR SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
514 INT (WINAPI *pStrCmpFn)(LPCSTR,LPCSTR,INT))
515 {
516 size_t iLen;
517
518 if (!lpszStr || !lpszSearch || !*lpszSearch)
519 return NULL;
520
521 iLen = strlen(lpszSearch);
522
523 while (*lpszStr)
524 {
525 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
526 return (LPSTR)lpszStr;
527 lpszStr = CharNextA(lpszStr);
528 }
529 return NULL;
530 }
531
532 /*************************************************************************
533 * StrStrA [SHLWAPI.@]
534 *
535 * Find a substring within a string.
536 *
537 * PARAMS
538 * lpszStr [I] String to search in
539 * lpszSearch [I] String to look for
540 *
541 * RETURNS
542 * The start of lpszSearch within lpszStr, or NULL if not found.
543 */
544 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
545 {
546 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
547
548 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNA);
549 }
550
551 /*************************************************************************
552 * StrStrW [SHLWAPI.@]
553 *
554 * See StrStrA.
555 */
556 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
557 {
558 if (!lpszStr || !lpszSearch) return NULL;
559 return strstrW( lpszStr, lpszSearch );
560 }
561
562 /*************************************************************************
563 * StrRStrIA [SHLWAPI.@]
564 *
565 * Find the last occurrence of a substring within a string.
566 *
567 * PARAMS
568 * lpszStr [I] String to search in
569 * lpszEnd [I] End of lpszStr
570 * lpszSearch [I] String to look for
571 *
572 * RETURNS
573 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
574 */
575 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
576 {
577 WORD ch1, ch2;
578 INT iLen;
579
580 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
581
582 if (!lpszStr || !lpszSearch || !*lpszSearch)
583 return NULL;
584
585 if (!lpszEnd)
586 lpszEnd = lpszStr + lstrlenA(lpszStr);
587 if (lpszEnd == lpszStr)
588 return NULL;
589
590 if (IsDBCSLeadByte(*lpszSearch))
591 ch1 = *lpszSearch << 8 | (UCHAR)lpszSearch[1];
592 else
593 ch1 = *lpszSearch;
594 iLen = lstrlenA(lpszSearch);
595
596 do
597 {
598 lpszEnd = CharPrevA(lpszStr, lpszEnd);
599 ch2 = IsDBCSLeadByte(*lpszEnd)? *lpszEnd << 8 | (UCHAR)lpszEnd[1] : *lpszEnd;
600 if (!ChrCmpIA(ch1, ch2))
601 {
602 if (!StrCmpNIA(lpszEnd, lpszSearch, iLen))
603 return (LPSTR)lpszEnd;
604 }
605 } while (lpszEnd > lpszStr);
606 return NULL;
607 }
608
609 /*************************************************************************
610 * StrRStrIW [SHLWAPI.@]
611 *
612 * See StrRStrIA.
613 */
614 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
615 {
616 INT iLen;
617
618 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
619
620 if (!lpszStr || !lpszSearch || !*lpszSearch)
621 return NULL;
622
623 if (!lpszEnd)
624 lpszEnd = lpszStr + strlenW(lpszStr);
625
626 iLen = strlenW(lpszSearch);
627
628 while (lpszEnd > lpszStr)
629 {
630 lpszEnd--;
631 if (!StrCmpNIW(lpszEnd, lpszSearch, iLen))
632 return (LPWSTR)lpszEnd;
633 }
634 return NULL;
635 }
636
637 /*************************************************************************
638 * StrStrIA [SHLWAPI.@]
639 *
640 * Find a substring within a string, ignoring case.
641 *
642 * PARAMS
643 * lpszStr [I] String to search in
644 * lpszSearch [I] String to look for
645 *
646 * RETURNS
647 * The start of lpszSearch within lpszStr, or NULL if not found.
648 */
649 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
650 {
651 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
652
653 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNIA);
654 }
655
656 /*************************************************************************
657 * StrStrIW [SHLWAPI.@]
658 *
659 * See StrStrIA.
660 */
661 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
662 {
663 int iLen;
664
665 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
666
667 if (!lpszStr || !lpszSearch || !*lpszSearch)
668 return NULL;
669
670 iLen = strlenW(lpszSearch);
671
672 while (*lpszStr)
673 {
674 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
675 return (LPWSTR)lpszStr;
676 lpszStr++;
677 }
678 return NULL;
679 }
680
681 /*************************************************************************
682 * StrToIntA [SHLWAPI.@]
683 *
684 * Read a signed integer from a string.
685 *
686 * PARAMS
687 * lpszStr [I] String to read integer from
688 *
689 * RETURNS
690 * The signed integer value represented by the string, or 0 if no integer is
691 * present.
692 *
693 * NOTES
694 * No leading space is allowed before the number, although a leading '-' is.
695 */
696 int WINAPI StrToIntA(LPCSTR lpszStr)
697 {
698 int iRet = 0;
699
700 TRACE("(%s)\n", debugstr_a(lpszStr));
701
702 if (!lpszStr)
703 {
704 WARN("Invalid lpszStr would crash under Win32!\n");
705 return 0;
706 }
707
708 if (*lpszStr == '-' || isdigit(*lpszStr))
709 StrToIntExA(lpszStr, 0, &iRet);
710 return iRet;
711 }
712
713 /*************************************************************************
714 * StrToIntW [SHLWAPI.@]
715 *
716 * See StrToIntA.
717 */
718 int WINAPI StrToIntW(LPCWSTR lpszStr)
719 {
720 int iRet = 0;
721
722 TRACE("(%s)\n", debugstr_w(lpszStr));
723
724 if (!lpszStr)
725 {
726 WARN("Invalid lpszStr would crash under Win32!\n");
727 return 0;
728 }
729
730 if (*lpszStr == '-' || isdigitW(*lpszStr))
731 StrToIntExW(lpszStr, 0, &iRet);
732 return iRet;
733 }
734
735 /*************************************************************************
736 * StrToIntExA [SHLWAPI.@]
737 *
738 * Read an integer from a string.
739 *
740 * PARAMS
741 * lpszStr [I] String to read integer from
742 * dwFlags [I] Flags controlling the conversion
743 * lpiRet [O] Destination for read integer.
744 *
745 * RETURNS
746 * Success: TRUE. lpiRet contains the integer value represented by the string.
747 * Failure: FALSE, if the string is invalid, or no number is present.
748 *
749 * NOTES
750 * Leading whitespace, '-' and '+' are allowed before the number. If
751 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
752 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
753 * the string is treated as a decimal string. A leading '-' is ignored for
754 * hexadecimal numbers.
755 */
756 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
757 {
758 BOOL bNegative = FALSE;
759 int iRet = 0;
760
761 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
762
763 if (!lpszStr || !lpiRet)
764 {
765 WARN("Invalid parameter would crash under Win32!\n");
766 return FALSE;
767 }
768 if (dwFlags > STIF_SUPPORT_HEX)
769 {
770 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
771 }
772
773 /* Skip leading space, '+', '-' */
774 while (isspace(*lpszStr))
775 lpszStr = CharNextA(lpszStr);
776
777 if (*lpszStr == '-')
778 {
779 bNegative = TRUE;
780 lpszStr++;
781 }
782 else if (*lpszStr == '+')
783 lpszStr++;
784
785 if (dwFlags & STIF_SUPPORT_HEX &&
786 *lpszStr == '' && tolower(lpszStr[1]) == 'x')
787 {
788 /* Read hex number */
789 lpszStr += 2;
790
791 if (!isxdigit(*lpszStr))
792 return FALSE;
793
794 while (isxdigit(*lpszStr))
795 {
796 iRet = iRet * 16;
797 if (isdigit(*lpszStr))
798 iRet += (*lpszStr - '');
799 else
800 iRet += 10 + (tolower(*lpszStr) - 'a');
801 lpszStr++;
802 }
803 *lpiRet = iRet;
804 return TRUE;
805 }
806
807 /* Read decimal number */
808 if (!isdigit(*lpszStr))
809 return FALSE;
810
811 while (isdigit(*lpszStr))
812 {
813 iRet = iRet * 10;
814 iRet += (*lpszStr - '');
815 lpszStr++;
816 }
817 *lpiRet = bNegative ? -iRet : iRet;
818 return TRUE;
819 }
820
821 /*************************************************************************
822 * StrToIntExW [SHLWAPI.@]
823 *
824 * See StrToIntExA.
825 */
826 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
827 {
828 BOOL bNegative = FALSE;
829 int iRet = 0;
830
831 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
832
833 if (!lpszStr || !lpiRet)
834 {
835 WARN("Invalid parameter would crash under Win32!\n");
836 return FALSE;
837 }
838 if (dwFlags > STIF_SUPPORT_HEX)
839 {
840 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
841 }
842
843 /* Skip leading space, '+', '-' */
844 while (isspaceW(*lpszStr)) lpszStr++;
845
846 if (*lpszStr == '-')
847 {
848 bNegative = TRUE;
849 lpszStr++;
850 }
851 else if (*lpszStr == '+')
852 lpszStr++;
853
854 if (dwFlags & STIF_SUPPORT_HEX &&
855 *lpszStr == '' && tolowerW(lpszStr[1]) == 'x')
856 {
857 /* Read hex number */
858 lpszStr += 2;
859
860 if (!isxdigitW(*lpszStr))
861 return FALSE;
862
863 while (isxdigitW(*lpszStr))
864 {
865 iRet = iRet * 16;
866 if (isdigitW(*lpszStr))
867 iRet += (*lpszStr - '');
868 else
869 iRet += 10 + (tolowerW(*lpszStr) - 'a');
870 lpszStr++;
871 }
872 *lpiRet = iRet;
873 return TRUE;
874 }
875
876 /* Read decimal number */
877 if (!isdigitW(*lpszStr))
878 return FALSE;
879
880 while (isdigitW(*lpszStr))
881 {
882 iRet = iRet * 10;
883 iRet += (*lpszStr - '');
884 lpszStr++;
885 }
886 *lpiRet = bNegative ? -iRet : iRet;
887 return TRUE;
888 }
889
890 /*************************************************************************
891 * StrDupA [SHLWAPI.@]
892 *
893 * Duplicate a string.
894 *
895 * PARAMS
896 * lpszStr [I] String to duplicate.
897 *
898 * RETURNS
899 * Success: A pointer to a new string containing the contents of lpszStr
900 * Failure: NULL, if memory cannot be allocated
901 *
902 * NOTES
903 * The string memory is allocated with LocalAlloc(), and so should be released
904 * by calling LocalFree().
905 */
906 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
907 {
908 int iLen;
909 LPSTR lpszRet;
910
911 TRACE("(%s)\n",debugstr_a(lpszStr));
912
913 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
914 lpszRet = LocalAlloc(LMEM_FIXED, iLen);
915
916 if (lpszRet)
917 {
918 if (lpszStr)
919 memcpy(lpszRet, lpszStr, iLen);
920 else
921 *lpszRet = '\0';
922 }
923 return lpszRet;
924 }
925
926 /*************************************************************************
927 * StrDupW [SHLWAPI.@]
928 *
929 * See StrDupA.
930 */
931 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
932 {
933 int iLen;
934 LPWSTR lpszRet;
935
936 TRACE("(%s)\n",debugstr_w(lpszStr));
937
938 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
939 lpszRet = LocalAlloc(LMEM_FIXED, iLen);
940
941 if (lpszRet)
942 {
943 if (lpszStr)
944 memcpy(lpszRet, lpszStr, iLen);
945 else
946 *lpszRet = '\0';
947 }
948 return lpszRet;
949 }
950
951 /*************************************************************************
952 * SHLWAPI_StrSpnHelperA
953 *
954 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
955 */
956 static int SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
957 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
958 BOOL bInvert)
959 {
960 LPCSTR lpszRead = lpszStr;
961 if (lpszStr && *lpszStr && lpszMatch)
962 {
963 while (*lpszRead)
964 {
965 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
966
967 if (!bInvert && !lpszTest)
968 break;
969 if (bInvert && lpszTest)
970 break;
971 lpszRead = CharNextA(lpszRead);
972 };
973 }
974 return lpszRead - lpszStr;
975 }
976
977 /*************************************************************************
978 * StrSpnA [SHLWAPI.@]
979 *
980 * Find the length of the start of a string that contains only certain
981 * characters.
982 *
983 * PARAMS
984 * lpszStr [I] String to search
985 * lpszMatch [I] Characters that can be in the substring
986 *
987 * RETURNS
988 * The length of the part of lpszStr containing only chars from lpszMatch,
989 * or 0 if any parameter is invalid.
990 */
991 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
992 {
993 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
994
995 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
996 }
997
998 /*************************************************************************
999 * StrSpnW [SHLWAPI.@]
1000 *
1001 * See StrSpnA.
1002 */
1003 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1004 {
1005 if (!lpszStr || !lpszMatch) return 0;
1006 return strspnW( lpszStr, lpszMatch );
1007 }
1008
1009 /*************************************************************************
1010 * StrCSpnA [SHLWAPI.@]
1011 *
1012 * Find the length of the start of a string that does not contain certain
1013 * characters.
1014 *
1015 * PARAMS
1016 * lpszStr [I] String to search
1017 * lpszMatch [I] Characters that cannot be in the substring
1018 *
1019 * RETURNS
1020 * The length of the part of lpszStr containing only chars not in lpszMatch,
1021 * or 0 if any parameter is invalid.
1022 */
1023 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1024 {
1025 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1026
1027 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1028 }
1029
1030 /*************************************************************************
1031 * StrCSpnW [SHLWAPI.@]
1032 *
1033 * See StrCSpnA.
1034 */
1035 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1036 {
1037 if (!lpszStr || !lpszMatch) return 0;
1038 return strcspnW( lpszStr, lpszMatch );
1039 }
1040
1041 /*************************************************************************
1042 * StrCSpnIA [SHLWAPI.@]
1043 *
1044 * Find the length of the start of a string that does not contain certain
1045 * characters, ignoring case.
1046 *
1047 * PARAMS
1048 * lpszStr [I] String to search
1049 * lpszMatch [I] Characters that cannot be in the substring
1050 *
1051 * RETURNS
1052 * The length of the part of lpszStr containing only chars not in lpszMatch,
1053 * or 0 if any parameter is invalid.
1054 */
1055 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1056 {
1057 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1058
1059 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1060 }
1061
1062 /*************************************************************************
1063 * StrCSpnIW [SHLWAPI.@]
1064 *
1065 * See StrCSpnIA.
1066 */
1067 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1068 {
1069 LPCWSTR lpszRead = lpszStr;
1070
1071 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1072
1073 if (lpszStr && *lpszStr && lpszMatch)
1074 {
1075 while (*lpszRead)
1076 {
1077 if (StrChrIW(lpszMatch, *lpszRead)) break;
1078 lpszRead++;
1079 }
1080 }
1081 return lpszRead - lpszStr;
1082 }
1083
1084 /*************************************************************************
1085 * StrPBrkA [SHLWAPI.@]
1086 *
1087 * Search a string for any of a group of characters.
1088 *
1089 * PARAMS
1090 * lpszStr [I] String to search
1091 * lpszMatch [I] Characters to match
1092 *
1093 * RETURNS
1094 * A pointer to the first matching character in lpszStr, or NULL if no
1095 * match was found.
1096 */
1097 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1098 {
1099 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1100
1101 if (lpszStr && lpszMatch && *lpszMatch)
1102 {
1103 while (*lpszStr)
1104 {
1105 if (StrChrA(lpszMatch, *lpszStr))
1106 return (LPSTR)lpszStr;
1107 lpszStr = CharNextA(lpszStr);
1108 }
1109 }
1110 return NULL;
1111 }
1112
1113 /*************************************************************************
1114 * StrPBrkW [SHLWAPI.@]
1115 *
1116 * See StrPBrkA.
1117 */
1118 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1119 {
1120 if (!lpszStr || !lpszMatch) return NULL;
1121 return strpbrkW( lpszStr, lpszMatch );
1122 }
1123
1124 /*************************************************************************
1125 * SHLWAPI_StrRChrHelperA
1126 *
1127 * Internal implementation of StrRChrA/StrRChrIA.
1128 */
1129 static LPSTR SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1130 LPCSTR lpszEnd, WORD ch,
1131 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1132 {
1133 LPCSTR lpszRet = NULL;
1134
1135 if (lpszStr)
1136 {
1137 WORD ch2;
1138
1139 if (!lpszEnd)
1140 lpszEnd = lpszStr + lstrlenA(lpszStr);
1141
1142 while (*lpszStr && lpszStr <= lpszEnd)
1143 {
1144 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1145
1146 if (!pChrCmpFn(ch, ch2))
1147 lpszRet = lpszStr;
1148 lpszStr = CharNextA(lpszStr);
1149 }
1150 }
1151 return (LPSTR)lpszRet;
1152 }
1153
1154 /**************************************************************************
1155 * StrRChrA [SHLWAPI.@]
1156 *
1157 * Find the last occurrence of a character in string.
1158 *
1159 * PARAMS
1160 * lpszStr [I] String to search in
1161 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1162 * ch [I] Character to search for.
1163 *
1164 * RETURNS
1165 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1166 * or NULL if not found.
1167 * Failure: NULL, if any arguments are invalid.
1168 */
1169 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1170 {
1171 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1172
1173 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1174 }
1175
1176 /**************************************************************************
1177 * StrRChrW [SHLWAPI.@]
1178 *
1179 * See StrRChrA.
1180 */
1181 LPWSTR WINAPI StrRChrW(LPCWSTR str, LPCWSTR end, WORD ch)
1182 {
1183 WCHAR *ret = NULL;
1184
1185 if (!str) return NULL;
1186 if (!end) end = str + strlenW(str);
1187 while (str < end)
1188 {
1189 if (*str == ch) ret = (WCHAR *)str;
1190 str++;
1191 }
1192 return ret;
1193 }
1194
1195 /**************************************************************************
1196 * StrRChrIA [SHLWAPI.@]
1197 *
1198 * Find the last occurrence of a character in string, ignoring case.
1199 *
1200 * PARAMS