- Better handling when settimeofday is not available.
[wine] / dlls / msvcrt / mbcs.c
1 /*
2  * msvcrt.dll mbcs functions
3  *
4  * Copyright 1999 Alexandre Julliard
5  * Copyright 2000 Jon Griffths
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  * FIXME
22  * Not currently binary compatible with win32. MSVCRT_mbctype must be
23  * populated correctly and the ismb* functions should reference it.
24  */
25
26 #include "msvcrt.h"
27
28 #include "msvcrt/mbctype.h"
29 #include "msvcrt/mbstring.h"
30 #include "msvcrt/stdlib.h"
31 #include "msvcrt/string.h"
32 #include "msvcrt/wctype.h"
33
34
35 #include "wine/debug.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
38
39 unsigned char MSVCRT_mbctype[257];
40 int MSVCRT___mb_cur_max = 1;
41
42 /*********************************************************************
43  *              __p__mbctype (MSVCRT.@)
44  */
45 unsigned char* __p__mbctype(void)
46 {
47   return MSVCRT_mbctype;
48 }
49
50 /*********************************************************************
51  *              __p___mb_cur_max(MSVCRT.@)
52  */
53 int* __p___mb_cur_max(void)
54 {
55   return &MSVCRT___mb_cur_max;
56 }
57
58 /*********************************************************************
59  *              _mbsnextc(MSVCRT.@)
60  */
61 unsigned int _mbsnextc(const unsigned char* str)
62 {
63   if(MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(*str))
64     return *str << 8 | str[1];
65   return *str; /* ASCII CP or SB char */
66 }
67
68 /*********************************************************************
69  *              _mbctolower(MSVCRT.@)
70  */
71 unsigned int _mbctolower(unsigned int c)
72 {
73     if (MSVCRT_isleadbyte(c))
74     {
75       FIXME("Handle MBC chars\n");
76       return c;
77     }
78     return tolower(c); /* ASCII CP or SB char */
79 }
80
81 /*********************************************************************
82  *              _mbctoupper(MSVCRT.@)
83  */
84 unsigned int _mbctoupper(unsigned int c)
85 {
86     if (MSVCRT_isleadbyte(c))
87     {
88       FIXME("Handle MBC chars\n");
89       return c;
90     }
91     return toupper(c); /* ASCII CP or SB char */
92 }
93
94 /*********************************************************************
95  *              _mbsdec(MSVCRT.@)
96  */
97 unsigned char* _mbsdec(const unsigned char* start, const unsigned char* cur)
98 {
99   if(MSVCRT___mb_cur_max > 1)
100     return (char *)(_ismbstrail(start,cur-1) ? cur - 2 : cur -1);
101
102   return (char *)cur - 1; /* ASCII CP or SB char */
103 }
104
105 /*********************************************************************
106  *              _mbsinc(MSVCRT.@)
107  */
108 unsigned char* _mbsinc(const unsigned char* str)
109 {
110   if(MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(*str))
111     return (unsigned char*)str + 2; /* MB char */
112
113   return (unsigned char*)str + 1; /* ASCII CP or SB char */
114 }
115
116 /*********************************************************************
117  *              _mbsninc(MSVCRT.@)
118  */
119 unsigned char* _mbsninc(const unsigned char* str, MSVCRT_size_t num)
120 {
121   if(!str || num < 1)
122     return NULL;
123   if(MSVCRT___mb_cur_max > 1)
124   {
125     while(num--)
126       str = _mbsinc(str);
127     return (unsigned char*)str;
128   }
129   return (unsigned char*)str + num; /* ASCII CP */
130 }
131
132 /*********************************************************************
133  *              _mbclen(MSVCRT.@)
134  */
135 unsigned int _mbclen(const unsigned char* str)
136 {
137   return MSVCRT_isleadbyte(*str) ? 2 : 1;
138 }
139
140 /*********************************************************************
141  *              mblen(MSVCRT.@)
142  */
143 int MSVCRT_mblen(const char* str, MSVCRT_size_t size)
144 {
145   if (str && *str && size)
146   {
147     if(MSVCRT___mb_cur_max == 1)
148       return 1; /* ASCII CP */
149
150     return !MSVCRT_isleadbyte(*str) ? 1 : (size>1 ? 2 : -1);
151   }
152   return 0;
153 }
154
155 /*********************************************************************
156  *              _mbslen(MSVCRT.@)
157  */
158 MSVCRT_size_t _mbslen(const unsigned char* str)
159 {
160   if(MSVCRT___mb_cur_max > 1)
161   {
162     MSVCRT_size_t len = 0;
163     while(*str)
164     {
165       str += MSVCRT_isleadbyte(*str) ? 2 : 1;
166       len++;
167     }
168     return len;
169   }
170   return strlen(str); /* ASCII CP */
171 }
172
173 /*********************************************************************
174  *              _mbstrlen(MSVCRT.@)
175  */
176 MSVCRT_size_t _mbstrlen(const char* str)
177 {
178   if(MSVCRT___mb_cur_max > 1)
179   {
180     MSVCRT_size_t len = 0;
181     while(*str)
182     {
183       /* FIXME: According to the documentation we are supposed to test for 
184        * multi-byte character validity. Whatever that means
185        */
186       str += MSVCRT_isleadbyte(*str) ? 2 : 1;
187       len++;
188     }
189     return len;
190   }
191   return strlen(str); /* ASCII CP */
192 }
193
194 /*********************************************************************
195  *              _mbccpy(MSVCRT.@)
196  */
197 void _mbccpy(unsigned char* dest, const unsigned char* src)
198 {
199   *dest++ = *src;
200   if(MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(*src))
201     *dest = *++src; /* MB char */
202   else
203     ERR("failure.. is this ok?\n");
204 }
205
206 /*********************************************************************
207  *              _mbsncpy(MSVCRT.@)
208  */
209 unsigned char* _mbsncpy(unsigned char* dst, const unsigned char* src, MSVCRT_size_t n)
210 {
211   if(!n)
212     return dst;
213   if(MSVCRT___mb_cur_max > 1)
214   {
215     unsigned char* ret = dst;
216     while (*src && n--)
217     {
218       *dst++ = *src;
219       if (MSVCRT_isleadbyte(*src++))
220           *dst++ = *src++;
221     }
222     while(n--)
223       *dst++ = '\0';
224     return ret;
225   }
226   return strncpy(dst, src, n); /* ASCII CP */
227 }
228
229 /*********************************************************************
230  *              _mbsnbcpy(MSVCRT.@)
231  */
232 unsigned char* _mbsnbcpy(unsigned char* dst, const unsigned char* src, MSVCRT_size_t n)
233 {
234   if(!n)
235     return dst;
236   if(MSVCRT___mb_cur_max > 1)
237   {
238     unsigned char* ret = dst;
239     while (*src && (n-- > 1))
240     {
241       *dst++ = *src;
242       if (MSVCRT_isleadbyte(*src++))
243       {
244         *dst++ = *src++;
245         n--;
246       }
247     }
248     if (*src && n && !MSVCRT_isleadbyte(*src))
249     {
250       /* If the last character is a multi-byte character then 
251        * we cannot copy it since we have only one byte left
252        */
253       *dst++ = *src;
254       n--;
255     }
256     while (n--)
257       *dst++ = '\0';
258     return ret;
259   }
260   return strncpy(dst, src, n); /* ASCII CP */
261 }
262
263 /*********************************************************************
264  *              _mbscmp(MSVCRT.@)
265  */
266 int _mbscmp(const unsigned char* str, const unsigned char* cmp)
267 {
268   if(MSVCRT___mb_cur_max > 1)
269   {
270     unsigned int strc, cmpc;
271     do {
272       if(!*str)
273         return *cmp ? -1 : 0;
274       if(!*cmp)
275         return 1;
276       strc = _mbsnextc(str);
277       cmpc = _mbsnextc(cmp);
278       if(strc != cmpc)
279         return strc < cmpc ? -1 : 1;
280       str +=(strc > 255) ? 2 : 1;
281       cmp +=(strc > 255) ? 2 : 1; /* equal, use same increment */
282     } while(1);
283   }
284   return strcmp(str, cmp); /* ASCII CP */
285 }
286
287 /*********************************************************************
288  *              _mbsicmp(MSVCRT.@)
289  */
290 int _mbsicmp(const unsigned char* str, const unsigned char* cmp)
291 {
292   if(MSVCRT___mb_cur_max > 1)
293   {
294     unsigned int strc, cmpc;
295     do {
296       if(!*str)
297         return *cmp ? -1 : 0;
298       if(!*cmp)
299         return 1;
300       strc = _mbctolower(_mbsnextc(str));
301       cmpc = _mbctolower(_mbsnextc(cmp));
302       if(strc != cmpc)
303         return strc < cmpc ? -1 : 1;
304       str +=(strc > 255) ? 2 : 1;
305       cmp +=(strc > 255) ? 2 : 1; /* equal, use same increment */
306     } while(1);
307   }
308   return strcasecmp(str, cmp); /* ASCII CP */
309 }
310
311 /*********************************************************************
312  *              _mbsncmp(MSVCRT.@)
313  */
314 int _mbsncmp(const unsigned char* str, const unsigned char* cmp, MSVCRT_size_t len)
315 {
316   if(!len)
317     return 0;
318
319   if(MSVCRT___mb_cur_max > 1)
320   {
321     unsigned int strc, cmpc;
322     while(len--)
323     {
324       int inc;
325       if(!*str)
326         return *cmp ? -1 : 0;
327       if(!*cmp)
328         return 1;
329       strc = _mbsnextc(str);
330       cmpc = _mbsnextc(cmp);
331       if(strc != cmpc)
332         return strc < cmpc ? -1 : 1;
333       inc=(strc > 255) ? 2 : 1; /* Equal, use same increment */
334       str += inc;
335       cmp += inc;
336     }
337     return 0; /* Matched len chars */
338   }
339   return strncmp(str, cmp, len); /* ASCII CP */
340 }
341
342 /*********************************************************************
343  *              _mbsnbcmp(MSVCRT.@)
344  */
345 int _mbsnbcmp(const unsigned char* str, const unsigned char* cmp, MSVCRT_size_t len)
346 {
347   if (!len)
348     return 0;
349   if(MSVCRT___mb_cur_max > 1)
350   {
351     unsigned int strc, cmpc;
352     while (len)
353     {
354       int clen;
355       if(!*str)
356         return *cmp ? -1 : 0;
357       if(!*cmp)
358         return 1;
359       if (MSVCRT_isleadbyte(*str))
360       {
361         strc=(len>=2)?_mbsnextc(str):0;
362         clen=2;
363       }
364       else
365       {
366         strc=*str;
367         clen=1;
368       }
369       if (MSVCRT_isleadbyte(*cmp))
370         cmpc=(len>=2)?_mbsnextc(cmp):0;
371       else
372         cmpc=*str;
373       if(strc != cmpc)
374         return strc < cmpc ? -1 : 1;
375       len -= clen;
376       str += clen;
377       cmp += clen;
378     }
379     return 0; /* Matched len chars */
380       FIXME("%s %s %d\n",str,cmp,len);
381   }
382   return strncmp(str,cmp,len);
383 }
384
385 /*********************************************************************
386  *              _mbsnicmp(MSVCRT.@)
387  *
388  * Compare two multibyte strings case insensitively to 'len' characters.
389  */
390 int _mbsnicmp(const unsigned char* str, const unsigned char* cmp, MSVCRT_size_t len)
391 {
392   /* FIXME: No tolower() for mb strings yet */
393   if(MSVCRT___mb_cur_max > 1)
394   {
395     unsigned int strc, cmpc;
396     while(len--)
397     {
398       if(!*str)
399         return *cmp ? -1 : 0;
400       if(!*cmp)
401         return 1;
402       strc = _mbctolower(_mbsnextc(str));
403       cmpc = _mbctolower(_mbsnextc(cmp));
404       if(strc != cmpc)
405         return strc < cmpc ? -1 : 1;
406       str +=(strc > 255) ? 2 : 1;
407       cmp +=(strc > 255) ? 2 : 1; /* Equal, use same increment */
408     }
409     return 0; /* Matched len chars */
410   }
411   return strncasecmp(str, cmp, len); /* ASCII CP */
412 }
413
414 /*********************************************************************
415  *              _mbschr(MSVCRT.@)
416  *
417  * Find a multibyte character in a multibyte string.
418  */
419 unsigned char* _mbschr(const unsigned char* s, unsigned int x)
420 {
421   if(MSVCRT___mb_cur_max > 1)
422   {
423     unsigned int c;
424     while (1)
425     {
426       c = _mbsnextc(s);
427       if (c == x)
428         return (unsigned char*)s;
429       if (!c)
430         return NULL;
431       s += c > 255 ? 2 : 1;
432     }
433   }
434   return strchr(s, x); /* ASCII CP */
435 }
436
437 /*********************************************************************
438  *              _mbsrchr(MSVCRT.@)
439  */
440 unsigned char* _mbsrchr(const unsigned char* s, unsigned int x)
441 {
442   if(MSVCRT___mb_cur_max > 1)
443   {
444     unsigned int c;
445     unsigned char* match=NULL;
446     if(!s)
447       return NULL;
448     while (1) {
449       c = _mbsnextc(s);
450       if (c == x)
451         match=(unsigned char*)s;
452       if (!c)
453         return match;
454       s +=(c > 255) ? 2 : 1;
455     }
456   }
457   return strrchr(s,x);
458 }
459
460 /*********************************************************************
461  *              mbtowc(MSVCRT.@)
462  */
463 int MSVCRT_mbtowc(WCHAR *dst, const char* str, MSVCRT_size_t n)
464 {
465   if(n <= 0 || !str)
466     return 0;
467   if(!MultiByteToWideChar(CP_ACP, 0, str, n, dst, 1))
468     return 0;
469   /* return the number of bytes from src that have been used */
470   if(!*str)
471     return 0;
472   if(n >= 2 && MSVCRT_isleadbyte(*str) && str[1])
473     return 2;
474   return 1;
475 }
476
477 /*********************************************************************
478  *              _mbbtombc(MSVCRT.@)
479  */
480 unsigned int _mbbtombc(unsigned int c)
481 {
482   if(MSVCRT___mb_cur_max > 1 &&
483      ((c >= 0x20 && c <=0x7e) ||(c >= 0xa1 && c <= 0xdf)))
484   {
485     /* FIXME: I can't get this function to return anything
486      * different to what I pass it...
487      */
488   }
489   return c;  /* ASCII CP or no MB char */
490 }
491
492 /*********************************************************************
493  *              _ismbbkana(MSVCRT.@)
494  */
495 int _ismbbkana(unsigned int c)
496 {
497   /* FIXME: use lc_ctype when supported, not lc_all */
498   if(MSVCRT_current_lc_all_cp == 932)
499   {
500     /* Japanese/Katakana, CP 932 */
501     return (c >= 0xa1 && c <= 0xdf);
502   }
503   return 0;
504 }
505
506 /*********************************************************************
507  *              _ismbcdigit(MSVCRT.@)
508  */
509 int _ismbcdigit(unsigned int ch)
510 {
511   if (ch <0x100)
512     return isdigit(ch);
513   else
514     {
515       FIXME("Handle MBC chars\n");
516       return 0;
517     }
518 }
519
520 /*********************************************************************
521  *              _ismbcspace (MSVCRT.@)
522  */
523 int _ismbcspace(unsigned int c)
524 {
525
526   if (c<0x100)
527     return isspace(c);
528   FIXME("%c\n",c);
529   return 0;
530 }
531
532 /*********************************************************************
533  *              _ismbchira(MSVCRT.@)
534  */
535 int _ismbchira(unsigned int c)
536 {
537   /* FIXME: use lc_ctype when supported, not lc_all */
538   if(MSVCRT_current_lc_all_cp == 932)
539   {
540     /* Japanese/Hiragana, CP 932 */
541     return (c >= 0x829f && c <= 0x82f1);
542   }
543   return 0;
544 }
545
546 /*********************************************************************
547  *              _ismbckata(MSVCRT.@)
548  */
549 int _ismbckata(unsigned int c)
550 {
551   /* FIXME: use lc_ctype when supported, not lc_all */
552   if(MSVCRT_current_lc_all_cp == 932)
553   {
554     if(c < 256)
555       return _ismbbkana(c);
556     /* Japanese/Katakana, CP 932 */
557     return (c >= 0x8340 && c <= 0x8396 && c != 0x837f);
558   }
559   return 0;
560 }
561
562 /*********************************************************************
563  *              _ismbblead(MSVCRT.@)
564  */
565 int _ismbblead(unsigned int c)
566 {
567   /* FIXME: should reference MSVCRT_mbctype */
568   return MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(c);
569 }
570
571
572 /*********************************************************************
573  *              _ismbbtrail(MSVCRT.@)
574  */
575 int _ismbbtrail(unsigned int c)
576 {
577   /* FIXME: should reference MSVCRT_mbctype */
578   return !_ismbblead(c);
579 }
580
581 /*********************************************************************
582  *              _ismbslead(MSVCRT.@)
583  */
584 int _ismbslead(const unsigned char* start, const unsigned char* str)
585 {
586   /* Lead bytes can also be trail bytes if caller messed up
587    * iterating through the string...
588    */
589   if(MSVCRT___mb_cur_max > 1)
590   {
591     while(start < str)
592       start += MSVCRT_isleadbyte(*str) ? 2 : 1;
593
594     if(start == str)
595       return MSVCRT_isleadbyte(*str);
596   }
597   return 0; /* Must have been a trail, we skipped it */
598 }
599
600 /*********************************************************************
601  *              _ismbstrail(MSVCRT.@)
602  */
603 int _ismbstrail(const unsigned char* start, const unsigned char* str)
604 {
605   /* Must not be a lead, and must be preceeded by one */
606   return !_ismbslead(start, str) && MSVCRT_isleadbyte(str[-1]);
607 }
608
609 /*********************************************************************
610  *              _mbsset(MSVCRT.@)
611  */
612 unsigned char* _mbsset(unsigned char* str, unsigned int c)
613 {
614   unsigned char* ret = str;
615
616   if(MSVCRT___mb_cur_max == 1 || c < 256)
617     return _strset(str, c); /* ASCII CP or SB char */
618
619   c &= 0xffff; /* Strip high bits */
620
621   while(str[0] && str[1])
622   {
623     *str++ = c >> 8;
624     *str++ = c & 0xff;
625   }
626   if(str[0])
627     str[0] = '\0'; /* FIXME: OK to shorten? */
628
629   return ret;
630 }
631
632 /*********************************************************************
633  *              _mbsnset(MSVCRT.@)
634  */
635 unsigned char* _mbsnset(unsigned char* str, unsigned int c, MSVCRT_size_t len)
636 {
637   unsigned char *ret = str;
638
639   if(!len)
640     return ret;
641
642   if(MSVCRT___mb_cur_max == 1 || c < 256)
643     return _strnset(str, c, len); /* ASCII CP or SB char */
644
645   c &= 0xffff; /* Strip high bits */
646
647   while(str[0] && str[1] && len--)
648   {
649     *str++ = c >> 8;
650     *str++ = c & 0xff;
651   }
652   if(len && str[0])
653     str[0] = '\0'; /* FIXME: OK to shorten? */
654
655   return ret;
656 }
657
658 /*********************************************************************
659  *              _mbsnccnt(MSVCRT.@)
660  * 'c' is for 'character'.
661  */
662 MSVCRT_size_t _mbsnccnt(const unsigned char* str, MSVCRT_size_t len)
663 {
664   MSVCRT_size_t ret;
665   if(MSVCRT___mb_cur_max > 1)
666   {
667     ret=0;
668     while(*str && len-- > 0)
669     {
670       if(MSVCRT_isleadbyte(*str))
671       {
672         if (!len)
673           break;
674         len--;
675         str++;
676       }
677       str++;
678       ret++;
679     }
680     return ret;
681   }
682   ret=strlen(str);
683   return min(ret, len); /* ASCII CP */
684 }
685
686 /*********************************************************************
687  *              _mbsnbcnt(MSVCRT.@)
688  * 'b' is for byte count.
689  */
690 MSVCRT_size_t _mbsnbcnt(const unsigned char* str, MSVCRT_size_t len)
691 {
692   MSVCRT_size_t ret;
693   if(MSVCRT___mb_cur_max > 1)
694   {
695     const unsigned char* xstr = str;
696     while(*xstr && len-- > 0)
697     {
698       if (MSVCRT_isleadbyte(*xstr++))
699         xstr++;
700     }
701     return xstr-str;
702   }
703   ret=strlen(str);
704   return min(ret, len); /* ASCII CP */
705 }
706
707
708 /*********************************************************************
709  *              _mbsncat(MSVCRT.@)
710  */
711 unsigned char* _mbsncat(unsigned char* dst, const unsigned char* src, MSVCRT_size_t len)
712 {
713   if(MSVCRT___mb_cur_max > 1)
714   {
715     char *res = dst;
716     while (*dst)
717     {
718       if (MSVCRT_isleadbyte(*dst++))
719         dst++;
720     }
721     while (*src && len--)
722     {
723       *dst++ = *src;
724       if(MSVCRT_isleadbyte(*src++))
725         *dst++ = *src++;
726     }
727     *dst = '\0';
728     return res;
729   }
730   return strncat(dst, src, len); /* ASCII CP */
731 }
732
733
734 /*********************************************************************
735  *              _mbslwr(MSVCRT.@)
736  */
737 unsigned char* _mbslwr(unsigned char* s)
738 {
739   if (!s)
740     return NULL;
741   if (MSVCRT___mb_cur_max > 1)
742   {
743     unsigned int c;
744     unsigned char* p=s;
745     while (*s)
746     {
747       c = _mbctolower(_mbsnextc(s));
748       /* Note that I assume that the size of the character is unchanged */
749       if (c > 255)
750       {
751           *s++=(c>>8);
752           c=c & 0xff;
753       }
754       *s++=c;
755     }
756     return p;
757   }
758   return _strlwr(s);
759 }
760
761
762 /*********************************************************************
763  *              _mbsupr(MSVCRT.@)
764  */
765 unsigned char* _mbsupr(unsigned char* s)
766 {
767   if (!s)
768     return NULL;
769   if (MSVCRT___mb_cur_max > 1)
770   {
771     unsigned int c;
772     unsigned char* p=s;
773     while (*s)
774     {
775       c = _mbctoupper(_mbsnextc(s));
776       /* Note that I assume that the size of the character is unchanged */
777       if (c > 255)
778       {
779           *s++=(c>>8);
780           c=c & 0xff;
781       }
782       *s++=c;
783     }
784     return p;
785   }
786   return _strupr(s);
787 }
788
789
790 /*********************************************************************
791  *              _mbsspn (MSVCRT.@)
792  */
793 MSVCRT_size_t _mbsspn(const unsigned char* string, const unsigned char* set)
794 {
795   const unsigned char *p, *q;
796
797   for (p = string; *p; p++)
798     {
799       if (MSVCRT_isleadbyte(*p))
800         {
801           for (q = set; *q; q++)
802             {
803               if (!q[1])
804                 break;
805               if ((*p == *q) &&  (p[1] == q[1]))
806                 break;
807               q++;
808             }
809           if (*++p == '\0')
810             break;
811         }
812       else
813         for (q = set; *q; q++)
814           if (*p == *q)
815             break;
816     }
817   return p - string;
818 }
819
820 /*********************************************************************
821  *              _mbscspn(MSVCRT.@)
822  */
823 MSVCRT_size_t _mbscspn(const unsigned char* str, const unsigned char* cmp)
824 {
825   if (MSVCRT___mb_cur_max > 1)
826     FIXME("don't handle double character case\n");
827   return strcspn(str, cmp);
828 }
829
830 /*********************************************************************
831  *              _mbsrev (MSVCRT.@)
832  */
833 unsigned char* _mbsrev(unsigned char* str)
834 {
835     int i, len = _mbslen(str);
836     unsigned char *p, *temp=MSVCRT_malloc(len*2);
837
838     if(!temp)
839         return str;
840
841     /* unpack multibyte string to temp buffer */
842     p=str;
843     for(i=0; i<len; i++)
844     {
845         if (MSVCRT_isleadbyte(*p))
846         {
847             temp[i*2]=*p++;
848             temp[i*2+1]=*p++;
849         }
850         else
851         {
852             temp[i*2]=*p++;
853             temp[i*2+1]=0;
854         }
855     }
856
857     /* repack it in the reverse order */
858     p=str;
859     for(i=len-1; i>=0; i--)
860     {
861         if(MSVCRT_isleadbyte(temp[i*2]))
862         {
863             *p++=temp[i*2];
864             *p++=temp[i*2+1];
865         }
866         else
867         {
868             *p++=temp[i*2];
869         }
870     }
871
872     MSVCRT_free(temp);
873
874     return str;
875 }
876
877 /*********************************************************************
878  *              _mbspbrk (MSVCRT.@)
879  */
880 unsigned char* _mbspbrk(const unsigned char* str, const unsigned char* accept)
881 {
882     const unsigned char* p;
883
884     while(*str)
885     {
886         for(p = accept; *p; p += (MSVCRT_isleadbyte(*p)?2:1) )
887         {
888             if (*p == *str)
889                 if( !MSVCRT_isleadbyte(*p) || ( *(p+1) == *(str+1) ) )
890                      return (unsigned char*)str;
891         }
892         str += (MSVCRT_isleadbyte(*str)?2:1);
893     }
894     return NULL;
895 }
896