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