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