blob: 28c87c8f832cb96613de7703aa4f46f8aaea0af0 [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
Victor Stinner41a863c2012-02-24 00:37:51 +01005#ifndef STRINGLIB_IS_UNICODE
6# error "localeutil is specific to Unicode"
7#endif
Eric Smith0923d1d2009-04-16 20:16:10 +00008
9typedef struct {
10 const char *grouping;
11 char previous;
12 Py_ssize_t i; /* Where we're currently pointing in grouping. */
Martin v. Löwisd63a3b82011-09-28 07:41:54 +020013} STRINGLIB(GroupGenerator);
Eric Smith0923d1d2009-04-16 20:16:10 +000014
15static void
Martin v. Löwisd63a3b82011-09-28 07:41:54 +020016STRINGLIB(GroupGenerator_init)(STRINGLIB(GroupGenerator) *self, const char *grouping)
Eric Smith0923d1d2009-04-16 20:16:10 +000017{
18 self->grouping = grouping;
19 self->i = 0;
20 self->previous = 0;
21}
22
23/* Returns the next grouping, or 0 to signify end. */
24static Py_ssize_t
Martin v. Löwisd63a3b82011-09-28 07:41:54 +020025STRINGLIB(GroupGenerator_next)(STRINGLIB(GroupGenerator) *self)
Eric Smith0923d1d2009-04-16 20:16:10 +000026{
27 /* Note that we don't really do much error checking here. If a
28 grouping string contains just CHAR_MAX, for example, then just
29 terminate the generator. That shouldn't happen, but at least we
30 fail gracefully. */
31 switch (self->grouping[self->i]) {
32 case 0:
33 return self->previous;
34 case CHAR_MAX:
35 /* Stop the generator. */
36 return 0;
37 default: {
38 char ch = self->grouping[self->i];
39 self->previous = ch;
40 self->i++;
41 return (Py_ssize_t)ch;
42 }
43 }
44}
45
46/* Fill in some digits, leading zeros, and thousands separator. All
47 are optional, depending on when we're called. */
48static void
Martin v. Löwisd63a3b82011-09-28 07:41:54 +020049STRINGLIB(fill)(STRINGLIB_CHAR **digits_end, STRINGLIB_CHAR **buffer_end,
Victor Stinner41a863c2012-02-24 00:37:51 +010050 Py_ssize_t n_chars, Py_ssize_t n_zeros, STRINGLIB_CHAR* thousands_sep,
Eric Smith0923d1d2009-04-16 20:16:10 +000051 Py_ssize_t thousands_sep_len)
52{
Eric Smith0923d1d2009-04-16 20:16:10 +000053 Py_ssize_t i;
Eric Smith0923d1d2009-04-16 20:16:10 +000054
55 if (thousands_sep) {
56 *buffer_end -= thousands_sep_len;
57
58 /* Copy the thousands_sep chars into the buffer. */
Victor Stinner41a863c2012-02-24 00:37:51 +010059 memcpy(*buffer_end, thousands_sep,
60 thousands_sep_len * STRINGLIB_SIZEOF_CHAR);
Eric Smith0923d1d2009-04-16 20:16:10 +000061 }
62
63 *buffer_end -= n_chars;
64 *digits_end -= n_chars;
65 memcpy(*buffer_end, *digits_end, n_chars * sizeof(STRINGLIB_CHAR));
66
67 *buffer_end -= n_zeros;
Martin v. Löwisd63a3b82011-09-28 07:41:54 +020068 for (i = 0; i < n_zeros; i++)
69 (*buffer_end)[i] = '0';
Eric Smith0923d1d2009-04-16 20:16:10 +000070}
71
Eric Smith5807c412008-05-11 21:00:57 +000072/**
Victor Stinner41a863c2012-02-24 00:37:51 +010073 * InsertThousandsGrouping:
Eric Smith5807c412008-05-11 21:00:57 +000074 * @buffer: A pointer to the start of a string.
Eric Smith0923d1d2009-04-16 20:16:10 +000075 * @n_buffer: Number of characters in @buffer.
76 * @digits: A pointer to the digits we're reading from. If count
77 * is non-NULL, this is unused.
Eric Smith6d7e7a72008-06-24 01:06:47 +000078 * @n_digits: The number of digits in the string, in which we want
79 * to put the grouping chars.
Eric Smith0923d1d2009-04-16 20:16:10 +000080 * @min_width: The minimum width of the digits in the output string.
81 * Output will be zero-padded on the left to fill.
Eric Smitha3b1ac82009-04-03 14:45:06 +000082 * @grouping: see definition in localeconv().
83 * @thousands_sep: see definition in localeconv().
Eric Smith5807c412008-05-11 21:00:57 +000084 *
Eric Smith0923d1d2009-04-16 20:16:10 +000085 * There are 2 modes: counting and filling. If @buffer is NULL,
86 * we are in counting mode, else filling mode.
87 * If counting, the required buffer size is returned.
88 * If filling, we know the buffer will be large enough, so we don't
89 * need to pass in the buffer size.
Eric Smitha3b1ac82009-04-03 14:45:06 +000090 * Inserts thousand grouping characters (as defined by grouping and
91 * thousands_sep) into the string between buffer and buffer+n_digits.
Eric Smith5807c412008-05-11 21:00:57 +000092 *
93 * Return value: 0 on error, else 1. Note that no error can occur if
94 * count is non-NULL.
95 *
96 * This name won't be used, the includer of this file should define
97 * it to be the actual function name, based on unicode or string.
Eric Smith0923d1d2009-04-16 20:16:10 +000098 *
99 * As closely as possible, this code mimics the logic in decimal.py's
100 _insert_thousands_sep().
Eric Smith5807c412008-05-11 21:00:57 +0000101 **/
Eric Smith0923d1d2009-04-16 20:16:10 +0000102Py_ssize_t
Victor Stinner41a863c2012-02-24 00:37:51 +0100103STRINGLIB(InsertThousandsGrouping)(
104 STRINGLIB_CHAR *buffer,
105 Py_ssize_t n_buffer,
106 STRINGLIB_CHAR *digits,
107 Py_ssize_t n_digits,
108 Py_ssize_t min_width,
109 const char *grouping,
110 STRINGLIB_CHAR *thousands_sep,
111 Py_ssize_t thousands_sep_len)
Eric Smith5807c412008-05-11 21:00:57 +0000112{
Eric Smith0923d1d2009-04-16 20:16:10 +0000113 Py_ssize_t count = 0;
114 Py_ssize_t n_zeros;
115 int loop_broken = 0;
116 int use_separator = 0; /* First time through, don't append the
117 separator. They only go between
118 groups. */
119 STRINGLIB_CHAR *buffer_end = NULL;
120 STRINGLIB_CHAR *digits_end = NULL;
121 Py_ssize_t l;
122 Py_ssize_t n_chars;
Eric Smith0923d1d2009-04-16 20:16:10 +0000123 Py_ssize_t remaining = n_digits; /* Number of chars remaining to
124 be looked at */
125 /* A generator that returns all of the grouping widths, until it
126 returns 0. */
Martin v. Löwisd63a3b82011-09-28 07:41:54 +0200127 STRINGLIB(GroupGenerator) groupgen;
128 STRINGLIB(GroupGenerator_init)(&groupgen, grouping);
Eric Smith5807c412008-05-11 21:00:57 +0000129
Eric Smith0923d1d2009-04-16 20:16:10 +0000130 if (buffer) {
131 buffer_end = buffer + n_buffer;
132 digits_end = digits + n_digits;
133 }
134
Martin v. Löwisd63a3b82011-09-28 07:41:54 +0200135 while ((l = STRINGLIB(GroupGenerator_next)(&groupgen)) > 0) {
Victor Stinner41a863c2012-02-24 00:37:51 +0100136 l = Py_MIN(l, Py_MAX(Py_MAX(remaining, min_width), 1));
137 n_zeros = Py_MAX(0, l - remaining);
138 n_chars = Py_MAX(0, Py_MIN(remaining, l));
Eric Smith0923d1d2009-04-16 20:16:10 +0000139
140 /* Use n_zero zero's and n_chars chars */
141
142 /* Count only, don't do anything. */
143 count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars;
144
145 if (buffer) {
146 /* Copy into the output buffer. */
Martin v. Löwisd63a3b82011-09-28 07:41:54 +0200147 STRINGLIB(fill)(&digits_end, &buffer_end, n_chars, n_zeros,
Eric Smith0923d1d2009-04-16 20:16:10 +0000148 use_separator ? thousands_sep : NULL, thousands_sep_len);
Eric Smitha3b1ac82009-04-03 14:45:06 +0000149 }
Eric Smith5807c412008-05-11 21:00:57 +0000150
Eric Smith0923d1d2009-04-16 20:16:10 +0000151 /* Use a separator next time. */
152 use_separator = 1;
Eric Smith5807c412008-05-11 21:00:57 +0000153
Eric Smith0923d1d2009-04-16 20:16:10 +0000154 remaining -= n_chars;
155 min_width -= l;
Eric Smith5807c412008-05-11 21:00:57 +0000156
Eric Smith0923d1d2009-04-16 20:16:10 +0000157 if (remaining <= 0 && min_width <= 0) {
158 loop_broken = 1;
159 break;
Eric Smitha3b1ac82009-04-03 14:45:06 +0000160 }
Eric Smith0923d1d2009-04-16 20:16:10 +0000161 min_width -= thousands_sep_len;
162 }
163 if (!loop_broken) {
164 /* We left the loop without using a break statement. */
165
Victor Stinner41a863c2012-02-24 00:37:51 +0100166 l = Py_MAX(Py_MAX(remaining, min_width), 1);
167 n_zeros = Py_MAX(0, l - remaining);
168 n_chars = Py_MAX(0, Py_MIN(remaining, l));
Eric Smith0923d1d2009-04-16 20:16:10 +0000169
170 /* Use n_zero zero's and n_chars chars */
171 count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars;
172 if (buffer) {
173 /* Copy into the output buffer. */
Martin v. Löwisd63a3b82011-09-28 07:41:54 +0200174 STRINGLIB(fill)(&digits_end, &buffer_end, n_chars, n_zeros,
Eric Smith0923d1d2009-04-16 20:16:10 +0000175 use_separator ? thousands_sep : NULL, thousands_sep_len);
Eric Smitha3b1ac82009-04-03 14:45:06 +0000176 }
Eric Smith0923d1d2009-04-16 20:16:10 +0000177 }
178 return count;
Eric Smitha3b1ac82009-04-03 14:45:06 +0000179}
180