Fixed some issues found by winapi_check.
[wine] / dlls / shlwapi / path.c
1 /*
2  * Path Functions
3  *
4  * Copyright 1999, 2000 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 <string.h>
23 #include <stdlib.h>
24
25 #include "winerror.h"
26 #include "wine/unicode.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winreg.h"
31 #define NO_SHLWAPI_STREAM
32 #include "shlwapi.h"
33 #include "wine/debug.h"
34 #include "ordinal.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(shell);
37
38 INT __cdecl _wtoi(LPWSTR string);
39
40 #define isSlash(x) ((x)=='\\' || (x)=='/')
41 /*
42         ########## Combining and Constructing paths ##########
43 */
44
45 /*************************************************************************
46  * PathAppendA          [SHLWAPI.@]
47  * 
48  * NOTES
49  *  concat path lpszPath2 onto lpszPath1
50  *
51  * FIXME
52  *  the resulting path is also canonicalized
53  */
54 BOOL WINAPI PathAppendA(
55         LPSTR lpszPath1,
56         LPCSTR lpszPath2) 
57 {
58         TRACE("%s %s\n",lpszPath1, lpszPath2);
59         while (lpszPath2[0]=='\\') lpszPath2++;
60         PathCombineA(lpszPath1,lpszPath1,lpszPath2);
61         return TRUE;
62 }
63
64 /*************************************************************************
65  * PathAppendW          [SHLWAPI.@]
66  */
67 BOOL WINAPI PathAppendW(
68         LPWSTR lpszPath1,
69         LPCWSTR lpszPath2) 
70 {
71         TRACE("%s %s\n",debugstr_w(lpszPath1), debugstr_w(lpszPath2));
72         while (lpszPath2[0]=='\\') lpszPath2++;
73         PathCombineW(lpszPath1,lpszPath1,lpszPath2);
74         return TRUE;
75 }
76
77 /*************************************************************************
78  * PathCombineA         [SHLWAPI.@]
79  * 
80  * NOTES
81  *  if lpszFile='.' skip it
82  *  szDest can be equal to lpszFile. Thats why we use sTemp
83  *
84  * FIXME
85  *  the resulting path is also canonicalized
86  */
87 LPSTR WINAPI PathCombineA(
88         LPSTR szDest,
89         LPCSTR lpszDir,
90         LPCSTR lpszFile) 
91 {
92         char sTemp[MAX_PATH];
93         TRACE("%p %p->%s %p->%s\n",szDest, lpszDir, lpszDir, lpszFile, lpszFile);
94         
95         
96         if (!lpszFile || !lpszFile[0] || (lpszFile[0]=='.' && !lpszFile[1]) ) 
97         {
98           strcpy(szDest,lpszDir);
99           return szDest;
100         }
101
102         /*  if lpszFile is a complete path don't care about lpszDir */
103         if (PathGetDriveNumberA(lpszFile) != -1)
104         {
105           strcpy(szDest,lpszFile);
106         }
107         else if (lpszFile[0] == '\\' )
108         {
109           strcpy(sTemp,lpszDir);
110           PathStripToRootA(sTemp);
111           strcat(sTemp,lpszFile);
112           strcpy(szDest,sTemp);
113         }
114         else
115         {
116           strcpy(sTemp,lpszDir);
117           PathAddBackslashA(sTemp);
118           strcat(sTemp,lpszFile);
119           strcpy(szDest,sTemp);
120         }
121         return szDest;
122 }
123
124 /*************************************************************************
125  * PathCombineW          [SHLWAPI.@]
126  */
127 LPWSTR WINAPI PathCombineW(
128         LPWSTR szDest,
129         LPCWSTR lpszDir,
130         LPCWSTR lpszFile) 
131 {
132         WCHAR sTemp[MAX_PATH];
133         TRACE("%p %p->%s %p->%s\n",szDest, lpszDir, debugstr_w(lpszDir),
134                          lpszFile, debugstr_w(lpszFile));
135         
136         
137         if (!lpszFile || !lpszFile[0] || (lpszFile[0]==(WCHAR)'.' && !lpszFile[1]) ) 
138         {
139           strcpyW(szDest,lpszDir);
140           return szDest;
141         }
142
143         /*  if lpszFile is a complete path don't care about lpszDir */
144         if (PathGetDriveNumberW(lpszFile) != -1)
145         {
146             strcpyW(szDest,lpszFile);
147         }
148         else if (lpszFile[0] == (WCHAR)'\\' )
149         {
150           strcpyW(sTemp,lpszDir);
151           PathStripToRootW(sTemp);
152           strcatW(sTemp,lpszFile);
153           strcpyW(szDest,sTemp);
154         }
155         else
156         {
157           strcpyW(sTemp,lpszDir);
158           PathAddBackslashW(sTemp);
159           strcatW(sTemp,lpszFile);
160           strcpyW(szDest,sTemp);
161         }
162         return szDest;
163 }
164
165 /*************************************************************************
166  * PathAddBackslashA    [SHLWAPI.@]
167  *
168  * NOTES
169  *     append \ if there is none
170  */
171 LPSTR WINAPI PathAddBackslashA(LPSTR lpszPath)
172 {
173         int len;
174         TRACE("%p->%s\n",lpszPath,lpszPath);
175
176         len = strlen(lpszPath);
177         if (len && lpszPath[len-1]!='\\') 
178         {
179           lpszPath[len]  = '\\';
180           lpszPath[len+1]= 0x00;
181           return lpszPath+len+1;
182         }
183         return lpszPath+len;
184 }
185
186 /*************************************************************************
187  * PathAddBackslashW    [SHLWAPI.@]
188  */
189 LPWSTR WINAPI PathAddBackslashW(LPWSTR lpszPath)
190 {
191         int len;
192         TRACE("%p->%s\n",lpszPath,debugstr_w(lpszPath));
193
194         len = strlenW(lpszPath);
195         if (len && lpszPath[len-1]!=(WCHAR)'\\') 
196         {
197           lpszPath[len]  = (WCHAR)'\\';
198           lpszPath[len+1]= 0x00;
199           return lpszPath+len+1;
200         }
201         return lpszPath+len;
202 }
203
204 /*************************************************************************
205  * PathBuildRootA               [SHLWAPI.@]
206  */
207 LPSTR WINAPI PathBuildRootA(LPSTR lpszPath, int drive) 
208 {
209         TRACE("%p %i\n",lpszPath, drive);
210
211         strcpy(lpszPath,"A:\\");
212         lpszPath[0]+=drive;
213         return lpszPath;
214 }
215
216 /*************************************************************************
217  * PathBuildRootW               [SHLWAPI.@]
218  */
219 LPWSTR WINAPI PathBuildRootW(LPWSTR lpszPath, int drive) 
220 {
221         lpszPath[0] = 'A' + drive;
222         lpszPath[1] = ':';
223         lpszPath[2] = '\\';
224         lpszPath[3] = 0;
225         TRACE("%p %i\n",debugstr_w(lpszPath), drive);
226         return lpszPath;
227 }
228
229 /*
230         Extracting Component Parts
231 */
232
233 /*************************************************************************
234  * PathFindFileNameA    [SHLWAPI.@]
235  */
236 LPSTR WINAPI PathFindFileNameA(LPCSTR lpszPath)
237 {
238         LPCSTR lastSlash = lpszPath;
239
240         TRACE("%s\n",lpszPath);
241         while (*lpszPath) 
242         {
243           if ( isSlash(lpszPath[0]) && lpszPath[1])
244               lastSlash = lpszPath+1;
245           lpszPath = CharNextA(lpszPath);
246         }
247         return (LPSTR)lastSlash;
248
249 }
250
251 /*************************************************************************
252  * PathFindFileNameW    [SHLWAPI.@]
253  */
254 LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath)
255 {
256         LPCWSTR wslash;
257         wslash = lpszPath;
258
259         TRACE("%s\n",debugstr_w(wslash));
260         while (lpszPath[0]) 
261         {
262           if (((lpszPath[0]=='\\') || (lpszPath[0]==':')) && lpszPath[1] && lpszPath[1]!='\\')
263             wslash = lpszPath+1;
264           lpszPath = CharNextW(lpszPath);
265         }
266         return (LPWSTR)wslash;  
267 }
268
269 /*************************************************************************
270  * PathFindExtensionA   [SHLWAPI.@]
271  *
272  * NOTES
273  *     returns pointer to last . in last lpszPath component or at \0.
274  */
275
276 LPSTR WINAPI PathFindExtensionA(LPCSTR lpszPath) 
277 {
278         LPCSTR   lastpoint = NULL;
279
280         TRACE("%p %s\n",lpszPath,lpszPath);
281
282         while (*lpszPath) 
283         {
284           if (*lpszPath=='\\'||*lpszPath==' ')
285             lastpoint=NULL;
286           if (*lpszPath=='.')
287             lastpoint=lpszPath;
288           lpszPath = CharNextA(lpszPath);
289         }
290         return (LPSTR)(lastpoint?lastpoint:lpszPath);
291 }
292
293 /*************************************************************************
294  * PathFindExtensionW   [SHLWAPI.@]
295  */
296 LPWSTR WINAPI PathFindExtensionW(LPCWSTR lpszPath) 
297 {
298         LPCWSTR   lastpoint = NULL;
299
300         TRACE("(%p %s)\n",lpszPath,debugstr_w(lpszPath));
301
302         while (*lpszPath)
303         {
304           if (*lpszPath==(WCHAR)'\\'||*lpszPath==(WCHAR)' ')
305             lastpoint=NULL;
306           if (*lpszPath==(WCHAR)'.')
307             lastpoint=lpszPath;
308           lpszPath = CharNextW(lpszPath);
309         }
310         return (LPWSTR)(lastpoint?lastpoint:lpszPath);
311 }
312
313 /*************************************************************************
314  * PathGetArgsA         [SHLWAPI.@]
315  *
316  * NOTES
317  *     look for next arg in string. handle "quoted" strings
318  *     returns pointer to argument *AFTER* the space. Or to the \0.
319  *
320  * FIXME
321  *     quoting by '\'
322  */
323 LPSTR WINAPI PathGetArgsA(LPCSTR lpszPath) 
324 {
325         BOOL    qflag = FALSE;
326
327         TRACE("%s\n",lpszPath);
328
329         while (*lpszPath) 
330         {
331           if ((*lpszPath==' ') && !qflag)
332             return (LPSTR)lpszPath+1;
333           if (*lpszPath=='"')
334             qflag=!qflag;
335           lpszPath = CharNextA(lpszPath);
336         }
337         return (LPSTR)lpszPath;
338 }
339
340 /*************************************************************************
341  * PathGetArgsW         [SHLWAPI.@]
342  */
343 LPWSTR WINAPI PathGetArgsW(LPCWSTR lpszPath) 
344 {
345         BOOL    qflag = FALSE;
346
347         TRACE("%s\n",debugstr_w(lpszPath));
348
349         while (*lpszPath) 
350         {
351           if ((*lpszPath==' ') && !qflag)
352             return (LPWSTR)lpszPath+1;
353           if (*lpszPath=='"')
354             qflag=!qflag;
355           lpszPath = CharNextW(lpszPath);
356         }
357         return (LPWSTR)lpszPath;
358 }
359
360 /*************************************************************************
361  * PathGetDriveNumberA  [SHLWAPI.@]
362  */
363 int WINAPI PathGetDriveNumberA(LPCSTR lpszPath)
364 {
365         int chr = tolower(lpszPath[0]);
366         
367         TRACE ("%s\n",debugstr_a(lpszPath));
368
369         if (!lpszPath || lpszPath[1]!=':' || chr < 'a' || chr > 'z') return -1;
370         return tolower(lpszPath[0]) - 'a' ;
371 }
372
373 /*************************************************************************
374  * PathGetDriveNumberW  [SHLWAPI.@]
375  */
376 int WINAPI PathGetDriveNumberW(LPCWSTR lpszPath)
377 {
378         int chr = tolowerW(lpszPath[0]);
379         
380         TRACE ("%s\n",debugstr_w(lpszPath));
381
382         if (!lpszPath || lpszPath[1]!=':' || chr < 'a' || chr > 'z') return -1;
383         return tolowerW(lpszPath[0]) - 'a' ;
384 }
385
386 /*************************************************************************
387  * PathRemoveFileSpecA  [SHLWAPI.@]
388  * 
389  * NOTES
390  *     truncates passed argument to a valid path
391  *     returns if the string was modified or not.
392  *     "\foo\xx\foo"-> "\foo\xx"
393  *     "\" -> "\"
394  *     "a:\foo" -> "a:\"
395  */
396 BOOL WINAPI PathRemoveFileSpecA(LPSTR lpszPath)
397 {
398         LPSTR cutplace = lpszPath;
399         BOOL ret = FALSE;
400         
401         TRACE("%s\n",lpszPath);
402
403         if(lpszPath)
404         {
405           while (*lpszPath == '\\') cutplace = ++lpszPath;
406           
407           while (*lpszPath)
408           {
409             if(lpszPath[0] == '\\') cutplace = lpszPath;
410           
411             if(lpszPath[0] == ':')
412             {
413               cutplace = lpszPath + 1;
414               if (lpszPath[1] == '\\') cutplace++;
415               lpszPath++;
416             }
417             lpszPath = CharNextA(lpszPath);
418             if (!lpszPath) break;
419           }
420           
421           ret = (*cutplace!='\0');
422           *cutplace = '\0';
423         }
424         return ret;
425 }
426
427 /*************************************************************************
428  * PathRemoveFileSpecW  [SHLWAPI.@]
429  */
430 BOOL WINAPI PathRemoveFileSpecW(LPWSTR lpszPath)
431 {
432         LPWSTR cutplace = lpszPath;
433         BOOL ret = FALSE;
434
435         TRACE("%s\n",debugstr_w(lpszPath));
436
437         if(lpszPath)
438         {
439           while (*lpszPath == '\\') cutplace = ++lpszPath;
440           
441           while (*lpszPath)
442           {
443             if(lpszPath[0] == '\\') cutplace = lpszPath;
444           
445             if(lpszPath[0] == ':')
446             {
447               cutplace = lpszPath + 1;
448               if (lpszPath[1] == '\\') cutplace++;
449               lpszPath++;
450             }
451             lpszPath = CharNextW(lpszPath);
452             if (!lpszPath) break;
453           }
454           
455           ret = (*cutplace!='\0');
456           *cutplace = '\0';
457         }
458         return ret;
459 }
460
461 /*************************************************************************
462  * PathStripPathA       [SHLWAPI.@]
463  * 
464  * NOTES
465  *  removes the path from the beginning of a filename
466  */
467 void WINAPI PathStripPathA(LPSTR lpszPath)
468 {
469         LPSTR lpszFileName = PathFindFileNameA(lpszPath);
470
471         TRACE("%s\n", lpszPath);
472
473         if(lpszFileName)
474           RtlMoveMemory(lpszPath, lpszFileName, strlen(lpszFileName)+1); 
475 }
476
477 /*************************************************************************
478  * PathStripPathW       [SHLWAPI.@]
479  */
480 void WINAPI PathStripPathW(LPWSTR lpszPath)
481 {
482         LPWSTR lpszFileName = PathFindFileNameW(lpszPath);
483
484         TRACE("%s\n", debugstr_w(lpszPath));
485         if(lpszFileName)
486           RtlMoveMemory(lpszPath, lpszFileName, (strlenW(lpszFileName)+1)*sizeof(WCHAR)); 
487 }
488
489 /*************************************************************************
490  * PathStripToRootA     [SHLWAPI.@]
491  */
492 BOOL WINAPI PathStripToRootA(LPSTR lpszPath)
493 {
494         TRACE("%s\n", lpszPath);
495
496         if (!lpszPath) return FALSE;
497         while(!PathIsRootA(lpszPath))
498           if (!PathRemoveFileSpecA(lpszPath)) return FALSE;
499         return TRUE;
500 }
501
502 /*************************************************************************
503  * PathStripToRootW     [SHLWAPI.@]
504  */
505 BOOL WINAPI PathStripToRootW(LPWSTR lpszPath)
506 {
507         TRACE("%s\n", debugstr_w(lpszPath));
508
509         if (!lpszPath) return FALSE;
510         while(!PathIsRootW(lpszPath))
511           if (!PathRemoveFileSpecW(lpszPath)) return FALSE;
512         return TRUE;
513 }
514
515 /*************************************************************************
516  * PathRemoveArgsA      [SHLWAPI.@]
517  *
518  */
519 void WINAPI PathRemoveArgsA(LPSTR lpszPath)
520 {
521         TRACE("%s\n",lpszPath);
522         
523         if(lpszPath)
524         {
525           LPSTR lpszArgs = PathGetArgsA(lpszPath);
526           if (!*lpszArgs)
527           {
528             LPSTR lpszLastChar = CharPrevA(lpszPath, lpszArgs);
529             if(*lpszLastChar==' ') *lpszLastChar = '\0';
530           }
531         }
532 }
533
534 /*************************************************************************
535  * PathRemoveArgsW      [SHLWAPI.@]
536  */
537 void WINAPI PathRemoveArgsW(LPWSTR lpszPath)
538 {
539         TRACE("%s\n", debugstr_w(lpszPath));
540
541         if(lpszPath)
542         {
543           LPWSTR lpszArgs = PathGetArgsW(lpszPath);
544           if (!*lpszArgs)
545           {
546             LPWSTR lpszLastChar = CharPrevW(lpszPath, lpszArgs);
547             if(*lpszLastChar==' ') *lpszLastChar = '\0';
548           }
549         }
550 }
551
552 /*************************************************************************
553  * PathRemoveExtensionA         [SHLWAPI.@]
554  */
555 void WINAPI PathRemoveExtensionA(LPSTR lpszPath)
556 {
557         LPSTR lpszExtension = PathFindExtensionA(lpszPath);
558
559         TRACE("%s\n", lpszPath);
560
561         if (lpszExtension) *lpszExtension='\0';
562 }
563
564 /*************************************************************************
565  * PathRemoveExtensionW         [SHLWAPI.@]
566  */
567 void WINAPI PathRemoveExtensionW(LPWSTR lpszPath)
568 {
569         LPWSTR lpszExtension = PathFindExtensionW(lpszPath);
570
571         TRACE("%s\n", debugstr_w(lpszPath));
572
573         if (lpszExtension) *lpszExtension='\0';
574 }
575
576 /*************************************************************************
577  * PathRemoveBackslashA [SHLWAPI.@]
578  *
579  * If the path ends in a backslash it is replaced by a NULL
580  * and the address of the NULL is returned
581  * Otherwise 
582  * the address of the last character is returned.
583  *
584  * FIXME
585  *  "c:\": keep backslash
586  */
587 LPSTR WINAPI PathRemoveBackslashA( LPSTR lpszPath )
588 {
589         int len;
590         LPSTR szTemp = NULL;
591         
592         if(lpszPath)
593         {
594           len = strlen(lpszPath);
595           szTemp = CharPrevA(lpszPath, lpszPath+len);
596           if (! PathIsRootA(lpszPath))
597           {
598             if (*szTemp == '\\') *szTemp = '\0';
599           }
600         }
601         return szTemp;
602 }
603
604 /*************************************************************************
605  * PathRemoveBackslashW [SHLWAPI.@]
606  */
607 LPWSTR WINAPI PathRemoveBackslashW( LPWSTR lpszPath )
608 {
609         int len;
610         LPWSTR szTemp = NULL;
611         
612         if(lpszPath)
613         {
614           len = strlenW(lpszPath);
615           szTemp = CharPrevW(lpszPath, lpszPath+len);
616           if (! PathIsRootW(lpszPath))
617           {
618             if (*szTemp == '\\') *szTemp = '\0';
619           }
620         }
621         return szTemp;
622 }
623
624
625 /*
626         Path Manipulations
627 */
628
629 /*************************************************************************
630  * PathRemoveBlanksA [SHLWAPI.@]
631  * 
632  * NOTES
633  *     remove spaces from beginning and end of passed string
634  */
635 void WINAPI PathRemoveBlanksA(LPSTR str)
636 {
637         LPSTR x = str;
638
639         TRACE("%s\n",str);
640
641         if(str)
642         {
643           while (*x==' ') x = CharNextA(x);
644           if (x!=str) strcpy(str,x);
645           x=str+strlen(str)-1;
646           while (*x==' ') x = CharPrevA(str, x);
647           if (*x==' ') *x='\0';
648         }
649 }
650
651 /*************************************************************************
652  * PathRemoveBlanksW [SHLWAPI.@]
653  */
654 void WINAPI PathRemoveBlanksW(LPWSTR str)
655 {
656         LPWSTR x = str;
657
658         TRACE("%s\n",debugstr_w(str));
659
660         if(str)
661         {
662           while (*x==' ') x = CharNextW(x);
663           if (x!=str) strcpyW(str,x);
664           x=str+strlenW(str)-1;
665           while (*x==' ') x = CharPrevW(str, x);
666           if (*x==' ') *x='\0';
667         }
668 }
669
670 /*************************************************************************
671  * PathQuoteSpacesA [SHLWAPI.@]
672  * 
673  */
674 LPSTR WINAPI PathQuoteSpacesA(LPSTR lpszPath)
675 {
676         TRACE("%s\n",lpszPath);
677
678         if(StrChrA(lpszPath,' '))
679         {
680           int len = strlen(lpszPath);
681           RtlMoveMemory(lpszPath+1, lpszPath, len);
682           *(lpszPath++) = '"';
683           lpszPath += len;
684           *(lpszPath++) = '"';
685           *(lpszPath) = '\0';
686           return --lpszPath;
687         }
688         return 0;
689 }
690
691 /*************************************************************************
692  * PathQuoteSpacesW [SHLWAPI.@]
693  */
694 LPWSTR WINAPI PathQuoteSpacesW(LPWSTR lpszPath)
695 {
696         TRACE("%s\n",debugstr_w(lpszPath));
697
698         if(StrChrW(lpszPath,' '))
699         {
700           int len = strlenW(lpszPath);
701           RtlMoveMemory(lpszPath+1, lpszPath, len*sizeof(WCHAR));
702           *(lpszPath++) = '"';
703           lpszPath += len;
704           *(lpszPath++) = '"';
705           *(lpszPath) = '\0';
706           return --lpszPath;
707         }
708         return 0;
709 }
710
711 /*************************************************************************
712  * PathUnquoteSpacesA [SHLWAPI.@]
713  * 
714  * NOTES
715  *     unquote string (remove ")
716  */
717 VOID WINAPI PathUnquoteSpacesA(LPSTR str) 
718 {
719         DWORD len = strlen(str);
720
721         TRACE("%s\n",str);
722
723         if (*str!='"')
724           return;
725         if (str[len-1]!='"')
726           return;
727         str[len-1]='\0';
728         strcpy(str,str+1);
729         return;
730 }
731
732 /*************************************************************************
733  * PathUnquoteSpacesW [SHLWAPI.@]
734  */
735 VOID WINAPI PathUnquoteSpacesW(LPWSTR str) 
736 {
737         DWORD len = strlenW(str);
738
739         TRACE("%s\n",debugstr_w(str));
740
741         if (*str!='"')
742           return;
743         if (str[len-1]!='"')
744           return;
745         str[len-1]='\0';
746         strcpyW(str,str+1);
747         return;
748 }
749
750 /*************************************************************************
751  * PathParseIconLocationA       [SHLWAPI.@]
752  */
753 int WINAPI PathParseIconLocationA(LPSTR lpszPath)
754 {
755         LPSTR lpstrComma = strchr(lpszPath, ',');
756         int ret = 0;
757         
758         TRACE("%s\n", debugstr_a(lpszPath));
759
760         if (lpstrComma && lpstrComma[1])
761         {
762           lpstrComma[0]='\0';
763           ret = atoi(&lpstrComma[1]);
764         }
765         
766         PathUnquoteSpacesA(lpszPath);
767         return ret;
768 }
769
770 /*************************************************************************
771  * PathParseIconLocationW       [SHLWAPI.@]
772  */
773 int WINAPI PathParseIconLocationW(LPWSTR lpszPath)
774 {
775         LPWSTR lpstrComma = strchrW(lpszPath, ',');
776         int ret = 0;
777         
778         TRACE("%s\n", debugstr_w(lpszPath));
779
780         if (lpstrComma && lpstrComma[1])
781         {
782           lpstrComma[0]='\0';
783           ret = _wtoi(&lpstrComma[1]);
784         }
785         PathUnquoteSpacesW(lpszPath);
786         return ret;
787 }
788
789 /*
790         ########## cleaning and resolving paths ##########
791  */
792
793 /*************************************************************************
794  * PathFindOnPathA      [SHLWAPI.@]
795  */
796 BOOL WINAPI PathFindOnPathA(LPSTR sFile, LPCSTR *sOtherDirs)
797 {
798         FIXME("%s %p\n",sFile, sOtherDirs);
799         return FALSE;
800 }
801
802 /*************************************************************************
803  * PathFindOnPathW      [SHLWAPI.@]
804  */
805 BOOL WINAPI PathFindOnPathW(LPWSTR sFile, LPCWSTR *sOtherDirs)
806 {
807         FIXME("%s %p\n",debugstr_w(sFile), sOtherDirs);
808         return FALSE;
809 }
810
811 /*************************************************************************
812  *      PathCompactPathExA   [SHLWAPI.@]
813  */
814 BOOL WINAPI PathCompactPathExA(
815         LPSTR pszOut,
816         LPCSTR pszSrc,
817         UINT cchMax,
818         DWORD dwFlags)
819 {
820         FIXME("%p %s 0x%08x 0x%08lx\n", pszOut, pszSrc, cchMax, dwFlags);
821         return FALSE;
822 }
823
824 /*************************************************************************
825  *      PathCompactPathExW   [SHLWAPI.@]
826  */
827 BOOL WINAPI PathCompactPathExW(
828         LPWSTR pszOut,
829         LPCWSTR pszSrc,
830         UINT cchMax,
831         DWORD dwFlags)
832 {
833         FIXME("%p %s 0x%08x 0x%08lx\n", pszOut, debugstr_w(pszSrc), cchMax, dwFlags);
834         return FALSE;
835 }
836
837 /*
838         ########## Path Testing ##########
839 */
840
841 /*************************************************************************
842  * PathIsUNCA           [SHLWAPI.@]
843  * 
844  * NOTES
845  *     PathIsUNC(char*path);
846  */
847 BOOL WINAPI PathIsUNCA(LPCSTR lpszPath) 
848 {
849         TRACE("%s\n",lpszPath);
850
851         return (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\'));
852 }
853
854 /*************************************************************************
855  * PathIsUNCW           [SHLWAPI.@]
856  */
857 BOOL WINAPI PathIsUNCW(LPCWSTR lpszPath) 
858 {
859         TRACE("%s\n",debugstr_w(lpszPath));
860
861         return (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\'));
862 }
863
864 /*************************************************************************
865  *  PathIsRelativeA     [SHLWAPI.@]
866  */
867 BOOL WINAPI PathIsRelativeA (LPCSTR lpszPath)
868 {
869         TRACE("lpszPath=%s\n",lpszPath);
870
871         return (lpszPath && (lpszPath[0]!='\\' && lpszPath[1]!=':'));
872 }
873
874 /*************************************************************************
875  *  PathIsRelativeW     [SHLWAPI.@]
876  */
877 BOOL WINAPI PathIsRelativeW (LPCWSTR lpszPath)
878 {
879         TRACE("lpszPath=%s\n",debugstr_w(lpszPath));
880
881         return (lpszPath && (lpszPath[0]!='\\' && lpszPath[1]!=':'));
882 }
883
884 /*************************************************************************
885  * PathIsRootA          [SHLWAPI.@]
886  *
887  * notes
888  *  TRUE if the path points to a root directory
889  */
890 BOOL WINAPI PathIsRootA(LPCSTR lpszPath)
891 {
892         TRACE("%s\n",lpszPath);
893
894         /* X:\ */
895         if (lpszPath[1]==':' && lpszPath[2]=='\\' && lpszPath[3]=='\0')
896           return TRUE;
897
898         /* "\" */
899         if (lpszPath[0]=='\\' && lpszPath[1]=='\0')
900           return TRUE;
901
902         /* UNC "\\<computer>\<share>" */
903         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
904         {
905           int foundbackslash = 0;
906           lpszPath += 2;
907           while (*lpszPath)
908           {
909             if (*lpszPath=='\\') foundbackslash++;
910             lpszPath = CharNextA(lpszPath);
911           }
912           if (foundbackslash <= 1)
913             return TRUE;
914         }
915         return FALSE;
916 }
917
918 /*************************************************************************
919  * PathIsRootW          [SHLWAPI.@]
920  */
921 BOOL WINAPI PathIsRootW(LPCWSTR lpszPath) 
922 {
923         TRACE("%s\n",debugstr_w(lpszPath));
924
925         /* X:\ */
926         if (lpszPath[1]==':' && lpszPath[2]=='\\' && lpszPath[3]=='\0')
927           return TRUE;
928
929         /* "\" */
930         if (lpszPath[0]=='\\' && lpszPath[1]=='\0')
931           return TRUE;
932
933         /* UNC "\\<computer>\<share>" */
934         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
935         {
936           int foundbackslash = 0;
937           lpszPath += 2;
938           while (*lpszPath)
939           {
940             if (*lpszPath=='\\') foundbackslash++;
941             lpszPath = CharNextW(lpszPath);
942           }
943           if (foundbackslash <= 1)
944             return TRUE;
945         }
946         return FALSE;
947
948 }
949
950 /*************************************************************************
951  * PathIsDirectoryA     [SHLWAPI.@]
952  */
953 BOOL WINAPI PathIsDirectoryA(LPCSTR lpszPath)
954 {
955         DWORD dwAttr;
956
957         TRACE("%s\n", debugstr_a(lpszPath));
958
959         dwAttr = GetFileAttributesA(lpszPath);
960         return  (dwAttr != -1) ? dwAttr & FILE_ATTRIBUTE_DIRECTORY : 0;
961 }
962
963 /*************************************************************************
964  * PathIsDirectoryW     [SHLWAPI.@]
965  */
966 BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
967 {
968         DWORD dwAttr;
969         
970         TRACE("%s\n", debugstr_w(lpszPath));
971
972         dwAttr = GetFileAttributesW(lpszPath);
973         return  (dwAttr != -1) ? dwAttr & FILE_ATTRIBUTE_DIRECTORY : 0;
974 }
975
976 /*************************************************************************
977  * PathFileExistsA      [SHLWAPI.@]
978  * 
979  * NOTES
980  *     file_exists(char *fn);
981  */
982 BOOL WINAPI PathFileExistsA(LPCSTR lpszPath) 
983 {
984         TRACE("%s\n",lpszPath);
985         return  (GetFileAttributesA(lpszPath)!=-1);
986 }
987
988 /*************************************************************************
989  * PathFileExistsW      [SHLWAPI.@]
990  */
991 BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath) 
992 {
993         TRACE("%s\n",debugstr_w(lpszPath));
994         return  (GetFileAttributesW(lpszPath)!=-1);
995 }
996
997 /*************************************************************************
998  * PathMatchSingleMaskA [internal]
999  * 
1000  * NOTES
1001  *     internal (used by PathMatchSpec)
1002  */
1003 static BOOL PathMatchSingleMaskA(LPCSTR name, LPCSTR mask)
1004 {
1005         while (*name && *mask && *mask!=';') 
1006         {
1007           if (*mask=='*') 
1008           {
1009             do 
1010             {
1011               if (PathMatchSingleMaskA(name,mask+1)) return 1;  /* try substrings */
1012             } while (*name++);
1013             return 0;
1014           }
1015           if (toupper(*mask)!=toupper(*name) && *mask!='?') return 0;
1016           name = CharNextA(name);
1017           mask = CharNextA(mask);
1018         }
1019         if (!*name) 
1020         {
1021           while (*mask=='*') mask++;
1022           if (!*mask || *mask==';') return 1;
1023         }
1024         return 0;
1025 }
1026
1027 /*************************************************************************
1028  * PathMatchSingleMaskW [internal]
1029  */
1030 static BOOL PathMatchSingleMaskW(LPCWSTR name, LPCWSTR mask)
1031 {
1032         while (*name && *mask && *mask!=';') 
1033         {
1034           if (*mask=='*') 
1035           {
1036             do 
1037             {
1038               if (PathMatchSingleMaskW(name,mask+1)) return 1;  /* try substrings */
1039             } while (*name++);
1040             return 0;
1041           }
1042           if (toupperW(*mask)!=toupperW(*name) && *mask!='?') return 0;
1043           name = CharNextW(name);
1044           mask = CharNextW(mask);
1045         }
1046         if (!*name) 
1047         {
1048           while (*mask=='*') mask++;
1049           if (!*mask || *mask==';') return 1;
1050         }
1051         return 0;
1052 }
1053 /*************************************************************************
1054  * PathMatchSpecA       [SHLWAPI.@]
1055  * 
1056  * NOTES
1057  *     used from COMDLG32
1058  */
1059 BOOL WINAPI PathMatchSpecA(LPCSTR name, LPCSTR mask) 
1060 {
1061         TRACE("%s %s\n",name,mask);
1062
1063         if (!lstrcmpA( mask, "*.*" )) return 1;   /* we don't require a period */
1064
1065         while (*mask) 
1066         {
1067           if (PathMatchSingleMaskA(name,mask)) return 1;    /* helper function */
1068           while (*mask && *mask!=';') mask = CharNextA(mask);
1069           if (*mask==';') 
1070           {
1071             mask++;
1072             while (*mask==' ') mask++;      /*  masks may be separated by "; " */
1073           }
1074         }
1075         return 0;
1076 }
1077
1078 /*************************************************************************
1079  * PathMatchSpecW       [SHLWAPI.@]
1080  */
1081 BOOL WINAPI PathMatchSpecW(LPCWSTR name, LPCWSTR mask) 
1082 {
1083     static const WCHAR stemp[] = { '*','.','*',0 };
1084         TRACE("%s %s\n",debugstr_w(name),debugstr_w(mask));
1085
1086         if (!lstrcmpW( mask, stemp )) return 1;   /* we don't require a period */
1087
1088         while (*mask) 
1089         {
1090           if (PathMatchSingleMaskW(name,mask)) return 1;    /* helper function */
1091           while (*mask && *mask!=';') mask = CharNextW(mask);
1092           if (*mask==';') 
1093           {
1094             mask++;
1095             while (*mask==' ') mask++;       /* masks may be separated by "; " */
1096           }
1097         }
1098         return 0;
1099 }
1100
1101 /*************************************************************************
1102  * PathIsSameRootA      [SHLWAPI.@]
1103  *
1104  * FIXME
1105  *  what to do with "\path" ??
1106  */
1107 BOOL WINAPI PathIsSameRootA(LPCSTR lpszPath1, LPCSTR lpszPath2)
1108 {
1109         TRACE("%s %s\n", lpszPath1, lpszPath2);
1110         
1111         if (PathIsRelativeA(lpszPath1) || PathIsRelativeA(lpszPath2)) return FALSE;
1112
1113         /* usual path */
1114         if ( toupper(lpszPath1[0])==toupper(lpszPath2[0]) &&
1115              lpszPath1[1]==':' && lpszPath2[1]==':' &&
1116              lpszPath1[2]=='\\' && lpszPath2[2]=='\\')
1117           return TRUE;
1118
1119         /* UNC */
1120         if (lpszPath1[0]=='\\' && lpszPath2[0]=='\\' &&
1121             lpszPath1[1]=='\\' && lpszPath2[1]=='\\')
1122         {
1123           int pos=2, bsfound=0;
1124           while (lpszPath1[pos] && lpszPath2[pos] &&
1125                 (lpszPath1[pos] == lpszPath2[pos]))
1126           {
1127             if (lpszPath1[pos]=='\\') bsfound++;
1128             if (bsfound == 2) return TRUE;
1129             pos++; /* FIXME: use CharNext*/
1130           }
1131           return (lpszPath1[pos] == lpszPath2[pos]);
1132         }
1133         return FALSE;
1134 }
1135
1136 /*************************************************************************
1137  * PathIsSameRootW      [SHLWAPI.@]
1138  */
1139 BOOL WINAPI PathIsSameRootW(LPCWSTR lpszPath1, LPCWSTR lpszPath2)
1140 {
1141         TRACE("%s %s\n", debugstr_w(lpszPath1), debugstr_w(lpszPath2));
1142         
1143         if (PathIsRelativeW(lpszPath1) || PathIsRelativeW(lpszPath2)) return FALSE;
1144
1145         /* usual path */
1146         if ( toupperW(lpszPath1[0])==toupperW(lpszPath2[0]) &&
1147              lpszPath1[1]==':' && lpszPath2[1]==':' &&
1148              lpszPath1[2]=='\\' && lpszPath2[2]=='\\')
1149           return TRUE;
1150
1151         /* UNC */
1152         if (lpszPath1[0]=='\\' && lpszPath2[0]=='\\' &&
1153             lpszPath1[1]=='\\' && lpszPath2[1]=='\\')
1154         {
1155           int pos=2, bsfound=0;
1156           while (lpszPath1[pos] && lpszPath2[pos] &&
1157                 (lpszPath1[pos] == lpszPath2[pos]))
1158           {
1159             if (lpszPath1[pos]=='\\') bsfound++;
1160             if (bsfound == 2) return TRUE;
1161             pos++;/* FIXME: use CharNext*/
1162           }
1163           return (lpszPath1[pos] == lpszPath2[pos]);
1164         }
1165         return FALSE;
1166 }
1167
1168 /*************************************************************************
1169  * PathIsURLA (SHLWAPI.@)
1170  */
1171 BOOL WINAPI PathIsURLA(LPCSTR lpstrPath)
1172 {
1173     UNKNOWN_SHLWAPI_1 base;
1174     DWORD res1;
1175
1176     if (!lpstrPath || !*lpstrPath) return FALSE;
1177
1178     /* get protocol        */
1179     base.size = 24;
1180     res1 = SHLWAPI_1(lpstrPath, &base);
1181     return (base.fcncde) ? TRUE : FALSE;
1182 }  
1183
1184 /*************************************************************************
1185  * PathIsURLW (SHLWAPI.@)
1186  */
1187 BOOL WINAPI PathIsURLW(LPCWSTR lpstrPath)
1188 {
1189     UNKNOWN_SHLWAPI_2 base;
1190     DWORD res1;
1191
1192     if (!lpstrPath || !*lpstrPath) return FALSE;
1193
1194     /* get protocol        */
1195     base.size = 24;
1196     res1 = SHLWAPI_2(lpstrPath, &base);
1197     return (base.fcncde) ? TRUE : FALSE;
1198 }  
1199
1200
1201 /*************************************************************************
1202  *      PathIsContentTypeA   [SHLWAPI.@]
1203  */
1204 BOOL WINAPI PathIsContentTypeA(LPCSTR pszPath, LPCSTR pszContentType)
1205 {
1206         FIXME("%s %s\n", pszPath, pszContentType);
1207         return FALSE;
1208 }
1209
1210 /*************************************************************************
1211  *      PathIsContentTypeW   [SHLWAPI.@]
1212  */
1213 BOOL WINAPI PathIsContentTypeW(LPCWSTR pszPath, LPCWSTR pszContentType)
1214 {
1215         FIXME("%s %s\n", debugstr_w(pszPath), debugstr_w(pszContentType));
1216         return FALSE;
1217 }
1218
1219 /*************************************************************************
1220  *      PathIsFileSpecA   [SHLWAPI.@]
1221  */
1222 BOOL WINAPI PathIsFileSpecA(LPCSTR pszPath)
1223 {
1224         FIXME("%s\n", pszPath);
1225         return FALSE;
1226 }
1227
1228 /*************************************************************************
1229  *      PathIsFileSpecW   [SHLWAPI.@]
1230  */
1231 BOOL WINAPI PathIsFileSpecW(LPCWSTR pszPath)
1232 {
1233         FIXME("%s\n", debugstr_w(pszPath));
1234         return FALSE;
1235 }
1236
1237 /*************************************************************************
1238  *      PathIsPrefixA   [SHLWAPI.@]
1239  */
1240 BOOL WINAPI PathIsPrefixA(LPCSTR pszPrefix, LPCSTR pszPath)
1241 {
1242         FIXME("%s %s\n", pszPrefix, pszPath);
1243         return FALSE;
1244 }
1245
1246 /*************************************************************************
1247  *      PathIsPrefixW   [SHLWAPI.@]
1248  */
1249 BOOL WINAPI PathIsPrefixW(LPCWSTR pszPrefix, LPCWSTR pszPath)
1250 {
1251         FIXME("%s %s\n", debugstr_w(pszPrefix), debugstr_w(pszPath));
1252         return FALSE;
1253 }
1254
1255 /*************************************************************************
1256  *      PathIsSystemFolderA   [SHLWAPI.@]
1257  */
1258 BOOL WINAPI PathIsSystemFolderA(LPCSTR pszPath, DWORD dwAttrb)
1259 {
1260         FIXME("%s 0x%08lx\n", pszPath, dwAttrb);
1261         return FALSE;
1262 }
1263
1264 /*************************************************************************
1265  *      PathIsSystemFolderW   [SHLWAPI.@]
1266  */
1267 BOOL WINAPI PathIsSystemFolderW(LPCWSTR pszPath, DWORD dwAttrb)
1268 {
1269         FIXME("%s 0x%08lx\n", debugstr_w(pszPath), dwAttrb);
1270         return FALSE;
1271 }
1272
1273 /*************************************************************************
1274  *      PathIsUNCServerA   [SHLWAPI.@]
1275  */
1276 BOOL WINAPI PathIsUNCServerA(
1277         LPCSTR lpszPath)
1278 {
1279         TRACE("%s\n", debugstr_a(lpszPath));
1280         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
1281         {
1282           int foundbackslash = 0;
1283           lpszPath += 2;
1284           while (*lpszPath)
1285           {
1286             if (*lpszPath=='\\') foundbackslash++;
1287             lpszPath = CharNextA(lpszPath);
1288           }
1289           if (foundbackslash == 0)
1290             return TRUE;
1291         }
1292         return FALSE;
1293 }
1294
1295 /*************************************************************************
1296  *      PathIsUNCServerW   [SHLWAPI.@]
1297  */
1298 BOOL WINAPI PathIsUNCServerW(
1299         LPCWSTR lpszPath)
1300 {
1301         TRACE("%s\n", debugstr_w(lpszPath));
1302         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
1303         {
1304           int foundbackslash = 0;
1305           lpszPath += 2;
1306           while (*lpszPath)
1307           {
1308             if (*lpszPath=='\\') foundbackslash++;
1309             lpszPath = CharNextW(lpszPath);
1310           }
1311           if (foundbackslash == 0)
1312             return TRUE;
1313         }
1314         return FALSE;
1315 }
1316
1317 /*************************************************************************
1318  *      PathIsUNCServerShareA   [SHLWAPI.@]
1319  */
1320 BOOL WINAPI PathIsUNCServerShareA(
1321         LPCSTR lpszPath)
1322 {
1323         TRACE("%s\n", debugstr_a(lpszPath));
1324         if (!lpszPath) return FALSE;
1325         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
1326         {
1327           int foundbackslash = 0;
1328           lpszPath += 2;
1329           while (*lpszPath)
1330           {
1331             if (*lpszPath=='\\') foundbackslash++;
1332             lpszPath = CharNextA(lpszPath);
1333           }
1334           if (foundbackslash == 1)
1335             return TRUE;
1336         }
1337         return FALSE;
1338 }
1339
1340 /*************************************************************************
1341  *      PathIsUNCServerShareW   [SHLWAPI.@]
1342  */
1343 BOOL WINAPI PathIsUNCServerShareW(
1344         LPCWSTR lpszPath)
1345 {
1346         TRACE("%s\n", debugstr_w(lpszPath));
1347         if (!lpszPath) return FALSE;
1348         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
1349         {
1350           int foundbackslash = 0;
1351           lpszPath += 2;
1352           while (*lpszPath)
1353           {
1354             if (*lpszPath=='\\') foundbackslash++;
1355             lpszPath = CharNextW(lpszPath);
1356           }
1357           if (foundbackslash == 1)
1358             return TRUE;
1359         }
1360         return FALSE;
1361 }
1362
1363 /*************************************************************************
1364  * PathCanonicalizeA   [SHLWAPI.@]
1365  *
1366  *  FIXME
1367  *   returnvalue, use CharNext
1368  */
1369  
1370 BOOL WINAPI PathCanonicalizeA(LPSTR pszBuf, LPCSTR pszPath)
1371 {
1372         int OffsetMin = 0, OffsetSrc = 0, OffsetDst = 0, LenSrc = strlen(pszPath);
1373         BOOL bModifyed = FALSE;
1374
1375         TRACE("%p %s\n", pszBuf, pszPath);
1376         
1377         pszBuf[OffsetDst]='\0';
1378
1379         /* keep the root of the path */
1380         if( LenSrc && (pszPath[OffsetSrc]=='\\'))
1381         {
1382           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1383         }
1384         else if ( (LenSrc >= 2) && (pszPath[OffsetSrc+1] == ':'))
1385         {
1386           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1387           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1388           if (LenSrc && (pszPath[OffsetSrc] == '\\'))
1389           {
1390             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1391             if (LenSrc == 1 && pszPath[OffsetSrc]=='.')
1392             {
1393               /* C:\. */
1394               OffsetSrc++; LenSrc--; bModifyed = TRUE;
1395             } 
1396             else if (LenSrc == 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='.')
1397             {
1398               /* C:\.. */
1399               OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
1400             } 
1401           }
1402         }
1403         
1404         /* ".\" at the beginning of the path */
1405         if (LenSrc >= 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='\\')
1406         {
1407           OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
1408         } 
1409         
1410         while ( LenSrc )
1411         {
1412           if((LenSrc>=3) && (pszPath[OffsetSrc]=='\\') && (pszPath[OffsetSrc+1]=='.') && (pszPath[OffsetSrc+2]=='.'))
1413           {
1414             /* "\.." found, go one deeper */
1415             while((OffsetDst > OffsetMin) && (pszBuf[OffsetDst]!='\\')) OffsetDst--;
1416             OffsetSrc += 3; LenSrc -= 3; bModifyed = TRUE;
1417             if(OffsetDst == OffsetMin && pszPath[OffsetSrc]=='\\') OffsetSrc++;
1418             pszBuf[OffsetDst] = '\0';                   /* important for \..\.. */
1419           }
1420           else if(LenSrc>=2 && pszPath[OffsetSrc]=='\\' && pszPath[OffsetSrc+1]=='.' )
1421           {
1422             /* "\." found, skip it */
1423             OffsetSrc += 2; LenSrc-=2; bModifyed = TRUE;
1424           }
1425           else
1426           {
1427             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; LenSrc--;
1428           }
1429         }
1430         pszBuf[OffsetDst] = '\0';
1431         TRACE("-- %s %u\n", pszBuf, bModifyed);
1432         return bModifyed;
1433 }
1434
1435
1436 /*************************************************************************
1437  * PathCanonicalizeW   [SHLWAPI.@]
1438  *
1439  *  FIXME
1440  *   returnvalue, use CharNext
1441  */
1442 BOOL WINAPI PathCanonicalizeW(LPWSTR pszBuf, LPCWSTR pszPath)
1443 {
1444         int OffsetMin = 0, OffsetSrc = 0, OffsetDst = 0, LenSrc = strlenW(pszPath);
1445         BOOL bModifyed = FALSE;
1446
1447         TRACE("%p %s\n", pszBuf, debugstr_w(pszPath));
1448         
1449         pszBuf[OffsetDst]='\0';
1450
1451         /* keep the root of the path */
1452         if( LenSrc && (pszPath[OffsetSrc]=='\\'))
1453         {
1454           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1455         }
1456         else if ( (LenSrc >= 2) && (pszPath[OffsetSrc+1] == ':'))
1457         {
1458           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1459           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1460           if (LenSrc && (pszPath[OffsetSrc] == '\\'))
1461           {
1462             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1463             if (LenSrc == 1 && pszPath[OffsetSrc]=='.')
1464             {
1465               /* C:\. */
1466               OffsetSrc++; LenSrc--; bModifyed = TRUE;
1467             } 
1468             else if (LenSrc == 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='.')
1469             {
1470               /* C:\.. */
1471               OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
1472             } 
1473           }
1474         }
1475         
1476         /* ".\" at the beginning of the path */
1477         if (LenSrc >= 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='\\')
1478         {
1479           OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
1480         } 
1481         
1482         while ( LenSrc )
1483         {
1484           if((LenSrc>=3) && (pszPath[OffsetSrc]=='\\') && (pszPath[OffsetSrc+1]=='.') && (pszPath[OffsetSrc+2]=='.'))
1485           {
1486             /* "\.." found, go one deeper */
1487             while((OffsetDst > OffsetMin) && (pszBuf[OffsetDst]!='\\')) OffsetDst--;
1488             OffsetSrc += 3; LenSrc -= 3; bModifyed = TRUE;
1489             if(OffsetDst == OffsetMin && pszPath[OffsetSrc]=='\\') OffsetSrc++;
1490             pszBuf[OffsetDst] = '\0';                   /* important for \..\.. */
1491           }
1492           else if(LenSrc>=2 && pszPath[OffsetSrc]=='\\' && pszPath[OffsetSrc+1]=='.' )
1493           {
1494             /* "\." found, skip it */
1495             OffsetSrc += 2; LenSrc-=2; bModifyed = TRUE;
1496           }
1497           else
1498           {
1499             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; LenSrc--;
1500           }
1501         }
1502         pszBuf[OffsetDst] = '\0';
1503         TRACE("-- %s %u\n", debugstr_w(pszBuf), bModifyed);
1504         return bModifyed;
1505 }
1506
1507 /*************************************************************************
1508  * PathFindNextComponentA   [SHLWAPI.@]
1509  *
1510  * NOTES
1511  * special cases:
1512  *      ""              null
1513  *      aa              "" (pointer to traling NULL)
1514  *      aa\             "" (pointer to traling NULL)
1515  *      aa\\            "" (pointer to traling NULL)
1516  *      aa\\bb          bb
1517  *      aa\\\bb         \bb
1518  *      c:\aa\          "aa\"
1519  *      \\aa            aa
1520  *      \\aa\b          aa\b
1521 */
1522 LPSTR WINAPI PathFindNextComponentA(LPCSTR pszPath)
1523 {
1524         LPSTR pos;
1525
1526         TRACE("%s\n", pszPath);
1527
1528         if(!pszPath || !*pszPath) return NULL;
1529         if(!(pos = StrChrA(pszPath, '\\')))
1530           return (LPSTR) pszPath + strlen(pszPath);
1531         pos++;
1532         if(pos[0] == '\\') pos++;
1533         return pos;
1534 }
1535
1536 /*************************************************************************
1537  * PathFindNextComponentW   [SHLWAPI.@]
1538  */
1539 LPWSTR WINAPI PathFindNextComponentW(LPCWSTR pszPath)
1540 {
1541         LPWSTR pos;
1542
1543         TRACE("%s\n", debugstr_w(pszPath));
1544         
1545         if(!pszPath || !*pszPath) return NULL;
1546         if (!(pos = StrChrW(pszPath, '\\')))
1547           return (LPWSTR) pszPath + strlenW(pszPath);
1548         pos++;
1549         if(pos[0] == '\\') pos++;
1550         return pos;
1551 }
1552
1553 /*************************************************************************
1554  * PathAddExtensionA   [SHLWAPI.@]
1555  *
1556  * NOTES
1557  *  it adds never a dot
1558  */
1559  
1560 BOOL WINAPI PathAddExtensionA(
1561         LPSTR  pszPath,
1562         LPCSTR pszExtension)
1563 {
1564         if (*pszPath)
1565         {
1566           if (*(PathFindExtensionA(pszPath))) return FALSE;
1567
1568           if (!pszExtension || *pszExtension=='\0')
1569             strcat(pszPath, "exe");
1570           else
1571             strcat(pszPath, pszExtension);
1572         }
1573
1574         return TRUE;
1575 }
1576
1577 /*************************************************************************
1578  *      PathAddExtensionW   [SHLWAPI.@]
1579  */
1580 BOOL WINAPI PathAddExtensionW(
1581         LPWSTR  pszPath,
1582         LPCWSTR pszExtension)
1583 {
1584         static const WCHAR ext[] = { 'e','x','e',0 };
1585
1586         if (*pszPath)
1587         {
1588           if (*(PathFindExtensionW(pszPath))) return FALSE;
1589
1590           if (!pszExtension || *pszExtension=='\0')
1591             strcatW(pszPath, ext);
1592           else
1593             strcatW(pszPath, pszExtension);
1594         }
1595         return TRUE;
1596
1597 }
1598
1599 /*************************************************************************
1600  *      PathMakePrettyA   [SHLWAPI.@]
1601  */
1602 BOOL WINAPI PathMakePrettyA(
1603         LPSTR lpPath)
1604 {
1605         FIXME("%s\n", lpPath);
1606         return TRUE;
1607 }
1608
1609 /*************************************************************************
1610  *      PathMakePrettyW   [SHLWAPI.@]
1611  */
1612 BOOL WINAPI PathMakePrettyW(
1613         LPWSTR lpPath)
1614 {
1615         FIXME("%s\n", debugstr_w(lpPath));
1616         return TRUE;
1617
1618 }
1619
1620 /*************************************************************************
1621  *      PathCommonPrefixA   [SHLWAPI.@]
1622  */
1623 int WINAPI PathCommonPrefixA(
1624         LPCSTR pszFile1,
1625         LPCSTR pszFile2,
1626         LPSTR achPath)
1627 {
1628         FIXME("%s %s %p\n", pszFile1, pszFile2, achPath);
1629         return 0;
1630 }
1631
1632 /*************************************************************************
1633  *      PathCommonPrefixW   [SHLWAPI.@]
1634  */
1635 int WINAPI PathCommonPrefixW(
1636         LPCWSTR pszFile1,
1637         LPCWSTR pszFile2,
1638         LPWSTR achPath)
1639 {
1640         FIXME("%s %s %p\n", debugstr_w(pszFile1), debugstr_w(pszFile2),achPath );
1641         return 0;
1642 }
1643
1644 /*************************************************************************
1645  *      PathCompactPathA   [SHLWAPI.@]
1646  */
1647 BOOL WINAPI PathCompactPathA(HDC hDC, LPSTR pszPath, UINT dx)
1648 {
1649         FIXME("0x%08x %s 0x%08x\n", hDC, pszPath, dx);
1650         return FALSE;
1651 }
1652
1653 /*************************************************************************
1654  *      PathCompactPathW   [SHLWAPI.@]
1655  */
1656 BOOL WINAPI PathCompactPathW(HDC hDC, LPWSTR pszPath, UINT dx)
1657 {
1658         FIXME("0x%08x %s 0x%08x\n", hDC, debugstr_w(pszPath), dx);
1659         return FALSE;
1660 }
1661
1662 /*************************************************************************
1663  *      PathGetCharTypeA   [SHLWAPI.@]
1664  */
1665 UINT WINAPI PathGetCharTypeA(UCHAR ch)
1666 {
1667         UINT flags = 0;
1668
1669         TRACE("%c\n", ch);
1670
1671         /* We could use them in filenames, but this would confuse 'ls' */
1672         if (iscntrl(ch))
1673             return GCT_INVALID;
1674         if ((ch == '*') || (ch=='?'))
1675             return GCT_WILD;
1676         if ((ch == '\\') || (ch=='/'))
1677             return GCT_SEPARATOR;
1678         flags = 0;
1679         /* all normal characters, no lower case letters */
1680         if ((ch > ' ') && (ch < 0x7f) && !islower(ch))
1681             flags |= GCT_SHORTCHAR;
1682         /* All other characters are valid in long filenames, even umlauts */
1683         return flags | GCT_LFNCHAR;
1684 }
1685
1686 /*************************************************************************
1687  *      PathGetCharTypeW   [SHLWAPI.@]
1688  */
1689 UINT WINAPI PathGetCharTypeW(WCHAR ch)
1690 {
1691         FIXME("%c, using ascii version\n", ch);
1692         return PathGetCharTypeA(ch);
1693 }
1694
1695 /*************************************************************************
1696  *      PathMakeSystemFolderA   [SHLWAPI.@]
1697  */
1698 BOOL WINAPI PathMakeSystemFolderA(LPCSTR pszPath)
1699 {
1700         FIXME("%s\n", pszPath);
1701         return FALSE;
1702 }
1703
1704 /*************************************************************************
1705  *      PathMakeSystemFolderW   [SHLWAPI.@]
1706  */
1707 BOOL WINAPI PathMakeSystemFolderW(LPCWSTR pszPath)
1708 {
1709         FIXME("%s\n", debugstr_w(pszPath));
1710         return FALSE;
1711 }
1712
1713 /*************************************************************************
1714  *      PathRenameExtensionA   [SHLWAPI.@]
1715  */
1716 BOOL WINAPI PathRenameExtensionA(LPSTR pszPath, LPCSTR pszExt)
1717 {
1718         LPSTR pszExtension = PathFindExtensionA(pszPath);
1719
1720         if (!pszExtension) return FALSE;
1721         if (pszExtension-pszPath + strlen(pszExt) > MAX_PATH) return FALSE;
1722
1723         strcpy(pszExtension, pszExt);
1724         TRACE("%s\n", pszPath);
1725         return TRUE;
1726 }
1727
1728 /*************************************************************************
1729  *      PathRenameExtensionW   [SHLWAPI.@]
1730  */
1731 BOOL WINAPI PathRenameExtensionW(LPWSTR pszPath, LPCWSTR pszExt)
1732 {
1733         LPWSTR pszExtension = PathFindExtensionW(pszPath);
1734
1735         if (!pszExtension) return FALSE;
1736         if (pszExtension-pszPath + strlenW(pszExt) > MAX_PATH) return FALSE;
1737
1738         strcpyW(pszExtension, pszExt);
1739         TRACE("%s\n", debugstr_w(pszPath));
1740         return TRUE;
1741 }
1742
1743 /*************************************************************************
1744  *      PathSearchAndQualifyA   [SHLWAPI.@]
1745  */
1746 BOOL WINAPI PathSearchAndQualifyA(
1747         LPCSTR pszPath,
1748         LPSTR pszBuf,
1749         UINT cchBuf)
1750 {
1751         FIXME("%s %s 0x%08x\n", pszPath, pszBuf, cchBuf);
1752         return FALSE;
1753 }
1754
1755 /*************************************************************************
1756  *      PathSearchAndQualifyW   [SHLWAPI.@]
1757  */
1758 BOOL WINAPI PathSearchAndQualifyW(
1759         LPCWSTR pszPath,
1760         LPWSTR pszBuf,
1761         UINT cchBuf)
1762 {
1763         FIXME("%s %s 0x%08x\n", debugstr_w(pszPath), debugstr_w(pszBuf), cchBuf);
1764         return FALSE;
1765 }
1766
1767 /*************************************************************************
1768  *      PathSkipRootA   [SHLWAPI.@]
1769  */
1770 LPSTR WINAPI PathSkipRootA(LPCSTR pszPath)
1771 {
1772         FIXME("%s\n", pszPath);
1773         return (LPSTR)pszPath;
1774 }
1775
1776 /*************************************************************************
1777  *      PathSkipRootW   [SHLWAPI.@]
1778  */
1779 LPWSTR WINAPI PathSkipRootW(LPCWSTR pszPath)
1780 {
1781         FIXME("%s\n", debugstr_w(pszPath));
1782         return (LPWSTR)pszPath;
1783 }
1784
1785 /*************************************************************************
1786  *      PathCreateFromUrlA   [SHLWAPI.@]
1787  */
1788 HRESULT WINAPI PathCreateFromUrlA(
1789         LPCSTR pszUrl,
1790         LPSTR pszPath,
1791         LPDWORD pcchPath,
1792         DWORD dwFlags)
1793 {
1794     /* extracts thing prior to : in pszURL and checks against:
1795      *   https
1796      *   shell
1797      *   local
1798      *   about  - if match returns E_INVALIDARG
1799      */
1800         FIXME("%s %p %p 0x%08lx\n",
1801           pszUrl, pszPath, pcchPath, dwFlags);
1802         return E_INVALIDARG;
1803 }
1804
1805 /*************************************************************************
1806  *      PathCreateFromUrlW   [SHLWAPI.@]
1807  */
1808 HRESULT WINAPI PathCreateFromUrlW(
1809         LPCWSTR pszUrl,
1810         LPWSTR pszPath,
1811         LPDWORD pcchPath,
1812         DWORD dwFlags)
1813 {
1814     /* extracts thing prior to : in pszURL and checks against:
1815      *   https
1816      *   shell
1817      *   local
1818      *   about  - if match returns E_INVALIDARG
1819      */
1820         FIXME("%s %p %p 0x%08lx\n",
1821           debugstr_w(pszUrl), pszPath, pcchPath, dwFlags);
1822         return E_INVALIDARG;
1823 }
1824
1825 /*************************************************************************
1826  *      PathRelativePathToA   [SHLWAPI.@]
1827  */
1828 BOOL WINAPI PathRelativePathToA(
1829         LPSTR pszPath,
1830         LPCSTR pszFrom,
1831         DWORD dwAttrFrom,
1832         LPCSTR pszTo,
1833         DWORD dwAttrTo)
1834 {
1835         FIXME("%s %s 0x%08lx %s 0x%08lx\n",
1836           pszPath, pszFrom, dwAttrFrom, pszTo, dwAttrTo);
1837         return FALSE;
1838 }
1839
1840 /*************************************************************************
1841  *      PathRelativePathToW   [SHLWAPI.@]
1842  */
1843 BOOL WINAPI PathRelativePathToW(
1844         LPWSTR pszPath,
1845         LPCWSTR pszFrom,
1846         DWORD dwAttrFrom,
1847         LPCWSTR pszTo,
1848         DWORD dwAttrTo)
1849 {
1850         FIXME("%s %s 0x%08lx %s 0x%08lx\n",
1851           debugstr_w(pszPath), debugstr_w(pszFrom), dwAttrFrom, debugstr_w(pszTo), dwAttrTo);
1852         return FALSE;
1853 }
1854
1855 /*************************************************************************
1856  *      PathUnmakeSystemFolderA   [SHLWAPI.@]
1857  */
1858 BOOL WINAPI PathUnmakeSystemFolderA(LPCSTR pszPath)
1859 {
1860         FIXME("%s\n", pszPath);
1861         return FALSE;
1862 }
1863
1864 /*************************************************************************
1865  *      PathUnmakeSystemFolderW   [SHLWAPI.@]
1866  */
1867 BOOL WINAPI PathUnmakeSystemFolderW(LPCWSTR pszPath)
1868 {
1869         FIXME("%s\n", debugstr_w(pszPath));
1870         return FALSE;
1871 }
1872
1873 /*
1874         ########## special ##########
1875 */
1876
1877 /*************************************************************************
1878  * PathSetDlgItemPathA   [SHLWAPI.@]
1879  *
1880  * NOTES
1881  *  use PathCompactPath to make sure, the path fits into the control
1882  */
1883 BOOL WINAPI PathSetDlgItemPathA(HWND hDlg, int id, LPCSTR pszPath) 
1884 {       TRACE("%x %x %s\n",hDlg, id, pszPath);
1885         return SetDlgItemTextA(hDlg, id, pszPath);
1886 }
1887
1888 /*************************************************************************
1889  * PathSetDlgItemPathW   [SHLWAPI.@]
1890  */
1891 BOOL WINAPI PathSetDlgItemPathW(HWND hDlg, int id, LPCWSTR pszPath) 
1892 {       TRACE("%x %x %s\n",hDlg, id, debugstr_w(pszPath));
1893         return SetDlgItemTextW(hDlg, id, pszPath);
1894 }