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