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
19 #include <boost/regex.hpp>
20 #include <boost/tokenizer.hpp>
31 #ifndef CXX_GLOBAL_CSTD
40 int compare_no_case(string const & s, string const & s2)
42 string::const_iterator p = s.begin();
43 string::const_iterator p2 = s2.begin();
45 while (p != s.end() && p2 != s2.end()) {
46 int const lc1 = tolower(*p);
47 int const lc2 = tolower(*p2);
49 return (lc1 < lc2) ? -1 : 1;
54 if (s.size() == s2.size())
56 if (s.size() < s2.size())
63 int ascii_tolower(int c) {
64 if (c >= 'A' && c <= 'Z')
71 int compare_ascii_no_case(string const & s, string const & s2)
73 string::const_iterator p = s.begin();
74 string::const_iterator p2 = s2.begin();
76 while (p != s.end() && p2 != s2.end()) {
77 int const lc1 = ascii_tolower(*p);
78 int const lc2 = ascii_tolower(*p2);
80 return (lc1 < lc2) ? -1 : 1;
85 if (s.size() == s2.size())
87 if (s.size() < s2.size())
93 int compare_no_case(string const & s, string const & s2, unsigned int len)
95 string::const_iterator p = s.begin();
96 string::const_iterator p2 = s2.begin();
98 while (i < len && p != s.end() && p2 != s2.end()) {
99 int const lc1 = tolower(*p);
100 int const lc2 = tolower(*p2);
102 return (lc1 < lc2) ? -1 : 1;
108 if (s.size() >= len && s2.size() >= len)
110 if (s.size() < s2.size())
116 bool isStrInt(string const & str)
118 if (str.empty()) return false;
120 // Remove leading and trailing white space chars.
121 string const tmpstr = trim(str);
122 if (tmpstr.empty()) return false;
124 string::const_iterator cit = tmpstr.begin();
125 if ((*cit) == '-') ++cit;
126 string::const_iterator end = tmpstr.end();
127 for (; cit != end; ++cit) {
128 if (!isdigit((*cit))) return false;
134 bool isStrUnsignedInt(string const & str)
136 if (str.empty()) return false;
138 // Remove leading and trailing white space chars.
139 string const tmpstr = trim(str);
140 if (tmpstr.empty()) return false;
142 string::const_iterator cit = tmpstr.begin();
143 string::const_iterator end = tmpstr.end();
144 for (; cit != end; ++cit) {
145 if (!isdigit((*cit))) return false;
151 int strToInt(string const & str)
154 // Remove leading and trailing white space chars.
155 string const tmpstr = trim(str);
156 // Do the conversion proper.
157 return lyx::atoi(tmpstr);
164 unsigned int strToUnsignedInt(string const & str)
166 if (isStrUnsignedInt(str)) {
167 // Remove leading and trailing white space chars.
168 string const tmpstr = trim(str);
169 // Do the conversion proper.
170 return lyx::atoi(tmpstr);
177 bool isStrDbl(string const & str)
179 if (str.empty()) return false;
181 // Remove leading and trailing white space chars.
182 string const tmpstr = trim(str);
183 if (tmpstr.empty()) return false;
184 // if (1 < tmpstr.count('.')) return false;
186 string::const_iterator cit = tmpstr.begin();
187 bool found_dot(false);
188 if ((*cit) == '-') ++cit;
189 string::const_iterator end = tmpstr.end();
190 for (; cit != end; ++cit) {
207 double strToDbl(string const & str)
210 // Remove leading and trailing white space chars.
211 string const tmpstr = trim(str);
212 // Do the conversion proper.
213 return ::atof(tmpstr.c_str());
220 char lowercase(char c)
222 return char(tolower(c));
226 char uppercase(char c)
228 return char(toupper(c));
234 // since we cannot use std::tolower and std::toupper directly in the
235 // calls to std::transform yet, we use these helper clases. (Lgb)
237 struct local_lowercase {
238 char operator()(char c) const {
243 struct local_uppercase {
244 char operator()(char c) const {
249 struct local_ascii_lowercase {
250 char operator()(char c) const {
251 return ascii_tolower(c);
255 } // end of anon namespace
257 string const lowercase(string const & a)
260 transform(tmp.begin(), tmp.end(), tmp.begin(), local_lowercase());
264 string const uppercase(string const & a)
267 transform(tmp.begin(), tmp.end(), tmp.begin(), local_uppercase());
272 string const ascii_lowercase(string const & a)
275 transform(tmp.begin(), tmp.end(), tmp.begin(),
276 local_ascii_lowercase());
281 bool prefixIs(string const & a, char const * pre)
285 size_t const l = strlen(pre);
286 string::size_type const alen = a.length();
288 if (l > alen || a.empty())
291 #if !defined(USE_INCLUDED_STRING) && !defined(STD_STRING_IS_GOOD)
292 // Delete this code when the compilers get a bit better.
293 return ::strncmp(a.c_str(), pre, l) == 0;
295 // This is the code that we really want to use
296 // but until gcc ships with a basic_string that
297 // implements std::string correctly we have to
298 // use the code above.
299 return a.compare(0, l, pre, l) == 0;
305 bool prefixIs(string const & a, string const & pre)
307 string::size_type const prelen = pre.length();
308 string::size_type const alen = a.length();
310 if (prelen > alen || a.empty())
313 #if !defined(USE_INCLUDED_STRING) && !defined(STD_STRING_IS_GOOD)
314 return ::strncmp(a.c_str(), pre.c_str(), prelen) == 0;
316 return a.compare(0, prelen, pre) == 0;
322 bool suffixIs(string const & a, char c)
324 if (a.empty()) return false;
325 return a[a.length() - 1] == c;
329 bool suffixIs(string const & a, char const * suf)
333 size_t const suflen = strlen(suf);
334 string::size_type const alen = a.length();
339 #if !defined(USE_INCLUDED_STRING) && !defined(STD_STRING_IS_GOOD)
340 // Delete this code when the compilers get a bit better.
341 string tmp(a, alen - suflen);
342 return ::strncmp(tmp.c_str(), suf, suflen) == 0;
344 // This is the code that we really want to use
345 // but until gcc ships with a basic_string that
346 // implements std::string correctly we have to
347 // use the code above.
348 return a.compare(alen - suflen, suflen, suf) == 0;
354 bool suffixIs(string const & a, string const & suf)
356 string::size_type const suflen = suf.length();
357 string::size_type const alen = a.length();
362 #if !defined(USE_INCLUDED_STRING) && !defined(STD_STRING_IS_GOOD)
363 string tmp(a, alen - suflen);
364 return ::strncmp(tmp.c_str(), suf.c_str(), suflen) == 0;
366 return a.compare(alen - suflen, suflen, suf) == 0;
372 bool contains(string const & a, string const & b)
376 return a.find(b) != string::npos;
380 bool contains(string const & a, char b)
384 return a.find(b) != string::npos;
388 bool containsOnly(string const & s, string const & cset)
390 return s.find_first_not_of(cset) == string::npos;
394 // ale970405+lasgoutt-970425
395 // rewritten to use new string (Lgb)
396 string const token(string const & a, char delim, int n)
398 if (a.empty()) return string();
400 string::size_type k = 0;
401 string::size_type i = 0;
403 // Find delimiter or end of string
405 if ((i = a.find(delim, i)) == string::npos)
409 // i is now the n'th delim (or string::npos)
410 if (i == string::npos) return string();
411 k = a.find(delim, i);
412 // k is now the n'th + 1 delim (or string::npos)
414 return a.substr(i, k - i);
418 // this could probably be faster and/or cleaner, but it seems to work (JMarc)
419 // rewritten to use new string (Lgb)
420 int tokenPos(string const & a, char delim, string const & tok)
426 while (!str.empty()) {
427 str = split(str, tmptok, delim);
436 bool regexMatch(string const & a, string const & pattern)
438 // We massage the pattern a bit so that the usual
439 // shell pattern we all are used to will work.
440 // One nice thing about using a real regex is that
441 // things like "*.*[^~]" will work also.
442 // build the regex string.
443 string regex(pattern);
444 regex = subst(regex, ".", "\\.");
445 regex = subst(regex, "*", ".*");
446 boost::regex reg(STRCONV(regex));
447 return boost::regex_match(STRCONV(a), reg);
451 string const subst(string const & a, char oldchar, char newchar)
454 string::iterator lit = tmp.begin();
455 string::iterator end = tmp.end();
456 for (; lit != end; ++lit)
457 if ((*lit) == oldchar)
463 string const subst(string const & a,
464 char const * oldstr, string const & newstr)
469 string::size_type i = 0;
470 string::size_type olen = strlen(oldstr);
471 while ((i = lstr.find(oldstr, i)) != string::npos) {
472 lstr.replace(i, olen, newstr);
473 i += newstr.length(); // We need to be sure that we dont
474 // use the same i over and over again.
480 string const subst(string const & a,
481 string const & oldstr, string const & newstr)
484 string::size_type i = 0;
485 string::size_type const olen = oldstr.length();
486 while ((i = lstr.find(oldstr, i)) != string::npos) {
487 lstr.replace(i, olen, newstr);
488 i += newstr.length(); // We need to be sure that we dont
489 // use the same i over and over again.
495 string const trim(string const & a, char const * p)
499 if (a.empty() || !*p)
502 string::size_type r = a.find_last_not_of(p);
503 string::size_type l = a.find_first_not_of(p);
505 // Is this the minimal test? (lgb)
506 if (r == string::npos && l == string::npos)
509 return a.substr(l, r - l + 1);
513 string const rtrim(string const & a, char const * p)
517 if (a.empty() || !*p)
520 string::size_type r = a.find_last_not_of(p);
522 // Is this test really needed? (Lgb)
523 if (r == string::npos)
526 return a.substr(0, r + 1);
530 string const ltrim(string const & a, char const * p)
534 if (a.empty() || !*p)
537 string::size_type l = a.find_first_not_of(p);
539 if (l == string::npos)
542 return a.substr(l, string::npos);
546 string const split(string const & a, string & piece, char delim)
549 string::size_type i = a.find(delim);
550 if (i == a.length() - 1) {
551 piece = a.substr(0, i);
552 } else if (i != string::npos) {
553 piece = a.substr(0, i);
554 tmp = a.substr(i + 1);
557 tmp = a.substr(i + 1);
565 string const split(string const & a, char delim)
568 string::size_type i = a.find(delim);
569 if (i != string::npos) // found delim
570 tmp = a.substr(i + 1);
576 string const rsplit(string const & a, string & piece, char delim)
579 string::size_type i = a.rfind(delim);
580 if (i != string::npos) { // delimiter was found
581 piece = a.substr(0, i);
582 tmp = a.substr(i + 1);
583 } else { // delimter was not found
590 // This function escapes 8-bit characters and other problematic
591 // characters that cause problems in latex labels.
592 string const escape(string const & lab)
594 char hexdigit[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
595 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
597 for (string::size_type i = 0; i < lab.length(); ++i) {
598 unsigned char c= lab[i];
599 if (c >= 128 || c == '=' || c == '%') {
601 enc += hexdigit[c>>4];
602 enc += hexdigit[c & 15];
611 /// gives a vector of stringparts which have the delimiter delim
612 vector<string> const getVectorFromString(string const & str,
613 string const & delim)
615 // Lars would like this code to go, but for now his replacement (below)
616 // doesn't fullfil the same function. I have, therefore, reactivated the
617 // old code for now. Angus 11 Nov 2002.
622 string keys(rtrim(str));
624 string::size_type const idx = keys.find(delim);
625 if (idx == string::npos) {
626 vec.push_back(ltrim(keys));
629 string const key = trim(keys.substr(0, idx));
632 string::size_type const start = idx + delim.size();
633 keys = keys.substr(start);
637 boost::char_separator<char> sep(delim.c_str());
638 boost::tokenizer<boost::char_separator<char> > tokens(str, sep);
639 #ifndef USE_INCLUDED_STRING
640 return vector<string>(tokens.begin(), tokens.end());
643 using boost::tokenizer;
644 using boost::char_separator;
646 tokenizer<char_separator<char> >::iterator it = tokens.begin();
647 tokenizer<char_separator<char> >::iterator end = tokens.end();
648 for (; it != end; ++it) {
649 vec.push_back(STRCONV((*it)));
657 // the same vice versa
658 string const getStringFromVector(vector<string> const & vec,
659 string const & delim)
663 for (vector<string>::const_iterator it = vec.begin();
664 it != vec.end(); ++it) {
665 string item = trim(*it);
666 if (item.empty()) continue;
668 if (i++ > 0) str += delim;