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