1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright (C) 1995 Matthias Ettrich
7 * Copyright (C) 1995-1998 The LyX Team.
9 *======================================================*/
15 #pragma implementation "LString.h"
18 // #include <assert.h> // Hmm, make depend crashes with this one in. (Asger)
24 // $Id: LString.C,v 1.1 1999/09/27 18:44:36 larsbj Exp $
26 #if !defined(lint) && !defined(WITH_WARNINGS)
27 static char vcid[] = "$Id: LString.C,v 1.1 1999/09/27 18:44:36 larsbj Exp $";
30 static const unsigned short xtra = 4;
31 // The extra space is used to reduce the number of allocations
32 // and copies required if a string is unshared. The performance
33 // boost can be considerable -- in some tests using LyX I found
34 // a 97% reduction in the runtime of operator+=(char) in some
35 // code for writing LaTeX files using LStrings.
36 // This was originally implemented using:
37 // xtra = 4 - (sizeof(srep) + len) % 4;
38 // where len is the length of the new string.
39 // This was intended to ensure the string was always aligned
40 // within 4-byte boundaries but after testing with xtra = 4,
41 // and finding a significant improvement I decided to just
42 // leave it at 4. ARRae.
46 static srep empty_rep;
53 LString::LString(char const *s)
55 static srep empty_rep;
59 register unsigned int const len = strlen(s);
60 p = (srep *) new char[sizeof(srep) + len + xtra];
64 memcpy(p->s, s, len + 1);
73 LString::LString(char const c)
75 static srep empty_rep;
78 p = (srep *) new char[sizeof(srep) + 1 + xtra];
91 LString& LString::operator=(char const *s)
93 static srep empty_rep;
96 lose(); // disconnect self
99 register unsigned int const len = strlen(s);
100 p = (srep *) new char[sizeof(srep) + len + xtra];
104 memcpy(p->s, s, len + 1);
114 LString& LString::operator=(LString const &x)
117 x.p->n++; // protect against ``st = st''
119 lose(); // disconnect self
126 LString& LString::operator=(char c)
128 static srep empty_rep;
132 lose(); // disconnect self
135 p = (srep *) new char[sizeof(srep) + 1 + xtra];
150 LString &LString::clean()
152 static srep empty_rep;
162 char& LString::operator[](int i)
165 if (i < 0 || i >= length()) {
166 fprintf(stderr,"LString::operator[]: Index out of range: '%s' %d\n", p->s, i);
171 if (p->n > 0) { // clone to maintain value semantics
172 srep * np = (srep *) new char[sizeof(srep) + p->l];
176 memcpy(np->s, p->s, length() + 1);
184 char const& LString::operator[](int i) const
187 if (i < 0 || i >= length()) {
188 fprintf(stderr,"LString::operator[] const: Index out of range: '%s' i:%d.\n",p->s,i);
195 #endif /* ndef const */
197 LString &LString::operator+=(LString const & x)
199 if (x.empty()) return *this;
201 register unsigned int const len = length() + x.length();
202 if (p->n || p->e < x.length()) {
203 srep *np = (srep *) new char[sizeof(srep) + len + xtra];
207 memcpy(np->s, p->s, length());
208 memcpy(np->s + length(), x.p->s, x.length() + 1);
209 lose(); // disconnect self
212 // in cases where x += x and x is short the
213 // explicit setting of the '\0' stops any problems
214 memcpy(p->s + length(), x.p->s, x.length());
224 LString &LString::operator+=(char const *x)
226 if (!x || *x==0) return *this;
228 register unsigned int const xlen = strlen(x);
229 register unsigned int const len = length() + xlen;
230 if (p->n || p->e < xlen) {
231 srep *np = (srep *) new char[sizeof(srep) + len + xtra];
235 memcpy(np->s, p->s, length());
236 memcpy(np->s + length(), x, xlen + 1);
237 lose(); // disconnect self
240 // Explicitly setting the '\0' stops any
241 // problems caused by x += x.c_str()
242 memcpy(p->s + length(), x, xlen);
252 LString &LString::operator+=(char c)
254 register unsigned int const len = length() + 1;
256 // 80% (from profiling)
257 // This is where all the speed gains are made.
264 srep *np = (srep *) new char[sizeof(srep) + len + xtra];
268 memcpy(np->s, p->s, length());
271 lose(); // disconnect self
279 LString &LString::operator+=(int i)
281 return this->operator+=((long)i);
285 LString &LString::operator+=(long i)
287 unsigned int tmplen = 0;
289 // calculate the length of i
294 tmplen++; // minus sign
295 a = -a; // switch sign
297 while(a >= 1) { a = a/10; tmplen++;}
299 char *str = new char[tmplen + 1];
300 sprintf(str, "%ld", i);
301 this->operator+=(str);
308 char * LString::copy() const
310 char * new_string = new char[length()+1];
311 memcpy(new_string, p->s, length() + 1);
316 bool LString::contains(char const *a) const
318 return strstr(p->s, a) != NULL;
322 LString& LString::substring(int i1, int i2)
325 if (i1 > i2 || i1 >= length() || i2 >= length()) {
327 "LString::substring: Wrong indexing in substring:"
328 " '%s' i1=%d i2=%d\n", p->s, i1, i2);
334 this->operator=(p->s[i1]);
336 char *str = new char[i2 - i1 +2];
338 for (i=0; i1<=i2; str[i++] = p->s[i1++]);
340 this->operator=(str);
347 // ale970405+lasgoutt-970425
348 LString LString::token(char delim, int n) const
354 // Find delimiter or end of string
355 for (i = 0; i < tokbuf.length(); i++) {
356 if (tokbuf[i] == delim) {
364 // Return the token if not empty
366 return tokbuf.substring(k, i-1);
373 // this could probably be faster and/or cleaner, but it seems to work (JMarc)
374 int LString::tokenPos(char delim, LString const &tok)
380 while (!str.empty()) {
381 str.split(tmptok, delim);
390 LString& LString::split(LString & piece, char delim)
393 // Find delimiter or end of string
394 while (i<length() && p->s[i] != delim)
396 // If not the first, we go for a substring
399 piece.substring(0, i-1);
404 this->substring(i+1, length()-1);
411 LString& LString::split(char delim)
414 // Find delimiter or end of string
415 while (i<length() && p->s[i] != delim)
419 this->substring(i+1, length()-1);
427 LString& LString::rsplit(LString & piece, char delim)
430 // Find delimiter or begin of string
431 while (i>=0 && p->s[i] != delim)
433 // If not the last, we go for a substring
434 if (i < length()-1) {
436 piece.substring(0, i-1);
437 this->substring(i+1, length()-1);
446 LString& LString::strip(char const c)
449 for (; i>=0 && p->s[i] == c; i--);
453 this->substring(0, i);
458 LString& LString::frontStrip(char const c)
461 while (i < length() && p->s[i] == c) i++;
466 this->substring (i, length()-1);
471 bool LString::prefixIs(char const * pre) const
473 if ((int) strlen(pre) > length())
476 return strncmp(p->s, pre, strlen(pre))==0;
480 bool LString::suffixIs(char c) const
482 if (empty()) return false;
483 return p->s[length()-1] == c;
487 bool LString::suffixIs(char const * suf) const
489 int suflen = (int) strlen(suf);
490 if (suflen > length())
493 return strncmp(p->s + (length()-suflen), suf, suflen)==0;
497 LString& LString::subst(char oldchar, char newchar)
499 for (int i=0; i<length() ; i++)
500 if (p->s[i]==oldchar)
506 LString& LString::subst(char const * oldstr, LString const & newstr)
508 LString lstr = *this;
509 char * str = lstr.copy();
512 while((first=strstr(str,oldstr))){
513 if (first==str) lstr.clean();
514 else lstr.substring(0,first-str-1);
516 lstr+=first+strlen(oldstr);
525 LString& LString::lowercase()
527 for (int i=0; i<length() ; i++)
528 p->s[i] = tolower((unsigned char) p->s[i]);
533 bool LString::regexMatch(LString const & pattern) const
541 int const sl = length();
542 int const pl = pattern.length();
544 while (si < sl && pi < pl) {
545 if (pattern[pi]=='*') {
546 // Skip all consequtive *s
547 while (pattern[pi] == '*') {
553 // Get next chunk of pattern to match
554 LString temp= pattern;
555 temp.substring(pi, pl-1);
557 temp.split(chunk, '*');
559 if (!chunk.empty() && pattern[pl-1] == '*' &&
564 // Last chunk, see if tail matches
566 temp.substring(sl - chunk.length(), sl - 1);
567 return temp == chunk;
569 // Middle chunk, see if we can find a match
571 while (!match && si<sl) {
573 temp.substring(si, sl - 1);
574 match = temp.prefixIs(chunk.c_str());
579 si += chunk.length()-1;
580 pi += chunk.length();
581 if (si==sl && pi==pl-1)
584 } else if (operator[](si++) != pattern[pi++]) {
588 if (pi < pl || si < sl)