coreutils: Update to 8.31
Signed-off-by: Stefan Schantl <stefan.schantl@ipfire.org> Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
This commit is contained in:
parent
6d9201b0ba
commit
e8da1929e0
|
@ -4,7 +4,7 @@
|
|||
###############################################################################
|
||||
|
||||
name = coreutils
|
||||
version = 8.30
|
||||
version = 8.31
|
||||
release = 1
|
||||
|
||||
groups = System/Base
|
||||
|
@ -23,7 +23,7 @@ sources = %{thisapp}.tar.xz
|
|||
build
|
||||
requires
|
||||
autoconf
|
||||
automake
|
||||
automake >= 1.15
|
||||
e2fsprogs-devel
|
||||
gettext-devel
|
||||
gmp-devel
|
||||
|
@ -43,6 +43,10 @@ build
|
|||
--enable-no-install-program=hostname,kill,uptime \
|
||||
--with-tty-group
|
||||
|
||||
prepare_cmds
|
||||
autoreconf -vfi
|
||||
end
|
||||
|
||||
test
|
||||
make check RUN_VERY_EXPENSIVE_TESTS=yes || true
|
||||
end
|
||||
|
|
|
@ -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 <assert.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
+
|
||||
+/* Get mbstate_t, mbrtowc(). */
|
||||
+#if HAVE_WCHAR_H
|
||||
+# include <wchar.h>
|
||||
+#endif
|
||||
#include "system.h"
|
||||
|
||||
#include "error.h"
|
||||
@@ -38,6 +43,18 @@
|
||||
|
||||
#include "set-fields.h"
|
||||
|
||||
+/* 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"
|
||||
|
||||
@@ -54,6 +71,52 @@
|
||||
} \
|
||||
while (0)
|
||||
|
||||
+/* 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 += fread (BUF + BUFLEN, sizeof(char), BUFSIZ, STREAM); \
|
||||
+ BUFPOS = 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. Otherwise false. */
|
||||
+#define GET_NEXT_WC_FROM_BUFFER(WC, BUFPOS, BUFLEN, MBLENGTH, STATE, CONVFAIL) \
|
||||
+ do \
|
||||
+ { \
|
||||
+ mbstate_t state_bak; \
|
||||
+ \
|
||||
+ if (BUFLEN < 1) \
|
||||
+ { \
|
||||
+ WC = WEOF; \
|
||||
+ break; \
|
||||
+ } \
|
||||
+ \
|
||||
+ /* Get a wide character. */ \
|
||||
+ CONVFAIL = false; \
|
||||
+ state_bak = STATE; \
|
||||
+ MBLENGTH = mbrtowc ((wchar_t *)&WC, BUFPOS, BUFLEN, &STATE); \
|
||||
+ \
|
||||
+ switch (MBLENGTH) \
|
||||
+ { \
|
||||
+ case (size_t)-1: \
|
||||
+ case (size_t)-2: \
|
||||
+ CONVFAIL = true; \
|
||||
+ STATE = state_bak; \
|
||||
+ /* Fall througn. */ \
|
||||
+ \
|
||||
+ case 0: \
|
||||
+ MBLENGTH = 1; \
|
||||
+ break; \
|
||||
+ } \
|
||||
+ } \
|
||||
+ while (0)
|
||||
+
|
||||
|
||||
/* 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;
|
||||
|
||||
+/* 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,
|
||||
|
||||
- /* Output characters that are in the given bytes. */
|
||||
+ /* Output bytes that are at the given positions. */
|
||||
byte_mode,
|
||||
|
||||
+ /* Output characters that are at the given positions. */
|
||||
+ character_mode,
|
||||
+
|
||||
/* Output the given delimiter-separated fields. */
|
||||
field_mode
|
||||
};
|
||||
|
||||
static enum operating_mode operating_mode;
|
||||
|
||||
+/* 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;
|
||||
|
||||
/* The delimiter character for field mode. */
|
||||
static unsigned char delim;
|
||||
+#if HAVE_WCHAR_H
|
||||
+static wchar_t wcdelim;
|
||||
+#endif
|
||||
|
||||
/* The delimiter for each line/record. */
|
||||
static unsigned char line_delim = '\n';
|
||||
@@ -164,7 +243,7 @@ Print selected parts of lines from each FILE to standard output.\n\
|
||||
-f, --fields=LIST 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)
|
||||
}
|
||||
}
|
||||
|
||||
+#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 bytes,
|
||||
+ 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 so 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 shows
|
||||
+ as same character as WC. */
|
||||
+ mbstate_t state; /* State of the stream. */
|
||||
+ bool convfail = false; /* true, when conversion failed. Otherwise false. */
|
||||
+ /* Whether to begin printing delimiters between ranges for the current line.
|
||||
+ Set after we've begun printing data corresponding to the first range. */
|
||||
+ bool print_delimiter = false;
|
||||
+
|
||||
+ idx = 0;
|
||||
+ buflen = 0;
|
||||
+ bufpos = buf;
|
||||
+ memset (&state, '\0', sizeof(mbstate_t));
|
||||
+
|
||||
+ current_rp = frp;
|
||||
+
|
||||
+ while (1)
|
||||
+ {
|
||||
+ REFILL_BUFFER (buf, bufpos, buflen, stream);
|
||||
+
|
||||
+ GET_NEXT_WC_FROM_BUFFER (wc, bufpos, buflen, mblength, state, convfail);
|
||||
+ (void) convfail; /* ignore unused */
|
||||
+
|
||||
+ if (wc == WEOF)
|
||||
+ {
|
||||
+ if (idx > 0)
|
||||
+ putchar (line_delim);
|
||||
+ break;
|
||||
+ }
|
||||
+ else if (wc == line_delim)
|
||||
+ {
|
||||
+ putchar (line_delim);
|
||||
+ idx = 0;
|
||||
+ print_delimiter = false;
|
||||
+ current_rp = 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 = true;
|
||||
+ }
|
||||
+ fwrite (bufpos, mblength, sizeof(char), stdout);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ buflen -= mblength;
|
||||
+ bufpos += mblength;
|
||||
+ }
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
/* Read from stream STREAM, printing to standard output any selected fields. */
|
||||
|
||||
static void
|
||||
@@ -425,13 +580,211 @@ cut_fields (FILE *stream)
|
||||
}
|
||||
}
|
||||
|
||||
+#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 = 0; /* A gotten wide character. */
|
||||
+ size_t mblength; /* The byte size of a multibyte character which shows
|
||||
+ as same character as WC. */
|
||||
+ mbstate_t state; /* State of the stream. */
|
||||
+ bool convfail = false; /* true, when conversion failed. Otherwise false. */
|
||||
+
|
||||
+ current_rp = frp;
|
||||
+
|
||||
+ found_any_selected_field = 0;
|
||||
+ field_idx = 1;
|
||||
+ bufpos = buf;
|
||||
+ buflen = 0;
|
||||
+ memset (&state, '\0', sizeof(mbstate_t));
|
||||
+
|
||||
+ c = getc (stream);
|
||||
+ empty_input = (c == EOF);
|
||||
+ if (c != EOF)
|
||||
+ {
|
||||
+ ungetc (c, stream);
|
||||
+ wc = 0;
|
||||
+ }
|
||||
+ else
|
||||
+ wc = 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 = (suppress_non_delimited ^ !print_kth (1));
|
||||
+
|
||||
+ while (1)
|
||||
+ {
|
||||
+ if (field_idx == 1 && buffer_first_field)
|
||||
+ {
|
||||
+ int len = 0;
|
||||
+
|
||||
+ while (1)
|
||||
+ {
|
||||
+ REFILL_BUFFER (buf, bufpos, buflen, stream);
|
||||
+
|
||||
+ GET_NEXT_WC_FROM_BUFFER
|
||||
+ (wc, bufpos, buflen, mblength, state, convfail);
|
||||
+
|
||||
+ if (wc == WEOF)
|
||||
+ break;
|
||||
+
|
||||
+ field_1_buffer = xrealloc (field_1_buffer, len + mblength);
|
||||
+ memcpy (field_1_buffer + len, bufpos, mblength);
|
||||
+ len += mblength;
|
||||
+ buflen -= mblength;
|
||||
+ bufpos += mblength;
|
||||
+
|
||||
+ if (!convfail && (wc == line_delim || wc == wcdelim))
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (len <= 0 && wc == 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 != 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 != 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 = 1;
|
||||
+ }
|
||||
+ next_item (&field_idx);
|
||||
+ }
|
||||
+
|
||||
+ if (wc != 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 = 1;
|
||||
+ }
|
||||
+
|
||||
+ while (1)
|
||||
+ {
|
||||
+ REFILL_BUFFER (buf, bufpos, buflen, stream);
|
||||
+
|
||||
+ GET_NEXT_WC_FROM_BUFFER
|
||||
+ (wc, bufpos, buflen, mblength, state, convfail);
|
||||
+
|
||||
+ if (wc == WEOF)
|
||||
+ break;
|
||||
+ else if (!convfail && (wc == wcdelim || wc == line_delim))
|
||||
+ {
|
||||
+ buflen -= mblength;
|
||||
+ bufpos += mblength;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (print_kth (field_idx))
|
||||
+ fwrite (bufpos, mblength, sizeof(char), stdout);
|
||||
+
|
||||
+ buflen -= mblength;
|
||||
+ bufpos += mblength;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if ((!convfail || wc == line_delim) && buflen < 1)
|
||||
+ wc = WEOF;
|
||||
+
|
||||
+ if (!convfail && wc == wcdelim)
|
||||
+ next_item (&field_idx);
|
||||
+ else if (wc == WEOF || (!convfail && wc == line_delim))
|
||||
+ {
|
||||
+ if (found_any_selected_field
|
||||
+ || (!empty_input && !(suppress_non_delimited && field_idx == 1)))
|
||||
+ putchar (line_delim);
|
||||
+ if (wc == WEOF)
|
||||
+ break;
|
||||
+ field_idx = 1;
|
||||
+ current_rp = frp;
|
||||
+ found_any_selected_field = 0;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
static void
|
||||
cut_stream (FILE *stream)
|
||||
{
|
||||
- if (operating_mode == 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 == 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 = 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 == field_mode)
|
||||
+ cut_fields (stream);
|
||||
+ else
|
||||
+ cut_bytes (stream);
|
||||
+ }
|
||||
}
|
||||
|
||||
/* Process file FILE to standard output.
|
||||
@@ -483,6 +836,7 @@ main (int argc, char **argv)
|
||||
bool ok;
|
||||
bool delim_specified = false;
|
||||
char *spec_list_string IF_LINT ( = NULL);
|
||||
+ char mbdelim[MB_LEN_MAX + 1];
|
||||
|
||||
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 != undefined_mode)
|
||||
FATAL_ERROR (_("only one type of list may be specified"));
|
||||
@@ -513,6 +866,14 @@ main (int argc, char **argv)
|
||||
spec_list_string = optarg;
|
||||
break;
|
||||
|
||||
+ case 'c':
|
||||
+ /* Build the character list. */
|
||||
+ if (operating_mode != undefined_mode)
|
||||
+ FATAL_ERROR (_("only one type of list may be specified"));
|
||||
+ operating_mode = character_mode;
|
||||
+ spec_list_string = optarg;
|
||||
+ break;
|
||||
+
|
||||
case 'f':
|
||||
/* Build the field list. */
|
||||
if (operating_mode != 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] != '\0' && optarg[1] != '\0')
|
||||
- FATAL_ERROR (_("the delimiter must be a single character"));
|
||||
- delim = optarg[0];
|
||||
- delim_specified = true;
|
||||
+ {
|
||||
+#if HAVE_MBRTOWC
|
||||
+ if(MB_CUR_MAX > 1)
|
||||
+ {
|
||||
+ mbstate_t state;
|
||||
+
|
||||
+ memset (&state, '\0', sizeof(mbstate_t));
|
||||
+ delimlen = mbrtowc (&wcdelim, optarg, strnlen(optarg, MB_LEN_MAX), &state);
|
||||
+
|
||||
+ if (delimlen == (size_t)-1 || delimlen == (size_t)-2)
|
||||
+ ++force_singlebyte_mode;
|
||||
+ else
|
||||
+ {
|
||||
+ delimlen = (delimlen < 1) ? 1 : delimlen;
|
||||
+ if (wcdelim != L'\0' && *(optarg + delimlen) != '\0')
|
||||
+ FATAL_ERROR (_("the delimiter must be a single character"));
|
||||
+ memcpy (mbdelim, optarg, delimlen);
|
||||
+ mbdelim[delimlen] = '\0';
|
||||
+ if (delimlen == 1)
|
||||
+ delim = *optarg;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (MB_CUR_MAX <= 1 || force_singlebyte_mode)
|
||||
+#endif
|
||||
+ {
|
||||
+ if (optarg[0] != '\0' && optarg[1] != '\0')
|
||||
+ FATAL_ERROR (_("the delimiter must be a single character"));
|
||||
+ delim = (unsigned char) optarg[0];
|
||||
+ }
|
||||
+ delim_specified = true;
|
||||
+ }
|
||||
break;
|
||||
|
||||
case OUTPUT_DELIMITER_OPTION:
|
||||
@@ -540,6 +929,7 @@ main (int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
+ byte_mode_character_aware = 1;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
@@ -579,15 +969,34 @@ main (int argc, char **argv)
|
||||
| (complement ? SETFLD_COMPLEMENT : 0) );
|
||||
|
||||
if (!delim_specified)
|
||||
- delim = '\t';
|
||||
+ {
|
||||
+ delim = '\t';
|
||||
+#ifdef HAVE_MBRTOWC
|
||||
+ wcdelim = L'\t';
|
||||
+ mbdelim[0] = '\t';
|
||||
+ mbdelim[1] = '\0';
|
||||
+ delimlen = 1;
|
||||
+#endif
|
||||
+ }
|
||||
|
||||
if (output_delimiter_string == NULL)
|
||||
{
|
||||
- static char dummy[2];
|
||||
- dummy[0] = delim;
|
||||
- dummy[1] = '\0';
|
||||
- output_delimiter_string = dummy;
|
||||
- output_delimiter_length = 1;
|
||||
+#ifdef HAVE_MBRTOWC
|
||||
+ if (MB_CUR_MAX > 1 && !force_singlebyte_mode)
|
||||
+ {
|
||||
+ output_delimiter_string = xstrdup(mbdelim);
|
||||
+ output_delimiter_length = delimlen;
|
||||
+ }
|
||||
+
|
||||
+ if (MB_CUR_MAX <= 1 || force_singlebyte_mode)
|
||||
+#endif
|
||||
+ {
|
||||
+ static char dummy[2];
|
||||
+ dummy[0] = delim;
|
||||
+ dummy[1] = '\0';
|
||||
+ output_delimiter_string = dummy;
|
||||
+ output_delimiter_length = 1;
|
||||
+ }
|
||||
}
|
||||
|
||||
if (optind == argc)
|
|
@ -0,0 +1,848 @@
|
|||
From e87ab5b991b08092a7e07af82b3ec822a8604151 Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Oprala <ooprala@redhat.com>
|
||||
Date: Wed, 5 Aug 2015 09:15:09 +0200
|
||||
Subject: [PATCH] expand,unexpand: add multibyte support
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
* NEWS: Mention the changes.
|
||||
* bootstrap.conf: Add mbfile to the list of modules.
|
||||
* configure.ac: Properly initialize mbfile.
|
||||
* src/expand.c (expand): Iterate over multibyte characters properly.
|
||||
* src/unexpand.c (unexpand): Iterate over multibyte characters
|
||||
properly.
|
||||
* tests/local.mk: Add new tests.
|
||||
* tests/{expand,unexpand}/mb.sh: New tests.
|
||||
|
||||
Co-authored-by: Pádraig Brady <pbrady@redhat.com>
|
||||
---
|
||||
bootstrap.conf | 1 +
|
||||
configure.ac | 2 +
|
||||
lib/mbfile.c | 3 +
|
||||
lib/mbfile.h | 255 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
m4/mbfile.m4 | 14 +++
|
||||
src/expand.c | 43 +++++----
|
||||
src/unexpand.c | 54 +++++++----
|
||||
tests/expand/mb.sh | 98 ++++++++++++++++++++
|
||||
tests/local.mk | 2 +
|
||||
tests/unexpand/mb.sh | 97 ++++++++++++++++++++
|
||||
10 files changed, 535 insertions(+), 34 deletions(-)
|
||||
create mode 100644 lib/mbfile.c
|
||||
create mode 100644 lib/mbfile.h
|
||||
create mode 100644 m4/mbfile.m4
|
||||
create mode 100755 tests/expand/mb.sh
|
||||
create mode 100755 tests/unexpand/mb.sh
|
||||
|
||||
diff --git a/bootstrap.conf b/bootstrap.conf
|
||||
index 8a0ff31..a1c78b2 100644
|
||||
--- a/bootstrap.conf
|
||||
+++ b/bootstrap.conf
|
||||
@@ -152,6 +152,7 @@ gnulib_modules="
|
||||
maintainer-makefile
|
||||
malloc-gnu
|
||||
manywarnings
|
||||
+ mbfile
|
||||
mbrlen
|
||||
mbrtowc
|
||||
mbsalign
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index 1e74b36..24c9725 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -427,6 +427,8 @@ fi
|
||||
# I'm leaving it here for now. This whole thing needs to be modernized...
|
||||
gl_WINSIZE_IN_PTEM
|
||||
|
||||
+gl_MBFILE
|
||||
+
|
||||
gl_HEADER_TIOCGWINSZ_IN_TERMIOS_H
|
||||
|
||||
if test $gl_cv_sys_tiocgwinsz_needs_termios_h = no && \
|
||||
diff --git a/lib/mbfile.c b/lib/mbfile.c
|
||||
new file mode 100644
|
||||
index 0000000..b0a468e
|
||||
--- /dev/null
|
||||
+++ b/lib/mbfile.c
|
||||
@@ -0,0 +1,3 @@
|
||||
+#include <config.h>
|
||||
+#define MBFILE_INLINE _GL_EXTERN_INLINE
|
||||
+#include "mbfile.h"
|
||||
diff --git a/lib/mbfile.h b/lib/mbfile.h
|
||||
new file mode 100644
|
||||
index 0000000..11f1b12
|
||||
--- /dev/null
|
||||
+++ b/lib/mbfile.h
|
||||
@@ -0,0 +1,255 @@
|
||||
+/* Multibyte character I/O: macros for multi-byte encodings.
|
||||
+ Copyright (C) 2001, 2005, 2009-2015 Free Software Foundation, Inc.
|
||||
+
|
||||
+ This program is free software: you can redistribute it and/or modify
|
||||
+ it under the terms of the GNU General Public License as published by
|
||||
+ the Free Software Foundation; either version 3 of the License, or
|
||||
+ (at your option) any later version.
|
||||
+
|
||||
+ This program is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ GNU General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU General Public License
|
||||
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+/* Written by Mitsuru Chinen <mchinen@yamato.ibm.com>
|
||||
+ and Bruno Haible <bruno@clisp.org>. */
|
||||
+
|
||||
+/* The macros in this file implement multi-byte character input from a
|
||||
+ stream.
|
||||
+
|
||||
+ mb_file_t
|
||||
+ is the type for multibyte character input stream, usable for variable
|
||||
+ declarations.
|
||||
+
|
||||
+ mbf_char_t
|
||||
+ is the type for multibyte character or EOF, usable for variable
|
||||
+ declarations.
|
||||
+
|
||||
+ mbf_init (mbf, stream)
|
||||
+ initializes the MB_FILE for reading from stream.
|
||||
+
|
||||
+ mbf_getc (mbc, mbf)
|
||||
+ reads the next multibyte character from mbf and stores it in mbc.
|
||||
+
|
||||
+ mb_iseof (mbc)
|
||||
+ returns true if mbc represents the EOF value.
|
||||
+
|
||||
+ Here are the function prototypes of the macros.
|
||||
+
|
||||
+ extern void mbf_init (mb_file_t mbf, FILE *stream);
|
||||
+ extern void mbf_getc (mbf_char_t mbc, mb_file_t mbf);
|
||||
+ extern bool mb_iseof (const mbf_char_t mbc);
|
||||
+ */
|
||||
+
|
||||
+#ifndef _MBFILE_H
|
||||
+#define _MBFILE_H 1
|
||||
+
|
||||
+#include <assert.h>
|
||||
+#include <stdbool.h>
|
||||
+#include <stdio.h>
|
||||
+#include <string.h>
|
||||
+
|
||||
+/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
|
||||
+ <wchar.h>.
|
||||
+ BSD/OS 4.1 has a bug: <stdio.h> and <time.h> must be included before
|
||||
+ <wchar.h>. */
|
||||
+#include <stdio.h>
|
||||
+#include <time.h>
|
||||
+#include <wchar.h>
|
||||
+
|
||||
+#include "mbchar.h"
|
||||
+
|
||||
+#ifndef _GL_INLINE_HEADER_BEGIN
|
||||
+ #error "Please include config.h first."
|
||||
+#endif
|
||||
+_GL_INLINE_HEADER_BEGIN
|
||||
+#ifndef MBFILE_INLINE
|
||||
+# define MBFILE_INLINE _GL_INLINE
|
||||
+#endif
|
||||
+
|
||||
+struct mbfile_multi {
|
||||
+ FILE *fp;
|
||||
+ bool eof_seen;
|
||||
+ bool have_pushback;
|
||||
+ mbstate_t state;
|
||||
+ unsigned int bufcount;
|
||||
+ char buf[MBCHAR_BUF_SIZE];
|
||||
+ struct mbchar pushback;
|
||||
+};
|
||||
+
|
||||
+MBFILE_INLINE void
|
||||
+mbfile_multi_getc (struct mbchar *mbc, struct mbfile_multi *mbf)
|
||||
+{
|
||||
+ size_t bytes;
|
||||
+
|
||||
+ /* If EOF has already been seen, don't use getc. This matters if
|
||||
+ mbf->fp is connected to an interactive tty. */
|
||||
+ if (mbf->eof_seen)
|
||||
+ goto eof;
|
||||
+
|
||||
+ /* Return character pushed back, if there is one. */
|
||||
+ if (mbf->have_pushback)
|
||||
+ {
|
||||
+ mb_copy (mbc, &mbf->pushback);
|
||||
+ mbf->have_pushback = false;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* Before using mbrtowc, we need at least one byte. */
|
||||
+ if (mbf->bufcount == 0)
|
||||
+ {
|
||||
+ int c = getc (mbf->fp);
|
||||
+ if (c == EOF)
|
||||
+ {
|
||||
+ mbf->eof_seen = true;
|
||||
+ goto eof;
|
||||
+ }
|
||||
+ mbf->buf[0] = (unsigned char) c;
|
||||
+ mbf->bufcount++;
|
||||
+ }
|
||||
+
|
||||
+ /* Handle most ASCII characters quickly, without calling mbrtowc(). */
|
||||
+ if (mbf->bufcount == 1 && mbsinit (&mbf->state) && is_basic (mbf->buf[0]))
|
||||
+ {
|
||||
+ /* These characters are part of the basic character set. ISO C 99
|
||||
+ guarantees that their wide character code is identical to their
|
||||
+ char code. */
|
||||
+ mbc->wc = mbc->buf[0] = mbf->buf[0];
|
||||
+ mbc->wc_valid = true;
|
||||
+ mbc->ptr = &mbc->buf[0];
|
||||
+ mbc->bytes = 1;
|
||||
+ mbf->bufcount = 0;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* Use mbrtowc on an increasing number of bytes. Read only as many bytes
|
||||
+ from mbf->fp as needed. This is needed to give reasonable interactive
|
||||
+ behaviour when mbf->fp is connected to an interactive tty. */
|
||||
+ for (;;)
|
||||
+ {
|
||||
+ /* We don't know whether the 'mbrtowc' function updates the state when
|
||||
+ it returns -2, - this is the ISO C 99 and glibc-2.2 behaviour - or
|
||||
+ not - amended ANSI C, glibc-2.1 and Solaris 2.7 behaviour. We
|
||||
+ don't have an autoconf test for this, yet.
|
||||
+ The new behaviour would allow us to feed the bytes one by one into
|
||||
+ mbrtowc. But the old behaviour forces us to feed all bytes since
|
||||
+ the end of the last character into mbrtowc. Since we want to retry
|
||||
+ with more bytes when mbrtowc returns -2, we must backup the state
|
||||
+ before calling mbrtowc, because implementations with the new
|
||||
+ behaviour will clobber it. */
|
||||
+ mbstate_t backup_state = mbf->state;
|
||||
+
|
||||
+ bytes = mbrtowc (&mbc->wc, &mbf->buf[0], mbf->bufcount, &mbf->state);
|
||||
+
|
||||
+ if (bytes == (size_t) -1)
|
||||
+ {
|
||||
+ /* An invalid multibyte sequence was encountered. */
|
||||
+ /* Return a single byte. */
|
||||
+ bytes = 1;
|
||||
+ mbc->wc_valid = false;
|
||||
+ break;
|
||||
+ }
|
||||
+ else if (bytes == (size_t) -2)
|
||||
+ {
|
||||
+ /* An incomplete multibyte character. */
|
||||
+ mbf->state = backup_state;
|
||||
+ if (mbf->bufcount == MBCHAR_BUF_SIZE)
|
||||
+ {
|
||||
+ /* An overlong incomplete multibyte sequence was encountered. */
|
||||
+ /* Return a single byte. */
|
||||
+ bytes = 1;
|
||||
+ mbc->wc_valid = false;
|
||||
+ break;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /* Read one more byte and retry mbrtowc. */
|
||||
+ int c = getc (mbf->fp);
|
||||
+ if (c == EOF)
|
||||
+ {
|
||||
+ /* An incomplete multibyte character at the end. */
|
||||
+ mbf->eof_seen = true;
|
||||
+ bytes = mbf->bufcount;
|
||||
+ mbc->wc_valid = false;
|
||||
+ break;
|
||||
+ }
|
||||
+ mbf->buf[mbf->bufcount] = (unsigned char) c;
|
||||
+ mbf->bufcount++;
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ if (bytes == 0)
|
||||
+ {
|
||||
+ /* A null wide character was encountered. */
|
||||
+ bytes = 1;
|
||||
+ assert (mbf->buf[0] == '\0');
|
||||
+ assert (mbc->wc == 0);
|
||||
+ }
|
||||
+ mbc->wc_valid = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Return the multibyte sequence mbf->buf[0..bytes-1]. */
|
||||
+ mbc->ptr = &mbc->buf[0];
|
||||
+ memcpy (&mbc->buf[0], &mbf->buf[0], bytes);
|
||||
+ mbc->bytes = bytes;
|
||||
+
|
||||
+ mbf->bufcount -= bytes;
|
||||
+ if (mbf->bufcount > 0)
|
||||
+ {
|
||||
+ /* It's not worth calling memmove() for so few bytes. */
|
||||
+ unsigned int count = mbf->bufcount;
|
||||
+ char *p = &mbf->buf[0];
|
||||
+
|
||||
+ do
|
||||
+ {
|
||||
+ *p = *(p + bytes);
|
||||
+ p++;
|
||||
+ }
|
||||
+ while (--count > 0);
|
||||
+ }
|
||||
+ return;
|
||||
+
|
||||
+eof:
|
||||
+ /* An mbchar_t with bytes == 0 is used to indicate EOF. */
|
||||
+ mbc->ptr = NULL;
|
||||
+ mbc->bytes = 0;
|
||||
+ mbc->wc_valid = false;
|
||||
+ return;
|
||||
+}
|
||||
+
|
||||
+MBFILE_INLINE void
|
||||
+mbfile_multi_ungetc (const struct mbchar *mbc, struct mbfile_multi *mbf)
|
||||
+{
|
||||
+ mb_copy (&mbf->pushback, mbc);
|
||||
+ mbf->have_pushback = true;
|
||||
+}
|
||||
+
|
||||
+typedef struct mbfile_multi mb_file_t;
|
||||
+
|
||||
+typedef mbchar_t mbf_char_t;
|
||||
+
|
||||
+#define mbf_init(mbf, stream) \
|
||||
+ ((mbf).fp = (stream), \
|
||||
+ (mbf).eof_seen = false, \
|
||||
+ (mbf).have_pushback = false, \
|
||||
+ memset (&(mbf).state, '\0', sizeof (mbstate_t)), \
|
||||
+ (mbf).bufcount = 0)
|
||||
+
|
||||
+#define mbf_getc(mbc, mbf) mbfile_multi_getc (&(mbc), &(mbf))
|
||||
+
|
||||
+#define mbf_ungetc(mbc, mbf) mbfile_multi_ungetc (&(mbc), &(mbf))
|
||||
+
|
||||
+#define mb_iseof(mbc) ((mbc).bytes == 0)
|
||||
+
|
||||
+#ifndef _GL_INLINE_HEADER_BEGIN
|
||||
+ #error "Please include config.h first."
|
||||
+#endif
|
||||
+_GL_INLINE_HEADER_BEGIN
|
||||
+
|
||||
+#endif /* _MBFILE_H */
|
||||
diff --git a/m4/mbfile.m4 b/m4/mbfile.m4
|
||||
new file mode 100644
|
||||
index 0000000..8589902
|
||||
--- /dev/null
|
||||
+++ b/m4/mbfile.m4
|
||||
@@ -0,0 +1,14 @@
|
||||
+# mbfile.m4 serial 7
|
||||
+dnl Copyright (C) 2005, 2008-2015 Free Software Foundation, Inc.
|
||||
+dnl This file is free software; the Free Software Foundation
|
||||
+dnl gives unlimited permission to copy and/or distribute it,
|
||||
+dnl with or without modifications, as long as this notice is preserved.
|
||||
+
|
||||
+dnl autoconf tests required for use of mbfile.h
|
||||
+dnl From Bruno Haible.
|
||||
+
|
||||
+AC_DEFUN([gl_MBFILE],
|
||||
+[
|
||||
+ AC_REQUIRE([AC_TYPE_MBSTATE_T])
|
||||
+ :
|
||||
+])
|
||||
diff --git a/src/expand.c b/src/expand.c
|
||||
index 9fa2e10..380e020 100644
|
||||
--- a/src/expand.c
|
||||
+++ b/src/expand.c
|
||||
@@ -37,6 +37,9 @@
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
+
|
||||
+#include <mbfile.h>
|
||||
+
|
||||
#include "system.h"
|
||||
#include "die.h"
|
||||
#include "xstrndup.h"
|
||||
@@ -100,19 +103,19 @@ expand (void)
|
||||
{
|
||||
/* Input stream. */
|
||||
FILE *fp = next_file (NULL);
|
||||
+ mb_file_t mbf;
|
||||
+ mbf_char_t c;
|
||||
|
||||
if (!fp)
|
||||
return;
|
||||
|
||||
+ mbf_init (mbf, fp);
|
||||
+
|
||||
while (true)
|
||||
{
|
||||
- /* Input character, or EOF. */
|
||||
- int c;
|
||||
-
|
||||
/* If true, perform translations. */
|
||||
bool convert = true;
|
||||
|
||||
-
|
||||
/* The following variables have valid values only when CONVERT
|
||||
is true: */
|
||||
|
||||
@@ -122,17 +125,23 @@ expand (void)
|
||||
/* Index in TAB_LIST of next tab stop to examine. */
|
||||
size_t tab_index = 0;
|
||||
|
||||
-
|
||||
/* Convert a line of text. */
|
||||
|
||||
do
|
||||
{
|
||||
- while ((c = getc (fp)) < 0 && (fp = next_file (fp)))
|
||||
- continue;
|
||||
+ do {
|
||||
+ mbf_getc (c, mbf);
|
||||
+ if (mb_iseof (c))
|
||||
+ {
|
||||
+ mbf_init (mbf, fp = next_file (fp));
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+ while (false);
|
||||
|
||||
if (convert)
|
||||
{
|
||||
- if (c == '\t')
|
||||
+ if (mb_iseq (c, '\t'))
|
||||
{
|
||||
/* Column the next input tab stop is on. */
|
||||
uintmax_t next_tab_column;
|
||||
@@ -151,32 +160,34 @@ expand (void)
|
||||
if (putchar (' ') < 0)
|
||||
die (EXIT_FAILURE, errno, _("write error"));
|
||||
|
||||
- c = ' ';
|
||||
+ mb_setascii (&c, ' ');
|
||||
}
|
||||
- else if (c == '\b')
|
||||
+ else if (mb_iseq (c, '\b'))
|
||||
{
|
||||
/* Go back one column, and force recalculation of the
|
||||
next tab stop. */
|
||||
column -= !!column;
|
||||
tab_index -= !!tab_index;
|
||||
}
|
||||
- else
|
||||
+ /* A leading control character could make us trip over. */
|
||||
+ else if (!mb_iscntrl (c))
|
||||
{
|
||||
- column++;
|
||||
+ column += mb_width (c);
|
||||
if (!column)
|
||||
die (EXIT_FAILURE, 0, _("input line is too long"));
|
||||
}
|
||||
|
||||
- convert &= convert_entire_line || !! isblank (c);
|
||||
+ convert &= convert_entire_line || mb_isblank (c);
|
||||
}
|
||||
|
||||
- if (c < 0)
|
||||
+ if (mb_iseof (c))
|
||||
return;
|
||||
|
||||
- if (putchar (c) < 0)
|
||||
+ mb_putc (c, stdout);
|
||||
+ if (ferror (stdout))
|
||||
die (EXIT_FAILURE, errno, _("write error"));
|
||||
}
|
||||
- while (c != '\n');
|
||||
+ while (!mb_iseq (c, '\n'));
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/unexpand.c b/src/unexpand.c
|
||||
index 7801274..569a7ee 100644
|
||||
--- a/src/unexpand.c
|
||||
+++ b/src/unexpand.c
|
||||
@@ -38,6 +38,9 @@
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
+
|
||||
+#include <mbfile.h>
|
||||
+
|
||||
#include "system.h"
|
||||
#include "die.h"
|
||||
#include "xstrndup.h"
|
||||
@@ -107,11 +110,12 @@ unexpand (void)
|
||||
{
|
||||
/* Input stream. */
|
||||
FILE *fp = next_file (NULL);
|
||||
+ mb_file_t mbf;
|
||||
|
||||
/* The array of pending blanks. In non-POSIX locales, blanks can
|
||||
include characters other than spaces, so the blanks must be
|
||||
stored, not merely counted. */
|
||||
- char *pending_blank;
|
||||
+ mbf_char_t *pending_blank;
|
||||
|
||||
if (!fp)
|
||||
return;
|
||||
@@ -119,12 +123,14 @@ unexpand (void)
|
||||
/* The worst case is a non-blank character, then one blank, then a
|
||||
tab stop, then MAX_COLUMN_WIDTH - 1 blanks, then a non-blank; so
|
||||
allocate MAX_COLUMN_WIDTH bytes to store the blanks. */
|
||||
- pending_blank = xmalloc (max_column_width);
|
||||
+ pending_blank = xmalloc (max_column_width * sizeof (mbf_char_t));
|
||||
+
|
||||
+ mbf_init (mbf, fp);
|
||||
|
||||
while (true)
|
||||
{
|
||||
/* Input character, or EOF. */
|
||||
- int c;
|
||||
+ mbf_char_t c;
|
||||
|
||||
/* If true, perform translations. */
|
||||
bool convert = true;
|
||||
@@ -158,12 +164,19 @@ unexpand (void)
|
||||
|
||||
do
|
||||
{
|
||||
- while ((c = getc (fp)) < 0 && (fp = next_file (fp)))
|
||||
- continue;
|
||||
+ do {
|
||||
+ mbf_getc (c, mbf);
|
||||
+ if (mb_iseof (c))
|
||||
+ {
|
||||
+ mbf_init (mbf, fp = next_file (fp));
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+ while (false);
|
||||
|
||||
if (convert)
|
||||
{
|
||||
- bool blank = !! isblank (c);
|
||||
+ bool blank = mb_isblank (c);
|
||||
|
||||
if (blank)
|
||||
{
|
||||
@@ -180,16 +193,16 @@ unexpand (void)
|
||||
if (next_tab_column < column)
|
||||
die (EXIT_FAILURE, 0, _("input line is too long"));
|
||||
|
||||
- if (c == '\t')
|
||||
+ if (mb_iseq (c, '\t'))
|
||||
{
|
||||
column = next_tab_column;
|
||||
|
||||
if (pending)
|
||||
- pending_blank[0] = '\t';
|
||||
+ mb_setascii (&pending_blank[0], '\t');
|
||||
}
|
||||
else
|
||||
{
|
||||
- column++;
|
||||
+ column += mb_width (c);
|
||||
|
||||
if (! (prev_blank && column == next_tab_column))
|
||||
{
|
||||
@@ -197,13 +210,14 @@ unexpand (void)
|
||||
will be replaced by tabs. */
|
||||
if (column == next_tab_column)
|
||||
one_blank_before_tab_stop = true;
|
||||
- pending_blank[pending++] = c;
|
||||
+ mb_copy (&pending_blank[pending++], &c);
|
||||
prev_blank = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Replace the pending blanks by a tab or two. */
|
||||
- pending_blank[0] = c = '\t';
|
||||
+ mb_setascii (&c, '\t');
|
||||
+ mb_setascii (&pending_blank[0], '\t');
|
||||
}
|
||||
|
||||
/* Discard pending blanks, unless it was a single
|
||||
@@ -211,7 +225,7 @@ unexpand (void)
|
||||
pending = one_blank_before_tab_stop;
|
||||
}
|
||||
}
|
||||
- else if (c == '\b')
|
||||
+ else if (mb_iseq (c, '\b'))
|
||||
{
|
||||
/* Go back one column, and force recalculation of the
|
||||
next tab stop. */
|
||||
@@ -221,7 +235,7 @@ unexpand (void)
|
||||
}
|
||||
else
|
||||
{
|
||||
- column++;
|
||||
+ column += mb_width (c);
|
||||
if (!column)
|
||||
die (EXIT_FAILURE, 0, _("input line is too long"));
|
||||
}
|
||||
@@ -229,8 +243,11 @@ unexpand (void)
|
||||
if (pending)
|
||||
{
|
||||
if (pending > 1 && one_blank_before_tab_stop)
|
||||
- pending_blank[0] = '\t';
|
||||
- if (fwrite (pending_blank, 1, pending, stdout) != pending)
|
||||
+ mb_setascii (&pending_blank[0], '\t');
|
||||
+
|
||||
+ for (int n = 0; n < pending; ++n)
|
||||
+ mb_putc (pending_blank[n], stdout);
|
||||
+ if (ferror (stdout))
|
||||
die (EXIT_FAILURE, errno, _("write error"));
|
||||
pending = 0;
|
||||
one_blank_before_tab_stop = false;
|
||||
@@ -240,16 +257,17 @@ unexpand (void)
|
||||
convert &= convert_entire_line || blank;
|
||||
}
|
||||
|
||||
- if (c < 0)
|
||||
+ if (mb_iseof (c))
|
||||
{
|
||||
free (pending_blank);
|
||||
return;
|
||||
}
|
||||
|
||||
- if (putchar (c) < 0)
|
||||
+ mb_putc (c, stdout);
|
||||
+ if (ferror (stdout))
|
||||
die (EXIT_FAILURE, errno, _("write error"));
|
||||
}
|
||||
- while (c != '\n');
|
||||
+ while (!mb_iseq (c, '\n'));
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/tests/expand/mb.sh b/tests/expand/mb.sh
|
||||
new file mode 100755
|
||||
index 0000000..7971e18
|
||||
--- /dev/null
|
||||
+++ b/tests/expand/mb.sh
|
||||
@@ -0,0 +1,98 @@
|
||||
+#!/bin/sh
|
||||
+
|
||||
+# Copyright (C) 2012-2015 Free Software Foundation, Inc.
|
||||
+
|
||||
+# This program is free software: you can redistribute it and/or modify
|
||||
+# it under the terms of the GNU General Public License as published by
|
||||
+# the Free Software Foundation, either version 3 of the License, or
|
||||
+# (at your option) any later version.
|
||||
+
|
||||
+# This program is distributed in the hope that it will be useful,
|
||||
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+# GNU General Public License for more details.
|
||||
+
|
||||
+# You should have received a copy of the GNU General Public License
|
||||
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
+
|
||||
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
|
||||
+print_ver_ expand
|
||||
+
|
||||
+export LC_ALL=en_US.UTF-8
|
||||
+
|
||||
+#input containing multibyte characters
|
||||
+cat <<\EOF > in || framework_failure_
|
||||
+1234567812345678123456781
|
||||
+. . . .
|
||||
+a b c d
|
||||
+. . . .
|
||||
+ä ö ü ß
|
||||
+. . . .
|
||||
+EOF
|
||||
+env printf ' äöü\t. öüä. \tä xx\n' >> in || framework_failure_
|
||||
+
|
||||
+cat <<\EOF > exp || framework_failure_
|
||||
+1234567812345678123456781
|
||||
+. . . .
|
||||
+a b c d
|
||||
+. . . .
|
||||
+ä ö ü ß
|
||||
+. . . .
|
||||
+ äöü . öüä. ä xx
|
||||
+EOF
|
||||
+
|
||||
+expand < in > out || fail=1
|
||||
+compare exp out > /dev/null 2>&1 || fail=1
|
||||
+
|
||||
+#test characters with display widths != 1
|
||||
+env printf '12345678
|
||||
+e\t|ascii(1)
|
||||
+\u00E9\t|composed(1)
|
||||
+e\u0301\t|decomposed(1)
|
||||
+\u3000\t|ideo-space(2)
|
||||
+\uFF0D\t|full-hypen(2)
|
||||
+' > in || framework_failure_
|
||||
+
|
||||
+env printf '12345678
|
||||
+e |ascii(1)
|
||||
+\u00E9 |composed(1)
|
||||
+e\u0301 |decomposed(1)
|
||||
+\u3000 |ideo-space(2)
|
||||
+\uFF0D |full-hypen(2)
|
||||
+' > exp || framework_failure_
|
||||
+
|
||||
+expand < in > out || fail=1
|
||||
+compare exp out > /dev/null 2>&1 || fail=1
|
||||
+
|
||||
+#shouldn't fail with "input line too long"
|
||||
+#when a line starts with a control character
|
||||
+env printf '\n' > in || framework_failure_
|
||||
+
|
||||
+expand < in > out || fail=1
|
||||
+compare in out > /dev/null 2>&1 || fail=1
|
||||
+
|
||||
+#non-Unicode characters interspersed between Unicode ones
|
||||
+env printf '12345678
|
||||
+\t\xFF|
|
||||
+\xFF\t|
|
||||
+\t\xFFä|
|
||||
+ä\xFF\t|
|
||||
+\tä\xFF|
|
||||
+\xFF\tä|
|
||||
+äbcdef\xFF\t|
|
||||
+' > in || framework_failure_
|
||||
+
|
||||
+env printf '12345678
|
||||
+ \xFF|
|
||||
+\xFF |
|
||||
+ \xFFä|
|
||||
+ä\xFF |
|
||||
+ ä\xFF|
|
||||
+\xFF ä|
|
||||
+äbcdef\xFF |
|
||||
+' > exp || framework_failure_
|
||||
+
|
||||
+expand < in > out || fail=1
|
||||
+compare exp out > /dev/null 2>&1 || fail=1
|
||||
+
|
||||
+exit $fail
|
||||
diff --git a/tests/local.mk b/tests/local.mk
|
||||
index 192f776..8053397 100644
|
||||
--- a/tests/local.mk
|
||||
+++ b/tests/local.mk
|
||||
@@ -544,6 +544,7 @@ all_tests = \
|
||||
tests/du/threshold.sh \
|
||||
tests/du/trailing-slash.sh \
|
||||
tests/du/two-args.sh \
|
||||
+ tests/expand/mb.sh \
|
||||
tests/id/gnu-zero-uids.sh \
|
||||
tests/id/no-context.sh \
|
||||
tests/id/context.sh \
|
||||
@@ -684,6 +685,7 @@ all_tests = \
|
||||
tests/touch/read-only.sh \
|
||||
tests/touch/relative.sh \
|
||||
tests/touch/trailing-slash.sh \
|
||||
+ tests/unexpand/mb.sh \
|
||||
$(all_root_tests)
|
||||
|
||||
# See tests/factor/create-test.sh.
|
||||
diff --git a/tests/unexpand/mb.sh b/tests/unexpand/mb.sh
|
||||
new file mode 100755
|
||||
index 0000000..60d4c1a
|
||||
--- /dev/null
|
||||
+++ b/tests/unexpand/mb.sh
|
||||
@@ -0,0 +1,97 @@
|
||||
+#!/bin/sh
|
||||
+
|
||||
+# Copyright (C) 2012-2015 Free Software Foundation, Inc.
|
||||
+
|
||||
+# This program is free software: you can redistribute it and/or modify
|
||||
+# it under the terms of the GNU General Public License as published by
|
||||
+# the Free Software Foundation, either version 3 of the License, or
|
||||
+# (at your option) any later version.
|
||||
+
|
||||
+# This program is distributed in the hope that it will be useful,
|
||||
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+# GNU General Public License for more details.
|
||||
+
|
||||
+# You should have received a copy of the GNU General Public License
|
||||
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
+
|
||||
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
|
||||
+print_ver_ unexpand
|
||||
+
|
||||
+export LC_ALL=en_US.UTF-8
|
||||
+
|
||||
+#input containing multibyte characters
|
||||
+cat > in <<\EOF
|
||||
+1234567812345678123456781
|
||||
+. . . .
|
||||
+a b c d
|
||||
+. . . .
|
||||
+ä ö ü ß
|
||||
+. . . .
|
||||
+ äöü . öüä. ä xx
|
||||
+EOF
|
||||
+
|
||||
+cat > exp <<\EOF
|
||||
+1234567812345678123456781
|
||||
+. . . .
|
||||
+a b c d
|
||||
+. . . .
|
||||
+ä ö ü ß
|
||||
+. . . .
|
||||
+ äöü . öüä. ä xx
|
||||
+EOF
|
||||
+
|
||||
+unexpand -a < in > out || fail=1
|
||||
+compare exp out > /dev/null 2>&1 || fail=1
|
||||
+
|
||||
+#test characters with a display width larger than 1
|
||||
+
|
||||
+env printf '12345678
|
||||
+e |ascii(1)
|
||||
+\u00E9 |composed(1)
|
||||
+e\u0301 |decomposed(1)
|
||||
+\u3000 |ideo-space(2)
|
||||
+\uFF0D |full-hypen(2)
|
||||
+' > in || framework_failure_
|
||||
+
|
||||
+env printf '12345678
|
||||
+e\t|ascii(1)
|
||||
+\u00E9\t|composed(1)
|
||||
+e\u0301\t|decomposed(1)
|
||||
+\u3000\t|ideo-space(2)
|
||||
+\uFF0D\t|full-hypen(2)
|
||||
+' > exp || framework_failure_
|
||||
+
|
||||
+unexpand -a < in > out || fail=1
|
||||
+compare exp out > /dev/null 2>&1 || fail=1
|
||||
+
|
||||
+#test input where a blank of width > 1 is not being substituted
|
||||
+in="$(LC_ALL=en_US.UTF-8 printf ' \u3000 ö ü ß')"
|
||||
+exp=' ö ü ß'
|
||||
+
|
||||
+unexpand -a < in > out || fail=1
|
||||
+compare exp out > /dev/null 2>&1 || fail=1
|
||||
+
|
||||
+#non-Unicode characters interspersed between Unicode ones
|
||||
+env printf '12345678
|
||||
+ \xFF|
|
||||
+\xFF |
|
||||
+ \xFFä|
|
||||
+ä\xFF |
|
||||
+ ä\xFF|
|
||||
+\xFF ä|
|
||||
+äbcdef\xFF |
|
||||
+' > in || framework_failure_
|
||||
+
|
||||
+env printf '12345678
|
||||
+\t\xFF|
|
||||
+\xFF\t|
|
||||
+\t\xFFä|
|
||||
+ä\xFF\t|
|
||||
+\tä\xFF|
|
||||
+\xFF\tä|
|
||||
+äbcdef\xFF\t|
|
||||
+' > exp || framework_failure_
|
||||
+
|
||||
+unexpand -a < in > out || fail=1
|
||||
+compare exp out > /dev/null 2>&1 || fail=1
|
||||
--
|
||||
2.7.4
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
From 02424bfcd719bbaa695f4e1c3ef17ad91b0d23c0 Mon Sep 17 00:00:00 2001
|
||||
From: Lubomir Rintel <lkundrak@v3.sk>
|
||||
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 = column;
|
||||
tab_index -= !!tab_index;
|
||||
}
|
||||
- else
|
||||
+ else if (!mb_iseq (c, '\n'))
|
||||
{
|
||||
column += mb_width (c);
|
||||
if (!column)
|
||||
--
|
||||
2.7.4
|
||||
|
|
@ -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)
|
||||
|
||||
do
|
||||
{
|
||||
- do {
|
||||
+ while (true) {
|
||||
mbf_getc (c, mbf);
|
||||
- if (mb_iseof (c))
|
||||
+ if ((mb_iseof (c)) && (fp = next_file (fp)))
|
||||
{
|
||||
- mbf_init (mbf, fp = next_file (fp));
|
||||
+ mbf_init (mbf, fp);
|
||||
continue;
|
||||
}
|
||||
+ else
|
||||
+ {
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
- while (false);
|
||||
+
|
||||
|
||||
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)
|
||||
|
||||
do
|
||||
{
|
||||
- do {
|
||||
+ while (true) {
|
||||
mbf_getc (c, mbf);
|
||||
- if (mb_iseof (c))
|
||||
+ if ((mb_iseof (c)) && (fp = next_file (fp)))
|
||||
{
|
||||
- mbf_init (mbf, fp = next_file (fp));
|
||||
+ mbf_init (mbf, fp);
|
||||
continue;
|
||||
}
|
||||
+ else
|
||||
+ {
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
- while (false);
|
||||
+
|
||||
|
||||
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=1
|
||||
compare exp out > /dev/null 2>&1 || fail=1
|
||||
|
||||
+#multiple files as an input
|
||||
+cat <<\EOF >> exp || framework_failure_
|
||||
+1234567812345678123456781
|
||||
+. . . .
|
||||
+a b c d
|
||||
+. . . .
|
||||
+ä ö ü ß
|
||||
+. . . .
|
||||
+ äöü . öüä. ä xx
|
||||
+EOF
|
||||
+
|
||||
+expand ./in ./in > out || fail=1
|
||||
+compare exp out > /dev/null 2>&1 || fail=1
|
||||
+
|
||||
#test characters with display widths != 1
|
||||
env printf '12345678
|
||||
e\t|ascii(1)
|
||||
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=1
|
||||
compare exp out > /dev/null 2>&1 || fail=1
|
||||
|
||||
+
|
||||
+#multiple files as an input
|
||||
+cat >> exp <<\EOF
|
||||
+1234567812345678123456781
|
||||
+. . . .
|
||||
+a b c d
|
||||
+. . . .
|
||||
+ä ö ü ß
|
||||
+. . . .
|
||||
+ äöü . öüä. ä xx
|
||||
+EOF
|
||||
+
|
||||
+
|
||||
+unexpand -a ./in ./in > out || fail=1
|
||||
+compare exp out > /dev/null 2>&1 || fail=1
|
||||
+
|
||||
#test characters with a display width larger than 1
|
||||
|
||||
env printf '12345678
|
|
@ -0,0 +1,80 @@
|
|||
From ff424639fe863cbd6963add1a79b97290c1606c6 Mon Sep 17 00:00:00 2001
|
||||
From: rpm-build <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)
|
||||
}
|
||||
|
||||
rescan:
|
||||
- if (operating_mode == byte_mode) /* byte mode */
|
||||
+ if (convfail)
|
||||
+ increment = 1;
|
||||
+ else if (wc == L'\n')
|
||||
+ {
|
||||
+ /* preserve newline */
|
||||
+ fwrite (line_out, sizeof(char), offset_out, stdout);
|
||||
+ START_NEW_LINE;
|
||||
+ continue;
|
||||
+ }
|
||||
+ else if (operating_mode == byte_mode) /* byte mode */
|
||||
increment = mblength;
|
||||
else if (operating_mode == character_mode) /* character mode */
|
||||
increment = 1;
|
||||
- else /* column mode */
|
||||
+ else /* column mode */
|
||||
{
|
||||
- if (convfail)
|
||||
- increment = 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 = (column > 0) ? -1 : 0;
|
||||
+ break;
|
||||
|
||||
- case L'\b':
|
||||
- increment = (column > 0) ? -1 : 0;
|
||||
- break;
|
||||
+ case L'\r':
|
||||
+ increment = -1 * column;
|
||||
+ break;
|
||||
|
||||
- case L'\r':
|
||||
- increment = -1 * column;
|
||||
- break;
|
||||
+ case L'\t':
|
||||
+ increment = 8 - column % 8;
|
||||
+ break;
|
||||
|
||||
- case L'\t':
|
||||
- increment = 8 - column % 8;
|
||||
- break;
|
||||
-
|
||||
- default:
|
||||
- increment = wcwidth (wc);
|
||||
- increment = (increment < 0) ? 0 : increment;
|
||||
- }
|
||||
+ default:
|
||||
+ increment = wcwidth (wc);
|
||||
+ increment = (increment < 0) ? 0 : increment;
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
2.7.4
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
From 3976ef5a20369d8b490907ab2cba2d617305a5e0 Mon Sep 17 00:00:00 2001
|
||||
From: Kamil Dudka <kdudka@redhat.com>
|
||||
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)
|
||||
<none/unknown> < K/k < M < G < T < P < E < Z < Y */
|
||||
|
||||
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));
|
||||
|
||||
int diff = find_unit_order (a) - find_unit_order (b);
|
||||
return (diff ? diff : strnumcmp (a, b, decimal_point, thousands_sep));
|
||||
--
|
||||
2.5.5
|
||||
|
|
@ -0,0 +1,456 @@
|
|||
From 7a7c776a4e228d180e74614fd8c8afcad5d4bdf7 Mon Sep 17 00:00:00 2001
|
||||
From: Jakub Martisko <jamartis@redhat.com>
|
||||
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 <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
+#include <mbfile.h>
|
||||
#include "system.h"
|
||||
#include "die.h"
|
||||
#include "error.h"
|
||||
@@ -126,6 +127,119 @@ set_increment_size (uintmax_t tabval)
|
||||
return ok;
|
||||
}
|
||||
|
||||
+extern int
|
||||
+set_utf_locale (void)
|
||||
+{
|
||||
+ /*try using some predefined locale */
|
||||
+ const char* predef_locales[] = {"C.UTF8","en_US.UTF8","en_GB.UTF8"};
|
||||
+
|
||||
+ const int predef_locales_count=3;
|
||||
+ for (int i=0;i<predef_locales_count;i++)
|
||||
+ {
|
||||
+ if (setlocale(LC_ALL,predef_locales[i])!=NULL)
|
||||
+ {
|
||||
+ break;
|
||||
+ }
|
||||
+ else if (i==predef_locales_count-1)
|
||||
+ {
|
||||
+ return 1;
|
||||
+ error (EXIT_FAILURE, errno, _("cannot set UTF-8 locale"));
|
||||
+ }
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+extern bool
|
||||
+check_utf_locale(void)
|
||||
+{
|
||||
+ char* locale = setlocale (LC_CTYPE , NULL);
|
||||
+ if (locale == NULL)
|
||||
+ {
|
||||
+ return false;
|
||||
+ }
|
||||
+ else if (strcasestr(locale, "utf8") == NULL && strcasestr(locale, "utf-8") == NULL)
|
||||
+ {
|
||||
+ return false;
|
||||
+ }
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+extern bool
|
||||
+check_bom(FILE* fp, mb_file_t *mbf)
|
||||
+{
|
||||
+ int c;
|
||||
+
|
||||
+
|
||||
+ c=fgetc(fp);
|
||||
+
|
||||
+ /*test BOM header of the first file */
|
||||
+ mbf->bufcount=0;
|
||||
+ if (c == 0xEF)
|
||||
+ {
|
||||
+ c=fgetc(fp);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ if (c != EOF)
|
||||
+ {
|
||||
+ ungetc(c,fp);
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ if (c == 0xBB)
|
||||
+ {
|
||||
+ c=fgetc(fp);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ if ( c!= EOF )
|
||||
+ {
|
||||
+ mbf->buf[0]=(unsigned char) 0xEF;
|
||||
+ mbf->bufcount=1;
|
||||
+ ungetc(c,fp);
|
||||
+ return false;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ ungetc(0xEF,fp);
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ if (c == 0xBF)
|
||||
+ {
|
||||
+ mbf->bufcount=0;
|
||||
+ return true;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ if (c != EOF)
|
||||
+ {
|
||||
+ mbf->buf[0]=(unsigned char) 0xEF;
|
||||
+ mbf->buf[1]=(unsigned char) 0xBB;
|
||||
+ mbf->bufcount=2;
|
||||
+ ungetc(c,fp);
|
||||
+ return false;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ mbf->buf[0]=(unsigned char) 0xEF;
|
||||
+ mbf->bufcount=1;
|
||||
+ 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;
|
||||
|
||||
+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 = 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=check_utf_locale();
|
||||
|
||||
if (!fp)
|
||||
return;
|
||||
-
|
||||
mbf_init (mbf, fp);
|
||||
+ found_bom=check_bom(fp,&mbf);
|
||||
+
|
||||
+ if (using_utf_locale == false && found_bom == true)
|
||||
+ {
|
||||
+ /*try using some predefined locale */
|
||||
+
|
||||
+ if (set_utf_locale () != 0)
|
||||
+ {
|
||||
+ error (EXIT_FAILURE, errno, _("cannot set UTF-8 locale"));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ if (found_bom == true)
|
||||
+ {
|
||||
+ print_bom();
|
||||
+ }
|
||||
|
||||
while (true)
|
||||
{
|
||||
@@ -132,6 +154,27 @@ expand (void)
|
||||
if ((mb_iseof (c)) && (fp = next_file (fp)))
|
||||
{
|
||||
mbf_init (mbf, fp);
|
||||
+ if (fp!=NULL)
|
||||
+ {
|
||||
+ if (check_bom(fp,&mbf)==true)
|
||||
+ {
|
||||
+ /*Not the first file - check BOM header*/
|
||||
+ if (using_utf_locale==false && found_bom==false)
|
||||
+ {
|
||||
+ /*BOM header in subsequent file but not in the first one. */
|
||||
+ error (EXIT_FAILURE, errno, _("combination of files with and without BOM header"));
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ if(using_utf_locale==false && found_bom==true)
|
||||
+ {
|
||||
+ /*First file conatined BOM header - locale was switched to UTF
|
||||
+ *all subsequent files should contain BOM. */
|
||||
+ error (EXIT_FAILURE, errno, _("combination of files with 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=check_utf_locale();
|
||||
|
||||
if (!fp)
|
||||
return;
|
||||
+ mbf_init (mbf, fp);
|
||||
+ found_bom=check_bom(fp,&mbf);
|
||||
+
|
||||
+ if (using_utf_locale == false && found_bom == true)
|
||||
+ {
|
||||
+ /*try using some predefined locale */
|
||||
|
||||
+ if (set_utf_locale () != 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 = xmalloc (max_column_width * sizeof (mbf_char_t));
|
||||
|
||||
- mbf_init (mbf, fp);
|
||||
+ if (found_bom == true)
|
||||
+ {
|
||||
+ print_bom();
|
||||
+ }
|
||||
|
||||
while (true)
|
||||
{
|
||||
@@ -169,6 +189,27 @@ unexpand (void)
|
||||
if ((mb_iseof (c)) && (fp = next_file (fp)))
|
||||
{
|
||||
mbf_init (mbf, fp);
|
||||
+ if (fp!=NULL)
|
||||
+ {
|
||||
+ if (check_bom(fp,&mbf)==true)
|
||||
+ {
|
||||
+ /*Not the first file - check BOM header*/
|
||||
+ if (using_utf_locale==false && found_bom==false)
|
||||
+ {
|
||||
+ /*BOM header in subsequent file but not in the first one. */
|
||||
+ error (EXIT_FAILURE, errno, _("combination of files with and without BOM header"));
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ if(using_utf_locale==false && found_bom==true)
|
||||
+ {
|
||||
+ /*First file conatined BOM header - locale was switched to UTF
|
||||
+ *all subsequent files should contain BOM. */
|
||||
+ error (EXIT_FAILURE, errno, _("combination of files with 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=1
|
||||
compare exp out > /dev/null 2>&1 || fail=1
|
||||
|
||||
+
|
||||
+
|
||||
+#BOM header test 1
|
||||
+printf "\xEF\xBB\xBF" > in; cat <<\EOF >> in || framework_failure_
|
||||
+1234567812345678123456781
|
||||
+. . . .
|
||||
+a b c d
|
||||
+. . . .
|
||||
+ä ö ü ß
|
||||
+. . . .
|
||||
+EOF
|
||||
+env printf ' äöü\t. öüä. \tä xx\n' >> in || framework_failure_
|
||||
+
|
||||
+printf "\xEF\xBB\xBF" > exp; cat <<\EOF >> exp || framework_failure_
|
||||
+1234567812345678123456781
|
||||
+. . . .
|
||||
+a b c d
|
||||
+. . . .
|
||||
+ä ö ü ß
|
||||
+. . . .
|
||||
+ äöü . öüä. ä xx
|
||||
+EOF
|
||||
+
|
||||
+
|
||||
+expand < in > out || fail=1
|
||||
+compare exp out > /dev/null 2>&1 || fail=1
|
||||
+
|
||||
+LANG=C expand < in > out || fail=1
|
||||
+compare exp out > /dev/null 2>&1 || fail=1
|
||||
+
|
||||
+LC_ALL=C expand < in > out || fail=1
|
||||
+compare exp out > /dev/null 2>&1 || fail=1
|
||||
+
|
||||
+
|
||||
+printf '\xEF\xBB\xBF' > in1; cat <<\EOF >> in1 || framework_failure_
|
||||
+1234567812345678123456781
|
||||
+. . . .
|
||||
+a b c d
|
||||
+. . . .
|
||||
+ä ö ü ß
|
||||
+. . . .
|
||||
+EOF
|
||||
+env printf ' äöü\t. öüä. \tä xx\n' >> in1 || framework_failure_
|
||||
+
|
||||
+
|
||||
+printf '\xEF\xBB\xBF' > exp; cat <<\EOF >> exp || framework_failure_
|
||||
+1234567812345678123456781
|
||||
+. . . .
|
||||
+a b c d
|
||||
+. . . .
|
||||
+ä ö ü ß
|
||||
+. . . .
|
||||
+ äöü . öüä. ä xx
|
||||
+1234567812345678123456781
|
||||
+. . . .
|
||||
+a b c d
|
||||
+. . . .
|
||||
+ä ö ü ß
|
||||
+. . . .
|
||||
+ äöü . öüä. ä xx
|
||||
+EOF
|
||||
+
|
||||
+expand in1 in1 > out || fail=1
|
||||
+compare exp out > /dev/null 2>&1 || fail=1
|
||||
+
|
||||
+LANG=C expand in1 in1 > out || fail=1
|
||||
+compare exp out > /dev/null 2>&1 || fail=1
|
||||
+
|
||||
+LC_ALL=C expand in1 in1 > out || fail=1
|
||||
+compare exp out > /dev/null 2>&1 || fail=1
|
||||
+
|
||||
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
|
||||
|
||||
unexpand -a < in > out || fail=1
|
||||
compare exp out > /dev/null 2>&1 || fail=1
|
||||
+
|
||||
+#BOM header test 1
|
||||
+printf "\xEF\xBB\xBF" > in; cat <<\EOF >> in || framework_failure_
|
||||
+1234567812345678123456781
|
||||
+. . . .
|
||||
+a b c d
|
||||
+. . . .
|
||||
+ä ö ü ß
|
||||
+. . . .
|
||||
+ äöü . öüä. ä xx
|
||||
+EOF
|
||||
+env printf ' äöü\t. öüä. \tä xx\n' >> in || framework_failure_
|
||||
+
|
||||
+printf "\xEF\xBB\xBF" > exp; cat <<\EOF >> exp || framework_failure_
|
||||
+1234567812345678123456781
|
||||
+. . . .
|
||||
+a b c d
|
||||
+. . . .
|
||||
+ä ö ü ß
|
||||
+. . . .
|
||||
+ äöü . öüä. ä xx
|
||||
+EOF
|
||||
+
|
||||
+unexpand < in > out || fail=1
|
||||
+compare exp out > /dev/null 2>&1 || fail=1
|
||||
+
|
||||
+LANG=C unexpand < in > out || fail=1
|
||||
+compare exp out > /dev/null 2>&1 || fail=1
|
||||
+
|
||||
+LC_ALL=C unexpand < in > out || fail=1
|
||||
+compare exp out > /dev/null 2>&1 || fail=1
|
||||
+
|
||||
+
|
||||
+printf "\xEF\xBB\xBF" > exp; cat <<\EOF >> exp || framework_failure_
|
||||
+1234567812345678123456781
|
||||
+. . . .
|
||||
+a b c d
|
||||
+. . . .
|
||||
+ä ö ü ß
|
||||
+. . . .
|
||||
+ äöü . öüä. ä xx
|
||||
+1234567812345678123456781
|
||||
+. . . .
|
||||
+a b c d
|
||||
+. . . .
|
||||
+ä ö ü ß
|
||||
+. . . .
|
||||
+ äöü . öüä. ä xx
|
||||
+EOF
|
||||
+
|
||||
+
|
||||
+unexpand in in > out || fail=1
|
||||
+compare exp out > /dev/null 2>&1 || fail=1
|
||||
+
|
||||
+LANG=C unexpand in in > out || fail=1
|
||||
+compare exp out > /dev/null 2>&1 || fail=1
|
||||
+
|
||||
+LC_ALL=C unexpand in in > out || fail=1
|
||||
+compare exp out > /dev/null 2>&1 || fail=1
|
||||
--
|
||||
2.9.3
|
||||
|
|
@ -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
|
||||
|
||||
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;
|
||||
+
|
||||
+
|
||||
+ case L'\b':
|
||||
+ increment = (column > 0) ? -1 : 0;
|
||||
+ break;
|
||||
|
@ -672,7 +671,7 @@ index 98b461c..9990f38 100644
|
|||
+ extract_field (line, ptr, lim - ptr);
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+
|
||||
static void
|
||||
freeline (struct line *line)
|
||||
{
|
||||
|
@ -845,7 +844,7 @@ index 98b461c..9990f38 100644
|
|||
xfields (line);
|
||||
|
||||
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)
|
||||
|
||||
/* Output all the fields in line, other than the join field. */
|
||||
|
||||
|
@ -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;
|
||||
|
||||
@@ -626,7 +872,7 @@ prjoin (struct line const *line1, struct line const *line2)
|
||||
@@ -622,7 +868,7 @@ prjoin (struct line const *line1, struct line const *line2)
|
||||
o = o->next;
|
||||
if (o == 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)
|
||||
|
||||
case 't':
|
||||
{
|
||||
|
@ -1171,7 +1170,7 @@ index 26f221f..633f50e 100644
|
|||
use_col_separator = true;
|
||||
if (optarg)
|
||||
separator_string (optarg);
|
||||
@@ -1166,10 +1250,45 @@ getoptnum (const char *n_str, int min, int *num, const char *err)
|
||||
@@ -1165,10 +1249,45 @@ getoptnum (const char *n_str, int min, int *num, const char *err)
|
||||
a number. */
|
||||
|
||||
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 = 0;
|
||||
|
@ -1231,7 +1230,7 @@ index 26f221f..633f50e 100644
|
|||
|
||||
lines_per_body = lines_per_page - lines_per_header - lines_per_footer;
|
||||
if (lines_per_body <= 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 = column_separator;
|
||||
|
||||
|
@ -1240,7 +1239,7 @@ index 26f221f..633f50e 100644
|
|||
use_col_separator = 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); */
|
||||
|
||||
/* Estimate chars_per_text without any margin and keep it constant. */
|
||||
|
@ -1254,7 +1253,7 @@ index 26f221f..633f50e 100644
|
|||
|
||||
/* 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)
|
||||
}
|
||||
|
||||
int sep_chars, useful_chars;
|
||||
|
@ -1263,7 +1262,7 @@ index 26f221f..633f50e 100644
|
|||
sep_chars = 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 = 8
|
||||
to expand a tab which is not an input_tab-char. */
|
||||
free (clump_buff);
|
||||
|
@ -1272,7 +1271,7 @@ index 26f221f..633f50e 100644
|
|||
}
|
||||
|
||||
/* Open the necessary files,
|
||||
@@ -1402,7 +1526,7 @@ init_funcs (void)
|
||||
@@ -1399,7 +1523,7 @@ init_funcs (void)
|
||||
|
||||
/* 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
|
|||
|
||||
/* This loop takes care of all but the rightmost column. */
|
||||
|
||||
@@ -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 = h + chars_per_column;
|
||||
}
|
||||
}
|
||||
@@ -1727,9 +1851,9 @@ static void
|
||||
@@ -1724,9 +1848,9 @@ static void
|
||||
align_column (COLUMN *p)
|
||||
{
|
||||
padding_not_printed = p->start_position;
|
||||
|
@ -1302,7 +1301,7 @@ index 26f221f..633f50e 100644
|
|||
padding_not_printed = ANYWHERE;
|
||||
}
|
||||
|
||||
@@ -2004,13 +2128,13 @@ store_char (char c)
|
||||
@@ -2001,13 +2125,13 @@ store_char (char c)
|
||||
/* May be too generous. */
|
||||
buff = X2REALLOC (buff, &buff_allocated);
|
||||
}
|
||||
|
@ -1318,7 +1317,7 @@ index 26f221f..633f50e 100644
|
|||
char *s;
|
||||
int num_width;
|
||||
|
||||
@@ -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-separators,
|
||||
but 'default n-separator = TAB' hasn't been given priority over
|
||||
equal column_width also specified by POSIX. */
|
||||
|
@ -1347,7 +1346,7 @@ index 26f221f..633f50e 100644
|
|||
output_position = 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 = POS_AFTER_TAB (chars_per_output_tab, h_old)) <= goal)
|
||||
{
|
||||
|
@ -1356,7 +1355,7 @@ index 26f221f..633f50e 100644
|
|||
h_old = h_new;
|
||||
}
|
||||
while (++h_old <= goal)
|
||||
@@ -2223,6 +2349,7 @@ print_sep_string (void)
|
||||
@@ -2218,6 +2344,7 @@ print_sep_string (void)
|
||||
{
|
||||
char const *s = col_sep_string;
|
||||
int l = col_sep_length;
|
||||
|
@ -1364,7 +1363,7 @@ index 26f221f..633f50e 100644
|
|||
|
||||
if (separators_not_printed <= 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. */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1473,7 +1472,7 @@ index 26f221f..633f50e 100644
|
|||
/* Skip to page PAGE before printing.
|
||||
PAGE may be larger than total number of pages. */
|
||||
|
||||
@@ -2483,9 +2682,9 @@ read_line (COLUMN *p)
|
||||
@@ -2476,9 +2675,9 @@ read_line (COLUMN *p)
|
||||
align_empty_cols = false;
|
||||
}
|
||||
|
||||
|
@ -1485,8 +1484,8 @@ index 26f221f..633f50e 100644
|
|||
padding_not_printed = ANYWHERE;
|
||||
}
|
||||
|
||||
@@ -2555,7 +2754,7 @@ print_stored (COLUMN *p)
|
||||
int i;
|
||||
@@ -2547,7 +2746,7 @@ print_stored (COLUMN *p)
|
||||
COLUMN *q;
|
||||
|
||||
int line = p->current_line++;
|
||||
- char *first = &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
|
|||
|
||||
pad_vertically = true;
|
||||
|
||||
@@ -2586,9 +2785,9 @@ print_stored (COLUMN *p)
|
||||
@@ -2579,9 +2778,9 @@ print_stored (COLUMN *p)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1515,7 +1514,7 @@ index 26f221f..633f50e 100644
|
|||
padding_not_printed = ANYWHERE;
|
||||
}
|
||||
|
||||
@@ -2601,8 +2800,8 @@ print_stored (COLUMN *p)
|
||||
@@ -2594,8 +2793,8 @@ print_stored (COLUMN *p)
|
||||
if (spaces_not_printed == 0)
|
||||
{
|
||||
output_position = p->start_position + end_vector[line];
|
||||
|
@ -1526,7 +1525,7 @@ index 26f221f..633f50e 100644
|
|||
}
|
||||
|
||||
return true;
|
||||
@@ -2621,7 +2820,7 @@ print_stored (COLUMN *p)
|
||||
@@ -2614,7 +2813,7 @@ print_stored (COLUMN *p)
|
||||
number of characters is 1.) */
|
||||
|
||||
static int
|
||||
|
@ -1535,7 +1534,7 @@ index 26f221f..633f50e 100644
|
|||
{
|
||||
unsigned char uc = c;
|
||||
char *s = 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 = 8;
|
||||
|
||||
|
@ -1548,7 +1547,7 @@ index 26f221f..633f50e 100644
|
|||
{
|
||||
width = TAB_WIDTH (chars_per_c, input_position);
|
||||
|
||||
@@ -2715,6 +2914,164 @@ char_to_clump (char c)
|
||||
@@ -2708,6 +2907,164 @@ char_to_clump (char c)
|
||||
return chars;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 };
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
@ -1790,7 +1789,7 @@ index 6d2eec5..f189a0d 100644
|
|||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
@ -1837,7 +1836,7 @@ index 6d2eec5..f189a0d 100644
|
|||
/* Clean up any remaining temporary files. */
|
||||
|
||||
static void
|
||||
@@ -1255,7 +1326,7 @@ zaptemp (char const *name)
|
||||
@@ -1274,7 +1345,7 @@ zaptemp (char const *name)
|
||||
free (node);
|
||||
}
|
||||
|
||||
|
@ -1846,7 +1845,7 @@ index 6d2eec5..f189a0d 100644
|
|||
|
||||
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. */
|
||||
|
||||
static void
|
||||
|
@ -1855,7 +1854,7 @@ index 6d2eec5..f189a0d 100644
|
|||
{
|
||||
size_t i;
|
||||
|
||||
@@ -1282,7 +1353,7 @@ inittables (void)
|
||||
@@ -1301,7 +1372,7 @@ inittables (void)
|
||||
fold_toupper[i] = toupper (i);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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. */
|
||||
|
||||
static char *
|
||||
|
@ -1958,7 +1957,7 @@ index 6d2eec5..f189a0d 100644
|
|||
{
|
||||
char *ptr = line->text, *lim = ptr + line->length - 1;
|
||||
size_t sword = key->sword;
|
||||
@@ -1606,10 +1755,10 @@ begfield (struct line const *line, struct keyfield const *key)
|
||||
@@ -1623,10 +1772,10 @@ begfield (struct line const *line, struct keyfield const *key)
|
||||
/* The leading field separator itself is included in a field when -t
|
||||
is absent. */
|
||||
|
||||
|
@ -1971,7 +1970,7 @@ index 6d2eec5..f189a0d 100644
|
|||
++ptr;
|
||||
if (ptr < lim)
|
||||
++ptr;
|
||||
@@ -1635,11 +1784,70 @@ begfield (struct line const *line, struct keyfield const *key)
|
||||
@@ -1652,11 +1801,70 @@ begfield (struct line const *line, struct keyfield const *key)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
@ -2043,7 +2042,7 @@ index 6d2eec5..f189a0d 100644
|
|||
{
|
||||
char *ptr = line->text, *lim = ptr + line->length - 1;
|
||||
size_t eword = key->eword, echar = key->echar;
|
||||
@@ -1654,10 +1862,10 @@ limfield (struct line const *line, struct keyfield const *key)
|
||||
@@ -1671,10 +1879,10 @@ limfield (struct line const *line, struct keyfield const *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 const *key)
|
||||
@@ -1720,10 +1928,10 @@ limfield (struct line const *line, struct keyfield const *key)
|
||||
*/
|
||||
|
||||
/* Make LIM point to the end of (one byte past) the current field. */
|
||||
|
@ -2069,7 +2068,7 @@ index 6d2eec5..f189a0d 100644
|
|||
if (newlim)
|
||||
lim = newlim;
|
||||
}
|
||||
@@ -1737,6 +1945,130 @@ limfield (struct line const *line, struct keyfield const *key)
|
||||
@@ -1754,6 +1962,130 @@ limfield (struct line const *line, struct keyfield const *key)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
@ -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 *file)
|
||||
@@ -1840,8 +2172,22 @@ fillbuf (struct buffer *buf, FILE *fp, char const *file)
|
||||
else
|
||||
{
|
||||
if (key->skipsblanks)
|
||||
|
@ -2225,7 +2224,7 @@ index 6d2eec5..f189a0d 100644
|
|||
line->keybeg = 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. */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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. */
|
||||
|
||||
static int
|
||||
|
@ -2269,7 +2268,7 @@ index 6d2eec5..f189a0d 100644
|
|||
{
|
||||
size_t lo = 0;
|
||||
size_t hi = 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 = *lim;
|
||||
*lim = '\0';
|
||||
|
||||
|
@ -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_only)
|
||||
@@ -2469,7 +2833,7 @@ key_warnings (struct keyfield const *gkey, bool gkey_only)
|
||||
/* Warn about significant leading blanks. */
|
||||
bool implicit_skip = key_numeric (key) || key->month;
|
||||
bool line_offset = key->eword == 0 && key->echar != 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"));
|
||||
}
|
||||
|
||||
|
@ -2385,7 +2384,7 @@ index 6d2eec5..f189a0d 100644
|
|||
{
|
||||
struct keyfield *key = keylist;
|
||||
|
||||
@@ -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 = human_numcompare (ta, tb);
|
||||
else if (key->month)
|
||||
|
@ -2394,7 +2393,7 @@ index 6d2eec5..f189a0d 100644
|
|||
else if (key->random)
|
||||
diff = 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;
|
||||
}
|
||||
|
||||
|
@ -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. */
|
||||
|
||||
@@ -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 = - NONZERO (blen);
|
||||
else if (blen == 0)
|
||||
diff = 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, enum blanktype blanktype)
|
||||
@@ -4149,6 +4794,7 @@ set_ordering (char const *s, struct keyfield *key, enum blanktype blanktype)
|
||||
break;
|
||||
case 'f':
|
||||
key->translate = fold_toupper;
|
||||
|
@ -2623,7 +2622,7 @@ index 6d2eec5..f189a0d 100644
|
|||
break;
|
||||
case 'g':
|
||||
key->general_numeric = true;
|
||||
@@ -4218,7 +4864,7 @@ main (int argc, char **argv)
|
||||
@@ -4228,7 +4874,7 @@ main (int argc, char **argv)
|
||||
initialize_exit_failure (SORT_FAILURE);
|
||||
|
||||
hard_LC_COLLATE = hard_locale (LC_COLLATE);
|
||||
|
@ -2632,7 +2631,7 @@ index 6d2eec5..f189a0d 100644
|
|||
hard_LC_TIME = hard_locale (LC_TIME);
|
||||
#endif
|
||||
|
||||
@@ -4239,6 +4885,29 @@ main (int argc, char **argv)
|
||||
@@ -4249,6 +4895,29 @@ main (int argc, char **argv)
|
||||
thousands_sep = -1;
|
||||
}
|
||||
|
||||
|
@ -2662,7 +2661,7 @@ index 6d2eec5..f189a0d 100644
|
|||
have_read_stdin = false;
|
||||
inittables ();
|
||||
|
||||
@@ -4513,13 +5182,34 @@ main (int argc, char **argv)
|
||||
@@ -4523,13 +5192,34 @@ main (int argc, char **argv)
|
||||
|
||||
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;
|
||||
|
||||
@@ -4770,12 +5462,10 @@ main (int argc, char **argv)
|
||||
@@ -4771,12 +5463,10 @@ main (int argc, char **argv)
|
||||
sort (files, nfiles, outfile, nthreads);
|
||||
}
|
||||
|
||||
|
@ -2843,7 +2842,7 @@ index 87a0c93..9f755d9 100644
|
|||
+ while (pos < size)
|
||||
+ {
|
||||
+ MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail);
|
||||
+
|
||||
+
|
||||
+ if (convfail || !(iswblank (wc) || wc == '\n'))
|
||||
+ {
|
||||
+ pos += mblength;
|
||||
|
@ -2886,7 +2885,7 @@ index 87a0c93..9f755d9 100644
|
|||
if (check_chars < oldlen)
|
||||
oldlen = 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)
|
||||
|
||||
if (ignore_case)
|
||||
{
|
||||
|
@ -2918,8 +2917,8 @@ index 87a0c93..9f755d9 100644
|
|||
+
|
||||
+ return xmemcoll (copy_old, oldlen, copy_new, newlen);
|
||||
+
|
||||
+}
|
||||
+
|
||||
}
|
||||
|
||||
+#if HAVE_MBRTOWC
|
||||
+static int
|
||||
+different_multi (const char *old, const char *new, size_t oldlen, size_t newlen, mbstate_t oldstate, mbstate_t newstate)
|
||||
|
@ -2990,11 +2989,12 @@ index 87a0c93..9f755d9 100644
|
|||
+ free (copy[1]);
|
||||
+ return rc;
|
||||
+
|
||||
}
|
||||
+}
|
||||
+#endif
|
||||
|
||||
+
|
||||
/* 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, char delimiter)
|
||||
char *prevfield IF_LINT ( = NULL);
|
||||
size_t prevlen IF_LINT ( = 0);
|
||||
|
@ -3118,7 +3118,7 @@ index 87a0c93..9f755d9 100644
|
|||
skip_fields = 0;
|
||||
check_chars = 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 = \
|
||||
@@ -368,6 +368,8 @@ all_tests = \
|
||||
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)} = ('C') x 3;
|
||||
|
||||
-my $mb_locale = $ENV{LOCALE_FR_UTF8};
|
||||
+my $mb_locale;
|
||||
+# uncommented enable multibyte paths
|
||||
+$mb_locale = $ENV{LOCALE_FR_UTF8};
|
||||
! defined $mb_locale || $mb_locale eq 'none'
|
||||
- and $mb_locale = 'C';
|
||||
+ and $mb_locale = 'C';
|
||||
|
||||
my $prog = 'cut';
|
||||
my $try = "Try '$prog --help' for more information.\n";
|
||||
@@ -240,6 +242,7 @@ if ($mb_locale ne 'C')
|
||||
my @new_t = @$t;
|
||||
my $test_name = shift @new_t;
|
||||
|
||||
+ next if ($test_name =~ "newline-[12][0-9]");
|
||||
push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$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 =
|
||||
(
|
||||
['t1', '--tabs=3', {IN=>"a\tb"}, {OUT=>"a b"}],
|
||||
@@ -140,6 +149,8 @@ my @Tests =
|
||||
@@ -168,6 +177,8 @@ my @Tests =
|
||||
|
||||
|
||||
# Test errors
|
||||
|
@ -3220,8 +3194,8 @@ index 8a9cad1..9293e39 100755
|
|||
['e1', '--tabs="a"', {IN=>''}, {OUT=>''}, {EXIT=>1},
|
||||
{ERR => "$prog: tab size contains invalid character(s): 'a'\n"}],
|
||||
['e2', "-t $UINTMAX_OFLOW", {IN=>''}, {OUT=>''}, {EXIT=>1},
|
||||
@@ -150,6 +161,37 @@ my @Tests =
|
||||
{ERR => "$prog: tab sizes must be ascending\n"}],
|
||||
@@ -184,6 +195,37 @@ my @Tests =
|
||||
{ERR => "$prog: '/' specifier not at start of number: '/'\n"}],
|
||||
);
|
||||
|
||||
+if ($mb_locale ne 'C')
|
||||
|
@ -3351,7 +3325,7 @@ index 4d399d8..07f2823 100755
|
|||
my $delim = 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;
|
||||
}
|
||||
|
||||
|
@ -3402,7 +3376,7 @@ index 4d399d8..07f2823 100755
|
|||
my $verbose = $ENV{VERBOSE};
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3572,7 +3546,7 @@ index c3e7f8e..6ecd3ff 100755
|
|||
@Tests = triple_test \@Tests;
|
||||
|
||||
# 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 = grep {$_->[0] ne 'output-is-input.p'} @Tests;
|
||||
|
|
Loading…
Reference in New Issue