From mboxrd@z Thu Jan 1 00:00:00 1970 From: Stefan Schantl To: development@lists.ipfire.org Subject: [PATCH] coreutils: Update to 8.31 Date: Fri, 21 Jun 2019 23:02:42 +0200 Message-ID: <20190621210242.6986-1-stefan.schantl@ipfire.org> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============3885591788525960139==" List-Id: --===============3885591788525960139== Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Signed-off-by: Stefan Schantl --- coreutils/coreutils.nm | 8 +- .../patches/coreutils-i18n-cut-old.patch | 565 ++++++++++++ .../coreutils-i18n-expand-unexpand.patch | 848 ++++++++++++++++++ .../patches/coreutils-i18n-fix-unexpand.patch | 28 + .../coreutils-i18n-fix2-expand-unexpand.patch | 108 +++ .../patches/coreutils-i18n-fold-newline.patch | 80 ++ .../patches/coreutils-i18n-sort-human.patch | 35 + .../coreutils-i18n-un-expand-BOM.patch | 456 ++++++++++ coreutils/patches/coreutils-i18n.patch | 190 ++-- 9 files changed, 2208 insertions(+), 110 deletions(-) create mode 100644 coreutils/patches/coreutils-i18n-cut-old.patch create mode 100644 coreutils/patches/coreutils-i18n-expand-unexpand.patch create mode 100644 coreutils/patches/coreutils-i18n-fix-unexpand.patch create mode 100644 coreutils/patches/coreutils-i18n-fix2-expand-unexpand.pat= ch create mode 100644 coreutils/patches/coreutils-i18n-fold-newline.patch create mode 100644 coreutils/patches/coreutils-i18n-sort-human.patch create mode 100644 coreutils/patches/coreutils-i18n-un-expand-BOM.patch diff --git a/coreutils/coreutils.nm b/coreutils/coreutils.nm index a85b6a872..026bc14da 100644 --- a/coreutils/coreutils.nm +++ b/coreutils/coreutils.nm @@ -4,7 +4,7 @@ ############################################################################= ### =20 name =3D coreutils -version =3D 8.30 +version =3D 8.31 release =3D 1 =20 groups =3D System/Base @@ -23,7 +23,7 @@ sources =3D %{thisapp}.tar.xz build requires autoconf - automake + automake >=3D 1.15 e2fsprogs-devel gettext-devel gmp-devel @@ -43,6 +43,10 @@ build --enable-no-install-program=3Dhostname,kill,uptime \ --with-tty-group =20 + prepare_cmds + autoreconf -vfi + end + test make check RUN_VERY_EXPENSIVE_TESTS=3Dyes || true end diff --git a/coreutils/patches/coreutils-i18n-cut-old.patch b/coreutils/patch= es/coreutils-i18n-cut-old.patch new file mode 100644 index 000000000..757ee0fbb --- /dev/null +++ b/coreutils/patches/coreutils-i18n-cut-old.patch @@ -0,0 +1,565 @@ +diff --git a/src/cut.c b/src/cut.c +index 7ab6be4..022d0ad 100644 +--- a/src/cut.c ++++ b/src/cut.c +@@ -28,6 +28,11 @@ + #include + #include + #include ++ ++/* Get mbstate_t, mbrtowc(). */ ++#if HAVE_WCHAR_H ++# include ++#endif + #include "system.h" +=20 + #include "error.h" +@@ -38,6 +43,18 @@ +=20 + #include "set-fields.h" +=20 ++/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC ++ installation; work around this configuration error. */ ++#if !defined MB_LEN_MAX || MB_LEN_MAX < 2 ++# undef MB_LEN_MAX ++# define MB_LEN_MAX 16 ++#endif ++ ++/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ ++#if HAVE_MBRTOWC && defined mbstate_t ++# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) ++#endif ++ + /* The official name of this program (e.g., no 'g' prefix). */ + #define PROGRAM_NAME "cut" +=20 +@@ -54,6 +71,52 @@ + } \ + while (0) +=20 ++/* Refill the buffer BUF to get a multibyte character. */ ++#define REFILL_BUFFER(BUF, BUFPOS, BUFLEN, STREAM) \ ++ do = \ ++ { = \ ++ if (BUFLEN < MB_LEN_MAX && !feof (STREAM) && !ferror (STREAM)) = \ ++ { \ ++ memmove (BUF, BUFPOS, BUFLEN); \ ++ BUFLEN +=3D fread (BUF + BUFLEN, sizeof(char), BUFSIZ, STREAM); \ ++ BUFPOS =3D BUF; = \ ++ } \ ++ } = \ ++ while (0) ++ ++/* Get wide character on BUFPOS. BUFPOS is not included after that. ++ If byte sequence is not valid as a character, CONVFAIL is true. Otherwis= e false. */ ++#define GET_NEXT_WC_FROM_BUFFER(WC, BUFPOS, BUFLEN, MBLENGTH, STATE, CONVFA= IL) \ ++ do = \ ++ { = \ ++ mbstate_t state_bak; \ ++ \ ++ if (BUFLEN < 1) = \ ++ { \ ++ WC =3D WEOF; = \ ++ break; \ ++ } \ ++ \ ++ /* Get a wide character. */ \ ++ CONVFAIL =3D false; = \ ++ state_bak =3D STATE; \ ++ MBLENGTH =3D mbrtowc ((wchar_t *)&WC, BUFPOS, BUFLEN, &STATE); = \ ++ \ ++ switch (MBLENGTH) = \ ++ { \ ++ case (size_t)-1: \ ++ case (size_t)-2: \ ++ CONVFAIL =3D true; = \ ++ STATE =3D state_bak; = \ ++ /* Fall througn. */ = \ ++ \ ++ case 0: = \ ++ MBLENGTH =3D 1; = \ ++ break; \ ++ } \ ++ } = \ ++ while (0) ++ +=20 + /* Pointer inside RP. When checking if a byte or field is selected + by a finite range, we check if it is between CURRENT_RP.LO +@@ -61,6 +124,9 @@ + CURRENT_RP.HI then we make CURRENT_RP to point to the next range pair. */ + static struct field_range_pair *current_rp; +=20 ++/* Length of the delimiter given as argument to -d. */ ++size_t delimlen; ++ + /* This buffer is used to support the semantics of the -s option + (or lack of same) when the specified field list includes (does + not include) the first field. In both of those cases, the entire +@@ -77,15 +143,25 @@ enum operating_mode + { + undefined_mode, +=20 +- /* Output characters that are in the given bytes. */ ++ /* Output bytes that are at the given positions. */ + byte_mode, +=20 ++ /* Output characters that are at the given positions. */ ++ character_mode, ++ + /* Output the given delimiter-separated fields. */ + field_mode + }; +=20 + static enum operating_mode operating_mode; +=20 ++/* If nonzero, when in byte mode, don't split multibyte characters. */ ++static int byte_mode_character_aware; ++ ++/* If nonzero, the function for single byte locale is work ++ if this program runs on multibyte locale. */ ++static int force_singlebyte_mode; ++ + /* If true do not output lines containing no delimiter characters. + Otherwise, all such lines are printed. This option is valid only + with field mode. */ +@@ -97,6 +173,9 @@ static bool complement; +=20 + /* The delimiter character for field mode. */ + static unsigned char delim; ++#if HAVE_WCHAR_H ++static wchar_t wcdelim; ++#endif +=20 + /* The delimiter for each line/record. */ + static unsigned char line_delim =3D '\n'; +@@ -164,7 +243,7 @@ Print selected parts of lines from each FILE to standard= output.\n\ + -f, --fields=3DLIST select only these fields; also print any line\= n\ + that contains no delimiter character, unless\n\ + the -s option is specified\n\ +- -n (ignored)\n\ ++ -n with -b: don't split multibyte characters\n\ + "), stdout); + fputs (_("\ + --complement complement the set of selected bytes, characters\= n\ +@@ -280,6 +359,82 @@ cut_bytes (FILE *stream) + } + } +=20 ++#if HAVE_MBRTOWC ++/* This function is in use for the following case. ++ ++ 1. Read from the stream STREAM, printing to standard output any selected ++ characters. ++ ++ 2. Read from stream STREAM, printing to standard output any selected byt= es, ++ without splitting multibyte characters. */ ++ ++static void ++cut_characters_or_cut_bytes_no_split (FILE *stream) ++{ ++ uintmax_t idx; /* number of bytes or characters in the line s= o far. */ ++ char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ ++ char *bufpos; /* Next read position of BUF. */ ++ size_t buflen; /* The length of the byte sequence in buf. */ ++ wint_t wc; /* A gotten wide character. */ ++ size_t mblength; /* The byte size of a multibyte character which s= hows ++ as same character as WC. */ ++ mbstate_t state; /* State of the stream. */ ++ bool convfail =3D false; /* true, when conversion failed. Otherwise fals= e. */ ++ /* Whether to begin printing delimiters between ranges for the current li= ne. ++ Set after we've begun printing data corresponding to the first range. = */ ++ bool print_delimiter =3D false; ++ ++ idx =3D 0; ++ buflen =3D 0; ++ bufpos =3D buf; ++ memset (&state, '\0', sizeof(mbstate_t)); ++ ++ current_rp =3D frp; ++ ++ while (1) ++ { ++ REFILL_BUFFER (buf, bufpos, buflen, stream); ++ ++ GET_NEXT_WC_FROM_BUFFER (wc, bufpos, buflen, mblength, state, convfai= l); ++ (void) convfail; /* ignore unused */ ++ ++ if (wc =3D=3D WEOF) ++ { ++ if (idx > 0) ++ putchar (line_delim); ++ break; ++ } ++ else if (wc =3D=3D line_delim) ++ { ++ putchar (line_delim); ++ idx =3D 0; ++ print_delimiter =3D false; ++ current_rp =3D frp; ++ } ++ else ++ { ++ next_item (&idx); ++ if (print_kth (idx)) ++ { ++ if (output_delimiter_specified) ++ { ++ if (print_delimiter && is_range_start_index (idx)) ++ { ++ fwrite (output_delimiter_string, sizeof (char), ++ output_delimiter_length, stdout); ++ } ++ print_delimiter =3D true; ++ } ++ fwrite (bufpos, mblength, sizeof(char), stdout); ++ } ++ } ++ ++ buflen -=3D mblength; ++ bufpos +=3D mblength; ++ } ++} ++#endif ++ + /* Read from stream STREAM, printing to standard output any selected fields= . */ +=20 + static void +@@ -425,13 +580,211 @@ cut_fields (FILE *stream) + } + } +=20 ++#if HAVE_MBRTOWC ++static void ++cut_fields_mb (FILE *stream) ++{ ++ int c; ++ uintmax_t field_idx; ++ int found_any_selected_field; ++ int buffer_first_field; ++ int empty_input; ++ char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ ++ char *bufpos; /* Next read position of BUF. */ ++ size_t buflen; /* The length of the byte sequence in buf. */ ++ wint_t wc =3D 0; /* A gotten wide character. */ ++ size_t mblength; /* The byte size of a multibyte character which s= hows ++ as same character as WC. */ ++ mbstate_t state; /* State of the stream. */ ++ bool convfail =3D false; /* true, when conversion failed. Otherwise fals= e. */ ++ ++ current_rp =3D frp; ++ ++ found_any_selected_field =3D 0; ++ field_idx =3D 1; ++ bufpos =3D buf; ++ buflen =3D 0; ++ memset (&state, '\0', sizeof(mbstate_t)); ++ ++ c =3D getc (stream); ++ empty_input =3D (c =3D=3D EOF); ++ if (c !=3D EOF) ++ { ++ ungetc (c, stream); ++ wc =3D 0; ++ } ++ else ++ wc =3D WEOF; ++ ++ /* To support the semantics of the -s flag, we may have to buffer ++ all of the first field to determine whether it is `delimited.' ++ But that is unnecessary if all non-delimited lines must be printed ++ and the first field has been selected, or if non-delimited lines ++ must be suppressed and the first field has *not* been selected. ++ That is because a non-delimited line has exactly one field. */ ++ buffer_first_field =3D (suppress_non_delimited ^ !print_kth (1)); ++ ++ while (1) ++ { ++ if (field_idx =3D=3D 1 && buffer_first_field) ++ { ++ int len =3D 0; ++ ++ while (1) ++ { ++ REFILL_BUFFER (buf, bufpos, buflen, stream); ++ ++ GET_NEXT_WC_FROM_BUFFER ++ (wc, bufpos, buflen, mblength, state, convfail); ++ ++ if (wc =3D=3D WEOF) ++ break; ++ ++ field_1_buffer =3D xrealloc (field_1_buffer, len + mblength); ++ memcpy (field_1_buffer + len, bufpos, mblength); ++ len +=3D mblength; ++ buflen -=3D mblength; ++ bufpos +=3D mblength; ++ ++ if (!convfail && (wc =3D=3D line_delim || wc =3D=3D wcdelim)) ++ break; ++ } ++ ++ if (len <=3D 0 && wc =3D=3D WEOF) ++ break; ++ ++ /* If the first field extends to the end of line (it is not ++ delimited) and we are printing all non-delimited lines, ++ print this one. */ ++ if (convfail || (!convfail && wc !=3D wcdelim)) ++ { ++ if (suppress_non_delimited) ++ { ++ /* Empty. */ ++ } ++ else ++ { ++ fwrite (field_1_buffer, sizeof (char), len, stdout); ++ /* Make sure the output line is newline terminated. */ ++ if (convfail || (!convfail && wc !=3D line_delim)) ++ putchar (line_delim); ++ } ++ continue; ++ } ++ ++ if (print_kth (1)) ++ { ++ /* Print the field, but not the trailing delimiter. */ ++ fwrite (field_1_buffer, sizeof (char), len - 1, stdout); ++ found_any_selected_field =3D 1; ++ } ++ next_item (&field_idx); ++ } ++ ++ if (wc !=3D WEOF) ++ { ++ if (print_kth (field_idx)) ++ { ++ if (found_any_selected_field) ++ { ++ fwrite (output_delimiter_string, sizeof (char), ++ output_delimiter_length, stdout); ++ } ++ found_any_selected_field =3D 1; ++ } ++ ++ while (1) ++ { ++ REFILL_BUFFER (buf, bufpos, buflen, stream); ++ ++ GET_NEXT_WC_FROM_BUFFER ++ (wc, bufpos, buflen, mblength, state, convfail); ++ ++ if (wc =3D=3D WEOF) ++ break; ++ else if (!convfail && (wc =3D=3D wcdelim || wc =3D=3D line_de= lim)) ++ { ++ buflen -=3D mblength; ++ bufpos +=3D mblength; ++ break; ++ } ++ ++ if (print_kth (field_idx)) ++ fwrite (bufpos, mblength, sizeof(char), stdout); ++ ++ buflen -=3D mblength; ++ bufpos +=3D mblength; ++ } ++ } ++ ++ if ((!convfail || wc =3D=3D line_delim) && buflen < 1) ++ wc =3D WEOF; ++ ++ if (!convfail && wc =3D=3D wcdelim) ++ next_item (&field_idx); ++ else if (wc =3D=3D WEOF || (!convfail && wc =3D=3D line_delim)) ++ { ++ if (found_any_selected_field ++ || (!empty_input && !(suppress_non_delimited && field_idx =3D= =3D 1))) ++ putchar (line_delim); ++ if (wc =3D=3D WEOF) ++ break; ++ field_idx =3D 1; ++ current_rp =3D frp; ++ found_any_selected_field =3D 0; ++ } ++ } ++} ++#endif ++ + static void + cut_stream (FILE *stream) + { +- if (operating_mode =3D=3D byte_mode) +- cut_bytes (stream); ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1 && !force_singlebyte_mode) ++ { ++ switch (operating_mode) ++ { ++ case byte_mode: ++ if (byte_mode_character_aware) ++ cut_characters_or_cut_bytes_no_split (stream); ++ else ++ cut_bytes (stream); ++ break; ++ ++ case character_mode: ++ cut_characters_or_cut_bytes_no_split (stream); ++ break; ++ ++ case field_mode: ++ if (delimlen =3D=3D 1) ++ { ++ /* Check if we have utf8 multibyte locale, so we can use this ++ optimization because of uniqueness of characters, which is ++ not true for e.g. SJIS */ ++ char * loc =3D setlocale(LC_CTYPE, NULL); ++ if (loc && (strstr (loc, "UTF-8") || strstr (loc, "utf-8") || ++ strstr (loc, "UTF8") || strstr (loc, "utf8"))) ++ { ++ cut_fields (stream); ++ break; ++ } ++ } ++ cut_fields_mb (stream); ++ break; ++ ++ default: ++ abort (); ++ } ++ } + else +- cut_fields (stream); ++#endif ++ { ++ if (operating_mode =3D=3D field_mode) ++ cut_fields (stream); ++ else ++ cut_bytes (stream); ++ } + } +=20 + /* Process file FILE to standard output. +@@ -483,6 +836,7 @@ main (int argc, char **argv) + bool ok; + bool delim_specified =3D false; + char *spec_list_string IF_LINT ( =3D NULL); ++ char mbdelim[MB_LEN_MAX + 1]; +=20 + initialize_main (&argc, &argv); + set_program_name (argv[0]); +@@ -505,7 +859,6 @@ main (int argc, char **argv) + switch (optc) + { + case 'b': +- case 'c': + /* Build the byte list. */ + if (operating_mode !=3D undefined_mode) + FATAL_ERROR (_("only one type of list may be specified")); +@@ -513,6 +866,14 @@ main (int argc, char **argv) + spec_list_string =3D optarg; + break; +=20 ++ case 'c': ++ /* Build the character list. */ ++ if (operating_mode !=3D undefined_mode) ++ FATAL_ERROR (_("only one type of list may be specified")); ++ operating_mode =3D character_mode; ++ spec_list_string =3D optarg; ++ break; ++ + case 'f': + /* Build the field list. */ + if (operating_mode !=3D undefined_mode) +@@ -524,10 +885,38 @@ main (int argc, char **argv) + case 'd': + /* New delimiter. */ + /* Interpret -d '' to mean 'use the NUL byte as the delimiter.' = */ +- if (optarg[0] !=3D '\0' && optarg[1] !=3D '\0') +- FATAL_ERROR (_("the delimiter must be a single character")); +- delim =3D optarg[0]; +- delim_specified =3D true; ++ { ++#if HAVE_MBRTOWC ++ if(MB_CUR_MAX > 1) ++ { ++ mbstate_t state; ++ ++ memset (&state, '\0', sizeof(mbstate_t)); ++ delimlen =3D mbrtowc (&wcdelim, optarg, strnlen(optarg, M= B_LEN_MAX), &state); ++ ++ if (delimlen =3D=3D (size_t)-1 || delimlen =3D=3D (size_t= )-2) ++ ++force_singlebyte_mode; ++ else ++ { ++ delimlen =3D (delimlen < 1) ? 1 : delimlen; ++ if (wcdelim !=3D L'\0' && *(optarg + delimlen) !=3D '= \0') ++ FATAL_ERROR (_("the delimiter must be a single char= acter")); ++ memcpy (mbdelim, optarg, delimlen); ++ mbdelim[delimlen] =3D '\0'; ++ if (delimlen =3D=3D 1) ++ delim =3D *optarg; ++ } ++ } ++ ++ if (MB_CUR_MAX <=3D 1 || force_singlebyte_mode) ++#endif ++ { ++ if (optarg[0] !=3D '\0' && optarg[1] !=3D '\0') ++ FATAL_ERROR (_("the delimiter must be a single characte= r")); ++ delim =3D (unsigned char) optarg[0]; ++ } ++ delim_specified =3D true; ++ } + break; +=20 + case OUTPUT_DELIMITER_OPTION: +@@ -540,6 +929,7 @@ main (int argc, char **argv) + break; +=20 + case 'n': ++ byte_mode_character_aware =3D 1; + break; +=20 + case 's': +@@ -579,15 +969,34 @@ main (int argc, char **argv) + | (complement ? SETFLD_COMPLEMENT : 0) ); +=20 + if (!delim_specified) +- delim =3D '\t'; ++ { ++ delim =3D '\t'; ++#ifdef HAVE_MBRTOWC ++ wcdelim =3D L'\t'; ++ mbdelim[0] =3D '\t'; ++ mbdelim[1] =3D '\0'; ++ delimlen =3D 1; ++#endif ++ } +=20 + if (output_delimiter_string =3D=3D NULL) + { +- static char dummy[2]; +- dummy[0] =3D delim; +- dummy[1] =3D '\0'; +- output_delimiter_string =3D dummy; +- output_delimiter_length =3D 1; ++#ifdef HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1 && !force_singlebyte_mode) ++ { ++ output_delimiter_string =3D xstrdup(mbdelim); ++ output_delimiter_length =3D delimlen; ++ } ++ ++ if (MB_CUR_MAX <=3D 1 || force_singlebyte_mode) ++#endif ++ { ++ static char dummy[2]; ++ dummy[0] =3D delim; ++ dummy[1] =3D '\0'; ++ output_delimiter_string =3D dummy; ++ output_delimiter_length =3D 1; ++ } + } +=20 + if (optind =3D=3D argc) diff --git a/coreutils/patches/coreutils-i18n-expand-unexpand.patch b/coreuti= ls/patches/coreutils-i18n-expand-unexpand.patch new file mode 100644 index 000000000..b5f571f5f --- /dev/null +++ b/coreutils/patches/coreutils-i18n-expand-unexpand.patch @@ -0,0 +1,848 @@ +From e87ab5b991b08092a7e07af82b3ec822a8604151 Mon Sep 17 00:00:00 2001 +From: Ondrej Oprala +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=3DUTF-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=C3=A1draig Brady +--- + 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=3D" + 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 +=20 ++gl_MBFILE ++ + gl_HEADER_TIOCGWINSZ_IN_TERMIOS_H +=20 + if test $gl_cv_sys_tiocgwinsz_needs_termios_h =3D 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 ++#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 . */ ++ ++/* Written by Mitsuru Chinen ++ and Bruno Haible . */ ++ ++/* 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 ++#include ++#include ++#include ++ ++/* Tru64 with Desktop Toolkit C has a bug: must be included before ++ . ++ BSD/OS 4.1 has a bug: and must be included before ++ . */ ++#include ++#include ++#include ++ ++#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 =3D false; ++ return; ++ } ++ ++ /* Before using mbrtowc, we need at least one byte. */ ++ if (mbf->bufcount =3D=3D 0) ++ { ++ int c =3D getc (mbf->fp); ++ if (c =3D=3D EOF) ++ { ++ mbf->eof_seen =3D true; ++ goto eof; ++ } ++ mbf->buf[0] =3D (unsigned char) c; ++ mbf->bufcount++; ++ } ++ ++ /* Handle most ASCII characters quickly, without calling mbrtowc(). */ ++ if (mbf->bufcount =3D=3D 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 =3D mbc->buf[0] =3D mbf->buf[0]; ++ mbc->wc_valid =3D true; ++ mbc->ptr =3D &mbc->buf[0]; ++ mbc->bytes =3D 1; ++ mbf->bufcount =3D 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 =3D mbf->state; ++ ++ bytes =3D mbrtowc (&mbc->wc, &mbf->buf[0], mbf->bufcount, &mbf->state= ); ++ ++ if (bytes =3D=3D (size_t) -1) ++ { ++ /* An invalid multibyte sequence was encountered. */ ++ /* Return a single byte. */ ++ bytes =3D 1; ++ mbc->wc_valid =3D false; ++ break; ++ } ++ else if (bytes =3D=3D (size_t) -2) ++ { ++ /* An incomplete multibyte character. */ ++ mbf->state =3D backup_state; ++ if (mbf->bufcount =3D=3D MBCHAR_BUF_SIZE) ++ { ++ /* An overlong incomplete multibyte sequence was encountered.= */ ++ /* Return a single byte. */ ++ bytes =3D 1; ++ mbc->wc_valid =3D false; ++ break; ++ } ++ else ++ { ++ /* Read one more byte and retry mbrtowc. */ ++ int c =3D getc (mbf->fp); ++ if (c =3D=3D EOF) ++ { ++ /* An incomplete multibyte character at the end. */ ++ mbf->eof_seen =3D true; ++ bytes =3D mbf->bufcount; ++ mbc->wc_valid =3D false; ++ break; ++ } ++ mbf->buf[mbf->bufcount] =3D (unsigned char) c; ++ mbf->bufcount++; ++ } ++ } ++ else ++ { ++ if (bytes =3D=3D 0) ++ { ++ /* A null wide character was encountered. */ ++ bytes =3D 1; ++ assert (mbf->buf[0] =3D=3D '\0'); ++ assert (mbc->wc =3D=3D 0); ++ } ++ mbc->wc_valid =3D true; ++ break; ++ } ++ } ++ ++ /* Return the multibyte sequence mbf->buf[0..bytes-1]. */ ++ mbc->ptr =3D &mbc->buf[0]; ++ memcpy (&mbc->buf[0], &mbf->buf[0], bytes); ++ mbc->bytes =3D bytes; ++ ++ mbf->bufcount -=3D bytes; ++ if (mbf->bufcount > 0) ++ { ++ /* It's not worth calling memmove() for so few bytes. */ ++ unsigned int count =3D mbf->bufcount; ++ char *p =3D &mbf->buf[0]; ++ ++ do ++ { ++ *p =3D *(p + bytes); ++ p++; ++ } ++ while (--count > 0); ++ } ++ return; ++ ++eof: ++ /* An mbchar_t with bytes =3D=3D 0 is used to indicate EOF. */ ++ mbc->ptr =3D NULL; ++ mbc->bytes =3D 0; ++ mbc->wc_valid =3D false; ++ return; ++} ++ ++MBFILE_INLINE void ++mbfile_multi_ungetc (const struct mbchar *mbc, struct mbfile_multi *mbf) ++{ ++ mb_copy (&mbf->pushback, mbc); ++ mbf->have_pushback =3D true; ++} ++ ++typedef struct mbfile_multi mb_file_t; ++ ++typedef mbchar_t mbf_char_t; ++ ++#define mbf_init(mbf, stream) \ ++ ((mbf).fp =3D (stream), \ ++ (mbf).eof_seen =3D false, \ ++ (mbf).have_pushback =3D false, \ ++ memset (&(mbf).state, '\0', sizeof (mbstate_t)), \ ++ (mbf).bufcount =3D 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 =3D=3D 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 + #include + #include ++ ++#include ++ + #include "system.h" + #include "die.h" + #include "xstrndup.h" +@@ -100,19 +103,19 @@ expand (void) + { + /* Input stream. */ + FILE *fp =3D next_file (NULL); ++ mb_file_t mbf; ++ mbf_char_t c; +=20 + if (!fp) + return; +=20 ++ mbf_init (mbf, fp); ++ + while (true) + { +- /* Input character, or EOF. */ +- int c; +- + /* If true, perform translations. */ + bool convert =3D true; +=20 +- + /* The following variables have valid values only when CONVERT + is true: */ +=20 +@@ -122,17 +125,23 @@ expand (void) + /* Index in TAB_LIST of next tab stop to examine. */ + size_t tab_index =3D 0; +=20 +- + /* Convert a line of text. */ +=20 + do + { +- while ((c =3D getc (fp)) < 0 && (fp =3D next_file (fp))) +- continue; ++ do { ++ mbf_getc (c, mbf); ++ if (mb_iseof (c)) ++ { ++ mbf_init (mbf, fp =3D next_file (fp)); ++ continue; ++ } ++ } ++ while (false); +=20 + if (convert) + { +- if (c =3D=3D '\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")); +=20 +- c =3D ' '; ++ mb_setascii (&c, ' '); + } +- else if (c =3D=3D '\b') ++ else if (mb_iseq (c, '\b')) + { + /* Go back one column, and force recalculation of the + next tab stop. */ + column -=3D !!column; + tab_index -=3D !!tab_index; + } +- else ++ /* A leading control character could make us trip over. */ ++ else if (!mb_iscntrl (c)) + { +- column++; ++ column +=3D mb_width (c); + if (!column) + die (EXIT_FAILURE, 0, _("input line is too long")); + } +=20 +- convert &=3D convert_entire_line || !! isblank (c); ++ convert &=3D convert_entire_line || mb_isblank (c); + } +=20 +- if (c < 0) ++ if (mb_iseof (c)) + return; +=20 +- if (putchar (c) < 0) ++ mb_putc (c, stdout); ++ if (ferror (stdout)) + die (EXIT_FAILURE, errno, _("write error")); + } +- while (c !=3D '\n'); ++ while (!mb_iseq (c, '\n')); + } + } +=20 +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 + #include + #include ++ ++#include ++ + #include "system.h" + #include "die.h" + #include "xstrndup.h" +@@ -107,11 +110,12 @@ unexpand (void) + { + /* Input stream. */ + FILE *fp =3D next_file (NULL); ++ mb_file_t mbf; +=20 + /* 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; +=20 + 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 =3D xmalloc (max_column_width); ++ pending_blank =3D xmalloc (max_column_width * sizeof (mbf_char_t)); ++ ++ mbf_init (mbf, fp); +=20 + while (true) + { + /* Input character, or EOF. */ +- int c; ++ mbf_char_t c; +=20 + /* If true, perform translations. */ + bool convert =3D true; +@@ -158,12 +164,19 @@ unexpand (void) +=20 + do + { +- while ((c =3D getc (fp)) < 0 && (fp =3D next_file (fp))) +- continue; ++ do { ++ mbf_getc (c, mbf); ++ if (mb_iseof (c)) ++ { ++ mbf_init (mbf, fp =3D next_file (fp)); ++ continue; ++ } ++ } ++ while (false); +=20 + if (convert) + { +- bool blank =3D !! isblank (c); ++ bool blank =3D mb_isblank (c); +=20 + if (blank) + { +@@ -180,16 +193,16 @@ unexpand (void) + if (next_tab_column < column) + die (EXIT_FAILURE, 0, _("input line is too long")); +=20 +- if (c =3D=3D '\t') ++ if (mb_iseq (c, '\t')) + { + column =3D next_tab_column; +=20 + if (pending) +- pending_blank[0] =3D '\t'; ++ mb_setascii (&pending_blank[0], '\t'); + } + else + { +- column++; ++ column +=3D mb_width (c); +=20 + if (! (prev_blank && column =3D=3D next_tab_colum= n)) + { +@@ -197,13 +210,14 @@ unexpand (void) + will be replaced by tabs. */ + if (column =3D=3D next_tab_column) + one_blank_before_tab_stop =3D true; +- pending_blank[pending++] =3D c; ++ mb_copy (&pending_blank[pending++], &c); + prev_blank =3D true; + continue; + } +=20 + /* Replace the pending blanks by a tab or two. */ +- pending_blank[0] =3D c =3D '\t'; ++ mb_setascii (&c, '\t'); ++ mb_setascii (&pending_blank[0], '\t'); + } +=20 + /* Discard pending blanks, unless it was a single +@@ -211,7 +225,7 @@ unexpand (void) + pending =3D one_blank_before_tab_stop; + } + } +- else if (c =3D=3D '\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 +=3D 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] =3D '\t'; +- if (fwrite (pending_blank, 1, pending, stdout) !=3D pendi= ng) ++ mb_setascii (&pending_blank[0], '\t'); ++ ++ for (int n =3D 0; n < pending; ++n) ++ mb_putc (pending_blank[n], stdout); ++ if (ferror (stdout)) + die (EXIT_FAILURE, errno, _("write error")); + pending =3D 0; + one_blank_before_tab_stop =3D false; +@@ -240,16 +257,17 @@ unexpand (void) + convert &=3D convert_entire_line || blank; + } +=20 +- if (c < 0) ++ if (mb_iseof (c)) + { + free (pending_blank); + return; + } +=20 +- if (putchar (c) < 0) ++ mb_putc (c, stdout); ++ if (ferror (stdout)) + die (EXIT_FAILURE, errno, _("write error")); + } +- while (c !=3D '\n'); ++ while (!mb_iseq (c, '\n')); + } + } +=20 +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 . ++ ++. "${srcdir=3D.}/tests/init.sh"; path_prepend_ ./src ++print_ver_ expand ++ ++export LC_ALL=3Den_US.UTF-8 ++ ++#input containing multibyte characters ++cat <<\EOF > in || framework_failure_ ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++=C3=A4 =C3=B6 =C3=BC =C3=9F ++. . . . ++EOF ++env printf ' =C3=A4=C3=B6=C3=BC\t. =C3=B6=C3=BC=C3=A4. \t=C3=A4 xx\n= ' >> in || framework_failure_ ++ ++cat <<\EOF > exp || framework_failure_ ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++=C3=A4 =C3=B6 =C3=BC =C3=9F ++. . . . ++ =C3=A4=C3=B6=C3=BC . =C3=B6=C3=BC=C3=A4. =C3=A4 xx ++EOF ++ ++expand < in > out || fail=3D1 ++compare exp out > /dev/null 2>&1 || fail=3D1 ++ ++#test characters with display widths !=3D 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=3D1 ++compare exp out > /dev/null 2>&1 || fail=3D1 ++ ++#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=3D1 ++compare in out > /dev/null 2>&1 || fail=3D1 ++ ++#non-Unicode characters interspersed between Unicode ones ++env printf '12345678 ++\t\xFF| ++\xFF\t| ++\t\xFF=C3=A4| ++=C3=A4\xFF\t| ++\t=C3=A4\xFF| ++\xFF\t=C3=A4| ++=C3=A4bcdef\xFF\t| ++' > in || framework_failure_ ++ ++env printf '12345678 ++ \xFF| ++\xFF | ++ \xFF=C3=A4| ++=C3=A4\xFF | ++ =C3=A4\xFF| ++\xFF =C3=A4| ++=C3=A4bcdef\xFF | ++' > exp || framework_failure_ ++ ++expand < in > out || fail=3D1 ++compare exp out > /dev/null 2>&1 || fail=3D1 ++ ++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 =3D \ + 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 =3D \ + tests/touch/read-only.sh \ + tests/touch/relative.sh \ + tests/touch/trailing-slash.sh \ ++ tests/unexpand/mb.sh \ + $(all_root_tests) +=20 + # 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 . ++ ++. "${srcdir=3D.}/tests/init.sh"; path_prepend_ ./src ++print_ver_ unexpand ++ ++export LC_ALL=3Den_US.UTF-8 ++ ++#input containing multibyte characters ++cat > in <<\EOF ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++=C3=A4 =C3=B6 =C3=BC =C3=9F ++. . . . ++ =C3=A4=C3=B6=C3=BC . =C3=B6=C3=BC=C3=A4. =C3=A4 xx ++EOF ++ ++cat > exp <<\EOF ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++=C3=A4 =C3=B6 =C3=BC =C3=9F ++. . . . ++ =C3=A4=C3=B6=C3=BC . =C3=B6=C3=BC=C3=A4. =C3=A4 xx ++EOF ++ ++unexpand -a < in > out || fail=3D1 ++compare exp out > /dev/null 2>&1 || fail=3D1 ++ ++#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=3D1 ++compare exp out > /dev/null 2>&1 || fail=3D1 ++ ++#test input where a blank of width > 1 is not being substituted ++in=3D"$(LC_ALL=3Den_US.UTF-8 printf ' \u3000 =C3=B6 =C3=BC =C3= =9F')" ++exp=3D' =E3=80=80 =C3=B6 =C3=BC =C3=9F' ++ ++unexpand -a < in > out || fail=3D1 ++compare exp out > /dev/null 2>&1 || fail=3D1 ++ ++#non-Unicode characters interspersed between Unicode ones ++env printf '12345678 ++ \xFF| ++\xFF | ++ \xFF=C3=A4| ++=C3=A4\xFF | ++ =C3=A4\xFF| ++\xFF =C3=A4| ++=C3=A4bcdef\xFF | ++' > in || framework_failure_ ++ ++env printf '12345678 ++\t\xFF| ++\xFF\t| ++\t\xFF=C3=A4| ++=C3=A4\xFF\t| ++\t=C3=A4\xFF| ++\xFF\t=C3=A4| ++=C3=A4bcdef\xFF\t| ++' > exp || framework_failure_ ++ ++unexpand -a < in > out || fail=3D1 ++compare exp out > /dev/null 2>&1 || fail=3D1 +--=20 +2.7.4 + diff --git a/coreutils/patches/coreutils-i18n-fix-unexpand.patch b/coreutils/= patches/coreutils-i18n-fix-unexpand.patch new file mode 100644 index 000000000..f0c347cd2 --- /dev/null +++ b/coreutils/patches/coreutils-i18n-fix-unexpand.patch @@ -0,0 +1,28 @@ +From 02424bfcd719bbaa695f4e1c3ef17ad91b0d23c0 Mon Sep 17 00:00:00 2001 +From: Lubomir Rintel +Date: Thu, 28 Jan 2016 20:57:22 +0100 +Subject: [PATCH] unexpand: fix blank line handling + + echo '' |./src/unexpand -a + +Really? +--- + src/unexpand.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/unexpand.c b/src/unexpand.c +index 569a7ee..3bbbd66 100644 +--- a/src/unexpand.c ++++ b/src/unexpand.c +@@ -233,7 +233,7 @@ unexpand (void) + next_tab_column =3D column; + tab_index -=3D !!tab_index; + } +- else ++ else if (!mb_iseq (c, '\n')) + { + column +=3D mb_width (c); + if (!column) +--=20 +2.7.4 + diff --git a/coreutils/patches/coreutils-i18n-fix2-expand-unexpand.patch b/co= reutils/patches/coreutils-i18n-fix2-expand-unexpand.patch new file mode 100644 index 000000000..b34d7b74f --- /dev/null +++ b/coreutils/patches/coreutils-i18n-fix2-expand-unexpand.patch @@ -0,0 +1,108 @@ +diff --git a/src/expand.c b/src/expand.c +index 380e020..310b349 100644 +--- a/src/expand.c ++++ b/src/expand.c +@@ -129,15 +129,19 @@ expand (void) +=20 + do + { +- do { ++ while (true) { + mbf_getc (c, mbf); +- if (mb_iseof (c)) ++ if ((mb_iseof (c)) && (fp =3D next_file (fp))) + { +- mbf_init (mbf, fp =3D next_file (fp)); ++ mbf_init (mbf, fp); + continue; + } ++ else ++ { ++ break; ++ } + } +- while (false); ++ +=20 + if (convert) + { +diff --git a/src/unexpand.c b/src/unexpand.c +index 3bbbd66..863a90a 100644 +--- a/src/unexpand.c ++++ b/src/unexpand.c +@@ -164,15 +164,19 @@ unexpand (void) +=20 + do + { +- do { ++ while (true) { + mbf_getc (c, mbf); +- if (mb_iseof (c)) ++ if ((mb_iseof (c)) && (fp =3D next_file (fp))) + { +- mbf_init (mbf, fp =3D next_file (fp)); ++ mbf_init (mbf, fp); + continue; + } ++ else ++ { ++ break; ++ } + } +- while (false); ++ +=20 + if (convert) + { +diff --git a/tests/expand/mb.sh b/tests/expand/mb.sh +index 7971e18..031be7a 100755 +--- a/tests/expand/mb.sh ++++ b/tests/expand/mb.sh +@@ -44,6 +44,20 @@ EOF + expand < in > out || fail=3D1 + compare exp out > /dev/null 2>&1 || fail=3D1 +=20 ++#multiple files as an input ++cat <<\EOF >> exp || framework_failure_ ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++=C3=A4 =C3=B6 =C3=BC =C3=9F ++. . . . ++ =C3=A4=C3=B6=C3=BC . =C3=B6=C3=BC=C3=A4. =C3=A4 xx ++EOF ++ ++expand ./in ./in > out || fail=3D1 ++compare exp out > /dev/null 2>&1 || fail=3D1 ++ + #test characters with display widths !=3D 1 + env printf '12345678 + e\t|ascii(1) +diff --git a/tests/unexpand/mb.sh b/tests/unexpand/mb.sh +index 60d4c1a..8d75652 100755 +--- a/tests/unexpand/mb.sh ++++ b/tests/unexpand/mb.sh +@@ -44,6 +44,22 @@ EOF + unexpand -a < in > out || fail=3D1 + compare exp out > /dev/null 2>&1 || fail=3D1 +=20 ++ ++#multiple files as an input ++cat >> exp <<\EOF ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++=C3=A4 =C3=B6 =C3=BC =C3=9F ++. . . . ++ =C3=A4=C3=B6=C3=BC . =C3=B6=C3=BC=C3=A4. =C3=A4 xx ++EOF ++ ++ ++unexpand -a ./in ./in > out || fail=3D1 ++compare exp out > /dev/null 2>&1 || fail=3D1 ++ + #test characters with a display width larger than 1 +=20 + env printf '12345678 diff --git a/coreutils/patches/coreutils-i18n-fold-newline.patch b/coreutils/= patches/coreutils-i18n-fold-newline.patch new file mode 100644 index 000000000..f7286efe0 --- /dev/null +++ b/coreutils/patches/coreutils-i18n-fold-newline.patch @@ -0,0 +1,80 @@ +From ff424639fe863cbd6963add1a79b97290c1606c6 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Fri, 3 Feb 2017 12:26:53 +0100 +Subject: [PATCH] fold.c: preserve new-lines in mutlibyte text + +--- + src/fold.c | 49 ++++++++++++++++++++++++------------------------- + 1 file changed, 24 insertions(+), 25 deletions(-) + +diff --git a/src/fold.c b/src/fold.c +index d23edd5..8c232a7 100644 +--- a/src/fold.c ++++ b/src/fold.c +@@ -342,39 +342,38 @@ fold_multibyte_text (FILE *istream, size_t width, int = *saved_errno) + } +=20 + rescan: +- if (operating_mode =3D=3D byte_mode) /* byte m= ode */ ++ if (convfail) ++ increment =3D 1; ++ else if (wc =3D=3D L'\n') ++ { ++ /* preserve newline */ ++ fwrite (line_out, sizeof(char), offset_out, stdout); ++ START_NEW_LINE; ++ continue; ++ } ++ else if (operating_mode =3D=3D byte_mode) /* byte mo= de */ + increment =3D mblength; + else if (operating_mode =3D=3D character_mode) /* character mo= de */ + increment =3D 1; +- else /* column mode */ ++ else /* column mode */ + { +- if (convfail) +- increment =3D 1; +- else ++ switch (wc) + { +- switch (wc) +- { +- case L'\n': +- fwrite (line_out, sizeof(char), offset_out, stdout); +- START_NEW_LINE; +- continue; ++ case L'\b': ++ increment =3D (column > 0) ? -1 : 0; ++ break; +=20 +- case L'\b': +- increment =3D (column > 0) ? -1 : 0; +- break; ++ case L'\r': ++ increment =3D -1 * column; ++ break; +=20 +- case L'\r': +- increment =3D -1 * column; +- break; ++ case L'\t': ++ increment =3D 8 - column % 8; ++ break; +=20 +- case L'\t': +- increment =3D 8 - column % 8; +- break; +- +- default: +- increment =3D wcwidth (wc); +- increment =3D (increment < 0) ? 0 : increment; +- } ++ default: ++ increment =3D wcwidth (wc); ++ increment =3D (increment < 0) ? 0 : increment; + } + } +=20 +--=20 +2.7.4 + diff --git a/coreutils/patches/coreutils-i18n-sort-human.patch b/coreutils/pa= tches/coreutils-i18n-sort-human.patch new file mode 100644 index 000000000..675249315 --- /dev/null +++ b/coreutils/patches/coreutils-i18n-sort-human.patch @@ -0,0 +1,35 @@ +From 3976ef5a20369d8b490907ab2cba2d617305a5e0 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Mon, 30 May 2016 16:19:20 +0200 +Subject: [PATCH] sort: do not use static array 'blanks' in human_numcompare() + +... because the array is not initialized with MB locales. Note this is +rather a conservative fix. I plan to do more cleanup of the i18n patch +in Fedora to prevent mistakes like this in future updates of coreutils. +--- + src/sort.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/src/sort.c b/src/sort.c +index 9e07ad8..e47b039 100644 +--- a/src/sort.c ++++ b/src/sort.c +@@ -2304,12 +2304,10 @@ find_unit_order (char const *number) + < K/k < M < G < T < P < E < Z < Y */ +=20 + static int +-human_numcompare (char const *a, char const *b) ++human_numcompare (char *a, char *b) + { +- while (blanks[to_uchar (*a)]) +- a++; +- while (blanks[to_uchar (*b)]) +- b++; ++ skipblanks(&a, a + strlen(a)); ++ skipblanks(&b, b + strlen(b)); +=20 + int diff =3D find_unit_order (a) - find_unit_order (b); + return (diff ? diff : strnumcmp (a, b, decimal_point, thousands_sep)); +--=20 +2.5.5 + diff --git a/coreutils/patches/coreutils-i18n-un-expand-BOM.patch b/coreutils= /patches/coreutils-i18n-un-expand-BOM.patch new file mode 100644 index 000000000..6210ce7e8 --- /dev/null +++ b/coreutils/patches/coreutils-i18n-un-expand-BOM.patch @@ -0,0 +1,456 @@ +From 7a7c776a4e228d180e74614fd8c8afcad5d4bdf7 Mon Sep 17 00:00:00 2001 +From: Jakub Martisko +Date: Thu, 7 Jul 2016 12:53:26 +0200 +Subject: [PATCH] coreutils-i18n-un-expand-BOM.patch + +--- + src/expand-common.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++= +++ + src/expand-common.h | 12 ++++++ + src/expand.c | 45 +++++++++++++++++++- + src/unexpand.c | 43 ++++++++++++++++++- + tests/expand/mb.sh | 71 ++++++++++++++++++++++++++++++++ + tests/unexpand/mb.sh | 59 ++++++++++++++++++++++++++ + 6 files changed, 342 insertions(+), 2 deletions(-) + +diff --git a/src/expand-common.c b/src/expand-common.c +index 4657e46..97cbb09 100644 +--- a/src/expand-common.c ++++ b/src/expand-common.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include "system.h" + #include "die.h" + #include "error.h" +@@ -126,6 +127,119 @@ set_increment_size (uintmax_t tabval) + return ok; + } +=20 ++extern int ++set_utf_locale (void) ++{ ++ /*try using some predefined locale */ ++ const char* predef_locales[] =3D {"C.UTF8","en_US.UTF8","en_GB.UTF8"}; ++ ++ const int predef_locales_count=3D3; ++ for (int i=3D0;ibufcount=3D0; ++ if (c =3D=3D 0xEF) ++ { ++ c=3Dfgetc(fp); ++ } ++ else ++ { ++ if (c !=3D EOF) ++ { ++ ungetc(c,fp); ++ } ++ return false; ++ } ++ ++ if (c =3D=3D 0xBB) ++ { ++ c=3Dfgetc(fp); ++ } ++ else ++ { ++ if ( c!=3D EOF ) ++ { ++ mbf->buf[0]=3D(unsigned char) 0xEF; ++ mbf->bufcount=3D1; ++ ungetc(c,fp); ++ return false; ++ } ++ else ++ { ++ ungetc(0xEF,fp); ++ return false; ++ } ++ } ++ if (c =3D=3D 0xBF) ++ { ++ mbf->bufcount=3D0; ++ return true; ++ } ++ else ++ { ++ if (c !=3D EOF) ++ { ++ mbf->buf[0]=3D(unsigned char) 0xEF; ++ mbf->buf[1]=3D(unsigned char) 0xBB; ++ mbf->bufcount=3D2; ++ ungetc(c,fp); ++ return false; ++ } ++ else ++ { ++ mbf->buf[0]=3D(unsigned char) 0xEF; ++ mbf->bufcount=3D1; ++ ungetc(0xBB,fp); ++ return false; ++ } ++ } ++ return false; ++} ++ ++extern void ++print_bom(void) ++{ ++ putc (0xEF, stdout); ++ putc (0xBB, stdout); ++ putc (0xBF, stdout); ++} ++ + /* Add the comma or blank separated list of tab stops STOPS + to the list of tab stops. */ + extern void +diff --git a/src/expand-common.h b/src/expand-common.h +index 8cb2079..763bfda 100644 +--- a/src/expand-common.h ++++ b/src/expand-common.h +@@ -34,6 +34,18 @@ extern size_t max_column_width; + /* The desired exit status. */ + extern int exit_status; +=20 ++extern int ++set_utf_locale (void); ++ ++extern bool ++check_utf_locale(void); ++ ++extern bool ++check_bom(FILE* fp, mb_file_t *mbf); ++ ++extern void ++print_bom(void); ++ + /* Add tab stop TABVAL to the end of 'tab_list'. */ + extern void + add_tab_stop (uintmax_t tabval); +diff --git a/src/expand.c b/src/expand.c +index 310b349..4136824 100644 +--- a/src/expand.c ++++ b/src/expand.c +@@ -103,11 +103,33 @@ expand (void) + FILE *fp =3D next_file (NULL); + mb_file_t mbf; + mbf_char_t c; ++ /* True if the starting locale is utf8. */ ++ bool using_utf_locale; ++ ++ /* True if the first file contains BOM header. */ ++ bool found_bom; ++ using_utf_locale=3Dcheck_utf_locale(); +=20 + if (!fp) + return; +- + mbf_init (mbf, fp); ++ found_bom=3Dcheck_bom(fp,&mbf); ++ ++ if (using_utf_locale =3D=3D false && found_bom =3D=3D true) ++ { ++ /*try using some predefined locale */ ++ ++ if (set_utf_locale () !=3D 0) ++ { ++ error (EXIT_FAILURE, errno, _("cannot set UTF-8 locale")); ++ } ++ } ++ ++ ++ if (found_bom =3D=3D true) ++ { ++ print_bom(); ++ } +=20 + while (true) + { +@@ -132,6 +154,27 @@ expand (void) + if ((mb_iseof (c)) && (fp =3D next_file (fp))) + { + mbf_init (mbf, fp); ++ if (fp!=3DNULL) ++ { ++ if (check_bom(fp,&mbf)=3D=3Dtrue) ++ { ++ /*Not the first file - check BOM header*/ ++ if (using_utf_locale=3D=3Dfalse && found_bom=3D=3Dfalse) ++ { ++ /*BOM header in subsequent file but not in the first = one. */ ++ error (EXIT_FAILURE, errno, _("combination of files w= ith and without BOM header")); ++ } ++ } ++ else ++ { ++ if(using_utf_locale=3D=3Dfalse && found_bom=3D=3Dtrue) ++ { ++ /*First file conatined BOM header - locale was switch= ed to UTF ++ *all subsequent files should contain BOM. */ ++ error (EXIT_FAILURE, errno, _("combination of files w= ith and without BOM header")); ++ } ++ } ++ } + continue; + } + else +diff --git a/src/unexpand.c b/src/unexpand.c +index 863a90a..5681b58 100644 +--- a/src/unexpand.c ++++ b/src/unexpand.c +@@ -116,16 +116,36 @@ unexpand (void) + include characters other than spaces, so the blanks must be + stored, not merely counted. */ + mbf_char_t *pending_blank; ++ /* True if the starting locale is utf8. */ ++ bool using_utf_locale; ++ ++ /* True if the first file contains BOM header. */ ++ bool found_bom; ++ using_utf_locale=3Dcheck_utf_locale(); +=20 + if (!fp) + return; ++ mbf_init (mbf, fp); ++ found_bom=3Dcheck_bom(fp,&mbf); ++ ++ if (using_utf_locale =3D=3D false && found_bom =3D=3D true) ++ { ++ /*try using some predefined locale */ +=20 ++ if (set_utf_locale () !=3D 0) ++ { ++ error (EXIT_FAILURE, errno, _("cannot set UTF-8 locale")); ++ } ++ } + /* 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 =3D xmalloc (max_column_width * sizeof (mbf_char_t)); +=20 +- mbf_init (mbf, fp); ++ if (found_bom =3D=3D true) ++ { ++ print_bom(); ++ } +=20 + while (true) + { +@@ -169,6 +189,27 @@ unexpand (void) + if ((mb_iseof (c)) && (fp =3D next_file (fp))) + { + mbf_init (mbf, fp); ++ if (fp!=3DNULL) ++ { ++ if (check_bom(fp,&mbf)=3D=3Dtrue) ++ { ++ /*Not the first file - check BOM header*/ ++ if (using_utf_locale=3D=3Dfalse && found_bom=3D=3Dfalse) ++ { ++ /*BOM header in subsequent file but not in the first = one. */ ++ error (EXIT_FAILURE, errno, _("combination of files w= ith and without BOM header")); ++ } ++ } ++ else ++ { ++ if(using_utf_locale=3D=3Dfalse && found_bom=3D=3Dtrue) ++ { ++ /*First file conatined BOM header - locale was switch= ed to UTF ++ *all subsequent files should contain BOM. */ ++ error (EXIT_FAILURE, errno, _("combination of files w= ith and without BOM header")); ++ } ++ } ++ } + continue; + } + else +diff --git a/tests/expand/mb.sh b/tests/expand/mb.sh +index 031be7a..1621c84 100755 +--- a/tests/expand/mb.sh ++++ b/tests/expand/mb.sh +@@ -109,4 +109,75 @@ env printf '12345678 + expand < in > out || fail=3D1 + compare exp out > /dev/null 2>&1 || fail=3D1 +=20 ++ ++ ++#BOM header test 1 ++printf "\xEF\xBB\xBF" > in; cat <<\EOF >> in || framework_failure_ ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++=C3=A4 =C3=B6 =C3=BC =C3=9F ++. . . . ++EOF ++env printf ' =C3=A4=C3=B6=C3=BC\t. =C3=B6=C3=BC=C3=A4. \t=C3=A4 xx\n= ' >> in || framework_failure_ ++ ++printf "\xEF\xBB\xBF" > exp; cat <<\EOF >> exp || framework_failure_ ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++=C3=A4 =C3=B6 =C3=BC =C3=9F ++. . . . ++ =C3=A4=C3=B6=C3=BC . =C3=B6=C3=BC=C3=A4. =C3=A4 xx ++EOF ++ ++ ++expand < in > out || fail=3D1 ++compare exp out > /dev/null 2>&1 || fail=3D1 ++ ++LANG=3DC expand < in > out || fail=3D1 ++compare exp out > /dev/null 2>&1 || fail=3D1 ++ ++LC_ALL=3DC expand < in > out || fail=3D1 ++compare exp out > /dev/null 2>&1 || fail=3D1 ++ ++ ++printf '\xEF\xBB\xBF' > in1; cat <<\EOF >> in1 || framework_failure_ ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++=C3=A4 =C3=B6 =C3=BC =C3=9F ++. . . . ++EOF ++env printf ' =C3=A4=C3=B6=C3=BC\t. =C3=B6=C3=BC=C3=A4. \t=C3=A4 xx\n= ' >> in1 || framework_failure_ ++ ++ ++printf '\xEF\xBB\xBF' > exp; cat <<\EOF >> exp || framework_failure_ ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++=C3=A4 =C3=B6 =C3=BC =C3=9F ++. . . . ++ =C3=A4=C3=B6=C3=BC . =C3=B6=C3=BC=C3=A4. =C3=A4 xx ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++=C3=A4 =C3=B6 =C3=BC =C3=9F ++. . . . ++ =C3=A4=C3=B6=C3=BC . =C3=B6=C3=BC=C3=A4. =C3=A4 xx ++EOF ++ ++expand in1 in1 > out || fail=3D1 ++compare exp out > /dev/null 2>&1 || fail=3D1 ++ ++LANG=3DC expand in1 in1 > out || fail=3D1 ++compare exp out > /dev/null 2>&1 || fail=3D1 ++ ++LC_ALL=3DC expand in1 in1 > out || fail=3D1 ++compare exp out > /dev/null 2>&1 || fail=3D1 ++ + exit $fail +diff --git a/tests/unexpand/mb.sh b/tests/unexpand/mb.sh +index 8d75652..9d4ee3e 100755 +--- a/tests/unexpand/mb.sh ++++ b/tests/unexpand/mb.sh +@@ -111,3 +111,62 @@ env printf '12345678 +=20 + unexpand -a < in > out || fail=3D1 + compare exp out > /dev/null 2>&1 || fail=3D1 ++ ++#BOM header test 1 ++printf "\xEF\xBB\xBF" > in; cat <<\EOF >> in || framework_failure_ ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++=C3=A4 =C3=B6 =C3=BC =C3=9F ++. . . . ++ =C3=A4=C3=B6=C3=BC . =C3=B6=C3=BC=C3=A4. =C3=A4 xx ++EOF ++env printf ' =C3=A4=C3=B6=C3=BC\t. =C3=B6=C3=BC=C3=A4. \t=C3=A4 xx\n= ' >> in || framework_failure_ ++ ++printf "\xEF\xBB\xBF" > exp; cat <<\EOF >> exp || framework_failure_ ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++=C3=A4 =C3=B6 =C3=BC =C3=9F ++. . . . ++ =C3=A4=C3=B6=C3=BC . =C3=B6=C3=BC=C3=A4. =C3=A4 xx ++EOF ++ ++unexpand < in > out || fail=3D1 ++compare exp out > /dev/null 2>&1 || fail=3D1 ++ ++LANG=3DC unexpand < in > out || fail=3D1 ++compare exp out > /dev/null 2>&1 || fail=3D1 ++ ++LC_ALL=3DC unexpand < in > out || fail=3D1 ++compare exp out > /dev/null 2>&1 || fail=3D1 ++ ++ ++printf "\xEF\xBB\xBF" > exp; cat <<\EOF >> exp || framework_failure_ ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++=C3=A4 =C3=B6 =C3=BC =C3=9F ++. . . . ++ =C3=A4=C3=B6=C3=BC . =C3=B6=C3=BC=C3=A4. =C3=A4 xx ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++=C3=A4 =C3=B6 =C3=BC =C3=9F ++. . . . ++ =C3=A4=C3=B6=C3=BC . =C3=B6=C3=BC=C3=A4. =C3=A4 xx ++EOF ++ ++ ++unexpand in in > out || fail=3D1 ++compare exp out > /dev/null 2>&1 || fail=3D1 ++ ++LANG=3DC unexpand in in > out || fail=3D1 ++compare exp out > /dev/null 2>&1 || fail=3D1 ++ ++LC_ALL=3DC unexpand in in > out || fail=3D1 ++compare exp out > /dev/null 2>&1 || fail=3D1 +--=20 +2.9.3 + diff --git a/coreutils/patches/coreutils-i18n.patch b/coreutils/patches/coreu= tils-i18n.patch index d7cf59ce1..e3428d933 100644 --- a/coreutils/patches/coreutils-i18n.patch +++ b/coreutils/patches/coreutils-i18n.patch @@ -13,7 +13,6 @@ TODO: merge upstream src/uniq.c | 265 ++++++++++++++- tests/i18n/sort.sh | 29 ++ tests/local.mk | 2 + - tests/misc/cut.pl | 7 +- tests/misc/expand.pl | 42 +++ tests/misc/fold.pl | 50 ++- tests/misc/join.pl | 50 +++ @@ -23,9 +22,9 @@ TODO: merge upstream tests/misc/unexpand.pl | 39 +++ tests/misc/uniq.pl | 55 ++++ tests/pr/pr-tests.pl | 49 +++ - 18 files changed, 2435 insertions(+), 162 deletions(-) - create mode 100644 tests/i18n/sort.sh - create mode 100644 tests/misc/sort-mb-tests.sh + 17 files changed, 2430 insertions(+), 160 deletions(-) + create mode 100755 tests/i18n/sort.sh + create mode 100755 tests/misc/sort-mb-tests.sh =20 diff --git a/lib/linebuffer.h b/lib/linebuffer.h index 64181af..9b8fe5a 100644 @@ -315,7 +314,7 @@ index 8cd0d6b..d23edd5 100644 + fwrite (line_out, sizeof(char), offset_out, stdout); + START_NEW_LINE; + continue; -+ =20 ++ + case L'\b': + increment =3D (column > 0) ? -1 : 0; + break; @@ -672,7 +671,7 @@ index 98b461c..9990f38 100644 + extract_field (line, ptr, lim - ptr); +} +#endif -+=20 ++ static void freeline (struct line *line) { @@ -845,7 +844,7 @@ index 98b461c..9990f38 100644 xfields (line); =20 if (prevline[which - 1]) -@@ -567,21 +807,28 @@ prfield (size_t n, struct line const *line) +@@ -563,21 +803,28 @@ prfield (size_t n, struct line const *line) =20 /* Output all the fields in line, other than the join field. */ =20 @@ -877,7 +876,7 @@ index 98b461c..9990f38 100644 prfield (i, line); } } -@@ -592,7 +839,6 @@ static void +@@ -588,7 +835,6 @@ static void prjoin (struct line const *line1, struct line const *line2) { const struct outlist *outlist; @@ -885,7 +884,7 @@ index 98b461c..9990f38 100644 size_t field; struct line const *line; =20 -@@ -626,7 +872,7 @@ prjoin (struct line const *line1, struct line const *lin= e2) +@@ -622,7 +868,7 @@ prjoin (struct line const *line1, struct line const *lin= e2) o =3D o->next; if (o =3D=3D NULL) break; @@ -894,7 +893,7 @@ index 98b461c..9990f38 100644 } putchar (eolchar); } -@@ -1104,20 +1350,43 @@ main (int argc, char **argv) +@@ -1099,20 +1345,43 @@ main (int argc, char **argv) =20 case 't': { @@ -1171,7 +1170,7 @@ index 26f221f..633f50e 100644 use_col_separator =3D true; if (optarg) separator_string (optarg); -@@ -1166,10 +1250,45 @@ getoptnum (const char *n_str, int min, int *num, con= st char *err) +@@ -1165,10 +1249,45 @@ getoptnum (const char *n_str, int min, int *num, con= st char *err) a number. */ =20 static void @@ -1219,7 +1218,7 @@ index 26f221f..633f50e 100644 if (*arg) { long int tmp_long; -@@ -1191,6 +1310,11 @@ static void +@@ -1190,6 +1309,11 @@ static void init_parameters (int number_of_files) { int chars_used_by_number =3D 0; @@ -1231,7 +1230,7 @@ index 26f221f..633f50e 100644 =20 lines_per_body =3D lines_per_page - lines_per_header - lines_per_footer; if (lines_per_body <=3D 0) -@@ -1228,7 +1352,7 @@ init_parameters (int number_of_files) +@@ -1227,7 +1351,7 @@ init_parameters (int number_of_files) else col_sep_string =3D column_separator; =20 @@ -1240,7 +1239,7 @@ index 26f221f..633f50e 100644 use_col_separator =3D true; } /* It's rather pointless to define a TAB separator with column -@@ -1258,11 +1382,11 @@ init_parameters (int number_of_files) +@@ -1257,11 +1381,11 @@ init_parameters (int number_of_files) + TAB_WIDTH (chars_per_input_tab, chars_per_number); */ =20 /* Estimate chars_per_text without any margin and keep it constant. */ @@ -1254,7 +1253,7 @@ index 26f221f..633f50e 100644 =20 /* The number is part of the column width unless we are printing files in parallel. */ -@@ -1271,7 +1395,7 @@ init_parameters (int number_of_files) +@@ -1270,7 +1394,7 @@ init_parameters (int number_of_files) } =20 int sep_chars, useful_chars; @@ -1263,7 +1262,7 @@ index 26f221f..633f50e 100644 sep_chars =3D INT_MAX; if (INT_SUBTRACT_WRAPV (chars_per_line - chars_used_by_number, sep_chars, &useful_chars)) -@@ -1294,7 +1418,7 @@ init_parameters (int number_of_files) +@@ -1293,7 +1417,7 @@ init_parameters (int number_of_files) We've to use 8 as the lower limit, if we use chars_per_default_tab =3D= 8 to expand a tab which is not an input_tab-char. */ free (clump_buff); @@ -1272,7 +1271,7 @@ index 26f221f..633f50e 100644 } =20 /* Open the necessary files, -@@ -1402,7 +1526,7 @@ init_funcs (void) +@@ -1399,7 +1523,7 @@ init_funcs (void) =20 /* Enlarge p->start_position of first column to use the same form of padding_not_printed with all columns. */ @@ -1281,7 +1280,7 @@ index 26f221f..633f50e 100644 =20 /* This loop takes care of all but the rightmost column. */ =20 -@@ -1436,7 +1560,7 @@ init_funcs (void) +@@ -1433,7 +1557,7 @@ init_funcs (void) } else { @@ -1290,7 +1289,7 @@ index 26f221f..633f50e 100644 h_next =3D h + chars_per_column; } } -@@ -1727,9 +1851,9 @@ static void +@@ -1724,9 +1848,9 @@ static void align_column (COLUMN *p) { padding_not_printed =3D p->start_position; @@ -1302,7 +1301,7 @@ index 26f221f..633f50e 100644 padding_not_printed =3D ANYWHERE; } =20 -@@ -2004,13 +2128,13 @@ store_char (char c) +@@ -2001,13 +2125,13 @@ store_char (char c) /* May be too generous. */ buff =3D X2REALLOC (buff, &buff_allocated); } @@ -1318,7 +1317,7 @@ index 26f221f..633f50e 100644 char *s; int num_width; =20 -@@ -2027,22 +2151,24 @@ add_line_number (COLUMN *p) +@@ -2024,22 +2148,24 @@ add_line_number (COLUMN *p) /* Tabification is assumed for multiple columns, also for n-separator= s, but 'default n-separator =3D TAB' hasn't been given priority over equal column_width also specified by POSIX. */ @@ -1347,7 +1346,7 @@ index 26f221f..633f50e 100644 output_position =3D POS_AFTER_TAB (chars_per_output_tab, output_position); } -@@ -2203,7 +2329,7 @@ print_white_space (void) +@@ -2198,7 +2324,7 @@ print_white_space (void) while (goal - h_old > 1 && (h_new =3D POS_AFTER_TAB (chars_per_output_tab, h_old)) <=3D go= al) { @@ -1356,7 +1355,7 @@ index 26f221f..633f50e 100644 h_old =3D h_new; } while (++h_old <=3D goal) -@@ -2223,6 +2349,7 @@ print_sep_string (void) +@@ -2218,6 +2344,7 @@ print_sep_string (void) { char const *s =3D col_sep_string; int l =3D col_sep_length; @@ -1364,7 +1363,7 @@ index 26f221f..633f50e 100644 =20 if (separators_not_printed <=3D 0) { -@@ -2234,6 +2361,7 @@ print_sep_string (void) +@@ -2229,6 +2356,7 @@ print_sep_string (void) { for (; separators_not_printed > 0; --separators_not_printed) { @@ -1372,7 +1371,7 @@ index 26f221f..633f50e 100644 while (l-- > 0) { /* 3 types of sep_strings: spaces only, spaces and chars, -@@ -2247,12 +2375,15 @@ print_sep_string (void) +@@ -2242,12 +2370,15 @@ print_sep_string (void) } else { @@ -1389,7 +1388,7 @@ index 26f221f..633f50e 100644 /* sep_string ends with some spaces */ if (spaces_not_printed > 0) print_white_space (); -@@ -2280,7 +2411,7 @@ print_clump (COLUMN *p, int n, char *clump) +@@ -2275,7 +2406,7 @@ print_clump (COLUMN *p, int n, char *clump) required number of tabs and spaces. */ =20 static void @@ -1398,7 +1397,7 @@ index 26f221f..633f50e 100644 { if (tabify_output) { -@@ -2304,6 +2435,74 @@ print_char (char c) +@@ -2299,6 +2430,74 @@ print_char (char c) putchar (c); } =20 @@ -1473,7 +1472,7 @@ index 26f221f..633f50e 100644 /* Skip to page PAGE before printing. PAGE may be larger than total number of pages. */ =20 -@@ -2483,9 +2682,9 @@ read_line (COLUMN *p) +@@ -2476,9 +2675,9 @@ read_line (COLUMN *p) align_empty_cols =3D false; } =20 @@ -1485,8 +1484,8 @@ index 26f221f..633f50e 100644 padding_not_printed =3D ANYWHERE; } =20 -@@ -2555,7 +2754,7 @@ print_stored (COLUMN *p) - int i; +@@ -2547,7 +2746,7 @@ print_stored (COLUMN *p) + COLUMN *q; =20 int line =3D p->current_line++; - char *first =3D &buff[line_vector[line]]; @@ -1494,7 +1493,7 @@ index 26f221f..633f50e 100644 /* FIXME UMR: Uninitialized memory read: * This is occurring while in: -@@ -2567,7 +2766,7 @@ print_stored (COLUMN *p) +@@ -2559,7 +2758,7 @@ print_stored (COLUMN *p) xmalloc [xmalloc.c:94] init_store_cols [pr.c:1648] */ @@ -1503,7 +1502,7 @@ index 26f221f..633f50e 100644 =20 pad_vertically =3D true; =20 -@@ -2586,9 +2785,9 @@ print_stored (COLUMN *p) +@@ -2579,9 +2778,9 @@ print_stored (COLUMN *p) } } =20 @@ -1515,7 +1514,7 @@ index 26f221f..633f50e 100644 padding_not_printed =3D ANYWHERE; } =20 -@@ -2601,8 +2800,8 @@ print_stored (COLUMN *p) +@@ -2594,8 +2793,8 @@ print_stored (COLUMN *p) if (spaces_not_printed =3D=3D 0) { output_position =3D p->start_position + end_vector[line]; @@ -1526,7 +1525,7 @@ index 26f221f..633f50e 100644 } =20 return true; -@@ -2621,7 +2820,7 @@ print_stored (COLUMN *p) +@@ -2614,7 +2813,7 @@ print_stored (COLUMN *p) number of characters is 1.) */ =20 static int @@ -1535,7 +1534,7 @@ index 26f221f..633f50e 100644 { unsigned char uc =3D c; char *s =3D clump_buff; -@@ -2631,10 +2830,10 @@ char_to_clump (char c) +@@ -2624,10 +2823,10 @@ char_to_clump (char c) int chars; int chars_per_c =3D 8; =20 @@ -1548,7 +1547,7 @@ index 26f221f..633f50e 100644 { width =3D TAB_WIDTH (chars_per_c, input_position); =20 -@@ -2715,6 +2914,164 @@ char_to_clump (char c) +@@ -2708,6 +2907,164 @@ char_to_clump (char c) return chars; } =20 @@ -1732,7 +1731,7 @@ index 6d2eec5..f189a0d 100644 #include "system.h" #include "argmatch.h" #include "die.h" -@@ -165,14 +173,39 @@ static int decimal_point; +@@ -161,14 +169,39 @@ static int decimal_point; /* Thousands separator; if -1, then there isn't one. */ static int thousands_sep; =20 @@ -1773,7 +1772,7 @@ index 6d2eec5..f189a0d 100644 /* The kind of blanks for '-b' to skip in various options. */ enum blanktype { bl_start, bl_end, bl_both }; =20 -@@ -346,13 +379,11 @@ static bool reverse; +@@ -342,13 +375,11 @@ static bool reverse; they were read if all keys compare equal. */ static bool stable; =20 @@ -1790,7 +1789,7 @@ index 6d2eec5..f189a0d 100644 =20 /* Flag to remove consecutive duplicate lines from the output. Only the last of a sequence of equal lines will be output. */ -@@ -811,6 +842,46 @@ reap_all (void) +@@ -806,6 +837,46 @@ reap_all (void) reap (-1); } =20 @@ -1837,7 +1836,7 @@ index 6d2eec5..f189a0d 100644 /* Clean up any remaining temporary files. */ =20 static void -@@ -1255,7 +1326,7 @@ zaptemp (char const *name) +@@ -1274,7 +1345,7 @@ zaptemp (char const *name) free (node); } =20 @@ -1846,7 +1845,7 @@ index 6d2eec5..f189a0d 100644 =20 static int struct_month_cmp (void const *m1, void const *m2) -@@ -1270,7 +1341,7 @@ struct_month_cmp (void const *m1, void const *m2) +@@ -1289,7 +1360,7 @@ struct_month_cmp (void const *m1, void const *m2) /* Initialize the character class tables. */ =20 static void @@ -1855,7 +1854,7 @@ index 6d2eec5..f189a0d 100644 { size_t i; =20 -@@ -1282,7 +1353,7 @@ inittables (void) +@@ -1301,7 +1372,7 @@ inittables (void) fold_toupper[i] =3D toupper (i); } =20 @@ -1864,7 +1863,7 @@ index 6d2eec5..f189a0d 100644 /* If we're not in the "C" locale, read different names for months. */ if (hard_LC_TIME) { -@@ -1364,6 +1435,84 @@ specify_nmerge (int oi, char c, char const *s) +@@ -1383,6 +1454,84 @@ specify_nmerge (int oi, char c, char const *s) xstrtol_fatal (e, oi, c, long_options, s); } =20 @@ -1949,7 +1948,7 @@ index 6d2eec5..f189a0d 100644 /* Specify the amount of main memory to use when sorting. */ static void specify_sort_size (int oi, char c, char const *s) -@@ -1597,7 +1746,7 @@ buffer_linelim (struct buffer const *buf) +@@ -1614,7 +1763,7 @@ buffer_linelim (struct buffer const *buf) by KEY in LINE. */ =20 static char * @@ -1958,7 +1957,7 @@ index 6d2eec5..f189a0d 100644 { char *ptr =3D line->text, *lim =3D ptr + line->length - 1; size_t sword =3D key->sword; -@@ -1606,10 +1755,10 @@ begfield (struct line const *line, struct keyfield c= onst *key) +@@ -1623,10 +1772,10 @@ begfield (struct line const *line, struct keyfield c= onst *key) /* The leading field separator itself is included in a field when -t is absent. */ =20 @@ -1971,7 +1970,7 @@ index 6d2eec5..f189a0d 100644 ++ptr; if (ptr < lim) ++ptr; -@@ -1635,11 +1784,70 @@ begfield (struct line const *line, struct keyfield c= onst *key) +@@ -1652,11 +1801,70 @@ begfield (struct line const *line, struct keyfield c= onst *key) return ptr; } =20 @@ -2043,7 +2042,7 @@ index 6d2eec5..f189a0d 100644 { char *ptr =3D line->text, *lim =3D ptr + line->length - 1; size_t eword =3D key->eword, echar =3D key->echar; -@@ -1654,10 +1862,10 @@ limfield (struct line const *line, struct keyfield c= onst *key) +@@ -1671,10 +1879,10 @@ limfield (struct line const *line, struct keyfield c= onst *key) 'beginning' is the first character following the delimiting TAB. Otherwise, leave PTR pointing at the first 'blank' character after the preceding field. */ @@ -2056,7 +2055,7 @@ index 6d2eec5..f189a0d 100644 ++ptr; if (ptr < lim && (eword || echar)) ++ptr; -@@ -1703,10 +1911,10 @@ limfield (struct line const *line, struct keyfield c= onst *key) +@@ -1720,10 +1928,10 @@ limfield (struct line const *line, struct keyfield c= onst *key) */ =20 /* Make LIM point to the end of (one byte past) the current field. */ @@ -2069,7 +2068,7 @@ index 6d2eec5..f189a0d 100644 if (newlim) lim =3D newlim; } -@@ -1737,6 +1945,130 @@ limfield (struct line const *line, struct keyfield c= onst *key) +@@ -1754,6 +1962,130 @@ limfield (struct line const *line, struct keyfield c= onst *key) return ptr; } =20 @@ -2200,7 +2199,7 @@ index 6d2eec5..f189a0d 100644 /* Fill BUF reading from FP, moving buf->left bytes from the end of buf->buf to the beginning first. If EOF is reached and the file wasn't terminated by a newline, supply one. Set up BUF's line -@@ -1823,8 +2155,22 @@ fillbuf (struct buffer *buf, FILE *fp, char const *fi= le) +@@ -1840,8 +2172,22 @@ fillbuf (struct buffer *buf, FILE *fp, char const *fi= le) else { if (key->skipsblanks) @@ -2225,7 +2224,7 @@ index 6d2eec5..f189a0d 100644 line->keybeg =3D line_start; } } -@@ -1974,7 +2320,7 @@ human_numcompare (char const *a, char const *b) +@@ -1991,7 +2337,7 @@ human_numcompare (char const *a, char const *b) hideously fast. */ =20 static int @@ -2234,7 +2233,7 @@ index 6d2eec5..f189a0d 100644 { while (blanks[to_uchar (*a)]) a++; -@@ -1984,6 +2330,25 @@ numcompare (char const *a, char const *b) +@@ -2001,6 +2347,25 @@ numcompare (char const *a, char const *b) return strnumcmp (a, b, decimal_point, thousands_sep); } =20 @@ -2259,8 +2258,8 @@ index 6d2eec5..f189a0d 100644 + /* Work around a problem whereby the long double value returned by glibc's strtold ("NaN", ...) contains uninitialized bits: clear all bytes of - A and B before calling strtold. FIXME: remove this function once -@@ -2034,7 +2399,7 @@ general_numcompare (char const *sa, char const *sb) + A and B before calling strtold. FIXME: remove this function if +@@ -2051,7 +2416,7 @@ general_numcompare (char const *sa, char const *sb) Return 0 if the name in S is not recognized. */ =20 static int @@ -2269,7 +2268,7 @@ index 6d2eec5..f189a0d 100644 { size_t lo =3D 0; size_t hi =3D MONTHS_PER_YEAR; -@@ -2310,15 +2675,14 @@ debug_key (struct line const *line, struct keyfield = const *key) +@@ -2327,15 +2692,14 @@ debug_key (struct line const *line, struct keyfield = const *key) char saved =3D *lim; *lim =3D '\0'; =20 @@ -2287,7 +2286,7 @@ index 6d2eec5..f189a0d 100644 else if (key->general_numeric) ignore_value (strtold (beg, &tighter_lim)); else if (key->numeric || key->human_numeric) -@@ -2452,7 +2816,7 @@ key_warnings (struct keyfield const *gkey, bool gkey_o= nly) +@@ -2469,7 +2833,7 @@ key_warnings (struct keyfield const *gkey, bool gkey_o= nly) /* Warn about significant leading blanks. */ bool implicit_skip =3D key_numeric (key) || key->month; bool line_offset =3D key->eword =3D=3D 0 && key->echar !=3D 0; /* -k1= .x,1.y */ @@ -2296,7 +2295,7 @@ index 6d2eec5..f189a0d 100644 && ((!key->skipsblanks && !implicit_skip) || (!key->skipsblanks && key->schar) || (!key->skipeblanks && key->echar))) -@@ -2510,11 +2874,87 @@ key_warnings (struct keyfield const *gkey, bool gkey= _only) +@@ -2527,11 +2891,87 @@ key_warnings (struct keyfield const *gkey, bool gkey= _only) error (0, 0, _("option '-r' only applies to last-resort comparison")); } =20 @@ -2385,7 +2384,7 @@ index 6d2eec5..f189a0d 100644 { struct keyfield *key =3D keylist; =20 -@@ -2599,7 +3039,7 @@ keycompare (struct line const *a, struct line const *b) +@@ -2616,7 +3056,7 @@ keycompare (struct line const *a, struct line const *b) else if (key->human_numeric) diff =3D human_numcompare (ta, tb); else if (key->month) @@ -2394,7 +2393,7 @@ index 6d2eec5..f189a0d 100644 else if (key->random) diff =3D compare_random (ta, tlena, tb, tlenb); else if (key->version) -@@ -2715,6 +3155,211 @@ keycompare (struct line const *a, struct line const = *b) +@@ -2732,6 +3172,211 @@ keycompare (struct line const *a, struct line const = *b) return key->reverse ? -diff : diff; } =20 @@ -2606,16 +2605,16 @@ index 6d2eec5..f189a0d 100644 /* Compare two lines A and B, returning negative, zero, or positive depending on whether A compares less than, equal to, or greater than B. = */ =20 -@@ -2742,7 +3387,7 @@ compare (struct line const *a, struct line const *b) +@@ -2759,7 +3404,7 @@ compare (struct line const *a, struct line const *b) diff =3D - NONZERO (blen); else if (blen =3D=3D 0) diff =3D 1; - else if (hard_LC_COLLATE) + else if (hard_LC_COLLATE && !folding) { - /* Note xmemcoll0 is a performance enhancement as + /* xmemcoll0 is a performance enhancement as it will not unconditionally write '\0' after the -@@ -4139,6 +4784,7 @@ set_ordering (char const *s, struct keyfield *key, enu= m blanktype blanktype) +@@ -4149,6 +4794,7 @@ set_ordering (char const *s, struct keyfield *key, enu= m blanktype blanktype) break; case 'f': key->translate =3D fold_toupper; @@ -2623,7 +2622,7 @@ index 6d2eec5..f189a0d 100644 break; case 'g': key->general_numeric =3D true; -@@ -4218,7 +4864,7 @@ main (int argc, char **argv) +@@ -4228,7 +4874,7 @@ main (int argc, char **argv) initialize_exit_failure (SORT_FAILURE); =20 hard_LC_COLLATE =3D hard_locale (LC_COLLATE); @@ -2632,7 +2631,7 @@ index 6d2eec5..f189a0d 100644 hard_LC_TIME =3D hard_locale (LC_TIME); #endif =20 -@@ -4239,6 +4885,29 @@ main (int argc, char **argv) +@@ -4249,6 +4895,29 @@ main (int argc, char **argv) thousands_sep =3D -1; } =20 @@ -2662,7 +2661,7 @@ index 6d2eec5..f189a0d 100644 have_read_stdin =3D false; inittables (); =20 -@@ -4513,13 +5182,34 @@ main (int argc, char **argv) +@@ -4523,13 +5192,34 @@ main (int argc, char **argv) =20 case 't': { @@ -2701,7 +2700,7 @@ index 6d2eec5..f189a0d 100644 else { /* Provoke with 'sort -txx'. Complain about -@@ -4530,9 +5220,11 @@ main (int argc, char **argv) +@@ -4540,9 +5230,11 @@ main (int argc, char **argv) quote (optarg)); } } @@ -2715,7 +2714,7 @@ index 6d2eec5..f189a0d 100644 } break; =20 -@@ -4770,12 +5462,10 @@ main (int argc, char **argv) +@@ -4771,12 +5463,10 @@ main (int argc, char **argv) sort (files, nfiles, outfile, nthreads); } =20 @@ -2843,7 +2842,7 @@ index 87a0c93..9f755d9 100644 + while (pos < size) + { + MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail); -+=20 ++ + if (convfail || !(iswblank (wc) || wc =3D=3D '\n')) + { + pos +=3D mblength; @@ -2886,7 +2885,7 @@ index 87a0c93..9f755d9 100644 if (check_chars < oldlen) oldlen =3D check_chars; if (check_chars < newlen) -@@ -295,14 +401,103 @@ different (char *old, char *new, size_t oldlen, size_= t newlen) +@@ -295,15 +401,104 @@ different (char *old, char *new, size_t oldlen, size_= t newlen) =20 if (ignore_case) { @@ -2918,8 +2917,8 @@ index 87a0c93..9f755d9 100644 + + return xmemcoll (copy_old, oldlen, copy_new, newlen); + -+} -+ + } +=20 +#if HAVE_MBRTOWC +static int +different_multi (const char *old, const char *new, size_t oldlen, size_t ne= wlen, mbstate_t oldstate, mbstate_t newstate) @@ -2990,11 +2989,12 @@ index 87a0c93..9f755d9 100644 + free (copy[1]); + return rc; + - } ++} +#endif -=20 ++ /* Output the line in linebuffer LINE to standard output provided that the switches say it should be output. + MATCH is true if the line matches the previous line. @@ -367,19 +562,38 @@ check_file (const char *infile, const char *outfile, c= har delimiter) char *prevfield IF_LINT ( =3D NULL); size_t prevlen IF_LINT ( =3D 0); @@ -3118,7 +3118,7 @@ index 87a0c93..9f755d9 100644 skip_fields =3D 0; check_chars =3D SIZE_MAX; diff --git a/tests/i18n/sort.sh b/tests/i18n/sort.sh -new file mode 100644 +new file mode 100755 index 0000000..26c95de --- /dev/null +++ b/tests/i18n/sort.sh @@ -3156,7 +3156,7 @@ diff --git a/tests/local.mk b/tests/local.mk index 568944e..192f776 100644 --- a/tests/local.mk +++ b/tests/local.mk -@@ -350,6 +350,8 @@ all_tests =3D \ +@@ -368,6 +368,8 @@ all_tests =3D \ tests/misc/sort-discrim.sh \ tests/misc/sort-files0-from.pl \ tests/misc/sort-float.sh \ @@ -3165,32 +3165,6 @@ index 568944e..192f776 100644 tests/misc/sort-h-thousands-sep.sh \ tests/misc/sort-merge.pl \ tests/misc/sort-merge-fdlimit.sh \ -diff --git a/tests/misc/cut.pl b/tests/misc/cut.pl -index f6f8a56..b426a80 100755 ---- a/tests/misc/cut.pl -+++ b/tests/misc/cut.pl -@@ -23,9 +23,11 @@ use strict; - # Turn off localization of executable's output. - @ENV{qw(LANGUAGE LANG LC_ALL)} =3D ('C') x 3; -=20 --my $mb_locale =3D $ENV{LOCALE_FR_UTF8}; -+my $mb_locale; -+# uncommented enable multibyte paths -+$mb_locale =3D $ENV{LOCALE_FR_UTF8}; - ! defined $mb_locale || $mb_locale eq 'none' -- and $mb_locale =3D 'C'; -+ and $mb_locale =3D 'C'; -=20 - my $prog =3D 'cut'; - my $try =3D "Try '$prog --help' for more information.\n"; -@@ -240,6 +242,7 @@ if ($mb_locale ne 'C') - my @new_t =3D @$t; - my $test_name =3D shift @new_t; -=20 -+ next if ($test_name =3D~ "newline-[12][0-9]"); - push @new, ["$test_name-mb", @new_t, {ENV =3D> "LC_ALL=3D$mb_locale= "}]; - } - push @Tests, @new; diff --git a/tests/misc/expand.pl b/tests/misc/expand.pl index 8a9cad1..9293e39 100755 --- a/tests/misc/expand.pl @@ -3211,7 +3185,7 @@ index 8a9cad1..9293e39 100755 my @Tests =3D ( ['t1', '--tabs=3D3', {IN=3D>"a\tb"}, {OUT=3D>"a b"}], -@@ -140,6 +149,8 @@ my @Tests =3D +@@ -168,6 +177,8 @@ my @Tests =3D =20 =20 # Test errors @@ -3220,8 +3194,8 @@ index 8a9cad1..9293e39 100755 ['e1', '--tabs=3D"a"', {IN=3D>''}, {OUT=3D>''}, {EXIT=3D>1}, {ERR =3D> "$prog: tab size contains invalid character(s): 'a'\n"}], ['e2', "-t $UINTMAX_OFLOW", {IN=3D>''}, {OUT=3D>''}, {EXIT=3D>1}, -@@ -150,6 +161,37 @@ my @Tests =3D - {ERR =3D> "$prog: tab sizes must be ascending\n"}], +@@ -184,6 +195,37 @@ my @Tests =3D + {ERR =3D> "$prog: '/' specifier not at start of number: '/'\n"}], ); =20 +if ($mb_locale ne 'C') @@ -3351,7 +3325,7 @@ index 4d399d8..07f2823 100755 my $delim =3D chr 0247; sub t_subst ($) { -@@ -329,8 +338,49 @@ foreach my $t (@tv) +@@ -333,8 +342,49 @@ foreach my $t (@tv) push @Tests, $new_ent; } =20 @@ -3402,7 +3376,7 @@ index 4d399d8..07f2823 100755 my $verbose =3D $ENV{VERBOSE}; =20 diff --git a/tests/misc/sort-mb-tests.sh b/tests/misc/sort-mb-tests.sh -new file mode 100644 +new file mode 100755 index 0000000..11836ba --- /dev/null +++ b/tests/misc/sort-mb-tests.sh @@ -3533,7 +3507,7 @@ index c3e7f8e..6ecd3ff 100755 # Since each test is run with a file name and with redirected stdin, # the name in the diagnostic is either the file name or "-". # Normalize each diagnostic to use '-'. -@@ -424,6 +429,38 @@ foreach my $t (@Tests) +@@ -423,6 +428,38 @@ foreach my $t (@Tests) } } =20 @@ -3572,7 +3546,7 @@ index c3e7f8e..6ecd3ff 100755 @Tests =3D triple_test \@Tests; =20 # Remember that triple_test creates from each test with exactly one "IN" -@@ -433,6 +470,7 @@ foreach my $t (@Tests) +@@ -432,6 +469,7 @@ foreach my $t (@Tests) # Remove the IN_PIPE version of the "output-is-input" test above. # The others aren't susceptible because they have three inputs each. @Tests =3D grep {$_->[0] ne 'output-is-input.p'} @Tests; --=20 2.20.1 --===============3885591788525960139==--