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