strwide.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. /*
  2. * libdpkg - Debian packaging suite library routines
  3. * strwide.c - wide character string handling routines
  4. *
  5. * Copyright © 2004 Changwoo Ryu <cwryu@debian.org>
  6. * Copyright © 2012-2013 Guillem Jover <guillem@debian.org>
  7. *
  8. * This is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. */
  21. #include <config.h>
  22. #include <compat.h>
  23. #include <string.h>
  24. #include <stdlib.h>
  25. #ifdef ENABLE_NLS
  26. #include <wchar.h>
  27. #endif
  28. #include <dpkg/i18n.h>
  29. #include <dpkg/dpkg.h>
  30. #include <dpkg/string.h>
  31. /**
  32. * Compute the screen width of a string.
  33. *
  34. * @param str The multibyte string.
  35. *
  36. * @return The width of the string.
  37. */
  38. int
  39. str_width(const char *str)
  40. {
  41. #ifdef ENABLE_NLS
  42. mbstate_t state;
  43. wchar_t *wcs;
  44. const char *mbs = str;
  45. size_t len, res;
  46. int width;
  47. len = strlen(str) + 1;
  48. wcs = m_malloc(sizeof(wcs[0]) * len);
  49. memset(&state, 0, sizeof(state));
  50. res = mbsrtowcs(wcs, &mbs, len, &state);
  51. if (res == (size_t)-1) {
  52. #ifdef DPKG_UNIFORM_ENCODING
  53. ohshit(_("cannot convert multibyte string '%s' "
  54. "to a wide-character string"), str);
  55. #else
  56. /* Cannot convert, fallback to ASCII method. */
  57. free(wcs);
  58. return strlen(str);
  59. #endif
  60. }
  61. width = wcswidth(wcs, res);
  62. free(wcs);
  63. return width;
  64. #else
  65. return strlen(str);
  66. #endif
  67. }
  68. /**
  69. * Generate the crop values for a string given a maximum screen width.
  70. *
  71. * This function analyzes the string passed and computes the correct point
  72. * where to crop the string, returning the amount of string and maximum
  73. * bytes to use for padding for example.
  74. *
  75. * On NLS enabled builds, in addition the string will be cropped on any
  76. * newline.
  77. *
  78. * @param str The string to crop.
  79. * @param max_width The max screen width to use.
  80. * @param[out] crop The generated crop values for the string.
  81. */
  82. void
  83. str_gen_crop(const char *str, int max_width, struct str_crop_info *crop)
  84. {
  85. #ifdef ENABLE_NLS
  86. mbstate_t state;
  87. size_t str_bytes;
  88. int mbs_bytes = 0;
  89. int mbs_width = 0;
  90. str_bytes = strlen(str) + 1;
  91. memset(&state, 0, sizeof(state));
  92. for (;;) {
  93. wchar_t wc;
  94. int wc_width;
  95. size_t mb_bytes;
  96. mb_bytes = mbrtowc(&wc, str, str_bytes, &state);
  97. if (mb_bytes == (size_t)-1 || mb_bytes == (size_t)-2) {
  98. #ifdef DPKG_UNIFORM_ENCODING
  99. ohshit(_("cannot convert multibyte sequence '%s' "
  100. "to a wide character"), str);
  101. #else
  102. /* Cannot convert, fallback to ASCII method. */
  103. crop->str_bytes = crop->max_bytes = max_width;
  104. return;
  105. #endif
  106. }
  107. if (mb_bytes == 0)
  108. break;
  109. wc_width = wcwidth(wc);
  110. if (wc_width < 0)
  111. break;
  112. if (mbs_width + wc_width > max_width)
  113. break;
  114. mbs_width += wc_width;
  115. mbs_bytes += mb_bytes;
  116. str_bytes -= mb_bytes;
  117. str += mb_bytes;
  118. }
  119. crop->str_bytes = mbs_bytes;
  120. crop->max_bytes = mbs_bytes + max_width - mbs_width;
  121. #else
  122. crop->str_bytes = crop->max_bytes = max_width;
  123. #endif
  124. }