source: trunk/src/kernel32/unicode/string.c@ 21329

Last change on this file since 21329 was 21329, checked in by vladest, 16 years ago

Added functionality, required for Flash10 to kernel32

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
14int 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
25int 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
33WCHAR *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
48long 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
167unsigned 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
278int 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
397int 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
407int 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.