OSDN Git Service

Replace FSF snail mail address with URLs
[uclinux-h8/uClibc.git] / libc / misc / wctype / _wctype.c
1 /*  Copyright (C) 2002, 2003     Manuel Novoa III
2  *
3  *  This library is free software; you can redistribute it and/or
4  *  modify it under the terms of the GNU Library General Public
5  *  License as published by the Free Software Foundation; either
6  *  version 2 of the License, or (at your option) any later version.
7  *
8  *  This library is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  *  Library General Public License for more details.
12  *
13  *  You should have received a copy of the GNU Library General Public
14  *  License along with this library; if not, see
15  *  <http://www.gnu.org/licenses/>.
16  */
17
18 /*  ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!
19  *
20  *  Besides uClibc, I'm using this code in my libc for elks, which is
21  *  a 16-bit environment with a fairly limited compiler.  It would make
22  *  things much easier for me if this file isn't modified unnecessarily.
23  *  In particular, please put any new or replacement functions somewhere
24  *  else, and modify the makefile to use your version instead.
25  *  Thanks.  Manuel
26  *
27  *  ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION! */
28
29 #define __NO_CTYPE
30
31 #include <wctype.h>
32 #include <assert.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <locale.h>
36 #include <ctype.h>
37 #include <stdint.h>
38 #include <bits/uClibc_uwchar.h>
39
40 #if defined(__LOCALE_C_ONLY) && defined(__UCLIBC_DO_XLOCALE)
41 # error xlocale functionality is not supported in stub locale mode.
42 #endif
43
44 /* We know wide char support is enabled.  We wouldn't be here otherwise. */
45
46 /* Define this if you want to unify the towupper and towlower code in the
47  * towctrans function. */
48 /* #define SMALL_UPLOW */
49
50
51 /* Pull in __CTYPE_xxx constants */
52 #include <bits/uClibc_charclass.h>
53
54
55 /* The following is used to implement wctype(), but it is defined
56  * here because the ordering must agree with that of the enumeration
57  * below (ignoring unclassified). */
58 #define __CTYPE_TYPESTRING \
59         "\6alnum\0\6alpha\0\6blank\0\6cntrl\0\6digit\0\6graph\0\6lower\0" \
60         "\6print\0\6punct\0\6space\0\6upper\0\7xdigit\0\0"
61
62
63 /* The values for wctype_t. */
64 enum {
65         _CTYPE_unclassified = 0,
66         _CTYPE_isalnum,
67         _CTYPE_isalpha,
68         _CTYPE_isblank,
69         _CTYPE_iscntrl,
70         _CTYPE_isdigit,
71         _CTYPE_isgraph,
72         _CTYPE_islower,
73         _CTYPE_isprint,
74         _CTYPE_ispunct,
75         _CTYPE_isspace,
76         _CTYPE_isupper,
77         _CTYPE_isxdigit                         /* _MUST_ be last of the standard classes! */
78 };
79
80 /* The following is used to implement wctrans(). */
81
82 #define __CTYPE_TRANSTRING      "\10tolower\0\10toupper\0\10totitle\0\0"
83
84 enum {
85         _CTYPE_tolower = 1,
86         _CTYPE_toupper,
87         _CTYPE_totitle
88 };
89
90 /*--------------------------------------------------------------------*/
91
92 #define _CTYPE_iswxdigit (_CTYPE_isxdigit)
93
94 /*--------------------------------------------------------------------*/
95
96 #ifdef __UCLIBC_MJN3_ONLY__
97 # ifdef L_iswspace
98 /* generates one warning */
99 #  warning TODO: Fix WC* defines!
100 # endif
101 #endif
102
103 #define ENCODING                (__UCLIBC_CURLOCALE->encoding)
104
105 #define WCctype                 (__UCLIBC_CURLOCALE->tblwctype)
106 #define WCuplow                 (__UCLIBC_CURLOCALE->tblwuplow)
107 #define WCcmob                  (__UCLIBC_CURLOCALE->tblwcomb)
108 #define WCuplow_diff            (__UCLIBC_CURLOCALE->tblwuplow_diff)
109
110
111 #define WC_TABLE_DOMAIN_MAX   __LOCALE_DATA_WC_TABLE_DOMAIN_MAX
112
113 #define WCctype_II_LEN        __LOCALE_DATA_WCctype_II_LEN
114 #define WCctype_TI_LEN        __LOCALE_DATA_WCctype_TI_LEN
115 #define WCctype_UT_LEN        __LOCALE_DATA_WCctype_UT_LEN
116 #define WCctype_II_SHIFT      __LOCALE_DATA_WCctype_II_SHIFT
117 #define WCctype_TI_SHIFT      __LOCALE_DATA_WCctype_TI_SHIFT
118
119 #define WCuplow_II_LEN        __LOCALE_DATA_WCuplow_II_LEN
120 #define WCuplow_TI_LEN        __LOCALE_DATA_WCuplow_TI_LEN
121 #define WCuplow_UT_LEN        __LOCALE_DATA_WCuplow_UT_LEN
122 #define WCuplow_II_SHIFT      __LOCALE_DATA_WCuplow_II_SHIFT
123 #define WCuplow_TI_SHIFT      __LOCALE_DATA_WCuplow_TI_SHIFT
124
125
126 #define WCctype_TI_MASK         ((1 << (WCctype_TI_SHIFT)) - 1)
127 #define WCctype_II_MASK         ((1 << (WCctype_II_SHIFT)) - 1)
128
129 /**********************************************************************/
130
131 #undef __PASTE2
132 #undef __PASTE3
133 #define __PASTE2(X,Y)           X ## Y
134 #define __PASTE3(X,Y,Z)         X ## Y ## Z
135
136 #ifdef __UCLIBC_DO_XLOCALE
137
138 #define ISW_FUNC_BODY(NAME) \
139 int __PASTE3(isw,NAME,_l) (wint_t wc, __locale_t l) \
140 { \
141         return iswctype_l(wc, __PASTE2(_CTYPE_is,NAME), l); \
142 }
143
144 #else  /* __UCLIBC_DO_XLOCALE */
145
146 #define ISW_FUNC_BODY(NAME) \
147 int __PASTE2(isw,NAME) (wint_t wc) \
148 { \
149         return iswctype(wc, __PASTE2(_CTYPE_is,NAME)); \
150 }
151
152 #endif /* __UCLIBC_DO_XLOCALE */
153 /**********************************************************************/
154 #if defined(L_iswalnum) || defined(L_iswalnum_l)
155
156 ISW_FUNC_BODY(alnum);
157 # ifdef L_iswalnum
158 libc_hidden_def(iswalnum)
159 # endif
160
161 #endif
162 /**********************************************************************/
163 #if defined(L_iswalpha) || defined(L_iswalpha_l)
164
165 ISW_FUNC_BODY(alpha);
166
167 #endif
168 /**********************************************************************/
169 #if defined(L_iswblank) || defined(L_iswblank_l)
170
171 ISW_FUNC_BODY(blank);
172
173 #endif
174 /**********************************************************************/
175 #if defined(L_iswcntrl) || defined(L_iswcntrl_l)
176
177 ISW_FUNC_BODY(cntrl);
178
179 #endif
180 /**********************************************************************/
181 #if defined(L_iswdigit) || defined(L_iswdigit_l)
182
183 ISW_FUNC_BODY(digit);
184
185 #endif
186 /**********************************************************************/
187 #if defined(L_iswgraph) || defined(L_iswgraph_l)
188
189 ISW_FUNC_BODY(graph);
190
191 #endif
192 /**********************************************************************/
193 #if defined(L_iswlower) || defined(L_iswlower_l)
194
195 ISW_FUNC_BODY(lower);
196 # ifdef L_iswlower
197 libc_hidden_def(iswlower)
198 # endif
199
200 #endif
201 /**********************************************************************/
202 #if defined(L_iswprint) || defined(L_iswprint_l)
203
204 ISW_FUNC_BODY(print);
205
206 #endif
207 /**********************************************************************/
208 #if defined(L_iswpunct) || defined(L_iswpunct_l)
209
210 ISW_FUNC_BODY(punct);
211
212 #endif
213 /**********************************************************************/
214 #if defined(L_iswspace) || defined(L_iswspace_l)
215
216 ISW_FUNC_BODY(space);
217 # ifdef L_iswspace
218 libc_hidden_def(iswspace)
219 # else
220 libc_hidden_def(iswspace_l)
221 # endif
222
223 #endif
224 /**********************************************************************/
225 #if defined(L_iswupper) || defined(L_iswupper_l)
226
227 ISW_FUNC_BODY(upper);
228 # ifdef L_iswupper
229 libc_hidden_def(iswupper)
230 # endif
231
232 #endif
233 /**********************************************************************/
234 #if defined(L_iswxdigit) || defined(L_iswxdigit_l)
235
236 ISW_FUNC_BODY(xdigit);
237
238 #endif
239 /**********************************************************************/
240 #if defined(L_towlower) || defined(L_towlower_l)
241
242 # ifdef L_towlower
243 #  define TOWLOWER(w) towlower(w)
244 # else
245 #  define TOWLOWER(w) towlower_l(w, __locale_t locale)
246 #  undef __UCLIBC_CURLOCALE
247 #  define __UCLIBC_CURLOCALE (locale)
248 # endif
249
250 # ifdef __UCLIBC_HAS_XLOCALE__
251 #  define TOWCTRANS(w,d) towctrans_l(w,d, __UCLIBC_CURLOCALE)
252 # else
253 #  define TOWCTRANS(w,d) towctrans(w,d)
254 # endif
255
256 # define __C_towlower(wc) \
257         (((__uwchar_t)(wc) <= 0x7f) ? (__C_ctype_tolower)[(wc)] : (wc))
258
259 # ifdef __LOCALE_C_ONLY
260
261 wint_t towlower(wint_t wc)
262 {
263 #  ifdef __UCLIBC_HAS_CTYPE_TABLES__
264         return __C_towlower(wc);
265 #  else
266         return (wc == (unsigned)wc)
267                 ? __C_tolower((unsigned)wc)
268                 : 0;
269 #  endif
270 }
271
272 # else  /* __LOCALE_C_ONLY */
273
274 #  ifdef SMALL_UPLOW
275
276 #   if defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__)
277 wint_t towlower(wint_t wc)
278 {
279         return towctrans_l(wc, _CTYPE_tolower, __UCLIBC_CURLOCALE);
280 }
281 #   else  /* defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__) */
282 wint_t TOWLOWER(wint_t wc)
283 {
284         return TOWCTRANS(wc, _CTYPE_tolower);
285 }
286 #   endif /* defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__) */
287
288 #  else  /* SMALL_UPLOW */
289
290 #   if defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__)
291
292 wint_t towlower(wint_t wc)
293 {
294         return towlower_l(wc, __UCLIBC_CURLOCALE);
295 }
296
297 #   else  /* defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__) */
298
299 wint_t TOWLOWER(wint_t wc)
300 {
301         unsigned sc, n, i;
302         __uwchar_t u = wc;
303
304         if (ENCODING == __ctype_encoding_7_bit) {
305                 /* We're in the C/POSIX locale, so ignore the tables. */
306                 return __C_towlower(wc);
307         }
308
309         if (u <= WC_TABLE_DOMAIN_MAX) {
310                 sc = u & ((1 << WCuplow_TI_SHIFT) - 1);
311                 u >>= WCuplow_TI_SHIFT;
312                 n = u & ((1 << WCuplow_II_SHIFT) - 1);
313                 u >>= WCuplow_II_SHIFT;
314
315                 i = ((unsigned) WCuplow[u]) << WCuplow_II_SHIFT;
316                 i = ((unsigned) WCuplow[WCuplow_II_LEN + i + n]) << WCuplow_TI_SHIFT;
317                 i = ((unsigned) WCuplow[WCuplow_II_LEN + WCuplow_TI_LEN + i + sc]) << 1;
318                 wc += WCuplow_diff[i + 1];
319         }
320         return wc;
321 }
322
323 #   endif /* defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__) */
324
325 #  endif /* SMALL_UPLOW */
326
327 #  ifdef L_towlower_l
328 libc_hidden_def(towlower_l)
329 #  endif
330
331 # endif /* __LOCALE_C_ONLY */
332
333 # ifndef L_towlower_l
334 libc_hidden_def(towlower)
335 # endif
336
337 #endif
338 /**********************************************************************/
339 #if defined(L_towupper) || defined(L_towupper_l)
340
341 # ifdef L_towupper
342 #  define TOWUPPER(w) towupper(w)
343 # else
344 #  define TOWUPPER(w) towupper_l(w, __locale_t locale)
345 #  undef __UCLIBC_CURLOCALE
346 #  define __UCLIBC_CURLOCALE (locale)
347 # endif
348
349 # ifdef __UCLIBC_HAS_XLOCALE__
350 #  define TOWCTRANS(w,d) towctrans_l(w,d, __UCLIBC_CURLOCALE)
351 # else
352 #  define TOWCTRANS(w,d) towctrans(w,d)
353 # endif
354
355 # define __C_towupper(wc) \
356         (((__uwchar_t)(wc) <= 0x7f) ? (__C_ctype_toupper)[(wc)] : (wc))
357
358 # ifdef __LOCALE_C_ONLY
359
360 wint_t towupper(wint_t wc)
361 {
362 #  ifdef __UCLIBC_HAS_CTYPE_TABLES__
363         return __C_towupper(wc);
364 #  else
365         return (wc == (unsigned)wc)
366                 ? __C_toupper((unsigned)wc)
367                 : 0;
368 #  endif
369 }
370
371 # else  /* __LOCALE_C_ONLY */
372
373 #  ifdef SMALL_UPLOW
374
375 #   if defined(L_towupper) && defined(__UCLIBC_HAS_XLOCALE__)
376 wint_t towupper(wint_t wc)
377 {
378         return towctrans_l(wc, _CTYPE_toupper, __UCLIBC_CURLOCALE);
379 }
380 #   else
381 wint_t TOWUPPER(wint_t wc)
382 {
383         return TOWCTRANS(wc, _CTYPE_toupper);
384 }
385 #   endif
386
387 #  else  /* SMALL_UPLOW */
388
389 #   if defined(L_towupper) && defined(__UCLIBC_HAS_XLOCALE__)
390 wint_t towupper(wint_t wc)
391 {
392         return towupper_l(wc, __UCLIBC_CURLOCALE);
393 }
394 #   else  /* defined(L_towupper) && defined(__UCLIBC_HAS_XLOCALE__) */
395 wint_t TOWUPPER(wint_t wc)
396 {
397         unsigned sc, n, i;
398         __uwchar_t u = wc;
399
400         if (ENCODING == __ctype_encoding_7_bit) {
401                 /* We're in the C/POSIX locale, so ignore the tables. */
402                 return __C_towupper(wc);
403         }
404
405         if (u <= WC_TABLE_DOMAIN_MAX) {
406                 sc = u & ((1 << WCuplow_TI_SHIFT) - 1);
407                 u >>= WCuplow_TI_SHIFT;
408                 n = u & ((1 << WCuplow_II_SHIFT) - 1);
409                 u >>= WCuplow_II_SHIFT;
410
411                 i = ((unsigned) WCuplow[u]) << WCuplow_II_SHIFT;
412                 i = ((unsigned) WCuplow[WCuplow_II_LEN + i + n]) << WCuplow_TI_SHIFT;
413                 i = ((unsigned) WCuplow[WCuplow_II_LEN + WCuplow_TI_LEN + i + sc]) << 1;
414                 wc += WCuplow_diff[i];
415         }
416         return wc;
417 }
418 #   endif /* defined(L_towupper) && defined(__UCLIBC_HAS_XLOCALE__) */
419
420 #  endif /* SMALL_UPLOW */
421
422 #  ifdef L_towupper_l
423 libc_hidden_def(towupper_l)
424 #  endif
425
426 # endif /* __LOCALE_C_ONLY */
427
428 # ifndef L_towupper_l
429 libc_hidden_def(towupper)
430 # endif
431
432 #endif
433 /**********************************************************************/
434 #ifdef L_wctype
435
436 static const unsigned char typestring[] = __CTYPE_TYPESTRING;
437
438 wctype_t wctype(const char *property)
439 {
440         const unsigned char *p;
441         int i;
442
443         p = typestring;
444         i = 1;
445         do {
446                 if (!strcmp(property, (const char *) ++p)) {
447                         return i;
448                 }
449                 ++i;
450                 p += p[-1];
451         } while (*p);
452
453         /* TODO - Add locale-specific classifications. */
454         return 0;
455 }
456 libc_hidden_def(wctype)
457
458 #endif
459 /**********************************************************************/
460 #ifdef L_wctype_l
461
462 #ifdef __UCLIBC_MJN3_ONLY__
463 # warning REMINDER: Currently wctype_l simply calls wctype.
464 #endif
465
466 wctype_t wctype_l (const char *property, __locale_t locale)
467 {
468         return wctype(property);
469 }
470
471 #endif
472 /**********************************************************************/
473 #if defined(L_iswctype) || defined(L_iswctype_l)
474
475 #define __C_iswdigit(c) \
476         ((sizeof(c) == sizeof(char)) \
477          ? ((unsigned char)((c) - '0') < 10) \
478          : ((__uwchar_t)((c) - '0') < 10) \
479         )
480 #define __C_iswxdigit(c) \
481         (__C_iswdigit(c) \
482          || ((sizeof(c) == sizeof(char)) \
483                  ? ((unsigned char)(((c) | 0x20) - 'a') < 6) \
484                  : ((__uwchar_t)(((c) | 0x20) - 'a') < 6) \
485             ) \
486         )
487
488 #ifdef __UCLIBC_MJN3_ONLY__
489 # ifdef L_iswctype
490 #  warning CONSIDER: Change to bit shift?  would need to sync with wctype.h
491 # endif
492 #endif
493
494 #ifdef __UCLIBC_HAS_CTYPE_TABLES__
495 # if !defined(__UCLIBC_HAS_XLOCALE__) || defined(L_iswctype_l)
496 static const unsigned short int desc2flag[] = {
497         [_CTYPE_unclassified] = 0,
498         [_CTYPE_isalnum] = (unsigned short int) _ISwalnum,
499         [_CTYPE_isalpha] = (unsigned short int) _ISwalpha,
500         [_CTYPE_isblank] = (unsigned short int) _ISwblank,
501         [_CTYPE_iscntrl] = (unsigned short int) _ISwcntrl,
502         [_CTYPE_isdigit] = (unsigned short int) _ISwdigit,
503         [_CTYPE_isgraph] = (unsigned short int) _ISwgraph,
504         [_CTYPE_islower] = (unsigned short int) _ISwlower,
505         [_CTYPE_isprint] = (unsigned short int) _ISwprint,
506         [_CTYPE_ispunct] = (unsigned short int) _ISwpunct,
507         [_CTYPE_isspace] = (unsigned short int) _ISwspace,
508         [_CTYPE_isupper] = (unsigned short int) _ISwupper,
509         [_CTYPE_isxdigit] = (unsigned short int) _ISwxdigit,
510 };
511 # endif
512 #endif
513
514 #ifdef __LOCALE_C_ONLY
515
516 #ifdef __UCLIBC_HAS_CTYPE_TABLES__
517
518 int iswctype(wint_t wc, wctype_t desc)
519 {
520         /* Note... wctype_t is unsigned. */
521
522         if ((__uwchar_t) wc <= 0x7f
523          && desc < (sizeof(desc2flag) / sizeof(desc2flag[0]))
524         ) {
525                 return __isctype(wc, desc2flag[desc]);
526         }
527         return 0;
528 }
529
530 #else  /* __UCLIBC_HAS_CTYPE_TABLES__ */
531
532 int iswctype(wint_t wc, wctype_t desc)
533 {
534         /* This is lame, but it is here just to get it working for now. */
535
536         if (wc == (unsigned)wc) {
537                 switch (desc) {
538                         case _CTYPE_isupper:
539                                 return __C_isupper((unsigned)wc);
540                         case _CTYPE_islower:
541                                 return __C_islower((unsigned)wc);
542                         case _CTYPE_isalpha:
543                                 return __C_isalpha((unsigned)wc);
544                         case _CTYPE_isdigit:
545                                 return __C_isdigit((unsigned)wc);
546                         case _CTYPE_isxdigit:
547                                 return __C_isxdigit((unsigned)wc);
548                         case _CTYPE_isspace:
549                                 return __C_isspace((unsigned)wc);
550                         case _CTYPE_isprint:
551                                 return __C_isprint((unsigned)wc);
552                         case _CTYPE_isgraph:
553                                 return __C_isgraph((unsigned)wc);
554                         case _CTYPE_isblank:
555                                 return __C_isblank((unsigned)wc);
556                         case _CTYPE_iscntrl:
557                                 return __C_iscntrl((unsigned)wc);
558                         case _CTYPE_ispunct:
559                                 return __C_ispunct((unsigned)wc);
560                         case _CTYPE_isalnum:
561                                 return __C_isalnum((unsigned)wc);
562                         default:
563                                 break;
564                 }
565         }
566         return 0;
567 }
568
569 #endif /* __UCLIBC_HAS_CTYPE_TABLES__ */
570
571 #else  /* __LOCALE_C_ONLY */
572
573 #ifdef __UCLIBC_MJN3_ONLY__
574 # ifdef L_iswctype
575 #  warning CONSIDER: Handle combining class?
576 # endif
577 #endif
578
579 #ifdef L_iswctype
580 # define ISWCTYPE(w,d) iswctype(w,d)
581 #else
582 # define ISWCTYPE(w,d) iswctype_l(w,d, __locale_t locale)
583 # undef __UCLIBC_CURLOCALE
584 # define __UCLIBC_CURLOCALE (locale)
585 #endif
586
587 #if defined(L_iswctype) && defined(__UCLIBC_HAS_XLOCALE__)
588
589 int iswctype(wint_t wc, wctype_t desc)
590 {
591         return iswctype_l(wc, desc, __UCLIBC_CURLOCALE);
592 }
593
594 #else  /* defined(L_iswctype) && defined(__UCLIBC_HAS_XLOCALE__) */
595
596 int ISWCTYPE(wint_t wc, wctype_t desc)
597 {
598         unsigned sc, n, i0, i1;
599         unsigned char d = __CTYPE_unclassified;
600
601         if ((ENCODING != __ctype_encoding_7_bit) || ((__uwchar_t)wc <= 0x7f)) {
602                 if (desc < _CTYPE_iswxdigit) {
603                         if ((__uwchar_t)wc <= WC_TABLE_DOMAIN_MAX) {
604                                 /* From here on, we know wc > 0. */
605                                 sc = wc & WCctype_TI_MASK;
606                                 wc >>= WCctype_TI_SHIFT;
607                                 n = wc & WCctype_II_MASK;
608                                 wc >>= WCctype_II_SHIFT;
609
610                                 i0 = WCctype[wc];
611                                 i0 <<= WCctype_II_SHIFT;
612                                 i1 = WCctype[WCctype_II_LEN + i0 + n];
613                                 i1 <<= (WCctype_TI_SHIFT-1);
614                                 d = WCctype[WCctype_II_LEN + WCctype_TI_LEN + i1 + (sc >> 1)];
615
616                                 d = (sc & 1) ? (d >> 4) : (d & 0xf);
617                         } else if ((__uwchar_t)(wc - 0xe0020UL) <= 0x5f
618                                 || wc == 0xe0001UL
619                                 || (((__uwchar_t)(wc - 0xf0000UL) < 0x20000UL) && ((wc & 0xffffU) <= 0xfffdU))
620                         ) {
621                                 d = __CTYPE_punct;
622                         }
623
624 #if 0
625                         return ((unsigned char)(d - ctype_range[2*desc]) <= ctype_range[2*desc + 1])
626                                 && ((desc != _CTYPE_iswblank) || (d & 1));
627 #else
628                         return __UCLIBC_CURLOCALE->code2flag[d] & desc2flag[desc];
629 #endif
630                 }
631
632 #ifdef __UCLIBC_MJN3_ONLY__
633 # warning TODO: xdigit really needs to be handled better.  Remember only for ascii!
634 #endif
635                 /* TODO - Add locale-specific classifications. */
636                 return (desc == _CTYPE_iswxdigit) ? __C_iswxdigit(wc) : 0;
637         }
638         return 0;
639 }
640
641 #endif /* defined(L_iswctype) && defined(__UCLIBC_HAS_XLOCALE__) */
642
643 #ifdef L_iswctype_l
644 libc_hidden_def(iswctype_l)
645 #endif
646
647 #endif /* __LOCALE_C_ONLY */
648
649 #ifdef L_iswctype
650 libc_hidden_def(iswctype)
651 #endif
652
653 #endif
654 /**********************************************************************/
655 #if defined(L_towctrans) || defined(L_towctrans_l)
656
657 #ifdef __LOCALE_C_ONLY
658
659 /* Minimal support for C/POSIX locale. */
660
661 wint_t towctrans(wint_t wc, wctrans_t desc)
662 {
663         if ((unsigned)(desc - _CTYPE_tolower) <= (_CTYPE_toupper - _CTYPE_tolower)) {
664                 /* Transliteration is either tolower or toupper. */
665 #if 0
666 /* I think it's wrong: _toupper(c) assumes that c is a *lowercase* *letter* -
667  * it is defined as ((c) ^ 0x20)! */
668                 if ((__uwchar_t) wc <= 0x7f) {
669                         return (desc == _CTYPE_tolower) ? _tolower(wc) : _toupper(wc);
670                 }
671 #endif
672                 __uwchar_t c = wc | 0x20; /* lowercase if it's a letter */
673                 if (c >= 'a' && c <= 'z') {
674                         if (desc == _CTYPE_toupper)
675                                 c &= ~0x20; /* uppercase */
676                         return c;
677                 }
678         } else {
679                 __set_errno(EINVAL);    /* Invalid transliteration. */
680         }
681         return wc;
682 }
683
684 #else  /* __LOCALE_C_ONLY */
685
686 #ifdef L_towctrans
687 # define TOWCTRANS(w,d) towctrans(w,d)
688 #else
689 # define TOWCTRANS(w,d) towctrans_l(w,d, __locale_t locale)
690 # undef __UCLIBC_CURLOCALE
691 # define __UCLIBC_CURLOCALE (locale)
692 #endif
693
694 #ifdef __UCLIBC_HAS_XLOCALE__
695 # define TOWLOWER(w,l) towlower_l(w,l)
696 # define TOWUPPER(w,l) towupper_l(w,l)
697 #else
698 # define TOWLOWER(w,l) towlower(w)
699 # define TOWUPPER(w,l) towupper(w)
700 #endif
701
702 #if defined(L_towctrans) && defined(__UCLIBC_HAS_XLOCALE__)
703
704 wint_t towctrans(wint_t wc, wctrans_t desc)
705 {
706         return towctrans_l(wc, desc, __UCLIBC_CURLOCALE);
707 }
708
709 #else  /* defined(L_towctrans) && defined(__UCLIBC_HAS_XLOCALE__) */
710
711 #ifdef SMALL_UPLOW
712
713 wint_t TOWCTRANS(wint_t wc, wctrans_t desc)
714 {
715         unsigned sc, n, i;
716         __uwchar_t u = wc;
717
718         /* TODO - clean up */
719         if (ENCODING == __ctype_encoding_7_bit) {
720                 if ((__uwchar_t)wc > 0x7f
721                  || (unsigned)(desc - _CTYPE_tolower) > (_CTYPE_toupper - _CTYPE_tolower)
722                 ) {
723                         /* We're in the C/POSIX locale, so ignore non-ASCII values
724                          * as well an any mappings other than toupper or tolower. */
725                         return wc;
726                 }
727         }
728
729         if ((unsigned)(desc - _CTYPE_tolower) <= (_CTYPE_totitle - _CTYPE_tolower)) {
730                 if (u <= WC_TABLE_DOMAIN_MAX) {
731                         sc = u & ((1 << WCuplow_TI_SHIFT) - 1);
732                         u >>= WCuplow_TI_SHIFT;
733                         n = u & ((1 << WCuplow_II_SHIFT) - 1);
734                         u >>= WCuplow_II_SHIFT;
735
736                         i = ((unsigned) WCuplow[u]) << WCuplow_II_SHIFT;
737                         i = ((unsigned) WCuplow[WCuplow_II_LEN + i + n]) << WCuplow_TI_SHIFT;
738                         i = ((unsigned) WCuplow[WCuplow_II_LEN + WCuplow_TI_LEN + i + sc]) << 1;
739                         if (desc == _CTYPE_tolower) {
740                                 ++i;
741                         }
742                         wc += WCuplow_diff[i];
743                         if (desc == _CTYPE_totitle) {
744 #ifdef __UCLIBC_MJN3_ONLY__
745 # warning TODO: Verify totitle special cases!
746 #endif
747                                 /* WARNING! These special cases work for glibc 2.2.4.  Changes
748                                  * may be needed if the glibc locale tables are updated. */
749                                 if ((__uwchar_t)(wc - 0x1c4) <= (0x1cc - 0x1c4)
750                                  || wc == 0x1f1
751                                 ) {
752                                         ++wc;
753                                 }
754                         }
755                 }
756         } else {
757                 /* TODO - Deal with other transliterations. */
758                 __set_errno(EINVAL);
759         }
760
761         return wc;
762 }
763
764 #else  /* SMALL_UPLOW */
765
766 wint_t TOWCTRANS(wint_t wc, wctrans_t desc)
767 {
768         if (ENCODING == __ctype_encoding_7_bit) {
769                 if ((__uwchar_t)wc > 0x7f
770                  || (unsigned)(desc - _CTYPE_tolower) > (_CTYPE_toupper - _CTYPE_tolower)
771                 ) {
772                         /* We're in the C/POSIX locale, so ignore non-ASCII values
773                          * as well an any mappings other than toupper or tolower. */
774                         return wc;
775                 }
776         }
777
778         if (desc == _CTYPE_tolower) {
779                 return TOWLOWER(wc, __UCLIBC_CURLOCALE);
780         }
781         if ((unsigned)(desc - _CTYPE_toupper) <= (_CTYPE_totitle - _CTYPE_toupper)) {
782                 wc = TOWUPPER(wc, __UCLIBC_CURLOCALE);
783                 if (desc == _CTYPE_totitle) {
784 #ifdef __UCLIBC_MJN3_ONLY__
785 # warning TODO: Verify totitle special cases!
786 #endif
787                         /* WARNING! These special cases work for glibc 2.2.4.  Changes
788                          * may be needed if the glibc locale tables are updated. */
789                         if ((__uwchar_t)(wc - 0x1c4) <= (0x1cc - 0x1c4)
790                          || wc == 0x1f1
791                         ) {
792                                 ++wc;
793                         }
794                 }
795         } else {
796                 /* TODO - Deal with other transliterations. */
797                 __set_errno(EINVAL);
798         }
799         return wc;
800 }
801
802 #endif /* SMALL_UPLOW */
803
804 #endif /* defined(L_towctrans) && defined(__UCLIBC_HAS_XLOCALE__) */
805
806 #ifdef L_towctrans_l
807 libc_hidden_def(towctrans_l)
808 #endif
809
810 #endif /* __LOCALE_C_ONLY */
811
812 #ifndef L_towctrans_l
813 libc_hidden_def(towctrans)
814 #endif
815
816 #endif
817 /**********************************************************************/
818 #ifdef L_wctrans
819
820 static const char transstring[] = __CTYPE_TRANSTRING;
821
822 wctrans_t wctrans(const char *property)
823 {
824         const unsigned char *p;
825         int i;
826
827         p = (const unsigned char *) transstring;
828         i = 1;
829         do {
830                 if (!strcmp(property, (const char*) ++p)) {
831                         return i;
832                 }
833                 ++i;
834                 p += p[-1];
835         } while (*p);
836
837         /* TODO - Add locale-specific translations. */
838         return 0;
839 }
840 libc_hidden_def(wctrans)
841
842 #endif
843 /**********************************************************************/
844 #ifdef L_wctrans_l
845
846 # ifdef __UCLIBC_MJN3_ONLY__
847 #  warning REMINDER: Currently wctrans_l simply calls wctrans.
848 # endif
849
850 wctrans_t wctrans_l(const char *property, __locale_t locale)
851 {
852         return wctrans(property);
853 }
854
855 #endif
856 /**********************************************************************/