blob: e501165a99520b20d6abdbbd935818671f01e179 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* 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
21char 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}