|
1 /* stringlib: locale related helpers implementation */ |
|
2 |
|
3 #ifndef STRINGLIB_LOCALEUTIL_H |
|
4 #define STRINGLIB_LOCALEUTIL_H |
|
5 |
|
6 #include <locale.h> |
|
7 |
|
8 /** |
|
9 * _Py_InsertThousandsGrouping: |
|
10 * @buffer: A pointer to the start of a string. |
|
11 * @n_buffer: The length of the string. |
|
12 * @n_digits: The number of digits in the string, in which we want |
|
13 * to put the grouping chars. |
|
14 * @buf_size: The maximum size of the buffer pointed to by buffer. |
|
15 * @count: If non-NULL, points to a variable that will receive the |
|
16 * number of characters we need to insert (and no formatting |
|
17 * will actually occur). |
|
18 * @append_zero_char: If non-zero, put a trailing zero at the end of |
|
19 * of the resulting string, if and only if we modified the |
|
20 * string. |
|
21 * |
|
22 * Inserts thousand grouping characters (as defined in the current |
|
23 * locale) into the string between buffer and buffer+n_digits. If |
|
24 * count is non-NULL, don't do any formatting, just count the number |
|
25 * of characters to insert. This is used by the caller to |
|
26 * appropriately resize the buffer, if needed. If count is non-NULL, |
|
27 * buffer can be NULL (it is not dereferenced at all in that case). |
|
28 * |
|
29 * Return value: 0 on error, else 1. Note that no error can occur if |
|
30 * count is non-NULL. |
|
31 * |
|
32 * This name won't be used, the includer of this file should define |
|
33 * it to be the actual function name, based on unicode or string. |
|
34 **/ |
|
35 int |
|
36 _Py_InsertThousandsGrouping(STRINGLIB_CHAR *buffer, |
|
37 Py_ssize_t n_buffer, |
|
38 Py_ssize_t n_digits, |
|
39 Py_ssize_t buf_size, |
|
40 Py_ssize_t *count, |
|
41 int append_zero_char) |
|
42 { |
|
43 struct lconv *locale_data = localeconv(); |
|
44 const char *grouping = locale_data->grouping; |
|
45 const char *thousands_sep = locale_data->thousands_sep; |
|
46 Py_ssize_t thousands_sep_len = strlen(thousands_sep); |
|
47 STRINGLIB_CHAR *pend = NULL; /* current end of buffer */ |
|
48 STRINGLIB_CHAR *pmax = NULL; /* max of buffer */ |
|
49 char current_grouping; |
|
50 Py_ssize_t remaining = n_digits; /* Number of chars remaining to |
|
51 be looked at */ |
|
52 |
|
53 /* Initialize the character count, if we're just counting. */ |
|
54 if (count) |
|
55 *count = 0; |
|
56 else { |
|
57 /* We're not just counting, we're modifying buffer */ |
|
58 pend = buffer + n_buffer; |
|
59 pmax = buffer + buf_size; |
|
60 } |
|
61 |
|
62 /* Starting at the end and working right-to-left, keep track of |
|
63 what grouping needs to be added and insert that. */ |
|
64 current_grouping = *grouping++; |
|
65 |
|
66 /* If the first character is 0, perform no grouping at all. */ |
|
67 if (current_grouping == 0) |
|
68 return 1; |
|
69 |
|
70 while (remaining > current_grouping) { |
|
71 /* Always leave buffer and pend valid at the end of this |
|
72 loop, since we might leave with a return statement. */ |
|
73 |
|
74 remaining -= current_grouping; |
|
75 if (count) { |
|
76 /* We're only counting, not touching the memory. */ |
|
77 *count += thousands_sep_len; |
|
78 } |
|
79 else { |
|
80 /* Do the formatting. */ |
|
81 |
|
82 STRINGLIB_CHAR *plast = buffer + remaining; |
|
83 |
|
84 /* Is there room to insert thousands_sep_len chars? */ |
|
85 if (pmax - pend < thousands_sep_len) |
|
86 /* No room. */ |
|
87 return 0; |
|
88 |
|
89 /* Move the rest of the string down. */ |
|
90 memmove(plast + thousands_sep_len, |
|
91 plast, |
|
92 (pend - plast) * sizeof(STRINGLIB_CHAR)); |
|
93 /* Copy the thousands_sep chars into the buffer. */ |
|
94 #if STRINGLIB_IS_UNICODE |
|
95 /* Convert from the char's of the thousands_sep from |
|
96 the locale into unicode. */ |
|
97 { |
|
98 Py_ssize_t i; |
|
99 for (i = 0; i < thousands_sep_len; ++i) |
|
100 plast[i] = thousands_sep[i]; |
|
101 } |
|
102 #else |
|
103 /* No conversion, just memcpy the thousands_sep. */ |
|
104 memcpy(plast, thousands_sep, thousands_sep_len); |
|
105 #endif |
|
106 } |
|
107 |
|
108 /* Adjust end pointer. */ |
|
109 pend += thousands_sep_len; |
|
110 |
|
111 /* Move to the next grouping character, unless we're |
|
112 repeating (which is designated by a grouping of 0). */ |
|
113 if (*grouping != 0) { |
|
114 current_grouping = *grouping++; |
|
115 if (current_grouping == CHAR_MAX) |
|
116 /* We're done. */ |
|
117 break; |
|
118 } |
|
119 } |
|
120 if (append_zero_char) { |
|
121 /* Append a zero character to mark the end of the string, |
|
122 if there's room. */ |
|
123 if (pend - (buffer + remaining) < 1) |
|
124 /* No room, error. */ |
|
125 return 0; |
|
126 *pend = 0; |
|
127 } |
|
128 return 1; |
|
129 } |
|
130 #endif /* STRINGLIB_LOCALEUTIL_H */ |