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