/home/mdboom/Work/builds/cpython/Python/formatter_unicode.c
Line | Count | Source (jump to first uncovered line) |
1 | /* implements the unicode (as opposed to string) version of the |
2 | built-in formatters for string, int, float. that is, the versions |
3 | of int.__float__, etc., that take and return unicode objects */ |
4 | |
5 | #include "Python.h" |
6 | #include "pycore_fileutils.h" // _Py_GetLocaleconvNumeric() |
7 | #include "pycore_long.h" // _PyLong_FormatWriter() |
8 | #include <locale.h> |
9 | |
10 | /* Raises an exception about an unknown presentation type for this |
11 | * type. */ |
12 | |
13 | static void |
14 | unknown_presentation_type(Py_UCS4 presentation_type, |
15 | const char* type_name) |
16 | { |
17 | /* %c might be out-of-range, hence the two cases. */ |
18 | if (presentation_type > 32 && presentation_type < 128) Branch (18:9): [True: 411, False: 0]
Branch (18:35): [True: 411, False: 0]
|
19 | PyErr_Format(PyExc_ValueError, |
20 | "Unknown format code '%c' " |
21 | "for object of type '%.200s'", |
22 | (char)presentation_type, |
23 | type_name); |
24 | else |
25 | PyErr_Format(PyExc_ValueError, |
26 | "Unknown format code '\\x%x' " |
27 | "for object of type '%.200s'", |
28 | (unsigned int)presentation_type, |
29 | type_name); |
30 | } |
31 | |
32 | static void |
33 | invalid_thousands_separator_type(char specifier, Py_UCS4 presentation_type) |
34 | { |
35 | assert(specifier == ',' || specifier == '_'); |
36 | if (presentation_type > 32 && presentation_type < 128) Branch (36:9): [True: 19, False: 0]
Branch (36:35): [True: 19, False: 0]
|
37 | PyErr_Format(PyExc_ValueError, |
38 | "Cannot specify '%c' with '%c'.", |
39 | specifier, (char)presentation_type); |
40 | else |
41 | PyErr_Format(PyExc_ValueError, |
42 | "Cannot specify '%c' with '\\x%x'.", |
43 | specifier, (unsigned int)presentation_type); |
44 | } |
45 | |
46 | static void |
47 | invalid_comma_and_underscore(void) |
48 | { |
49 | PyErr_Format(PyExc_ValueError, "Cannot specify both ',' and '_'."); |
50 | } |
51 | |
52 | /* |
53 | get_integer consumes 0 or more decimal digit characters from an |
54 | input string, updates *result with the corresponding positive |
55 | integer, and returns the number of digits consumed. |
56 | |
57 | returns -1 on error. |
58 | */ |
59 | static int |
60 | get_integer(PyObject *str, Py_ssize_t *ppos, Py_ssize_t end, |
61 | Py_ssize_t *result) |
62 | { |
63 | Py_ssize_t accumulator, digitval, pos = *ppos; |
64 | int numdigits; |
65 | int kind = PyUnicode_KIND(str); |
66 | const void *data = PyUnicode_DATA(str); |
67 | |
68 | accumulator = numdigits = 0; |
69 | for (; pos < end; pos++, numdigits++179k ) { Branch (69:12): [True: 373k, False: 8.41k]
|
70 | digitval = Py_UNICODE_TODECIMAL(PyUnicode_READ(kind, data, pos)); |
71 | if (digitval < 0) Branch (71:13): [True: 193k, False: 179k]
|
72 | break; |
73 | /* |
74 | Detect possible overflow before it happens: |
75 | |
76 | accumulator * 10 + digitval > PY_SSIZE_T_MAX if and only if |
77 | accumulator > (PY_SSIZE_T_MAX - digitval) / 10. |
78 | */ |
79 | if (accumulator > (PY_SSIZE_T_MAX - digitval) / 10) { Branch (79:13): [True: 7, False: 179k]
|
80 | PyErr_Format(PyExc_ValueError, |
81 | "Too many decimal digits in format string"); |
82 | *ppos = pos; |
83 | return -1; |
84 | } |
85 | accumulator = accumulator * 10 + digitval; |
86 | } |
87 | *ppos = pos; |
88 | *result = accumulator; |
89 | return numdigits; |
90 | } |
91 | |
92 | /************************************************************************/ |
93 | /*********** standard format specifier parsing **************************/ |
94 | /************************************************************************/ |
95 | |
96 | /* returns true if this character is a specifier alignment token */ |
97 | Py_LOCAL_INLINE(int) |
98 | is_alignment_token(Py_UCS4 c) |
99 | { |
100 | switch (c) { |
101 | case '<': 83 case '>': 1.50k case '=': 1.52k case '^': Branch (101:5): [True: 83, False: 362k]
Branch (101:15): [True: 1.42k, False: 361k]
Branch (101:25): [True: 13, False: 362k]
Branch (101:35): [True: 75, False: 362k]
|
102 | return 1; |
103 | default: Branch (103:5): [True: 361k, False: 1.59k]
|
104 | return 0; |
105 | } |
106 | } |
107 | |
108 | /* returns true if this character is a sign element */ |
109 | Py_LOCAL_INLINE(int) |
110 | is_sign_element(Py_UCS4 c) |
111 | { |
112 | switch (c) { |
113 | case ' ': 81 case '+': 18.6k case '-': Branch (113:5): [True: 81, False: 191k]
Branch (113:15): [True: 18.5k, False: 173k]
Branch (113:25): [True: 44, False: 191k]
|
114 | return 1; |
115 | default: Branch (115:5): [True: 173k, False: 18.7k]
|
116 | return 0; |
117 | } |
118 | } |
119 | |
120 | /* Locale type codes. LT_NO_LOCALE must be zero. */ |
121 | enum LocaleType { |
122 | LT_NO_LOCALE = 0, |
123 | LT_DEFAULT_LOCALE = ',', |
124 | LT_UNDERSCORE_LOCALE = '_', |
125 | LT_UNDER_FOUR_LOCALE, |
126 | LT_CURRENT_LOCALE |
127 | }; |
128 | |
129 | typedef struct { |
130 | Py_UCS4 fill_char; |
131 | Py_UCS4 align; |
132 | int alternate; |
133 | int no_neg_0; |
134 | Py_UCS4 sign; |
135 | Py_ssize_t width; |
136 | enum LocaleType thousands_separators; |
137 | Py_ssize_t precision; |
138 | Py_UCS4 type; |
139 | } InternalFormatSpec; |
140 | |
141 | |
142 | /* |
143 | ptr points to the start of the format_spec, end points just past its end. |
144 | fills in format with the parsed information. |
145 | returns 1 on success, 0 on failure. |
146 | if failure, sets the exception |
147 | */ |
148 | static int |
149 | parse_internal_render_format_spec(PyObject *obj, |
150 | PyObject *format_spec, |
151 | Py_ssize_t start, Py_ssize_t end, |
152 | InternalFormatSpec *format, |
153 | char default_type, |
154 | char default_align) |
155 | { |
156 | Py_ssize_t pos = start; |
157 | int kind = PyUnicode_KIND(format_spec); |
158 | const void *data = PyUnicode_DATA(format_spec); |
159 | /* end-pos is used throughout this code to specify the length of |
160 | the input string */ |
161 | #define READ_spec(index) PyUnicode_READ(kind, data, index) |
162 | |
163 | Py_ssize_t consumed; |
164 | int align_specified = 0; |
165 | int fill_char_specified = 0; |
166 | |
167 | format->fill_char = ' '; |
168 | format->align = default_align; |
169 | format->alternate = 0; |
170 | format->no_neg_0 = 0; |
171 | format->sign = '\0'; |
172 | format->width = -1; |
173 | format->thousands_separators = LT_NO_LOCALE; |
174 | format->precision = -1; |
175 | format->type = default_type; |
176 | |
177 | /* If the second char is an alignment token, |
178 | then parse the fill char */ |
179 | if (end-pos >= 2 && is_alignment_token(171k READ_spec171k (pos+1))) { Branch (179:9): [True: 171k, False: 20.8k]
Branch (179:25): [True: 74, False: 170k]
|
180 | format->align = READ_spec(pos+1); |
181 | format->fill_char = READ_spec(pos); |
182 | fill_char_specified = 1; |
183 | align_specified = 1; |
184 | pos += 2; |
185 | } |
186 | else if (end-pos >= 1 && is_alignment_token(READ_spec(pos))) { Branch (186:14): [True: 191k, False: 0]
Branch (186:30): [True: 1.52k, False: 190k]
|
187 | format->align = READ_spec(pos); |
188 | align_specified = 1; |
189 | ++pos; |
190 | } |
191 | |
192 | /* Parse the various sign options */ |
193 | if (end-pos >= 1 && is_sign_element(191k READ_spec191k (pos))) { Branch (193:9): [True: 191k, False: 5]
Branch (193:25): [True: 18.7k, False: 173k]
|
194 | format->sign = READ_spec(pos); |
195 | ++pos; |
196 | } |
197 | |
198 | /* If the next character is z, request coercion of negative 0. |
199 | Applies only to floats. */ |
200 | if (end-pos >= 1 && READ_spec191k (pos) == 'z'191k ) { Branch (200:9): [True: 191k, False: 62]
Branch (200:25): [True: 50, False: 191k]
|
201 | format->no_neg_0 = 1; |
202 | ++pos; |
203 | } |
204 | |
205 | /* If the next character is #, we're in alternate mode. This only |
206 | applies to integers. */ |
207 | if (end-pos >= 1 && READ_spec191k (pos) == '#'191k ) { Branch (207:9): [True: 191k, False: 70]
Branch (207:25): [True: 194, False: 191k]
|
208 | format->alternate = 1; |
209 | ++pos; |
210 | } |
211 | |
212 | /* The special case for 0-padding (backwards compat) */ |
213 | if (!fill_char_specified && end-pos >= 1191k && READ_spec191k (pos) == '0'191k ) { Branch (213:9): [True: 191k, False: 74]
Branch (213:33): [True: 191k, False: 71]
Branch (213:49): [True: 138k, False: 53.6k]
|
214 | format->fill_char = '0'; |
215 | if (!align_specified && default_align == '>'138k ) { Branch (215:13): [True: 138k, False: 3]
Branch (215:33): [True: 138k, False: 2]
|
216 | format->align = '='; |
217 | } |
218 | ++pos; |
219 | } |
220 | |
221 | consumed = get_integer(format_spec, &pos, end, &format->width); |
222 | if (consumed == -1) Branch (222:9): [True: 3, False: 191k]
|
223 | /* Overflow error. Exception already set. */ |
224 | return 0; |
225 | |
226 | /* If consumed is 0, we didn't consume any characters for the |
227 | width. In that case, reset the width to -1, because |
228 | get_integer() will have set it to zero. -1 is how we record |
229 | that the width wasn't specified. */ |
230 | if (consumed == 0) Branch (230:9): [True: 46.4k, False: 145k]
|
231 | format->width = -1; |
232 | |
233 | /* Comma signifies add thousands separators */ |
234 | if (end-pos && READ_spec186k (pos) == ','186k ) { Branch (234:9): [True: 186k, False: 5.20k]
Branch (234:20): [True: 56, False: 186k]
|
235 | format->thousands_separators = LT_DEFAULT_LOCALE; |
236 | ++pos; |
237 | } |
238 | /* Underscore signifies add thousands separators */ |
239 | if (end-pos && READ_spec186k (pos) == '_'186k ) { Branch (239:9): [True: 186k, False: 5.21k]
Branch (239:20): [True: 102, False: 186k]
|
240 | if (format->thousands_separators != LT_NO_LOCALE) { Branch (240:13): [True: 4, False: 98]
|
241 | invalid_comma_and_underscore(); |
242 | return 0; |
243 | } |
244 | format->thousands_separators = LT_UNDERSCORE_LOCALE; |
245 | ++pos; |
246 | } |
247 | if (end-pos && READ_spec186k (pos) == ','186k ) { Branch (247:9): [True: 186k, False: 5.21k]
Branch (247:20): [True: 6, False: 186k]
|
248 | if (format->thousands_separators == LT_UNDERSCORE_LOCALE) { Branch (248:13): [True: 4, False: 2]
|
249 | invalid_comma_and_underscore(); |
250 | return 0; |
251 | } |
252 | } |
253 | |
254 | /* Parse field precision */ |
255 | if (end-pos && READ_spec186k (pos) == '.'186k ) { Branch (255:9): [True: 186k, False: 5.21k]
Branch (255:20): [True: 9.91k, False: 176k]
|
256 | ++pos; |
257 | |
258 | consumed = get_integer(format_spec, &pos, end, &format->precision); |
259 | if (consumed == -1) Branch (259:13): [True: 4, False: 9.90k]
|
260 | /* Overflow error. Exception already set. */ |
261 | return 0; |
262 | |
263 | /* Not having a precision after a dot is an error. */ |
264 | if (consumed == 0) { Branch (264:13): [True: 0, False: 9.90k]
|
265 | PyErr_Format(PyExc_ValueError, |
266 | "Format specifier missing precision"); |
267 | return 0; |
268 | } |
269 | |
270 | } |
271 | |
272 | /* Finally, parse the type field. */ |
273 | |
274 | if (end-pos > 1) { Branch (274:9): [True: 15, False: 191k]
|
275 | /* More than one char remains, so this is an invalid format |
276 | specifier. */ |
277 | /* Create a temporary object that contains the format spec we're |
278 | operating on. It's format_spec[start:end] (in Python syntax). */ |
279 | PyObject* actual_format_spec = PyUnicode_FromKindAndData(kind, |
280 | (char*)data + kind*start, |
281 | end-start); |
282 | if (actual_format_spec != NULL) { Branch (282:13): [True: 15, False: 0]
|
283 | PyErr_Format(PyExc_ValueError, |
284 | "Invalid format specifier '%U' for object of type '%.200s'", |
285 | actual_format_spec, Py_TYPE(obj)->tp_name); |
286 | Py_DECREF(actual_format_spec); |
287 | } |
288 | return 0; |
289 | } |
290 | |
291 | if (end-pos == 1) { Branch (291:9): [True: 183k, False: 8.42k]
|
292 | format->type = READ_spec(pos); |
293 | ++pos; |
294 | } |
295 | |
296 | /* Do as much validating as we can, just by looking at the format |
297 | specifier. Do not take into account what type of formatting |
298 | we're doing (int, float, string). */ |
299 | |
300 | if (format->thousands_separators) { Branch (300:9): [True: 146, False: 191k]
|
301 | switch (format->type) { |
302 | case 'd': Branch (302:9): [True: 80, False: 66]
|
303 | case 'e': Branch (303:9): [True: 0, False: 146]
|
304 | case 'f': Branch (304:9): [True: 25, False: 121]
|
305 | case 'g': Branch (305:9): [True: 0, False: 146]
|
306 | case 'E': Branch (306:9): [True: 0, False: 146]
|
307 | case 'G': Branch (307:9): [True: 0, False: 146]
|
308 | case '%': Branch (308:9): [True: 0, False: 146]
|
309 | case 'F': Branch (309:9): [True: 0, False: 146]
|
310 | case '\0': Branch (310:9): [True: 2, False: 144]
|
311 | /* These are allowed. See PEP 378.*/ |
312 | break; |
313 | case 'b': Branch (313:9): [True: 9, False: 137]
|
314 | case 'o': Branch (314:9): [True: 3, False: 143]
|
315 | case 'x': Branch (315:9): [True: 9, False: 137]
|
316 | case 'X': Branch (316:9): [True: 6, False: 140]
|
317 | /* Underscores are allowed in bin/oct/hex. See PEP 515. */ |
318 | if (format->thousands_separators == LT_UNDERSCORE_LOCALE) { Branch (318:17): [True: 20, False: 7]
|
319 | /* Every four digits, not every three, in bin/oct/hex. */ |
320 | format->thousands_separators = LT_UNDER_FOUR_LOCALE; |
321 | break; |
322 | } |
323 | /* fall through */ |
324 | default: Branch (324:9): [True: 12, False: 134]
|
325 | invalid_thousands_separator_type(format->thousands_separators, format->type); |
326 | return 0; |
327 | } |
328 | } |
329 | |
330 | assert (format->align <= 127); |
331 | assert (format->sign <= 127); |
332 | return 1; |
333 | } |
334 | |
335 | /* Calculate the padding needed. */ |
336 | static void |
337 | calc_padding(Py_ssize_t nchars, Py_ssize_t width, Py_UCS4 align, |
338 | Py_ssize_t *n_lpadding, Py_ssize_t *n_rpadding, |
339 | Py_ssize_t *n_total) |
340 | { |
341 | if (width >= 0) { Branch (341:9): [True: 6.29k, False: 778]
|
342 | if (nchars > width) Branch (342:13): [True: 195, False: 6.09k]
|
343 | *n_total = nchars; |
344 | else |
345 | *n_total = width; |
346 | } |
347 | else { |
348 | /* not specified, use all of the chars and no more */ |
349 | *n_total = nchars; |
350 | } |
351 | |
352 | /* Figure out how much leading space we need, based on the |
353 | aligning */ |
354 | if (align == '>') Branch (354:9): [True: 1.29k, False: 5.78k]
|
355 | *n_lpadding = *n_total - nchars; |
356 | else if (align == '^') Branch (356:14): [True: 48, False: 5.73k]
|
357 | *n_lpadding = (*n_total - nchars) / 2; |
358 | else if (align == '<' || align == '='0 ) Branch (358:14): [True: 5.73k, False: 0]
Branch (358:30): [True: 0, False: 0]
|
359 | *n_lpadding = 0; |
360 | else { |
361 | /* We should never have an unspecified alignment. */ |
362 | Py_UNREACHABLE(); |
363 | } |
364 | |
365 | *n_rpadding = *n_total - nchars - *n_lpadding; |
366 | } |
367 | |
368 | /* Do the padding, and return a pointer to where the caller-supplied |
369 | content goes. */ |
370 | static int |
371 | fill_padding(_PyUnicodeWriter *writer, |
372 | Py_ssize_t nchars, |
373 | Py_UCS4 fill_char, Py_ssize_t n_lpadding, |
374 | Py_ssize_t n_rpadding) |
375 | { |
376 | Py_ssize_t pos; |
377 | |
378 | /* Pad on left. */ |
379 | if (n_lpadding) { Branch (379:9): [True: 1.17k, False: 5.89k]
|
380 | pos = writer->pos; |
381 | _PyUnicode_FastFill(writer->buffer, pos, n_lpadding, fill_char); |
382 | } |
383 | |
384 | /* Pad on right. */ |
385 | if (n_rpadding) { Branch (385:9): [True: 4.96k, False: 2.10k]
|
386 | pos = writer->pos + nchars + n_lpadding; |
387 | _PyUnicode_FastFill(writer->buffer, pos, n_rpadding, fill_char); |
388 | } |
389 | |
390 | /* Pointer to the user content. */ |
391 | writer->pos += n_lpadding; |
392 | return 0; |
393 | } |
394 | |
395 | /************************************************************************/ |
396 | /*********** common routines for numeric formatting *********************/ |
397 | /************************************************************************/ |
398 | |
399 | /* Locale info needed for formatting integers and the part of floats |
400 | before and including the decimal. Note that locales only support |
401 | 8-bit chars, not unicode. */ |
402 | typedef struct { |
403 | PyObject *decimal_point; |
404 | PyObject *thousands_sep; |
405 | const char *grouping; |
406 | char *grouping_buffer; |
407 | } LocaleInfo; |
408 | |
409 | #define LocaleInfo_STATIC_INIT {0, 0, 0, 0} |
410 | |
411 | /* describes the layout for an integer, see the comment in |
412 | calc_number_widths() for details */ |
413 | typedef struct { |
414 | Py_ssize_t n_lpadding; |
415 | Py_ssize_t n_prefix; |
416 | Py_ssize_t n_spadding; |
417 | Py_ssize_t n_rpadding; |
418 | char sign; |
419 | Py_ssize_t n_sign; /* number of digits needed for sign (0/1) */ |
420 | Py_ssize_t n_grouped_digits; /* Space taken up by the digits, including |
421 | any grouping chars. */ |
422 | Py_ssize_t n_decimal; /* 0 if only an integer */ |
423 | Py_ssize_t n_remainder; /* Digits in decimal and/or exponent part, |
424 | excluding the decimal itself, if |
425 | present. */ |
426 | |
427 | /* These 2 are not the widths of fields, but are needed by |
428 | STRINGLIB_GROUPING. */ |
429 | Py_ssize_t n_digits; /* The number of digits before a decimal |
430 | or exponent. */ |
431 | Py_ssize_t n_min_width; /* The min_width we used when we computed |
432 | the n_grouped_digits width. */ |
433 | } NumberFieldWidths; |
434 | |
435 | |
436 | /* Given a number of the form: |
437 | digits[remainder] |
438 | where ptr points to the start and end points to the end, find where |
439 | the integer part ends. This could be a decimal, an exponent, both, |
440 | or neither. |
441 | If a decimal point is present, set *has_decimal and increment |
442 | remainder beyond it. |
443 | Results are undefined (but shouldn't crash) for improperly |
444 | formatted strings. |
445 | */ |
446 | static void |
447 | parse_number(PyObject *s, Py_ssize_t pos, Py_ssize_t end, |
448 | Py_ssize_t *n_remainder, int *has_decimal) |
449 | { |
450 | Py_ssize_t remainder; |
451 | int kind = PyUnicode_KIND(s); |
452 | const void *data = PyUnicode_DATA(s); |
453 | |
454 | while (pos<end && Py_ISDIGIT1.16k (PyUnicode_READ(kind, data, pos))) Branch (454:12): [True: 1.16k, False: 65]
|
455 | ++pos; |
456 | remainder = pos; |
457 | |
458 | /* Does remainder start with a decimal point? */ |
459 | *has_decimal = pos<end && PyUnicode_READ402 (kind, data, remainder) == '.'402 ; Branch (459:20): [True: 402, False: 65]
Branch (459:31): [True: 280, False: 122]
|
460 | |
461 | /* Skip the decimal point. */ |
462 | if (*has_decimal) Branch (462:9): [True: 280, False: 187]
|
463 | remainder++; |
464 | |
465 | *n_remainder = end - remainder; |
466 | } |
467 | |
468 | /* not all fields of format are used. for example, precision is |
469 | unused. should this take discrete params in order to be more clear |
470 | about what it does? or is passing a single format parameter easier |
471 | and more efficient enough to justify a little obfuscation? |
472 | Return -1 on error. */ |
473 | static Py_ssize_t |
474 | calc_number_widths(NumberFieldWidths *spec, Py_ssize_t n_prefix, |
475 | Py_UCS4 sign_char, Py_ssize_t n_start, |
476 | Py_ssize_t n_end, Py_ssize_t n_remainder, |
477 | int has_decimal, const LocaleInfo *locale, |
478 | const InternalFormatSpec *format, Py_UCS4 *maxchar) |
479 | { |
480 | Py_ssize_t n_non_digit_non_padding; |
481 | Py_ssize_t n_padding; |
482 | |
483 | spec->n_digits = n_end - n_start - n_remainder - (has_decimal?1280 :0157k ); Branch (483:55): [True: 280, False: 157k]
|
484 | spec->n_lpadding = 0; |
485 | spec->n_prefix = n_prefix; |
486 | spec->n_decimal = has_decimal ? PyUnicode_GET_LENGTH280 (locale->decimal_point) : 0157k ; Branch (486:23): [True: 280, False: 157k]
|
487 | spec->n_remainder = n_remainder; |
488 | spec->n_spadding = 0; |
489 | spec->n_rpadding = 0; |
490 | spec->sign = '\0'; |
491 | spec->n_sign = 0; |
492 | |
493 | /* the output will look like: |
494 | | | |
495 | | <lpadding> <sign> <prefix> <spadding> <grouped_digits> <decimal> <remainder> <rpadding> | |
496 | | | |
497 | |
498 | sign is computed from format->sign and the actual |
499 | sign of the number |
500 | |
501 | prefix is given (it's for the '0x' prefix) |
502 | |
503 | digits is already known |
504 | |
505 | the total width is either given, or computed from the |
506 | actual digits |
507 | |
508 | only one of lpadding, spadding, and rpadding can be non-zero, |
509 | and it's calculated from the width and other fields |
510 | */ |
511 | |
512 | /* compute the various parts we're going to write */ |
513 | switch (format->sign) { |
514 | case '+': Branch (514:5): [True: 18.6k, False: 138k]
|
515 | /* always put a + or - */ |
516 | spec->n_sign = 1; |
517 | spec->sign = (sign_char == '-' ? '-'5.37k : '+'13.3k ); Branch (517:23): [True: 5.37k, False: 13.3k]
|
518 | break; |
519 | case ' ': Branch (519:5): [True: 80, False: 157k]
|
520 | spec->n_sign = 1; |
521 | spec->sign = (sign_char == '-' ? '-'28 : ' '52 ); Branch (521:23): [True: 28, False: 52]
|
522 | break; |
523 | default: Branch (523:5): [True: 138k, False: 18.7k]
|
524 | /* Not specified, or the default (-) */ |
525 | if (sign_char == '-') { Branch (525:13): [True: 88, False: 138k]
|
526 | spec->n_sign = 1; |
527 | spec->sign = '-'; |
528 | } |
529 | } |
530 | |
531 | /* The number of chars used for non-digits and non-padding. */ |
532 | n_non_digit_non_padding = spec->n_sign + spec->n_prefix + spec->n_decimal + |
533 | spec->n_remainder; |
534 | |
535 | /* min_width can go negative, that's okay. format->width == -1 means |
536 | we don't care. */ |
537 | if (format->fill_char == '0' && format->align == '='138k ) Branch (537:9): [True: 138k, False: 19.4k]
Branch (537:37): [True: 138k, False: 6]
|
538 | spec->n_min_width = format->width - n_non_digit_non_padding; |
539 | else |
540 | spec->n_min_width = 0; |
541 | |
542 | if (spec->n_digits == 0) Branch (542:9): [True: 117, False: 157k]
|
543 | /* This case only occurs when using 'c' formatting, we need |
544 | to special case it because the grouping code always wants |
545 | to have at least one character. */ |
546 | spec->n_grouped_digits = 0; |
547 | else { |
548 | Py_UCS4 grouping_maxchar; |
549 | spec->n_grouped_digits = _PyUnicode_InsertThousandsGrouping( |
550 | NULL, 0, |
551 | NULL, 0, spec->n_digits, |
552 | spec->n_min_width, |
553 | locale->grouping, locale->thousands_sep, &grouping_maxchar); |
554 | if (spec->n_grouped_digits == -1) { Branch (554:13): [True: 0, False: 157k]
|
555 | return -1; |
556 | } |
557 | *maxchar = Py_MAX(*maxchar, grouping_maxchar); |
558 | } |
559 | |
560 | /* Given the desired width and the total of digit and non-digit |
561 | space we consume, see if we need any padding. format->width can |
562 | be negative (meaning no padding), but this code still works in |
563 | that case. */ |
564 | n_padding = format->width - |
565 | (n_non_digit_non_padding + spec->n_grouped_digits); |
566 | if (n_padding > 0) { Branch (566:9): [True: 265, False: 157k]
|
567 | /* Some padding is needed. Determine if it's left, space, or right. */ |
568 | switch (format->align) { |
569 | case '<': Branch (569:9): [True: 39, False: 226]
|
570 | spec->n_rpadding = n_padding; |
571 | break; |
572 | case '^': Branch (572:9): [True: 27, False: 238]
|
573 | spec->n_lpadding = n_padding / 2; |
574 | spec->n_rpadding = n_padding - spec->n_lpadding; |
575 | break; |
576 | case '=': Branch (576:9): [True: 8, False: 257]
|
577 | spec->n_spadding = n_padding; |
578 | break; |
579 | case '>': Branch (579:9): [True: 191, False: 74]
|
580 | spec->n_lpadding = n_padding; |
581 | break; |
582 | default: Branch (582:9): [True: 0, False: 265]
|
583 | /* Shouldn't get here */ |
584 | Py_UNREACHABLE(); |
585 | } |
586 | } |
587 | |
588 | if (spec->n_lpadding || spec->n_spadding157k || spec->n_rpadding157k ) Branch (588:9): [True: 218, False: 157k]
Branch (588:29): [True: 8, False: 157k]
Branch (588:49): [True: 39, False: 157k]
|
589 | *maxchar = Py_MAX(*maxchar, format->fill_char); |
590 | |
591 | if (spec->n_decimal) Branch (591:9): [True: 280, False: 157k]
|
592 | *maxchar = Py_MAX(*maxchar, PyUnicode_MAX_CHAR_VALUE(locale->decimal_point)); |
593 | |
594 | return spec->n_lpadding + spec->n_sign + spec->n_prefix + |
595 | spec->n_spadding + spec->n_grouped_digits + spec->n_decimal + |
596 | spec->n_remainder + spec->n_rpadding; |
597 | } |
598 | |
599 | /* Fill in the digit parts of a number's string representation, |
600 | as determined in calc_number_widths(). |
601 | Return -1 on error, or 0 on success. */ |
602 | static int |
603 | fill_number(_PyUnicodeWriter *writer, const NumberFieldWidths *spec, |
604 | PyObject *digits, Py_ssize_t d_start, |
605 | PyObject *prefix, Py_ssize_t p_start, |
606 | Py_UCS4 fill_char, |
607 | LocaleInfo *locale, int toupper) |
608 | { |
609 | /* Used to keep track of digits, decimal, and remainder. */ |
610 | Py_ssize_t d_pos = d_start; |
611 | const int kind = writer->kind; |
612 | const void *data = writer->data; |
613 | Py_ssize_t r; |
614 | |
615 | if (spec->n_lpadding) { Branch (615:9): [True: 218, False: 157k]
|
616 | _PyUnicode_FastFill(writer->buffer, |
617 | writer->pos, spec->n_lpadding, fill_char); |
618 | writer->pos += spec->n_lpadding; |
619 | } |
620 | if (spec->n_sign == 1) { Branch (620:9): [True: 18.8k, False: 138k]
|
621 | PyUnicode_WRITE(kind, data, writer->pos, spec->sign); |
622 | writer->pos++; |
623 | } |
624 | if (spec->n_prefix) { Branch (624:9): [True: 49, False: 157k]
|
625 | _PyUnicode_FastCopyCharacters(writer->buffer, writer->pos, |
626 | prefix, p_start, |
627 | spec->n_prefix); |
628 | if (toupper) { Branch (628:13): [True: 15, False: 34]
|
629 | Py_ssize_t t; |
630 | for (t = 0; t < spec->n_prefix; t++30 ) { Branch (630:25): [True: 30, False: 15]
|
631 | Py_UCS4 c = PyUnicode_READ(kind, data, writer->pos + t); |
632 | c = Py_TOUPPER(c); |
633 | assert (c <= 127); |
634 | PyUnicode_WRITE(kind, data, writer->pos + t, c); |
635 | } |
636 | } |
637 | writer->pos += spec->n_prefix; |
638 | } |
639 | if (spec->n_spadding) { Branch (639:9): [True: 8, False: 157k]
|
640 | _PyUnicode_FastFill(writer->buffer, |
641 | writer->pos, spec->n_spadding, fill_char); |
642 | writer->pos += spec->n_spadding; |
643 | } |
644 | |
645 | /* Only for type 'c' special case, it has no digits. */ |
646 | if (spec->n_digits != 0) { Branch (646:9): [True: 157k, False: 117]
|
647 | /* Fill the digits with InsertThousandsGrouping. */ |
648 | r = _PyUnicode_InsertThousandsGrouping( |
649 | writer, spec->n_grouped_digits, |
650 | digits, d_pos, spec->n_digits, |
651 | spec->n_min_width, |
652 | locale->grouping, locale->thousands_sep, NULL); |
653 | if (r == -1) Branch (653:13): [True: 0, False: 157k]
|
654 | return -1; |
655 | assert(r == spec->n_grouped_digits); |
656 | d_pos += spec->n_digits; |
657 | } |
658 | if (toupper) { Branch (658:9): [True: 461, False: 157k]
|
659 | Py_ssize_t t; |
660 | for (t = 0; t < spec->n_grouped_digits; t++1.35k ) { Branch (660:21): [True: 1.35k, False: 461]
|
661 | Py_UCS4 c = PyUnicode_READ(kind, data, writer->pos + t); |
662 | c = Py_TOUPPER(c); |
663 | if (c > 127) { Branch (663:17): [True: 0, False: 1.35k]
|
664 | PyErr_SetString(PyExc_SystemError, "non-ascii grouped digit"); |
665 | return -1; |
666 | } |
667 | PyUnicode_WRITE(kind, data, writer->pos + t, c); |
668 | } |
669 | } |
670 | writer->pos += spec->n_grouped_digits; |
671 | |
672 | if (spec->n_decimal) { Branch (672:9): [True: 280, False: 157k]
|
673 | _PyUnicode_FastCopyCharacters( |
674 | writer->buffer, writer->pos, |
675 | locale->decimal_point, 0, spec->n_decimal); |
676 | writer->pos += spec->n_decimal; |
677 | d_pos += 1; |
678 | } |
679 | |
680 | if (spec->n_remainder) { Branch (680:9): [True: 398, False: 157k]
|
681 | _PyUnicode_FastCopyCharacters( |
682 | writer->buffer, writer->pos, |
683 | digits, d_pos, spec->n_remainder); |
684 | writer->pos += spec->n_remainder; |
685 | /* d_pos += spec->n_remainder; */ |
686 | } |
687 | |
688 | if (spec->n_rpadding) { Branch (688:9): [True: 66, False: 157k]
|
689 | _PyUnicode_FastFill(writer->buffer, |
690 | writer->pos, spec->n_rpadding, |
691 | fill_char); |
692 | writer->pos += spec->n_rpadding; |
693 | } |
694 | return 0; |
695 | } |
696 | |
697 | static const char no_grouping[1] = {CHAR_MAX}; |
698 | |
699 | /* Find the decimal point character(s?), thousands_separator(s?), and |
700 | grouping description, either for the current locale if type is |
701 | LT_CURRENT_LOCALE, a hard-coded locale if LT_DEFAULT_LOCALE or |
702 | LT_UNDERSCORE_LOCALE/LT_UNDER_FOUR_LOCALE, or none if LT_NO_LOCALE. */ |
703 | static int |
704 | get_locale_info(enum LocaleType type, LocaleInfo *locale_info) |
705 | { |
706 | switch (type) { Branch (706:13): [True: 0, False: 157k]
|
707 | case LT_CURRENT_LOCALE: { Branch (707:5): [True: 122, False: 157k]
|
708 | struct lconv *lc = localeconv(); |
709 | if (_Py_GetLocaleconvNumeric(lc, Branch (709:13): [True: 0, False: 122]
|
710 | &locale_info->decimal_point, |
711 | &locale_info->thousands_sep) < 0) { |
712 | return -1; |
713 | } |
714 | |
715 | /* localeconv() grouping can become a dangling pointer or point |
716 | to a different string if another thread calls localeconv() during |
717 | the string formatting. Copy the string to avoid this risk. */ |
718 | locale_info->grouping_buffer = _PyMem_Strdup(lc->grouping); |
719 | if (locale_info->grouping_buffer == NULL) { Branch (719:13): [True: 0, False: 122]
|
720 | PyErr_NoMemory(); |
721 | return -1; |
722 | } |
723 | locale_info->grouping = locale_info->grouping_buffer; |
724 | break; |
725 | } |
726 | case LT_DEFAULT_LOCALE: Branch (726:5): [True: 37, False: 157k]
|
727 | case LT_UNDERSCORE_LOCALE: Branch (727:5): [True: 70, False: 157k]
|
728 | case LT_UNDER_FOUR_LOCALE: Branch (728:5): [True: 20, False: 157k]
|
729 | locale_info->decimal_point = PyUnicode_FromOrdinal('.'); |
730 | locale_info->thousands_sep = PyUnicode_FromOrdinal( |
731 | type == LT_DEFAULT_LOCALE ? ','37 : '_'90 ); Branch (731:13): [True: 37, False: 90]
|
732 | if (!locale_info->decimal_point || !locale_info->thousands_sep) Branch (732:13): [True: 0, False: 127]
Branch (732:44): [True: 0, False: 127]
|
733 | return -1; |
734 | if (type != LT_UNDER_FOUR_LOCALE) Branch (734:13): [True: 107, False: 20]
|
735 | locale_info->grouping = "\3"; /* Group every 3 characters. The |
736 | (implicit) trailing 0 means repeat |
737 | infinitely. */ |
738 | else |
739 | locale_info->grouping = "\4"; /* Bin/oct/hex group every four. */ |
740 | break; |
741 | case LT_NO_LOCALE: Branch (741:5): [True: 157k, False: 249]
|
742 | locale_info->decimal_point = PyUnicode_FromOrdinal('.'); |
743 | locale_info->thousands_sep = PyUnicode_New(0, 0); |
744 | if (!locale_info->decimal_point || !locale_info->thousands_sep) Branch (744:13): [True: 0, False: 157k]
Branch (744:44): [True: 0, False: 157k]
|
745 | return -1; |
746 | locale_info->grouping = no_grouping; |
747 | break; |
748 | } |
749 | return 0; |
750 | } |
751 | |
752 | static void |
753 | free_locale_info(LocaleInfo *locale_info) |
754 | { |
755 | Py_XDECREF(locale_info->decimal_point); |
756 | Py_XDECREF(locale_info->thousands_sep); |
757 | PyMem_Free(locale_info->grouping_buffer); |
758 | } |
759 | |
760 | /************************************************************************/ |
761 | /*********** string formatting ******************************************/ |
762 | /************************************************************************/ |
763 | |
764 | static int |
765 | format_string_internal(PyObject *value, const InternalFormatSpec *format, |
766 | _PyUnicodeWriter *writer) |
767 | { |
768 | Py_ssize_t lpad; |
769 | Py_ssize_t rpad; |
770 | Py_ssize_t total; |
771 | Py_ssize_t len; |
772 | int result = -1; |
773 | Py_UCS4 maxchar; |
774 | |
775 | assert(PyUnicode_IS_READY(value)); |
776 | len = PyUnicode_GET_LENGTH(value); |
777 | |
778 | /* sign is not allowed on strings */ |
779 | if (format->sign != '\0') { Branch (779:9): [True: 3, False: 7.83k]
|
780 | if (format->sign == ' ') { Branch (780:13): [True: 1, False: 2]
|
781 | PyErr_SetString(PyExc_ValueError, |
782 | "Space not allowed in string format specifier"); |
783 | } |
784 | else { |
785 | PyErr_SetString(PyExc_ValueError, |
786 | "Sign not allowed in string format specifier"); |
787 | } |
788 | goto done; |
789 | } |
790 | |
791 | /* negative 0 coercion is not allowed on strings */ |
792 | if (format->no_neg_0) { Branch (792:9): [True: 1, False: 7.83k]
|
793 | PyErr_SetString(PyExc_ValueError, |
794 | "Negative zero coercion (z) not allowed in string format " |
795 | "specifier"); |
796 | goto done; |
797 | } |
798 | |
799 | /* alternate is not allowed on strings */ |
800 | if (format->alternate) { Branch (800:9): [True: 2, False: 7.83k]
|
801 | PyErr_SetString(PyExc_ValueError, |
802 | "Alternate form (#) not allowed in string format " |
803 | "specifier"); |
804 | goto done; |
805 | } |
806 | |
807 | /* '=' alignment not allowed on strings */ |
808 | if (format->align == '=') { Branch (808:9): [True: 1, False: 7.83k]
|
809 | PyErr_SetString(PyExc_ValueError, |
810 | "'=' alignment not allowed " |
811 | "in string format specifier"); |
812 | goto done; |
813 | } |
814 | |
815 | if ((format->width == -1 || format->width <= len6.64k ) Branch (815:10): [True: 1.18k, False: 6.64k]
Branch (815:33): [True: 1.10k, False: 5.54k]
|
816 | && (2.29k format->precision == -12.29k || format->precision >= len1.96k )) { Branch (816:13): [True: 322, False: 1.96k]
Branch (816:40): [True: 534, False: 1.43k]
|
817 | /* Fast path */ |
818 | return _PyUnicodeWriter_WriteStr(writer, value); |
819 | } |
820 | |
821 | /* if precision is specified, output no more that format.precision |
822 | characters */ |
823 | if (format->precision >= 0 && len >= format->precision2.68k ) { Branch (823:9): [True: 2.68k, False: 4.29k]
Branch (823:35): [True: 2.33k, False: 356]
|
824 | len = format->precision; |
825 | } |
826 | |
827 | calc_padding(len, format->width, format->align, &lpad, &rpad, &total); |
828 | |
829 | maxchar = writer->maxchar; |
830 | if (lpad != 0 || rpad != 05.81k ) Branch (830:9): [True: 1.16k, False: 5.81k]
Branch (830:22): [True: 4.91k, False: 906]
|
831 | maxchar = Py_MAX(maxchar, format->fill_char); |
832 | if (PyUnicode_MAX_CHAR_VALUE(value) > maxchar) { Branch (832:9): [True: 6.97k, False: 4]
|
833 | Py_UCS4 valmaxchar = _PyUnicode_FindMaxChar(value, 0, len); |
834 | maxchar = Py_MAX(maxchar, valmaxchar); |
835 | } |
836 | |
837 | /* allocate the resulting string */ |
838 | if (_PyUnicodeWriter_Prepare(writer, total, maxchar) == -1) Branch (838:9): [True: 0, False: 6.97k]
|
839 | goto done; |
840 | |
841 | /* Write into that space. First the padding. */ |
842 | result = fill_padding(writer, len, format->fill_char, lpad, rpad); |
843 | if (result == -1) Branch (843:9): [True: 0, False: 6.97k]
|
844 | goto done; |
845 | |
846 | /* Then the source string. */ |
847 | if (len) { Branch (847:9): [True: 5.15k, False: 1.82k]
|
848 | _PyUnicode_FastCopyCharacters(writer->buffer, writer->pos, |
849 | value, 0, len); |
850 | } |
851 | writer->pos += (len + rpad); |
852 | result = 0; |
853 | |
854 | done: |
855 | return result; |
856 | } |
857 | |
858 | |
859 | /************************************************************************/ |
860 | /*********** long formatting ********************************************/ |
861 | /************************************************************************/ |
862 | |
863 | static int |
864 | format_long_internal(PyObject *value, const InternalFormatSpec *format, |
865 | _PyUnicodeWriter *writer) |
866 | { |
867 | int result = -1; |
868 | Py_UCS4 maxchar = 127; |
869 | PyObject *tmp = NULL; |
870 | Py_ssize_t inumeric_chars; |
871 | Py_UCS4 sign_char = '\0'; |
872 | Py_ssize_t n_digits; /* count of digits need from the computed |
873 | string */ |
874 | Py_ssize_t n_remainder = 0; /* Used only for 'c' formatting, which |
875 | produces non-digits */ |
876 | Py_ssize_t n_prefix = 0; /* Count of prefix chars, (e.g., '0x') */ |
877 | Py_ssize_t n_total; |
878 | Py_ssize_t prefix = 0; |
879 | NumberFieldWidths spec; |
880 | long x; |
881 | |
882 | /* Locale settings, either from the actual locale or |
883 | from a hard-code pseudo-locale */ |
884 | LocaleInfo locale = LocaleInfo_STATIC_INIT; |
885 | |
886 | /* no precision allowed on integers */ |
887 | if (format->precision != -1) { Branch (887:9): [True: 2, False: 176k]
|
888 | PyErr_SetString(PyExc_ValueError, |
889 | "Precision not allowed in integer format specifier"); |
890 | goto done; |
891 | } |
892 | /* no negative zero coercion on integers */ |
893 | if (format->no_neg_0) { Branch (893:9): [True: 9, False: 176k]
|
894 | PyErr_SetString(PyExc_ValueError, |
895 | "Negative zero coercion (z) not allowed in integer" |
896 | " format specifier"); |
897 | goto done; |
898 | } |
899 | |
900 | /* special case for character formatting */ |
901 | if (format->type == 'c') { Branch (901:9): [True: 4, False: 176k]
|
902 | /* error to specify a sign */ |
903 | if (format->sign != '\0') { Branch (903:13): [True: 2, False: 2]
|
904 | PyErr_SetString(PyExc_ValueError, |
905 | "Sign not allowed with integer" |
906 | " format specifier 'c'"); |
907 | goto done; |
908 | } |
909 | /* error to request alternate format */ |
910 | if (format->alternate) { Branch (910:13): [True: 1, False: 1]
|
911 | PyErr_SetString(PyExc_ValueError, |
912 | "Alternate form (#) not allowed with integer" |
913 | " format specifier 'c'"); |
914 | goto done; |
915 | } |
916 | |
917 | /* taken from unicodeobject.c formatchar() */ |
918 | /* Integer input truncated to a character */ |
919 | x = PyLong_AsLong(value); |
920 | if (x == -1 && PyErr_Occurred()0 ) Branch (920:13): [True: 0, False: 1]
Branch (920:24): [True: 0, False: 0]
|
921 | goto done; |
922 | if (x < 0 || x > 0x10ffff) { Branch (922:13): [True: 0, False: 1]
Branch (922:22): [True: 0, False: 1]
|
923 | PyErr_SetString(PyExc_OverflowError, |
924 | "%c arg not in range(0x110000)"); |
925 | goto done; |
926 | } |
927 | tmp = PyUnicode_FromOrdinal(x); |
928 | inumeric_chars = 0; |
929 | n_digits = 1; |
930 | maxchar = Py_MAX(maxchar, (Py_UCS4)x); |
931 | |
932 | /* As a sort-of hack, we tell calc_number_widths that we only |
933 | have "remainder" characters. calc_number_widths thinks |
934 | these are characters that don't get formatted, only copied |
935 | into the output string. We do this for 'c' formatting, |
936 | because the characters are likely to be non-digits. */ |
937 | n_remainder = 1; |
938 | } |
939 | else { |
940 | int base; |
941 | int leading_chars_to_skip = 0; /* Number of characters added by |
942 | PyNumber_ToBase that we want to |
943 | skip over. */ |
944 | |
945 | /* Compute the base and how many characters will be added by |
946 | PyNumber_ToBase */ |
947 | switch (format->type) { |
948 | case 'b': Branch (948:9): [True: 42, False: 176k]
|
949 | base = 2; |
950 | leading_chars_to_skip = 2; /* 0b */ |
951 | break; |
952 | case 'o': Branch (952:9): [True: 40, False: 176k]
|
953 | base = 8; |
954 | leading_chars_to_skip = 2; /* 0o */ |
955 | break; |
956 | case 'x': Branch (956:9): [True: 148k, False: 27.5k]
|
957 | case 'X': Branch (957:9): [True: 461, False: 175k]
|
958 | base = 16; |
959 | leading_chars_to_skip = 2; /* 0x */ |
960 | break; |
961 | default: /* shouldn't be needed, but stops a compiler warning */ Branch (961:9): [True: 0, False: 176k]
|
962 | case 'd': Branch (962:9): [True: 26.9k, False: 149k]
|
963 | case 'n': Branch (963:9): [True: 79, False: 176k]
|
964 | base = 10; |
965 | break; |
966 | } |
967 | |
968 | if (format->sign != '+' && format->sign != ' '157k Branch (968:13): [True: 157k, False: 18.5k]
Branch (968:36): [True: 157k, False: 16]
|
969 | && format->width == -1157k Branch (969:16): [True: 19.2k, False: 138k]
|
970 | && format->type != 'X'19.2k && format->type != 'n'19.1k Branch (970:16): [True: 19.1k, False: 50]
Branch (970:39): [True: 19.1k, False: 31]
|
971 | && !format->thousands_separators19.1k Branch (971:16): [True: 19.0k, False: 82]
|
972 | && PyLong_CheckExact19.0k (value)) |
973 | { |
974 | /* Fast path */ |
975 | return _PyLong_FormatWriter(writer, value, base, format->alternate); |
976 | } |
977 | |
978 | /* The number of prefix chars is the same as the leading |
979 | chars to skip */ |
980 | if (format->alternate) Branch (980:13): [True: 49, False: 157k]
|
981 | n_prefix = leading_chars_to_skip; |
982 | |
983 | /* Do the hard part, converting to a string in a given base */ |
984 | tmp = _PyLong_Format(value, base); |
985 | if (tmp == NULL || PyUnicode_READY(tmp) == -1) Branch (985:13): [True: 0, False: 157k]
Branch (985:28): [True: 0, False: 157k]
|
986 | goto done; |
987 | |
988 | inumeric_chars = 0; |
989 | n_digits = PyUnicode_GET_LENGTH(tmp); |
990 | |
991 | prefix = inumeric_chars; |
992 | |
993 | /* Is a sign character present in the output? If so, remember it |
994 | and skip it */ |
995 | if (PyUnicode_READ_CHAR(tmp, inumeric_chars) == '-') { Branch (995:13): [True: 5.37k, False: 151k]
|
996 | sign_char = '-'; |
997 | ++prefix; |
998 | ++leading_chars_to_skip; |
999 | } |
1000 | |
1001 | /* Skip over the leading chars (0x, 0b, etc.) */ |
1002 | n_digits -= leading_chars_to_skip; |
1003 | inumeric_chars += leading_chars_to_skip; |
1004 | } |
1005 | |
1006 | /* Determine the grouping, separator, and decimal point, if any. */ |
1007 | if (get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE79 : Branch (1007:9): [True: 0, False: 157k]
Branch (1007:25): [True: 79, False: 157k]
|
1008 | format->thousands_separators157k , |
1009 | &locale) == -1) |
1010 | goto done; |
1011 | |
1012 | /* Calculate how much memory we'll need. */ |
1013 | n_total = calc_number_widths(&spec, n_prefix, sign_char, inumeric_chars, |
1014 | inumeric_chars + n_digits, n_remainder, 0, |
1015 | &locale, format, &maxchar); |
1016 | if (n_total == -1) { Branch (1016:9): [True: 0, False: 157k]
|
1017 | goto done; |
1018 | } |
1019 | |
1020 | /* Allocate the memory. */ |
1021 | if (_PyUnicodeWriter_Prepare(writer, n_total, maxchar) == -1) Branch (1021:9): [True: 0, False: 157k]
|
1022 | goto done; |
1023 | |
1024 | /* Populate the memory. */ |
1025 | result = fill_number(writer, &spec, |
1026 | tmp, inumeric_chars, |
1027 | tmp, prefix, format->fill_char, |
1028 | &locale, format->type == 'X'); |
1029 | |
1030 | done: |
1031 | Py_XDECREF(tmp); |
1032 | free_locale_info(&locale); |
1033 | return result; |
1034 | } |
1035 | |
1036 | /************************************************************************/ |
1037 | /*********** float formatting *******************************************/ |
1038 | /************************************************************************/ |
1039 | |
1040 | /* much of this is taken from unicodeobject.c */ |
1041 | static int |
1042 | format_float_internal(PyObject *value, |
1043 | const InternalFormatSpec *format, |
1044 | _PyUnicodeWriter *writer) |
1045 | { |
1046 | char *buf = NULL; /* buffer returned from PyOS_double_to_string */ |
1047 | Py_ssize_t n_digits; |
1048 | Py_ssize_t n_remainder; |
1049 | Py_ssize_t n_total; |
1050 | int has_decimal; |
1051 | double val; |
1052 | int precision, default_precision = 6; |
1053 | Py_UCS4 type = format->type; |
1054 | int add_pct = 0; |
1055 | Py_ssize_t index; |
1056 | NumberFieldWidths spec; |
1057 | int flags = 0; |
1058 | int result = -1; |
1059 | Py_UCS4 maxchar = 127; |
1060 | Py_UCS4 sign_char = '\0'; |
1061 | int float_type; /* Used to see if we have a nan, inf, or regular float. */ |
1062 | PyObject *unicode_tmp = NULL; |
1063 | |
1064 | /* Locale settings, either from the actual locale or |
1065 | from a hard-code pseudo-locale */ |
1066 | LocaleInfo locale = LocaleInfo_STATIC_INIT; |
1067 | |
1068 | if (format->precision > INT_MAX) { Branch (1068:9): [True: 1, False: 7.31k]
|
1069 | PyErr_SetString(PyExc_ValueError, "precision too big"); |
1070 | goto done; |
1071 | } |
1072 | precision = (int)format->precision; |
1073 | |
1074 | if (format->alternate) Branch (1074:9): [True: 92, False: 7.22k]
|
1075 | flags |= Py_DTSF_ALT; |
1076 | if (format->no_neg_0) Branch (1076:9): [True: 35, False: 7.27k]
|
1077 | flags |= Py_DTSF_NO_NEG_0; |
1078 | |
1079 | if (type == '\0') { Branch (1079:9): [True: 55, False: 7.25k]
|
1080 | /* Omitted type specifier. Behaves in the same way as repr(x) |
1081 | and str(x) if no precision is given, else like 'g', but with |
1082 | at least one digit after the decimal point. */ |
1083 | flags |= Py_DTSF_ADD_DOT_0; |
1084 | type = 'r'; |
1085 | default_precision = 0; |
1086 | } |
1087 | |
1088 | if (type == 'n') Branch (1088:9): [True: 43, False: 7.27k]
|
1089 | /* 'n' is the same as 'g', except for the locale used to |
1090 | format the result. We take care of that later. */ |
1091 | type = 'g'; |
1092 | |
1093 | val = PyFloat_AsDouble(value); |
1094 | if (val == -1.0 && PyErr_Occurred()52 ) Branch (1094:9): [True: 52, False: 7.26k]
Branch (1094:24): [True: 0, False: 52]
|
1095 | goto done; |
1096 | |
1097 | if (type == '%') { Branch (1097:9): [True: 40, False: 7.27k]
|
1098 | type = 'f'; |
1099 | val *= 100; |
1100 | add_pct = 1; |
1101 | } |
1102 | |
1103 | if (precision < 0) Branch (1103:9): [True: 662, False: 6.65k]
|
1104 | precision = default_precision; |
1105 | else if (type == 'r') Branch (1105:14): [True: 9, False: 6.64k]
|
1106 | type = 'g'; |
1107 | |
1108 | /* Cast "type", because if we're in unicode we need to pass an |
1109 | 8-bit char. This is safe, because we've restricted what "type" |
1110 | can be. */ |
1111 | buf = PyOS_double_to_string(val, (char)type, precision, flags, |
1112 | &float_type); |
1113 | if (buf == NULL) Branch (1113:9): [True: 0, False: 7.31k]
|
1114 | goto done; |
1115 | n_digits = strlen(buf); |
1116 | |
1117 | if (add_pct) { Branch (1117:9): [True: 40, False: 7.27k]
|
1118 | /* We know that buf has a trailing zero (since we just called |
1119 | strlen() on it), and we don't use that fact any more. So we |
1120 | can just write over the trailing zero. */ |
1121 | buf[n_digits] = '%'; |
1122 | n_digits += 1; |
1123 | } |
1124 | |
1125 | if (format->sign != '+' && format->sign != ' '7.24k Branch (1125:9): [True: 7.24k, False: 68]
Branch (1125:32): [True: 7.18k, False: 60]
|
1126 | && format->width == -17.18k Branch (1126:12): [True: 7.07k, False: 108]
|
1127 | && format->type != 'n'7.07k Branch (1127:12): [True: 7.03k, False: 43]
|
1128 | && !format->thousands_separators7.03k ) Branch (1128:12): [True: 7.03k, False: 0]
|
1129 | { |
1130 | /* Fast path */ |
1131 | result = _PyUnicodeWriter_WriteASCIIString(writer, buf, n_digits); |
1132 | PyMem_Free(buf); |
1133 | return result; |
1134 | } |
1135 | |
1136 | /* Since there is no unicode version of PyOS_double_to_string, |
1137 | just use the 8 bit version and then convert to unicode. */ |
1138 | unicode_tmp = _PyUnicode_FromASCII(buf, n_digits); |
1139 | PyMem_Free(buf); |
1140 | if (unicode_tmp == NULL) Branch (1140:9): [True: 0, False: 279]
|
1141 | goto done; |
1142 | |
1143 | /* Is a sign character present in the output? If so, remember it |
1144 | and skip it */ |
1145 | index = 0; |
1146 | if (PyUnicode_READ_CHAR(unicode_tmp, index) == '-') { Branch (1146:9): [True: 76, False: 203]
|
1147 | sign_char = '-'; |
1148 | ++index; |
1149 | --n_digits; |
1150 | } |
1151 | |
1152 | /* Determine if we have any "remainder" (after the digits, might include |
1153 | decimal or exponent or both (or neither)) */ |
1154 | parse_number(unicode_tmp, index, index + n_digits, &n_remainder, &has_decimal); |
1155 | |
1156 | /* Determine the grouping, separator, and decimal point, if any. */ |
1157 | if (get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE43 : Branch (1157:9): [True: 0, False: 279]
Branch (1157:25): [True: 43, False: 236]
|
1158 | format->thousands_separators236 , |
1159 | &locale) == -1) |
1160 | goto done; |
1161 | |
1162 | /* Calculate how much memory we'll need. */ |
1163 | n_total = calc_number_widths(&spec, 0, sign_char, index, |
1164 | index + n_digits, n_remainder, has_decimal, |
1165 | &locale, format, &maxchar); |
1166 | if (n_total == -1) { Branch (1166:9): [True: 0, False: 279]
|
1167 | goto done; |
1168 | } |
1169 | |
1170 | /* Allocate the memory. */ |
1171 | if (_PyUnicodeWriter_Prepare(writer, n_total, maxchar) == -1) Branch (1171:9): [True: 0, False: 279]
|
1172 | goto done; |
1173 | |
1174 | /* Populate the memory. */ |
1175 | result = fill_number(writer, &spec, |
1176 | unicode_tmp, index, |
1177 | NULL, 0, format->fill_char, |
1178 | &locale, 0); |
1179 | |
1180 | done: |
1181 | Py_XDECREF(unicode_tmp); |
1182 | free_locale_info(&locale); |
1183 | return result; |
1184 | } |
1185 | |
1186 | /************************************************************************/ |
1187 | /*********** complex formatting *****************************************/ |
1188 | /************************************************************************/ |
1189 | |
1190 | static int |
1191 | format_complex_internal(PyObject *value, |
1192 | const InternalFormatSpec *format, |
1193 | _PyUnicodeWriter *writer) |
1194 | { |
1195 | double re; |
1196 | double im; |
1197 | char *re_buf = NULL; /* buffer returned from PyOS_double_to_string */ |
1198 | char *im_buf = NULL; /* buffer returned from PyOS_double_to_string */ |
1199 | |
1200 | InternalFormatSpec tmp_format = *format; |
1201 | Py_ssize_t n_re_digits; |
1202 | Py_ssize_t n_im_digits; |
1203 | Py_ssize_t n_re_remainder; |
1204 | Py_ssize_t n_im_remainder; |
1205 | Py_ssize_t n_re_total; |
1206 | Py_ssize_t n_im_total; |
1207 | int re_has_decimal; |
1208 | int im_has_decimal; |
1209 | int precision, default_precision = 6; |
1210 | Py_UCS4 type = format->type; |
1211 | Py_ssize_t i_re; |
1212 | Py_ssize_t i_im; |
1213 | NumberFieldWidths re_spec; |
1214 | NumberFieldWidths im_spec; |
1215 | int flags = 0; |
1216 | int result = -1; |
1217 | Py_UCS4 maxchar = 127; |
1218 | int rkind; |
1219 | void *rdata; |
1220 | Py_UCS4 re_sign_char = '\0'; |
1221 | Py_UCS4 im_sign_char = '\0'; |
1222 | int re_float_type; /* Used to see if we have a nan, inf, or regular float. */ |
1223 | int im_float_type; |
1224 | int add_parens = 0; |
1225 | int skip_re = 0; |
1226 | Py_ssize_t lpad; |
1227 | Py_ssize_t rpad; |
1228 | Py_ssize_t total; |
1229 | PyObject *re_unicode_tmp = NULL; |
1230 | PyObject *im_unicode_tmp = NULL; |
1231 | |
1232 | /* Locale settings, either from the actual locale or |
1233 | from a hard-code pseudo-locale */ |
1234 | LocaleInfo locale = LocaleInfo_STATIC_INIT; |
1235 | |
1236 | if (format->precision > INT_MAX) { Branch (1236:9): [True: 1, False: 96]
|
1237 | PyErr_SetString(PyExc_ValueError, "precision too big"); |
1238 | goto done; |
1239 | } |
1240 | precision = (int)format->precision; |
1241 | |
1242 | /* Zero padding is not allowed. */ |
1243 | if (format->fill_char == '0') { Branch (1243:9): [True: 1, False: 95]
|
1244 | PyErr_SetString(PyExc_ValueError, |
1245 | "Zero padding is not allowed in complex format " |
1246 | "specifier"); |
1247 | goto done; |
1248 | } |
1249 | |
1250 | /* Neither is '=' alignment . */ |
1251 | if (format->align == '=') { Branch (1251:9): [True: 1, False: 94]
|
1252 | PyErr_SetString(PyExc_ValueError, |
1253 | "'=' alignment flag is not allowed in complex format " |
1254 | "specifier"); |
1255 | goto done; |
1256 | } |
1257 | |
1258 | re = PyComplex_RealAsDouble(value); |
1259 | if (re == -1.0 && PyErr_Occurred()0 ) Branch (1259:9): [True: 0, False: 94]
Branch (1259:23): [True: 0, False: 0]
|
1260 | goto done; |
1261 | im = PyComplex_ImagAsDouble(value); |
1262 | if (im == -1.0 && PyErr_Occurred()4 ) Branch (1262:9): [True: 4, False: 90]
Branch (1262:23): [True: 0, False: 4]
|
1263 | goto done; |
1264 | |
1265 | if (format->alternate) Branch (1265:9): [True: 11, False: 83]
|
1266 | flags |= Py_DTSF_ALT; |
1267 | if (format->no_neg_0) Branch (1267:9): [True: 4, False: 90]
|
1268 | flags |= Py_DTSF_NO_NEG_0; |
1269 | |
1270 | if (type == '\0') { Branch (1270:9): [True: 25, False: 69]
|
1271 | /* Omitted type specifier. Should be like str(self). */ |
1272 | type = 'r'; |
1273 | default_precision = 0; |
1274 | if (re == 0.0 && copysign(1.0, re) == 1.09 ) Branch (1274:13): [True: 9, False: 16]
Branch (1274:26): [True: 6, False: 3]
|
1275 | skip_re = 1; |
1276 | else |
1277 | add_parens = 1; |
1278 | } |
1279 | |
1280 | if (type == 'n') Branch (1280:9): [True: 0, False: 94]
|
1281 | /* 'n' is the same as 'g', except for the locale used to |
1282 | format the result. We take care of that later. */ |
1283 | type = 'g'; |
1284 | |
1285 | if (precision < 0) Branch (1285:9): [True: 63, False: 31]
|
1286 | precision = default_precision; |
1287 | else if (type == 'r') Branch (1287:14): [True: 1, False: 30]
|
1288 | type = 'g'; |
1289 | |
1290 | /* Cast "type", because if we're in unicode we need to pass an |
1291 | 8-bit char. This is safe, because we've restricted what "type" |
1292 | can be. */ |
1293 | re_buf = PyOS_double_to_string(re, (char)type, precision, flags, |
1294 | &re_float_type); |
1295 | if (re_buf == NULL) Branch (1295:9): [True: 0, False: 94]
|
1296 | goto done; |
1297 | im_buf = PyOS_double_to_string(im, (char)type, precision, flags, |
1298 | &im_float_type); |
1299 | if (im_buf == NULL) Branch (1299:9): [True: 0, False: 94]
|
1300 | goto done; |
1301 | |
1302 | n_re_digits = strlen(re_buf); |
1303 | n_im_digits = strlen(im_buf); |
1304 | |
1305 | /* Since there is no unicode version of PyOS_double_to_string, |
1306 | just use the 8 bit version and then convert to unicode. */ |
1307 | re_unicode_tmp = _PyUnicode_FromASCII(re_buf, n_re_digits); |
1308 | if (re_unicode_tmp == NULL) Branch (1308:9): [True: 0, False: 94]
|
1309 | goto done; |
1310 | i_re = 0; |
1311 | |
1312 | im_unicode_tmp = _PyUnicode_FromASCII(im_buf, n_im_digits); |
1313 | if (im_unicode_tmp == NULL) Branch (1313:9): [True: 0, False: 94]
|
1314 | goto done; |
1315 | i_im = 0; |
1316 | |
1317 | /* Is a sign character present in the output? If so, remember it |
1318 | and skip it */ |
1319 | if (PyUnicode_READ_CHAR(re_unicode_tmp, i_re) == '-') { Branch (1319:9): [True: 19, False: 75]
|
1320 | re_sign_char = '-'; |
1321 | ++i_re; |
1322 | --n_re_digits; |
1323 | } |
1324 | if (PyUnicode_READ_CHAR(im_unicode_tmp, i_im) == '-') { Branch (1324:9): [True: 19, False: 75]
|
1325 | im_sign_char = '-'; |
1326 | ++i_im; |
1327 | --n_im_digits; |
1328 | } |
1329 | |
1330 | /* Determine if we have any "remainder" (after the digits, might include |
1331 | decimal or exponent or both (or neither)) */ |
1332 | parse_number(re_unicode_tmp, i_re, i_re + n_re_digits, |
1333 | &n_re_remainder, &re_has_decimal); |
1334 | parse_number(im_unicode_tmp, i_im, i_im + n_im_digits, |
1335 | &n_im_remainder, &im_has_decimal); |
1336 | |
1337 | /* Determine the grouping, separator, and decimal point, if any. */ |
1338 | if (get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE0 : Branch (1338:9): [True: 0, False: 94]
Branch (1338:25): [True: 0, False: 94]
|
1339 | format->thousands_separators, |
1340 | &locale) == -1) |
1341 | goto done; |
1342 | |
1343 | /* Turn off any padding. We'll do it later after we've composed |
1344 | the numbers without padding. */ |
1345 | tmp_format.fill_char = '\0'; |
1346 | tmp_format.align = '<'; |
1347 | tmp_format.width = -1; |
1348 | |
1349 | /* Calculate how much memory we'll need. */ |
1350 | n_re_total = calc_number_widths(&re_spec, 0, re_sign_char, |
1351 | i_re, i_re + n_re_digits, n_re_remainder, |
1352 | re_has_decimal, &locale, &tmp_format, |
1353 | &maxchar); |
1354 | if (n_re_total == -1) { Branch (1354:9): [True: 0, False: 94]
|
1355 | goto done; |
1356 | } |
1357 | |
1358 | /* Same formatting, but always include a sign, unless the real part is |
1359 | * going to be omitted, in which case we use whatever sign convention was |
1360 | * requested by the original format. */ |
1361 | if (!skip_re) Branch (1361:9): [True: 88, False: 6]
|
1362 | tmp_format.sign = '+'; |
1363 | n_im_total = calc_number_widths(&im_spec, 0, im_sign_char, |
1364 | i_im, i_im + n_im_digits, n_im_remainder, |
1365 | im_has_decimal, &locale, &tmp_format, |
1366 | &maxchar); |
1367 | if (n_im_total == -1) { Branch (1367:9): [True: 0, False: 94]
|
1368 | goto done; |
1369 | } |
1370 | |
1371 | if (skip_re) Branch (1371:9): [True: 6, False: 88]
|
1372 | n_re_total = 0; |
1373 | |
1374 | /* Add 1 for the 'j', and optionally 2 for parens. */ |
1375 | calc_padding(n_re_total + n_im_total + 1 + add_parens * 2, |
1376 | format->width, format->align, &lpad, &rpad, &total); |
1377 | |
1378 | if (lpad || rpad78 ) Branch (1378:9): [True: 16, False: 78]
Branch (1378:17): [True: 8, False: 70]
|
1379 | maxchar = Py_MAX(maxchar, format->fill_char); |
1380 | |
1381 | if (_PyUnicodeWriter_Prepare(writer, total, maxchar) == -1) Branch (1381:9): [True: 0, False: 94]
|
1382 | goto done; |
1383 | rkind = writer->kind; |
1384 | rdata = writer->data; |
1385 | |
1386 | /* Populate the memory. First, the padding. */ |
1387 | result = fill_padding(writer, |
1388 | n_re_total + n_im_total + 1 + add_parens * 2, |
1389 | format->fill_char, lpad, rpad); |
1390 | if (result == -1) Branch (1390:9): [True: 0, False: 94]
|
1391 | goto done; |
1392 | |
1393 | if (add_parens) { Branch (1393:9): [True: 19, False: 75]
|
1394 | PyUnicode_WRITE(rkind, rdata, writer->pos, '('); |
1395 | writer->pos++; |
1396 | } |
1397 | |
1398 | if (!skip_re) { Branch (1398:9): [True: 88, False: 6]
|
1399 | result = fill_number(writer, &re_spec, |
1400 | re_unicode_tmp, i_re, |
1401 | NULL, 0, |
1402 | 0, |
1403 | &locale, 0); |
1404 | if (result == -1) Branch (1404:13): [True: 0, False: 88]
|
1405 | goto done; |
1406 | } |
1407 | result = fill_number(writer, &im_spec, |
1408 | im_unicode_tmp, i_im, |
1409 | NULL, 0, |
1410 | 0, |
1411 | &locale, 0); |
1412 | if (result == -1) Branch (1412:9): [True: 0, False: 94]
|
1413 | goto done; |
1414 | PyUnicode_WRITE(rkind, rdata, writer->pos, 'j'); |
1415 | writer->pos++; |
1416 | |
1417 | if (add_parens) { Branch (1417:9): [True: 19, False: 75]
|
1418 | PyUnicode_WRITE(rkind, rdata, writer->pos, ')'); |
1419 | writer->pos++; |
1420 | } |
1421 | |
1422 | writer->pos += rpad; |
1423 | |
1424 | done: |
1425 | PyMem_Free(re_buf); |
1426 | PyMem_Free(im_buf); |
1427 | Py_XDECREF(re_unicode_tmp); |
1428 | Py_XDECREF(im_unicode_tmp); |
1429 | free_locale_info(&locale); |
1430 | return result; |
1431 | } |
1432 | |
1433 | /************************************************************************/ |
1434 | /*********** built in formatters ****************************************/ |
1435 | /************************************************************************/ |
1436 | static int |
1437 | format_obj(PyObject *obj, _PyUnicodeWriter *writer) |
1438 | { |
1439 | PyObject *str; |
1440 | int err; |
1441 | |
1442 | str = PyObject_Str(obj); |
1443 | if (str == NULL) Branch (1443:9): [True: 0, False: 16.5k]
|
1444 | return -1; |
1445 | err = _PyUnicodeWriter_WriteStr(writer, str); |
1446 | Py_DECREF(str); |
1447 | return err; |
1448 | } |
1449 | |
1450 | int |
1451 | _PyUnicode_FormatAdvancedWriter(_PyUnicodeWriter *writer, |
1452 | PyObject *obj, |
1453 | PyObject *format_spec, |
1454 | Py_ssize_t start, Py_ssize_t end) |
1455 | { |
1456 | InternalFormatSpec format; |
1457 | |
1458 | assert(PyUnicode_Check(obj)); |
1459 | |
1460 | /* check for the special case of zero length format spec, make |
1461 | it equivalent to str(obj) */ |
1462 | if (start == end) { Branch (1462:9): [True: 593k, False: 7.84k]
|
1463 | if (PyUnicode_CheckExact(obj)) |
1464 | return _PyUnicodeWriter_WriteStr(writer, obj); |
1465 | else |
1466 | return format_obj(obj, writer); |
1467 | } |
1468 | |
1469 | /* parse the format_spec */ |
1470 | if (!parse_internal_render_format_spec(obj, format_spec, start, end, Branch (1470:9): [True: 4, False: 7.84k]
|
1471 | &format, 's', '<')) |
1472 | return -1; |
1473 | |
1474 | /* type conversion? */ |
1475 | switch (format.type) { |
1476 | case 's': Branch (1476:5): [True: 7.84k, False: 0]
|
1477 | /* no type conversion needed, already a string. do the formatting */ |
1478 | return format_string_internal(obj, &format, writer); |
1479 | default: Branch (1479:5): [True: 0, False: 7.84k]
|
1480 | /* unknown */ |
1481 | unknown_presentation_type(format.type, Py_TYPE(obj)->tp_name); |
1482 | return -1; |
1483 | } |
1484 | } |
1485 | |
1486 | int |
1487 | _PyLong_FormatAdvancedWriter(_PyUnicodeWriter *writer, |
1488 | PyObject *obj, |
1489 | PyObject *format_spec, |
1490 | Py_ssize_t start, Py_ssize_t end) |
1491 | { |
1492 | PyObject *tmp = NULL; |
1493 | InternalFormatSpec format; |
1494 | int result = -1; |
1495 | |
1496 | /* check for the special case of zero length format spec, make |
1497 | it equivalent to str(obj) */ |
1498 | if (start == end) { Branch (1498:9): [True: 274k, False: 176k]
|
1499 | if (PyLong_CheckExact(obj)) |
1500 | return _PyLong_FormatWriter(writer, obj, 10, 0); |
1501 | else |
1502 | return format_obj(obj, writer); |
1503 | } |
1504 | |
1505 | /* parse the format_spec */ |
1506 | if (!parse_internal_render_format_spec(obj, format_spec, start, end, Branch (1506:9): [True: 35, False: 176k]
|
1507 | &format, 'd', '>')) |
1508 | goto done; |
1509 | |
1510 | /* type conversion? */ |
1511 | switch (format.type) { |
1512 | case 'b': Branch (1512:5): [True: 42, False: 176k]
|
1513 | case 'c': Branch (1513:5): [True: 4, False: 176k]
|
1514 | case 'd': Branch (1514:5): [True: 26.9k, False: 149k]
|
1515 | case 'o': Branch (1515:5): [True: 40, False: 176k]
|
1516 | case 'x': Branch (1516:5): [True: 148k, False: 27.9k]
|
1517 | case 'X': Branch (1517:5): [True: 461, False: 176k]
|
1518 | case 'n': Branch (1518:5): [True: 79, False: 176k]
|
1519 | /* no type conversion needed, already an int. do the formatting */ |
1520 | result = format_long_internal(obj, &format, writer); |
1521 | break; |
1522 | |
1523 | case 'e': Branch (1523:5): [True: 14, False: 176k]
|
1524 | case 'E': Branch (1524:5): [True: 14, False: 176k]
|
1525 | case 'f': Branch (1525:5): [True: 22, False: 176k]
|
1526 | case 'F': Branch (1526:5): [True: 14, False: 176k]
|
1527 | case 'g': Branch (1527:5): [True: 14, False: 176k]
|
1528 | case 'G': Branch (1528:5): [True: 14, False: 176k]
|
1529 | case '%': Branch (1529:5): [True: 14, False: 176k]
|
1530 | /* convert to float */ |
1531 | tmp = PyNumber_Float(obj); |
1532 | if (tmp == NULL) Branch (1532:13): [True: 0, False: 106]
|
1533 | goto done; |
1534 | result = format_float_internal(tmp, &format, writer); |
1535 | break; |
1536 | |
1537 | default: Branch (1537:5): [True: 306, False: 176k]
|
1538 | /* unknown */ |
1539 | unknown_presentation_type(format.type, Py_TYPE(obj)->tp_name); |
1540 | goto done; |
1541 | } |
1542 | |
1543 | done: |
1544 | Py_XDECREF(tmp); |
1545 | return result; |
1546 | } |
1547 | |
1548 | int |
1549 | _PyFloat_FormatAdvancedWriter(_PyUnicodeWriter *writer, |
1550 | PyObject *obj, |
1551 | PyObject *format_spec, |
1552 | Py_ssize_t start, Py_ssize_t end) |
1553 | { |
1554 | InternalFormatSpec format; |
1555 | |
1556 | /* check for the special case of zero length format spec, make |
1557 | it equivalent to str(obj) */ |
1558 | if (start == end) Branch (1558:9): [True: 16.2k, False: 7.31k]
|
1559 | return format_obj(obj, writer); |
1560 | |
1561 | /* parse the format_spec */ |
1562 | if (!parse_internal_render_format_spec(obj, format_spec, start, end, Branch (1562:9): [True: 6, False: 7.30k]
|
1563 | &format, '\0', '>')) |
1564 | return -1; |
1565 | |
1566 | /* type conversion? */ |
1567 | switch (format.type) { |
1568 | case '\0': /* No format code: like 'g', but with at least one decimal. */ Branch (1568:5): [True: 55, False: 7.25k]
|
1569 | case 'e': Branch (1569:5): [True: 290, False: 7.01k]
|
1570 | case 'E': Branch (1570:5): [True: 22, False: 7.28k]
|
1571 | case 'f': Branch (1571:5): [True: 6.62k, False: 679]
|
1572 | case 'F': Branch (1572:5): [True: 18, False: 7.28k]
|
1573 | case 'g': Branch (1573:5): [True: 110, False: 7.19k]
|
1574 | case 'G': Branch (1574:5): [True: 16, False: 7.29k]
|
1575 | case 'n': Branch (1575:5): [True: 43, False: 7.26k]
|
1576 | case '%': Branch (1576:5): [True: 26, False: 7.28k]
|
1577 | /* no conversion, already a float. do the formatting */ |
1578 | return format_float_internal(obj, &format, writer); |
1579 | |
1580 | default: Branch (1580:5): [True: 99, False: 7.20k]
|
1581 | /* unknown */ |
1582 | unknown_presentation_type(format.type, Py_TYPE(obj)->tp_name); |
1583 | return -1; |
1584 | } |
1585 | } |
1586 | |
1587 | int |
1588 | _PyComplex_FormatAdvancedWriter(_PyUnicodeWriter *writer, |
1589 | PyObject *obj, |
1590 | PyObject *format_spec, |
1591 | Py_ssize_t start, Py_ssize_t end) |
1592 | { |
1593 | InternalFormatSpec format; |
1594 | |
1595 | /* check for the special case of zero length format spec, make |
1596 | it equivalent to str(obj) */ |
1597 | if (start == end) Branch (1597:9): [True: 11, False: 107]
|
1598 | return format_obj(obj, writer); |
1599 | |
1600 | /* parse the format_spec */ |
1601 | if (!parse_internal_render_format_spec(obj, format_spec, start, end, Branch (1601:9): [True: 4, False: 103]
|
1602 | &format, '\0', '>')) |
1603 | return -1; |
1604 | |
1605 | /* type conversion? */ |
1606 | switch (format.type) { |
1607 | case '\0': /* No format code: like 'g', but with at least one decimal. */ Branch (1607:5): [True: 26, False: 77]
|
1608 | case 'e': Branch (1608:5): [True: 8, False: 95]
|
1609 | case 'E': Branch (1609:5): [True: 1, False: 102]
|
1610 | case 'f': Branch (1610:5): [True: 32, False: 71]
|
1611 | case 'F': Branch (1611:5): [True: 9, False: 94]
|
1612 | case 'g': Branch (1612:5): [True: 20, False: 83]
|
1613 | case 'G': Branch (1613:5): [True: 1, False: 102]
|
1614 | case 'n': Branch (1614:5): [True: 0, False: 103]
|
1615 | /* no conversion, already a complex. do the formatting */ |
1616 | return format_complex_internal(obj, &format, writer); |
1617 | |
1618 | default: Branch (1618:5): [True: 6, False: 97]
|
1619 | /* unknown */ |
1620 | unknown_presentation_type(format.type, Py_TYPE(obj)->tp_name); |
1621 | return -1; |
1622 | } |
1623 | } |