Fixed off-by-one ordinals in MPR.
[wine] / memory / string.c
1 /*
2  * String functions
3  *
4  * Copyright 1993 Yngvi Sigurjonsson
5  * Copyright 1996 Alexandre Julliard
6  */
7
8 #include <ctype.h>
9 #include <string.h>
10 #include "winbase.h"
11 #include "winuser.h"
12 #include "wine/keyboard16.h"
13 #include "winerror.h"
14 #include "ldt.h"
15 #include "debug.h"
16 #include "winnls.h"
17
18 DEFAULT_DEBUG_CHANNEL(string)
19
20 static const BYTE STRING_Oem2Ansi[256] =
21 "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\244"
22 "\020\021\022\023\266\247\026\027\030\031\032\033\034\035\036\037"
23 "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057"
24 "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077"
25 "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117"
26 "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137"
27 "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157"
28 "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177"
29 "\307\374\351\342\344\340\345\347\352\353\350\357\356\354\304\305"
30 "\311\346\306\364\366\362\373\371\377\326\334\242\243\245\120\203"
31 "\341\355\363\372\361\321\252\272\277\137\254\275\274\241\253\273"
32 "\137\137\137\246\246\246\246\053\053\246\246\053\053\053\053\053"
33 "\053\055\055\053\055\053\246\246\053\053\055\055\246\055\053\055"
34 "\055\055\055\053\053\053\053\053\053\053\053\137\137\246\137\137"
35 "\137\337\137\266\137\137\265\137\137\137\137\137\137\137\137\137"
36 "\137\261\137\137\137\137\367\137\260\225\267\137\156\262\137\137";
37
38 static const BYTE STRING_Ansi2Oem[256] =
39 "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017"
40 "\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
41 "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057"
42 "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077"
43 "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117"
44 "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137"
45 "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157"
46 "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177"
47 "\200\201\054\237\054\137\375\374\210\045\123\074\117\215\216\217"
48 "\220\140\047\042\042\371\055\137\230\231\163\076\157\235\236\131"
49 "\040\255\233\234\017\235\335\025\042\143\246\256\252\055\162\137"
50 "\370\361\375\063\047\346\024\372\054\061\247\257\254\253\137\250"
51 "\101\101\101\101\216\217\222\200\105\220\105\105\111\111\111\111"
52 "\104\245\117\117\117\117\231\170\117\125\125\125\232\131\137\341"
53 "\205\240\203\141\204\206\221\207\212\202\210\211\215\241\214\213"
54 "\144\244\225\242\223\157\224\366\157\227\243\226\201\171\137\230";
55
56 #define OEM_TO_ANSI(ch) (STRING_Oem2Ansi[(unsigned char)(ch)])
57 #define ANSI_TO_OEM(ch) (STRING_Ansi2Oem[(unsigned char)(ch)])
58
59 /* Internaly used by strchr family functions */
60 static BOOL ChrCmpA( WORD word1, WORD word2);
61 static BOOL ChrCmpW( WORD word1, WORD word2);
62
63 extern LPWSTR __cdecl CRTDLL_wcschr(LPCWSTR str,WCHAR xchar);
64
65
66 /***********************************************************************
67  *           hmemcpy   (KERNEL.348)
68  */
69 void WINAPI hmemcpy16( LPVOID dst, LPCVOID src, LONG count )
70 {
71     memcpy( dst, src, count );
72 }
73
74
75 /***********************************************************************
76  *           lstrcat16   (KERNEL.89)
77  */
78 SEGPTR WINAPI lstrcat16( SEGPTR dst, LPCSTR src )
79 {
80     lstrcatA( (LPSTR)PTR_SEG_TO_LIN(dst), src );
81     return dst;
82 }
83
84
85 /***********************************************************************
86  *           lstrcat32A   (KERNEL32.599)
87  */
88 LPSTR WINAPI lstrcatA( LPSTR dst, LPCSTR src )
89 {
90     TRACE(string,"Append %s to %s\n",
91                    debugstr_a (src), debugstr_a (dst));
92     /* Windows does not check for NULL pointers here, so we don't either */
93     strcat( dst, src );
94     return dst;
95 }
96
97
98 /***********************************************************************
99  *           lstrcat32W   (KERNEL32.600)
100  */
101 LPWSTR WINAPI lstrcatW( LPWSTR dst, LPCWSTR src )
102 {
103     register LPWSTR p = dst;
104     TRACE(string,"Append L%s to L%s\n",
105                    debugstr_w (src), debugstr_w (dst));
106     /* Windows does not check for NULL pointers here, so we don't either */
107     while (*p) p++;
108     while ((*p++ = *src++));
109     return dst;
110 }
111
112
113 /***********************************************************************
114  *           lstrcatn16   (KERNEL.352)
115  */
116 SEGPTR WINAPI lstrcatn16( SEGPTR dst, LPCSTR src, INT16 n )
117 {
118     lstrcatnA( (LPSTR)PTR_SEG_TO_LIN(dst), src, n );
119     return dst;
120 }
121
122
123 /***********************************************************************
124  *           lstrcatn32A   (Not a Windows API)
125  */
126 LPSTR WINAPI lstrcatnA( LPSTR dst, LPCSTR src, INT n )
127 {
128     register LPSTR p = dst;
129     TRACE(string,"strcatn add %d chars from %s to %s\n",
130                    n, debugstr_an (src, n), debugstr_a (dst));
131     while (*p) p++;
132     if ((n -= (INT)(p - dst)) <= 0) return dst;
133     lstrcpynA( p, src, n );
134     return dst;
135 }
136
137
138 /***********************************************************************
139  *           lstrcatn32W   (Not a Windows API)
140  */
141 LPWSTR WINAPI lstrcatnW( LPWSTR dst, LPCWSTR src, INT n )
142 {
143     register LPWSTR p = dst;
144     TRACE(string,"strcatn add %d chars from L%s to L%s\n",
145                    n, debugstr_wn (src, n), debugstr_w (dst));
146     while (*p) p++;
147     if ((n -= (INT)(p - dst)) <= 0) return dst;
148     lstrcpynW( p, src, n );
149     return dst;
150 }
151
152
153 /***********************************************************************
154  *           lstrcmp16   (USER.430)
155  */
156 INT16 WINAPI lstrcmp16( LPCSTR str1, LPCSTR str2 )
157 {
158     return (INT16)strcmp( str1, str2 );
159 }
160
161
162 /***********************************************************************
163  *           lstrcmp32A   (KERNEL.602)
164  */
165 INT WINAPI lstrcmpA( LPCSTR str1, LPCSTR str2 )
166 {
167     return CompareStringA(LOCALE_SYSTEM_DEFAULT,0,str1,-1,str2,-1) - 2 ;
168 }
169
170
171 /***********************************************************************
172  *           lstrcmp32W   (KERNEL.603)
173  * FIXME : should call CompareString32W, when it is implemented.
174  *    This implementation is not "word sort", as it should.
175  */
176 INT WINAPI lstrcmpW( LPCWSTR str1, LPCWSTR str2 )
177 {
178     TRACE(string,"L%s and L%s\n",
179                    debugstr_w (str1), debugstr_w (str2));
180     if (!str1 || !str2) {
181         SetLastError(ERROR_INVALID_PARAMETER);
182         return 0;
183     }
184     while (*str1 && (*str1 == *str2)) { str1++; str2++; }
185     return (INT)(*str1 - *str2);
186 }
187
188
189 /***********************************************************************
190  *           lstrcmpi16   (USER.471)
191  */
192 INT16 WINAPI lstrcmpi16( LPCSTR str1, LPCSTR str2 )
193 {
194     return (INT16)lstrcmpiA( str1, str2 );
195 }
196
197
198 /***********************************************************************
199  *           lstrcmpi32A   (KERNEL32.605)
200  */
201 INT WINAPI lstrcmpiA( LPCSTR str1, LPCSTR str2 )
202 {    TRACE(string,"strcmpi %s and %s\n",
203                    debugstr_a (str1), debugstr_a (str2));
204     return CompareStringA(LOCALE_SYSTEM_DEFAULT,NORM_IGNORECASE,str1,-1,str2,-1)-2;
205 }
206
207
208 /***********************************************************************
209  *           lstrcmpi32W   (KERNEL32.606)
210  */
211 INT WINAPI lstrcmpiW( LPCWSTR str1, LPCWSTR str2 )
212 {
213     INT res;
214
215 #if 0
216     /* Too much!  (From registry loading.)  */
217     TRACE(string,"strcmpi L%s and L%s\n",
218                    debugstr_w (str1), debugstr_w (str2));
219 #endif
220     if (!str1 || !str2) {
221         SetLastError(ERROR_INVALID_PARAMETER);
222         return 0;
223     }
224     while (*str1)
225     {
226         if ((*str1<0x100 ) && (*str2<0x100)) {
227             if ((res = toupper(*str1) - toupper(*str2)) != 0) return res;
228         } else {
229             if ((res = towupper(*str1) - towupper(*str2)) != 0) return res;
230         }
231         str1++;
232         str2++;
233     }
234     return towupper(*str1) - towupper(*str2);
235 }
236
237
238 /***********************************************************************
239  *           lstrcpy16   (KERNEL.88)
240  */
241 SEGPTR WINAPI lstrcpy16( SEGPTR dst, LPCSTR src )
242 {
243     lstrcpyA( (LPSTR)PTR_SEG_TO_LIN(dst), src );
244     return dst;
245 }
246
247
248 /***********************************************************************
249  *           lstrcpyA   (KERNEL32.608)
250  */
251 LPSTR WINAPI lstrcpyA( LPSTR dst, LPCSTR src )
252 {
253     TRACE(string,"strcpy %s\n", debugstr_a (src));
254     /* In real windows the whole function is protected by an exception handler
255      * that returns ERROR_INVALID_PARAMETER on faulty parameters
256      * We currently just check for NULL.
257      */
258     if (!dst || !src) {
259         SetLastError(ERROR_INVALID_PARAMETER);
260         return 0;
261     }
262     /* this is how Windows does it */
263     memmove( dst, src, strlen(src)+1 );
264     return dst;
265 }
266
267
268 /***********************************************************************
269  *           lstrcpy32W   (KERNEL32.609)
270  */
271 LPWSTR WINAPI lstrcpyW( LPWSTR dst, LPCWSTR src )
272 {
273     register LPWSTR p = dst;
274     TRACE(string,"strcpy L%s\n", debugstr_w (src));
275     /* In real windows the whole function is protected by an exception handler
276      * that returns ERROR_INVALID_PARAMETER on faulty parameters
277      * We currently just check for NULL.
278      */
279     if (!dst || !src) {
280         SetLastError(ERROR_INVALID_PARAMETER);
281         return 0;
282     }
283     while ((*p++ = *src++));
284     return dst;
285 }
286
287
288 /***********************************************************************
289  *           lstrcpyn16   (KERNEL.353)
290  */
291 SEGPTR WINAPI lstrcpyn16( SEGPTR dst, LPCSTR src, INT16 n )
292 {
293     lstrcpynA( (LPSTR)PTR_SEG_TO_LIN(dst), src, n );
294     return dst;
295 }
296
297
298 /***********************************************************************
299  *           lstrcpyn32A   (KERNEL32.611)
300  * Note: this function differs from the UNIX strncpy, it _always_ writes
301  * a terminating \0
302  */
303 LPSTR WINAPI lstrcpynA( LPSTR dst, LPCSTR src, INT n )
304 {
305     LPSTR p = dst;
306     TRACE(string,"strcpyn %s for %d chars\n",
307                    debugstr_an (src,n), n);
308     /* In real windows the whole function is protected by an exception handler
309      * that returns ERROR_INVALID_PARAMETER on faulty parameters
310      * We currently just check for NULL.
311      */
312     if (!dst || !src) {
313         SetLastError(ERROR_INVALID_PARAMETER);
314         return 0;
315     }
316     while ((n-- > 1) && *src) *p++ = *src++;
317     if (n >= 0) *p = 0;
318     return dst;
319 }
320
321
322 /***********************************************************************
323  *           lstrcpyn32W   (KERNEL32.612)
324  * Note: this function differs from the UNIX strncpy, it _always_ writes
325  * a terminating \0
326  */
327 LPWSTR WINAPI lstrcpynW( LPWSTR dst, LPCWSTR src, INT n )
328 {
329     LPWSTR p = dst;
330     TRACE(string,"strcpyn L%s for %d chars\n",
331                    debugstr_wn (src,n), n);
332     /* In real windows the whole function is protected by an exception handler
333      * that returns ERROR_INVALID_PARAMETER on faulty parameters
334      * We currently just check for NULL.
335      */
336     if (!dst || !src) {
337         SetLastError(ERROR_INVALID_PARAMETER);
338         return 0;
339     }
340     while ((n-- > 1) && *src) *p++ = *src++;
341     if (n >= 0) *p = 0;
342     return dst;
343 }
344
345
346 /***********************************************************************
347  *           lstrlen16   (KERNEL.90)
348  */
349 INT16 WINAPI lstrlen16( LPCSTR str )
350 {
351     return (INT16)lstrlenA( str );
352 }
353
354
355 /***********************************************************************
356  *           lstrlen32A   (KERNEL32.614)
357  */
358 INT WINAPI lstrlenA( LPCSTR str )
359 {
360     /* looks weird, but win3.1 KERNEL got a GeneralProtection handler
361      * in lstrlen() ... we check only for NULL pointer reference.
362      * - Marcus Meissner
363      */
364     TRACE(string,"strlen %s\n", debugstr_a (str));
365     if (!str) return 0;
366     return (INT)strlen(str);
367 }
368
369
370 /***********************************************************************
371  *           lstrlen32W   (KERNEL32.615)
372  */
373 INT WINAPI lstrlenW( LPCWSTR str )
374 {
375     INT len = 0;
376     TRACE(string,"strlen L%s\n", debugstr_w (str));
377     if (!str) return 0;
378     while (*str++) len++;
379     return len;
380 }
381
382
383 /***********************************************************************
384  *           lstrncmp32A   (Not a Windows API)
385  */
386 INT WINAPI lstrncmpA( LPCSTR str1, LPCSTR str2, INT n )
387 {
388     TRACE(string,"strncmp %s and %s for %d chars\n",
389                    debugstr_an (str1, n), debugstr_an (str2, n), n);
390     return (INT)strncmp( str1, str2, n );
391 }
392
393
394 /***********************************************************************
395  *           lstrncmp32W   (Not a Windows API)
396  */
397 INT WINAPI lstrncmpW( LPCWSTR str1, LPCWSTR str2, INT n )
398 {
399     TRACE(string,"strncmp L%s and L%s for %d chars\n",
400                    debugstr_wn (str1, n), debugstr_wn (str2, n), n);
401     if (!n) return 0;
402     while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
403     return (INT)(*str1 - *str2);
404 }
405
406
407 /***********************************************************************
408  *           lstrncmpi32A   (Not a Windows API)
409  */
410 INT WINAPI lstrncmpiA( LPCSTR str1, LPCSTR str2, INT n )
411 {
412     INT res;
413
414     TRACE(string,"strncmpi %s and %s for %d chars\n",
415                    debugstr_an (str1, n), debugstr_an (str2, n), n);
416     if (!n) return 0;
417     while ((--n > 0) && *str1)
418       if ( (res = toupper(*str1++) - toupper(*str2++)) ) return res;
419
420     return toupper(*str1) - toupper(*str2);
421 }
422
423
424 /***********************************************************************
425  *           lstrncmpi32W   (Not a Windows API)
426  */
427 INT WINAPI lstrncmpiW( LPCWSTR str1, LPCWSTR str2, INT n )
428 {
429     INT res;
430
431     TRACE(string,"strncmpi L%s and L%s for %d chars\n",
432                    debugstr_wn (str1, n), debugstr_wn (str2, n), n);
433     if (!n) return 0;
434     while ((--n > 0) && *str1)
435     {
436         if ((res = towupper(*str1) - towupper(*str2)) != 0) return res;
437         str1++;
438         str2++;
439     }
440     return towupper(*str1) - towupper(*str2);
441 }
442
443
444 /***********************************************************************
445  *           lstrcpyAtoW   (Not a Windows API)
446  */
447 LPWSTR WINAPI lstrcpyAtoW( LPWSTR dst, LPCSTR src )
448 {
449     register LPWSTR p = dst;
450
451     TRACE(string,"%s\n",src);
452
453     while ((*p++ = (WCHAR)(unsigned char)*src++));
454     return dst;
455 }
456
457
458 /***********************************************************************
459  *           lstrcpyWtoA   (Not a Windows API)
460  */
461 LPSTR WINAPI lstrcpyWtoA( LPSTR dst, LPCWSTR src )
462 {
463     register LPSTR p = dst;
464
465     TRACE(string,"L%s\n",debugstr_w(src));
466
467     while ((*p++ = (CHAR)*src++));
468     return dst;
469 }
470
471
472 /***********************************************************************
473  *           lstrcpynAtoW   (Not a Windows API)
474  * Note: this function differs from the UNIX strncpy, it _always_ writes
475  * a terminating \0
476  */
477 LPWSTR WINAPI lstrcpynAtoW( LPWSTR dst, LPCSTR src, INT n )
478 {
479     LPWSTR p = dst;
480
481     TRACE(string,"%s %i\n",src, n);
482
483     while ((n-- > 1) && *src) *p++ = (WCHAR)(unsigned char)*src++;
484     if (n >= 0) *p = 0;
485     return dst;
486 }
487
488
489 /***********************************************************************
490  *           lstrcpynWtoA   (Not a Windows API)
491  * Note: this function differs from the UNIX strncpy, it _always_ writes
492  * a terminating \0
493  */
494 LPSTR WINAPI lstrcpynWtoA( LPSTR dst, LPCWSTR src, INT n )
495 {
496     LPSTR p = dst;
497
498     TRACE(string,"L%s %i\n",debugstr_w(src), n);
499
500     while ((n-- > 1) && *src) *p++ = (CHAR)*src++;
501     if (n >= 0) *p = 0;
502     return dst;
503 }
504
505 /***********************************************************************
506  *           UnicodeToAnsi   (KERNEL.434)
507  */
508 INT16 WINAPI UnicodeToAnsi16( LPCWSTR src, LPSTR dst, INT16 codepage )
509 {
510     if ( codepage != -1 )
511         FIXME( string, "codepage %d not supported\n", codepage );
512
513     lstrcpyWtoA( dst, src );
514
515     return (INT16)lstrlenA( dst );
516 }
517
518
519 /***********************************************************************
520  *           Copy   (GDI.250)
521  */
522 void WINAPI Copy16( LPVOID src, LPVOID dst, WORD size )
523 {
524     memcpy( dst, src, size );
525 }
526
527
528 /***********************************************************************
529  *           RtlFillMemory   (KERNEL32.441)
530  */
531 VOID WINAPI RtlFillMemory( LPVOID ptr, UINT len, UINT fill )
532 {
533     memset( ptr, fill, len );
534 }
535
536
537 /***********************************************************************
538  *           RtlMoveMemory   (KERNEL32.442)
539  */
540 VOID WINAPI RtlMoveMemory( LPVOID dst, LPCVOID src, UINT len )
541 {
542     memmove( dst, src, len );
543 }
544
545
546 /***********************************************************************
547  *           RtlZeroMemory   (KERNEL32.444)
548  */
549 VOID WINAPI RtlZeroMemory( LPVOID ptr, UINT len )
550 {
551     memset( ptr, 0, len );
552 }
553
554
555 /***********************************************************************
556  *           AnsiToOem16   (KEYBOARD.5)
557  */
558 INT16 WINAPI AnsiToOem16( LPCSTR s, LPSTR d )
559 {
560     CharToOemA( s, d );
561     return -1;
562 }
563
564
565 /***********************************************************************
566  *           OemToAnsi16   (KEYBOARD.6)
567  */
568 INT16 WINAPI OemToAnsi16( LPCSTR s, LPSTR d )
569 {
570     OemToCharA( s, d );
571     return -1;
572 }
573
574
575 /***********************************************************************
576  *           AnsiToOemBuff16   (KEYBOARD.134)
577  */
578 void WINAPI AnsiToOemBuff16( LPCSTR s, LPSTR d, UINT16 len )
579 {
580     if (len != 0) CharToOemBuffA( s, d, len );
581 }
582
583
584 /***********************************************************************
585  *           OemToAnsiBuff16   (KEYBOARD.135)
586  */
587 void WINAPI OemToAnsiBuff16( LPCSTR s, LPSTR d, UINT16 len )
588 {
589     if (len != 0) OemToCharBuffA( s, d, len );
590 }
591
592
593 /***********************************************************************
594  *           CharToOem32A   (USER32.37)
595  */
596 BOOL WINAPI CharToOemA( LPCSTR s, LPSTR d )
597 {
598     LPSTR oldd = d;
599     if (!s || !d) return TRUE;
600     TRACE(string,"CharToOem %s\n", debugstr_a (s));
601     while ((*d++ = ANSI_TO_OEM(*s++)));
602     TRACE(string,"       to %s\n", debugstr_a (oldd));
603     return TRUE;
604 }
605
606
607 /***********************************************************************
608  *           CharToOemBuff32A   (USER32.38)
609  */
610 BOOL WINAPI CharToOemBuffA( LPCSTR s, LPSTR d, DWORD len )
611 {
612     while (len--) *d++ = ANSI_TO_OEM(*s++);
613     return TRUE;
614 }
615
616
617 /***********************************************************************
618  *           CharToOemBuff32W   (USER32.39)
619  */
620 BOOL WINAPI CharToOemBuffW( LPCWSTR s, LPSTR d, DWORD len )
621 {
622     while (len--) *d++ = ANSI_TO_OEM(*s++);
623     return TRUE;
624 }
625
626
627 /***********************************************************************
628  *           CharToOem32W   (USER32.40)
629  */
630 BOOL WINAPI CharToOemW( LPCWSTR s, LPSTR d )
631 {
632     LPSTR oldd = d;
633     if (!s || !d) return TRUE;
634     TRACE(string,"CharToOem L%s\n", debugstr_w (s));
635     while ((*d++ = ANSI_TO_OEM(*s++)));
636     TRACE(string,"       to %s\n", debugstr_a (oldd));
637     return TRUE;
638 }
639
640
641 /***********************************************************************
642  *           OemToChar32A   (USER32.402)
643  */
644 BOOL WINAPI OemToCharA( LPCSTR s, LPSTR d )
645 {
646     LPSTR oldd = d;
647     TRACE(string,"OemToChar %s\n", debugstr_a (s));
648     while ((*d++ = OEM_TO_ANSI(*s++)));
649     TRACE(string,"       to %s\n", debugstr_a (oldd));
650     return TRUE;
651 }
652
653
654 /***********************************************************************
655  *           OemToCharBuff32A   (USER32.403)
656  */
657 BOOL WINAPI OemToCharBuffA( LPCSTR s, LPSTR d, DWORD len )
658 {
659     TRACE(string,"OemToCharBuff %s\n", debugstr_an (s, len));
660     while (len--) *d++ = OEM_TO_ANSI(*s++);
661     return TRUE;
662 }
663
664
665 /***********************************************************************
666  *           OemToCharBuff32W   (USER32.404)
667  */
668 BOOL WINAPI OemToCharBuffW( LPCSTR s, LPWSTR d, DWORD len )
669 {
670     TRACE(string,"OemToCharBuff %s\n", debugstr_an (s, len));
671     while (len--) *d++ = (WCHAR)OEM_TO_ANSI(*s++);
672     return TRUE;
673 }
674
675
676 /***********************************************************************
677  *           OemToChar32W   (USER32.405)
678  */
679 BOOL WINAPI OemToCharW( LPCSTR s, LPWSTR d )
680 {
681     while ((*d++ = (WCHAR)OEM_TO_ANSI(*s++)));
682     return TRUE;
683 }
684
685 /***********************************************************************
686  *  WideCharToLocal (Not a Windows API)
687  *  similar lstrcpyWtoA, should handle codepages properly
688  *
689  *  RETURNS
690  *    strlen of the destination string
691  */
692  
693 INT WINAPI WideCharToLocal(
694     LPSTR pLocal, 
695                 LPWSTR pWide, 
696                 INT dwChars)
697 { *pLocal = 0;
698   TRACE(string,"(%p, %s, %i)\n",        pLocal, debugstr_w(pWide),dwChars);
699   WideCharToMultiByte(CP_ACP,0,pWide,-1,pLocal,dwChars,NULL,NULL);
700   return strlen(pLocal);
701 }
702 /***********************************************************************
703  *  LocalToWideChar (Not a Windows API)
704  *  similar lstrcpyAtoW, should handle codepages properly
705  *
706  *  RETURNS
707  *    strlen of the destination string
708  */
709 INT WINAPI LocalToWideChar(
710     LPWSTR pWide, 
711                 LPSTR pLocal, 
712                 INT dwChars)
713 { *pWide = 0;
714   TRACE(string,"(%p, %s, %i)\n",pWide,  pLocal, dwChars);
715         MultiByteToWideChar(CP_ACP,0,pLocal,-1,pWide,dwChars); 
716   return lstrlenW(pWide);
717 }
718
719
720 /***********************************************************************
721  *           lstrrchr   (Not a Windows API)
722  *
723  * This is the implementation meant to be invoked form within
724  * COMCTL32_StrRChrA and shell32(TODO)...
725  *
726  * Return a pointer to the last occurence of wMatch in lpStart
727  * not looking further than lpEnd...
728  */
729 LPSTR WINAPI lstrrchr( LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch )
730 {
731   LPCSTR lpGotIt = NULL;
732
733   TRACE(string,"(%s, %s)\n", lpStart, lpEnd);
734
735   if (!lpEnd) lpEnd = lpStart + strlen(lpStart);
736
737   for(; lpStart < lpEnd; lpStart = CharNextA(lpStart)) 
738     if (!ChrCmpA( GET_WORD(lpStart), wMatch)) 
739       lpGotIt = lpStart;
740     
741   return ((LPSTR)lpGotIt);
742 }
743
744 /***********************************************************************
745  *           lstrrchrw    (Not a Windows API)
746  *
747  * This is the implementation meant to be invoked form within
748  * COMCTL32_StrRChrW and shell32(TODO)...
749  *
750  * Return a pointer to the last occurence of wMatch in lpStart
751  * not looking further than lpEnd...
752  */  
753 LPWSTR WINAPI lstrrchrw( LPCWSTR lpStart, LPCWSTR lpEnd, WORD wMatch )
754 {
755   LPCWSTR lpGotIt = NULL;
756
757   TRACE(string,"(%p, %p, %c)\n", lpStart,      lpEnd, wMatch);
758   if (!lpEnd) lpEnd = lpStart + lstrlenW(lpStart);
759
760   for(; lpStart < lpEnd; lpStart = CharNextW(lpStart)) 
761     if (!ChrCmpW( GET_WORD(lpStart), wMatch)) 
762       lpGotIt = lpStart;
763     
764   return (LPWSTR)lpGotIt;
765 }
766
767 /***********************************************************************
768  *           strstrw   (Not a Windows API)
769  *
770  * This is the implementation meant to be invoked form within
771  * COMCTL32_StrStrW and shell32(TODO)...
772  *
773  */
774 LPWSTR WINAPI strstrw( LPCWSTR lpFirst, LPCWSTR lpSrch) {
775   UINT uSrchLen  = (UINT)lstrlenW(lpSrch);
776   WORD wMatchBeg   = *(WORD*)lpSrch;
777
778   TRACE(string,"(%p, %p)\n", lpFirst,  lpSrch);
779
780   for(; 
781     ((lpFirst=CRTDLL_wcschr(lpFirst, wMatchBeg))!=0) && 
782       lstrncmpW(lpFirst, lpSrch, uSrchLen); 
783     lpFirst++) {
784       continue;
785   }
786   return (LPWSTR)lpFirst;
787 }
788
789
790 /***********************************************************************
791  *           ChrCmpA   
792  * This fuction returns FALSE if both words match, TRUE otherwise...
793  */
794 static BOOL ChrCmpA( WORD word1, WORD word2) {
795   if (LOBYTE(word1) == LOBYTE(word2)) {
796     if (IsDBCSLeadByte(LOBYTE(word1))) {
797       return (word1 != word2);
798     }
799     return FALSE;
800   }
801   return TRUE;
802 }
803
804 /***********************************************************************
805  *           ChrCmpW   
806  * This fuction returns FALSE if both words match, TRUE otherwise...
807  */
808 static BOOL ChrCmpW( WORD word1, WORD word2) {
809   return (word1 != word2);
810 }
811
812