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