Optimized {,p}MoveTo{,Ex}{,16}.
[wine] / dlls / shlwapi / path.c
1 /*
2  * Path Functions
3  */
4
5 #include <ctype.h>
6 #include <string.h>
7
8 #include "winerror.h"
9 #include "wine/unicode.h"
10 #include "wine/undocshell.h"
11 #include "wine/winestring.h"
12 #include "shlwapi.h"
13 #include "debugtools.h"
14
15 DEFAULT_DEBUG_CHANNEL(shell);
16
17 #define isSlash(x) ((x)=='\\' || (x)=='/')
18 /*
19         ########## Combining and Constructing paths ##########
20 */
21
22 /*************************************************************************
23  * PathAppendA          [SHLWAPI.@]
24  * 
25  * NOTES
26  *  concat path lpszPath2 onto lpszPath1
27  *
28  * FIXME
29  *  the resulting path is also canonicalized
30  */
31 BOOL WINAPI PathAppendA(
32         LPSTR lpszPath1,
33         LPCSTR lpszPath2) 
34 {
35         TRACE("%s %s\n",lpszPath1, lpszPath2);
36         while (lpszPath2[0]=='\\') lpszPath2++;
37         PathCombineA(lpszPath1,lpszPath1,lpszPath2);
38         return TRUE;
39 }
40
41 /*************************************************************************
42  * PathAppendW          [SHLWAPI.@]
43  */
44 BOOL WINAPI PathAppendW(
45         LPWSTR lpszPath1,
46         LPCWSTR lpszPath2) 
47 {
48         TRACE("%s %s\n",debugstr_w(lpszPath1), debugstr_w(lpszPath2));
49         while (lpszPath2[0]=='\\') lpszPath2++;
50         PathCombineW(lpszPath1,lpszPath1,lpszPath2);
51         return TRUE;
52 }
53
54 /*************************************************************************
55  * PathCombineA         [SHLWAPI.@]
56  * 
57  * NOTES
58  *  if lpszFile='.' skip it
59  *  szDest can be equal to lpszFile. Thats why we use sTemp
60  *
61  * FIXME
62  *  the resulting path is also canonicalized
63  */
64 LPSTR WINAPI PathCombineA(
65         LPSTR szDest,
66         LPCSTR lpszDir,
67         LPCSTR lpszFile) 
68 {
69         char sTemp[MAX_PATH];
70         TRACE("%p %p->%s %p->%s\n",szDest, lpszDir, lpszDir, lpszFile, lpszFile);
71         
72         
73         if (!lpszFile || !lpszFile[0] || (lpszFile[0]=='.' && !lpszFile[1]) ) 
74         {
75           strcpy(szDest,lpszDir);
76           return szDest;
77         }
78
79         /*  if lpszFile is a complete path don't care about lpszDir */
80         if (PathGetDriveNumberA(lpszFile) != -1)
81         {
82           strcpy(szDest,lpszFile);
83         }
84         else if (lpszFile[0] == '\\' )
85         {
86           strcpy(sTemp,lpszDir);
87           PathStripToRootA(sTemp);
88           strcat(sTemp,lpszFile);
89           strcpy(szDest,sTemp);
90         }
91         else
92         {
93           strcpy(sTemp,lpszDir);
94           PathAddBackslashA(sTemp);
95           strcat(sTemp,lpszFile);
96           strcpy(szDest,sTemp);
97         }
98         return szDest;
99 }
100
101 /*************************************************************************
102  * PathCombineW          [SHLWAPI.@]
103  */
104 LPWSTR WINAPI PathCombineW(
105         LPWSTR szDest,
106         LPCWSTR lpszDir,
107         LPCWSTR lpszFile) 
108 {
109         WCHAR sTemp[MAX_PATH];
110         TRACE("%p %p->%s %p->%s\n",szDest, lpszDir, debugstr_w(lpszDir),
111                          lpszFile, debugstr_w(lpszFile));
112         
113         
114         if (!lpszFile || !lpszFile[0] || (lpszFile[0]==(WCHAR)'.' && !lpszFile[1]) ) 
115         {
116           strcpyW(szDest,lpszDir);
117           return szDest;
118         }
119
120         /*  if lpszFile is a complete path don't care about lpszDir */
121         if (PathGetDriveNumberW(lpszFile) != -1)
122         {
123             strcpyW(szDest,lpszFile);
124         }
125         else if (lpszFile[0] == (WCHAR)'\\' )
126         {
127           strcpyW(sTemp,lpszDir);
128           PathStripToRootW(sTemp);
129           strcatW(sTemp,lpszFile);
130           strcpyW(szDest,sTemp);
131         }
132         else
133         {
134           strcpyW(sTemp,lpszDir);
135           PathAddBackslashW(sTemp);
136           strcatW(sTemp,lpszFile);
137           strcpyW(szDest,sTemp);
138         }
139         return szDest;
140 }
141
142 /*************************************************************************
143  * PathAddBackslashA    [SHLWAPI.@]
144  *
145  * NOTES
146  *     append \ if there is none
147  */
148 LPSTR WINAPI PathAddBackslashA(LPSTR lpszPath)
149 {
150         int len;
151         TRACE("%p->%s\n",lpszPath,lpszPath);
152
153         len = strlen(lpszPath);
154         if (len && lpszPath[len-1]!='\\') 
155         {
156           lpszPath[len]  = '\\';
157           lpszPath[len+1]= 0x00;
158           return lpszPath+len+1;
159         }
160         return lpszPath+len;
161 }
162
163 /*************************************************************************
164  * PathAddBackslashW    [SHLWAPI.@]
165  */
166 LPWSTR WINAPI PathAddBackslashW(LPWSTR lpszPath)
167 {
168         int len;
169         TRACE("%p->%s\n",lpszPath,debugstr_w(lpszPath));
170
171         len = strlenW(lpszPath);
172         if (len && lpszPath[len-1]!=(WCHAR)'\\') 
173         {
174           lpszPath[len]  = (WCHAR)'\\';
175           lpszPath[len+1]= 0x00;
176           return lpszPath+len+1;
177         }
178         return lpszPath+len;
179 }
180
181 /*************************************************************************
182  * PathBuildRootA               [SHLWAPI.@]
183  */
184 LPSTR WINAPI PathBuildRootA(LPSTR lpszPath, int drive) 
185 {
186         TRACE("%p %i\n",lpszPath, drive);
187
188         strcpy(lpszPath,"A:\\");
189         lpszPath[0]+=drive;
190         return lpszPath;
191 }
192
193 /*************************************************************************
194  * PathBuildRootW               [SHLWAPI.@]
195  */
196 LPWSTR WINAPI PathBuildRootW(LPWSTR lpszPath, int drive) 
197 {
198         TRACE("%p %i\n",debugstr_w(lpszPath), drive);
199
200         lstrcpyAtoW(lpszPath,"A:\\");
201         lpszPath[0]+=drive;
202         return lpszPath;
203 }
204
205 /*
206         Extracting Component Parts
207 */
208
209 /*************************************************************************
210  * PathFindFileNameA    [SHLWAPI.@]
211  */
212 LPSTR WINAPI PathFindFileNameA(LPCSTR lpszPath)
213 {
214         LPCSTR lastSlash = lpszPath;
215
216         TRACE("%s\n",lpszPath);
217         while (*lpszPath) 
218         {
219           if ( isSlash(lpszPath[0]) && lpszPath[1])
220               lastSlash = lpszPath+1;
221           lpszPath = CharNextA(lpszPath);
222         }
223         return (LPSTR)lastSlash;
224
225 }
226
227 /*************************************************************************
228  * PathFindFileNameW    [SHLWAPI.@]
229  */
230 LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath)
231 {
232         LPCWSTR wslash;
233         wslash = lpszPath;
234
235         TRACE("%s\n",debugstr_w(wslash));
236         while (lpszPath[0]) 
237         {
238           if (((lpszPath[0]=='\\') || (lpszPath[0]==':')) && lpszPath[1] && lpszPath[1]!='\\')
239             wslash = lpszPath+1;
240           lpszPath = CharNextW(lpszPath);
241         }
242         return (LPWSTR)wslash;  
243 }
244
245 /*************************************************************************
246  * PathFindExtensionA   [SHLWAPI.@]
247  *
248  * NOTES
249  *     returns pointer to last . in last lpszPath component or at \0.
250  */
251
252 LPSTR WINAPI PathFindExtensionA(LPCSTR lpszPath) 
253 {
254         LPCSTR   lastpoint = NULL;
255
256         TRACE("%p %s\n",lpszPath,lpszPath);
257
258         while (*lpszPath) 
259         {
260           if (*lpszPath=='\\'||*lpszPath==' ')
261             lastpoint=NULL;
262           if (*lpszPath=='.')
263             lastpoint=lpszPath;
264           lpszPath = CharNextA(lpszPath);
265         }
266         return (LPSTR)(lastpoint?lastpoint:lpszPath);
267 }
268
269 /*************************************************************************
270  * PathFindExtensionW   [SHLWAPI.@]
271  */
272 LPWSTR WINAPI PathFindExtensionW(LPCWSTR lpszPath) 
273 {
274         LPCWSTR   lastpoint = NULL;
275
276         TRACE("(%p %s)\n",lpszPath,debugstr_w(lpszPath));
277
278         while (*lpszPath)
279         {
280           if (*lpszPath==(WCHAR)'\\'||*lpszPath==(WCHAR)' ')
281             lastpoint=NULL;
282           if (*lpszPath==(WCHAR)'.')
283             lastpoint=lpszPath;
284           lpszPath = CharNextW(lpszPath);
285         }
286         return (LPWSTR)(lastpoint?lastpoint:lpszPath);
287 }
288
289 /*************************************************************************
290  * PathGetArgsA         [SHLWAPI.@]
291  *
292  * NOTES
293  *     look for next arg in string. handle "quoted" strings
294  *     returns pointer to argument *AFTER* the space. Or to the \0.
295  *
296  * FIXME
297  *     quoting by '\'
298  */
299 LPSTR WINAPI PathGetArgsA(LPCSTR lpszPath) 
300 {
301         BOOL    qflag = FALSE;
302
303         TRACE("%s\n",lpszPath);
304
305         while (*lpszPath) 
306         {
307           if ((*lpszPath==' ') && !qflag)
308             return (LPSTR)lpszPath+1;
309           if (*lpszPath=='"')
310             qflag=!qflag;
311           lpszPath = CharNextA(lpszPath);
312         }
313         return (LPSTR)lpszPath;
314 }
315
316 /*************************************************************************
317  * PathGetArgsW         [SHLWAPI.@]
318  */
319 LPWSTR WINAPI PathGetArgsW(LPCWSTR lpszPath) 
320 {
321         BOOL    qflag = FALSE;
322
323         TRACE("%s\n",debugstr_w(lpszPath));
324
325         while (*lpszPath) 
326         {
327           if ((*lpszPath==' ') && !qflag)
328             return (LPWSTR)lpszPath+1;
329           if (*lpszPath=='"')
330             qflag=!qflag;
331           lpszPath = CharNextW(lpszPath);
332         }
333         return (LPWSTR)lpszPath;
334 }
335
336 /*************************************************************************
337  * PathGetDriveNumberA  [SHLWAPI.@]
338  */
339 int WINAPI PathGetDriveNumberA(LPCSTR lpszPath)
340 {
341         int chr = tolower(lpszPath[0]);
342         
343         TRACE ("%s\n",debugstr_a(lpszPath));
344
345         if (!lpszPath || lpszPath[1]!=':' || chr < 'a' || chr > 'z') return -1;
346         return tolower(lpszPath[0]) - 'a' ;
347 }
348
349 /*************************************************************************
350  * PathGetDriveNumberW  [SHLWAPI.@]
351  */
352 int WINAPI PathGetDriveNumberW(LPCWSTR lpszPath)
353 {
354         int chr = tolowerW(lpszPath[0]);
355         
356         TRACE ("%s\n",debugstr_w(lpszPath));
357
358         if (!lpszPath || lpszPath[1]!=':' || chr < 'a' || chr > 'z') return -1;
359         return tolowerW(lpszPath[0]) - 'a' ;
360 }
361
362 /*************************************************************************
363  * PathRemoveFileSpecA  [SHLWAPI.@]
364  * 
365  * NOTES
366  *     truncates passed argument to a valid path
367  *     returns if the string was modified or not.
368  *     "\foo\xx\foo"-> "\foo\xx"
369  *     "\" -> "\"
370  *     "a:\foo" -> "a:\"
371  */
372 BOOL WINAPI PathRemoveFileSpecA(LPSTR lpszPath)
373 {
374         LPSTR cutplace = lpszPath;
375         BOOL ret = FALSE;
376         
377         TRACE("%s\n",lpszPath);
378
379         if(lpszPath)
380         {
381           while (*lpszPath == '\\') cutplace = ++lpszPath;
382           
383           while (*lpszPath)
384           {
385             if(lpszPath[0] == '\\') cutplace = lpszPath;
386           
387             if(lpszPath[0] == ':')
388             {
389               cutplace = lpszPath + 1;
390               if (lpszPath[1] == '\\') cutplace++;
391               lpszPath++;
392             }
393             lpszPath = CharNextA(lpszPath);
394             if (!lpszPath) break;
395           }
396           
397           ret = (*cutplace!='\0');
398           *cutplace = '\0';
399         }
400         return ret;
401 }
402
403 /*************************************************************************
404  * PathRemoveFileSpecW  [SHLWAPI.@]
405  */
406 BOOL WINAPI PathRemoveFileSpecW(LPWSTR lpszPath)
407 {
408         LPWSTR cutplace = lpszPath;
409         BOOL ret = FALSE;
410
411         TRACE("%s\n",debugstr_w(lpszPath));
412
413         if(lpszPath)
414         {
415           while (*lpszPath == '\\') cutplace = ++lpszPath;
416           
417           while (*lpszPath)
418           {
419             if(lpszPath[0] == '\\') cutplace = lpszPath;
420           
421             if(lpszPath[0] == ':')
422             {
423               cutplace = lpszPath + 1;
424               if (lpszPath[1] == '\\') cutplace++;
425               lpszPath++;
426             }
427             lpszPath = CharNextW(lpszPath);
428             if (!lpszPath) break;
429           }
430           
431           ret = (*cutplace!='\0');
432           *cutplace = '\0';
433         }
434         return ret;
435 }
436
437 /*************************************************************************
438  * PathStripPathA       [SHELLWAPI.@]
439  * 
440  * NOTES
441  *  removes the path from the beginning of a filename
442  */
443 void WINAPI PathStripPathA(LPSTR lpszPath)
444 {
445         LPSTR lpszFileName = PathFindFileNameA(lpszPath);
446
447         TRACE("%s\n", lpszPath);
448
449         if(lpszFileName)
450           RtlMoveMemory(lpszPath, lpszFileName, strlen(lpszFileName)+1); 
451 }
452
453 /*************************************************************************
454  * PathStripPathW       [SHELLWAPI.@]
455  */
456 void WINAPI PathStripPathW(LPWSTR lpszPath)
457 {
458         LPWSTR lpszFileName = PathFindFileNameW(lpszPath);
459
460         TRACE("%s\n", debugstr_w(lpszPath));
461         if(lpszFileName)
462           RtlMoveMemory(lpszPath, lpszFileName, (strlenW(lpszFileName)+1)*sizeof(WCHAR)); 
463 }
464
465 /*************************************************************************
466  * PathStripToRootA     [SHLWAPI.@]
467  */
468 BOOL WINAPI PathStripToRootA(LPSTR lpszPath)
469 {
470         TRACE("%s\n", lpszPath);
471
472         if (!lpszPath) return FALSE;
473         while(!PathIsRootA(lpszPath))
474           if (!PathRemoveFileSpecA(lpszPath)) return FALSE;
475         return TRUE;
476 }
477
478 /*************************************************************************
479  * PathStripToRootW     [SHLWAPI.@]
480  */
481 BOOL WINAPI PathStripToRootW(LPWSTR lpszPath)
482 {
483         TRACE("%s\n", debugstr_w(lpszPath));
484
485         if (!lpszPath) return FALSE;
486         while(!PathIsRootW(lpszPath))
487           if (!PathRemoveFileSpecW(lpszPath)) return FALSE;
488         return TRUE;
489 }
490
491 /*************************************************************************
492  * PathRemoveArgsA      [SHLWAPI.@]
493  *
494  */
495 void WINAPI PathRemoveArgsA(LPSTR lpszPath)
496 {
497         TRACE("%s\n",lpszPath);
498         
499         if(lpszPath)
500         {
501           LPSTR lpszArgs = PathGetArgsA(lpszPath);
502           if (!*lpszArgs)
503           {
504             LPSTR lpszLastChar = CharPrevA(lpszPath, lpszArgs);
505             if(*lpszLastChar==' ') *lpszLastChar = '\0';
506           }
507         }
508 }
509
510 /*************************************************************************
511  * PathRemoveArgsW      [SHLWAPI.@]
512  */
513 void WINAPI PathRemoveArgsW(LPWSTR lpszPath)
514 {
515         TRACE("%s\n", debugstr_w(lpszPath));
516
517         if(lpszPath)
518         {
519           LPWSTR lpszArgs = PathGetArgsW(lpszPath);
520           if (!*lpszArgs)
521           {
522             LPWSTR lpszLastChar = CharPrevW(lpszPath, lpszArgs);
523             if(*lpszLastChar==' ') *lpszLastChar = '\0';
524           }
525         }
526 }
527
528 /*************************************************************************
529  * PathRemoveExtensionA         [SHLWAPI.@]
530  */
531 void WINAPI PathRemoveExtensionA(LPSTR lpszPath)
532 {
533         LPSTR lpszExtension = PathFindExtensionA(lpszPath);
534
535         TRACE("%s\n", lpszPath);
536
537         if (lpszExtension) *lpszExtension='\0';
538 }
539
540 /*************************************************************************
541  * PathRemoveExtensionW         [SHLWAPI.@]
542  */
543 void WINAPI PathRemoveExtensionW(LPWSTR lpszPath)
544 {
545         LPWSTR lpszExtension = PathFindExtensionW(lpszPath);
546
547         TRACE("%s\n", debugstr_w(lpszPath));
548
549         if (lpszExtension) *lpszExtension='\0';
550 }
551
552 /*************************************************************************
553  * PathRemoveBackslashA [SHLWAPI.@]
554  *
555  * If the path ends in a backslash it is replaced by a NULL
556  * and the address of the NULL is returned
557  * Otherwise 
558  * the address of the last character is returned.
559  *
560  * FIXME
561  *  "c:\": keep backslash
562  */
563 LPSTR WINAPI PathRemoveBackslashA( LPSTR lpszPath )
564 {
565         int len;
566         LPSTR szTemp = NULL;
567         
568         if(lpszPath)
569         {
570           len = strlen(lpszPath);
571           szTemp = CharPrevA(lpszPath, lpszPath+len);
572           if (! PathIsRootA(lpszPath))
573           {
574             if (*szTemp == '\\') *szTemp = '\0';
575           }
576         }
577         return szTemp;
578 }
579
580 /*************************************************************************
581  * PathRemoveBackslashW [SHLWAPI.@]
582  */
583 LPWSTR WINAPI PathRemoveBackslashW( LPWSTR lpszPath )
584 {
585         int len;
586         LPWSTR szTemp = NULL;
587         
588         if(lpszPath)
589         {
590           len = strlenW(lpszPath);
591           szTemp = CharPrevW(lpszPath, lpszPath+len);
592           if (! PathIsRootW(lpszPath))
593           {
594             if (*szTemp == '\\') *szTemp = '\0';
595           }
596         }
597         return szTemp;
598 }
599
600
601 /*
602         Path Manipulations
603 */
604
605 /*************************************************************************
606  * PathRemoveBlanksA [SHLWAPI.@]
607  * 
608  * NOTES
609  *     remove spaces from beginning and end of passed string
610  */
611 void WINAPI PathRemoveBlanksA(LPSTR str)
612 {
613         LPSTR x = str;
614
615         TRACE("%s\n",str);
616
617         if(str)
618         {
619           while (*x==' ') x = CharNextA(x);
620           if (x!=str) strcpy(str,x);
621           x=str+strlen(str)-1;
622           while (*x==' ') x = CharPrevA(str, x);
623           if (*x==' ') *x='\0';
624         }
625 }
626
627 /*************************************************************************
628  * PathRemoveBlanksW [SHLWAPI.@]
629  */
630 void WINAPI PathRemoveBlanksW(LPWSTR str)
631 {
632         LPWSTR x = str;
633
634         TRACE("%s\n",debugstr_w(str));
635
636         if(str)
637         {
638           while (*x==' ') x = CharNextW(x);
639           if (x!=str) strcpyW(str,x);
640           x=str+strlenW(str)-1;
641           while (*x==' ') x = CharPrevW(str, x);
642           if (*x==' ') *x='\0';
643         }
644 }
645
646 /*************************************************************************
647  * PathQuoteSpacesA [SHLWAPI.@]
648  * 
649  */
650 LPSTR WINAPI PathQuoteSpacesA(LPSTR lpszPath)
651 {
652         TRACE("%s\n",lpszPath);
653
654         if(StrChrA(lpszPath,' '))
655         {
656           int len = strlen(lpszPath);
657           RtlMoveMemory(lpszPath+1, lpszPath, len);
658           *(lpszPath++) = '"';
659           lpszPath += len;
660           *(lpszPath++) = '"';
661           *(lpszPath) = '\0';
662           return --lpszPath;
663         }
664         return 0;
665 }
666
667 /*************************************************************************
668  * PathQuoteSpacesW [SHLWAPI.@]
669  */
670 LPWSTR WINAPI PathQuoteSpacesW(LPWSTR lpszPath)
671 {
672         TRACE("%s\n",debugstr_w(lpszPath));
673
674         if(StrChrW(lpszPath,' '))
675         {
676           int len = strlenW(lpszPath);
677           RtlMoveMemory(lpszPath+1, lpszPath, len*sizeof(WCHAR));
678           *(lpszPath++) = '"';
679           lpszPath += len;
680           *(lpszPath++) = '"';
681           *(lpszPath) = '\0';
682           return --lpszPath;
683         }
684         return 0;
685 }
686
687 /*************************************************************************
688  * PathUnquoteSpacesA [SHLWAPI.@]
689  * 
690  * NOTES
691  *     unquote string (remove ")
692  */
693 VOID WINAPI PathUnquoteSpacesA(LPSTR str) 
694 {
695         DWORD len = strlen(str);
696
697         TRACE("%s\n",str);
698
699         if (*str!='"')
700           return;
701         if (str[len-1]!='"')
702           return;
703         str[len-1]='\0';
704         strcpy(str,str+1);
705         return;
706 }
707
708 /*************************************************************************
709  * PathUnquoteSpacesW [SHLWAPI.@]
710  */
711 VOID WINAPI PathUnquoteSpacesW(LPWSTR str) 
712 {
713         DWORD len = strlenW(str);
714
715         TRACE("%s\n",debugstr_w(str));
716
717         if (*str!='"')
718           return;
719         if (str[len-1]!='"')
720           return;
721         str[len-1]='\0';
722         strcpyW(str,str+1);
723         return;
724 }
725
726 /*************************************************************************
727  * PathParseIconLocationA       [SHLWAPI.@]
728  */
729 int WINAPI PathParseIconLocationA(LPSTR lpszPath)
730 {
731         LPSTR lpstrComma = strchr(lpszPath, ',');
732         
733         FIXME("%s stub\n", debugstr_a(lpszPath));
734
735         if (lpstrComma && lpstrComma[1])
736         {
737           lpstrComma[0]='\0';
738 /*        return atoi(&lpstrComma[1]);  FIXME */
739         }
740         
741         PathUnquoteSpacesA(lpszPath);
742         return 0;
743 }
744
745 /*************************************************************************
746  * PathParseIconLocationW       [SHLWAPI.@]
747  */
748 int WINAPI PathParseIconLocationW(LPWSTR lpszPath)
749 {
750         LPWSTR lpstrComma = strchrW(lpszPath, ',');
751         
752         FIXME("%s stub\n", debugstr_w(lpszPath));
753
754         if (lpstrComma && lpstrComma[1])
755         {
756           lpstrComma[0]='\0';
757 /*        return _wtoi(&lpstrComma[1]); FIXME */
758         }
759         PathUnquoteSpacesW(lpszPath);
760         return 0;
761 }
762
763 /*
764         ########## cleaning and resolving paths ##########
765  */
766
767 /*************************************************************************
768  * PathFindOnPathA      [SHLWAPI.@]
769  */
770 BOOL WINAPI PathFindOnPathA(LPSTR sFile, LPCSTR sOtherDirs)
771 {
772         FIXME("%s %s\n",sFile, sOtherDirs);
773         return FALSE;
774 }
775
776 /*************************************************************************
777  * PathFindOnPathW      [SHLWAPI.@]
778  */
779 BOOL WINAPI PathFindOnPathW(LPWSTR sFile, LPCWSTR sOtherDirs)
780 {
781         FIXME("%s %s\n",debugstr_w(sFile), debugstr_w(sOtherDirs));
782         return FALSE;
783 }
784
785 /*************************************************************************
786  *      PathCompactPathExA   [SHLWAPI.@]
787  */
788 BOOL WINAPI PathCompactPathExA(
789         LPSTR pszOut,
790         LPCSTR pszSrc,
791         UINT cchMax,
792         DWORD dwFlags)
793 {
794         FIXME("%p %s 0x%08x 0x%08lx\n", pszOut, pszSrc, cchMax, dwFlags);
795         return FALSE;
796 }
797
798 /*************************************************************************
799  *      PathCompactPathExW   [SHLWAPI.@]
800  */
801 BOOL WINAPI PathCompactPathExW(
802         LPWSTR pszOut,
803         LPCWSTR pszSrc,
804         UINT cchMax,
805         DWORD dwFlags)
806 {
807         FIXME("%p %s 0x%08x 0x%08lx\n", pszOut, debugstr_w(pszSrc), cchMax, dwFlags);
808         return FALSE;
809 }
810
811 /*
812         ########## Path Testing ##########
813 */
814
815 /*************************************************************************
816  * PathIsUNCA           [SHLWAPI.@]
817  * 
818  * NOTES
819  *     PathIsUNC(char*path);
820  */
821 BOOL WINAPI PathIsUNCA(LPCSTR lpszPath) 
822 {
823         TRACE("%s\n",lpszPath);
824
825         return (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\'));
826 }
827
828 /*************************************************************************
829  * PathIsUNCW           [SHLWAPI.@]
830  */
831 BOOL WINAPI PathIsUNCW(LPCWSTR lpszPath) 
832 {
833         TRACE("%s\n",debugstr_w(lpszPath));
834
835         return (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\'));
836 }
837
838 /*************************************************************************
839  *  PathIsRelativeA     [SHLWAPI.@]
840  */
841 BOOL WINAPI PathIsRelativeA (LPCSTR lpszPath)
842 {
843         TRACE("lpszPath=%s\n",lpszPath);
844
845         return (lpszPath && (lpszPath[0]!='\\' && lpszPath[1]!=':'));
846 }
847
848 /*************************************************************************
849  *  PathIsRelativeW     [SHLWAPI.@]
850  */
851 BOOL WINAPI PathIsRelativeW (LPCWSTR lpszPath)
852 {
853         TRACE("lpszPath=%s\n",debugstr_w(lpszPath));
854
855         return (lpszPath && (lpszPath[0]!='\\' && lpszPath[1]!=':'));
856 }
857
858 /*************************************************************************
859  * PathIsRootA          [SHLWAPI.@]
860  *
861  * notes
862  *  TRUE if the path points to a root directory
863  */
864 BOOL WINAPI PathIsRootA(LPCSTR lpszPath)
865 {
866         TRACE("%s\n",lpszPath);
867
868         /* X:\ */
869         if (lpszPath[1]==':' && lpszPath[2]=='\\' && lpszPath[3]=='\0')
870           return TRUE;
871
872         /* "\" */
873         if (lpszPath[0]=='\\' && lpszPath[1]=='\0')
874           return TRUE;
875
876         /* UNC "\\<computer>\<share>" */
877         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
878         {
879           int foundbackslash = 0;
880           lpszPath += 2;
881           while (*lpszPath)
882           {
883             if (*lpszPath=='\\') foundbackslash++;
884             lpszPath = CharNextA(lpszPath);
885           }
886           if (foundbackslash <= 1)
887             return TRUE;
888         }
889         return FALSE;
890 }
891
892 /*************************************************************************
893  * PathIsRootW          [SHLWAPI.@]
894  */
895 BOOL WINAPI PathIsRootW(LPCWSTR lpszPath) 
896 {
897         TRACE("%s\n",debugstr_w(lpszPath));
898
899         /* X:\ */
900         if (lpszPath[1]==':' && lpszPath[2]=='\\' && lpszPath[3]=='\0')
901           return TRUE;
902
903         /* "\" */
904         if (lpszPath[0]=='\\' && lpszPath[1]=='\0')
905           return TRUE;
906
907         /* UNC "\\<computer>\<share>" */
908         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
909         {
910           int foundbackslash = 0;
911           lpszPath += 2;
912           while (*lpszPath)
913           {
914             if (*lpszPath=='\\') foundbackslash++;
915             lpszPath = CharNextW(lpszPath);
916           }
917           if (foundbackslash <= 1)
918             return TRUE;
919         }
920         return FALSE;
921
922 }
923
924 /*************************************************************************
925  * PathIsDirectoryA     [SHLWAPI.@]
926  */
927 BOOL WINAPI PathIsDirectoryA(LPCSTR lpszPath)
928 {
929         DWORD dwAttr;
930
931         TRACE("%s\n", debugstr_a(lpszPath));
932
933         dwAttr = GetFileAttributesA(lpszPath);
934         return  (dwAttr != -1) ? dwAttr & FILE_ATTRIBUTE_DIRECTORY : 0;
935 }
936
937 /*************************************************************************
938  * PathIsDirectoryW     [SHLWAPI.@]
939  */
940 BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
941 {
942         DWORD dwAttr;
943         
944         TRACE("%s\n", debugstr_w(lpszPath));
945
946         dwAttr = GetFileAttributesW(lpszPath);
947         return  (dwAttr != -1) ? dwAttr & FILE_ATTRIBUTE_DIRECTORY : 0;
948 }
949
950 /*************************************************************************
951  * PathFileExistsA      [SHLWAPI.@]
952  * 
953  * NOTES
954  *     file_exists(char *fn);
955  */
956 BOOL WINAPI PathFileExistsA(LPCSTR lpszPath) 
957 {
958         TRACE("%s\n",lpszPath);
959         return  (GetFileAttributesA(lpszPath)!=-1);
960 }
961
962 /*************************************************************************
963  * PathFileExistsW      [SHLWAPI.@]
964  */
965 BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath) 
966 {
967         TRACE("%s\n",debugstr_w(lpszPath));
968         return  (GetFileAttributesW(lpszPath)!=-1);
969 }
970
971 /*************************************************************************
972  * PathMatchSingleMaskA [internal]
973  * 
974  * NOTES
975  *     internal (used by PathMatchSpec)
976  */
977 static BOOL PathMatchSingleMaskA(LPCSTR name, LPCSTR mask)
978 {
979         while (*name && *mask && *mask!=';') 
980         {
981           if (*mask=='*') 
982           {
983             do 
984             {
985               if (PathMatchSingleMaskA(name,mask+1)) return 1;  /* try substrings */
986             } while (*name++);
987             return 0;
988           }
989           if (toupper(*mask)!=toupper(*name) && *mask!='?') return 0;
990           name = CharNextA(name);
991           mask = CharNextA(mask);
992         }
993         if (!*name) 
994         {
995           while (*mask=='*') mask++;
996           if (!*mask || *mask==';') return 1;
997         }
998         return 0;
999 }
1000
1001 /*************************************************************************
1002  * PathMatchSingleMaskW [internal]
1003  */
1004 static BOOL PathMatchSingleMaskW(LPCWSTR name, LPCWSTR mask)
1005 {
1006         while (*name && *mask && *mask!=';') 
1007         {
1008           if (*mask=='*') 
1009           {
1010             do 
1011             {
1012               if (PathMatchSingleMaskW(name,mask+1)) return 1;  /* try substrings */
1013             } while (*name++);
1014             return 0;
1015           }
1016           if (toupperW(*mask)!=toupperW(*name) && *mask!='?') return 0;
1017           name = CharNextW(name);
1018           mask = CharNextW(mask);
1019         }
1020         if (!*name) 
1021         {
1022           while (*mask=='*') mask++;
1023           if (!*mask || *mask==';') return 1;
1024         }
1025         return 0;
1026 }
1027 /*************************************************************************
1028  * PathMatchSpecA       [SHLWAPI.@]
1029  * 
1030  * NOTES
1031  *     used from COMDLG32
1032  */
1033 BOOL WINAPI PathMatchSpecA(LPCSTR name, LPCSTR mask) 
1034 {
1035         TRACE("%s %s\n",name,mask);
1036
1037         if (!lstrcmpA( mask, "*.*" )) return 1;   /* we don't require a period */
1038
1039         while (*mask) 
1040         {
1041           if (PathMatchSingleMaskA(name,mask)) return 1;    /* helper function */
1042           while (*mask && *mask!=';') mask = CharNextA(mask);
1043           if (*mask==';') 
1044           {
1045             mask++;
1046             while (*mask==' ') mask++;      /*  masks may be separated by "; " */
1047           }
1048         }
1049         return 0;
1050 }
1051
1052 /*************************************************************************
1053  * PathMatchSpecW       [SHLWAPI.@]
1054  */
1055 BOOL WINAPI PathMatchSpecW(LPCWSTR name, LPCWSTR mask) 
1056 {
1057         WCHAR stemp[4];
1058         TRACE("%s %s\n",debugstr_w(name),debugstr_w(mask));
1059
1060         lstrcpyAtoW(stemp,"*.*");       
1061         if (!lstrcmpW( mask, stemp )) return 1;   /* we don't require a period */
1062
1063         while (*mask) 
1064         {
1065           if (PathMatchSingleMaskW(name,mask)) return 1;    /* helper function */
1066           while (*mask && *mask!=';') mask = CharNextW(mask);
1067           if (*mask==';') 
1068           {
1069             mask++;
1070             while (*mask==' ') mask++;       /* masks may be separated by "; " */
1071           }
1072         }
1073         return 0;
1074 }
1075
1076 /*************************************************************************
1077  * PathIsSameRootA      [SHLWAPI.@]
1078  *
1079  * FIXME
1080  *  what to do with "\path" ??
1081  */
1082 BOOL WINAPI PathIsSameRootA(LPCSTR lpszPath1, LPCSTR lpszPath2)
1083 {
1084         TRACE("%s %s\n", lpszPath1, lpszPath2);
1085         
1086         if (PathIsRelativeA(lpszPath1) || PathIsRelativeA(lpszPath2)) return FALSE;
1087
1088         /* usual path */
1089         if ( toupper(lpszPath1[0])==toupper(lpszPath2[0]) &&
1090              lpszPath1[1]==':' && lpszPath2[1]==':' &&
1091              lpszPath1[2]=='\\' && lpszPath2[2]=='\\')
1092           return TRUE;
1093
1094         /* UNC */
1095         if (lpszPath1[0]=='\\' && lpszPath2[0]=='\\' &&
1096             lpszPath1[1]=='\\' && lpszPath2[1]=='\\')
1097         {
1098           int pos=2, bsfound=0;
1099           while (lpszPath1[pos] && lpszPath2[pos] &&
1100                 (lpszPath1[pos] == lpszPath2[pos]))
1101           {
1102             if (lpszPath1[pos]=='\\') bsfound++;
1103             if (bsfound == 2) return TRUE;
1104             pos++; /* fixme: use CharNext*/
1105           }
1106           return (lpszPath1[pos] == lpszPath2[pos]);
1107         }
1108         return FALSE;
1109 }
1110
1111 /*************************************************************************
1112  * PathIsSameRootW      [SHLWAPI.@]
1113  */
1114 BOOL WINAPI PathIsSameRootW(LPCWSTR lpszPath1, LPCWSTR lpszPath2)
1115 {
1116         TRACE("%s %s\n", debugstr_w(lpszPath1), debugstr_w(lpszPath2));
1117         
1118         if (PathIsRelativeW(lpszPath1) || PathIsRelativeW(lpszPath2)) return FALSE;
1119
1120         /* usual path */
1121         if ( toupperW(lpszPath1[0])==toupperW(lpszPath2[0]) &&
1122              lpszPath1[1]==':' && lpszPath2[1]==':' &&
1123              lpszPath1[2]=='\\' && lpszPath2[2]=='\\')
1124           return TRUE;
1125
1126         /* UNC */
1127         if (lpszPath1[0]=='\\' && lpszPath2[0]=='\\' &&
1128             lpszPath1[1]=='\\' && lpszPath2[1]=='\\')
1129         {
1130           int pos=2, bsfound=0;
1131           while (lpszPath1[pos] && lpszPath2[pos] &&
1132                 (lpszPath1[pos] == lpszPath2[pos]))
1133           {
1134             if (lpszPath1[pos]=='\\') bsfound++;
1135             if (bsfound == 2) return TRUE;
1136             pos++;/* fixme: use CharNext*/
1137           }
1138           return (lpszPath1[pos] == lpszPath2[pos]);
1139         }
1140         return FALSE;
1141 }
1142
1143 /*************************************************************************
1144  * PathIsURLA
1145  */
1146 BOOL WINAPI PathIsURLA(LPCSTR lpstrPath)
1147 {
1148         LPSTR lpstrRes;
1149         int iSize, i=0;
1150         static LPSTR SupportedProtocol[] = 
1151           {"http","https","ftp","gopher","file","mailto",NULL};
1152
1153         if(!lpstrPath) return FALSE;
1154
1155         /* get protocol        */
1156         lpstrRes = strchr(lpstrPath,':');
1157         if(!lpstrRes) return FALSE;
1158         iSize = lpstrRes - lpstrPath;
1159
1160         while(SupportedProtocol[i])
1161         {
1162           if (iSize == strlen(SupportedProtocol[i]))
1163             if(!strncasecmp(lpstrPath, SupportedProtocol[i], iSize))
1164               return TRUE;
1165           i++;
1166         }
1167
1168         return FALSE;
1169 }  
1170
1171 /*************************************************************************
1172  * PathIsURLW
1173  */
1174 BOOL WINAPI PathIsURLW(LPCWSTR lpstrPath)
1175 {
1176         LPWSTR lpstrRes;
1177         int iSize, i=0;
1178         static WCHAR SupportedProtocol[7][7] = 
1179           {{'h','t','t','p','\0'},{'h','t','t','p','s','\0'},{'f','t','p','\0'},
1180           {'g','o','p','h','e','r','\0'},{'f','i','l','e','\0'},
1181           {'m','a','i','l','t','o','\0'},{0}};
1182
1183         if(!lpstrPath) return FALSE;
1184
1185         /* get protocol        */
1186         lpstrRes = strchrW(lpstrPath,':');
1187         if(!lpstrRes) return FALSE;
1188         iSize = lpstrRes - lpstrPath;
1189
1190         while(SupportedProtocol[i])
1191         {
1192           if (iSize == strlenW(SupportedProtocol[i]))
1193             if(!strncmpiW(lpstrPath, SupportedProtocol[i], iSize))
1194               return TRUE;
1195           i++;
1196         }
1197
1198         return FALSE;
1199 }  
1200
1201
1202 /*************************************************************************
1203  *      PathIsContentTypeA   [SHLWAPI.@]
1204  */
1205 BOOL WINAPI PathIsContentTypeA(LPCSTR pszPath, LPCSTR pszContentType)
1206 {
1207         FIXME("%s %s\n", pszPath, pszContentType);
1208         return FALSE;
1209 }
1210
1211 /*************************************************************************
1212  *      PathIsContentTypeW   [SHLWAPI.@]
1213  */
1214 BOOL WINAPI PathIsContentTypeW(LPCWSTR pszPath, LPCWSTR pszContentType)
1215 {
1216         FIXME("%s %s\n", debugstr_w(pszPath), debugstr_w(pszContentType));
1217         return FALSE;
1218 }
1219
1220 /*************************************************************************
1221  *      PathIsFileSpecA   [SHLWAPI.@]
1222  */
1223 BOOL WINAPI PathIsFileSpecA(LPCSTR pszPath)
1224 {
1225         FIXME("%s\n", pszPath);
1226         return FALSE;
1227 }
1228
1229 /*************************************************************************
1230  *      PathIsFileSpecW   [SHLWAPI.@]
1231  */
1232 BOOL WINAPI PathIsFileSpecW(LPCWSTR pszPath)
1233 {
1234         FIXME("%s\n", debugstr_w(pszPath));
1235         return FALSE;
1236 }
1237
1238 /*************************************************************************
1239  *      PathIsPrefixA   [SHLWAPI.@]
1240  */
1241 BOOL WINAPI PathIsPrefixA(LPCSTR pszPrefix, LPCSTR pszPath)
1242 {
1243         FIXME("%s %s\n", pszPrefix, pszPath);
1244         return FALSE;
1245 }
1246
1247 /*************************************************************************
1248  *      PathIsPrefixW   [SHLWAPI.@]
1249  */
1250 BOOL WINAPI PathIsPrefixW(LPCWSTR pszPrefix, LPCWSTR pszPath)
1251 {
1252         FIXME("%s %s\n", debugstr_w(pszPrefix), debugstr_w(pszPath));
1253         return FALSE;
1254 }
1255
1256 /*************************************************************************
1257  *      PathIsSystemFolderA   [SHLWAPI.@]
1258  */
1259 BOOL WINAPI PathIsSystemFolderA(LPCSTR pszPath, DWORD dwAttrb)
1260 {
1261         FIXME("%s 0x%08lx\n", pszPath, dwAttrb);
1262         return FALSE;
1263 }
1264
1265 /*************************************************************************
1266  *      PathIsSystemFolderW   [SHLWAPI.@]
1267  */
1268 BOOL WINAPI PathIsSystemFolderW(LPCWSTR pszPath, DWORD dwAttrb)
1269 {
1270         FIXME("%s 0x%08lx\n", debugstr_w(pszPath), dwAttrb);
1271         return FALSE;
1272 }
1273
1274 /*************************************************************************
1275  *      PathIsUNCServerA   [SHLWAPI.@]
1276  */
1277 BOOL WINAPI PathIsUNCServerA(
1278         LPCSTR pszPath)
1279 {
1280         FIXME("%s\n", pszPath);
1281         return FALSE;
1282 }
1283
1284 /*************************************************************************
1285  *      PathIsUNCServerW   [SHLWAPI.@]
1286  */
1287 BOOL WINAPI PathIsUNCServerW(
1288         LPCWSTR pszPath)
1289 {
1290         FIXME("%s\n", debugstr_w(pszPath));
1291         return FALSE;
1292 }
1293
1294 /*************************************************************************
1295  *      PathIsUNCServerShareA   [SHLWAPI.@]
1296  */
1297 BOOL WINAPI PathIsUNCServerShareA(
1298         LPCSTR pszPath)
1299 {
1300         FIXME("%s\n", pszPath);
1301         return FALSE;
1302 }
1303
1304 /*************************************************************************
1305  *      PathIsUNCServerShareW   [SHLWAPI.@]
1306  */
1307 BOOL WINAPI PathIsUNCServerShareW(
1308         LPCWSTR pszPath)
1309 {
1310         FIXME("%s\n", debugstr_w(pszPath));
1311         return FALSE;
1312 }
1313
1314 /*************************************************************************
1315  * PathCanonicalizeA   [SHLWAPI.@]
1316  *
1317  *  FIXME
1318  *   returnvalue, use CharNext
1319  */
1320  
1321 BOOL WINAPI PathCanonicalizeA(LPSTR pszBuf, LPCSTR pszPath)
1322 {
1323         int OffsetMin = 0, OffsetSrc = 0, OffsetDst = 0, LenSrc = strlen(pszPath);
1324         BOOL bModifyed = FALSE;
1325
1326         TRACE("%p %s\n", pszBuf, pszPath);
1327         
1328         pszBuf[OffsetDst]='\0';
1329
1330         /* keep the root of the path */
1331         if( LenSrc && (pszPath[OffsetSrc]=='\\'))
1332         {
1333           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1334         }
1335         else if ( (LenSrc >= 2) && (pszPath[OffsetSrc+1] == ':'))
1336         {
1337           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1338           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1339           if (LenSrc && (pszPath[OffsetSrc] == '\\'))
1340           {
1341             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1342             if (LenSrc == 1 && pszPath[OffsetSrc]=='.')
1343             {
1344               /* C:\. */
1345               OffsetSrc++; LenSrc--; bModifyed = TRUE;
1346             } 
1347             else if (LenSrc == 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='.')
1348             {
1349               /* C:\.. */
1350               OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
1351             } 
1352           }
1353         }
1354         
1355         /* ".\" at the beginning of the path */
1356         if (LenSrc >= 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='\\')
1357         {
1358           OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
1359         } 
1360         
1361         while ( LenSrc )
1362         {
1363           if((LenSrc>=3) && (pszPath[OffsetSrc]=='\\') && (pszPath[OffsetSrc+1]=='.') && (pszPath[OffsetSrc+2]=='.'))
1364           {
1365             /* "\.." found, go one deeper */
1366             while((OffsetDst > OffsetMin) && (pszBuf[OffsetDst]!='\\')) OffsetDst--;
1367             OffsetSrc += 3; LenSrc -= 3; bModifyed = TRUE;
1368             if(OffsetDst == OffsetMin && pszPath[OffsetSrc]=='\\') OffsetSrc++;
1369             pszBuf[OffsetDst] = '\0';                   /* important for \..\.. */
1370           }
1371           else if(LenSrc>=2 && pszPath[OffsetSrc]=='\\' && pszPath[OffsetSrc+1]=='.' )
1372           {
1373             /* "\." found, skip it */
1374             OffsetSrc += 2; LenSrc-=2; bModifyed = TRUE;
1375           }
1376           else
1377           {
1378             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; LenSrc--;
1379           }
1380         }
1381         pszBuf[OffsetDst] = '\0';
1382         TRACE("-- %s %u\n", pszBuf, bModifyed);
1383         return bModifyed;
1384 }
1385
1386
1387 /*************************************************************************
1388  * PathCanonicalizeW   [SHLWAPI.@]
1389  *
1390  *  FIXME
1391  *   returnvalue, use CharNext
1392  */
1393 BOOL WINAPI PathCanonicalizeW(LPWSTR pszBuf, LPCWSTR pszPath)
1394 {
1395         int OffsetMin = 0, OffsetSrc = 0, OffsetDst = 0, LenSrc = strlenW(pszPath);
1396         BOOL bModifyed = FALSE;
1397
1398         TRACE("%p %s\n", pszBuf, debugstr_w(pszPath));
1399         
1400         pszBuf[OffsetDst]='\0';
1401
1402         /* keep the root of the path */
1403         if( LenSrc && (pszPath[OffsetSrc]=='\\'))
1404         {
1405           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1406         }
1407         else if ( (LenSrc >= 2) && (pszPath[OffsetSrc+1] == ':'))
1408         {
1409           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1410           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1411           if (LenSrc && (pszPath[OffsetSrc] == '\\'))
1412           {
1413             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1414             if (LenSrc == 1 && pszPath[OffsetSrc]=='.')
1415             {
1416               /* C:\. */
1417               OffsetSrc++; LenSrc--; bModifyed = TRUE;
1418             } 
1419             else if (LenSrc == 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='.')
1420             {
1421               /* C:\.. */
1422               OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
1423             } 
1424           }
1425         }
1426         
1427         /* ".\" at the beginning of the path */
1428         if (LenSrc >= 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='\\')
1429         {
1430           OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
1431         } 
1432         
1433         while ( LenSrc )
1434         {
1435           if((LenSrc>=3) && (pszPath[OffsetSrc]=='\\') && (pszPath[OffsetSrc+1]=='.') && (pszPath[OffsetSrc+2]=='.'))
1436           {
1437             /* "\.." found, go one deeper */
1438             while((OffsetDst > OffsetMin) && (pszBuf[OffsetDst]!='\\')) OffsetDst--;
1439             OffsetSrc += 3; LenSrc -= 3; bModifyed = TRUE;
1440             if(OffsetDst == OffsetMin && pszPath[OffsetSrc]=='\\') OffsetSrc++;
1441             pszBuf[OffsetDst] = '\0';                   /* important for \..\.. */
1442           }
1443           else if(LenSrc>=2 && pszPath[OffsetSrc]=='\\' && pszPath[OffsetSrc+1]=='.' )
1444           {
1445             /* "\." found, skip it */
1446             OffsetSrc += 2; LenSrc-=2; bModifyed = TRUE;
1447           }
1448           else
1449           {
1450             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; LenSrc--;
1451           }
1452         }
1453         pszBuf[OffsetDst] = '\0';
1454         TRACE("-- %s %u\n", debugstr_w(pszBuf), bModifyed);
1455         return bModifyed;
1456 }
1457
1458 /*************************************************************************
1459  * PathFindNextComponentA   [SHLWAPI.@]
1460  *
1461  * NOTES
1462  * special cases:
1463  *      ""              null
1464  *      aa              "" (pointer to traling NULL)
1465  *      aa\             "" (pointer to traling NULL)
1466  *      aa\\            "" (pointer to traling NULL)
1467  *      aa\\bb          bb
1468  *      aa\\\bb         \bb
1469  *      c:\aa\          "aa\"
1470  *      \\aa            aa
1471  *      \\aa\b          aa\b
1472 */
1473 LPSTR WINAPI PathFindNextComponentA(LPCSTR pszPath)
1474 {
1475         LPSTR pos;
1476
1477         TRACE("%s\n", pszPath);
1478
1479         if(!pszPath || !*pszPath) return NULL;
1480         if(!(pos = StrChrA(pszPath, '\\')))
1481           return (LPSTR) pszPath + strlen(pszPath);
1482         pos++;
1483         if(pos[0] == '\\') pos++;
1484         return pos;
1485 }
1486
1487 /*************************************************************************
1488  * PathFindNextComponentW   [SHLWAPI.@]
1489  */
1490 LPWSTR WINAPI PathFindNextComponentW(LPCWSTR pszPath)
1491 {
1492         LPWSTR pos;
1493
1494         TRACE("%s\n", debugstr_w(pszPath));
1495         
1496         if(!pszPath || !*pszPath) return NULL;
1497         if (!(pos = StrChrW(pszPath, '\\')))
1498           return (LPWSTR) pszPath + strlenW(pszPath);
1499         pos++;
1500         if(pos[0] == '\\') pos++;
1501         return pos;
1502 }
1503
1504 /*************************************************************************
1505  * PathAddExtensionA   [SHLWAPI.@]
1506  *
1507  * NOTES
1508  *  it adds never a dot
1509  */
1510  
1511 BOOL WINAPI PathAddExtensionA(
1512         LPSTR  pszPath,
1513         LPCSTR pszExtension)
1514 {
1515         if (*pszPath)
1516         {
1517           if (*(PathFindExtensionA(pszPath))) return FALSE;
1518
1519           if (!pszExtension || *pszExtension=='\0')
1520             strcat(pszPath, "exe");
1521           else
1522             strcat(pszPath, pszExtension);
1523         }
1524
1525         return TRUE;
1526 }
1527
1528 /*************************************************************************
1529  *      PathAddExtensionW   [SHLWAPI.@]
1530  */
1531 BOOL WINAPI PathAddExtensionW(
1532         LPWSTR  pszPath,
1533         LPCWSTR pszExtension)
1534 {
1535         static const WCHAR ext[] = { 'e','x','e',0 };
1536
1537         if (*pszPath)
1538         {
1539           if (*(PathFindExtensionW(pszPath))) return FALSE;
1540
1541           if (!pszExtension || *pszExtension=='\0')
1542             strcatW(pszPath, ext);
1543           else
1544             strcatW(pszPath, pszExtension);
1545         }
1546         return TRUE;
1547
1548 }
1549
1550 /*************************************************************************
1551  *      PathMakePrettyA   [SHLWAPI.@]
1552  */
1553 BOOL WINAPI PathMakePrettyA(
1554         LPSTR lpPath)
1555 {
1556         FIXME("%s\n", lpPath);
1557         return TRUE;
1558 }
1559
1560 /*************************************************************************
1561  *      PathMakePrettyW   [SHLWAPI.@]
1562  */
1563 BOOL WINAPI PathMakePrettyW(
1564         LPWSTR lpPath)
1565 {
1566         FIXME("%s\n", debugstr_w(lpPath));
1567         return TRUE;
1568
1569 }
1570
1571 /*************************************************************************
1572  *      PathCommonPrefixA   [SHLWAPI.@]
1573  */
1574 int WINAPI PathCommonPrefixA(
1575         LPCSTR pszFile1,
1576         LPCSTR pszFile2,
1577         LPSTR achPath)
1578 {
1579         FIXME("%s %s %p\n", pszFile1, pszFile2, achPath);
1580         return 0;
1581 }
1582
1583 /*************************************************************************
1584  *      PathCommonPrefixW   [SHLWAPI.@]
1585  */
1586 int WINAPI PathCommonPrefixW(
1587         LPCWSTR pszFile1,
1588         LPCWSTR pszFile2,
1589         LPWSTR achPath)
1590 {
1591         FIXME("%s %s %p\n", debugstr_w(pszFile1), debugstr_w(pszFile2),achPath );
1592         return 0;
1593 }
1594
1595 /*************************************************************************
1596  *      PathCompactPathA   [SHLWAPI.@]
1597  */
1598 BOOL WINAPI PathCompactPathA(HDC hDC, LPSTR pszPath, UINT dx)
1599 {
1600         FIXME("0x%08x %s 0x%08x\n", hDC, pszPath, dx);
1601         return FALSE;
1602 }
1603
1604 /*************************************************************************
1605  *      PathCompactPathW   [SHLWAPI.@]
1606  */
1607 BOOL WINAPI PathCompactPathW(HDC hDC, LPWSTR pszPath, UINT dx)
1608 {
1609         FIXME("0x%08x %s 0x%08x\n", hDC, debugstr_w(pszPath), dx);
1610         return FALSE;
1611 }
1612
1613 /*************************************************************************
1614  *      PathGetCharTypeA   [SHLWAPI.@]
1615  */
1616 UINT WINAPI PathGetCharTypeA(UCHAR ch)
1617 {
1618         FIXME("%c\n", ch);
1619         return 0;
1620 }
1621
1622 /*************************************************************************
1623  *      PathGetCharTypeW   [SHLWAPI.@]
1624  */
1625 UINT WINAPI PathGetCharTypeW(WCHAR ch)
1626 {
1627         FIXME("%c\n", ch);
1628         return 0;
1629 }
1630
1631 /*************************************************************************
1632  *      PathMakeSystemFolderA   [SHLWAPI.@]
1633  */
1634 BOOL WINAPI PathMakeSystemFolderA(LPCSTR pszPath)
1635 {
1636         FIXME("%s\n", pszPath);
1637         return FALSE;
1638 }
1639
1640 /*************************************************************************
1641  *      PathMakeSystemFolderW   [SHLWAPI.@]
1642  */
1643 BOOL WINAPI PathMakeSystemFolderW(LPCWSTR pszPath)
1644 {
1645         FIXME("%s\n", debugstr_w(pszPath));
1646         return FALSE;
1647 }
1648
1649 /*************************************************************************
1650  *      PathRenameExtensionA   [SHLWAPI.@]
1651  */
1652 BOOL WINAPI PathRenameExtensionA(LPSTR pszPath, LPCSTR pszExt)
1653 {
1654         FIXME("%s %s\n", pszPath, pszExt);
1655         return FALSE;
1656 }
1657
1658 /*************************************************************************
1659  *      PathRenameExtensionW   [SHLWAPI.@]
1660  */
1661 BOOL WINAPI PathRenameExtensionW(LPWSTR pszPath, LPCWSTR pszExt)
1662 {
1663         FIXME("%s %s\n", debugstr_w(pszPath), debugstr_w(pszExt));
1664         return FALSE;
1665 }
1666
1667 /*************************************************************************
1668  *      PathSearchAndQualifyA   [SHLWAPI.@]
1669  */
1670 BOOL WINAPI PathSearchAndQualifyA(
1671         LPCSTR pszPath,
1672         LPSTR pszBuf,
1673         UINT cchBuf)
1674 {
1675         FIXME("%s %s 0x%08x\n", pszPath, pszBuf, cchBuf);
1676         return FALSE;
1677 }
1678
1679 /*************************************************************************
1680  *      PathSearchAndQualifyW   [SHLWAPI.@]
1681  */
1682 BOOL WINAPI PathSearchAndQualifyW(
1683         LPCWSTR pszPath,
1684         LPWSTR pszBuf,
1685         UINT cchBuf)
1686 {
1687         FIXME("%s %s 0x%08x\n", debugstr_w(pszPath), debugstr_w(pszBuf), cchBuf);
1688         return FALSE;
1689 }
1690
1691 /*************************************************************************
1692  *      PathSkipRootA   [SHLWAPI.@]
1693  */
1694 LPSTR WINAPI PathSkipRootA(LPCSTR pszPath)
1695 {
1696         FIXME("%s\n", pszPath);
1697         return (LPSTR)pszPath;
1698 }
1699
1700 /*************************************************************************
1701  *      PathSkipRootW   [SHLWAPI.@]
1702  */
1703 LPWSTR WINAPI PathSkipRootW(LPCWSTR pszPath)
1704 {
1705         FIXME("%s\n", debugstr_w(pszPath));
1706         return (LPWSTR)pszPath;
1707 }
1708
1709 /*************************************************************************
1710  *      PathCreateFromUrlA   [SHLWAPI.@]
1711  */
1712 HRESULT WINAPI PathCreateFromUrlA(
1713         LPCSTR pszUrl,
1714         LPSTR pszPath,
1715         LPDWORD pcchPath,
1716         DWORD dwFlags)
1717 {
1718         FIXME("%s %p %p 0x%08lx\n",
1719           pszUrl, pszPath, pcchPath, dwFlags);
1720         return S_OK;
1721 }
1722
1723 /*************************************************************************
1724  *      PathCreateFromUrlW   [SHLWAPI.@]
1725  */
1726 HRESULT WINAPI PathCreateFromUrlW(
1727         LPCWSTR pszUrl,
1728         LPWSTR pszPath,
1729         LPDWORD pcchPath,
1730         DWORD dwFlags)
1731 {
1732         FIXME("%s %p %p 0x%08lx\n",
1733           debugstr_w(pszUrl), pszPath, pcchPath, dwFlags);
1734         return S_OK;
1735 }
1736
1737 /*************************************************************************
1738  *      PathRelativePathToA   [SHLWAPI.@]
1739  */
1740 BOOL WINAPI PathRelativePathToA(
1741         LPSTR pszPath,
1742         LPCSTR pszFrom,
1743         DWORD dwAttrFrom,
1744         LPCSTR pszTo,
1745         DWORD dwAttrTo)
1746 {
1747         FIXME("%s %s 0x%08lx %s 0x%08lx\n",
1748           pszPath, pszFrom, dwAttrFrom, pszTo, dwAttrTo);
1749         return FALSE;
1750 }
1751
1752 /*************************************************************************
1753  *      PathRelativePathToW   [SHLWAPI.@]
1754  */
1755 BOOL WINAPI PathRelativePathToW(
1756         LPWSTR pszPath,
1757         LPCWSTR pszFrom,
1758         DWORD dwAttrFrom,
1759         LPCWSTR pszTo,
1760         DWORD dwAttrTo)
1761 {
1762         FIXME("%s %s 0x%08lx %s 0x%08lx\n",
1763           debugstr_w(pszPath), debugstr_w(pszFrom), dwAttrFrom, debugstr_w(pszTo), dwAttrTo);
1764         return FALSE;
1765 }
1766
1767 /*************************************************************************
1768  *      PathUnmakeSystemFolderA   [SHLWAPI.@]
1769  */
1770 BOOL WINAPI PathUnmakeSystemFolderA(LPCSTR pszPath)
1771 {
1772         FIXME("%s\n", pszPath);
1773         return FALSE;
1774 }
1775
1776 /*************************************************************************
1777  *      PathUnmakeSystemFolderW   [SHLWAPI.@]
1778  */
1779 BOOL WINAPI PathUnmakeSystemFolderW(LPCWSTR pszPath)
1780 {
1781         FIXME("%s\n", debugstr_w(pszPath));
1782         return FALSE;
1783 }
1784
1785 /*
1786         ########## special ##########
1787 */
1788
1789 /*************************************************************************
1790  * PathSetDlgItemPathA   [SHLWAPI.@]
1791  *
1792  * NOTES
1793  *  use PathCompactPath to make sure, the path fits into the control
1794  */
1795 BOOL WINAPI PathSetDlgItemPathA(HWND hDlg, int id, LPCSTR pszPath) 
1796 {       TRACE("%x %x %s\n",hDlg, id, pszPath);
1797         return SetDlgItemTextA(hDlg, id, pszPath);
1798 }
1799
1800 /*************************************************************************
1801  * PathSetDlgItemPathW   [SHLWAPI.@]
1802  */
1803 BOOL WINAPI PathSetDlgItemPathW(HWND hDlg, int id, LPCWSTR pszPath) 
1804 {       TRACE("%x %x %s\n",hDlg, id, debugstr_w(pszPath));
1805         return SetDlgItemTextW(hDlg, id, pszPath);
1806 }