Ondrej Oprala 32b1e5
From 332e9adf944e4ea232a855b1bf75ea4ddfd7e794 Mon Sep 17 00:00:00 2001
Ondrej Oprala 32b1e5
From: Ondrej Oprala <ooprala@redhat.com>
Ondrej Oprala 32b1e5
Date: Wed, 5 Aug 2015 09:15:09 +0200
Ondrej Oprala 32b1e5
Subject: [PATCH] expand,unexpand: add multibyte support
Ondrej Oprala 32b1e5
MIME-Version: 1.0
Ondrej Oprala 32b1e5
Content-Type: text/plain; charset=UTF-8
Ondrej Oprala 32b1e5
Content-Transfer-Encoding: 8bit
Ondrej Oprala 32b1e5
Ondrej Oprala 32b1e5
* NEWS: Mention the changes.
Ondrej Oprala 32b1e5
* bootstrap.conf: Add mbfile to the list of modules.
Ondrej Oprala 32b1e5
* configure.ac: Properly initialize mbfile.
Ondrej Oprala 32b1e5
* po/POTFILES.in: Add new source file.
Ondrej Oprala 32b1e5
* src/expand-core.c: Move functions common to both expand and
Ondrej Oprala 32b1e5
unexpand to this file.
Ondrej Oprala 32b1e5
* src/expand-core.h: Add function prototypes from expand-core.c.
Ondrej Oprala 32b1e5
* src/expand.c (expand): Iterate over multibyte characters properly.
Ondrej Oprala 32b1e5
* src/local.mk: Add expand-core.c to the lists of source codes for
Ondrej Oprala 32b1e5
expand and unexpand
Ondrej Oprala 32b1e5
* src/unexpand.c (unexpand): Iterate over multibyte characters
Ondrej Oprala 32b1e5
properly.
Ondrej Oprala 32b1e5
* tests/local.mk: Add new tests.
Ondrej Oprala 32b1e5
* tests/{expand,unexpand}/mb.sh: New tests.
Ondrej Oprala 32b1e5
Ondrej Oprala 32b1e5
Co-authored-by: Pádraig Brady <pbrady@redhat.com>
Ondrej Oprala 32b1e5
---
Ondrej Oprala 32b1e5
 NEWS                 |   3 +
Ondrej Oprala 32b1e5
 bootstrap.conf       |   1 +
Ondrej Oprala 32b1e5
 configure.ac         |   2 +
Ondrej Oprala 32b1e5
 po/POTFILES.in       |   1 +
Ondrej Oprala 32b1e5
 src/expand-core.c    | 150 +++++++++++++++++++++++++++++++++++++++
Ondrej Oprala 32b1e5
 src/expand-core.h    |  44 ++++++++++++
Ondrej Oprala 32b1e5
 src/expand.c         | 183 ++++++++++-------------------------------------
Ondrej Oprala 32b1e5
 src/local.mk         |   2 +
Ondrej Oprala 32b1e5
 src/unexpand.c       | 197 ++++++++++++---------------------------------------
Ondrej Oprala 32b1e5
 tests/expand/mb.sh   |  98 +++++++++++++++++++++++++
Ondrej Oprala 32b1e5
 tests/local.mk       |   2 +
Ondrej Oprala 32b1e5
 tests/unexpand/mb.sh |  97 +++++++++++++++++++++++++
Ondrej Oprala 32b1e5
 12 files changed, 482 insertions(+), 298 deletions(-)
Ondrej Oprala 32b1e5
 create mode 100644 src/expand-core.c
Ondrej Oprala 32b1e5
 create mode 100644 src/expand-core.h
Ondrej Oprala 32b1e5
 create mode 100755 tests/expand/mb.sh
Ondrej Oprala 32b1e5
 create mode 100755 tests/unexpand/mb.sh
Ondrej Oprala 32b1e5
Ondrej Oprala 32b1e5
diff --git a/bootstrap.conf b/bootstrap.conf
Ondrej Oprala 32b1e5
index ef1c078..ea8cebc 100644
Ondrej Oprala 32b1e5
--- a/bootstrap.conf
Ondrej Oprala 32b1e5
+++ b/bootstrap.conf
Ondrej Oprala 32b1e5
@@ -152,6 +152,7 @@ gnulib_modules="
Ondrej Oprala 32b1e5
   maintainer-makefile
Ondrej Oprala 32b1e5
   malloc-gnu
Ondrej Oprala 32b1e5
   manywarnings
Ondrej Oprala 32b1e5
+  mbfile
Ondrej Oprala 32b1e5
   mbrlen
Ondrej Oprala 32b1e5
   mbrtowc
Ondrej Oprala 32b1e5
   mbsalign
Ondrej Oprala 32b1e5
diff --git a/configure.ac b/configure.ac
Ondrej Oprala 32b1e5
index 8dc2192..b8b5114 100644
Ondrej Oprala 32b1e5
--- a/configure.ac
Ondrej Oprala 32b1e5
+++ b/configure.ac
Ondrej Oprala 32b1e5
@@ -422,6 +422,8 @@ gl_WINSIZE_IN_PTEM
Ondrej Oprala 32b1e5
 # I'm leaving it here for now.  This whole thing needs to be modernized...
Ondrej Oprala 32b1e5
 gl_WINSIZE_IN_PTEM
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
+gl_MBFILE
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
 gl_HEADER_TIOCGWINSZ_IN_TERMIOS_H
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
 if test $gl_cv_sys_tiocgwinsz_needs_termios_h = no && \
Ondrej Oprala 32b1e5
diff --git a/po/POTFILES.in b/po/POTFILES.in
Ondrej Oprala 32b1e5
index b3fe668..c594d20 100644
Ondrej Oprala 32b1e5
--- a/po/POTFILES.in
Ondrej Oprala 32b1e5
+++ b/po/POTFILES.in
Ondrej Oprala 32b1e5
@@ -57,6 +57,7 @@ src/dirname.c
Ondrej Oprala 32b1e5
 src/du.c
Ondrej Oprala 32b1e5
 src/echo.c
Ondrej Oprala 32b1e5
 src/env.c
Ondrej Oprala 32b1e5
+src/expand-core.c
Ondrej Oprala 32b1e5
 src/expand.c
Ondrej Oprala 32b1e5
 src/expr.c
Ondrej Oprala 32b1e5
 src/factor.c
Ondrej Oprala 32b1e5
diff --git a/src/expand-core.c b/src/expand-core.c
Ondrej Oprala 32b1e5
new file mode 100644
Ondrej Oprala 32b1e5
index 0000000..c8445db
Ondrej Oprala 32b1e5
--- /dev/null
Ondrej Oprala 32b1e5
+++ b/src/expand-core.c
Ondrej Oprala 32b1e5
@@ -0,0 +1,150 @@
Ondrej Oprala 32b1e5
+/* expand-core.c - elementary functions for the expand and unexpand utilities
Ondrej Oprala 32b1e5
+   Copyright (C) 1989-2015 Free Software Foundation, Inc.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+   This program is free software: you can redistribute it and/or modify
Ondrej Oprala 32b1e5
+   it under the terms of the GNU General Public License as published by
Ondrej Oprala 32b1e5
+   the Free Software Foundation, either version 3 of the License, or
Ondrej Oprala 32b1e5
+   (at your option) any later version.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+   This program is distributed in the hope that it will be useful,
Ondrej Oprala 32b1e5
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
Ondrej Oprala 32b1e5
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Ondrej Oprala 32b1e5
+   GNU General Public License for more details.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+   You should have received a copy of the GNU General Public License
Ondrej Oprala 32b1e5
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#include <config.h>
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#include <stdio.h>
Ondrej Oprala 32b1e5
+#include <sys/types.h>
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#include "system.h"
Ondrej Oprala 32b1e5
+#include "error.h"
Ondrej Oprala 32b1e5
+#include "fadvise.h"
Ondrej Oprala 32b1e5
+#include "quote.h"
Ondrej Oprala 32b1e5
+#include "xstrndup.h"
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#include "expand-core.h"
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+/* Add the comma or blank separated list of tab stops STOPS
Ondrej Oprala 32b1e5
+   to the list of tab stops.  */
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+extern void
Ondrej Oprala 32b1e5
+parse_tab_stops (char const *stops, void (*add_tab_stop)(uintmax_t))
Ondrej Oprala 32b1e5
+{
Ondrej Oprala 32b1e5
+  bool have_tabval = false;
Ondrej Oprala 32b1e5
+  uintmax_t tabval IF_LINT ( = 0);
Ondrej Oprala 32b1e5
+  char const *num_start IF_LINT ( = NULL);
Ondrej Oprala 32b1e5
+  bool ok = true;
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+  for (; *stops; stops++)
Ondrej Oprala 32b1e5
+    {
Ondrej Oprala 32b1e5
+      if (*stops == ',' || isblank (to_uchar (*stops)))
Ondrej Oprala 32b1e5
+        {
Ondrej Oprala 32b1e5
+          if (have_tabval)
Ondrej Oprala 32b1e5
+            add_tab_stop (tabval);
Ondrej Oprala 32b1e5
+          have_tabval = false;
Ondrej Oprala 32b1e5
+        }
Ondrej Oprala 32b1e5
+      else if (ISDIGIT (*stops))
Ondrej Oprala 32b1e5
+        {
Ondrej Oprala 32b1e5
+          if (!have_tabval)
Ondrej Oprala 32b1e5
+            {
Ondrej Oprala 32b1e5
+              tabval = 0;
Ondrej Oprala 32b1e5
+              have_tabval = true;
Ondrej Oprala 32b1e5
+              num_start = stops;
Ondrej Oprala 32b1e5
+            }
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+          /* Detect overflow.  */
Ondrej Oprala 32b1e5
+          if (!DECIMAL_DIGIT_ACCUMULATE (tabval, *stops - '0', uintmax_t))
Ondrej Oprala 32b1e5
+            {
Ondrej Oprala 32b1e5
+              size_t len = strspn (num_start, "0123456789");
Ondrej Oprala 32b1e5
+              char *bad_num = xstrndup (num_start, len);
Ondrej Oprala 32b1e5
+              error (0, 0, _("tab stop is too large %s"), quote (bad_num));
Ondrej Oprala 32b1e5
+              free (bad_num);
Ondrej Oprala 32b1e5
+              ok = false;
Ondrej Oprala 32b1e5
+              stops = num_start + len - 1;
Ondrej Oprala 32b1e5
+            }
Ondrej Oprala 32b1e5
+        }
Ondrej Oprala 32b1e5
+      else
Ondrej Oprala 32b1e5
+        {
Ondrej Oprala 32b1e5
+          error (0, 0, _("tab size contains invalid character(s): %s"),
Ondrej Oprala 32b1e5
+                 quote (stops));
Ondrej Oprala 32b1e5
+          ok = false;
Ondrej Oprala 32b1e5
+          break;
Ondrej Oprala 32b1e5
+        }
Ondrej Oprala 32b1e5
+    }
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+  if (!ok)
Ondrej Oprala 32b1e5
+    exit (EXIT_FAILURE);
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+  if (have_tabval)
Ondrej Oprala 32b1e5
+    add_tab_stop (tabval);
Ondrej Oprala 32b1e5
+}
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+/* Check that the list of tab stops TABS, with ENTRIES entries,
Ondrej Oprala 32b1e5
+   contains only nonzero, ascending values.  */
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+extern void
Ondrej Oprala 32b1e5
+validate_tab_stops (uintmax_t const *tabs, size_t entries)
Ondrej Oprala 32b1e5
+{
Ondrej Oprala 32b1e5
+  uintmax_t prev_tab = 0;
Ondrej Oprala 32b1e5
+  size_t i;
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+  for (i = 0; i < entries; i++)
Ondrej Oprala 32b1e5
+    {
Ondrej Oprala 32b1e5
+      if (tabs[i] == 0)
Ondrej Oprala 32b1e5
+        error (EXIT_FAILURE, 0, _("tab size cannot be 0"));
Ondrej Oprala 32b1e5
+      if (tabs[i] <= prev_tab)
Ondrej Oprala 32b1e5
+        error (EXIT_FAILURE, 0, _("tab sizes must be ascending"));
Ondrej Oprala 32b1e5
+      prev_tab = tabs[i];
Ondrej Oprala 32b1e5
+    }
Ondrej Oprala 32b1e5
+}
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+/* Close the old stream pointer FP if it is non-NULL,
Ondrej Oprala 32b1e5
+   and return a new one opened to read the next input file.
Ondrej Oprala 32b1e5
+   Open a filename of '-' as the standard input.
Ondrej Oprala 32b1e5
+   Return NULL if there are no more input files.  */
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+extern FILE *
Ondrej Oprala 32b1e5
+next_file (FILE *fp)
Ondrej Oprala 32b1e5
+{
Ondrej Oprala 32b1e5
+  static char *prev_file;
Ondrej Oprala 32b1e5
+  char *file;
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+  if (fp)
Ondrej Oprala 32b1e5
+    {
Ondrej Oprala 32b1e5
+      if (ferror (fp))
Ondrej Oprala 32b1e5
+        {
Ondrej Oprala 32b1e5
+          error (0, errno, "%s", prev_file);
Ondrej Oprala 32b1e5
+          exit_status = EXIT_FAILURE;
Ondrej Oprala 32b1e5
+        }
Ondrej Oprala 32b1e5
+      if (STREQ (prev_file, "-"))
Ondrej Oprala 32b1e5
+        clearerr (fp);		/* Also clear EOF.  */
Ondrej Oprala 32b1e5
+      else if (fclose (fp) != 0)
Ondrej Oprala 32b1e5
+        {
Ondrej Oprala 32b1e5
+          error (0, errno, "%s", prev_file);
Ondrej Oprala 32b1e5
+          exit_status = EXIT_FAILURE;
Ondrej Oprala 32b1e5
+        }
Ondrej Oprala 32b1e5
+    }
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+  while ((file = *file_list++) != NULL)
Ondrej Oprala 32b1e5
+    {
Ondrej Oprala 32b1e5
+      if (STREQ (file, "-"))
Ondrej Oprala 32b1e5
+        {
Ondrej Oprala 32b1e5
+          have_read_stdin = true;
Ondrej Oprala 32b1e5
+          fp = stdin;
Ondrej Oprala 32b1e5
+        }
Ondrej Oprala 32b1e5
+      else
Ondrej Oprala 32b1e5
+        fp = fopen (file, "r");
Ondrej Oprala 32b1e5
+      if (fp)
Ondrej Oprala 32b1e5
+        {
Ondrej Oprala 32b1e5
+          prev_file = file;
Ondrej Oprala 32b1e5
+          fadvise (fp, FADVISE_SEQUENTIAL);
Ondrej Oprala 32b1e5
+          return fp;
Ondrej Oprala 32b1e5
+        }
Ondrej Oprala 32b1e5
+      error (0, errno, "%s", file);
Ondrej Oprala 32b1e5
+      exit_status = EXIT_FAILURE;
Ondrej Oprala 32b1e5
+    }
Ondrej Oprala 32b1e5
+  return NULL;
Ondrej Oprala 32b1e5
+}
Ondrej Oprala 32b1e5
diff --git a/src/expand-core.h b/src/expand-core.h
Ondrej Oprala 32b1e5
new file mode 100644
Ondrej Oprala 32b1e5
index 0000000..2419407
Ondrej Oprala 32b1e5
--- /dev/null
Ondrej Oprala 32b1e5
+++ b/src/expand-core.h
Ondrej Oprala 32b1e5
@@ -0,0 +1,41 @@
Ondrej Oprala 32b1e5
+/* expand-core.h - function prototypes for the expand and unexpand utilities
Ondrej Oprala 32b1e5
+   Copyright (C) 1989-2015 Free Software Foundation, Inc.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+   This program is free software: you can redistribute it and/or modify
Ondrej Oprala 32b1e5
+   it under the terms of the GNU General Public License as published by
Ondrej Oprala 32b1e5
+   the Free Software Foundation, either version 3 of the License, or
Ondrej Oprala 32b1e5
+   (at your option) any later version.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+   This program is distributed in the hope that it will be useful,
Ondrej Oprala 32b1e5
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
Ondrej Oprala 32b1e5
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Ondrej Oprala 32b1e5
+   GNU General Public License for more details.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+   You should have received a copy of the GNU General Public License
Ondrej Oprala 32b1e5
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#ifndef EXPAND_CORE_H_
Ondrej Oprala 32b1e5
+# define EXPAND_CORE_H_
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+extern size_t first_free_tab;
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+extern size_t n_tabs_allocated;
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+extern uintmax_t *tab_list;
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+extern int exit_status;
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+extern char **file_list;
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+extern bool have_read_stdin;
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+void
Ondrej Oprala 32b1e5
+parse_tab_stops (char const *stops, void (*add_tab_stop)(uintmax_t));
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+void
Ondrej Oprala 32b1e5
+validate_tab_stops (uintmax_t const *tabs, size_t entries);
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+FILE *
Ondrej Oprala 32b1e5
+next_file (FILE *fp);
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#endif /* EXPAND_CORE_H_ */
Ondrej Oprala 32b1e5
diff --git a/src/expand.c b/src/expand.c
Ondrej Oprala 32b1e5
index 0a40a1a..ed97fd4 100644
Ondrej Oprala 32b1e5
--- a/src/expand.c
Ondrej Oprala 32b1e5
+++ b/src/expand.c
Ondrej Oprala 32b1e5
@@ -37,12 +37,16 @@
Ondrej Oprala 32b1e5
 #include <stdio.h>
Ondrej Oprala 32b1e5
 #include <getopt.h>
Ondrej Oprala 32b1e5
 #include <sys/types.h>
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#include <mbfile.h>
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
 #include "system.h"
Ondrej Oprala 32b1e5
 #include "error.h"
Ondrej Oprala 32b1e5
 #include "fadvise.h"
Ondrej Oprala 32b1e5
-#include "quote.h"
Ondrej Oprala 32b1e5
 #include "xstrndup.h"
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
+#include "expand-core.h"
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
 /* The official name of this program (e.g., no 'g' prefix).  */
Ondrej Oprala 32b1e5
 #define PROGRAM_NAME "expand"
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
@@ -58,17 +62,17 @@ static uintmax_t tab_size;
Ondrej Oprala 32b1e5
 /* Array of the explicit column numbers of the tab stops;
Ondrej Oprala 32b1e5
    after 'tab_list' is exhausted, each additional tab is replaced
Ondrej Oprala 32b1e5
    by a space.  The first column is column 0.  */
Ondrej Oprala 32b1e5
-static uintmax_t *tab_list;
Ondrej Oprala 32b1e5
+uintmax_t *tab_list;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
 /* The number of allocated entries in 'tab_list'.  */
Ondrej Oprala 32b1e5
-static size_t n_tabs_allocated;
Ondrej Oprala 32b1e5
+size_t n_tabs_allocated;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
 /* The index of the first invalid element of 'tab_list',
Ondrej Oprala 32b1e5
    where the next element can be added.  */
Ondrej Oprala 32b1e5
-static size_t first_free_tab;
Ondrej Oprala 32b1e5
+size_t first_free_tab;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
 /* Null-terminated array of input filenames.  */
Ondrej Oprala 32b1e5
-static char **file_list;
Ondrej Oprala 32b1e5
+char **file_list;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
 /* Default for 'file_list' if no files are given on the command line.  */
Ondrej Oprala 32b1e5
 static char *stdin_argv[] =
Ondrej Oprala 32b1e5
@@ -77,10 +81,10 @@ static char *stdin_argv[] =
Ondrej Oprala 32b1e5
 };
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
 /* True if we have ever read standard input.  */
Ondrej Oprala 32b1e5
-static bool have_read_stdin;
Ondrej Oprala 32b1e5
+bool have_read_stdin;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
 /* The desired exit status.  */
Ondrej Oprala 32b1e5
-static int exit_status;
Ondrej Oprala 32b1e5
+int exit_status;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
 static char const shortopts[] = "it:0::1::2::3::4::5::6::7::8::9::";
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
@@ -125,128 +129,6 @@
Ondrej Oprala 32b1e5
   if (first_free_tab == n_tabs_allocated)
Ondrej Oprala 32b1e5
     tab_list = X2NREALLOC (tab_list, &n_tabs_allocated);
Ondrej Oprala 32b1e5
   tab_list[first_free_tab++] = tabval;
Ondrej Oprala 32b1e5
-}
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-/* Add the comma or blank separated list of tab stops STOPS
Ondrej Oprala 32b1e5
-   to the list of tab stops.  */
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-static void
Ondrej Oprala 32b1e5
-parse_tab_stops (char const *stops)
Ondrej Oprala 32b1e5
-{
Ondrej Oprala 32b1e5
-  bool have_tabval = false;
Ondrej Oprala 32b1e5
-  uintmax_t tabval IF_LINT ( = 0);
Ondrej Oprala 32b1e5
-  char const *num_start IF_LINT ( = NULL);
Ondrej Oprala 32b1e5
-  bool ok = true;
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-  for (; *stops; stops++)
Ondrej Oprala 32b1e5
-    {
Ondrej Oprala 32b1e5
-      if (*stops == ',' || isblank (to_uchar (*stops)))
Ondrej Oprala 32b1e5
-        {
Ondrej Oprala 32b1e5
-          if (have_tabval)
Ondrej Oprala 32b1e5
-            add_tab_stop (tabval);
Ondrej Oprala 32b1e5
-          have_tabval = false;
Ondrej Oprala 32b1e5
-        }
Ondrej Oprala 32b1e5
-      else if (ISDIGIT (*stops))
Ondrej Oprala 32b1e5
-        {
Ondrej Oprala 32b1e5
-          if (!have_tabval)
Ondrej Oprala 32b1e5
-            {
Ondrej Oprala 32b1e5
-              tabval = 0;
Ondrej Oprala 32b1e5
-              have_tabval = true;
Ondrej Oprala 32b1e5
-              num_start = stops;
Ondrej Oprala 32b1e5
-            }
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-          /* Detect overflow.  */
Ondrej Oprala 32b1e5
-          if (!DECIMAL_DIGIT_ACCUMULATE (tabval, *stops - '0', uintmax_t))
Ondrej Oprala 32b1e5
-            {
Ondrej Oprala 32b1e5
-              size_t len = strspn (num_start, "0123456789");
Ondrej Oprala 32b1e5
-              char *bad_num = xstrndup (num_start, len);
Ondrej Oprala 32b1e5
-              error (0, 0, _("tab stop is too large %s"), quote (bad_num));
Ondrej Oprala 32b1e5
-              free (bad_num);
Ondrej Oprala 32b1e5
-              ok = false;
Ondrej Oprala 32b1e5
-              stops = num_start + len - 1;
Ondrej Oprala 32b1e5
-            }
Ondrej Oprala 32b1e5
-        }
Ondrej Oprala 32b1e5
-      else
Ondrej Oprala 32b1e5
-        {
Ondrej Oprala 32b1e5
-          error (0, 0, _("tab size contains invalid character(s): %s"),
Ondrej Oprala 32b1e5
-                 quote (stops));
Ondrej Oprala 32b1e5
-          ok = false;
Ondrej Oprala 32b1e5
-          break;
Ondrej Oprala 32b1e5
-        }
Ondrej Oprala 32b1e5
-    }
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-  if (!ok)
Ondrej Oprala 32b1e5
-    exit (EXIT_FAILURE);
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-  if (have_tabval)
Ondrej Oprala 32b1e5
-    add_tab_stop (tabval);
Ondrej Oprala 32b1e5
-}
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-/* Check that the list of tab stops TABS, with ENTRIES entries,
Ondrej Oprala 32b1e5
-   contains only nonzero, ascending values.  */
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-static void
Ondrej Oprala 32b1e5
-validate_tab_stops (uintmax_t const *tabs, size_t entries)
Ondrej Oprala 32b1e5
-{
Ondrej Oprala 32b1e5
-  uintmax_t prev_tab = 0;
Ondrej Oprala 32b1e5
-  size_t i;
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-  for (i = 0; i < entries; i++)
Ondrej Oprala 32b1e5
-    {
Ondrej Oprala 32b1e5
-      if (tabs[i] == 0)
Ondrej Oprala 32b1e5
-        error (EXIT_FAILURE, 0, _("tab size cannot be 0"));
Ondrej Oprala 32b1e5
-      if (tabs[i] <= prev_tab)
Ondrej Oprala 32b1e5
-        error (EXIT_FAILURE, 0, _("tab sizes must be ascending"));
Ondrej Oprala 32b1e5
-      prev_tab = tabs[i];
Ondrej Oprala 32b1e5
-    }
Ondrej Oprala 32b1e5
-}
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-/* Close the old stream pointer FP if it is non-NULL,
Ondrej Oprala 32b1e5
-   and return a new one opened to read the next input file.
Ondrej Oprala 32b1e5
-   Open a filename of '-' as the standard input.
Ondrej Oprala 32b1e5
-   Return NULL if there are no more input files.  */
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-static FILE *
Ondrej Oprala 32b1e5
-next_file (FILE *fp)
Ondrej Oprala 32b1e5
-{
Ondrej Oprala 32b1e5
-  static char *prev_file;
Ondrej Oprala 32b1e5
-  char *file;
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-  if (fp)
Ondrej Oprala 32b1e5
-    {
Ondrej Oprala 32b1e5
-      if (ferror (fp))
Ondrej Oprala 32b1e5
-        {
Ondřej Vašík 7d9c9a
-          error (0, errno, "%s", quotef (prev_file));
Ondrej Oprala 32b1e5
-          exit_status = EXIT_FAILURE;
Ondrej Oprala 32b1e5
-        }
Ondrej Oprala 32b1e5
-      if (STREQ (prev_file, "-"))
Ondrej Oprala 32b1e5
-        clearerr (fp);		/* Also clear EOF.  */
Ondrej Oprala 32b1e5
-      else if (fclose (fp) != 0)
Ondrej Oprala 32b1e5
-        {
Ondřej Vašík 7d9c9a
-          error (0, errno, "%s", quotef (prev_file));
Ondrej Oprala 32b1e5
-          exit_status = EXIT_FAILURE;
Ondrej Oprala 32b1e5
-        }
Ondrej Oprala 32b1e5
-    }
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-  while ((file = *file_list++) != NULL)
Ondrej Oprala 32b1e5
-    {
Ondrej Oprala 32b1e5
-      if (STREQ (file, "-"))
Ondrej Oprala 32b1e5
-        {
Ondrej Oprala 32b1e5
-          have_read_stdin = true;
Ondrej Oprala 32b1e5
-          fp = stdin;
Ondrej Oprala 32b1e5
-        }
Ondrej Oprala 32b1e5
-      else
Ondrej Oprala 32b1e5
-        fp = fopen (file, "r");
Ondrej Oprala 32b1e5
-      if (fp)
Ondrej Oprala 32b1e5
-        {
Ondrej Oprala 32b1e5
-          prev_file = file;
Ondrej Oprala 32b1e5
-          fadvise (fp, FADVISE_SEQUENTIAL);
Ondrej Oprala 32b1e5
-          return fp;
Ondrej Oprala 32b1e5
-        }
Ondřej Vašík 7d9c9a
-      error (0, errno, "%s", quotef (file));
Ondrej Oprala 32b1e5
-      exit_status = EXIT_FAILURE;
Ondrej Oprala 32b1e5
-    }
Ondrej Oprala 32b1e5
-  return NULL;
Ondrej Oprala 32b1e5
 }
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
 /* Change tabs to spaces, writing to stdout.
Ondrej Oprala 32b1e5
@@ -265,19 +146,19 @@ expand (void)
Ondrej Oprala 32b1e5
 {
Ondrej Oprala 32b1e5
   /* Input stream.  */
Ondrej Oprala 32b1e5
   FILE *fp = next_file (NULL);
Ondrej Oprala 32b1e5
+  mb_file_t mbf;
Ondrej Oprala 32b1e5
+  mbf_char_t c;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
   if (!fp)
Ondrej Oprala 32b1e5
     return;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
+  mbf_init (mbf, fp);
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
   while (true)
Ondrej Oprala 32b1e5
     {
Ondrej Oprala 32b1e5
-      /* Input character, or EOF.  */
Ondrej Oprala 32b1e5
-      int c;
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
       /* If true, perform translations.  */
Ondrej Oprala 32b1e5
       bool convert = true;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
       /* The following variables have valid values only when CONVERT
Ondrej Oprala 32b1e5
          is true:  */
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
@@ -287,17 +168,23 @@ expand (void)
Ondrej Oprala 32b1e5
       /* Index in TAB_LIST of next tab stop to examine.  */
Ondrej Oprala 32b1e5
       size_t tab_index = 0;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
       /* Convert a line of text.  */
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
       do
Ondrej Oprala 32b1e5
         {
Ondrej Oprala 32b1e5
-          while ((c = getc (fp)) < 0 && (fp = next_file (fp)))
Ondrej Oprala 32b1e5
-            continue;
Ondrej Oprala 32b1e5
+          do {
Ondrej Oprala 32b1e5
+            mbf_getc (c, mbf);
Ondrej Oprala 32b1e5
+            if (mb_iseof (c))
Ondrej Oprala 32b1e5
+              {
Ondrej Oprala 32b1e5
+                mbf_init (mbf, fp = next_file (fp));
Ondrej Oprala 32b1e5
+                continue;
Ondrej Oprala 32b1e5
+              }
Ondrej Oprala 32b1e5
+            }
Ondrej Oprala 32b1e5
+          while (false);
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
           if (convert)
Ondrej Oprala 32b1e5
             {
Ondrej Oprala 32b1e5
-              if (c == '\t')
Ondrej Oprala 32b1e5
+              if (mb_iseq (c, '\t'))
Ondrej Oprala 32b1e5
                 {
Ondrej Oprala 32b1e5
                   /* Column the next input tab stop is on.  */
Ondrej Oprala 32b1e5
                   uintmax_t next_tab_column;
Ondrej Oprala 32b1e5
@@ -328,32 +215,34 @@ expand (void)
Ondrej Oprala 32b1e5
                     if (putchar (' ') < 0)
Ondrej Oprala 32b1e5
                       error (EXIT_FAILURE, errno, _("write error"));
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
-                  c = ' ';
Ondrej Oprala 32b1e5
+                  mb_setascii (&c, ' ');
Ondrej Oprala 32b1e5
                 }
Ondrej Oprala 32b1e5
-              else if (c == '\b')
Ondrej Oprala 32b1e5
+              else if (mb_iseq (c, '\b'))
Ondrej Oprala 32b1e5
                 {
Ondrej Oprala 32b1e5
                   /* Go back one column, and force recalculation of the
Ondrej Oprala 32b1e5
                      next tab stop.  */
Ondrej Oprala 32b1e5
                   column -= !!column;
Ondrej Oprala 32b1e5
                   tab_index -= !!tab_index;
Ondrej Oprala 32b1e5
                 }
Ondrej Oprala 32b1e5
-              else
Ondrej Oprala 32b1e5
+              /* A leading control character could make us trip over.  */
Ondrej Oprala 32b1e5
+              else if (!mb_iscntrl (c))
Ondrej Oprala 32b1e5
                 {
Ondrej Oprala 32b1e5
-                  column++;
Ondrej Oprala 32b1e5
+                  column += mb_width (c);
Ondrej Oprala 32b1e5
                   if (!column)
Ondrej Oprala 32b1e5
                     error (EXIT_FAILURE, 0, _("input line is too long"));
Ondrej Oprala 32b1e5
                 }
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
-              convert &= convert_entire_line || !! isblank (c);
Ondrej Oprala 32b1e5
+              convert &= convert_entire_line || mb_isblank (c);
Ondrej Oprala 32b1e5
             }
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
-          if (c < 0)
Ondrej Oprala 32b1e5
+          if (mb_iseof (c))
Ondrej Oprala 32b1e5
             return;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
-          if (putchar (c) < 0)
Ondrej Oprala 32b1e5
+          mb_putc (c, stdout);
Ondrej Oprala 32b1e5
+          if (ferror (stdout))
Ondrej Oprala 32b1e5
             error (EXIT_FAILURE, errno, _("write error"));
Ondrej Oprala 32b1e5
         }
Ondrej Oprala 32b1e5
-      while (c != '\n');
Ondrej Oprala 32b1e5
+      while (!mb_iseq (c, '\n'));
Ondrej Oprala 32b1e5
     }
Ondrej Oprala 32b1e5
 }
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
@@ -385,19 +274,19 @@ main (int argc, char **argv)
Ondrej Oprala 32b1e5
           break;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
         case 't':
Ondrej Oprala 32b1e5
-          parse_tab_stops (optarg);
Ondrej Oprala 32b1e5
+          parse_tab_stops (optarg, add_tab_stop);
Ondrej Oprala 32b1e5
           break;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
         case '0': case '1': case '2': case '3': case '4':
Ondrej Oprala 32b1e5
         case '5': case '6': case '7': case '8': case '9':
Ondrej Oprala 32b1e5
           if (optarg)
Ondrej Oprala 32b1e5
-            parse_tab_stops (optarg - 1);
Ondrej Oprala 32b1e5
+            parse_tab_stops (optarg - 1, add_tab_stop);
Ondrej Oprala 32b1e5
           else
Ondrej Oprala 32b1e5
             {
Ondrej Oprala 32b1e5
               char tab_stop[2];
Ondrej Oprala 32b1e5
               tab_stop[0] = c;
Ondrej Oprala 32b1e5
               tab_stop[1] = '\0';
Ondrej Oprala 32b1e5
-              parse_tab_stops (tab_stop);
Ondrej Oprala 32b1e5
+              parse_tab_stops (tab_stop, add_tab_stop);
Ondrej Oprala 32b1e5
             }
Ondrej Oprala 32b1e5
           break;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
diff --git a/src/local.mk b/src/local.mk
Ondrej Oprala 32b1e5
index 536b7cc..bfede88 100644
Ondrej Oprala 32b1e5
--- a/src/local.mk
Ondrej Oprala 32b1e5
+++ b/src/local.mk
Ondrej Oprala 32b1e5
@@ -362,6 +362,8 @@ src_coreutils_SOURCES = src/coreutils.c
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
 src_cp_SOURCES = src/cp.c $(copy_sources) $(selinux_sources)
Ondrej Oprala 32b1e5
 src_dir_SOURCES = src/ls.c src/ls-dir.c
Ondrej Oprala 32b1e5
+src_expand_SOURCES = src/expand.c src/expand-core.c
Ondrej Oprala 32b1e5
+src_unexpand_SOURCES = src/unexpand.c src/expand-core.c
Ondrej Oprala 32b1e5
 src_vdir_SOURCES = src/ls.c src/ls-vdir.c
Ondrej Oprala 32b1e5
 src_id_SOURCES = src/id.c src/group-list.c
Ondrej Oprala 32b1e5
 src_groups_SOURCES = src/groups.c src/group-list.c
Ondrej Oprala 32b1e5
diff --git a/src/unexpand.c b/src/unexpand.c
Ondrej Oprala 32b1e5
index e0f7c22..48fbb32 100644
Ondrej Oprala 32b1e5
--- a/src/unexpand.c
Ondrej Oprala 32b1e5
+++ b/src/unexpand.c
Ondrej Oprala 32b1e5
@@ -38,12 +38,16 @@
Ondrej Oprala 32b1e5
 #include <stdio.h>
Ondrej Oprala 32b1e5
 #include <getopt.h>
Ondrej Oprala 32b1e5
 #include <sys/types.h>
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#include <mbfile.h>
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
 #include "system.h"
Ondrej Oprala 32b1e5
 #include "error.h"
Ondrej Oprala 32b1e5
 #include "fadvise.h"
Ondrej Oprala 32b1e5
-#include "quote.h"
Ondrej Oprala 32b1e5
 #include "xstrndup.h"
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
+#include "expand-core.h"
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
 /* The official name of this program (e.g., no 'g' prefix).  */
Ondrej Oprala 32b1e5
 #define PROGRAM_NAME "unexpand"
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
@@ -62,17 +66,17 @@ static size_t max_column_width;
Ondrej Oprala 32b1e5
 /* Array of the explicit column numbers of the tab stops;
Ondrej Oprala 32b1e5
    after 'tab_list' is exhausted, the rest of the line is printed
Ondrej Oprala 32b1e5
    unchanged.  The first column is column 0.  */
Ondrej Oprala 32b1e5
-static uintmax_t *tab_list;
Ondrej Oprala 32b1e5
+uintmax_t *tab_list;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
 /* The number of allocated entries in 'tab_list'.  */
Ondrej Oprala 32b1e5
-static size_t n_tabs_allocated;
Ondrej Oprala 32b1e5
+size_t n_tabs_allocated;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
 /* The index of the first invalid element of 'tab_list',
Ondrej Oprala 32b1e5
    where the next element can be added.  */
Ondrej Oprala 32b1e5
-static size_t first_free_tab;
Ondrej Oprala 32b1e5
+size_t first_free_tab;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
 /* Null-terminated array of input filenames.  */
Ondrej Oprala 32b1e5
-static char **file_list;
Ondrej Oprala 32b1e5
+char **file_list;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
 /* Default for 'file_list' if no files are given on the command line.  */
Ondrej Oprala 32b1e5
 static char *stdin_argv[] =
Ondrej Oprala 32b1e5
@@ -81,10 +85,10 @@ static char *stdin_argv[] =
Ondrej Oprala 32b1e5
 };
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
 /* True if we have ever read standard input.  */
Ondrej Oprala 32b1e5
-static bool have_read_stdin;
Ondrej Oprala 32b1e5
+bool have_read_stdin;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
 /* The desired exit status.  */
Ondrej Oprala 32b1e5
-static int exit_status;
Ondrej Oprala 32b1e5
+int exit_status;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
 /* For long options that have no equivalent short option, use a
Ondrej Oprala 32b1e5
    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
Ondrej Oprala 32b1e5
@@ -154,128 +156,6 @@ add_tab_stop (uintmax_t tabval)
Ondrej Oprala 32b1e5
     }
Ondrej Oprala 32b1e5
 }
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
-/* Add the comma or blank separated list of tab stops STOPS
Ondrej Oprala 32b1e5
-   to the list of tab stops.  */
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-static void
Ondrej Oprala 32b1e5
-parse_tab_stops (char const *stops)
Ondrej Oprala 32b1e5
-{
Ondrej Oprala 32b1e5
-  bool have_tabval = false;
Ondrej Oprala 32b1e5
-  uintmax_t tabval IF_LINT ( = 0);
Ondrej Oprala 32b1e5
-  char const *num_start IF_LINT ( = NULL);
Ondrej Oprala 32b1e5
-  bool ok = true;
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-  for (; *stops; stops++)
Ondrej Oprala 32b1e5
-    {
Ondrej Oprala 32b1e5
-      if (*stops == ',' || isblank (to_uchar (*stops)))
Ondrej Oprala 32b1e5
-        {
Ondrej Oprala 32b1e5
-          if (have_tabval)
Ondrej Oprala 32b1e5
-            add_tab_stop (tabval);
Ondrej Oprala 32b1e5
-          have_tabval = false;
Ondrej Oprala 32b1e5
-        }
Ondrej Oprala 32b1e5
-      else if (ISDIGIT (*stops))
Ondrej Oprala 32b1e5
-        {
Ondrej Oprala 32b1e5
-          if (!have_tabval)
Ondrej Oprala 32b1e5
-            {
Ondrej Oprala 32b1e5
-              tabval = 0;
Ondrej Oprala 32b1e5
-              have_tabval = true;
Ondrej Oprala 32b1e5
-              num_start = stops;
Ondrej Oprala 32b1e5
-            }
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-          /* Detect overflow.  */
Ondrej Oprala 32b1e5
-          if (!DECIMAL_DIGIT_ACCUMULATE (tabval, *stops - '0', uintmax_t))
Ondrej Oprala 32b1e5
-            {
Ondrej Oprala 32b1e5
-              size_t len = strspn (num_start, "0123456789");
Ondrej Oprala 32b1e5
-              char *bad_num = xstrndup (num_start, len);
Ondrej Oprala 32b1e5
-              error (0, 0, _("tab stop is too large %s"), quote (bad_num));
Ondrej Oprala 32b1e5
-              free (bad_num);
Ondrej Oprala 32b1e5
-              ok = false;
Ondrej Oprala 32b1e5
-              stops = num_start + len - 1;
Ondrej Oprala 32b1e5
-            }
Ondrej Oprala 32b1e5
-        }
Ondrej Oprala 32b1e5
-      else
Ondrej Oprala 32b1e5
-        {
Ondrej Oprala 32b1e5
-          error (0, 0, _("tab size contains invalid character(s): %s"),
Ondrej Oprala 32b1e5
-                 quote (stops));
Ondrej Oprala 32b1e5
-          ok = false;
Ondrej Oprala 32b1e5
-          break;
Ondrej Oprala 32b1e5
-        }
Ondrej Oprala 32b1e5
-    }
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-  if (!ok)
Ondrej Oprala 32b1e5
-    exit (EXIT_FAILURE);
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-  if (have_tabval)
Ondrej Oprala 32b1e5
-    add_tab_stop (tabval);
Ondrej Oprala 32b1e5
-}
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-/* Check that the list of tab stops TABS, with ENTRIES entries,
Ondrej Oprala 32b1e5
-   contains only nonzero, ascending values.  */
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-static void
Ondrej Oprala 32b1e5
-validate_tab_stops (uintmax_t const *tabs, size_t entries)
Ondrej Oprala 32b1e5
-{
Ondrej Oprala 32b1e5
-  uintmax_t prev_tab = 0;
Ondrej Oprala 32b1e5
-  size_t i;
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-  for (i = 0; i < entries; i++)
Ondrej Oprala 32b1e5
-    {
Ondrej Oprala 32b1e5
-      if (tabs[i] == 0)
Ondrej Oprala 32b1e5
-        error (EXIT_FAILURE, 0, _("tab size cannot be 0"));
Ondrej Oprala 32b1e5
-      if (tabs[i] <= prev_tab)
Ondrej Oprala 32b1e5
-        error (EXIT_FAILURE, 0, _("tab sizes must be ascending"));
Ondrej Oprala 32b1e5
-      prev_tab = tabs[i];
Ondrej Oprala 32b1e5
-    }
Ondrej Oprala 32b1e5
-}
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-/* Close the old stream pointer FP if it is non-NULL,
Ondrej Oprala 32b1e5
-   and return a new one opened to read the next input file.
Ondrej Oprala 32b1e5
-   Open a filename of '-' as the standard input.
Ondrej Oprala 32b1e5
-   Return NULL if there are no more input files.  */
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-static FILE *
Ondrej Oprala 32b1e5
-next_file (FILE *fp)
Ondrej Oprala 32b1e5
-{
Ondrej Oprala 32b1e5
-  static char *prev_file;
Ondrej Oprala 32b1e5
-  char *file;
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-  if (fp)
Ondrej Oprala 32b1e5
-    {
Ondrej Oprala 32b1e5
-      if (ferror (fp))
Ondrej Oprala 32b1e5
-        {
Ondřej Vašík 7d9c9a
-          error (0, errno, "%s", quotef (prev_file));
Ondrej Oprala 32b1e5
-          exit_status = EXIT_FAILURE;
Ondrej Oprala 32b1e5
-        }
Ondrej Oprala 32b1e5
-      if (STREQ (prev_file, "-"))
Ondrej Oprala 32b1e5
-        clearerr (fp);		/* Also clear EOF.  */
Ondrej Oprala 32b1e5
-      else if (fclose (fp) != 0)
Ondrej Oprala 32b1e5
-        {
Ondřej Vašík 7d9c9a
-          error (0, errno, "%s", quotef (prev_file));
Ondrej Oprala 32b1e5
-          exit_status = EXIT_FAILURE;
Ondrej Oprala 32b1e5
-        }
Ondrej Oprala 32b1e5
-    }
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-  while ((file = *file_list++) != NULL)
Ondrej Oprala 32b1e5
-    {
Ondrej Oprala 32b1e5
-      if (STREQ (file, "-"))
Ondrej Oprala 32b1e5
-        {
Ondrej Oprala 32b1e5
-          have_read_stdin = true;
Ondrej Oprala 32b1e5
-          fp = stdin;
Ondrej Oprala 32b1e5
-        }
Ondrej Oprala 32b1e5
-      else
Ondrej Oprala 32b1e5
-        fp = fopen (file, "r");
Ondrej Oprala 32b1e5
-      if (fp)
Ondrej Oprala 32b1e5
-        {
Ondrej Oprala 32b1e5
-          prev_file = file;
Ondrej Oprala 32b1e5
-          fadvise (fp, FADVISE_SEQUENTIAL);
Ondrej Oprala 32b1e5
-          return fp;
Ondrej Oprala 32b1e5
-        }
Ondřej Vašík 7d9c9a
-      error (0, errno, "%s", quotef (file));
Ondrej Oprala 32b1e5
-      exit_status = EXIT_FAILURE;
Ondrej Oprala 32b1e5
-    }
Ondrej Oprala 32b1e5
-  return NULL;
Ondrej Oprala 32b1e5
-}
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
 /* Change blanks to tabs, writing to stdout.
Ondrej Oprala 32b1e5
    Read each file in 'file_list', in order.  */
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
@@ -284,11 +164,12 @@ unexpand (void)
Ondrej Oprala 32b1e5
 {
Ondrej Oprala 32b1e5
   /* Input stream.  */
Ondrej Oprala 32b1e5
   FILE *fp = next_file (NULL);
Ondrej Oprala 32b1e5
+  mb_file_t mbf;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
   /* The array of pending blanks.  In non-POSIX locales, blanks can
Ondrej Oprala 32b1e5
      include characters other than spaces, so the blanks must be
Ondrej Oprala 32b1e5
      stored, not merely counted.  */
Ondrej Oprala 32b1e5
-  char *pending_blank;
Ondrej Oprala 32b1e5
+  mbf_char_t *pending_blank;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
   if (!fp)
Ondrej Oprala 32b1e5
     return;
Ondrej Oprala 32b1e5
@@ -296,12 +177,14 @@ unexpand (void)
Ondrej Oprala 32b1e5
   /* The worst case is a non-blank character, then one blank, then a
Ondrej Oprala 32b1e5
      tab stop, then MAX_COLUMN_WIDTH - 1 blanks, then a non-blank; so
Ondrej Oprala 32b1e5
      allocate MAX_COLUMN_WIDTH bytes to store the blanks.  */
Ondrej Oprala 32b1e5
-  pending_blank = xmalloc (max_column_width);
Ondrej Oprala 32b1e5
+  pending_blank = xmalloc (max_column_width * sizeof (mbf_char_t));
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+  mbf_init (mbf, fp);
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
   while (true)
Ondrej Oprala 32b1e5
     {
Ondrej Oprala 32b1e5
       /* Input character, or EOF.  */
Ondrej Oprala 32b1e5
-      int c;
Ondrej Oprala 32b1e5
+      mbf_char_t c;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
       /* If true, perform translations.  */
Ondrej Oprala 32b1e5
       bool convert = true;
Ondrej Oprala 32b1e5
@@ -335,12 +218,19 @@ unexpand (void)
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
       do
Ondrej Oprala 32b1e5
         {
Ondrej Oprala 32b1e5
-          while ((c = getc (fp)) < 0 && (fp = next_file (fp)))
Ondrej Oprala 32b1e5
-            continue;
Ondrej Oprala 32b1e5
+          do {
Ondrej Oprala 32b1e5
+            mbf_getc (c, mbf);
Ondrej Oprala 32b1e5
+            if (mb_iseof (c))
Ondrej Oprala 32b1e5
+              {
Ondrej Oprala 32b1e5
+                mbf_init (mbf, fp = next_file (fp));
Ondrej Oprala 32b1e5
+                continue;
Ondrej Oprala 32b1e5
+              }
Ondrej Oprala 32b1e5
+            }
Ondrej Oprala 32b1e5
+          while (false);
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
           if (convert)
Ondrej Oprala 32b1e5
             {
Ondrej Oprala 32b1e5
-              bool blank = !! isblank (c);
Ondrej Oprala 32b1e5
+              bool blank = mb_isblank (c);
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
               if (blank)
Ondrej Oprala 32b1e5
                 {
Ondrej Oprala 32b1e5
@@ -372,16 +262,16 @@ unexpand (void)
Ondrej Oprala 32b1e5
                       if (next_tab_column < column)
Ondrej Oprala 32b1e5
                         error (EXIT_FAILURE, 0, _("input line is too long"));
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
-                      if (c == '\t')
Ondrej Oprala 32b1e5
+                      if (mb_iseq (c, '\t'))
Ondrej Oprala 32b1e5
                         {
Ondrej Oprala 32b1e5
                           column = next_tab_column;
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
                           if (pending)
Ondrej Oprala 32b1e5
-                            pending_blank[0] = '\t';
Ondrej Oprala 32b1e5
+                            mb_setascii (&pending_blank[0], '\t');
Ondrej Oprala 32b1e5
                         }
Ondrej Oprala 32b1e5
                       else
Ondrej Oprala 32b1e5
                         {
Ondrej Oprala 32b1e5
-                          column++;
Ondrej Oprala 32b1e5
+                          column += mb_width (c);
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
                           if (! (prev_blank && column == next_tab_column))
Ondrej Oprala 32b1e5
                             {
Ondrej Oprala 32b1e5
@@ -389,13 +279,14 @@ unexpand (void)
Ondrej Oprala 32b1e5
                                  will be replaced by tabs.  */
Ondrej Oprala 32b1e5
                               if (column == next_tab_column)
Ondrej Oprala 32b1e5
                                 one_blank_before_tab_stop = true;
Ondrej Oprala 32b1e5
-                              pending_blank[pending++] = c;
Ondrej Oprala 32b1e5
+                              mb_copy (&pending_blank[pending++], &c);
Ondrej Oprala 32b1e5
                               prev_blank = true;
Ondrej Oprala 32b1e5
                               continue;
Ondrej Oprala 32b1e5
                             }
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
                           /* Replace the pending blanks by a tab or two.  */
Ondrej Oprala 32b1e5
-                          pending_blank[0] = c = '\t';
Ondrej Oprala 32b1e5
+                          mb_setascii (&c, '\t');
Ondrej Oprala 32b1e5
+                          mb_setascii (&pending_blank[0], '\t');
Ondrej Oprala 32b1e5
                         }
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
                       /* Discard pending blanks, unless it was a single
Ondrej Oprala 32b1e5
@@ -403,7 +294,7 @@ unexpand (void)
Ondrej Oprala 32b1e5
                       pending = one_blank_before_tab_stop;
Ondrej Oprala 32b1e5
                     }
Ondrej Oprala 32b1e5
                 }
Ondrej Oprala 32b1e5
-              else if (c == '\b')
Ondrej Oprala 32b1e5
+              else if (mb_iseq (c, '\b'))
Ondrej Oprala 32b1e5
                 {
Ondrej Oprala 32b1e5
                   /* Go back one column, and force recalculation of the
Ondrej Oprala 32b1e5
                      next tab stop.  */
Ondrej Oprala 32b1e5
@@ -413,7 +304,7 @@ unexpand (void)
Ondrej Oprala 32b1e5
                 }
Ondrej Oprala 32b1e5
               else
Ondrej Oprala 32b1e5
                 {
Ondrej Oprala 32b1e5
-                  column++;
Ondrej Oprala 32b1e5
+                  column += mb_width (c);
Ondrej Oprala 32b1e5
                   if (!column)
Ondrej Oprala 32b1e5
                     error (EXIT_FAILURE, 0, _("input line is too long"));
Ondrej Oprala 32b1e5
                 }
Ondrej Oprala 32b1e5
@@ -421,9 +312,13 @@ unexpand (void)
Ondrej Oprala 32b1e5
               if (pending)
Ondrej Oprala 32b1e5
                 {
Ondrej Oprala 32b1e5
                   if (pending > 1 && one_blank_before_tab_stop)
Ondrej Oprala 32b1e5
-                    pending_blank[0] = '\t';
Ondrej Oprala 32b1e5
-                  if (fwrite (pending_blank, 1, pending, stdout) != pending)
Ondrej Oprala 32b1e5
+                    mb_setascii (&pending_blank[0], '\t');
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+                  for (int n = 0; n < pending; ++n)
Ondrej Oprala 32b1e5
+                    mb_putc (pending_blank[n], stdout);
Ondrej Oprala 32b1e5
+                  if (ferror (stdout))
Ondrej Oprala 32b1e5
                     error (EXIT_FAILURE, errno, _("write error"));
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
                   pending = 0;
Ondrej Oprala 32b1e5
                   one_blank_before_tab_stop = false;
Ondrej Oprala 32b1e5
                 }
Ondrej Oprala 32b1e5
@@ -432,16 +327,16 @@ unexpand (void)
Ondrej Oprala 32b1e5
               convert &= convert_entire_line || blank;
Ondrej Oprala 32b1e5
             }
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
-          if (c < 0)
Ondrej Oprala 32b1e5
+          if (mb_iseof (c))
Ondrej Oprala 32b1e5
             {
Ondrej Oprala 32b1e5
               free (pending_blank);
Ondrej Oprala 32b1e5
               return;
Ondrej Oprala 32b1e5
             }
Ondrej Oprala 32b1e5
-
Ondrej Oprala 32b1e5
-          if (putchar (c) < 0)
Ondrej Oprala 32b1e5
+          mb_putc (c, stdout);
Ondrej Oprala 32b1e5
+          if (ferror (stdout))
Ondrej Oprala 32b1e5
             error (EXIT_FAILURE, errno, _("write error"));
Ondrej Oprala 32b1e5
         }
Ondrej Oprala 32b1e5
-      while (c != '\n');
Ondrej Oprala 32b1e5
+      while (!mb_iseq (c, '\n'));
Ondrej Oprala 32b1e5
     }
Ondrej Oprala 32b1e5
 }
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
@@ -482,7 +377,7 @@ main (int argc, char **argv)
Ondrej Oprala 32b1e5
           break;
Ondrej Oprala 32b1e5
         case 't':
Ondrej Oprala 32b1e5
           convert_entire_line = true;
Ondrej Oprala 32b1e5
-          parse_tab_stops (optarg);
Ondrej Oprala 32b1e5
+          parse_tab_stops (optarg, add_tab_stop);
Ondrej Oprala 32b1e5
           break;
Ondrej Oprala 32b1e5
         case CONVERT_FIRST_ONLY_OPTION:
Ondrej Oprala 32b1e5
           convert_first_only = true;
Ondrej Oprala 32b1e5
diff --git a/tests/expand/mb.sh b/tests/expand/mb.sh
Ondrej Oprala 32b1e5
new file mode 100755
Ondrej Oprala 32b1e5
index 0000000..7971e18
Ondrej Oprala 32b1e5
--- /dev/null
Ondrej Oprala 32b1e5
+++ b/tests/expand/mb.sh
Ondrej Oprala 32b1e5
@@ -0,0 +1,98 @@
Ondrej Oprala 32b1e5
+#!/bin/sh
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+# Copyright (C) 2012-2015 Free Software Foundation, Inc.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+# This program is free software: you can redistribute it and/or modify
Ondrej Oprala 32b1e5
+# it under the terms of the GNU General Public License as published by
Ondrej Oprala 32b1e5
+# the Free Software Foundation, either version 3 of the License, or
Ondrej Oprala 32b1e5
+# (at your option) any later version.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+# This program is distributed in the hope that it will be useful,
Ondrej Oprala 32b1e5
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
Ondrej Oprala 32b1e5
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Ondrej Oprala 32b1e5
+# GNU General Public License for more details.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+# You should have received a copy of the GNU General Public License
Ondrej Oprala 32b1e5
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
Ondrej Oprala 32b1e5
+print_ver_ expand
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+export LC_ALL=en_US.UTF-8
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#input containing multibyte characters
Ondrej Oprala 32b1e5
+cat <<\EOF > in || framework_failure_
Ondrej Oprala 32b1e5
+1234567812345678123456781
Ondrej Oprala 32b1e5
+.       .       .       .
Ondrej Oprala 32b1e5
+a	b	c	d
Ondrej Oprala 32b1e5
+.       .       .       .
Ondrej Oprala 32b1e5
+ä	ö	ü	ß
Ondrej Oprala 32b1e5
+.       .       .       .
Ondrej Oprala 32b1e5
+EOF
Ondrej Oprala 32b1e5
+env printf '   äöü\t.    öüä.   \tä xx\n' >> in || framework_failure_
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+cat <<\EOF > exp || framework_failure_
Ondrej Oprala 32b1e5
+1234567812345678123456781
Ondrej Oprala 32b1e5
+.       .       .       .
Ondrej Oprala 32b1e5
+a       b       c       d
Ondrej Oprala 32b1e5
+.       .       .       .
Ondrej Oprala 32b1e5
+ä       ö       ü       ß
Ondrej Oprala 32b1e5
+.       .       .       .
Ondrej Oprala 32b1e5
+   äöü  .    öüä.       ä xx
Ondrej Oprala 32b1e5
+EOF
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+expand < in > out || fail=1
Ondrej Oprala 32b1e5
+compare exp out > /dev/null 2>&1 || fail=1
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#test characters with display widths != 1
Ondrej Oprala 32b1e5
+env printf '12345678
Ondrej Oprala 32b1e5
+e\t|ascii(1)
Ondrej Oprala 32b1e5
+\u00E9\t|composed(1)
Ondrej Oprala 32b1e5
+e\u0301\t|decomposed(1)
Ondrej Oprala 32b1e5
+\u3000\t|ideo-space(2)
Ondrej Oprala 32b1e5
+\uFF0D\t|full-hypen(2)
Ondrej Oprala 32b1e5
+' > in || framework_failure_
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+env printf '12345678
Ondrej Oprala 32b1e5
+e       |ascii(1)
Ondrej Oprala 32b1e5
+\u00E9       |composed(1)
Ondrej Oprala 32b1e5
+e\u0301       |decomposed(1)
Ondrej Oprala 32b1e5
+\u3000      |ideo-space(2)
Ondrej Oprala 32b1e5
+\uFF0D      |full-hypen(2)
Ondrej Oprala 32b1e5
+' > exp || framework_failure_
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+expand < in > out || fail=1
Ondrej Oprala 32b1e5
+compare exp out > /dev/null 2>&1 || fail=1
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#shouldn't fail with "input line too long"
Ondrej Oprala 32b1e5
+#when a line starts with a control character
Ondrej Oprala 32b1e5
+env printf '\n' > in || framework_failure_
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+expand < in > out || fail=1
Ondrej Oprala 32b1e5
+compare in out > /dev/null 2>&1 || fail=1
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#non-Unicode characters interspersed between Unicode ones
Ondrej Oprala 32b1e5
+env printf '12345678
Ondrej Oprala 32b1e5
+\t\xFF|
Ondrej Oprala 32b1e5
+\xFF\t|
Ondrej Oprala 32b1e5
+\t\xFFä|
Ondrej Oprala 32b1e5
+ä\xFF\t|
Ondrej Oprala 32b1e5
+\tä\xFF|
Ondrej Oprala 32b1e5
+\xFF\tä|
Ondrej Oprala 32b1e5
+äbcdef\xFF\t|
Ondrej Oprala 32b1e5
+' > in || framework_failure_
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+env printf '12345678
Ondrej Oprala 32b1e5
+        \xFF|
Ondrej Oprala 32b1e5
+\xFF       |
Ondrej Oprala 32b1e5
+        \xFFä|
Ondrej Oprala 32b1e5
+ä\xFF      |
Ondrej Oprala 32b1e5
+        ä\xFF|
Ondrej Oprala 32b1e5
+\xFF       ä|
Ondrej Oprala 32b1e5
+äbcdef\xFF |
Ondrej Oprala 32b1e5
+' > exp || framework_failure_
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+expand < in > out || fail=1
Ondrej Oprala 32b1e5
+compare exp out > /dev/null 2>&1 || fail=1
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+exit $fail
Ondrej Oprala 32b1e5
diff --git a/tests/local.mk b/tests/local.mk
Ondrej Oprala 32b1e5
index 7df04da..d3462be 100644
Ondrej Oprala 32b1e5
--- a/tests/local.mk
Ondrej Oprala 32b1e5
+++ b/tests/local.mk
Ondrej Oprala 32b1e5
@@ -532,6 +532,7 @@ all_tests =					\
Ondrej Oprala 32b1e5
   tests/du/threshold.sh				\
Ondrej Oprala 32b1e5
   tests/du/trailing-slash.sh			\
Ondrej Oprala 32b1e5
   tests/du/two-args.sh				\
Ondrej Oprala 32b1e5
+  tests/expand/mb.sh				\
Ondrej Oprala 32b1e5
   tests/id/gnu-zero-uids.sh			\
Ondrej Oprala 32b1e5
   tests/id/no-context.sh			\
Ondrej Oprala 32b1e5
   tests/id/context.sh				\
Ondrej Oprala 32b1e5
@@ -671,6 +672,7 @@ all_tests =					\
Ondrej Oprala 32b1e5
   tests/touch/read-only.sh			\
Ondrej Oprala 32b1e5
   tests/touch/relative.sh			\
Ondrej Oprala 32b1e5
   tests/touch/trailing-slash.sh			\
Ondrej Oprala 32b1e5
+  tests/unexpand/mb.sh				\
Ondrej Oprala 32b1e5
   $(all_root_tests)
Ondrej Oprala 32b1e5
 
Ondrej Oprala 32b1e5
 # See tests/factor/create-test.sh.
Ondrej Oprala 32b1e5
diff --git a/tests/unexpand/mb.sh b/tests/unexpand/mb.sh
Ondrej Oprala 32b1e5
new file mode 100755
Ondrej Oprala 32b1e5
index 0000000..60d4c1a
Ondrej Oprala 32b1e5
--- /dev/null
Ondrej Oprala 32b1e5
+++ b/tests/unexpand/mb.sh
Ondrej Oprala 32b1e5
@@ -0,0 +1,97 @@
Ondrej Oprala 32b1e5
+#!/bin/sh
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+# Copyright (C) 2012-2015 Free Software Foundation, Inc.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+# This program is free software: you can redistribute it and/or modify
Ondrej Oprala 32b1e5
+# it under the terms of the GNU General Public License as published by
Ondrej Oprala 32b1e5
+# the Free Software Foundation, either version 3 of the License, or
Ondrej Oprala 32b1e5
+# (at your option) any later version.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+# This program is distributed in the hope that it will be useful,
Ondrej Oprala 32b1e5
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
Ondrej Oprala 32b1e5
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Ondrej Oprala 32b1e5
+# GNU General Public License for more details.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+# You should have received a copy of the GNU General Public License
Ondrej Oprala 32b1e5
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
Ondrej Oprala 32b1e5
+print_ver_ unexpand
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+export LC_ALL=en_US.UTF-8
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#input containing multibyte characters
Ondrej Oprala 32b1e5
+cat > in <<\EOF
Ondrej Oprala 32b1e5
+1234567812345678123456781
Ondrej Oprala 32b1e5
+.       .       .       .
Ondrej Oprala 32b1e5
+a       b       c       d
Ondrej Oprala 32b1e5
+.       .       .       .
Ondrej Oprala 32b1e5
+ä       ö       ü       ß
Ondrej Oprala 32b1e5
+.       .       .       .
Ondrej Oprala 32b1e5
+   äöü  .    öüä.       ä xx
Ondrej Oprala 32b1e5
+EOF
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+cat > exp <<\EOF
Ondrej Oprala 32b1e5
+1234567812345678123456781
Ondrej Oprala 32b1e5
+.	.	.	.
Ondrej Oprala 32b1e5
+a	b	c	d
Ondrej Oprala 32b1e5
+.	.	.	.
Ondrej Oprala 32b1e5
+ä	ö	ü	ß
Ondrej Oprala 32b1e5
+.	.	.	.
Ondrej Oprala 32b1e5
+   äöü	.    öüä.	ä xx
Ondrej Oprala 32b1e5
+EOF
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+unexpand -a < in > out || fail=1
Ondrej Oprala 32b1e5
+compare exp out > /dev/null 2>&1 || fail=1
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#test characters with a display width larger than 1
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+env printf '12345678
Ondrej Oprala 32b1e5
+e       |ascii(1)
Ondrej Oprala 32b1e5
+\u00E9       |composed(1)
Ondrej Oprala 32b1e5
+e\u0301       |decomposed(1)
Ondrej Oprala 32b1e5
+\u3000      |ideo-space(2)
Ondrej Oprala 32b1e5
+\uFF0D      |full-hypen(2)
Ondrej Oprala 32b1e5
+' > in || framework_failure_
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+env printf '12345678
Ondrej Oprala 32b1e5
+e\t|ascii(1)
Ondrej Oprala 32b1e5
+\u00E9\t|composed(1)
Ondrej Oprala 32b1e5
+e\u0301\t|decomposed(1)
Ondrej Oprala 32b1e5
+\u3000\t|ideo-space(2)
Ondrej Oprala 32b1e5
+\uFF0D\t|full-hypen(2)
Ondrej Oprala 32b1e5
+' > exp || framework_failure_
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+unexpand -a < in > out || fail=1
Ondrej Oprala 32b1e5
+compare exp out > /dev/null 2>&1 || fail=1
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#test input where a blank of width > 1 is not being substituted
Ondrej Oprala 32b1e5
+in="$(LC_ALL=en_US.UTF-8 printf ' \u3000  ö       ü       ß')"
Ondrej Oprala 32b1e5
+exp='    ö	     ü	     ß'
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+unexpand -a < in > out || fail=1
Ondrej Oprala 32b1e5
+compare exp out > /dev/null 2>&1 || fail=1
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#non-Unicode characters interspersed between Unicode ones
Ondrej Oprala 32b1e5
+env printf '12345678
Ondrej Oprala 32b1e5
+        \xFF|
Ondrej Oprala 32b1e5
+\xFF       |
Ondrej Oprala 32b1e5
+        \xFFä|
Ondrej Oprala 32b1e5
+ä\xFF      |
Ondrej Oprala 32b1e5
+        ä\xFF|
Ondrej Oprala 32b1e5
+\xFF       ä|
Ondrej Oprala 32b1e5
+äbcdef\xFF |
Ondrej Oprala 32b1e5
+' > in || framework_failure_
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+env printf '12345678
Ondrej Oprala 32b1e5
+\t\xFF|
Ondrej Oprala 32b1e5
+\xFF\t|
Ondrej Oprala 32b1e5
+\t\xFFä|
Ondrej Oprala 32b1e5
+ä\xFF\t|
Ondrej Oprala 32b1e5
+\tä\xFF|
Ondrej Oprala 32b1e5
+\xFF\tä|
Ondrej Oprala 32b1e5
+äbcdef\xFF\t|
Ondrej Oprala 32b1e5
+' > exp || framework_failure_
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+unexpand -a < in > out || fail=1
Ondrej Oprala 32b1e5
+compare exp out > /dev/null 2>&1 || fail=1
Ondrej Oprala 32b1e5
-- 
Ondrej Oprala 32b1e5
2.4.3
Ondrej Oprala 32b1e5
Ondrej Oprala 32b1e5
--- /dev/null	2015-11-30 08:40:17.566742513 +0100
Ondrej Oprala 32b1e5
+++ coreutils-8.24/m4/mbfile.m4	2015-12-01 09:30:55.951149907 +0100
Ondrej Oprala 32b1e5
@@ -0,0 +1,14 @@
Ondrej Oprala 32b1e5
+# mbfile.m4 serial 7
Ondrej Oprala 32b1e5
+dnl Copyright (C) 2005, 2008-2015 Free Software Foundation, Inc.
Ondrej Oprala 32b1e5
+dnl This file is free software; the Free Software Foundation
Ondrej Oprala 32b1e5
+dnl gives unlimited permission to copy and/or distribute it,
Ondrej Oprala 32b1e5
+dnl with or without modifications, as long as this notice is preserved.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+dnl autoconf tests required for use of mbfile.h
Ondrej Oprala 32b1e5
+dnl From Bruno Haible.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+AC_DEFUN([gl_MBFILE],
Ondrej Oprala 32b1e5
+[
Ondrej Oprala 32b1e5
+  AC_REQUIRE([AC_TYPE_MBSTATE_T])
Ondrej Oprala 32b1e5
+  :
Ondrej Oprala 32b1e5
+])
Ondrej Oprala 32b1e5
--- /dev/null	2015-11-30 08:40:17.566742513 +0100
Ondrej Oprala 32b1e5
+++ coreutils-8.24/lib/mbfile.c	2015-12-01 09:28:22.254928468 +0100
Ondrej Oprala 32b1e5
@@ -0,0 +1,3 @@
Ondrej Oprala 32b1e5
+#include <config.h>
Ondrej Oprala 32b1e5
+#define MBFILE_INLINE _GL_EXTERN_INLINE
Ondrej Oprala 32b1e5
+#include "mbfile.h"
Ondrej Oprala 32b1e5
--- /dev/null	2015-11-30 08:40:17.566742513 +0100
Ondrej Oprala 32b1e5
+++ coreutils-8.24/lib/mbfile.h	2015-12-01 09:28:30.829885570 +0100
Ondrej Oprala 32b1e5
@@ -0,0 +1,255 @@
Ondrej Oprala 32b1e5
+/* Multibyte character I/O: macros for multi-byte encodings.
Ondrej Oprala 32b1e5
+   Copyright (C) 2001, 2005, 2009-2015 Free Software Foundation, Inc.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+   This program is free software: you can redistribute it and/or modify
Ondrej Oprala 32b1e5
+   it under the terms of the GNU General Public License as published by
Ondrej Oprala 32b1e5
+   the Free Software Foundation; either version 3 of the License, or
Ondrej Oprala 32b1e5
+   (at your option) any later version.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+   This program is distributed in the hope that it will be useful,
Ondrej Oprala 32b1e5
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
Ondrej Oprala 32b1e5
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Ondrej Oprala 32b1e5
+   GNU General Public License for more details.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+   You should have received a copy of the GNU General Public License
Ondrej Oprala 32b1e5
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+/* Written by Mitsuru Chinen <mchinen@yamato.ibm.com>
Ondrej Oprala 32b1e5
+   and Bruno Haible <bruno@clisp.org>.  */
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+/* The macros in this file implement multi-byte character input from a
Ondrej Oprala 32b1e5
+   stream.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+   mb_file_t
Ondrej Oprala 32b1e5
+     is the type for multibyte character input stream, usable for variable
Ondrej Oprala 32b1e5
+     declarations.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+   mbf_char_t
Ondrej Oprala 32b1e5
+     is the type for multibyte character or EOF, usable for variable
Ondrej Oprala 32b1e5
+     declarations.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+   mbf_init (mbf, stream)
Ondrej Oprala 32b1e5
+     initializes the MB_FILE for reading from stream.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+   mbf_getc (mbc, mbf)
Ondrej Oprala 32b1e5
+     reads the next multibyte character from mbf and stores it in mbc.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+   mb_iseof (mbc)
Ondrej Oprala 32b1e5
+     returns true if mbc represents the EOF value.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+   Here are the function prototypes of the macros.
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+   extern void          mbf_init (mb_file_t mbf, FILE *stream);
Ondrej Oprala 32b1e5
+   extern void          mbf_getc (mbf_char_t mbc, mb_file_t mbf);
Ondrej Oprala 32b1e5
+   extern bool          mb_iseof (const mbf_char_t mbc);
Ondrej Oprala 32b1e5
+ */
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#ifndef _MBFILE_H
Ondrej Oprala 32b1e5
+#define _MBFILE_H 1
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#include <assert.h>
Ondrej Oprala 32b1e5
+#include <stdbool.h>
Ondrej Oprala 32b1e5
+#include <stdio.h>
Ondrej Oprala 32b1e5
+#include <string.h>
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
Ondrej Oprala 32b1e5
+   <wchar.h>.
Ondrej Oprala 32b1e5
+   BSD/OS 4.1 has a bug: <stdio.h> and <time.h> must be included before
Ondrej Oprala 32b1e5
+   <wchar.h>.  */
Ondrej Oprala 32b1e5
+#include <stdio.h>
Ondrej Oprala 32b1e5
+#include <time.h>
Ondrej Oprala 32b1e5
+#include <wchar.h>
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#include "mbchar.h"
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#ifndef _GL_INLINE_HEADER_BEGIN
Ondrej Oprala 32b1e5
+ #error "Please include config.h first."
Ondrej Oprala 32b1e5
+#endif
Ondrej Oprala 32b1e5
+_GL_INLINE_HEADER_BEGIN
Ondrej Oprala 32b1e5
+#ifndef MBFILE_INLINE
Ondrej Oprala 32b1e5
+# define MBFILE_INLINE _GL_INLINE
Ondrej Oprala 32b1e5
+#endif
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+struct mbfile_multi {
Ondrej Oprala 32b1e5
+  FILE *fp;
Ondrej Oprala 32b1e5
+  bool eof_seen;
Ondrej Oprala 32b1e5
+  bool have_pushback;
Ondrej Oprala 32b1e5
+  mbstate_t state;
Ondrej Oprala 32b1e5
+  unsigned int bufcount;
Ondrej Oprala 32b1e5
+  char buf[MBCHAR_BUF_SIZE];
Ondrej Oprala 32b1e5
+  struct mbchar pushback;
Ondrej Oprala 32b1e5
+};
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+MBFILE_INLINE void
Ondrej Oprala 32b1e5
+mbfile_multi_getc (struct mbchar *mbc, struct mbfile_multi *mbf)
Ondrej Oprala 32b1e5
+{
Ondrej Oprala 32b1e5
+  size_t bytes;
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+  /* If EOF has already been seen, don't use getc.  This matters if
Ondrej Oprala 32b1e5
+     mbf->fp is connected to an interactive tty.  */
Ondrej Oprala 32b1e5
+  if (mbf->eof_seen)
Ondrej Oprala 32b1e5
+    goto eof;
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+  /* Return character pushed back, if there is one.  */
Ondrej Oprala 32b1e5
+  if (mbf->have_pushback)
Ondrej Oprala 32b1e5
+    {
Ondrej Oprala 32b1e5
+      mb_copy (mbc, &mbf->pushback);
Ondrej Oprala 32b1e5
+      mbf->have_pushback = false;
Ondrej Oprala 32b1e5
+      return;
Ondrej Oprala 32b1e5
+    }
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+  /* Before using mbrtowc, we need at least one byte.  */
Ondrej Oprala 32b1e5
+  if (mbf->bufcount == 0)
Ondrej Oprala 32b1e5
+    {
Ondrej Oprala 32b1e5
+      int c = getc (mbf->fp);
Ondrej Oprala 32b1e5
+      if (c == EOF)
Ondrej Oprala 32b1e5
+        {
Ondrej Oprala 32b1e5
+          mbf->eof_seen = true;
Ondrej Oprala 32b1e5
+          goto eof;
Ondrej Oprala 32b1e5
+        }
Ondrej Oprala 32b1e5
+      mbf->buf[0] = (unsigned char) c;
Ondrej Oprala 32b1e5
+      mbf->bufcount++;
Ondrej Oprala 32b1e5
+    }
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+  /* Handle most ASCII characters quickly, without calling mbrtowc().  */
Ondrej Oprala 32b1e5
+  if (mbf->bufcount == 1 && mbsinit (&mbf->state) && is_basic (mbf->buf[0]))
Ondrej Oprala 32b1e5
+    {
Ondrej Oprala 32b1e5
+      /* These characters are part of the basic character set.  ISO C 99
Ondrej Oprala 32b1e5
+         guarantees that their wide character code is identical to their
Ondrej Oprala 32b1e5
+         char code.  */
Ondrej Oprala 32b1e5
+      mbc->wc = mbc->buf[0] = mbf->buf[0];
Ondrej Oprala 32b1e5
+      mbc->wc_valid = true;
Ondrej Oprala 32b1e5
+      mbc->ptr = &mbc->buf[0];
Ondrej Oprala 32b1e5
+      mbc->bytes = 1;
Ondrej Oprala 32b1e5
+      mbf->bufcount = 0;
Ondrej Oprala 32b1e5
+      return;
Ondrej Oprala 32b1e5
+    }
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+  /* Use mbrtowc on an increasing number of bytes.  Read only as many bytes
Ondrej Oprala 32b1e5
+     from mbf->fp as needed.  This is needed to give reasonable interactive
Ondrej Oprala 32b1e5
+     behaviour when mbf->fp is connected to an interactive tty.  */
Ondrej Oprala 32b1e5
+  for (;;)
Ondrej Oprala 32b1e5
+    {
Ondrej Oprala 32b1e5
+      /* We don't know whether the 'mbrtowc' function updates the state when
Ondrej Oprala 32b1e5
+         it returns -2, - this is the ISO C 99 and glibc-2.2 behaviour - or
Ondrej Oprala 32b1e5
+         not - amended ANSI C, glibc-2.1 and Solaris 2.7 behaviour.  We
Ondrej Oprala 32b1e5
+         don't have an autoconf test for this, yet.
Ondrej Oprala 32b1e5
+         The new behaviour would allow us to feed the bytes one by one into
Ondrej Oprala 32b1e5
+         mbrtowc.  But the old behaviour forces us to feed all bytes since
Ondrej Oprala 32b1e5
+         the end of the last character into mbrtowc.  Since we want to retry
Ondrej Oprala 32b1e5
+         with more bytes when mbrtowc returns -2, we must backup the state
Ondrej Oprala 32b1e5
+         before calling mbrtowc, because implementations with the new
Ondrej Oprala 32b1e5
+         behaviour will clobber it.  */
Ondrej Oprala 32b1e5
+      mbstate_t backup_state = mbf->state;
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+      bytes = mbrtowc (&mbc->wc, &mbf->buf[0], mbf->bufcount, &mbf->state);
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+      if (bytes == (size_t) -1)
Ondrej Oprala 32b1e5
+        {
Ondrej Oprala 32b1e5
+          /* An invalid multibyte sequence was encountered.  */
Ondrej Oprala 32b1e5
+          /* Return a single byte.  */
Ondrej Oprala 32b1e5
+          bytes = 1;
Ondrej Oprala 32b1e5
+          mbc->wc_valid = false;
Ondrej Oprala 32b1e5
+          break;
Ondrej Oprala 32b1e5
+        }
Ondrej Oprala 32b1e5
+      else if (bytes == (size_t) -2)
Ondrej Oprala 32b1e5
+        {
Ondrej Oprala 32b1e5
+          /* An incomplete multibyte character.  */
Ondrej Oprala 32b1e5
+          mbf->state = backup_state;
Ondrej Oprala 32b1e5
+          if (mbf->bufcount == MBCHAR_BUF_SIZE)
Ondrej Oprala 32b1e5
+            {
Ondrej Oprala 32b1e5
+              /* An overlong incomplete multibyte sequence was encountered.  */
Ondrej Oprala 32b1e5
+              /* Return a single byte.  */
Ondrej Oprala 32b1e5
+              bytes = 1;
Ondrej Oprala 32b1e5
+              mbc->wc_valid = false;
Ondrej Oprala 32b1e5
+              break;
Ondrej Oprala 32b1e5
+            }
Ondrej Oprala 32b1e5
+          else
Ondrej Oprala 32b1e5
+            {
Ondrej Oprala 32b1e5
+              /* Read one more byte and retry mbrtowc.  */
Ondrej Oprala 32b1e5
+              int c = getc (mbf->fp);
Ondrej Oprala 32b1e5
+              if (c == EOF)
Ondrej Oprala 32b1e5
+                {
Ondrej Oprala 32b1e5
+                  /* An incomplete multibyte character at the end.  */
Ondrej Oprala 32b1e5
+                  mbf->eof_seen = true;
Ondrej Oprala 32b1e5
+                  bytes = mbf->bufcount;
Ondrej Oprala 32b1e5
+                  mbc->wc_valid = false;
Ondrej Oprala 32b1e5
+                  break;
Ondrej Oprala 32b1e5
+                }
Ondrej Oprala 32b1e5
+              mbf->buf[mbf->bufcount] = (unsigned char) c;
Ondrej Oprala 32b1e5
+              mbf->bufcount++;
Ondrej Oprala 32b1e5
+            }
Ondrej Oprala 32b1e5
+        }
Ondrej Oprala 32b1e5
+      else
Ondrej Oprala 32b1e5
+        {
Ondrej Oprala 32b1e5
+          if (bytes == 0)
Ondrej Oprala 32b1e5
+            {
Ondrej Oprala 32b1e5
+              /* A null wide character was encountered.  */
Ondrej Oprala 32b1e5
+              bytes = 1;
Ondrej Oprala 32b1e5
+              assert (mbf->buf[0] == '\0');
Ondrej Oprala 32b1e5
+              assert (mbc->wc == 0);
Ondrej Oprala 32b1e5
+            }
Ondrej Oprala 32b1e5
+          mbc->wc_valid = true;
Ondrej Oprala 32b1e5
+          break;
Ondrej Oprala 32b1e5
+        }
Ondrej Oprala 32b1e5
+    }
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+  /* Return the multibyte sequence mbf->buf[0..bytes-1].  */
Ondrej Oprala 32b1e5
+  mbc->ptr = &mbc->buf[0];
Ondrej Oprala 32b1e5
+  memcpy (&mbc->buf[0], &mbf->buf[0], bytes);
Ondrej Oprala 32b1e5
+  mbc->bytes = bytes;
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+  mbf->bufcount -= bytes;
Ondrej Oprala 32b1e5
+  if (mbf->bufcount > 0)
Ondrej Oprala 32b1e5
+    {
Ondrej Oprala 32b1e5
+      /* It's not worth calling memmove() for so few bytes.  */
Ondrej Oprala 32b1e5
+      unsigned int count = mbf->bufcount;
Ondrej Oprala 32b1e5
+      char *p = &mbf->buf[0];
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+      do
Ondrej Oprala 32b1e5
+        {
Ondrej Oprala 32b1e5
+          *p = *(p + bytes);
Ondrej Oprala 32b1e5
+          p++;
Ondrej Oprala 32b1e5
+        }
Ondrej Oprala 32b1e5
+      while (--count > 0);
Ondrej Oprala 32b1e5
+    }
Ondrej Oprala 32b1e5
+  return;
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+eof:
Ondrej Oprala 32b1e5
+  /* An mbchar_t with bytes == 0 is used to indicate EOF.  */
Ondrej Oprala 32b1e5
+  mbc->ptr = NULL;
Ondrej Oprala 32b1e5
+  mbc->bytes = 0;
Ondrej Oprala 32b1e5
+  mbc->wc_valid = false;
Ondrej Oprala 32b1e5
+  return;
Ondrej Oprala 32b1e5
+}
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+MBFILE_INLINE void
Ondrej Oprala 32b1e5
+mbfile_multi_ungetc (const struct mbchar *mbc, struct mbfile_multi *mbf)
Ondrej Oprala 32b1e5
+{
Ondrej Oprala 32b1e5
+  mb_copy (&mbf->pushback, mbc);
Ondrej Oprala 32b1e5
+  mbf->have_pushback = true;
Ondrej Oprala 32b1e5
+}
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+typedef struct mbfile_multi mb_file_t;
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+typedef mbchar_t mbf_char_t;
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#define mbf_init(mbf, stream)                                           \
Ondrej Oprala 32b1e5
+  ((mbf).fp = (stream),                                                 \
Ondrej Oprala 32b1e5
+   (mbf).eof_seen = false,                                              \
Ondrej Oprala 32b1e5
+   (mbf).have_pushback = false,                                         \
Ondrej Oprala 32b1e5
+   memset (&(mbf).state, '\0', sizeof (mbstate_t)),                     \
Ondrej Oprala 32b1e5
+   (mbf).bufcount = 0)
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#define mbf_getc(mbc, mbf) mbfile_multi_getc (&(mbc), &(mbf))
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#define mbf_ungetc(mbc, mbf) mbfile_multi_ungetc (&(mbc), &(mbf))
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#define mb_iseof(mbc) ((mbc).bytes == 0)
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#ifndef _GL_INLINE_HEADER_BEGIN
Ondrej Oprala 32b1e5
+ #error "Please include config.h first."
Ondrej Oprala 32b1e5
+#endif
Ondrej Oprala 32b1e5
+_GL_INLINE_HEADER_BEGIN
Ondrej Oprala 32b1e5
+
Ondrej Oprala 32b1e5
+#endif /* _MBFILE_H */