]> git.lyx.org Git - lyx.git/blob - src/support/lyxstring.C
lyx-devel.diff
[lyx.git] / src / support / lyxstring.C
1 /* This file is part of
2  * ====================================================== 
3  * 
4  *           LyX, The Document Processor
5  *       
6  *          Copyright 1995 Matthias Ettrich
7  *          Copyright 1995-2000 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 #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 #ifdef ENABLE_ASSERTIONS
308
309 /** Testing of the lyxstring invariant
310  * By creating an object that tests the lyxstring invariant during its
311  * construction *and* its deconstruction we greatly simplify our code.
312  * Calling TestlyxstringInvariant() upon entry to an lyxstring method 
313  * will test the invariant upon entry to the code.  If the Asserts fail
314  * then we know from the stack trace that the corruption occurred *before*
315  * entry to this method.  We can also be sure it didn't happen in any of
316  * the tested lyxstring methods.  It is therefore likely to be due to some
317  * other external force.
318  * Several lyxstring methods have multiple exit points which would otherwise
319  * require us to insert a separate test before each return.  But since we
320  * created an object its destructor will be called upon exit (any exit!).
321  * We thus get testing at both start and end of a method with one line of
322  * code at the head of a method.  More importantly,  we get good testing
323  * everytime we run the code.
324  * NOTE:  just because we test the invariant doesn't mean we can forget
325  * about testing pre and post conditions specific to any given method.
326  * This test simply proves that the lyxstring/Srep is in a valid state it
327  * does *not* prove that the method did what it was supposed to.
328  */
329 class lyxstringInvariant {
330 public:
331         lyxstringInvariant(lyxstring const *);
332         ~lyxstringInvariant();
333 private:
334         void helper() const;
335         lyxstring const * object;
336 };
337
338
339 // To test if this scheme works "as advertised" uncomment the printf's in
340 // the constructor and destructor below and then uncomment the printf and the
341 // call to TestlyxstringInvariant() in lyxstring::operator=(char const *).
342 // The correct output when LyX has been recompiled and run is:
343 //     lyxstringInvariant constructor
344 //     lyxstring::operator=(char const *)
345 //     lyxstringInvariant constructor
346 //     lyxstringInvariant destructor completed
347 //     lyxstringInvariant destructor completed
348 // NOTE: The easiest way to catch this snippet of the output is to wait for
349 //       the splash screen to disappear and then open and close Help->Credits
350 //
351 lyxstringInvariant::lyxstringInvariant(lyxstring const * ls) : object(ls)
352 {
353         // printf("lyxstringInvariant constructor\n");
354         helper();
355 }
356
357
358 lyxstringInvariant::~lyxstringInvariant()
359 {
360         helper();
361         // printf("lyxstringInvariant destructor completed\n");
362 }
363
364
365 void lyxstringInvariant::helper() const
366 {
367         // Some of these tests might look pointless but they are
368         // all part of the invariant and if we want to make sure
369         // we have a bullet proof implementation then we need to
370         // test every last little thing we *know* should be true.
371         // I may have missed a test or two, so feel free to fill
372         // in the gaps.  ARRae.
373         Assert(object);
374         Assert(object->rep);
375         Assert(object->rep->s);    // s is never 0
376         Assert(object->rep->res);  // res cannot be 0
377         Assert(object->rep->sz <= object->rep->res);
378         Assert(object->rep->ref >= 1);  // its in use so it must be referenced
379         Assert(object->rep->ref < 1UL << (8UL * sizeof(object->rep->ref) - 1));
380         // if it does ever == then we should be generating a new copy
381         // and starting again.  (Is char always 8-bits?)
382 }
383 #define TestlyxstringInvariant(s) lyxstringInvariant lyxstring_invariant(s);
384 #else
385 #define TestlyxstringInvariant(s)
386 #endif /* ENABLE_ASSERTIONS */
387
388
389 ///////////////////////////////////////
390 // Constructors and Deconstructors.
391 ///////////////////////////////////////
392
393 lyxstring::size_type const lyxstring::npos =
394 static_cast<lyxstring::size_type>(-1);
395
396
397 lyxstring::lyxstring()
398 {
399         static Srep empty_rep(0, "");
400         ++empty_rep.ref;
401         rep = &empty_rep;
402 }
403
404
405 lyxstring::lyxstring(lyxstring const & x, size_type pos, size_type n)
406 {
407         Assert(pos <= x.rep->sz); // STD!
408         if (pos == 0 && n >= x.length()) { // this is the default
409                 x.rep->ref++;
410                 rep = x.rep;
411         } else {
412                 rep = new Srep(min(n, x.rep->sz - pos), &(x.rep->s[pos]));
413         }
414 }
415
416
417 lyxstring::lyxstring(value_type const * s, size_type n)
418 {
419         Assert(s && n < npos); // STD!
420         static Srep empty_rep(0, "");
421         if (n) { // n > 0
422                 rep = new Srep(n, s);
423         } else {
424                 ++empty_rep.ref;
425                 rep = &empty_rep;
426         }
427 }
428
429
430 lyxstring::lyxstring(value_type const * s)
431 {
432         Assert(s); // STD!
433         static Srep empty_rep(0, "");
434         if (*s) { // s is not empty string
435                 rep = new Srep(strlen(s), s);
436         } else {
437                 ++empty_rep.ref;
438                 rep = &empty_rep;
439         }
440 }
441
442
443 lyxstring::lyxstring(size_type n, value_type c)
444 {
445         Assert(n < npos); // STD!
446         rep = new Srep(n, c);
447 }
448
449
450 lyxstring::lyxstring(const_iterator first, const_iterator last)
451 {
452         rep = new Srep(last - first, first);
453 }
454
455
456 lyxstring::~lyxstring()
457 {
458         if (--rep->ref == 0) delete rep;
459 }
460
461 ///////////////////////
462 // Iterators
463 ///////////////////////
464
465 lyxstring::iterator lyxstring::begin()
466 {
467         rep = rep->get_own_copy();
468         return rep->s;
469 }
470
471
472 lyxstring::const_iterator lyxstring::begin() const
473 {
474         return rep->s;
475 }
476
477
478 lyxstring::iterator lyxstring::end()
479 {
480         rep = rep->get_own_copy();
481         return rep->s + rep->sz;
482 }
483
484
485 lyxstring::const_iterator lyxstring::end() const
486 {
487         return rep->s + rep->sz;
488 }
489
490 #if 0
491 reverse_iterator lyxstring::rbegin()
492 {
493         return reverse_iterator( end() );
494 }
495
496
497 const_reverse_iterator lyxstring::rbegin() const
498 {
499         return const_reverse_iterator( end() );
500 }
501
502
503 reverse_iterator lyxstring::rend()
504 {
505         return reverse_iterator( begin() );
506 }
507
508
509 const_reverse_iterator lyxstring::rend() const
510 {
511         return const_reverse_iterator( begin() );
512 }
513 #endif
514
515
516 ///////////////////////
517 // Size and Capacity
518 ///////////////////////
519
520 lyxstring::size_type lyxstring::size() const
521
522         return rep->sz;
523 }
524
525
526 void lyxstring::resize(size_type n, value_type c)
527 {
528         Assert(n <= npos); // STD!
529         TestlyxstringInvariant(this);
530
531         // This resets sz to res_arg
532         rep = rep->get_own_copy();
533         rep->resize(n, c);
534 }
535
536
537 lyxstring::size_type lyxstring::capacity() const
538 {
539         return rep->res;
540 }
541
542
543 void lyxstring::reserve(size_type res_arg)
544 {
545         TestlyxstringInvariant(this);
546
547         rep = rep->get_own_copy();
548         rep->reserve(res_arg);
549 }
550
551
552 ////////////////
553 // Assignment
554 ////////////////
555
556 lyxstring & lyxstring::operator=(lyxstring const & x)
557 {
558         TestlyxstringInvariant(this);
559
560         return assign(x);
561 }
562
563
564 lyxstring & lyxstring::operator=(value_type const * s)
565 {
566         Assert(s); // OURS!
567         TestlyxstringInvariant(this);
568 //      printf("lyxstring::operator= (value_type const *)\n");
569
570         return assign(s);
571 }
572
573
574 lyxstring & lyxstring::operator=(value_type c)
575 {
576         TestlyxstringInvariant(this);
577
578         value_type s[1];
579         s[0] = c;
580         if (rep->ref == 1) // recycle rep
581                 rep->assign(1, s);
582         else {
583                 rep->ref--;
584                 rep = new Srep(1, s);
585         }
586         return *this;
587 }
588
589
590 lyxstring & lyxstring::assign(lyxstring const & x)
591 {
592         TestlyxstringInvariant(this);
593
594         x.rep->ref++; // protect against ``st = st''
595         if (--rep->ref == 0) delete rep;
596         rep = x.rep; // share representation
597         return *this;
598 }
599         
600
601 lyxstring & lyxstring::assign(lyxstring const & x, size_type pos, size_type n)
602 {
603         Assert(pos <= x.rep->sz); // STD!
604         TestlyxstringInvariant(this);
605
606         return assign(x.substr(pos, n));
607 }
608         
609
610 lyxstring & lyxstring::assign(value_type const * s, size_type n)
611 {
612         Assert(s && n < npos); // STD!
613         TestlyxstringInvariant(this);
614
615         if (rep->ref == 1) // recycle rep
616                 rep->assign(n, s);
617         else {
618                 --rep->ref;
619                 rep = new Srep(n, s);
620         }
621         return *this;
622 }
623         
624
625 lyxstring & lyxstring::assign(value_type const * s)
626 {
627         Assert(s); // OURS!
628         TestlyxstringInvariant(this);
629
630         return assign(s, strlen(s));
631 }
632
633
634 lyxstring & lyxstring::assign(size_type n, value_type ch)
635 {
636         TestlyxstringInvariant(this);
637
638         rep = rep->get_own_copy();
639         rep->assign(n, ch);
640         return *this;
641 }
642
643
644 lyxstring & lyxstring::assign(const_iterator first, const_iterator last)
645 {
646         TestlyxstringInvariant(this);
647
648         rep = rep->get_own_copy();
649         rep->assign(last - first, first);
650         return *this;
651 }
652
653
654 ////////////////////
655 // Element Access
656 ////////////////////
657
658 lyxstring::const_reference lyxstring::operator[](size_type pos) const
659 {
660         Assert(pos <= rep->sz); // OURS!
661         static char helper = '\0';
662         return pos == rep->sz ? helper : rep->s[pos];
663 }
664
665
666 lyxstring::reference lyxstring::operator[](size_type pos)
667 {
668         Assert(pos < rep->sz); // OURS!
669         TestlyxstringInvariant(this);
670
671         rep = rep->get_own_copy();
672         return rep->s[pos];
673 }
674
675
676 lyxstring::const_reference lyxstring::at(size_type n) const
677 {
678         Assert(n < rep->sz); // STD!
679         return rep->s[n];
680 }
681
682
683 lyxstring::reference lyxstring::at(size_type n)
684 {
685         Assert(n < rep->sz); // STD!
686         TestlyxstringInvariant(this);
687
688         rep = rep->get_own_copy();
689         return rep->s[n];
690 }
691
692
693 /////////////
694 // Insert
695 /////////////
696
697 lyxstring & lyxstring::operator+=(lyxstring const & x)
698 {
699         TestlyxstringInvariant(this);
700
701         return append(x);
702 }
703
704
705 lyxstring & lyxstring::operator+=(value_type const * x)
706 {
707         Assert(x); // OURS!
708         TestlyxstringInvariant(this);
709
710         return append(x);
711 }
712
713
714 lyxstring & lyxstring::operator+=(value_type c)
715 {
716         TestlyxstringInvariant(this);
717
718         push_back(c);
719         return *this;
720 }
721
722
723 void lyxstring::push_back(value_type c)
724 {
725         TestlyxstringInvariant(this);
726
727         rep = rep->get_own_copy();
728         rep->push_back(c);
729 }
730
731
732 lyxstring & lyxstring::append(lyxstring const & x)
733 {
734         TestlyxstringInvariant(this);
735
736         if (x.empty()) return *this;
737         rep = rep->get_own_copy();
738         rep->append(x.length(), x.rep->s);
739         return *this;
740 }
741
742
743 lyxstring & lyxstring::append(lyxstring const & x, size_type pos, size_type n)
744 {
745         Assert(pos <= x.rep->sz); // STD!
746         TestlyxstringInvariant(this);
747
748         return append(x.substr(pos, n));
749 }
750
751
752 lyxstring & lyxstring::append(value_type const * p, size_type n)
753 {
754         Assert(p); // OURS!
755         TestlyxstringInvariant(this);
756
757         if (!*p || !n) return *this;
758         rep = rep->get_own_copy();
759         rep->append(n, p);
760         return *this;
761 }
762
763
764 lyxstring & lyxstring::append(value_type const * p)
765 {
766         Assert(p); // OURS!
767         return append(p, strlen(p));
768 }
769
770
771 lyxstring & lyxstring::append(size_type n, value_type c)
772 {
773         TestlyxstringInvariant(this);
774
775         value_type * tmp = new value_type[n];
776         memset(tmp, c, n);
777         rep = rep->get_own_copy();
778         rep->append(n, tmp);
779         delete[] tmp;
780         return *this;
781 }
782
783
784 lyxstring & lyxstring::append(iterator first, iterator last)
785 {
786         TestlyxstringInvariant(this);
787
788         rep = rep->get_own_copy();
789         rep->append(last - first, first);
790         return *this;
791 }
792
793 // insert characters before (*this)[pos]
794
795 lyxstring & lyxstring::insert(size_type pos, lyxstring const & x)
796 {
797         TestlyxstringInvariant(this);
798
799         return insert(pos, x, 0, x.rep->sz);
800 }
801
802
803 lyxstring & lyxstring::insert(size_type pos, lyxstring const & x,
804                               size_type pos2, size_type n)
805 {
806         Assert(pos <= rep->sz && pos2 <= x.rep->sz); // STD!
807         TestlyxstringInvariant(this);
808
809         rep = rep->get_own_copy();
810         rep->insert(pos, &(x.rep->s[pos2]), min(n, x.rep->sz));
811         return *this;
812 }
813
814
815 lyxstring & lyxstring::insert(size_type pos, value_type const * p, size_type n)
816 {
817         Assert(p); // OURS!
818         TestlyxstringInvariant(this);
819
820         if (*p && n) {
821                 // insert nothing and you change nothing
822                 rep = rep->get_own_copy();
823                 rep->insert(pos, p, n);
824         }
825         return *this;
826 }
827
828
829 lyxstring & lyxstring::insert(size_type pos, value_type const * p)
830 {
831         Assert(p); // OURS!
832         return insert(pos, p, strlen(p));
833 }
834
835
836 lyxstring & lyxstring::insert(size_type pos, size_type n, value_type c)
837 {
838         TestlyxstringInvariant(this);
839
840         rep = rep->get_own_copy();
841         value_type * tmp = new value_type[n];
842         memset(tmp, c, n);
843         rep->insert(pos, tmp, n);
844         delete[] tmp;
845         return *this;
846 }
847
848
849 lyxstring::iterator lyxstring::insert(iterator p, value_type c)
850 {
851         TestlyxstringInvariant(this);
852
853         // what iterator is this supposed to return??
854         size_type tmp = p - begin();
855         insert(p - begin(), 1, c);
856         return begin() + tmp + 1; // ??
857 }
858
859
860 void lyxstring::insert(iterator p, size_type n , value_type c)
861 {
862         TestlyxstringInvariant(this);
863
864         insert(p - begin(), n , c);
865 }
866
867
868 void lyxstring::insert(iterator p, iterator first, iterator last)
869 {
870         TestlyxstringInvariant(this);
871
872         insert(p - begin(), first, last - first);
873 }
874         
875
876 ////////////////
877 // Find
878 ////////////////
879  
880          // All the below find functions should be verified,
881          // it is very likely that I have mixed up or interpreted
882          // some of the parameters wrong, also some of the funcs can surely
883          // be written more effectively.
884
885 lyxstring::size_type lyxstring::find(lyxstring const & a, size_type i) const
886 {
887         if (!rep->sz || i >= rep->sz) return npos;
888         
889         TestlyxstringInvariant(this);
890
891         size_type n = a.length();
892         if (!n) return npos;
893         for (size_type t = i; rep->sz - t >= n; ++t) {
894                 // search until (*this)[i] == a[0]
895                 if (rep->s[t] == a[0]) {
896                         // check if the rest of the value_types match
897                         bool equal = true;
898                         for (size_type j = 1; j < n; ++j) {
899                                 if (rep->s[t + j] != a[j]) {
900                                         equal = false;
901                                         break;
902                                 }
903                         }
904                         if (equal) return t;
905                 }
906         }
907         return npos;
908 }
909
910
911 lyxstring::size_type lyxstring::find(value_type const * ptr, size_type i,
912                                      size_type n) const
913 {
914         Assert(ptr); // OURS!
915         if (!rep->sz || !*ptr || i >= rep->sz) return npos;
916         
917         TestlyxstringInvariant(this);
918
919         // What is "n" here? is it the number of value_types to use in ptr
920         // or does "i" and "n" togeter form a substring to search
921         // for ptr in? For now I will assume that "n" tells the length
922         // of ptr. (Lgb)
923         n = min(n, strlen(ptr));
924         if (!n) return npos;
925         for (size_type t = i; rep->sz - t >= n; ++t) {
926                 // search until (*this)[i] == a[0]
927                 if (rep->s[t] == ptr[0]) {
928                         // check if the rest of the value_types match
929                         bool equal = true;
930                         for (size_type j = 1; j < n; ++j) {
931                                 if (rep->s[t + j] != ptr[j]) {
932                                         equal = false;
933                                         break;
934                                 }
935                         }
936                         if (equal) return t;
937                 }
938         }
939         return npos;
940 }
941
942
943 lyxstring::size_type lyxstring::find(value_type const * s, size_type i) const
944 {
945         Assert(s); // OURS!
946         if (!rep->sz || i >= rep->sz) return npos;
947         
948         TestlyxstringInvariant(this);
949
950         if (!s || !*s) return npos;
951         return find(s, i, strlen(s));
952 }
953
954
955 lyxstring::size_type lyxstring::find(value_type c, size_type i) const
956 {
957         if (!rep->sz || i >= rep->sz) return npos;
958
959         TestlyxstringInvariant(this);
960
961         for (size_type t = 0; t + i < rep->sz; ++t) {
962                 if (rep->s[t + i] == c) return t + i;
963         }
964         return npos;
965 }
966
967
968 lyxstring::size_type lyxstring::rfind(lyxstring const & a, size_type i) const
969 {
970         TestlyxstringInvariant(this);
971
972         size_type n = a.length();
973         if (!n || rep->sz < n)
974                 return npos;
975
976         size_type t = min(rep->sz - n, i);
977         do {
978                 if (rep->s[t] == a[0]) {
979                         // check if the rest of the value_types match
980                         bool equal = true;
981                         for (size_type j = 1; j < n; ++j) {
982                                 if (rep->s[t + j] != a[j]) {
983                                         equal = false;
984                                         break;
985                                 }
986                         }
987                         if (equal) return t;
988                 }
989         } while(t-- > 0);
990         return npos;
991 }
992
993
994 lyxstring::size_type lyxstring::rfind(value_type const * ptr, size_type i,
995                                       size_type n) const
996 {
997         Assert(ptr); // OURS!
998         TestlyxstringInvariant(this);
999
1000         n = min(n, strlen(ptr));
1001         if (!n || rep->sz < n)
1002                 return npos;
1003
1004         size_type t = min(rep->sz - n, i);
1005         do {
1006                 if (rep->s[t] == ptr[0]) {
1007                         // check if the rest of the value_types match
1008                         bool equal = true;
1009                         for (size_type j = 1; j < n; ++j) {
1010                                 if (rep->s[t + j] != ptr[j]) {
1011                                         equal = false;
1012                                         break;
1013                                 }
1014                         }
1015                         if (equal) return t;
1016                 }
1017         } while (t-- > 0);
1018         return npos;
1019 }
1020
1021
1022 lyxstring::size_type lyxstring::rfind(value_type const * ptr,
1023                                       size_type i) const
1024 {
1025         Assert(ptr); // OURS!
1026
1027         if (!ptr || !*ptr) return npos;
1028         return rfind(ptr, i, strlen(ptr));
1029 }
1030
1031
1032 lyxstring::size_type lyxstring::rfind(value_type c, size_type i) const
1033 {
1034         TestlyxstringInvariant(this);
1035
1036         size_type const sz = rep->sz;
1037         if (sz < 1) return npos;
1038         size_type ii = min(sz - 1, i);
1039         do {
1040                 if (rep->s[ii] == c) return ii;
1041         } while (ii-- > 0);
1042         return npos;
1043 }
1044
1045
1046 lyxstring::size_type lyxstring::find_first_of(lyxstring const & a,
1047                                               size_type i) const
1048 {
1049         Assert(i <= rep->sz); // OURS!
1050         TestlyxstringInvariant(this);
1051
1052         for (size_type t = i; t < rep->sz; ++t) {
1053                 if (a.find(rep->s[t]) != npos) return t;
1054         }
1055         return npos;
1056 }
1057
1058
1059 lyxstring::size_type lyxstring::find_first_of(value_type const * ptr,
1060                                               size_type i,
1061                                               size_type n) const
1062 {
1063         Assert(ptr && i <= rep->sz); // OURS!
1064         TestlyxstringInvariant(this);
1065         if (!n) return npos;
1066
1067         for (size_type t = i; t < rep->sz; ++t) {
1068                 if (memchr(ptr, rep->s[t], n) != 0) return t;
1069         }
1070         return npos;
1071 }
1072
1073
1074 lyxstring::size_type lyxstring::find_first_of(value_type const * ptr,
1075                                               size_type i) const
1076 {
1077         Assert(ptr && i <= rep->sz); // OURS!
1078         TestlyxstringInvariant(this);
1079
1080         for (size_type t = i; t < rep->sz; ++t) {
1081                 if (strchr(ptr, rep->s[t]) != 0) return t;
1082         }
1083         return npos;
1084 }
1085
1086
1087 lyxstring::size_type lyxstring::find_first_of(value_type c, size_type i) const
1088 {
1089         Assert(i <= rep->sz); // OURS!
1090         TestlyxstringInvariant(this);
1091
1092         for (size_type t = i; t < rep->sz; ++t) {
1093                 if (rep->s[t] == c) return t;
1094         }
1095         return npos;
1096 }
1097
1098
1099 lyxstring::size_type lyxstring::find_last_of(lyxstring const & a,
1100                                              size_type i) const
1101 {
1102         TestlyxstringInvariant(this);
1103
1104         size_type ii = min(rep->sz - 1, i);
1105         for (int t = ii; t >= 0; --t) {
1106                 if (a.find(rep->s[t]) != npos) return t;
1107         }
1108         return npos;
1109 }
1110
1111
1112 lyxstring::size_type lyxstring::find_last_of(value_type const * ptr,
1113                                              size_type i,
1114                                              size_type n) const
1115 {
1116         Assert(ptr); // OURS!
1117         TestlyxstringInvariant(this);
1118         if (!n) return npos;
1119
1120         size_type ii = min(rep->sz - 1, i);
1121         for (int t = ii; t >= 0; --t) {
1122                 if (memchr(ptr, rep->s[t], n) != 0) return t;
1123         }
1124         return npos;
1125 }
1126
1127
1128 lyxstring::size_type lyxstring::find_last_of(value_type const * ptr,
1129                                              size_type i) const
1130 {
1131         Assert(ptr); // OURS!
1132         TestlyxstringInvariant(this);
1133
1134         size_type ii = min(rep->sz - 1, i);
1135         for (int t = ii; t >= 0; --t) {
1136                 if (strchr(ptr, rep->s[t]) != 0) return t;
1137         }
1138         return npos;
1139 }
1140
1141
1142 lyxstring::size_type lyxstring::find_last_of(value_type c, size_type i) const
1143 {
1144         TestlyxstringInvariant(this);
1145
1146         if (!rep->sz) return npos;
1147         size_type ii = min(rep->sz - 1, i);
1148         for (int t = ii; t >= 0; --t) {
1149                 if (rep->s[t] == c) return t;
1150         }
1151         return npos;
1152 }
1153
1154
1155 lyxstring::size_type lyxstring::find_first_not_of(lyxstring const & a,
1156                                                   size_type i) const
1157 {
1158         TestlyxstringInvariant(this);
1159
1160         if (!rep->sz) return npos;
1161         Assert(i <= rep->sz);
1162         for (size_type t = i; t < rep->sz; ++t) {
1163                 if (a.find(rep->s[t]) == npos) return t;
1164         }
1165         return npos;
1166 }
1167
1168
1169 lyxstring::size_type lyxstring::find_first_not_of(value_type const * ptr,
1170                                                   size_type i,
1171                                                   size_type n) const
1172 {
1173         Assert(ptr && i <= rep->sz); // OURS!
1174         TestlyxstringInvariant(this);
1175
1176         if (!n) return (i < rep->sz) ? i : npos;
1177         for (size_type t = i; t < rep->sz; ++t) {
1178                 if (memchr(ptr, rep->s[t], n) == 0) return t;
1179         }
1180         return npos;
1181 }
1182
1183
1184 lyxstring::size_type lyxstring::find_first_not_of(value_type const * ptr,
1185                                                   size_type i) const
1186 {
1187         Assert(ptr && i <= rep->sz); // OURS!
1188         TestlyxstringInvariant(this);
1189
1190         for (size_type t = i; t < rep->sz; ++t) {
1191                 if (strchr(ptr, rep->s[t]) == 0) return t;
1192         }
1193         return npos;
1194 }
1195
1196
1197 lyxstring::size_type lyxstring::find_first_not_of(value_type c,
1198                                                   size_type i) const
1199 {
1200         if (!rep->sz) return npos;
1201         Assert(i <= rep->sz); // OURS!
1202         TestlyxstringInvariant(this);
1203
1204         for (size_type t = i; t < rep->sz; ++t) {
1205                 if (rep->s[t] != c) return t;
1206         }
1207         return npos;
1208 }
1209
1210
1211 lyxstring::size_type lyxstring::find_last_not_of(lyxstring const & a,
1212                                                  size_type i) const
1213 {
1214         TestlyxstringInvariant(this);
1215
1216         size_type ii = min(rep->sz - 1, i);
1217         for (int t = ii; t >= 0; --t) {
1218                 if (a.find(rep->s[t]) == npos) return t;
1219         }
1220         return npos;
1221 }
1222
1223
1224 lyxstring::size_type lyxstring::find_last_not_of(value_type const * ptr,
1225                                                  size_type i,
1226                                                  size_type n) const
1227 {
1228         Assert(ptr); // OURS!
1229         TestlyxstringInvariant(this);
1230
1231         if (!n) return npos;
1232         size_type ii = min(rep->sz - 1, i);
1233
1234         for (int t = ii; t >= 0; --t) {
1235                 if (memchr(ptr, rep->s[t], n) == 0) return t;
1236         }
1237         return npos;
1238 }
1239
1240
1241 lyxstring::size_type lyxstring::find_last_not_of(value_type const * ptr,
1242                                                  size_type i) const
1243 {
1244         Assert(ptr); // OURS!
1245         TestlyxstringInvariant(this);
1246
1247         size_type ii = min(rep->sz - 1, i);
1248         for (int t = ii; t >= 0; --t) {
1249                 if (strchr(ptr, rep->s[t]) == 0) return t;
1250         }
1251         return npos;
1252 }
1253
1254
1255 lyxstring::size_type lyxstring::find_last_not_of(value_type c,
1256                                                  size_type i) const
1257 {
1258         TestlyxstringInvariant(this);
1259
1260         size_type ii = min(rep->sz - 1, i);
1261         for (int t = ii; t >= 0; --t) {
1262                 if (rep->s[t] != c) return t;
1263         }
1264         return npos;
1265 }
1266
1267
1268 /////////////////
1269 // Replace
1270 /////////////////
1271
1272 lyxstring & lyxstring::replace(size_type i, size_type n, lyxstring const & x)
1273 {
1274         Assert(i <= rep->sz); // OURS!
1275         TestlyxstringInvariant(this);
1276
1277         return replace(i, n, x, 0, x.rep->sz);
1278 }
1279
1280
1281 lyxstring & lyxstring::replace(size_type i, size_type n, lyxstring const & x,
1282                                size_type i2, size_type n2)
1283 {
1284         Assert(i <= rep->sz && i2 <= x.rep->sz); // STD!
1285         TestlyxstringInvariant(this);
1286
1287         rep = rep->get_own_copy();
1288         rep->replace(i, min(n, rep->sz), &(x.rep->s[i2]), min(n2, x.rep->sz));
1289         return *this;
1290 }
1291
1292
1293 lyxstring & lyxstring::replace(size_type i, size_type n,
1294                                value_type const * p, size_type n2)
1295 {
1296         Assert(p && i <= rep->sz); // OURS!
1297         TestlyxstringInvariant(this);
1298
1299         rep = rep->get_own_copy();
1300         rep->replace(i, min(n, rep->sz), p, min(n2, strlen(p)));
1301         return *this;
1302 }
1303
1304
1305 lyxstring & lyxstring::replace(size_type i, size_type n, value_type const * p)
1306 {
1307         Assert(p && i <= rep->sz); // OURS!
1308         TestlyxstringInvariant(this);
1309
1310         return replace(i, min(n, rep->sz), p, (!p) ? 0 : strlen(p));
1311 }
1312
1313
1314 lyxstring & lyxstring::replace(size_type i, size_type n,
1315                                size_type n2, value_type c)
1316 {
1317         Assert(i <= rep->sz);  // OURS!
1318         TestlyxstringInvariant(this);
1319
1320         rep = rep->get_own_copy();
1321         value_type * tmp = new value_type[n2];
1322         memset(tmp, c, n2);
1323         rep->replace(i, min(n, rep->sz), tmp, n2);
1324         delete[] tmp;
1325         return *this;
1326 }
1327
1328
1329 lyxstring & lyxstring::replace(iterator i, iterator i2, const lyxstring & str)
1330 {
1331         TestlyxstringInvariant(this);
1332
1333         return replace(i - begin(), i2 - i, str); 
1334 }
1335
1336
1337 lyxstring & lyxstring::replace(iterator i, iterator i2,
1338                                value_type const * p, size_type n)
1339 {
1340         Assert(p); // OURS!
1341         TestlyxstringInvariant(this);
1342
1343         return replace(i - begin(), i2 - i, p, n);
1344 }
1345
1346
1347 lyxstring & lyxstring::replace(iterator i, iterator i2, value_type const * p)
1348 {
1349         Assert(p); // OURS!
1350         TestlyxstringInvariant(this);
1351
1352         return replace(i - begin(), i2 - i, p);
1353 }
1354
1355
1356 lyxstring & lyxstring::replace(iterator i, iterator i2,
1357                                size_type n , value_type c)
1358 {
1359         TestlyxstringInvariant(this);
1360
1361         return replace(i - begin(), i2 - i, n, c);
1362 }
1363         
1364
1365 lyxstring & lyxstring::replace(iterator i, iterator i2,
1366                                iterator j, iterator j2)
1367 {
1368         TestlyxstringInvariant(this);
1369
1370         return replace(i - begin(), i2 - i, j, j2 - j);
1371 }
1372
1373
1374 void lyxstring::swap(lyxstring & str)
1375 {
1376         if (rep == str.rep) return;
1377         Srep * tmp = str.rep;
1378         str.rep = rep;
1379         rep = tmp;
1380 }
1381
1382
1383 lyxstring & lyxstring::erase(size_type i, size_type n)
1384 {
1385         Assert(i <= rep->sz); // STD!
1386         TestlyxstringInvariant(this);
1387
1388         rep = rep->get_own_copy();
1389         if (i == 0 && n >= rep->sz) {
1390                 rep->sz = 0;
1391         } else {
1392                 n = min(n, rep->sz - i);
1393                 memmove(&(rep->s[i]), &(rep->s[i + n]), rep->sz - i - n);
1394                 rep->sz -= n;
1395         }
1396         return *this;
1397 }
1398
1399
1400 lyxstring::iterator lyxstring::erase(iterator i)
1401 {
1402         TestlyxstringInvariant(this);
1403
1404         // what iterator is this supposed to return?
1405         // the iterator after the one erased
1406         erase(i - begin(), 1);
1407         return begin(); // BUG
1408 }
1409
1410
1411 lyxstring::iterator lyxstring::erase(iterator first, iterator last)
1412 {
1413         TestlyxstringInvariant(this);
1414
1415         erase(first - begin(), last - first);
1416         return begin(); // BUG
1417 }
1418
1419
1420 /////////////////////////////////////
1421 // Conversion to C-style Strings
1422 /////////////////////////////////////
1423
1424 lyxstring::value_type const * lyxstring::c_str() const
1425 {
1426         rep->s[length()] = '\0';
1427         return rep->s;
1428 }
1429
1430
1431 lyxstring::value_type const * lyxstring::data() const
1432 {
1433         return rep->s;
1434 }
1435
1436
1437 lyxstring::size_type lyxstring::copy(value_type * buf, size_type len,
1438                                      size_type pos) const
1439 {
1440         Assert(buf); // OURS!
1441         Assert(pos <= rep->sz); // STD!
1442         TestlyxstringInvariant(this);
1443
1444         register int nn = min(len, length() - pos);
1445         memcpy(buf, &(rep->s[pos]), nn);
1446         return nn;
1447 }
1448
1449
1450 ////////////////////
1451 // Comparisons
1452 ////////////////////
1453
1454 // Compare funcs should be verified.
1455
1456 int lyxstring::internal_compare(size_type pos, size_type n,
1457                                 value_type const * s,
1458                                 size_type slen, size_type n2) const
1459 {
1460         if ((rep->sz == 0 || n == 0) && (!*s || n2 == 0)) return 0;
1461         if (!*s) return 1;
1462         // since n > n2, min(n, n2) == 0, c == 0 (stops segfault also)
1463
1464         // remember that n can very well be a lot larger than rep->sz
1465         // so we have to ensure that n is no larger than rep->sz
1466         n = min(n, rep->sz);
1467         n2 = min(n2, slen);
1468         if (n == n2)
1469                 return memcmp(&(rep->s[pos]), s, n);
1470         int c = memcmp(&(rep->s[pos]), s, min(n, n2));
1471         if (c)
1472                 return c;
1473         if (n < n2)
1474                 return -1;
1475         return 1;
1476 }
1477
1478
1479 int lyxstring::compare(lyxstring const & str) const
1480 {
1481         TestlyxstringInvariant(this);
1482         return internal_compare(0, rep->sz, str.rep->s,
1483                                 str.rep->sz, str.rep->sz);
1484 }
1485
1486
1487 int lyxstring::compare(value_type const * s) const
1488 {
1489         Assert(s); //OURS!
1490         TestlyxstringInvariant(this);
1491         int n = (!s) ? 0 : strlen(s);
1492         return internal_compare(0, rep->sz, s, n, n);
1493 }
1494
1495
1496 int lyxstring::compare(size_type pos, size_type n,
1497                        lyxstring const & str) const
1498 {
1499         Assert(pos <= rep->sz); // OURS!
1500         TestlyxstringInvariant(this);
1501         return internal_compare(pos, n, str.rep->s, str.rep->sz, str.rep->sz);
1502 }
1503
1504
1505 int lyxstring::compare(size_type pos, size_type n, lyxstring const & str,
1506                        size_type pos2, size_type n2) const
1507 {
1508         Assert(pos <= rep->sz); // OURS!
1509         Assert(pos2 <= str.rep->sz); // OURS!
1510         TestlyxstringInvariant(this);
1511         return internal_compare(pos, n,
1512                                 str.rep->s + pos2,
1513                                 str.rep->sz - pos2, n2);
1514 }
1515
1516
1517 int lyxstring::compare(size_type pos, size_type n, value_type const * s,
1518                        size_type n2) const
1519 {
1520         Assert(s && pos <= rep->sz); // OURS!
1521         TestlyxstringInvariant(this);
1522         return internal_compare(pos, n, s, (!s) ? 0 : strlen(s), n2);
1523 }
1524
1525
1526 /////////////////
1527 // Substrings
1528 /////////////////
1529
1530 // i = index, n = length
1531 lyxstring lyxstring::substr(size_type i, size_type n) const
1532 {
1533         Assert(i <= rep->sz); // STD!
1534         TestlyxstringInvariant(this);
1535
1536         return lyxstring(*this, i, n);
1537 }
1538
1539
1540 /////////////////////////////////////////////
1541 // String operators, non member functions
1542 /////////////////////////////////////////////
1543
1544 bool operator==(lyxstring const & a, lyxstring const & b)
1545 {
1546         return a.compare(b) == 0;
1547 }
1548
1549
1550 bool operator==(lyxstring::value_type const * a, lyxstring const & b)
1551 {
1552         Assert(a); // OURS!
1553         return b.compare(a) == 0;
1554 }
1555
1556
1557 bool operator==(lyxstring const & a, lyxstring::value_type const * b)
1558 {
1559         Assert(b); // OURS!
1560         return a.compare(b) == 0;
1561 }
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         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         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         Assert(a); // OURS!
1593         return b.compare(a) < 0; // since we reverse the parameters
1594 }
1595
1596
1597 bool operator>(lyxstring const & a, lyxstring::value_type const * b)
1598 {
1599         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         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         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         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         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         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         Assert(b); // OURS!
1660         return a.compare(b) <= 0;
1661 }
1662
1663
1664 lyxstring operator+(lyxstring const & a, lyxstring const & b)
1665 {
1666         lyxstring tmp(a);
1667         tmp += b;
1668         return tmp;
1669 }
1670
1671
1672 lyxstring operator+(lyxstring::value_type const * a, lyxstring const & b)
1673 {
1674         Assert(a); // OURS!
1675         lyxstring tmp(a);
1676         tmp += b;
1677         return tmp;
1678 }
1679
1680
1681 lyxstring operator+(lyxstring::value_type a, lyxstring const & b)
1682 {
1683         lyxstring tmp;
1684         tmp += a;
1685         tmp += b;
1686         return tmp;
1687 }
1688
1689
1690 lyxstring operator+(lyxstring const & a, lyxstring::value_type const * b)
1691 {
1692         Assert(b); // OURS!
1693         lyxstring tmp(a);
1694         tmp += b;
1695         return tmp;
1696 }
1697
1698
1699 lyxstring operator+(lyxstring const & a, lyxstring::value_type b)
1700 {
1701         lyxstring tmp(a);
1702         tmp += b;
1703         return tmp;
1704 }
1705
1706
1707 void swap(lyxstring & str1, lyxstring & str2)
1708 {
1709         str1.swap(str2);
1710 }
1711
1712
1713 #include <iostream>
1714
1715 istream & operator>>(istream & is, lyxstring & s)
1716 {
1717 #if 1
1718         // very bad solution
1719         char * nome = new char[1024];
1720         is >> nome;
1721         lyxstring tmp(nome);
1722         delete [] nome;
1723         if (!tmp.empty()) s = tmp;
1724 #else
1725         // better solution
1726         int w = is.widdth(0);
1727         s.clear();
1728         char c = 0;
1729         while (is.get(c)) {
1730                 if (isspace(c)) { is.putback(c); break; }
1731                 s += c;
1732                 if (--w == 1) break;
1733         }
1734         if (s.empty()) is.setstate(ios::failbit);
1735 #endif
1736         return is;
1737 }
1738
1739
1740 ostream & operator<<(ostream & o, lyxstring const & s)
1741 {
1742         return o.write(s.data(), s.length());
1743 }
1744
1745
1746 istream & getline(istream & is, lyxstring & s,
1747                   lyxstring::value_type delim)
1748 {
1749         // very bad solution
1750         char tmp = 0;
1751         s.erase();
1752         while(is) {
1753                 is.get(tmp);
1754                 if (tmp != delim) {
1755                         s += tmp;
1756                 } else {
1757                         break;
1758                 }
1759         }
1760         return is;
1761 }
1762
1763 #ifdef TEST_MAIN
1764 int main() {
1765         lyxstring a = "abcac";
1766         cout << a.rfind("ab") << endl;
1767         cout << a.rfind("c") << endl;
1768         cout << a.rfind("d") << endl;
1769 }
1770 #endif