]> git.lyx.org Git - lyx.git/blob - src/support/lyxstring.C
Another fix for lyxstring::rfind
[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         for (size_type t = i; rep->sz - t >= a.length(); ++t) {
892                 // search until (*this)[i] == a[0]
893                 if (rep->s[t] == a[0]) {
894                         // check if the rest of the value_types match
895                         bool equal = true;
896                         for (size_type j = 0; j < a.length(); ++j) {
897                                 if (rep->s[t + j] != a[j]) {
898                                         equal = false;
899                                         break;
900                                 }
901                         }
902                         if (equal) return t;
903                 }
904         }
905         return npos;
906 }
907
908
909 lyxstring::size_type lyxstring::find(value_type const * ptr, size_type i,
910                                      size_type n) const
911 {
912         Assert(ptr); // OURS!
913         if (!rep->sz || !*ptr || i >= rep->sz) return npos;
914         
915         TestlyxstringInvariant(this);
916
917         // What is "n" here? is it the number of value_types to use in ptr
918         // or does "i" and "n" togeter form a substring to search
919         // for ptr in? For now I will assume that "n" tells the length
920         // of ptr. (Lgb)
921         n = min(n, strlen(ptr));
922         for (size_type t = i; rep->sz - t >= n; ++t) {
923                 // search until (*this)[i] == a[0]
924                 if (rep->s[t] == ptr[0]) {
925                         // check if the rest of the value_types match
926                         bool equal = true;
927                         for (size_type j = 0; j < n; ++j) {
928                                 if (rep->s[t + j] != ptr[j]) {
929                                         equal = false;
930                                         break;
931                                 }
932                         }
933                         if (equal) return t;
934                 }
935         }
936         return npos;
937 }
938
939
940 lyxstring::size_type lyxstring::find(value_type const * s, size_type i) const
941 {
942         Assert(s); // OURS!
943         if (!rep->sz || i >= rep->sz) return npos;
944         
945         TestlyxstringInvariant(this);
946
947         if (!s || !*s) return npos;
948         return find(s, i, strlen(s));
949 }
950
951
952 lyxstring::size_type lyxstring::find(value_type c, size_type i) const
953 {
954         if (!rep->sz || i >= rep->sz) return npos;
955
956         TestlyxstringInvariant(this);
957
958         for (size_type t = 0; t + i < rep->sz; ++t) {
959                 if (rep->s[t + i] == c) return t + i;
960         }
961         return npos;
962 }
963
964
965 lyxstring::size_type lyxstring::rfind(lyxstring const & a, size_type i) const
966 {
967         TestlyxstringInvariant(this);
968
969         size_type ii = min(rep->sz - 1, i);
970         do {
971                 if (a[a.length() - 1] == rep->s[ii]) {
972                         int t = rep->sz - 2;
973                         size_type l = ii - 1;
974                         for (; t >= 0; --t, --l) {
975                                 if (a[t] != rep->s[l]) break;
976                         }
977                         if (a[t] == rep->s[l]) return l;
978                 }
979         } while(ii-- > 0);
980         return npos;
981 }
982
983
984 lyxstring::size_type lyxstring::rfind(value_type const * ptr, size_type i,
985                                       size_type n) const
986 {
987         Assert(ptr); // OURS!
988         TestlyxstringInvariant(this);
989         if (!*ptr) return npos;
990
991         size_type ii = min(rep->sz - 1, i);
992         do {
993                 if (ptr[n - 1] == rep->s[ii]) {
994                         int t = n - 2;
995                         size_type l = ii - 1;
996                         for (; t >= 0; --t, --l) {
997                                 if (ptr[t] != rep->s[l]) break;
998                         }
999                         if (ptr[t] == rep->s[l]) return l;
1000                 }
1001         } while (ii-- > 0);
1002         return npos;
1003 }
1004
1005
1006 lyxstring::size_type lyxstring::rfind(value_type const * ptr,
1007                                       size_type i) const
1008 {
1009         Assert(ptr); // OURS!
1010         TestlyxstringInvariant(this);
1011         if (!*ptr) return npos;
1012
1013         size_type ii = min(rep->sz - 1, i);
1014         do {
1015                 if (ptr[strlen(ptr) - 1] == rep->s[ii]) {
1016                         int t = strlen(ptr) - 2;
1017                         size_type l = ii - 1;
1018                         for (; t >= 0; --t, --l) {
1019                                 if (ptr[t] != rep->s[l]) break;
1020                         }
1021                         if (ptr[t] == rep->s[l]) return l;
1022                 }
1023         } while (ii-- > 0);
1024         return npos;
1025 }
1026
1027
1028 lyxstring::size_type lyxstring::rfind(value_type c, size_type i) const
1029 {
1030         TestlyxstringInvariant(this);
1031
1032         size_type const sz = rep->sz;
1033         if (sz < 1) return npos;
1034         size_type ii = min(sz - 1, i);
1035         do {
1036                 if (rep->s[ii] == c) return ii;
1037         } while (ii-- > 0);
1038         return npos;
1039 }
1040
1041
1042 lyxstring::size_type lyxstring::find_first_of(lyxstring const & a,
1043                                               size_type i) const
1044 {
1045         Assert(i < rep->sz); // OURS!
1046         TestlyxstringInvariant(this);
1047
1048         for (size_type t = i; t < rep->sz; ++t) {
1049                 if (a.find(rep->s[t]) != npos) return t;
1050         }
1051         return npos;
1052 }
1053
1054
1055 lyxstring::size_type lyxstring::find_first_of(value_type const * ptr,
1056                                               size_type i,
1057                                               size_type n) const
1058 {
1059         Assert(ptr && i < rep->sz); // OURS!
1060         TestlyxstringInvariant(this);
1061         if (!n) return npos;
1062
1063         for (size_type t = i; t < rep->sz; ++t) {
1064                 if (memchr(ptr, rep->s[t], n) != 0) return t;
1065         }
1066         return npos;
1067 }
1068
1069
1070 lyxstring::size_type lyxstring::find_first_of(value_type const * ptr,
1071                                               size_type i) const
1072 {
1073         Assert(ptr && i < rep->sz); // OURS!
1074         TestlyxstringInvariant(this);
1075
1076         for (size_type t = i; t < rep->sz; ++t) {
1077                 if (strchr(ptr, rep->s[t]) != 0) return t;
1078         }
1079         return npos;
1080 }
1081
1082
1083 lyxstring::size_type lyxstring::find_first_of(value_type c, size_type i) const
1084 {
1085         Assert(i < rep->sz); // OURS!
1086         TestlyxstringInvariant(this);
1087
1088         for (size_type t = i; t < rep->sz; ++t) {
1089                 if (rep->s[t] == c) return t;
1090         }
1091         return npos;
1092 }
1093
1094
1095 lyxstring::size_type lyxstring::find_last_of(lyxstring const & a,
1096                                              size_type i) const
1097 {
1098         TestlyxstringInvariant(this);
1099
1100         size_type ii = min(rep->sz - 1, i);
1101         for (int t = ii; t >= 0; --t) {
1102                 if (a.find(rep->s[t]) != npos) return t;
1103         }
1104         return npos;
1105 }
1106
1107
1108 lyxstring::size_type lyxstring::find_last_of(value_type const * ptr,
1109                                              size_type i,
1110                                              size_type n) const
1111 {
1112         Assert(ptr); // OURS!
1113         TestlyxstringInvariant(this);
1114         if (!n) return npos;
1115
1116         size_type ii = min(rep->sz - 1, i);
1117         for (int t = ii; t >= 0; --t) {
1118                 if (memchr(ptr, rep->s[t], n) != 0) return t;
1119         }
1120         return npos;
1121 }
1122
1123
1124 lyxstring::size_type lyxstring::find_last_of(value_type const * ptr,
1125                                              size_type i) const
1126 {
1127         Assert(ptr); // OURS!
1128         TestlyxstringInvariant(this);
1129
1130         size_type ii = min(rep->sz - 1, i);
1131         for (int t = ii; t >= 0; --t) {
1132                 if (strchr(ptr, rep->s[t]) != 0) return t;
1133         }
1134         return npos;
1135 }
1136
1137
1138 lyxstring::size_type lyxstring::find_last_of(value_type c, size_type i) const
1139 {
1140         TestlyxstringInvariant(this);
1141
1142         if (!rep->sz) return npos;
1143         size_type ii = min(rep->sz - 1, i);
1144         for (int t = ii; t >= 0; --t) {
1145                 if (rep->s[t] == c) return t;
1146         }
1147         return npos;
1148 }
1149
1150
1151 lyxstring::size_type lyxstring::find_first_not_of(lyxstring const & a,
1152                                                   size_type i) const
1153 {
1154         TestlyxstringInvariant(this);
1155
1156         if (!rep->sz) return npos;
1157         Assert(i < rep->sz);
1158         for (size_type t = i; t < rep->sz; ++t) {
1159                 if (a.find(rep->s[t]) == npos) return t;
1160         }
1161         return npos;
1162 }
1163
1164
1165 lyxstring::size_type lyxstring::find_first_not_of(value_type const * ptr,
1166                                                   size_type i,
1167                                                   size_type n) const
1168 {
1169         Assert(ptr && i < rep->sz); // OURS!
1170         TestlyxstringInvariant(this);
1171
1172         if (!n) return (i < rep->sz) ? i : npos;
1173         for (size_type t = i; t < rep->sz; ++t) {
1174                 if (memchr(ptr, rep->s[t], n) == 0) return t;
1175         }
1176         return npos;
1177 }
1178
1179
1180 lyxstring::size_type lyxstring::find_first_not_of(value_type const * ptr,
1181                                                   size_type i) const
1182 {
1183         Assert(ptr && i < rep->sz); // OURS!
1184         TestlyxstringInvariant(this);
1185
1186         for (size_type t = i; t < rep->sz; ++t) {
1187                 if (strchr(ptr, rep->s[t]) == 0) return t;
1188         }
1189         return npos;
1190 }
1191
1192
1193 lyxstring::size_type lyxstring::find_first_not_of(value_type c,
1194                                                   size_type i) const
1195 {
1196         if (!rep->sz) return npos;
1197         Assert(i < rep->sz); // OURS!
1198         TestlyxstringInvariant(this);
1199
1200         for (size_type t = i; t < rep->sz; ++t) {
1201                 if (rep->s[t] != c) return t;
1202         }
1203         return npos;
1204 }
1205
1206
1207 lyxstring::size_type lyxstring::find_last_not_of(lyxstring const & a,
1208                                                  size_type i) const
1209 {
1210         TestlyxstringInvariant(this);
1211
1212         size_type ii = min(rep->sz - 1, i);
1213         for (int t = ii; t >= 0; --t) {
1214                 if (a.find(rep->s[t]) == npos) return t;
1215         }
1216         return npos;
1217 }
1218
1219
1220 lyxstring::size_type lyxstring::find_last_not_of(value_type const * ptr,
1221                                                  size_type i,
1222                                                  size_type n) const
1223 {
1224         Assert(ptr); // OURS!
1225         TestlyxstringInvariant(this);
1226
1227         if (!n) return npos;
1228         size_type ii = min(rep->sz - 1, i);
1229
1230         for (int t = ii; t >= 0; --t) {
1231                 if (memchr(ptr, rep->s[t], n) == 0) 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) const
1239 {
1240         Assert(ptr); // OURS!
1241         TestlyxstringInvariant(this);
1242
1243         size_type ii = min(rep->sz - 1, i);
1244         for (int t = ii; t >= 0; --t) {
1245                 if (strchr(ptr, rep->s[t]) == 0) return t;
1246         }
1247         return npos;
1248 }
1249
1250
1251 lyxstring::size_type lyxstring::find_last_not_of(value_type c,
1252                                                  size_type i) const
1253 {
1254         TestlyxstringInvariant(this);
1255
1256         size_type ii = min(rep->sz - 1, i);
1257         for (int t = ii; t >= 0; --t) {
1258                 if (rep->s[t] != c) return t;
1259         }
1260         return npos;
1261 }
1262
1263
1264 /////////////////
1265 // Replace
1266 /////////////////
1267
1268 lyxstring & lyxstring::replace(size_type i, size_type n, lyxstring const & x)
1269 {
1270         Assert(i <= rep->sz); // OURS!
1271         TestlyxstringInvariant(this);
1272
1273         return replace(i, n, x, 0, x.rep->sz);
1274 }
1275
1276
1277 lyxstring & lyxstring::replace(size_type i, size_type n, lyxstring const & x,
1278                                size_type i2, size_type n2)
1279 {
1280         Assert(i <= rep->sz && i2 <= x.rep->sz); // STD!
1281         TestlyxstringInvariant(this);
1282
1283         rep = rep->get_own_copy();
1284         rep->replace(i, min(n, rep->sz), &(x.rep->s[i2]), min(n2, x.rep->sz));
1285         return *this;
1286 }
1287
1288
1289 lyxstring & lyxstring::replace(size_type i, size_type n,
1290                                value_type const * p, size_type n2)
1291 {
1292         Assert(p && i < rep->sz); // OURS!
1293         TestlyxstringInvariant(this);
1294
1295         rep = rep->get_own_copy();
1296         rep->replace(i, min(n, rep->sz), p, min(n2, strlen(p)));
1297         return *this;
1298 }
1299
1300
1301 lyxstring & lyxstring::replace(size_type i, size_type n, value_type const * p)
1302 {
1303         Assert(p && i < rep->sz); // OURS!
1304         TestlyxstringInvariant(this);
1305
1306         return replace(i, min(n, rep->sz), p, (!p) ? 0 : strlen(p));
1307 }
1308
1309
1310 lyxstring & lyxstring::replace(size_type i, size_type n,
1311                                size_type n2, value_type c)
1312 {
1313         Assert(i <= rep->sz);  // OURS!
1314         TestlyxstringInvariant(this);
1315
1316         rep = rep->get_own_copy();
1317         value_type * tmp = new value_type[n2];
1318         memset(tmp, c, n2);
1319         rep->replace(i, min(n, rep->sz), tmp, n2);
1320         delete[] tmp;
1321         return *this;
1322 }
1323
1324
1325 lyxstring & lyxstring::replace(iterator i, iterator i2, const lyxstring & str)
1326 {
1327         TestlyxstringInvariant(this);
1328
1329         return replace(i - begin(), i2 - i, str); 
1330 }
1331
1332
1333 lyxstring & lyxstring::replace(iterator i, iterator i2,
1334                                value_type const * p, size_type n)
1335 {
1336         Assert(p); // OURS!
1337         TestlyxstringInvariant(this);
1338
1339         return replace(i - begin(), i2 - i, p, n);
1340 }
1341
1342
1343 lyxstring & lyxstring::replace(iterator i, iterator i2, value_type const * p)
1344 {
1345         Assert(p); // OURS!
1346         TestlyxstringInvariant(this);
1347
1348         return replace(i - begin(), i2 - i, p);
1349 }
1350
1351
1352 lyxstring & lyxstring::replace(iterator i, iterator i2,
1353                                size_type n , value_type c)
1354 {
1355         TestlyxstringInvariant(this);
1356
1357         return replace(i - begin(), i2 - i, n, c);
1358 }
1359         
1360
1361 lyxstring & lyxstring::replace(iterator i, iterator i2,
1362                                iterator j, iterator j2)
1363 {
1364         TestlyxstringInvariant(this);
1365
1366         return replace(i - begin(), i2 - i, j, j2 - j);
1367 }
1368
1369
1370 void lyxstring::swap(lyxstring & str)
1371 {
1372         if (rep == str.rep) return;
1373         Srep * tmp = str.rep;
1374         str.rep = rep;
1375         rep = tmp;
1376 }
1377
1378
1379 lyxstring & lyxstring::erase(size_type i, size_type n)
1380 {
1381         Assert(i <= rep->sz); // STD!
1382         TestlyxstringInvariant(this);
1383
1384         rep = rep->get_own_copy();
1385         if (i == 0 && n >= rep->sz) {
1386                 rep->sz = 0;
1387         } else {
1388                 n = min(n, rep->sz - i);
1389                 memmove(&(rep->s[i]), &(rep->s[i + n]), rep->sz - i - n);
1390                 rep->sz -= n;
1391         }
1392         return *this;
1393 }
1394
1395
1396 lyxstring::iterator lyxstring::erase(iterator i)
1397 {
1398         TestlyxstringInvariant(this);
1399
1400         // what iterator is this supposed to return?
1401         // the iterator after the one erased
1402         erase(i - begin(), 1);
1403         return begin(); // BUG
1404 }
1405
1406
1407 lyxstring::iterator lyxstring::erase(iterator first, iterator last)
1408 {
1409         TestlyxstringInvariant(this);
1410
1411         erase(first - begin(), last - first);
1412         return begin(); // BUG
1413 }
1414
1415
1416 /////////////////////////////////////
1417 // Conversion to C-style Strings
1418 /////////////////////////////////////
1419
1420 lyxstring::value_type const * lyxstring::c_str() const
1421 {
1422         rep->s[length()] = '\0';
1423         return rep->s;
1424 }
1425
1426
1427 lyxstring::value_type const * lyxstring::data() const
1428 {
1429         return rep->s;
1430 }
1431
1432
1433 lyxstring::size_type lyxstring::copy(value_type * buf, size_type len,
1434                                      size_type pos) const
1435 {
1436         Assert(buf); // OURS!
1437         Assert(pos <= rep->sz); // STD!
1438         TestlyxstringInvariant(this);
1439
1440         register int nn = min(len, length() - pos);
1441         memcpy(buf, &(rep->s[pos]), nn);
1442         return nn;
1443 }
1444
1445
1446 ////////////////////
1447 // Comparisons
1448 ////////////////////
1449
1450 // Compare funcs should be verified.
1451
1452 int lyxstring::internal_compare(size_type pos, size_type n,
1453                                 value_type const * s,
1454                                 size_type slen, size_type n2) const
1455 {
1456         if ((rep->sz == 0 || n == 0) && (!*s || n2 == 0)) return 0;
1457         if (!*s) return 1;
1458         // since n > n2, min(n, n2) == 0, c == 0 (stops segfault also)
1459
1460         // remember that n can very well be a lot larger than rep->sz
1461         // so we have to ensure that n is no larger than rep->sz
1462         n = min(n, rep->sz);
1463         n2 = min(n2, slen);
1464         if (n == n2)
1465                 return memcmp(&(rep->s[pos]), s, n);
1466         int c = memcmp(&(rep->s[pos]), s, min(n, n2));
1467         if (c)
1468                 return c;
1469         if (n < n2)
1470                 return -1;
1471         return 1;
1472 }
1473
1474
1475 int lyxstring::compare(lyxstring const & str) const
1476 {
1477         TestlyxstringInvariant(this);
1478         return internal_compare(0, rep->sz, str.rep->s,
1479                                 str.rep->sz, str.rep->sz);
1480 }
1481
1482
1483 int lyxstring::compare(value_type const * s) const
1484 {
1485         Assert(s); //OURS!
1486         TestlyxstringInvariant(this);
1487         int n = (!s) ? 0 : strlen(s);
1488         return internal_compare(0, rep->sz, s, n, n);
1489 }
1490
1491
1492 int lyxstring::compare(size_type pos, size_type n,
1493                        lyxstring const & str) const
1494 {
1495         Assert(pos <= rep->sz); // OURS!
1496         TestlyxstringInvariant(this);
1497         return internal_compare(pos, n, str.rep->s, str.rep->sz, str.rep->sz);
1498 }
1499
1500
1501 int lyxstring::compare(size_type pos, size_type n, lyxstring const & str,
1502                        size_type pos2, size_type n2) const
1503 {
1504         Assert(pos <= rep->sz); // OURS!
1505         Assert(pos2 <= str.rep->sz); // OURS!
1506         TestlyxstringInvariant(this);
1507         return internal_compare(pos, n,
1508                                 str.rep->s + pos2,
1509                                 str.rep->sz - pos2, n2);
1510 }
1511
1512
1513 int lyxstring::compare(size_type pos, size_type n, value_type const * s,
1514                        size_type n2) const
1515 {
1516         Assert(s && pos <= rep->sz); // OURS!
1517         TestlyxstringInvariant(this);
1518         return internal_compare(pos, n, s, (!s) ? 0 : strlen(s), n2);
1519 }
1520
1521
1522 /////////////////
1523 // Substrings
1524 /////////////////
1525
1526 // i = index, n = length
1527 lyxstring lyxstring::substr(size_type i, size_type n) const
1528 {
1529         Assert(i <= rep->sz); // STD!
1530         TestlyxstringInvariant(this);
1531
1532         return lyxstring(*this, i, n);
1533 }
1534
1535
1536 /////////////////////////////////////////////
1537 // String operators, non member functions
1538 /////////////////////////////////////////////
1539
1540 bool operator==(lyxstring const & a, lyxstring const & b)
1541 {
1542         return a.compare(b) == 0;
1543 }
1544
1545
1546 bool operator==(lyxstring::value_type const * a, lyxstring const & b)
1547 {
1548         Assert(a); // OURS!
1549         return b.compare(a) == 0;
1550 }
1551
1552
1553 bool operator==(lyxstring const & a, lyxstring::value_type const * b)
1554 {
1555         Assert(b); // OURS!
1556         return a.compare(b) == 0;
1557 }
1558
1559
1560 bool operator!=(lyxstring const & a, lyxstring const & b)
1561 {
1562         return a.compare(b) != 0;
1563 }
1564
1565
1566 bool operator!=(lyxstring::value_type const * a, lyxstring const & b)
1567 {
1568         Assert(a); // OURS!
1569         return b.compare(a) != 0;
1570 }
1571
1572
1573 bool operator!=(lyxstring const & a, lyxstring::value_type const * b)
1574 {
1575         Assert(b); // OURS!
1576         return a.compare(b) != 0;
1577 }
1578
1579
1580 bool operator>(lyxstring const & a, lyxstring const & b)
1581 {
1582         return a.compare(b) > 0;
1583 }
1584
1585
1586 bool operator>(lyxstring::value_type const * a, lyxstring const & b)
1587 {
1588         Assert(a); // OURS!
1589         return b.compare(a) < 0; // since we reverse the parameters
1590 }
1591
1592
1593 bool operator>(lyxstring const & a, lyxstring::value_type const * b)
1594 {
1595         Assert(b); // OURS!
1596         return a.compare(b) > 0;
1597 }
1598
1599
1600 bool operator<(lyxstring const & a, lyxstring const & b)
1601 {
1602         return a.compare(b) < 0;
1603 }
1604
1605
1606 bool operator<(lyxstring::value_type const * a, lyxstring const & b)
1607 {
1608         Assert(a); // OURS!
1609         return b.compare(a) > 0; // since we reverse the parameters
1610 }
1611
1612
1613 bool operator<(lyxstring const & a, lyxstring::value_type const * b)
1614 {
1615         Assert(b); // OURS!
1616         return a.compare(b) < 0;
1617 }
1618
1619
1620 bool operator>=(lyxstring const & a, lyxstring const & b)
1621 {
1622         return a.compare(b) >= 0;
1623 }
1624
1625
1626 bool operator>=(lyxstring::value_type const * a, lyxstring const & b)
1627 {
1628         Assert(a); // OURS!
1629         return b.compare(a) <= 0; // since we reverse the parameters
1630 }
1631
1632
1633 bool operator>=(lyxstring const & a, lyxstring::value_type const * b)
1634 {
1635         Assert(b); // OURS!
1636         return a.compare(b) >= 0;
1637 }
1638
1639
1640 bool operator<=(lyxstring const & a, lyxstring const & b)
1641 {
1642         return a.compare(b) <= 0;
1643 }
1644
1645
1646 bool operator<=(lyxstring::value_type const * a, lyxstring const & b)
1647 {
1648         Assert(a); // OURS!
1649         return b.compare(a) >= 0; // since we reverse the parameters
1650 }
1651
1652
1653 bool operator<=(lyxstring const & a, lyxstring::value_type const * b)
1654 {
1655         Assert(b); // OURS!
1656         return a.compare(b) <= 0;
1657 }
1658
1659
1660 lyxstring operator+(lyxstring const & a, lyxstring const & b)
1661 {
1662         lyxstring tmp(a);
1663         tmp += b;
1664         return tmp;
1665 }
1666
1667
1668 lyxstring operator+(lyxstring::value_type const * a, lyxstring const & b)
1669 {
1670         Assert(a); // OURS!
1671         lyxstring tmp(a);
1672         tmp += b;
1673         return tmp;
1674 }
1675
1676
1677 lyxstring operator+(lyxstring::value_type a, lyxstring const & b)
1678 {
1679         lyxstring tmp;
1680         tmp += a;
1681         tmp += b;
1682         return tmp;
1683 }
1684
1685
1686 lyxstring operator+(lyxstring const & a, lyxstring::value_type const * b)
1687 {
1688         Assert(b); // OURS!
1689         lyxstring tmp(a);
1690         tmp += b;
1691         return tmp;
1692 }
1693
1694
1695 lyxstring operator+(lyxstring const & a, lyxstring::value_type b)
1696 {
1697         lyxstring tmp(a);
1698         tmp += b;
1699         return tmp;
1700 }
1701
1702
1703 void swap(lyxstring & str1, lyxstring & str2)
1704 {
1705         str1.swap(str2);
1706 }
1707
1708
1709 #include <iostream>
1710
1711 istream & operator>>(istream & is, lyxstring & s)
1712 {
1713 #if 1
1714         // very bad solution
1715         char * nome = new char[1024];
1716         is >> nome;
1717         lyxstring tmp(nome);
1718         delete [] nome;
1719         if (!tmp.empty()) s = tmp;
1720 #else
1721         // better solution
1722         int w = is.widdth(0);
1723         s.clear();
1724         char c = 0;
1725         while (is.get(c)) {
1726                 if (isspace(c)) { is.putback(c); break; }
1727                 s += c;
1728                 if (--w == 1) break;
1729         }
1730         if (s.empty()) is.setstate(ios::failbit);
1731 #endif
1732         return is;
1733 }
1734
1735
1736 ostream & operator<<(ostream & o, lyxstring const & s)
1737 {
1738         return o.write(s.data(), s.length());
1739 }
1740
1741
1742 istream & getline(istream & is, lyxstring & s,
1743                   lyxstring::value_type delim)
1744 {
1745         // very bad solution
1746         char tmp = 0;
1747         s.erase();
1748         while(is) {
1749                 is.get(tmp);
1750                 if (tmp != delim) {
1751                         s += tmp;
1752                 } else {
1753                         break;
1754                 }
1755         }
1756         return is;
1757 }