blob: ddce69d4558cd4da4208f22809c6f524ca5cb593 [file] [log] [blame]
Eric Smith5807c412008-05-11 21:00:57 +00001/* stringlib: locale related helpers implementation */
2
Eric Smith5807c412008-05-11 21:00:57 +00003#include <locale.h>
4
Eric Smith0923d1d2009-04-16 20:16:10 +00005#define MAX(x, y) ((x) < (y) ? (y) : (x))
6#define MIN(x, y) ((x) < (y) ? (x) : (y))
7
8typedef struct {
9 const char *grouping;
10 char previous;
11 Py_ssize_t i; /* Where we're currently pointing in grouping. */
Martin v. Löwisd63a3b82011-09-28 07:41:54 +020012} STRINGLIB(GroupGenerator);
Eric Smith0923d1d2009-04-16 20:16:10 +000013
14static void
Martin v. Löwisd63a3b82011-09-28 07:41:54 +020015STRINGLIB(GroupGenerator_init)(STRINGLIB(GroupGenerator) *self, const char *grouping)
Eric Smith0923d1d2009-04-16 20:16:10 +000016{
17 self->grouping = grouping;
18 self->i = 0;
19 self->previous = 0;
20}
21
22/* Returns the next grouping, or 0 to signify end. */
23static Py_ssize_t
Martin v. Löwisd63a3b82011-09-28 07:41:54 +020024STRINGLIB(GroupGenerator_next)(STRINGLIB(GroupGenerator) *self)
Eric Smith0923d1d2009-04-16 20:16:10 +000025{
26 /* Note that we don't really do much error checking here. If a
27 grouping string contains just CHAR_MAX, for example, then just
28 terminate the generator. That shouldn't happen, but at least we
29 fail gracefully. */
30 switch (self->grouping[self->i]) {
31 case 0:
32 return self->previous;
33 case CHAR_MAX:
34 /* Stop the generator. */
35 return 0;
36 default: {
37 char ch = self->grouping[self->i];
38 self->previous = ch;
39 self->i++;
40 return (Py_ssize_t)ch;
41 }
42 }
43}
44
45/* Fill in some digits, leading zeros, and thousands separator. All
46 are optional, depending on when we're called. */
47static void
Martin v. Löwisd63a3b82011-09-28 07:41:54 +020048STRINGLIB(fill)(STRINGLIB_CHAR **digits_end, STRINGLIB_CHAR **buffer_end,
Eric Smith0923d1d2009-04-16 20:16:10 +000049 Py_ssize_t n_chars, Py_ssize_t n_zeros, const char* thousands_sep,
50 Py_ssize_t thousands_sep_len)
51{
Eric Smith0923d1d2009-04-16 20:16:10 +000052 Py_ssize_t i;
Eric Smith0923d1d2009-04-16 20:16:10 +000053
54 if (thousands_sep) {
55 *buffer_end -= thousands_sep_len;
56
57 /* Copy the thousands_sep chars into the buffer. */
58#if STRINGLIB_IS_UNICODE
59 /* Convert from the char's of the thousands_sep from
60 the locale into unicode. */
61 for (i = 0; i < thousands_sep_len; ++i)
62 (*buffer_end)[i] = thousands_sep[i];
63#else
64 /* No conversion, just memcpy the thousands_sep. */
65 memcpy(*buffer_end, thousands_sep, thousands_sep_len);
66#endif
67 }
68
69 *buffer_end -= n_chars;
70 *digits_end -= n_chars;
71 memcpy(*buffer_end, *digits_end, n_chars * sizeof(STRINGLIB_CHAR));
72
73 *buffer_end -= n_zeros;
Martin v. Löwisd63a3b82011-09-28 07:41:54 +020074 for (i = 0; i < n_zeros; i++)
75 (*buffer_end)[i] = '0';
Eric Smith0923d1d2009-04-16 20:16:10 +000076}
77
Eric Smith5807c412008-05-11 21:00:57 +000078/**
79 * _Py_InsertThousandsGrouping:
80 * @buffer: A pointer to the start of a string.
Eric Smith0923d1d2009-04-16 20:16:10 +000081 * @n_buffer: Number of characters in @buffer.
82 * @digits: A pointer to the digits we're reading from. If count
83 * is non-NULL, this is unused.
Eric Smith6d7e7a72008-06-24 01:06:47 +000084 * @n_digits: The number of digits in the string, in which we want
85 * to put the grouping chars.
Eric Smith0923d1d2009-04-16 20:16:10 +000086 * @min_width: The minimum width of the digits in the output string.
87 * Output will be zero-padded on the left to fill.
Eric Smitha3b1ac82009-04-03 14:45:06 +000088 * @grouping: see definition in localeconv().
89 * @thousands_sep: see definition in localeconv().
Eric Smith5807c412008-05-11 21:00:57 +000090 *
Eric Smith0923d1d2009-04-16 20:16:10 +000091 * There are 2 modes: counting and filling. If @buffer is NULL,
92 * we are in counting mode, else filling mode.
93 * If counting, the required buffer size is returned.
94 * If filling, we know the buffer will be large enough, so we don't
95 * need to pass in the buffer size.
Eric Smitha3b1ac82009-04-03 14:45:06 +000096 * Inserts thousand grouping characters (as defined by grouping and
97 * thousands_sep) into the string between buffer and buffer+n_digits.
Eric Smith5807c412008-05-11 21:00:57 +000098 *
99 * Return value: 0 on error, else 1. Note that no error can occur if
100 * count is non-NULL.
101 *
102 * This name won't be used, the includer of this file should define
103 * it to be the actual function name, based on unicode or string.
Eric Smith0923d1d2009-04-16 20:16:10 +0000104 *
105 * As closely as possible, this code mimics the logic in decimal.py's
106 _insert_thousands_sep().
Eric Smith5807c412008-05-11 21:00:57 +0000107 **/
Eric Smith0923d1d2009-04-16 20:16:10 +0000108Py_ssize_t
Eric Smith5807c412008-05-11 21:00:57 +0000109_Py_InsertThousandsGrouping(STRINGLIB_CHAR *buffer,
Eric Smitha3b1ac82009-04-03 14:45:06 +0000110 Py_ssize_t n_buffer,
Eric Smith0923d1d2009-04-16 20:16:10 +0000111 STRINGLIB_CHAR *digits,
Eric Smitha3b1ac82009-04-03 14:45:06 +0000112 Py_ssize_t n_digits,
Eric Smith0923d1d2009-04-16 20:16:10 +0000113 Py_ssize_t min_width,
Eric Smitha3b1ac82009-04-03 14:45:06 +0000114 const char *grouping,
115 const char *thousands_sep)
Eric Smith5807c412008-05-11 21:00:57 +0000116{
Eric Smith0923d1d2009-04-16 20:16:10 +0000117 Py_ssize_t count = 0;
118 Py_ssize_t n_zeros;
119 int loop_broken = 0;
120 int use_separator = 0; /* First time through, don't append the
121 separator. They only go between
122 groups. */
123 STRINGLIB_CHAR *buffer_end = NULL;
124 STRINGLIB_CHAR *digits_end = NULL;
125 Py_ssize_t l;
126 Py_ssize_t n_chars;
127 Py_ssize_t thousands_sep_len = strlen(thousands_sep);
128 Py_ssize_t remaining = n_digits; /* Number of chars remaining to
129 be looked at */
130 /* A generator that returns all of the grouping widths, until it
131 returns 0. */
Martin v. Löwisd63a3b82011-09-28 07:41:54 +0200132 STRINGLIB(GroupGenerator) groupgen;
133 STRINGLIB(GroupGenerator_init)(&groupgen, grouping);
Eric Smith5807c412008-05-11 21:00:57 +0000134
Eric Smith0923d1d2009-04-16 20:16:10 +0000135 if (buffer) {
136 buffer_end = buffer + n_buffer;
137 digits_end = digits + n_digits;
138 }
139
Martin v. Löwisd63a3b82011-09-28 07:41:54 +0200140 while ((l = STRINGLIB(GroupGenerator_next)(&groupgen)) > 0) {
Eric Smith0923d1d2009-04-16 20:16:10 +0000141 l = MIN(l, MAX(MAX(remaining, min_width), 1));
142 n_zeros = MAX(0, l - remaining);
143 n_chars = MAX(0, MIN(remaining, l));
144
145 /* Use n_zero zero's and n_chars chars */
146
147 /* Count only, don't do anything. */
148 count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars;
149
150 if (buffer) {
151 /* Copy into the output buffer. */
Martin v. Löwisd63a3b82011-09-28 07:41:54 +0200152 STRINGLIB(fill)(&digits_end, &buffer_end, n_chars, n_zeros,
Eric Smith0923d1d2009-04-16 20:16:10 +0000153 use_separator ? thousands_sep : NULL, thousands_sep_len);
Eric Smitha3b1ac82009-04-03 14:45:06 +0000154 }
Eric Smith5807c412008-05-11 21:00:57 +0000155
Eric Smith0923d1d2009-04-16 20:16:10 +0000156 /* Use a separator next time. */
157 use_separator = 1;
Eric Smith5807c412008-05-11 21:00:57 +0000158
Eric Smith0923d1d2009-04-16 20:16:10 +0000159 remaining -= n_chars;
160 min_width -= l;
Eric Smith5807c412008-05-11 21:00:57 +0000161
Eric Smith0923d1d2009-04-16 20:16:10 +0000162 if (remaining <= 0 && min_width <= 0) {
163 loop_broken = 1;
164 break;
Eric Smitha3b1ac82009-04-03 14:45:06 +0000165 }
Eric Smith0923d1d2009-04-16 20:16:10 +0000166 min_width -= thousands_sep_len;
167 }
168 if (!loop_broken) {
169 /* We left the loop without using a break statement. */
170
171 l = MAX(MAX(remaining, min_width), 1);
172 n_zeros = MAX(0, l - remaining);
173 n_chars = MAX(0, MIN(remaining, l));
174
175 /* Use n_zero zero's and n_chars chars */
176 count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars;
177 if (buffer) {
178 /* Copy into the output buffer. */
Martin v. Löwisd63a3b82011-09-28 07:41:54 +0200179 STRINGLIB(fill)(&digits_end, &buffer_end, n_chars, n_zeros,
Eric Smith0923d1d2009-04-16 20:16:10 +0000180 use_separator ? thousands_sep : NULL, thousands_sep_len);
Eric Smitha3b1ac82009-04-03 14:45:06 +0000181 }
Eric Smith0923d1d2009-04-16 20:16:10 +0000182 }
183 return count;
Eric Smitha3b1ac82009-04-03 14:45:06 +0000184}
185
186/**
187 * _Py_InsertThousandsGroupingLocale:
188 * @buffer: A pointer to the start of a string.
Eric Smitha3b1ac82009-04-03 14:45:06 +0000189 * @n_digits: The number of digits in the string, in which we want
190 * to put the grouping chars.
Eric Smitha3b1ac82009-04-03 14:45:06 +0000191 *
192 * Reads thee current locale and calls _Py_InsertThousandsGrouping().
193 **/
Eric Smith0923d1d2009-04-16 20:16:10 +0000194Py_ssize_t
Eric Smitha3b1ac82009-04-03 14:45:06 +0000195_Py_InsertThousandsGroupingLocale(STRINGLIB_CHAR *buffer,
196 Py_ssize_t n_buffer,
Eric Smith0923d1d2009-04-16 20:16:10 +0000197 STRINGLIB_CHAR *digits,
Eric Smitha3b1ac82009-04-03 14:45:06 +0000198 Py_ssize_t n_digits,
Eric Smith0923d1d2009-04-16 20:16:10 +0000199 Py_ssize_t min_width)
Eric Smitha3b1ac82009-04-03 14:45:06 +0000200{
201 struct lconv *locale_data = localeconv();
202 const char *grouping = locale_data->grouping;
203 const char *thousands_sep = locale_data->thousands_sep;
204
Eric Smith0923d1d2009-04-16 20:16:10 +0000205 return _Py_InsertThousandsGrouping(buffer, n_buffer, digits, n_digits,
206 min_width, grouping, thousands_sep);
Eric Smith5807c412008-05-11 21:00:57 +0000207}