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