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
50 int compare_no_case(string const & s, string const & s2)
52 string::const_iterator p = s.begin();
53 string::const_iterator p2 = s2.begin();
55 while (p != s.end() && p2 != s2.end()) {
56 int const lc1 = tolower(*p);
57 int const lc2 = tolower(*p2);
59 return (lc1 < lc2) ? -1 : 1;
64 if (s.size() == s2.size())
66 if (s.size() < s2.size())
73 int ascii_tolower(int c) {
74 if (c >= 'A' && c <= 'Z')
81 int compare_ascii_no_case(string const & s, string const & s2)
83 string::const_iterator p = s.begin();
84 string::const_iterator p2 = s2.begin();
86 while (p != s.end() && p2 != s2.end()) {
87 int const lc1 = ascii_tolower(*p);
88 int const lc2 = ascii_tolower(*p2);
90 return (lc1 < lc2) ? -1 : 1;
95 if (s.size() == s2.size())
97 if (s.size() < s2.size())
103 int compare_no_case(string const & s, string const & s2, unsigned int len)
105 string::const_iterator p = s.begin();
106 string::const_iterator p2 = s2.begin();
108 while (i < len && p != s.end() && p2 != s2.end()) {
109 int const lc1 = tolower(*p);
110 int const lc2 = tolower(*p2);
112 return (lc1 < lc2) ? -1 : 1;
118 if (s.size() >= len && s2.size() >= len)
120 if (s.size() < s2.size())
126 bool isStrInt(string const & str)
128 if (str.empty()) return false;
130 // Remove leading and trailing white space chars.
131 string const tmpstr = trim(str);
132 if (tmpstr.empty()) return false;
134 string::const_iterator cit = tmpstr.begin();
135 if ((*cit) == '-') ++cit;
136 string::const_iterator end = tmpstr.end();
137 for (; cit != end; ++cit) {
138 if (!isdigit((*cit))) return false;
144 bool isStrUnsignedInt(string const & str)
146 if (str.empty()) return false;
148 // Remove leading and trailing white space chars.
149 string const tmpstr = trim(str);
150 if (tmpstr.empty()) return false;
152 string::const_iterator cit = tmpstr.begin();
153 string::const_iterator end = tmpstr.end();
154 for (; cit != end; ++cit) {
155 if (!isdigit((*cit))) return false;
161 int strToInt(string const & str)
164 // Remove leading and trailing white space chars.
165 string const tmpstr = trim(str);
166 // Do the conversion proper.
174 unsigned int strToUnsignedInt(string const & str)
176 if (isStrUnsignedInt(str)) {
177 // Remove leading and trailing white space chars.
178 string const tmpstr = trim(str);
179 // Do the conversion proper.
187 bool isStrDbl(string const & str)
189 if (str.empty()) return false;
191 // Remove leading and trailing white space chars.
192 string const tmpstr = trim(str);
193 if (tmpstr.empty()) return false;
194 // if (1 < tmpstr.count('.')) return false;
196 string::const_iterator cit = tmpstr.begin();
197 bool found_dot(false);
198 if ((*cit) == '-') ++cit;
199 string::const_iterator end = tmpstr.end();
200 for (; cit != end; ++cit) {
217 double strToDbl(string const & str)
220 // Remove leading and trailing white space chars.
221 string const tmpstr = trim(str);
222 // Do the conversion proper.
223 return ::atof(tmpstr.c_str());
230 char lowercase(char c)
232 return char(tolower(c));
236 char uppercase(char c)
238 return char(toupper(c));
244 // since we cannot use std::tolower and std::toupper directly in the
245 // calls to std::transform yet, we use these helper clases. (Lgb)
247 struct local_lowercase {
248 char operator()(char c) const {
253 struct local_uppercase {
254 char operator()(char c) const {
259 struct local_ascii_lowercase {
260 char operator()(char c) const {
261 return ascii_tolower(c);
265 } // end of anon namespace
267 string const lowercase(string const & a)
270 transform(tmp.begin(), tmp.end(), tmp.begin(), local_lowercase());
274 string const uppercase(string const & a)
277 transform(tmp.begin(), tmp.end(), tmp.begin(), local_uppercase());
282 string const ascii_lowercase(string const & a)
285 transform(tmp.begin(), tmp.end(), tmp.begin(),
286 local_ascii_lowercase());
291 bool prefixIs(string const & a, string const & pre)
293 string::size_type const prelen = pre.length();
294 string::size_type const alen = a.length();
296 if (prelen > alen || a.empty())
299 #if defined(STD_STRING_IS_GOOD)
300 return a.compare(0, prelen, pre) == 0;
302 return ::strncmp(a.c_str(), pre.c_str(), prelen) == 0;
308 bool suffixIs(string const & a, char c)
310 if (a.empty()) return false;
311 return a[a.length() - 1] == c;
315 bool suffixIs(string const & a, string const & suf)
317 string::size_type const suflen = suf.length();
318 string::size_type const alen = a.length();
323 #if !defined(USE_INCLUDED_STRING) && !defined(STD_STRING_IS_GOOD)
324 string tmp(a, alen - suflen);
325 return ::strncmp(tmp.c_str(), suf.c_str(), suflen) == 0;
327 return a.compare(alen - suflen, suflen, suf) == 0;
333 bool containsOnly(string const & s, string const & cset)
335 return s.find_first_not_of(cset) == string::npos;
339 // ale970405+lasgoutt-970425
340 // rewritten to use new string (Lgb)
341 string const token(string const & a, char delim, int n)
343 if (a.empty()) return string();
345 string::size_type k = 0;
346 string::size_type i = 0;
348 // Find delimiter or end of string
350 if ((i = a.find(delim, i)) == string::npos)
354 // i is now the n'th delim (or string::npos)
355 if (i == string::npos) return string();
356 k = a.find(delim, i);
357 // k is now the n'th + 1 delim (or string::npos)
359 return a.substr(i, k - i);
363 // this could probably be faster and/or cleaner, but it seems to work (JMarc)
364 // rewritten to use new string (Lgb)
365 int tokenPos(string const & a, char delim, string const & tok)
371 while (!str.empty()) {
372 str = split(str, tmptok, delim);
381 string const subst(string const & a, char oldchar, char newchar)
384 string::iterator lit = tmp.begin();
385 string::iterator end = tmp.end();
386 for (; lit != end; ++lit)
387 if ((*lit) == oldchar)
393 string const subst(string const & a,
394 string const & oldstr, string const & newstr)
397 string::size_type i = 0;
398 string::size_type const olen = oldstr.length();
399 while ((i = lstr.find(oldstr, i)) != string::npos) {
400 lstr.replace(i, olen, newstr);
401 i += newstr.length(); // We need to be sure that we dont
402 // use the same i over and over again.
408 string const trim(string const & a, char const * p)
412 if (a.empty() || !*p)
415 string::size_type r = a.find_last_not_of(p);
416 string::size_type l = a.find_first_not_of(p);
418 // Is this the minimal test? (lgb)
419 if (r == string::npos && l == string::npos)
422 return a.substr(l, r - l + 1);
426 string const rtrim(string const & a, char const * p)
430 if (a.empty() || !*p)
433 string::size_type r = a.find_last_not_of(p);
435 // Is this test really needed? (Lgb)
436 if (r == string::npos)
439 return a.substr(0, r + 1);
443 string const ltrim(string const & a, char const * p)
447 if (a.empty() || !*p)
450 string::size_type l = a.find_first_not_of(p);
452 if (l == string::npos)
455 return a.substr(l, string::npos);
459 string const split(string const & a, string & piece, char delim)
462 string::size_type i = a.find(delim);
463 if (i == a.length() - 1) {
464 piece = a.substr(0, i);
465 } else if (i != string::npos) {
466 piece = a.substr(0, i);
467 tmp = a.substr(i + 1);
470 tmp = a.substr(i + 1);
478 string const split(string const & a, char delim)
481 string::size_type i = a.find(delim);
482 if (i != string::npos) // found delim
483 tmp = a.substr(i + 1);
489 string const rsplit(string const & a, string & piece, char delim)
492 string::size_type i = a.rfind(delim);
493 if (i != string::npos) { // delimiter was found
494 piece = a.substr(0, i);
495 tmp = a.substr(i + 1);
496 } else { // delimiter was not found
503 // This function escapes 8-bit characters and other problematic
504 // characters that cause problems in latex labels.
505 string const escape(string const & lab)
507 char hexdigit[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
508 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
510 for (string::size_type i = 0; i < lab.length(); ++i) {
511 unsigned char c= lab[i];
512 if (c >= 128 || c == '=' || c == '%') {
514 enc += hexdigit[c>>4];
515 enc += hexdigit[c & 15];
524 /// gives a vector of stringparts which have the delimiter delim
525 vector<string> const getVectorFromString(string const & str,
526 string const & delim)
528 // Lars would like this code to go, but for now his replacement (below)
529 // doesn't fullfil the same function. I have, therefore, reactivated the
530 // old code for now. Angus 11 Nov 2002.
535 string keys(rtrim(str));
537 string::size_type const idx = keys.find(delim);
538 if (idx == string::npos) {
539 vec.push_back(ltrim(keys));
542 string const key = trim(keys.substr(0, idx));
545 string::size_type const start = idx + delim.size();
546 keys = keys.substr(start);
550 boost::char_separator<char> sep(delim.c_str());
551 boost::tokenizer<boost::char_separator<char> > tokens(str, sep);
552 return vector<string>(tokens.begin(), tokens.end());
557 // the same vice versa
558 string const getStringFromVector(vector<string> const & vec,
559 string const & delim)
563 for (vector<string>::const_iterator it = vec.begin();
564 it != vec.end(); ++it) {
565 string item = trim(*it);
576 #ifndef I_AM_NOT_AFRAID_OF_HEADER_LIBRARIES
580 string bformat(string const & fmt, int arg1)
582 return (boost::format(fmt) % arg1).str();
587 string bformat(string const & fmt, long arg1)
589 return (boost::format(fmt) % arg1).str();
594 string bformat(string const & fmt, unsigned int arg1)
596 return (boost::format(fmt) % arg1).str();
601 string bformat<string>(string const & fmt, string arg1)
603 return (boost::format(fmt) % arg1).str();
608 string bformat(string const & fmt, char * arg1)
610 return (boost::format(fmt) % arg1).str();
615 string bformat(string const & fmt, int arg1, int arg2)
617 return (boost::format(fmt) % arg1 % arg2).str();
622 string bformat(string const & fmt, string arg1, string arg2)
624 return (boost::format(fmt) % arg1 % arg2).str();
629 string bformat(string const & fmt, char const * arg1, string arg2)
631 return (boost::format(fmt) % arg1 % arg2).str();
636 string bformat(string const & fmt, string arg1, string arg2, string arg3)
638 return (boost::format(fmt) % arg1 % arg2 % arg3).str();
643 string bformat(string const & fmt,
644 string arg1, string arg2, string arg3, string arg4)
646 return (boost::format(fmt) % arg1 % arg2 % arg3 % arg4).str();
652 string bformat(string const & fmt, int arg1)
654 BOOST_ASSERT(contains(fmt, "%1$d"));
655 string const str = subst(fmt, "%1$d", convert<string>(arg1));
656 return subst(str, "%%", "%");
661 string bformat(string const & fmt, long arg1)
663 BOOST_ASSERT(contains(fmt, "%1$d"));
664 string const str = subst(fmt, "%1$d", convert<string>(arg1));
665 return subst(str, "%%", "%");
670 string bformat(string const & fmt, unsigned int arg1)
672 BOOST_ASSERT(contains(fmt, "%1$d"));
673 string const str = subst(fmt, "%1$d", convert<string>(arg1));
674 return subst(str, "%%", "%");
679 string bformat(string const & fmt, string arg1)
681 BOOST_ASSERT(contains(fmt, "%1$s"));
682 string const str = subst(fmt, "%1$s", arg1);
683 return subst(str, "%%", "%");
688 string bformat(string const & fmt, char * arg1)
690 BOOST_ASSERT(contains(fmt, "%1$s"));
691 string const str = subst(fmt, "%1$s", arg1);
692 return subst(str, "%%", "%");
695 string bformat(string const & fmt, string arg1, string arg2)
697 BOOST_ASSERT(contains(fmt, "%1$s"));
698 BOOST_ASSERT(contains(fmt, "%2$s"));
699 string str = subst(fmt, "%1$s", arg1);
700 str = subst(str, "%2$s", arg2);
701 return subst(str, "%%", "%");
706 string bformat(string const & fmt, char const * arg1, string arg2)
708 BOOST_ASSERT(contains(fmt, "%1$s"));
709 BOOST_ASSERT(contains(fmt, "%2$s"));
710 string str = subst(fmt, "%1$s", arg1);
711 str = subst(fmt, "%2$s", arg2);
712 return subst(str, "%%", "%");
717 string bformat(string const & fmt, int arg1, int arg2)
719 BOOST_ASSERT(contains(fmt, "%1$d"));
720 BOOST_ASSERT(contains(fmt, "%2$d"));
721 string str = subst(fmt, "%1$d", convert<string>(arg1));
722 str = subst(str, "%2$d", convert<string>(arg2));
723 return subst(str, "%%", "%");
728 string bformat(string const & fmt, string arg1, string arg2, string arg3)
730 BOOST_ASSERT(contains(fmt, "%1$s"));
731 BOOST_ASSERT(contains(fmt, "%2$s"));
732 BOOST_ASSERT(contains(fmt, "%3$s"));
733 string str = subst(fmt, "%1$s", arg1);
734 str = subst(str, "%2$s", arg2);
735 str = subst(str, "%3$s", arg3);
736 return subst(str, "%%", "%");
741 string bformat(string const & fmt,
742 string arg1, string arg2, string arg3, string arg4)
744 BOOST_ASSERT(contains(fmt, "%1$s"));
745 BOOST_ASSERT(contains(fmt, "%2$s"));
746 BOOST_ASSERT(contains(fmt, "%3$s"));
747 BOOST_ASSERT(contains(fmt, "%4$s"));
748 string str = subst(fmt, "%1$s", arg1);
749 str = subst(str, "%2$s", arg2);
750 str = subst(str, "%3$s", arg3);
751 str = subst(str, "%4$s", arg4);
752 return subst(str, "%%", "%");
758 } // namespace support