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