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