Replaced all lstr* calls from inside Wine code by their str* equivalent.
[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         TRACE("%p %i\n",debugstr_w(lpszPath), drive);
198
199         lstrcpyAtoW(lpszPath,"A:\\");
200         lpszPath[0]+=drive;
201         return lpszPath;
202 }
203
204 /*
205         Extracting Component Parts
206 */
207
208 /*************************************************************************
209  * PathFindFileNameA    [SHLWAPI.@]
210  */
211 LPSTR WINAPI PathFindFileNameA(LPCSTR lpszPath)
212 {
213         LPCSTR lastSlash = lpszPath;
214
215         TRACE("%s\n",lpszPath);
216         while (*lpszPath) 
217         {
218           if ( isSlash(lpszPath[0]) && lpszPath[1])
219               lastSlash = lpszPath+1;
220           lpszPath = CharNextA(lpszPath);
221         }
222         return (LPSTR)lastSlash;
223
224 }
225
226 /*************************************************************************
227  * PathFindFileNameW    [SHLWAPI.@]
228  */
229 LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath)
230 {
231         LPCWSTR wslash;
232         wslash = lpszPath;
233
234         TRACE("%s\n",debugstr_w(wslash));
235         while (lpszPath[0]) 
236         {
237           if (((lpszPath[0]=='\\') || (lpszPath[0]==':')) && lpszPath[1] && lpszPath[1]!='\\')
238             wslash = lpszPath+1;
239           lpszPath = CharNextW(lpszPath);
240         }
241         return (LPWSTR)wslash;  
242 }
243
244 /*************************************************************************
245  * PathFindExtensionA   [SHLWAPI.@]
246  *
247  * NOTES
248  *     returns pointer to last . in last lpszPath component or at \0.
249  */
250
251 LPSTR WINAPI PathFindExtensionA(LPCSTR lpszPath) 
252 {
253         LPCSTR   lastpoint = NULL;
254
255         TRACE("%p %s\n",lpszPath,lpszPath);
256
257         while (*lpszPath) 
258         {
259           if (*lpszPath=='\\'||*lpszPath==' ')
260             lastpoint=NULL;
261           if (*lpszPath=='.')
262             lastpoint=lpszPath;
263           lpszPath = CharNextA(lpszPath);
264         }
265         return (LPSTR)(lastpoint?lastpoint:lpszPath);
266 }
267
268 /*************************************************************************
269  * PathFindExtensionW   [SHLWAPI.@]
270  */
271 LPWSTR WINAPI PathFindExtensionW(LPCWSTR lpszPath) 
272 {
273         LPCWSTR   lastpoint = NULL;
274
275         TRACE("(%p %s)\n",lpszPath,debugstr_w(lpszPath));
276
277         while (*lpszPath)
278         {
279           if (*lpszPath==(WCHAR)'\\'||*lpszPath==(WCHAR)' ')
280             lastpoint=NULL;
281           if (*lpszPath==(WCHAR)'.')
282             lastpoint=lpszPath;
283           lpszPath = CharNextW(lpszPath);
284         }
285         return (LPWSTR)(lastpoint?lastpoint:lpszPath);
286 }
287
288 /*************************************************************************
289  * PathGetArgsA         [SHLWAPI.@]
290  *
291  * NOTES
292  *     look for next arg in string. handle "quoted" strings
293  *     returns pointer to argument *AFTER* the space. Or to the \0.
294  *
295  * FIXME
296  *     quoting by '\'
297  */
298 LPSTR WINAPI PathGetArgsA(LPCSTR lpszPath) 
299 {
300         BOOL    qflag = FALSE;
301
302         TRACE("%s\n",lpszPath);
303
304         while (*lpszPath) 
305         {
306           if ((*lpszPath==' ') && !qflag)
307             return (LPSTR)lpszPath+1;
308           if (*lpszPath=='"')
309             qflag=!qflag;
310           lpszPath = CharNextA(lpszPath);
311         }
312         return (LPSTR)lpszPath;
313 }
314
315 /*************************************************************************
316  * PathGetArgsW         [SHLWAPI.@]
317  */
318 LPWSTR WINAPI PathGetArgsW(LPCWSTR lpszPath) 
319 {
320         BOOL    qflag = FALSE;
321
322         TRACE("%s\n",debugstr_w(lpszPath));
323
324         while (*lpszPath) 
325         {
326           if ((*lpszPath==' ') && !qflag)
327             return (LPWSTR)lpszPath+1;
328           if (*lpszPath=='"')
329             qflag=!qflag;
330           lpszPath = CharNextW(lpszPath);
331         }
332         return (LPWSTR)lpszPath;
333 }
334
335 /*************************************************************************
336  * PathGetDriveNumberA  [SHLWAPI.@]
337  */
338 int WINAPI PathGetDriveNumberA(LPCSTR lpszPath)
339 {
340         int chr = tolower(lpszPath[0]);
341         
342         TRACE ("%s\n",debugstr_a(lpszPath));
343
344         if (!lpszPath || lpszPath[1]!=':' || chr < 'a' || chr > 'z') return -1;
345         return tolower(lpszPath[0]) - 'a' ;
346 }
347
348 /*************************************************************************
349  * PathGetDriveNumberW  [SHLWAPI.@]
350  */
351 int WINAPI PathGetDriveNumberW(LPCWSTR lpszPath)
352 {
353         int chr = tolowerW(lpszPath[0]);
354         
355         TRACE ("%s\n",debugstr_w(lpszPath));
356
357         if (!lpszPath || lpszPath[1]!=':' || chr < 'a' || chr > 'z') return -1;
358         return tolowerW(lpszPath[0]) - 'a' ;
359 }
360
361 /*************************************************************************
362  * PathRemoveFileSpecA  [SHLWAPI.@]
363  * 
364  * NOTES
365  *     truncates passed argument to a valid path
366  *     returns if the string was modified or not.
367  *     "\foo\xx\foo"-> "\foo\xx"
368  *     "\" -> "\"
369  *     "a:\foo" -> "a:\"
370  */
371 BOOL WINAPI PathRemoveFileSpecA(LPSTR lpszPath)
372 {
373         LPSTR cutplace = lpszPath;
374         BOOL ret = FALSE;
375         
376         TRACE("%s\n",lpszPath);
377
378         if(lpszPath)
379         {
380           while (*lpszPath == '\\') cutplace = ++lpszPath;
381           
382           while (*lpszPath)
383           {
384             if(lpszPath[0] == '\\') cutplace = lpszPath;
385           
386             if(lpszPath[0] == ':')
387             {
388               cutplace = lpszPath + 1;
389               if (lpszPath[1] == '\\') cutplace++;
390               lpszPath++;
391             }
392             lpszPath = CharNextA(lpszPath);
393             if (!lpszPath) break;
394           }
395           
396           ret = (*cutplace!='\0');
397           *cutplace = '\0';
398         }
399         return ret;
400 }
401
402 /*************************************************************************
403  * PathRemoveFileSpecW  [SHLWAPI.@]
404  */
405 BOOL WINAPI PathRemoveFileSpecW(LPWSTR lpszPath)
406 {
407         LPWSTR cutplace = lpszPath;
408         BOOL ret = FALSE;
409
410         TRACE("%s\n",debugstr_w(lpszPath));
411
412         if(lpszPath)
413         {
414           while (*lpszPath == '\\') cutplace = ++lpszPath;
415           
416           while (*lpszPath)
417           {
418             if(lpszPath[0] == '\\') cutplace = lpszPath;
419           
420             if(lpszPath[0] == ':')
421             {
422               cutplace = lpszPath + 1;
423               if (lpszPath[1] == '\\') cutplace++;
424               lpszPath++;
425             }
426             lpszPath = CharNextW(lpszPath);
427             if (!lpszPath) break;
428           }
429           
430           ret = (*cutplace!='\0');
431           *cutplace = '\0';
432         }
433         return ret;
434 }
435
436 /*************************************************************************
437  * PathStripPathA       [SHELLWAPI.@]
438  * 
439  * NOTES
440  *  removes the path from the beginning of a filename
441  */
442 void WINAPI PathStripPathA(LPSTR lpszPath)
443 {
444         LPSTR lpszFileName = PathFindFileNameA(lpszPath);
445
446         TRACE("%s\n", lpszPath);
447
448         if(lpszFileName)
449           RtlMoveMemory(lpszPath, lpszFileName, strlen(lpszFileName)+1); 
450 }
451
452 /*************************************************************************
453  * PathStripPathW       [SHELLWAPI.@]
454  */
455 void WINAPI PathStripPathW(LPWSTR lpszPath)
456 {
457         LPWSTR lpszFileName = PathFindFileNameW(lpszPath);
458
459         TRACE("%s\n", debugstr_w(lpszPath));
460         if(lpszFileName)
461           RtlMoveMemory(lpszPath, lpszFileName, (strlenW(lpszFileName)+1)*sizeof(WCHAR)); 
462 }
463
464 /*************************************************************************
465  * PathStripToRootA     [SHLWAPI.@]
466  */
467 BOOL WINAPI PathStripToRootA(LPSTR lpszPath)
468 {
469         TRACE("%s\n", lpszPath);
470
471         if (!lpszPath) return FALSE;
472         while(!PathIsRootA(lpszPath))
473           if (!PathRemoveFileSpecA(lpszPath)) return FALSE;
474         return TRUE;
475 }
476
477 /*************************************************************************
478  * PathStripToRootW     [SHLWAPI.@]
479  */
480 BOOL WINAPI PathStripToRootW(LPWSTR lpszPath)
481 {
482         TRACE("%s\n", debugstr_w(lpszPath));
483
484         if (!lpszPath) return FALSE;
485         while(!PathIsRootW(lpszPath))
486           if (!PathRemoveFileSpecW(lpszPath)) return FALSE;
487         return TRUE;
488 }
489
490 /*************************************************************************
491  * PathRemoveArgsA      [SHLWAPI.@]
492  *
493  */
494 void WINAPI PathRemoveArgsA(LPSTR lpszPath)
495 {
496         TRACE("%s\n",lpszPath);
497         
498         if(lpszPath)
499         {
500           LPSTR lpszArgs = PathGetArgsA(lpszPath);
501           if (!*lpszArgs)
502           {
503             LPSTR lpszLastChar = CharPrevA(lpszPath, lpszArgs);
504             if(*lpszLastChar==' ') *lpszLastChar = '\0';
505           }
506         }
507 }
508
509 /*************************************************************************
510  * PathRemoveArgsW      [SHLWAPI.@]
511  */
512 void WINAPI PathRemoveArgsW(LPWSTR lpszPath)
513 {
514         TRACE("%s\n", debugstr_w(lpszPath));
515
516         if(lpszPath)
517         {
518           LPWSTR lpszArgs = PathGetArgsW(lpszPath);
519           if (!*lpszArgs)
520           {
521             LPWSTR lpszLastChar = CharPrevW(lpszPath, lpszArgs);
522             if(*lpszLastChar==' ') *lpszLastChar = '\0';
523           }
524         }
525 }
526
527 /*************************************************************************
528  * PathRemoveExtensionA         [SHLWAPI.@]
529  */
530 void WINAPI PathRemoveExtensionA(LPSTR lpszPath)
531 {
532         LPSTR lpszExtension = PathFindExtensionA(lpszPath);
533
534         TRACE("%s\n", lpszPath);
535
536         if (lpszExtension) *lpszExtension='\0';
537 }
538
539 /*************************************************************************
540  * PathRemoveExtensionW         [SHLWAPI.@]
541  */
542 void WINAPI PathRemoveExtensionW(LPWSTR lpszPath)
543 {
544         LPWSTR lpszExtension = PathFindExtensionW(lpszPath);
545
546         TRACE("%s\n", debugstr_w(lpszPath));
547
548         if (lpszExtension) *lpszExtension='\0';
549 }
550
551 /*************************************************************************
552  * PathRemoveBackslashA [SHLWAPI.@]
553  *
554  * If the path ends in a backslash it is replaced by a NULL
555  * and the address of the NULL is returned
556  * Otherwise 
557  * the address of the last character is returned.
558  *
559  * FIXME
560  *  "c:\": keep backslash
561  */
562 LPSTR WINAPI PathRemoveBackslashA( LPSTR lpszPath )
563 {
564         int len;
565         LPSTR szTemp = NULL;
566         
567         if(lpszPath)
568         {
569           len = strlen(lpszPath);
570           szTemp = CharPrevA(lpszPath, lpszPath+len);
571           if (! PathIsRootA(lpszPath))
572           {
573             if (*szTemp == '\\') *szTemp = '\0';
574           }
575         }
576         return szTemp;
577 }
578
579 /*************************************************************************
580  * PathRemoveBackslashW [SHLWAPI.@]
581  */
582 LPWSTR WINAPI PathRemoveBackslashW( LPWSTR lpszPath )
583 {
584         int len;
585         LPWSTR szTemp = NULL;
586         
587         if(lpszPath)
588         {
589           len = strlenW(lpszPath);
590           szTemp = CharPrevW(lpszPath, lpszPath+len);
591           if (! PathIsRootW(lpszPath))
592           {
593             if (*szTemp == '\\') *szTemp = '\0';
594           }
595         }
596         return szTemp;
597 }
598
599
600 /*
601         Path Manipulations
602 */
603
604 /*************************************************************************
605  * PathRemoveBlanksA [SHLWAPI.@]
606  * 
607  * NOTES
608  *     remove spaces from beginning and end of passed string
609  */
610 void WINAPI PathRemoveBlanksA(LPSTR str)
611 {
612         LPSTR x = str;
613
614         TRACE("%s\n",str);
615
616         if(str)
617         {
618           while (*x==' ') x = CharNextA(x);
619           if (x!=str) strcpy(str,x);
620           x=str+strlen(str)-1;
621           while (*x==' ') x = CharPrevA(str, x);
622           if (*x==' ') *x='\0';
623         }
624 }
625
626 /*************************************************************************
627  * PathRemoveBlanksW [SHLWAPI.@]
628  */
629 void WINAPI PathRemoveBlanksW(LPWSTR str)
630 {
631         LPWSTR x = str;
632
633         TRACE("%s\n",debugstr_w(str));
634
635         if(str)
636         {
637           while (*x==' ') x = CharNextW(x);
638           if (x!=str) strcpyW(str,x);
639           x=str+strlenW(str)-1;
640           while (*x==' ') x = CharPrevW(str, x);
641           if (*x==' ') *x='\0';
642         }
643 }
644
645 /*************************************************************************
646  * PathQuoteSpacesA [SHLWAPI.@]
647  * 
648  */
649 LPSTR WINAPI PathQuoteSpacesA(LPSTR lpszPath)
650 {
651         TRACE("%s\n",lpszPath);
652
653         if(StrChrA(lpszPath,' '))
654         {
655           int len = strlen(lpszPath);
656           RtlMoveMemory(lpszPath+1, lpszPath, len);
657           *(lpszPath++) = '"';
658           lpszPath += len;
659           *(lpszPath++) = '"';
660           *(lpszPath) = '\0';
661           return --lpszPath;
662         }
663         return 0;
664 }
665
666 /*************************************************************************
667  * PathQuoteSpacesW [SHLWAPI.@]
668  */
669 LPWSTR WINAPI PathQuoteSpacesW(LPWSTR lpszPath)
670 {
671         TRACE("%s\n",debugstr_w(lpszPath));
672
673         if(StrChrW(lpszPath,' '))
674         {
675           int len = strlenW(lpszPath);
676           RtlMoveMemory(lpszPath+1, lpszPath, len*sizeof(WCHAR));
677           *(lpszPath++) = '"';
678           lpszPath += len;
679           *(lpszPath++) = '"';
680           *(lpszPath) = '\0';
681           return --lpszPath;
682         }
683         return 0;
684 }
685
686 /*************************************************************************
687  * PathUnquoteSpacesA [SHLWAPI.@]
688  * 
689  * NOTES
690  *     unquote string (remove ")
691  */
692 VOID WINAPI PathUnquoteSpacesA(LPSTR str) 
693 {
694         DWORD len = strlen(str);
695
696         TRACE("%s\n",str);
697
698         if (*str!='"')
699           return;
700         if (str[len-1]!='"')
701           return;
702         str[len-1]='\0';
703         strcpy(str,str+1);
704         return;
705 }
706
707 /*************************************************************************
708  * PathUnquoteSpacesW [SHLWAPI.@]
709  */
710 VOID WINAPI PathUnquoteSpacesW(LPWSTR str) 
711 {
712         DWORD len = strlenW(str);
713
714         TRACE("%s\n",debugstr_w(str));
715
716         if (*str!='"')
717           return;
718         if (str[len-1]!='"')
719           return;
720         str[len-1]='\0';
721         strcpyW(str,str+1);
722         return;
723 }
724
725 /*************************************************************************
726  * PathParseIconLocationA       [SHLWAPI.@]
727  */
728 int WINAPI PathParseIconLocationA(LPSTR lpszPath)
729 {
730         LPSTR lpstrComma = strchr(lpszPath, ',');
731         
732         FIXME("%s stub\n", debugstr_a(lpszPath));
733
734         if (lpstrComma && lpstrComma[1])
735         {
736           lpstrComma[0]='\0';
737 /*        return atoi(&lpstrComma[1]);  FIXME */
738         }
739         
740         PathUnquoteSpacesA(lpszPath);
741         return 0;
742 }
743
744 /*************************************************************************
745  * PathParseIconLocationW       [SHLWAPI.@]
746  */
747 int WINAPI PathParseIconLocationW(LPWSTR lpszPath)
748 {
749         LPWSTR lpstrComma = strchrW(lpszPath, ',');
750         
751         FIXME("%s stub\n", debugstr_w(lpszPath));
752
753         if (lpstrComma && lpstrComma[1])
754         {
755           lpstrComma[0]='\0';
756 /*        return _wtoi(&lpstrComma[1]); FIXME */
757         }
758         PathUnquoteSpacesW(lpszPath);
759         return 0;
760 }
761
762 /*
763         ########## cleaning and resolving paths ##########
764  */
765
766 /*************************************************************************
767  * PathFindOnPathA      [SHLWAPI.@]
768  */
769 BOOL WINAPI PathFindOnPathA(LPSTR sFile, LPCSTR sOtherDirs)
770 {
771         FIXME("%s %s\n",sFile, sOtherDirs);
772         return FALSE;
773 }
774
775 /*************************************************************************
776  * PathFindOnPathW      [SHLWAPI.@]
777  */
778 BOOL WINAPI PathFindOnPathW(LPWSTR sFile, LPCWSTR sOtherDirs)
779 {
780         FIXME("%s %s\n",debugstr_w(sFile), debugstr_w(sOtherDirs));
781         return FALSE;
782 }
783
784 /*************************************************************************
785  *      PathCompactPathExA   [SHLWAPI.@]
786  */
787 BOOL WINAPI PathCompactPathExA(
788         LPSTR pszOut,
789         LPCSTR pszSrc,
790         UINT cchMax,
791         DWORD dwFlags)
792 {
793         FIXME("%p %s 0x%08x 0x%08lx\n", pszOut, pszSrc, cchMax, dwFlags);
794         return FALSE;
795 }
796
797 /*************************************************************************
798  *      PathCompactPathExW   [SHLWAPI.@]
799  */
800 BOOL WINAPI PathCompactPathExW(
801         LPWSTR pszOut,
802         LPCWSTR pszSrc,
803         UINT cchMax,
804         DWORD dwFlags)
805 {
806         FIXME("%p %s 0x%08x 0x%08lx\n", pszOut, debugstr_w(pszSrc), cchMax, dwFlags);
807         return FALSE;
808 }
809
810 /*
811         ########## Path Testing ##########
812 */
813
814 /*************************************************************************
815  * PathIsUNCA           [SHLWAPI.@]
816  * 
817  * NOTES
818  *     PathIsUNC(char*path);
819  */
820 BOOL WINAPI PathIsUNCA(LPCSTR lpszPath) 
821 {
822         TRACE("%s\n",lpszPath);
823
824         return (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\'));
825 }
826
827 /*************************************************************************
828  * PathIsUNCW           [SHLWAPI.@]
829  */
830 BOOL WINAPI PathIsUNCW(LPCWSTR lpszPath) 
831 {
832         TRACE("%s\n",debugstr_w(lpszPath));
833
834         return (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\'));
835 }
836
837 /*************************************************************************
838  *  PathIsRelativeA     [SHLWAPI.@]
839  */
840 BOOL WINAPI PathIsRelativeA (LPCSTR lpszPath)
841 {
842         TRACE("lpszPath=%s\n",lpszPath);
843
844         return (lpszPath && (lpszPath[0]!='\\' && lpszPath[1]!=':'));
845 }
846
847 /*************************************************************************
848  *  PathIsRelativeW     [SHLWAPI.@]
849  */
850 BOOL WINAPI PathIsRelativeW (LPCWSTR lpszPath)
851 {
852         TRACE("lpszPath=%s\n",debugstr_w(lpszPath));
853
854         return (lpszPath && (lpszPath[0]!='\\' && lpszPath[1]!=':'));
855 }
856
857 /*************************************************************************
858  * PathIsRootA          [SHLWAPI.@]
859  *
860  * notes
861  *  TRUE if the path points to a root directory
862  */
863 BOOL WINAPI PathIsRootA(LPCSTR lpszPath)
864 {
865         TRACE("%s\n",lpszPath);
866
867         /* X:\ */
868         if (lpszPath[1]==':' && lpszPath[2]=='\\' && lpszPath[3]=='\0')
869           return TRUE;
870
871         /* "\" */
872         if (lpszPath[0]=='\\' && lpszPath[1]=='\0')
873           return TRUE;
874
875         /* UNC "\\<computer>\<share>" */
876         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
877         {
878           int foundbackslash = 0;
879           lpszPath += 2;
880           while (*lpszPath)
881           {
882             if (*lpszPath=='\\') foundbackslash++;
883             lpszPath = CharNextA(lpszPath);
884           }
885           if (foundbackslash <= 1)
886             return TRUE;
887         }
888         return FALSE;
889 }
890
891 /*************************************************************************
892  * PathIsRootW          [SHLWAPI.@]
893  */
894 BOOL WINAPI PathIsRootW(LPCWSTR lpszPath) 
895 {
896         TRACE("%s\n",debugstr_w(lpszPath));
897
898         /* X:\ */
899         if (lpszPath[1]==':' && lpszPath[2]=='\\' && lpszPath[3]=='\0')
900           return TRUE;
901
902         /* "\" */
903         if (lpszPath[0]=='\\' && lpszPath[1]=='\0')
904           return TRUE;
905
906         /* UNC "\\<computer>\<share>" */
907         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
908         {
909           int foundbackslash = 0;
910           lpszPath += 2;
911           while (*lpszPath)
912           {
913             if (*lpszPath=='\\') foundbackslash++;
914             lpszPath = CharNextW(lpszPath);
915           }
916           if (foundbackslash <= 1)
917             return TRUE;
918         }
919         return FALSE;
920
921 }
922
923 /*************************************************************************
924  * PathIsDirectoryA     [SHLWAPI.@]
925  */
926 BOOL WINAPI PathIsDirectoryA(LPCSTR lpszPath)
927 {
928         DWORD dwAttr;
929
930         TRACE("%s\n", debugstr_a(lpszPath));
931
932         dwAttr = GetFileAttributesA(lpszPath);
933         return  (dwAttr != -1) ? dwAttr & FILE_ATTRIBUTE_DIRECTORY : 0;
934 }
935
936 /*************************************************************************
937  * PathIsDirectoryW     [SHLWAPI.@]
938  */
939 BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
940 {
941         DWORD dwAttr;
942         
943         TRACE("%s\n", debugstr_w(lpszPath));
944
945         dwAttr = GetFileAttributesW(lpszPath);
946         return  (dwAttr != -1) ? dwAttr & FILE_ATTRIBUTE_DIRECTORY : 0;
947 }
948
949 /*************************************************************************
950  * PathFileExistsA      [SHLWAPI.@]
951  * 
952  * NOTES
953  *     file_exists(char *fn);
954  */
955 BOOL WINAPI PathFileExistsA(LPCSTR lpszPath) 
956 {
957         TRACE("%s\n",lpszPath);
958         return  (GetFileAttributesA(lpszPath)!=-1);
959 }
960
961 /*************************************************************************
962  * PathFileExistsW      [SHLWAPI.@]
963  */
964 BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath) 
965 {
966         TRACE("%s\n",debugstr_w(lpszPath));
967         return  (GetFileAttributesW(lpszPath)!=-1);
968 }
969
970 /*************************************************************************
971  * PathMatchSingleMaskA [internal]
972  * 
973  * NOTES
974  *     internal (used by PathMatchSpec)
975  */
976 static BOOL PathMatchSingleMaskA(LPCSTR name, LPCSTR mask)
977 {
978         while (*name && *mask && *mask!=';') 
979         {
980           if (*mask=='*') 
981           {
982             do 
983             {
984               if (PathMatchSingleMaskA(name,mask+1)) return 1;  /* try substrings */
985             } while (*name++);
986             return 0;
987           }
988           if (toupper(*mask)!=toupper(*name) && *mask!='?') return 0;
989           name = CharNextA(name);
990           mask = CharNextA(mask);
991         }
992         if (!*name) 
993         {
994           while (*mask=='*') mask++;
995           if (!*mask || *mask==';') return 1;
996         }
997         return 0;
998 }
999
1000 /*************************************************************************
1001  * PathMatchSingleMaskW [internal]
1002  */
1003 static BOOL PathMatchSingleMaskW(LPCWSTR name, LPCWSTR mask)
1004 {
1005         while (*name && *mask && *mask!=';') 
1006         {
1007           if (*mask=='*') 
1008           {
1009             do 
1010             {
1011               if (PathMatchSingleMaskW(name,mask+1)) return 1;  /* try substrings */
1012             } while (*name++);
1013             return 0;
1014           }
1015           if (toupperW(*mask)!=toupperW(*name) && *mask!='?') return 0;
1016           name = CharNextW(name);
1017           mask = CharNextW(mask);
1018         }
1019         if (!*name) 
1020         {
1021           while (*mask=='*') mask++;
1022           if (!*mask || *mask==';') return 1;
1023         }
1024         return 0;
1025 }
1026 /*************************************************************************
1027  * PathMatchSpecA       [SHLWAPI.@]
1028  * 
1029  * NOTES
1030  *     used from COMDLG32
1031  */
1032 BOOL WINAPI PathMatchSpecA(LPCSTR name, LPCSTR mask) 
1033 {
1034         TRACE("%s %s\n",name,mask);
1035
1036         if (!lstrcmpA( mask, "*.*" )) return 1;   /* we don't require a period */
1037
1038         while (*mask) 
1039         {
1040           if (PathMatchSingleMaskA(name,mask)) return 1;    /* helper function */
1041           while (*mask && *mask!=';') mask = CharNextA(mask);
1042           if (*mask==';') 
1043           {
1044             mask++;
1045             while (*mask==' ') mask++;      /*  masks may be separated by "; " */
1046           }
1047         }
1048         return 0;
1049 }
1050
1051 /*************************************************************************
1052  * PathMatchSpecW       [SHLWAPI.@]
1053  */
1054 BOOL WINAPI PathMatchSpecW(LPCWSTR name, LPCWSTR mask) 
1055 {
1056         WCHAR stemp[4];
1057         TRACE("%s %s\n",debugstr_w(name),debugstr_w(mask));
1058
1059         lstrcpyAtoW(stemp,"*.*");       
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 }