Make WIN_WindowFromPoint take a POINT instead of a POINT16.
[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       [SHELLWAPI.@]
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       [SHELLWAPI.@]
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
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
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         FIXME("%c\n", ch);
1621         return 0;
1622 }
1623
1624 /*************************************************************************
1625  *      PathGetCharTypeW   [SHLWAPI.@]
1626  */
1627 UINT WINAPI PathGetCharTypeW(WCHAR ch)
1628 {
1629         FIXME("%c\n", ch);
1630         return 0;
1631 }
1632
1633 /*************************************************************************
1634  *      PathMakeSystemFolderA   [SHLWAPI.@]
1635  */
1636 BOOL WINAPI PathMakeSystemFolderA(LPCSTR pszPath)
1637 {
1638         FIXME("%s\n", pszPath);
1639         return FALSE;
1640 }
1641
1642 /*************************************************************************
1643  *      PathMakeSystemFolderW   [SHLWAPI.@]
1644  */
1645 BOOL WINAPI PathMakeSystemFolderW(LPCWSTR pszPath)
1646 {
1647         FIXME("%s\n", debugstr_w(pszPath));
1648         return FALSE;
1649 }
1650
1651 /*************************************************************************
1652  *      PathRenameExtensionA   [SHLWAPI.@]
1653  */
1654 BOOL WINAPI PathRenameExtensionA(LPSTR pszPath, LPCSTR pszExt)
1655 {
1656         FIXME("%s %s\n", pszPath, pszExt);
1657         return FALSE;
1658 }
1659
1660 /*************************************************************************
1661  *      PathRenameExtensionW   [SHLWAPI.@]
1662  */
1663 BOOL WINAPI PathRenameExtensionW(LPWSTR pszPath, LPCWSTR pszExt)
1664 {
1665         FIXME("%s %s\n", debugstr_w(pszPath), debugstr_w(pszExt));
1666         return FALSE;
1667 }
1668
1669 /*************************************************************************
1670  *      PathSearchAndQualifyA   [SHLWAPI.@]
1671  */
1672 BOOL WINAPI PathSearchAndQualifyA(
1673         LPCSTR pszPath,
1674         LPSTR pszBuf,
1675         UINT cchBuf)
1676 {
1677         FIXME("%s %s 0x%08x\n", pszPath, pszBuf, cchBuf);
1678         return FALSE;
1679 }
1680
1681 /*************************************************************************
1682  *      PathSearchAndQualifyW   [SHLWAPI.@]
1683  */
1684 BOOL WINAPI PathSearchAndQualifyW(
1685         LPCWSTR pszPath,
1686         LPWSTR pszBuf,
1687         UINT cchBuf)
1688 {
1689         FIXME("%s %s 0x%08x\n", debugstr_w(pszPath), debugstr_w(pszBuf), cchBuf);
1690         return FALSE;
1691 }
1692
1693 /*************************************************************************
1694  *      PathSkipRootA   [SHLWAPI.@]
1695  */
1696 LPSTR WINAPI PathSkipRootA(LPCSTR pszPath)
1697 {
1698         FIXME("%s\n", pszPath);
1699         return (LPSTR)pszPath;
1700 }
1701
1702 /*************************************************************************
1703  *      PathSkipRootW   [SHLWAPI.@]
1704  */
1705 LPWSTR WINAPI PathSkipRootW(LPCWSTR pszPath)
1706 {
1707         FIXME("%s\n", debugstr_w(pszPath));
1708         return (LPWSTR)pszPath;
1709 }
1710
1711 /*************************************************************************
1712  *      PathCreateFromUrlA   [SHLWAPI.@]
1713  */
1714 HRESULT WINAPI PathCreateFromUrlA(
1715         LPCSTR pszUrl,
1716         LPSTR pszPath,
1717         LPDWORD pcchPath,
1718         DWORD dwFlags)
1719 {
1720         FIXME("%s %p %p 0x%08lx\n",
1721           pszUrl, pszPath, pcchPath, dwFlags);
1722         return S_OK;
1723 }
1724
1725 /*************************************************************************
1726  *      PathCreateFromUrlW   [SHLWAPI.@]
1727  */
1728 HRESULT WINAPI PathCreateFromUrlW(
1729         LPCWSTR pszUrl,
1730         LPWSTR pszPath,
1731         LPDWORD pcchPath,
1732         DWORD dwFlags)
1733 {
1734         FIXME("%s %p %p 0x%08lx\n",
1735           debugstr_w(pszUrl), pszPath, pcchPath, dwFlags);
1736         return S_OK;
1737 }
1738
1739 /*************************************************************************
1740  *      PathRelativePathToA   [SHLWAPI.@]
1741  */
1742 BOOL WINAPI PathRelativePathToA(
1743         LPSTR pszPath,
1744         LPCSTR pszFrom,
1745         DWORD dwAttrFrom,
1746         LPCSTR pszTo,
1747         DWORD dwAttrTo)
1748 {
1749         FIXME("%s %s 0x%08lx %s 0x%08lx\n",
1750           pszPath, pszFrom, dwAttrFrom, pszTo, dwAttrTo);
1751         return FALSE;
1752 }
1753
1754 /*************************************************************************
1755  *      PathRelativePathToW   [SHLWAPI.@]
1756  */
1757 BOOL WINAPI PathRelativePathToW(
1758         LPWSTR pszPath,
1759         LPCWSTR pszFrom,
1760         DWORD dwAttrFrom,
1761         LPCWSTR pszTo,
1762         DWORD dwAttrTo)
1763 {
1764         FIXME("%s %s 0x%08lx %s 0x%08lx\n",
1765           debugstr_w(pszPath), debugstr_w(pszFrom), dwAttrFrom, debugstr_w(pszTo), dwAttrTo);
1766         return FALSE;
1767 }
1768
1769 /*************************************************************************
1770  *      PathUnmakeSystemFolderA   [SHLWAPI.@]
1771  */
1772 BOOL WINAPI PathUnmakeSystemFolderA(LPCSTR pszPath)
1773 {
1774         FIXME("%s\n", pszPath);
1775         return FALSE;
1776 }
1777
1778 /*************************************************************************
1779  *      PathUnmakeSystemFolderW   [SHLWAPI.@]
1780  */
1781 BOOL WINAPI PathUnmakeSystemFolderW(LPCWSTR pszPath)
1782 {
1783         FIXME("%s\n", debugstr_w(pszPath));
1784         return FALSE;
1785 }
1786
1787 /*
1788         ########## special ##########
1789 */
1790
1791 /*************************************************************************
1792  * PathSetDlgItemPathA   [SHLWAPI.@]
1793  *
1794  * NOTES
1795  *  use PathCompactPath to make sure, the path fits into the control
1796  */
1797 BOOL WINAPI PathSetDlgItemPathA(HWND hDlg, int id, LPCSTR pszPath) 
1798 {       TRACE("%x %x %s\n",hDlg, id, pszPath);
1799         return SetDlgItemTextA(hDlg, id, pszPath);
1800 }
1801
1802 /*************************************************************************
1803  * PathSetDlgItemPathW   [SHLWAPI.@]
1804  */
1805 BOOL WINAPI PathSetDlgItemPathW(HWND hDlg, int id, LPCWSTR pszPath) 
1806 {       TRACE("%x %x %s\n",hDlg, id, debugstr_w(pszPath));
1807         return SetDlgItemTextW(hDlg, id, pszPath);
1808 }