Moved libwine_unicode to the libs/ directory.
[wine] / libs / unicode / string.c
1 /*
2  * Unicode string manipulation functions
3  *
4  * Copyright 2000 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <limits.h>
22 #include <stdio.h>
23
24 #include "wine/unicode.h"
25
26 int strcmpiW( const WCHAR *str1, const WCHAR *str2 )
27 {
28     for (;;)
29     {
30         int ret = toupperW(*str1) - toupperW(*str2);
31         if (ret || !*str1) return ret;
32         str1++;
33         str2++;
34     }
35 }
36
37 int strncmpiW( const WCHAR *str1, const WCHAR *str2, int n )
38 {
39     int ret = 0;
40     for ( ; n > 0; n--, str1++, str2++)
41         if ((ret = toupperW(*str1) - toupperW(*str2)) || !*str1) break;
42     return ret;
43 }
44
45 WCHAR *strstrW( const WCHAR *str, const WCHAR *sub )
46 {
47     while (*str)
48     {
49         const WCHAR *p1 = str, *p2 = sub;
50         while (*p1 && *p2 && *p1 == *p2) { p1++; p2++; }
51         if (!*p2) return (WCHAR *)str;
52         str++;
53     }
54     return NULL;
55 }
56
57 /* strtolW and strtoulW implementation based on the GNU C library code */
58 /* Copyright (C) 1991,92,94,95,96,97,98,99,2000,2001 Free Software Foundation, Inc. */
59
60 long int strtolW( const WCHAR *nptr, WCHAR **endptr, int base )
61 {
62   int negative;
63   register unsigned long int cutoff;
64   register unsigned int cutlim;
65   register unsigned long int i;
66   register const WCHAR *s;
67   register WCHAR c;
68   const WCHAR *save, *end;
69   int overflow;
70
71   if (base < 0 || base == 1 || base > 36) return 0;
72
73   save = s = nptr;
74
75   /* Skip white space.  */
76   while (isspaceW (*s))
77     ++s;
78   if (!*s) goto noconv;
79
80   /* Check for a sign.  */
81   negative = 0;
82   if (*s == '-')
83     {
84       negative = 1;
85       ++s;
86     }
87   else if (*s == '+')
88     ++s;
89
90   /* Recognize number prefix and if BASE is zero, figure it out ourselves.  */
91   if (*s == '0')
92     {
93       if ((base == 0 || base == 16) && toupperW(s[1]) == 'X')
94         {
95           s += 2;
96           base = 16;
97         }
98       else if (base == 0)
99         base = 8;
100     }
101   else if (base == 0)
102     base = 10;
103
104   /* Save the pointer so we can check later if anything happened.  */
105   save = s;
106   end = NULL;
107
108   cutoff = ULONG_MAX / (unsigned long int) base;
109   cutlim = ULONG_MAX % (unsigned long int) base;
110
111   overflow = 0;
112   i = 0;
113   c = *s;
114   for (;c != '\0'; c = *++s)
115   {
116       if (s == end)
117           break;
118       if (c >= '0' && c <= '9')
119           c -= '0';
120       else if (isalphaW (c))
121           c = toupperW (c) - 'A' + 10;
122       else
123           break;
124       if ((int) c >= base)
125           break;
126       /* Check for overflow.  */
127       if (i > cutoff || (i == cutoff && c > cutlim))
128           overflow = 1;
129       else
130       {
131           i *= (unsigned long int) base;
132           i += c;
133       }
134   }
135
136   /* Check if anything actually happened.  */
137   if (s == save)
138     goto noconv;
139
140   /* Store in ENDPTR the address of one character
141      past the last character we converted.  */
142   if (endptr != NULL)
143     *endptr = (WCHAR *)s;
144
145   /* Check for a value that is within the range of
146      `unsigned LONG int', but outside the range of `LONG int'.  */
147   if (overflow == 0
148       && i > (negative
149               ? -((unsigned long int) (LONG_MIN + 1)) + 1
150               : (unsigned long int) LONG_MAX))
151     overflow = 1;
152
153   if (overflow)
154     {
155       return negative ? LONG_MIN : LONG_MAX;
156     }
157
158   /* Return the result of the appropriate sign.  */
159   return negative ? -i : i;
160
161 noconv:
162   /* We must handle a special case here: the base is 0 or 16 and the
163      first two characters are '0' and 'x', but the rest are no
164      hexadecimal digits.  This is no error case.  We return 0 and
165      ENDPTR points to the `x`.  */
166   if (endptr != NULL)
167     {
168       if (save - nptr >= 2 && toupperW (save[-1]) == 'X'
169           && save[-2] == '0')
170         *endptr = (WCHAR *)&save[-1];
171       else
172         /*  There was no number to convert.  */
173         *endptr = (WCHAR *)nptr;
174     }
175
176   return 0L;
177 }
178
179
180 unsigned long int strtoulW( const WCHAR *nptr, WCHAR **endptr, int base )
181 {
182   int negative;
183   register unsigned long int cutoff;
184   register unsigned int cutlim;
185   register unsigned long int i;
186   register const WCHAR *s;
187   register WCHAR c;
188   const WCHAR *save, *end;
189   int overflow;
190
191   if (base < 0 || base == 1 || base > 36) return 0;
192
193   save = s = nptr;
194
195   /* Skip white space.  */
196   while (isspaceW (*s))
197     ++s;
198   if (!*s) goto noconv;
199
200   /* Check for a sign.  */
201   negative = 0;
202   if (*s == '-')
203     {
204       negative = 1;
205       ++s;
206     }
207   else if (*s == '+')
208     ++s;
209
210   /* Recognize number prefix and if BASE is zero, figure it out ourselves.  */
211   if (*s == '0')
212     {
213       if ((base == 0 || base == 16) && toupperW(s[1]) == 'X')
214         {
215           s += 2;
216           base = 16;
217         }
218       else if (base == 0)
219         base = 8;
220     }
221   else if (base == 0)
222     base = 10;
223
224   /* Save the pointer so we can check later if anything happened.  */
225   save = s;
226   end = NULL;
227
228   cutoff = ULONG_MAX / (unsigned long int) base;
229   cutlim = ULONG_MAX % (unsigned long int) base;
230
231   overflow = 0;
232   i = 0;
233   c = *s;
234   for (;c != '\0'; c = *++s)
235   {
236       if (s == end)
237           break;
238       if (c >= '0' && c <= '9')
239           c -= '0';
240       else if (isalphaW (c))
241           c = toupperW (c) - 'A' + 10;
242       else
243           break;
244       if ((int) c >= base)
245           break;
246       /* Check for overflow.  */
247       if (i > cutoff || (i == cutoff && c > cutlim))
248           overflow = 1;
249       else
250       {
251           i *= (unsigned long int) base;
252           i += c;
253       }
254   }
255
256   /* Check if anything actually happened.  */
257   if (s == save)
258     goto noconv;
259
260   /* Store in ENDPTR the address of one character
261      past the last character we converted.  */
262   if (endptr != NULL)
263     *endptr = (WCHAR *)s;
264
265   if (overflow)
266     {
267       return ULONG_MAX;
268     }
269
270   /* Return the result of the appropriate sign.  */
271   return negative ? -i : i;
272
273 noconv:
274   /* We must handle a special case here: the base is 0 or 16 and the
275      first two characters are '0' and 'x', but the rest are no
276      hexadecimal digits.  This is no error case.  We return 0 and
277      ENDPTR points to the `x`.  */
278   if (endptr != NULL)
279     {
280       if (save - nptr >= 2 && toupperW (save[-1]) == 'X'
281           && save[-2] == '0')
282         *endptr = (WCHAR *)&save[-1];
283       else
284         /*  There was no number to convert.  */
285         *endptr = (WCHAR *)nptr;
286     }
287
288   return 0L;
289 }
290
291
292 int vsnprintfW(WCHAR *str, size_t len, const WCHAR *format, va_list valist)
293 {
294     unsigned int written = 0;
295     const WCHAR *iter = format;
296     char bufa[256], fmtbufa[64], *fmta;
297
298     while (*iter)
299     {
300         while (*iter && *iter != '%')
301         {
302             if (written++ >= len)
303                 return -1;
304             *str++ = *iter++;
305         }
306         if (*iter == '%')
307         {
308             fmta = fmtbufa;
309             *fmta++ = *iter++;
310             while (*iter == '0' ||
311                    *iter == '+' ||
312                    *iter == '-' ||
313                    *iter == ' ' ||
314                    *iter == '0' ||
315                    *iter == '*' ||
316                    *iter == '#')
317             {
318                 if (*iter == '*')
319                 {
320                     char *buffiter = bufa;
321                     int fieldlen = va_arg(valist, int);
322                     sprintf(buffiter, "%d", fieldlen);
323                     while (*buffiter)
324                         *fmta++ = *buffiter++;
325                 }
326                 else
327                     *fmta++ = *iter;
328                 iter++;
329             }
330
331             while (isdigit(*iter))
332                 *fmta++ = *iter++;
333
334             if (*iter == '.')
335             {
336                 *fmta++ = *iter++;
337                 if (*iter == '*')
338                 {
339                     char *buffiter = bufa;
340                     int fieldlen = va_arg(valist, int);
341                     sprintf(buffiter, "%d", fieldlen);
342                     while (*buffiter)
343                         *fmta++ = *buffiter++;
344                 }
345                 else
346                     while (isdigit(*iter))
347                         *fmta++ = *iter++;
348             }
349             if (*iter == 'h' || *iter == 'l')
350                 *fmta++ = *iter++;
351
352             switch (*iter)
353             {
354             case 's':
355             {
356                 static const WCHAR none[] = { '(','n','u','l','l',')',0 };
357                 const WCHAR *wstr = va_arg(valist, const WCHAR *);
358                 const WCHAR *striter = wstr ? wstr : none;
359                 while (*striter)
360                 {
361                     if (written++ >= len)
362                         return -1;
363                     *str++ = *striter++;
364                 }
365                 iter++;
366                 break;
367             }
368
369             case 'c':
370                 if (written++ >= len)
371                     return -1;
372                 *str++ = (WCHAR)va_arg(valist, int);
373                 iter++;
374                 break;
375
376             default:
377             {
378                 /* For non wc types, use system sprintf and append to wide char output */
379                 /* FIXME: for unrecognised types, should ignore % when printing */
380                 char *bufaiter = bufa;
381                 if (*iter == 'p')
382                     sprintf(bufaiter, "%08lX", va_arg(valist, long));
383                 else
384                 {
385                     *fmta++ = *iter;
386                     *fmta = '\0';
387                     if (*iter == 'f')
388                         sprintf(bufaiter, fmtbufa, va_arg(valist, double));
389                     else
390                         sprintf(bufaiter, fmtbufa, va_arg(valist, void *));
391                 }
392                 while (*bufaiter)
393                 {
394                     if (written++ >= len)
395                         return -1;
396                     *str++ = *bufaiter++;
397                 }
398                 iter++;
399                 break;
400             }
401             }
402         }
403     }
404     if (written >= len)
405         return -1;
406     *str++ = 0;
407     return (int)written;
408 }
409
410 int vsprintfW( WCHAR *str, const WCHAR *format, va_list valist )
411 {
412     return vsnprintfW( str, INT_MAX, format, valist );
413 }
414
415 int snprintfW( WCHAR *str, size_t len, const WCHAR *format, ...)
416 {
417     int retval;
418     va_list valist;
419     va_start(valist, format);
420     retval = vsnprintfW(str, len, format, valist);
421     va_end(valist);
422     return retval;
423 }
424
425 int sprintfW( WCHAR *str, const WCHAR *format, ...)
426 {
427     int retval;
428     va_list valist;
429     va_start(valist, format);
430     retval = vsnprintfW(str, INT_MAX, format, valist);
431     va_end(valist);
432     return retval;
433 }