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