]> git.lyx.org Git - features.git/blob - src/LString.h
last updates from 1.0.4, no more updates expected from that branch now
[features.git] / src / LString.h
1 // -*- C++ -*-
2 /* This file is part of
3  * ======================================================
4  * 
5  *           LyX, The Document Processor
6  *       
7  *          Copyright (C) 1995 1996 Matthias Ettrich
8  *           and the LyX Team.
9  *
10  *======================================================*/
11
12 // This one is heavily based on the string class in The C++
13 // Programming Language by Bjarne Stroustrup
14
15 #ifndef _LSTRING_H_
16 #define _LSTRING_H_ 
17
18 #ifdef __GNUG__
19 #pragma interface
20 #endif
21
22 #include <config.h> // needed at least for compiler that do not
23                     // understand 'explicit' (JMarc)
24 #ifdef _AIX
25 // AIX has strange ideas about where definitions like strcasecmp
26 // should go (JMarc)
27 #include <strings.h>
28 #else
29 #include <string.h>
30 #endif
31
32 /** A string class for LyX
33   
34   This is a permanent String class. It was supposed to be superseeded
35   with QString when we switch to the Qt library, but now it's so developed
36   that it is as good as theirs (or maybe even better :-)
37
38   Notes for usage:
39
40   When you declare an LString, it is initially empty. There is no need to
41   do things like #LString a= "";#, especially not in constructors.
42
43   If you want to use a default empty LString as a parameter, use
44   
45         #void foo(LString par = LString());     // Correct#
46   
47   rather than
48
49         #void foo(LString par = "");    // WRONG!#
50         #void foo(LString par = 0);     // WRONG!#
51
52   (The last one is only wrong because some compilers can't handle it.)
53
54   Methods that take an index as parameter all follow this rule: Valid indexes
55   go from 0 to length()-1.
56   \begin{tabular}{rl}
57   Correct: & #foo.substring(0, length()-1);# \\
58   Wrong:   & #bar.substring(0, length());#
59   \end{tabular}
60   
61   It is important that you declare LStrings as const if possible, because
62   some methods are much more efficient in const versions.
63   
64   If you want to check whether a string is empty, do
65
66         #if (foo.empty()) something right#
67
68   rather than something along the lines of
69
70         #if (!foo) completely wrong#
71
72   When you use the #.copy()# method, LString calls "#new []#", so you have to
73   release the memory with #delete[]#. Don't preallocate memory.
74
75   When you want to copy an LString, just do
76   
77         #LString a, b = "String";#
78         #a = b; // That's it!#
79
80   not something like
81   
82         #LString a, b = "String";#
83         #a = b.copy(); // This leaks.#
84   
85   The class automatically handles deep copying when required.
86 */
87 class LString {
88 public:
89         /**@name Constructors and Deconstructors */
90         //@{
91         /// #LString x;#
92         LString();
93         /// #LString x(LString ...)#
94         LString(LString const &);
95         /// #LString x("abc")#
96         LString(char const*);
97         /// #LString x('a')# 
98         explicit LString(char const);
99         // not all C++ compilers understands explicit as of now
100
101         ///
102         ~LString();
103         //@}
104
105         /**@name Operators */
106         //@{
107         ///
108         LString& operator=(LString const &);
109         ///
110         LString& operator=(char const *);
111         ///
112         LString& operator=(char);
113
114         ///
115         char& operator[](int);
116 #ifndef const
117         ///
118         char const& operator[](int) const;
119 #endif
120         ///
121         LString& operator+=(LString const &);
122         ///
123         LString& operator+=(char const*);
124         ///
125         LString& operator+=(char);
126         ///
127         LString& operator+=(int);
128         ///
129         LString& operator+=(long);
130         //@}
131
132         /**@name Methods */
133         //@{
134         ///  to comply with the STL strings
135         bool empty() const;
136         ///
137         //bool isEmpty() const;
138         ///
139         //bool notEmpty() const;
140         ///
141         int length() const;
142
143         // should be renamed to erase() (STL)
144         /** equivalent to  *this = empty. But usable outside LString
145             implementation */
146         LString &clean();
147
148         /// This should be renamed to c_str()
149         char const* c_str() const;
150
151         // we should make the caller supply the storage to copy into. (STL)
152         /** This one returns a verbatim copy. Only temporary.
153           The caller should call delete [] when done with the string
154           */
155         char * copy() const;
156
157         ///
158         bool contains(char const *) const;
159
160         // Remove and replace (STL)
161         /// Truncate to substring. I.e. #"abcdef".substring(2,4)="cde"#
162         LString& substring(int i1, int i2);
163             
164         /** Splits the string by the first delim.
165           Splits the string by the first appearance of delim.
166             The leading string up to delim is returned in piece (not including
167             delim), while the original string is cut from after the delimiter.
168             Example:
169             #s1=""; s2="a;bc".split(s1, ';') -> s1=="a"; s2 == "bc";#
170         */
171         LString& split(LString& piece, char delim);
172         /// Same as split but does not return a piece
173         LString& split(char delim);
174         /// Same as split but uses the last delim.
175         LString& rsplit(LString& piece, char delim);
176         
177         /** Extracts a token from this string at the nth delim.
178             Doesn't modify the original string. Similar to strtok.
179             Example:
180             #"a;bc;d".token(';', 1) == "bc";#
181             #"a;bc;d".token(';', 2) == "d";#
182         */
183         LString token(char delim, int n=0) const;
184
185         /** Search a token in this string using the delim.
186             Doesn't modify the original string. Returns -1 in case of
187             failure. 
188             Example:
189             #"a;bc;d".tokenPos(';', "bc") == 1;#
190             #"a;bc;d".token(';', "d") == 2;#
191         */
192         int tokenPos(char delim, LString const &tok);
193
194         /** Strips characters off the end of a string.
195             #"abccc".strip('c') = "ab".#
196         */
197         LString& strip(char const c = ' ');
198
199         /** Strips characters of the beginning of a string.
200           #"cccba".frontstrip('c') = "ba"#. */
201         LString& frontStrip(char const c = ' ');
202         
203         /// Does the string start with this prefix?
204         bool prefixIs(char const *) const;
205
206         /// Does the string end with this char?
207         bool suffixIs(char) const;
208
209         /// Does the string end with this suffix?
210         bool suffixIs(char const *) const;
211         
212         /// Substitute all "oldchar"s with "newchar"
213         LString& subst(char oldchar, char newchar);
214
215         /// Substitutes all instances of oldstr with newstr
216         LString& subst(char const * oldstr, LString const & newstr);
217  
218         /** Compares a string and a (simple) regular expression
219           The only element allowed is "*" for any string of characters
220           */
221         bool regexMatch(LString const & pattern) const;
222
223         /// Lowercases a string
224         LString& lowercase();
225
226         /// Counts how many of character c there is in string
227         int countChar(const char c) const;
228
229         /// Position of the character c from the beggining
230         int charPos(const char c) const;
231             
232         //@}
233
234         /**@name Friends */
235         //@{
236         
237         ///
238         friend bool operator==(LString const &x, char const *s)
239         {
240                 if (s == 0 || !(*s)) 
241                         return x.p->s[0] == '\0';
242                 else
243                         return strcmp(x.p->s, s) == 0;
244         }
245         
246         ///
247         friend bool operator==(LString const &x, LString const &y)
248         {
249                 return strcmp(x.p->s, y.p->s) == 0;
250         }
251         
252         ///
253         friend bool operator!=(LString const &x, char const *s)
254         {
255                 if (s == 0 || !(*s)) 
256                         return x.p->s[0] != '\0';
257                 else
258                         return strcmp(x.p->s, s) != 0;
259         }
260         
261         ///
262         friend bool operator!=(LString const &x, LString const &y)
263         {
264                 return strcmp(x.p->s, y.p->s) != 0;
265         }
266         //@}
267
268 protected:
269 private:
270         /// A string representation
271         struct srep {
272                 /// Length
273                 unsigned int l;
274                 /// Reference count (number of references - 1)
275                 unsigned short n;
276                 /// Extra space at end of allocated string
277                 unsigned short e;
278                 /// Data. At least 1 char for trailing null.
279                 char s[1];
280                 ///
281                 srep() { n = 0; l = 0; e = 0; s[0] = '\0'; }
282         };
283
284         /** The empty srep is a local static in each function that
285             needs one. There is no "global" empty srep but LString
286             doesn't need one (no code actually relies upon a single
287             empty srep).
288             This overcomes *all* "static initialization" problems,
289             at maximum speed, with a small overhead of 6 local static
290             empty_reps.
291          */
292 // This is the only other option (or a variant of this anyway)
293 // I originally offered this style of empty_rep in 9709 but
294 // it was rejected for requiring too many function calls and pointer operations(!)
295 // and because another implementation was to be trialed (which has since
296 // apparently failed for some compilers). ARRae
297 //      static srep& empty_rep()
298 //              {
299 //                      static srep mt;
300 //                      return mt;
301 //              }
302
303         /// A string is a pointer to it's representation
304         srep *p;
305         ///
306         void lose();
307 };
308
309
310 inline LString::LString(LString const &x)
311 {
312         x.p->n++;
313         p = x.p;
314 }
315
316
317 inline void LString::lose()
318 {
319         if (p->n-- == 0) {
320                 delete[] (char*)p;
321         }
322 }
323
324 inline LString::~LString()
325 {
326    lose();
327 }
328
329
330 inline int LString::length() const
331 {
332         return p->l;
333 }
334
335
336 inline bool LString::empty() const
337 {
338         return p->l == 0;
339 }
340
341
342 inline int LString::countChar(const char c) const
343 {
344         int n = 0;
345         for (int i=0; i < length(); i++)
346                 if (operator[](i) == c) n++;
347         return n;
348 }
349
350
351 inline LString operator+(LString const &x, LString const &y)
352 {
353         LString str(x);
354         str += y;
355         return str;
356 }
357
358
359 inline LString operator+(LString const &x, char const &y)
360 {
361         LString str(x);
362         str += y;
363         return str;
364 }
365
366
367 inline LString operator+(LString const &x, int const &y)
368 {
369         LString str(x);
370         str += y;
371         return str;
372 }
373
374
375 inline LString operator+(LString const &x, long const &y)
376 {
377         LString str(x);
378         str += y;
379         return str;
380 }
381
382 inline char const* LString::c_str() const
383 {
384         return (char const*)p->s;
385 }
386
387
388 inline int LString::charPos(const char c) const
389 {
390         for (int i=0; i < length(); i++) {
391                 if (operator[](i) == c) return i;
392         }
393         return -1;
394 }
395          
396 #endif