1// std::ctype implementation details, GNU version -*- C++ -*-
2
3// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
4// Free Software Foundation, Inc.
5//
6// This file is part of the GNU ISO C++ Library.  This library is free
7// software; you can redistribute it and/or modify it under the
8// terms of the GNU General Public License as published by the
9// Free Software Foundation; either version 3, or (at your option)
10// any later version.
11
12// This library is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15// GNU General Public License for more details.
16
17// Under Section 7 of GPL version 3, you are granted additional
18// permissions described in the GCC Runtime Library Exception, version
19// 3.1, as published by the Free Software Foundation.
20
21// You should have received a copy of the GNU General Public License and
22// a copy of the GCC Runtime Library Exception along with this program;
23// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24// <http://www.gnu.org/licenses/>.
25
26//
27// ISO C++ 14882: 22.2.1.1.2  ctype virtual functions.
28//
29
30// Written by Benjamin Kosnik <bkoz@redhat.com>
31
32#include <locale>
33#include <cstdio>
34#include <bits/c++locale_internal.h>
35
36_GLIBCXX_BEGIN_NAMESPACE(std)
37
38  // NB: The other ctype<char> specializations are in src/locale.cc and
39  // various /config/os/* files.
40  ctype_byname<char>::ctype_byname(const char* __s, size_t __refs)
41  : ctype<char>(0, false, __refs)
42  {
43    if (std::strcmp(__s, "C") != 0 && std::strcmp(__s, "POSIX") != 0)
44      {
45	this->_S_destroy_c_locale(this->_M_c_locale_ctype);
46	this->_S_create_c_locale(this->_M_c_locale_ctype, __s);
47	this->_M_toupper = this->_M_c_locale_ctype->__ctype_toupper;
48	this->_M_tolower = this->_M_c_locale_ctype->__ctype_tolower;
49	this->_M_table = this->_M_c_locale_ctype->__ctype_b;
50      }
51  }
52
53  ctype_byname<char>::~ctype_byname()
54  { }
55
56#ifdef _GLIBCXX_USE_WCHAR_T
57  ctype<wchar_t>::__wmask_type
58  ctype<wchar_t>::_M_convert_to_wmask(const mask __m) const throw()
59  {
60    __wmask_type __ret;
61    switch (__m)
62      {
63      case space:
64	__ret = __wctype_l("space", _M_c_locale_ctype);
65	break;
66      case print:
67	__ret = __wctype_l("print", _M_c_locale_ctype);
68	break;
69      case cntrl:
70	__ret = __wctype_l("cntrl", _M_c_locale_ctype);
71	break;
72      case upper:
73	__ret = __wctype_l("upper", _M_c_locale_ctype);
74	break;
75      case lower:
76	__ret = __wctype_l("lower", _M_c_locale_ctype);
77	break;
78      case alpha:
79	__ret = __wctype_l("alpha", _M_c_locale_ctype);
80	break;
81      case digit:
82	__ret = __wctype_l("digit", _M_c_locale_ctype);
83	break;
84      case punct:
85	__ret = __wctype_l("punct", _M_c_locale_ctype);
86	break;
87      case xdigit:
88	__ret = __wctype_l("xdigit", _M_c_locale_ctype);
89	break;
90      case alnum:
91	__ret = __wctype_l("alnum", _M_c_locale_ctype);
92	break;
93      case graph:
94	__ret = __wctype_l("graph", _M_c_locale_ctype);
95	break;
96      default:
97	__ret = __wmask_type();
98      }
99    return __ret;
100  }
101
102  wchar_t
103  ctype<wchar_t>::do_toupper(wchar_t __c) const
104  { return __towupper_l(__c, _M_c_locale_ctype); }
105
106  const wchar_t*
107  ctype<wchar_t>::do_toupper(wchar_t* __lo, const wchar_t* __hi) const
108  {
109    while (__lo < __hi)
110      {
111        *__lo = __towupper_l(*__lo, _M_c_locale_ctype);
112        ++__lo;
113      }
114    return __hi;
115  }
116
117  wchar_t
118  ctype<wchar_t>::do_tolower(wchar_t __c) const
119  { return __towlower_l(__c, _M_c_locale_ctype); }
120
121  const wchar_t*
122  ctype<wchar_t>::do_tolower(wchar_t* __lo, const wchar_t* __hi) const
123  {
124    while (__lo < __hi)
125      {
126        *__lo = __towlower_l(*__lo, _M_c_locale_ctype);
127        ++__lo;
128      }
129    return __hi;
130  }
131
132  bool
133  ctype<wchar_t>::
134  do_is(mask __m, wchar_t __c) const
135  {
136    // The case of __m == ctype_base::space is particularly important,
137    // due to its use in many istream functions.  Therefore we deal with
138    // it first, exploiting the knowledge that on GNU systems _M_bit[5]
139    // is the mask corresponding to ctype_base::space.  NB: an encoding
140    // change would not affect correctness!
141    bool __ret = false;
142    if (__m == _M_bit[5])
143      __ret = __iswctype_l(__c, _M_wmask[5], _M_c_locale_ctype);
144    else
145      {
146	// Highest bitmask in ctype_base == 10, but extra in "C"
147	// library for blank.
148	const size_t __bitmasksize = 11;
149	for (size_t __bitcur = 0; __bitcur <= __bitmasksize; ++__bitcur)
150	  if (__m & _M_bit[__bitcur])
151	    {
152	      if (__iswctype_l(__c, _M_wmask[__bitcur], _M_c_locale_ctype))
153		{
154		  __ret = true;
155		  break;
156		}
157	      else if (__m == _M_bit[__bitcur])
158		break;
159	    }
160      }
161    return __ret;
162  }
163
164  const wchar_t*
165  ctype<wchar_t>::
166  do_is(const wchar_t* __lo, const wchar_t* __hi, mask* __vec) const
167  {
168    for (; __lo < __hi; ++__vec, ++__lo)
169      {
170	// Highest bitmask in ctype_base == 10, but extra in "C"
171	// library for blank.
172	const size_t __bitmasksize = 11;
173	mask __m = 0;
174	for (size_t __bitcur = 0; __bitcur <= __bitmasksize; ++__bitcur)
175	  if (__iswctype_l(*__lo, _M_wmask[__bitcur], _M_c_locale_ctype))
176	    __m |= _M_bit[__bitcur];
177	*__vec = __m;
178      }
179    return __hi;
180  }
181
182  const wchar_t*
183  ctype<wchar_t>::
184  do_scan_is(mask __m, const wchar_t* __lo, const wchar_t* __hi) const
185  {
186    while (__lo < __hi && !this->do_is(__m, *__lo))
187      ++__lo;
188    return __lo;
189  }
190
191  const wchar_t*
192  ctype<wchar_t>::
193  do_scan_not(mask __m, const char_type* __lo, const char_type* __hi) const
194  {
195    while (__lo < __hi && this->do_is(__m, *__lo) != 0)
196      ++__lo;
197    return __lo;
198  }
199
200  wchar_t
201  ctype<wchar_t>::
202  do_widen(char __c) const
203  { return _M_widen[static_cast<unsigned char>(__c)]; }
204
205  const char*
206  ctype<wchar_t>::
207  do_widen(const char* __lo, const char* __hi, wchar_t* __dest) const
208  {
209    while (__lo < __hi)
210      {
211	*__dest = _M_widen[static_cast<unsigned char>(*__lo)];
212	++__lo;
213	++__dest;
214      }
215    return __hi;
216  }
217
218  char
219  ctype<wchar_t>::
220  do_narrow(wchar_t __wc, char __dfault) const
221  {
222    if (__wc >= 0 && __wc < 128 && _M_narrow_ok)
223      return _M_narrow[__wc];
224#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
225    __c_locale __old = __uselocale(_M_c_locale_ctype);
226#endif
227    const int __c = wctob(__wc);
228#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
229    __uselocale(__old);
230#endif
231    return (__c == EOF ? __dfault : static_cast<char>(__c));
232  }
233
234  const wchar_t*
235  ctype<wchar_t>::
236  do_narrow(const wchar_t* __lo, const wchar_t* __hi, char __dfault,
237	    char* __dest) const
238  {
239#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
240    __c_locale __old = __uselocale(_M_c_locale_ctype);
241#endif
242    if (_M_narrow_ok)
243      while (__lo < __hi)
244	{
245	  if (*__lo >= 0 && *__lo < 128)
246	    *__dest = _M_narrow[*__lo];
247	  else
248	    {
249	      const int __c = wctob(*__lo);
250	      *__dest = (__c == EOF ? __dfault : static_cast<char>(__c));
251	    }
252	  ++__lo;
253	  ++__dest;
254	}
255    else
256      while (__lo < __hi)
257	{
258	  const int __c = wctob(*__lo);
259	  *__dest = (__c == EOF ? __dfault : static_cast<char>(__c));
260	  ++__lo;
261	  ++__dest;
262	}
263#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
264    __uselocale(__old);
265#endif
266    return __hi;
267  }
268
269  void
270  ctype<wchar_t>::_M_initialize_ctype() throw()
271  {
272#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
273    __c_locale __old = __uselocale(_M_c_locale_ctype);
274#endif
275    wint_t __i;
276    for (__i = 0; __i < 128; ++__i)
277      {
278	const int __c = wctob(__i);
279	if (__c == EOF)
280	  break;
281	else
282	  _M_narrow[__i] = static_cast<char>(__c);
283      }
284    if (__i == 128)
285      _M_narrow_ok = true;
286    else
287      _M_narrow_ok = false;
288    for (size_t __j = 0;
289	 __j < sizeof(_M_widen) / sizeof(wint_t); ++__j)
290      _M_widen[__j] = btowc(__j);
291
292    for (size_t __k = 0; __k <= 11; ++__k)
293      {
294	_M_bit[__k] = static_cast<mask>(_ISbit(__k));
295	_M_wmask[__k] = _M_convert_to_wmask(_M_bit[__k]);
296      }
297#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
298    __uselocale(__old);
299#endif
300  }
301#endif //  _GLIBCXX_USE_WCHAR_T
302
303_GLIBCXX_END_NAMESPACE
304