source: trunk/lib/unicode/string.c@ 22145

Last change on this file since 22145 was 21927, checked in by dmik, 14 years ago

Fix build breaks with the newest GCC 4.4.6 from GIT.

In particular, GCC is now strict about matching the calling convention
of the prototype (argument) and the real function used.

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