source: main/tags/2.51-jcdl/gsdl/lib/text_t.cpp@ 33234

Last change on this file since 33234 was 7382, checked in by mdewsnip, 20 years ago

(Human Info) Added const text_t g_EmptyText("") to use instead of plain ol' "".

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 19.3 KB
Line 
1/**********************************************************************
2 *
3 * text_t.cpp -- a simple 16-bit character string class
4 * Copyright (C) 1999 The New Zealand Digital Library Project
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 * $Id: text_t.cpp 7382 2004-05-24 03:44:50Z mdewsnip $
25 *
26 *********************************************************************/
27
28/*
29 $Log$
30 Revision 1.22 2004/05/24 03:43:22 mdewsnip
31 (Human Info) Added const text_t g_EmptyText("") to use instead of plain ol' "".
32
33 Revision 1.21 2001/06/01 02:51:28 sjboddie
34 Changes to get phind working under windows
35
36 Revision 1.20 2001/01/25 18:26:44 cs025
37 Included CORBA branch for first time
38
39 Revision 1.15.2.2 2000/04/05 10:19:38 syeates
40 added automatic conversion to allow text_t's to be <<'ed to ostreams
41
42 Revision 1.15.2.1 2000/04/04 15:02:29 cs025
43 Corba first commit
44
45 Revision 1.15 1999/10/14 22:52:39 sjboddie
46 joinchar can join using text_t string now too
47
48 Revision 1.14 1999/09/24 02:30:03 rjmcnab
49 added function has_unicode_letdig
50
51 Revision 1.13 1999/09/07 04:57:43 sjboddie
52 added gpl notice
53
54 Revision 1.12 1999/08/31 08:04:41 rjmcnab
55 Fixed a small but hard to find bug in getcarr
56
57 Revision 1.11 1999/07/01 04:05:09 rjmcnab
58 Optimised append functions slightly and added a reserve function.
59
60 Revision 1.10 1999/04/26 03:58:03 sjboddie
61 added is_number function
62
63 Revision 1.9 1999/04/06 22:17:24 rjmcnab
64 Added splits and joins using text_tset.
65
66 Revision 1.8 1999/02/28 23:14:41 rjmcnab
67
68 Added uc and lc to convert to uppercase and lowercase.
69
70 Revision 1.7 1999/02/21 22:26:39 rjmcnab
71
72 Made getint() a constant function.
73
74 Revision 1.6 1999/02/03 01:13:26 sjboddie
75
76 Got interface to handle subcollections and language subcollections -
77 committed changes made to some of the collections
78
79 Revision 1.5 1999/01/19 01:38:14 rjmcnab
80
81 Made the source more portable.
82
83 Revision 1.4 1999/01/12 01:51:00 rjmcnab
84
85 Standard header.
86
87 Revision 1.3 1999/01/08 02:33:16 rjmcnab
88
89 Added standard header to source files.
90
91 */
92
93#include "text_t.h"
94
95#if defined(GSDL_USE_OBJECTSPACE)
96# include <ospace\std\algorithm>
97#elif defined(GSDL_USE_STL_H)
98# if defined(GSDL_USE_ALGO_H)
99# include <algo.h>
100# else
101# include <algorithm.h>
102# endif
103#else
104# include <algorithm>
105#endif
106
107#ifdef HAVE_CONFIG_H
108# ifdef __WIN32__
109# include "WIN32cfg.h"
110# else
111# include "config.h"
112# endif
113#endif
114
115
116#include "unitool.h"
117
118const text_t g_EmptyText("");
119
120////////////////////////////////////
121// text_t methods
122////////////////////////////////////
123
124// new stream converter ...
125ostream& operator<< (ostream &o, const text_t text)
126{
127 text_t::const_iterator ithere = text.begin();
128 text_t::const_iterator itend = text.end();
129
130 while (ithere != itend)
131 {
132 if (*ithere < 256)
133 {
134 o << (unsigned char)(*ithere);
135 }
136 else
137 {
138 // put a space or a question mark depending on what
139 // the character is. Question marks tell the user that
140 // they are missing some information.
141 if (is_unicode_space (*ithere))
142 o << ' ';
143 else
144 o << '?';
145 }
146 ithere++;
147 }
148
149 return o;
150}
151
152text_t::text_t ()
153{
154 setencoding(0);
155 clear ();
156}
157
158text_t::text_t (int i)
159{
160 setencoding(0);
161 clear ();
162 appendint (i);
163}
164
165text_t::text_t (char *s)
166{
167 setencoding(0);
168 clear ();
169 appendcstr (s);
170}
171
172
173void text_t::append (const text_t &t)
174{
175 text.insert(text.end(), t.begin(), t.end());
176 // const_iterator here, end=t.end();
177 // for (here=t.begin(); here!=end;here++)
178 // {
179 // text.push_back(*here);
180 // }
181}
182
183void text_t::appendrange (iterator first, iterator last)
184{
185 text.insert(text.end(), first, last);
186 // while (first != last)
187 // {
188 // text.push_back (*first);
189 // first++;
190 // }
191}
192
193void text_t::appendrange (const_iterator first, const_iterator last)
194{
195 text.insert(text.end(), first, last);
196 // while (first != last)
197 // {
198 // text.push_back (*first);
199 // first++;
200 // }
201}
202
203void text_t::appendint (int i)
204{
205 // deal with zeros and negatives
206 if (i == 0)
207 {
208 text.push_back('0');
209 return;
210 }
211 else if (i < 0)
212 {
213 text.push_back('-');
214 i *= -1;
215 }
216
217 // get a buffer for the conversion
218 int maxbuflen = sizeof(int)*3;
219 char *buf = new char[maxbuflen];
220 int len = 0;
221
222 // get the number in reverse
223 while (i > 0)
224 {
225 buf[len++] = '0'+ (i%10);
226 i = i/10;
227 }
228
229 // reverse the number
230 while (len > 0)
231 {
232 text.push_back(buf[--len]);
233 }
234
235 delete buf;
236}
237
238int text_t::getint () const
239{
240 int i = 0;
241 int mult = 1; // become -1 for negative numbers
242
243 const_iterator here = text.begin();
244 const_iterator end = text.end();
245
246 // do plus and minus signs
247 if (here != end)
248 {
249 if (*here == '-')
250 {
251 mult = -1;
252 here++;
253 }
254 else if (*here == '+')
255 {
256 mult = 1;
257 here++;
258 }
259 }
260
261 // deal with the number
262 while ((here != end) && (*here >= '0') && (*here <= '9'))
263 {
264 i = 10*i + (*here - '0');
265 here++;
266 }
267
268 i *= mult;
269 return i;
270}
271
272unsigned long text_t::getulong () const
273{
274 unsigned long i = 0;
275
276 const_iterator here = text.begin();
277 const_iterator end = text.end();
278
279 while ((here != end) && (*here >= '0') && (*here <= '9'))
280 {
281 i = 10*i + (*here - '0');
282 here++;
283 }
284
285 return i;
286}
287
288void text_t::appendcarr (char *s, size_type len)
289{
290 unsigned char *us = (unsigned char *)s;
291 while (len > 0)
292 {
293 text.push_back (*us); // append this character
294 us++;
295 len--;
296 }
297}
298
299void text_t::appendcstr (char *s)
300{
301 unsigned char *us = (unsigned char *)s;
302 while (*us != '\0')
303 {
304 text.push_back (*us); // append this character
305 us++;
306 }
307}
308
309
310// strings returned from getcarr and getcstr become the callers
311// responsibility and should be deallocated with "delete"
312
313char *text_t::getcarr(size_type &len) const
314{
315 unsigned char *cstr = new unsigned char[size()];
316 len = 0;
317
318 const_iterator ithere = begin();
319 const_iterator itend = end();
320 while (ithere != itend)
321 {
322 if (*ithere < 256) cstr[len] = (unsigned char)(*ithere);
323 else {
324 // put a space or a question mark depending on what
325 // the character is. Question marks tell the user that
326 // they are missing some information.
327 if (is_unicode_space (*ithere)) cstr[len] = ' ';
328 else cstr[len] = '?';
329 }
330 len++;
331 ithere++;
332 }
333
334 return (char *)cstr;
335}
336
337char *text_t::getcstr() const
338{
339 unsigned char *cstr = new unsigned char[size() + 1];
340 const_iterator ithere = begin();
341 const_iterator itend = end();
342 int len = 0;
343
344 while (ithere != itend)
345 {
346 if (*ithere < 256) cstr[len] = (unsigned char)(*ithere);
347 else {
348 // put a space or a question mark depending on what
349 // the character is. Question marks tell the user that
350 // they are missing some information.
351 if (is_unicode_space (*ithere)) cstr[len] = ' ';
352 else cstr[len] = '?';
353 }
354 len++;
355 ithere++;
356 }
357
358 cstr[len] = '\0';
359
360 return (char *)cstr;
361}
362
363
364// general functions which work on text_ts
365
366// find a character within a range
367text_t::const_iterator findchar (text_t::const_iterator first, text_t::const_iterator last,
368 unsigned short c)
369{
370 while (first != last)
371 {
372 if (*first == c) break;
373 first++;
374 }
375 return first;
376}
377
378text_t::iterator findchar (text_t::iterator first, text_t::iterator last,
379 unsigned short c)
380{
381 while (first != last)
382 {
383 if (*first == c) break;
384 first++;
385 }
386 return first;
387}
388
389text_t::iterator findword (text_t::iterator first, text_t::iterator last,
390 const text_t& word)
391{
392 text_t::const_iterator word_begin = word.begin();
393 text_t::const_iterator word_end = word.end();
394
395 while (first != last)
396 {
397 text_t::iterator char_match = first;
398 text_t::const_iterator word_here = word_begin;
399 while (word_here!=word_end)
400 {
401 if (*char_match != *word_here)
402 {
403 break;
404 }
405 char_match++;
406 word_here++;
407 }
408 if (word_here==word_end)
409 {
410 return first;
411 }
412 first++;
413 }
414 return last; // get to here only if there is no match
415}
416
417// get a string up to the next delimiter (which is skipped)
418text_t::const_iterator getdelimitstr (text_t::const_iterator first,
419 text_t::const_iterator last,
420 unsigned short c, text_t &outstr)
421{
422 text_t::const_iterator here = first;
423 here = findchar (first, last, c);
424 outstr.clear();
425 outstr.appendrange (first, here);
426 if (here != last) here++; // skip c
427 return here;
428}
429
430text_t::iterator getdelimitstr (text_t::iterator first, text_t::iterator last,
431 unsigned short c, text_t &outstr)
432{
433 text_t::iterator here = first;
434 here = findchar (first, last, c);
435 outstr.clear();
436 outstr.appendrange (first, here);
437 if (here != last) here++; // skip c
438 return here;
439}
440
441// split a string with a character
442void splitchar (text_t::const_iterator first, text_t::const_iterator last,
443 unsigned short c, text_tset &outlist)
444{
445 outlist.erase(outlist.begin(), outlist.end());
446
447 text_t t;
448
449 while (first != last)
450 {
451 first = getdelimitstr (first, last, c, t);
452 outlist.insert (t);
453 }
454}
455
456void splitchar (text_t::const_iterator first, text_t::const_iterator last,
457 unsigned short c, text_tlist &outlist)
458{
459 outlist.erase(outlist.begin(), outlist.end());
460
461 text_t t;
462
463 while (first != last)
464 {
465 first = getdelimitstr (first, last, c, t);
466 outlist.push_back (t);
467 }
468}
469
470void splitchar (text_t::const_iterator first, text_t::const_iterator last,
471 unsigned short c, text_tarray &outlist)
472{
473 outlist.erase(outlist.begin(), outlist.end());
474
475 text_t t;
476
477 while (first != last)
478 {
479 first = getdelimitstr (first, last, c, t);
480 outlist.push_back (t);
481 }
482}
483
484// join a string using a character
485void joinchar (const text_tset &inlist, unsigned short c, text_t &outtext)
486{
487 outtext.clear ();
488
489 text_tset::const_iterator here = inlist.begin ();
490 text_tset::const_iterator end = inlist.end ();
491 bool first = true;
492 while (here != end)
493 {
494 if (!first) outtext.push_back (c);
495 first = false;
496 outtext += *here;
497 here++;
498 }
499}
500
501void joinchar (const text_tlist &inlist, unsigned short c, text_t &outtext)
502{
503 outtext.clear ();
504
505 text_tlist::const_iterator here = inlist.begin ();
506 text_tlist::const_iterator end = inlist.end ();
507 bool first = true;
508 while (here != end)
509 {
510 if (!first) outtext.push_back (c);
511 first = false;
512 outtext += *here;
513 here++;
514 }
515}
516
517void joinchar (const text_tarray &inlist, unsigned short c, text_t &outtext)
518{
519 outtext.clear ();
520
521 text_tarray::const_iterator here = inlist.begin ();
522 text_tarray::const_iterator end = inlist.end ();
523 bool first = true;
524 while (here != end)
525 {
526 if (!first) outtext.push_back (c);
527 first = false;
528 outtext += *here;
529 here++;
530 }
531}
532
533void joinchar (const text_tlist &inlist, text_t c, text_t &outtext)
534{
535 outtext.clear ();
536
537 text_tlist::const_iterator here = inlist.begin ();
538 text_tlist::const_iterator end = inlist.end ();
539 bool first = true;
540 while (here != end)
541 {
542 if (!first) outtext += c;
543 first = false;
544 outtext += *here;
545 here++;
546 }
547}
548
549void joinchar (const text_tset &inlist, text_t c, text_t &outtext)
550{
551 outtext.clear ();
552
553 text_tset::const_iterator here = inlist.begin ();
554 text_tset::const_iterator end = inlist.end ();
555 bool first = true;
556 while (here != end)
557 {
558 if (!first) outtext += c;
559 first = false;
560 outtext += *here;
561 here++;
562 }
563}
564
565void joinchar (const text_tarray &inlist, text_t c, text_t &outtext)
566{
567 outtext.clear ();
568
569 text_tarray::const_iterator here = inlist.begin ();
570 text_tarray::const_iterator end = inlist.end ();
571 bool first = true;
572 while (here != end)
573 {
574 if (!first) outtext += c;
575 first = false;
576 outtext += *here;
577 here++;
578 }
579}
580
581// count the occurances of a character within a range
582int countchar (text_t::const_iterator first, text_t::const_iterator last,
583 unsigned short c)
584{
585 int count = 0;
586 while (first != last) {
587 if (*first == c) count ++;
588 first ++;
589 }
590 return count;
591}
592
593// return a substring of string from first up to but not including last
594text_t substr (text_t::const_iterator first, text_t::const_iterator last) {
595
596 text_t substr;
597 while (first != last) {
598 substr.push_back(*first);
599 first ++;
600 }
601 return substr;
602}
603
604
605// convert to lowercase
606void lc (text_t::iterator first, text_t::iterator last) {
607 while (first != last) {
608 *first = unicode_tolower(*first);
609 first++;
610 }
611}
612
613// convert to uppercase
614void uc (text_t::iterator first, text_t::iterator last) {
615 while (first != last) {
616 *first = unicode_toupper(*first);
617 first++;
618 }
619}
620
621
622// checks to see if it is a number (i.e. contains only 0-9)
623bool is_number (const text_t &text) {
624
625 text_t::const_iterator here = text.begin();
626 text_t::const_iterator end = text.end();
627
628 while (here != end) {
629 if ((*here!='0') && (*here!='1') && (*here!='2') &&
630 (*here!='3') && (*here!='4') && (*here!='5') &&
631 (*here!='6') && (*here!='7') && (*here!='8') &&
632 (*here!='9')) return false;
633 here ++;
634 }
635 return true;
636}
637
638
639// checks to see if the text has any letters or digits
640bool has_unicode_letdig (const text_t &text) {
641 if (text.empty()) return false;
642
643 text_t::const_iterator here = text.begin();
644 text_t::const_iterator end = text.end();
645 while (here != end) {
646 if (is_unicode_letdig (*here)) return true;
647 here++;
648 }
649
650 return false;
651}
652
653
654
655////////////////////////////////////
656// convertclass methods
657////////////////////////////////////
658
659// conversion classes used for getting information in to and out of
660// the text_t class.
661
662convertclass::convertclass ()
663{
664 // nothing to do
665}
666
667void convertclass::reset ()
668{
669 // nothing to do
670}
671
672
673////////////////////////////////////
674// inconvertclass methods
675////////////////////////////////////
676
677// convert from a char stream to the text_t class
678// the default version assumes the input is a ascii
679// character array
680
681inconvertclass::inconvertclass ()
682{
683 start = NULL;
684 len = 0;
685}
686
687
688void inconvertclass::reset ()
689{
690 start = NULL;
691 len = 0;
692}
693
694void inconvertclass::setinput (char *thestart, size_t thelen)
695{
696 start = thestart;
697 len = thelen;
698}
699
700void inconvertclass::convert (text_t &output, status_t &status)
701{
702 output.clear();
703
704 if (start == NULL || len == 0)
705 {
706 status = finished;
707 return;
708 }
709
710 // don't want any funny sign conversions happening
711 unsigned char *here = (unsigned char *)start;
712 while (len > 0)
713 {
714 output.push_back (*here); // append this character
715 ++here;
716 --len;
717 }
718
719 start = (char *)here; // save current position
720 status = finished;
721}
722
723// will treat the text_t as a 8-bit string and convert
724// it to a 16-bit string using the about convert method.
725text_t inconvertclass::convert (const text_t &t) {
726 text_t out;
727 text_t tmpout;
728 status_t status;
729 text_t::const_iterator here = t.begin();
730 text_t::const_iterator end = t.end();
731 unsigned char cbuf[256];
732 size_t cbuflen = 0;
733
734 while (here != end) {
735 while (here != end && cbuflen < 256) {
736 cbuf[cbuflen++] = (unsigned char)(*here & 0xff);
737 here++;
738 }
739
740 if (cbuflen > 0) {
741 setinput ((char *)cbuf, cbuflen);
742 status = unfinished;
743 while (status == unfinished) {
744 convert (tmpout, status);
745 out += tmpout;
746 }
747 cbuflen = 0;
748 }
749 }
750
751 out.setencoding (0); // unicode
752
753 return out;
754}
755
756// an instance of the default inconvertclass to do simple
757// conversions. Note that any functions that use this are
758// not reentrant. If a function needs to be reentrant it
759// should declare its own instance.
760inconvertclass ascii2text_t;
761
762
763////////////////////////////////////
764// outconvertclass methods
765////////////////////////////////////
766
767// Convert from a text_t class to a char stream
768// This default version assumes the output is a ascii
769// character array. If you set the output stream you
770// can use this class to output to a stream using the
771// << operator. The << operator can also be conveniently
772// used to set the output stream by doing something like
773//
774// cout << text_t2ascii << text_tstr << anothertext_tstr;
775//
776outconvertclass::outconvertclass ()
777{
778 input = NULL;
779 outs = NULL;
780}
781
782void outconvertclass::reset ()
783{
784 input = NULL;
785 outs = NULL;
786}
787
788void outconvertclass::setinput (text_t *theinput)
789{
790 input = theinput;
791 if (input != NULL) texthere = input->begin();
792}
793
794void outconvertclass::convert (char *output, size_t maxlen,
795 size_t &len, status_t &status)
796{
797 if (input == NULL || output == NULL)
798 {
799 status = finished;
800 return;
801 }
802
803 // don't want any funny sign conversions happening
804 unsigned char *uoutput = (unsigned char *)output;
805 text_t::iterator textend = input->end();
806 len = 0;
807 while ((len < maxlen) && (texthere != textend))
808 {
809 if (*texthere < 256) *uoutput = (unsigned char)(*texthere);
810 else {
811 // put a space or a question mark depending on what
812 // the character is. Question marks tell the user that
813 // they are missing some information.
814 if (is_unicode_space (*texthere)) *uoutput = ' ';
815 else *uoutput = '?';
816 }
817 ++uoutput;
818 ++len;
819 ++texthere;
820 }
821
822 if (texthere == textend) status = finished;
823 else status = unfinished;
824}
825
826// will convert the 16-bit string to a 8-bit stream
827// and place the result in a text_t. This method uses
828// the above convert function.
829text_t outconvertclass::convert (const text_t &t) {
830 text_t out;
831 unsigned char cbuf[256];
832 size_t cbuflen = 0;
833 status_t status = unfinished;
834
835 setinput ((text_t *)&t); // discard constant
836 while (status == unfinished) {
837 convert ((char *)cbuf, 256, cbuflen, status);
838 out.appendcarr ((char *)cbuf, cbuflen);
839 }
840
841 out.setencoding (1); // other encoding
842
843 return out;
844}
845
846
847void outconvertclass::setostream (ostream *theouts)
848{
849 outs = theouts;
850}
851
852ostream *outconvertclass::getostream ()
853{
854 return outs;
855}
856
857
858
859
860// an instance of the default outconvertclass to do simple
861// conversions
862outconvertclass text_t2ascii;
863
864
865
866// stream operators for the output class
867
868outconvertclass &operator<< (ostream &theouts, outconvertclass &outconverter)
869{
870 outconverter.setostream(&theouts);
871 return outconverter;
872}
873
874
875#define STREAMBUFSIZE 256
876outconvertclass &operator<< (outconvertclass &outconverter, const text_t &t)
877{
878 ostream *outstream = outconverter.getostream();
879
880 if (outstream == NULL) return outconverter;
881
882 char outbuf[STREAMBUFSIZE];
883 size_t len;
884 outconvertclass::status_t status = outconvertclass::unfinished;
885
886 // assume that there is no data needing converting
887 // left in the converter
888 outconverter.setinput ((text_t *)(&t)); // note the const -> nonconst conversion
889
890 while (status == outconvertclass::unfinished)
891 {
892 outconverter.convert (outbuf, STREAMBUFSIZE, len, status);
893 if (len > 0) outstream->write(outbuf, len);
894 }
895
896 return outconverter;
897}
Note: See TracBrowser for help on using the repository browser.