1 #include "config.h"
2
3 #include <iostream>
4 #include <string>
5 #include <cstdio>
6 #include <cctype>
7 #include <string.h>
8
9 #include "asserts.h"
10 #include "types.h"
11 #include "error.h"
12 #include "estring.h"
13
14 //----------------------------------------------------------------------------
15
estring_value()16 estring_value::estring_value()
17 {
18 clear();
19 }
20
clear(void)21 void estring_value::clear(void)
22 {
23 memset(static_cast<void*>(&value), 0, sizeof(value));
24 }
25
operator =(const estring_value & a_estring_value)26 estring_value& estring_value::operator=(const estring_value& a_estring_value)
27 {
28 value = a_estring_value.value;
29
30 return(*this);
31 }
32
33 //----------------------------------------------------------------------------
34
35 /** Alphabet used for base number conversions
36 */
37
38 const char * estring::m_alphabet = "0123456789abcdefghijklmnopqrstuvwxyz";
39
40 /** The length of the alphabet used for base number conversions
41 */
42 const size_t estring::m_alphabet_len = 36;
43
44 /** Helper member template function to convert an integral type to an estring.
45
46 Integrals are converted to string form using a default base of 10 unless
47 specified otherwise through the base() member function. For bases greater
48 than ten the letters of the alphabet are used, starting with 'a' for eleven,
49 'b' for twelve, etc.
50
51 Variables:
52 - a_t - the integral type. Usually uint8, uint16, uint32, or uint64.
53 - a_str - the std::string object in which to store the string converstion.
54
55 Exceptions:
56 - An err_nomem is thrown for memory allocation failure.
57 */
58 template <class T>
T_integral_to_string(const T & a_t,value_type & a_str)59 void estring::T_integral_to_string(const T& a_t, value_type& a_str)
60 {
61 T num = a_t;
62 int digit;
63 char ch;
64
65 ASSERT(a_t >= 0);
66 ASSERT(m_base >= 2);
67 ASSERT(m_base <= m_alphabet_len);
68
69 TRY_nomem(a_str = "");
70 if (a_t == 0) {
71 TRY_nomem(a_str = "0");
72 return;
73 }
74 while (num > 0) {
75 digit = num % m_base;
76 ch = m_alphabet[digit];
77 TRY_nomem(a_str = ch + a_str);
78 num /= m_base;
79 }
80 }
81
82 /** Helper member template function to convert a fractional type to an estring.
83
84 Fractions are converted to string form using a default base of 10 unless
85 specified otherwise through the base() member function. For bases greater
86 than ten the letters of the alphabet are used, starting with 'a' for eleven,
87 'b' for twelve, etc.
88
89 By default a precision of 1 digit to the right of the decimal point is used
90 unless specified otherwise by the precision() member function.
91
92 Variables:
93 - a_t - the fractional type: float or double.
94 - a_ws - the std::string object in which to store the whole part.
95 - a_fs - the std::string object in which to store the fractional part.
96
97 Exceptions:
98 - An err_nomem is thrown for memory allocation failure.
99 */
100 template <class T>
T_fraction_to_strings(const T & a_t,value_type & a_ws,value_type & a_fs)101 void estring::T_fraction_to_strings(const T& a_t,
102 value_type& a_ws, value_type& a_fs)
103 {
104 T fraction = a_t;
105 uint64 rounded;
106 bool negative = false;
107 uint64 whole_part;
108 uint64 fractional_part;
109 uint64 multiplier;
110 size_type c;
111 int digit;
112 char ch;
113
114 ASSERT(m_base >= 2);
115 ASSERT(m_base <= m_alphabet_len);
116
117 TRY_nomem(a_ws = "");
118 TRY_nomem(a_fs = "");
119
120 if (fraction < 0.0) {
121 negative = true;
122 fraction = -fraction;
123 }
124
125 multiplier = m_base;
126 for (c = 0; c < m_precision; c++) {
127 multiplier *= m_base;
128 }
129
130 rounded = static_cast<uint64>(fraction * multiplier);
131 fractional_part = rounded % multiplier;
132 whole_part = rounded / multiplier;
133
134 if ((fractional_part % m_base) + (m_base/2) >= m_base) {
135 fractional_part += m_base/2;
136 if (fractional_part > (fractional_part % multiplier)) {
137 whole_part++;
138 }
139 fractional_part %= multiplier;
140 }
141
142 if (whole_part == 0) {
143 TRY_nomem(a_ws = "0");
144 }
145 else {
146 while (whole_part > 0) {
147 digit = whole_part % m_base;
148 ch = m_alphabet[digit];
149 TRY_nomem(a_ws = ch + a_ws);
150 whole_part /= m_base;
151 }
152 }
153
154 fractional_part /= m_base;
155 if (fractional_part == 0) {
156 TRY_nomem(a_fs = "0");
157 }
158 else {
159 while (fractional_part > 0) {
160 digit = fractional_part % m_base;
161 ch = m_alphabet[digit];
162 TRY_nomem(a_fs = ch +a_fs);
163 fractional_part /= m_base;
164 }
165 }
166 if (a_fs.size() > m_precision) {
167 a_fs.erase(m_precision);
168 }
169 for (c = a_fs.size(); c < m_precision; c++) {
170 TRY_nomem(a_fs += "0");
171 }
172
173 if (negative) {
174 TRY_nomem(a_ws = "-" + a_ws);
175 }
176 }
177
178 /** Helper member template function to convert a string to an integral type.
179
180 Characters in the string are converted using a default base of 10 unless
181 specified otherwise through the base() member function. For bases greater
182 than ten the letters of the alphabet will be assumed, starting with 'a' for
183 eleven, 'b' for twelve, etc.
184
185 Variables:
186 - a_str - the std::string object from which to convert.
187 - a_t - a variable of the integral type to which to convert.
188
189 Exceptions:
190 - An err_nomem is thrown for memory allocation failure.
191 - If a symbol is encountered in the string that is not expected then an
192 invalid character or invalid base error is thrown.
193 - If the type to which to convert the string is not large enough to hold
194 the value of the converted string then an overflow error is thrown.
195 */
196 template<class T>
T_string_to_integral(const value_type & a_str,T & a_t) const197 void estring::T_string_to_integral(const value_type& a_str, T& a_t) const
198 {
199 value_type::const_iterator stri;
200 T value = 0;
201 T digit = 0;
202 T overflow_check_1 = 0;
203 T overflow_check_2 = 0;
204 value_type es;
205 value_type alphabet;
206 size_type idx;
207 const static size_t buffer_len = 256;
208 char buffer[buffer_len] = { 0 };
209 unsigned int index;
210
211 ASSERT(m_base >= 2);
212 ASSERT(m_base <= m_alphabet_len);
213
214 TRY_nomem(alphabet = m_alphabet);
215 for (stri = a_str.begin(), index = 0;
216 stri != a_str.end();
217 ++stri, ++index
218 )
219 {
220 idx = alphabet.find(*stri);
221 if (idx > m_base) {
222 snprintf(buffer, buffer_len, "%u", index);
223
224 TRY_nomem(es = "Parse error at index ");
225 TRY_nomem(es += buffer);
226 TRY_nomem(es += " (char '");
227 TRY_nomem(es += *stri);
228 TRY_nomem(es += "')");
229 TRY_nomem(es += " converting \"");
230 TRY_nomem(es += (*this));
231 TRY_nomem(es += "\"");
232 if (idx == value_type::npos) {
233 TRY_nomem(es += ", invalid character");
234 }
235 else {
236 TRY_nomem(es += ", invalid base or invalid string");
237 }
238 throw(ERROR(0,es));
239 }
240
241 value *= m_base;
242 digit = static_cast<unsigned int>(idx);
243 value += digit;
244
245 overflow_check_1 *= m_base;
246 overflow_check_1 += 1;
247 if (overflow_check_1 == overflow_check_2) {
248 snprintf(buffer, buffer_len, "%u", index);
249
250 TRY_nomem(es = "Overflow error at index ");
251 TRY_nomem(es += buffer);
252 TRY_nomem(es += " (char '");
253 TRY_nomem(es += *stri);
254 TRY_nomem(es += "')");
255 TRY_nomem(es += " converting \"");
256 TRY_nomem(es += (*this));
257 TRY_nomem(es += "\" to unsigned int");
258 throw(ERROR(0,es));
259 }
260 overflow_check_2 = overflow_check_1;
261 }
262 a_t = value;
263 }
264
265 /** Helper member template function to convert a string to a signed integral.
266
267 Variables:
268 - a_str - the std::string to convert from.
269 - a_t - a variable of the type to convert to.
270
271 Exceptions:
272 - An err_nomem is thrown for memory allocation failure.
273 - Any exception thrown from the called member template function
274 T_string_to_integral().
275 */
276 template <class T>
T_string_to_signed_integral(const value_type & a_str,T & a_t) const277 void estring::T_string_to_signed_integral(const value_type& a_str, T& a_t)
278 const
279 {
280 value_type tmp;
281 T value = 0;
282 bool negative = false;
283
284 if ((value_type::size() > 0) && (this->at(0) == '-')) {
285 negative = true;
286 TRY_nomem(tmp = (*this).substr(1));
287 }
288 else {
289 TRY_nomem(tmp = (*this));
290 }
291 T_string_to_integral(tmp,value);
292 if (negative)
293 value = -value;
294 a_t = value;
295 }
296
297 /** Helper member template function to convert a string to a fractional.
298
299 Variables:
300 - a_str - the std::string to convert from.
301 - a_t - a variable of the type to convert to.
302
303 Exceptions:
304 - An err_nomem is thrown for memory allocation failure.
305 - Any exception thrown by the member template function
306 T_string_to_integral().
307 - An overflow error is thrown if the wole part of the string is too large
308 for the type a_t.
309 - An underflow error is thrown if the fractional part of the string is too
310 large for the type a_t.
311 */
312 template <class T>
T_string_to_fractional(const value_type & a_str,T & a_t) const313 void estring::T_string_to_fractional(const value_type& a_str, T& a_t) const
314 {
315 value_type es;
316 value_type tmp;
317 value_type whole_string;
318 value_type fractional_string;
319 size_type idx = 0;
320 bool negative = false;;
321 uint64 whole_part_converter = 0;
322 uint64 fractional_part_converter = 0;
323 uint64 fractional_check = 0;
324 T whole_part = 0;
325 T fractional_part = 0;
326 T value =0;
327 unsigned int divisor = 0;
328 unsigned int c = 0;
329
330 ASSERT(m_base >= 2);
331 ASSERT(m_base <= m_alphabet_len);
332
333 if ((value_type::size() > 0) && (this->at(0) == '-')) {
334 negative = true;
335 TRY_nomem(tmp = (*this).substr(1));
336 }
337 else {
338 TRY_nomem(tmp = (*this));
339 }
340
341 idx = tmp.find('.');
342 if (idx != value_type::npos) {
343 TRY_nomem(whole_string = tmp.substr(0,idx));
344 TRY_nomem(fractional_string = tmp.substr(idx+1));
345 }
346 else {
347 TRY_nomem(whole_string = tmp);
348 TRY_nomem(fractional_string = "");
349 }
350
351 TRY_nomem(es = "Could not convert whole part of estring \"");
352 TRY_nomem(es += a_str);
353 TRY_nomem(es += "\"");
354 TRY(T_string_to_integral(whole_string, whole_part_converter),es);
355
356 TRY_nomem(es = "Could not convert fractional part of estring \"");
357 TRY_nomem(es += a_str);
358 TRY_nomem(es += "\"");
359 TRY(T_string_to_integral(fractional_string, fractional_part_converter),es);
360
361 divisor = 1;
362 for (c = 0; c < fractional_string.size(); c++)
363 divisor *= m_base;
364
365 whole_part = static_cast<T>(whole_part_converter);
366 if (static_cast<uint64>(whole_part) != whole_part_converter) {
367 TRY_nomem(es = "Overflow error converting whole part of estring \"");
368 TRY_nomem(es += a_str);
369 TRY_nomem(es += "\"");
370 throw(ERROR(0,es));
371 }
372 fractional_part = static_cast<T>(fractional_part_converter)/divisor;
373 fractional_check = static_cast<uint64>(fractional_part*divisor);
374 if (fractional_check != fractional_part_converter) {
375 TRY_nomem(es = "Underflow error converting fractional part of estring \"");
376 TRY_nomem(es += a_str);
377 TRY_nomem(es += "\"");
378 throw(ERROR(0,es));
379 }
380
381 value = whole_part + fractional_part;
382
383 if (negative) {
384 value = -value;
385 }
386 a_t = value;
387 }
388
389 //---------
390
391 /** Initialize the estring object.
392
393 Defaults:
394 - A precision of one digit to the right of the decimal.
395 - A base of 10.
396 - A width of 5 characters for formatted printing.
397 - A space as the fill character for padding the left of a string.
398 - A space as the fill character for padding the right of a string.
399 - Initialize the conversion type to type_unknown.
400 */
init(void)401 void estring::init(void)
402 {
403 m_precision = 1;
404 m_base = 10;
405 m_width = 5;
406 m_alignment = left;
407 m_left_fillchar = ' ';
408 m_right_fillchar = ' ';
409 m_type = type_unknown;
410 }
411
412 /** Erase the string value.
413 */
clear(void)414 void estring::clear(void)
415 {
416 value_type::erase();
417 }
418
419 /** Erase and reinitialize.
420 */
reset(void)421 void estring::reset(void)
422 {
423 clear();
424 init();
425 }
426
427 //---------
428
429 /** Default constructor
430 */
estring()431 estring::estring()
432 {
433 init();
434 }
435
436 //---------
437
438 /** Set the width of a formatted string.
439
440 Variables:
441 - a_l - new width to use for formatting strings.
442
443 Returns:
444 - size_type - the last width.
445 */
width(const size_type a_l)446 estring::size_type estring::width(const size_type a_l)
447 {
448 size_type old;
449
450 old = m_width;
451 m_width = a_l;
452
453 return(old);
454 }
455
456 /** Retrieve the set width for formatted strings.
457
458 Returns:
459 - size_type - the current width.
460 */
width(void) const461 estring::size_type estring::width(void) const
462 {
463 return(m_width);
464 }
465
466 /** Set the alignment used for formatted strings.
467
468 Vaiables:
469 - a_alignment - the type of alignment to use for formatting strings.
470 */
align(const alignment a_alignment)471 estring::alignment estring::align(const alignment a_alignment)
472 {
473 alignment old;
474
475 old = m_alignment;
476 m_alignment = a_alignment;
477
478 return(old);
479 }
480
481 /** Retrieve the set alignment for formatted strings.
482
483 Returns:
484 - enum alignment - the current alignment.
485 */
align(void) const486 estring::alignment estring::align(void) const
487 {
488 return(m_alignment);
489 }
490
491 /** Set the precision used in converting to/from fractional types.
492
493 Variables:
494 - a_p - the number of digits to use to the right of the decimal point when
495 converting fractional types.
496
497 Returns:
498 - size_type - the last precision.
499
500 */
precision(size_type a_p)501 estring::size_type estring::precision(size_type a_p)
502 {
503 size_type old;
504
505 old = m_precision;
506 m_precision = a_p;
507
508 if (m_type == type_float)
509 assign(m_value.value.f);
510 else if (m_type == type_double)
511 assign(m_value.value.d);
512
513 return(old);
514 }
515
516 /** Retrieve the set precision used in fractional conversions.
517
518 Returns:
519 - size_type - the current precision.
520 */
precision(void) const521 estring::size_type estring::precision(void) const
522 {
523 return(m_precision);
524 }
525
526 /** Set the base used in numeric conversions.
527
528 Variables:
529 - a_base - The base to use in converting numbers to/from strings.
530
531 Return:
532 - const unsigned int - the last base.
533
534 Exceptions:
535 - An err_nomem is thrown for memory allocation failure.
536 - An invalid base is thrown if the base is smaller than 2 (binary).
537 - A base too large is thrown if the base is larger than the alphabet of
538 usable symbols.
539 */
base(const unsigned int a_base)540 const unsigned int estring::base(const unsigned int a_base)
541 {
542 unsigned int old = m_base;
543 value_type es;
544 char str[255] = { 0 };
545
546 if (a_base < 2) {
547 sprintf(str, "%u", a_base);
548 TRY_nomem(es = "Invalid base: ");
549 TRY_nomem(es += str);
550 throw(ERROR(0,es));
551 }
552 if (a_base > m_alphabet_len) {
553 sprintf(str, "%u", a_base);
554 TRY_nomem(es = "Base too large: ");
555 TRY_nomem(es += str);
556 throw(ERROR(0,es));
557 }
558 m_base = a_base;
559
560 if (m_type == type_unsigned_int)
561 assign(m_value.value.ui);
562 if (m_type == type_int)
563 assign(m_value.value.i);
564 if (m_type == type_unsigned_short)
565 assign(m_value.value.us);
566 if (m_type == type_short)
567 assign(m_value.value.s);
568 if (m_type == type_unsigned_long)
569 assign(m_value.value.ul);
570 if (m_type == type_long)
571 assign(m_value.value.l);
572 if (m_type == type_unsigned_long_long)
573 assign(m_value.value.ull);
574 if (m_type == type_long_long)
575 assign(m_value.value.ll);
576 if (m_type == type_float)
577 assign(m_value.value.f);
578 if (m_type == type_double)
579 assign(m_value.value.d);
580
581 return(old);
582 }
583
584 /** Retrieve the base used in numeric conversions.
585
586 Returns:
587 - const unsigned int - the current numeric base.
588 */
base(void) const589 const unsigned int estring::base(void) const
590 {
591 return(m_base);
592 }
593
594 /** Set the fill character used to padd the left side of a formatted string.
595
596 Variables:
597 - a_char - the character to use as the fill character.
598
599 Returns:
600 - char - the last fill character.
601
602 */
left_fillchar(const char a_char)603 char estring::left_fillchar(const char a_char)
604 {
605 char old;
606
607 old = m_left_fillchar;
608 m_left_fillchar = a_char;
609
610 return(old);
611 }
612
613 /** Retrieve the fill character used to padd the left side of a formatted
614 string.
615
616 Returns:
617 - char - the current fill character.
618
619 */
left_fillchar(void) const620 char estring::left_fillchar(void) const
621 {
622 return(m_left_fillchar);
623 }
624
625 /** Set the fill character used to padd the right side of a formatted string.
626
627 Variables:
628 - a_char - the character to use as the fill character.
629
630 Returns:
631 - char - the last fill character.
632
633 */
right_fillchar(const char a_char)634 char estring::right_fillchar(const char a_char)
635 {
636 char old;
637
638 old = m_right_fillchar;
639 m_right_fillchar = a_char;
640
641 return(old);
642 }
643
644 /** Retrieve the fill character used to padd the right side of a formatted
645 string.
646
647 Returns:
648 - char - the current fill character.
649
650 */
right_fillchar(void) const651 char estring::right_fillchar(void) const
652 {
653 return(m_right_fillchar);
654 }
655
656 /** Set the fill character used for padding both the left and right side of a
657 formatted string.
658
659 Variables:
660 - a_char - the character to use as the fill character.
661 */
fillchar(const char a_char)662 void estring::fillchar(const char a_char)
663 {
664 left_fillchar(a_char);
665 right_fillchar(a_char);
666 }
667
668 //---------
669
670 /** Generate a formatted string.
671
672 Returns:
673 - value_type - a formatted rendition of the current string.
674
675 If the string being printed is wider than the assigned width then as many as
676 three periods are used ("...") to denote that the contents of the string
677 have been truncated. For strings that use left alignment these three
678 periods are printed on the right-hand side of the string, while showing as
679 many characters on the left as possible beginning with the left-most
680 character. For strings that use right alignment these three periods are
681 printed on the left-hand side of the string, while showing as many
682 characters on the right as possible includingn the right-most character.
683 For strings that are center-aligned as many characters on both the left and
684 the right are printed, including the left-most and the right-most
685 characters, while characters in the center of the string are replaced with
686 the three periods.
687 */
fmt_str(void)688 estring::value_type estring::fmt_str(void)
689 {
690 std::string str;
691 std::string lstr;
692 std::string rstr;
693 std::string::size_type c = 0;
694 std::string::size_type c_max = 0;
695 std::string::size_type offset = 0;
696 std::string::size_type length = 0;
697 std::string::size_type l_offset = 0;
698 std::string::size_type r_offset = 0;
699 bool last = true;
700
701 TRY_nomem(str = "");
702 TRY_nomem(lstr = "");
703 TRY_nomem(rstr = "");
704
705 if (std::string::size() > m_width) {
706 if (m_alignment == left) {
707 if (m_width >= 3)
708 length = m_width-3;
709 else
710 length = 0;
711 TRY_nomem(str = std::string::substr(0,length) + "...");
712 TRY_nomem(str = str.substr(0,m_width));
713 }
714 else if (m_alignment == right) {
715 if (m_width >= 3)
716 length = m_width-3;
717 else
718 length = 0;
719
720 offset = std::string::size()-length;
721 TRY_nomem(str = "..." + std::string::substr(offset,length));
722 TRY_nomem(str = str.substr(str.size()-m_width,m_width));
723 }
724 else {
725 if (m_width < 4) {
726 TRY_nomem(str = static_cast<std::string>("....").substr(0,m_width));
727 return(str);
728 }
729
730 c_max = m_width-3;
731 r_offset = std::string::size()-1;
732 for (c = 0; c < c_max; c++) {
733 if (last) {
734 TRY_nomem(lstr += (*this)[l_offset++]);
735 }
736 else {
737 TRY_nomem(rstr = (*this)[r_offset--] + rstr);
738 }
739 last = !last;
740 }
741
742 TRY_nomem(str = lstr);
743 TRY_nomem(str += "...");
744 TRY_nomem(str += rstr);
745 }
746 return(str);
747 }
748
749 TRY_nomem(str = (*this));
750 c_max = m_width - std::string::size();
751 for (c = 0; c < c_max; c++) {
752 if (m_alignment == right) {
753 TRY_nomem(str = m_left_fillchar + str);
754 }
755 else if (m_alignment == left) {
756 TRY_nomem(str += m_right_fillchar);
757 }
758 else {
759 if (last) {
760 TRY_nomem(str += m_right_fillchar);
761 }
762 else {
763 TRY_nomem(str = m_left_fillchar + str);
764 }
765 last = !last;
766 }
767 }
768
769 return(str);
770 }
771
772 /** Set all the formatting options.
773
774 Variables:
775 - a_width - the width of the formatted string.
776 - a_alignment - the alignment used to format the string.
777 - a_left_fill - the character used for left-hand padding.
778 - a_right_fill - the character used for right-hand padding.
779
780 Returns:
781 - value_type - a formatted rendition of the current string.
782
783 */
fmt_str(const size_type a_width,const alignment a_alignment,const char a_left_fill,const char a_right_fill)784 estring::value_type estring::fmt_str(
785 const size_type a_width,
786 const alignment a_alignment,
787 const char a_left_fill,
788 const char a_right_fill
789 )
790 {
791 value_type str;
792
793 width(a_width);
794 align(a_alignment);
795 left_fillchar(a_left_fill);
796 right_fillchar(a_right_fill);
797
798 str = fmt_str();
799
800 return(str);
801 }
802
803 //---------
804
805 /** Retrieve the type of value being held by this estring.
806
807 Returns:
808 - set_from_type& - the enumeration of the type of value currently assigned.
809 */
get_from_type(void) const810 const estring::set_from_type& estring::get_from_type(void) const
811 {
812 return(m_type);
813 }
814
815 /** Retrieve the typeless_value being held by this estring.
816
817 Returns:
818 - typeless_value& - the union that holds the current value.
819
820 */
get_from_value(void) const821 const estring_value& estring::get_from_value(void) const
822 {
823 return(m_value);
824 }
825
826 /** Copy constructor for estring objects.
827
828 Variables:
829 - a_estr - the estring object to copy.
830
831 Exceptions:
832 - Anything thrown by estring::assign(const estring& a_estr).
833 */
estring(const estring & a_estr)834 estring::estring(const estring& a_estr)
835 {
836 init();
837 assign(a_estr);
838 }
839
840 /** Assignment for estring objects.
841
842 Variables:
843 - a_estr - the estring object to copy.
844
845 Returns:
846 - estring& - a reference to self.
847
848 Exceptions:
849 - An err_nomem is thrown if memory allocation fails.
850 - It is possible that an "Invalid base" or "Base too large" may be thrown
851 if the estring object is corrupted, but this should never happen.
852 */
assign(const estring & a_estr)853 estring& estring::assign(const estring& a_estr)
854 {
855 TRY_nomem(std::string::assign(a_estr));
856 m_precision = a_estr.m_precision;
857 m_width = a_estr.m_width;
858 m_alignment = a_estr.m_alignment;
859 m_left_fillchar = a_estr.m_left_fillchar;
860 m_right_fillchar = a_estr.m_right_fillchar;
861 m_type = a_estr.m_type;
862 m_value = a_estr.m_value;
863
864 return(*this);
865 }
866
867 /** Assignment operator for estring objects.
868
869 Variables:
870 - a_estr - the estring object to copy.
871
872 Returns:
873 - estring& - a reference to self.
874
875 Exceptions:
876 - Anything thrown by estring::assign(const estring& a_estr).
877 */
operator =(const estring & a_estr)878 estring& estring::operator=(const estring& a_estr)
879 {
880 assign(a_estr);
881
882 return(*this);
883 }
884
885 /** Convert all characters to lowercase.
886
887 Returns:
888 - estring& - a reference to self.
889
890 */
lower(void)891 estring& estring::lower(void)
892 {
893 std::string::iterator si;
894
895 for (si = (*this).begin(); si != (*this).end(); ++si) {
896 (*si) = tolower((*si));
897 }
898
899 return(*this);
900 }
901
902 /** Convert all characters to uppercase.
903
904 Returns:
905 - estring& - a reference to self.
906
907 */
upper(void)908 estring& estring::upper(void)
909 {
910 std::string::iterator si;
911
912 for (si = (*this).begin(); si != (*this).end(); ++si) {
913 (*si) = toupper((*si));
914 }
915
916 return(*this);
917 }
918
919 //---------
920
921 /** Copy constructor for chars.
922
923 Exceptions:
924 - Anything thrown by estring::assign(const char& a_char).
925 */
estring(const char a_char)926 estring::estring(const char a_char)
927 {
928 init();
929 assign(a_char);
930 }
931
932 /** Assignment for chars.
933
934 Variables:
935 - a_char - the character to assign.
936
937 Returns:
938 - estring& - a reference to self.
939
940 Exceptions:
941 - An err_nomem is thrown if memory allocation fails.
942 */
assign(const char a_char)943 estring& estring::assign(const char a_char)
944 {
945 std::string s;
946
947 TRY_nomem(s = a_char);
948 TRY_nomem(std::string::assign(s));
949 m_type = type_string;
950
951 return(*this);
952 }
953
954 /** Assignment operator for chars
955
956 Variables:
957 - a_char - the character to assign.
958
959 Returns:
960 - estring& - a reference to self.
961
962 Exceptions:
963 - Anything thrown by estring::assign(const char& a_char).
964 */
operator =(const char a_char)965 estring& estring::operator=(const char a_char)
966 {
967 assign(a_char);
968
969 return(*this);
970 }
971
972 //---------
973
974 /** Copy constructor for std::string objects.
975
976 Variables:
977 - a_string - the std::string object to copy.
978
979 Exceptions:
980 - Anything thrown by estring::assign(const value_type& a_string).
981 */
estring(const value_type & a_string)982 estring::estring(const value_type& a_string)
983 {
984 init();
985 assign(a_string);
986 }
987
988 /** Assignment for std::string objects.
989
990 Variables:
991 - a_string - the std::string object to assign.
992
993 Returns:
994 - estring& - a reference to self.
995
996 Exceptions:
997 - An err_nomem is thrown if memory allocation fails.
998 */
assign(const value_type & a_string)999 estring& estring::assign(const value_type& a_string)
1000 {
1001 TRY_nomem(std::string::assign(a_string));
1002 m_type = type_string;
1003
1004 return(*this);
1005 }
1006
1007 /** Assignment operator for std::string objects.
1008
1009 Variables:
1010 - a_string - the std::string object to copy.
1011
1012 Returns:
1013 - estring& - a reference to self.
1014
1015 Exceptions:
1016 - An err_nomem is thrown if memory allocation fails.
1017 */
operator =(const value_type & a_string)1018 estring& estring::operator=(const value_type& a_string)
1019 {
1020 assign(a_string);
1021
1022 return(*this);
1023 }
1024
1025 //---------
1026
1027 /** Copy constructor for unsigned ints.
1028
1029 Variables:
1030 - a_int - unsigned int to copy.
1031
1032 Exceptions:
1033 - Anything thrown by estring::assign(const unsigned int& a_int).
1034 */
estring(const unsigned int a_int)1035 estring::estring(const unsigned int a_int)
1036 {
1037 init();
1038 assign(a_int);
1039 }
1040
1041 /** Assignment for unsigned ints.
1042
1043 Variables:
1044 - a_int - unsigned int to assign.
1045
1046 Returns:
1047 - estring& - a reference to self.
1048
1049 Exceptions:
1050 - err_nomem on memory allocation failure.
1051 - Anything thrown by
1052 T_integral_to_string(const T& a_t, value_type& a_str).
1053 */
assign(const unsigned int a_int)1054 estring& estring::assign(const unsigned int a_int)
1055 {
1056 std::string s;
1057
1058 TRY(T_integral_to_string(a_int,s),
1059 "Could not convert unsigned int to string");
1060 TRY_nomem(std::string::assign(s));
1061 m_type = type_unsigned_int;
1062 m_value.clear();
1063 m_value.value.ui = a_int;
1064
1065 return(*this);
1066 }
1067
1068 /** Assignment operator for unsigned ints.
1069 */
operator =(const unsigned int a_int)1070 estring& estring::operator=(const unsigned int a_int)
1071 {
1072 assign(a_int);
1073
1074 return(*this);
1075 }
1076
1077 /** Implicit conversion operator to an unsigned int.
1078 */
operator unsigned int() const1079 estring::operator unsigned int() const
1080 {
1081 unsigned int value = 0;
1082
1083 TRY(T_string_to_integral((*this),value),
1084 "Cannot convert string to unsigned int");
1085
1086 return(value);
1087 }
1088
1089 //---------
1090
estring(const int a_int)1091 estring::estring(const int a_int)
1092 {
1093 init();
1094 assign(a_int);
1095 }
1096
assign(const int a_int)1097 estring& estring::assign(const int a_int)
1098 {
1099 if (a_int < 0) {
1100 TRY(assign(static_cast<unsigned int>(-a_int)),
1101 "Coud not convert signed int to string");
1102 TRY_nomem(std::string::insert(0,"-"));
1103 }
1104 else {
1105 TRY(assign(static_cast<unsigned int>(a_int)),
1106 "Could not convert signed int to string");
1107 }
1108 m_type = type_int;
1109 m_value.clear();
1110 m_value.value.i = a_int;
1111
1112 return(*this);
1113 }
1114
operator =(const int a_int)1115 estring& estring::operator=(const int a_int)
1116 {
1117 assign(a_int);
1118
1119 return(*this);
1120 }
1121
operator int() const1122 estring::operator int() const
1123 {
1124 int value = 0;
1125
1126 TRY(T_string_to_signed_integral((*this),value),
1127 "Cannot convert string to signed int");
1128
1129 return(value);
1130 }
1131
1132 //---------
1133
estring(const unsigned short a_short)1134 estring::estring(const unsigned short a_short)
1135 {
1136 init();
1137 assign(a_short);
1138 }
1139
assign(const unsigned short a_short)1140 estring& estring::assign(const unsigned short a_short)
1141 {
1142 std::string s;
1143
1144 TRY(T_integral_to_string(a_short,s),
1145 "Could not convert unsigned short to string");
1146 TRY_nomem(std::string::assign(s));
1147 m_type = type_unsigned_short;
1148 m_value.clear();
1149 m_value.value.us = a_short;
1150
1151 return(*this);
1152 }
1153
operator =(const unsigned short a_short)1154 estring& estring::operator=(const unsigned short a_short)
1155 {
1156 assign(a_short);
1157
1158 return(*this);
1159 }
1160
operator unsigned short() const1161 estring::operator unsigned short() const
1162 {
1163 unsigned short value = 0;
1164
1165 TRY(T_string_to_integral((*this),value),
1166 "Cannot convert string to unsigned short");
1167
1168 return(value);
1169 }
1170
1171 //---------
1172
estring(const short a_short)1173 estring::estring(const short a_short)
1174 {
1175 init();
1176 assign(a_short);
1177 }
1178
assign(const short a_short)1179 estring& estring::assign(const short a_short)
1180 {
1181 if (a_short < 0) {
1182 TRY(assign(static_cast<unsigned short>(-a_short)),
1183 "Could not convert signed short to string");
1184 TRY_nomem(std::string::insert(0,"-"));
1185 }
1186 else {
1187 TRY(assign(static_cast<unsigned short>(a_short)),
1188 "Could not convert signed short to string");
1189 }
1190 m_type = type_short;
1191 m_value.clear();
1192 m_value.value.s = a_short;
1193
1194 return(*this);
1195 }
1196
operator =(const short a_short)1197 estring& estring::operator=(const short a_short)
1198 {
1199 assign(a_short);
1200
1201 return(*this);
1202 }
1203
operator short() const1204 estring::operator short() const
1205 {
1206 short value = 0;
1207
1208 TRY(T_string_to_signed_integral((*this),value),
1209 "Cannot convert string to signed short");
1210
1211 return(value);
1212 }
1213
1214 //---------
1215
estring(const unsigned long a_long)1216 estring::estring(const unsigned long a_long)
1217 {
1218 init();
1219 assign(a_long);
1220 }
1221
assign(const unsigned long a_long)1222 estring& estring::assign(const unsigned long a_long)
1223 {
1224 std::string s;
1225
1226 TRY(T_integral_to_string(a_long,s),
1227 "Could not convert unsigned long to string");
1228 TRY_nomem(std::string::assign(s));
1229 m_type = type_unsigned_long;
1230 m_value.clear();
1231 m_value.value.ul = a_long;
1232
1233 return(*this);
1234 }
1235
operator =(const unsigned long a_long)1236 estring& estring::operator=(const unsigned long a_long)
1237 {
1238 assign(a_long);
1239
1240 return(*this);
1241 }
1242
operator unsigned long() const1243 estring::operator unsigned long() const
1244 {
1245 unsigned long value = 0;
1246
1247 TRY(T_string_to_integral((*this),value),
1248 "Cannot convert string to unsigned long");
1249
1250 return(value);
1251 }
1252
1253 //---------
1254
estring(const long a_long)1255 estring::estring(const long a_long)
1256 {
1257 init();
1258 assign(a_long);
1259 }
1260
assign(const long a_long)1261 estring& estring::assign(const long a_long)
1262 {
1263 if (a_long < 0) {
1264 TRY(assign(static_cast<unsigned long>(-a_long)),
1265 "Could not convert signed long to string");
1266 TRY_nomem(std::string::insert(0,"-"));
1267 }
1268 else {
1269 TRY(assign(static_cast<unsigned long>(a_long)),
1270 "Could not convert signed long to string");
1271 }
1272 m_type = type_long;
1273 m_value.clear();
1274 m_value.value.l = a_long;
1275
1276 return(*this);
1277 }
1278
operator =(const long a_long)1279 estring& estring::operator=(const long a_long)
1280 {
1281 assign(a_long);
1282
1283 return(*this);
1284 }
1285
operator long() const1286 estring::operator long() const
1287 {
1288 long value = 0;
1289
1290 TRY(T_string_to_signed_integral((*this),value),
1291 "Cannot convert string to signed long");
1292
1293 return(value);
1294 }
1295
1296 //---------
1297
estring(const unsigned long long a_long)1298 estring::estring(const unsigned long long a_long)
1299 {
1300 init();
1301 assign(a_long);
1302 }
1303
assign(const unsigned long long a_long)1304 estring& estring::assign(const unsigned long long a_long)
1305 {
1306 std::string s;
1307
1308 TRY(T_integral_to_string(a_long,s),
1309 "Could not convert unsigned long long to string");
1310 TRY_nomem(std::string::assign(s));
1311 m_type = type_unsigned_long_long;
1312 m_value.clear();
1313 m_value.value.ull = a_long;
1314
1315 return(*this);
1316 }
1317
operator =(const unsigned long long a_long)1318 estring& estring::operator=(const unsigned long long a_long)
1319 {
1320 assign(a_long);
1321
1322 return(*this);
1323 }
1324
operator unsigned long long() const1325 estring::operator unsigned long long() const
1326 {
1327 unsigned long long value = 0;
1328
1329 TRY(T_string_to_integral((*this),value),
1330 "Cannot convert string to unsigned long long");
1331
1332 return(value);
1333 }
1334
1335 //---------
1336
estring(const long long a_long)1337 estring::estring(const long long a_long)
1338 {
1339 init();
1340 assign(a_long);
1341 }
1342
assign(const long long a_long)1343 estring& estring::assign(const long long a_long)
1344 {
1345 if (a_long < 0) {
1346 TRY(assign(static_cast<unsigned long long>(-a_long)),
1347 "Could not convert unsigned long long to string");
1348 TRY_nomem(insert(0,"-"));
1349 }
1350 else {
1351 TRY(assign(static_cast<unsigned long long>(a_long)),
1352 "Could not convert unsigned long long to string");
1353 }
1354 m_type = type_long_long;
1355 m_value.clear();
1356 m_value.value.ll = a_long;
1357
1358 return(*this);
1359 }
1360
operator =(const long long a_long)1361 estring& estring::operator=(const long long a_long)
1362 {
1363 assign(a_long);
1364
1365 return(*this);
1366 }
1367
operator long long() const1368 estring::operator long long() const
1369 {
1370 long long value = 0;
1371
1372 TRY(T_string_to_signed_integral((*this),value),
1373 "Cannot convert string to signed long long");
1374
1375 return(value);
1376 }
1377
1378 //---------
1379
estring(char const * a_ptr)1380 estring::estring(char const * a_ptr)
1381 {
1382 init();
1383 assign(a_ptr);
1384 }
1385
assign(char const * a_ptr)1386 estring& estring::assign(char const * a_ptr)
1387 {
1388 std::string str;
1389
1390 TRY_nomem(str = a_ptr);
1391 TRY_nomem(assign(str));
1392 m_type = type_char_ptr;
1393 m_value.clear();
1394 m_value.value.char_ptr = a_ptr;
1395
1396 return(*this);
1397 }
1398
operator =(char const * a_ptr)1399 estring& estring::operator=(char const * a_ptr)
1400 {
1401 assign(a_ptr);
1402
1403 return(*this);
1404 }
1405
operator char const*() const1406 estring::operator char const *()const
1407 {
1408 char const * value = 0;
1409
1410 if ((m_type != type_char_ptr) && (m_type != type_void_ptr)) {
1411 throw(ERROR(0,"Value type is not a pointer"));
1412 }
1413
1414 value = m_value.value.char_ptr;
1415
1416 return(value);
1417 }
1418
1419 //---------
1420
estring(void * const a_ptr)1421 estring::estring(void* const a_ptr)
1422 {
1423 init();
1424 assign(a_ptr);
1425 }
1426
assign(void * const a_ptr)1427 estring& estring::assign(void* const a_ptr)
1428 {
1429 static const size_t buffer_len = 32;
1430 char buffer[buffer_len] = { 0 };
1431
1432 snprintf(buffer, buffer_len, "%p", a_ptr);
1433 TRY_nomem(std::string::assign(buffer));
1434 m_type = type_void_ptr;
1435 m_value.clear();
1436 m_value.value.void_ptr = a_ptr;
1437
1438 return(*this);
1439 }
1440
operator =(void * const a_ptr)1441 estring& estring::operator=(void* const a_ptr)
1442 {
1443 assign(a_ptr);
1444
1445 return(*this);
1446 }
1447
operator void*() const1448 estring::operator void*()const
1449 {
1450 void * value = 0;
1451
1452 if ((m_type != type_void_ptr) && (m_type != type_char_ptr)) {
1453 throw(ERROR(0,"Value type is not a pointer"));
1454 }
1455
1456 value = m_value.value.void_ptr;
1457
1458 return(value);
1459 }
1460
1461 //---------
1462
estring(const float a_float)1463 estring::estring(const float a_float)
1464 {
1465 init();
1466 assign(a_float);
1467 }
1468
assign(const float a_float)1469 estring& estring::assign(const float a_float)
1470 {
1471 std::string ws;
1472 std::string fs;
1473 std::string s;
1474
1475 TRY(T_fraction_to_strings(a_float,ws,fs),
1476 "Cannot convert float to string");
1477 TRY_nomem(s = ws);
1478 if (fs.size() > 0) {
1479 TRY_nomem(s += ".");
1480 TRY_nomem(s += fs);
1481 }
1482 TRY_nomem(std::string::assign(s));
1483 m_type = type_float;
1484 m_value.clear();
1485 m_value.value.f = a_float;
1486
1487 return(*this);
1488 }
1489
operator =(const float a_float)1490 estring& estring::operator=(const float a_float)
1491 {
1492 assign(a_float);
1493
1494 return(*this);
1495 }
1496
estring(const float a_float,unsigned a_precision,unsigned int a_base)1497 estring::estring(const float a_float, unsigned a_precision,
1498 unsigned int a_base)
1499 {
1500 init();
1501 assign(a_float, a_precision, a_base);
1502 }
1503
assign(const float a_float,unsigned a_precision,unsigned int a_base)1504 estring& estring::assign(const float a_float, unsigned a_precision,
1505 unsigned int a_base)
1506 {
1507 std::string ws;
1508 std::string fs;
1509 std::string s;
1510
1511 precision(a_precision);
1512 base(a_base);
1513 assign(a_float);
1514
1515 return(*this);
1516 }
1517
operator float() const1518 estring::operator float() const
1519 {
1520 float value = 0.0;
1521
1522 TRY(T_string_to_fractional((*this), value),
1523 "Cannot convert string to float");
1524
1525 return(value);
1526 }
1527
1528 //---------
1529
estring(const double a_double)1530 estring::estring(const double a_double)
1531 {
1532 init();
1533 assign(a_double);
1534 }
1535
assign(const double a_double)1536 estring& estring::assign(const double a_double)
1537 {
1538 std::string ws;
1539 std::string fs;
1540 std::string s;
1541
1542 TRY(T_fraction_to_strings(a_double,ws,fs),
1543 "Cannot convert double to string");
1544 TRY_nomem(s = ws);
1545 if (fs.size() > 0) {
1546 TRY_nomem(s += ".");
1547 TRY_nomem(s += fs);
1548 }
1549 TRY_nomem(std::string::assign(s));
1550 m_type = type_double;
1551 m_value.clear();
1552 m_value.value.d = a_double;
1553
1554 return(*this);
1555 }
1556
operator =(const double a_double)1557 estring& estring::operator=(const double a_double)
1558 {
1559 assign(a_double);
1560
1561 return(*this);
1562 }
1563
estring(const double a_double,unsigned a_precision,unsigned int a_base)1564 estring::estring(const double a_double, unsigned a_precision,
1565 unsigned int a_base)
1566 {
1567 init();
1568 assign(a_double, a_precision, a_base);
1569 }
1570
assign(const double a_double,unsigned a_precision,unsigned int a_base)1571 estring& estring::assign(const double a_double, unsigned a_precision,
1572 unsigned int a_base)
1573 {
1574 std::string ws;
1575 std::string fs;
1576 std::string s;
1577
1578 precision(a_precision);
1579 assign(a_base);
1580 assign(a_double);
1581
1582 return(*this);
1583 }
1584
operator double() const1585 estring::operator double() const
1586 {
1587 double value = 0.0;
1588
1589 TRY(T_string_to_fractional((*this), value),
1590 "Cannot convert string to double");
1591
1592 return(value);
1593 }
1594
1595