]> git.lyx.org Git - lyx.git/blob - src/support/lstrings.cpp
Fix layout bug. Pasting text into a cell tried to set Standard layout, because
[lyx.git] / src / support / lstrings.cpp
1 /**
2  * \file lstrings.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  * \author Jean-Marc Lasgouttes
8  * \author Dekel Tsur
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "support/lstrings.h"
16
17 #include "support/convert.h"
18 #include "support/qstring_helpers.h"
19 #include "support/textutils.h"
20
21 #include <boost/tokenizer.hpp>
22 #include "support/lassert.h"
23
24 #include <QString>
25 #include <QVector>
26
27 #include <algorithm>
28
29 using namespace std;
30
31 namespace lyx {
32
33 // Using this allows us to have docstring default arguments in headers
34 // without #include "support/docstring" there.
35 docstring const & empty_docstring()
36 {
37         static docstring s;
38         return s;
39 }
40
41 // Using this allows us to have string default arguments in headers
42 // without #include <string>
43 string const & empty_string()
44 {
45         static string s;
46         return s;
47 }
48
49 /**
50  * Convert a QChar into a UCS4 character.
51  * This is a hack (it does only make sense for the common part of the UCS4
52  * and UTF16 encodings) and should not be used.
53  * This does only exist because of performance reasons (a real conversion
54  * using iconv is too slow on windows).
55  */
56 static inline char_type qchar_to_ucs4(QChar const & qchar)
57 {
58         LASSERT(is_utf16(static_cast<char_type>(qchar.unicode())), /**/);
59         return static_cast<char_type>(qchar.unicode());
60 }
61
62
63 /**
64  * Convert a UCS4 character into a QChar.
65  * This is a hack (it does only make sense for the common part of the UCS4
66  * and UTF16 encodings) and should not be used.
67  * This does only exist because of performance reasons (a real conversion
68  * using iconv is too slow on windows).
69  */
70 static inline QChar const ucs4_to_qchar(char_type const ucs4)
71 {
72         LASSERT(is_utf16(ucs4), /**/);
73         return QChar(static_cast<unsigned short>(ucs4));
74 }
75
76
77 namespace {
78         /// Maximum valid UCS4 code point
79         char_type const ucs4_max = 0x10ffff;
80 }
81
82
83 bool isLetterChar(char_type c)
84 {
85         if (!is_utf16(c)) {
86                 if (c > ucs4_max)
87                         // outside the UCS4 range
88                         return false;
89                 // assume that all non-utf16 characters are letters
90                 return true;
91         }
92         return ucs4_to_qchar(c).isLetter();
93 }
94
95
96 bool isAlphaASCII(char_type c)
97 {
98         return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
99 }
100
101
102 bool isPrintable(char_type c)
103 {
104         if (!is_utf16(c)) {
105                 if (c > ucs4_max)
106                         // outside the UCS4 range
107                         return false;
108                 // assume that all non-utf16 characters are printable
109                 return true;
110         }
111         return ucs4_to_qchar(c).isPrint();
112 }
113
114
115 bool isPrintableNonspace(char_type c)
116 {
117         if (!is_utf16(c)) {
118                 if (c > ucs4_max)
119                         // outside the UCS4 range
120                         return false;
121                 // assume that all non-utf16 characters are printable and
122                 // no space
123                 return true;
124         }
125         QChar const qc = ucs4_to_qchar(c);
126         return qc.isPrint() && !qc.isSpace();
127 }
128
129
130 bool isSpace(char_type c)
131 {
132         if (!is_utf16(c)) {
133                 // assume that no non-utf16 character is a space
134                 // c outside the UCS4 range is catched as well
135                 return false;
136         }
137         QChar const qc = ucs4_to_qchar(c);
138         return qc.isSpace();
139 }
140
141
142 bool isDigit(char_type c)
143 {
144         if (!is_utf16(c))
145                 // assume that no non-utf16 character is a digit
146                 // c outside the UCS4 range is catched as well
147                 return false;
148         return ucs4_to_qchar(c).isDigit();
149 }
150
151
152 bool isDigitASCII(char_type c)
153 {
154         return '0' <= c && c <= '9';
155 }
156
157 namespace support {
158
159 int compare_no_case(docstring const & s, docstring const & s2)
160 {
161         docstring::const_iterator p = s.begin();
162         docstring::const_iterator p2 = s2.begin();
163
164         while (p != s.end() && p2 != s2.end()) {
165                 char_type const lc1 = lowercase(*p);
166                 char_type const lc2 = lowercase(*p2);
167                 if (lc1 != lc2)
168                         return (lc1 < lc2) ? -1 : 1;
169                 ++p;
170                 ++p2;
171         }
172
173         if (s.size() == s2.size())
174                 return 0;
175         if (s.size() < s2.size())
176                 return -1;
177         return 1;
178 }
179
180
181 namespace {
182
183 template<typename Char>
184 Char ascii_tolower(Char c) {
185         if (c >= 'A' && c <= 'Z')
186                 return c - 'A' + 'a';
187         return c;
188 }
189
190 }
191
192
193 int compare_ascii_no_case(string const & s, string const & s2)
194 {
195         string::const_iterator p = s.begin();
196         string::const_iterator p2 = s2.begin();
197
198         while (p != s.end() && p2 != s2.end()) {
199                 int const lc1 = ascii_tolower(*p);
200                 int const lc2 = ascii_tolower(*p2);
201                 if (lc1 != lc2)
202                         return (lc1 < lc2) ? -1 : 1;
203                 ++p;
204                 ++p2;
205         }
206
207         if (s.size() == s2.size())
208                 return 0;
209         if (s.size() < s2.size())
210                 return -1;
211         return 1;
212 }
213
214
215 int compare_ascii_no_case(docstring const & s, docstring const & s2)
216 {
217         docstring::const_iterator p = s.begin();
218         docstring::const_iterator p2 = s2.begin();
219
220         while (p != s.end() && p2 != s2.end()) {
221                 char_type const lc1 = ascii_tolower(*p);
222                 char_type const lc2 = ascii_tolower(*p2);
223                 if (lc1 != lc2)
224                         return (lc1 < lc2) ? -1 : 1;
225                 ++p;
226                 ++p2;
227         }
228
229         if (s.size() == s2.size())
230                 return 0;
231         if (s.size() < s2.size())
232                 return -1;
233         return 1;
234 }
235
236
237 bool isStrInt(string const & str)
238 {
239         if (str.empty())
240                 return false;
241
242         // Remove leading and trailing white space chars.
243         string const tmpstr = trim(str);
244         if (tmpstr.empty())
245                 return false;
246
247         string::const_iterator cit = tmpstr.begin();
248         if ((*cit) == '-')
249                 ++cit;
250
251         string::const_iterator end = tmpstr.end();
252         for (; cit != end; ++cit)
253                 if (!isdigit((*cit)))
254                         return false;
255
256         return true;
257 }
258
259
260 bool isStrUnsignedInt(string const & str)
261 {
262         if (str.empty())
263                 return false;
264
265         // Remove leading and trailing white space chars.
266         string const tmpstr = trim(str);
267         if (tmpstr.empty())
268                 return false;
269
270         string::const_iterator cit = tmpstr.begin();
271         string::const_iterator end = tmpstr.end();
272         for (; cit != end; ++cit)
273                 if (!isdigit((*cit)))
274                         return false;
275
276         return true;
277 }
278
279
280 bool isStrDbl(string const & str)
281 {
282         if (str.empty())
283                 return false;
284
285         // Remove leading and trailing white space chars.
286         string const tmpstr = trim(str);
287         if (tmpstr.empty())
288                 return false;
289         //      if (tmpstr.count('.') > 1) return false;
290
291         string::const_iterator cit = tmpstr.begin();
292         bool found_dot = false;
293         if (*cit == '-')
294                 ++cit;
295         string::const_iterator end = tmpstr.end();
296         for (; cit != end; ++cit) {
297                 if (!isdigit(*cit) && *cit != '.')
298                         return false;
299                 if ('.' == (*cit)) {
300                         if (found_dot)
301                                 return false;
302                         found_dot = true;
303                 }
304         }
305         return true;
306 }
307
308
309 static bool isHexChar(char_type c)
310 {
311         return c == '0' ||
312                 c == '1' ||
313                 c == '2' ||
314                 c == '3' ||
315                 c == '4' ||
316                 c == '5' ||
317                 c == '6' ||
318                 c == '7' ||
319                 c == '8' ||
320                 c == '9' ||
321                 c == 'a' || c == 'A' ||
322                 c == 'b' || c == 'B' ||
323                 c == 'c' || c == 'C' ||
324                 c == 'd' || c == 'D' ||
325                 c == 'e' || c == 'E' ||
326                 c == 'f' || c == 'F';
327 }
328
329
330 bool isHex(docstring const & str)
331 {
332         int index = 0;
333
334         if (str.length() > 2 && str[0] == '0' &&
335             (str[1] == 'x' || str[1] == 'X'))
336                 index = 2;
337
338         int const len = str.length();
339
340         for (; index < len; ++index) {
341                 if (!isHexChar(str[index]))
342                         return false;
343         }
344         return true;
345 }
346
347
348 int hexToInt(docstring const & str)
349 {
350         string s = to_ascii(str);
351         int h;
352         sscanf(s.c_str(), "%x", &h);
353         return h;
354 }
355
356
357 bool isAscii(docstring const & str)
358 {
359         int const len = str.length();
360         for (int i = 0; i < len; ++i)
361                 if (str[i] >= 0x80)
362                         return false;
363         return true;
364 }
365
366
367 bool isAscii(string const & str)
368 {
369         int const len = str.length();
370         for (int i = 0; i < len; ++i)
371                 if (static_cast<unsigned char>(str[i]) >= 0x80)
372                         return false;
373         return true;
374 }
375
376
377 char lowercase(char c)
378 {
379         LASSERT(static_cast<unsigned char>(c) < 0x80, /**/);
380         return char(tolower(c));
381 }
382
383
384 char uppercase(char c)
385 {
386         LASSERT(static_cast<unsigned char>(c) < 0x80, /**/);
387         return char(toupper(c));
388 }
389
390
391 char_type lowercase(char_type c)
392 {
393         if (!is_utf16(c))
394                 // We don't know how to lowercase a non-utf16 char
395                 return c;
396         return qchar_to_ucs4(ucs4_to_qchar(c).toLower());
397 }
398
399
400 char_type uppercase(char_type c)
401 {
402         if (!is_utf16(c))
403                 // We don't know how to uppercase a non-utf16 char
404                 return c;
405         return qchar_to_ucs4(ucs4_to_qchar(c).toUpper());
406 }
407
408
409 namespace {
410
411 // since we cannot use tolower and toupper directly in the
412 // calls to transform yet, we use these helper clases. (Lgb)
413
414 struct local_lowercase {
415         char_type operator()(char_type c) const {
416                 if (!is_utf16(c))
417                         // We don't know how to lowercase a non-utf16 char
418                         return c;
419                 return qchar_to_ucs4(ucs4_to_qchar(c).toLower());
420         }
421 };
422
423 struct local_uppercase {
424         char_type operator()(char_type c) const {
425                 if (!is_utf16(c))
426                         // We don't know how to uppercase a non-utf16 char
427                         return c;
428                 return qchar_to_ucs4(ucs4_to_qchar(c).toUpper());
429         }
430 };
431
432 template<typename Char> struct local_ascii_lowercase {
433         Char operator()(Char c) const { return ascii_tolower(c); }
434 };
435
436 } // end of anon namespace
437
438 docstring const lowercase(docstring const & a)
439 {
440         docstring tmp(a);
441         transform(tmp.begin(), tmp.end(), tmp.begin(), local_lowercase());
442         return tmp;
443 }
444
445
446 docstring const uppercase(docstring const & a)
447 {
448         docstring tmp(a);
449         transform(tmp.begin(), tmp.end(), tmp.begin(), local_uppercase());
450         return tmp;
451 }
452
453
454 string const ascii_lowercase(string const & a)
455 {
456         string tmp(a);
457         transform(tmp.begin(), tmp.end(), tmp.begin(),
458                   local_ascii_lowercase<char>());
459         return tmp;
460 }
461
462
463 docstring const ascii_lowercase(docstring const & a)
464 {
465         docstring tmp(a);
466         transform(tmp.begin(), tmp.end(), tmp.begin(),
467                   local_ascii_lowercase<char_type>());
468         return tmp;
469 }
470
471
472 bool prefixIs(docstring const & a, char_type c)
473 {
474         if (a.empty())
475                 return false;
476         return a[0] == c;
477 }
478
479
480 bool prefixIs(string const & a, string const & pre)
481 {
482         size_t const prelen = pre.length();
483         size_t const alen = a.length();
484         return prelen <= alen && !a.empty() && a.compare(0, prelen, pre) == 0;
485 }
486
487
488 bool prefixIs(docstring const & a, docstring const & pre)
489 {
490         size_t const prelen = pre.length();
491         size_t const alen = a.length();
492         return prelen <= alen && !a.empty() && a.compare(0, prelen, pre) == 0;
493 }
494
495
496 bool suffixIs(string const & a, char c)
497 {
498         if (a.empty()) 
499                 return false;
500         return a[a.length() - 1] == c;
501 }
502
503
504 bool suffixIs(docstring const & a, char_type c)
505 {
506         if (a.empty())
507                 return false;
508         return a[a.length() - 1] == c;
509 }
510
511
512 bool suffixIs(string const & a, string const & suf)
513 {
514         size_t const suflen = suf.length();
515         size_t const alen = a.length();
516         return suflen <= alen && a.compare(alen - suflen, suflen, suf) == 0;
517 }
518
519
520 bool suffixIs(docstring const & a, docstring const & suf)
521 {
522         size_t const suflen = suf.length();
523         size_t const alen = a.length();
524         return suflen <= alen && a.compare(alen - suflen, suflen, suf) == 0;
525 }
526
527
528 bool containsOnly(string const & s, string const & cset)
529 {
530         return s.find_first_not_of(cset) == string::npos;
531 }
532
533
534 // ale970405+lasgoutt-970425
535 // rewritten to use new string (Lgb)
536 string const token(string const & a, char delim, int n)
537 {
538         if (a.empty())
539                 return string();
540
541         size_t k = 0;
542         size_t i = 0;
543
544         // Find delimiter or end of string
545         for (; n--;) {
546                 if ((i = a.find(delim, i)) == string::npos)
547                         break;
548                 else
549                         ++i; // step delim
550         }
551
552         // i is now the n'th delim (or string::npos)
553         if (i == string::npos)
554                 return string();
555
556         k = a.find(delim, i);
557         // k is now the n'th + 1 delim (or string::npos)
558
559         return a.substr(i, k - i);
560 }
561
562
563 docstring const token(docstring const & a, char_type delim, int n)
564 {
565         if (a.empty())
566                 return docstring();
567
568         size_t k = 0;
569         size_t i = 0;
570
571         // Find delimiter or end of string
572         for (; n--;) {
573                 if ((i = a.find(delim, i)) == docstring::npos)
574                         break;
575                 else
576                         ++i; // step delim
577         }
578
579         // i is now the n'th delim (or string::npos)
580         if (i == docstring::npos)
581                 return docstring();
582
583         k = a.find(delim, i);
584         // k is now the n'th + 1 delim (or string::npos)
585
586         return a.substr(i, k - i);
587 }
588
589
590 // this could probably be faster and/or cleaner, but it seems to work (JMarc)
591 // rewritten to use new string (Lgb)
592 int tokenPos(string const & a, char delim, string const & tok)
593 {
594         int i = 0;
595         string str = a;
596         string tmptok;
597
598         while (!str.empty()) {
599                 str = split(str, tmptok, delim);
600                 if (tok == tmptok)
601                         return i;
602                 ++i;
603         }
604         return -1;
605 }
606
607
608 // this could probably be faster and/or cleaner, but it seems to work (JMarc)
609 // rewritten to use new string (Lgb)
610 int tokenPos(docstring const & a, char_type delim, docstring const & tok)
611 {
612         int i = 0;
613         docstring str = a;
614         docstring tmptok;
615
616         while (!str.empty()) {
617                 str = split(str, tmptok, delim);
618                 if (tok == tmptok)
619                         return i;
620                 ++i;
621         }
622         return -1;
623 }
624
625
626 namespace {
627
628 /// Substitute all \a oldchar with \a newchar
629 template<typename Ch> inline
630 basic_string<Ch> const subst_char(basic_string<Ch> const & a,
631                 Ch oldchar, Ch newchar)
632 {
633         typedef basic_string<Ch> String;
634         String tmp(a);
635         typename String::iterator lit = tmp.begin();
636         typename String::iterator end = tmp.end();
637         for (; lit != end; ++lit)
638                 if ((*lit) == oldchar)
639                         (*lit) = newchar;
640         return tmp;
641 }
642
643 /// Substitute all \a oldchar with \a newchar
644 docstring const subst_char(docstring const & a,
645         docstring::value_type oldchar, docstring::value_type newchar)
646 {
647         docstring tmp(a);
648         docstring::iterator lit = tmp.begin();
649         docstring::iterator end = tmp.end();
650         for (; lit != end; ++lit)
651                 if ((*lit) == oldchar)
652                         (*lit) = newchar;
653         return tmp;
654 }
655
656
657 /// substitutes all instances of \a oldstr with \a newstr
658 template<typename String> inline
659 String const subst_string(String const & a,
660                 String const & oldstr, String const & newstr)
661 {
662         LASSERT(!oldstr.empty(), /**/);
663         String lstr = a;
664         size_t i = 0;
665         size_t const olen = oldstr.length();
666         while ((i = lstr.find(oldstr, i)) != string::npos) {
667                 lstr.replace(i, olen, newstr);
668                 i += newstr.length(); // We need to be sure that we dont
669                 // use the same i over and over again.
670         }
671         return lstr;
672 }
673
674 docstring const subst_string(docstring const & a,
675                 docstring const & oldstr, docstring const & newstr)
676 {
677         LASSERT(!oldstr.empty(), /**/);
678         docstring lstr = a;
679         size_t i = 0;
680         size_t const olen = oldstr.length();
681         while ((i = lstr.find(oldstr, i)) != string::npos) {
682                 lstr.replace(i, olen, newstr);
683                 i += newstr.length(); // We need to be sure that we dont
684                 // use the same i over and over again.
685         }
686         return lstr;
687 }
688
689 }
690
691
692 string const subst(string const & a, char oldchar, char newchar)
693 {
694         return subst_char(a, oldchar, newchar);
695 }
696
697
698 docstring const subst(docstring const & a,
699                 char_type oldchar, char_type newchar)
700 {
701         return subst_char(a, oldchar, newchar);
702 }
703
704
705 string const subst(string const & a,
706                 string const & oldstr, string const & newstr)
707 {
708         return subst_string(a, oldstr, newstr);
709 }
710
711
712 docstring const subst(docstring const & a,
713                 docstring const & oldstr, docstring const & newstr)
714 {
715         return subst_string(a, oldstr, newstr);
716 }
717
718
719 docstring const trim(docstring const & a, char const * p)
720 {
721         LASSERT(p, /**/);
722
723         if (a.empty() || !*p)
724                 return a;
725
726         docstring s = from_ascii(p);
727         size_t r = a.find_last_not_of(s);
728         size_t l = a.find_first_not_of(s);
729
730         // Is this the minimal test? (lgb)
731         if (r == docstring::npos && l == docstring::npos)
732                 return docstring();
733
734         return a.substr(l, r - l + 1);
735 }
736
737
738 string const trim(string const & a, char const * p)
739 {
740         LASSERT(p, /**/);
741
742         if (a.empty() || !*p)
743                 return a;
744
745         size_t r = a.find_last_not_of(p);
746         size_t l = a.find_first_not_of(p);
747
748         // Is this the minimal test? (lgb)
749         if (r == string::npos && l == string::npos)
750                 return string();
751
752         return a.substr(l, r - l + 1);
753 }
754
755
756 string const rtrim(string const & a, char const * p)
757 {
758         LASSERT(p, /**/);
759
760         if (a.empty() || !*p)
761                 return a;
762
763         size_t r = a.find_last_not_of(p);
764
765         // Is this test really needed? (Lgb)
766         if (r == string::npos)
767                 return string();
768
769         return a.substr(0, r + 1);
770 }
771
772
773 docstring const rtrim(docstring const & a, char const * p)
774 {
775         LASSERT(p, /**/);
776
777         if (a.empty() || !*p)
778                 return a;
779
780         size_t r = a.find_last_not_of(from_ascii(p));
781
782         // Is this test really needed? (Lgb)
783         if (r == docstring::npos)
784                 return docstring();
785
786         return a.substr(0, r + 1);
787 }
788
789
790 string const ltrim(string const & a, char const * p)
791 {
792         LASSERT(p, /**/);
793         if (a.empty() || !*p)
794                 return a;
795         size_t l = a.find_first_not_of(p);
796         if (l == string::npos)
797                 return string();
798         return a.substr(l, string::npos);
799 }
800
801
802 docstring const ltrim(docstring const & a, char const * p)
803 {
804         LASSERT(p, /**/);
805         if (a.empty() || !*p)
806                 return a;
807         size_t l = a.find_first_not_of(from_ascii(p));
808         if (l == docstring::npos)
809                 return docstring();
810         return a.substr(l, docstring::npos);
811 }
812
813 namespace {
814
815 template<typename String, typename Char> inline
816 String const doSplit(String const & a, String & piece, Char delim)
817 {
818         String tmp;
819         size_t i = a.find(delim);
820         if (i == a.length() - 1) {
821                 piece = a.substr(0, i);
822         } else if (i != String::npos) {
823                 piece = a.substr(0, i);
824                 tmp = a.substr(i + 1);
825         } else if (i == 0) {
826                 piece.erase();
827                 tmp = a.substr(i + 1);
828         } else {
829                 piece = a;
830         }
831         return tmp;
832 }
833
834 template<typename Char> inline
835 docstring const doSplit(docstring const & a, docstring & piece, Char delim)
836 {
837         docstring tmp;
838         size_t i = a.find(delim);
839         if (i == a.length() - 1) {
840                 piece = a.substr(0, i);
841         } else if (i != docstring::npos) {
842                 piece = a.substr(0, i);
843                 tmp = a.substr(i + 1);
844         } else if (i == 0) {
845                 piece.erase();
846                 tmp = a.substr(i + 1);
847         } else {
848                 piece = a;
849         }
850         return tmp;
851 }
852
853 } // anon
854
855
856 string const split(string const & a, string & piece, char delim)
857 {
858         return doSplit(a, piece, delim);
859 }
860
861
862 docstring const split(docstring const & a, docstring & piece, char_type delim)
863 {
864         return doSplit(a, piece, delim);
865 }
866
867
868 string const split(string const & a, char delim)
869 {
870         string tmp;
871         size_t i = a.find(delim);
872         if (i != string::npos) // found delim
873                 tmp = a.substr(i + 1);
874         return tmp;
875 }
876
877
878 // ale970521
879 string const rsplit(string const & a, string & piece, char delim)
880 {
881         string tmp;
882         size_t i = a.rfind(delim);
883         if (i != string::npos) { // delimiter was found
884                 piece = a.substr(0, i);
885                 tmp = a.substr(i + 1);
886         } else { // delimiter was not found
887                 piece.erase();
888         }
889         return tmp;
890 }
891
892
893 docstring const escape(docstring const & lab)
894 {
895         char_type hexdigit[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
896                                    '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
897         docstring enc;
898         for (size_t i = 0; i < lab.length(); ++i) {
899                 char_type c = lab[i];
900                 if (c >= 128 || c == '=' || c == '%') {
901                         // Although char_type is a 32 bit type we know that
902                         // UCS4 occupies only 21 bits, so we don't need to
903                         // encode bigger values. Test for 2^24 because we
904                         // can encode that with the 6 hex digits that are
905                         // needed for 21 bits anyway.
906                         LASSERT(c < (1 << 24), /**/);
907                         enc += '=';
908                         enc += hexdigit[(c>>20) & 15];
909                         enc += hexdigit[(c>>16) & 15];
910                         enc += hexdigit[(c>>12) & 15];
911                         enc += hexdigit[(c>> 8) & 15];
912                         enc += hexdigit[(c>> 4) & 15];
913                         enc += hexdigit[ c      & 15];
914                 } else {
915                         enc += c;
916                 }
917         }
918         return enc;
919 }
920
921
922 namespace {
923
924 template<typename String> vector<String> const
925 getVectorFromStringT(String const & str, String const & delim, bool keepempty)
926 {
927 // Lars would like this code to go, but for now his replacement (below)
928 // doesn't fullfil the same function. I have, therefore, reactivated the
929 // old code for now. Angus 11 Nov 2002.
930 #if 1
931         vector<String> vec;
932         if (str.empty())
933                 return vec;
934         String keys = rtrim(str);
935         while (true) {
936                 size_t const idx = keys.find(delim);
937                 if (idx == String::npos) {
938                         vec.push_back(ltrim(keys));
939                         break;
940                 }
941                 String const key = trim(keys.substr(0, idx));
942                 if (!key.empty() || keepempty)
943                         vec.push_back(key);
944                 size_t const start = idx + delim.size();
945                 keys = keys.substr(start);
946         }
947         return vec;
948 #else
949         typedef boost::char_separator<typename String::value_type> Separator;
950         typedef boost::tokenizer<Separator, typename String::const_iterator, String> Tokenizer;
951         Separator sep(delim.c_str());
952         Tokenizer tokens(str, sep);
953         return vector<String>(tokens.begin(), tokens.end());
954 #endif
955 }
956
957 } // namespace anon
958
959
960 vector<string> const getVectorFromString(string const & str,
961                                          string const & delim,
962                                          bool keepempty)
963 {
964         return getVectorFromStringT<string>(str, delim, keepempty);
965 }
966
967
968 vector<docstring> const getVectorFromString(docstring const & str,
969                                             docstring const & delim,
970                                             bool keepempty)
971 {
972         return getVectorFromStringT<docstring>(str, delim, keepempty);
973 }
974
975
976 // the same vice versa
977 string const getStringFromVector(vector<string> const & vec,
978                                  string const & delim)
979 {
980         string str;
981         int i = 0;
982         for (vector<string>::const_iterator it = vec.begin();
983              it != vec.end(); ++it) {
984                 string item = trim(*it);
985                 if (item.empty())
986                         continue;
987                 if (i++ > 0)
988                         str += delim;
989                 str += item;
990         }
991         return str;
992 }
993
994
995 int findToken(char const * const str[], string const & search_token)
996 {
997         int i = 0;
998
999         while (str[i][0] && str[i] != search_token)
1000                 ++i;
1001         if (!str[i][0])
1002                 i = -1;
1003         return i;
1004 }
1005
1006
1007 docstring const externalLineEnding(docstring const & str)
1008 {
1009 #if defined(__APPLE__)
1010         // The MAC clipboard uses \r for lineendings, and we use \n
1011         return subst(str, '\n', '\r');
1012 #elif defined (_WIN32) || (defined (__CYGWIN__) && defined (X_DISPLAY_MISSING))
1013         // Windows clipboard uses \r\n for lineendings, and we use \n
1014         return subst(str, from_ascii("\n"), from_ascii("\r\n"));
1015 #else
1016         return str;
1017 #endif
1018 }
1019
1020
1021 docstring const internalLineEnding(docstring const & str)
1022 {
1023         docstring const s = subst(str, from_ascii("\r\n"), from_ascii("\n"));
1024         return subst(s, '\r', '\n');
1025 }
1026
1027
1028 template<>
1029 docstring bformat(docstring const & fmt, int arg1)
1030 {
1031         LASSERT(contains(fmt, from_ascii("%1$d")), /**/);
1032         docstring const str = subst(fmt, from_ascii("%1$d"), convert<docstring>(arg1));
1033         return subst(str, from_ascii("%%"), from_ascii("%"));
1034 }
1035
1036
1037 template<>
1038 docstring bformat(docstring const & fmt, long arg1)
1039 {
1040         LASSERT(contains(fmt, from_ascii("%1$d")), /**/);
1041         docstring const str = subst(fmt, from_ascii("%1$d"), convert<docstring>(arg1));
1042         return subst(str, from_ascii("%%"), from_ascii("%"));
1043 }
1044
1045
1046 template<>
1047 docstring bformat(docstring const & fmt, unsigned int arg1)
1048 {
1049         LASSERT(contains(fmt, from_ascii("%1$d")), /**/);
1050         docstring const str = subst(fmt, from_ascii("%1$d"), convert<docstring>(arg1));
1051         return subst(str, from_ascii("%%"), from_ascii("%"));
1052 }
1053
1054
1055 template<>
1056 docstring bformat(docstring const & fmt, docstring arg1)
1057 {
1058         LASSERT(contains(fmt, from_ascii("%1$s")), /**/);
1059         docstring const str = subst(fmt, from_ascii("%1$s"), arg1);
1060         return subst(str, from_ascii("%%"), from_ascii("%"));
1061 }
1062
1063
1064 template<>
1065 docstring bformat(docstring const & fmt, char * arg1)
1066 {
1067         LASSERT(contains(fmt, from_ascii("%1$s")), /**/);
1068         docstring const str = subst(fmt, from_ascii("%1$s"), from_ascii(arg1));
1069         return subst(str, from_ascii("%%"), from_ascii("%"));
1070 }
1071
1072
1073 template<>
1074 docstring bformat(docstring const & fmt, docstring arg1, docstring arg2)
1075 {
1076         LASSERT(contains(fmt, from_ascii("%1$s")), /**/);
1077         LASSERT(contains(fmt, from_ascii("%2$s")), /**/);
1078         docstring str = subst(fmt, from_ascii("%1$s"), arg1);
1079         str = subst(str, from_ascii("%2$s"), arg2);
1080         return subst(str, from_ascii("%%"), from_ascii("%"));
1081 }
1082
1083
1084 template<>
1085 docstring bformat(docstring const & fmt, char const * arg1, docstring arg2)
1086 {
1087         LASSERT(contains(fmt, from_ascii("%1$s")), /**/);
1088         LASSERT(contains(fmt, from_ascii("%2$s")), /**/);
1089         docstring str = subst(fmt, from_ascii("%1$s"), from_ascii(arg1));
1090         str = subst(fmt, from_ascii("%2$s"), arg2);
1091         return subst(str, from_ascii("%%"), from_ascii("%"));
1092 }
1093
1094
1095 template<>
1096 docstring bformat(docstring const & fmt, int arg1, int arg2)
1097 {
1098         LASSERT(contains(fmt, from_ascii("%1$d")), /**/);
1099         LASSERT(contains(fmt, from_ascii("%2$d")), /**/);
1100         docstring str = subst(fmt, from_ascii("%1$d"), convert<docstring>(arg1));
1101         str = subst(str, from_ascii("%2$d"), convert<docstring>(arg2));
1102         return subst(str, from_ascii("%%"), from_ascii("%"));
1103 }
1104
1105
1106 template<>
1107 docstring bformat(docstring const & fmt, docstring arg1, docstring arg2, docstring arg3)
1108 {
1109         LASSERT(contains(fmt, from_ascii("%1$s")), /**/);
1110         LASSERT(contains(fmt, from_ascii("%2$s")), /**/);
1111         LASSERT(contains(fmt, from_ascii("%3$s")), /**/);
1112         docstring str = subst(fmt, from_ascii("%1$s"), arg1);
1113         str = subst(str, from_ascii("%2$s"), arg2);
1114         str = subst(str, from_ascii("%3$s"), arg3);
1115         return subst(str, from_ascii("%%"), from_ascii("%"));
1116 }
1117
1118
1119 template<>
1120 docstring bformat(docstring const & fmt,
1121                docstring arg1, docstring arg2, docstring arg3, docstring arg4)
1122 {
1123         LASSERT(contains(fmt, from_ascii("%1$s")), /**/);
1124         LASSERT(contains(fmt, from_ascii("%2$s")), /**/);
1125         LASSERT(contains(fmt, from_ascii("%3$s")), /**/);
1126         LASSERT(contains(fmt, from_ascii("%4$s")), /**/);
1127         docstring str = subst(fmt, from_ascii("%1$s"), arg1);
1128         str = subst(str, from_ascii("%2$s"), arg2);
1129         str = subst(str, from_ascii("%3$s"), arg3);
1130         str = subst(str, from_ascii("%4$s"), arg4);
1131         return subst(str, from_ascii("%%"), from_ascii("%"));
1132 }
1133
1134 } // namespace support
1135 } // namespace lyx