home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / lyx-0.13.2.tar.gz / lyx-0.13.2.tar / lyx-0.13.2 / src / LString.C < prev    next >
C/C++ Source or Header  |  1998-04-23  |  11KB  |  552 lines

  1. /* This file is part of
  2.  * ======================================================
  3.  * 
  4.  *           LyX, The Document Processor
  5.  *      
  6.  *        Copyright (C) 1995 Matthias Ettrich
  7.  *          Copyright (C) 1995-1998 The LyX Team.
  8.  *
  9.  *======================================================*/
  10.  
  11.  
  12. #include <config.h>
  13.  
  14. #ifdef __GNUG__
  15. #pragma implementation "LString.h"
  16. #endif
  17.  
  18. #include "LString.h"
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <ctype.h>
  22.  
  23. #include "LAssert.h"
  24.  
  25. //     $Id: LString.C,v 1.1.1.1 1998/04/23 16:02:47 larsbj Exp $    
  26.  
  27. #if !defined(lint) && !defined(WITH_WARNINGS)
  28. static char vcid[] = "$Id: LString.C,v 1.1.1.1 1998/04/23 16:02:47 larsbj Exp $";
  29. #endif /* lint */
  30.  
  31. // All empty strings use this string representation.
  32. LString::srep LString::empty_rep(0);
  33. int const LString::npos = 1<<(sizeof(int)-1);
  34.  
  35. static const unsigned short xtra = 4;
  36. // The extra space is used to reduce the number of allocations
  37. // and copies required if a string is unshared. The performance
  38. // boost can be considerable -- in some tests using LyX I found
  39. // a 97% reduction in the runtime of operator+=(char) in some
  40. // code for writing LaTeX files using LStrings.
  41. // This was originally implemented using:
  42. //     xtra = 4 - (sizeof(srep) + len) % 4;
  43. // where len is the length of the new string.
  44. // This was intended to ensure the string was always aligned
  45. // within 4-byte boundaries but after testing with xtra = 4,
  46. // and finding a significant improvement I decided to just
  47. // leave it at 4. ARRae.
  48.  
  49. LString::LString(char const *s)
  50. {
  51.     if (s && *s) {
  52.         // > 99 %
  53.         register unsigned int const len = strlen(s);
  54.         p = (srep *) new char[sizeof(srep) + len + xtra];
  55.         p->l = len;
  56.         p->n = 0;
  57.         p->e = xtra;
  58.         memcpy(p->s, s, len + 1);
  59.     } else {
  60.         // < 1 %
  61.         p = &empty_rep;
  62.         empty_rep.n++;
  63.     }
  64. }
  65.  
  66.  
  67. LString& LString::operator=(char const *s)
  68. {
  69.     Assert(p);
  70.  
  71.     lose(); // disconnect self
  72.  
  73.     if (s && *s) {
  74.         register unsigned int const len = strlen(s);
  75.         p = (srep *) new char[sizeof(srep) + len + xtra];
  76.         p->l = len;
  77.         p->n = 0;
  78.         p->e = xtra;
  79.         memcpy(p->s, s, len + 1);
  80.     } else {
  81.         p = &empty_rep;
  82.         empty_rep.n++;
  83.     }
  84.     
  85.     return *this;
  86. }
  87.  
  88.  
  89. LString& LString::operator=(LString const &x)
  90. {
  91.     Assert(p);
  92.     x.p->n++; // protect against ``st = st''
  93.  
  94.         lose(); // disconnect self
  95.  
  96.     p = x.p;
  97.     return *this;
  98. }
  99.  
  100.  
  101. LString& LString::operator=(char c)
  102. {
  103.     Assert(p);
  104.  
  105.     lose(); // disconnect self
  106.  
  107.     if (c) {
  108.         p = (srep *) new char[sizeof(srep) + 1 + xtra];
  109.         p->l = 1;
  110.         p->n = 0;
  111.         p->e = xtra;
  112.         p->s[0] = c;
  113.         p->s[1] = '\0';
  114.     } else {
  115.         p = &empty_rep;
  116.         empty_rep.n++;
  117.     }
  118.  
  119.     return *this;
  120. }
  121.  
  122.  
  123. char& LString::operator[](int i)
  124. {
  125. //#ifdef DEVEL_VERSION
  126. //    if (i < 0 || i >= length()) {
  127. //        fprintf(stderr,"LString::operator[]: Index out of range: '%s' %d\n", p->s, i);
  128. //        abort();
  129. //    }
  130. //#endif
  131.     Assert(i>=0 && i < length());
  132.  
  133.     if (p->n > 0) { // clone to maintain value semantics
  134.         srep * np = (srep *) new char[sizeof(srep) + p->l];
  135.         np->l = p->l;
  136.         np->n = 0;
  137.         np->e = 0;
  138.         memcpy(np->s, p->s, length() + 1);
  139.         p->n--;
  140.         p = np;
  141.     }
  142.     return p->s[i];
  143. }
  144.  
  145. #ifndef const
  146. char const& LString::operator[](int i) const
  147. {
  148. //#ifdef DEVEL_VERSION
  149. //    if (i < 0 || i >= length()) {
  150. //        fprintf(stderr,"LString::operator[] const: Index out of range: '%s' i:%d.\n",p->s,i);
  151. //        abort();
  152. //    }
  153. //#endif
  154.     Assert(i>=0 && i < length());
  155.     
  156.     return p->s[i];
  157. }
  158. #endif /* ndef const */
  159.  
  160. LString &LString::operator+=(LString const & x)
  161. {
  162.     if (x.empty()) return *this;
  163.  
  164.     register unsigned int const len = length() + x.length();
  165.     if (p->n || p->e < x.length()) {
  166.         srep *np = (srep *) new char[sizeof(srep) + len + xtra];
  167.         np->l = len;
  168.         np->n = 0;
  169.         np->e = xtra;
  170.         memcpy(np->s, p->s, length());
  171.         memcpy(np->s + length(), x.p->s, x.length() + 1);
  172.         lose(); // disconnect self
  173.         p = np;
  174.     } else {
  175.         // in cases where x += x and x is short the
  176.         // explicit setting of the '\0' stops any problems
  177.         memcpy(p->s + length(), x.p->s, x.length());
  178.         p->s[len] = '\0';
  179.         p->l += x.length();
  180.         p->e -= x.length();
  181.     }
  182.  
  183.     return *this;
  184. }
  185.  
  186.  
  187. LString &LString::operator+=(char const *x)
  188. {
  189.     if (!x || *x==0) return *this;
  190.  
  191.     register unsigned int const xlen = strlen(x);
  192.     register unsigned int const len = length() + xlen;
  193.     if (p->n || p->e < xlen) {
  194.         srep *np = (srep *) new char[sizeof(srep) + len + xtra];
  195.         np->l = len;
  196.         np->n = 0;
  197.         np->e = xtra;
  198.         memcpy(np->s, p->s, length());
  199.         memcpy(np->s + length(), x, xlen + 1);
  200.         lose(); // disconnect self
  201.         p = np;
  202.     } else {
  203.         // Explicitly setting the '\0' stops any
  204.         // problems caused by x += x.c_str()
  205.         memcpy(p->s + length(), x, xlen);
  206.         p->s[len] = '\0';
  207.         p->l += xlen;
  208.         p->e -= xlen;
  209.     }
  210.  
  211.     return *this;
  212. }
  213.  
  214.  
  215. LString &LString::operator+=(char c)
  216. {
  217.     register unsigned int const len = length() + 1;
  218.     if (!p->n && p->e) {
  219.         // 80% (from profiling)
  220.         // This is where all the speed gains are made.
  221.         p->s[length()] = c;
  222.         p->s[len] = '\0';
  223.         p->l = len;
  224.         p->e -= 1;
  225.     } else {
  226.         // 20%
  227.         srep *np = (srep *) new char[sizeof(srep) + len + xtra];
  228.         np->l = len;
  229.         np->n = 0;
  230.         np->e = xtra;
  231.         memcpy(np->s, p->s, length());
  232.         np->s[length()] = c;
  233.         np->s[len] = '\0';
  234.         lose(); // disconnect self
  235.         p = np;
  236.     }
  237.  
  238.     return *this;
  239. }
  240.  
  241.  
  242. //LString &LString::operator+=(int i)
  243. //{
  244. //    return this->operator+=((long)i);
  245. //}
  246.  
  247.  
  248. LString &LString::operator+=(long i)
  249. {
  250.     unsigned int tmplen = 0;
  251.     long a = i;
  252.     // calculate the length of i
  253.     if (!i) {
  254.         tmplen = 1;
  255.     } else {
  256.         if (a < 0) {
  257.             tmplen++; // minus sign
  258.             a = -a; // switch sign
  259.         }
  260.         while(a >= 1) { a = a/10; tmplen++;}
  261.     }
  262.     char *str = new char[tmplen + 1];
  263.     sprintf(str, "%ld", i);
  264.     this->operator+=(str);
  265.     delete[] str;
  266.  
  267.     return *this;
  268. }
  269.  
  270.  
  271. //bool LString::contains(char const *a) const
  272. //{
  273. //    return strstr(p->s, a) != NULL;
  274. //}
  275.  
  276.  
  277. LString& LString::substring(int i1, int i2)
  278. {
  279. //#ifdef DEVEL_VERSION
  280. //    if (i1 > i2 || i1 >= length() || i2 >= length()) {
  281. //        fprintf(stderr,
  282. //            "LString::substring: Wrong indexing in substring:"
  283. //            " '%s' i1=%d i2=%d\n", p->s, i1, i2);
  284. //        abort();
  285. //    }
  286. //#endif
  287.     Assert(i1 <= i2 && i1 < length() && i2 < length());
  288.     
  289.     if (i1==i2)
  290.         this->operator=(p->s[i1]);
  291.     else {
  292.         char *str = new char[i2 - i1 +2];
  293.         int i;
  294.         for (i=0; i1<=i2; str[i++] = p->s[i1++]);
  295.         str[i] = 0;
  296.         this->operator=(str);
  297.         delete[] str;
  298.     }
  299.     return *this;
  300. }
  301.  
  302.  
  303. // ale970405+lasgoutt-970425
  304. LString LString::token(char delim, int n) const
  305. {
  306.     int k=0, i;
  307.         LString tokbuf;
  308.  
  309.         tokbuf = *this;   
  310.     // Find delimiter or end of string
  311.     for (i = 0; i < tokbuf.length(); i++) {
  312.         if (tokbuf[i] == delim) {
  313.             if (n > 0) {
  314.                 k = i+1;
  315.                 n--;
  316.             } else break;
  317.         }
  318.     }
  319.  
  320.     // Return the token if not empty
  321.     if (n == 0 && k<i){
  322.         return tokbuf.substring(k, i-1);
  323.     } else {
  324.         return LString();
  325.     }
  326. }
  327.  
  328.  
  329. // this could probably be faster and/or cleaner, but it seems to work (JMarc)
  330. int LString::tokenPos(char delim, LString const &tok)
  331. {
  332.     int i=0;
  333.     LString str = *this;
  334.     LString tmptok;
  335.  
  336.     while (!str.empty()) {
  337.         str.split(tmptok, delim);
  338.         if (tok==tmptok)
  339.             return i;
  340.         i++;
  341.     }
  342.     return -1;
  343. }
  344.  
  345.  
  346. LString& LString::split(LString & piece, char delim)
  347. {
  348.     int i=0;
  349.     // Find delimiter or end of string
  350.     while (i<length() && p->s[i] != delim)
  351.         i++;
  352.     // If not the first, we go for a substring
  353.     if (i>0) {
  354.         piece = *this;
  355.         piece.substring(0, i-1);
  356.     } else
  357.         piece.erase();
  358.  
  359.     if (i < length()-1)
  360.         this->substring(i+1, length()-1);
  361.     else
  362.         erase();
  363.     return *this;
  364. }
  365.  
  366.  
  367. LString& LString::split(char delim)
  368. {
  369.     int i=0;
  370.     // Find delimiter or end of string
  371.     while (i<length() && p->s[i] != delim)
  372.         i++;
  373.  
  374.     if (i < length()-1)
  375.         this->substring(i+1, length()-1);
  376.     else
  377.         erase();
  378.     return *this;
  379. }
  380.  
  381.  
  382. // ale970521
  383. LString& LString::rsplit(LString & piece, char delim)
  384. {
  385.     int i=length()-1;
  386.     // Find delimiter or begin of string
  387.     while (i>=0 && p->s[i] != delim)
  388.         i--;
  389.     // If not the last, we go for a substring
  390.     if (i < length()-1) {
  391.         piece = *this;
  392.         piece.substring(0, i-1);
  393.         this->substring(i+1, length()-1);
  394.     } else {
  395.         piece.erase();
  396.         erase();
  397.     }
  398.     return *this;
  399. }
  400.  
  401.  
  402. LString& LString::strip(char const c)
  403. {
  404.     int i=length()-1;
  405.     for (; i>=0 && p->s[i] == c; i--);
  406.     if (i<0) 
  407.         erase();
  408.     else
  409.         this->substring(0, i);
  410.     return *this;
  411. }
  412.  
  413.  
  414. LString& LString::frontStrip(char const c)
  415. {
  416.     int i=0;
  417.     while (i < length() && p->s[i] == c) i++;
  418.     if (i > 0)
  419.         if (i == length())
  420.             erase();
  421.         else
  422.             this->substring (i, length()-1);
  423.     return *this;
  424. }
  425.  
  426.  
  427. bool LString::prefixIs(char const * pre) const
  428. {
  429.     if ((int) strlen(pre) > length())
  430.         return false;
  431.     else
  432.         return strncmp(p->s, pre, strlen(pre))==0;
  433. }
  434.  
  435.  
  436. bool LString::suffixIs(char c) const
  437. {
  438.     if (empty()) return false;
  439.     return p->s[length()-1] == c;
  440. }
  441.  
  442.  
  443. bool LString::suffixIs(char const * suf) const
  444. {
  445.     int suflen = (int) strlen(suf);
  446.     if (suflen > length())
  447.         return false;
  448.     else
  449.         return strncmp(p->s + (length()-suflen), suf, suflen)==0;
  450. }
  451.  
  452.  
  453. LString& LString::subst(char oldchar, char newchar)
  454. {
  455.     for (int i=0; i<length() ; i++)
  456.         if (p->s[i]==oldchar)
  457.             p->s[i]=newchar;
  458.     return *this;
  459. }
  460.  
  461.  
  462. LString& LString::subst(char const * oldstr, LString const & newstr)
  463. {
  464.     LString lstr = *this;
  465.     char * str = new char[lstr.length()+1]; // note +1
  466.     lstr.copy(str, LString::npos);
  467.     str[lstr.length()]=0; // adding terminator
  468.     char * first;
  469.       
  470.     while((first=strstr(str,oldstr))){
  471.             if (first==str) lstr.erase();
  472.         else lstr.substring(0,first-str-1);
  473.         lstr+=newstr;
  474.         lstr+=first+strlen(oldstr);
  475.         delete[] str;        
  476.         str = new char[lstr.length()+1]; // note +1
  477.         lstr.copy(str, LString::npos);
  478.         str[lstr.length()]=0; // adding terminator
  479.     }
  480.     delete[] str;
  481.     return *this=lstr;
  482. }
  483.  
  484.  
  485. LString& LString::lowercase()
  486. {
  487.     for (int i=0; i<length() ; i++)
  488.         p->s[i] = tolower((unsigned char) p->s[i]);
  489.     return *this;
  490. }
  491.  
  492.  
  493. bool LString::regexMatch(LString const & pattern) const
  494. {
  495.     if (pattern.empty())
  496.         return true;
  497.     if (empty())
  498.         return false;
  499.     
  500.     int si=0, pi=0;
  501.     int const sl = length();
  502.     int const pl = pattern.length();    
  503.  
  504.     while (si < sl && pi < pl) {
  505.         if (pattern[pi]=='*') {
  506.             // Skip all consequtive *s
  507.             while (pattern[pi] == '*') {
  508.                 pi++;
  509.                 if (pi == pl)
  510.                     return true;
  511.             }
  512.  
  513.             // Get next chunk of pattern to match
  514.             LString temp= pattern;
  515.             temp.substring(pi, pl-1);
  516.             LString chunk;
  517.             temp.split(chunk, '*');
  518.  
  519.             if (!chunk.empty() && pattern[pl-1] == '*' && 
  520.                 temp.empty())
  521.                 temp = '*';
  522.  
  523.             if (temp.empty()) {
  524.                 // Last chunk, see if tail matches
  525.                 temp = *this;
  526.                 temp.substring(sl - chunk.length(), sl - 1);
  527.                 return temp == chunk;
  528.             } else {
  529.                 // Middle chunk, see if we can find a match
  530.                 bool match = false;
  531.                 while (!match && si<sl) {
  532.                     temp = *this;
  533.                     temp.substring(si, sl - 1);
  534.                     match = temp.prefixIs(chunk.c_str());
  535.                     si++;
  536.                 };
  537.                 if (!match)
  538.                     return false;
  539.                 si += chunk.length()-1;
  540.                 pi += chunk.length();
  541.                 if (si==sl && pi==pl-1)
  542.                     return true;
  543.             }
  544.         } else if (operator[](si++) != pattern[pi++]) {
  545.                 return false;
  546.         }
  547.     }
  548.     if (pi < pl || si < sl)
  549.         return false;    
  550.     return true;
  551. }
  552.