Use min/max instead of MIN/MAX.
[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 /*************************************************************************
861  * PathGetDriveNumber32 [SHELL32.57]
862  *
863  */
864 HRESULT WINAPI PathGetDriveNumber(LPSTR u)
865 {       FIXME("%s stub\n",debugstr_a(u));
866         return 0;
867 }
868
869 /*************************************************************************
870  * PathYetAnotherMakeUniqueNameA [SHELL32.75]
871  * 
872  * NOTES
873  *     exported by ordinal
874  */
875 BOOL WINAPI PathYetAnotherMakeUniqueNameA(LPDWORD x,LPDWORD y) {
876     FIXME("(%p,%p):stub.\n",x,y);
877     return TRUE;
878 }
879
880 /*************************************************************************
881  * IsLFNDriveA [SHELL32.119]
882  * 
883  * NOTES
884  *     exported by ordinal Name
885  */
886 BOOL WINAPI IsLFNDriveA(LPCSTR path) {
887     DWORD       fnlen;
888
889     if (!GetVolumeInformationA(path,NULL,0,NULL,&fnlen,NULL,NULL,0))
890         return FALSE;
891     return fnlen>12;
892 }
893
894 /*************************************************************************
895  * PathFindOnPathA
896  */
897 BOOL WINAPI PathFindOnPathA(LPSTR sFile, LPCSTR sOtherDirs)
898 {       FIXME("%s %s\n",sFile, sOtherDirs);
899         return FALSE;
900 }
901
902 /*************************************************************************
903  * PathFindOnPathW
904  */
905 BOOL WINAPI PathFindOnPathW(LPWSTR sFile, LPCWSTR sOtherDirs)
906 {       FIXME("%s %s\n",debugstr_w(sFile), debugstr_w(sOtherDirs));
907         return FALSE;
908 }
909
910 /*************************************************************************
911  * PathFindOnPath [SHELL32.145]
912  */
913 BOOL WINAPI PathFindOnPathAW(LPVOID sFile, LPCVOID sOtherDirs)
914 {       if (VERSION_OsIsUnicode())
915           return PathFindOnPathW(sFile, sOtherDirs);
916         return PathFindOnPathA(sFile, sOtherDirs);
917 }
918
919 /*************************************************************************
920  * PathGetExtension [SHELL32.158]
921  *
922  * NOTES
923  *     exported by ordinal
924  */
925 LPCSTR WINAPI PathGetExtensionA(LPCSTR path,DWORD y,DWORD z)
926 {       TRACE("(%s,%08lx,%08lx)\n",path,y,z);
927         path = PathFindExtensionA(path);
928         return *path?(path+1):path;
929 }
930 LPCWSTR WINAPI PathGetExtensionW(LPCWSTR path,DWORD y,DWORD z)
931 {       TRACE("(%s, %08lx, %08lx)\n",debugstr_w(path),y,z);
932         path = PathFindExtensionW(path);
933         return *path?(path+1):path;
934 }
935 LPCVOID WINAPI PathGetExtensionAW(LPCVOID path,DWORD y,DWORD z) 
936 {       if (VERSION_OsIsUnicode())
937           return PathGetExtensionW(path,y,z);
938         return PathGetExtensionA(path,y,z);
939 }
940
941 /*************************************************************************
942  * PathCleanupSpec                              [SHELL32.171]
943  *
944  */
945 DWORD WINAPI PathCleanupSpecA(LPSTR x, LPSTR y)
946 {
947         FIXME("(%p %s, %p %s) stub\n",x,debugstr_a(x),y,debugstr_a(y));
948         return TRUE;
949 }
950
951 DWORD WINAPI PathCleanupSpecW(LPWSTR x, LPWSTR y)
952 {
953         FIXME("(%p %s, %p %s) stub\n",x,debugstr_w(x),y,debugstr_w(y));
954         return TRUE;
955 }
956
957 DWORD WINAPI PathCleanupSpecAW (LPVOID x, LPVOID y)
958 {
959         if (VERSION_OsIsUnicode())
960           return PathCleanupSpecW(x,y);
961         return PathCleanupSpecA(x,y);
962 }
963
964 /*************************************************************************
965  * SheGetDirW [SHELL32.281]
966  *
967  */
968 HRESULT WINAPI SheGetDirW(LPWSTR u, LPWSTR v)
969 {       FIXME("%p %p stub\n",u,v);
970         return 0;
971 }
972
973 /*************************************************************************
974  * SheChangeDirW [SHELL32.274]
975  *
976  */
977 HRESULT WINAPI SheChangeDirW(LPWSTR u)
978 {       FIXME("(%s),stub\n",debugstr_w(u));
979         return 0;
980 }
981
982 /*************************************************************************
983 *       PathProcessCommand      [SHELL32.653]
984 */
985 HRESULT WINAPI PathProcessCommandA (LPSTR lpCommand, LPSTR v, DWORD w, DWORD x)
986 {
987         FIXME("%p(%s) %p 0x%04lx 0x%04lx stub\n",
988         lpCommand, lpCommand, v, w,x );
989         lstrcpyA(v, lpCommand);
990         return 0;
991 }
992
993 HRESULT WINAPI PathProcessCommandW (LPWSTR lpCommand, LPSTR v, DWORD w, DWORD x)
994 {
995         FIXME("(%p %s, %p, 0x%04lx, 0x%04lx) stub\n",
996         lpCommand, debugstr_w(lpCommand), v, w,x );
997         return 0;
998 }
999
1000 HRESULT WINAPI PathProcessCommandAW (LPVOID lpCommand, LPSTR v, DWORD w, DWORD x)
1001 {
1002         if (VERSION_OsIsUnicode())
1003           return PathProcessCommandW(lpCommand, v, w, x);
1004         return PathProcessCommandA(lpCommand, v, w, x);
1005 }
1006
1007 /*************************************************************************
1008  * SHGetSpecialFolderPathA
1009  * 
1010  * converts csidl to path
1011  * 
1012  */
1013  
1014 static char * szSHFolders = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders";
1015
1016 BOOL WINAPI SHGetSpecialFolderPathA (
1017         HWND hwndOwner,
1018         LPSTR szPath,
1019         DWORD csidl,
1020         BOOL bCreate)
1021 {
1022         CHAR    szValueName[MAX_PATH], szDefaultPath[MAX_PATH];
1023         HKEY    hRootKey, hKey;
1024         BOOL    bRelative = TRUE;
1025         DWORD   dwType, dwDisp, dwPathLen = MAX_PATH;
1026
1027         TRACE("0x%04x,%p,csidl=%lu,0x%04x\n", hwndOwner,szPath,csidl,bCreate);
1028
1029         /* build default values */
1030         switch(csidl)
1031         {
1032           case CSIDL_APPDATA:
1033             hRootKey = HKEY_CURRENT_USER;
1034             strcpy (szValueName, "AppData");
1035             strcpy (szDefaultPath, "AppData");
1036             break;
1037
1038           case CSIDL_COOKIES:
1039             hRootKey = HKEY_CURRENT_USER;
1040             strcpy (szValueName, "Cookies");
1041             strcpy(szDefaultPath, "Cookies");
1042             break;
1043
1044           case CSIDL_DESKTOPDIRECTORY:
1045             hRootKey = HKEY_CURRENT_USER;
1046             strcpy(szValueName, "Desktop");
1047             strcpy(szDefaultPath, "Desktop");
1048             break;
1049
1050           case CSIDL_COMMON_DESKTOPDIRECTORY:
1051             hRootKey = HKEY_LOCAL_MACHINE;
1052             strcpy(szValueName, "Common Desktop");
1053             strcpy(szDefaultPath, "Desktop");
1054             break;
1055
1056           case CSIDL_FAVORITES:
1057             hRootKey = HKEY_CURRENT_USER;
1058             strcpy(szValueName, "Favorites");
1059             strcpy(szDefaultPath, "Favorites");
1060             break;
1061
1062           case CSIDL_FONTS:
1063             hRootKey = HKEY_CURRENT_USER;
1064             strcpy(szValueName, "Fonts");
1065             strcpy(szDefaultPath, "Fonts");
1066             break;
1067
1068           case CSIDL_HISTORY:
1069             hRootKey = HKEY_CURRENT_USER;
1070             strcpy(szValueName, "History");
1071             strcpy(szDefaultPath, "History");
1072             break;
1073
1074           case CSIDL_NETHOOD:
1075             hRootKey = HKEY_CURRENT_USER;
1076             strcpy(szValueName, "NetHood");
1077             strcpy(szDefaultPath, "NetHood");
1078             break;
1079
1080           case CSIDL_INTERNET_CACHE:
1081             hRootKey = HKEY_CURRENT_USER;
1082             strcpy(szValueName, "Cache");
1083             strcpy(szDefaultPath, "Temporary Internet Files");
1084             break;
1085
1086           case CSIDL_PERSONAL:
1087             hRootKey = HKEY_CURRENT_USER;
1088             strcpy(szValueName, "Personal");
1089             strcpy(szDefaultPath, "My Own Files");
1090             bRelative = FALSE;
1091             break;
1092
1093           case CSIDL_PRINTHOOD:
1094             hRootKey = HKEY_CURRENT_USER;
1095             strcpy(szValueName, "PrintHood");
1096             strcpy(szDefaultPath, "PrintHood");
1097             break;
1098
1099           case CSIDL_PROGRAMS:
1100             hRootKey = HKEY_CURRENT_USER;
1101             strcpy(szValueName, "Programs");
1102             strcpy(szDefaultPath, "StartMenu\\Programs");
1103             break;
1104
1105           case CSIDL_COMMON_PROGRAMS:
1106             hRootKey = HKEY_LOCAL_MACHINE;
1107             strcpy(szValueName, "Common Programs");
1108             strcpy(szDefaultPath, "");
1109             break;
1110
1111           case CSIDL_RECENT:
1112             hRootKey = HKEY_CURRENT_USER;
1113             strcpy(szValueName, "Recent");
1114             strcpy(szDefaultPath, "Recent");
1115             break;
1116
1117           case CSIDL_SENDTO:
1118             hRootKey = HKEY_CURRENT_USER;
1119             strcpy(szValueName, "SendTo");
1120             strcpy(szDefaultPath, "SendTo");
1121             break;
1122
1123           case CSIDL_STARTMENU:
1124             hRootKey = HKEY_CURRENT_USER;
1125             strcpy(szValueName, "StartMenu");
1126             strcpy(szDefaultPath, "StartMenu");
1127             break;
1128
1129           case CSIDL_COMMON_STARTMENU:
1130             hRootKey = HKEY_LOCAL_MACHINE;
1131             strcpy(szValueName, "Common StartMenu");
1132             strcpy(szDefaultPath, "StartMenu");
1133             break;
1134
1135           case CSIDL_STARTUP:
1136             hRootKey = HKEY_CURRENT_USER;
1137             strcpy(szValueName, "Startup");
1138             strcpy(szDefaultPath, "StartMenu\\Programs\\Startup");
1139             break;
1140
1141           case CSIDL_COMMON_STARTUP:
1142             hRootKey = HKEY_LOCAL_MACHINE;
1143             strcpy(szValueName, "Common Startup");
1144             strcpy(szDefaultPath, "StartMenu\\Programs\\Startup");
1145             break;
1146
1147           case CSIDL_TEMPLATES:
1148             hRootKey = HKEY_CURRENT_USER;
1149             strcpy(szValueName, "Templates");
1150             strcpy(szDefaultPath, "ShellNew");
1151             break;
1152
1153           default:
1154             ERR("folder unknown or not allowed\n");
1155             return FALSE;
1156         }
1157
1158         if (RegCreateKeyExA(hRootKey,szSHFolders,0,NULL,REG_OPTION_NON_VOLATILE,KEY_WRITE,NULL,&hKey,&dwDisp))
1159         {
1160           return FALSE;
1161         }
1162
1163         if (RegQueryValueExA(hKey,szValueName,NULL,&dwType,(LPBYTE)szPath,&dwPathLen))
1164         {
1165           /* value not existing */
1166           if (bRelative)
1167           {
1168             GetWindowsDirectoryA(szPath, MAX_PATH);
1169             PathAddBackslashA(szPath);
1170             strcat(szPath, szDefaultPath);
1171           }
1172           else
1173           {
1174             strcpy(szPath, szDefaultPath);
1175           }
1176           if (bCreate)
1177           {
1178             CreateDirectoryA(szPath,NULL);
1179           }
1180           RegSetValueExA(hKey,szValueName,0,REG_SZ,(LPBYTE)szPath,strlen(szPath)+1);
1181         }
1182         RegCloseKey(hKey);
1183
1184         return TRUE;
1185 }
1186
1187 /*************************************************************************
1188  * SHGetSpecialFolderPathW
1189  * 
1190  * converts csidl to path
1191  * 
1192  */
1193 BOOL WINAPI SHGetSpecialFolderPathW (
1194         HWND hwndOwner,
1195         LPWSTR szPath,
1196         DWORD csidl,
1197         BOOL bCreate)
1198 {
1199         char szTemp[MAX_PATH];
1200         
1201         if (SHGetSpecialFolderPathA(hwndOwner, szTemp, csidl, bCreate))
1202         {
1203           lstrcpynAtoW(szPath, szTemp, MAX_PATH);
1204         }
1205
1206         TRACE("0x%04x,%p,csidl=%lu,0x%04x\n", hwndOwner,szPath,csidl,bCreate);
1207
1208         return TRUE;
1209 }
1210
1211 /*************************************************************************
1212  * SHGetSpecialFolderPath [SHELL32.175]
1213  * 
1214  * converts csidl to path
1215  * 
1216  */
1217 BOOL WINAPI SHGetSpecialFolderPathAW (
1218         HWND hwndOwner,
1219         LPVOID szPath,
1220         DWORD csidl,
1221         BOOL bCreate)
1222
1223 {
1224         if (VERSION_OsIsUnicode())
1225           return SHGetSpecialFolderPathW (hwndOwner, szPath, csidl, bCreate);
1226         return SHGetSpecialFolderPathA (hwndOwner, szPath, csidl, bCreate);
1227 }
1228
1229 /*************************************************************************
1230  * PathRemoveBackslashA
1231  *
1232  * If the path ends in a backslash it is replaced by a NULL
1233  * and the address of the NULL is returned
1234  * Otherwise 
1235  * the address of the last character is returned.
1236  *
1237  */
1238 LPSTR WINAPI PathRemoveBackslashA( LPSTR lpPath )
1239 {
1240         LPSTR p = lpPath;
1241         
1242         while (*lpPath) p = lpPath++;
1243         if ( *p == (CHAR)'\\') *p = (CHAR)'\0';
1244         return p;
1245 }
1246
1247 /*************************************************************************
1248  * PathRemoveBackslashW
1249  *
1250  */
1251 LPWSTR WINAPI PathRemoveBackslashW( LPWSTR lpPath )
1252 {
1253         LPWSTR p = lpPath;
1254         
1255         while (*lpPath); p = lpPath++;
1256         if ( *p == (WCHAR)'\\') *p = (WCHAR)'\0';
1257         return p;
1258 }
1259
1260 /*************************************************************************
1261  * PathIsURLA
1262  *
1263  */
1264 BOOL WINAPI PathIsURLA(LPCSTR lpstrPath)
1265 {
1266   LPSTR lpstrRes;
1267   char lpstrFileType[10] = "";
1268   int iSize;
1269   int i = 0;
1270   /* sanity check */
1271   if(!lpstrPath)
1272     return FALSE;
1273
1274   /* get protocol        */
1275   /* protocol://location */
1276   if(!(lpstrRes = strchr(lpstrPath,':')))
1277   {
1278     return FALSE;
1279   }
1280   iSize = lpstrRes - lpstrPath;
1281   if(iSize > sizeof(lpstrFileType))
1282     return FALSE;
1283
1284   strncpy(lpstrFileType,lpstrPath,iSize);
1285
1286   while(strlen(SupportedProtocol[i]))
1287   {
1288     if(!_stricmp(lpstrFileType,SupportedProtocol[i++]))
1289       return TRUE;
1290   }
1291
1292   return FALSE;
1293 }  
1294
1295 /*************************************************************************
1296  * PathIsDirectoryA
1297  *
1298  */
1299 BOOL WINAPI PathIsDirectoryA(LPCSTR pszPath)
1300 {
1301         FIXME("%s\n", debugstr_a(pszPath));
1302         return TRUE;
1303 }
1304
1305 /*************************************************************************
1306  * PathIsDirectoryW
1307  *
1308  */
1309 BOOL WINAPI PathIsDirectoryW(LPCWSTR pszPath)
1310 {
1311         FIXME("%s\n", debugstr_w(pszPath));
1312         return TRUE;
1313 }
1314 /*************************************************************************
1315  * PathIsDirectory
1316  *
1317  */
1318 BOOL WINAPI PathIsDirectoryAW (LPCVOID pszPath)
1319 {
1320         if (VERSION_OsIsUnicode())
1321           return PathIsDirectoryW (pszPath);
1322         return PathIsDirectoryA (pszPath);
1323 }