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