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