No longer directly accessing debuggee memory.
[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 #include "tchar.h"
15
16 #include "shlobj.h"
17 #include "shell32_main.h"
18 #include "windef.h"
19 #include "options.h"
20
21 DEFAULT_DEBUG_CHANNEL(shell)
22
23 /* Supported protocols for PathIsURL */
24 LPSTR SupportedProtocol[] = {"http","https","ftp","gopher","file","mailto",""};
25
26 /*************************************************************************
27  * PathIsRoot [SHELL32.29]
28  */
29 BOOL WINAPI PathIsRootA(LPCSTR x)
30 {       TRACE("%s\n",x);
31         if (*(x+1)==':' && *(x+2)=='\\')                /* "X:\" */
32           return 1;
33         if (*x=='\\')           /* "\" */
34           return 0;
35         if (x[0]=='\\' && x[1]=='\\')           /* UNC "\\<xx>\" */
36         { int   foundbackslash = 0;
37           x=x+2;
38           while (*x)
39           { if (*x++=='\\')
40               foundbackslash++;
41           }
42           if (foundbackslash<=1)        /* max 1 \ more ... */
43             return 1;
44         }
45         return 0;
46 }
47 BOOL WINAPI PathIsRootW(LPCWSTR x) 
48 {       TRACE("%s\n",debugstr_w(x));
49         if (*(x+1)==':' && *(x+2)=='\\')                /* "X:\" */
50           return 1;
51         if (*x == (WCHAR) '\\')         /* "\" */
52           return 0;
53         if (x[0]==(WCHAR)'\\' && x[1]==(WCHAR)'\\')     /* UNC "\\<xx>\" */
54         { int   foundbackslash = 0;
55           x=x+2;
56           while (*x) 
57           { if (*x++==(WCHAR)'\\')
58               foundbackslash++;
59           }
60           if (foundbackslash<=1)        /* max 1 \ more ... */
61             return 1;
62         }
63         return 0;
64 }
65 BOOL WINAPI PathIsRootAW(LPCVOID x) 
66 {       if (VERSION_OsIsUnicode())
67           return PathIsRootW(x);
68         return PathIsRootA(x);
69
70 }
71 /*************************************************************************
72  * PathBuildRoot [SHELL32.30]
73  */
74 LPSTR WINAPI PathBuildRootA(LPSTR root,BYTE drive) {
75   TRACE("%p %i\n",root, drive);
76         strcpy(root,"A:\\");
77         root[0]+=drive;
78         return root;
79 }
80
81 /*************************************************************************
82  * PathFindExtension [SHELL32.31]
83  *
84  * NOTES
85  *     returns pointer to last . in last pathcomponent or at \0.
86  */
87 LPCSTR WINAPI PathFindExtensionA(LPCSTR path) 
88 {       LPCSTR   lastpoint = NULL;
89         TRACE("%p %s\n",path,path);
90         while (*path) 
91         { if (*path=='\\'||*path==' ')
92             lastpoint=NULL;
93           if (*path=='.')
94             lastpoint=path;
95           path++;
96         }
97         return lastpoint?lastpoint:path;
98 }
99 LPCWSTR WINAPI PathFindExtensionW(LPCWSTR path) 
100 {       LPCWSTR   lastpoint = NULL;
101         TRACE("(%p %s)\n",path,debugstr_w(path));
102         while (*path)
103         { if (*path==(WCHAR)'\\'||*path==(WCHAR)' ')
104             lastpoint=NULL;
105           if (*path==(WCHAR)'.')
106             lastpoint=path;
107           path++;
108         }
109         return lastpoint?lastpoint:path;
110 }
111 LPCVOID WINAPI PathFindExtensionAW(LPCVOID path) 
112 {       if (VERSION_OsIsUnicode())
113           return PathFindExtensionW(path);
114         return PathFindExtensionA(path);
115
116 }
117
118 /*************************************************************************
119  * PathAddBackslash [SHELL32.32]
120  * 
121  * NOTES
122  *     append \ if there is none
123  */
124 LPSTR WINAPI PathAddBackslashA(LPSTR path)
125 {       int len;
126         TRACE("%p->%s\n",path,path);
127
128         len = strlen(path);
129         if (len && path[len-1]!='\\') 
130         { path[len]  = '\\';
131           path[len+1]= 0x00;
132           return path+len+1;
133         }
134         return path+len;
135 }
136 LPWSTR WINAPI PathAddBackslashW(LPWSTR path)
137 {       int len;
138         TRACE("%p->%s\n",path,debugstr_w(path));
139
140         len = CRTDLL_wcslen(path);
141         if (len && path[len-1]!=(WCHAR)'\\') 
142         { path[len]  = (WCHAR)'\\';
143           path[len+1]= 0x00;
144           return path+len+1;
145         }
146         return path+len;
147 }
148 LPVOID WINAPI PathAddBackslashAW(LPVOID path)
149 {       if(VERSION_OsIsUnicode())
150           return PathAddBackslashW(path);
151         return PathAddBackslashA(path);
152 }
153
154 /*************************************************************************
155  * PathRemoveBlanks [SHELL32.33]
156  * 
157  * NOTES
158  *     remove spaces from beginning and end of passed string
159  */
160 LPSTR WINAPI PathRemoveBlanksA(LPSTR str)
161 {       LPSTR x = str;
162         TRACE("%s\n",str);
163         while (*x==' ') x++;
164         if (x!=str)
165           strcpy(str,x);
166         if (!*str)
167           return str;
168         x=str+strlen(str)-1;
169         while (*x==' ')
170           x--;
171         if (*x==' ')
172           *x='\0';
173         return x;
174 }
175 LPWSTR WINAPI PathRemoveBlanksW(LPWSTR str)
176 {       LPWSTR x = str;
177         TRACE("%s\n",debugstr_w(str));
178         while (*x==' ') x++;
179         if (x!=str)
180           CRTDLL_wcscpy(str,x);
181         if (!*str)
182           return str;
183         x=str+CRTDLL_wcslen(str)-1;
184         while (*x==' ')
185           x--;
186         if (*x==' ')
187           *x='\0';
188         return x;
189 }
190 LPVOID WINAPI PathRemoveBlanksAW(LPVOID str)
191 {       if(VERSION_OsIsUnicode())
192           return PathRemoveBlanksW(str);
193         return PathRemoveBlanksA(str);
194 }
195
196
197
198 /*************************************************************************
199  * PathFindFilename [SHELL32.34]
200  * 
201  * NOTES
202  *     basename(char *fn);
203  */
204 LPCSTR WINAPI PathFindFilenameA(LPCSTR aptr)
205 {       LPCSTR aslash;
206         aslash = aptr;
207
208         TRACE("%s\n",aslash);
209         while (aptr[0]) 
210         { if (((aptr[0]=='\\') || (aptr[0]==':')) && aptr[1] && aptr[1]!='\\')
211               aslash = aptr+1;
212           aptr++;
213         }
214         return aslash;
215
216 }
217 LPCWSTR WINAPI PathFindFilenameW(LPCWSTR wptr)
218 {       LPCWSTR wslash;
219         wslash = wptr;
220
221         TRACE("%s\n",debugstr_w(wslash));
222         while (wptr[0]) 
223         { if (((wptr[0]=='\\') || (wptr[0]==':')) && wptr[1] && wptr[1]!='\\')
224             wslash = wptr+1;
225           wptr++;
226         }
227         return wslash;  
228 }
229 LPCVOID WINAPI PathFindFilenameAW(LPCVOID fn)
230 {
231         if(VERSION_OsIsUnicode())
232           return PathFindFilenameW(fn);
233         return PathFindFilenameA(fn);
234 }
235
236 /*************************************************************************
237  * PathRemoveFileSpec [SHELL32.35]
238  * 
239  * NOTES
240  *     bool getpath(char *pathname); truncates passed argument to a valid path
241  *     returns if the string was modified or not.
242  *     "\foo\xx\foo"-> "\foo\xx"
243  *     "\" -> "\"
244  *     "a:\foo" -> "a:\"
245  */
246 DWORD WINAPI PathRemoveFileSpecA(LPSTR fn) {
247         LPSTR   x,cutplace;
248   TRACE("%s\n",fn);
249         if (!fn[0])
250                 return 0;
251         x=fn;
252         cutplace = fn;
253         while (*x) {
254                 if (*x=='\\') {
255                         cutplace=x++;
256                         continue;
257                 }
258                 if (*x==':') {
259                         x++;
260                         if (*x=='\\')
261                                 cutplace=++x;
262                         continue; /* already x++ed */
263                 }
264                 x++;
265         }
266         if (!*cutplace)
267                 return 0;
268         if (cutplace==fn) {
269                 if (fn[0]=='\\') {
270                         if (!fn[1])
271                                 return 0;
272                         fn[0]='\0';
273                         return 1;
274                 }
275         }
276         *cutplace='\0';
277         return 1;
278 }
279
280 /*************************************************************************
281  * PathAppend [SHELL32.36]
282  * 
283  * NOTES
284  *     concat_paths(char*target,const char*add);
285  *     concats "target\\add" and writes them to target
286  */
287 LPSTR WINAPI PathAppendA(LPSTR x1,LPSTR x2) {
288   TRACE("%s %s\n",x1,x2);
289   while (x2[0]=='\\') x2++;
290   return PathCombineA(x1,x1,x2);
291 }
292
293 /*************************************************************************
294  * PathCombine [SHELL32.37]
295  * 
296  * NOTES
297  *  if lpszFile='.' skip it
298  *  szDest can be equal to lpszFile. Thats why we use sTemp
299  */
300 LPSTR WINAPI PathCombineA(LPSTR szDest, LPCSTR lpszDir, LPCSTR lpszFile) 
301 {       char sTemp[MAX_PATH];
302         TRACE("%p %p->%s %p->%s\n",szDest, lpszDir, lpszDir, lpszFile, lpszFile);
303         
304         
305         if (!lpszFile || !lpszFile[0] || (lpszFile[0]=='.' && !lpszFile[1]) ) 
306         { strcpy(szDest,lpszDir);
307           return szDest;
308         }
309
310         /*  if lpszFile is a complete path don't care about lpszDir */
311         if (PathIsRootA(lpszFile))
312         { strcpy(szDest,lpszFile);
313         }
314         else
315         { strcpy(sTemp,lpszDir);
316           PathAddBackslashA(sTemp);
317           strcat(sTemp,lpszFile);
318           strcpy(szDest,sTemp);
319         }
320         return szDest;
321 }
322 LPWSTR WINAPI PathCombineW(LPWSTR szDest, LPCWSTR lpszDir, LPCWSTR lpszFile) 
323 {       WCHAR sTemp[MAX_PATH];
324         TRACE("%p %p->%s %p->%s\n",szDest, lpszDir, debugstr_w(lpszDir),
325                          lpszFile, debugstr_w(lpszFile));
326         
327         
328         if (!lpszFile || !lpszFile[0] || (lpszFile[0]==(WCHAR)'.' && !lpszFile[1]) ) 
329         { CRTDLL_wcscpy(szDest,lpszDir);
330           return szDest;
331         }
332
333         /*  if lpszFile is a complete path don't care about lpszDir */
334         if (PathIsRootW(lpszFile))
335         { CRTDLL_wcscpy(szDest,lpszFile);
336         }
337         else
338         { CRTDLL_wcscpy(sTemp,lpszDir);
339           PathAddBackslashW(sTemp);
340           CRTDLL_wcscat(sTemp,lpszFile);
341           CRTDLL_wcscpy(szDest,sTemp);
342         }
343         return szDest;
344 }
345 LPVOID WINAPI PathCombineAW(LPVOID szDest, LPCVOID lpszDir, LPCVOID lpszFile) 
346 {       if (VERSION_OsIsUnicode())
347           return PathCombineW( szDest, lpszDir, lpszFile );
348         return PathCombineA( szDest, lpszDir, lpszFile );
349 }
350
351 /*************************************************************************
352  * PathIsUNC [SHELL32.39]
353  * 
354  * NOTES
355  *     PathIsUNC(char*path);
356  */
357 BOOL WINAPI PathIsUNCA(LPCSTR path) 
358 {       TRACE("%s\n",path);
359
360         if ((path[0]=='\\') && (path[1]=='\\'))
361           return TRUE;
362         return FALSE;
363 }
364 BOOL WINAPI PathIsUNCW(LPCWSTR path) 
365 {       TRACE("%s\n",debugstr_w(path));
366
367         if ((path[0]=='\\') && (path[1]=='\\'))
368           return TRUE;
369         return FALSE;
370 }
371 BOOL WINAPI PathIsUNCAW (LPCVOID path)
372 {       if (VERSION_OsIsUnicode())
373           return PathIsUNCW( path );
374         return PathIsUNCA( path );  
375 }
376 /*************************************************************************
377  *  PathIsRelativ [SHELL32.40]
378  * 
379  */
380 BOOL WINAPI PathIsRelativeA (LPCSTR path)
381 {       TRACE("path=%s\n",path);
382
383         if (path && (path[0]!='\\' && path[1]==':'))
384           return TRUE;
385         return FALSE;    
386 }
387 BOOL WINAPI PathIsRelativeW (LPCWSTR path)
388 {       TRACE("path=%s\n",debugstr_w(path));
389
390         if (path && (path[0]!='\\' && path[1]==':'))
391           return TRUE;
392         return FALSE;    
393 }
394 BOOL WINAPI PathIsRelativeAW (LPCVOID path)
395 {       if (VERSION_OsIsUnicode())
396           return PathIsRelativeW( path );
397         return PathIsRelativeA( path );  
398 }
399 /*************************************************************************
400  *  PathIsExe [SHELL32.43]
401  * 
402  */
403 BOOL WINAPI PathIsExeA (LPCSTR path)
404 {       FIXME("path=%s\n",path);
405         return FALSE;
406 }
407 BOOL WINAPI PathIsExeW (LPCWSTR path)
408 {       FIXME("path=%s\n",debugstr_w(path));
409         return FALSE;
410 }
411 BOOL WINAPI PathIsExeAW (LPCVOID path)
412 {       if (VERSION_OsIsUnicode())
413           return PathIsExeW (path);
414         return PathIsExeA(path);
415 }
416
417 /*************************************************************************
418  * PathFileExists [SHELL32.45]
419  * 
420  * NOTES
421  *     file_exists(char *fn);
422  */
423 BOOL WINAPI PathFileExistsA(LPSTR fn) {
424   TRACE("%s\n",fn);
425    if (GetFileAttributesA(fn)==-1)
426         return FALSE;
427     else
428         return TRUE;
429 }
430 /*************************************************************************
431  * PathMatchSingleMask
432  * 
433  * NOTES
434  *     internal (used by PathMatchSpec)
435  */
436 static BOOL PathMatchSingleMaskA(LPCSTR name, LPCSTR mask)
437 {
438   while (*name && *mask && *mask!=';') {
439     if (*mask=='*') {
440       do {
441         if (PathMatchSingleMaskA(name,mask+1)) return 1;  /* try substrings */
442       } while (*name++);
443       return 0;
444     }
445     if (toupper(*mask)!=toupper(*name) && *mask!='?') return 0;
446     name++;
447     mask++;
448   }
449   if (!*name) {
450     while (*mask=='*') mask++;
451     if (!*mask || *mask==';') return 1;
452   }
453   return 0;
454 }
455 static BOOL PathMatchSingleMaskW(LPCWSTR name, LPCWSTR mask)
456 {
457   while (*name && *mask && *mask!=';') {
458     if (*mask=='*') {
459       do {
460         if (PathMatchSingleMaskW(name,mask+1)) return 1;  /* try substrings */
461       } while (*name++);
462       return 0;
463     }
464     if (towupper(*mask)!=towupper(*name) && *mask!='?') return 0;
465     name++;
466     mask++;
467   }
468   if (!*name) {
469     while (*mask=='*') mask++;
470     if (!*mask || *mask==';') return 1;
471   }
472   return 0;
473 }
474 /*************************************************************************
475  * PathMatchSpec [SHELL32.46]
476  * 
477  * NOTES
478  *     used from COMDLG32
479  */
480 BOOL WINAPI PathMatchSpecA(LPCSTR name, LPCSTR mask) 
481 {
482   TRACE("%s %s\n",name,mask);
483
484   if (!lstrcmpA( mask, "*.*" )) return 1;   /* we don't require a period */
485
486   while (*mask) {
487     if (PathMatchSingleMaskA(name,mask)) return 1;    /* helper function */
488     while (*mask && *mask!=';') mask++;
489     if (*mask==';') {
490       mask++;
491       while (*mask==' ') mask++;      /*  masks may be separated by "; " */
492           }
493         }
494   return 0;
495 }
496 BOOL WINAPI PathMatchSpecW(LPCWSTR name, LPCWSTR mask) 
497 {
498   WCHAR stemp[4];
499   TRACE("%s %s\n",debugstr_w(name),debugstr_w(mask));
500
501         lstrcpyAtoW(stemp,"*.*");       
502   if (!lstrcmpW( mask, stemp )) return 1;   /* we don't require a period */
503
504   while (*mask) {
505     if (PathMatchSingleMaskW(name,mask)) return 1;    /* helper function */
506     while (*mask && *mask!=';') mask++;
507     if (*mask==';') {
508       mask++;
509       while (*mask==' ') mask++;       /* masks may be separated by "; " */
510           }
511         }
512   return 0;
513 }
514 BOOL WINAPI PathMatchSpecAW(LPVOID name, LPVOID mask) 
515 {       if (VERSION_OsIsUnicode())
516           return PathMatchSpecW( name, mask );
517         return PathMatchSpecA( name, mask );
518 }
519 /*************************************************************************
520  * PathSetDlgItemPathAW [SHELL32.48]
521  * NOTES
522  *  use PathCompactPath to make sure, the path fits into the control
523  */
524
525 BOOL WINAPI PathSetDlgItemPathA(HWND hDlg, int id, LPCSTR pszPath) 
526 {       TRACE("%x %x %s\n",hDlg, id, pszPath);
527         return SetDlgItemTextA(hDlg, id, pszPath);
528 }
529 BOOL WINAPI PathSetDlgItemPathW(HWND hDlg, int id, LPCWSTR pszPath) 
530 {       TRACE("%x %x %s\n",hDlg, id, debugstr_w(pszPath));
531         return SetDlgItemTextW(hDlg, id, pszPath);
532 }
533 BOOL WINAPI PathSetDlgItemPathAW(HWND hDlg, int id, LPCVOID pszPath) 
534 {       if (VERSION_OsIsUnicode())
535           return PathSetDlgItemPathW(hDlg, id, pszPath);
536         return PathSetDlgItemPathA(hDlg, id, pszPath);
537 }
538
539 /*************************************************************************
540  * PathQualifyAW [SHELL32.49]
541  */
542
543 BOOL WINAPI PathQualifyA(LPCSTR pszPath) 
544 {       FIXME("%s\n",pszPath);
545         return 0;
546 }
547 BOOL WINAPI PathQualifyW(LPCWSTR pszPath) 
548 {       FIXME("%s\n",debugstr_w(pszPath));
549         return 0;
550 }
551 BOOL WINAPI PathQualifyAW(LPCVOID pszPath) 
552 {       if (VERSION_OsIsUnicode())
553           return PathQualifyW(pszPath);
554         return PathQualifyA(pszPath);
555 }
556
557 /*************************************************************************
558  * PathResolve [SHELL32.51]
559  */
560 DWORD WINAPI PathResolve(LPCSTR s,DWORD x2,DWORD x3) {
561         FIXME("(%s,0x%08lx,0x%08lx),stub!\n",s,x2,x3);
562         return 0;
563 }
564
565 /*************************************************************************
566  * PathGetArgs [SHELL32.52]
567  *
568  * NOTES
569  *     look for next arg in string. handle "quoted" strings
570  *     returns pointer to argument *AFTER* the space. Or to the \0.
571  */
572 LPCSTR WINAPI PathGetArgsA(LPCSTR cmdline) 
573 {       BOOL    qflag = FALSE;
574
575         TRACE("%s\n",cmdline);
576
577         while (*cmdline) 
578         { if ((*cmdline==' ') && !qflag)
579             return cmdline+1;
580           if (*cmdline=='"')
581             qflag=!qflag;
582           cmdline++;
583         }
584         return cmdline;
585
586 }
587 LPCWSTR WINAPI PathGetArgsW(LPCWSTR cmdline) 
588 {       BOOL    qflag = FALSE;
589
590         TRACE("%s\n",debugstr_w(cmdline));
591
592         while (*cmdline) 
593         { if ((*cmdline==' ') && !qflag)
594             return cmdline+1;
595           if (*cmdline=='"')
596             qflag=!qflag;
597           cmdline++;
598         }
599         return cmdline;
600 }
601 LPCVOID WINAPI PathGetArgsAW(LPVOID cmdline) 
602 {       if (VERSION_OsIsUnicode())
603           return PathGetArgsW(cmdline);
604         return PathGetArgsA(cmdline);
605 }
606 /*************************************************************************
607  * PathQuoteSpaces [SHELL32.55]
608  * 
609  * NOTES
610  *     basename(char *fn);
611  */
612 LPSTR WINAPI PathQuoteSpacesA(LPCSTR aptr)
613 {       FIXME("%s\n",aptr);
614         return 0;
615
616 }
617 LPWSTR WINAPI PathQuoteSpacesW(LPCWSTR wptr)
618 {       FIXME("%s\n",debugstr_w(wptr));
619         return 0;       
620 }
621 LPVOID WINAPI PathQuoteSpacesAW (LPCVOID fn)
622 {       if(VERSION_OsIsUnicode())
623           return PathQuoteSpacesW(fn);
624         return PathQuoteSpacesA(fn);
625 }
626
627
628 /*************************************************************************
629  * PathUnquoteSpaces [SHELL32.56]
630  * 
631  * NOTES
632  *     unquote string (remove ")
633  */
634 VOID WINAPI PathUnquoteSpacesA(LPSTR str) 
635 {       DWORD      len = lstrlenA(str);
636         TRACE("%s\n",str);
637         if (*str!='"')
638           return;
639         if (str[len-1]!='"')
640           return;
641         str[len-1]='\0';
642         lstrcpyA(str,str+1);
643         return;
644 }
645 VOID WINAPI PathUnquoteSpacesW(LPWSTR str) 
646 {       DWORD len = CRTDLL_wcslen(str);
647
648         TRACE("%s\n",debugstr_w(str));
649
650         if (*str!='"')
651           return;
652         if (str[len-1]!='"')
653           return;
654         str[len-1]='\0';
655         CRTDLL_wcscpy(str,str+1);
656         return;
657 }
658 VOID WINAPI PathUnquoteSpacesAW(LPVOID str) 
659 {
660         if(VERSION_OsIsUnicode())
661           PathUnquoteSpacesW(str);
662         else
663           PathUnquoteSpacesA(str);
664 }
665
666
667 /*************************************************************************
668  * PathGetDriveNumber32 [SHELL32.57]
669  *
670  */
671 HRESULT WINAPI PathGetDriveNumber(LPSTR u)
672 {       FIXME("%s stub\n",debugstr_a(u));
673         return 0;
674 }
675
676 /*************************************************************************
677  * PathYetAnotherMakeUniqueName [SHELL32.75]
678  * 
679  * NOTES
680  *     exported by ordinal
681  */
682 BOOL WINAPI PathYetAnotherMakeUniqueNameA(LPDWORD x,LPDWORD y) {
683     FIXME("(%p,%p):stub.\n",x,y);
684     return TRUE;
685 }
686
687 /*************************************************************************
688  * IsLFNDrive [SHELL32.119]
689  * 
690  * NOTES
691  *     exported by ordinal Name
692  */
693 BOOL WINAPI IsLFNDriveA(LPCSTR path) {
694     DWORD       fnlen;
695
696     if (!GetVolumeInformationA(path,NULL,0,NULL,&fnlen,NULL,NULL,0))
697         return FALSE;
698     return fnlen>12;
699 }
700 /*************************************************************************
701  * PathFindOnPath [SHELL32.145]
702  */
703 BOOL WINAPI PathFindOnPathA(LPSTR sFile, LPCSTR sOtherDirs)
704 {       FIXME("%s %s\n",sFile, sOtherDirs);
705         return FALSE;
706 }
707 BOOL WINAPI PathFindOnPathW(LPWSTR sFile, LPCWSTR sOtherDirs)
708 {       FIXME("%s %s\n",debugstr_w(sFile), debugstr_w(sOtherDirs));
709         return FALSE;
710 }
711 BOOL WINAPI PathFindOnPathAW(LPVOID sFile, LPCVOID sOtherDirs)
712 {       if (VERSION_OsIsUnicode())
713           return PathFindOnPathW(sFile, sOtherDirs);
714         return PathFindOnPathA(sFile, sOtherDirs);
715 }
716
717 /*************************************************************************
718  * PathGetExtension [SHELL32.158]
719  *
720  * NOTES
721  *     exported by ordinal
722  */
723 LPCSTR WINAPI PathGetExtensionA(LPCSTR path,DWORD y,DWORD z)
724 {       TRACE("(%s,%08lx,%08lx)\n",path,y,z);
725         path = PathFindExtensionA(path);
726         return *path?(path+1):path;
727 }
728 LPCWSTR WINAPI PathGetExtensionW(LPCWSTR path,DWORD y,DWORD z)
729 {       TRACE("(%s, %08lx, %08lx)\n",debugstr_w(path),y,z);
730         path = PathFindExtensionW(path);
731         return *path?(path+1):path;
732 }
733 LPCVOID WINAPI PathGetExtensionAW(LPCVOID path,DWORD y,DWORD z) 
734 {       if (VERSION_OsIsUnicode())
735           return PathGetExtensionW(path,y,z);
736         return PathGetExtensionA(path,y,z);
737 }
738
739 /*************************************************************************
740  * PathCleanupSpec                              [SHELL32.171]
741  *
742  */
743 DWORD WINAPI PathCleanupSpecA(LPSTR x, LPSTR y)
744 {
745         FIXME("(%p %s, %p %s) stub\n",x,debugstr_a(x),y,debugstr_a(y));
746         return TRUE;
747 }
748
749 DWORD WINAPI PathCleanupSpecW(LPWSTR x, LPWSTR y)
750 {
751         FIXME("(%p %s, %p %s) stub\n",x,debugstr_w(x),y,debugstr_w(y));
752         return TRUE;
753 }
754
755 DWORD WINAPI PathCleanupSpecAW (LPVOID x, LPVOID y)
756 {
757         if (VERSION_OsIsUnicode())
758           return PathCleanupSpecW(x,y);
759         return PathCleanupSpecA(x,y);
760 }
761
762 /*************************************************************************
763  * SheGetDirW [SHELL32.281]
764  *
765  */
766 HRESULT WINAPI SheGetDirW(LPWSTR u, LPWSTR v)
767 {       FIXME("%p %p stub\n",u,v);
768         return 0;
769 }
770
771 /*************************************************************************
772  * SheChangeDirW [SHELL32.274]
773  *
774  */
775 HRESULT WINAPI SheChangeDirW(LPWSTR u)
776 {       FIXME("(%s),stub\n",debugstr_w(u));
777         return 0;
778 }
779
780 /*************************************************************************
781 *       PathProcessCommand      [SHELL32.653]
782 */
783 HRESULT WINAPI PathProcessCommandA (LPSTR lpCommand, LPSTR v, DWORD w, DWORD x)
784 {
785         FIXME("%p(%s) %p 0x%04lx 0x%04lx stub\n",
786         lpCommand, lpCommand, v, w,x );
787         lstrcpyA(v, lpCommand);
788         return 0;
789 }
790
791 HRESULT WINAPI PathProcessCommandW (LPWSTR lpCommand, LPSTR v, DWORD w, DWORD x)
792 {
793         FIXME("(%p %s, %p, 0x%04lx, 0x%04lx) stub\n",
794         lpCommand, debugstr_w(lpCommand), v, w,x );
795         return 0;
796 }
797
798 HRESULT WINAPI PathProcessCommandAW (LPVOID lpCommand, LPSTR v, DWORD w, DWORD x)
799 {
800         if (VERSION_OsIsUnicode())
801           return PathProcessCommandW(lpCommand, v, w, x);
802         return PathProcessCommandA(lpCommand, v, w, x);
803 }
804
805 /*************************************************************************
806  * SHGetSpecialFolderPath [SHELL32.175]
807  * 
808  * converts csidl to path
809  * 
810  */
811  
812 static char * szSHFolders = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders";
813
814 BOOL WINAPI SHGetSpecialFolderPathA (
815         HWND hwndOwner,
816         LPSTR szPath,
817         DWORD csidl,
818         BOOL bCreate)
819 {
820         CHAR    szValueName[MAX_PATH], szDefaultPath[MAX_PATH];
821         HKEY    hRootKey, hKey;
822         BOOL    bRelative = TRUE;
823         DWORD   dwType, dwDisp, dwPathLen = MAX_PATH;
824
825         TRACE("0x%04x,%p,csidl=%lu,0x%04x\n", hwndOwner,szPath,csidl,bCreate);
826
827         /* build default values */
828         switch(csidl)
829         {
830           case CSIDL_APPDATA:
831             hRootKey = HKEY_CURRENT_USER;
832             strcpy (szValueName, "AppData");
833             strcpy (szDefaultPath, "AppData");
834             break;
835
836           case CSIDL_COOKIES:
837             hRootKey = HKEY_CURRENT_USER;
838             strcpy (szValueName, "Cookies");
839             strcpy(szDefaultPath, "Cookies");
840             break;
841
842           case CSIDL_DESKTOPDIRECTORY:
843             hRootKey = HKEY_CURRENT_USER;
844             strcpy(szValueName, "Desktop");
845             strcpy(szDefaultPath, "Desktop");
846             break;
847
848           case CSIDL_COMMON_DESKTOPDIRECTORY:
849             hRootKey = HKEY_LOCAL_MACHINE;
850             strcpy(szValueName, "Common Desktop");
851             strcpy(szDefaultPath, "Desktop");
852             break;
853
854           case CSIDL_FAVORITES:
855             hRootKey = HKEY_CURRENT_USER;
856             strcpy(szValueName, "Favorites");
857             strcpy(szDefaultPath, "Favorites");
858             break;
859
860           case CSIDL_FONTS:
861             hRootKey = HKEY_CURRENT_USER;
862             strcpy(szValueName, "Fonts");
863             strcpy(szDefaultPath, "Fonts");
864             break;
865
866           case CSIDL_HISTORY:
867             hRootKey = HKEY_CURRENT_USER;
868             strcpy(szValueName, "History");
869             strcpy(szDefaultPath, "History");
870             break;
871
872           case CSIDL_NETHOOD:
873             hRootKey = HKEY_CURRENT_USER;
874             strcpy(szValueName, "NetHood");
875             strcpy(szDefaultPath, "NetHood");
876             break;
877
878           case CSIDL_INTERNET_CACHE:
879             hRootKey = HKEY_CURRENT_USER;
880             strcpy(szValueName, "Cache");
881             strcpy(szDefaultPath, "Temporary Internet Files");
882             break;
883
884           case CSIDL_PERSONAL:
885             hRootKey = HKEY_CURRENT_USER;
886             strcpy(szValueName, "Personal");
887             strcpy(szDefaultPath, "My Own Files");
888             bRelative = FALSE;
889             break;
890
891           case CSIDL_PRINTHOOD:
892             hRootKey = HKEY_CURRENT_USER;
893             strcpy(szValueName, "PrintHood");
894             strcpy(szDefaultPath, "PrintHood");
895             break;
896
897           case CSIDL_PROGRAMS:
898             hRootKey = HKEY_CURRENT_USER;
899             strcpy(szValueName, "Programs");
900             strcpy(szDefaultPath, "StartMenu\\Programs");
901             break;
902
903           case CSIDL_COMMON_PROGRAMS:
904             hRootKey = HKEY_LOCAL_MACHINE;
905             strcpy(szValueName, "Common Programs");
906             strcpy(szDefaultPath, "");
907             break;
908
909           case CSIDL_RECENT:
910             hRootKey = HKEY_CURRENT_USER;
911             strcpy(szValueName, "Recent");
912             strcpy(szDefaultPath, "Recent");
913             break;
914
915           case CSIDL_SENDTO:
916             hRootKey = HKEY_CURRENT_USER;
917             strcpy(szValueName, "SendTo");
918             strcpy(szDefaultPath, "SendTo");
919             break;
920
921           case CSIDL_STARTMENU:
922             hRootKey = HKEY_CURRENT_USER;
923             strcpy(szValueName, "StartMenu");
924             strcpy(szDefaultPath, "StartMenu");
925             break;
926
927           case CSIDL_COMMON_STARTMENU:
928             hRootKey = HKEY_LOCAL_MACHINE;
929             strcpy(szValueName, "Common StartMenu");
930             strcpy(szDefaultPath, "StartMenu");
931             break;
932
933           case CSIDL_STARTUP:
934             hRootKey = HKEY_CURRENT_USER;
935             strcpy(szValueName, "Startup");
936             strcpy(szDefaultPath, "StartMenu\\Programs\\Startup");
937             break;
938
939           case CSIDL_COMMON_STARTUP:
940             hRootKey = HKEY_LOCAL_MACHINE;
941             strcpy(szValueName, "Common Startup");
942             strcpy(szDefaultPath, "StartMenu\\Programs\\Startup");
943             break;
944
945           case CSIDL_TEMPLATES:
946             hRootKey = HKEY_CURRENT_USER;
947             strcpy(szValueName, "Templates");
948             strcpy(szDefaultPath, "ShellNew");
949             break;
950
951           default:
952             ERR("folder unknown or not allowed\n");
953             return FALSE;
954         }
955
956         if (RegCreateKeyExA(hRootKey,szSHFolders,0,NULL,REG_OPTION_NON_VOLATILE,KEY_WRITE,NULL,&hKey,&dwDisp))
957         {
958           return FALSE;
959         }
960
961         if (RegQueryValueExA(hKey,szValueName,NULL,&dwType,(LPBYTE)szPath,&dwPathLen))
962         {
963           /* value not existing */
964           if (bRelative)
965           {
966             GetWindowsDirectoryA(szPath, MAX_PATH);
967             PathAddBackslashA(szPath);
968             strcat(szPath, szDefaultPath);
969           }
970           else
971           {
972             strcpy(szPath, szDefaultPath);
973           }
974           if (bCreate)
975           {
976             CreateDirectoryA(szPath,NULL);
977           }
978           RegSetValueExA(hKey,szValueName,0,REG_SZ,(LPBYTE)szPath,strlen(szPath)+1);
979         }
980         RegCloseKey(hKey);
981
982         return TRUE;
983 }
984 BOOL WINAPI SHGetSpecialFolderPathW (
985         HWND hwndOwner,
986         LPWSTR szPath,
987         DWORD csidl,
988         BOOL bCreate)
989 {
990         char szTemp[MAX_PATH];
991         
992         if (SHGetSpecialFolderPathA(hwndOwner, szTemp, csidl, bCreate))
993         {
994           lstrcpynAtoW(szPath, szTemp, MAX_PATH);
995         }
996
997         TRACE("0x%04x,%p,csidl=%lu,0x%04x\n", hwndOwner,szPath,csidl,bCreate);
998
999         return TRUE;
1000 }
1001 BOOL WINAPI SHGetSpecialFolderPathAW (
1002         HWND hwndOwner,
1003         LPVOID szPath,
1004         DWORD csidl,
1005         BOOL bCreate)
1006
1007 {
1008         if (VERSION_OsIsUnicode())
1009           return SHGetSpecialFolderPathW (hwndOwner, szPath, csidl, bCreate);
1010         return SHGetSpecialFolderPathA (hwndOwner, szPath, csidl, bCreate);
1011 }
1012
1013 /* PathRemoveBackslash
1014  *
1015  * If the path ends in a backslash it is replaced by a NULL
1016  * and the address of the NULL is returned
1017  * Otherwise 
1018  * the address of the last character is returned.
1019  *
1020  */
1021
1022 LPSTR WINAPI PathRemoveBackslashA( LPSTR lpPath )
1023 {
1024         LPSTR p = lpPath;
1025         
1026         while (*lpPath) p = lpPath++;
1027         if ( *p == (CHAR)'\\') *p = (CHAR)'\0';
1028         return p;
1029 }
1030
1031 LPWSTR WINAPI PathRemoveBackslashW( LPWSTR lpPath )
1032 {
1033         LPWSTR p = lpPath;
1034         
1035         while (*lpPath); p = lpPath++;
1036         if ( *p == (WCHAR)'\\') *p = (WCHAR)'\0';
1037         return p;
1038 }
1039
1040 BOOL WINAPI PathIsURLA(LPCSTR lpstrPath)
1041 {
1042   LPSTR lpstrRes;
1043   char lpstrFileType[10] = "";
1044   int iSize;
1045   int i = 0;
1046   /* sanity check */
1047   if(!lpstrPath)
1048     return FALSE;
1049
1050   /* get protocol        */
1051   /* protocol://location */
1052   if(!(lpstrRes = strchr(lpstrPath,':')))
1053   {
1054     return FALSE;
1055   }
1056   iSize = lpstrRes - lpstrPath;
1057   if(iSize > sizeof(lpstrFileType))
1058     return FALSE;
1059
1060   strncpy(lpstrFileType,lpstrPath,iSize);
1061
1062   while(strlen(SupportedProtocol[i]))
1063   {
1064     if(!_stricmp(lpstrFileType,SupportedProtocol[i++]))
1065       return TRUE;
1066   }
1067
1068   return FALSE;
1069 }  
1070
1071 /*************************************************************************
1072  * PathIsDirectory
1073  *
1074  */
1075 BOOL WINAPI PathIsDirectoryA(LPCSTR pszPath)
1076 {
1077         FIXME("%s\n", debugstr_a(pszPath));
1078         return TRUE;
1079 }
1080 BOOL WINAPI PathIsDirectoryW(LPCWSTR pszPath)
1081 {
1082         FIXME("%s\n", debugstr_w(pszPath));
1083         return TRUE;
1084 }
1085 BOOL WINAPI PathIsDirectoryAW (LPCVOID pszPath)
1086 {
1087         if (VERSION_OsIsUnicode())
1088           return PathIsDirectoryW (pszPath);
1089         return PathIsDirectoryA (pszPath);
1090 }