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