]> git.lyx.org Git - lyx.git/blob - src/support/lyxstring.C
1d12bd51d24507c62975e7b640b24c347fd983ef
[lyx.git] / src / support / lyxstring.C
1 /* This file is part of
2  * ======================================================
3  * 
4  *           LyX, The Document Processor
5  *       
6  *          Copyright (C) 1995 Matthias Ettrich
7  *          Copyright (C) 1995-1999 The LyX Team.
8  *
9  * ======================================================*/
10
11 #ifdef HAVE_CONFIG_H
12 #include <config.h>
13 #endif
14
15 #ifdef __GNUG__
16 #pragma implementation "lyxstring.h"
17 #endif
18
19 #include "lyxstring.h"
20 #include <cstdlib>
21 #include <cctype>
22 #include <algorithm>
23
24 #include "LAssert.h"
25
26 using std::min;
27
28 // This class is supposed to be functionaly equivalent to a
29 // standard conformant string. This mean among others that we
30 // are useing the same requirements. Before you change anything
31 // in this file consult me and/or the standard to discover the
32 // right behavior.
33
34 // Reference count has been checked, empty_rep removed and
35 // introduced again in a similar guise. Where is empty_rep _really_
36 // needed?
37
38 // Insertion and replace is implemented, as far as I can see everything
39 // works, but could perhaps be done smarter.
40
41 // All the different find functions need a good look over.
42 // I have so far not tested them extensively and would be
43 // happy if others took the time to have a peek.
44
45
46 ///////////////////////////////////////
47 // The internal string representation
48 ///////////////////////////////////////
49
50 struct lyxstring::Srep {
51         ///
52         static lyxstring::size_type const xtra = 
53         static_cast<lyxstring::size_type>(8);
54         /// size
55         lyxstring::size_type sz;
56         /// Reference count
57         unsigned short ref;
58         /// The total amount of data reserved for this representaion
59         lyxstring::size_type res;
60         /// Data. At least 1 char for trailing null.
61         lyxstring::value_type * s;
62         
63         ///
64         Srep(lyxstring::size_type nsz, const lyxstring::value_type * p);
65         ///
66         Srep(lyxstring::size_type nsz, lyxstring::value_type ch);
67         ///
68         ~Srep() { delete[] s; }
69         ///
70         Srep * get_own_copy()
71                 {
72                         if (ref == 1) return this;
73                         --ref;
74                         return new Srep(sz, s);
75                 }
76         
77         ///
78         void assign(lyxstring::size_type nsz, const lyxstring::value_type * p);
79         ///
80         void assign(lyxstring::size_type nsz, lyxstring::value_type ch);
81         ///
82         void append(lyxstring::size_type asz, const lyxstring::value_type * p);
83         ///
84         void push_back(lyxstring::value_type c);
85         ///
86         void insert(lyxstring::size_type pos,
87                     const lyxstring::value_type * p,
88                     lyxstring::size_type n);
89         ///
90         void resize(lyxstring::size_type n, lyxstring::value_type c);
91         ///
92         void reserve(lyxstring::size_type res_arg);
93         ///
94         void replace(lyxstring::size_type i, lyxstring::size_type n,
95                      lyxstring::value_type const * p, lyxstring::size_type n2);
96 private:
97         Srep(const Srep &);
98         Srep & operator=(const Srep &);
99 };
100
101
102 lyxstring::Srep::Srep(lyxstring::size_type nsz, const value_type * p)
103 {
104 // can be called with p==0 by lyxstring::assign(const value_type *, size_type)
105
106         sz = nsz;
107         ref = 1;
108         res = sz + xtra;
109         s = new value_type[res + 1]; // add space for terminator
110         if (p && sz) {
111                 // if sz = 0 nothing gets copied and we have an error
112                 memcpy(s, p, sz);
113         } else {
114                 // possibly allows for large but empty string
115                 sz = 0;  // this line should be redundant
116                 s[0] = '\0';
117         }
118 }
119
120
121 lyxstring::Srep::Srep(lyxstring::size_type nsz, value_type ch)
122 {
123         sz = nsz;
124         ref = 1;
125         res = sz + xtra;
126         s = new value_type[res + 1]; // add space for terminator
127         memset(s, ch, sz);
128         if (!ch) {
129                 // if ch == '\0' strlen(lyxstring.c_str()) == 0 so sz = 0
130                 // allows for large but empty string
131                 sz = 0;
132         }
133 }
134         
135
136 void lyxstring::Srep::assign(lyxstring::size_type nsz, const value_type * p)
137 {
138 // can be called with p==0 by lyxstring::assign(const value_type *, size_type)
139
140         if (res < nsz) {
141                 delete[] s;
142                 sz = nsz;
143                 res = sz + xtra;
144                 s = new value_type[res + 1]; // add space for terminator
145         } else {
146                 sz = nsz;
147         }
148         if (p && sz) {
149                 // if sz = 0 nothing gets copied and we have an error
150                 memcpy(s, p, sz);
151         } else {
152                 // stops segfaults
153                 sz = 0;  // this line should be redundant
154                 s[0] = '\0';
155         }
156 }
157
158
159 void lyxstring::Srep::assign(lyxstring::size_type nsz, value_type ch)
160 {
161         sz = nsz;
162         if (res < nsz) {
163                 delete[] s;
164                 res = sz + xtra;
165                 s = new value_type[res + 1]; // add space for terminator
166         }
167         memset(s, ch, sz);
168         if (!ch) {
169                 // if ch == '\0' strlen(lyxstring.c_str()) == 0 so sz = 0
170                 // allows for a large empty string
171                 sz = 0;
172         }
173 }
174
175
176 void lyxstring::Srep::append(lyxstring::size_type asz, const value_type * p)
177 {
178         register unsigned int const len = sz + asz;
179         if (res < len) {
180                 res = len + xtra;
181                 value_type * tmp = new value_type[res + 1];
182                 memcpy(tmp, s, sz);
183                 memcpy(tmp + sz, p, asz);
184                 sz += asz;
185                 delete[] s;
186                 s = tmp;
187         } else {
188                 memcpy(s + sz, p, asz);
189                 sz += asz;
190         }
191 }
192
193
194 void lyxstring::Srep::push_back(value_type c)
195 {
196         s[sz] = c; // it is always room to put a value_type at the end
197         ++sz;
198         if (res < sz) {
199                 res = sz + xtra;
200                 value_type * tmp = new value_type[res + 1];
201                 memcpy(tmp, s, sz);
202                 delete[] s;
203                 s = tmp;
204         }
205 }
206
207
208 void lyxstring::Srep::insert(lyxstring::size_type pos, const value_type * p,
209                            lyxstring::size_type n)
210 {
211         Assert(pos <= sz);
212         if (res < n + sz) {
213                 res = sz + n + xtra;
214                 value_type * tmp = new value_type[res + 1];
215                 memcpy(tmp, s, pos);
216                 memcpy(tmp + pos, p, n);
217                 memcpy(tmp + pos + n, & s[pos], sz - pos);
218                 sz += n;
219                 delete[] s;
220                 s = tmp;
221         } else {
222                 memmove(s + pos + n, & s[pos], sz - pos);
223                 memcpy(s + pos, p, n);
224                 sz += n;
225         }
226 }
227
228
229 void lyxstring::Srep::resize(size_type n, value_type c)
230 {
231         Assert(n < npos);
232         // This resets sz to res_arg
233         res = min(n, npos - 2); // We keep no xtra when we resize
234         value_type * tmp = new value_type[res + 1];
235         memcpy(tmp, s, min(sz, res));
236         if (res > sz)
237                 memset(tmp + sz, c, res - sz);
238         delete[] s;
239         sz = res;
240         s = tmp;
241 }
242
243
244 void lyxstring::Srep::reserve(lyxstring::size_type res_arg)
245 {
246         // This keeps the old sz, but
247         // increases res with res_arg
248         res += res_arg;
249         value_type * tmp = new value_type[res + 1];
250         memcpy(tmp, s, sz);
251         delete[] s;
252         s = tmp;
253 }
254
255
256 void lyxstring::Srep::replace(lyxstring::size_type i, lyxstring::size_type n,
257                             value_type const * p, size_type n2)
258 {
259 // can be called with p=0 and n2=0
260         Assert(i < sz && ((!p && !n2) || p));
261         n = min(sz - i, n);
262         sz -= n;
263         if (res >= n2 + sz) {
264                 memmove(s + i + n2, &s[i + n], sz - i);
265                 memcpy(s + i, p, n2);
266                 sz += n2;
267         } else {
268                 res = sz + n2 + xtra;
269                 value_type * tmp = new value_type[res + 1];
270                 memcpy(tmp, s, i);
271                 memcpy(tmp + i, p, n2);
272                 memcpy(tmp + i + n2, &s[i + n], sz - i);
273                 delete[] s;
274                 s = tmp;
275                 sz += n2; 
276         }
277 }
278
279
280 ///////////////////////////////////////
281 // The lyxstring Invariant tester
282 ///////////////////////////////////////
283 #ifdef DEVEL_VERSION
284
285 /** Testing of the lyxstring invariant
286  * By creating an object that tests the lyxstring invariant during its
287  * construction *and* its deconstruction we greatly simplify our code.
288  * Calling TestlyxstringInvariant() upon entry to an lyxstring method 
289  * will test the invariant upon entry to the code.  If the Asserts fail
290  * then we know from the stack trace that the corruption occurred *before*
291  * entry to this method.  We can also be sure it didn't happen in any of
292  * the tested lyxstring methods.  It is therefore likely to be due to some
293  * other external force.
294  * Several lyxstring methods have multiple exit points which would otherwise
295  * require us to insert a separate test before each return.  But since we
296  * created an object its destructor will be called upon exit (any exit!).
297  * We thus get testing at both start and end of a method with one line of
298  * code at the head of a method.  More importantly,  we get good testing
299  * everytime we run the code.
300  * NOTE:  just because we test the invariant doesn't mean we can forget
301  * about testing pre and post conditions specific to any given method.
302  * This test simply proves that the lyxstring/Srep is in a valid state it
303  * does *not* prove that the method did what it was supposed to.
304  */
305 class lyxstringInvariant {
306 public:
307         lyxstringInvariant(lyxstring const *);
308         ~lyxstringInvariant();
309 private:
310         void helper() const;
311         lyxstring const * object;
312 };
313
314
315 // To test if this scheme works "as advertised" uncomment the printf's in
316 // the constructor and destructor below and then uncomment the printf and the
317 // call to TestlyxstringInvariant() in lyxstring::operator=(char const *).
318 // The correct output when LyX has been recompiled and run is:
319 //     lyxstringInvariant constructor
320 //     lyxstring::operator=(char const *)
321 //     lyxstringInvariant constructor
322 //     lyxstringInvariant destructor completed
323 //     lyxstringInvariant destructor completed
324 // NOTE: The easiest way to catch this snippet of the output is to wait for
325 //       the splash screen to disappear and then open and close Help->Credits
326 //
327 lyxstringInvariant::lyxstringInvariant(lyxstring const * ls) : object(ls)
328 {
329         // printf("lyxstringInvariant constructor\n");
330         helper();
331 }
332
333 lyxstringInvariant::~lyxstringInvariant()
334 {
335         helper();
336         // printf("lyxstringInvariant destructor completed\n");
337 }
338
339 void lyxstringInvariant::helper() const
340 {
341         // Some of these tests might look pointless but they are
342         // all part of the invariant and if we want to make sure
343         // we have a bullet proof implementation then we need to
344         // test every last little thing we *know* should be true.
345         // I may have missed a test or two, so feel free to fill
346         // in the gaps.  ARRae.
347         // NOTE:  Don't put TestlyxstringInvariant() in any of the
348         // lyxstring methods used below otherwise you'll get an
349         // infinite recursion and a crash.
350         Assert(object);
351         Assert(object->rep);
352         Assert(object->rep->s);    // s is never 0
353         Assert(object->rep->res);  // always some space allocated
354         Assert(object->size() <= object->rep->res);
355         Assert(object->rep->ref >= 1);  // its in use so it must be referenced
356         Assert(object->rep->ref < (1 << 8*sizeof(object->rep->ref)) - 1);
357         // if it does ever == then we should be generating a new copy
358         // and starting again.  (Is char always 8-bits?)
359 }
360 #define TestlyxstringInvariant(s) lyxstringInvariant lyxstring_invariant(s);
361 #else
362 #define TestlyxstringInvariant(s)
363 #endif //DEVEL_VERSION
364
365
366 ///////////////////////////////////////
367 // Constructors and Deconstructors.
368 ///////////////////////////////////////
369
370 lyxstring::size_type const lyxstring::npos = static_cast<lyxstring::size_type>(-1);
371
372 lyxstring::lyxstring()
373 {
374         static Srep empty_rep(0, "");
375         ++empty_rep.ref;
376         rep = &empty_rep;
377 }
378
379
380 lyxstring::lyxstring(lyxstring const & x, size_type pos, size_type n)
381 {
382         Assert(pos < x.rep->sz || pos == 0);
383         if (pos == 0 && n >= x.length()) { // this is the default
384                 x.rep->ref++;
385                 rep = x.rep;
386         } else {
387                 rep = new Srep(min(n, x.rep->sz - pos), &(x.rep->s[pos]));
388         }
389 }
390
391
392 lyxstring::lyxstring(value_type const * s, size_type n)
393 {
394         Assert(s); // we don't allow null pointers
395         static Srep empty_rep(0, "");
396         if (*s && n) { // s is not empty string and n > 0
397                 rep = new Srep(min(strlen(s), n), s);
398         } else {
399                 ++empty_rep.ref;
400                 rep = &empty_rep;
401         }
402 }
403
404
405 lyxstring::lyxstring(value_type const * s)
406 {
407         Assert(s); // we don't allow null pointers
408         static Srep empty_rep(0, "");
409         if (*s) { // s is not empty string
410                 rep = new Srep(strlen(s), s);
411         } else {
412                 ++empty_rep.ref;
413                 rep = &empty_rep;
414         }
415 }
416
417
418 lyxstring::lyxstring(size_type n, value_type c)
419 {
420         rep = new Srep(n, c);
421 }
422
423
424 lyxstring::lyxstring(iterator first, iterator last)
425 {
426         rep = new Srep(last - first, first);
427 }
428
429
430 lyxstring::~lyxstring()
431 {
432         if (--rep->ref == 0) delete rep;
433 }
434
435 ///////////////////////
436 // Iterators
437 ///////////////////////
438
439 lyxstring::iterator lyxstring::begin()
440 {
441         return rep->s;
442 }
443
444
445 lyxstring::const_iterator lyxstring::begin() const
446 {
447         return rep->s;
448 }
449
450
451 lyxstring::iterator lyxstring::end()
452 {
453         return rep->s + rep->sz;
454 }
455
456
457 lyxstring::const_iterator lyxstring::end() const
458 {
459         return rep->s + rep->sz;
460 }
461
462 #if 0
463 reverse_iterator lyxstring::rbegin()
464 {
465         return reverse_iterator( end() );
466 }
467
468
469 const_reverse_iterator lyxstring::rbegin() const
470 {
471         return const_reverse_iterator( end() );
472 }
473
474
475 reverse_iterator lyxstring::rend()
476 {
477         return reverse_iterator( begin() );
478 }
479
480
481 const_reverse_iterator lyxstring::rend() const
482 {
483         return const_reverse_iterator( begin() );
484 }
485 #endif
486
487
488 ///////////////////////
489 // Size and Capacity
490 ///////////////////////
491
492 lyxstring::size_type lyxstring::size() const
493
494         return rep->sz;
495 }
496
497
498 void lyxstring::resize(size_type n, value_type c)
499 {
500         TestlyxstringInvariant(this);
501
502         // This resets sz to res_arg
503         rep = rep->get_own_copy();
504         rep->resize(n, c);
505 }
506
507
508 lyxstring::size_type lyxstring::capacity() const
509 {
510         return rep->res;
511 }
512
513
514 void lyxstring::reserve(size_type res_arg)
515 {
516         TestlyxstringInvariant(this);
517
518         rep = rep->get_own_copy();
519         rep->reserve(res_arg);
520 }
521
522
523 ////////////////
524 // Assignment
525 ////////////////
526
527 lyxstring & lyxstring::operator=(lyxstring const & x)
528 {
529         TestlyxstringInvariant(this);
530
531         return assign(x);
532 }
533
534
535 lyxstring & lyxstring::operator=(value_type const * s)
536 {
537         Assert(s);      
538         TestlyxstringInvariant(this);
539 //      printf("lyxstring::operator=(value_type const *)\n");
540
541         return assign(s);
542 }
543
544
545 lyxstring & lyxstring::operator=(value_type c)
546 {
547         TestlyxstringInvariant(this);
548
549         value_type s[1];
550         s[0] = c;
551         if (rep->ref == 1) // recycle rep
552                 rep->assign(1, s);
553         else {
554                 rep->ref--;
555                 rep = new Srep(1, s);
556         }
557         return *this;
558 }
559
560
561 lyxstring & lyxstring::assign(lyxstring const & x)
562 {
563         TestlyxstringInvariant(this);
564
565         x.rep->ref++; // protect against ``st = st''
566         if (--rep->ref == 0) delete rep;
567         rep = x.rep; // share representation
568         return *this;
569 }
570         
571
572 lyxstring & lyxstring::assign(lyxstring const & x, size_type pos, size_type n)
573 {
574         TestlyxstringInvariant(this);
575
576         return assign(x.substr(pos, n));
577 }
578         
579
580 lyxstring & lyxstring::assign(value_type const * s, size_type n)
581 {
582         Assert(s);
583         TestlyxstringInvariant(this);
584
585         n = min(strlen(s), n);
586         if (rep->ref == 1) // recycle rep
587                 rep->assign(n, s);
588         else {
589                 rep->ref--;
590                 rep = new Srep(n, s);
591         }
592         return *this;
593 }
594         
595
596 lyxstring & lyxstring::assign(value_type const * s)
597 {
598         Assert(s);
599         TestlyxstringInvariant(this);
600
601         return assign(s, strlen(s));
602 }
603
604
605 lyxstring & lyxstring::assign(size_type n, value_type ch)
606 {
607         TestlyxstringInvariant(this);
608
609         rep = rep->get_own_copy();
610         rep->assign(n, ch);
611         return *this;
612 }
613
614
615 lyxstring & lyxstring::assign(iterator first, iterator last)
616 {
617         TestlyxstringInvariant(this);
618
619         rep = rep->get_own_copy();
620         rep->assign(last - first, first);
621         return *this;
622 }
623
624
625 ////////////////////
626 // Element Access
627 ////////////////////
628
629 lyxstring::const_reference lyxstring::operator[](size_type pos) const
630 {
631         Assert(pos < rep->sz);
632         return rep->s[pos];
633 }
634
635
636 lyxstring::reference lyxstring::operator[](size_type pos)
637 {
638         Assert(pos < rep->sz);
639         TestlyxstringInvariant(this);
640
641         rep = rep->get_own_copy();
642         return rep->s[pos];
643 }
644
645
646 lyxstring::const_reference lyxstring::at(size_type n) const
647 {
648         Assert(n < rep->sz);
649         return rep->s[n];
650 }
651
652
653 lyxstring::reference lyxstring::at(size_type n)
654 {
655         Assert(n < rep->sz);
656         TestlyxstringInvariant(this);
657
658         rep = rep->get_own_copy();
659         return rep->s[n];
660 }
661
662
663 /////////////
664 // Insert
665 /////////////
666
667 lyxstring & lyxstring::operator+=(lyxstring const & x)
668 {
669         TestlyxstringInvariant(this);
670
671         return append(x);
672 }
673
674
675 lyxstring & lyxstring::operator+=(value_type const * x)
676 {
677         Assert(x);
678         TestlyxstringInvariant(this);
679
680         return append(x);
681 }
682
683
684 lyxstring & lyxstring::operator+=(value_type c)
685 {
686         TestlyxstringInvariant(this);
687
688         push_back(c);
689         return *this;
690 }
691
692
693 void lyxstring::push_back(value_type c)
694 {
695         TestlyxstringInvariant(this);
696
697         rep = rep->get_own_copy();
698         rep->push_back(c);
699 }
700
701
702 lyxstring & lyxstring::append(lyxstring const & x)
703 {
704         TestlyxstringInvariant(this);
705
706         if (x.empty()) return *this;
707         rep = rep->get_own_copy();
708         rep->append(x.length(), x.rep->s);
709         return *this;
710 }
711
712
713 lyxstring & lyxstring::append(lyxstring const & x, size_type pos, size_type n)
714 {
715         TestlyxstringInvariant(this);
716
717         return append(x.substr(pos, n));
718 }
719
720
721 lyxstring & lyxstring::append(value_type const * p, size_type n)
722 {
723         Assert(p);
724         TestlyxstringInvariant(this);
725
726         if (!*p || !n) return *this;
727         rep = rep->get_own_copy();
728         rep->append(min(n, strlen(p)), p);
729         return *this;
730 }
731
732
733 lyxstring & lyxstring::append(value_type const * p)
734 {
735         Assert(p);
736         TestlyxstringInvariant(this);
737
738         if (!*p) return *this;
739         rep = rep->get_own_copy();
740         rep->append(strlen(p), p);
741         return *this;
742 }
743
744
745 lyxstring & lyxstring::append(size_type n, value_type c)
746 {
747         TestlyxstringInvariant(this);
748
749         value_type * tmp = new value_type[n];
750         memset(tmp, c, n);
751         rep = rep->get_own_copy();
752         rep->append(n, tmp);
753         delete[] tmp;
754         return *this;
755 }
756
757
758 lyxstring & lyxstring::append(iterator first, iterator last)
759 {
760         TestlyxstringInvariant(this);
761
762         rep = rep->get_own_copy();
763         rep->append(last - first, first);
764         return *this;
765 }
766
767 // insert value_typeacters before (*this)[pos]
768
769 lyxstring & lyxstring::insert(size_type pos, lyxstring const & x)
770 {
771         TestlyxstringInvariant(this);
772
773         return insert(pos, x, 0, x.rep->sz);
774 }
775
776
777 lyxstring & lyxstring::insert(size_type pos, lyxstring const & x,
778                           size_type pos2, size_type n)
779 {
780         TestlyxstringInvariant(this);
781
782         rep = rep->get_own_copy();
783         rep->insert(pos, &(x.rep->s[pos2]), min(n, x.rep->sz));
784         return *this;
785 }
786
787
788 lyxstring & lyxstring::insert(size_type pos, value_type const * p, size_type n)
789 {
790         Assert(p);
791         TestlyxstringInvariant(this);
792
793         if (*p && n) {
794                 // insert nothing and you change nothing
795                 rep = rep->get_own_copy();
796                 rep->insert(pos, p, min(n, strlen(p)));
797         }
798         return *this;
799 }
800
801
802 lyxstring & lyxstring::insert(size_type pos, value_type const * p)
803 {
804         Assert(p);
805         TestlyxstringInvariant(this);
806
807         if (*p) {
808                 // insert nothing and you change nothing
809                 rep = rep->get_own_copy();
810                 rep->insert(pos, p, strlen(p));
811         }
812         return *this;
813 }
814
815
816 lyxstring & lyxstring::insert(size_type pos, size_type n, value_type c)
817 {
818         TestlyxstringInvariant(this);
819
820         rep = rep->get_own_copy();
821         value_type * tmp = new value_type[n];
822         memset(tmp, c, n);
823         rep->insert(pos, tmp, n);
824         delete[] tmp;
825         return *this;
826 }
827
828
829 lyxstring::iterator lyxstring::insert(iterator p, value_type c)
830 {
831         TestlyxstringInvariant(this);
832
833         // what iterator is this supposed to return??
834         size_type tmp = p - begin();
835         insert(p - begin(), 1, c);
836         return begin() + tmp + 1; // ??
837 }
838
839
840 void lyxstring::insert(iterator p, size_type n , value_type c)
841 {
842         TestlyxstringInvariant(this);
843
844         insert(p - begin(), n , c);
845 }
846
847
848 void lyxstring::insert(iterator p, iterator first, iterator last)
849 {
850         TestlyxstringInvariant(this);
851
852         insert(p - begin(), first, last - first);
853 }
854         
855
856 ////////////////
857 // Find
858 ////////////////
859  
860          // All the below find functions should be verified,
861          // it is very likely that I have mixed up or interpreted
862          // some of the parameters wrong, also some of the funcs can surely
863          // be written more effectively.
864
865 lyxstring::size_type lyxstring::find(lyxstring const & a, size_type i) const
866 {
867         if (!rep->sz || i >= rep->sz) return npos;
868         
869         TestlyxstringInvariant(this);
870
871         for (size_type t = i; rep->sz - t >= a.length(); ++t) {
872                 // search until (*this)[i] == a[0]
873                 if (rep->s[t] == a[0]) {
874                         // check if the rest of the value_types match
875                         bool equal = true;
876                         for (size_type j = 0; j < a.length(); ++j) {
877                                 if (rep->s[t + j] != a[j]) {
878                                         equal = false;
879                                         break;
880                                 }
881                         }
882                         if (equal) return t;
883                 }
884         }
885         return npos;
886 }
887
888
889 lyxstring::size_type lyxstring::find(value_type const * ptr, size_type i,
890                                  size_type n) const
891 {
892         Assert(ptr);
893         if (!rep->sz || !*ptr || i >= rep->sz) return npos;
894         
895         TestlyxstringInvariant(this);
896
897         // What is "n" here? is it the number of value_types to use in ptr
898         // or does "i" and "n" togeter form a substring to search
899         // for ptr in? For now I will assume that "n" tells the length
900         // of ptr. (Lgb)
901         n = min(n, strlen(ptr));
902         for (size_type t = i; rep->sz - t >= n; ++t) {
903                 // search until (*this)[i] == a[0]
904                 if (rep->s[t] == ptr[0]) {
905                         // check if the rest of the value_types match
906                         bool equal = true;
907                         for (size_type j = 0; j < n; ++j) {
908                                 if (rep->s[t + j] != ptr[j]) {
909                                         equal = false;
910                                         break;
911                                 }
912                         }
913                         if (equal) return t;
914                 }
915         }
916         return npos;
917 }
918
919
920 lyxstring::size_type lyxstring::find(value_type const * s, size_type i) const
921 {
922         Assert(s);
923         if (!rep->sz || i >= rep->sz) return npos;
924         
925         TestlyxstringInvariant(this);
926
927         if (!s || !*s) return npos;
928         return find(s, i, strlen(s));
929 }
930
931
932 lyxstring::size_type lyxstring::find(value_type c, size_type i) const
933 {
934         if (!rep->sz || i >= rep->sz) return npos;
935
936         TestlyxstringInvariant(this);
937
938         for (size_type t = 0; t + i < rep->sz; ++t) {
939                 if (rep->s[t + i] == c) return t + i;
940         }
941         return npos;
942 }
943
944
945 lyxstring::size_type lyxstring::rfind(lyxstring const & a, size_type i) const
946 {
947         TestlyxstringInvariant(this);
948
949         size_type ii = min(rep->sz - 1, i);
950         do {
951                 if (a[a.length() - 1] == rep->s[ii]) {
952                         int t = rep->sz - 2;
953                         size_type l = ii - 1;
954                         for (; t >= 0; --t, --l) {
955                                 if (a[t] != rep->s[l]) break;
956                         }
957                         if (a[t] == rep->s[l]) return l;
958                 }
959         } while(ii-- > 0);
960         return npos;
961 }
962
963
964 lyxstring::size_type lyxstring::rfind(value_type const * ptr, size_type i,
965                                   size_type n) const
966 {
967         Assert(ptr);
968         TestlyxstringInvariant(this);
969         if (!*ptr) return npos;
970
971         size_type ii = min(rep->sz - 1, i);
972         do {
973                 if (ptr[n - 1] == rep->s[ii]) {
974                         int t = n - 2;
975                         size_type l = ii - 1;
976                         for (; t >= 0; --t, --l) {
977                                 if (ptr[t] != rep->s[l]) break;
978                         }
979                         if (ptr[t] == rep->s[l]) return l;
980                 }
981         } while (ii-- > 0);
982         return npos;
983 }
984
985
986 lyxstring::size_type lyxstring::rfind(value_type const * ptr, size_type i) const
987 {
988         Assert(ptr);
989         TestlyxstringInvariant(this);
990         if (!*ptr) return npos;
991
992         size_type ii = min(rep->sz - 1, i);
993         do {
994                 if (ptr[strlen(ptr) - 1] == rep->s[ii]) {
995                         int t = strlen(ptr) - 2;
996                         size_type l = ii - 1;
997                         for (; t >= 0; --t, --l) {
998                                 if (ptr[t] != rep->s[l]) break;
999                         }
1000                         if (ptr[t] == rep->s[l]) return l;
1001                 }
1002         } while (ii-- > 0);
1003         return npos;
1004 }
1005
1006
1007 lyxstring::size_type lyxstring::rfind(value_type c, size_type i) const
1008 {
1009         TestlyxstringInvariant(this);
1010
1011         size_type ii = min(rep->sz - 1, i);
1012         for (size_type t = ii; t != 0; --t) {
1013                 if (rep->s[t] == c) return t;
1014         }
1015         return npos;
1016 }
1017
1018
1019 lyxstring::size_type lyxstring::find_first_of(lyxstring const & a,
1020                                           size_type i) const
1021 {
1022         Assert(i < rep->sz);
1023         TestlyxstringInvariant(this);
1024
1025         for (size_type t = i; t < rep->sz; ++t) {
1026                 if (a.find(rep->s[t]) != npos) return t;
1027         }
1028         return npos;
1029 }
1030
1031
1032 lyxstring::size_type lyxstring::find_first_of(value_type const * ptr, size_type i,
1033                                           size_type n) const
1034 {
1035         Assert(ptr && i < rep->sz);
1036         TestlyxstringInvariant(this);
1037         if (!n) return npos;
1038
1039         for (size_type t = i; t < rep->sz; ++t) {
1040                 if(memchr(ptr, rep->s[t], n) != 0) return t;
1041         }
1042         return npos;
1043 }
1044
1045
1046 lyxstring::size_type lyxstring::find_first_of(value_type const * ptr,
1047                                           size_type i) const
1048 {
1049         Assert(ptr && i < rep->sz);
1050         TestlyxstringInvariant(this);
1051
1052         for (size_type t = i; t < rep->sz; ++t) {
1053                 if (strchr(ptr, rep->s[t]) != 0) return t;
1054         }
1055         return npos;
1056 }
1057
1058
1059 lyxstring::size_type lyxstring::find_first_of(value_type c, size_type i) const
1060 {
1061         Assert(i < rep->sz);
1062         TestlyxstringInvariant(this);
1063
1064         for (size_type t = i; t < rep->sz; ++t) {
1065                 if (rep->s[t] == c) return t;
1066         }
1067         return npos;
1068 }
1069
1070
1071 lyxstring::size_type lyxstring::find_last_of(lyxstring const & a,
1072                                          size_type i) const
1073 {
1074         TestlyxstringInvariant(this);
1075
1076         size_type ii = min(rep->sz - 1, i);
1077         for (int t = ii; t >= 0; --t) {
1078                 if (a.find(rep->s[t]) != npos) return t;
1079         }
1080         return npos;
1081 }
1082
1083 lyxstring::size_type lyxstring::find_last_of(value_type const * ptr, size_type i,
1084                                          size_type n) const
1085 {
1086         Assert(ptr);
1087         TestlyxstringInvariant(this);
1088         if (!n) return npos;
1089
1090         size_type ii = min(rep->sz - 1, i);
1091         for (int t = ii; t >= 0; --t) {
1092                 if(memchr(ptr, rep->s[t], n) != 0) return t;
1093         }
1094         return npos;
1095 }
1096
1097
1098 lyxstring::size_type lyxstring::find_last_of(value_type const * ptr,
1099                                          size_type i) const
1100 {
1101         Assert(ptr);
1102         TestlyxstringInvariant(this);
1103
1104         size_type ii = min(rep->sz - 1, i);
1105         for (int t = ii; t >= 0; --t) {
1106                 if (strchr(ptr, rep->s[t]) != 0) return t;
1107         }
1108         return npos;
1109 }
1110
1111
1112 lyxstring::size_type lyxstring::find_last_of(value_type c, size_type i) const
1113 {
1114         TestlyxstringInvariant(this);
1115
1116         if (!rep->sz) return npos;
1117         size_type ii = min(rep->sz - 1, i);
1118         for (int t = ii; t >= 0; --t) {
1119                 if (rep->s[t] == c) return t;
1120         }
1121         return npos;
1122 }
1123
1124
1125 lyxstring::size_type lyxstring::find_first_not_of(lyxstring const & a,
1126                                               size_type i) const
1127 {
1128         TestlyxstringInvariant(this);
1129
1130         if (!rep->sz) return npos;
1131         Assert(i < rep->sz);
1132         for (size_type t = i; t < rep->sz; ++t) {
1133                 if (a.find(rep->s[t]) == npos) return t;
1134         }
1135         return npos;
1136 }
1137
1138
1139 lyxstring::size_type lyxstring::find_first_not_of(value_type const * ptr,
1140                                                   size_type i,
1141                                                   size_type n) const
1142 {
1143         Assert(ptr && i < rep->sz);
1144         TestlyxstringInvariant(this);
1145
1146         if (!n) return (i < rep->sz) ? i : npos;
1147         for (size_type t = i; t < rep->sz; ++t) {
1148                 if(memchr(ptr, rep->s[t], n) == 0) return t;
1149         }
1150         return npos;
1151 }
1152
1153
1154 lyxstring::size_type lyxstring::find_first_not_of(value_type const * ptr,
1155                                                   size_type i) const
1156 {
1157         Assert(ptr && i < rep->sz);
1158         TestlyxstringInvariant(this);
1159
1160         for (size_type t = i; t < rep->sz; ++t) {
1161                 if (strchr(ptr, rep->s[t]) == 0) return t;
1162         }
1163         return npos;
1164 }
1165
1166
1167 lyxstring::size_type lyxstring::find_first_not_of(value_type c,
1168                                                   size_type i) const
1169 {
1170         if (!rep->sz) return npos;
1171         Assert(i < rep->sz);
1172         TestlyxstringInvariant(this);
1173
1174         for (size_type t = i; t < rep->sz; ++t) {
1175                 if (rep->s[t] != c) return t;
1176         }
1177         return npos;
1178 }
1179
1180
1181 lyxstring::size_type lyxstring::find_last_not_of(lyxstring const & a,
1182                                                  size_type i) const
1183 {
1184         TestlyxstringInvariant(this);
1185
1186         size_type ii = min(rep->sz - 1, i);
1187         for (int t = ii; t >= 0; --t) {
1188                 if (a.find(rep->s[t]) == npos) return t;
1189         }
1190         return npos;
1191 }
1192
1193
1194 lyxstring::size_type lyxstring::find_last_not_of(value_type const * ptr,
1195                                                  size_type i,
1196                                                  size_type n) const
1197 {
1198         Assert(ptr);
1199         TestlyxstringInvariant(this);
1200
1201         if (!n) return npos;
1202         size_type ii = min(rep->sz - 1, i);
1203         for (int t = ii; t >= 0; --t) {
1204                 if(memchr(ptr, rep->s[t], n) == 0) return t;
1205         }
1206         return npos;
1207 }
1208
1209
1210 lyxstring::size_type lyxstring::find_last_not_of(value_type const * ptr,
1211                                                  size_type i) const
1212 {
1213         Assert(ptr);
1214         TestlyxstringInvariant(this);
1215
1216         size_type ii = min(rep->sz - 1, i);
1217         for (int t = ii; t >= 0; --t) {
1218                 if (strchr(ptr, rep->s[t]) == 0) return t;
1219         }
1220         return npos;
1221 }
1222
1223
1224 lyxstring::size_type lyxstring::find_last_not_of(value_type c,
1225                                                  size_type i) const
1226 {
1227         TestlyxstringInvariant(this);
1228
1229         size_type ii = min(rep->sz - 1, i);
1230         for (int t = ii; t >= 0; --t) {
1231                 if (rep->s[t] != c) return t;
1232         }
1233         return npos;
1234 }
1235
1236
1237 /////////////////
1238 // Replace
1239 /////////////////
1240
1241 lyxstring & lyxstring::replace(size_type i, size_type n, lyxstring const & x)
1242 {
1243         Assert(i < rep->sz || i == 0);
1244         TestlyxstringInvariant(this);
1245
1246         return replace(i, n, x, 0, x.length());
1247 }
1248
1249
1250 lyxstring & lyxstring::replace(size_type i,size_type n, lyxstring const & x,
1251                                size_type i2, size_type n2)
1252 {
1253         Assert((i < rep->sz || i == 0) && (i2 < x.rep->sz || i2 == 0));
1254         TestlyxstringInvariant(this);
1255
1256         rep = rep->get_own_copy();
1257         rep->replace(i, min(n, rep->sz), &(x.rep->s[i2]), min(n2, x.rep->sz));
1258         return *this;
1259 }
1260
1261
1262 lyxstring & lyxstring::replace(size_type i, size_type n,
1263                                value_type const * p, size_type n2)
1264 {
1265         Assert(p && i < rep->sz);
1266         TestlyxstringInvariant(this);
1267
1268         rep = rep->get_own_copy();
1269         rep->replace(i, min(n, rep->sz), p, min(n2, strlen(p)));
1270         return *this;
1271 }
1272
1273
1274 lyxstring & lyxstring::replace(size_type i, size_type n, value_type const * p)
1275 {
1276         Assert(p && i < rep->sz);
1277         TestlyxstringInvariant(this);
1278
1279         return replace(i, min(n, rep->sz), p, (!p) ? 0 : strlen(p));
1280 }
1281
1282
1283 lyxstring & lyxstring::replace(size_type i, size_type n,
1284                                size_type n2, value_type c)
1285 {
1286         Assert(i < rep->sz);
1287         TestlyxstringInvariant(this);
1288
1289         rep = rep->get_own_copy();
1290         value_type * tmp = new value_type[n2];
1291         memset(tmp, c, n2);
1292         rep->replace(i, min(n, rep->sz), tmp, n2);
1293         delete[] tmp;
1294         return *this;
1295 }
1296
1297
1298 lyxstring & lyxstring::replace(iterator i, iterator i2, const lyxstring & str)
1299 {
1300         TestlyxstringInvariant(this);
1301
1302         return replace(i - begin(), i2 - i, str); 
1303 }
1304
1305
1306 lyxstring & lyxstring::replace(iterator i, iterator i2,
1307                                value_type const * p, size_type n)
1308 {
1309         Assert(p);
1310         TestlyxstringInvariant(this);
1311
1312         return replace(i - begin(), i2 - i, p, n);
1313 }
1314
1315
1316 lyxstring & lyxstring::replace(iterator i, iterator i2, value_type const * p)
1317 {
1318         Assert(p);
1319         TestlyxstringInvariant(this);
1320
1321         return replace(i - begin(), i2 - i, p);
1322 }
1323
1324
1325 lyxstring & lyxstring::replace(iterator i, iterator i2,
1326                                size_type n , value_type c)
1327 {
1328         TestlyxstringInvariant(this);
1329
1330         return replace(i - begin(), i2 - i, n, c);
1331 }
1332         
1333
1334 lyxstring & lyxstring::replace(iterator i, iterator i2,
1335                                iterator j, iterator j2)
1336 {
1337         TestlyxstringInvariant(this);
1338
1339         return replace(i - begin(), i2 - i, j, j2 - j);
1340 }
1341
1342
1343 lyxstring & lyxstring::erase(size_type i, size_type n)
1344 {
1345         Assert(i < rep->sz || i == 0);
1346         TestlyxstringInvariant(this);
1347
1348         rep = rep->get_own_copy();
1349         if (i == 0 && n >= rep->sz) {
1350                 rep->sz = 0;
1351         } else {
1352                 n = min(n, rep->sz - i);
1353                 memmove(&(rep->s[i]), &(rep->s[i + n]), rep->sz - i - n);
1354                 rep->sz -= n;
1355         }
1356         return *this;
1357 }
1358
1359
1360 lyxstring::iterator lyxstring::erase(iterator i)
1361 {
1362         TestlyxstringInvariant(this);
1363
1364         // what iterator is this supposed to return?
1365         // the iterator after the one erased
1366         erase(i - begin(), 1);
1367         return begin(); // BUG
1368 }
1369
1370
1371 lyxstring::iterator lyxstring::erase(iterator first, iterator last)
1372 {
1373         TestlyxstringInvariant(this);
1374
1375         erase(first - begin(), last - first);
1376         return begin(); // BUG
1377 }
1378
1379
1380 /////////////////////////////////////
1381 // Conversion to C-style Strings
1382 /////////////////////////////////////
1383
1384 lyxstring::value_type const * lyxstring::c_str() const
1385 {
1386         rep->s[length()] = '\0';
1387         return rep->s;
1388 }
1389
1390
1391 lyxstring::value_type const * lyxstring::data() const
1392 {
1393         return rep->s;
1394 }
1395
1396
1397 lyxstring::size_type lyxstring::copy(value_type * buf, size_type len,
1398                                      size_type pos) const
1399 {
1400         Assert(buf);
1401         TestlyxstringInvariant(this);
1402
1403         register int nn = min(len, length() - pos);
1404         memcpy(buf, &(rep->s[pos]), nn);
1405         return nn;
1406 }
1407
1408
1409 ////////////////////
1410 // Comparisons
1411 ////////////////////
1412
1413 // Compare funcs should be verified.
1414 // Should we try to make them work with '\0' value_types?
1415 // An STL string can usually contain '\0' value_types.
1416
1417 int lyxstring::compare(lyxstring const & str) const
1418 {
1419         TestlyxstringInvariant(this);
1420
1421         return compare(0, rep->sz, str.c_str(), str.rep->sz);
1422 }
1423
1424
1425 int lyxstring::compare(value_type const * s) const
1426 {
1427         Assert(s);
1428         TestlyxstringInvariant(this);
1429
1430         return compare(0, rep->sz, s, (!s) ? 0 : strlen(s));
1431 }
1432
1433
1434 int lyxstring::compare(size_type pos, size_type n, lyxstring const & str) const
1435 {
1436         TestlyxstringInvariant(this);
1437
1438         return compare(pos, n, str.c_str(), str.rep->sz);
1439 }
1440
1441
1442 int lyxstring::compare(size_type pos, size_type n, lyxstring const & str,
1443                      size_type pos2, size_type n2) const
1444 {
1445         TestlyxstringInvariant(this);
1446
1447         return compare(pos, n, str.c_str() + pos2, n2);
1448 }
1449
1450
1451 int lyxstring::compare(size_type pos, size_type n, value_type const * s,
1452                      size_type n2) const
1453 {
1454         Assert(s && (pos < rep->sz || pos == 0));
1455         TestlyxstringInvariant(this);
1456
1457         if ((rep->sz == 0 || n == 0) && (!*s || n2 == 0)) return 0;
1458         if (!*s) return 1;
1459         // since n > n2, min(n,n2) == 0, c == 0 (stops segfault also)
1460
1461         // remember that n can very well be a lot larger than rep->sz
1462         // so we have to ensure that n is no larger than rep->sz
1463         n = min(n, rep->sz);
1464         n2 = min(n2, strlen(s));
1465         if (n == n2)
1466                 return memcmp(&(rep->s[pos]), s, n);
1467         int c = memcmp(&(rep->s[pos]), s, min(n,n2));
1468         if (c)
1469                 return c;
1470         if (n < n2)
1471                 return -1;
1472         return 1;
1473 }
1474
1475
1476 /////////////////
1477 // Substrings
1478 /////////////////
1479
1480 // i = index, n = length
1481 lyxstring lyxstring::substr(size_type i, size_type n) const
1482 {
1483         Assert(i < rep->sz || i == 0);
1484         TestlyxstringInvariant(this);
1485
1486         return lyxstring(*this, i, n);
1487 }
1488
1489
1490 /////////////////////////////////////////////
1491 // String operators, non member functions
1492 /////////////////////////////////////////////
1493
1494 bool operator==(lyxstring const & a, lyxstring const & b)
1495 {
1496         return a.compare(b) == 0;
1497 }
1498
1499
1500 bool operator==(lyxstring::value_type const * a, lyxstring const & b)
1501 {
1502         Assert(a);
1503         return b.compare(a) == 0;
1504 }
1505
1506
1507 bool operator==(lyxstring const & a, lyxstring::value_type const * b)
1508 {
1509         Assert(b);
1510         return a.compare(b) == 0;
1511 }
1512
1513
1514 bool operator!=(lyxstring const & a, lyxstring const & b)
1515 {
1516         return a.compare(b) != 0;
1517 }
1518
1519
1520 bool operator!=(lyxstring::value_type const * a, lyxstring const & b)
1521 {
1522         Assert(a);
1523         return b.compare(a) != 0;
1524 }
1525
1526
1527 bool operator!=(lyxstring const & a, lyxstring::value_type const * b)
1528 {
1529         Assert(b);
1530         return a.compare(b) != 0;
1531 }
1532
1533
1534 bool operator>(lyxstring const & a, lyxstring const & b)
1535 {
1536         return a.compare(b) > 0;
1537 }
1538
1539
1540 bool operator>(lyxstring::value_type const * a, lyxstring const & b)
1541 {
1542         Assert(a);
1543         return b.compare(a) < 0; // since we reverse the parameters
1544 }
1545
1546
1547 bool operator>(lyxstring const & a, lyxstring::value_type const * b)
1548 {
1549         Assert(b);
1550         return a.compare(b) > 0;
1551 }
1552
1553
1554 bool operator<(lyxstring const & a, lyxstring const & b)
1555 {
1556         return a.compare(b) < 0;
1557 }
1558
1559
1560 bool operator<(lyxstring::value_type const * a, lyxstring const & b)
1561 {
1562         Assert(a);
1563         return b.compare(a) > 0; // since we reverse the parameters
1564 }
1565
1566
1567 bool operator<(lyxstring const & a, lyxstring::value_type const * b)
1568 {
1569         Assert(b);
1570         return a.compare(b) < 0;
1571 }
1572
1573
1574 bool operator>=(lyxstring const & a, lyxstring const & b)
1575 {
1576         return a.compare(b) >= 0;
1577 }
1578
1579
1580 bool operator>=(lyxstring::value_type const * a, lyxstring const & b)
1581 {
1582         Assert(a);
1583         return b.compare(a) <= 0; // since we reverse the parameters
1584 }
1585
1586
1587 bool operator>=(lyxstring const & a, lyxstring::value_type const * b)
1588 {
1589         Assert(b);
1590         return a.compare(b) >= 0;
1591 }
1592
1593
1594 bool operator<=(lyxstring const & a, lyxstring const & b)
1595 {
1596         return a.compare(b) <= 0;
1597 }
1598
1599
1600 bool operator<=(lyxstring::value_type const * a, lyxstring const & b)
1601 {
1602         Assert(a);
1603         return b.compare(a) >= 0; // since we reverse the parameters
1604 }
1605
1606
1607 bool operator<=(lyxstring const & a, lyxstring::value_type const * b)
1608 {
1609         Assert(b);
1610         return a.compare(b) <= 0;
1611 }
1612
1613
1614 lyxstring operator+(lyxstring const & a, lyxstring const & b)
1615 {
1616         lyxstring tmp(a);
1617         tmp += b;
1618         return tmp;
1619 }
1620
1621
1622 lyxstring operator+(lyxstring::value_type const * a, lyxstring const & b)
1623 {
1624         Assert(a);
1625         lyxstring tmp(a);
1626         tmp += b;
1627         return tmp;
1628 }
1629
1630
1631 lyxstring operator+(lyxstring::value_type a, lyxstring const & b)
1632 {
1633         lyxstring tmp;
1634         tmp += a;
1635         tmp += b;
1636         return tmp;
1637 }
1638
1639
1640 lyxstring operator+(lyxstring const & a, lyxstring::value_type const * b)
1641 {
1642         Assert(b);
1643         lyxstring tmp(a);
1644         tmp += b;
1645         return tmp;
1646 }
1647
1648
1649 lyxstring operator+(lyxstring const & a, lyxstring::value_type b)
1650 {
1651         lyxstring tmp(a);
1652         tmp += b;
1653         return tmp;
1654 }
1655
1656 #include <iostream>
1657
1658 istream & operator>>(istream & is, lyxstring & s)
1659 {
1660         // very bad solution
1661         char * nome = new char[1024];
1662         is >> nome;
1663         lyxstring tmp(nome);
1664         delete [] nome;
1665         if (!tmp.empty()) s = tmp;
1666         return is;
1667 }
1668
1669 ostream & operator<<(ostream & o, lyxstring const & s)
1670 {
1671         return o.write(s.data(), s.length());
1672 }
1673
1674 istream & getline(istream & is, lyxstring & s,
1675                   lyxstring::value_type delim)
1676 {
1677         // very bad solution
1678         char tmp;
1679         s.erase();
1680         while(is) {
1681                 is >> tmp;
1682                 if (tmp != delim) {
1683                         s += tmp;
1684                 } else {
1685                         break;
1686                 }
1687         }
1688         return is;
1689 }