]> git.lyx.org Git - lyx.git/blob - src/support/lstrings.C
lyx-devel.diff
[lyx.git] / src / support / lstrings.C
1 /* This file is part of
2  * ====================================================== 
3  * 
4  *           LyX, The Document Processor
5  *        
6  *           Copyright 1995 Matthias Ettrich
7  *           Copyright 1995-2000 The LyX Team.
8  *
9  * ====================================================== */
10
11 #include <config.h>
12
13 #ifdef __GNUG__
14 #pragma implementation
15 #endif
16
17 #include <algorithm>
18
19 #include <cctype>
20 #include <cstdlib>
21
22 #include "LString.h"
23 #include "lstrings.h"
24 #include "LRegex.h"
25 #include "LAssert.h"
26
27 using std::count;
28 using std::transform;
29 #ifndef CXX_GLOBAL_CSTD
30 using std::tolower;
31 using std::toupper;
32 #endif
33
34
35 int compare_no_case(string const & s, string const & s2)
36 {
37         string::const_iterator p = s.begin();
38         string::const_iterator p2 = s2.begin();
39
40         while (p != s.end() && p2 != s2.end()) {
41                 int const lc1 = tolower(*p);
42                 int const lc2 = tolower(*p2);
43                 if (lc1 != lc2)
44                         return (lc1 < lc2) ? -1 : 1;
45                 ++p;
46                 ++p2;
47         }
48
49         if (s.size() == s2.size())
50                 return 0;
51         if (s.size() < s2.size())
52                 return -1;
53         return 1;
54 }
55
56
57 int compare_no_case(string const & s, string const & s2, unsigned int len)
58 {
59         string::const_iterator p = s.begin();
60         string::const_iterator p2 = s2.begin();
61         unsigned int i = 0;
62         while (i < len && p != s.end() && p2 != s2.end()) {
63                 int const lc1 = tolower(*p);
64                 int const lc2 = tolower(*p2);
65                 if (lc1 != lc2)
66                         return (lc1 < lc2) ? -1 : 1;
67                 ++i;
68                 ++p;
69                 ++p2;
70         }
71
72         if (s.size() >= len && s2.size() >= len)
73                 return 0;
74         if (s.size() < s2.size())
75                 return -1;
76         return 1;
77 }
78
79
80 bool isStrInt(string const & str)
81 {
82         if (str.empty()) return false;
83        
84         // Remove leading and trailing white space chars.
85         string const tmpstr = frontStrip(strip(str, ' '), ' ');
86         if (tmpstr.empty()) return false;
87        
88         string::const_iterator cit = tmpstr.begin();
89         if ((*cit) == '-') ++cit;
90         string::const_iterator end = tmpstr.end();
91         for (; cit != end; ++cit) {
92                 if (!isdigit((*cit))) return false;
93         }
94         return true;
95 }
96
97
98 bool isStrUnsignedInt(string const & str)
99 {
100         if (str.empty()) return false;
101        
102         // Remove leading and trailing white space chars.
103         string const tmpstr = frontStrip(strip(str, ' '), ' ');
104         if (tmpstr.empty()) return false;
105        
106         string::const_iterator cit = tmpstr.begin();
107         string::const_iterator end = tmpstr.end();
108         for (; cit != end; ++cit) {
109                 if (!isdigit((*cit))) return false;
110         }
111         return true;
112 }
113
114
115 int strToInt(string const & str)
116 {
117         if (isStrInt(str)) {
118                 // Remove leading and trailing white space chars.
119                 string const tmpstr = frontStrip(strip(str, ' '), ' ');
120                 // Do the conversion proper.
121                 return lyx::atoi(tmpstr);
122         } else {
123                 return 0;
124         }
125 }
126
127
128 unsigned int strToUnsignedInt(string const & str)
129 {
130         if (isStrUnsignedInt(str)) {
131                 // Remove leading and trailing white space chars.
132                 string const tmpstr = frontStrip(strip(str, ' '), ' ');
133                 // Do the conversion proper.
134                 return lyx::atoi(tmpstr);
135         } else {
136                 return 0;
137         }
138 }
139
140
141 bool isStrDbl(string const & str)
142 {
143         if (str.empty()) return false;
144         
145         // Remove leading and trailing white space chars.
146         string const tmpstr = frontStrip(strip(str, ' '), ' ');
147         if (tmpstr.empty()) return false;
148         //      if (1 < tmpstr.count('.')) return false;
149
150         string::const_iterator cit = tmpstr.begin();
151         bool found_dot(false);
152         if ((*cit) == '-') ++cit;
153         string::const_iterator end = tmpstr.end();
154         for (; cit != end; ++cit) {
155                 if (!isdigit((*cit))
156                     && '.' != (*cit)) {
157                         return false;
158                 }
159                 if ('.' == (*cit)) {
160                         if (found_dot) {
161                                 return false;
162                         } else {
163                                 found_dot = true;
164                         }
165                 }
166         }
167         return true;
168 }
169
170
171 double strToDbl(string const & str)
172 {
173         if (isStrDbl(str)) {
174                 // Remove leading and trailing white space chars.
175                 string const tmpstr = frontStrip(strip(str, ' '), ' ');
176                 // Do the conversion proper.
177                 return ::atof(tmpstr.c_str());
178         } else {
179                 return 0.0;
180         }
181 }
182
183
184 char lowercase(char c) 
185
186         return char( tolower(c) ); 
187 }
188
189
190 char uppercase(char c) 
191
192         return char( toupper(c) ); 
193 }
194
195
196 string const lowercase(string const & a)
197 {
198         string tmp(a);
199 #if 1
200         string::iterator result = tmp.begin();
201         string::iterator end = tmp.end();
202         for (string::iterator first = tmp.begin();
203              first != end; ++first, ++result) {
204                 *result = lowercase(*first);
205         }
206 #else
207         // We want to use this one. (Lgb)
208         transform(tmp.begin(), tmp.end(), tmp.begin(), lowercase);
209 #endif
210         return tmp;
211 }
212
213
214 string const uppercase(string const & a)
215 {
216         string tmp(a);
217 #if 1
218         string::iterator result = tmp.begin();
219         string::iterator end = tmp.end();
220         for (string::iterator first = tmp.begin();
221              first != end; ++first, ++result) {
222                 *result = uppercase(*first);
223         }
224 #else
225         // We want to use this one. (Lgb)
226         transform(tmp.begin(), tmp.end(), tmp.begin(), uppercase);
227 #endif
228         return tmp;
229 }
230
231
232 bool prefixIs(string const & a, char const * pre)
233 {
234         Assert(pre);
235         
236         size_t const l = strlen(pre);
237         string::size_type const alen = a.length();
238         
239         if (l > alen || a.empty())
240                 return false;
241         else {
242 #if !defined(USE_INCLUDED_STRING) && !defined(STD_STRING_IS_GOOD)
243                 // Delete this code when the compilers get a bit better.
244                 return ::strncmp(a.c_str(), pre, l) == 0;
245 #else
246                 // This is the code that we really want to use
247                 // but until gcc ships with a basic_string that
248                 // implements std::string correctly we have to
249                 // use the code above.
250                 return a.compare(0, l, pre, l) == 0;
251 #endif
252         }
253 }
254
255
256 bool prefixIs(string const & a, string const & pre)
257 {
258         string::size_type const prelen = pre.length();
259         string::size_type const alen = a.length();
260         
261         if (prelen > alen || a.empty())
262                 return false;
263         else {
264 #if !defined(USE_INCLUDED_STRING) && !defined(STD_STRING_IS_GOOD)
265                 return ::strncmp(a.c_str(), pre.c_str(), prelen) == 0;
266 #else
267                 return a.compare(0, prelen, pre) == 0;
268 #endif
269         }
270 }
271
272
273 bool suffixIs(string const & a, char c)
274 {
275         if (a.empty()) return false;
276         return a[a.length() - 1] == c;
277 }
278
279
280 bool suffixIs(string const & a, char const * suf)
281 {
282         Assert(suf);
283         
284         size_t const suflen = strlen(suf);
285         string::size_type const alen = a.length();
286         
287         if (suflen > alen)
288                 return false;
289         else {
290 #if !defined(USE_INCLUDED_STRING) && !defined(STD_STRING_IS_GOOD)
291                 // Delete this code when the compilers get a bit better.
292                 string tmp(a, alen - suflen);
293                 return ::strncmp(tmp.c_str(), suf, suflen) == 0;
294 #else
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(alen - suflen, suflen, suf) == 0;
300 #endif
301         }
302 }
303
304
305 bool suffixIs(string const & a, string const & suf)
306 {
307         string::size_type const suflen = suf.length();
308         string::size_type const alen = a.length();
309         
310         if (suflen > alen) {
311                 return false;
312         } else {
313 #if !defined(USE_INCLUDED_STRING) && !defined(STD_STRING_IS_GOOD)
314                 string tmp(a, alen - suflen);
315                 return ::strncmp(tmp.c_str(), suf.c_str(), suflen) == 0;
316 #else
317                 return a.compare(alen - suflen, suflen, suf) == 0;
318 #endif
319         }
320 }
321
322
323 bool contains(char const * a, string const & b)
324 {
325         Assert(a);
326         string const at(a);
327         return contains(at, b);
328 }
329
330
331 bool contains(string const & a, char const * b)
332 {
333         Assert(b);
334         string const bt(b);
335         return contains(a, bt);
336 }
337
338
339 bool contains(string const & a, string const & b)
340 {
341         if (a.empty())
342                 return false;
343         return a.find(b) != string::npos;
344 }
345
346
347 bool contains(string const & a, char b)
348 {
349         if (a.empty())
350                 return false;
351         return a.find(b) != string::npos;
352 }
353
354
355 bool contains(char const * a, char const * b)
356 {
357         Assert(a && b);
358         string const at(a);
359         string const bt(b);
360         return contains(at, bt);
361 }
362
363
364 bool containsOnly(string const & s, char const * cset)
365 {
366         Assert(cset);
367         
368         return s.find_first_not_of(cset) == string::npos;
369 }
370
371
372 bool containsOnly(string const & s, string const & cset)
373 {
374         return s.find_first_not_of(cset) == string::npos;
375 }
376
377
378 bool containsOnly(char const * s, char const * cset)
379 {
380         Assert(s && cset);
381         
382         return string(s).find_first_not_of(cset) == string::npos;
383 }
384
385
386 bool containsOnly(char const * s, string const & cset)
387 {
388         Assert(s);
389         
390         return string(s).find_first_not_of(cset) == string::npos;
391 }
392
393
394 string::size_type countChar(string const & a, char c)
395 {
396 #ifdef HAVE_STD_COUNT
397         return count(a.begin(), a.end(), c);
398 #else
399         unsigned int n = 0;
400         count(a.begin(), a.end(), c, n);
401         return n;
402 #endif
403 }
404
405
406 // ale970405+lasgoutt-970425
407 // rewritten to use new string (Lgb)
408 string const token(string const & a, char delim, int n)
409 {
410         if (a.empty()) return string();
411         
412         string::size_type k = 0;
413         string::size_type i = 0;
414
415         // Find delimiter or end of string
416         for (; n--;)
417                 if ((i = a.find(delim, i)) == string::npos)
418                         break;
419                 else
420                         ++i; // step delim
421         // i is now the n'th delim (or string::npos)
422         if (i == string::npos) return string();
423         k = a.find(delim, i);
424         // k is now the n'th + 1 delim (or string::npos)
425
426         return a.substr(i, k - i);
427 }
428
429
430 // this could probably be faster and/or cleaner, but it seems to work (JMarc)
431 // rewritten to use new string (Lgb)
432 int tokenPos(string const & a, char delim, string const & tok)
433 {
434         int i = 0;
435         string str(a);
436         string tmptok;
437
438         while (!str.empty()) {
439                 str = split(str, tmptok, delim);
440                 if (tok == tmptok)
441                         return i;
442                 ++i;
443         }
444         return -1;
445 }
446
447
448 bool regexMatch(string const & a, string const & pattern)
449 {
450         // We massage the pattern a bit so that the usual
451         // shell pattern we all are used to will work.
452         // One nice thing about using a real regex is that
453         // things like "*.*[^~]" will work also.
454         // build the regex string.
455         string regex(pattern);
456         regex = subst(regex, ".", "\\.");
457         regex = subst(regex, "*", ".*");
458         LRegex reg(regex);
459         return reg.exact_match(a);
460 }
461
462
463 string const subst(string const & a, char oldchar, char newchar)
464 {
465         string tmp(a);
466         string::iterator lit = tmp.begin();
467         string::iterator end = tmp.end();
468         for (; lit != end; ++lit)
469                 if ((*lit) == oldchar)
470                         (*lit) = newchar;
471         return tmp;
472 }
473
474
475 string const subst(string const & a,
476              char const * oldstr, string const & newstr)
477 {
478         Assert(oldstr);
479         
480         string lstr(a);
481         string::size_type i = 0;
482         string::size_type olen = strlen(oldstr);
483         while((i = lstr.find(oldstr, i)) != string::npos) {
484                 lstr.replace(i, olen, newstr);
485                 i += newstr.length(); // We need to be sure that we dont
486                 // use the same i over and over again.
487         }
488         return lstr;
489 }
490
491
492 string const subst(string const & a,
493                    string const & oldstr, string const & newstr)
494 {
495         string lstr(a);
496         string::size_type i = 0;
497         string::size_type const olen = oldstr.length();
498         while((i = lstr.find(oldstr, i)) != string::npos) {
499                 lstr.replace(i, olen, newstr);
500                 i += newstr.length(); // We need to be sure that we dont
501                 // use the same i over and over again.
502         }
503         return lstr;
504 }
505
506
507 string const strip(string const & a, char c)
508 {
509         if (a.empty()) return a;
510         string tmp(a);
511         string::size_type i = tmp.find_last_not_of(c);
512         if (i == a.length() - 1) return tmp; // no c's at end of a
513         if (i != string::npos) 
514                 tmp.erase(i + 1, string::npos);
515 #if !defined(USE_INCLUDED_STRING) && !defined(STD_STRING_IS_GOOD)
516         /// Needed for broken string::find_last_not_of
517         else if (tmp[0] != c) {
518                 if (a.length() == 1) return tmp;
519                 tmp.erase(1, string::npos);
520         }
521 #endif
522         else
523                 tmp.erase(); // only c in the whole string
524         return tmp;
525 }
526
527
528 string const frontStrip(string const & a, char const * p)
529 {
530         Assert(p);
531         
532         if (a.empty() || !*p) return a;
533         string tmp(a);
534         string::size_type i = tmp.find_first_not_of(p);
535         if (i > 0)
536                 tmp.erase(0, i);
537         return tmp;
538 }
539
540
541 string const frontStrip(string const & a, char c)
542 {
543         if (a.empty()) return a;
544         string tmp(a);
545         string::size_type i = tmp.find_first_not_of(c);
546         if (i > 0)
547                 tmp.erase(0, i);
548         return tmp;
549 }
550
551
552 string const split(string const & a, string & piece, char delim)
553 {
554         string tmp;
555         string::size_type i = a.find(delim);
556         if (i == a.length() - 1) {
557                 piece = a.substr(0, i);
558         } else if (i != string::npos) {
559                 piece = a.substr(0, i);
560                 tmp = a.substr(i + 1);
561         } else if (i == 0) {
562                 piece.erase();
563                 tmp = a.substr(i + 1);
564         } else {
565                 piece = a;
566         }
567         return tmp;
568 }
569
570
571 string const split(string const & a, char delim)
572 {
573         string tmp;
574         string::size_type i = a.find(delim);
575         if (i != string::npos) // found delim
576                 tmp = a.substr(i + 1);
577         return tmp;
578 }
579
580
581 // ale970521
582 string const rsplit(string const & a, string & piece, char delim)
583 {
584         string tmp;
585         string::size_type i = a.rfind(delim);
586         if (i != string::npos) { // delimiter was found
587                 piece = a.substr(0, i);
588                 tmp = a.substr(i + 1);
589         } else { // delimter was not found
590                 piece.erase();
591         }
592         return tmp;
593 }