]> git.proxmox.com Git - mirror_edk2.git/blame - AppPkg/Applications/Python/PyMod-2.7.2/Objects/stringlib/localeutil.h
StdLib: Improve robustness of stat() and make basename() a public function.
[mirror_edk2.git] / AppPkg / Applications / Python / PyMod-2.7.2 / Objects / stringlib / localeutil.h
CommitLineData
41b152c5 1/** @file\r
2 stringlib: locale related helpers implementation.\r
3\r
4 Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials are licensed and made available under\r
6 the terms and conditions of the BSD License that accompanies this distribution.\r
7 The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12**/\r
6c0ebd5f 13\r
14#ifndef STRINGLIB_LOCALEUTIL_H\r
15#define STRINGLIB_LOCALEUTIL_H\r
16\r
17#include <locale.h>\r
18\r
19// Prevent conflicts with EFI\r
20#undef MAX\r
21#undef MIN\r
22\r
23#define MAX(x, y) ((x) < (y) ? (y) : (x))\r
24#define MIN(x, y) ((x) < (y) ? (x) : (y))\r
25\r
26typedef struct {\r
27 const char *grouping;\r
28 char previous;\r
29 Py_ssize_t i; /* Where we're currently pointing in grouping. */\r
30} GroupGenerator;\r
31\r
32static void\r
33_GroupGenerator_init(GroupGenerator *self, const char *grouping)\r
34{\r
35 self->grouping = grouping;\r
36 self->i = 0;\r
37 self->previous = 0;\r
38}\r
39\r
40/* Returns the next grouping, or 0 to signify end. */\r
41static Py_ssize_t\r
42_GroupGenerator_next(GroupGenerator *self)\r
43{\r
44 /* Note that we don't really do much error checking here. If a\r
45 grouping string contains just CHAR_MAX, for example, then just\r
46 terminate the generator. That shouldn't happen, but at least we\r
47 fail gracefully. */\r
48 switch (self->grouping[self->i]) {\r
49 case 0:\r
50 return self->previous;\r
51 case CHAR_MAX:\r
52 /* Stop the generator. */\r
53 return 0;\r
54 default: {\r
55 char ch = self->grouping[self->i];\r
56 self->previous = ch;\r
57 self->i++;\r
58 return (Py_ssize_t)ch;\r
59 }\r
60 }\r
61}\r
62\r
63/* Fill in some digits, leading zeros, and thousands separator. All\r
64 are optional, depending on when we're called. */\r
65static void\r
66fill(STRINGLIB_CHAR **digits_end, STRINGLIB_CHAR **buffer_end,\r
67 Py_ssize_t n_chars, Py_ssize_t n_zeros, const char* thousands_sep,\r
68 Py_ssize_t thousands_sep_len)\r
69{\r
70#if STRINGLIB_IS_UNICODE\r
71 Py_ssize_t i;\r
72#endif\r
73\r
74 if (thousands_sep) {\r
75 *buffer_end -= thousands_sep_len;\r
76\r
77 /* Copy the thousands_sep chars into the buffer. */\r
78#if STRINGLIB_IS_UNICODE\r
79 /* Convert from the char's of the thousands_sep from\r
80 the locale into unicode. */\r
81 for (i = 0; i < thousands_sep_len; ++i)\r
82 (*buffer_end)[i] = thousands_sep[i];\r
83#else\r
84 /* No conversion, just memcpy the thousands_sep. */\r
85 memcpy(*buffer_end, thousands_sep, thousands_sep_len);\r
86#endif\r
87 }\r
88\r
89 *buffer_end -= n_chars;\r
90 *digits_end -= n_chars;\r
91 memcpy(*buffer_end, *digits_end, n_chars * sizeof(STRINGLIB_CHAR));\r
92\r
93 *buffer_end -= n_zeros;\r
94 STRINGLIB_FILL(*buffer_end, '0', n_zeros);\r
95}\r
96\r
97/**\r
98 * _Py_InsertThousandsGrouping:\r
99 * @buffer: A pointer to the start of a string.\r
100 * @n_buffer: Number of characters in @buffer.\r
101 * @digits: A pointer to the digits we're reading from. If count\r
102 * is non-NULL, this is unused.\r
103 * @n_digits: The number of digits in the string, in which we want\r
104 * to put the grouping chars.\r
105 * @min_width: The minimum width of the digits in the output string.\r
106 * Output will be zero-padded on the left to fill.\r
107 * @grouping: see definition in localeconv().\r
108 * @thousands_sep: see definition in localeconv().\r
109 *\r
110 * There are 2 modes: counting and filling. If @buffer is NULL,\r
111 * we are in counting mode, else filling mode.\r
112 * If counting, the required buffer size is returned.\r
113 * If filling, we know the buffer will be large enough, so we don't\r
114 * need to pass in the buffer size.\r
115 * Inserts thousand grouping characters (as defined by grouping and\r
116 * thousands_sep) into the string between buffer and buffer+n_digits.\r
117 *\r
118 * Return value: 0 on error, else 1. Note that no error can occur if\r
119 * count is non-NULL.\r
120 *\r
121 * This name won't be used, the includer of this file should define\r
122 * it to be the actual function name, based on unicode or string.\r
123 *\r
124 * As closely as possible, this code mimics the logic in decimal.py's\r
125 _insert_thousands_sep().\r
126 **/\r
127Py_ssize_t\r
128_Py_InsertThousandsGrouping(STRINGLIB_CHAR *buffer,\r
129 Py_ssize_t n_buffer,\r
130 STRINGLIB_CHAR *digits,\r
131 Py_ssize_t n_digits,\r
132 Py_ssize_t min_width,\r
133 const char *grouping,\r
134 const char *thousands_sep)\r
135{\r
136 Py_ssize_t count = 0;\r
137 Py_ssize_t n_zeros;\r
138 int loop_broken = 0;\r
139 int use_separator = 0; /* First time through, don't append the\r
140 separator. They only go between\r
141 groups. */\r
142 STRINGLIB_CHAR *buffer_end = NULL;\r
143 STRINGLIB_CHAR *digits_end = NULL;\r
144 Py_ssize_t l;\r
145 Py_ssize_t n_chars;\r
146 Py_ssize_t thousands_sep_len = strlen(thousands_sep);\r
147 Py_ssize_t remaining = n_digits; /* Number of chars remaining to\r
148 be looked at */\r
149 /* A generator that returns all of the grouping widths, until it\r
150 returns 0. */\r
151 GroupGenerator groupgen;\r
152 _GroupGenerator_init(&groupgen, grouping);\r
153\r
154 if (buffer) {\r
155 buffer_end = buffer + n_buffer;\r
156 digits_end = digits + n_digits;\r
157 }\r
158\r
159 while ((l = _GroupGenerator_next(&groupgen)) > 0) {\r
160 l = MIN(l, MAX(MAX(remaining, min_width), 1));\r
161 n_zeros = MAX(0, l - remaining);\r
162 n_chars = MAX(0, MIN(remaining, l));\r
163\r
164 /* Use n_zero zero's and n_chars chars */\r
165\r
166 /* Count only, don't do anything. */\r
167 count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars;\r
168\r
169 if (buffer) {\r
170 /* Copy into the output buffer. */\r
171 fill(&digits_end, &buffer_end, n_chars, n_zeros,\r
172 use_separator ? thousands_sep : NULL, thousands_sep_len);\r
173 }\r
174\r
175 /* Use a separator next time. */\r
176 use_separator = 1;\r
177\r
178 remaining -= n_chars;\r
179 min_width -= l;\r
180\r
181 if (remaining <= 0 && min_width <= 0) {\r
182 loop_broken = 1;\r
183 break;\r
184 }\r
185 min_width -= thousands_sep_len;\r
186 }\r
187 if (!loop_broken) {\r
188 /* We left the loop without using a break statement. */\r
189\r
190 l = MAX(MAX(remaining, min_width), 1);\r
191 n_zeros = MAX(0, l - remaining);\r
192 n_chars = MAX(0, MIN(remaining, l));\r
193\r
194 /* Use n_zero zero's and n_chars chars */\r
195 count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars;\r
196 if (buffer) {\r
197 /* Copy into the output buffer. */\r
198 fill(&digits_end, &buffer_end, n_chars, n_zeros,\r
199 use_separator ? thousands_sep : NULL, thousands_sep_len);\r
200 }\r
201 }\r
202 return count;\r
203}\r
204\r
205/**\r
206 * _Py_InsertThousandsGroupingLocale:\r
207 * @buffer: A pointer to the start of a string.\r
208 * @n_digits: The number of digits in the string, in which we want\r
209 * to put the grouping chars.\r
210 *\r
211 * Reads thee current locale and calls _Py_InsertThousandsGrouping().\r
212 **/\r
213Py_ssize_t\r
214_Py_InsertThousandsGroupingLocale(STRINGLIB_CHAR *buffer,\r
215 Py_ssize_t n_buffer,\r
216 STRINGLIB_CHAR *digits,\r
217 Py_ssize_t n_digits,\r
218 Py_ssize_t min_width)\r
219{\r
220 struct lconv *locale_data = localeconv();\r
221 const char *grouping = locale_data->grouping;\r
222 const char *thousands_sep = locale_data->thousands_sep;\r
223\r
224 return _Py_InsertThousandsGrouping(buffer, n_buffer, digits, n_digits,\r
225 min_width, grouping, thousands_sep);\r
226}\r
227#endif /* STRINGLIB_LOCALEUTIL_H */\r