Removed most inclusions of options.h.
[wine] / dlls / shlwapi / string.c
1 /*
2  * Shlwapi string functions
3  *
4  * Copyright 1998 Juergen Schmied
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <ctype.h>
22 #include <stdlib.h> 
23 #include <stdio.h>
24 #include <string.h>
25
26 #include "winerror.h"
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "winreg.h"
32 #define NO_SHLWAPI_STREAM
33 #include "shlwapi.h"
34 #include "shlobj.h"
35 #include "wine/unicode.h"
36 #include "wine/debug.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(shell);
39
40 /*************************************************************************
41  * ChrCmpIA                                     [SHLWAPI.385]
42  *
43  * Note: Returns 0 (FALSE) if characters are equal (insensitive).
44  */
45 BOOL WINAPI ChrCmpIA (WORD w1, WORD w2)
46 {
47         TRACE("%c ? %c\n", w1, w2);
48         return (toupper(w1) != toupper(w2));
49 }
50
51 /*************************************************************************
52  * ChrCmpIW                                     [SHLWAPI.386]
53  *
54  * Note: Returns 0 (FALSE) if characters are equal (insensitive).
55  */
56 BOOL WINAPI ChrCmpIW (WCHAR w1, WCHAR w2)
57 {
58         TRACE("%c ? %c\n", w1, w2);
59         return (toupperW(w1) != toupperW(w2));
60 }
61
62 /*************************************************************************
63  * StrChrA                                      [SHLWAPI.@]
64  */
65 LPSTR WINAPI StrChrA (LPCSTR str, WORD c)
66 {
67         TRACE("%s %i\n", str,c);
68         return strchr(str, c);
69 }
70
71 /*************************************************************************
72  * StrChrW                                      [SHLWAPI.@]
73  *
74  */
75 LPWSTR WINAPI StrChrW (LPCWSTR str, WCHAR x )
76 {
77         TRACE("%s 0x%04x\n",debugstr_w(str),x);
78         return strchrW(str, x);
79 }
80
81 /*************************************************************************
82  * StrCmpIW                                     [SHLWAPI.@]
83  */
84 int WINAPI StrCmpIW ( LPCWSTR wstr1, LPCWSTR wstr2 )
85 {
86     TRACE("%s %s\n", debugstr_w(wstr1),debugstr_w(wstr2));
87     return strcmpiW( wstr1, wstr2 );
88 }
89
90 /*************************************************************************
91  * StrCmpNA                                     [SHLWAPI.@]
92  */
93 INT WINAPI StrCmpNA ( LPCSTR str1, LPCSTR str2, INT len)
94 {
95         TRACE("%s %s %i stub\n", str1,str2,len);
96         return strncmp(str1, str2, len);
97 }
98
99 /*************************************************************************
100  * StrCmpNW                                     [SHLWAPI.@]
101  */
102 INT WINAPI StrCmpNW ( LPCWSTR wstr1, LPCWSTR wstr2, INT len)
103 {
104         TRACE("%s %s %i stub\n", debugstr_w(wstr1),debugstr_w(wstr2),len);
105         return strncmpW(wstr1, wstr2, len);
106 }
107
108 /*************************************************************************
109  * StrCmpNIA                                    [SHLWAPI.@]
110  */
111 int WINAPI StrCmpNIA ( LPCSTR str1, LPCSTR str2, int len)
112 {
113         TRACE("%s %s %i stub\n", str1,str2,len);
114         return strncasecmp(str1, str2, len);
115 }
116
117 /*************************************************************************
118  * StrCmpNIW                                    [SHLWAPI.@]
119  */
120 int WINAPI StrCmpNIW ( LPCWSTR wstr1, LPCWSTR wstr2, int len)
121 {
122         TRACE("%s %s %i stub\n", debugstr_w(wstr1),debugstr_w(wstr2),len);
123         return strncmpiW(wstr1, wstr2, len);
124 }
125
126 /*************************************************************************
127  * StrCmpW                                      [SHLWAPI.@]
128  */
129 int WINAPI StrCmpW ( LPCWSTR wstr1, LPCWSTR wstr2 )
130 {
131     TRACE("%s %s\n", debugstr_w(wstr1),debugstr_w(wstr2));
132     return strcmpW( wstr1, wstr2 );
133 }
134
135 /*************************************************************************
136  * StrCatW                                      [SHLWAPI.@]
137  */
138 LPWSTR WINAPI StrCatW( LPWSTR wstr1, LPCWSTR wstr2 )
139 {
140     return strcatW( wstr1, wstr2 );
141 }
142
143
144 /*************************************************************************
145  * StrCpyW                                      [SHLWAPI.@]
146  */
147 LPWSTR WINAPI StrCpyW( LPWSTR wstr1, LPCWSTR wstr2 )
148 {
149     return strcpyW( wstr1, wstr2 );
150 }
151
152
153 /*************************************************************************
154  * StrCpyNW                                     [SHLWAPI.@]
155  */
156 LPWSTR WINAPI StrCpyNW( LPWSTR wstr1, LPCWSTR wstr2, int n )
157 {
158     return lstrcpynW( wstr1, wstr2, n );
159 }
160
161
162 /*************************************************************************
163  * StrStrA                                      [SHLWAPI.@]
164  */
165 LPSTR WINAPI StrStrA(LPCSTR lpFirst, LPCSTR lpSrch)
166 {
167     while (*lpFirst)
168     {
169         LPCSTR p1 = lpFirst, p2 = lpSrch;
170         while (*p1 && *p2 && *p1 == *p2) { p1++; p2++; }
171         if (!*p2) return (LPSTR)lpFirst;
172         lpFirst++;
173     }
174     return NULL;
175 }
176
177 /*************************************************************************
178  * StrStrW                                      [SHLWAPI.@]
179  */
180 LPWSTR WINAPI StrStrW(LPCWSTR lpFirst, LPCWSTR lpSrch)
181 {
182     while (*lpFirst)
183     {
184         LPCWSTR p1 = lpFirst, p2 = lpSrch;
185         while (*p1 && *p2 && *p1 == *p2) { p1++; p2++; }
186         if (!*p2) return (LPWSTR)lpFirst;
187         lpFirst++;
188     }
189     return NULL;
190 }
191
192 /*************************************************************************
193  * StrStrIA                                     [SHLWAPI.@]
194  */
195 LPSTR WINAPI StrStrIA(LPCSTR lpFirst, LPCSTR lpSrch)
196 {
197     while (*lpFirst)
198     {
199         LPCSTR p1 = lpFirst, p2 = lpSrch;
200         while (*p1 && *p2 && toupper(*p1) == toupper(*p2)) { p1++; p2++; }
201         if (!*p2) return (LPSTR)lpFirst;
202         lpFirst++;
203     }
204     return NULL;
205 }
206
207 /*************************************************************************
208  * StrStrIW                                     [SHLWAPI.@]
209  */
210 LPWSTR WINAPI StrStrIW(LPCWSTR lpFirst, LPCWSTR lpSrch)
211 {
212     while (*lpFirst)
213     {
214         LPCWSTR p1 = lpFirst, p2 = lpSrch;
215         while (*p1 && *p2 && toupperW(*p1) == toupperW(*p2)) { p1++; p2++; }
216         if (!*p2) return (LPWSTR)lpFirst;
217         lpFirst++;
218     }
219     return NULL;
220 }
221
222 /*************************************************************************
223  *      StrToIntA                       [SHLWAPI.@]
224  */
225 int WINAPI StrToIntA(LPCSTR lpSrc)
226 {
227         TRACE("%s\n", lpSrc);
228         return atol(lpSrc);
229 }
230
231 /*************************************************************************
232  *      StrToIntW                       [SHLWAPI.@]
233  */
234 int WINAPI StrToIntW(LPCWSTR lpSrc)
235 {
236     char buffer[32];
237
238     TRACE("%s\n", debugstr_w(lpSrc));
239     WideCharToMultiByte( CP_ACP, 0, lpSrc, -1, buffer, sizeof(buffer), NULL, NULL );
240     buffer[sizeof(buffer)-1] = 0;
241     return atol(buffer);
242 }
243
244 /*************************************************************************
245  *      StrToIntExA                     [SHLWAPI.@]
246  */
247 BOOL WINAPI StrToIntExA( LPCSTR pszString, DWORD dwFlags, LPINT piRet)
248 {
249         TRACE("%s %ld stub !\n", debugstr_a(pszString), dwFlags);
250         piRet = (LPINT) StrToIntA(pszString);
251         return TRUE;
252 }
253
254 /*************************************************************************
255  *      StrToIntExW                     [SHLWAPI.@]
256  */
257 BOOL WINAPI StrToIntExW( LPCWSTR pszString, DWORD dwFlags, LPINT piRet)
258 {
259         TRACE("%s %ld stub !\n", debugstr_w(pszString), dwFlags);
260         piRet = (LPINT) StrToIntW(pszString);
261         return TRUE;
262 }
263
264 /*************************************************************************
265  *      StrDupA                 [SHLWAPI.@]
266  */
267 LPSTR WINAPI StrDupA (LPCSTR lpSrc)
268 {
269         int len = strlen(lpSrc);
270         LPSTR lpDest = (LPSTR) LocalAlloc(LMEM_FIXED, len+1);
271         
272         TRACE("%s\n", lpSrc);
273
274         if (lpDest) strcpy(lpDest, lpSrc);
275         return lpDest;
276 }
277
278 /*************************************************************************
279  *      StrDupW                 [SHLWAPI.@]
280  */
281 LPWSTR WINAPI StrDupW (LPCWSTR lpSrc)
282 {
283         int len = strlenW(lpSrc);
284         LPWSTR lpDest = (LPWSTR) LocalAlloc(LMEM_FIXED, sizeof(WCHAR) * (len+1));
285         
286         TRACE("%s\n", debugstr_w(lpSrc));
287
288         if (lpDest) strcpyW(lpDest, lpSrc);
289         return lpDest;
290 }
291
292 /*************************************************************************
293  *      StrCSpnA                [SHLWAPI.@]
294  */
295 int WINAPI StrCSpnA (LPCSTR lpStr, LPCSTR lpSet)
296 {
297         int i,j, pos = strlen(lpStr);
298
299         TRACE("(%p %s  %p %s)\n",
300            lpStr, debugstr_a(lpStr), lpSet, debugstr_a(lpSet));
301
302         for (i=0; i < strlen(lpSet) ; i++ )
303         {
304           for (j = 0; j < pos;j++)
305           {
306             if (lpStr[j] == lpSet[i])
307             {
308               pos = j;
309             }
310           }
311         }      
312         TRACE("-- %u\n", pos);
313         return pos;     
314 }
315
316 /*************************************************************************
317  *      StrCSpnW                [SHLWAPI.@]
318  */
319 int WINAPI StrCSpnW (LPCWSTR lpStr, LPCWSTR lpSet)
320 {
321         int i,j, pos = strlenW(lpStr);
322
323         TRACE("(%p %s %p %s)\n",
324            lpStr, debugstr_w(lpStr), lpSet, debugstr_w(lpSet));
325
326         for (i=0; i < strlenW(lpSet) ; i++ )
327         {
328           for (j = 0; j < pos;j++)
329           {
330             if (lpStr[j] == lpSet[i])
331             {
332               pos = j;
333             }
334           }
335         }      
336         TRACE("-- %u\n", pos);
337         return pos;     
338 }
339
340 /**************************************************************************
341  * StrRChrA [SHLWAPI.@]
342  *
343  */
344 LPSTR WINAPI StrRChrA( LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch )
345 {
346     LPCSTR lpGotIt = NULL;
347     BOOL dbcs = IsDBCSLeadByte( LOBYTE(wMatch) );
348
349     TRACE("(%p, %p, %x)\n", lpStart, lpEnd, wMatch);
350     if (!lpStart && !lpEnd) return NULL;
351     if (!lpEnd) lpEnd = lpStart + strlen(lpStart);
352
353     for(; lpStart < lpEnd; lpStart = CharNextA(lpStart))
354     {
355         if (*lpStart != LOBYTE(wMatch)) continue;
356         if (dbcs && lpStart[1] != HIBYTE(wMatch)) continue;
357         lpGotIt = lpStart;
358     }    
359     return (LPSTR)lpGotIt;
360 }
361
362
363 /**************************************************************************
364  * StrRChrW [SHLWAPI.@]
365  *
366  */
367 LPWSTR WINAPI StrRChrW( LPCWSTR lpStart, LPCWSTR lpEnd, WORD wMatch)
368 {
369     LPCWSTR lpGotIt = NULL;
370
371     TRACE("(%p, %p, %x)\n", lpStart, lpEnd, wMatch);
372     if (!lpStart && !lpEnd) return NULL;
373     if (!lpEnd) lpEnd = lpStart + strlenW(lpStart);
374
375     for(; lpStart < lpEnd; lpStart = CharNextW(lpStart))
376         if (*lpStart == wMatch) lpGotIt = lpStart;
377
378     return (LPWSTR)lpGotIt;
379 }
380
381
382 /**************************************************************************
383  * StrRChrIA [SHLWAPI.@]
384  *
385  */
386 LPSTR WINAPI StrRChrIA( LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch )
387 {
388     LPCSTR lpGotIt = NULL;
389     BOOL dbcs = IsDBCSLeadByte( LOBYTE(wMatch) );
390
391     TRACE("(%p, %p, %x)\n", lpStart, lpEnd, wMatch);
392     if (!lpStart && !lpEnd) return NULL;
393     if (!lpEnd) lpEnd = lpStart + strlen(lpStart);
394
395     for(; lpStart < lpEnd; lpStart = CharNextA(lpStart))
396     {
397         if (dbcs) {
398             /*
399             if (_mbctoupper(*lpStart) == _mbctoupper(wMatch))
400                 lpGotIt = lpStart;
401             */
402             if (toupper(*lpStart) == toupper(wMatch)) lpGotIt = lpStart;
403         } else {
404             if (toupper(*lpStart) == toupper(wMatch)) lpGotIt = lpStart;
405         }
406     }    
407     return (LPSTR)lpGotIt;
408 }
409
410
411 /**************************************************************************
412  * StrRChrIW [SHLWAPI.@]
413  *
414  */
415 LPWSTR WINAPI StrRChrIW( LPCWSTR lpStart, LPCWSTR lpEnd, WORD wMatch)
416 {
417     LPCWSTR lpGotIt = NULL;
418
419     TRACE("(%p, %p, %x)\n", lpStart, lpEnd, wMatch);
420     if (!lpStart && !lpEnd) return NULL;
421     if (!lpEnd) lpEnd = lpStart + strlenW(lpStart);
422
423     for(; lpStart < lpEnd; lpStart = CharNextW(lpStart))
424         if (toupperW(*lpStart) == toupperW(wMatch)) lpGotIt = lpStart;
425
426     return (LPWSTR)lpGotIt;
427 }
428
429
430 /*************************************************************************
431  *      StrCatBuffA             [SHLWAPI.@]
432  *
433  * Appends back onto front, stopping when front is size-1 characters long.
434  * Returns front.
435  *
436  */
437 LPSTR WINAPI StrCatBuffA(LPSTR front, LPCSTR back, INT size)
438 {
439     LPSTR dst = front + strlen(front);
440     LPCSTR src = back, end = front + size - 1;
441
442     while(dst < end && *src)
443         *dst++ = *src++;
444     *dst = '\0';
445     return front;
446 }
447
448 /*************************************************************************
449  *      StrCatBuffW             [SHLWAPI.@]
450  *
451  * Appends back onto front, stopping when front is size-1 characters long.
452  * Returns front.
453  *
454  */
455 LPWSTR WINAPI StrCatBuffW(LPWSTR front, LPCWSTR back, INT size)
456 {
457     LPWSTR dst = front + strlenW(front);
458     LPCWSTR src = back, end = front + size - 1;
459
460     while(dst < end && *src)
461         *dst++ = *src++;
462     *dst = '\0';
463     return front;
464 }
465
466 /*************************************************************************
467  * StrRetToBufA                                 [SHLWAPI.@]
468  * 
469  * converts a STRRET to a normal string
470  *
471  * NOTES
472  *  the pidl is for STRRET OFFSET
473  *
474  * ***** NOTE *****
475  *  This routine is identical to StrRetToStrNA in dlls/shell32/shellstring.c.
476  *  It was duplicated there because not every version of Shlwapi.dll exports
477  *  StrRetToBufA. If you change one routine, change them both. YOU HAVE BEEN
478  *  WARNED.
479  * ***** NOTE *****
480  */
481 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, DWORD len)
482 {
483         TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest,len,src,pidl);
484
485         switch (src->uType)
486         {
487           case STRRET_WSTR:
488             WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
489 /*          SHFree(src->u.pOleStr);  FIXME: is this right? */
490             break;
491
492           case STRRET_CSTRA:
493             lstrcpynA((LPSTR)dest, src->u.cStr, len);
494             break;
495
496           case STRRET_OFFSETA:
497             lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
498             break;
499
500           default:
501             FIXME("unknown type!\n");
502             if (len)
503             {
504               *(LPSTR)dest = '\0';
505             }
506             return(FALSE);
507         }
508         return S_OK;
509 }
510
511 /*************************************************************************
512  * StrRetToBufW                                 [SHLWAPI.@]
513  * 
514  * converts a STRRET to a normal string
515  *
516  * NOTES
517  *  the pidl is for STRRET OFFSET
518  *
519  * ***** NOTE *****
520  *  This routine is identical to StrRetToStrNW in dlls/shell32/shellstring.c.
521  *  It was duplicated there because not every version of Shlwapi.dll exports
522  *  StrRetToBufW. If you change one routine, change them both. YOU HAVE BEEN
523  *  WARNED.
524  * ***** NOTE *****
525  */
526 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, DWORD len)
527 {
528         TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest,len,src,pidl);
529
530         switch (src->uType)
531         {
532           case STRRET_WSTR:
533             lstrcpynW((LPWSTR)dest, src->u.pOleStr, len);
534 /*          SHFree(src->u.pOleStr);  FIXME: is this right? */
535             break;
536
537           case STRRET_CSTRA:
538               if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
539                   dest[len-1] = 0;
540             break;
541
542           case STRRET_OFFSETA:
543             if (pidl)
544             {
545               if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
546                                         dest, len ) && len)
547                   dest[len-1] = 0;
548             }
549             break;
550
551           default:
552             FIXME("unknown type!\n");
553             if (len)
554             { *(LPSTR)dest = '\0';
555             }
556             return(FALSE);
557         }
558         return S_OK;
559 }
560
561 /*************************************************************************
562  * StrFormatByteSizeA                           [SHLWAPI.@]
563  */
564 LPSTR WINAPI StrFormatByteSizeA ( DWORD dw, LPSTR pszBuf, UINT cchBuf )
565 {       char buf[64];
566         TRACE("%lx %p %i\n", dw, pszBuf, cchBuf);
567         if ( dw<1024L )
568         { sprintf (buf,"%ld bytes", dw);
569         }
570         else if ( dw<1048576L)
571         { sprintf (buf,"%3.1f KB", (FLOAT)dw/1024);
572         }
573         else if ( dw < 1073741824L)
574         { sprintf (buf,"%3.1f MB", (FLOAT)dw/1048576L);
575         }
576         else
577         { sprintf (buf,"%3.1f GB", (FLOAT)dw/1073741824L);
578         }
579         lstrcpynA (pszBuf, buf, cchBuf);
580         return pszBuf;  
581 }
582
583 /*************************************************************************
584  * StrFormatByteSizeW                           [SHLWAPI.@]
585  */
586 LPWSTR WINAPI StrFormatByteSizeW ( DWORD dw, LPWSTR pszBuf, UINT cchBuf )
587 {
588         char buf[64];
589         StrFormatByteSizeA( dw, buf, sizeof(buf) );
590         if (!MultiByteToWideChar( CP_ACP, 0, buf, -1, pszBuf, cchBuf ) && cchBuf)
591             pszBuf[cchBuf-1] = 0;
592         return pszBuf;
593 }
594
595 /*************************************************************************
596  *      StrNCatA        [SHLWAPI.@]
597  */
598 LPSTR WINAPI StrNCatA(LPSTR front, LPCSTR back, INT cchMax)
599 {
600         TRACE("%s %s %i stub\n", debugstr_a(front),debugstr_a(back),cchMax);
601         return (front);
602 }
603
604 /*************************************************************************
605  *      StrNCatW        [SHLWAPI.@]
606  */
607 LPWSTR WINAPI StrNCatW(LPWSTR front, LPCWSTR back, INT cchMax)
608 {
609         TRACE("%s %s %i stub\n", debugstr_w(front),debugstr_w(back),cchMax);
610         return (front);
611 }
612
613 /*************************************************************************
614  *      StrTrimA        [SHLWAPI.@]
615  */
616 BOOL WINAPI StrTrimA(LPSTR pszSource, LPCSTR pszTrimChars)
617 {
618     BOOL trimmed = FALSE;
619     LPSTR pSrc;
620     LPCSTR pTrim;
621
622     TRACE("('%s', '%s');\n", pszSource, pszTrimChars);
623     for (pTrim = pszTrimChars; *pTrim; pTrim++)
624     {
625          for (pSrc = pszSource; *pSrc; pSrc++)
626              if (*pSrc == *pTrim)
627              {
628                  /* match -> remove this char.
629                   * strlen(pSrc) equiv. to the correct strlen(pSrc+1)+1 */
630                  memmove(pSrc, pSrc+1, strlen(pSrc));
631                  trimmed = TRUE;
632              }
633     }
634     TRACE("<- '%s'\n", pszSource);
635     return trimmed;
636 }
637
638 /*************************************************************************
639  *      wnsprintfA      [SHLWAPI.@]
640  */
641 int WINAPIV wnsprintfA(LPSTR lpOut, int cchLimitIn, LPCSTR lpFmt, ...)
642 {
643     va_list valist;
644     INT res;
645
646     va_start( valist, lpFmt );
647     res = wvsnprintfA( lpOut, cchLimitIn, lpFmt, valist );
648     va_end( valist );
649     return res;
650 }
651
652 /*************************************************************************
653  *      wnsprintfW      [SHLWAPI.@]
654  */
655 int WINAPIV wnsprintfW(LPWSTR lpOut, int cchLimitIn, LPCWSTR lpFmt, ...)
656 {
657     va_list valist;
658     INT res;
659
660     va_start( valist, lpFmt );
661     res = wvsnprintfW( lpOut, cchLimitIn, lpFmt, valist );
662     va_end( valist );
663     return res;
664 }