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);
341 string const subst(string const & a, char oldchar, char newchar)
344 string::iterator lit = tmp.begin();
345 string::iterator end = tmp.end();
346 for (; lit != end; ++lit)
347 if ((*lit) == oldchar)
353 string const subst(string const & a,
354 string const & oldstr, string const & newstr)
357 string::size_type i = 0;
358 string::size_type const olen = oldstr.length();
359 while ((i = lstr.find(oldstr, i)) != string::npos) {
360 lstr.replace(i, olen, newstr);
361 i += newstr.length(); // We need to be sure that we dont
362 // use the same i over and over again.
368 string const trim(string const & a, char const * p)
372 if (a.empty() || !*p)
375 string::size_type r = a.find_last_not_of(p);
376 string::size_type l = a.find_first_not_of(p);
378 // Is this the minimal test? (lgb)
379 if (r == string::npos && l == string::npos)
382 return a.substr(l, r - l + 1);
386 string const rtrim(string const & a, char const * p)
390 if (a.empty() || !*p)
393 string::size_type r = a.find_last_not_of(p);
395 // Is this test really needed? (Lgb)
396 if (r == string::npos)
399 return a.substr(0, r + 1);
403 string const ltrim(string const & a, char const * p)
407 if (a.empty() || !*p)
410 string::size_type l = a.find_first_not_of(p);
412 if (l == string::npos)
415 return a.substr(l, string::npos);
419 string const split(string const & a, string & piece, char delim)
422 string::size_type i = a.find(delim);
423 if (i == a.length() - 1) {
424 piece = a.substr(0, i);
425 } else if (i != string::npos) {
426 piece = a.substr(0, i);
427 tmp = a.substr(i + 1);
430 tmp = a.substr(i + 1);
438 string const split(string const & a, char delim)
441 string::size_type i = a.find(delim);
442 if (i != string::npos) // found delim
443 tmp = a.substr(i + 1);
449 string const rsplit(string const & a, string & piece, char delim)
452 string::size_type i = a.rfind(delim);
453 if (i != string::npos) { // delimiter was found
454 piece = a.substr(0, i);
455 tmp = a.substr(i + 1);
456 } else { // delimiter was not found
463 // This function escapes 8-bit characters and other problematic
464 // characters that cause problems in latex labels.
465 string const escape(string const & lab)
467 char hexdigit[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
468 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
470 for (string::size_type i = 0; i < lab.length(); ++i) {
471 unsigned char c= lab[i];
472 if (c >= 128 || c == '=' || c == '%') {
474 enc += hexdigit[c>>4];
475 enc += hexdigit[c & 15];
484 /// gives a vector of stringparts which have the delimiter delim
485 vector<string> const getVectorFromString(string const & str,
486 string const & delim)
488 // Lars would like this code to go, but for now his replacement (below)
489 // doesn't fullfil the same function. I have, therefore, reactivated the
490 // old code for now. Angus 11 Nov 2002.
495 string keys(rtrim(str));
497 string::size_type const idx = keys.find(delim);
498 if (idx == string::npos) {
499 vec.push_back(ltrim(keys));
502 string const key = trim(keys.substr(0, idx));
505 string::size_type const start = idx + delim.size();
506 keys = keys.substr(start);
510 boost::char_separator<char> sep(delim.c_str());
511 boost::tokenizer<boost::char_separator<char> > tokens(str, sep);
512 return vector<string>(tokens.begin(), tokens.end());
517 // the same vice versa
518 string const getStringFromVector(vector<string> const & vec,
519 string const & delim)
523 for (vector<string>::const_iterator it = vec.begin();
524 it != vec.end(); ++it) {
525 string item = trim(*it);
536 #ifndef I_AM_NOT_AFRAID_OF_HEADER_LIBRARIES
540 string bformat(string const & fmt, int arg1)
542 return (boost::format(fmt) % arg1).str();
547 string bformat(string const & fmt, long arg1)
549 return (boost::format(fmt) % arg1).str();
554 string bformat(string const & fmt, unsigned int arg1)
556 return (boost::format(fmt) % arg1).str();
561 string bformat<string>(string const & fmt, string arg1)
563 return (boost::format(fmt) % arg1).str();
568 string bformat(string const & fmt, char * arg1)
570 return (boost::format(fmt) % arg1).str();
575 string bformat(string const & fmt, int arg1, int arg2)
577 return (boost::format(fmt) % arg1 % arg2).str();
582 string bformat(string const & fmt, string arg1, string arg2)
584 return (boost::format(fmt) % arg1 % arg2).str();
589 string bformat(string const & fmt, char const * arg1, string arg2)
591 return (boost::format(fmt) % arg1 % arg2).str();
596 string bformat(string const & fmt, string arg1, string arg2, string arg3)
598 return (boost::format(fmt) % arg1 % arg2 % arg3).str();
603 string bformat(string const & fmt,
604 string arg1, string arg2, string arg3, string arg4)
606 return (boost::format(fmt) % arg1 % arg2 % arg3 % arg4).str();
612 string bformat(string const & fmt, int arg1)
614 BOOST_ASSERT(contains(fmt, "%1$d"));
615 string const str = subst(fmt, "%1$d", convert<string>(arg1));
616 return subst(str, "%%", "%");
621 string bformat(string const & fmt, long arg1)
623 BOOST_ASSERT(contains(fmt, "%1$d"));
624 string const str = subst(fmt, "%1$d", convert<string>(arg1));
625 return subst(str, "%%", "%");
630 string bformat(string const & fmt, unsigned int arg1)
632 BOOST_ASSERT(contains(fmt, "%1$d"));
633 string const str = subst(fmt, "%1$d", convert<string>(arg1));
634 return subst(str, "%%", "%");
639 string bformat(string const & fmt, string arg1)
641 BOOST_ASSERT(contains(fmt, "%1$s"));
642 string const str = subst(fmt, "%1$s", arg1);
643 return subst(str, "%%", "%");
648 string bformat(string const & fmt, char * arg1)
650 BOOST_ASSERT(contains(fmt, "%1$s"));
651 string const str = subst(fmt, "%1$s", arg1);
652 return subst(str, "%%", "%");
655 string bformat(string const & fmt, string arg1, string arg2)
657 BOOST_ASSERT(contains(fmt, "%1$s"));
658 BOOST_ASSERT(contains(fmt, "%2$s"));
659 string str = subst(fmt, "%1$s", arg1);
660 str = subst(str, "%2$s", arg2);
661 return subst(str, "%%", "%");
666 string bformat(string const & fmt, char const * arg1, string arg2)
668 BOOST_ASSERT(contains(fmt, "%1$s"));
669 BOOST_ASSERT(contains(fmt, "%2$s"));
670 string str = subst(fmt, "%1$s", arg1);
671 str = subst(fmt, "%2$s", arg2);
672 return subst(str, "%%", "%");
677 string bformat(string const & fmt, int arg1, int arg2)
679 BOOST_ASSERT(contains(fmt, "%1$d"));
680 BOOST_ASSERT(contains(fmt, "%2$d"));
681 string str = subst(fmt, "%1$d", convert<string>(arg1));
682 str = subst(str, "%2$d", convert<string>(arg2));
683 return subst(str, "%%", "%");
688 string bformat(string const & fmt, string arg1, string arg2, string arg3)
690 BOOST_ASSERT(contains(fmt, "%1$s"));
691 BOOST_ASSERT(contains(fmt, "%2$s"));
692 BOOST_ASSERT(contains(fmt, "%3$s"));
693 string str = subst(fmt, "%1$s", arg1);
694 str = subst(str, "%2$s", arg2);
695 str = subst(str, "%3$s", arg3);
696 return subst(str, "%%", "%");
701 string bformat(string const & fmt,
702 string arg1, string arg2, string arg3, string arg4)
704 BOOST_ASSERT(contains(fmt, "%1$s"));
705 BOOST_ASSERT(contains(fmt, "%2$s"));
706 BOOST_ASSERT(contains(fmt, "%3$s"));
707 BOOST_ASSERT(contains(fmt, "%4$s"));
708 string str = subst(fmt, "%1$s", arg1);
709 str = subst(str, "%2$s", arg2);
710 str = subst(str, "%3$s", arg3);
711 str = subst(str, "%4$s", arg4);
712 return subst(str, "%%", "%");
718 } // namespace support