]> git.ipfire.org Git - ipfire-3.x.git/blobdiff - coreutils/patches/coreutils-i18n-expand-unexpand.patch
coreutils: Update to 9.1
[ipfire-3.x.git] / coreutils / patches / coreutils-i18n-expand-unexpand.patch
diff --git a/coreutils/patches/coreutils-i18n-expand-unexpand.patch b/coreutils/patches/coreutils-i18n-expand-unexpand.patch
deleted file mode 100644 (file)
index b5f571f..0000000
+++ /dev/null
@@ -1,848 +0,0 @@
-From e87ab5b991b08092a7e07af82b3ec822a8604151 Mon Sep 17 00:00:00 2001
-From: Ondrej Oprala <ooprala@redhat.com>
-Date: Wed, 5 Aug 2015 09:15:09 +0200
-Subject: [PATCH] expand,unexpand: add multibyte support
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-* NEWS: Mention the changes.
-* bootstrap.conf: Add mbfile to the list of modules.
-* configure.ac: Properly initialize mbfile.
-* src/expand.c (expand): Iterate over multibyte characters properly.
-* src/unexpand.c (unexpand): Iterate over multibyte characters
-properly.
-* tests/local.mk: Add new tests.
-* tests/{expand,unexpand}/mb.sh: New tests.
-
-Co-authored-by: Pádraig Brady <pbrady@redhat.com>
----
- bootstrap.conf       |   1 +
- configure.ac         |   2 +
- lib/mbfile.c         |   3 +
- lib/mbfile.h         | 255 +++++++++++++++++++++++++++++++++++++++++++++++++++
- m4/mbfile.m4         |  14 +++
- src/expand.c         |  43 +++++----
- src/unexpand.c       |  54 +++++++----
- tests/expand/mb.sh   |  98 ++++++++++++++++++++
- tests/local.mk       |   2 +
- tests/unexpand/mb.sh |  97 ++++++++++++++++++++
- 10 files changed, 535 insertions(+), 34 deletions(-)
- create mode 100644 lib/mbfile.c
- create mode 100644 lib/mbfile.h
- create mode 100644 m4/mbfile.m4
- create mode 100755 tests/expand/mb.sh
- create mode 100755 tests/unexpand/mb.sh
-
-diff --git a/bootstrap.conf b/bootstrap.conf
-index 8a0ff31..a1c78b2 100644
---- a/bootstrap.conf
-+++ b/bootstrap.conf
-@@ -152,6 +152,7 @@ gnulib_modules="
-   maintainer-makefile
-   malloc-gnu
-   manywarnings
-+  mbfile
-   mbrlen
-   mbrtowc
-   mbsalign
-diff --git a/configure.ac b/configure.ac
-index 1e74b36..24c9725 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -427,6 +427,8 @@ fi
- # I'm leaving it here for now.  This whole thing needs to be modernized...
- gl_WINSIZE_IN_PTEM
-+gl_MBFILE
-+
- gl_HEADER_TIOCGWINSZ_IN_TERMIOS_H
- if test $gl_cv_sys_tiocgwinsz_needs_termios_h = no && \
-diff --git a/lib/mbfile.c b/lib/mbfile.c
-new file mode 100644
-index 0000000..b0a468e
---- /dev/null
-+++ b/lib/mbfile.c
-@@ -0,0 +1,3 @@
-+#include <config.h>
-+#define MBFILE_INLINE _GL_EXTERN_INLINE
-+#include "mbfile.h"
-diff --git a/lib/mbfile.h b/lib/mbfile.h
-new file mode 100644
-index 0000000..11f1b12
---- /dev/null
-+++ b/lib/mbfile.h
-@@ -0,0 +1,255 @@
-+/* Multibyte character I/O: macros for multi-byte encodings.
-+   Copyright (C) 2001, 2005, 2009-2015 Free Software Foundation, Inc.
-+
-+   This program is free software: you can redistribute it and/or modify
-+   it under the terms of the GNU General Public License as published by
-+   the Free Software Foundation; either version 3 of the License, or
-+   (at your option) any later version.
-+
-+   This program is distributed in the hope that it will be useful,
-+   but WITHOUT ANY WARRANTY; without even the implied warranty of
-+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+   GNU General Public License for more details.
-+
-+   You should have received a copy of the GNU General Public License
-+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
-+
-+/* Written by Mitsuru Chinen <mchinen@yamato.ibm.com>
-+   and Bruno Haible <bruno@clisp.org>.  */
-+
-+/* The macros in this file implement multi-byte character input from a
-+   stream.
-+
-+   mb_file_t
-+     is the type for multibyte character input stream, usable for variable
-+     declarations.
-+
-+   mbf_char_t
-+     is the type for multibyte character or EOF, usable for variable
-+     declarations.
-+
-+   mbf_init (mbf, stream)
-+     initializes the MB_FILE for reading from stream.
-+
-+   mbf_getc (mbc, mbf)
-+     reads the next multibyte character from mbf and stores it in mbc.
-+
-+   mb_iseof (mbc)
-+     returns true if mbc represents the EOF value.
-+
-+   Here are the function prototypes of the macros.
-+
-+   extern void          mbf_init (mb_file_t mbf, FILE *stream);
-+   extern void          mbf_getc (mbf_char_t mbc, mb_file_t mbf);
-+   extern bool          mb_iseof (const mbf_char_t mbc);
-+ */
-+
-+#ifndef _MBFILE_H
-+#define _MBFILE_H 1
-+
-+#include <assert.h>
-+#include <stdbool.h>
-+#include <stdio.h>
-+#include <string.h>
-+
-+/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
-+   <wchar.h>.
-+   BSD/OS 4.1 has a bug: <stdio.h> and <time.h> must be included before
-+   <wchar.h>.  */
-+#include <stdio.h>
-+#include <time.h>
-+#include <wchar.h>
-+
-+#include "mbchar.h"
-+
-+#ifndef _GL_INLINE_HEADER_BEGIN
-+ #error "Please include config.h first."
-+#endif
-+_GL_INLINE_HEADER_BEGIN
-+#ifndef MBFILE_INLINE
-+# define MBFILE_INLINE _GL_INLINE
-+#endif
-+
-+struct mbfile_multi {
-+  FILE *fp;
-+  bool eof_seen;
-+  bool have_pushback;
-+  mbstate_t state;
-+  unsigned int bufcount;
-+  char buf[MBCHAR_BUF_SIZE];
-+  struct mbchar pushback;
-+};
-+
-+MBFILE_INLINE void
-+mbfile_multi_getc (struct mbchar *mbc, struct mbfile_multi *mbf)
-+{
-+  size_t bytes;
-+
-+  /* If EOF has already been seen, don't use getc.  This matters if
-+     mbf->fp is connected to an interactive tty.  */
-+  if (mbf->eof_seen)
-+    goto eof;
-+
-+  /* Return character pushed back, if there is one.  */
-+  if (mbf->have_pushback)
-+    {
-+      mb_copy (mbc, &mbf->pushback);
-+      mbf->have_pushback = false;
-+      return;
-+    }
-+
-+  /* Before using mbrtowc, we need at least one byte.  */
-+  if (mbf->bufcount == 0)
-+    {
-+      int c = getc (mbf->fp);
-+      if (c == EOF)
-+        {
-+          mbf->eof_seen = true;
-+          goto eof;
-+        }
-+      mbf->buf[0] = (unsigned char) c;
-+      mbf->bufcount++;
-+    }
-+
-+  /* Handle most ASCII characters quickly, without calling mbrtowc().  */
-+  if (mbf->bufcount == 1 && mbsinit (&mbf->state) && is_basic (mbf->buf[0]))
-+    {
-+      /* These characters are part of the basic character set.  ISO C 99
-+         guarantees that their wide character code is identical to their
-+         char code.  */
-+      mbc->wc = mbc->buf[0] = mbf->buf[0];
-+      mbc->wc_valid = true;
-+      mbc->ptr = &mbc->buf[0];
-+      mbc->bytes = 1;
-+      mbf->bufcount = 0;
-+      return;
-+    }
-+
-+  /* Use mbrtowc on an increasing number of bytes.  Read only as many bytes
-+     from mbf->fp as needed.  This is needed to give reasonable interactive
-+     behaviour when mbf->fp is connected to an interactive tty.  */
-+  for (;;)
-+    {
-+      /* We don't know whether the 'mbrtowc' function updates the state when
-+         it returns -2, - this is the ISO C 99 and glibc-2.2 behaviour - or
-+         not - amended ANSI C, glibc-2.1 and Solaris 2.7 behaviour.  We
-+         don't have an autoconf test for this, yet.
-+         The new behaviour would allow us to feed the bytes one by one into
-+         mbrtowc.  But the old behaviour forces us to feed all bytes since
-+         the end of the last character into mbrtowc.  Since we want to retry
-+         with more bytes when mbrtowc returns -2, we must backup the state
-+         before calling mbrtowc, because implementations with the new
-+         behaviour will clobber it.  */
-+      mbstate_t backup_state = mbf->state;
-+
-+      bytes = mbrtowc (&mbc->wc, &mbf->buf[0], mbf->bufcount, &mbf->state);
-+
-+      if (bytes == (size_t) -1)
-+        {
-+          /* An invalid multibyte sequence was encountered.  */
-+          /* Return a single byte.  */
-+          bytes = 1;
-+          mbc->wc_valid = false;
-+          break;
-+        }
-+      else if (bytes == (size_t) -2)
-+        {
-+          /* An incomplete multibyte character.  */
-+          mbf->state = backup_state;
-+          if (mbf->bufcount == MBCHAR_BUF_SIZE)
-+            {
-+              /* An overlong incomplete multibyte sequence was encountered.  */
-+              /* Return a single byte.  */
-+              bytes = 1;
-+              mbc->wc_valid = false;
-+              break;
-+            }
-+          else
-+            {
-+              /* Read one more byte and retry mbrtowc.  */
-+              int c = getc (mbf->fp);
-+              if (c == EOF)
-+                {
-+                  /* An incomplete multibyte character at the end.  */
-+                  mbf->eof_seen = true;
-+                  bytes = mbf->bufcount;
-+                  mbc->wc_valid = false;
-+                  break;
-+                }
-+              mbf->buf[mbf->bufcount] = (unsigned char) c;
-+              mbf->bufcount++;
-+            }
-+        }
-+      else
-+        {
-+          if (bytes == 0)
-+            {
-+              /* A null wide character was encountered.  */
-+              bytes = 1;
-+              assert (mbf->buf[0] == '\0');
-+              assert (mbc->wc == 0);
-+            }
-+          mbc->wc_valid = true;
-+          break;
-+        }
-+    }
-+
-+  /* Return the multibyte sequence mbf->buf[0..bytes-1].  */
-+  mbc->ptr = &mbc->buf[0];
-+  memcpy (&mbc->buf[0], &mbf->buf[0], bytes);
-+  mbc->bytes = bytes;
-+
-+  mbf->bufcount -= bytes;
-+  if (mbf->bufcount > 0)
-+    {
-+      /* It's not worth calling memmove() for so few bytes.  */
-+      unsigned int count = mbf->bufcount;
-+      char *p = &mbf->buf[0];
-+
-+      do
-+        {
-+          *p = *(p + bytes);
-+          p++;
-+        }
-+      while (--count > 0);
-+    }
-+  return;
-+
-+eof:
-+  /* An mbchar_t with bytes == 0 is used to indicate EOF.  */
-+  mbc->ptr = NULL;
-+  mbc->bytes = 0;
-+  mbc->wc_valid = false;
-+  return;
-+}
-+
-+MBFILE_INLINE void
-+mbfile_multi_ungetc (const struct mbchar *mbc, struct mbfile_multi *mbf)
-+{
-+  mb_copy (&mbf->pushback, mbc);
-+  mbf->have_pushback = true;
-+}
-+
-+typedef struct mbfile_multi mb_file_t;
-+
-+typedef mbchar_t mbf_char_t;
-+
-+#define mbf_init(mbf, stream)                                           \
-+  ((mbf).fp = (stream),                                                 \
-+   (mbf).eof_seen = false,                                              \
-+   (mbf).have_pushback = false,                                         \
-+   memset (&(mbf).state, '\0', sizeof (mbstate_t)),                     \
-+   (mbf).bufcount = 0)
-+
-+#define mbf_getc(mbc, mbf) mbfile_multi_getc (&(mbc), &(mbf))
-+
-+#define mbf_ungetc(mbc, mbf) mbfile_multi_ungetc (&(mbc), &(mbf))
-+
-+#define mb_iseof(mbc) ((mbc).bytes == 0)
-+
-+#ifndef _GL_INLINE_HEADER_BEGIN
-+ #error "Please include config.h first."
-+#endif
-+_GL_INLINE_HEADER_BEGIN
-+
-+#endif /* _MBFILE_H */
-diff --git a/m4/mbfile.m4 b/m4/mbfile.m4
-new file mode 100644
-index 0000000..8589902
---- /dev/null
-+++ b/m4/mbfile.m4
-@@ -0,0 +1,14 @@
-+# mbfile.m4 serial 7
-+dnl Copyright (C) 2005, 2008-2015 Free Software Foundation, Inc.
-+dnl This file is free software; the Free Software Foundation
-+dnl gives unlimited permission to copy and/or distribute it,
-+dnl with or without modifications, as long as this notice is preserved.
-+
-+dnl autoconf tests required for use of mbfile.h
-+dnl From Bruno Haible.
-+
-+AC_DEFUN([gl_MBFILE],
-+[
-+  AC_REQUIRE([AC_TYPE_MBSTATE_T])
-+  :
-+])
-diff --git a/src/expand.c b/src/expand.c
-index 9fa2e10..380e020 100644
---- a/src/expand.c
-+++ b/src/expand.c
-@@ -37,6 +37,9 @@
- #include <stdio.h>
- #include <getopt.h>
- #include <sys/types.h>
-+
-+#include <mbfile.h>
-+
- #include "system.h"
- #include "die.h"
- #include "xstrndup.h"
-@@ -100,19 +103,19 @@ expand (void)
- {
-   /* Input stream.  */
-   FILE *fp = next_file (NULL);
-+  mb_file_t mbf;
-+  mbf_char_t c;
-   if (!fp)
-     return;
-+  mbf_init (mbf, fp);
-+
-   while (true)
-     {
--      /* Input character, or EOF.  */
--      int c;
--
-       /* If true, perform translations.  */
-       bool convert = true;
--
-       /* The following variables have valid values only when CONVERT
-          is true:  */
-@@ -122,17 +125,23 @@ expand (void)
-       /* Index in TAB_LIST of next tab stop to examine.  */
-       size_t tab_index = 0;
--
-       /* Convert a line of text.  */
-       do
-         {
--          while ((c = getc (fp)) < 0 && (fp = next_file (fp)))
--            continue;
-+          do {
-+            mbf_getc (c, mbf);
-+            if (mb_iseof (c))
-+              {
-+                mbf_init (mbf, fp = next_file (fp));
-+                continue;
-+              }
-+            }
-+          while (false);
-           if (convert)
-             {
--              if (c == '\t')
-+              if (mb_iseq (c, '\t'))
-                 {
-                   /* Column the next input tab stop is on.  */
-                   uintmax_t next_tab_column;
-@@ -151,32 +160,34 @@ expand (void)
-                     if (putchar (' ') < 0)
-                       die (EXIT_FAILURE, errno, _("write error"));
--                  c = ' ';
-+                  mb_setascii (&c, ' ');
-                 }
--              else if (c == '\b')
-+              else if (mb_iseq (c, '\b'))
-                 {
-                   /* Go back one column, and force recalculation of the
-                      next tab stop.  */
-                   column -= !!column;
-                   tab_index -= !!tab_index;
-                 }
--              else
-+              /* A leading control character could make us trip over.  */
-+              else if (!mb_iscntrl (c))
-                 {
--                  column++;
-+                  column += mb_width (c);
-                   if (!column)
-                     die (EXIT_FAILURE, 0, _("input line is too long"));
-                 }
--              convert &= convert_entire_line || !! isblank (c);
-+              convert &= convert_entire_line || mb_isblank (c);
-             }
--          if (c < 0)
-+          if (mb_iseof (c))
-             return;
--          if (putchar (c) < 0)
-+          mb_putc (c, stdout);
-+          if (ferror (stdout))
-             die (EXIT_FAILURE, errno, _("write error"));
-         }
--      while (c != '\n');
-+      while (!mb_iseq (c, '\n'));
-     }
- }
-diff --git a/src/unexpand.c b/src/unexpand.c
-index 7801274..569a7ee 100644
---- a/src/unexpand.c
-+++ b/src/unexpand.c
-@@ -38,6 +38,9 @@
- #include <stdio.h>
- #include <getopt.h>
- #include <sys/types.h>
-+
-+#include <mbfile.h>
-+
- #include "system.h"
- #include "die.h"
- #include "xstrndup.h"
-@@ -107,11 +110,12 @@ unexpand (void)
- {
-   /* Input stream.  */
-   FILE *fp = next_file (NULL);
-+  mb_file_t mbf;
-   /* The array of pending blanks.  In non-POSIX locales, blanks can
-      include characters other than spaces, so the blanks must be
-      stored, not merely counted.  */
--  char *pending_blank;
-+  mbf_char_t *pending_blank;
-   if (!fp)
-     return;
-@@ -119,12 +123,14 @@ unexpand (void)
-   /* The worst case is a non-blank character, then one blank, then a
-      tab stop, then MAX_COLUMN_WIDTH - 1 blanks, then a non-blank; so
-      allocate MAX_COLUMN_WIDTH bytes to store the blanks.  */
--  pending_blank = xmalloc (max_column_width);
-+  pending_blank = xmalloc (max_column_width * sizeof (mbf_char_t));
-+
-+  mbf_init (mbf, fp);
-   while (true)
-     {
-       /* Input character, or EOF.  */
--      int c;
-+      mbf_char_t c;
-       /* If true, perform translations.  */
-       bool convert = true;
-@@ -158,12 +164,19 @@ unexpand (void)
-       do
-         {
--          while ((c = getc (fp)) < 0 && (fp = next_file (fp)))
--            continue;
-+          do {
-+            mbf_getc (c, mbf);
-+            if (mb_iseof (c))
-+              {
-+                mbf_init (mbf, fp = next_file (fp));
-+                continue;
-+              }
-+            }
-+          while (false);
-           if (convert)
-             {
--              bool blank = !! isblank (c);
-+              bool blank = mb_isblank (c);
-               if (blank)
-                 {
-@@ -180,16 +193,16 @@ unexpand (void)
-                       if (next_tab_column < column)
-                         die (EXIT_FAILURE, 0, _("input line is too long"));
--                      if (c == '\t')
-+                      if (mb_iseq (c, '\t'))
-                         {
-                           column = next_tab_column;
-                           if (pending)
--                            pending_blank[0] = '\t';
-+                            mb_setascii (&pending_blank[0], '\t');
-                         }
-                       else
-                         {
--                          column++;
-+                          column += mb_width (c);
-                           if (! (prev_blank && column == next_tab_column))
-                             {
-@@ -197,13 +210,14 @@ unexpand (void)
-                                  will be replaced by tabs.  */
-                               if (column == next_tab_column)
-                                 one_blank_before_tab_stop = true;
--                              pending_blank[pending++] = c;
-+                              mb_copy (&pending_blank[pending++], &c);
-                               prev_blank = true;
-                               continue;
-                             }
-                           /* Replace the pending blanks by a tab or two.  */
--                          pending_blank[0] = c = '\t';
-+                          mb_setascii (&c, '\t');
-+                          mb_setascii (&pending_blank[0], '\t');
-                         }
-                       /* Discard pending blanks, unless it was a single
-@@ -211,7 +225,7 @@ unexpand (void)
-                       pending = one_blank_before_tab_stop;
-                     }
-                 }
--              else if (c == '\b')
-+              else if (mb_iseq (c, '\b'))
-                 {
-                   /* Go back one column, and force recalculation of the
-                      next tab stop.  */
-@@ -221,7 +235,7 @@ unexpand (void)
-                 }
-               else
-                 {
--                  column++;
-+                  column += mb_width (c);
-                   if (!column)
-                     die (EXIT_FAILURE, 0, _("input line is too long"));
-                 }
-@@ -229,8 +243,11 @@ unexpand (void)
-               if (pending)
-                 {
-                   if (pending > 1 && one_blank_before_tab_stop)
--                    pending_blank[0] = '\t';
--                  if (fwrite (pending_blank, 1, pending, stdout) != pending)
-+                    mb_setascii (&pending_blank[0], '\t');
-+
-+                  for (int n = 0; n < pending; ++n)
-+                    mb_putc (pending_blank[n], stdout);
-+                  if (ferror (stdout))
-                     die (EXIT_FAILURE, errno, _("write error"));
-                   pending = 0;
-                   one_blank_before_tab_stop = false;
-@@ -240,16 +257,17 @@ unexpand (void)
-               convert &= convert_entire_line || blank;
-             }
--          if (c < 0)
-+          if (mb_iseof (c))
-             {
-               free (pending_blank);
-               return;
-             }
--          if (putchar (c) < 0)
-+          mb_putc (c, stdout);
-+          if (ferror (stdout))
-             die (EXIT_FAILURE, errno, _("write error"));
-         }
--      while (c != '\n');
-+      while (!mb_iseq (c, '\n'));
-     }
- }
-diff --git a/tests/expand/mb.sh b/tests/expand/mb.sh
-new file mode 100755
-index 0000000..7971e18
---- /dev/null
-+++ b/tests/expand/mb.sh
-@@ -0,0 +1,98 @@
-+#!/bin/sh
-+
-+# Copyright (C) 2012-2015 Free Software Foundation, Inc.
-+
-+# This program is free software: you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation, either version 3 of the License, or
-+# (at your option) any later version.
-+
-+# This program is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+# GNU General Public License for more details.
-+
-+# You should have received a copy of the GNU General Public License
-+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+
-+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
-+print_ver_ expand
-+
-+export LC_ALL=en_US.UTF-8
-+
-+#input containing multibyte characters
-+cat <<\EOF > in || framework_failure_
-+1234567812345678123456781
-+.       .       .       .
-+a     b       c       d
-+.       .       .       .
-+ä    ö      ü      ß
-+.       .       .       .
-+EOF
-+env printf '   äöü\t.    öüä.   \tä xx\n' >> in || framework_failure_
-+
-+cat <<\EOF > exp || framework_failure_
-+1234567812345678123456781
-+.       .       .       .
-+a       b       c       d
-+.       .       .       .
-+ä       ö       ü       ß
-+.       .       .       .
-+   äöü  .    öüä.       ä xx
-+EOF
-+
-+expand < in > out || fail=1
-+compare exp out > /dev/null 2>&1 || fail=1
-+
-+#test characters with display widths != 1
-+env printf '12345678
-+e\t|ascii(1)
-+\u00E9\t|composed(1)
-+e\u0301\t|decomposed(1)
-+\u3000\t|ideo-space(2)
-+\uFF0D\t|full-hypen(2)
-+' > in || framework_failure_
-+
-+env printf '12345678
-+e       |ascii(1)
-+\u00E9       |composed(1)
-+e\u0301       |decomposed(1)
-+\u3000      |ideo-space(2)
-+\uFF0D      |full-hypen(2)
-+' > exp || framework_failure_
-+
-+expand < in > out || fail=1
-+compare exp out > /dev/null 2>&1 || fail=1
-+
-+#shouldn't fail with "input line too long"
-+#when a line starts with a control character
-+env printf '\n' > in || framework_failure_
-+
-+expand < in > out || fail=1
-+compare in out > /dev/null 2>&1 || fail=1
-+
-+#non-Unicode characters interspersed between Unicode ones
-+env printf '12345678
-+\t\xFF|
-+\xFF\t|
-+\t\xFFä|
-+ä\xFF\t|
-+\tä\xFF|
-+\xFF\tä|
-+äbcdef\xFF\t|
-+' > in || framework_failure_
-+
-+env printf '12345678
-+        \xFF|
-+\xFF       |
-+        \xFFä|
-+ä\xFF      |
-+        ä\xFF|
-+\xFF       ä|
-+äbcdef\xFF |
-+' > exp || framework_failure_
-+
-+expand < in > out || fail=1
-+compare exp out > /dev/null 2>&1 || fail=1
-+
-+exit $fail
-diff --git a/tests/local.mk b/tests/local.mk
-index 192f776..8053397 100644
---- a/tests/local.mk
-+++ b/tests/local.mk
-@@ -544,6 +544,7 @@ all_tests =                                        \
-   tests/du/threshold.sh                               \
-   tests/du/trailing-slash.sh                  \
-   tests/du/two-args.sh                                \
-+  tests/expand/mb.sh                          \
-   tests/id/gnu-zero-uids.sh                   \
-   tests/id/no-context.sh                      \
-   tests/id/context.sh                         \
-@@ -684,6 +685,7 @@ all_tests =                                        \
-   tests/touch/read-only.sh                    \
-   tests/touch/relative.sh                     \
-   tests/touch/trailing-slash.sh                       \
-+  tests/unexpand/mb.sh                                \
-   $(all_root_tests)
- # See tests/factor/create-test.sh.
-diff --git a/tests/unexpand/mb.sh b/tests/unexpand/mb.sh
-new file mode 100755
-index 0000000..60d4c1a
---- /dev/null
-+++ b/tests/unexpand/mb.sh
-@@ -0,0 +1,97 @@
-+#!/bin/sh
-+
-+# Copyright (C) 2012-2015 Free Software Foundation, Inc.
-+
-+# This program is free software: you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation, either version 3 of the License, or
-+# (at your option) any later version.
-+
-+# This program is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+# GNU General Public License for more details.
-+
-+# You should have received a copy of the GNU General Public License
-+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+
-+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
-+print_ver_ unexpand
-+
-+export LC_ALL=en_US.UTF-8
-+
-+#input containing multibyte characters
-+cat > in <<\EOF
-+1234567812345678123456781
-+.       .       .       .
-+a       b       c       d
-+.       .       .       .
-+ä       ö       ü       ß
-+.       .       .       .
-+   äöü  .    öüä.       ä xx
-+EOF
-+
-+cat > exp <<\EOF
-+1234567812345678123456781
-+.     .       .       .
-+a     b       c       d
-+.     .       .       .
-+ä    ö      ü      ß
-+.     .       .       .
-+   äöü     .    öüä.    ä xx
-+EOF
-+
-+unexpand -a < in > out || fail=1
-+compare exp out > /dev/null 2>&1 || fail=1
-+
-+#test characters with a display width larger than 1
-+
-+env printf '12345678
-+e       |ascii(1)
-+\u00E9       |composed(1)
-+e\u0301       |decomposed(1)
-+\u3000      |ideo-space(2)
-+\uFF0D      |full-hypen(2)
-+' > in || framework_failure_
-+
-+env printf '12345678
-+e\t|ascii(1)
-+\u00E9\t|composed(1)
-+e\u0301\t|decomposed(1)
-+\u3000\t|ideo-space(2)
-+\uFF0D\t|full-hypen(2)
-+' > exp || framework_failure_
-+
-+unexpand -a < in > out || fail=1
-+compare exp out > /dev/null 2>&1 || fail=1
-+
-+#test input where a blank of width > 1 is not being substituted
-+in="$(LC_ALL=en_US.UTF-8 printf ' \u3000  ö       ü       ß')"
-+exp='    ö      ü      ß'
-+
-+unexpand -a < in > out || fail=1
-+compare exp out > /dev/null 2>&1 || fail=1
-+
-+#non-Unicode characters interspersed between Unicode ones
-+env printf '12345678
-+        \xFF|
-+\xFF       |
-+        \xFFä|
-+ä\xFF      |
-+        ä\xFF|
-+\xFF       ä|
-+äbcdef\xFF |
-+' > in || framework_failure_
-+
-+env printf '12345678
-+\t\xFF|
-+\xFF\t|
-+\t\xFFä|
-+ä\xFF\t|
-+\tä\xFF|
-+\xFF\tä|
-+äbcdef\xFF\t|
-+' > exp || framework_failure_
-+
-+unexpand -a < in > out || fail=1
-+compare exp out > /dev/null 2>&1 || fail=1
--- 
-2.7.4
-