Reimplemented Unicode case mapping in a slightly more efficient way.
[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 #include "crtdll.h"
14
15 #include "shlobj.h"
16 #include "shell32_main.h"
17 #include "windef.h"
18 #include "options.h"
19 #include "wine/undocshell.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           CRTDLL_wcscpy(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           CRTDLL_wcscpy(szDest,lpszFile);
139         }
140         else if (lpszFile[0] == (WCHAR)'\\' )
141         {
142           CRTDLL_wcscpy(sTemp,lpszDir);
143           PathStripToRootW(sTemp);
144           CRTDLL_wcscat(sTemp,lpszFile);
145           CRTDLL_wcscpy(szDest,sTemp);
146         }
147         else
148         {
149           CRTDLL_wcscpy(sTemp,lpszDir);
150           PathAddBackslashW(sTemp);
151           CRTDLL_wcscat(sTemp,lpszFile);
152           CRTDLL_wcscpy(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 = CRTDLL_wcslen(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 /*************************************************************************
424  * PathGetArgsW         [SHLWAPI.@]
425  */
426 LPWSTR WINAPI PathGetArgsW(LPCWSTR lpszPath) 
427 {
428         BOOL    qflag = FALSE;
429
430         TRACE("%s\n",debugstr_w(lpszPath));
431
432         while (*lpszPath) 
433         {
434           if ((*lpszPath==' ') && !qflag)
435             return (LPWSTR)lpszPath+1;
436           if (*lpszPath=='"')
437             qflag=!qflag;
438           lpszPath++;
439         }
440         return (LPWSTR)lpszPath;
441 }
442
443 /*************************************************************************
444  * PathGetArgsAW        [SHELL32.52]
445  */
446 LPVOID WINAPI PathGetArgsAW(LPVOID lpszPath) 
447 {
448         if (VERSION_OsIsUnicode())
449           return PathGetArgsW(lpszPath);
450         return PathGetArgsA(lpszPath);
451 }
452
453 /*************************************************************************
454  * PathGetDriveNumberA  [SHLWAPI.@]
455  */
456 int WINAPI PathGetDriveNumberA(LPCSTR lpszPath)
457 {
458         int chr = tolower(lpszPath[0]);
459         
460         TRACE ("%s\n",debugstr_a(lpszPath));
461
462         if (!lpszPath || lpszPath[1]!=':' || chr < 'a' || chr > 'z') return -1;
463         return tolower(lpszPath[0]) - 'a' ;
464 }
465
466 /*************************************************************************
467  * PathGetDriveNumberW  [SHLWAPI.@]
468  */
469 int WINAPI PathGetDriveNumberW(LPCWSTR lpszPath)
470 {
471         int chr = CRTDLL_towlower(lpszPath[0]);
472         
473         TRACE ("%s\n",debugstr_w(lpszPath));
474
475         if (!lpszPath || lpszPath[1]!=':' || chr < 'a' || chr > 'z') return -1;
476         return tolower(lpszPath[0]) - 'a' ;
477 }
478
479 /*************************************************************************
480  * PathGetDriveNumber   [SHELL32.57]
481  */
482 int WINAPI PathGetDriveNumberAW(LPVOID lpszPath) 
483 {
484         if (VERSION_OsIsUnicode())
485           return PathGetDriveNumberW(lpszPath);
486         return PathGetDriveNumberA(lpszPath);
487 }
488
489 /*************************************************************************
490  * PathRemoveFileSpecA  [SHLWAPI.@]
491  * 
492  * NOTES
493  *     truncates passed argument to a valid path
494  *     returns if the string was modified or not.
495  *     "\foo\xx\foo"-> "\foo\xx"
496  *     "\" -> "\"
497  *     "a:\foo" -> "a:\"
498  */
499 BOOL WINAPI PathRemoveFileSpecA(LPSTR lpszPath)
500 {
501         LPSTR cutplace;
502
503         TRACE("%s\n",lpszPath);
504
505         if (!lpszPath[0]) return 0;
506
507         cutplace = PathFindFileNameA(lpszPath);
508         if (cutplace)
509         {
510           *cutplace='\0';
511           if (PathIsRootA(lpszPath))
512           {
513             PathAddBackslashA(lpszPath);
514           }
515           else
516           {
517             PathRemoveBackslashA(lpszPath);
518           }
519           return TRUE;
520         }
521         return FALSE;
522 }
523
524 /*************************************************************************
525  * PathRemoveFileSpecW  [SHLWAPI.@]
526  */
527 BOOL WINAPI PathRemoveFileSpecW(LPWSTR lpszPath)
528 {
529         LPWSTR cutplace;
530
531         TRACE("%s\n",debugstr_w(lpszPath));
532
533         if (!lpszPath[0]) return 0;
534         cutplace = PathFindFileNameW(lpszPath);
535         if (cutplace)
536         {
537           *cutplace='\0';
538           if (PathIsRootW(lpszPath))
539           {
540             PathAddBackslashW(lpszPath);
541           }
542           else
543           {
544             PathRemoveBackslashW(lpszPath);
545           }
546           return TRUE;
547         }
548         return FALSE;
549 }
550
551 /*************************************************************************
552  * PathRemoveFileSpec [SHELL32.35]
553  */
554 BOOL WINAPI PathRemoveFileSpecAW(LPVOID lpszPath) 
555 {
556         if (VERSION_OsIsUnicode())
557           return PathRemoveFileSpecW(lpszPath);
558         return PathRemoveFileSpecA(lpszPath);
559 }
560
561 /*************************************************************************
562  * PathStripPathA       [SHELLWAPI.@]
563  * 
564  * NOTES
565  *  removes the path from the beginning of a filename
566  */
567 void WINAPI PathStripPathA(LPSTR lpszPath)
568 {
569         LPSTR lpszFileName = PathFindFileNameA(lpszPath);
570
571         TRACE("%s\n", lpszPath);
572
573         if(lpszFileName)
574           RtlMoveMemory(lpszPath, lpszFileName, strlen(lpszFileName)); 
575 }
576
577 /*************************************************************************
578  * PathStripPathW       [SHELLWAPI.@]
579  */
580 void WINAPI PathStripPathW(LPWSTR lpszPath)
581 {
582         LPWSTR lpszFileName = PathFindFileNameW(lpszPath);
583
584         TRACE("%s\n", debugstr_w(lpszPath));
585         if(lpszFileName)
586           RtlMoveMemory(lpszPath, lpszFileName, lstrlenW(lpszFileName)*sizeof(WCHAR)); 
587 }
588
589 /*************************************************************************
590  * PathStripPathAW      [SHELL32.38]
591  */
592 void WINAPI PathStripPathAW(LPVOID lpszPath) 
593 {
594         if (VERSION_OsIsUnicode())
595           return PathStripPathW(lpszPath);
596         return PathStripPathA(lpszPath);
597 }
598
599 /*************************************************************************
600  * PathStripToRootA     [SHLWAPI.@]
601  */
602 BOOL WINAPI PathStripToRootA(LPSTR lpszPath)
603 {
604         TRACE("%s\n", lpszPath);
605
606         /* X:\ */
607         if (lpszPath[1]==':' && lpszPath[2]=='\\')
608         {
609           lpszPath[3]='\0';
610           return TRUE;
611         }
612
613         /* "\" */
614         if (lpszPath[0]=='\\')
615         {
616           lpszPath[1]='\0';
617           return TRUE;
618         }
619
620         /* UNC "\\<computer>\<share>" */
621         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
622         {
623           int foundbackslash = 0;
624           lpszPath += 2;
625           while (*lpszPath)
626           {
627             if (*lpszPath=='\\') foundbackslash++;
628             if (foundbackslash==2)
629             {
630               *lpszPath = '\0';
631               return TRUE;
632             }
633             lpszPath++;
634           }
635         }
636
637         return FALSE;
638 }
639
640 /*************************************************************************
641  * PathStripToRootW     [SHLWAPI.@]
642  */
643 BOOL WINAPI PathStripToRootW(LPWSTR lpszPath)
644 {
645         TRACE("%s\n", debugstr_w(lpszPath));
646
647         /* X:\ */
648         if (lpszPath[1]==':' && lpszPath[2]=='\\')
649         {
650           lpszPath[3]='\0';
651           return TRUE;
652         }
653
654         /* "\" */
655         if (lpszPath[0]=='\\')
656         {
657           lpszPath[1]='\0';
658           return TRUE;
659         }
660
661         /* UNC "\\<computer>\<share>" */
662         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
663         {
664           int foundbackslash = 0;
665           lpszPath += 2;
666           while (*lpszPath)
667           {
668             if (*lpszPath=='\\') foundbackslash++;
669             if (foundbackslash==2)
670             {
671               *lpszPath = '\0';
672               return TRUE;
673             }
674             lpszPath++;
675           }
676         }
677
678         return FALSE;
679 }
680
681 /*************************************************************************
682  * PathStripToRootAW    [SHELL32.50]
683  */
684 BOOL WINAPI PathStripToRootAW(LPVOID lpszPath) 
685 {
686         if (VERSION_OsIsUnicode())
687           return PathStripToRootW(lpszPath);
688         return PathStripToRootA(lpszPath);
689 }
690
691 /*************************************************************************
692  * PathRemoveArgsA      [SHLWAPI.@]
693  */
694 void WINAPI PathRemoveArgsA(LPSTR lpszPath)
695 {
696         LPSTR lpszArgs = PathGetArgsA(lpszPath);
697
698         TRACE("%s\n", lpszPath);
699
700         if (lpszArgs) *(--lpszArgs)='\0';
701 }
702
703 /*************************************************************************
704  * PathRemoveArgsW      [SHLWAPI.@]
705  */
706 void WINAPI PathRemoveArgsW(LPWSTR lpszPath)
707 {
708         LPWSTR lpszArgs = PathGetArgsW(lpszPath);
709
710         TRACE("%s\n", debugstr_w(lpszPath));
711
712         if (lpszArgs) *(--lpszArgs)='\0';
713 }
714
715 /*************************************************************************
716  * PathRemoveArgsAW     [SHELL32.251]
717  */
718 void WINAPI PathRemoveArgsAW(LPVOID lpszPath) 
719 {
720         if (VERSION_OsIsUnicode())
721           return PathRemoveArgsW(lpszPath);
722         return PathRemoveArgsA(lpszPath);
723 }
724
725 /*************************************************************************
726  * PathRemoveExtensionA         [SHLWAPI.@]
727  */
728 void WINAPI PathRemoveExtensionA(LPSTR lpszPath)
729 {
730         LPSTR lpszExtension = PathFindExtensionA(lpszPath);
731
732         TRACE("%s\n", lpszPath);
733
734         if (lpszExtension) *lpszExtension='\0';
735 }
736
737 /*************************************************************************
738  * PathRemoveExtensionW         [SHLWAPI.@]
739  */
740 void WINAPI PathRemoveExtensionW(LPWSTR lpszPath)
741 {
742         LPWSTR lpszExtension = PathFindExtensionW(lpszPath);
743
744         TRACE("%s\n", debugstr_w(lpszPath));
745
746         if (lpszExtension) *lpszExtension='\0';
747 }
748
749 /*************************************************************************
750  * PathRemoveExtensionAW        [SHELL32.250]
751  */
752 void WINAPI PathRemoveExtensionAW(LPVOID lpszPath) 
753 {
754         if (VERSION_OsIsUnicode())
755           return PathRemoveExtensionW(lpszPath);
756         return PathRemoveExtensionA(lpszPath);
757 }
758
759 /*************************************************************************
760  * PathRemoveBackslashA [SHLWAPI.@]
761  *
762  * If the path ends in a backslash it is replaced by a NULL
763  * and the address of the NULL is returned
764  * Otherwise 
765  * the address of the last character is returned.
766  *
767  */
768 LPSTR WINAPI PathRemoveBackslashA( LPSTR lpszPath )
769 {
770         LPSTR p = lpszPath;
771         
772         while (*lpszPath) p = lpszPath++;
773         if ( *p == (CHAR)'\\') *p = (CHAR)'\0';
774         return p;
775 }
776
777 /*************************************************************************
778  * PathRemoveBackslashW [SHLWAPI.@]
779  */
780 LPWSTR WINAPI PathRemoveBackslashW( LPWSTR lpszPath )
781 {
782         LPWSTR p = lpszPath;
783         
784         while (*lpszPath) p = lpszPath++;
785         if ( *p == (WCHAR)'\\') *p = (WCHAR)'\0';
786         return p;
787 }
788
789 /*
790         Path Manipulations
791 */
792
793 /*************************************************************************
794  * PathGetShortPathA [internal]
795  */
796 LPSTR WINAPI PathGetShortPathA(LPSTR lpszPath)
797 {
798         FIXME("%s stub\n", lpszPath);
799         return NULL;
800 }
801
802 /*************************************************************************
803  * PathGetShortPathW [internal]
804  */
805 LPWSTR WINAPI PathGetShortPathW(LPWSTR lpszPath)
806 {
807         FIXME("%s stub\n", debugstr_w(lpszPath));
808         return NULL;
809 }
810
811 /*************************************************************************
812  * PathGetShortPathAW [SHELL32.92]
813  */
814 LPVOID WINAPI PathGetShortPathAW(LPVOID lpszPath)
815 {
816         if(VERSION_OsIsUnicode())
817           return PathGetShortPathW(lpszPath);
818         return PathGetShortPathA(lpszPath);
819 }
820
821 /*************************************************************************
822  * PathRemoveBlanksA [SHLWAPI.@]
823  * 
824  * NOTES
825  *     remove spaces from beginning and end of passed string
826  */
827 LPSTR WINAPI PathRemoveBlanksA(LPSTR str)
828 {
829         LPSTR x = str;
830
831         TRACE("%s\n",str);
832
833         while (*x==' ') x++;
834         if (x!=str)
835           strcpy(str,x);
836         if (!*str)
837           return str;
838         x=str+strlen(str)-1;
839         while (*x==' ')
840           x--;
841         if (*x==' ')
842           *x='\0';
843         return x;
844 }
845
846 /*************************************************************************
847  * PathRemoveBlanksW [SHLWAPI.@]
848  */
849 LPWSTR WINAPI PathRemoveBlanksW(LPWSTR str)
850 {
851         LPWSTR x = str;
852
853         TRACE("%s\n",debugstr_w(str));
854
855         while (*x==' ') x++;
856         if (x!=str)
857           CRTDLL_wcscpy(str,x);
858         if (!*str)
859           return str;
860         x=str+CRTDLL_wcslen(str)-1;
861         while (*x==' ')
862           x--;
863         if (*x==' ')
864           *x='\0';
865         return x;
866 }
867
868 /*************************************************************************
869  * PathRemoveBlanksAW [SHELL32.33]
870  */
871 LPVOID WINAPI PathRemoveBlanksAW(LPVOID str)
872 {
873         if(VERSION_OsIsUnicode())
874           return PathRemoveBlanksW(str);
875         return PathRemoveBlanksA(str);
876 }
877
878 /*************************************************************************
879  * PathQuoteSpacesA [SHLWAPI.@]
880  * 
881  * NOTES
882  */
883 LPSTR WINAPI PathQuoteSpacesA(LPCSTR lpszPath)
884 {
885         FIXME("%s\n",lpszPath);
886         return 0;
887 }
888
889 /*************************************************************************
890  * PathQuoteSpacesW [SHLWAPI.@]
891  */
892 LPWSTR WINAPI PathQuoteSpacesW(LPCWSTR lpszPath)
893 {
894         FIXME("%s\n",debugstr_w(lpszPath));
895         return 0;       
896 }
897
898 /*************************************************************************
899  * PathQuoteSpacesAW [SHELL32.55]
900  */
901 LPVOID WINAPI PathQuoteSpacesAW (LPCVOID lpszPath)
902 {
903         if(VERSION_OsIsUnicode())
904           return PathQuoteSpacesW(lpszPath);
905         return PathQuoteSpacesA(lpszPath);
906 }
907
908 /*************************************************************************
909  * PathUnquoteSpacesA [SHLWAPI.@]
910  * 
911  * NOTES
912  *     unquote string (remove ")
913  */
914 VOID WINAPI PathUnquoteSpacesA(LPSTR str) 
915 {
916         DWORD len = lstrlenA(str);
917
918         TRACE("%s\n",str);
919
920         if (*str!='"')
921           return;
922         if (str[len-1]!='"')
923           return;
924         str[len-1]='\0';
925         lstrcpyA(str,str+1);
926         return;
927 }
928
929 /*************************************************************************
930  * PathUnquoteSpacesW [SHLWAPI.@]
931  */
932 VOID WINAPI PathUnquoteSpacesW(LPWSTR str) 
933 {
934         DWORD len = CRTDLL_wcslen(str);
935
936         TRACE("%s\n",debugstr_w(str));
937
938         if (*str!='"')
939           return;
940         if (str[len-1]!='"')
941           return;
942         str[len-1]='\0';
943         CRTDLL_wcscpy(str,str+1);
944         return;
945 }
946
947 /*************************************************************************
948  * PathUnquoteSpacesAW [SHELL32.56]
949  */
950 VOID WINAPI PathUnquoteSpacesAW(LPVOID str) 
951 {
952         if(VERSION_OsIsUnicode())
953           PathUnquoteSpacesW(str);
954         else
955           PathUnquoteSpacesA(str);
956 }
957
958 /*************************************************************************
959  * PathParseIconLocationA       [SHLWAPI.@]
960  */
961 int WINAPI PathParseIconLocationA(LPSTR lpszPath)
962 {
963         LPSTR lpstrComma = strchr(lpszPath, ',');
964         
965         FIXME("%s stub\n", debugstr_a(lpszPath));
966
967         if (lpstrComma && lpstrComma[1])
968         {
969           lpstrComma[0]='\0';
970 /*        return atoi(&lpstrComma[1]);  FIXME */
971         }
972         return 0;
973 }
974
975 /*************************************************************************
976  * PathParseIconLocationW       [SHLWAPI.@]
977  */
978 int WINAPI PathParseIconLocationW(LPWSTR lpszPath)
979 {
980         LPWSTR lpstrComma = CRTDLL_wcschr(lpszPath, ',');
981         
982         FIXME("%s stub\n", debugstr_w(lpszPath));
983
984         if (lpstrComma && lpstrComma[1])
985         {
986           lpstrComma[0]='\0';
987 /*        return _wtoi(&lpstrComma[1]); FIXME */
988         }
989         return 0;
990 }
991
992 /*************************************************************************
993  * PathParseIconLocationAW      [SHELL32.249]
994  */
995 int WINAPI PathParseIconLocationAW (LPVOID lpszPath)
996 {
997         if(VERSION_OsIsUnicode())
998           return PathParseIconLocationW(lpszPath);
999         return PathParseIconLocationA(lpszPath);
1000 }
1001
1002 /*
1003         Path Testing
1004 */
1005 /*************************************************************************
1006  * PathIsUNCA           [SHLWAPI.@]
1007  * 
1008  * NOTES
1009  *     PathIsUNC(char*path);
1010  */
1011 BOOL WINAPI PathIsUNCA(LPCSTR lpszPath) 
1012 {
1013         TRACE("%s\n",lpszPath);
1014
1015         return (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\'));
1016 }
1017
1018 /*************************************************************************
1019  * PathIsUNCW           [SHLWAPI.@]
1020  */
1021 BOOL WINAPI PathIsUNCW(LPCWSTR lpszPath) 
1022 {
1023         TRACE("%s\n",debugstr_w(lpszPath));
1024
1025         return (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\'));
1026 }
1027
1028 /*************************************************************************
1029  * PathIsUNCAW          [SHELL32.39]
1030  */
1031 BOOL WINAPI PathIsUNCAW (LPCVOID lpszPath)
1032 {
1033         if (VERSION_OsIsUnicode())
1034           return PathIsUNCW( lpszPath );
1035         return PathIsUNCA( lpszPath );  
1036 }
1037
1038 /*************************************************************************
1039  *  PathIsRelativeA     [SHLWAPI.@]
1040  */
1041 BOOL WINAPI PathIsRelativeA (LPCSTR lpszPath)
1042 {
1043         TRACE("lpszPath=%s\n",lpszPath);
1044
1045         return (lpszPath && (lpszPath[0]!='\\' && lpszPath[1]!=':'));
1046 }
1047
1048 /*************************************************************************
1049  *  PathIsRelativeW     [SHLWAPI.@]
1050  */
1051 BOOL WINAPI PathIsRelativeW (LPCWSTR lpszPath)
1052 {
1053         TRACE("lpszPath=%s\n",debugstr_w(lpszPath));
1054
1055         return (lpszPath && (lpszPath[0]!='\\' && lpszPath[1]!=':'));
1056 }
1057
1058 /*************************************************************************
1059  *  PathIsRelativeAW    [SHELL32.40]
1060  */
1061 BOOL WINAPI PathIsRelativeAW (LPCVOID lpszPath)
1062 {
1063         if (VERSION_OsIsUnicode())
1064           return PathIsRelativeW( lpszPath );
1065         return PathIsRelativeA( lpszPath );  
1066 }
1067
1068 /*************************************************************************
1069  * PathIsRootA          [SHLWAPI.@]
1070  *
1071  * notes
1072  *  TRUE if the path points to a root directory
1073  */
1074 BOOL WINAPI PathIsRootA(LPCSTR lpszPath)
1075 {
1076         TRACE("%s\n",lpszPath);
1077
1078         /* X:\ */
1079         if (lpszPath[1]==':' && lpszPath[2]=='\\' && lpszPath[3]=='\0')
1080           return TRUE;
1081
1082         /* "\" */
1083         if (lpszPath[0]=='\\' && lpszPath[1]=='\0')
1084           return TRUE;
1085
1086         /* UNC "\\<computer>\<share>" */
1087         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
1088         {
1089           int foundbackslash = 0;
1090           lpszPath += 2;
1091           while (*lpszPath)
1092           {
1093             if (*(lpszPath++)=='\\') foundbackslash++;
1094           }
1095           if (foundbackslash==1)
1096             return TRUE;
1097         }
1098         return FALSE;
1099 }
1100
1101 /*************************************************************************
1102  * PathIsRootW          [SHLWAPI.@]
1103  */
1104 BOOL WINAPI PathIsRootW(LPCWSTR lpszPath) 
1105 {
1106         TRACE("%s\n",debugstr_w(lpszPath));
1107
1108         /* X:\ */
1109         if (lpszPath[1]==':' && lpszPath[2]=='\\' && lpszPath[3]=='\0')
1110           return TRUE;
1111
1112         /* "\" */
1113         if (lpszPath[0]=='\\' && lpszPath[1]=='\0')
1114           return TRUE;
1115
1116         /* UNC "\\<computer>\<share>" */
1117         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
1118         {
1119           int foundbackslash = 0;
1120           lpszPath += 2;
1121           while (*lpszPath)
1122           {
1123             if (*(lpszPath++)=='\\') foundbackslash++;
1124           }
1125           if (foundbackslash==1)
1126             return TRUE;
1127         }
1128         return FALSE;
1129
1130 }
1131
1132 /*************************************************************************
1133  * PathIsRootAW         [SHELL32.29]
1134  */
1135 BOOL WINAPI PathIsRootAW(LPCVOID lpszPath) 
1136 {
1137         if (VERSION_OsIsUnicode())
1138           return PathIsRootW(lpszPath);
1139         return PathIsRootA(lpszPath);
1140 }
1141
1142 /*************************************************************************
1143  *  PathIsExeA          [internal]
1144  */
1145 BOOL WINAPI PathIsExeA (LPCSTR lpszPath)
1146 {
1147         LPCSTR lpszExtension = PathGetExtensionA(lpszPath);
1148         int i = 0;
1149         static char * lpszExtensions[6] = {"exe", "com", "pid", "cmd", "bat", NULL };
1150         
1151         TRACE("path=%s\n",lpszPath);
1152
1153         for(i=0; lpszExtensions[i]; i++)
1154           if (!strcasecmp(lpszExtension,lpszExtensions[i])) return TRUE;
1155           
1156         return FALSE;
1157 }
1158
1159 /*************************************************************************
1160  *  PathIsExeW          [internal]
1161  */
1162 BOOL WINAPI PathIsExeW (LPCWSTR lpszPath)
1163 {
1164         LPCWSTR lpszExtension = PathGetExtensionW(lpszPath);
1165         int i = 0;
1166         static WCHAR lpszExtensions[6][4] =
1167           {{'e','x','e','\0'}, {'c','o','m','\0'}, {'p','i','d','\0'},
1168            {'c','m','d','\0'}, {'b','a','t','\0'}, {'\0'} };
1169         
1170         TRACE("path=%s\n",debugstr_w(lpszPath));
1171
1172         for(i=0; lpszExtensions[i]; i++)
1173           if (!CRTDLL__wcsicmp(lpszExtension,lpszExtensions[i])) return TRUE;
1174           
1175         return FALSE;
1176 }
1177
1178 /*************************************************************************
1179  *  PathIsExeAW         [SHELL32.43]
1180  */
1181 BOOL WINAPI PathIsExeAW (LPCVOID path)
1182 {
1183         if (VERSION_OsIsUnicode())
1184           return PathIsExeW (path);
1185         return PathIsExeA(path);
1186 }
1187
1188 /*************************************************************************
1189  * PathIsDirectoryA     [SHLWAPI.@]
1190  */
1191 BOOL WINAPI PathIsDirectoryA(LPCSTR lpszPath)
1192 {
1193         HANDLE hFile;
1194         WIN32_FIND_DATAA stffile;
1195         
1196         TRACE("%s\n", debugstr_a(lpszPath));
1197
1198         hFile = FindFirstFileA(lpszPath, &stffile);
1199
1200         if ( hFile != INVALID_HANDLE_VALUE )
1201         {
1202           FindClose (hFile);
1203           return (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
1204         }
1205
1206         return FALSE;   
1207 }
1208
1209 /*************************************************************************
1210  * PathIsDirectoryW     [SHLWAPI.@]
1211  */
1212 BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
1213 {
1214         HANDLE hFile;
1215         WIN32_FIND_DATAW stffile;
1216         
1217         TRACE("%s\n", debugstr_w(lpszPath));
1218
1219         hFile = FindFirstFileW(lpszPath, &stffile);
1220
1221         if ( hFile != INVALID_HANDLE_VALUE )
1222         {
1223           FindClose (hFile);
1224           return (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
1225         }
1226
1227         return FALSE;   
1228 }
1229
1230 /*************************************************************************
1231  * PathIsDirectoryAW    [SHELL32.159]
1232  */
1233 BOOL WINAPI PathIsDirectoryAW (LPCVOID lpszPath)
1234 {
1235         if (VERSION_OsIsUnicode())
1236           return PathIsDirectoryW (lpszPath);
1237         return PathIsDirectoryA (lpszPath);
1238 }
1239
1240 /*************************************************************************
1241  * PathFileExistsA      [SHLWAPI.@]
1242  * 
1243  * NOTES
1244  *     file_exists(char *fn);
1245  */
1246 BOOL WINAPI PathFileExistsA(LPCSTR lpszPath) 
1247 {
1248         TRACE("%s\n",lpszPath);
1249         return  (GetFileAttributesA(lpszPath)!=-1);
1250 }
1251
1252 /*************************************************************************
1253  * PathFileExistsW      [SHLWAPI.@]
1254  */
1255 BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath) 
1256 {
1257         TRACE("%s\n",debugstr_w(lpszPath));
1258         return  (GetFileAttributesW(lpszPath)!=-1);
1259 }
1260
1261 /*************************************************************************
1262  * PathFileExistsAW     [SHELL32.45]
1263  */ 
1264 BOOL WINAPI PathFileExistsAW (LPCVOID lpszPath)
1265 {
1266         if (VERSION_OsIsUnicode())
1267           return PathFileExistsW (lpszPath);
1268         return PathFileExistsA (lpszPath);
1269 }
1270
1271 /*************************************************************************
1272  * PathMatchSingleMaskA [internal]
1273  * 
1274  * NOTES
1275  *     internal (used by PathMatchSpec)
1276  */
1277 static BOOL PathMatchSingleMaskA(LPCSTR name, LPCSTR mask)
1278 {
1279         while (*name && *mask && *mask!=';') 
1280         {
1281           if (*mask=='*') 
1282           {
1283             do 
1284             {
1285               if (PathMatchSingleMaskA(name,mask+1)) return 1;  /* try substrings */
1286             } while (*name++);
1287             return 0;
1288           }
1289           if (toupper(*mask)!=toupper(*name) && *mask!='?') return 0;
1290           name++;
1291           mask++;
1292         }
1293         if (!*name) 
1294         {
1295           while (*mask=='*') mask++;
1296           if (!*mask || *mask==';') return 1;
1297         }
1298         return 0;
1299 }
1300
1301 /*************************************************************************
1302  * PathMatchSingleMaskW [internal]
1303  */
1304 static BOOL PathMatchSingleMaskW(LPCWSTR name, LPCWSTR mask)
1305 {
1306         while (*name && *mask && *mask!=';') 
1307         {
1308           if (*mask=='*') 
1309           {
1310             do 
1311             {
1312               if (PathMatchSingleMaskW(name,mask+1)) return 1;  /* try substrings */
1313             } while (*name++);
1314             return 0;
1315           }
1316           if (CRTDLL_towupper(*mask)!=CRTDLL_towupper(*name) && *mask!='?') return 0;
1317           name++;
1318           mask++;
1319         }
1320         if (!*name) 
1321         {
1322           while (*mask=='*') mask++;
1323           if (!*mask || *mask==';') return 1;
1324         }
1325         return 0;
1326 }
1327 /*************************************************************************
1328  * PathMatchSpecA       [SHLWAPI.@]
1329  * 
1330  * NOTES
1331  *     used from COMDLG32
1332  */
1333 BOOL WINAPI PathMatchSpecA(LPCSTR name, LPCSTR mask) 
1334 {
1335         TRACE("%s %s\n",name,mask);
1336
1337         if (!lstrcmpA( mask, "*.*" )) return 1;   /* we don't require a period */
1338
1339         while (*mask) 
1340         {
1341           if (PathMatchSingleMaskA(name,mask)) return 1;    /* helper function */
1342           while (*mask && *mask!=';') mask++;
1343           if (*mask==';') 
1344           {
1345             mask++;
1346             while (*mask==' ') mask++;      /*  masks may be separated by "; " */
1347           }
1348         }
1349         return 0;
1350 }
1351
1352 /*************************************************************************
1353  * PathMatchSpecW       [SHLWAPI.@]
1354  */
1355 BOOL WINAPI PathMatchSpecW(LPCWSTR name, LPCWSTR mask) 
1356 {
1357         WCHAR stemp[4];
1358         TRACE("%s %s\n",debugstr_w(name),debugstr_w(mask));
1359
1360         lstrcpyAtoW(stemp,"*.*");       
1361         if (!lstrcmpW( mask, stemp )) return 1;   /* we don't require a period */
1362
1363         while (*mask) 
1364         {
1365           if (PathMatchSingleMaskW(name,mask)) return 1;    /* helper function */
1366           while (*mask && *mask!=';') mask++;
1367           if (*mask==';') 
1368           {
1369             mask++;
1370             while (*mask==' ') mask++;       /* masks may be separated by "; " */
1371           }
1372         }
1373         return 0;
1374 }
1375
1376 /*************************************************************************
1377  * PathMatchSpecAW      [SHELL32.46]
1378  */
1379 BOOL WINAPI PathMatchSpecAW(LPVOID name, LPVOID mask) 
1380 {
1381         if (VERSION_OsIsUnicode())
1382           return PathMatchSpecW( name, mask );
1383         return PathMatchSpecA( name, mask );
1384 }
1385
1386 /*************************************************************************
1387  * PathIsSameRootA      [SHLWAPI.@]
1388  *
1389  * FIXME
1390  *  what to do with "\path" ??
1391  */
1392 BOOL WINAPI PathIsSameRootA(LPCSTR lpszPath1, LPCSTR lpszPath2)
1393 {
1394         TRACE("%s %s\n", lpszPath1, lpszPath2);
1395         
1396         if (PathIsRelativeA(lpszPath1) || PathIsRelativeA(lpszPath2)) return FALSE;
1397
1398         /* usual path */
1399         if ( toupper(lpszPath1[0])==toupper(lpszPath2[0]) &&
1400              lpszPath1[1]==':' && lpszPath2[1]==':' &&
1401              lpszPath1[2]=='\\' && lpszPath2[2]=='\\')
1402           return TRUE;
1403
1404         /* UNC */
1405         if (lpszPath1[0]=='\\' && lpszPath2[0]=='\\' &&
1406             lpszPath1[1]=='\\' && lpszPath2[1]=='\\')
1407         {
1408           int pos=2, bsfound=0;
1409           while (lpszPath1[pos] && lpszPath2[pos] &&
1410                 (lpszPath1[pos] == lpszPath2[pos]))
1411           {
1412             if (lpszPath1[pos]=='\\') bsfound++;
1413             if (bsfound == 2) return TRUE;
1414             pos++;
1415           }
1416           return (lpszPath1[pos] == lpszPath2[pos]);
1417         }
1418         return FALSE;
1419 }
1420
1421 /*************************************************************************
1422  * PathIsSameRootW      [SHLWAPI.@]
1423  */
1424 BOOL WINAPI PathIsSameRootW(LPCWSTR lpszPath1, LPCWSTR lpszPath2)
1425 {
1426         TRACE("%s %s\n", debugstr_w(lpszPath1), debugstr_w(lpszPath2));
1427         
1428         if (PathIsRelativeW(lpszPath1) || PathIsRelativeW(lpszPath2)) return FALSE;
1429
1430         /* usual path */
1431         if ( CRTDLL_towupper(lpszPath1[0])==CRTDLL_towupper(lpszPath2[0]) &&
1432              lpszPath1[1]==':' && lpszPath2[1]==':' &&
1433              lpszPath1[2]=='\\' && lpszPath2[2]=='\\')
1434           return TRUE;
1435
1436         /* UNC */
1437         if (lpszPath1[0]=='\\' && lpszPath2[0]=='\\' &&
1438             lpszPath1[1]=='\\' && lpszPath2[1]=='\\')
1439         {
1440           int pos=2, bsfound=0;
1441           while (lpszPath1[pos] && lpszPath2[pos] &&
1442                 (lpszPath1[pos] == lpszPath2[pos]))
1443           {
1444             if (lpszPath1[pos]=='\\') bsfound++;
1445             if (bsfound == 2) return TRUE;
1446             pos++;
1447           }
1448           return (lpszPath1[pos] == lpszPath2[pos]);
1449         }
1450         return FALSE;
1451 }
1452
1453 /*************************************************************************
1454  * PathIsSameRootAW     [SHELL32.650]
1455  */
1456 BOOL WINAPI PathIsSameRootAW(LPCVOID lpszPath1, LPCVOID lpszPath2)
1457 {
1458         if (VERSION_OsIsUnicode())
1459           return PathIsSameRootW(lpszPath1, lpszPath2);
1460         return PathIsSameRootA(lpszPath1, lpszPath2);
1461 }
1462
1463 /*************************************************************************
1464  * PathIsURLA
1465  */
1466 BOOL WINAPI PathIsURLA(LPCSTR lpstrPath)
1467 {
1468         LPSTR lpstrRes;
1469         int iSize, i=0;
1470         static LPSTR SupportedProtocol[] = 
1471           {"http","https","ftp","gopher","file","mailto",NULL};
1472
1473         if(!lpstrPath) return FALSE;
1474
1475         /* get protocol        */
1476         lpstrRes = strchr(lpstrPath,':');
1477         if(!lpstrRes) return FALSE;
1478         iSize = lpstrRes - lpstrPath;
1479
1480         while(SupportedProtocol[i])
1481         {
1482           if (iSize == strlen(SupportedProtocol[i]))
1483             if(!strncasecmp(lpstrPath, SupportedProtocol[i], iSize));
1484               return TRUE;
1485           i++;
1486         }
1487
1488         return FALSE;
1489 }  
1490
1491 /*************************************************************************
1492  * PathIsURLW
1493  */
1494 BOOL WINAPI PathIsURLW(LPCWSTR lpstrPath)
1495 {
1496         LPWSTR lpstrRes;
1497         int iSize, i=0;
1498         static WCHAR SupportedProtocol[7][7] = 
1499           {{'h','t','t','p','\0'},{'h','t','t','p','s','\0'},{'f','t','p','\0'},
1500           {'g','o','p','h','e','r','\0'},{'f','i','l','e','\0'},
1501           {'m','a','i','l','t','o','\0'},{0}};
1502
1503         if(!lpstrPath) return FALSE;
1504
1505         /* get protocol        */
1506         lpstrRes = CRTDLL_wcschr(lpstrPath,':');
1507         if(!lpstrRes) return FALSE;
1508         iSize = lpstrRes - lpstrPath;
1509
1510         while(SupportedProtocol[i])
1511         {
1512           if (iSize == CRTDLL_wcslen(SupportedProtocol[i]))
1513             if(!CRTDLL__wcsnicmp(lpstrPath, SupportedProtocol[i], iSize));
1514               return TRUE;
1515           i++;
1516         }
1517
1518         return FALSE;
1519 }  
1520
1521 /*************************************************************************
1522  * IsLFNDriveA          [SHELL32.119]
1523  * 
1524  * NOTES
1525  *     exported by ordinal Name
1526  */
1527 BOOL WINAPI IsLFNDriveA(LPCSTR lpszPath) 
1528 {
1529     DWORD       fnlen;
1530
1531     if (!GetVolumeInformationA(lpszPath,NULL,0,NULL,&fnlen,NULL,NULL,0))
1532         return FALSE;
1533     return fnlen>12;
1534 }
1535
1536 /*
1537         Creating Something Unique
1538 */
1539 /*************************************************************************
1540  * PathMakeUniqueNameA  [internal]
1541  */
1542 BOOL WINAPI PathMakeUniqueNameA(
1543         LPSTR lpszBuffer,
1544         DWORD dwBuffSize, 
1545         LPCSTR lpszShortName,
1546         LPCSTR lpszLongName,
1547         LPCSTR lpszPathName)
1548 {
1549         FIXME("%p %lu %s %s %s stub\n",
1550          lpszBuffer, dwBuffSize, debugstr_a(lpszShortName),
1551          debugstr_a(lpszLongName), debugstr_a(lpszPathName));
1552         return TRUE;
1553 }
1554
1555 /*************************************************************************
1556  * PathMakeUniqueNameW  [internal]
1557  */
1558 BOOL WINAPI PathMakeUniqueNameW(
1559         LPWSTR lpszBuffer,
1560         DWORD dwBuffSize, 
1561         LPCWSTR lpszShortName,
1562         LPCWSTR lpszLongName,
1563         LPCWSTR lpszPathName)
1564 {
1565         FIXME("%p %lu %s %s %s stub\n",
1566          lpszBuffer, dwBuffSize, debugstr_w(lpszShortName),
1567          debugstr_w(lpszLongName), debugstr_w(lpszPathName));
1568         return TRUE;
1569 }
1570
1571 /*************************************************************************
1572  * PathMakeUniqueNameAW [SHELL32.47]
1573  */
1574 BOOL WINAPI PathMakeUniqueNameAW(
1575         LPVOID lpszBuffer,
1576         DWORD dwBuffSize, 
1577         LPCVOID lpszShortName,
1578         LPCVOID lpszLongName,
1579         LPCVOID lpszPathName)
1580 {
1581         if (VERSION_OsIsUnicode())
1582           return PathMakeUniqueNameW(lpszBuffer,dwBuffSize, lpszShortName,lpszLongName,lpszPathName);
1583         return PathMakeUniqueNameA(lpszBuffer,dwBuffSize, lpszShortName,lpszLongName,lpszPathName);
1584 }
1585
1586 /*************************************************************************
1587  * PathYetAnotherMakeUniqueNameA [SHELL32.75]
1588  * 
1589  * NOTES
1590  *     exported by ordinal
1591  */
1592 BOOL WINAPI PathYetAnotherMakeUniqueNameA(
1593         LPSTR lpszBuffer,
1594         LPCSTR lpszPathName,
1595         LPCSTR lpszShortName,
1596         LPCSTR lpszLongName)
1597 {
1598     FIXME("(%p,%p, %p ,%p):stub.\n",
1599      lpszBuffer, lpszPathName, lpszShortName, lpszLongName);
1600     return TRUE;
1601 }
1602
1603
1604 /*
1605         cleaning and resolving paths 
1606  */
1607
1608 /*************************************************************************
1609  * PathFindOnPathA      [SHELL32.145]
1610  */
1611 BOOL WINAPI PathFindOnPathA(LPSTR sFile, LPCSTR sOtherDirs)
1612 {
1613         FIXME("%s %s\n",sFile, sOtherDirs);
1614         return FALSE;
1615 }
1616
1617 /*************************************************************************
1618  * PathFindOnPathW      [SHELL32]
1619  */
1620 BOOL WINAPI PathFindOnPathW(LPWSTR sFile, LPCWSTR sOtherDirs)
1621 {
1622         FIXME("%s %s\n",debugstr_w(sFile), debugstr_w(sOtherDirs));
1623         return FALSE;
1624 }
1625
1626 /*************************************************************************
1627  * PathFindOnPathAW     [SHELL32]
1628  */
1629 BOOL WINAPI PathFindOnPathAW(LPVOID sFile, LPCVOID sOtherDirs)
1630 {
1631         if (VERSION_OsIsUnicode())
1632           return PathFindOnPathW(sFile, sOtherDirs);
1633         return PathFindOnPathA(sFile, sOtherDirs);
1634 }
1635
1636 /*************************************************************************
1637  * PathCleanupSpecA     [SHELL32.171]
1638  */
1639 DWORD WINAPI PathCleanupSpecA(LPSTR x, LPSTR y)
1640 {
1641         FIXME("(%p %s, %p %s) stub\n",x,debugstr_a(x),y,debugstr_a(y));
1642         return TRUE;
1643 }
1644
1645 /*************************************************************************
1646  * PathCleanupSpecA     [SHELL32]
1647  */
1648 DWORD WINAPI PathCleanupSpecW(LPWSTR x, LPWSTR y)
1649 {
1650         FIXME("(%p %s, %p %s) stub\n",x,debugstr_w(x),y,debugstr_w(y));
1651         return TRUE;
1652 }
1653
1654 /*************************************************************************
1655  * PathCleanupSpecAW    [SHELL32]
1656  */
1657 DWORD WINAPI PathCleanupSpecAW (LPVOID x, LPVOID y)
1658 {
1659         if (VERSION_OsIsUnicode())
1660           return PathCleanupSpecW(x,y);
1661         return PathCleanupSpecA(x,y);
1662 }
1663
1664 /*************************************************************************
1665  * PathQualifyA         [SHELL32]
1666  */
1667 BOOL WINAPI PathQualifyA(LPCSTR pszPath) 
1668 {
1669         FIXME("%s\n",pszPath);
1670         return 0;
1671 }
1672
1673 /*************************************************************************
1674  * PathQualifyW         [SHELL32]
1675  */
1676 BOOL WINAPI PathQualifyW(LPCWSTR pszPath) 
1677 {
1678         FIXME("%s\n",debugstr_w(pszPath));
1679         return 0;
1680 }
1681
1682 /*************************************************************************
1683  * PathQualifyAW        [SHELL32]
1684  */
1685 BOOL WINAPI PathQualifyAW(LPCVOID pszPath) 
1686 {
1687         if (VERSION_OsIsUnicode())
1688           return PathQualifyW(pszPath);
1689         return PathQualifyA(pszPath);
1690 }
1691
1692 /*************************************************************************
1693  * PathResolveA [SHELL32.51]
1694  */
1695 BOOL WINAPI PathResolveA(
1696         LPSTR lpszPath,
1697         LPCSTR *alpszPaths, 
1698         DWORD dwFlags)
1699 {
1700         FIXME("(%s,%p,0x%08lx),stub!\n",
1701           lpszPath, *alpszPaths, dwFlags);
1702         return 0;
1703 }
1704
1705 /*************************************************************************
1706  * PathResolveW [SHELL32]
1707  */
1708 BOOL WINAPI PathResolveW(
1709         LPWSTR lpszPath,
1710         LPCWSTR *alpszPaths, 
1711         DWORD dwFlags)
1712 {
1713         FIXME("(%s,%p,0x%08lx),stub!\n",
1714           debugstr_w(lpszPath), debugstr_w(*alpszPaths), dwFlags);
1715         return 0;
1716 }
1717
1718 /*************************************************************************
1719  * PathResolveAW [SHELL32]
1720  */
1721 BOOL WINAPI PathResolveAW(
1722         LPVOID lpszPath,
1723         LPCVOID *alpszPaths, 
1724         DWORD dwFlags)
1725 {
1726         if (VERSION_OsIsUnicode())
1727           return PathResolveW(lpszPath, (LPCWSTR*)alpszPaths, dwFlags);
1728         return PathResolveA(lpszPath, (LPCSTR*)alpszPaths, dwFlags);
1729 }
1730
1731 /*************************************************************************
1732 *       PathProcessCommandA     [SHELL32.653]
1733 */
1734 HRESULT WINAPI PathProcessCommandA (
1735         LPCSTR lpszPath,
1736         LPSTR lpszBuff,
1737         DWORD dwBuffSize,
1738         DWORD dwFlags)
1739 {
1740         FIXME("%s %p 0x%04lx 0x%04lx stub\n",
1741         lpszPath, lpszBuff, dwBuffSize, dwFlags);
1742         lstrcpyA(lpszBuff, lpszPath);
1743         return 0;
1744 }
1745
1746 /*************************************************************************
1747 *       PathProcessCommandW
1748 */
1749 HRESULT WINAPI PathProcessCommandW (
1750         LPCWSTR lpszPath,
1751         LPWSTR lpszBuff,
1752         DWORD dwBuffSize,
1753         DWORD dwFlags)
1754 {
1755         FIXME("(%s, %p, 0x%04lx, 0x%04lx) stub\n",
1756         debugstr_w(lpszPath), lpszBuff, dwBuffSize, dwFlags);
1757         lstrcpyW(lpszBuff, lpszPath);
1758         return 0;
1759 }
1760
1761 /*************************************************************************
1762 *       PathProcessCommandAW
1763 */
1764 HRESULT WINAPI PathProcessCommandAW (
1765         LPCVOID lpszPath,
1766         LPVOID lpszBuff,
1767         DWORD dwBuffSize,
1768         DWORD dwFlags)
1769 {
1770         if (VERSION_OsIsUnicode())
1771           return PathProcessCommandW(lpszPath, lpszBuff, dwBuffSize, dwFlags);
1772         return PathProcessCommandA(lpszPath, lpszBuff, dwBuffSize, dwFlags);
1773 }
1774
1775 /*
1776         special
1777 */
1778
1779 /*************************************************************************
1780  * PathSetDlgItemPathA
1781  *
1782  * NOTES
1783  *  use PathCompactPath to make sure, the path fits into the control
1784  */
1785 BOOL WINAPI PathSetDlgItemPathA(HWND hDlg, int id, LPCSTR pszPath) 
1786 {       TRACE("%x %x %s\n",hDlg, id, pszPath);
1787         return SetDlgItemTextA(hDlg, id, pszPath);
1788 }
1789
1790 /*************************************************************************
1791  * PathSetDlgItemPathW
1792  */
1793 BOOL WINAPI PathSetDlgItemPathW(HWND hDlg, int id, LPCWSTR pszPath) 
1794 {       TRACE("%x %x %s\n",hDlg, id, debugstr_w(pszPath));
1795         return SetDlgItemTextW(hDlg, id, pszPath);
1796 }
1797
1798 /*************************************************************************
1799  * PathSetDlgItemPathAW
1800  */
1801 BOOL WINAPI PathSetDlgItemPathAW(HWND hDlg, int id, LPCVOID pszPath) 
1802 {       if (VERSION_OsIsUnicode())
1803           return PathSetDlgItemPathW(hDlg, id, pszPath);
1804         return PathSetDlgItemPathA(hDlg, id, pszPath);
1805 }
1806
1807
1808 /*************************************************************************
1809  * SHGetSpecialFolderPathA [SHELL32.175]
1810  * 
1811  * converts csidl to path
1812  * 
1813  */
1814  
1815 static char * szSHFolders = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders";
1816 static char * szSHUserFolders = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders";
1817
1818 BOOL WINAPI SHGetSpecialFolderPathA (
1819         HWND hwndOwner,
1820         LPSTR szPath,
1821         DWORD csidl,
1822         BOOL bCreate)
1823 {
1824         CHAR    szValueName[MAX_PATH], szDefaultPath[MAX_PATH];
1825         HKEY    hRootKey, hKey;
1826         BOOL    bRelative = TRUE;
1827         DWORD   dwType, dwDisp, dwPathLen = MAX_PATH;
1828
1829         TRACE("0x%04x,%p,csidl=%lu,0x%04x\n", hwndOwner,szPath,csidl,bCreate);
1830
1831         /* build default values */
1832         switch(csidl)
1833         {
1834           case CSIDL_APPDATA:
1835             hRootKey = HKEY_CURRENT_USER;
1836             strcpy (szValueName, "AppData");
1837             strcpy (szDefaultPath, "AppData");
1838             break;
1839
1840           case CSIDL_COOKIES:
1841             hRootKey = HKEY_CURRENT_USER;
1842             strcpy (szValueName, "Cookies");
1843             strcpy(szDefaultPath, "Cookies");
1844             break;
1845
1846           case CSIDL_DESKTOPDIRECTORY:
1847             hRootKey = HKEY_CURRENT_USER;
1848             strcpy(szValueName, "Desktop");
1849             strcpy(szDefaultPath, "Desktop");
1850             break;
1851
1852           case CSIDL_COMMON_DESKTOPDIRECTORY:
1853             hRootKey = HKEY_LOCAL_MACHINE;
1854             strcpy(szValueName, "Common Desktop");
1855             strcpy(szDefaultPath, "Desktop");
1856             break;
1857
1858           case CSIDL_FAVORITES:
1859             hRootKey = HKEY_CURRENT_USER;
1860             strcpy(szValueName, "Favorites");
1861             strcpy(szDefaultPath, "Favorites");
1862             break;
1863
1864           case CSIDL_FONTS:
1865             hRootKey = HKEY_CURRENT_USER;
1866             strcpy(szValueName, "Fonts");
1867             strcpy(szDefaultPath, "Fonts");
1868             break;
1869
1870           case CSIDL_HISTORY:
1871             hRootKey = HKEY_CURRENT_USER;
1872             strcpy(szValueName, "History");
1873             strcpy(szDefaultPath, "History");
1874             break;
1875
1876           case CSIDL_NETHOOD:
1877             hRootKey = HKEY_CURRENT_USER;
1878             strcpy(szValueName, "NetHood");
1879             strcpy(szDefaultPath, "NetHood");
1880             break;
1881
1882           case CSIDL_INTERNET_CACHE:
1883             hRootKey = HKEY_CURRENT_USER;
1884             strcpy(szValueName, "Cache");
1885             strcpy(szDefaultPath, "Temporary Internet Files");
1886             break;
1887
1888           case CSIDL_PERSONAL:
1889             hRootKey = HKEY_CURRENT_USER;
1890             strcpy(szValueName, "Personal");
1891             strcpy(szDefaultPath, "My Own Files");
1892             bRelative = FALSE;
1893             break;
1894
1895           case CSIDL_PRINTHOOD:
1896             hRootKey = HKEY_CURRENT_USER;
1897             strcpy(szValueName, "PrintHood");
1898             strcpy(szDefaultPath, "PrintHood");
1899             break;
1900
1901           case CSIDL_PROGRAMS:
1902             hRootKey = HKEY_CURRENT_USER;
1903             strcpy(szValueName, "Programs");
1904             strcpy(szDefaultPath, "StartMenu\\Programs");
1905             break;
1906
1907           case CSIDL_COMMON_PROGRAMS:
1908             hRootKey = HKEY_LOCAL_MACHINE;
1909             strcpy(szValueName, "Common Programs");
1910             strcpy(szDefaultPath, "");
1911             break;
1912
1913           case CSIDL_RECENT:
1914             hRootKey = HKEY_CURRENT_USER;
1915             strcpy(szValueName, "Recent");
1916             strcpy(szDefaultPath, "Recent");
1917             break;
1918
1919           case CSIDL_SENDTO:
1920             hRootKey = HKEY_CURRENT_USER;
1921             strcpy(szValueName, "SendTo");
1922             strcpy(szDefaultPath, "SendTo");
1923             break;
1924
1925           case CSIDL_STARTMENU:
1926             hRootKey = HKEY_CURRENT_USER;
1927             strcpy(szValueName, "StartMenu");
1928             strcpy(szDefaultPath, "StartMenu");
1929             break;
1930
1931           case CSIDL_COMMON_STARTMENU:
1932             hRootKey = HKEY_LOCAL_MACHINE;
1933             strcpy(szValueName, "Common StartMenu");
1934             strcpy(szDefaultPath, "StartMenu");
1935             break;
1936
1937           case CSIDL_STARTUP:
1938             hRootKey = HKEY_CURRENT_USER;
1939             strcpy(szValueName, "Startup");
1940             strcpy(szDefaultPath, "StartMenu\\Programs\\Startup");
1941             break;
1942
1943           case CSIDL_COMMON_STARTUP:
1944             hRootKey = HKEY_LOCAL_MACHINE;
1945             strcpy(szValueName, "Common Startup");
1946             strcpy(szDefaultPath, "StartMenu\\Programs\\Startup");
1947             break;
1948
1949           case CSIDL_TEMPLATES:
1950             hRootKey = HKEY_CURRENT_USER;
1951             strcpy(szValueName, "Templates");
1952             strcpy(szDefaultPath, "ShellNew");
1953             break;
1954
1955           default:
1956             ERR("folder unknown or not allowed\n");
1957             return FALSE;
1958         }
1959
1960         /* user shell folders */
1961         if (RegCreateKeyExA(hRootKey,szSHUserFolders,0,NULL,0,KEY_ALL_ACCESS,NULL,&hKey,&dwDisp)) return FALSE;
1962
1963         if (RegQueryValueExA(hKey,szValueName,NULL,&dwType,(LPBYTE)szPath,&dwPathLen))
1964         {
1965           RegCloseKey(hKey);
1966
1967           /* shell folders */
1968           if (RegCreateKeyExA(hRootKey,szSHFolders,0,NULL,0,KEY_ALL_ACCESS,NULL,&hKey,&dwDisp)) return FALSE;
1969
1970           if (RegQueryValueExA(hKey,szValueName,NULL,&dwType,(LPBYTE)szPath,&dwPathLen))
1971           {
1972
1973             /* value not existing */
1974             if (bRelative)
1975             {
1976               GetWindowsDirectoryA(szPath, MAX_PATH);
1977               PathAddBackslashA(szPath);
1978               strcat(szPath, szDefaultPath);
1979             }
1980             else
1981             {
1982               strcpy(szPath, "C:\\");   /* fixme ??? */
1983               strcat(szPath, szDefaultPath);
1984             }
1985             RegSetValueExA(hKey,szValueName,0,REG_SZ,(LPBYTE)szPath,strlen(szPath)+1);
1986           }
1987         }
1988         RegCloseKey(hKey);
1989
1990         if (bCreate && CreateDirectoryA(szPath,NULL))
1991         {
1992             MESSAGE("Created not existing system directory '%s'\n", szPath);
1993         }
1994
1995         return TRUE;
1996 }
1997
1998 /*************************************************************************
1999  * SHGetSpecialFolderPathW
2000  */
2001 BOOL WINAPI SHGetSpecialFolderPathW (
2002         HWND hwndOwner,
2003         LPWSTR szPath,
2004         DWORD csidl,
2005         BOOL bCreate)
2006 {
2007         char szTemp[MAX_PATH];
2008         
2009         if (SHGetSpecialFolderPathA(hwndOwner, szTemp, csidl, bCreate))
2010         {
2011           lstrcpynAtoW(szPath, szTemp, MAX_PATH);
2012         }
2013
2014         TRACE("0x%04x,%p,csidl=%lu,0x%04x\n", hwndOwner,szPath,csidl,bCreate);
2015
2016         return TRUE;
2017 }
2018
2019 /*************************************************************************
2020  * SHGetSpecialFolderPathAW
2021  */
2022 BOOL WINAPI SHGetSpecialFolderPathAW (
2023         HWND hwndOwner,
2024         LPVOID szPath,
2025         DWORD csidl,
2026         BOOL bCreate)
2027
2028 {
2029         if (VERSION_OsIsUnicode())
2030           return SHGetSpecialFolderPathW (hwndOwner, szPath, csidl, bCreate);
2031         return SHGetSpecialFolderPathA (hwndOwner, szPath, csidl, bCreate);
2032 }
2033
2034 /*************************************************************************
2035  * PathCanonicalizeA
2036  *
2037  *  FIXME
2038  *   returnvalue
2039  */
2040  
2041 BOOL WINAPI PathCanonicalizeA(LPSTR pszBuf, LPCSTR pszPath)
2042 {
2043         int OffsetMin = 0, OffsetSrc = 0, OffsetDst = 0, LenSrc = strlen(pszPath);
2044         BOOL bModifyed = FALSE;
2045
2046         TRACE("%p %s\n", pszBuf, pszPath);
2047         
2048         pszBuf[OffsetDst]='\0';
2049
2050         /* keep the root of the path */
2051         if( LenSrc && (pszPath[OffsetSrc]=='\\'))
2052         {
2053           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2054         }
2055         else if ( (LenSrc >= 2) && (pszPath[OffsetSrc+1] == ':'))
2056         {
2057           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2058           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2059           if (LenSrc && (pszPath[OffsetSrc] == '\\'))
2060           {
2061             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2062             if (LenSrc == 1 && pszPath[OffsetSrc]=='.')
2063             {
2064               /* C:\. */
2065               OffsetSrc++; LenSrc--; bModifyed = TRUE;
2066             } 
2067             else if (LenSrc == 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='.')
2068             {
2069               /* C:\.. */
2070               OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
2071             } 
2072           }
2073         }
2074         
2075         /* ".\" at the beginning of the path */
2076         if (LenSrc >= 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='\\')
2077         {
2078           OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
2079         } 
2080         
2081         while ( LenSrc )
2082         {
2083           if((LenSrc>=3) && (pszPath[OffsetSrc]=='\\') && (pszPath[OffsetSrc+1]=='.') && (pszPath[OffsetSrc+2]=='.'))
2084           {
2085             /* "\.." found, go one deeper */
2086             while((OffsetDst > OffsetMin) && (pszBuf[OffsetDst]!='\\')) OffsetDst--;
2087             OffsetSrc += 3; LenSrc -= 3; bModifyed = TRUE;
2088             if(OffsetDst == OffsetMin && pszPath[OffsetSrc]=='\\') OffsetSrc++;
2089             pszBuf[OffsetDst] = '\0';                   /* important for \..\.. */
2090           }
2091           else if(LenSrc>=2 && pszPath[OffsetSrc]=='\\' && pszPath[OffsetSrc+1]=='.' )
2092           {
2093             /* "\." found, skip it */
2094             OffsetSrc += 2; LenSrc-=2; bModifyed = TRUE;
2095           }
2096           else
2097           {
2098             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; LenSrc--;
2099           }
2100         }
2101         pszBuf[OffsetDst] = '\0';
2102         TRACE("-- %s %u\n", pszBuf, bModifyed);
2103         return bModifyed;
2104 }
2105
2106
2107 /*************************************************************************
2108  * PathCanonicalizeW
2109  *
2110  *  FIXME
2111  *   returnvalue
2112  */
2113 BOOL WINAPI PathCanonicalizeW(LPWSTR pszBuf, LPCWSTR pszPath)
2114 {
2115         int OffsetMin = 0, OffsetSrc = 0, OffsetDst = 0, LenSrc = lstrlenW(pszPath);
2116         BOOL bModifyed = FALSE;
2117
2118         TRACE("%p %s\n", pszBuf, debugstr_w(pszPath));
2119         
2120         pszBuf[OffsetDst]='\0';
2121
2122         /* keep the root of the path */
2123         if( LenSrc && (pszPath[OffsetSrc]=='\\'))
2124         {
2125           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2126         }
2127         else if ( (LenSrc >= 2) && (pszPath[OffsetSrc+1] == ':'))
2128         {
2129           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2130           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2131           if (LenSrc && (pszPath[OffsetSrc] == '\\'))
2132           {
2133             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2134             if (LenSrc == 1 && pszPath[OffsetSrc]=='.')
2135             {
2136               /* C:\. */
2137               OffsetSrc++; LenSrc--; bModifyed = TRUE;
2138             } 
2139             else if (LenSrc == 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='.')
2140             {
2141               /* C:\.. */
2142               OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
2143             } 
2144           }
2145         }
2146         
2147         /* ".\" at the beginning of the path */
2148         if (LenSrc >= 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='\\')
2149         {
2150           OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
2151         } 
2152         
2153         while ( LenSrc )
2154         {
2155           if((LenSrc>=3) && (pszPath[OffsetSrc]=='\\') && (pszPath[OffsetSrc+1]=='.') && (pszPath[OffsetSrc+2]=='.'))
2156           {
2157             /* "\.." found, go one deeper */
2158             while((OffsetDst > OffsetMin) && (pszBuf[OffsetDst]!='\\')) OffsetDst--;
2159             OffsetSrc += 3; LenSrc -= 3; bModifyed = TRUE;
2160             if(OffsetDst == OffsetMin && pszPath[OffsetSrc]=='\\') OffsetSrc++;
2161             pszBuf[OffsetDst] = '\0';                   /* important for \..\.. */
2162           }
2163           else if(LenSrc>=2 && pszPath[OffsetSrc]=='\\' && pszPath[OffsetSrc+1]=='.' )
2164           {
2165             /* "\." found, skip it */
2166             OffsetSrc += 2; LenSrc-=2; bModifyed = TRUE;
2167           }
2168           else
2169           {
2170             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; LenSrc--;
2171           }
2172         }
2173         pszBuf[OffsetDst] = '\0';
2174         TRACE("-- %s %u\n", debugstr_w(pszBuf), bModifyed);
2175         return bModifyed;
2176 }
2177
2178 /*************************************************************************
2179  * PathFindNextComponentA
2180  *
2181  * Windows returns a pointer NULL (BO 000605)
2182  */
2183 LPSTR WINAPI PathFindNextComponentA(LPCSTR pszPath)
2184 {
2185         while( *pszPath )
2186         {
2187           if(*pszPath++=='\\')
2188             return (LPSTR) pszPath;
2189         }
2190         return (LPSTR) pszPath;
2191 }
2192
2193 /*************************************************************************
2194  * PathFindNextComponentW
2195  */
2196 LPWSTR WINAPI PathFindNextComponentW(LPCWSTR pszPath)
2197 {
2198         while( *pszPath )
2199         {
2200           if(*pszPath++=='\\')
2201             return (LPWSTR) pszPath;
2202         }
2203         return (LPWSTR) pszPath;
2204 }
2205
2206 /*************************************************************************
2207  * PathAddExtensionA
2208  */
2209  
2210 static void _PathAddDotA(LPSTR lpszPath)
2211 {
2212         int len = strlen(lpszPath);
2213         if (len && lpszPath[len-1]!='.')
2214         {
2215           lpszPath[len]  = '.';
2216           lpszPath[len+1]= '\0';
2217         }
2218 }
2219
2220 BOOL WINAPI PathAddExtensionA(
2221         LPSTR  pszPath,
2222         LPCSTR pszExtension)
2223 {
2224         if (*pszPath)
2225         {
2226           LPSTR pszExt = PathFindFileNameA(pszPath);    /* last path component */
2227           pszExt = PathFindExtensionA(pszExt);      
2228           if (*pszExt != '\0') return FALSE;            /* already with extension */
2229           _PathAddDotA(pszPath);
2230         }
2231
2232         if (!pszExtension || *pszExtension=='\0')
2233           strcat(pszPath, "exe");
2234         else
2235           strcat(pszPath, pszExtension);
2236         return TRUE;
2237 }
2238
2239 /*************************************************************************
2240  *      PathAddExtensionW
2241  */
2242 static void _PathAddDotW(LPWSTR lpszPath)
2243 {
2244         int len = lstrlenW(lpszPath);
2245         if (len && lpszPath[len-1]!='.')
2246         {
2247           lpszPath[len]  = '.';
2248           lpszPath[len+1]= '\0';
2249         }
2250 }
2251
2252 /*************************************************************************
2253  *      PathAddExtensionW
2254  */
2255 BOOL WINAPI PathAddExtensionW(
2256         LPWSTR  pszPath,
2257         LPCWSTR pszExtension)
2258 {
2259         static const WCHAR ext[] = { 'e','x','e',0 };
2260
2261         if (*pszPath)
2262         {
2263           LPWSTR pszExt = PathFindFileNameW(pszPath);   /* last path component */
2264           pszExt = PathFindExtensionW(pszExt);      
2265           if (*pszExt != '\0') return FALSE;            /* already with extension */
2266           _PathAddDotW(pszPath);
2267         }
2268
2269         if (!pszExtension || *pszExtension=='\0')
2270           lstrcatW(pszPath, ext);
2271         else
2272           lstrcatW(pszPath, pszExtension);
2273         return TRUE;
2274
2275 }
2276
2277 /*************************************************************************
2278  *      PathIsUNCServerA
2279  */
2280 BOOL WINAPI PathIsUNCServerA(
2281         LPCSTR pszPath)
2282 {
2283         FIXME("%s\n", pszPath);
2284         return FALSE;
2285 }
2286
2287 /*************************************************************************
2288  *      PathIsUNCServerW
2289  */
2290 BOOL WINAPI PathIsUNCServerW(
2291         LPCWSTR pszPath)
2292 {
2293         FIXME("%s\n", debugstr_w(pszPath));
2294         return FALSE;
2295 }
2296
2297 /*************************************************************************
2298  *      PathIsUNCServerShareA
2299  */
2300 BOOL WINAPI PathIsUNCServerShareA(
2301         LPCSTR pszPath)
2302 {
2303         FIXME("%s\n", pszPath);
2304         return FALSE;
2305 }
2306
2307 /*************************************************************************
2308  *      PathIsUNCServerShareW
2309  */
2310 BOOL WINAPI PathIsUNCServerShareW(
2311         LPCWSTR pszPath)
2312 {
2313         FIXME("%s\n", debugstr_w(pszPath));
2314         return FALSE;
2315 }
2316
2317 /*************************************************************************
2318  *      PathMakePrettyA
2319  */
2320 BOOL WINAPI PathMakePrettyA(
2321         LPSTR lpPath)
2322 {
2323         FIXME("%s\n", lpPath);
2324         return TRUE;
2325 }
2326
2327 /*************************************************************************
2328  *      PathMakePrettyW
2329  */
2330 BOOL WINAPI PathMakePrettyW(
2331         LPWSTR lpPath)
2332 {
2333         FIXME("%s\n", debugstr_w(lpPath));
2334         return TRUE;
2335 }