1// std::ctype implementation details, newlib version -*- C++ -*-
2
3// Copyright (C) 2011-2015 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library.  This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23// <http://www.gnu.org/licenses/>.
24
25//
26// ISO C++ 14882: 22.2.1.1.2  ctype virtual functions.
27//
28
29#include <locale>
30#include <cstdlib>
31#include <cstring>
32#include <cstdio>
33
34namespace std _GLIBCXX_VISIBILITY(default)
35{
36_GLIBCXX_BEGIN_NAMESPACE_VERSION
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      }
48  }
49
50  ctype_byname<char>::~ctype_byname()
51  { }
52
53#ifdef _GLIBCXX_USE_WCHAR_T
54  ctype<wchar_t>::__wmask_type
55  ctype<wchar_t>::_M_convert_to_wmask(const mask __m) const throw()
56  {
57    __wmask_type __ret;
58    switch (__m)
59      {
60      case space:
61	__ret = wctype("space");
62	break;
63      case print:
64	__ret = wctype("print");
65	break;
66      case cntrl:
67	__ret = wctype("cntrl");
68	break;
69      case upper:
70	__ret = wctype("upper");
71	break;
72      case lower:
73	__ret = wctype("lower");
74	break;
75      case alpha:
76	__ret = wctype("alpha");
77	break;
78      case digit:
79	__ret = wctype("digit");
80	break;
81      case punct:
82	__ret = wctype("punct");
83	break;
84      case xdigit:
85	__ret = wctype("xdigit");
86	break;
87      case alnum:
88	__ret = wctype("alnum");
89	break;
90      case graph:
91	__ret = wctype("graph");
92	break;
93      default:
94	// Different from the generic version, xdigit and print in
95	// newlib are defined as bitwise-OR result of bitmasks:
96	//   xdigit = _X | _N;
97	//   print  = _P | _U | _L | _N | _B;
98	// in which _X and _B don't correspond to any ctype mask.
99	// In order to get the wmask correctly converted when __m is
100	// equal to _X or _B, the two cases are specifically handled
101	// here.
102	if (__m & xdigit)
103	  __ret = wctype("xdigit");
104	else if (__m & print)
105	  __ret = wctype("print");
106	else
107	  __ret = __wmask_type();
108      }
109    return __ret;
110  };
111
112  wchar_t
113  ctype<wchar_t>::do_toupper(wchar_t __c) const
114  { return towupper(__c); }
115
116  const wchar_t*
117  ctype<wchar_t>::do_toupper(wchar_t* __lo, const wchar_t* __hi) const
118  {
119    while (__lo < __hi)
120      {
121        *__lo = towupper(*__lo);
122        ++__lo;
123      }
124    return __hi;
125  }
126
127  wchar_t
128  ctype<wchar_t>::do_tolower(wchar_t __c) const
129  { return towlower(__c); }
130
131  const wchar_t*
132  ctype<wchar_t>::do_tolower(wchar_t* __lo, const wchar_t* __hi) const
133  {
134    while (__lo < __hi)
135      {
136        *__lo = towlower(*__lo);
137        ++__lo;
138      }
139    return __hi;
140  }
141
142  bool
143  ctype<wchar_t>::
144  do_is(mask __m, wchar_t __c) const
145  {
146    bool __ret = false;
147    // Newlib C library has a compact encoding that uses 8 bits only.
148    const size_t __bitmasksize = 7;
149    for (size_t __bitcur = 0; __bitcur <= __bitmasksize; ++__bitcur)
150      if (__m & _M_bit[__bitcur]
151	  && iswctype(__c, _M_wmask[__bitcur]))
152	{
153	  __ret = true;
154	  break;
155	}
156    return __ret;
157  }
158
159  const wchar_t*
160  ctype<wchar_t>::
161  do_is(const wchar_t* __lo, const wchar_t* __hi, mask* __vec) const
162  {
163    for (; __lo < __hi; ++__vec, ++__lo)
164      {
165	// Newlib C library has a compact encoding that uses 8 bits only.
166	const size_t __bitmasksize = 7;
167	mask __m = 0;
168	for (size_t __bitcur = 0; __bitcur <= __bitmasksize; ++__bitcur)
169	  if (iswctype(*__lo, _M_wmask[__bitcur]))
170	    __m |= _M_bit[__bitcur];
171	*__vec = __m;
172      }
173    return __hi;
174  }
175
176  const wchar_t*
177  ctype<wchar_t>::
178  do_scan_is(mask __m, const wchar_t* __lo, const wchar_t* __hi) const
179  {
180    while (__lo < __hi && !this->do_is(__m, *__lo))
181      ++__lo;
182    return __lo;
183  }
184
185  const wchar_t*
186  ctype<wchar_t>::
187  do_scan_not(mask __m, const char_type* __lo, const char_type* __hi) const
188  {
189    while (__lo < __hi && this->do_is(__m, *__lo) != 0)
190      ++__lo;
191    return __lo;
192  }
193
194  wchar_t
195  ctype<wchar_t>::
196  do_widen(char __c) const
197  { return _M_widen[static_cast<unsigned char>(__c)]; }
198
199  const char*
200  ctype<wchar_t>::
201  do_widen(const char* __lo, const char* __hi, wchar_t* __dest) const
202  {
203    while (__lo < __hi)
204      {
205	*__dest = _M_widen[static_cast<unsigned char>(*__lo)];
206	++__lo;
207	++__dest;
208      }
209    return __hi;
210  }
211
212  char
213  ctype<wchar_t>::
214  do_narrow(wchar_t __wc, char __dfault) const
215  {
216    if (__wc >= 0 && __wc < 128 && _M_narrow_ok)
217      return _M_narrow[__wc];
218    const int __c = wctob(__wc);
219    return (__c == EOF ? __dfault : static_cast<char>(__c));
220  }
221
222  const wchar_t*
223  ctype<wchar_t>::
224  do_narrow(const wchar_t* __lo, const wchar_t* __hi, char __dfault,
225	    char* __dest) const
226  {
227    if (_M_narrow_ok)
228      while (__lo < __hi)
229	{
230	  if (*__lo >= 0 && *__lo < 128)
231	    *__dest = _M_narrow[*__lo];
232	  else
233	    {
234	      const int __c = wctob(*__lo);
235	      *__dest = (__c == EOF ? __dfault : static_cast<char>(__c));
236	    }
237	  ++__lo;
238	  ++__dest;
239	}
240    else
241      while (__lo < __hi)
242	{
243	  const int __c = wctob(*__lo);
244	  *__dest = (__c == EOF ? __dfault : static_cast<char>(__c));
245	  ++__lo;
246	  ++__dest;
247	}
248    return __hi;
249  }
250
251  void
252  ctype<wchar_t>::_M_initialize_ctype() throw()
253  {
254    wint_t __i;
255    for (__i = 0; __i < 128; ++__i)
256      {
257	const int __c = wctob(__i);
258	if (__c == EOF)
259	  break;
260	else
261	  _M_narrow[__i] = static_cast<char>(__c);
262      }
263    if (__i == 128)
264      _M_narrow_ok = true;
265    else
266      _M_narrow_ok = false;
267    for (size_t __i = 0;
268	 __i < sizeof(_M_widen) / sizeof(wint_t); ++__i)
269      _M_widen[__i] = btowc(__i);
270
271    for (size_t __i = 0; __i <= 7; ++__i)
272      {
273	_M_bit[__i] = static_cast<mask>(1 << __i);
274	_M_wmask[__i] = _M_convert_to_wmask(_M_bit[__i]);
275      }
276  }
277#endif //  _GLIBCXX_USE_WCHAR_T
278
279_GLIBCXX_END_NAMESPACE_VERSION
280} // namespace
281