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