Recovery of release 990110 after disk crash.
[wine.git] / dlls / shell32 / shellpath.c
blobf6c49f6a14222acf1f6bab18926e974ac6cc3ecb
1 /*
2 * Path Functions
4 * Many of this functions are in SHLWAPI.DLL also
6 */
7 #include <stdlib.h>
8 #include <string.h>
9 #include <ctype.h>
10 #include "windows.h"
11 #include "winerror.h"
12 #include "file.h"
13 #include "shell.h"
14 #include "shlobj.h"
15 #include "debug.h"
16 #include "winnls.h"
17 #include "winversion.h"
18 #include "shell32_main.h"
20 /*************************************************************************
21 * PathIsRoot [SHELL32.29]
23 BOOL32 WINAPI PathIsRoot32A(LPCSTR x)
24 { TRACE(shell,"%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++;
36 if (foundbackslash<=1) /* max 1 \ more ... */
37 return 1;
39 return 0;
41 BOOL32 WINAPI PathIsRoot32W(LPCWSTR x)
42 { TRACE(shell,"%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++;
54 if (foundbackslash<=1) /* max 1 \ more ... */
55 return 1;
57 return 0;
59 BOOL32 WINAPI PathIsRoot32AW(LPCVOID x)
60 { if (VERSION_OsIsUnicode())
61 return PathIsRoot32W(x);
62 return PathIsRoot32A(x);
65 /*************************************************************************
66 * PathBuildRoot [SHELL32.30]
68 LPSTR WINAPI PathBuildRoot32A(LPSTR root,BYTE drive) {
69 TRACE(shell,"%p %i\n",root, drive);
70 strcpy(root,"A:\\");
71 root[0]+=drive;
72 return root;
75 /*************************************************************************
76 * PathFindExtension [SHELL32.31]
78 * NOTES
79 * returns pointer to last . in last pathcomponent or at \0.
81 LPCSTR WINAPI PathFindExtension32A(LPCSTR path)
82 { LPCSTR lastpoint = NULL;
83 TRACE(shell,"%p %s\n",path,path);
84 while (*path)
85 { if (*path=='\\'||*path==' ')
86 lastpoint=NULL;
87 if (*path=='.')
88 lastpoint=path;
89 path++;
91 return lastpoint?lastpoint:path;
93 LPCWSTR WINAPI PathFindExtension32W(LPCWSTR path)
94 { LPCWSTR lastpoint = NULL;
95 TRACE(shell,"%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++;
103 return lastpoint?lastpoint:path;
105 LPCVOID WINAPI PathFindExtension32AW(LPCVOID path)
106 { if (VERSION_OsIsUnicode())
107 return PathFindExtension32W(path);
108 return PathFindExtension32A(path);
112 /*************************************************************************
113 * PathAddBackslash [SHELL32.32]
115 * NOTES
116 * append \ if there is none
118 LPSTR WINAPI PathAddBackslash32A(LPSTR path)
119 { int len;
120 TRACE(shell,"%p->%s\n",path,path);
122 len = strlen(path);
123 if (len && path[len-1]!='\\')
124 { path[len] = '\\';
125 path[len+1]= 0x00;
126 return path+len+1;
128 return path+len;
130 LPWSTR WINAPI PathAddBackslash32W(LPWSTR path)
131 { int len;
132 TRACE(shell,"%p->%s\n",path,debugstr_w(path));
134 len = lstrlen32W(path);
135 if (len && path[len-1]!=(WCHAR)'\\')
136 { path[len] = (WCHAR)'\\';
137 path[len+1]= 0x00;
138 return path+len+1;
140 return path+len;
142 LPVOID WINAPI PathAddBackslash32AW(LPVOID path)
143 { if(VERSION_OsIsUnicode())
144 return PathAddBackslash32W(path);
145 return PathAddBackslash32A(path);
148 /*************************************************************************
149 * PathRemoveBlanks [SHELL32.33]
151 * NOTES
152 * remove spaces from beginning and end of passed string
154 LPSTR WINAPI PathRemoveBlanks32A(LPSTR str)
155 { LPSTR x = str;
156 TRACE(shell,"%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;
169 LPWSTR WINAPI PathRemoveBlanks32W(LPWSTR str)
170 { LPWSTR x = str;
171 TRACE(shell,"%s\n",debugstr_w(str));
172 while (*x==' ') x++;
173 if (x!=str)
174 lstrcpy32W(str,x);
175 if (!*str)
176 return str;
177 x=str+lstrlen32W(str)-1;
178 while (*x==' ')
179 x--;
180 if (*x==' ')
181 *x='\0';
182 return x;
184 LPVOID WINAPI PathRemoveBlanks32AW(LPVOID str)
185 { if(VERSION_OsIsUnicode())
186 return PathRemoveBlanks32W(str);
187 return PathRemoveBlanks32A(str);
192 /*************************************************************************
193 * PathFindFilename [SHELL32.34]
195 * NOTES
196 * basename(char *fn);
198 LPCSTR WINAPI PathFindFilename32A(LPCSTR aptr)
199 { LPCSTR aslash;
200 aslash = aptr;
202 TRACE(shell,"%s\n",aslash);
203 while (aptr[0])
204 { if (((aptr[0]=='\\') || (aptr[0]==':')) && aptr[1] && aptr[1]!='\\')
205 aslash = aptr+1;
206 aptr++;
208 return aslash;
211 LPCWSTR WINAPI PathFindFilename32W(LPCWSTR wptr)
212 { LPCWSTR wslash;
213 wslash = wptr;
215 TRACE(shell,"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++;
221 return wslash;
223 LPCVOID WINAPI PathFindFilename32AW(LPCVOID fn)
225 if(VERSION_OsIsUnicode())
226 return PathFindFilename32W(fn);
227 return PathFindFilename32A(fn);
230 /*************************************************************************
231 * PathRemoveFileSpec [SHELL32.35]
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:\"
240 DWORD WINAPI PathRemoveFileSpec32A(LPSTR fn) {
241 LPSTR x,cutplace;
242 TRACE(shell,"%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;
252 if (*x==':') {
253 x++;
254 if (*x=='\\')
255 cutplace=++x;
256 continue; /* already x++ed */
258 x++;
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;
270 *cutplace='\0';
271 return 1;
274 /*************************************************************************
275 * PathAppend [SHELL32.36]
277 * NOTES
278 * concat_paths(char*target,const char*add);
279 * concats "target\\add" and writes them to target
281 LPSTR WINAPI PathAppend32A(LPSTR x1,LPSTR x2) {
282 TRACE(shell,"%s %s\n",x1,x2);
283 while (x2[0]=='\\') x2++;
284 return PathCombine32A(x1,x1,x2);
287 /*************************************************************************
288 * PathCombine [SHELL32.37]
290 * NOTES
291 * if lpszFile='.' skip it
292 * szDest can be equal to lpszFile. Thats why we use sTemp
294 LPSTR WINAPI PathCombine32A(LPSTR szDest, LPCSTR lpszDir, LPCSTR lpszFile)
295 { char sTemp[MAX_PATH];
296 TRACE(shell,"%p %p->%s %p->%s\n",szDest, lpszDir, lpszDir, lpszFile, lpszFile);
299 if (!lpszFile || !lpszFile[0] || (lpszFile[0]=='.' && !lpszFile[1]) )
300 { strcpy(szDest,lpszDir);
301 return szDest;
304 /* if lpszFile is a complete path don't care about lpszDir */
305 if (PathIsRoot32A(lpszFile))
306 { strcpy(szDest,lpszFile);
308 else
309 { strcpy(sTemp,lpszDir);
310 PathAddBackslash32A(sTemp);
311 strcat(sTemp,lpszFile);
312 strcpy(szDest,sTemp);
314 return szDest;
316 LPWSTR WINAPI PathCombine32W(LPWSTR szDest, LPCWSTR lpszDir, LPCWSTR lpszFile)
317 { WCHAR sTemp[MAX_PATH];
318 TRACE(shell,"%p %p->%s %p->%s\n",szDest, lpszDir, debugstr_w(lpszDir),
319 lpszFile, debugstr_w(lpszFile));
322 if (!lpszFile || !lpszFile[0] || (lpszFile[0]==(WCHAR)'.' && !lpszFile[1]) )
323 { lstrcpy32W(szDest,lpszDir);
324 return szDest;
327 /* if lpszFile is a complete path don't care about lpszDir */
328 if (PathIsRoot32W(lpszFile))
329 { lstrcpy32W(szDest,lpszFile);
331 else
332 { lstrcpy32W(sTemp,lpszDir);
333 PathAddBackslash32W(sTemp);
334 lstrcat32W(sTemp,lpszFile);
335 lstrcpy32W(szDest,sTemp);
337 return szDest;
339 LPVOID WINAPI PathCombine32AW(LPVOID szDest, LPCVOID lpszDir, LPCVOID lpszFile)
340 { if (VERSION_OsIsUnicode())
341 return PathCombine32W( szDest, lpszDir, lpszFile );
342 return PathCombine32A( szDest, lpszDir, lpszFile );
345 /*************************************************************************
346 * PathIsUNC [SHELL32.39]
348 * NOTES
349 * PathIsUNC(char*path);
351 BOOL32 WINAPI PathIsUNC32A(LPCSTR path)
352 { TRACE(shell,"%s\n",path);
354 if ((path[0]=='\\') && (path[1]=='\\'))
355 return TRUE;
356 return FALSE;
358 BOOL32 WINAPI PathIsUNC32W(LPCWSTR path)
359 { TRACE(shell,"%s\n",debugstr_w(path));
361 if ((path[0]=='\\') && (path[1]=='\\'))
362 return TRUE;
363 return FALSE;
365 BOOL32 WINAPI PathIsUNC32AW (LPCVOID path)
366 { if (VERSION_OsIsUnicode())
367 return PathIsUNC32W( path );
368 return PathIsUNC32A( path );
370 /*************************************************************************
371 * PathIsRelativ [SHELL32.40]
374 BOOL32 WINAPI PathIsRelative32A (LPCSTR path)
375 { TRACE(shell,"path=%s\n",path);
377 if (path && (path[0]!='\\' && path[1]==':'))
378 return TRUE;
379 return FALSE;
381 BOOL32 WINAPI PathIsRelative32W (LPCWSTR path)
382 { TRACE(shell,"path=%s\n",debugstr_w(path));
384 if (path && (path[0]!='\\' && path[1]==':'))
385 return TRUE;
386 return FALSE;
388 BOOL32 WINAPI PathIsRelative32AW (LPCVOID path)
389 { if (VERSION_OsIsUnicode())
390 return PathIsRelative32W( path );
391 return PathIsRelative32A( path );
393 /*************************************************************************
394 * PathIsExe [SHELL32.43]
397 BOOL32 WINAPI PathIsExe32A (LPCSTR path)
398 { FIXME(shell,"path=%s\n",path);
399 return FALSE;
401 BOOL32 WINAPI PathIsExe32W (LPCWSTR path)
402 { FIXME(shell,"path=%s\n",debugstr_w(path));
403 return FALSE;
405 BOOL32 WINAPI PathIsExe32AW (LPCVOID path)
406 { if (VERSION_OsIsUnicode())
407 return PathIsExe32W (path);
408 return PathIsExe32A(path);
411 /*************************************************************************
412 * PathFileExists [SHELL32.45]
414 * NOTES
415 * file_exists(char *fn);
417 BOOL32 WINAPI PathFileExists32A(LPSTR fn) {
418 TRACE(shell,"%s\n",fn);
419 if (GetFileAttributes32A(fn)==-1)
420 return FALSE;
421 else
422 return TRUE;
424 /*************************************************************************
425 * PathMatchSpec [SHELL32.46]
427 * NOTES
428 * used from COMDLG32
431 BOOL32 WINAPI PathMatchSpec32A(LPCSTR name, LPCSTR mask)
432 { LPCSTR _name;
434 TRACE(shell,"%s %s stub\n",name,mask);
436 _name = name;
437 while (*_name && *mask)
438 { if (*mask ==';')
439 { mask++;
440 _name = name;
442 else if (*mask == '*')
443 { mask++;
444 while (*mask == '*') mask++; /* Skip consecutive '*' */
445 if (!*mask || *mask==';') return TRUE; /* '*' matches everything */
446 while (*_name && (toupper(*_name) != toupper(*mask))) _name++;
447 if (!*_name)
448 { while ( *mask && *mask != ';') mask++;
449 _name = name;
452 else if ( (*mask == '?') || (toupper(*mask) == toupper(*_name)) )
453 { mask++;
454 _name++;
456 else
457 { while ( *mask && *mask != ';') mask++;
460 return (!*_name && (!*mask || *mask==';'));
462 BOOL32 WINAPI PathMatchSpec32W(LPCWSTR name, LPCWSTR mask)
463 { WCHAR stemp[4];
464 LPCWSTR _name;
466 TRACE(shell,"%s %s stub\n",debugstr_w(name),debugstr_w(mask));
468 lstrcpyAtoW(stemp,"*.*");
469 if (!lstrcmp32W( mask, stemp )) return 1;
471 _name = name;
472 while (*_name && *mask)
473 { if (*mask ==';')
474 { mask++;
475 _name = name;
477 else if (*mask == '*')
478 { mask++;
479 while (*mask == '*') mask++; /* Skip consecutive '*' */
480 if (!*mask || *mask==';') return TRUE; /* '*' matches everything */
481 while (*_name && (towupper(*_name) != towupper(*mask))) _name++;
482 if (!*_name)
483 { while ( *mask && *mask != ';') mask++;
484 _name = name;
487 else if ( (*mask == '?') || (towupper(*mask) == towupper(*_name)) )
488 { mask++;
489 _name++;
491 else
492 { while ( *mask && *mask != ';') mask++;
495 return (!*_name && (!*mask || *mask==';'));
497 BOOL32 WINAPI PathMatchSpec32AW(LPVOID name, LPVOID mask)
498 { if (VERSION_OsIsUnicode())
499 return PathMatchSpec32W( name, mask );
500 return PathMatchSpec32A( name, mask );
502 /*************************************************************************
503 * PathSetDlgItemPath32AW [SHELL32.48]
504 * NOTES
505 * use PathCompactPath to make sure, the path fits into the control
508 BOOL32 WINAPI PathSetDlgItemPath32A(HWND32 hDlg, int id, LPCSTR pszPath)
509 { TRACE(shell,"%x %x %s\n",hDlg, id, pszPath);
510 return SetDlgItemText32A(hDlg, id, pszPath);
512 BOOL32 WINAPI PathSetDlgItemPath32W(HWND32 hDlg, int id, LPCWSTR pszPath)
513 { TRACE(shell,"%x %x %s\n",hDlg, id, debugstr_w(pszPath));
514 return SetDlgItemText32W(hDlg, id, pszPath);
516 BOOL32 WINAPI PathSetDlgItemPath32AW(HWND32 hDlg, int id, LPCVOID pszPath)
517 { if (VERSION_OsIsUnicode())
518 return PathSetDlgItemPath32W(hDlg, id, pszPath);
519 return PathSetDlgItemPath32A(hDlg, id, pszPath);
522 /*************************************************************************
523 * PathResolve [SHELL32.51]
525 DWORD WINAPI PathResolve(LPCSTR s,DWORD x2,DWORD x3) {
526 FIXME(shell,"(%s,0x%08lx,0x%08lx),stub!\n",s,x2,x3);
527 return 0;
530 /*************************************************************************
531 * PathGetArgs [SHELL32.52]
533 * NOTES
534 * look for next arg in string. handle "quoted" strings
535 * returns pointer to argument *AFTER* the space. Or to the \0.
537 LPCSTR WINAPI PathGetArgs32A(LPCSTR cmdline)
538 { BOOL32 qflag = FALSE;
540 TRACE(shell,"%s\n",cmdline);
542 while (*cmdline)
543 { if ((*cmdline==' ') && !qflag)
544 return cmdline+1;
545 if (*cmdline=='"')
546 qflag=!qflag;
547 cmdline++;
549 return cmdline;
552 LPCWSTR WINAPI PathGetArgs32W(LPCWSTR cmdline)
553 { BOOL32 qflag = FALSE;
555 TRACE(shell,"%sL\n",debugstr_w(cmdline));
557 while (*cmdline)
558 { if ((*cmdline==' ') && !qflag)
559 return cmdline+1;
560 if (*cmdline=='"')
561 qflag=!qflag;
562 cmdline++;
564 return cmdline;
566 LPCVOID WINAPI PathGetArgs32AW(LPVOID cmdline)
567 { if (VERSION_OsIsUnicode())
568 return PathGetArgs32W(cmdline);
569 return PathGetArgs32A(cmdline);
571 /*************************************************************************
572 * PathQuoteSpaces [SHELL32.55]
574 * NOTES
575 * basename(char *fn);
577 LPSTR WINAPI PathQuoteSpaces32A(LPCSTR aptr)
578 { FIXME(shell,"%s\n",aptr);
579 return 0;
582 LPWSTR WINAPI PathQuoteSpaces32W(LPCWSTR wptr)
583 { FIXME(shell,"L%s\n",debugstr_w(wptr));
584 return 0;
586 LPVOID WINAPI PathQuoteSpaces32AW (LPCVOID fn)
587 { if(VERSION_OsIsUnicode())
588 return PathQuoteSpaces32W(fn);
589 return PathQuoteSpaces32A(fn);
593 /*************************************************************************
594 * PathUnquoteSpaces [SHELL32.56]
596 * NOTES
597 * unquote string (remove ")
599 VOID WINAPI PathUnquoteSpaces32A(LPSTR str)
600 { DWORD len = lstrlen32A(str);
601 TRACE(shell,"%s\n",str);
602 if (*str!='"')
603 return;
604 if (str[len-1]!='"')
605 return;
606 str[len-1]='\0';
607 lstrcpy32A(str,str+1);
608 return;
610 VOID WINAPI PathUnquoteSpaces32W(LPWSTR str)
611 { DWORD len = lstrlen32W(str);
613 TRACE(shell,"%s\n",debugstr_w(str));
615 if (*str!='"')
616 return;
617 if (str[len-1]!='"')
618 return;
619 str[len-1]='\0';
620 lstrcpy32W(str,str+1);
621 return;
623 VOID WINAPI PathUnquoteSpaces32AW(LPVOID str)
624 { if(VERSION_OsIsUnicode())
625 PathUnquoteSpaces32W(str);
626 PathUnquoteSpaces32A(str);
630 /*************************************************************************
631 * PathGetDriveNumber32 [SHELL32.57]
634 HRESULT WINAPI PathGetDriveNumber32(LPSTR u)
635 { FIXME(shell,"%s stub\n",debugstr_a(u));
636 return 0;
639 /*************************************************************************
640 * PathYetAnotherMakeUniqueName [SHELL32.75]
642 * NOTES
643 * exported by ordinal
645 BOOL32 WINAPI PathYetAnotherMakeUniqueName32A(LPDWORD x,LPDWORD y) {
646 FIXME(shell,"(%p,%p):stub.\n",x,y);
647 return TRUE;
650 /*************************************************************************
651 * IsLFNDrive [SHELL32.119]
653 * NOTES
654 * exported by ordinal Name
656 BOOL32 WINAPI IsLFNDrive32A(LPCSTR path) {
657 DWORD fnlen;
659 if (!GetVolumeInformation32A(path,NULL,0,NULL,&fnlen,NULL,NULL,0))
660 return FALSE;
661 return fnlen>12;
663 /*************************************************************************
664 * PathFindOnPath [SHELL32.145]
666 BOOL32 WINAPI PathFindOnPath32A(LPSTR sFile, LPCSTR sOtherDirs)
667 { FIXME(shell,"%s %s\n",sFile, sOtherDirs);
668 return FALSE;
670 BOOL32 WINAPI PathFindOnPath32W(LPWSTR sFile, LPCWSTR sOtherDirs)
671 { FIXME(shell,"%s %s\n",debugstr_w(sFile), debugstr_w(sOtherDirs));
672 return FALSE;
674 BOOL32 WINAPI PathFindOnPath32AW(LPVOID sFile, LPCVOID sOtherDirs)
675 { if (VERSION_OsIsUnicode())
676 return PathFindOnPath32W(sFile, sOtherDirs);
677 return PathFindOnPath32A(sFile, sOtherDirs);
680 /*************************************************************************
681 * PathGetExtension [SHELL32.158]
683 * NOTES
684 * exported by ordinal
686 LPCSTR WINAPI PathGetExtension32A(LPCSTR path,DWORD y,DWORD z)
687 { TRACE(shell,"(%s,%08lx,%08lx)\n",path,y,z);
688 path = PathFindExtension32A(path);
689 return *path?(path+1):path;
691 LPCWSTR WINAPI PathGetExtension32W(LPCWSTR path,DWORD y,DWORD z)
692 { TRACE(shell,"(L%s,%08lx,%08lx)\n",debugstr_w(path),y,z);
693 path = PathFindExtension32W(path);
694 return *path?(path+1):path;
696 LPCVOID WINAPI PathGetExtension32AW(LPCVOID path,DWORD y,DWORD z)
697 { if (VERSION_OsIsUnicode())
698 return PathGetExtension32W(path,y,z);
699 return PathGetExtension32A(path,y,z);
702 /*************************************************************************
703 * SheGetDirW [SHELL32.281]
706 HRESULT WINAPI SheGetDir32W(LPWSTR u, LPWSTR v)
707 { FIXME(shell,"%s %s stub\n",debugstr_w(u),debugstr_w(v) );
708 return 0;
711 /*************************************************************************
712 * SheChangeDirW [SHELL32.274]
715 HRESULT WINAPI SheChangeDir32W(LPWSTR u)
716 { FIXME(shell,"(%s),stub\n",debugstr_w(u));
717 return 0;
720 /*************************************************************************
721 * PathProcessCommand [SHELL32.653]
723 HRESULT WINAPI PathProcessCommand (DWORD u, DWORD v, DWORD w, DWORD x)
724 { FIXME(shell,"0x%04lx 0x%04lx 0x%04lx 0x%04lx stub\n",u,v,w,x);
725 return 0;