Fixed some issues found by winapi_check.
[wine] / dlls / shell32 / shellpath.c
1 /*
2  * Path Functions
3  *
4  * Many of this functions are in SHLWAPI.DLL also
5  *
6  */
7 #include <string.h>
8 #include <ctype.h>
9 #include "debugtools.h"
10 #include "winnls.h"
11 #include "winversion.h"
12 #include "winreg.h"
13
14 #include "shlobj.h"
15 #include "shell32_main.h"
16 #include "windef.h"
17 #include "options.h"
18 #include "wine/undocshell.h"
19 #include "wine/unicode.h"
20 #include "shlwapi.h"
21
22 DEFAULT_DEBUG_CHANNEL(shell);
23
24 /*
25         Combining and Constructing paths
26 */
27
28 /*************************************************************************
29  * PathAppendA          [SHLWAPI.@]
30  * 
31  * NOTES
32  *  concat path lpszPath2 onto lpszPath1
33  *
34  * FIXME
35  *  the resulting path is also canonicalized
36  */
37 LPSTR WINAPI PathAppendA(
38         LPSTR lpszPath1,
39         LPCSTR lpszPath2) 
40 {
41         TRACE("%s %s\n",lpszPath1, lpszPath2);
42         while (lpszPath2[0]=='\\') lpszPath2++;
43         return PathCombineA(lpszPath1,lpszPath1,lpszPath2);
44 }
45
46 /*************************************************************************
47  * PathAppendW          [SHLWAPI.@]
48  */
49 LPSTR WINAPI PathAppendW(
50         LPWSTR lpszPath1,
51         LPCWSTR lpszPath2) 
52 {
53         FIXME("%s %s\n",debugstr_w(lpszPath1), debugstr_w(lpszPath2));
54         return NULL;
55 }
56
57 /*************************************************************************
58  * PathAppendAW         [SHELL32.36]
59  */
60 LPVOID WINAPI PathAppendAW(
61         LPVOID lpszPath1,
62         LPCVOID lpszPath2)
63 {
64         if (VERSION_OsIsUnicode())
65           return PathAppendW(lpszPath1, lpszPath2);
66         return PathAppendA(lpszPath1, lpszPath2);
67 }
68
69 /*************************************************************************
70  * PathCombineA         [SHLWAPI.@]
71  * 
72  * NOTES
73  *  if lpszFile='.' skip it
74  *  szDest can be equal to lpszFile. Thats why we use sTemp
75  *
76  * FIXME
77  *  the resulting path is also canonicalized
78  */
79 LPSTR WINAPI PathCombineA(
80         LPSTR szDest,
81         LPCSTR lpszDir,
82         LPCSTR lpszFile) 
83 {
84         char sTemp[MAX_PATH];
85         TRACE("%p %p->%s %p->%s\n",szDest, lpszDir, lpszDir, lpszFile, lpszFile);
86         
87         
88         if (!lpszFile || !lpszFile[0] || (lpszFile[0]=='.' && !lpszFile[1]) ) 
89         {
90           strcpy(szDest,lpszDir);
91           return szDest;
92         }
93
94         /*  if lpszFile is a complete path don't care about lpszDir */
95         if (PathGetDriveNumberA(lpszFile) != -1)
96         {
97           strcpy(szDest,lpszFile);
98         }
99         else if (lpszFile[0] == '\\' )
100         {
101           strcpy(sTemp,lpszDir);
102           PathStripToRootA(sTemp);
103           strcat(sTemp,lpszFile);
104           strcpy(szDest,sTemp);
105         }
106         else
107         {
108           strcpy(sTemp,lpszDir);
109           PathAddBackslashA(sTemp);
110           strcat(sTemp,lpszFile);
111           strcpy(szDest,sTemp);
112         }
113         return szDest;
114 }
115
116 /*************************************************************************
117  * PathCombineW          [SHLWAPI.@]
118  */
119 LPWSTR WINAPI PathCombineW(
120         LPWSTR szDest,
121         LPCWSTR lpszDir,
122         LPCWSTR lpszFile) 
123 {
124         WCHAR sTemp[MAX_PATH];
125         TRACE("%p %p->%s %p->%s\n",szDest, lpszDir, debugstr_w(lpszDir),
126                          lpszFile, debugstr_w(lpszFile));
127         
128         
129         if (!lpszFile || !lpszFile[0] || (lpszFile[0]==(WCHAR)'.' && !lpszFile[1]) ) 
130         {
131           strcpyW(szDest,lpszDir);
132           return szDest;
133         }
134
135         /*  if lpszFile is a complete path don't care about lpszDir */
136         if (PathGetDriveNumberW(lpszFile) != -1)
137         {
138             strcpyW(szDest,lpszFile);
139         }
140         else if (lpszFile[0] == (WCHAR)'\\' )
141         {
142           strcpyW(sTemp,lpszDir);
143           PathStripToRootW(sTemp);
144           strcatW(sTemp,lpszFile);
145           strcpyW(szDest,sTemp);
146         }
147         else
148         {
149           strcpyW(sTemp,lpszDir);
150           PathAddBackslashW(sTemp);
151           strcatW(sTemp,lpszFile);
152           strcpyW(szDest,sTemp);
153         }
154         return szDest;
155 }
156
157 /*************************************************************************
158  * PathCombineAW         [SHELL32.37]
159  */
160 LPVOID WINAPI PathCombineAW(
161         LPVOID szDest,
162         LPCVOID lpszDir,
163         LPCVOID lpszFile) 
164 {
165         if (VERSION_OsIsUnicode())
166           return PathCombineW( szDest, lpszDir, lpszFile );
167         return PathCombineA( szDest, lpszDir, lpszFile );
168 }
169
170 /*************************************************************************
171  * PathAddBackslashA    [SHLWAPI.@]
172  *
173  * NOTES
174  *     append \ if there is none
175  */
176 LPSTR WINAPI PathAddBackslashA(LPSTR lpszPath)
177 {
178         int len;
179         TRACE("%p->%s\n",lpszPath,lpszPath);
180
181         len = strlen(lpszPath);
182         if (len && lpszPath[len-1]!='\\') 
183         {
184           lpszPath[len]  = '\\';
185           lpszPath[len+1]= 0x00;
186           return lpszPath+len+1;
187         }
188         return lpszPath+len;
189 }
190
191 /*************************************************************************
192  * PathAddBackslashW    [SHLWAPI.@]
193  */
194 LPWSTR WINAPI PathAddBackslashW(LPWSTR lpszPath)
195 {
196         int len;
197         TRACE("%p->%s\n",lpszPath,debugstr_w(lpszPath));
198
199         len = strlenW(lpszPath);
200         if (len && lpszPath[len-1]!=(WCHAR)'\\') 
201         {
202           lpszPath[len]  = (WCHAR)'\\';
203           lpszPath[len+1]= 0x00;
204           return lpszPath+len+1;
205         }
206         return lpszPath+len;
207 }
208
209 /*************************************************************************
210  * PathAddBackslashAW           [SHELL32.32]
211  */
212 LPVOID WINAPI PathAddBackslashAW(LPVOID lpszPath)
213 {
214         if(VERSION_OsIsUnicode())
215           return PathAddBackslashW(lpszPath);
216         return PathAddBackslashA(lpszPath);
217 }
218
219 /*************************************************************************
220  * PathBuildRootA               [SHLWAPI.@]
221  */
222 LPSTR WINAPI PathBuildRootA(LPSTR lpszPath, int drive) 
223 {
224         TRACE("%p %i\n",lpszPath, drive);
225
226         strcpy(lpszPath,"A:\\");
227         lpszPath[0]+=drive;
228         return lpszPath;
229 }
230
231 /*************************************************************************
232  * PathBuildRootW               [SHLWAPI.@]
233  */
234 LPWSTR WINAPI PathBuildRootW(LPWSTR lpszPath, int drive) 
235 {
236         TRACE("%p %i\n",debugstr_w(lpszPath), drive);
237
238         lstrcpyAtoW(lpszPath,"A:\\");
239         lpszPath[0]+=drive;
240         return lpszPath;
241 }
242
243 /*************************************************************************
244  * PathBuildRootAW              [SHELL32.30]
245  */
246 LPVOID WINAPI PathBuildRootAW(LPVOID lpszPath, int drive)
247 {
248         if(VERSION_OsIsUnicode())
249           return PathBuildRootW(lpszPath, drive);
250         return PathBuildRootA(lpszPath, drive);
251 }
252
253 /*
254         Extracting Component Parts
255 */
256
257 /*************************************************************************
258  * PathFindFileNameA    [SHLWAPI.@]
259  */
260 LPSTR WINAPI PathFindFileNameA(LPCSTR lpszPath)
261 {
262         LPCSTR aslash;
263         aslash = lpszPath;
264
265         TRACE("%s\n",aslash);
266         while (lpszPath[0]) 
267         {
268           if (((lpszPath[0]=='\\') || (lpszPath[0]==':')) && lpszPath[1] && lpszPath[1]!='\\')
269               aslash = lpszPath+1;
270           lpszPath++;
271         }
272         return (LPSTR)aslash;
273
274 }
275
276 /*************************************************************************
277  * PathFindFileNameW    [SHLWAPI.@]
278  */
279 LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath)
280 {
281         LPCWSTR wslash;
282         wslash = lpszPath;
283
284         TRACE("%s\n",debugstr_w(wslash));
285         while (lpszPath[0]) 
286         {
287           if (((lpszPath[0]=='\\') || (lpszPath[0]==':')) && lpszPath[1] && lpszPath[1]!='\\')
288             wslash = lpszPath+1;
289           lpszPath++;
290         }
291         return (LPWSTR)wslash;  
292 }
293
294 /*************************************************************************
295  * PathFindFileNameAW   [SHELL32.34]
296  */
297 LPVOID WINAPI PathFindFileNameAW(LPCVOID lpszPath)
298 {
299         if(VERSION_OsIsUnicode())
300           return PathFindFileNameW(lpszPath);
301         return PathFindFileNameA(lpszPath);
302 }
303
304 /*************************************************************************
305  * PathFindExtensionA   [SHLWAPI.@]
306  *
307  * NOTES
308  *     returns pointer to last . in last lpszPath component or at \0.
309  */
310
311 LPSTR WINAPI PathFindExtensionA(LPCSTR lpszPath) 
312 {
313         LPCSTR   lastpoint = NULL;
314
315         TRACE("%p %s\n",lpszPath,lpszPath);
316
317         while (*lpszPath) 
318         {
319           if (*lpszPath=='\\'||*lpszPath==' ')
320             lastpoint=NULL;
321           if (*lpszPath=='.')
322             lastpoint=lpszPath;
323           lpszPath++;
324         }
325         return (LPSTR)(lastpoint?lastpoint:lpszPath);
326 }
327
328 /*************************************************************************
329  * PathFindExtensionW   [SHLWAPI.@]
330  */
331 LPWSTR WINAPI PathFindExtensionW(LPCWSTR lpszPath) 
332 {
333         LPCWSTR   lastpoint = NULL;
334
335         TRACE("(%p %s)\n",lpszPath,debugstr_w(lpszPath));
336
337         while (*lpszPath)
338         {
339           if (*lpszPath==(WCHAR)'\\'||*lpszPath==(WCHAR)' ')
340             lastpoint=NULL;
341           if (*lpszPath==(WCHAR)'.')
342             lastpoint=lpszPath;
343           lpszPath++;
344         }
345         return (LPWSTR)(lastpoint?lastpoint:lpszPath);
346 }
347
348 /*************************************************************************
349  * PathFindExtensionAW          [SHELL32.31]
350  */
351 LPVOID WINAPI PathFindExtensionAW(LPCVOID lpszPath) 
352 {
353         if (VERSION_OsIsUnicode())
354           return PathFindExtensionW(lpszPath);
355         return PathFindExtensionA(lpszPath);
356
357 }
358
359 /*************************************************************************
360  * PathGetExtensionA            [internal]
361  *
362  * NOTES
363  *  exported by ordinal
364  *  return value points to the first char after the dot
365  */
366 LPSTR WINAPI PathGetExtensionA(LPCSTR lpszPath)
367 {
368         TRACE("(%s)\n",lpszPath);
369
370         lpszPath = PathFindExtensionA(lpszPath);
371         return (LPSTR)(*lpszPath?(lpszPath+1):lpszPath);
372 }
373
374 /*************************************************************************
375  * PathGetExtensionW            [internal]
376  */
377 LPWSTR WINAPI PathGetExtensionW(LPCWSTR lpszPath)
378 {
379         TRACE("(%s)\n",debugstr_w(lpszPath));
380
381         lpszPath = PathFindExtensionW(lpszPath);
382         return (LPWSTR)(*lpszPath?(lpszPath+1):lpszPath);
383 }
384
385 /*************************************************************************
386  * PathGetExtensionAW           [SHELL32.158]
387  */
388 LPVOID WINAPI PathGetExtensionAW(LPCVOID lpszPath) 
389 {
390         if (VERSION_OsIsUnicode())
391           return PathGetExtensionW(lpszPath);
392         return PathGetExtensionA(lpszPath);
393 }
394
395 /*************************************************************************
396  * PathGetArgsA         [SHLWAPI.@]
397  *
398  * NOTES
399  *     look for next arg in string. handle "quoted" strings
400  *     returns pointer to argument *AFTER* the space. Or to the \0.
401  *
402  * FIXME
403  *     quoting by '\'
404  */
405 LPSTR WINAPI PathGetArgsA(LPCSTR lpszPath) 
406 {
407         BOOL    qflag = FALSE;
408
409         TRACE("%s\n",lpszPath);
410
411         while (*lpszPath) 
412         {
413           if ((*lpszPath==' ') && !qflag)
414             return (LPSTR)lpszPath+1;
415           if (*lpszPath=='"')
416             qflag=!qflag;
417           lpszPath++;
418         }
419         return (LPSTR)lpszPath;
420 }
421
422 /*************************************************************************
423  * PathGetArgsW         [SHLWAPI.@]
424  */
425 LPWSTR WINAPI PathGetArgsW(LPCWSTR lpszPath) 
426 {
427         BOOL    qflag = FALSE;
428
429         TRACE("%s\n",debugstr_w(lpszPath));
430
431         while (*lpszPath) 
432         {
433           if ((*lpszPath==' ') && !qflag)
434             return (LPWSTR)lpszPath+1;
435           if (*lpszPath=='"')
436             qflag=!qflag;
437           lpszPath++;
438         }
439         return (LPWSTR)lpszPath;
440 }
441
442 /*************************************************************************
443  * PathGetArgsAW        [SHELL32.52]
444  */
445 LPVOID WINAPI PathGetArgsAW(LPVOID lpszPath) 
446 {
447         if (VERSION_OsIsUnicode())
448           return PathGetArgsW(lpszPath);
449         return PathGetArgsA(lpszPath);
450 }
451
452 /*************************************************************************
453  * PathGetDriveNumberA  [SHLWAPI.@]
454  */
455 int WINAPI PathGetDriveNumberA(LPCSTR lpszPath)
456 {
457         int chr = tolower(lpszPath[0]);
458         
459         TRACE ("%s\n",debugstr_a(lpszPath));
460
461         if (!lpszPath || lpszPath[1]!=':' || chr < 'a' || chr > 'z') return -1;
462         return tolower(lpszPath[0]) - 'a' ;
463 }
464
465 /*************************************************************************
466  * PathGetDriveNumberW  [SHLWAPI.@]
467  */
468 int WINAPI PathGetDriveNumberW(LPCWSTR lpszPath)
469 {
470         int chr = tolowerW(lpszPath[0]);
471         
472         TRACE ("%s\n",debugstr_w(lpszPath));
473
474         if (!lpszPath || lpszPath[1]!=':' || chr < 'a' || chr > 'z') return -1;
475         return tolowerW(lpszPath[0]) - 'a' ;
476 }
477
478 /*************************************************************************
479  * PathGetDriveNumber   [SHELL32.57]
480  */
481 int WINAPI PathGetDriveNumberAW(LPVOID lpszPath) 
482 {
483         if (VERSION_OsIsUnicode())
484           return PathGetDriveNumberW(lpszPath);
485         return PathGetDriveNumberA(lpszPath);
486 }
487
488 /*************************************************************************
489  * PathRemoveFileSpecA  [SHLWAPI.@]
490  * 
491  * NOTES
492  *     truncates passed argument to a valid path
493  *     returns if the string was modified or not.
494  *     "\foo\xx\foo"-> "\foo\xx"
495  *     "\" -> "\"
496  *     "a:\foo" -> "a:\"
497  */
498 BOOL WINAPI PathRemoveFileSpecA(LPSTR lpszPath)
499 {
500         LPSTR cutplace;
501
502         TRACE("%s\n",lpszPath);
503
504         if (!lpszPath[0]) return 0;
505
506         cutplace = PathFindFileNameA(lpszPath);
507         if (cutplace)
508         {
509           *cutplace='\0';
510           if (PathIsRootA(lpszPath))
511           {
512             PathAddBackslashA(lpszPath);
513           }
514           else
515           {
516             PathRemoveBackslashA(lpszPath);
517           }
518           return TRUE;
519         }
520         return FALSE;
521 }
522
523 /*************************************************************************
524  * PathRemoveFileSpecW  [SHLWAPI.@]
525  */
526 BOOL WINAPI PathRemoveFileSpecW(LPWSTR lpszPath)
527 {
528         LPWSTR cutplace;
529
530         TRACE("%s\n",debugstr_w(lpszPath));
531
532         if (!lpszPath[0]) return 0;
533         cutplace = PathFindFileNameW(lpszPath);
534         if (cutplace)
535         {
536           *cutplace='\0';
537           if (PathIsRootW(lpszPath))
538           {
539             PathAddBackslashW(lpszPath);
540           }
541           else
542           {
543             PathRemoveBackslashW(lpszPath);
544           }
545           return TRUE;
546         }
547         return FALSE;
548 }
549
550 /*************************************************************************
551  * PathRemoveFileSpec [SHELL32.35]
552  */
553 BOOL WINAPI PathRemoveFileSpecAW(LPVOID lpszPath) 
554 {
555         if (VERSION_OsIsUnicode())
556           return PathRemoveFileSpecW(lpszPath);
557         return PathRemoveFileSpecA(lpszPath);
558 }
559
560 /*************************************************************************
561  * PathStripPathA       [SHELLWAPI.@]
562  * 
563  * NOTES
564  *  removes the path from the beginning of a filename
565  */
566 void WINAPI PathStripPathA(LPSTR lpszPath)
567 {
568         LPSTR lpszFileName = PathFindFileNameA(lpszPath);
569
570         TRACE("%s\n", lpszPath);
571
572         if(lpszFileName)
573           RtlMoveMemory(lpszPath, lpszFileName, strlen(lpszFileName)+1); 
574 }
575
576 /*************************************************************************
577  * PathStripPathW       [SHELLWAPI.@]
578  */
579 void WINAPI PathStripPathW(LPWSTR lpszPath)
580 {
581         LPWSTR lpszFileName = PathFindFileNameW(lpszPath);
582
583         TRACE("%s\n", debugstr_w(lpszPath));
584         if(lpszFileName)
585           RtlMoveMemory(lpszPath, lpszFileName, (lstrlenW(lpszFileName)+1)*sizeof(WCHAR)); 
586 }
587
588 /*************************************************************************
589  * PathStripPathAW      [SHELL32.38]
590  */
591 void WINAPI PathStripPathAW(LPVOID lpszPath) 
592 {
593         if (VERSION_OsIsUnicode())
594           return PathStripPathW(lpszPath);
595         return PathStripPathA(lpszPath);
596 }
597
598 /*************************************************************************
599  * PathStripToRootA     [SHLWAPI.@]
600  */
601 BOOL WINAPI PathStripToRootA(LPSTR lpszPath)
602 {
603         TRACE("%s\n", lpszPath);
604
605         /* X:\ */
606         if (lpszPath[1]==':' )
607         {
608           if(lpszPath[2]=='\\')
609           {
610             lpszPath[3]='\0';
611             return TRUE;
612           }
613           lpszPath[2]='\0';
614           return FALSE;
615         }
616
617         /* UNC "\\<computer>\<share>" FIXME: not complete*/
618         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
619         {
620           int foundbackslash = 0;
621           lpszPath += 2;
622           while (*lpszPath)
623           {
624             if (*lpszPath=='\\') foundbackslash++;
625             if (foundbackslash==2)
626             {
627               *lpszPath = '\0';
628               return TRUE;
629             }
630             lpszPath++;
631           }
632         }
633
634         /* "\" */
635         if (lpszPath[0]=='\\')
636         {
637           lpszPath[1]='\0';
638           return TRUE;
639         }
640
641         lpszPath[0]='\0';
642         return FALSE;
643 }
644
645 /*************************************************************************
646  * PathStripToRootW     [SHLWAPI.@]
647  */
648 BOOL WINAPI PathStripToRootW(LPWSTR lpszPath)
649 {
650         TRACE("%s\n", debugstr_w(lpszPath));
651
652         /* X:\ */
653         if (lpszPath[1]==':' )
654         {
655           if(lpszPath[2]=='\\')
656           {
657             lpszPath[3]='\0';
658             return TRUE;
659           }
660           lpszPath[2]='\0';
661           return FALSE;
662         }
663
664
665         /* UNC "\\<computer>\<share>" */
666         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
667         {
668           int foundbackslash = 0;
669           lpszPath += 2;
670           while (*lpszPath)
671           {
672             if (*lpszPath=='\\') foundbackslash++;
673             if (foundbackslash==2)
674             {
675               *lpszPath = '\0';
676               return TRUE;
677             }
678             lpszPath++;
679           }
680         }
681
682         /* "\" */
683         if (lpszPath[0]=='\\')
684         {
685           lpszPath[1]='\0';
686           return TRUE;
687         }
688
689         lpszPath[0]=(WCHAR)'\0';
690         return FALSE;
691 }
692
693 /*************************************************************************
694  * PathStripToRootAW    [SHELL32.50]
695  */
696 BOOL WINAPI PathStripToRootAW(LPVOID lpszPath) 
697 {
698         if (VERSION_OsIsUnicode())
699           return PathStripToRootW(lpszPath);
700         return PathStripToRootA(lpszPath);
701 }
702
703 /*************************************************************************
704  * PathRemoveArgsA      [SHLWAPI.@]
705  *
706  * NOTES
707  *  returns pointer to last character, not void
708  */
709 LPSTR WINAPI PathRemoveArgsA(LPSTR lpszPath)
710 {
711         BOOL    qflag = FALSE;
712         LPSTR   pPos = lpszPath;
713         
714         TRACE("%s\n",lpszPath);
715
716         while (*lpszPath) 
717         {
718           if (!qflag && *lpszPath==' ') break;
719           if (*lpszPath=='"') qflag=!qflag;
720           lpszPath++;
721           if (*lpszPath) pPos++;
722         };
723         *lpszPath = '\0';
724         return pPos;
725 }
726
727 /*************************************************************************
728  * PathRemoveArgsW      [SHLWAPI.@]
729  */
730 LPWSTR WINAPI PathRemoveArgsW(LPWSTR lpszPath)
731 {
732         BOOL    qflag = FALSE;
733         LPWSTR  pPos = lpszPath;
734         
735
736         TRACE("%s\n", debugstr_w(lpszPath));
737
738         while (*lpszPath) 
739         {
740           if (!qflag && *lpszPath==(WCHAR)' ') break;
741           if (*lpszPath==(WCHAR)'"') qflag=!qflag;
742           lpszPath++;
743           if (*lpszPath) pPos++;
744         };
745         *lpszPath = (WCHAR)'\0';
746         return pPos;
747 }
748
749 /*************************************************************************
750  * PathRemoveArgsAW     [SHELL32.251]
751  */
752 LPVOID WINAPI PathRemoveArgsAW(LPVOID lpszPath) 
753 {
754         if (VERSION_OsIsUnicode())
755           return PathRemoveArgsW(lpszPath);
756         return PathRemoveArgsA(lpszPath);
757 }
758
759 /*************************************************************************
760  * PathRemoveExtensionA         [SHLWAPI.@]
761  */
762 void WINAPI PathRemoveExtensionA(LPSTR lpszPath)
763 {
764         LPSTR lpszExtension = PathFindExtensionA(lpszPath);
765
766         TRACE("%s\n", lpszPath);
767
768         if (lpszExtension) *lpszExtension='\0';
769 }
770
771 /*************************************************************************
772  * PathRemoveExtensionW         [SHLWAPI.@]
773  */
774 void WINAPI PathRemoveExtensionW(LPWSTR lpszPath)
775 {
776         LPWSTR lpszExtension = PathFindExtensionW(lpszPath);
777
778         TRACE("%s\n", debugstr_w(lpszPath));
779
780         if (lpszExtension) *lpszExtension='\0';
781 }
782
783 /*************************************************************************
784  * PathRemoveExtensionAW        [SHELL32.250]
785  */
786 void WINAPI PathRemoveExtensionAW(LPVOID lpszPath) 
787 {
788         if (VERSION_OsIsUnicode())
789           return PathRemoveExtensionW(lpszPath);
790         return PathRemoveExtensionA(lpszPath);
791 }
792
793 /*************************************************************************
794  * PathRemoveBackslashA [SHLWAPI.@]
795  *
796  * If the path ends in a backslash it is replaced by a NULL
797  * and the address of the NULL is returned
798  * Otherwise 
799  * the address of the last character is returned.
800  *
801  * FIXME
802  *  "c:\": keep backslash
803  */
804 LPSTR WINAPI PathRemoveBackslashA( LPSTR lpszPath )
805 {
806         LPSTR p = lpszPath;
807         
808         while (*lpszPath) p = lpszPath++;
809         if ( *p == (CHAR)'\\') *p = (CHAR)'\0';
810         return p;
811 }
812
813 /*************************************************************************
814  * PathRemoveBackslashW [SHLWAPI.@]
815  */
816 LPWSTR WINAPI PathRemoveBackslashW( LPWSTR lpszPath )
817 {
818         LPWSTR p = lpszPath;
819         
820         while (*lpszPath) p = lpszPath++;
821         if ( *p == (WCHAR)'\\') *p = (WCHAR)'\0';
822         return p;
823 }
824
825 /*
826         Path Manipulations
827 */
828
829 /*************************************************************************
830  * PathGetShortPathA [internal]
831  */
832 LPSTR WINAPI PathGetShortPathA(LPSTR lpszPath)
833 {
834         FIXME("%s stub\n", lpszPath);
835         return NULL;
836 }
837
838 /*************************************************************************
839  * PathGetShortPathW [internal]
840  */
841 LPWSTR WINAPI PathGetShortPathW(LPWSTR lpszPath)
842 {
843         FIXME("%s stub\n", debugstr_w(lpszPath));
844         return NULL;
845 }
846
847 /*************************************************************************
848  * PathGetShortPathAW [SHELL32.92]
849  */
850 LPVOID WINAPI PathGetShortPathAW(LPVOID lpszPath)
851 {
852         if(VERSION_OsIsUnicode())
853           return PathGetShortPathW(lpszPath);
854         return PathGetShortPathA(lpszPath);
855 }
856
857 /*************************************************************************
858  * PathRemoveBlanksA [SHLWAPI.@]
859  * 
860  * NOTES
861  *     remove spaces from beginning and end of passed string
862  */
863 LPSTR WINAPI PathRemoveBlanksA(LPSTR str)
864 {
865         LPSTR x = str;
866
867         TRACE("%s\n",str);
868
869         while (*x==' ') x++;
870         if (x!=str)
871           strcpy(str,x);
872         if (!*str)
873           return str;
874         x=str+strlen(str)-1;
875         while (*x==' ')
876           x--;
877         if (*x==' ')
878           *x='\0';
879         return x;
880 }
881
882 /*************************************************************************
883  * PathRemoveBlanksW [SHLWAPI.@]
884  */
885 LPWSTR WINAPI PathRemoveBlanksW(LPWSTR str)
886 {
887         LPWSTR x = str;
888
889         TRACE("%s\n",debugstr_w(str));
890
891         while (*x==' ') x++;
892         if (x!=str)
893           strcpyW(str,x);
894         if (!*str)
895           return str;
896         x=str+strlenW(str)-1;
897         while (*x==' ')
898           x--;
899         if (*x==' ')
900           *x='\0';
901         return x;
902 }
903
904 /*************************************************************************
905  * PathRemoveBlanksAW [SHELL32.33]
906  */
907 LPVOID WINAPI PathRemoveBlanksAW(LPVOID str)
908 {
909         if(VERSION_OsIsUnicode())
910           return PathRemoveBlanksW(str);
911         return PathRemoveBlanksA(str);
912 }
913
914 /*************************************************************************
915  * PathQuoteSpacesA [SHLWAPI.@]
916  * 
917  */
918 LPSTR WINAPI PathQuoteSpacesA(LPSTR lpszPath)
919 {
920         TRACE("%s\n",lpszPath);
921
922         if(StrChrA(lpszPath,' '))
923         {
924           int len = strlen(lpszPath);
925           RtlMoveMemory(lpszPath+1, lpszPath, len);
926           *(lpszPath++) = '"';
927           lpszPath += len;
928           *(lpszPath++) = '"';
929           *(lpszPath) = '\0';
930           return --lpszPath;
931         }
932         return 0;
933 }
934
935 /*************************************************************************
936  * PathQuoteSpacesW [SHLWAPI.@]
937  */
938 LPWSTR WINAPI PathQuoteSpacesW(LPWSTR lpszPath)
939 {
940         TRACE("%s\n",debugstr_w(lpszPath));
941
942         if(StrChrW(lpszPath,' '))
943         {
944           int len = lstrlenW(lpszPath);
945           RtlMoveMemory(lpszPath+1, lpszPath, len*sizeof(WCHAR));
946           *(lpszPath++) = '"';
947           lpszPath += len;
948           *(lpszPath++) = '"';
949           *(lpszPath) = '\0';
950           return --lpszPath;
951         }
952         return 0;
953 }
954
955 /*************************************************************************
956  * PathQuoteSpacesAW [SHELL32.55]
957  */
958 LPVOID WINAPI PathQuoteSpacesAW (LPVOID lpszPath)
959 {
960         if(VERSION_OsIsUnicode())
961           return PathQuoteSpacesW(lpszPath);
962         return PathQuoteSpacesA(lpszPath);
963 }
964
965 /*************************************************************************
966  * PathUnquoteSpacesA [SHLWAPI.@]
967  * 
968  * NOTES
969  *     unquote string (remove ")
970  */
971 VOID WINAPI PathUnquoteSpacesA(LPSTR str) 
972 {
973         DWORD len = lstrlenA(str);
974
975         TRACE("%s\n",str);
976
977         if (*str!='"')
978           return;
979         if (str[len-1]!='"')
980           return;
981         str[len-1]='\0';
982         lstrcpyA(str,str+1);
983         return;
984 }
985
986 /*************************************************************************
987  * PathUnquoteSpacesW [SHLWAPI.@]
988  */
989 VOID WINAPI PathUnquoteSpacesW(LPWSTR str) 
990 {
991         DWORD len = strlenW(str);
992
993         TRACE("%s\n",debugstr_w(str));
994
995         if (*str!='"')
996           return;
997         if (str[len-1]!='"')
998           return;
999         str[len-1]='\0';
1000         strcpyW(str,str+1);
1001         return;
1002 }
1003
1004 /*************************************************************************
1005  * PathUnquoteSpacesAW [SHELL32.56]
1006  */
1007 VOID WINAPI PathUnquoteSpacesAW(LPVOID str) 
1008 {
1009         if(VERSION_OsIsUnicode())
1010           PathUnquoteSpacesW(str);
1011         else
1012           PathUnquoteSpacesA(str);
1013 }
1014
1015 /*************************************************************************
1016  * PathParseIconLocationA       [SHLWAPI.@]
1017  */
1018 int WINAPI PathParseIconLocationA(LPSTR lpszPath)
1019 {
1020         LPSTR lpstrComma = strchr(lpszPath, ',');
1021         
1022         FIXME("%s stub\n", debugstr_a(lpszPath));
1023
1024         if (lpstrComma && lpstrComma[1])
1025         {
1026           lpstrComma[0]='\0';
1027 /*        return atoi(&lpstrComma[1]);  FIXME */
1028         }
1029         
1030         PathUnquoteSpacesA(lpszPath);
1031         return 0;
1032 }
1033
1034 /*************************************************************************
1035  * PathParseIconLocationW       [SHLWAPI.@]
1036  */
1037 int WINAPI PathParseIconLocationW(LPWSTR lpszPath)
1038 {
1039         LPWSTR lpstrComma = strchrW(lpszPath, ',');
1040         
1041         FIXME("%s stub\n", debugstr_w(lpszPath));
1042
1043         if (lpstrComma && lpstrComma[1])
1044         {
1045           lpstrComma[0]='\0';
1046 /*        return _wtoi(&lpstrComma[1]); FIXME */
1047         }
1048         PathUnquoteSpacesW(lpszPath);
1049         return 0;
1050 }
1051
1052 /*************************************************************************
1053  * PathParseIconLocationAW      [SHELL32.249]
1054  */
1055 int WINAPI PathParseIconLocationAW (LPVOID lpszPath)
1056 {
1057         if(VERSION_OsIsUnicode())
1058           return PathParseIconLocationW(lpszPath);
1059         return PathParseIconLocationA(lpszPath);
1060 }
1061
1062 /*
1063         Path Testing
1064 */
1065 /*************************************************************************
1066  * PathIsUNCA           [SHLWAPI.@]
1067  * 
1068  * NOTES
1069  *     PathIsUNC(char*path);
1070  */
1071 BOOL WINAPI PathIsUNCA(LPCSTR lpszPath) 
1072 {
1073         TRACE("%s\n",lpszPath);
1074
1075         return (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\'));
1076 }
1077
1078 /*************************************************************************
1079  * PathIsUNCW           [SHLWAPI.@]
1080  */
1081 BOOL WINAPI PathIsUNCW(LPCWSTR lpszPath) 
1082 {
1083         TRACE("%s\n",debugstr_w(lpszPath));
1084
1085         return (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\'));
1086 }
1087
1088 /*************************************************************************
1089  * PathIsUNCAW          [SHELL32.39]
1090  */
1091 BOOL WINAPI PathIsUNCAW (LPCVOID lpszPath)
1092 {
1093         if (VERSION_OsIsUnicode())
1094           return PathIsUNCW( lpszPath );
1095         return PathIsUNCA( lpszPath );  
1096 }
1097
1098 /*************************************************************************
1099  *  PathIsRelativeA     [SHLWAPI.@]
1100  */
1101 BOOL WINAPI PathIsRelativeA (LPCSTR lpszPath)
1102 {
1103         TRACE("lpszPath=%s\n",lpszPath);
1104
1105         return (lpszPath && (lpszPath[0]!='\\' && lpszPath[1]!=':'));
1106 }
1107
1108 /*************************************************************************
1109  *  PathIsRelativeW     [SHLWAPI.@]
1110  */
1111 BOOL WINAPI PathIsRelativeW (LPCWSTR lpszPath)
1112 {
1113         TRACE("lpszPath=%s\n",debugstr_w(lpszPath));
1114
1115         return (lpszPath && (lpszPath[0]!='\\' && lpszPath[1]!=':'));
1116 }
1117
1118 /*************************************************************************
1119  *  PathIsRelativeAW    [SHELL32.40]
1120  */
1121 BOOL WINAPI PathIsRelativeAW (LPCVOID lpszPath)
1122 {
1123         if (VERSION_OsIsUnicode())
1124           return PathIsRelativeW( lpszPath );
1125         return PathIsRelativeA( lpszPath );  
1126 }
1127
1128 /*************************************************************************
1129  * PathIsRootA          [SHLWAPI.@]
1130  *
1131  * notes
1132  *  TRUE if the path points to a root directory
1133  */
1134 BOOL WINAPI PathIsRootA(LPCSTR lpszPath)
1135 {
1136         TRACE("%s\n",lpszPath);
1137
1138         /* X:\ */
1139         if (lpszPath[1]==':' && lpszPath[2]=='\\' && lpszPath[3]=='\0')
1140           return TRUE;
1141
1142         /* "\" */
1143         if (lpszPath[0]=='\\' && lpszPath[1]=='\0')
1144           return TRUE;
1145
1146         /* UNC "\\<computer>\<share>" */
1147         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
1148         {
1149           int foundbackslash = 0;
1150           lpszPath += 2;
1151           while (*lpszPath)
1152           {
1153             if (*(lpszPath++)=='\\') foundbackslash++;
1154           }
1155           if (foundbackslash <= 1)
1156             return TRUE;
1157         }
1158         return FALSE;
1159 }
1160
1161 /*************************************************************************
1162  * PathIsRootW          [SHLWAPI.@]
1163  */
1164 BOOL WINAPI PathIsRootW(LPCWSTR lpszPath) 
1165 {
1166         TRACE("%s\n",debugstr_w(lpszPath));
1167
1168         /* X:\ */
1169         if (lpszPath[1]==':' && lpszPath[2]=='\\' && lpszPath[3]=='\0')
1170           return TRUE;
1171
1172         /* "\" */
1173         if (lpszPath[0]=='\\' && lpszPath[1]=='\0')
1174           return TRUE;
1175
1176         /* UNC "\\<computer>\<share>" */
1177         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
1178         {
1179           int foundbackslash = 0;
1180           lpszPath += 2;
1181           while (*lpszPath)
1182           {
1183             if (*(lpszPath++)=='\\') foundbackslash++;
1184           }
1185           if (foundbackslash <= 1)
1186             return TRUE;
1187         }
1188         return FALSE;
1189
1190 }
1191
1192 /*************************************************************************
1193  * PathIsRootAW         [SHELL32.29]
1194  */
1195 BOOL WINAPI PathIsRootAW(LPCVOID lpszPath) 
1196 {
1197         if (VERSION_OsIsUnicode())
1198           return PathIsRootW(lpszPath);
1199         return PathIsRootA(lpszPath);
1200 }
1201
1202 /*************************************************************************
1203  *  PathIsExeA          [internal]
1204  */
1205 BOOL WINAPI PathIsExeA (LPCSTR lpszPath)
1206 {
1207         LPCSTR lpszExtension = PathGetExtensionA(lpszPath);
1208         int i = 0;
1209         static char * lpszExtensions[6] = {"exe", "com", "pid", "cmd", "bat", NULL };
1210         
1211         TRACE("path=%s\n",lpszPath);
1212
1213         for(i=0; lpszExtensions[i]; i++)
1214           if (!strcasecmp(lpszExtension,lpszExtensions[i])) return TRUE;
1215           
1216         return FALSE;
1217 }
1218
1219 /*************************************************************************
1220  *  PathIsExeW          [internal]
1221  */
1222 BOOL WINAPI PathIsExeW (LPCWSTR lpszPath)
1223 {
1224         LPCWSTR lpszExtension = PathGetExtensionW(lpszPath);
1225         int i = 0;
1226         static WCHAR lpszExtensions[6][4] =
1227           {{'e','x','e','\0'}, {'c','o','m','\0'}, {'p','i','d','\0'},
1228            {'c','m','d','\0'}, {'b','a','t','\0'}, {'\0'} };
1229         
1230         TRACE("path=%s\n",debugstr_w(lpszPath));
1231
1232         for(i=0; lpszExtensions[i]; i++)
1233           if (!strcmpiW(lpszExtension,lpszExtensions[i])) return TRUE;
1234           
1235         return FALSE;
1236 }
1237
1238 /*************************************************************************
1239  *  PathIsExeAW         [SHELL32.43]
1240  */
1241 BOOL WINAPI PathIsExeAW (LPCVOID path)
1242 {
1243         if (VERSION_OsIsUnicode())
1244           return PathIsExeW (path);
1245         return PathIsExeA(path);
1246 }
1247
1248 /*************************************************************************
1249  * PathIsDirectoryA     [SHLWAPI.@]
1250  */
1251 BOOL WINAPI PathIsDirectoryA(LPCSTR lpszPath)
1252 {
1253         HANDLE hFile;
1254         WIN32_FIND_DATAA stffile;
1255         
1256         TRACE("%s\n", debugstr_a(lpszPath));
1257
1258         hFile = FindFirstFileA(lpszPath, &stffile);
1259
1260         if ( hFile != INVALID_HANDLE_VALUE )
1261         {
1262           FindClose (hFile);
1263           return (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
1264         }
1265
1266         return FALSE;   
1267 }
1268
1269 /*************************************************************************
1270  * PathIsDirectoryW     [SHLWAPI.@]
1271  */
1272 BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
1273 {
1274         HANDLE hFile;
1275         WIN32_FIND_DATAW stffile;
1276         
1277         TRACE("%s\n", debugstr_w(lpszPath));
1278
1279         hFile = FindFirstFileW(lpszPath, &stffile);
1280
1281         if ( hFile != INVALID_HANDLE_VALUE )
1282         {
1283           FindClose (hFile);
1284           return (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
1285         }
1286
1287         return FALSE;   
1288 }
1289
1290 /*************************************************************************
1291  * PathIsDirectoryAW    [SHELL32.159]
1292  */
1293 BOOL WINAPI PathIsDirectoryAW (LPCVOID lpszPath)
1294 {
1295         if (VERSION_OsIsUnicode())
1296           return PathIsDirectoryW (lpszPath);
1297         return PathIsDirectoryA (lpszPath);
1298 }
1299
1300 /*************************************************************************
1301  * PathFileExistsA      [SHLWAPI.@]
1302  * 
1303  * NOTES
1304  *     file_exists(char *fn);
1305  */
1306 BOOL WINAPI PathFileExistsA(LPCSTR lpszPath) 
1307 {
1308         TRACE("%s\n",lpszPath);
1309         return  (GetFileAttributesA(lpszPath)!=-1);
1310 }
1311
1312 /*************************************************************************
1313  * PathFileExistsW      [SHLWAPI.@]
1314  */
1315 BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath) 
1316 {
1317         TRACE("%s\n",debugstr_w(lpszPath));
1318         return  (GetFileAttributesW(lpszPath)!=-1);
1319 }
1320
1321 /*************************************************************************
1322  * PathFileExistsAW     [SHELL32.45]
1323  */ 
1324 BOOL WINAPI PathFileExistsAW (LPCVOID lpszPath)
1325 {
1326         if (VERSION_OsIsUnicode())
1327           return PathFileExistsW (lpszPath);
1328         return PathFileExistsA (lpszPath);
1329 }
1330
1331 /*************************************************************************
1332  * PathMatchSingleMaskA [internal]
1333  * 
1334  * NOTES
1335  *     internal (used by PathMatchSpec)
1336  */
1337 static BOOL PathMatchSingleMaskA(LPCSTR name, LPCSTR mask)
1338 {
1339         while (*name && *mask && *mask!=';') 
1340         {
1341           if (*mask=='*') 
1342           {
1343             do 
1344             {
1345               if (PathMatchSingleMaskA(name,mask+1)) return 1;  /* try substrings */
1346             } while (*name++);
1347             return 0;
1348           }
1349           if (toupper(*mask)!=toupper(*name) && *mask!='?') return 0;
1350           name++;
1351           mask++;
1352         }
1353         if (!*name) 
1354         {
1355           while (*mask=='*') mask++;
1356           if (!*mask || *mask==';') return 1;
1357         }
1358         return 0;
1359 }
1360
1361 /*************************************************************************
1362  * PathMatchSingleMaskW [internal]
1363  */
1364 static BOOL PathMatchSingleMaskW(LPCWSTR name, LPCWSTR mask)
1365 {
1366         while (*name && *mask && *mask!=';') 
1367         {
1368           if (*mask=='*') 
1369           {
1370             do 
1371             {
1372               if (PathMatchSingleMaskW(name,mask+1)) return 1;  /* try substrings */
1373             } while (*name++);
1374             return 0;
1375           }
1376           if (toupperW(*mask)!=toupperW(*name) && *mask!='?') return 0;
1377           name++;
1378           mask++;
1379         }
1380         if (!*name) 
1381         {
1382           while (*mask=='*') mask++;
1383           if (!*mask || *mask==';') return 1;
1384         }
1385         return 0;
1386 }
1387 /*************************************************************************
1388  * PathMatchSpecA       [SHLWAPI.@]
1389  * 
1390  * NOTES
1391  *     used from COMDLG32
1392  */
1393 BOOL WINAPI PathMatchSpecA(LPCSTR name, LPCSTR mask) 
1394 {
1395         TRACE("%s %s\n",name,mask);
1396
1397         if (!lstrcmpA( mask, "*.*" )) return 1;   /* we don't require a period */
1398
1399         while (*mask) 
1400         {
1401           if (PathMatchSingleMaskA(name,mask)) return 1;    /* helper function */
1402           while (*mask && *mask!=';') mask++;
1403           if (*mask==';') 
1404           {
1405             mask++;
1406             while (*mask==' ') mask++;      /*  masks may be separated by "; " */
1407           }
1408         }
1409         return 0;
1410 }
1411
1412 /*************************************************************************
1413  * PathMatchSpecW       [SHLWAPI.@]
1414  */
1415 BOOL WINAPI PathMatchSpecW(LPCWSTR name, LPCWSTR mask) 
1416 {
1417         WCHAR stemp[4];
1418         TRACE("%s %s\n",debugstr_w(name),debugstr_w(mask));
1419
1420         lstrcpyAtoW(stemp,"*.*");       
1421         if (!lstrcmpW( mask, stemp )) return 1;   /* we don't require a period */
1422
1423         while (*mask) 
1424         {
1425           if (PathMatchSingleMaskW(name,mask)) return 1;    /* helper function */
1426           while (*mask && *mask!=';') mask++;
1427           if (*mask==';') 
1428           {
1429             mask++;
1430             while (*mask==' ') mask++;       /* masks may be separated by "; " */
1431           }
1432         }
1433         return 0;
1434 }
1435
1436 /*************************************************************************
1437  * PathMatchSpecAW      [SHELL32.46]
1438  */
1439 BOOL WINAPI PathMatchSpecAW(LPVOID name, LPVOID mask) 
1440 {
1441         if (VERSION_OsIsUnicode())
1442           return PathMatchSpecW( name, mask );
1443         return PathMatchSpecA( name, mask );
1444 }
1445
1446 /*************************************************************************
1447  * PathIsSameRootA      [SHLWAPI.@]
1448  *
1449  * FIXME
1450  *  what to do with "\path" ??
1451  */
1452 BOOL WINAPI PathIsSameRootA(LPCSTR lpszPath1, LPCSTR lpszPath2)
1453 {
1454         TRACE("%s %s\n", lpszPath1, lpszPath2);
1455         
1456         if (PathIsRelativeA(lpszPath1) || PathIsRelativeA(lpszPath2)) return FALSE;
1457
1458         /* usual path */
1459         if ( toupper(lpszPath1[0])==toupper(lpszPath2[0]) &&
1460              lpszPath1[1]==':' && lpszPath2[1]==':' &&
1461              lpszPath1[2]=='\\' && lpszPath2[2]=='\\')
1462           return TRUE;
1463
1464         /* UNC */
1465         if (lpszPath1[0]=='\\' && lpszPath2[0]=='\\' &&
1466             lpszPath1[1]=='\\' && lpszPath2[1]=='\\')
1467         {
1468           int pos=2, bsfound=0;
1469           while (lpszPath1[pos] && lpszPath2[pos] &&
1470                 (lpszPath1[pos] == lpszPath2[pos]))
1471           {
1472             if (lpszPath1[pos]=='\\') bsfound++;
1473             if (bsfound == 2) return TRUE;
1474             pos++;
1475           }
1476           return (lpszPath1[pos] == lpszPath2[pos]);
1477         }
1478         return FALSE;
1479 }
1480
1481 /*************************************************************************
1482  * PathIsSameRootW      [SHLWAPI.@]
1483  */
1484 BOOL WINAPI PathIsSameRootW(LPCWSTR lpszPath1, LPCWSTR lpszPath2)
1485 {
1486         TRACE("%s %s\n", debugstr_w(lpszPath1), debugstr_w(lpszPath2));
1487         
1488         if (PathIsRelativeW(lpszPath1) || PathIsRelativeW(lpszPath2)) return FALSE;
1489
1490         /* usual path */
1491         if ( toupperW(lpszPath1[0])==toupperW(lpszPath2[0]) &&
1492              lpszPath1[1]==':' && lpszPath2[1]==':' &&
1493              lpszPath1[2]=='\\' && lpszPath2[2]=='\\')
1494           return TRUE;
1495
1496         /* UNC */
1497         if (lpszPath1[0]=='\\' && lpszPath2[0]=='\\' &&
1498             lpszPath1[1]=='\\' && lpszPath2[1]=='\\')
1499         {
1500           int pos=2, bsfound=0;
1501           while (lpszPath1[pos] && lpszPath2[pos] &&
1502                 (lpszPath1[pos] == lpszPath2[pos]))
1503           {
1504             if (lpszPath1[pos]=='\\') bsfound++;
1505             if (bsfound == 2) return TRUE;
1506             pos++;
1507           }
1508           return (lpszPath1[pos] == lpszPath2[pos]);
1509         }
1510         return FALSE;
1511 }
1512
1513 /*************************************************************************
1514  * PathIsSameRootAW     [SHELL32.650]
1515  */
1516 BOOL WINAPI PathIsSameRootAW(LPCVOID lpszPath1, LPCVOID lpszPath2)
1517 {
1518         if (VERSION_OsIsUnicode())
1519           return PathIsSameRootW(lpszPath1, lpszPath2);
1520         return PathIsSameRootA(lpszPath1, lpszPath2);
1521 }
1522
1523 /*************************************************************************
1524  * PathIsURLA
1525  */
1526 BOOL WINAPI PathIsURLA(LPCSTR lpstrPath)
1527 {
1528         LPSTR lpstrRes;
1529         int iSize, i=0;
1530         static LPSTR SupportedProtocol[] = 
1531           {"http","https","ftp","gopher","file","mailto",NULL};
1532
1533         if(!lpstrPath) return FALSE;
1534
1535         /* get protocol        */
1536         lpstrRes = strchr(lpstrPath,':');
1537         if(!lpstrRes) return FALSE;
1538         iSize = lpstrRes - lpstrPath;
1539
1540         while(SupportedProtocol[i])
1541         {
1542           if (iSize == strlen(SupportedProtocol[i]))
1543             if(!strncasecmp(lpstrPath, SupportedProtocol[i], iSize))
1544               return TRUE;
1545           i++;
1546         }
1547
1548         return FALSE;
1549 }  
1550
1551 /*************************************************************************
1552  * PathIsURLW
1553  */
1554 BOOL WINAPI PathIsURLW(LPCWSTR lpstrPath)
1555 {
1556         LPWSTR lpstrRes;
1557         int iSize, i=0;
1558         static WCHAR SupportedProtocol[7][7] = 
1559           {{'h','t','t','p','\0'},{'h','t','t','p','s','\0'},{'f','t','p','\0'},
1560           {'g','o','p','h','e','r','\0'},{'f','i','l','e','\0'},
1561           {'m','a','i','l','t','o','\0'},{0}};
1562
1563         if(!lpstrPath) return FALSE;
1564
1565         /* get protocol        */
1566         lpstrRes = strchrW(lpstrPath,':');
1567         if(!lpstrRes) return FALSE;
1568         iSize = lpstrRes - lpstrPath;
1569
1570         while(SupportedProtocol[i])
1571         {
1572           if (iSize == strlenW(SupportedProtocol[i]))
1573             if(!strncmpiW(lpstrPath, SupportedProtocol[i], iSize))
1574               return TRUE;
1575           i++;
1576         }
1577
1578         return FALSE;
1579 }  
1580
1581 /*************************************************************************
1582  * IsLFNDriveA          [SHELL32.119]
1583  * 
1584  * NOTES
1585  *     exported by ordinal Name
1586  */
1587 BOOL WINAPI IsLFNDriveA(LPCSTR lpszPath) 
1588 {
1589     DWORD       fnlen;
1590
1591     if (!GetVolumeInformationA(lpszPath,NULL,0,NULL,&fnlen,NULL,NULL,0))
1592         return FALSE;
1593     return fnlen>12;
1594 }
1595
1596 /*
1597         Creating Something Unique
1598 */
1599 /*************************************************************************
1600  * PathMakeUniqueNameA  [internal]
1601  */
1602 BOOL WINAPI PathMakeUniqueNameA(
1603         LPSTR lpszBuffer,
1604         DWORD dwBuffSize, 
1605         LPCSTR lpszShortName,
1606         LPCSTR lpszLongName,
1607         LPCSTR lpszPathName)
1608 {
1609         FIXME("%p %lu %s %s %s stub\n",
1610          lpszBuffer, dwBuffSize, debugstr_a(lpszShortName),
1611          debugstr_a(lpszLongName), debugstr_a(lpszPathName));
1612         return TRUE;
1613 }
1614
1615 /*************************************************************************
1616  * PathMakeUniqueNameW  [internal]
1617  */
1618 BOOL WINAPI PathMakeUniqueNameW(
1619         LPWSTR lpszBuffer,
1620         DWORD dwBuffSize, 
1621         LPCWSTR lpszShortName,
1622         LPCWSTR lpszLongName,
1623         LPCWSTR lpszPathName)
1624 {
1625         FIXME("%p %lu %s %s %s stub\n",
1626          lpszBuffer, dwBuffSize, debugstr_w(lpszShortName),
1627          debugstr_w(lpszLongName), debugstr_w(lpszPathName));
1628         return TRUE;
1629 }
1630
1631 /*************************************************************************
1632  * PathMakeUniqueNameAW [SHELL32.47]
1633  */
1634 BOOL WINAPI PathMakeUniqueNameAW(
1635         LPVOID lpszBuffer,
1636         DWORD dwBuffSize, 
1637         LPCVOID lpszShortName,
1638         LPCVOID lpszLongName,
1639         LPCVOID lpszPathName)
1640 {
1641         if (VERSION_OsIsUnicode())
1642           return PathMakeUniqueNameW(lpszBuffer,dwBuffSize, lpszShortName,lpszLongName,lpszPathName);
1643         return PathMakeUniqueNameA(lpszBuffer,dwBuffSize, lpszShortName,lpszLongName,lpszPathName);
1644 }
1645
1646 /*************************************************************************
1647  * PathYetAnotherMakeUniqueNameA [SHELL32.75]
1648  * 
1649  * NOTES
1650  *     exported by ordinal
1651  */
1652 BOOL WINAPI PathYetAnotherMakeUniqueNameA(
1653         LPSTR lpszBuffer,
1654         LPCSTR lpszPathName,
1655         LPCSTR lpszShortName,
1656         LPCSTR lpszLongName)
1657 {
1658     FIXME("(%p,%p, %p ,%p):stub.\n",
1659      lpszBuffer, lpszPathName, lpszShortName, lpszLongName);
1660     return TRUE;
1661 }
1662
1663
1664 /*
1665         cleaning and resolving paths 
1666  */
1667
1668 /*************************************************************************
1669  * PathFindOnPathA      [SHELL32.145]
1670  */
1671 BOOL WINAPI PathFindOnPathA(LPSTR sFile, LPCSTR sOtherDirs)
1672 {
1673         FIXME("%s %s\n",sFile, sOtherDirs);
1674         return FALSE;
1675 }
1676
1677 /*************************************************************************
1678  * PathFindOnPathW      [SHELL32]
1679  */
1680 BOOL WINAPI PathFindOnPathW(LPWSTR sFile, LPCWSTR sOtherDirs)
1681 {
1682         FIXME("%s %s\n",debugstr_w(sFile), debugstr_w(sOtherDirs));
1683         return FALSE;
1684 }
1685
1686 /*************************************************************************
1687  * PathFindOnPathAW     [SHELL32]
1688  */
1689 BOOL WINAPI PathFindOnPathAW(LPVOID sFile, LPCVOID sOtherDirs)
1690 {
1691         if (VERSION_OsIsUnicode())
1692           return PathFindOnPathW(sFile, sOtherDirs);
1693         return PathFindOnPathA(sFile, sOtherDirs);
1694 }
1695
1696 /*************************************************************************
1697  * PathCleanupSpecA     [SHELL32.171]
1698  */
1699 DWORD WINAPI PathCleanupSpecA(LPSTR x, LPSTR y)
1700 {
1701         FIXME("(%p %s, %p %s) stub\n",x,debugstr_a(x),y,debugstr_a(y));
1702         return TRUE;
1703 }
1704
1705 /*************************************************************************
1706  * PathCleanupSpecA     [SHELL32]
1707  */
1708 DWORD WINAPI PathCleanupSpecW(LPWSTR x, LPWSTR y)
1709 {
1710         FIXME("(%p %s, %p %s) stub\n",x,debugstr_w(x),y,debugstr_w(y));
1711         return TRUE;
1712 }
1713
1714 /*************************************************************************
1715  * PathCleanupSpecAW    [SHELL32]
1716  */
1717 DWORD WINAPI PathCleanupSpecAW (LPVOID x, LPVOID y)
1718 {
1719         if (VERSION_OsIsUnicode())
1720           return PathCleanupSpecW(x,y);
1721         return PathCleanupSpecA(x,y);
1722 }
1723
1724 /*************************************************************************
1725  * PathQualifyA         [SHELL32]
1726  */
1727 BOOL WINAPI PathQualifyA(LPCSTR pszPath) 
1728 {
1729         FIXME("%s\n",pszPath);
1730         return 0;
1731 }
1732
1733 /*************************************************************************
1734  * PathQualifyW         [SHELL32]
1735  */
1736 BOOL WINAPI PathQualifyW(LPCWSTR pszPath) 
1737 {
1738         FIXME("%s\n",debugstr_w(pszPath));
1739         return 0;
1740 }
1741
1742 /*************************************************************************
1743  * PathQualifyAW        [SHELL32]
1744  */
1745 BOOL WINAPI PathQualifyAW(LPCVOID pszPath) 
1746 {
1747         if (VERSION_OsIsUnicode())
1748           return PathQualifyW(pszPath);
1749         return PathQualifyA(pszPath);
1750 }
1751
1752 /*************************************************************************
1753  * PathResolveA [SHELL32.51]
1754  */
1755 BOOL WINAPI PathResolveA(
1756         LPSTR lpszPath,
1757         LPCSTR *alpszPaths, 
1758         DWORD dwFlags)
1759 {
1760         FIXME("(%s,%p,0x%08lx),stub!\n",
1761           lpszPath, *alpszPaths, dwFlags);
1762         return 0;
1763 }
1764
1765 /*************************************************************************
1766  * PathResolveW [SHELL32]
1767  */
1768 BOOL WINAPI PathResolveW(
1769         LPWSTR lpszPath,
1770         LPCWSTR *alpszPaths, 
1771         DWORD dwFlags)
1772 {
1773         FIXME("(%s,%p,0x%08lx),stub!\n",
1774           debugstr_w(lpszPath), debugstr_w(*alpszPaths), dwFlags);
1775         return 0;
1776 }
1777
1778 /*************************************************************************
1779  * PathResolveAW [SHELL32]
1780  */
1781 BOOL WINAPI PathResolveAW(
1782         LPVOID lpszPath,
1783         LPCVOID *alpszPaths, 
1784         DWORD dwFlags)
1785 {
1786         if (VERSION_OsIsUnicode())
1787           return PathResolveW(lpszPath, (LPCWSTR*)alpszPaths, dwFlags);
1788         return PathResolveA(lpszPath, (LPCSTR*)alpszPaths, dwFlags);
1789 }
1790
1791 /*************************************************************************
1792 *       PathProcessCommandA     [SHELL32.653]
1793 */
1794 HRESULT WINAPI PathProcessCommandA (
1795         LPCSTR lpszPath,
1796         LPSTR lpszBuff,
1797         DWORD dwBuffSize,
1798         DWORD dwFlags)
1799 {
1800         FIXME("%s %p 0x%04lx 0x%04lx stub\n",
1801         lpszPath, lpszBuff, dwBuffSize, dwFlags);
1802         lstrcpyA(lpszBuff, lpszPath);
1803         return 0;
1804 }
1805
1806 /*************************************************************************
1807 *       PathProcessCommandW
1808 */
1809 HRESULT WINAPI PathProcessCommandW (
1810         LPCWSTR lpszPath,
1811         LPWSTR lpszBuff,
1812         DWORD dwBuffSize,
1813         DWORD dwFlags)
1814 {
1815         FIXME("(%s, %p, 0x%04lx, 0x%04lx) stub\n",
1816         debugstr_w(lpszPath), lpszBuff, dwBuffSize, dwFlags);
1817         lstrcpyW(lpszBuff, lpszPath);
1818         return 0;
1819 }
1820
1821 /*************************************************************************
1822 *       PathProcessCommandAW
1823 */
1824 HRESULT WINAPI PathProcessCommandAW (
1825         LPCVOID lpszPath,
1826         LPVOID lpszBuff,
1827         DWORD dwBuffSize,
1828         DWORD dwFlags)
1829 {
1830         if (VERSION_OsIsUnicode())
1831           return PathProcessCommandW(lpszPath, lpszBuff, dwBuffSize, dwFlags);
1832         return PathProcessCommandA(lpszPath, lpszBuff, dwBuffSize, dwFlags);
1833 }
1834
1835 /*
1836         special
1837 */
1838
1839 /*************************************************************************
1840  * PathSetDlgItemPathA
1841  *
1842  * NOTES
1843  *  use PathCompactPath to make sure, the path fits into the control
1844  */
1845 BOOL WINAPI PathSetDlgItemPathA(HWND hDlg, int id, LPCSTR pszPath) 
1846 {       TRACE("%x %x %s\n",hDlg, id, pszPath);
1847         return SetDlgItemTextA(hDlg, id, pszPath);
1848 }
1849
1850 /*************************************************************************
1851  * PathSetDlgItemPathW
1852  */
1853 BOOL WINAPI PathSetDlgItemPathW(HWND hDlg, int id, LPCWSTR pszPath) 
1854 {       TRACE("%x %x %s\n",hDlg, id, debugstr_w(pszPath));
1855         return SetDlgItemTextW(hDlg, id, pszPath);
1856 }
1857
1858 /*************************************************************************
1859  * PathSetDlgItemPathAW
1860  */
1861 BOOL WINAPI PathSetDlgItemPathAW(HWND hDlg, int id, LPCVOID pszPath) 
1862 {       if (VERSION_OsIsUnicode())
1863           return PathSetDlgItemPathW(hDlg, id, pszPath);
1864         return PathSetDlgItemPathA(hDlg, id, pszPath);
1865 }
1866
1867
1868 /*************************************************************************
1869  * SHGetSpecialFolderPathA [SHELL32.175]
1870  * 
1871  * converts csidl to path
1872  * 
1873  */
1874  
1875 static char * szSHFolders = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders";
1876 static char * szSHUserFolders = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders";
1877
1878 BOOL WINAPI SHGetSpecialFolderPathA (
1879         HWND hwndOwner,
1880         LPSTR szPath,
1881         DWORD csidl,
1882         BOOL bCreate)
1883 {
1884         CHAR    szValueName[MAX_PATH], szDefaultPath[MAX_PATH];
1885         HKEY    hRootKey, hKey;
1886         BOOL    bRelative = TRUE;
1887         DWORD   dwType, dwDisp, dwPathLen = MAX_PATH;
1888
1889         TRACE("0x%04x,%p,csidl=%lu,0x%04x\n", hwndOwner,szPath,csidl,bCreate);
1890
1891         /* build default values */
1892         switch(csidl)
1893         {
1894           case CSIDL_APPDATA:
1895             hRootKey = HKEY_CURRENT_USER;
1896             strcpy (szValueName, "AppData");
1897             strcpy (szDefaultPath, "AppData");
1898             break;
1899
1900           case CSIDL_COOKIES:
1901             hRootKey = HKEY_CURRENT_USER;
1902             strcpy (szValueName, "Cookies");
1903             strcpy(szDefaultPath, "Cookies");
1904             break;
1905
1906           case CSIDL_DESKTOPDIRECTORY:
1907             hRootKey = HKEY_CURRENT_USER;
1908             strcpy(szValueName, "Desktop");
1909             strcpy(szDefaultPath, "Desktop");
1910             break;
1911
1912           case CSIDL_COMMON_DESKTOPDIRECTORY:
1913             hRootKey = HKEY_LOCAL_MACHINE;
1914             strcpy(szValueName, "Common Desktop");
1915             strcpy(szDefaultPath, "Desktop");
1916             break;
1917
1918           case CSIDL_FAVORITES:
1919             hRootKey = HKEY_CURRENT_USER;
1920             strcpy(szValueName, "Favorites");
1921             strcpy(szDefaultPath, "Favorites");
1922             break;
1923
1924           case CSIDL_FONTS:
1925             hRootKey = HKEY_CURRENT_USER;
1926             strcpy(szValueName, "Fonts");
1927             strcpy(szDefaultPath, "Fonts");
1928             break;
1929
1930           case CSIDL_HISTORY:
1931             hRootKey = HKEY_CURRENT_USER;
1932             strcpy(szValueName, "History");
1933             strcpy(szDefaultPath, "History");
1934             break;
1935
1936           case CSIDL_NETHOOD:
1937             hRootKey = HKEY_CURRENT_USER;
1938             strcpy(szValueName, "NetHood");
1939             strcpy(szDefaultPath, "NetHood");
1940             break;
1941
1942           case CSIDL_INTERNET_CACHE:
1943             hRootKey = HKEY_CURRENT_USER;
1944             strcpy(szValueName, "Cache");
1945             strcpy(szDefaultPath, "Temporary Internet Files");
1946             break;
1947
1948           case CSIDL_PERSONAL:
1949             hRootKey = HKEY_CURRENT_USER;
1950             strcpy(szValueName, "Personal");
1951             strcpy(szDefaultPath, "My Own Files");
1952             bRelative = FALSE;
1953             break;
1954
1955           case CSIDL_PRINTHOOD:
1956             hRootKey = HKEY_CURRENT_USER;
1957             strcpy(szValueName, "PrintHood");
1958             strcpy(szDefaultPath, "PrintHood");
1959             break;
1960
1961           case CSIDL_PROGRAMS:
1962             hRootKey = HKEY_CURRENT_USER;
1963             strcpy(szValueName, "Programs");
1964             strcpy(szDefaultPath, "StartMenu\\Programs");
1965             break;
1966
1967           case CSIDL_COMMON_PROGRAMS:
1968             hRootKey = HKEY_LOCAL_MACHINE;
1969             strcpy(szValueName, "Common Programs");
1970             strcpy(szDefaultPath, "");
1971             break;
1972
1973           case CSIDL_RECENT:
1974             hRootKey = HKEY_CURRENT_USER;
1975             strcpy(szValueName, "Recent");
1976             strcpy(szDefaultPath, "Recent");
1977             break;
1978
1979           case CSIDL_SENDTO:
1980             hRootKey = HKEY_CURRENT_USER;
1981             strcpy(szValueName, "SendTo");
1982             strcpy(szDefaultPath, "SendTo");
1983             break;
1984
1985           case CSIDL_STARTMENU:
1986             hRootKey = HKEY_CURRENT_USER;
1987             strcpy(szValueName, "StartMenu");
1988             strcpy(szDefaultPath, "StartMenu");
1989             break;
1990
1991           case CSIDL_COMMON_STARTMENU:
1992             hRootKey = HKEY_LOCAL_MACHINE;
1993             strcpy(szValueName, "Common StartMenu");
1994             strcpy(szDefaultPath, "StartMenu");
1995             break;
1996
1997           case CSIDL_STARTUP:
1998             hRootKey = HKEY_CURRENT_USER;
1999             strcpy(szValueName, "Startup");
2000             strcpy(szDefaultPath, "StartMenu\\Programs\\Startup");
2001             break;
2002
2003           case CSIDL_COMMON_STARTUP:
2004             hRootKey = HKEY_LOCAL_MACHINE;
2005             strcpy(szValueName, "Common Startup");
2006             strcpy(szDefaultPath, "StartMenu\\Programs\\Startup");
2007             break;
2008
2009           case CSIDL_TEMPLATES:
2010             hRootKey = HKEY_CURRENT_USER;
2011             strcpy(szValueName, "Templates");
2012             strcpy(szDefaultPath, "ShellNew");
2013             break;
2014
2015           default:
2016             ERR("folder unknown or not allowed\n");
2017             return FALSE;
2018         }
2019
2020         /* user shell folders */
2021         if (RegCreateKeyExA(hRootKey,szSHUserFolders,0,NULL,0,KEY_ALL_ACCESS,NULL,&hKey,&dwDisp)) return FALSE;
2022
2023         if (RegQueryValueExA(hKey,szValueName,NULL,&dwType,(LPBYTE)szPath,&dwPathLen))
2024         {
2025           RegCloseKey(hKey);
2026
2027           /* shell folders */
2028           if (RegCreateKeyExA(hRootKey,szSHFolders,0,NULL,0,KEY_ALL_ACCESS,NULL,&hKey,&dwDisp)) return FALSE;
2029
2030           if (RegQueryValueExA(hKey,szValueName,NULL,&dwType,(LPBYTE)szPath,&dwPathLen))
2031           {
2032
2033             /* value not existing */
2034             if (bRelative)
2035             {
2036               GetWindowsDirectoryA(szPath, MAX_PATH);
2037               PathAddBackslashA(szPath);
2038               strcat(szPath, szDefaultPath);
2039             }
2040             else
2041             {
2042               strcpy(szPath, "C:\\");   /* fixme ??? */
2043               strcat(szPath, szDefaultPath);
2044             }
2045             RegSetValueExA(hKey,szValueName,0,REG_SZ,(LPBYTE)szPath,strlen(szPath)+1);
2046           }
2047         }
2048         RegCloseKey(hKey);
2049
2050         /* if we don't care about existing directorys we are ready */
2051         if(csidl & CSIDL_FLAG_DONT_VERIFY) return TRUE;
2052
2053         if (PathFileExistsA(szPath)) return TRUE;
2054
2055         /* not existing but we not allowed to create it */
2056         if (!bCreate) return FALSE;
2057         
2058         if (!CreateDirectoryA(szPath,NULL))
2059         {
2060           ERR("Failed to create directory '%s'.\n", szPath);
2061           return FALSE;
2062         }
2063
2064         MESSAGE("Created not existing system directory '%s'\n", szPath);
2065         return TRUE;
2066 }
2067
2068 /*************************************************************************
2069  * SHGetSpecialFolderPathW
2070  */
2071 BOOL WINAPI SHGetSpecialFolderPathW (
2072         HWND hwndOwner,
2073         LPWSTR szPath,
2074         DWORD csidl,
2075         BOOL bCreate)
2076 {
2077         char szTemp[MAX_PATH];
2078         
2079         if (SHGetSpecialFolderPathA(hwndOwner, szTemp, csidl, bCreate))
2080         {
2081           lstrcpynAtoW(szPath, szTemp, MAX_PATH);
2082         }
2083
2084         TRACE("0x%04x,%p,csidl=%lu,0x%04x\n", hwndOwner,szPath,csidl,bCreate);
2085
2086         return TRUE;
2087 }
2088
2089 /*************************************************************************
2090  * SHGetSpecialFolderPathAW
2091  */
2092 BOOL WINAPI SHGetSpecialFolderPathAW (
2093         HWND hwndOwner,
2094         LPVOID szPath,
2095         DWORD csidl,
2096         BOOL bCreate)
2097
2098 {
2099         if (VERSION_OsIsUnicode())
2100           return SHGetSpecialFolderPathW (hwndOwner, szPath, csidl, bCreate);
2101         return SHGetSpecialFolderPathA (hwndOwner, szPath, csidl, bCreate);
2102 }
2103
2104 /*************************************************************************
2105  * SHGetFolderPathA                     [SHFOLDER.@]
2106  */
2107 HRESULT WINAPI SHGetFolderPathA(
2108         HWND hwndOwner,
2109         int nFolder,
2110         HANDLE hToken,  /* FIXME: get paths for specific user */
2111         DWORD dwFlags,  /* FIXME: SHGFP_TYPE_CURRENT|SHGFP_TYPE_DEFAULT */
2112         LPSTR pszPath)
2113 {
2114         return (SHGetSpecialFolderPathA(
2115                 hwndOwner,
2116                 pszPath,
2117                 CSIDL_FOLDER_MASK & nFolder,
2118                 CSIDL_FLAG_CREATE & nFolder )) ? S_OK : E_FAIL;
2119 }
2120
2121 /*************************************************************************
2122  * SHGetFolderPathW                     [SHFOLDER.@]
2123  */
2124 HRESULT WINAPI SHGetFolderPathW(
2125         HWND hwndOwner,
2126         int nFolder,
2127         HANDLE hToken,
2128         DWORD dwFlags,
2129         LPWSTR pszPath)
2130 {
2131         return (SHGetSpecialFolderPathW(
2132                 hwndOwner,
2133                 pszPath,
2134                 CSIDL_FOLDER_MASK & nFolder,
2135                 CSIDL_FLAG_CREATE & nFolder )) ? S_OK : E_FAIL;
2136 }
2137
2138 /*************************************************************************
2139  * PathCanonicalizeA
2140  *
2141  *  FIXME
2142  *   returnvalue
2143  */
2144  
2145 BOOL WINAPI PathCanonicalizeA(LPSTR pszBuf, LPCSTR pszPath)
2146 {
2147         int OffsetMin = 0, OffsetSrc = 0, OffsetDst = 0, LenSrc = strlen(pszPath);
2148         BOOL bModifyed = FALSE;
2149
2150         TRACE("%p %s\n", pszBuf, pszPath);
2151         
2152         pszBuf[OffsetDst]='\0';
2153
2154         /* keep the root of the path */
2155         if( LenSrc && (pszPath[OffsetSrc]=='\\'))
2156         {
2157           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2158         }
2159         else if ( (LenSrc >= 2) && (pszPath[OffsetSrc+1] == ':'))
2160         {
2161           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2162           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2163           if (LenSrc && (pszPath[OffsetSrc] == '\\'))
2164           {
2165             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2166             if (LenSrc == 1 && pszPath[OffsetSrc]=='.')
2167             {
2168               /* C:\. */
2169               OffsetSrc++; LenSrc--; bModifyed = TRUE;
2170             } 
2171             else if (LenSrc == 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='.')
2172             {
2173               /* C:\.. */
2174               OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
2175             } 
2176           }
2177         }
2178         
2179         /* ".\" at the beginning of the path */
2180         if (LenSrc >= 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='\\')
2181         {
2182           OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
2183         } 
2184         
2185         while ( LenSrc )
2186         {
2187           if((LenSrc>=3) && (pszPath[OffsetSrc]=='\\') && (pszPath[OffsetSrc+1]=='.') && (pszPath[OffsetSrc+2]=='.'))
2188           {
2189             /* "\.." found, go one deeper */
2190             while((OffsetDst > OffsetMin) && (pszBuf[OffsetDst]!='\\')) OffsetDst--;
2191             OffsetSrc += 3; LenSrc -= 3; bModifyed = TRUE;
2192             if(OffsetDst == OffsetMin && pszPath[OffsetSrc]=='\\') OffsetSrc++;
2193             pszBuf[OffsetDst] = '\0';                   /* important for \..\.. */
2194           }
2195           else if(LenSrc>=2 && pszPath[OffsetSrc]=='\\' && pszPath[OffsetSrc+1]=='.' )
2196           {
2197             /* "\." found, skip it */
2198             OffsetSrc += 2; LenSrc-=2; bModifyed = TRUE;
2199           }
2200           else
2201           {
2202             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; LenSrc--;
2203           }
2204         }
2205         pszBuf[OffsetDst] = '\0';
2206         TRACE("-- %s %u\n", pszBuf, bModifyed);
2207         return bModifyed;
2208 }
2209
2210
2211 /*************************************************************************
2212  * PathCanonicalizeW
2213  *
2214  *  FIXME
2215  *   returnvalue
2216  */
2217 BOOL WINAPI PathCanonicalizeW(LPWSTR pszBuf, LPCWSTR pszPath)
2218 {
2219         int OffsetMin = 0, OffsetSrc = 0, OffsetDst = 0, LenSrc = lstrlenW(pszPath);
2220         BOOL bModifyed = FALSE;
2221
2222         TRACE("%p %s\n", pszBuf, debugstr_w(pszPath));
2223         
2224         pszBuf[OffsetDst]='\0';
2225
2226         /* keep the root of the path */
2227         if( LenSrc && (pszPath[OffsetSrc]=='\\'))
2228         {
2229           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2230         }
2231         else if ( (LenSrc >= 2) && (pszPath[OffsetSrc+1] == ':'))
2232         {
2233           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2234           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2235           if (LenSrc && (pszPath[OffsetSrc] == '\\'))
2236           {
2237             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2238             if (LenSrc == 1 && pszPath[OffsetSrc]=='.')
2239             {
2240               /* C:\. */
2241               OffsetSrc++; LenSrc--; bModifyed = TRUE;
2242             } 
2243             else if (LenSrc == 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='.')
2244             {
2245               /* C:\.. */
2246               OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
2247             } 
2248           }
2249         }
2250         
2251         /* ".\" at the beginning of the path */
2252         if (LenSrc >= 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='\\')
2253         {
2254           OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
2255         } 
2256         
2257         while ( LenSrc )
2258         {
2259           if((LenSrc>=3) && (pszPath[OffsetSrc]=='\\') && (pszPath[OffsetSrc+1]=='.') && (pszPath[OffsetSrc+2]=='.'))
2260           {
2261             /* "\.." found, go one deeper */
2262             while((OffsetDst > OffsetMin) && (pszBuf[OffsetDst]!='\\')) OffsetDst--;
2263             OffsetSrc += 3; LenSrc -= 3; bModifyed = TRUE;
2264             if(OffsetDst == OffsetMin && pszPath[OffsetSrc]=='\\') OffsetSrc++;
2265             pszBuf[OffsetDst] = '\0';                   /* important for \..\.. */
2266           }
2267           else if(LenSrc>=2 && pszPath[OffsetSrc]=='\\' && pszPath[OffsetSrc+1]=='.' )
2268           {
2269             /* "\." found, skip it */
2270             OffsetSrc += 2; LenSrc-=2; bModifyed = TRUE;
2271           }
2272           else
2273           {
2274             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; LenSrc--;
2275           }
2276         }
2277         pszBuf[OffsetDst] = '\0';
2278         TRACE("-- %s %u\n", debugstr_w(pszBuf), bModifyed);
2279         return bModifyed;
2280 }
2281
2282 /*************************************************************************
2283  * PathFindNextComponentA
2284  *
2285  * NOTES
2286  * special cases:
2287  *      ""              null
2288  *      aa              "" (pointer to traling NULL)
2289  *      aa\             "" (pointer to traling NULL)
2290  *      aa\\            "" (pointer to traling NULL)
2291  *      aa\\bb          bb
2292  *      aa\\\bb         \bb
2293  *      c:\aa\          "aa\"
2294  *      \\aa            aa
2295  *      \\aa\b          aa\b
2296 */
2297 LPSTR WINAPI PathFindNextComponentA(LPCSTR pszPath)
2298 {
2299         LPSTR pos;
2300
2301         TRACE("%s\n", pszPath);
2302
2303         if(!pszPath || !*pszPath) return NULL;
2304         if(!(pos = StrChrA(pszPath, '\\')))
2305           return (LPSTR) pszPath + strlen(pszPath);
2306         pos++;
2307         if(pos[0] == '\\') pos++;
2308         return pos;
2309 }
2310
2311 /*************************************************************************
2312  * PathFindNextComponentW
2313  */
2314 LPWSTR WINAPI PathFindNextComponentW(LPCWSTR pszPath)
2315 {
2316         LPWSTR pos;
2317
2318         TRACE("%s\n", debugstr_w(pszPath));
2319         
2320         if(!pszPath || !*pszPath) return NULL;
2321         if (!(pos = StrChrW(pszPath, '\\')))
2322           return (LPWSTR) pszPath + lstrlenW(pszPath);
2323         pos++;
2324         if(pos[0] == '\\') pos++;
2325         return pos;
2326 }
2327
2328 /*************************************************************************
2329  * PathAddExtensionA
2330  */
2331  
2332 static void _PathAddDotA(LPSTR lpszPath)
2333 {
2334         int len = strlen(lpszPath);
2335         if (len && lpszPath[len-1]!='.')
2336         {
2337           lpszPath[len]  = '.';
2338           lpszPath[len+1]= '\0';
2339         }
2340 }
2341
2342 BOOL WINAPI PathAddExtensionA(
2343         LPSTR  pszPath,
2344         LPCSTR pszExtension)
2345 {
2346         if (*pszPath)
2347         {
2348           LPSTR pszExt = PathFindFileNameA(pszPath);    /* last path component */
2349           pszExt = PathFindExtensionA(pszExt);      
2350           if (*pszExt != '\0') return FALSE;            /* already with extension */
2351           _PathAddDotA(pszPath);
2352         }
2353
2354         if (!pszExtension || *pszExtension=='\0')
2355           strcat(pszPath, "exe");
2356         else
2357           strcat(pszPath, pszExtension);
2358         return TRUE;
2359 }
2360
2361 /*************************************************************************
2362  *      PathAddExtensionW
2363  */
2364 static void _PathAddDotW(LPWSTR lpszPath)
2365 {
2366         int len = lstrlenW(lpszPath);
2367         if (len && lpszPath[len-1]!='.')
2368         {
2369           lpszPath[len]  = '.';
2370           lpszPath[len+1]= '\0';
2371         }
2372 }
2373
2374 /*************************************************************************
2375  *      PathAddExtensionW
2376  */
2377 BOOL WINAPI PathAddExtensionW(
2378         LPWSTR  pszPath,
2379         LPCWSTR pszExtension)
2380 {
2381         static const WCHAR ext[] = { 'e','x','e',0 };
2382
2383         if (*pszPath)
2384         {
2385           LPWSTR pszExt = PathFindFileNameW(pszPath);   /* last path component */
2386           pszExt = PathFindExtensionW(pszExt);      
2387           if (*pszExt != '\0') return FALSE;            /* already with extension */
2388           _PathAddDotW(pszPath);
2389         }
2390
2391         if (!pszExtension || *pszExtension=='\0')
2392           lstrcatW(pszPath, ext);
2393         else
2394           lstrcatW(pszPath, pszExtension);
2395         return TRUE;
2396
2397 }
2398
2399 /*************************************************************************
2400  *      PathIsUNCServerA
2401  */
2402 BOOL WINAPI PathIsUNCServerA(
2403         LPCSTR pszPath)
2404 {
2405         FIXME("%s\n", pszPath);
2406         return FALSE;
2407 }
2408
2409 /*************************************************************************
2410  *      PathIsUNCServerW
2411  */
2412 BOOL WINAPI PathIsUNCServerW(
2413         LPCWSTR pszPath)
2414 {
2415         FIXME("%s\n", debugstr_w(pszPath));
2416         return FALSE;
2417 }
2418
2419 /*************************************************************************
2420  *      PathIsUNCServerShareA
2421  */
2422 BOOL WINAPI PathIsUNCServerShareA(
2423         LPCSTR pszPath)
2424 {
2425         FIXME("%s\n", pszPath);
2426         return FALSE;
2427 }
2428
2429 /*************************************************************************
2430  *      PathIsUNCServerShareW
2431  */
2432 BOOL WINAPI PathIsUNCServerShareW(
2433         LPCWSTR pszPath)
2434 {
2435         FIXME("%s\n", debugstr_w(pszPath));
2436         return FALSE;
2437 }
2438
2439 /*************************************************************************
2440  *      PathMakePrettyA
2441  */
2442 BOOL WINAPI PathMakePrettyA(
2443         LPSTR lpPath)
2444 {
2445         FIXME("%s\n", lpPath);
2446         return TRUE;
2447 }
2448
2449 /*************************************************************************
2450  *      PathMakePrettyW
2451  */
2452 BOOL WINAPI PathMakePrettyW(
2453         LPWSTR lpPath)
2454 {
2455         FIXME("%s\n", debugstr_w(lpPath));
2456         return TRUE;
2457
2458 }
2459
2460 /*************************************************************************
2461  *      PathCommonPrefixA
2462  */
2463 int WINAPI PathCommonPrefixA(
2464         LPCSTR pszFile1,
2465         LPCSTR pszFile2,
2466         LPSTR achPath)
2467 {
2468         FIXME("%s %s %p\n", pszFile1, pszFile2, achPath);
2469         return 0;
2470 }
2471
2472 /*************************************************************************
2473  *      PathCommonPrefixW
2474  */
2475 int WINAPI PathCommonPrefixW(
2476         LPCWSTR pszFile1,
2477         LPCWSTR pszFile2,
2478         LPWSTR achPath)
2479 {
2480         FIXME("%s %s %p\n", debugstr_w(pszFile1), debugstr_w(pszFile2),achPath );
2481         return 0;
2482 }