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