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));
201 // FIXME for lowercase() and uppercase() function below:
202 // 1) std::tolower() and std::toupper() are templates that
203 // compile fine with char_type. With the test (c >= 256) we
204 // do not trust these function to do the right thing with
206 // 2) these functions use the current locale, which is wrong
207 // if it is not latin1 based (latin1 is a subset of UCS4).
209 char_type lowercase(char_type c)
218 char_type uppercase(char_type c)
229 // since we cannot use std::tolower and std::toupper directly in the
230 // calls to std::transform yet, we use these helper clases. (Lgb)
232 struct local_lowercase {
233 char operator()(char c) const {
238 struct local_uppercase {
239 char operator()(char c) const {
244 struct local_ascii_lowercase {
245 char operator()(char c) const {
246 return ascii_tolower(c);
250 } // end of anon namespace
252 string const lowercase(string const & a)
255 transform(tmp.begin(), tmp.end(), tmp.begin(), local_lowercase());
259 string const uppercase(string const & a)
262 transform(tmp.begin(), tmp.end(), tmp.begin(), local_uppercase());
267 string const ascii_lowercase(string const & a)
270 transform(tmp.begin(), tmp.end(), tmp.begin(),
271 local_ascii_lowercase());
276 bool prefixIs(string const & a, string const & pre)
278 string::size_type const prelen = pre.length();
279 string::size_type const alen = a.length();
281 if (prelen > alen || a.empty())
284 #if defined(STD_STRING_IS_GOOD)
285 return a.compare(0, prelen, pre) == 0;
287 return ::strncmp(a.c_str(), pre.c_str(), prelen) == 0;
293 bool suffixIs(string const & a, char c)
295 if (a.empty()) return false;
296 return a[a.length() - 1] == c;
300 bool suffixIs(string const & a, string const & suf)
302 string::size_type const suflen = suf.length();
303 string::size_type const alen = a.length();
308 #if !defined(USE_INCLUDED_STRING) && !defined(STD_STRING_IS_GOOD)
309 string tmp(a, alen - suflen);
310 return ::strncmp(tmp.c_str(), suf.c_str(), suflen) == 0;
312 return a.compare(alen - suflen, suflen, suf) == 0;
318 bool containsOnly(string const & s, string const & cset)
320 return s.find_first_not_of(cset) == string::npos;
324 // ale970405+lasgoutt-970425
325 // rewritten to use new string (Lgb)
326 string const token(string const & a, char delim, int n)
328 if (a.empty()) return string();
330 string::size_type k = 0;
331 string::size_type i = 0;
333 // Find delimiter or end of string
335 if ((i = a.find(delim, i)) == string::npos)
339 // i is now the n'th delim (or string::npos)
340 if (i == string::npos) return string();
341 k = a.find(delim, i);
342 // k is now the n'th + 1 delim (or string::npos)
344 return a.substr(i, k - i);
348 // this could probably be faster and/or cleaner, but it seems to work (JMarc)
349 // rewritten to use new string (Lgb)
350 int tokenPos(string const & a, char delim, string const & tok)
356 while (!str.empty()) {
357 str = split(str, tmptok, delim);
368 template<typename Ch> inline
369 std::basic_string<Ch> const subst_char(std::basic_string<Ch> const & a,
370 Ch oldchar, Ch newchar)
372 typedef std::basic_string<Ch> String;
374 typename String::iterator lit = tmp.begin();
375 typename String::iterator end = tmp.end();
376 for (; lit != end; ++lit)
377 if ((*lit) == oldchar)
383 template<typename String> inline
384 String const subst_string(String const & a,
385 String const & oldstr, String const & newstr)
387 BOOST_ASSERT(!oldstr.empty());
389 typename String::size_type i = 0;
390 typename String::size_type const olen = oldstr.length();
391 while ((i = lstr.find(oldstr, i)) != string::npos) {
392 lstr.replace(i, olen, newstr);
393 i += newstr.length(); // We need to be sure that we dont
394 // use the same i over and over again.
402 string const subst(string const & a, char oldchar, char newchar)
404 return subst_char(a, oldchar, newchar);
408 docstring const subst(docstring const & a,
409 char_type oldchar, char_type newchar)
411 return subst_char(a, oldchar, newchar);
415 string const subst(string const & a,
416 string const & oldstr, string const & newstr)
418 return subst_string(a, oldstr, newstr);
422 docstring const subst(docstring const & a,
423 docstring const & oldstr, docstring const & newstr)
425 return subst_string(a, oldstr, newstr);
429 string const trim(string const & a, char const * p)
433 if (a.empty() || !*p)
436 string::size_type r = a.find_last_not_of(p);
437 string::size_type l = a.find_first_not_of(p);
439 // Is this the minimal test? (lgb)
440 if (r == string::npos && l == string::npos)
443 return a.substr(l, r - l + 1);
447 string const rtrim(string const & a, char const * p)
451 if (a.empty() || !*p)
454 string::size_type r = a.find_last_not_of(p);
456 // Is this test really needed? (Lgb)
457 if (r == string::npos)
460 return a.substr(0, r + 1);
464 string const ltrim(string const & a, char const * p)
468 if (a.empty() || !*p)
471 string::size_type l = a.find_first_not_of(p);
473 if (l == string::npos)
476 return a.substr(l, string::npos);
480 string const split(string const & a, string & piece, char delim)
483 string::size_type i = a.find(delim);
484 if (i == a.length() - 1) {
485 piece = a.substr(0, i);
486 } else if (i != string::npos) {
487 piece = a.substr(0, i);
488 tmp = a.substr(i + 1);
491 tmp = a.substr(i + 1);
499 string const split(string const & a, char delim)
502 string::size_type i = a.find(delim);
503 if (i != string::npos) // found delim
504 tmp = a.substr(i + 1);
510 string const rsplit(string const & a, string & piece, char delim)
513 string::size_type i = a.rfind(delim);
514 if (i != string::npos) { // delimiter was found
515 piece = a.substr(0, i);
516 tmp = a.substr(i + 1);
517 } else { // delimiter was not found
524 // This function escapes 8-bit characters and other problematic
525 // characters that cause problems in latex labels.
526 string const escape(string const & lab)
528 char hexdigit[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
529 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
531 for (string::size_type i = 0; i < lab.length(); ++i) {
532 unsigned char c= lab[i];
533 if (c >= 128 || c == '=' || c == '%') {
535 enc += hexdigit[c>>4];
536 enc += hexdigit[c & 15];
545 /// gives a vector of stringparts which have the delimiter delim
546 vector<string> const getVectorFromString(string const & str,
547 string const & delim)
549 // Lars would like this code to go, but for now his replacement (below)
550 // doesn't fullfil the same function. I have, therefore, reactivated the
551 // old code for now. Angus 11 Nov 2002.
556 string keys = rtrim(str);
558 string::size_type const idx = keys.find(delim);
559 if (idx == string::npos) {
560 vec.push_back(ltrim(keys));
563 string const key = trim(keys.substr(0, idx));
566 string::size_type const start = idx + delim.size();
567 keys = keys.substr(start);
571 boost::char_separator<char> sep(delim.c_str());
572 boost::tokenizer<boost::char_separator<char> > tokens(str, sep);
573 return vector<string>(tokens.begin(), tokens.end());
578 // the same vice versa
579 string const getStringFromVector(vector<string> const & vec,
580 string const & delim)
584 for (vector<string>::const_iterator it = vec.begin();
585 it != vec.end(); ++it) {
586 string item = trim(*it);
597 int findToken(char const * const str[], string const & search_token)
601 while (str[i][0] && str[i] != search_token)
609 docstring const externalLineEnding(docstring const & str)
611 #if defined(__APPLE__)
612 // The MAC clipboard uses \r for lineendings, and we use \n
613 return subst(str, '\n', '\r');
614 #elif defined (_WIN32) || (defined (__CYGWIN__) && defined (X_DISPLAY_MISSING))
615 // Windows clipboard uses \r\n for lineendings, and we use \n
616 return subst(str, lyx::from_ascii("\n"), lyx::from_ascii("\r\n"));
623 docstring const internalLineEnding(docstring const & str)
625 docstring const s = subst(str,
626 lyx::from_ascii("\r\n"), lyx::from_ascii("\n"));
627 return subst(s, '\r', '\n');
631 #ifndef I_AM_NOT_AFRAID_OF_HEADER_LIBRARIES
635 string bformat(string const & fmt, int arg1)
637 return (boost::format(fmt) % arg1).str();
642 string bformat(string const & fmt, long arg1)
644 return (boost::format(fmt) % arg1).str();
649 string bformat(string const & fmt, unsigned int arg1)
651 return (boost::format(fmt) % arg1).str();
656 string bformat<string>(string const & fmt, string arg1)
658 return (boost::format(fmt) % arg1).str();
663 string bformat(string const & fmt, char * arg1)
665 return (boost::format(fmt) % arg1).str();
670 string bformat(string const & fmt, int arg1, int arg2)
672 return (boost::format(fmt) % arg1 % arg2).str();
677 string bformat(string const & fmt, string arg1, string arg2)
679 return (boost::format(fmt) % arg1 % arg2).str();
684 string bformat(string const & fmt, char const * arg1, string arg2)
686 return (boost::format(fmt) % arg1 % arg2).str();
691 string bformat(string const & fmt, string arg1, string arg2, string arg3)
693 return (boost::format(fmt) % arg1 % arg2 % arg3).str();
698 string bformat(string const & fmt,
699 string arg1, string arg2, string arg3, string arg4)
701 return (boost::format(fmt) % arg1 % arg2 % arg3 % arg4).str();
707 string bformat(string const & fmt, int arg1)
709 BOOST_ASSERT(contains(fmt, "%1$d"));
710 string const str = subst(fmt, "%1$d", convert<string>(arg1));
711 return subst(str, "%%", "%");
716 string bformat(string const & fmt, long arg1)
718 BOOST_ASSERT(contains(fmt, "%1$d"));
719 string const str = subst(fmt, "%1$d", convert<string>(arg1));
720 return subst(str, "%%", "%");
725 string bformat(string const & fmt, unsigned int arg1)
727 BOOST_ASSERT(contains(fmt, "%1$d"));
728 string const str = subst(fmt, "%1$d", convert<string>(arg1));
729 return subst(str, "%%", "%");
734 string bformat(string const & fmt, string arg1)
736 BOOST_ASSERT(contains(fmt, "%1$s"));
737 string const str = subst(fmt, "%1$s", arg1);
738 return subst(str, "%%", "%");
743 string bformat(string const & fmt, char * arg1)
745 BOOST_ASSERT(contains(fmt, "%1$s"));
746 string const str = subst(fmt, "%1$s", arg1);
747 return subst(str, "%%", "%");
750 string bformat(string const & fmt, string arg1, string arg2)
752 BOOST_ASSERT(contains(fmt, "%1$s"));
753 BOOST_ASSERT(contains(fmt, "%2$s"));
754 string str = subst(fmt, "%1$s", arg1);
755 str = subst(str, "%2$s", arg2);
756 return subst(str, "%%", "%");
761 string bformat(string const & fmt, char const * arg1, string arg2)
763 BOOST_ASSERT(contains(fmt, "%1$s"));
764 BOOST_ASSERT(contains(fmt, "%2$s"));
765 string str = subst(fmt, "%1$s", arg1);
766 str = subst(fmt, "%2$s", arg2);
767 return subst(str, "%%", "%");
772 string bformat(string const & fmt, int arg1, int arg2)
774 BOOST_ASSERT(contains(fmt, "%1$d"));
775 BOOST_ASSERT(contains(fmt, "%2$d"));
776 string str = subst(fmt, "%1$d", convert<string>(arg1));
777 str = subst(str, "%2$d", convert<string>(arg2));
778 return subst(str, "%%", "%");
783 string bformat(string const & fmt, string arg1, string arg2, string arg3)
785 BOOST_ASSERT(contains(fmt, "%1$s"));
786 BOOST_ASSERT(contains(fmt, "%2$s"));
787 BOOST_ASSERT(contains(fmt, "%3$s"));
788 string str = subst(fmt, "%1$s", arg1);
789 str = subst(str, "%2$s", arg2);
790 str = subst(str, "%3$s", arg3);
791 return subst(str, "%%", "%");
796 string bformat(string const & fmt,
797 string arg1, string arg2, string arg3, string arg4)
799 BOOST_ASSERT(contains(fmt, "%1$s"));
800 BOOST_ASSERT(contains(fmt, "%2$s"));
801 BOOST_ASSERT(contains(fmt, "%3$s"));
802 BOOST_ASSERT(contains(fmt, "%4$s"));
803 string str = subst(fmt, "%1$s", arg1);
804 str = subst(str, "%2$s", arg2);
805 str = subst(str, "%3$s", arg3);
806 str = subst(str, "%4$s", arg4);
807 return subst(str, "%%", "%");
813 } // namespace support