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