netinet/in.h: add IPPROTO_MH
[uclibc-ng.git] / libc / stdio / _uintmaxtostr.c
blob82eb862e1924ae40d95d4830ca9eb12146539fc9
1 /* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org>
3 * GNU Library General Public License (LGPL) version 2 or later.
5 * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details.
6 */
8 #include "_stdio.h"
9 #include <limits.h>
10 #include <locale.h>
11 #include <bits/uClibc_uintmaxtostr.h>
14 /* Avoid using long long / and % operations to cut down dependencies on
15 * libgcc.a. Definitely helps on i386 at least. */
16 #if (INTMAX_MAX > INT_MAX) && (((INTMAX_MAX/INT_MAX)/2) - 2 <= INT_MAX)
17 #define INTERNAL_DIV_MOD
18 #endif
20 char attribute_hidden *_uintmaxtostr(register char * __restrict bufend, uintmax_t uval,
21 int base, __UIM_CASE alphacase)
23 int negative;
24 unsigned int digit;
25 #ifdef INTERNAL_DIV_MOD
26 unsigned int H, L, high, low, rh;
27 #endif
28 #ifndef __LOCALE_C_ONLY
29 int grouping, outdigit;
30 const char *g; /* This does not need to be initialized. */
31 #endif /* __LOCALE_C_ONLY */
33 negative = 0;
34 if (base < 0) { /* signed value */
35 base = -base;
36 if (uval > INTMAX_MAX) {
37 uval = -uval;
38 negative = 1;
42 /* this is an internal routine -- we shouldn't need to check this */
43 assert(!((base < 2) || (base > 36)));
45 #ifndef __LOCALE_C_ONLY
46 grouping = -1;
47 outdigit = 0x80 & alphacase;
48 alphacase ^= outdigit;
49 if (alphacase == __UIM_GROUP) {
50 assert(base == 10);
51 if (*(g = __UCLIBC_CURLOCALE->grouping)) {
52 grouping = *g;
55 #endif /* __LOCALE_C_ONLY */
57 *bufend = '\0';
59 #ifndef INTERNAL_DIV_MOD
60 do {
61 #ifndef __LOCALE_C_ONLY
62 if (!grouping) { /* Finished a group. */
63 bufend -= __UCLIBC_CURLOCALE->thousands_sep_len;
64 memcpy(bufend, __UCLIBC_CURLOCALE->thousands_sep,
65 __UCLIBC_CURLOCALE->thousands_sep_len);
66 if (g[1] != 0) { /* g[1] == 0 means repeat last grouping. */
67 /* Note: g[1] == -1 means no further grouping. But since
68 * we'll never wrap around, we can set grouping to -1 without
69 * fear of */
70 ++g;
72 grouping = *g;
74 --grouping;
75 #endif /* __LOCALE_C_ONLY */
76 digit = uval % base;
77 uval /= base;
79 #ifndef __LOCALE_C_ONLY
80 if (unlikely(outdigit)) {
81 bufend -= __UCLIBC_CURLOCALE->outdigit_length[digit];
82 memcpy(bufend,
83 (&__UCLIBC_CURLOCALE->outdigit0_mb)[digit],
84 __UCLIBC_CURLOCALE->outdigit_length[digit]);
85 } else
86 #endif
88 *--bufend = ( (digit < 10) ? digit + '0' : digit + alphacase );
90 } while (uval);
92 #else /* ************************************************** */
94 H = (UINT_MAX / base);
95 L = UINT_MAX % base + 1;
96 if (L == base) {
97 ++H;
98 L = 0;
100 low = (unsigned int) uval;
101 high = (unsigned int) (uval >> (sizeof(unsigned int) * CHAR_BIT));
103 do {
104 #ifndef __LOCALE_C_ONLY
105 if (!grouping) { /* Finished a group. */
106 bufend -= __UCLIBC_CURLOCALE->thousands_sep_len;
107 memcpy(bufend, __UCLIBC_CURLOCALE->thousands_sep,
108 __UCLIBC_CURLOCALE->thousands_sep_len);
109 if (g[1] != 0) { /* g[1] == 0 means repeat last grouping. */
110 /* Note: g[1] == -1 means no further grouping. But since
111 * we'll never wrap around, we can set grouping to -1 without
112 * fear of */
113 ++g;
115 grouping = *g;
117 --grouping;
118 #endif /* __LOCALE_C_ONLY */
120 if (unlikely(high)) {
121 rh = high % base;
122 high /= base;
123 digit = (low % base) + (L * rh);
124 low = (low / base) + (H * rh) + (digit / base);
125 digit %= base;
126 } else {
127 digit = low % base;
128 low /= base;
131 #ifndef __LOCALE_C_ONLY
132 if (unlikely(outdigit)) {
133 bufend -= __UCLIBC_CURLOCALE->outdigit_length[digit];
134 memcpy(bufend,
135 (&__UCLIBC_CURLOCALE->outdigit0_mb)[digit],
136 __UCLIBC_CURLOCALE->outdigit_length[digit]);
137 } else
138 #endif
140 *--bufend = ( (digit < 10) ? digit + '0' : digit + alphacase );
142 } while (low | high);
144 #endif /******************************************************/
146 if (negative) {
147 *--bufend = '-';
150 return bufend;