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