Support for nonstandard baud rate in SetCommState.
[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[0]=='\\' && lpszPath[1]=='\\')             
1309         {
1310           int foundbackslash = 0;
1311           lpszPath += 2;
1312           while (*lpszPath)
1313           {
1314             if (*lpszPath=='\\') foundbackslash++;
1315             lpszPath = CharNextA(lpszPath);
1316           }
1317           if (foundbackslash == 1)
1318             return TRUE;
1319         }
1320         return FALSE;
1321 }
1322
1323 /*************************************************************************
1324  *      PathIsUNCServerShareW   [SHLWAPI.@]
1325  */
1326 BOOL WINAPI PathIsUNCServerShareW(
1327         LPCWSTR lpszPath)
1328 {
1329         TRACE("%s\n", debugstr_w(lpszPath));
1330         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
1331         {
1332           int foundbackslash = 0;
1333           lpszPath += 2;
1334           while (*lpszPath)
1335           {
1336             if (*lpszPath=='\\') foundbackslash++;
1337             lpszPath = CharNextW(lpszPath);
1338           }
1339           if (foundbackslash == 1)
1340             return TRUE;
1341         }
1342         return FALSE;
1343 }
1344
1345 /*************************************************************************
1346  * PathCanonicalizeA   [SHLWAPI.@]
1347  *
1348  *  FIXME
1349  *   returnvalue, use CharNext
1350  */
1351  
1352 BOOL WINAPI PathCanonicalizeA(LPSTR pszBuf, LPCSTR pszPath)
1353 {
1354         int OffsetMin = 0, OffsetSrc = 0, OffsetDst = 0, LenSrc = strlen(pszPath);
1355         BOOL bModifyed = FALSE;
1356
1357         TRACE("%p %s\n", pszBuf, pszPath);
1358         
1359         pszBuf[OffsetDst]='\0';
1360
1361         /* keep the root of the path */
1362         if( LenSrc && (pszPath[OffsetSrc]=='\\'))
1363         {
1364           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1365         }
1366         else if ( (LenSrc >= 2) && (pszPath[OffsetSrc+1] == ':'))
1367         {
1368           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1369           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1370           if (LenSrc && (pszPath[OffsetSrc] == '\\'))
1371           {
1372             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1373             if (LenSrc == 1 && pszPath[OffsetSrc]=='.')
1374             {
1375               /* C:\. */
1376               OffsetSrc++; LenSrc--; bModifyed = TRUE;
1377             } 
1378             else if (LenSrc == 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='.')
1379             {
1380               /* C:\.. */
1381               OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
1382             } 
1383           }
1384         }
1385         
1386         /* ".\" at the beginning of the path */
1387         if (LenSrc >= 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='\\')
1388         {
1389           OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
1390         } 
1391         
1392         while ( LenSrc )
1393         {
1394           if((LenSrc>=3) && (pszPath[OffsetSrc]=='\\') && (pszPath[OffsetSrc+1]=='.') && (pszPath[OffsetSrc+2]=='.'))
1395           {
1396             /* "\.." found, go one deeper */
1397             while((OffsetDst > OffsetMin) && (pszBuf[OffsetDst]!='\\')) OffsetDst--;
1398             OffsetSrc += 3; LenSrc -= 3; bModifyed = TRUE;
1399             if(OffsetDst == OffsetMin && pszPath[OffsetSrc]=='\\') OffsetSrc++;
1400             pszBuf[OffsetDst] = '\0';                   /* important for \..\.. */
1401           }
1402           else if(LenSrc>=2 && pszPath[OffsetSrc]=='\\' && pszPath[OffsetSrc+1]=='.' )
1403           {
1404             /* "\." found, skip it */
1405             OffsetSrc += 2; LenSrc-=2; bModifyed = TRUE;
1406           }
1407           else
1408           {
1409             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; LenSrc--;
1410           }
1411         }
1412         pszBuf[OffsetDst] = '\0';
1413         TRACE("-- %s %u\n", pszBuf, bModifyed);
1414         return bModifyed;
1415 }
1416
1417
1418 /*************************************************************************
1419  * PathCanonicalizeW   [SHLWAPI.@]
1420  *
1421  *  FIXME
1422  *   returnvalue, use CharNext
1423  */
1424 BOOL WINAPI PathCanonicalizeW(LPWSTR pszBuf, LPCWSTR pszPath)
1425 {
1426         int OffsetMin = 0, OffsetSrc = 0, OffsetDst = 0, LenSrc = strlenW(pszPath);
1427         BOOL bModifyed = FALSE;
1428
1429         TRACE("%p %s\n", pszBuf, debugstr_w(pszPath));
1430         
1431         pszBuf[OffsetDst]='\0';
1432
1433         /* keep the root of the path */
1434         if( LenSrc && (pszPath[OffsetSrc]=='\\'))
1435         {
1436           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1437         }
1438         else if ( (LenSrc >= 2) && (pszPath[OffsetSrc+1] == ':'))
1439         {
1440           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1441           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1442           if (LenSrc && (pszPath[OffsetSrc] == '\\'))
1443           {
1444             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
1445             if (LenSrc == 1 && pszPath[OffsetSrc]=='.')
1446             {
1447               /* C:\. */
1448               OffsetSrc++; LenSrc--; bModifyed = TRUE;
1449             } 
1450             else if (LenSrc == 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='.')
1451             {
1452               /* C:\.. */
1453               OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
1454             } 
1455           }
1456         }
1457         
1458         /* ".\" at the beginning of the path */
1459         if (LenSrc >= 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='\\')
1460         {
1461           OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
1462         } 
1463         
1464         while ( LenSrc )
1465         {
1466           if((LenSrc>=3) && (pszPath[OffsetSrc]=='\\') && (pszPath[OffsetSrc+1]=='.') && (pszPath[OffsetSrc+2]=='.'))
1467           {
1468             /* "\.." found, go one deeper */
1469             while((OffsetDst > OffsetMin) && (pszBuf[OffsetDst]!='\\')) OffsetDst--;
1470             OffsetSrc += 3; LenSrc -= 3; bModifyed = TRUE;
1471             if(OffsetDst == OffsetMin && pszPath[OffsetSrc]=='\\') OffsetSrc++;
1472             pszBuf[OffsetDst] = '\0';                   /* important for \..\.. */
1473           }
1474           else if(LenSrc>=2 && pszPath[OffsetSrc]=='\\' && pszPath[OffsetSrc+1]=='.' )
1475           {
1476             /* "\." found, skip it */
1477             OffsetSrc += 2; LenSrc-=2; bModifyed = TRUE;
1478           }
1479           else
1480           {
1481             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; LenSrc--;
1482           }
1483         }
1484         pszBuf[OffsetDst] = '\0';
1485         TRACE("-- %s %u\n", debugstr_w(pszBuf), bModifyed);
1486         return bModifyed;
1487 }
1488
1489 /*************************************************************************
1490  * PathFindNextComponentA   [SHLWAPI.@]
1491  *
1492  * NOTES
1493  * special cases:
1494  *      ""              null
1495  *      aa              "" (pointer to traling NULL)
1496  *      aa\             "" (pointer to traling NULL)
1497  *      aa\\            "" (pointer to traling NULL)
1498  *      aa\\bb          bb
1499  *      aa\\\bb         \bb
1500  *      c:\aa\          "aa\"
1501  *      \\aa            aa
1502  *      \\aa\b          aa\b
1503 */
1504 LPSTR WINAPI PathFindNextComponentA(LPCSTR pszPath)
1505 {
1506         LPSTR pos;
1507
1508         TRACE("%s\n", pszPath);
1509
1510         if(!pszPath || !*pszPath) return NULL;
1511         if(!(pos = StrChrA(pszPath, '\\')))
1512           return (LPSTR) pszPath + strlen(pszPath);
1513         pos++;
1514         if(pos[0] == '\\') pos++;
1515         return pos;
1516 }
1517
1518 /*************************************************************************
1519  * PathFindNextComponentW   [SHLWAPI.@]
1520  */
1521 LPWSTR WINAPI PathFindNextComponentW(LPCWSTR pszPath)
1522 {
1523         LPWSTR pos;
1524
1525         TRACE("%s\n", debugstr_w(pszPath));
1526         
1527         if(!pszPath || !*pszPath) return NULL;
1528         if (!(pos = StrChrW(pszPath, '\\')))
1529           return (LPWSTR) pszPath + strlenW(pszPath);
1530         pos++;
1531         if(pos[0] == '\\') pos++;
1532         return pos;
1533 }
1534
1535 /*************************************************************************
1536  * PathAddExtensionA   [SHLWAPI.@]
1537  *
1538  * NOTES
1539  *  it adds never a dot
1540  */
1541  
1542 BOOL WINAPI PathAddExtensionA(
1543         LPSTR  pszPath,
1544         LPCSTR pszExtension)
1545 {
1546         if (*pszPath)
1547         {
1548           if (*(PathFindExtensionA(pszPath))) return FALSE;
1549
1550           if (!pszExtension || *pszExtension=='\0')
1551             strcat(pszPath, "exe");
1552           else
1553             strcat(pszPath, pszExtension);
1554         }
1555
1556         return TRUE;
1557 }
1558
1559 /*************************************************************************
1560  *      PathAddExtensionW   [SHLWAPI.@]
1561  */
1562 BOOL WINAPI PathAddExtensionW(
1563         LPWSTR  pszPath,
1564         LPCWSTR pszExtension)
1565 {
1566         static const WCHAR ext[] = { 'e','x','e',0 };
1567
1568         if (*pszPath)
1569         {
1570           if (*(PathFindExtensionW(pszPath))) return FALSE;
1571
1572           if (!pszExtension || *pszExtension=='\0')
1573             strcatW(pszPath, ext);
1574           else
1575             strcatW(pszPath, pszExtension);
1576         }
1577         return TRUE;
1578
1579 }
1580
1581 /*************************************************************************
1582  *      PathMakePrettyA   [SHLWAPI.@]
1583  */
1584 BOOL WINAPI PathMakePrettyA(
1585         LPSTR lpPath)
1586 {
1587         FIXME("%s\n", lpPath);
1588         return TRUE;
1589 }
1590
1591 /*************************************************************************
1592  *      PathMakePrettyW   [SHLWAPI.@]
1593  */
1594 BOOL WINAPI PathMakePrettyW(
1595         LPWSTR lpPath)
1596 {
1597         FIXME("%s\n", debugstr_w(lpPath));
1598         return TRUE;
1599
1600 }
1601
1602 /*************************************************************************
1603  *      PathCommonPrefixA   [SHLWAPI.@]
1604  */
1605 int WINAPI PathCommonPrefixA(
1606         LPCSTR pszFile1,
1607         LPCSTR pszFile2,
1608         LPSTR achPath)
1609 {
1610         FIXME("%s %s %p\n", pszFile1, pszFile2, achPath);
1611         return 0;
1612 }
1613
1614 /*************************************************************************
1615  *      PathCommonPrefixW   [SHLWAPI.@]
1616  */
1617 int WINAPI PathCommonPrefixW(
1618         LPCWSTR pszFile1,
1619         LPCWSTR pszFile2,
1620         LPWSTR achPath)
1621 {
1622         FIXME("%s %s %p\n", debugstr_w(pszFile1), debugstr_w(pszFile2),achPath );
1623         return 0;
1624 }
1625
1626 /*************************************************************************
1627  *      PathCompactPathA   [SHLWAPI.@]
1628  */
1629 BOOL WINAPI PathCompactPathA(HDC hDC, LPSTR pszPath, UINT dx)
1630 {
1631         FIXME("0x%08x %s 0x%08x\n", hDC, pszPath, dx);
1632         return FALSE;
1633 }
1634
1635 /*************************************************************************
1636  *      PathCompactPathW   [SHLWAPI.@]
1637  */
1638 BOOL WINAPI PathCompactPathW(HDC hDC, LPWSTR pszPath, UINT dx)
1639 {
1640         FIXME("0x%08x %s 0x%08x\n", hDC, debugstr_w(pszPath), dx);
1641         return FALSE;
1642 }
1643
1644 /*************************************************************************
1645  *      PathGetCharTypeA   [SHLWAPI.@]
1646  */
1647 UINT WINAPI PathGetCharTypeA(UCHAR ch)
1648 {
1649         UINT flags = 0;
1650
1651         TRACE("%c\n", ch);
1652
1653         /* We could use them in filenames, but this would confuse 'ls' */
1654         if (iscntrl(ch))
1655             return GCT_INVALID;
1656         if ((ch == '*') || (ch=='?'))
1657             return GCT_WILD;
1658         if ((ch == '\\') || (ch=='/'))
1659             return GCT_SEPARATOR;
1660         flags = 0;
1661         /* all normal characters, no lower case letters */
1662         if ((ch > ' ') && (ch < 0x7f) && !islower(ch))
1663             flags |= GCT_SHORTCHAR;
1664         /* All other characters are valid in long filenames, even umlauts */
1665         return flags | GCT_LFNCHAR;
1666 }
1667
1668 /*************************************************************************
1669  *      PathGetCharTypeW   [SHLWAPI.@]
1670  */
1671 UINT WINAPI PathGetCharTypeW(WCHAR ch)
1672 {
1673         FIXME("%c, using ascii version\n", ch);
1674         return PathGetCharTypeA(ch);
1675 }
1676
1677 /*************************************************************************
1678  *      PathMakeSystemFolderA   [SHLWAPI.@]
1679  */
1680 BOOL WINAPI PathMakeSystemFolderA(LPCSTR pszPath)
1681 {
1682         FIXME("%s\n", pszPath);
1683         return FALSE;
1684 }
1685
1686 /*************************************************************************
1687  *      PathMakeSystemFolderW   [SHLWAPI.@]
1688  */
1689 BOOL WINAPI PathMakeSystemFolderW(LPCWSTR pszPath)
1690 {
1691         FIXME("%s\n", debugstr_w(pszPath));
1692         return FALSE;
1693 }
1694
1695 /*************************************************************************
1696  *      PathRenameExtensionA   [SHLWAPI.@]
1697  */
1698 BOOL WINAPI PathRenameExtensionA(LPSTR pszPath, LPCSTR pszExt)
1699 {
1700         LPSTR pszExtension = PathFindExtensionA(pszPath);
1701
1702         if (!pszExtension) return FALSE;
1703         if (pszExtension-pszPath + strlen(pszExt) > MAX_PATH) return FALSE;
1704
1705         strcpy(pszExtension, pszExt);
1706         TRACE("%s\n", pszPath);
1707         return TRUE;
1708 }
1709
1710 /*************************************************************************
1711  *      PathRenameExtensionW   [SHLWAPI.@]
1712  */
1713 BOOL WINAPI PathRenameExtensionW(LPWSTR pszPath, LPCWSTR pszExt)
1714 {
1715         LPWSTR pszExtension = PathFindExtensionW(pszPath);
1716
1717         if (!pszExtension) return FALSE;
1718         if (pszExtension-pszPath + strlenW(pszExt) > MAX_PATH) return FALSE;
1719
1720         strcpyW(pszExtension, pszExt);
1721         TRACE("%s\n", debugstr_w(pszPath));
1722         return TRUE;
1723 }
1724
1725 /*************************************************************************
1726  *      PathSearchAndQualifyA   [SHLWAPI.@]
1727  */
1728 BOOL WINAPI PathSearchAndQualifyA(
1729         LPCSTR pszPath,
1730         LPSTR pszBuf,
1731         UINT cchBuf)
1732 {
1733         FIXME("%s %s 0x%08x\n", pszPath, pszBuf, cchBuf);
1734         return FALSE;
1735 }
1736
1737 /*************************************************************************
1738  *      PathSearchAndQualifyW   [SHLWAPI.@]
1739  */
1740 BOOL WINAPI PathSearchAndQualifyW(
1741         LPCWSTR pszPath,
1742         LPWSTR pszBuf,
1743         UINT cchBuf)
1744 {
1745         FIXME("%s %s 0x%08x\n", debugstr_w(pszPath), debugstr_w(pszBuf), cchBuf);
1746         return FALSE;
1747 }
1748
1749 /*************************************************************************
1750  *      PathSkipRootA   [SHLWAPI.@]
1751  */
1752 LPSTR WINAPI PathSkipRootA(LPCSTR pszPath)
1753 {
1754         FIXME("%s\n", pszPath);
1755         return (LPSTR)pszPath;
1756 }
1757
1758 /*************************************************************************
1759  *      PathSkipRootW   [SHLWAPI.@]
1760  */
1761 LPWSTR WINAPI PathSkipRootW(LPCWSTR pszPath)
1762 {
1763         FIXME("%s\n", debugstr_w(pszPath));
1764         return (LPWSTR)pszPath;
1765 }
1766
1767 /*************************************************************************
1768  *      PathCreateFromUrlA   [SHLWAPI.@]
1769  */
1770 HRESULT WINAPI PathCreateFromUrlA(
1771         LPCSTR pszUrl,
1772         LPSTR pszPath,
1773         LPDWORD pcchPath,
1774         DWORD dwFlags)
1775 {
1776     /* extracts thing prior to : in pszURL and checks against:
1777      *   https
1778      *   shell
1779      *   local
1780      *   about  - if match returns E_INVALIDARG
1781      */
1782         FIXME("%s %p %p 0x%08lx\n",
1783           pszUrl, pszPath, pcchPath, dwFlags);
1784         return E_INVALIDARG;
1785 }
1786
1787 /*************************************************************************
1788  *      PathCreateFromUrlW   [SHLWAPI.@]
1789  */
1790 HRESULT WINAPI PathCreateFromUrlW(
1791         LPCWSTR pszUrl,
1792         LPWSTR pszPath,
1793         LPDWORD pcchPath,
1794         DWORD dwFlags)
1795 {
1796     /* extracts thing prior to : in pszURL and checks against:
1797      *   https
1798      *   shell
1799      *   local
1800      *   about  - if match returns E_INVALIDARG
1801      */
1802         FIXME("%s %p %p 0x%08lx\n",
1803           debugstr_w(pszUrl), pszPath, pcchPath, dwFlags);
1804         return E_INVALIDARG;
1805 }
1806
1807 /*************************************************************************
1808  *      PathRelativePathToA   [SHLWAPI.@]
1809  */
1810 BOOL WINAPI PathRelativePathToA(
1811         LPSTR pszPath,
1812         LPCSTR pszFrom,
1813         DWORD dwAttrFrom,
1814         LPCSTR pszTo,
1815         DWORD dwAttrTo)
1816 {
1817         FIXME("%s %s 0x%08lx %s 0x%08lx\n",
1818           pszPath, pszFrom, dwAttrFrom, pszTo, dwAttrTo);
1819         return FALSE;
1820 }
1821
1822 /*************************************************************************
1823  *      PathRelativePathToW   [SHLWAPI.@]
1824  */
1825 BOOL WINAPI PathRelativePathToW(
1826         LPWSTR pszPath,
1827         LPCWSTR pszFrom,
1828         DWORD dwAttrFrom,
1829         LPCWSTR pszTo,
1830         DWORD dwAttrTo)
1831 {
1832         FIXME("%s %s 0x%08lx %s 0x%08lx\n",
1833           debugstr_w(pszPath), debugstr_w(pszFrom), dwAttrFrom, debugstr_w(pszTo), dwAttrTo);
1834         return FALSE;
1835 }
1836
1837 /*************************************************************************
1838  *      PathUnmakeSystemFolderA   [SHLWAPI.@]
1839  */
1840 BOOL WINAPI PathUnmakeSystemFolderA(LPCSTR pszPath)
1841 {
1842         FIXME("%s\n", pszPath);
1843         return FALSE;
1844 }
1845
1846 /*************************************************************************
1847  *      PathUnmakeSystemFolderW   [SHLWAPI.@]
1848  */
1849 BOOL WINAPI PathUnmakeSystemFolderW(LPCWSTR pszPath)
1850 {
1851         FIXME("%s\n", debugstr_w(pszPath));
1852         return FALSE;
1853 }
1854
1855 /*
1856         ########## special ##########
1857 */
1858
1859 /*************************************************************************
1860  * PathSetDlgItemPathA   [SHLWAPI.@]
1861  *
1862  * NOTES
1863  *  use PathCompactPath to make sure, the path fits into the control
1864  */
1865 BOOL WINAPI PathSetDlgItemPathA(HWND hDlg, int id, LPCSTR pszPath) 
1866 {       TRACE("%x %x %s\n",hDlg, id, pszPath);
1867         return SetDlgItemTextA(hDlg, id, pszPath);
1868 }
1869
1870 /*************************************************************************
1871  * PathSetDlgItemPathW   [SHLWAPI.@]
1872  */
1873 BOOL WINAPI PathSetDlgItemPathW(HWND hDlg, int id, LPCWSTR pszPath) 
1874 {       TRACE("%x %x %s\n",hDlg, id, debugstr_w(pszPath));
1875         return SetDlgItemTextW(hDlg, id, pszPath);
1876 }