1 // std::ctype implementation details, newlib version -*- C++ -*-
2 
3 // Copyright (C) 2011-2020 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 
34 namespace 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.
ctype_byname(const char * __s,size_t __refs)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 
~ctype_byname()50   ctype_byname<char>::~ctype_byname()
51   { }
52 
53 #ifdef _GLIBCXX_USE_WCHAR_T
54   ctype<wchar_t>::__wmask_type
_M_convert_to_wmask(const mask __m) const55   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
do_toupper(wchar_t __c) const113   ctype<wchar_t>::do_toupper(wchar_t __c) const
114   { return towupper(__c); }
115 
116   const wchar_t*
do_toupper(wchar_t * __lo,const wchar_t * __hi) const117   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
do_tolower(wchar_t __c) const128   ctype<wchar_t>::do_tolower(wchar_t __c) const
129   { return towlower(__c); }
130 
131   const wchar_t*
do_tolower(wchar_t * __lo,const wchar_t * __hi) const132   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>::
do_is(mask __m,wchar_t __c) const144   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>::
do_is(const wchar_t * __lo,const wchar_t * __hi,mask * __vec) const161   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>::
do_scan_is(mask __m,const wchar_t * __lo,const wchar_t * __hi) const178   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>::
do_scan_not(mask __m,const char_type * __lo,const char_type * __hi) const187   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>::
do_widen(char __c) const196   do_widen(char __c) const
197   { return _M_widen[static_cast<unsigned char>(__c)]; }
198 
199   const char*
200   ctype<wchar_t>::
do_widen(const char * __lo,const char * __hi,wchar_t * __dest) const201   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>::
do_narrow(wchar_t __wc,char __dfault) const214   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>::
do_narrow(const wchar_t * __lo,const wchar_t * __hi,char __dfault,char * __dest) const224   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
_M_initialize_ctype()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