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