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