Added a small test for process exit code retrieval.
[wine.git] / ole / ole2nls.c
bloba812f0be25ae095173304255bfa8a7ec40f3b592
1 /*
2 * National Language Support library
4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 David Lee Lambert
6 * Copyright 2000 Julio César Gázquez
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "config.h"
24 #include "wine/port.h"
26 #include <string.h>
27 #include <stdio.h>
28 #include <ctype.h>
29 #include <stdlib.h>
30 #include <locale.h>
32 #include "windef.h"
33 #include "winbase.h"
34 #include "wingdi.h"
35 #include "winuser.h"
36 #include "winternl.h"
37 #include "wine/unicode.h"
38 #include "winver.h"
39 #include "winnls.h"
40 #include "winreg.h"
41 #include "winerror.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(nls);
47 static const unsigned char LCM_Unicode_LUT[] = {
48 6 , 3, /* - 1 */
49 6 , 4, /* - 2 */
50 6 , 5, /* - 3 */
51 6 , 6, /* - 4 */
52 6 , 7, /* - 5 */
53 6 , 8, /* - 6 */
54 6 , 9, /* - 7 */
55 6 , 10, /* - 8 */
56 7 , 5, /* - 9 */
57 7 , 6, /* - 10 */
58 7 , 7, /* - 11 */
59 7 , 8, /* - 12 */
60 7 , 9, /* - 13 */
61 6 , 11, /* - 14 */
62 6 , 12, /* - 15 */
63 6 , 13, /* - 16 */
64 6 , 14, /* - 17 */
65 6 , 15, /* - 18 */
66 6 , 16, /* - 19 */
67 6 , 17, /* - 20 */
68 6 , 18, /* - 21 */
69 6 , 19, /* - 22 */
70 6 , 20, /* - 23 */
71 6 , 21, /* - 24 */
72 6 , 22, /* - 25 */
73 6 , 23, /* - 26 */
74 6 , 24, /* - 27 */
75 6 , 25, /* - 28 */
76 6 , 26, /* - 29 */
77 6 , 27, /* - 30 */
78 6 , 28, /* - 31 */
79 7 , 2, /* - 32 */
80 7 , 28, /* ! - 33 */
81 7 , 29, /* " - 34 */ /* " */
82 7 , 31, /* # - 35 */
83 7 , 33, /* $ - 36 */
84 7 , 35, /* % - 37 */
85 7 , 37, /* & - 38 */
86 6 , 128, /* ' - 39 */
87 7 , 39, /* ( - 40 */
88 7 , 42, /* ) - 41 */
89 7 , 45, /* * - 42 */
90 8 , 3, /* + - 43 */
91 7 , 47, /* , - 44 */
92 6 , 130, /* - - 45 */
93 7 , 51, /* . - 46 */
94 7 , 53, /* / - 47 */
95 12 , 3, /* 0 - 48 */
96 12 , 33, /* 1 - 49 */
97 12 , 51, /* 2 - 50 */
98 12 , 70, /* 3 - 51 */
99 12 , 88, /* 4 - 52 */
100 12 , 106, /* 5 - 53 */
101 12 , 125, /* 6 - 54 */
102 12 , 144, /* 7 - 55 */
103 12 , 162, /* 8 - 56 */
104 12 , 180, /* 9 - 57 */
105 7 , 55, /* : - 58 */
106 7 , 58, /* ; - 59 */
107 8 , 14, /* < - 60 */
108 8 , 18, /* = - 61 */
109 8 , 20, /* > - 62 */
110 7 , 60, /* ? - 63 */
111 7 , 62, /* @ - 64 */
112 14 , 2, /* A - 65 */
113 14 , 9, /* B - 66 */
114 14 , 10, /* C - 67 */
115 14 , 26, /* D - 68 */
116 14 , 33, /* E - 69 */
117 14 , 35, /* F - 70 */
118 14 , 37, /* G - 71 */
119 14 , 44, /* H - 72 */
120 14 , 50, /* I - 73 */
121 14 , 53, /* J - 74 */
122 14 , 54, /* K - 75 */
123 14 , 72, /* L - 76 */
124 14 , 81, /* M - 77 */
125 14 , 112, /* N - 78 */
126 14 , 124, /* O - 79 */
127 14 , 126, /* P - 80 */
128 14 , 137, /* Q - 81 */
129 14 , 138, /* R - 82 */
130 14 , 145, /* S - 83 */
131 14 , 153, /* T - 84 */
132 14 , 159, /* U - 85 */
133 14 , 162, /* V - 86 */
134 14 , 164, /* W - 87 */
135 14 , 166, /* X - 88 */
136 14 , 167, /* Y - 89 */
137 14 , 169, /* Z - 90 */
138 7 , 63, /* [ - 91 */
139 7 , 65, /* \ - 92 */
140 7 , 66, /* ] - 93 */
141 7 , 67, /* ^ - 94 */
142 7 , 68, /* _ - 95 */
143 7 , 72, /* ` - 96 */
144 14 , 2, /* a - 97 */
145 14 , 9, /* b - 98 */
146 14 , 10, /* c - 99 */
147 14 , 26, /* d - 100 */
148 14 , 33, /* e - 101 */
149 14 , 35, /* f - 102 */
150 14 , 37, /* g - 103 */
151 14 , 44, /* h - 104 */
152 14 , 50, /* i - 105 */
153 14 , 53, /* j - 106 */
154 14 , 54, /* k - 107 */
155 14 , 72, /* l - 108 */
156 14 , 81, /* m - 109 */
157 14 , 112, /* n - 110 */
158 14 , 124, /* o - 111 */
159 14 , 126, /* p - 112 */
160 14 , 137, /* q - 113 */
161 14 , 138, /* r - 114 */
162 14 , 145, /* s - 115 */
163 14 , 153, /* t - 116 */
164 14 , 159, /* u - 117 */
165 14 , 162, /* v - 118 */
166 14 , 164, /* w - 119 */
167 14 , 166, /* x - 120 */
168 14 , 167, /* y - 121 */
169 14 , 169, /* z - 122 */
170 7 , 74, /* { - 123 */
171 7 , 76, /* | - 124 */
172 7 , 78, /* } - 125 */
173 7 , 80, /* ~ - 126 */
174 6 , 29, /* \x7f - 127 */
175 6 , 30, /* € - 128 */
176 6 , 31, /* � - 129 */
177 7 , 123, /* ‚ - 130 */
178 14 , 35, /* ƒ - 131 */
179 7 , 127, /* „ - 132 */
180 10 , 21, /* … - 133 */
181 10 , 15, /* † - 134 */
182 10 , 16, /* ‡ - 135 */
183 7 , 67, /* ˆ - 136 */
184 10 , 22, /* ‰ - 137 */
185 14 , 145, /* Š - 138 */
186 7 , 136, /* ‹ - 139 */
187 14 + 16 , 124, /* Œ - 140 */
188 6 , 43, /* � - 141 */
189 6 , 44, /* Ž - 142 */
190 6 , 45, /* � - 143 */
191 6 , 46, /* � - 144 */
192 7 , 121, /* ‘ - 145 */
193 7 , 122, /* ’ - 146 */
194 7 , 125, /* “ - 147 */
195 7 , 126, /* ” - 148 */
196 10 , 17, /* • - 149 */
197 6 , 137, /* – - 150 */
198 6 , 139, /* — - 151 */
199 7 , 93, /* ˜ - 152 */
200 14 , 156, /* ™ - 153 */
201 14 , 145, /* š - 154 */
202 7 , 137, /* › - 155 */
203 14 + 16 , 124, /* œ - 156 */
204 6 , 59, /* � - 157 */
205 6 , 60, /* ž - 158 */
206 14 , 167, /* Ÿ - 159 */
207 7 , 4, /*   - 160 */
208 7 , 81, /* ¡ - 161 */
209 10 , 2, /* ¢ - 162 */
210 10 , 3, /* £ - 163 */
211 10 , 4, /* ¤ - 164 */
212 10 , 5, /* ¥ - 165 */
213 7 , 82, /* ¦ - 166 */
214 10 , 6, /* § - 167 */
215 7 , 83, /* ¨ - 168 */
216 10 , 7, /* © - 169 */
217 14 , 2, /* ª - 170 */
218 8 , 24, /* « - 171 */
219 10 , 8, /* ¬ - 172 */
220 6 , 131, /* ­ - 173 */
221 10 , 9, /* ® - 174 */
222 7 , 84, /* ¯ - 175 */
223 10 , 10, /* ° - 176 */
224 8 , 23, /* ± - 177 */
225 12 , 51, /* ² - 178 */
226 12 , 70, /* ³ - 179 */
227 7 , 85, /* ´ - 180 */
228 10 , 11, /* µ - 181 */
229 10 , 12, /* ¶ - 182 */
230 10 , 13, /* · - 183 */
231 7 , 86, /* ¸ - 184 */
232 12 , 33, /* ¹ - 185 */
233 14 , 124, /* º - 186 */
234 8 , 26, /* » - 187 */
235 12 , 21, /* ¼ - 188 */
236 12 , 25, /* ½ - 189 */
237 12 , 29, /* ¾ - 190 */
238 7 , 87, /* ¿ - 191 */
239 14 , 2, /* À - 192 */
240 14 , 2, /* Á - 193 */
241 14 , 2, /* Â - 194 */
242 14 , 2, /* Ã - 195 */
243 14 , 2, /* Ä - 196 */
244 14 , 2, /* Å - 197 */
245 14 + 16 , 2, /* Æ - 198 */
246 14 , 10, /* Ç - 199 */
247 14 , 33, /* È - 200 */
248 14 , 33, /* É - 201 */
249 14 , 33, /* Ê - 202 */
250 14 , 33, /* Ë - 203 */
251 14 , 50, /* Ì - 204 */
252 14 , 50, /* Í - 205 */
253 14 , 50, /* Î - 206 */
254 14 , 50, /* Ï - 207 */
255 14 , 26, /* Ð - 208 */
256 14 , 112, /* Ñ - 209 */
257 14 , 124, /* Ò - 210 */
258 14 , 124, /* Ó - 211 */
259 14 , 124, /* Ô - 212 */
260 14 , 124, /* Õ - 213 */
261 14 , 124, /* Ö - 214 */
262 8 , 28, /* × - 215 */
263 14 , 124, /* Ø - 216 */
264 14 , 159, /* Ù - 217 */
265 14 , 159, /* Ú - 218 */
266 14 , 159, /* Û - 219 */
267 14 , 159, /* Ü - 220 */
268 14 , 167, /* Ý - 221 */
269 14 + 32 , 153, /* Þ - 222 */
270 14 + 48 , 145, /* ß - 223 */
271 14 , 2, /* à - 224 */
272 14 , 2, /* á - 225 */
273 14 , 2, /* â - 226 */
274 14 , 2, /* ã - 227 */
275 14 , 2, /* ä - 228 */
276 14 , 2, /* å - 229 */
277 14 + 16 , 2, /* æ - 230 */
278 14 , 10, /* ç - 231 */
279 14 , 33, /* è - 232 */
280 14 , 33, /* é - 233 */
281 14 , 33, /* ê - 234 */
282 14 , 33, /* ë - 235 */
283 14 , 50, /* ì - 236 */
284 14 , 50, /* í - 237 */
285 14 , 50, /* î - 238 */
286 14 , 50, /* ï - 239 */
287 14 , 26, /* ð - 240 */
288 14 , 112, /* ñ - 241 */
289 14 , 124, /* ò - 242 */
290 14 , 124, /* ó - 243 */
291 14 , 124, /* ô - 244 */
292 14 , 124, /* õ - 245 */
293 14 , 124, /* ö - 246 */
294 8 , 29, /* ÷ - 247 */
295 14 , 124, /* ø - 248 */
296 14 , 159, /* ù - 249 */
297 14 , 159, /* ú - 250 */
298 14 , 159, /* û - 251 */
299 14 , 159, /* ü - 252 */
300 14 , 167, /* ý - 253 */
301 14 + 32 , 153, /* þ - 254 */
302 14 , 167 /* ÿ - 255 */ };
304 static const unsigned char LCM_Unicode_LUT_2[] = { 33, 44, 145 };
306 #define LCM_Diacritic_Start 131
308 static const unsigned char LCM_Diacritic_LUT[] = {
309 123, /* ƒ - 131 */
310 2, /* „ - 132 */
311 2, /* … - 133 */
312 2, /* † - 134 */
313 2, /* ‡ - 135 */
314 3, /* ˆ - 136 */
315 2, /* ‰ - 137 */
316 20, /* Š - 138 */
317 2, /* ‹ - 139 */
318 2, /* Œ - 140 */
319 2, /* � - 141 */
320 2, /* Ž - 142 */
321 2, /* � - 143 */
322 2, /* � - 144 */
323 2, /* ‘ - 145 */
324 2, /* ’ - 146 */
325 2, /* “ - 147 */
326 2, /* ” - 148 */
327 2, /* • - 149 */
328 2, /* – - 150 */
329 2, /* — - 151 */
330 2, /* ˜ - 152 */
331 2, /* ™ - 153 */
332 20, /* š - 154 */
333 2, /* › - 155 */
334 2, /* œ - 156 */
335 2, /* � - 157 */
336 2, /* ž - 158 */
337 19, /* Ÿ - 159 */
338 2, /*   - 160 */
339 2, /* ¡ - 161 */
340 2, /* ¢ - 162 */
341 2, /* £ - 163 */
342 2, /* ¤ - 164 */
343 2, /* ¥ - 165 */
344 2, /* ¦ - 166 */
345 2, /* § - 167 */
346 2, /* ¨ - 168 */
347 2, /* © - 169 */
348 3, /* ª - 170 */
349 2, /* « - 171 */
350 2, /* ¬ - 172 */
351 2, /* ­ - 173 */
352 2, /* ® - 174 */
353 2, /* ¯ - 175 */
354 2, /* ° - 176 */
355 2, /* ± - 177 */
356 2, /* ² - 178 */
357 2, /* ³ - 179 */
358 2, /* ´ - 180 */
359 2, /* µ - 181 */
360 2, /* ¶ - 182 */
361 2, /* · - 183 */
362 2, /* ¸ - 184 */
363 2, /* ¹ - 185 */
364 3, /* º - 186 */
365 2, /* » - 187 */
366 2, /* ¼ - 188 */
367 2, /* ½ - 189 */
368 2, /* ¾ - 190 */
369 2, /* ¿ - 191 */
370 15, /* À - 192 */
371 14, /* Á - 193 */
372 18, /* Â - 194 */
373 25, /* Ã - 195 */
374 19, /* Ä - 196 */
375 26, /* Å - 197 */
376 2, /* Æ - 198 */
377 28, /* Ç - 199 */
378 15, /* È - 200 */
379 14, /* É - 201 */
380 18, /* Ê - 202 */
381 19, /* Ë - 203 */
382 15, /* Ì - 204 */
383 14, /* Í - 205 */
384 18, /* Î - 206 */
385 19, /* Ï - 207 */
386 104, /* Ð - 208 */
387 25, /* Ñ - 209 */
388 15, /* Ò - 210 */
389 14, /* Ó - 211 */
390 18, /* Ô - 212 */
391 25, /* Õ - 213 */
392 19, /* Ö - 214 */
393 2, /* × - 215 */
394 33, /* Ø - 216 */
395 15, /* Ù - 217 */
396 14, /* Ú - 218 */
397 18, /* Û - 219 */
398 19, /* Ü - 220 */
399 14, /* Ý - 221 */
400 2, /* Þ - 222 */
401 2, /* ß - 223 */
402 15, /* à - 224 */
403 14, /* á - 225 */
404 18, /* â - 226 */
405 25, /* ã - 227 */
406 19, /* ä - 228 */
407 26, /* å - 229 */
408 2, /* æ - 230 */
409 28, /* ç - 231 */
410 15, /* è - 232 */
411 14, /* é - 233 */
412 18, /* ê - 234 */
413 19, /* ë - 235 */
414 15, /* ì - 236 */
415 14, /* í - 237 */
416 18, /* î - 238 */
417 19, /* ï - 239 */
418 104, /* ð - 240 */
419 25, /* ñ - 241 */
420 15, /* ò - 242 */
421 14, /* ó - 243 */
422 18, /* ô - 244 */
423 25, /* õ - 245 */
424 19, /* ö - 246 */
425 2, /* ÷ - 247 */
426 33, /* ø - 248 */
427 15, /* ù - 249 */
428 14, /* ú - 250 */
429 18, /* û - 251 */
430 19, /* ü - 252 */
431 14, /* ý - 253 */
432 2, /* þ - 254 */
433 19, /* ÿ - 255 */
436 /******************************************************************************
437 * OLE2NLS_isPunctuation [INTERNAL]
439 static int OLE2NLS_isPunctuation(unsigned char c)
441 /* "punctuation character" in this context is a character which is
442 considered "less important" during word sort comparison.
443 See LCMapString implementation for the precise definition
444 of "less important". */
446 return (LCM_Unicode_LUT[-2+2*c]==6);
449 /******************************************************************************
450 * OLE2NLS_isNonSpacing [INTERNAL]
452 static int OLE2NLS_isNonSpacing(unsigned char c)
454 /* This function is used by LCMapStringA. Characters
455 for which it returns true are ignored when mapping a
456 string with NORM_IGNORENONSPACE */
457 return ((c==136) || (c==170) || (c==186));
460 /******************************************************************************
461 * OLE2NLS_isSymbol [INTERNAL]
462 * FIXME: handle current locale
464 static int OLE2NLS_isSymbol(unsigned char c)
466 /* This function is used by LCMapStringA. Characters
467 for which it returns true are ignored when mapping a
468 string with NORM_IGNORESYMBOLS */
469 return ( (c!=0) && !(isalpha(c) || isdigit(c)) );
472 /******************************************************************************
473 * identity [Internal]
475 static int identity(int c)
477 return c;
480 /*************************************************************************
481 * LCMapStringA [KERNEL32.@]
483 * Convert a string, or generate a sort key from it.
485 * RETURNS
486 * Success: The length of the string written to dststr.
487 * Failure: 0.
489 * NOTES
490 * -If mapflags includes LCMAP_SORTKEY, the function will generate a
491 * sort key for srcstr. Otherwise, srcstr is converted according to
492 * mapflags.
493 * -If scrlen is -1, the function will compute the length of strsrc
494 * (which must be NUL terminated) itself.
495 * -If dstlen is 0, The return value is the buffer length that is needed.
496 * -NORM_IGNOREWIDTH means to compare ASCII and wide characters
497 * as if they are equal.
498 * In the only code page implemented so far, there may not be
499 * wide characters in strings passed to this function,
500 * so there is nothing to be done for this flag.
502 INT WINAPI LCMapStringA(
503 LCID lcid, /* [in] Locale Id */
504 DWORD mapflags, /* [in] Flags */
505 LPCSTR srcstr, /* [in] Source buffer */
506 INT srclen, /* [in] Length of srcstr */
507 LPSTR dststr, /* [out] Destination buffer */
508 INT dstlen) /* [in] Length of dststr */
510 int i;
512 TRACE("(0x%04lx,0x%08lx,%s,%d,%p,%d)\n",
513 lcid,mapflags,debugstr_an(srcstr,srclen),srclen,dststr,dstlen);
515 if ( ((dstlen!=0) && (dststr==NULL)) || (srcstr==NULL) )
517 ERR("(src=%s,dest=%s): Invalid NULL string\n",
518 debugstr_an(srcstr,srclen), dststr);
519 SetLastError(ERROR_INVALID_PARAMETER);
520 return 0;
522 if (srclen == -1)
523 srclen = strlen(srcstr) + 1 ; /* (include final '\0') */
525 #define LCMAPSTRINGA_SUPPORTED_FLAGS (LCMAP_UPPERCASE | \
526 LCMAP_LOWERCASE | \
527 LCMAP_SORTKEY | \
528 NORM_IGNORECASE | \
529 NORM_IGNORENONSPACE | \
530 SORT_STRINGSORT | \
531 NORM_IGNOREWIDTH | \
532 NORM_IGNOREKANATYPE)
533 /* FIXME: as long as we don't support Katakana nor Hiragana
534 * characters, we can support NORM_IGNOREKANATYPE
536 if (mapflags & ~LCMAPSTRINGA_SUPPORTED_FLAGS)
538 FIXME("(0x%04lx,0x%08lx,%p,%d,%p,%d): "
539 "unimplemented flags: 0x%08lx\n",
540 lcid,
541 mapflags,
542 srcstr,
543 srclen,
544 dststr,
545 dstlen,
546 mapflags & ~LCMAPSTRINGA_SUPPORTED_FLAGS
550 if ( !(mapflags & LCMAP_SORTKEY) )
552 int i,j;
553 int (*f)(int) = identity;
554 int flag_ignorenonspace = mapflags & NORM_IGNORENONSPACE;
555 int flag_ignoresymbols = mapflags & NORM_IGNORESYMBOLS;
557 if (flag_ignorenonspace || flag_ignoresymbols)
559 /* For some values of mapflags, the length of the resulting
560 string is not known at this point. Windows does map the string
561 and does not SetLastError ERROR_INSUFFICIENT_BUFFER in
562 these cases. */
563 if (dstlen==0)
565 /* Compute required length */
566 for (i=j=0; i < srclen; i++)
568 if ( !(flag_ignorenonspace && OLE2NLS_isNonSpacing(srcstr[i]))
569 && !(flag_ignoresymbols && OLE2NLS_isSymbol(srcstr[i])) )
570 j++;
572 return j;
575 else
577 if (dstlen==0)
578 return srclen;
579 if (dstlen<srclen)
581 SetLastError(ERROR_INSUFFICIENT_BUFFER);
582 return 0;
585 if (mapflags & LCMAP_UPPERCASE)
586 f = toupper;
587 else if (mapflags & LCMAP_LOWERCASE)
588 f = tolower;
589 /* FIXME: NORM_IGNORENONSPACE requires another conversion */
590 for (i=j=0; (i<srclen) && (j<dstlen) ; i++)
592 if ( !(flag_ignorenonspace && OLE2NLS_isNonSpacing(srcstr[i]))
593 && !(flag_ignoresymbols && OLE2NLS_isSymbol(srcstr[i])) )
595 dststr[j] = (CHAR) f(srcstr[i]);
596 j++;
599 return j;
602 /* FIXME: This function completely ignores the "lcid" parameter. */
603 /* else ... (mapflags & LCMAP_SORTKEY) */
605 int unicode_len=0;
606 int case_len=0;
607 int diacritic_len=0;
608 int delayed_punctuation_len=0;
609 char *case_component;
610 char *diacritic_component;
611 char *delayed_punctuation_component;
612 int room,count;
613 int flag_stringsort = mapflags & SORT_STRINGSORT;
615 /* compute how much room we will need */
616 for (i=0;i<srclen;i++)
618 int ofs;
619 unsigned char source_char = srcstr[i];
620 if (source_char!='\0')
622 if (flag_stringsort || !OLE2NLS_isPunctuation(source_char))
624 unicode_len++;
625 if ( LCM_Unicode_LUT[-2+2*source_char] & ~15 )
626 unicode_len++; /* double letter */
628 else
630 delayed_punctuation_len++;
634 if (isupper(source_char))
635 case_len=unicode_len;
637 ofs = source_char - LCM_Diacritic_Start;
638 if ((ofs>=0) && (LCM_Diacritic_LUT[ofs]!=2))
639 diacritic_len=unicode_len;
642 if (mapflags & NORM_IGNORECASE)
643 case_len=0;
644 if (mapflags & NORM_IGNORENONSPACE)
645 diacritic_len=0;
647 room = 2 * unicode_len /* "unicode" component */
648 + diacritic_len /* "diacritic" component */
649 + case_len /* "case" component */
650 + 4 * delayed_punctuation_len /* punctuation in word sort mode */
651 + 4 /* four '\1' separators */
652 + 1 ; /* terminal '\0' */
653 if (dstlen==0)
654 return room;
655 else if (dstlen<room)
657 SetLastError(ERROR_INSUFFICIENT_BUFFER);
658 return 0;
660 #if 0
661 /*FIXME the Pointercheck should not be nessesary */
662 if (IsBadWritePtr (dststr,room))
663 { ERR("bad destination buffer (dststr) : %p,%d\n",dststr,dstlen);
664 SetLastError(ERROR_INSUFFICIENT_BUFFER);
665 return 0;
667 #endif
668 /* locate each component, write separators */
669 diacritic_component = dststr + 2*unicode_len ;
670 *diacritic_component++ = '\1';
671 case_component = diacritic_component + diacritic_len ;
672 *case_component++ = '\1';
673 delayed_punctuation_component = case_component + case_len ;
674 *delayed_punctuation_component++ = '\1';
675 *delayed_punctuation_component++ = '\1';
677 /* read source string char by char, write
678 corresponding weight in each component. */
679 for (i=0,count=0;i<srclen;i++)
681 unsigned char source_char=srcstr[i];
682 if (source_char!='\0')
684 int type,longcode;
685 type = LCM_Unicode_LUT[-2+2*source_char];
686 longcode = type >> 4;
687 type &= 15;
688 if (!flag_stringsort && OLE2NLS_isPunctuation(source_char))
690 WORD encrypted_location = (1<<15) + 7 + 4*count;
691 *delayed_punctuation_component++ = (unsigned char) (encrypted_location>>8);
692 *delayed_punctuation_component++ = (unsigned char) (encrypted_location&255);
693 /* big-endian is used here because it lets string comparison be
694 compatible with numerical comparison */
696 *delayed_punctuation_component++ = type;
697 *delayed_punctuation_component++ = LCM_Unicode_LUT[-1+2*source_char];
698 /* assumption : a punctuation character is never a
699 double or accented letter */
701 else
703 dststr[2*count] = type;
704 dststr[2*count+1] = LCM_Unicode_LUT[-1+2*source_char];
705 if (longcode)
707 if (count<case_len)
708 case_component[count] = ( isupper(source_char) ? 18 : 2 ) ;
709 if (count<diacritic_len)
710 diacritic_component[count] = 2; /* assumption: a double letter
711 is never accented */
712 count++;
714 dststr[2*count] = type;
715 dststr[2*count+1] = *(LCM_Unicode_LUT_2 - 1 + longcode);
716 /* 16 in the first column of LCM_Unicode_LUT --> longcode = 1
717 32 in the first column of LCM_Unicode_LUT --> longcode = 2
718 48 in the first column of LCM_Unicode_LUT --> longcode = 3 */
721 if (count<case_len)
722 case_component[count] = ( isupper(source_char) ? 18 : 2 ) ;
723 if (count<diacritic_len)
725 int ofs = source_char - LCM_Diacritic_Start;
726 diacritic_component[count] = (ofs>=0 ? LCM_Diacritic_LUT[ofs] : 2);
728 count++;
732 dststr[room-1] = '\0';
733 return room;
737 /*************************************************************************
738 * LCMapStringW [KERNEL32.@]
740 * See LCMapStringA.
742 INT WINAPI LCMapStringW(
743 LCID lcid,DWORD mapflags,LPCWSTR srcstr,INT srclen,LPWSTR dststr,
744 INT dstlen)
746 int i;
748 TRACE("(0x%04lx,0x%08lx,%p,%d,%p,%d)\n",
749 lcid, mapflags, srcstr, srclen, dststr, dstlen);
751 if ( ((dstlen!=0) && (dststr==NULL)) || (srcstr==NULL) )
753 ERR("(src=%p,dst=%p): Invalid NULL string\n", srcstr, dststr);
754 SetLastError(ERROR_INVALID_PARAMETER);
755 return 0;
757 if (srclen==-1)
758 srclen = strlenW(srcstr)+1;
760 /* FIXME: Both this function and it's companion LCMapStringA()
761 * completely ignore the "lcid" parameter. In place of the "lcid"
762 * parameter the application must set the "LC_COLLATE" or "LC_ALL"
763 * environment variable prior to invoking this function. */
764 if (mapflags & LCMAP_SORTKEY)
766 /* Possible values of LC_COLLATE. */
767 char *lc_collate_default = 0; /* value prior to this function */
768 char *lc_collate_env = 0; /* value retrieved from the environment */
770 /* General purpose index into strings of any type. */
771 int str_idx = 0;
773 /* Lengths of various strings where the length is measured in
774 * wide characters for wide character strings and in bytes for
775 * native strings. The lengths include the NULL terminator. */
776 size_t returned_len = 0;
777 size_t src_native_len = 0;
778 size_t dst_native_len = 0;
779 size_t dststr_libc_len = 0;
781 /* Native (character set determined by locale) versions of the
782 * strings source and destination strings. */
783 LPSTR src_native = 0;
784 LPSTR dst_native = 0;
786 /* Version of the source and destination strings using the
787 * "wchar_t" Unicode data type needed by various libc functions. */
788 wchar_t *srcstr_libc = 0;
789 wchar_t *dststr_libc = 0;
791 if(!(srcstr_libc = (wchar_t *)HeapAlloc(GetProcessHeap(), 0,
792 srclen * sizeof(wchar_t))))
794 ERR("Unable to allocate %d bytes for srcstr_libc\n",
795 srclen * sizeof(wchar_t));
796 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
797 return 0;
800 /* Convert source string to a libc Unicode string. */
801 for(str_idx = 0; str_idx < srclen; str_idx++)
803 srcstr_libc[str_idx] = srcstr[str_idx];
806 /* src_native should contain at most 3 bytes for each
807 * multibyte characters in the original srcstr string. */
808 src_native_len = 3 * srclen;
809 if(!(src_native = (LPSTR)HeapAlloc(GetProcessHeap(), 0,
810 src_native_len)))
812 ERR("Unable to allocate %d bytes for src_native\n", src_native_len);
813 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
814 if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc);
815 return 0;
818 /* FIXME: Prior to to setting the LC_COLLATE locale category the
819 * current value is backed up so it can be restored after the
820 * last LC_COLLATE sensitive function returns.
822 * Even though the locale is adjusted for a minimum amount of
823 * time a race condition exists where other threads may be
824 * affected if they invoke LC_COLLATE sensitive functions. One
825 * possible solution is to wrap all LC_COLLATE sensitive Wine
826 * functions, like LCMapStringW(), in a mutex.
828 * Another enhancement to the following would be to set the
829 * LC_COLLATE locale category as a function of the "lcid"
830 * parameter instead of the "LC_COLLATE" environment variable. */
831 if(!(lc_collate_default = setlocale(LC_COLLATE, NULL)))
833 ERR("Unable to query the LC_COLLATE catagory\n");
834 SetLastError(ERROR_INVALID_PARAMETER);
835 if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc);
836 if(src_native) HeapFree(GetProcessHeap(), 0, src_native);
837 return 0;
840 if(!(lc_collate_env = setlocale(LC_COLLATE, "")))
842 ERR("Unable to inherit the LC_COLLATE locale category from the "
843 "environment. The \"LC_COLLATE\" environment variable is "
844 "\"%s\".\n", getenv("LC_COLLATE") ?
845 getenv("LC_COLLATE") : "<unset>");
846 SetLastError(ERROR_INVALID_PARAMETER);
847 if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc);
848 if(src_native) HeapFree(GetProcessHeap(), 0, src_native);
849 return 0;
852 TRACE("lc_collate_default = %s\n", lc_collate_default);
853 TRACE("lc_collate_env = %s\n", lc_collate_env);
855 /* Convert the libc Unicode string to a native multibyte character
856 * string. */
857 returned_len = wcstombs(src_native, srcstr_libc, src_native_len) + 1;
858 if(returned_len == 0)
860 ERR("wcstombs failed. The string specified (%s) may contain an invalid character.\n",
861 debugstr_w(srcstr));
862 SetLastError(ERROR_INVALID_PARAMETER);
863 if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc);
864 if(src_native) HeapFree(GetProcessHeap(), 0, src_native);
865 setlocale(LC_COLLATE, lc_collate_default);
866 return 0;
868 else if(returned_len > src_native_len)
870 src_native[src_native_len - 1] = 0;
871 ERR("wcstombs returned a string (%s) that was longer (%d bytes) "
872 "than expected (%d bytes).\n", src_native, returned_len,
873 dst_native_len);
875 /* Since this is an internal error I'm not sure what the correct
876 * error code is. */
877 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
879 if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc);
880 if(src_native) HeapFree(GetProcessHeap(), 0, src_native);
881 setlocale(LC_COLLATE, lc_collate_default);
882 return 0;
884 src_native_len = returned_len;
886 TRACE("src_native = %s src_native_len = %d\n",
887 src_native, src_native_len);
889 /* dst_native seems to contain at most 4 bytes for each byte in
890 * the original src_native string. Change if need be since this
891 * isn't documented by the strxfrm() man page. */
892 dst_native_len = 4 * src_native_len;
893 if(!(dst_native = (LPSTR)HeapAlloc(GetProcessHeap(), 0, dst_native_len)))
895 ERR("Unable to allocate %d bytes for dst_native\n", dst_native_len);
896 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
897 if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc);
898 if(src_native) HeapFree(GetProcessHeap(), 0, src_native);
899 setlocale(LC_COLLATE, lc_collate_default);
900 return 0;
903 /* The actual translation is done by the following call to
904 * strxfrm(). The surrounding code could have been simplified
905 * by calling wcsxfrm() instead except that wcsxfrm() is not
906 * available on older Linux systems (RedHat 4.1 with
907 * libc-5.3.12-17).
909 * Also, it is possible that the translation could be done by
910 * various tables as it is done in LCMapStringA(). However, I'm
911 * not sure what those tables are. */
912 returned_len = strxfrm(dst_native, src_native, dst_native_len) + 1;
914 if(returned_len > dst_native_len)
916 dst_native[dst_native_len - 1] = 0;
917 ERR("strxfrm returned a string (%s) that was longer (%d bytes) "
918 "than expected (%d bytes).\n", dst_native, returned_len,
919 dst_native_len);
921 /* Since this is an internal error I'm not sure what the correct
922 * error code is. */
923 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
925 if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc);
926 if(src_native) HeapFree(GetProcessHeap(), 0, src_native);
927 if(dst_native) HeapFree(GetProcessHeap(), 0, dst_native);
928 setlocale(LC_COLLATE, lc_collate_default);
929 return 0;
931 dst_native_len = returned_len;
933 TRACE("dst_native = %s dst_native_len = %d\n",
934 dst_native, dst_native_len);
936 dststr_libc_len = dst_native_len;
937 if(!(dststr_libc = (wchar_t *)HeapAlloc(GetProcessHeap(), 0,
938 dststr_libc_len * sizeof(wchar_t))))
940 ERR("Unable to allocate %d bytes for dststr_libc\n",
941 dststr_libc_len * sizeof(wchar_t));
942 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
943 if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc);
944 if(src_native) HeapFree(GetProcessHeap(), 0, src_native);
945 if(dst_native) HeapFree(GetProcessHeap(), 0, dst_native);
946 setlocale(LC_COLLATE, lc_collate_default);
947 return 0;
950 /* Convert the native multibyte string to a libc Unicode string. */
951 returned_len = mbstowcs(dststr_libc, dst_native, dst_native_len) + 1;
953 /* Restore LC_COLLATE now that the last LC_COLLATE sensitive
954 * function has returned. */
955 setlocale(LC_COLLATE, lc_collate_default);
957 if(returned_len == 0)
959 ERR("mbstowcs failed. The native version of the translated string "
960 "(%s) may contain an invalid character.\n", dst_native);
961 SetLastError(ERROR_INVALID_PARAMETER);
962 if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc);
963 if(src_native) HeapFree(GetProcessHeap(), 0, src_native);
964 if(dst_native) HeapFree(GetProcessHeap(), 0, dst_native);
965 if(dststr_libc) HeapFree(GetProcessHeap(), 0, dststr_libc);
966 return 0;
968 if(dstlen)
970 if(returned_len > dstlen)
972 ERR("mbstowcs returned a string that was longer (%d chars) "
973 "than the buffer provided (%d chars).\n", returned_len,
974 dstlen);
975 SetLastError(ERROR_INSUFFICIENT_BUFFER);
976 if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc);
977 if(src_native) HeapFree(GetProcessHeap(), 0, src_native);
978 if(dst_native) HeapFree(GetProcessHeap(), 0, dst_native);
979 if(dststr_libc) HeapFree(GetProcessHeap(), 0, dststr_libc);
980 return 0;
982 dstlen = returned_len;
984 /* Convert a libc Unicode string to the destination string. */
985 for(str_idx = 0; str_idx < dstlen; str_idx++)
987 dststr[str_idx] = dststr_libc[str_idx];
989 TRACE("1st 4 int sized chunks of dststr = %x %x %x %x\n",
990 *(((int *)dststr) + 0),
991 *(((int *)dststr) + 1),
992 *(((int *)dststr) + 2),
993 *(((int *)dststr) + 3));
995 else
997 dstlen = returned_len;
999 TRACE("dstlen (return) = %d\n", dstlen);
1000 if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc);
1001 if(src_native) HeapFree(GetProcessHeap(), 0, src_native);
1002 if(dst_native) HeapFree(GetProcessHeap(), 0, dst_native);
1003 if(dststr_libc) HeapFree(GetProcessHeap(), 0, dststr_libc);
1004 return dstlen;
1006 else
1008 int (*f)(int)=identity;
1010 if (dstlen==0)
1011 return srclen;
1012 if (dstlen<srclen)
1014 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1015 return 0;
1018 if (mapflags & LCMAP_UPPERCASE)
1019 f = toupper;
1020 else if (mapflags & LCMAP_LOWERCASE)
1021 f = tolower;
1022 for (i=0; i < srclen; i++)
1023 dststr[i] = (WCHAR) f(srcstr[i]);
1024 return srclen;
1029 /***********************************************************************
1030 * OLE2NLS_EstimateMappingLength
1032 * Estimates the number of characters required to hold the string
1033 * computed by LCMapStringA.
1035 * The size is always over-estimated, with a fixed limit on the
1036 * amount of estimation error.
1038 * Note that len == -1 is not permitted.
1040 static inline int OLE2NLS_EstimateMappingLength(LCID lcid, DWORD dwMapFlags,
1041 LPCSTR str, DWORD len)
1043 /* Estimate only for small strings to keep the estimation error from
1044 * becoming too large. */
1045 if (len < 128) return len * 8 + 5;
1046 else return LCMapStringA(lcid, dwMapFlags, str, len, NULL, 0);
1049 /******************************************************************************
1050 * CompareStringA [KERNEL32.@]
1051 * Compares two strings using locale
1053 * RETURNS
1055 * success: CSTR_LESS_THAN, CSTR_EQUAL, CSTR_GREATER_THAN
1056 * failure: 0
1058 * NOTES
1060 * Defaults to a word sort, but uses a string sort if
1061 * SORT_STRINGSORT is set.
1062 * Calls SetLastError for ERROR_INVALID_FLAGS, ERROR_INVALID_PARAMETER.
1064 * BUGS
1066 * This implementation ignores the locale
1068 * FIXME
1070 * Quite inefficient.
1072 int WINAPI CompareStringA(
1073 LCID lcid, /* [in] locale ID */
1074 DWORD fdwStyle, /* [in] comparison-style options */
1075 LPCSTR s1, /* [in] first string */
1076 int l1, /* [in] length of first string */
1077 LPCSTR s2, /* [in] second string */
1078 int l2) /* [in] length of second string */
1080 int mapstring_flags;
1081 int len1,len2;
1082 int result;
1083 LPSTR sk1,sk2;
1084 TRACE("%s and %s\n",
1085 debugstr_an (s1,l1), debugstr_an (s2,l2));
1087 if ( (s1==NULL) || (s2==NULL) )
1089 ERR("(s1=%s,s2=%s): Invalid NULL string\n",
1090 debugstr_an(s1,l1), debugstr_an(s2,l2));
1091 SetLastError(ERROR_INVALID_PARAMETER);
1092 return 0;
1095 if(fdwStyle & NORM_IGNORESYMBOLS)
1096 FIXME("IGNORESYMBOLS not supported\n");
1098 if (l1 == -1) l1 = strlen(s1);
1099 if (l2 == -1) l2 = strlen(s2);
1101 mapstring_flags = LCMAP_SORTKEY | fdwStyle ;
1102 len1 = OLE2NLS_EstimateMappingLength(lcid, mapstring_flags, s1, l1);
1103 len2 = OLE2NLS_EstimateMappingLength(lcid, mapstring_flags, s2, l2);
1105 if ((len1==0)||(len2==0))
1106 return 0; /* something wrong happened */
1108 sk1 = (LPSTR)HeapAlloc(GetProcessHeap(), 0, len1 + len2);
1109 sk2 = sk1 + len1;
1110 if ( (!LCMapStringA(lcid,mapstring_flags,s1,l1,sk1,len1))
1111 || (!LCMapStringA(lcid,mapstring_flags,s2,l2,sk2,len2)) )
1113 ERR("Bug in LCmapStringA.\n");
1114 result = 0;
1116 else
1118 /* strcmp doesn't necessarily return -1, 0, or 1 */
1119 result = strcmp(sk1,sk2);
1121 HeapFree(GetProcessHeap(),0,sk1);
1123 if (result < 0)
1124 return 1;
1125 if (result == 0)
1126 return 2;
1128 /* must be greater, if we reach this point */
1129 return 3;
1132 /******************************************************************************
1133 * CompareStringW [KERNEL32.@]
1134 * This implementation ignores the locale
1135 * FIXME : Does only string sort. Should
1136 * be reimplemented the same way as CompareStringA.
1138 int WINAPI CompareStringW(LCID lcid, DWORD fdwStyle,
1139 LPCWSTR s1, int l1, LPCWSTR s2, int l2)
1141 int len,ret;
1142 if(fdwStyle & NORM_IGNORENONSPACE)
1143 FIXME("IGNORENONSPACE not supported\n");
1144 if(fdwStyle & NORM_IGNORESYMBOLS)
1145 FIXME("IGNORESYMBOLS not supported\n");
1147 if(s1==NULL || s2==NULL)
1149 SetLastError(ERROR_INVALID_PARAMETER);
1150 return 0;
1152 /* Is strcmp defaulting to string sort or to word sort?? */
1153 /* FIXME: Handle NORM_STRINGSORT */
1154 l1 = (l1==-1)?strlenW(s1):l1;
1155 l2 = (l2==-1)?strlenW(s2):l2;
1156 len = l1<l2 ? l1:l2;
1157 ret = (fdwStyle & NORM_IGNORECASE) ? strncmpiW(s1,s2,len) : strncmpW(s1,s2,len);
1158 /* not equal, return 1 or 3 */
1159 if(ret!=0) {
1160 /* need to translate result */
1161 return ((int)ret < 0) ? 1 : 3;
1163 /* same len, return 2 */
1164 if(l1==l2) return 2;
1165 /* the longer one is lexically greater */
1166 return (l1<l2)? 1 : 3;
1169 /***********************************************************************
1170 * lstrcmp (KERNEL32.@)
1171 * lstrcmpA (KERNEL32.@)
1173 INT WINAPI lstrcmpA( LPCSTR str1, LPCSTR str2 )
1175 return CompareStringA(LOCALE_SYSTEM_DEFAULT,0,str1,-1,str2,-1) - 2 ;
1179 /***********************************************************************
1180 * lstrcmpW (KERNEL32.@)
1181 * FIXME : should call CompareStringW, when it is implemented.
1182 * This implementation is not "word sort", as it should.
1184 INT WINAPI lstrcmpW( LPCWSTR str1, LPCWSTR str2 )
1186 TRACE("%s and %s\n",
1187 debugstr_w (str1), debugstr_w (str2));
1188 if (!str1 || !str2) {
1189 SetLastError(ERROR_INVALID_PARAMETER);
1190 return 0;
1192 while (*str1 && (*str1 == *str2)) { str1++; str2++; }
1193 return (INT)(*str1 - *str2);
1197 /***********************************************************************
1198 * lstrcmpi (KERNEL32.@)
1199 * lstrcmpiA (KERNEL32.@)
1201 INT WINAPI lstrcmpiA( LPCSTR str1, LPCSTR str2 )
1202 { TRACE("strcmpi %s and %s\n",
1203 debugstr_a (str1), debugstr_a (str2));
1204 return CompareStringA(LOCALE_SYSTEM_DEFAULT,NORM_IGNORECASE,str1,-1,str2,-1)-2;
1208 /***********************************************************************
1209 * lstrcmpiW (KERNEL32.@)
1211 INT WINAPI lstrcmpiW( LPCWSTR str1, LPCWSTR str2 )
1213 if (!str1 || !str2) {
1214 SetLastError(ERROR_INVALID_PARAMETER);
1215 return 0;
1217 return strcmpiW( str1, str2 );