| /* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org> | 
 |  * | 
 |  * GNU Library General Public License (LGPL) version 2 or later. | 
 |  * | 
 |  * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details. | 
 |  */ | 
 |  | 
 | #define _ISOC99_SOURCE			/* for ULLONG primarily... */ | 
 | #include "_stdio.h" | 
 | #include <limits.h> | 
 | #include <locale.h> | 
 | #include <bits/uClibc_uintmaxtostr.h> | 
 |  | 
 |  | 
 | /* Avoid using long long / and % operations to cut down dependencies on | 
 |  * libgcc.a.  Definitely helps on i386 at least. */ | 
 | #if (INTMAX_MAX > INT_MAX) && (((INTMAX_MAX/INT_MAX)/2) - 2 <= INT_MAX) | 
 | #define INTERNAL_DIV_MOD | 
 | #endif | 
 |  | 
 | char attribute_hidden *_uintmaxtostr(register char * __restrict bufend, uintmax_t uval, | 
 | 					int base, __UIM_CASE alphacase) | 
 | { | 
 | 	int negative; | 
 | 	unsigned int digit; | 
 | #ifdef INTERNAL_DIV_MOD | 
 | 	unsigned int H, L, high, low, rh; | 
 | #endif | 
 | #ifndef __LOCALE_C_ONLY | 
 | 	int grouping, outdigit; | 
 | 	const char *g;		   /* This does not need to be initialized. */ | 
 | #endif /* __LOCALE_C_ONLY */ | 
 |  | 
 | 	negative = 0; | 
 | 	if (base < 0) {				/* signed value */ | 
 | 		base = -base; | 
 | 		if (uval > INTMAX_MAX) { | 
 | 			uval = -uval; | 
 | 			negative = 1; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	/* this is an internal routine -- we shouldn't need to check this */ | 
 | 	assert(!((base < 2) || (base > 36))); | 
 |  | 
 | #ifndef __LOCALE_C_ONLY | 
 | 	grouping = -1; | 
 | 	outdigit = 0x80 & alphacase; | 
 | 	alphacase ^= outdigit; | 
 | 	if (alphacase == __UIM_GROUP) { | 
 | 		assert(base == 10); | 
 | 		if (*(g = __UCLIBC_CURLOCALE->grouping)) { | 
 | 			grouping = *g; | 
 | 		} | 
 | 	} | 
 | #endif /* __LOCALE_C_ONLY */ | 
 |  | 
 | 	*bufend = '\0'; | 
 |  | 
 | #ifndef INTERNAL_DIV_MOD | 
 | 	do { | 
 | #ifndef __LOCALE_C_ONLY | 
 | 		if (!grouping) {		/* Finished a group. */ | 
 | 			bufend -= __UCLIBC_CURLOCALE->thousands_sep_len; | 
 | 			memcpy(bufend, __UCLIBC_CURLOCALE->thousands_sep, | 
 | 				   __UCLIBC_CURLOCALE->thousands_sep_len); | 
 | 			if (g[1] != 0) { 	/* g[1] == 0 means repeat last grouping. */ | 
 | 				/* Note: g[1] == -1 means no further grouping.  But since | 
 | 				 * we'll never wrap around, we can set grouping to -1 without | 
 | 				 * fear of */ | 
 | 				++g; | 
 | 			} | 
 | 			grouping = *g; | 
 | 		} | 
 | 		--grouping; | 
 | #endif /* __LOCALE_C_ONLY */ | 
 | 		digit = uval % base; | 
 | 		uval /= base; | 
 |  | 
 | #ifndef __LOCALE_C_ONLY | 
 | 		if (unlikely(outdigit)) { | 
 | 			bufend -= __UCLIBC_CURLOCALE->outdigit_length[digit]; | 
 | 			memcpy(bufend, | 
 | 				   (&__UCLIBC_CURLOCALE->outdigit0_mb)[digit], | 
 | 				   __UCLIBC_CURLOCALE->outdigit_length[digit]); | 
 | 		} else | 
 | #endif | 
 | 		{ | 
 | 			*--bufend = ( (digit < 10) ? digit + '0' : digit + alphacase ); | 
 | 		} | 
 | 	} while (uval); | 
 |  | 
 | #else  /* ************************************************** */ | 
 |  | 
 | 	H = (UINT_MAX / base); | 
 | 	L = UINT_MAX % base + 1; | 
 | 	if (L == base) { | 
 | 		++H; | 
 | 		L = 0; | 
 | 	} | 
 | 	low = (unsigned int) uval; | 
 | 	high = (unsigned int) (uval >> (sizeof(unsigned int) * CHAR_BIT)); | 
 |  | 
 | 	do { | 
 | #ifndef __LOCALE_C_ONLY | 
 | 		if (!grouping) {		/* Finished a group. */ | 
 | 			bufend -= __UCLIBC_CURLOCALE->thousands_sep_len; | 
 | 			memcpy(bufend, __UCLIBC_CURLOCALE->thousands_sep, | 
 | 				   __UCLIBC_CURLOCALE->thousands_sep_len); | 
 | 			if (g[1] != 0) { 	/* g[1] == 0 means repeat last grouping. */ | 
 | 				/* Note: g[1] == -1 means no further grouping.  But since | 
 | 				 * we'll never wrap around, we can set grouping to -1 without | 
 | 				 * fear of */ | 
 | 				++g; | 
 | 			} | 
 | 			grouping = *g; | 
 | 		} | 
 | 		--grouping; | 
 | #endif /* __LOCALE_C_ONLY */ | 
 |  | 
 | 		if (unlikely(high)) { | 
 | 			rh = high % base; | 
 | 			high /= base; | 
 | 			digit = (low % base) + (L * rh); | 
 | 			low = (low / base) + (H * rh) + (digit / base); | 
 | 			digit %= base; | 
 | 		} else { | 
 | 			digit = low % base; | 
 | 			low /= base; | 
 | 		} | 
 |  | 
 | #ifndef __LOCALE_C_ONLY | 
 | 		if (unlikely(outdigit)) { | 
 | 			bufend -= __UCLIBC_CURLOCALE->outdigit_length[digit]; | 
 | 			memcpy(bufend, | 
 | 				   (&__UCLIBC_CURLOCALE->outdigit0_mb)[digit], | 
 | 				   __UCLIBC_CURLOCALE->outdigit_length[digit]); | 
 | 		} else | 
 | #endif | 
 | 		{ | 
 | 			*--bufend = ( (digit < 10) ? digit + '0' : digit + alphacase ); | 
 | 		} | 
 | 	} while (low | high); | 
 |  | 
 | #endif /******************************************************/ | 
 |  | 
 | 	if (negative) { | 
 | 		*--bufend = '-'; | 
 | 	} | 
 |  | 
 | 	return bufend; | 
 | } |