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
11 #include "argp-fmtstream.h"
12 #include "argp-namefrob.h"
13 +#include "mbswidth.h"
15 #ifndef ARGP_FMTSTREAM_USE_LINEWRAP
17 @@ -116,6 +118,51 @@ weak_alias (__argp_fmtstream_free, argp_fmtstream_free)
22 +/* Return the pointer to the first character that doesn't fit in l columns. */
23 +static inline const ptrdiff_t
24 +add_width (const char *ptr, const char *end, size_t l)
27 + const char *ptr0 = ptr;
29 + memset (&ps, 0, sizeof (ps));
36 + s = mbrtowc (&wc, ptr, end - ptr, &ps);
37 + if (s == (size_t) -1)
39 + if (s == (size_t) -2)
48 + if (wc == '\e' && ptr + 3 < end
49 + && ptr[1] == '[' && (ptr[2] == '0' || ptr[2] == '1')
66 /* Process FS's buffer so that line wrapping is done from POINT_OFFS to the
67 end of its buffer. This code is mostly from glibc stdio/linewrap.c. */
69 @@ -168,14 +215,15 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
73 + size_t display_width = mbsnwidth (buf, fs->p - buf, MBSW_STOP_AT_NUL);
74 /* The buffer ends in a partial line. */
76 - if (fs->point_col + len < fs->rmargin)
77 + if (fs->point_col + display_width < fs->rmargin)
79 /* The remaining buffer text is a partial line and fits
80 within the maximum line width. Advance point for the
81 characters to be written and stop scanning. */
82 - fs->point_col += len;
83 + fs->point_col += display_width;
87 @@ -183,14 +231,18 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
88 the end of the buffer. */
91 - else if (fs->point_col + (nl - buf) < (ssize_t) fs->rmargin)
93 - /* The buffer contains a full line that fits within the maximum
94 - line width. Reset point and scan the next line. */
101 + size_t display_width = mbsnwidth (buf, nl - buf, MBSW_STOP_AT_NUL);
102 + if (display_width < (ssize_t) fs->rmargin)
104 + /* The buffer contains a full line that fits within the maximum
105 + line width. Reset point and scan the next line. */
112 /* This line is too long. */
114 @@ -226,7 +278,7 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
118 - p = buf + (r + 1 - fs->point_col);
119 + p = buf + add_width (buf, fs->p, (r + 1 - fs->point_col));
120 while (p >= buf && !isblank ((unsigned char) *p))
122 nextline = p + 1; /* This will begin the next line. */
123 @@ -244,7 +296,7 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
125 /* A single word that is greater than the maximum line width.
126 Oh well. Put it on an overlong line by itself. */
127 - p = buf + (r + 1 - fs->point_col);
128 + p = buf + add_width (buf, fs->p, (r + 1 - fs->point_col));
129 /* Find the end of the long word. */
132 @@ -278,7 +330,8 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
135 /* The margin needs more blanks than we removed. */
136 - if (fs->end - fs->p > fs->wmargin + 1)
137 + if (mbsnwidth (fs->p, fs->end - fs->p, MBSW_STOP_AT_NUL)
139 /* Make some space for them. */
141 size_t mv = fs->p - nextline;
142 diff --git a/lib/argp-help.c b/lib/argp-help.c
143 index 354f1e2..2914f47 100644
144 --- a/lib/argp-help.c
145 +++ b/lib/argp-help.c
148 #include "argp-fmtstream.h"
149 #include "argp-namefrob.h"
150 +#include "mbswidth.h"
153 # define SIZE_MAX ((size_t) -1)
154 @@ -1452,7 +1453,7 @@ argp_args_usage (const struct argp *argp, const struct argp_state *state,
156 /* Manually do line wrapping so that it (probably) won't get wrapped at
157 any embedded spaces. */
158 - space (stream, 1 + nl - cp);
159 + space (stream, 1 + mbsnwidth (cp, nl - cp, MBSW_STOP_AT_NUL));
161 __argp_fmtstream_write (stream, cp, nl - cp);
163 diff --git a/lib/mbswidth.c b/lib/mbswidth.c
164 index 7c2dfce..baa4f27 100644
167 @@ -90,6 +90,9 @@ mbsnwidth (const char *string, size_t nbytes, int flags)
172 + if (flags & MBSW_STOP_AT_NUL)
175 /* If we have a multibyte sequence, scan it up to its end. */
177 @@ -168,6 +171,9 @@ mbsnwidth (const char *string, size_t nbytes, int flags)
179 unsigned char c = (unsigned char) *p++;
181 + if (c == 0 && (flags & MBSW_STOP_AT_NUL))
186 if (width == INT_MAX)
187 diff --git a/lib/mbswidth.h b/lib/mbswidth.h
188 index e9c0b03..d7207c5 100644
191 @@ -45,6 +45,9 @@ extern "C" {
192 control characters and 1 otherwise. */
193 #define MBSW_REJECT_UNPRINTABLE 2
195 +/* If this bit is set \0 is treated as the end of string.
196 + Otherwise it's treated as a normal one column width character. */
197 +#define MBSW_STOP_AT_NUL 4
199 /* Returns the number of screen columns needed for STRING. */
200 #define mbswidth gnu_mbswidth /* avoid clash with UnixWare 7.1.1 function */
201 diff --git a/modules/argp b/modules/argp
202 index 125046a..6f14d10 100644
205 @@ -40,6 +40,7 @@ stdalign
213 diff --git a/modules/argp-tests b/modules/argp-tests
214 index 8f92a4d..0463927 100644
215 --- a/modules/argp-tests
216 +++ b/modules/argp-tests
221 +tests/test-argp-2-utf.sh
227 TESTS += test-argp test-argp-2.sh
228 -check_PROGRAMS += test-argp
229 +TESTS += test-argp test-argp-2.sh test-argp-2-utf.sh
230 +check_PROGRAMS += test-argp test-argp-utf8
231 test_argp_LDADD = $(LDADD) @LIBINTL@