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