]> git.lyx.org Git - lyx.git/blob - src/support/lstrings.C
74fc4fee8cb72d5a5934d3c64b31a90c67a849c5
[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         // ANSI C
38         string::const_iterator p = s.begin();
39         string::const_iterator p2 = s2.begin();
40
41         while (p != s.end() && p2 != s2.end()) {
42                 int const lc1 = tolower(*p);
43                 int const lc2 = tolower(*p2);
44                 if (lc1 != lc2)
45                         return (lc1 < lc2) ? -1 : 1;
46                 ++p;
47                 ++p2;
48         }
49         
50         if (s.size() == s2.size())
51                 return 0;
52         if (s.size() < s2.size())
53                 return -1;
54         return 1;
55 }
56
57
58 int compare_no_case(string const & s, string const & s2, unsigned int len)
59 {
60         string::const_iterator p = s.begin();
61         string::const_iterator p2 = s2.begin();
62         unsigned int i = 0;
63         while (i < len && p != s.end() && p2 != s2.end()) {
64                 int const lc1 = tolower(*p);
65                 int const lc2 = tolower(*p2);
66                 if (lc1 != lc2)
67                         return (lc1 < lc2) ? -1 : 1;
68                 ++i;
69                 ++p;
70                 ++p2;
71         }
72         if (s.size() == s2.size())
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(char const * a, char const * b)
348 {
349         Assert(a && b);
350         string const at(a);
351         string const bt(b);
352         return contains(at, bt);
353 }
354
355
356 bool containsOnly(string const & s, char const * cset)
357 {
358         Assert(cset);
359         
360         return s.find_first_not_of(cset) == string::npos;
361 }
362
363
364 bool containsOnly(string const & s, string const & cset)
365 {
366         return s.find_first_not_of(cset) == string::npos;
367 }
368
369
370 bool containsOnly(char const * s, char const * cset)
371 {
372         Assert(s && cset);
373         
374         return string(s).find_first_not_of(cset) == string::npos;
375 }
376
377
378 bool containsOnly(char const * s, string const & cset)
379 {
380         Assert(s);
381         
382         return string(s).find_first_not_of(cset) == string::npos;
383 }
384
385
386 string::size_type countChar(string const & a, char c)
387 {
388 #ifdef HAVE_STD_COUNT
389         return count(a.begin(), a.end(), c);
390 #else
391         unsigned int n = 0;
392         count(a.begin(), a.end(), c, n);
393         return n;
394 #endif
395 }
396
397
398 // ale970405+lasgoutt-970425
399 // rewritten to use new string (Lgb)
400 string const token(string const & a, char delim, int n)
401 {
402         if (a.empty()) return string();
403         
404         string::size_type k = 0;
405         string::size_type i = 0;
406
407         // Find delimiter or end of string
408         for (; n--;)
409                 if ((i = a.find(delim, i)) == string::npos)
410                         break;
411                 else
412                         ++i; // step delim
413         // i is now the n'th delim (or string::npos)
414         if (i == string::npos) return string();
415         k = a.find(delim, i);
416         // k is now the n'th + 1 delim (or string::npos)
417
418         return a.substr(i, k - i);
419 }
420
421
422 // this could probably be faster and/or cleaner, but it seems to work (JMarc)
423 // rewritten to use new string (Lgb)
424 int tokenPos(string const & a, char delim, string const & tok)
425 {
426         int i = 0;
427         string str(a);
428         string tmptok;
429
430         while (!str.empty()) {
431                 str = split(str, tmptok, delim);
432                 if (tok == tmptok)
433                         return i;
434                 ++i;
435         }
436         return -1;
437 }
438
439
440 bool regexMatch(string const & a, string const & pattern)
441 {
442         // We massage the pattern a bit so that the usual
443         // shell pattern we all are used to will work.
444         // One nice thing about using a real regex is that
445         // things like "*.*[^~]" will work also.
446         // build the regex string.
447         string regex(pattern);
448         regex = subst(regex, ".", "\\.");
449         regex = subst(regex, "*", ".*");
450         LRegex reg(regex);
451         return reg.exact_match(a);
452 }
453
454
455 string const subst(string const & a, char oldchar, char newchar)
456 {
457         string tmp(a);
458         string::iterator lit = tmp.begin();
459         string::iterator end = tmp.end();
460         for (; lit != end; ++lit)
461                 if ((*lit) == oldchar)
462                         (*lit) = newchar;
463         return tmp;
464 }
465
466
467 string const subst(string const & a,
468              char const * oldstr, string const & newstr)
469 {
470         Assert(oldstr);
471         
472         string lstr(a);
473         string::size_type i = 0;
474         string::size_type olen = strlen(oldstr);
475         while((i = lstr.find(oldstr, i)) != string::npos) {
476                 lstr.replace(i, olen, newstr);
477                 i += newstr.length(); // We need to be sure that we dont
478                 // use the same i over and over again.
479         }
480         return lstr;
481 }
482
483
484 string const subst(string const & a,
485                    string const & oldstr, string const & newstr)
486 {
487         string lstr(a);
488         string::size_type i = 0;
489         string::size_type const olen = oldstr.length();
490         while((i = lstr.find(oldstr, i)) != string::npos) {
491                 lstr.replace(i, olen, newstr);
492                 i += newstr.length(); // We need to be sure that we dont
493                 // use the same i over and over again.
494         }
495         return lstr;
496 }
497
498
499 string const strip(string const & a, char c)
500 {
501         if (a.empty()) return a;
502         string tmp(a);
503         string::size_type i = tmp.find_last_not_of(c);
504         if (i == a.length() - 1) return tmp; // no c's at end of a
505         if (i != string::npos) 
506                 tmp.erase(i + 1, string::npos);
507         else
508                 tmp.erase(); // only c in the whole string
509         return tmp;
510 }
511
512
513 string const frontStrip(string const & a, char const * p)
514 {
515         Assert(p);
516         
517         if (a.empty() || !*p) return a;
518         string tmp(a);
519         string::size_type i = tmp.find_first_not_of(p);
520         if (i > 0)
521                 tmp.erase(0, i);
522         return tmp;
523 }
524
525
526 string const frontStrip(string const & a, char c)
527 {
528         if (a.empty()) return a;
529         string tmp(a);
530         string::size_type i = tmp.find_first_not_of(c);
531         if (i > 0)
532                 tmp.erase(0, i);
533         return tmp;
534 }
535
536
537 string const split(string const & a, string & piece, char delim)
538 {
539         string tmp;
540         string::size_type i = a.find(delim);
541         if (i == a.length() - 1) {
542                 piece = a.substr(0, i);
543         } else if (i != string::npos) {
544                 piece = a.substr(0, i);
545                 tmp = a.substr(i + 1);
546         } else if (i == 0) {
547                 piece.erase();
548                 tmp = a.substr(i + 1);
549         } else {
550                 piece = a;
551         }
552         return tmp;
553 }
554
555
556 string const split(string const & a, char delim)
557 {
558         string tmp;
559         string::size_type i = a.find(delim);
560         if (i != string::npos) // found delim
561                 tmp = a.substr(i + 1);
562         return tmp;
563 }
564
565
566 // ale970521
567 string const rsplit(string const & a, string & piece, char delim)
568 {
569         string tmp;
570         string::size_type i = a.rfind(delim);
571         if (i != string::npos) { // delimiter was found
572                 piece = a.substr(0, i);
573                 tmp = a.substr(i + 1);
574         } else { // delimter was not found
575                 piece.erase();
576         }
577         return tmp;
578 }