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)
356 BOOST_ASSERT(!oldstr.empty());
358 string::size_type i = 0;
359 string::size_type const olen = oldstr.length();
360 while ((i = lstr.find(oldstr, i)) != string::npos) {
361 lstr.replace(i, olen, newstr);
362 i += newstr.length(); // We need to be sure that we dont
363 // use the same i over and over again.
369 string const trim(string const & a, char const * p)
373 if (a.empty() || !*p)
376 string::size_type r = a.find_last_not_of(p);
377 string::size_type l = a.find_first_not_of(p);
379 // Is this the minimal test? (lgb)
380 if (r == string::npos && l == string::npos)
383 return a.substr(l, r - l + 1);
387 string const rtrim(string const & a, char const * p)
391 if (a.empty() || !*p)
394 string::size_type r = a.find_last_not_of(p);
396 // Is this test really needed? (Lgb)
397 if (r == string::npos)
400 return a.substr(0, r + 1);
404 string const ltrim(string const & a, char const * p)
408 if (a.empty() || !*p)
411 string::size_type l = a.find_first_not_of(p);
413 if (l == string::npos)
416 return a.substr(l, string::npos);
420 string const split(string const & a, string & piece, char delim)
423 string::size_type i = a.find(delim);
424 if (i == a.length() - 1) {
425 piece = a.substr(0, i);
426 } else if (i != string::npos) {
427 piece = a.substr(0, i);
428 tmp = a.substr(i + 1);
431 tmp = a.substr(i + 1);
439 string const split(string const & a, char delim)
442 string::size_type i = a.find(delim);
443 if (i != string::npos) // found delim
444 tmp = a.substr(i + 1);
450 string const rsplit(string const & a, string & piece, char delim)
453 string::size_type i = a.rfind(delim);
454 if (i != string::npos) { // delimiter was found
455 piece = a.substr(0, i);
456 tmp = a.substr(i + 1);
457 } else { // delimiter was not found
464 // This function escapes 8-bit characters and other problematic
465 // characters that cause problems in latex labels.
466 string const escape(string const & lab)
468 char hexdigit[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
469 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
471 for (string::size_type i = 0; i < lab.length(); ++i) {
472 unsigned char c= lab[i];
473 if (c >= 128 || c == '=' || c == '%') {
475 enc += hexdigit[c>>4];
476 enc += hexdigit[c & 15];
485 /// gives a vector of stringparts which have the delimiter delim
486 vector<string> const getVectorFromString(string const & str,
487 string const & delim)
489 // Lars would like this code to go, but for now his replacement (below)
490 // doesn't fullfil the same function. I have, therefore, reactivated the
491 // old code for now. Angus 11 Nov 2002.
496 string keys = rtrim(str);
498 string::size_type const idx = keys.find(delim);
499 if (idx == string::npos) {
500 vec.push_back(ltrim(keys));
503 string const key = trim(keys.substr(0, idx));
506 string::size_type const start = idx + delim.size();
507 keys = keys.substr(start);
511 boost::char_separator<char> sep(delim.c_str());
512 boost::tokenizer<boost::char_separator<char> > tokens(str, sep);
513 return vector<string>(tokens.begin(), tokens.end());
518 // the same vice versa
519 string const getStringFromVector(vector<string> const & vec,
520 string const & delim)
524 for (vector<string>::const_iterator it = vec.begin();
525 it != vec.end(); ++it) {
526 string item = trim(*it);
537 int findToken(char const * const str[], string const & search_token)
541 while (str[i][0] && str[i] != search_token)
549 string const externalLineEnding(string const & str)
551 #if defined(__APPLE__)
552 // The MAC clipboard uses \r for lineendings, and we use \n
553 return subst(str, '\n', '\r');
554 #elif defined (_WIN32) || (defined (__CYGWIN__) && defined (X_DISPLAY_MISSING))
555 // Windows clipboard uses \r\n for lineendings, and we use \n
556 return subst(str, "\n", "\r\n");
563 string const internalLineEnding(string const & str)
565 string s = subst(str, "\r\n", "\n");
566 return subst(s, '\r', '\n');
570 #ifndef I_AM_NOT_AFRAID_OF_HEADER_LIBRARIES
574 string bformat(string const & fmt, int arg1)
576 return (boost::format(fmt) % arg1).str();
581 string bformat(string const & fmt, long arg1)
583 return (boost::format(fmt) % arg1).str();
588 string bformat(string const & fmt, unsigned int arg1)
590 return (boost::format(fmt) % arg1).str();
595 string bformat<string>(string const & fmt, string arg1)
597 return (boost::format(fmt) % arg1).str();
602 string bformat(string const & fmt, char * arg1)
604 return (boost::format(fmt) % arg1).str();
609 string bformat(string const & fmt, int arg1, int arg2)
611 return (boost::format(fmt) % arg1 % arg2).str();
616 string bformat(string const & fmt, string arg1, string arg2)
618 return (boost::format(fmt) % arg1 % arg2).str();
623 string bformat(string const & fmt, char const * arg1, string arg2)
625 return (boost::format(fmt) % arg1 % arg2).str();
630 string bformat(string const & fmt, string arg1, string arg2, string arg3)
632 return (boost::format(fmt) % arg1 % arg2 % arg3).str();
637 string bformat(string const & fmt,
638 string arg1, string arg2, string arg3, string arg4)
640 return (boost::format(fmt) % arg1 % arg2 % arg3 % arg4).str();
646 string bformat(string const & fmt, int arg1)
648 BOOST_ASSERT(contains(fmt, "%1$d"));
649 string const str = subst(fmt, "%1$d", convert<string>(arg1));
650 return subst(str, "%%", "%");
655 string bformat(string const & fmt, long arg1)
657 BOOST_ASSERT(contains(fmt, "%1$d"));
658 string const str = subst(fmt, "%1$d", convert<string>(arg1));
659 return subst(str, "%%", "%");
664 string bformat(string const & fmt, unsigned int arg1)
666 BOOST_ASSERT(contains(fmt, "%1$d"));
667 string const str = subst(fmt, "%1$d", convert<string>(arg1));
668 return subst(str, "%%", "%");
673 string bformat(string const & fmt, string arg1)
675 BOOST_ASSERT(contains(fmt, "%1$s"));
676 string const str = subst(fmt, "%1$s", arg1);
677 return subst(str, "%%", "%");
682 string bformat(string const & fmt, char * arg1)
684 BOOST_ASSERT(contains(fmt, "%1$s"));
685 string const str = subst(fmt, "%1$s", arg1);
686 return subst(str, "%%", "%");
689 string bformat(string const & fmt, string arg1, string arg2)
691 BOOST_ASSERT(contains(fmt, "%1$s"));
692 BOOST_ASSERT(contains(fmt, "%2$s"));
693 string str = subst(fmt, "%1$s", arg1);
694 str = subst(str, "%2$s", arg2);
695 return subst(str, "%%", "%");
700 string bformat(string const & fmt, char const * arg1, string arg2)
702 BOOST_ASSERT(contains(fmt, "%1$s"));
703 BOOST_ASSERT(contains(fmt, "%2$s"));
704 string str = subst(fmt, "%1$s", arg1);
705 str = subst(fmt, "%2$s", arg2);
706 return subst(str, "%%", "%");
711 string bformat(string const & fmt, int arg1, int arg2)
713 BOOST_ASSERT(contains(fmt, "%1$d"));
714 BOOST_ASSERT(contains(fmt, "%2$d"));
715 string str = subst(fmt, "%1$d", convert<string>(arg1));
716 str = subst(str, "%2$d", convert<string>(arg2));
717 return subst(str, "%%", "%");
722 string bformat(string const & fmt, string arg1, string arg2, string arg3)
724 BOOST_ASSERT(contains(fmt, "%1$s"));
725 BOOST_ASSERT(contains(fmt, "%2$s"));
726 BOOST_ASSERT(contains(fmt, "%3$s"));
727 string str = subst(fmt, "%1$s", arg1);
728 str = subst(str, "%2$s", arg2);
729 str = subst(str, "%3$s", arg3);
730 return subst(str, "%%", "%");
735 string bformat(string const & fmt,
736 string arg1, string arg2, string arg3, string arg4)
738 BOOST_ASSERT(contains(fmt, "%1$s"));
739 BOOST_ASSERT(contains(fmt, "%2$s"));
740 BOOST_ASSERT(contains(fmt, "%3$s"));
741 BOOST_ASSERT(contains(fmt, "%4$s"));
742 string str = subst(fmt, "%1$s", arg1);
743 str = subst(str, "%2$s", arg2);
744 str = subst(str, "%3$s", arg3);
745 str = subst(str, "%4$s", arg4);
746 return subst(str, "%%", "%");
752 } // namespace support