/Objects/stringlib/localeutil.h

http://unladen-swallow.googlecode.com/ · C Header · 130 lines · 65 code · 13 blank · 52 comment · 15 complexity · 1d87a92ba0baf6c9d21ba00b17fe9f24 MD5 · raw file

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