You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

207 lines
7.0 KiB

  1. /* stringlib: locale related helpers implementation */
  2. #include <locale.h>
  3. #define MAX(x, y) ((x) < (y) ? (y) : (x))
  4. #define MIN(x, y) ((x) < (y) ? (x) : (y))
  5. typedef struct {
  6. const char *grouping;
  7. char previous;
  8. Py_ssize_t i; /* Where we're currently pointing in grouping. */
  9. } STRINGLIB(GroupGenerator);
  10. static void
  11. STRINGLIB(GroupGenerator_init)(STRINGLIB(GroupGenerator) *self, const char *grouping)
  12. {
  13. self->grouping = grouping;
  14. self->i = 0;
  15. self->previous = 0;
  16. }
  17. /* Returns the next grouping, or 0 to signify end. */
  18. static Py_ssize_t
  19. STRINGLIB(GroupGenerator_next)(STRINGLIB(GroupGenerator) *self)
  20. {
  21. /* Note that we don't really do much error checking here. If a
  22. grouping string contains just CHAR_MAX, for example, then just
  23. terminate the generator. That shouldn't happen, but at least we
  24. fail gracefully. */
  25. switch (self->grouping[self->i]) {
  26. case 0:
  27. return self->previous;
  28. case CHAR_MAX:
  29. /* Stop the generator. */
  30. return 0;
  31. default: {
  32. char ch = self->grouping[self->i];
  33. self->previous = ch;
  34. self->i++;
  35. return (Py_ssize_t)ch;
  36. }
  37. }
  38. }
  39. /* Fill in some digits, leading zeros, and thousands separator. All
  40. are optional, depending on when we're called. */
  41. static void
  42. STRINGLIB(fill)(STRINGLIB_CHAR **digits_end, STRINGLIB_CHAR **buffer_end,
  43. Py_ssize_t n_chars, Py_ssize_t n_zeros, const char* thousands_sep,
  44. Py_ssize_t thousands_sep_len)
  45. {
  46. Py_ssize_t i;
  47. if (thousands_sep) {
  48. *buffer_end -= thousands_sep_len;
  49. /* Copy the thousands_sep chars into the buffer. */
  50. #if STRINGLIB_IS_UNICODE
  51. /* Convert from the char's of the thousands_sep from
  52. the locale into unicode. */
  53. for (i = 0; i < thousands_sep_len; ++i)
  54. (*buffer_end)[i] = thousands_sep[i];
  55. #else
  56. /* No conversion, just memcpy the thousands_sep. */
  57. memcpy(*buffer_end, thousands_sep, thousands_sep_len);
  58. #endif
  59. }
  60. *buffer_end -= n_chars;
  61. *digits_end -= n_chars;
  62. memcpy(*buffer_end, *digits_end, n_chars * sizeof(STRINGLIB_CHAR));
  63. *buffer_end -= n_zeros;
  64. for (i = 0; i < n_zeros; i++)
  65. (*buffer_end)[i] = '0';
  66. }
  67. /**
  68. * _Py_InsertThousandsGrouping:
  69. * @buffer: A pointer to the start of a string.
  70. * @n_buffer: Number of characters in @buffer.
  71. * @digits: A pointer to the digits we're reading from. If count
  72. * is non-NULL, this is unused.
  73. * @n_digits: The number of digits in the string, in which we want
  74. * to put the grouping chars.
  75. * @min_width: The minimum width of the digits in the output string.
  76. * Output will be zero-padded on the left to fill.
  77. * @grouping: see definition in localeconv().
  78. * @thousands_sep: see definition in localeconv().
  79. *
  80. * There are 2 modes: counting and filling. If @buffer is NULL,
  81. * we are in counting mode, else filling mode.
  82. * If counting, the required buffer size is returned.
  83. * If filling, we know the buffer will be large enough, so we don't
  84. * need to pass in the buffer size.
  85. * Inserts thousand grouping characters (as defined by grouping and
  86. * thousands_sep) into the string between buffer and buffer+n_digits.
  87. *
  88. * Return value: 0 on error, else 1. Note that no error can occur if
  89. * count is non-NULL.
  90. *
  91. * This name won't be used, the includer of this file should define
  92. * it to be the actual function name, based on unicode or string.
  93. *
  94. * As closely as possible, this code mimics the logic in decimal.py's
  95. _insert_thousands_sep().
  96. **/
  97. Py_ssize_t
  98. _Py_InsertThousandsGrouping(STRINGLIB_CHAR *buffer,
  99. Py_ssize_t n_buffer,
  100. STRINGLIB_CHAR *digits,
  101. Py_ssize_t n_digits,
  102. Py_ssize_t min_width,
  103. const char *grouping,
  104. const char *thousands_sep)
  105. {
  106. Py_ssize_t count = 0;
  107. Py_ssize_t n_zeros;
  108. int loop_broken = 0;
  109. int use_separator = 0; /* First time through, don't append the
  110. separator. They only go between
  111. groups. */
  112. STRINGLIB_CHAR *buffer_end = NULL;
  113. STRINGLIB_CHAR *digits_end = NULL;
  114. Py_ssize_t l;
  115. Py_ssize_t n_chars;
  116. Py_ssize_t thousands_sep_len = strlen(thousands_sep);
  117. Py_ssize_t remaining = n_digits; /* Number of chars remaining to
  118. be looked at */
  119. /* A generator that returns all of the grouping widths, until it
  120. returns 0. */
  121. STRINGLIB(GroupGenerator) groupgen;
  122. STRINGLIB(GroupGenerator_init)(&groupgen, grouping);
  123. if (buffer) {
  124. buffer_end = buffer + n_buffer;
  125. digits_end = digits + n_digits;
  126. }
  127. while ((l = STRINGLIB(GroupGenerator_next)(&groupgen)) > 0) {
  128. l = MIN(l, MAX(MAX(remaining, min_width), 1));
  129. n_zeros = MAX(0, l - remaining);
  130. n_chars = MAX(0, MIN(remaining, l));
  131. /* Use n_zero zero's and n_chars chars */
  132. /* Count only, don't do anything. */
  133. count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars;
  134. if (buffer) {
  135. /* Copy into the output buffer. */
  136. STRINGLIB(fill)(&digits_end, &buffer_end, n_chars, n_zeros,
  137. use_separator ? thousands_sep : NULL, thousands_sep_len);
  138. }
  139. /* Use a separator next time. */
  140. use_separator = 1;
  141. remaining -= n_chars;
  142. min_width -= l;
  143. if (remaining <= 0 && min_width <= 0) {
  144. loop_broken = 1;
  145. break;
  146. }
  147. min_width -= thousands_sep_len;
  148. }
  149. if (!loop_broken) {
  150. /* We left the loop without using a break statement. */
  151. l = MAX(MAX(remaining, min_width), 1);
  152. n_zeros = MAX(0, l - remaining);
  153. n_chars = MAX(0, MIN(remaining, l));
  154. /* Use n_zero zero's and n_chars chars */
  155. count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars;
  156. if (buffer) {
  157. /* Copy into the output buffer. */
  158. STRINGLIB(fill)(&digits_end, &buffer_end, n_chars, n_zeros,
  159. use_separator ? thousands_sep : NULL, thousands_sep_len);
  160. }
  161. }
  162. return count;
  163. }
  164. /**
  165. * _Py_InsertThousandsGroupingLocale:
  166. * @buffer: A pointer to the start of a string.
  167. * @n_digits: The number of digits in the string, in which we want
  168. * to put the grouping chars.
  169. *
  170. * Reads thee current locale and calls _Py_InsertThousandsGrouping().
  171. **/
  172. Py_ssize_t
  173. _Py_InsertThousandsGroupingLocale(STRINGLIB_CHAR *buffer,
  174. Py_ssize_t n_buffer,
  175. STRINGLIB_CHAR *digits,
  176. Py_ssize_t n_digits,
  177. Py_ssize_t min_width)
  178. {
  179. struct lconv *locale_data = localeconv();
  180. const char *grouping = locale_data->grouping;
  181. const char *thousands_sep = locale_data->thousands_sep;
  182. return _Py_InsertThousandsGrouping(buffer, n_buffer, digits, n_digits,
  183. min_width, grouping, thousands_sep);
  184. }