]> git.lyx.org Git - lyx.git/blob - src/support/docstring.C
Add operator += for ASCII C strings and single ASCII chars
[lyx.git] / src / support / docstring.C
1 /**
2  * \file docstring.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Georg Baum
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "docstring.h"
14 #include "unicode.h"
15
16 #include <locale>
17
18 #include <boost/assert.hpp>
19
20
21 namespace lyx {
22
23 docstring const from_ascii(char const * ascii)
24 {
25         docstring s;
26         for (char const * c = ascii; *c; ++c) {
27                 BOOST_ASSERT(static_cast<unsigned char>(*c) < 0x80);
28                 s.push_back(*c);
29         }
30         return s;
31 }
32
33
34 docstring const from_ascii(std::string const & ascii)
35 {
36         int const len = ascii.length();
37         for (int i = 0; i < len; ++i)
38                 BOOST_ASSERT(static_cast<unsigned char>(ascii[i]) < 0x80);
39         return docstring(ascii.begin(), ascii.end());
40 }
41
42
43 std::string const to_ascii(docstring const & ucs4)
44 {
45         int const len = ucs4.length();
46         std::string ascii;
47         ascii.resize(len);
48         for (int i = 0; i < len; ++i) {
49                 BOOST_ASSERT(ucs4[i] < 0x80);
50                 ascii[i] = static_cast<char>(ucs4[i]);
51         }
52         return ascii;
53 }
54
55
56 docstring const from_utf8(std::string const & utf8)
57 {
58         std::vector<lyx::char_type> const ucs4 =
59                 utf8_to_ucs4(utf8.data(), utf8.size());
60         return docstring(ucs4.begin(), ucs4.end());
61 }
62
63
64 std::string const to_utf8(docstring const & ucs4)
65 {
66         std::vector<char> const utf8 =
67                 ucs4_to_utf8(ucs4.data(), ucs4.size());
68         return std::string(utf8.begin(), utf8.end());
69 }
70
71 }
72
73
74 bool operator==(lyx::docstring const & l, char const * r)
75 {
76         int const len = l.length();
77         for (int i = 0; i < len; ++i) {
78                 BOOST_ASSERT(static_cast<unsigned char>(r[i]) < 0x80);
79                 if (!r[i])
80                         return false;
81                 if (l[i] != lyx::docstring::value_type(r[i]))
82                         return false;
83         }
84         return r[len] == '\0';
85 }
86
87
88 lyx::docstring operator+(lyx::docstring const & l, char const * r)
89 {
90         lyx::docstring s(l);
91         for (char const * c = r; *c; ++c) {
92                 BOOST_ASSERT(static_cast<unsigned char>(*c) < 0x80);
93                 s.push_back(*c);
94         }
95         return s;
96 }
97
98
99 lyx::docstring operator+(char const * l, lyx::docstring const & r)
100 {
101         lyx::docstring s;
102         for (char const * c = l; *c; ++c) {
103                 BOOST_ASSERT(static_cast<unsigned char>(*c) < 0x80);
104                 s.push_back(*c);
105         }
106         s += r;
107         return s;
108 }
109
110
111 lyx::docstring operator+(lyx::docstring const & l, char r)
112 {
113         BOOST_ASSERT(static_cast<unsigned char>(r) < 0x80);
114         return l + lyx::docstring::value_type(r);
115 }
116
117
118 lyx::docstring operator+(char l, lyx::docstring const & r)
119 {
120         BOOST_ASSERT(static_cast<unsigned char>(l) < 0x80);
121         return lyx::docstring::value_type(l) + r;
122 }
123
124
125 lyx::docstring operator+=(lyx::docstring & l, char const * r)
126 {
127         for (char const * c = r; *c; ++c) {
128                 BOOST_ASSERT(static_cast<unsigned char>(*c) < 0x80);
129                 l.push_back(*c);
130         }
131         return l;
132 }
133
134
135 lyx::docstring operator+=(lyx::docstring & l, char r)
136 {
137         BOOST_ASSERT(static_cast<unsigned char>(r) < 0x80);
138         l.push_back(r);
139         return l;
140 }
141
142
143 #if (!defined(HAVE_WCHAR_T) || SIZEOF_WCHAR_T != 4) && defined(__GNUC__)
144
145 // gcc does not have proper locale facets for lyx::char_type if
146 // sizeof(wchar_t) == 2, so we have to implement them on our own.
147
148
149 // We get undefined references to these virtual methods. This looks like
150 // a bug in gcc. The implementation here does not do anything useful, since
151 // it is overriden in ascii_ctype_facet.
152 namespace std {
153 template<> ctype<lyx::char_type>::~ctype() {}
154 template<> bool
155 ctype<lyx::char_type>::do_is(ctype<lyx::char_type>::mask, lyx::char_type) const { return false; }
156 template<> lyx::char_type const *
157 ctype<lyx::char_type>::do_is(const lyx::char_type *, const lyx::char_type *, ctype<lyx::char_type>::mask *) const { return 0; }
158 template<> const lyx::char_type *
159 ctype<lyx::char_type>::do_scan_is(ctype<lyx::char_type>::mask, const lyx::char_type *, const lyx::char_type *) const { return 0; }
160 template<> const lyx::char_type *
161 ctype<lyx::char_type>::do_scan_not(ctype<lyx::char_type>::mask, const lyx::char_type *, const lyx::char_type *) const { return 0; }
162 template<> lyx::char_type ctype<lyx::char_type>::do_toupper(lyx::char_type) const { return 0; }
163 template<> const lyx::char_type * ctype<lyx::char_type>::do_toupper(lyx::char_type *, lyx::char_type const *) const { return 0; }
164 template<> lyx::char_type ctype<lyx::char_type>::do_tolower(lyx::char_type) const { return 0; }
165 template<> const lyx::char_type * ctype<lyx::char_type>::do_tolower(lyx::char_type *, lyx::char_type const *) const { return 0; }
166 template<> lyx::char_type ctype<lyx::char_type>::do_widen(char) const { return 0; }
167 template<> const char *
168 ctype<lyx::char_type>::do_widen(const char *, const char *, lyx::char_type *) const { return 0; }
169 template<> char
170 ctype<lyx::char_type>::do_narrow(const lyx::char_type, char) const { return 0; }
171 template<> const lyx::char_type *
172 ctype<lyx::char_type>::do_narrow(const lyx::char_type *, const lyx::char_type *, char, char *) const { return 0; }
173 }
174
175
176 namespace lyx {
177
178 class ctype_failure : public std::bad_cast {
179 public:
180         ctype_failure() throw() : std::bad_cast() {}
181         virtual ~ctype_failure() throw() {}
182         virtual const char* what() const throw()
183         {
184                 return "The ctype<lyx::char_type> locale facet does only support ASCII characters on this platform.";
185         }
186 };
187
188
189 /// ctype facet for UCS4 characters. The implementation does only support pure
190 /// ASCII, since we do not need anything else for now.
191 /// The code is partly stolen from std::ctype<wchar_t> from gcc.
192 class ascii_ctype_facet : public std::ctype<lyx::char_type>
193 {
194 public:
195         typedef lyx::char_type char_type;
196         typedef wctype_t wmask_type;
197         explicit ascii_ctype_facet(size_t refs = 0) : std::ctype<char_type>(refs)
198         {
199                 M_initialize_ctype();
200         }
201 protected:
202         bool       M_narrow_ok;
203         char       M_narrow[128];
204         wint_t     M_widen[1 + static_cast<unsigned char>(-1)];
205         mask       M_bit[16];
206         wmask_type M_wmask[16];
207         wmask_type M_convert_to_wmask(const mask m) const
208         {
209                 wmask_type ret;
210                 switch (m) {
211                         case space:  ret = wctype("space");  break;
212                         case print:  ret = wctype("print");  break;
213                         case cntrl:  ret = wctype("cntrl");  break;
214                         case upper:  ret = wctype("upper");  break;
215                         case lower:  ret = wctype("lower");  break;
216                         case alpha:  ret = wctype("alpha");  break;
217                         case digit:  ret = wctype("digit");  break;
218                         case punct:  ret = wctype("punct");  break;
219                         case xdigit: ret = wctype("xdigit"); break;
220                         case alnum:  ret = wctype("alnum");  break;
221                         case graph:  ret = wctype("graph");  break;
222                         default:     ret = wmask_type();
223                 }
224                 return ret;
225         }
226         void M_initialize_ctype()
227         {
228                 wint_t i;
229                 for (i = 0; i < 128; ++i) {
230                         const int c = wctob(i);
231                         if (c == EOF)
232                                 break;
233                         else
234                                 M_narrow[i] = static_cast<char>(c);
235                 }
236                 if (i == 128)
237                         M_narrow_ok = true;
238                 else
239                         M_narrow_ok = false;
240                 for (size_t i = 0; i < sizeof(M_widen) / sizeof(wint_t); ++i)
241                         M_widen[i] = btowc(i);
242
243                 for (size_t i = 0; i <= 15; ++i) {
244                         M_bit[i] = static_cast<mask>(1 << i);
245                         M_wmask[i] = M_convert_to_wmask(M_bit[i]);
246                 }
247         }
248         virtual ~ascii_ctype_facet() {}
249         char_type do_toupper(char_type c) const
250         {
251                 if (c >= 0x80)
252                         throw ctype_failure();
253                 return toupper(static_cast<int>(c));
254         }
255         char_type const * do_toupper(char_type * lo, char_type const * hi) const
256         {
257                 while (lo < hi) {
258                         if (*lo >= 0x80)
259                                 throw ctype_failure();
260                         *lo = toupper(static_cast<int>(*lo));
261                         ++lo;
262                 }
263                 return hi;
264         }
265         char_type do_tolower(char_type c) const
266         {
267                 if (c >= 0x80)
268                         throw ctype_failure();
269                 return tolower(c);
270         }
271         char_type const * do_tolower(char_type * lo, char_type const * hi) const
272         {
273                 while (lo < hi) {
274                         if (*lo >= 0x80)
275                                 throw ctype_failure();
276                         *lo = tolower(*lo);
277                         ++lo;
278                 }
279                 return hi;
280         }
281         bool do_is(mask m, char_type c) const
282         {
283                 if (c >= 0x80)
284                         throw ctype_failure();
285                 // The code below works because c is in the ASCII range.
286                 // We could not use iswctype() which is designed for a 2byte
287                 // whar_t without encoding conversion otherwise.
288                 bool ret = false;
289                 // Generically, 15 (instead of 10) since we don't know the numerical
290                 // encoding of the various categories in /usr/include/ctype.h.
291                 const size_t bitmasksize = 15;
292                 for (size_t bitcur = 0; bitcur <= bitmasksize; ++bitcur)
293                         if (m & M_bit[bitcur] &&
294                             iswctype(static_cast<int>(c), M_wmask[bitcur])) {
295                                 ret = true;
296                                 break;
297                         }
298                 return ret;
299         }
300         char_type const * do_is(char_type const * lo, char_type const * hi, mask * vec) const
301         {
302                 for (;lo < hi; ++vec, ++lo) {
303                         if (*lo >= 0x80)
304                                 throw ctype_failure();
305                         // The code below works because c is in the ASCII range.
306                         // We could not use iswctype() which is designed for a 2byte
307                         // whar_t without encoding conversion otherwise.
308                         // Generically, 15 (instead of 10) since we don't know the numerical
309                         // encoding of the various categories in /usr/include/ctype.h.
310                         const size_t bitmasksize = 15;
311                         mask m = 0;
312                         for (size_t bitcur = 0; bitcur <= bitmasksize; ++bitcur)
313                                 if (iswctype(static_cast<int>(*lo), M_wmask[bitcur]))
314                                         m |= M_bit[bitcur];
315                         *vec = m;
316                 }
317                 return hi;
318         }
319         char_type const * do_scan_is(mask m, char_type const * lo, char_type const * hi) const
320         {
321                 while (lo < hi && !this->do_is(m, *lo))
322                         ++lo;
323                 return lo;
324         }
325         char_type const * do_scan_not(mask m, char_type const * lo, char_type const * hi) const
326         {
327                 while (lo < hi && this->do_is(m, *lo) != 0)
328                         ++lo;
329                 return lo;
330         }
331         char_type do_widen(char c) const
332         {
333                 if (static_cast<unsigned char>(c) < 0x80)
334                         return c;
335                 throw ctype_failure();
336         }
337         const char* do_widen(const char* lo, const char* hi, char_type* dest) const
338         {
339                 while (lo < hi) {
340                         if (static_cast<unsigned char>(*lo) >= 0x80)
341                                 throw ctype_failure();
342                         *dest = *lo;
343                         ++lo;
344                         ++dest;
345                 }
346                 return hi;
347         }
348         char do_narrow(char_type wc, char) const
349         {
350                 if (wc < 0x80)
351                         return static_cast<char>(wc);
352                 throw ctype_failure();
353         }
354         const char_type * do_narrow(const char_type * lo, const char_type * hi, char, char * dest) const
355         {
356                 while (lo < hi) {
357                         if (*lo < 0x80)
358                                 *dest = static_cast<char>(*lo);
359                         else
360                                 throw ctype_failure();
361                         ++lo;
362                         ++dest;
363                 }
364                 return hi;
365         }
366 };
367
368
369 /// class to add our ascii_ctype_facet to the global locale
370 class locale_initializer {
371 public:
372         locale_initializer()
373         {
374                 std::locale global;
375                 std::locale const loc(global, new ascii_ctype_facet);
376                 std::locale::global(loc);
377         }
378 };
379
380
381 namespace {
382
383 /// make sure that our ascii_ctype_facet gets used
384 static locale_initializer initializer;
385
386 }
387 }
388 #endif