3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
7 * \author Jean-Marc Lasgouttes
9 * Full author contact details are available in file CREDITS.
14 #include "support/lstrings.h"
15 #include "support/lyxlib.h"
16 #include "support/convert.h"
20 #include <boost/tokenizer.hpp>
21 #include <boost/assert.hpp>
23 #ifndef I_AM_NOT_AFRAID_OF_HEADER_LIBRARIES
25 #include <boost/format.hpp>
39 #ifndef CXX_GLOBAL_CSTD
49 int compare_no_case(string const & s, string const & s2)
51 string::const_iterator p = s.begin();
52 string::const_iterator p2 = s2.begin();
54 while (p != s.end() && p2 != s2.end()) {
55 int const lc1 = tolower(*p);
56 int const lc2 = tolower(*p2);
58 return (lc1 < lc2) ? -1 : 1;
63 if (s.size() == s2.size())
65 if (s.size() < s2.size())
72 int ascii_tolower(int c) {
73 if (c >= 'A' && c <= 'Z')
80 int compare_ascii_no_case(string const & s, string const & s2)
82 string::const_iterator p = s.begin();
83 string::const_iterator p2 = s2.begin();
85 while (p != s.end() && p2 != s2.end()) {
86 int const lc1 = ascii_tolower(*p);
87 int const lc2 = ascii_tolower(*p2);
89 return (lc1 < lc2) ? -1 : 1;
94 if (s.size() == s2.size())
96 if (s.size() < s2.size())
102 int compare_no_case(string const & s, string const & s2, unsigned int len)
104 string::const_iterator p = s.begin();
105 string::const_iterator p2 = s2.begin();
107 while (i < len && p != s.end() && p2 != s2.end()) {
108 int const lc1 = tolower(*p);
109 int const lc2 = tolower(*p2);
111 return (lc1 < lc2) ? -1 : 1;
117 if (s.size() >= len && s2.size() >= len)
119 if (s.size() < s2.size())
125 bool isStrInt(string const & str)
127 if (str.empty()) return false;
129 // Remove leading and trailing white space chars.
130 string const tmpstr = trim(str);
131 if (tmpstr.empty()) return false;
133 string::const_iterator cit = tmpstr.begin();
134 if ((*cit) == '-') ++cit;
135 string::const_iterator end = tmpstr.end();
136 for (; cit != end; ++cit) {
137 if (!isdigit((*cit))) return false;
143 bool isStrUnsignedInt(string const & str)
145 if (str.empty()) return false;
147 // Remove leading and trailing white space chars.
148 string const tmpstr = trim(str);
149 if (tmpstr.empty()) return false;
151 string::const_iterator cit = tmpstr.begin();
152 string::const_iterator end = tmpstr.end();
153 for (; cit != end; ++cit) {
154 if (!isdigit((*cit))) return false;
160 bool isStrDbl(string const & str)
162 if (str.empty()) return false;
164 // Remove leading and trailing white space chars.
165 string const tmpstr = trim(str);
166 if (tmpstr.empty()) return false;
167 // if (1 < tmpstr.count('.')) return false;
169 string::const_iterator cit = tmpstr.begin();
170 bool found_dot(false);
171 if ((*cit) == '-') ++cit;
172 string::const_iterator end = tmpstr.end();
173 for (; cit != end; ++cit) {
190 char lowercase(char c)
192 return char(tolower(c));
196 char uppercase(char c)
198 return char(toupper(c));
204 // since we cannot use std::tolower and std::toupper directly in the
205 // calls to std::transform yet, we use these helper clases. (Lgb)
207 struct local_lowercase {
208 char operator()(char c) const {
213 struct local_uppercase {
214 char operator()(char c) const {
219 struct local_ascii_lowercase {
220 char operator()(char c) const {
221 return ascii_tolower(c);
225 } // end of anon namespace
227 string const lowercase(string const & a)
230 transform(tmp.begin(), tmp.end(), tmp.begin(), local_lowercase());
234 string const uppercase(string const & a)
237 transform(tmp.begin(), tmp.end(), tmp.begin(), local_uppercase());
242 string const ascii_lowercase(string const & a)
245 transform(tmp.begin(), tmp.end(), tmp.begin(),
246 local_ascii_lowercase());
251 bool prefixIs(string const & a, string const & pre)
253 string::size_type const prelen = pre.length();
254 string::size_type const alen = a.length();
256 if (prelen > alen || a.empty())
259 #if defined(STD_STRING_IS_GOOD)
260 return a.compare(0, prelen, pre) == 0;
262 return ::strncmp(a.c_str(), pre.c_str(), prelen) == 0;
268 bool suffixIs(string const & a, char c)
270 if (a.empty()) return false;
271 return a[a.length() - 1] == c;
275 bool suffixIs(string const & a, string const & suf)
277 string::size_type const suflen = suf.length();
278 string::size_type const alen = a.length();
283 #if !defined(USE_INCLUDED_STRING) && !defined(STD_STRING_IS_GOOD)
284 string tmp(a, alen - suflen);
285 return ::strncmp(tmp.c_str(), suf.c_str(), suflen) == 0;
287 return a.compare(alen - suflen, suflen, suf) == 0;
293 bool containsOnly(string const & s, string const & cset)
295 return s.find_first_not_of(cset) == string::npos;
299 // ale970405+lasgoutt-970425
300 // rewritten to use new string (Lgb)
301 string const token(string const & a, char delim, int n)
303 if (a.empty()) return string();
305 string::size_type k = 0;
306 string::size_type i = 0;
308 // Find delimiter or end of string
310 if ((i = a.find(delim, i)) == string::npos)
314 // i is now the n'th delim (or string::npos)
315 if (i == string::npos) return string();
316 k = a.find(delim, i);
317 // k is now the n'th + 1 delim (or string::npos)
319 return a.substr(i, k - i);
323 // this could probably be faster and/or cleaner, but it seems to work (JMarc)
324 // rewritten to use new string (Lgb)
325 int tokenPos(string const & a, char delim, string const & tok)
331 while (!str.empty()) {
332 str = split(str, tmptok, delim);
343 template<typename Ch> inline
344 std::basic_string<Ch> const subst(std::basic_string<Ch> const & a, Ch oldchar, Ch newchar)
346 typedef std::basic_string<Ch> String;
348 typename String::iterator lit = tmp.begin();
349 typename String::iterator end = tmp.end();
350 for (; lit != end; ++lit)
351 if ((*lit) == oldchar)
357 template<typename String> inline
358 String const subst(String const & a,
359 String const & oldstr, String const & newstr)
361 BOOST_ASSERT(!oldstr.empty());
363 typename String::size_type i = 0;
364 typename String::size_type const olen = oldstr.length();
365 while ((i = lstr.find(oldstr, i)) != string::npos) {
366 lstr.replace(i, olen, newstr);
367 i += newstr.length(); // We need to be sure that we dont
368 // use the same i over and over again.
376 string const subst(string const & a, char oldchar, char newchar)
378 return subst<char>(a, oldchar, newchar);
382 docstring const subst(docstring const & a,
383 char_type oldchar, char_type newchar)
385 return subst<char_type>(a, oldchar, newchar);
389 string const subst(string const & a,
390 string const & oldstr, string const & newstr)
392 return subst<string>(a, oldstr, newstr);
396 docstring const subst(docstring const & a,
397 docstring const & oldstr, docstring const & newstr)
399 return subst<docstring>(a, oldstr, newstr);
403 string const trim(string const & a, char const * p)
407 if (a.empty() || !*p)
410 string::size_type r = a.find_last_not_of(p);
411 string::size_type l = a.find_first_not_of(p);
413 // Is this the minimal test? (lgb)
414 if (r == string::npos && l == string::npos)
417 return a.substr(l, r - l + 1);
421 string const rtrim(string const & a, char const * p)
425 if (a.empty() || !*p)
428 string::size_type r = a.find_last_not_of(p);
430 // Is this test really needed? (Lgb)
431 if (r == string::npos)
434 return a.substr(0, r + 1);
438 string const ltrim(string const & a, char const * p)
442 if (a.empty() || !*p)
445 string::size_type l = a.find_first_not_of(p);
447 if (l == string::npos)
450 return a.substr(l, string::npos);
454 string const split(string const & a, string & piece, char delim)
457 string::size_type i = a.find(delim);
458 if (i == a.length() - 1) {
459 piece = a.substr(0, i);
460 } else if (i != string::npos) {
461 piece = a.substr(0, i);
462 tmp = a.substr(i + 1);
465 tmp = a.substr(i + 1);
473 string const split(string const & a, char delim)
476 string::size_type i = a.find(delim);
477 if (i != string::npos) // found delim
478 tmp = a.substr(i + 1);
484 string const rsplit(string const & a, string & piece, char delim)
487 string::size_type i = a.rfind(delim);
488 if (i != string::npos) { // delimiter was found
489 piece = a.substr(0, i);
490 tmp = a.substr(i + 1);
491 } else { // delimiter was not found
498 // This function escapes 8-bit characters and other problematic
499 // characters that cause problems in latex labels.
500 string const escape(string const & lab)
502 char hexdigit[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
503 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
505 for (string::size_type i = 0; i < lab.length(); ++i) {
506 unsigned char c= lab[i];
507 if (c >= 128 || c == '=' || c == '%') {
509 enc += hexdigit[c>>4];
510 enc += hexdigit[c & 15];
519 /// gives a vector of stringparts which have the delimiter delim
520 vector<string> const getVectorFromString(string const & str,
521 string const & delim)
523 // Lars would like this code to go, but for now his replacement (below)
524 // doesn't fullfil the same function. I have, therefore, reactivated the
525 // old code for now. Angus 11 Nov 2002.
530 string keys = rtrim(str);
532 string::size_type const idx = keys.find(delim);
533 if (idx == string::npos) {
534 vec.push_back(ltrim(keys));
537 string const key = trim(keys.substr(0, idx));
540 string::size_type const start = idx + delim.size();
541 keys = keys.substr(start);
545 boost::char_separator<char> sep(delim.c_str());
546 boost::tokenizer<boost::char_separator<char> > tokens(str, sep);
547 return vector<string>(tokens.begin(), tokens.end());
552 // the same vice versa
553 string const getStringFromVector(vector<string> const & vec,
554 string const & delim)
558 for (vector<string>::const_iterator it = vec.begin();
559 it != vec.end(); ++it) {
560 string item = trim(*it);
571 int findToken(char const * const str[], string const & search_token)
575 while (str[i][0] && str[i] != search_token)
583 docstring const externalLineEnding(docstring const & str)
585 #if defined(__APPLE__)
586 // The MAC clipboard uses \r for lineendings, and we use \n
587 return subst(str, '\n', '\r');
588 #elif defined (_WIN32) || (defined (__CYGWIN__) && defined (X_DISPLAY_MISSING))
589 // Windows clipboard uses \r\n for lineendings, and we use \n
590 return subst(str, lyx::from_ascii("\n"), lyx::from_ascii("\r\n"));
597 docstring const internalLineEnding(docstring const & str)
599 docstring const s = subst(str,
600 lyx::from_ascii("\r\n"), lyx::from_ascii("\n"));
601 return subst(s, '\r', '\n');
605 #ifndef I_AM_NOT_AFRAID_OF_HEADER_LIBRARIES
609 string bformat(string const & fmt, int arg1)
611 return (boost::format(fmt) % arg1).str();
616 string bformat(string const & fmt, long arg1)
618 return (boost::format(fmt) % arg1).str();
623 string bformat(string const & fmt, unsigned int arg1)
625 return (boost::format(fmt) % arg1).str();
630 string bformat<string>(string const & fmt, string arg1)
632 return (boost::format(fmt) % arg1).str();
637 string bformat(string const & fmt, char * arg1)
639 return (boost::format(fmt) % arg1).str();
644 string bformat(string const & fmt, int arg1, int arg2)
646 return (boost::format(fmt) % arg1 % arg2).str();
651 string bformat(string const & fmt, string arg1, string arg2)
653 return (boost::format(fmt) % arg1 % arg2).str();
658 string bformat(string const & fmt, char const * arg1, string arg2)
660 return (boost::format(fmt) % arg1 % arg2).str();
665 string bformat(string const & fmt, string arg1, string arg2, string arg3)
667 return (boost::format(fmt) % arg1 % arg2 % arg3).str();
672 string bformat(string const & fmt,
673 string arg1, string arg2, string arg3, string arg4)
675 return (boost::format(fmt) % arg1 % arg2 % arg3 % arg4).str();
681 string bformat(string const & fmt, int arg1)
683 BOOST_ASSERT(contains(fmt, "%1$d"));
684 string const str = subst(fmt, "%1$d", convert<string>(arg1));
685 return subst(str, "%%", "%");
690 string bformat(string const & fmt, long arg1)
692 BOOST_ASSERT(contains(fmt, "%1$d"));
693 string const str = subst(fmt, "%1$d", convert<string>(arg1));
694 return subst(str, "%%", "%");
699 string bformat(string const & fmt, unsigned int arg1)
701 BOOST_ASSERT(contains(fmt, "%1$d"));
702 string const str = subst(fmt, "%1$d", convert<string>(arg1));
703 return subst(str, "%%", "%");
708 string bformat(string const & fmt, string arg1)
710 BOOST_ASSERT(contains(fmt, "%1$s"));
711 string const str = subst(fmt, "%1$s", arg1);
712 return subst(str, "%%", "%");
717 string bformat(string const & fmt, char * arg1)
719 BOOST_ASSERT(contains(fmt, "%1$s"));
720 string const str = subst(fmt, "%1$s", arg1);
721 return subst(str, "%%", "%");
724 string bformat(string const & fmt, string arg1, string arg2)
726 BOOST_ASSERT(contains(fmt, "%1$s"));
727 BOOST_ASSERT(contains(fmt, "%2$s"));
728 string str = subst(fmt, "%1$s", arg1);
729 str = subst(str, "%2$s", arg2);
730 return subst(str, "%%", "%");
735 string bformat(string const & fmt, char const * arg1, string arg2)
737 BOOST_ASSERT(contains(fmt, "%1$s"));
738 BOOST_ASSERT(contains(fmt, "%2$s"));
739 string str = subst(fmt, "%1$s", arg1);
740 str = subst(fmt, "%2$s", arg2);
741 return subst(str, "%%", "%");
746 string bformat(string const & fmt, int arg1, int arg2)
748 BOOST_ASSERT(contains(fmt, "%1$d"));
749 BOOST_ASSERT(contains(fmt, "%2$d"));
750 string str = subst(fmt, "%1$d", convert<string>(arg1));
751 str = subst(str, "%2$d", convert<string>(arg2));
752 return subst(str, "%%", "%");
757 string bformat(string const & fmt, string arg1, string arg2, string arg3)
759 BOOST_ASSERT(contains(fmt, "%1$s"));
760 BOOST_ASSERT(contains(fmt, "%2$s"));
761 BOOST_ASSERT(contains(fmt, "%3$s"));
762 string str = subst(fmt, "%1$s", arg1);
763 str = subst(str, "%2$s", arg2);
764 str = subst(str, "%3$s", arg3);
765 return subst(str, "%%", "%");
770 string bformat(string const & fmt,
771 string arg1, string arg2, string arg3, string arg4)
773 BOOST_ASSERT(contains(fmt, "%1$s"));
774 BOOST_ASSERT(contains(fmt, "%2$s"));
775 BOOST_ASSERT(contains(fmt, "%3$s"));
776 BOOST_ASSERT(contains(fmt, "%4$s"));
777 string str = subst(fmt, "%1$s", arg1);
778 str = subst(str, "%2$s", arg2);
779 str = subst(str, "%3$s", arg3);
780 str = subst(str, "%4$s", arg4);
781 return subst(str, "%%", "%");
787 } // namespace support