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