2013-04-11 19:12:46 +00:00
|
|
|
|
diff --git a/lib/argp-fmtstream.c b/lib/argp-fmtstream.c
|
2019-02-27 10:03:55 +00:00
|
|
|
|
index ba6a407f7..d0685b3d4 100644
|
2013-04-11 19:12:46 +00:00
|
|
|
|
--- a/lib/argp-fmtstream.c
|
|
|
|
|
+++ b/lib/argp-fmtstream.c
|
2019-02-27 10:03:55 +00:00
|
|
|
|
@@ -28,9 +28,11 @@
|
2013-04-11 19:12:46 +00:00
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
+#include <wchar.h>
|
|
|
|
|
|
|
|
|
|
#include "argp-fmtstream.h"
|
|
|
|
|
#include "argp-namefrob.h"
|
|
|
|
|
+#include "mbswidth.h"
|
|
|
|
|
|
|
|
|
|
#ifndef ARGP_FMTSTREAM_USE_LINEWRAP
|
|
|
|
|
|
2019-02-27 10:03:55 +00:00
|
|
|
|
@@ -115,6 +117,51 @@ weak_alias (__argp_fmtstream_free, argp_fmtstream_free)
|
2013-04-11 19:12:46 +00:00
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
|
+/* Return the pointer to the first character that doesn't fit in l columns. */
|
|
|
|
|
+static inline const ptrdiff_t
|
|
|
|
|
+add_width (const char *ptr, const char *end, size_t l)
|
|
|
|
|
+{
|
|
|
|
|
+ mbstate_t ps;
|
|
|
|
|
+ const char *ptr0 = ptr;
|
|
|
|
|
+
|
|
|
|
|
+ memset (&ps, 0, sizeof (ps));
|
|
|
|
|
+
|
|
|
|
|
+ while (ptr < end)
|
|
|
|
|
+ {
|
|
|
|
|
+ wchar_t wc;
|
|
|
|
|
+ size_t s, k;
|
|
|
|
|
+
|
|
|
|
|
+ s = mbrtowc (&wc, ptr, end - ptr, &ps);
|
|
|
|
|
+ if (s == (size_t) -1)
|
|
|
|
|
+ break;
|
|
|
|
|
+ if (s == (size_t) -2)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (1 >= l)
|
|
|
|
|
+ break;
|
|
|
|
|
+ l--;
|
|
|
|
|
+ ptr++;
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (wc == '\e' && ptr + 3 < end
|
|
|
|
|
+ && ptr[1] == '[' && (ptr[2] == '0' || ptr[2] == '1')
|
|
|
|
|
+ && ptr[3] == 'm')
|
|
|
|
|
+ {
|
|
|
|
|
+ ptr += 4;
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ k = wcwidth (wc);
|
|
|
|
|
+
|
|
|
|
|
+ if (k >= l)
|
|
|
|
|
+ break;
|
|
|
|
|
+ l -= k;
|
|
|
|
|
+ ptr += s;
|
|
|
|
|
+ }
|
|
|
|
|
+ return ptr - ptr0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
/* Process FS's buffer so that line wrapping is done from POINT_OFFS to the
|
|
|
|
|
end of its buffer. This code is mostly from glibc stdio/linewrap.c. */
|
|
|
|
|
void
|
2019-02-27 10:03:55 +00:00
|
|
|
|
@@ -168,13 +215,15 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
|
2013-04-11 19:12:46 +00:00
|
|
|
|
if (!nl)
|
|
|
|
|
{
|
|
|
|
|
/* The buffer ends in a partial line. */
|
2019-02-27 10:03:55 +00:00
|
|
|
|
+ size_t display_width = mbsnwidth (buf, fs->p - buf,
|
|
|
|
|
+ MBSW_STOP_AT_NUL);
|
2013-04-11 19:12:46 +00:00
|
|
|
|
|
|
|
|
|
- if (fs->point_col + len < fs->rmargin)
|
|
|
|
|
+ if (fs->point_col + display_width < fs->rmargin)
|
|
|
|
|
{
|
|
|
|
|
/* The remaining buffer text is a partial line and fits
|
|
|
|
|
within the maximum line width. Advance point for the
|
|
|
|
|
characters to be written and stop scanning. */
|
|
|
|
|
- fs->point_col += len;
|
|
|
|
|
+ fs->point_col += display_width;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else
|
2019-02-27 10:03:55 +00:00
|
|
|
|
@@ -182,14 +231,18 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
|
2013-04-11 19:12:46 +00:00
|
|
|
|
the end of the buffer. */
|
|
|
|
|
nl = fs->p;
|
|
|
|
|
}
|
|
|
|
|
- else if (fs->point_col + (nl - buf) < (ssize_t) fs->rmargin)
|
|
|
|
|
- {
|
|
|
|
|
- /* The buffer contains a full line that fits within the maximum
|
|
|
|
|
- line width. Reset point and scan the next line. */
|
|
|
|
|
- fs->point_col = 0;
|
|
|
|
|
- buf = nl + 1;
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ size_t display_width = mbsnwidth (buf, nl - buf, MBSW_STOP_AT_NUL);
|
|
|
|
|
+ if (display_width < (ssize_t) fs->rmargin)
|
|
|
|
|
+ {
|
|
|
|
|
+ /* The buffer contains a full line that fits within the maximum
|
|
|
|
|
+ line width. Reset point and scan the next line. */
|
|
|
|
|
+ fs->point_col = 0;
|
|
|
|
|
+ buf = nl + 1;
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
/* This line is too long. */
|
|
|
|
|
r = fs->rmargin - 1;
|
2019-02-27 10:03:55 +00:00
|
|
|
|
@@ -225,7 +278,7 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
|
2013-04-11 19:12:46 +00:00
|
|
|
|
char *p, *nextline;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
- p = buf + (r + 1 - fs->point_col);
|
2019-02-27 10:03:55 +00:00
|
|
|
|
+ p = buf + add_width (buf, fs->p, (r + 1 - fs->point_col));
|
2013-04-11 19:12:46 +00:00
|
|
|
|
while (p >= buf && !isblank ((unsigned char) *p))
|
|
|
|
|
--p;
|
|
|
|
|
nextline = p + 1; /* This will begin the next line. */
|
2019-02-27 10:03:55 +00:00
|
|
|
|
@@ -243,7 +296,7 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
|
2013-04-11 19:12:46 +00:00
|
|
|
|
{
|
|
|
|
|
/* A single word that is greater than the maximum line width.
|
|
|
|
|
Oh well. Put it on an overlong line by itself. */
|
|
|
|
|
- p = buf + (r + 1 - fs->point_col);
|
|
|
|
|
+ p = buf + add_width (buf, fs->p, (r + 1 - fs->point_col));
|
|
|
|
|
/* Find the end of the long word. */
|
|
|
|
|
if (p < nl)
|
|
|
|
|
do
|
2019-02-27 10:03:55 +00:00
|
|
|
|
@@ -277,7 +330,8 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
|
2013-04-11 19:12:46 +00:00
|
|
|
|
&& fs->p > nextline)
|
|
|
|
|
{
|
|
|
|
|
/* The margin needs more blanks than we removed. */
|
|
|
|
|
- if (fs->end - fs->p > fs->wmargin + 1)
|
|
|
|
|
+ if (mbsnwidth (fs->p, fs->end - fs->p, MBSW_STOP_AT_NUL)
|
2019-02-27 10:03:55 +00:00
|
|
|
|
+ > fs->wmargin + 1)
|
2013-04-11 19:12:46 +00:00
|
|
|
|
/* Make some space for them. */
|
|
|
|
|
{
|
|
|
|
|
size_t mv = fs->p - nextline;
|
|
|
|
|
diff --git a/lib/argp-help.c b/lib/argp-help.c
|
2019-02-27 10:03:55 +00:00
|
|
|
|
index e5375a0f0..5d8f451ec 100644
|
2013-04-11 19:12:46 +00:00
|
|
|
|
--- a/lib/argp-help.c
|
|
|
|
|
+++ b/lib/argp-help.c
|
2019-02-27 10:03:55 +00:00
|
|
|
|
@@ -51,6 +51,7 @@
|
2013-04-11 19:12:46 +00:00
|
|
|
|
#include "argp.h"
|
|
|
|
|
#include "argp-fmtstream.h"
|
|
|
|
|
#include "argp-namefrob.h"
|
|
|
|
|
+#include "mbswidth.h"
|
|
|
|
|
|
|
|
|
|
#ifndef SIZE_MAX
|
|
|
|
|
# define SIZE_MAX ((size_t) -1)
|
2019-02-27 10:03:55 +00:00
|
|
|
|
@@ -1432,7 +1433,7 @@ argp_args_usage (const struct argp *argp, const struct argp_state *state,
|
2013-04-11 19:12:46 +00:00
|
|
|
|
|
|
|
|
|
/* Manually do line wrapping so that it (probably) won't get wrapped at
|
|
|
|
|
any embedded spaces. */
|
|
|
|
|
- space (stream, 1 + nl - cp);
|
|
|
|
|
+ space (stream, 1 + mbsnwidth (cp, nl - cp, MBSW_STOP_AT_NUL));
|
|
|
|
|
|
|
|
|
|
__argp_fmtstream_write (stream, cp, nl - cp);
|
|
|
|
|
}
|
|
|
|
|
diff --git a/lib/mbswidth.c b/lib/mbswidth.c
|
2019-02-27 10:03:55 +00:00
|
|
|
|
index 408a15e34..b3fb7f83a 100644
|
2013-04-11 19:12:46 +00:00
|
|
|
|
--- a/lib/mbswidth.c
|
|
|
|
|
+++ b/lib/mbswidth.c
|
2019-02-27 10:03:55 +00:00
|
|
|
|
@@ -38,6 +38,14 @@
|
|
|
|
|
/* Get INT_MAX. */
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
|
|
|
|
|
+#ifndef FALLTHROUGH
|
|
|
|
|
+# if __GNUC__ < 7
|
|
|
|
|
+# define FALLTHROUGH ((void) 0)
|
|
|
|
|
+# else
|
|
|
|
|
+# define FALLTHROUGH __attribute__ ((__fallthrough__))
|
|
|
|
|
+# endif
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
/* Returns the number of columns needed to represent the multibyte
|
|
|
|
|
character string pointed to by STRING. If a non-printable character
|
|
|
|
|
occurs, and MBSW_REJECT_UNPRINTABLE is specified, -1 is returned.
|
|
|
|
|
@@ -90,6 +98,10 @@ mbsnwidth (const char *string, size_t nbytes, int flags)
|
2013-04-11 19:12:46 +00:00
|
|
|
|
p++;
|
|
|
|
|
width++;
|
|
|
|
|
break;
|
2019-02-27 10:03:55 +00:00
|
|
|
|
+ case '\0':
|
|
|
|
|
+ if (flags & MBSW_STOP_AT_NUL)
|
|
|
|
|
+ return width;
|
|
|
|
|
+ FALLTHROUGH;
|
2013-04-11 19:12:46 +00:00
|
|
|
|
default:
|
|
|
|
|
/* If we have a multibyte sequence, scan it up to its end. */
|
|
|
|
|
{
|
2019-02-27 10:03:55 +00:00
|
|
|
|
@@ -168,6 +180,9 @@ mbsnwidth (const char *string, size_t nbytes, int flags)
|
2013-04-11 19:12:46 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned char c = (unsigned char) *p++;
|
|
|
|
|
|
|
|
|
|
+ if (c == 0 && (flags & MBSW_STOP_AT_NUL))
|
2019-02-27 10:03:55 +00:00
|
|
|
|
+ return width;
|
2013-04-11 19:12:46 +00:00
|
|
|
|
+
|
|
|
|
|
if (isprint (c))
|
|
|
|
|
{
|
|
|
|
|
if (width == INT_MAX)
|
|
|
|
|
diff --git a/lib/mbswidth.h b/lib/mbswidth.h
|
2019-02-27 10:03:55 +00:00
|
|
|
|
index 2b5c53c37..45a123e63 100644
|
2013-04-11 19:12:46 +00:00
|
|
|
|
--- a/lib/mbswidth.h
|
|
|
|
|
+++ b/lib/mbswidth.h
|
2019-02-27 10:03:55 +00:00
|
|
|
|
@@ -45,6 +45,10 @@ extern "C" {
|
2013-04-11 19:12:46 +00:00
|
|
|
|
control characters and 1 otherwise. */
|
|
|
|
|
#define MBSW_REJECT_UNPRINTABLE 2
|
|
|
|
|
|
|
|
|
|
+/* If this bit is set \0 is treated as the end of string.
|
|
|
|
|
+ Otherwise it's treated as a normal one column width character. */
|
|
|
|
|
+#define MBSW_STOP_AT_NUL 4
|
2019-02-27 10:03:55 +00:00
|
|
|
|
+
|
2013-04-11 19:12:46 +00:00
|
|
|
|
|
|
|
|
|
/* Returns the number of screen columns needed for STRING. */
|
|
|
|
|
#define mbswidth gnu_mbswidth /* avoid clash with UnixWare 7.1.1 function */
|