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