gnulib-fix-width.diff 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. diff --git a/lib/argp-fmtstream.c b/lib/argp-fmtstream.c
  2. index 7aa317c..02406ff 100644
  3. --- a/lib/argp-fmtstream.c
  4. +++ b/lib/argp-fmtstream.c
  5. @@ -29,9 +29,11 @@
  6. #include <errno.h>
  7. #include <stdarg.h>
  8. #include <ctype.h>
  9. +#include <wchar.h>
  10. #include "argp-fmtstream.h"
  11. #include "argp-namefrob.h"
  12. +#include "mbswidth.h"
  13. #ifndef ARGP_FMTSTREAM_USE_LINEWRAP
  14. @@ -116,6 +118,51 @@ weak_alias (__argp_fmtstream_free, argp_fmtstream_free)
  15. #endif
  16. #endif
  17. +
  18. +/* Return the pointer to the first character that doesn't fit in l columns. */
  19. +static inline const ptrdiff_t
  20. +add_width (const char *ptr, const char *end, size_t l)
  21. +{
  22. + mbstate_t ps;
  23. + const char *ptr0 = ptr;
  24. +
  25. + memset (&ps, 0, sizeof (ps));
  26. +
  27. + while (ptr < end)
  28. + {
  29. + wchar_t wc;
  30. + size_t s, k;
  31. +
  32. + s = mbrtowc (&wc, ptr, end - ptr, &ps);
  33. + if (s == (size_t) -1)
  34. + break;
  35. + if (s == (size_t) -2)
  36. + {
  37. + if (1 >= l)
  38. + break;
  39. + l--;
  40. + ptr++;
  41. + continue;
  42. + }
  43. +
  44. + if (wc == '\e' && ptr + 3 < end
  45. + && ptr[1] == '[' && (ptr[2] == '0' || ptr[2] == '1')
  46. + && ptr[3] == 'm')
  47. + {
  48. + ptr += 4;
  49. + continue;
  50. + }
  51. +
  52. + k = wcwidth (wc);
  53. +
  54. + if (k >= l)
  55. + break;
  56. + l -= k;
  57. + ptr += s;
  58. + }
  59. + return ptr - ptr0;
  60. +}
  61. +
  62. /* Process FS's buffer so that line wrapping is done from POINT_OFFS to the
  63. end of its buffer. This code is mostly from glibc stdio/linewrap.c. */
  64. void
  65. @@ -168,14 +215,15 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
  66. if (!nl)
  67. {
  68. + size_t display_width = mbsnwidth (buf, fs->p - buf, MBSW_STOP_AT_NUL);
  69. /* The buffer ends in a partial line. */
  70. - if (fs->point_col + len < fs->rmargin)
  71. + if (fs->point_col + display_width < fs->rmargin)
  72. {
  73. /* The remaining buffer text is a partial line and fits
  74. within the maximum line width. Advance point for the
  75. characters to be written and stop scanning. */
  76. - fs->point_col += len;
  77. + fs->point_col += display_width;
  78. break;
  79. }
  80. else
  81. @@ -183,14 +231,18 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
  82. the end of the buffer. */
  83. nl = fs->p;
  84. }
  85. - else if (fs->point_col + (nl - buf) < (ssize_t) fs->rmargin)
  86. - {
  87. - /* The buffer contains a full line that fits within the maximum
  88. - line width. Reset point and scan the next line. */
  89. - fs->point_col = 0;
  90. - buf = nl + 1;
  91. - continue;
  92. - }
  93. + else
  94. + {
  95. + size_t display_width = mbsnwidth (buf, nl - buf, MBSW_STOP_AT_NUL);
  96. + if (display_width < (ssize_t) fs->rmargin)
  97. + {
  98. + /* The buffer contains a full line that fits within the maximum
  99. + line width. Reset point and scan the next line. */
  100. + fs->point_col = 0;
  101. + buf = nl + 1;
  102. + continue;
  103. + }
  104. + }
  105. /* This line is too long. */
  106. r = fs->rmargin - 1;
  107. @@ -226,7 +278,7 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
  108. char *p, *nextline;
  109. int i;
  110. - p = buf + (r + 1 - fs->point_col);
  111. + p = buf + add_width (buf, fs->p, (r + 1 - fs->point_col));
  112. while (p >= buf && !isblank ((unsigned char) *p))
  113. --p;
  114. nextline = p + 1; /* This will begin the next line. */
  115. @@ -244,7 +296,7 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
  116. {
  117. /* A single word that is greater than the maximum line width.
  118. Oh well. Put it on an overlong line by itself. */
  119. - p = buf + (r + 1 - fs->point_col);
  120. + p = buf + add_width (buf, fs->p, (r + 1 - fs->point_col));
  121. /* Find the end of the long word. */
  122. if (p < nl)
  123. do
  124. @@ -278,7 +330,8 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
  125. && fs->p > nextline)
  126. {
  127. /* The margin needs more blanks than we removed. */
  128. - if (fs->end - fs->p > fs->wmargin + 1)
  129. + if (mbsnwidth (fs->p, fs->end - fs->p, MBSW_STOP_AT_NUL)
  130. + > fs->wmargin + 1)
  131. /* Make some space for them. */
  132. {
  133. size_t mv = fs->p - nextline;
  134. diff --git a/lib/argp-help.c b/lib/argp-help.c
  135. index 354f1e2..2914f47 100644
  136. --- a/lib/argp-help.c
  137. +++ b/lib/argp-help.c
  138. @@ -50,6 +50,7 @@
  139. #include "argp.h"
  140. #include "argp-fmtstream.h"
  141. #include "argp-namefrob.h"
  142. +#include "mbswidth.h"
  143. #ifndef SIZE_MAX
  144. # define SIZE_MAX ((size_t) -1)
  145. @@ -1452,7 +1453,7 @@ argp_args_usage (const struct argp *argp, const struct argp_state *state,
  146. /* Manually do line wrapping so that it (probably) won't get wrapped at
  147. any embedded spaces. */
  148. - space (stream, 1 + nl - cp);
  149. + space (stream, 1 + mbsnwidth (cp, nl - cp, MBSW_STOP_AT_NUL));
  150. __argp_fmtstream_write (stream, cp, nl - cp);
  151. }
  152. diff --git a/lib/mbswidth.c b/lib/mbswidth.c
  153. index 7c2dfce..baa4f27 100644
  154. --- a/lib/mbswidth.c
  155. +++ b/lib/mbswidth.c
  156. @@ -90,6 +90,9 @@ mbsnwidth (const char *string, size_t nbytes, int flags)
  157. p++;
  158. width++;
  159. break;
  160. + case '\0':
  161. + if (flags & MBSW_STOP_AT_NUL)
  162. + return width;
  163. default:
  164. /* If we have a multibyte sequence, scan it up to its end. */
  165. {
  166. @@ -168,6 +171,9 @@ mbsnwidth (const char *string, size_t nbytes, int flags)
  167. {
  168. unsigned char c = (unsigned char) *p++;
  169. + if (c == 0 && (flags & MBSW_STOP_AT_NUL))
  170. + return width;
  171. +
  172. if (isprint (c))
  173. {
  174. if (width == INT_MAX)
  175. diff --git a/lib/mbswidth.h b/lib/mbswidth.h
  176. index e9c0b03..d7207c5 100644
  177. --- a/lib/mbswidth.h
  178. +++ b/lib/mbswidth.h
  179. @@ -45,6 +45,9 @@ extern "C" {
  180. control characters and 1 otherwise. */
  181. #define MBSW_REJECT_UNPRINTABLE 2
  182. +/* If this bit is set \0 is treated as the end of string.
  183. + Otherwise it's treated as a normal one column width character. */
  184. +#define MBSW_STOP_AT_NUL 4
  185. /* Returns the number of screen columns needed for STRING. */
  186. #define mbswidth gnu_mbswidth /* avoid clash with UnixWare 7.1.1 function */
  187. diff --git a/modules/argp b/modules/argp
  188. index 125046a..6f14d10 100644
  189. --- a/modules/argp
  190. +++ b/modules/argp
  191. @@ -40,6 +40,7 @@ stdalign
  192. strerror
  193. memchr
  194. memmove
  195. +mbswidth
  196. configure.ac:
  197. gl_ARGP
  198. diff --git a/modules/argp-tests b/modules/argp-tests
  199. index 8f92a4d..0463927 100644
  200. --- a/modules/argp-tests
  201. +++ b/modules/argp-tests
  202. @@ -1,11 +1,13 @@
  203. Files:
  204. tests/test-argp.c
  205. tests/test-argp-2.sh
  206. +tests/test-argp-2-utf.sh
  207. Depends-on:
  208. progname
  209. Makefile.am:
  210. TESTS += test-argp test-argp-2.sh
  211. -check_PROGRAMS += test-argp
  212. +TESTS += test-argp test-argp-2.sh test-argp-2-utf.sh
  213. +check_PROGRAMS += test-argp test-argp-utf8
  214. test_argp_LDADD = $(LDADD) @LIBINTL@