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