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