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