diff options
| author | Mark Hatle <mark.hatle@windriver.com> | 2011-02-03 20:40:40 -0600 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2011-02-07 16:52:41 +0000 |
| commit | 522d16a70fb2f1ad922a4cac8d63f1dddc61ba8d (patch) | |
| tree | 6507437450798a9759bbac328b298b00a9e41477 /meta/recipes-core/coreutils | |
| parent | 427472e980cd6254a5e4ef37209b327e15af259b (diff) | |
| download | openembedded-core-522d16a70fb2f1ad922a4cac8d63f1dddc61ba8d.tar.gz openembedded-core-522d16a70fb2f1ad922a4cac8d63f1dddc61ba8d.tar.bz2 openembedded-core-522d16a70fb2f1ad922a4cac8d63f1dddc61ba8d.zip | |
coreutils: Add various bug fixes
Add a number of bug fixes, mostly imported from Fedora and Wind River
Linux.
cp-i-u: fix unnecessary prompting
fix-install: Fix installing to a dangling symlink
i18n: li18nux/lsb compliance
ls-x: Fix incorrect output
overflow: Fix potential overflow in who command
Signed-off-by: Mark Hatle <mark.hatle@windriver.com>
Diffstat (limited to 'meta/recipes-core/coreutils')
6 files changed, 4403 insertions, 0 deletions
diff --git a/meta/recipes-core/coreutils/coreutils-6.9/coreutils-6.9-cp-i-u.patch b/meta/recipes-core/coreutils/coreutils-6.9/coreutils-6.9-cp-i-u.patch new file mode 100644 index 0000000000..6fec683bc3 --- /dev/null +++ b/meta/recipes-core/coreutils/coreutils-6.9/coreutils-6.9-cp-i-u.patch @@ -0,0 +1,118 @@ +This patch was imported from the Fedora Core 8 coreutils-6.9-9 package. + +The package is stated as being Licensed as GPLv2+. + +Signed-off-by: Mark Hatle <mark.hatle@windriver.com> + +---- + +When "cp -i --update old new" would do nothing because "new" is +newer than "old", cp would nonetheless prompt for whether it is +ok to overwrite "new". Then, regardless of the response (because +of the --update option), cp would do nothing. + +The following patch eliminates the unnecessary prompt in that case. + +diff --git a/src/copy.c b/src/copy.c +index b7bf73b..0e549d2 100644 +--- a/src/copy.c ++++ b/src/copy.c +@@ -1210,6 +1210,30 @@ copy_internal (char const *src_name, char const *dst_name, + return false; + } + ++ if (!S_ISDIR (src_mode) && x->update) ++ { ++ /* When preserving time stamps (but not moving within a file ++ system), don't worry if the destination time stamp is ++ less than the source merely because of time stamp ++ truncation. */ ++ int options = ((x->preserve_timestamps ++ && ! (x->move_mode ++ && dst_sb.st_dev == src_sb.st_dev)) ++ ? UTIMECMP_TRUNCATE_SOURCE ++ : 0); ++ ++ if (0 <= utimecmp (dst_name, &dst_sb, &src_sb, options)) ++ { ++ /* We're using --update and the destination is not older ++ than the source, so do not copy or move. Pretend the ++ rename succeeded, so the caller (if it's mv) doesn't ++ end up removing the source file. */ ++ if (rename_succeeded) ++ *rename_succeeded = true; ++ return true; ++ } ++ } ++ + /* When there is an existing destination file, we may end up + returning early, and hence not copying/moving the file. + This may be due to an interactive `negative' reply to the +@@ -1302,30 +1326,6 @@ copy_internal (char const *src_name, char const *dst_name, + return false; + } + } +- +- if (x->update) +- { +- /* When preserving time stamps (but not moving within a file +- system), don't worry if the destination time stamp is +- less than the source merely because of time stamp +- truncation. */ +- int options = ((x->preserve_timestamps +- && ! (x->move_mode +- && dst_sb.st_dev == src_sb.st_dev)) +- ? UTIMECMP_TRUNCATE_SOURCE +- : 0); +- +- if (0 <= utimecmp (dst_name, &dst_sb, &src_sb, options)) +- { +- /* We're using --update and the destination is not older +- than the source, so do not copy or move. Pretend the +- rename succeeded, so the caller (if it's mv) doesn't +- end up removing the source file. */ +- if (rename_succeeded) +- *rename_succeeded = true; +- return true; +- } +- } + } + + if (x->move_mode) +diff --git a/tests/mv/update b/tests/mv/update +index 0c06024..6c3d149 100755 +--- a/tests/mv/update ++++ b/tests/mv/update +@@ -1,7 +1,7 @@ + #!/bin/sh + # make sure --update works as advertised + +-# Copyright (C) 2001, 2004, 2006 Free Software Foundation, Inc. ++# Copyright (C) 2001, 2004, 2006-2007 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 +@@ -46,11 +46,16 @@ fi + + fail=0 + +-for cp_or_mv in cp mv; do +- # This is a no-op. +- $cp_or_mv --update old new || fail=1 +- case "`cat new`" in new) ;; *) fail=1 ;; esac +- case "`cat old`" in old) ;; *) fail=1 ;; esac ++for interactive in '' -i; do ++ for cp_or_mv in cp mv; do ++ # This is a no-op, with no prompt. ++ # With coreutils-6.9 and earlier, using --update with -i would ++ # mistakenly elicit a prompt. ++ $cp_or_mv $interactive --update old new < /dev/null > out 2>&1 || fail=1 ++ test -s out && fail=1 ++ case "`cat new`" in new) ;; *) fail=1 ;; esac ++ case "`cat old`" in old) ;; *) fail=1 ;; esac ++ done + done + + # This will actually perform the rename. +-- +1.5.3.rc1.16.g9d6f diff --git a/meta/recipes-core/coreutils/coreutils-6.9/coreutils-fix-install.patch b/meta/recipes-core/coreutils/coreutils-6.9/coreutils-fix-install.patch new file mode 100644 index 0000000000..1b989f5311 --- /dev/null +++ b/meta/recipes-core/coreutils/coreutils-6.9/coreutils-fix-install.patch @@ -0,0 +1,99 @@ +The install command doesn't over write the dangling symlink, for +example: + +$ install fileA /tmp/fileA + +If /tmp/fileA is a dangling symlink, there would be an error: + +install: cannot create regular file '/tmp/fileA': File exists + +This is because of the following code in copy.c: + + if (!new_dst) + { + if (XSTAT (x, dst_name, &dst_sb) != 0) + { + if (errno != ENOENT) + { + error (0, errno, _("cannot stat %s"), quote (dst_name)); + return false; + } + else + { + new_dst = true; + } + } + +XSTAT() use stat() for dst_name(the dangling symlink /tmp/fileA) when +install.c invokes it, and stat will set errno to ENOENT, and then +new_dst will be set to true which means that /tmp/fileA doesn't exist, +then we will create /tmp/fileA without remove it first, so the error +comes. + +This is fixed in a way which adds the member cmd_install in +struct cp_options to make sure my change only affected to the install +command and use lstat to fix the problem. + +Signed-off-by: Robert Yang <liezhi.yang@windriver.com> +Signed-off-by: Mark Hatle <mark.hatle@windriver.com> + +--- + src/copy.c | 10 +++++++++- + src/copy.h | 3 +++ + src/install.c | 1 + + 3 files changed, 13 insertions(+), 1 deletions(-) + +diff --git a/src/copy.c b/src/copy.c +--- a/src/copy.c ++++ b/src/copy.c +@@ -1029,6 +1029,7 @@ copy_internal (char const *src_name, char const *dst_name, + bool delayed_ok; + bool copied_as_regular = false; + bool preserve_metadata; ++ int dst_stat_result; + + if (x->move_mode && rename_succeeded) + *rename_succeeded = false; +@@ -1069,7 +1070,14 @@ copy_internal (char const *src_name, char const *dst_name, + + if (!new_dst) + { +- if (XSTAT (x, dst_name, &dst_sb) != 0) ++ if ( x->cmd_install && ( x->backup_type == no_backups)) ++ dst_stat_result = lstat (dst_name, &dst_sb); ++ else ++ { ++ dst_stat_result = XSTAT (x, dst_name, &dst_sb); ++ } ++ ++ if (dst_stat_result != 0) + { + if (errno != ENOENT) + { +diff --git a/src/copy.h b/src/copy.h +--- a/src/copy.h ++++ b/src/copy.h +@@ -114,6 +114,9 @@ struct cp_options + If that fails, then resort to copying. */ + bool move_mode; + ++ /* For the install command */ ++ bool cmd_install; ++ + /* Whether this process has appropriate privileges to chown a file + whose owner is not the effective user ID. */ + bool chown_privileges; +diff --git a/src/install.c b/src/install.c +--- a/src/install.c ++++ b/src/install.c +@@ -149,6 +149,7 @@ cp_option_init (struct cp_options *x) + x->hard_link = false; + x->interactive = I_UNSPECIFIED; + x->move_mode = false; ++ x->cmd_install = true; + x->chown_privileges = chown_privileges (); + x->one_file_system = false; + x->preserve_ownership = false; +-- +1.7.0.1 + diff --git a/meta/recipes-core/coreutils/coreutils-6.9/coreutils-i18n.patch b/meta/recipes-core/coreutils/coreutils-6.9/coreutils-i18n.patch new file mode 100644 index 0000000000..3587186af1 --- /dev/null +++ b/meta/recipes-core/coreutils/coreutils-6.9/coreutils-i18n.patch @@ -0,0 +1,4049 @@ +This patch was imported from the Fedora Core 8 coreutils-6.9-9 package. + +The package is stated as being Licensed as GPLv2+. + +The comment indicates that the purpose is lin18nux/lsb compliance. + +Signed-off-by: Mark Hatle <mark.hatle@windriver.com> + +--- /dev/null 2007-03-01 09:16:39.219409909 +0000 ++++ coreutils-6.8+/tests/sort/sort-mb-tests 2007-03-01 15:08:24.000000000 +0000 +@@ -0,0 +1,58 @@ ++#! /bin/sh ++case $# in ++ 0) xx='../../src/sort';; ++ *) xx="$1";; ++esac ++test "$VERBOSE" && echo=echo || echo=: ++$echo testing program: $xx ++errors=0 ++test "$srcdir" || srcdir=. ++test "$VERBOSE" && $xx --version 2> /dev/null ++ ++export LC_ALL=en_US.UTF-8 ++locale -k LC_CTYPE 2>&1 | grep -q charmap.*UTF-8 || exit 77 ++errors=0 ++ ++$xx -t @ -k2 -n mb1.I > mb1.O ++code=$? ++if test $code != 0; then ++ $echo "Test mb1 failed: $xx return code $code differs from expected value 0" 1>&2 ++ errors=`expr $errors + 1` ++else ++ cmp mb1.O $srcdir/mb1.X > /dev/null 2>&1 ++ case $? in ++ 0) if test "$VERBOSE"; then $echo "passed mb1"; fi;; ++ 1) $echo "Test mb1 failed: files mb1.O and $srcdir/mb1.X differ" 1>&2 ++ (diff -c mb1.O $srcdir/mb1.X) 2> /dev/null ++ errors=`expr $errors + 1`;; ++ 2) $echo "Test mb1 may have failed." 1>&2 ++ $echo The command "cmp mb1.O $srcdir/mb1.X" failed. 1>&2 ++ errors=`expr $errors + 1`;; ++ esac ++fi ++ ++$xx -t @ -k4 -n mb2.I > mb2.O ++code=$? ++if test $code != 0; then ++ $echo "Test mb2 failed: $xx return code $code differs from expected value 0" 1>&2 ++ errors=`expr $errors + 1` ++else ++ cmp mb2.O $srcdir/mb2.X > /dev/null 2>&1 ++ case $? in ++ 0) if test "$VERBOSE"; then $echo "passed mb2"; fi;; ++ 1) $echo "Test mb2 failed: files mb2.O and $srcdir/mb2.X differ" 1>&2 ++ (diff -c mb2.O $srcdir/mb2.X) 2> /dev/null ++ errors=`expr $errors + 1`;; ++ 2) $echo "Test mb2 may have failed." 1>&2 ++ $echo The command "cmp mb2.O $srcdir/mb2.X" failed. 1>&2 ++ errors=`expr $errors + 1`;; ++ esac ++fi ++ ++if test $errors = 0; then ++ $echo Passed all 113 tests. 1>&2 ++else ++ $echo Failed $errors tests. 1>&2 ++fi ++test $errors = 0 || errors=1 ++exit $errors +--- /dev/null 2007-03-01 09:16:39.219409909 +0000 ++++ coreutils-6.8+/tests/sort/mb2.I 2007-03-01 15:08:24.000000000 +0000 +@@ -0,0 +1,4 @@ ++Apple@AA10@@20 ++Banana@AA5@@30 ++Citrus@AA20@@5 ++Cherry@AA30@@10 +--- /dev/null 2007-03-01 09:16:39.219409909 +0000 ++++ coreutils-6.8+/tests/sort/mb2.X 2007-03-01 15:08:24.000000000 +0000 +@@ -0,0 +1,4 @@ ++Citrus@AA20@@5 ++Cherry@AA30@@10 ++Apple@AA10@@20 ++Banana@AA5@@30 +--- /dev/null 2007-03-01 09:16:39.219409909 +0000 ++++ coreutils-6.8+/tests/sort/mb1.I 2007-03-01 15:08:24.000000000 +0000 +@@ -0,0 +1,4 @@ ++Apple@10 ++Banana@5 ++Citrus@20 ++Cherry@30 +--- /dev/null 2007-03-01 09:16:39.219409909 +0000 ++++ coreutils-6.8+/tests/sort/mb1.X 2007-03-01 15:08:24.000000000 +0000 +@@ -0,0 +1,4 @@ ++Banana@5 ++Apple@10 ++Citrus@20 ++Cherry@30 +--- coreutils-6.8+/tests/sort/Makefile.am.i18n 2007-01-24 07:47:37.000000000 +0000 ++++ coreutils-6.8+/tests/sort/Makefile.am 2007-03-01 15:09:59.000000000 +0000 +@@ -66,15 +66,17 @@ + bigfield.O bigfield.E + ##test-files-end + +-EXTRA_DIST = Test.pm $x-tests $(explicit) $(maint_gen) +-noinst_SCRIPTS = $x-tests ++run_gen += mb1.0 mb2.0 ++ ++EXTRA_DIST = Test.pm $x-tests $(explicit) $(maint_gen) mb1.I mb1.X mb2.I mb2.X ++noinst_SCRIPTS = $x-tests # $x-mb-tests + TESTS_ENVIRONMENT = \ + CU_TEST_NAME=`basename $(abs_srcdir)`,$$tst \ + PATH="$(VG_PATH_PREFIX)`pwd`/../../src$(PATH_SEPARATOR)$$PATH" + + editpl = sed -e 's,@''PERL''@,$(PERL),g' -e 's,@''srcdir''@,$(srcdir),g' + +-TESTS = $x-tests ++TESTS = $x-tests $x-mb-tests + + mk_script = $(srcdir)/../mk-script + $(srcdir)/$x-tests: $(mk_script) Test.pm Makefile.am +--- coreutils-6.8+/lib/linebuffer.h.i18n 2005-05-14 07:44:24.000000000 +0100 ++++ coreutils-6.8+/lib/linebuffer.h 2007-03-01 15:08:24.000000000 +0000 +@@ -22,6 +22,11 @@ + + # include <stdio.h> + ++/* Get mbstate_t. */ ++# if HAVE_WCHAR_H ++# include <wchar.h> ++# endif ++ + /* A `struct linebuffer' holds a line of text. */ + + struct linebuffer +@@ -29,6 +34,9 @@ + size_t size; /* Allocated. */ + size_t length; /* Used. */ + char *buffer; ++# if HAVE_WCHAR_H ++ mbstate_t state; ++# endif + }; + + /* Initialize linebuffer LINEBUFFER for use. */ +--- coreutils-6.8+/src/expand.c.i18n 2007-01-14 15:41:28.000000000 +0000 ++++ coreutils-6.8+/src/expand.c 2007-03-01 15:08:24.000000000 +0000 +@@ -38,11 +38,28 @@ + #include <stdio.h> + #include <getopt.h> + #include <sys/types.h> ++ ++/* Get mbstate_t, mbrtowc(), wcwidth(). */ ++#if HAVE_WCHAR_H ++# include <wchar.h> ++#endif ++ + #include "system.h" + #include "error.h" + #include "quote.h" + #include "xstrndup.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 ++# 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 "expand" + +@@ -183,6 +200,7 @@ + stops = num_start + len - 1; + } + } ++ + else + { + error (0, 0, _("tab size contains invalid character(s): %s"), +@@ -365,6 +383,142 @@ + } + } + ++#if HAVE_MBRTOWC ++static void ++expand_multibyte (void) ++{ ++ FILE *fp; /* Input strem. */ ++ mbstate_t i_state; /* Current shift state of the input stream. */ ++ mbstate_t i_state_bak; /* Back up the I_STATE. */ ++ mbstate_t o_state; /* Current shift state of the output stream. */ ++ char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ ++ char *bufpos; /* Next read position of BUF. */ ++ size_t buflen = 0; /* The length of the byte sequence in buf. */ ++ wchar_t wc; /* A gotten wide character. */ ++ size_t mblength; /* The byte size of a multibyte character ++ which shows as same character as WC. */ ++ int tab_index = 0; /* Index in `tab_list' of next tabstop. */ ++ int column = 0; /* Column on screen of the next char. */ ++ int next_tab_column; /* Column the next tab stop is on. */ ++ int convert = 1; /* If nonzero, perform translations. */ ++ ++ fp = next_file ((FILE *) NULL); ++ if (fp == NULL) ++ return; ++ ++ memset (&o_state, '\0', sizeof(mbstate_t)); ++ memset (&i_state, '\0', sizeof(mbstate_t)); ++ ++ for (;;) ++ { ++ /* Refill the buffer BUF. */ ++ if (buflen < MB_LEN_MAX && !feof(fp) && !ferror(fp)) ++ { ++ memmove (buf, bufpos, buflen); ++ buflen += fread (buf + buflen, sizeof(char), BUFSIZ, fp); ++ bufpos = buf; ++ } ++ ++ /* No character is left in BUF. */ ++ if (buflen < 1) ++ { ++ fp = next_file (fp); ++ ++ if (fp == NULL) ++ break; /* No more files. */ ++ else ++ { ++ memset (&i_state, '\0', sizeof(mbstate_t)); ++ continue; ++ } ++ } ++ ++ /* Get a wide character. */ ++ i_state_bak = i_state; ++ mblength = mbrtowc (&wc, bufpos, buflen, &i_state); ++ ++ switch (mblength) ++ { ++ case (size_t)-1: /* illegal byte sequence. */ ++ case (size_t)-2: ++ mblength = 1; ++ i_state = i_state_bak; ++ if (convert) ++ { ++ ++column; ++ if (convert_entire_line == 0) ++ convert = 0; ++ } ++ putchar (*bufpos); ++ break; ++ ++ case 0: /* null. */ ++ mblength = 1; ++ if (convert && convert_entire_line == 0) ++ convert = 0; ++ putchar ('\0'); ++ break; ++ ++ default: ++ if (wc == L'\n') /* LF. */ ++ { ++ tab_index = 0; ++ column = 0; ++ convert = 1; ++ putchar ('\n'); ++ } ++ else if (wc == L'\t' && convert) /* Tab. */ ++ { ++ if (tab_size == 0) ++ { ++ /* Do not let tab_index == first_free_tab; ++ stop when it is 1 less. */ ++ while (tab_index < first_free_tab - 1 ++ && column >= tab_list[tab_index]) ++ tab_index++; ++ next_tab_column = tab_list[tab_index]; ++ if (tab_index < first_free_tab - 1) ++ tab_index++; ++ if (column >= next_tab_column) ++ next_tab_column = column + 1; ++ } ++ else ++ next_tab_column = column + tab_size - column % tab_size; ++ ++ while (column < next_tab_column) ++ { ++ putchar (' '); ++ ++column; ++ } ++ } ++ else /* Others. */ ++ { ++ if (convert) ++ { ++ if (wc == L'\b') ++ { ++ if (column > 0) ++ --column; ++ } ++ else ++ { ++ int width; /* The width of WC. */ ++ ++ width = wcwidth (wc); ++ column += (width > 0) ? width : 0; ++ if (convert_entire_line == 0) ++ convert = 0; ++ } ++ } ++ fwrite (bufpos, sizeof(char), mblength, stdout); ++ } ++ } ++ buflen -= mblength; ++ bufpos += mblength; ++ } ++} ++#endif ++ + int + main (int argc, char **argv) + { +@@ -429,7 +583,12 @@ + + file_list = (optind < argc ? &argv[optind] : stdin_argv); + +- expand (); ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ expand_multibyte (); ++ else ++#endif ++ expand (); + + if (have_read_stdin && fclose (stdin) != 0) + error (EXIT_FAILURE, errno, "-"); +--- coreutils-6.8+/src/join.c.i18n 2007-01-14 15:41:28.000000000 +0000 ++++ coreutils-6.8+/src/join.c 2007-03-01 15:08:24.000000000 +0000 +@@ -23,16 +23,30 @@ + #include <sys/types.h> + #include <getopt.h> + ++/* Get mbstate_t, mbrtowc(), mbrtowc(), wcwidth(). */ ++#if HAVE_WCHAR_H ++# include <wchar.h> ++#endif ++ ++/* Get iswblank(), towupper. */ ++#if HAVE_WCTYPE_H ++# include <wctype.h> ++#endif ++ + #include "system.h" + #include "error.h" + #include "hard-locale.h" + #include "linebuffer.h" +-#include "memcasecmp.h" + #include "quote.h" + #include "stdio--.h" + #include "xmemcoll.h" + #include "xstrtol.h" + ++/* 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 "join" + +@@ -104,10 +118,12 @@ + /* Last element in `outlist', where a new element can be added. */ + static struct outlist *outlist_end = &outlist_head; + +-/* Tab character separating fields. If negative, fields are separated +- by any nonempty string of blanks, otherwise by exactly one +- tab character whose value (when cast to unsigned char) equals TAB. */ +-static int tab = -1; ++/* Tab character separating fields. If NULL, fields are separated ++ by any nonempty string of blanks. */ ++static char *tab = NULL; ++ ++/* The number of bytes used for tab. */ ++static size_t tablen = 0; + + static struct option const longopts[] = + { +@@ -190,6 +206,8 @@ + + /* Fill in the `fields' structure in LINE. */ + ++/* Fill in the `fields' structure in LINE. */ ++ + static void + xfields (struct line *line) + { +@@ -199,10 +217,11 @@ + if (ptr == lim) + return; + +- if (0 <= tab) ++ if (tab != NULL) + { ++ unsigned char t = tab[0]; + char *sep; +- for (; (sep = memchr (ptr, tab, lim - ptr)) != NULL; ptr = sep + 1) ++ for (; (sep = memchr (ptr, t, lim - ptr)) != NULL; ptr = sep + 1) + extract_field (line, ptr, sep - ptr); + } + else +@@ -229,6 +248,148 @@ + extract_field (line, ptr, lim - ptr); + } + ++#if HAVE_MBRTOWC ++static void ++xfields_multibyte (struct line *line) ++{ ++ char *ptr = line->buf.buffer; ++ char const *lim = ptr + line->buf.length - 1; ++ wchar_t wc = 0; ++ size_t mblength = 1; ++ mbstate_t state, state_bak; ++ ++ memset (&state, 0, sizeof (mbstate_t)); ++ ++ if (ptr == lim) ++ return; ++ ++ if (tab != NULL) ++ { ++ unsigned char t = tab[0]; ++ char *sep = ptr; ++ for (; ptr < lim; ptr = sep + mblength) ++ { ++ sep = ptr; ++ while (sep < lim) ++ { ++ state_bak = state; ++ mblength = mbrtowc (&wc, sep, lim - sep + 1, &state); ++ ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ if (mblength == tablen && !memcmp (sep, tab, mblength)) ++ break; ++ else ++ { ++ sep += mblength; ++ continue; ++ } ++ } ++ ++ if (sep == lim) ++ break; ++ ++ extract_field (line, ptr, sep - ptr); ++ } ++ } ++ else ++ { ++ /* Skip leading blanks before the first field. */ ++ while(ptr < lim) ++ { ++ state_bak = state; ++ mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state); ++ ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ break; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ if (!iswblank(wc)) ++ break; ++ ptr += mblength; ++ } ++ ++ do ++ { ++ char *sep; ++ state_bak = state; ++ mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state); ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ break; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ sep = ptr + mblength; ++ while (sep != lim) ++ { ++ state_bak = state; ++ mblength = mbrtowc (&wc, sep, lim - sep + 1, &state); ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ break; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ if (iswblank (wc)) ++ break; ++ ++ sep += mblength; ++ } ++ ++ extract_field (line, ptr, sep - ptr); ++ if (sep == lim) ++ return; ++ ++ state_bak = state; ++ mblength = mbrtowc (&wc, sep, lim - sep + 1, &state); ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ break; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ ptr = sep + mblength; ++ while (ptr != lim) ++ { ++ state_bak = state; ++ mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state); ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ break; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ if (!iswblank (wc)) ++ break; ++ ++ ptr += mblength; ++ } ++ } ++ while (ptr != lim); ++ } ++ ++ extract_field (line, ptr, lim - ptr); ++} ++#endif ++ + /* Read a line from FP into LINE and split it into fields. + Return true if successful. */ + +@@ -249,6 +410,11 @@ + line->nfields_allocated = 0; + line->nfields = 0; + line->fields = NULL; ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ xfields_multibyte (line); ++ else ++#endif + xfields (line); + return true; + } +@@ -303,56 +469,114 @@ + keycmp (struct line const *line1, struct line const *line2) + { + /* Start of field to compare in each file. */ +- char *beg1; +- char *beg2; +- +- size_t len1; +- size_t len2; /* Length of fields to compare. */ ++ char *beg[2]; ++ char *copy[2]; ++ size_t len[2]; /* Length of fields to compare. */ + int diff; ++ int i, j; + + if (join_field_1 < line1->nfields) + { +- beg1 = line1->fields[join_field_1].beg; +- len1 = line1->fields[join_field_1].len; ++ beg[0] = line1->fields[join_field_1].beg; ++ len[0] = line1->fields[join_field_1].len; + } + else + { +- beg1 = NULL; +- len1 = 0; ++ beg[0] = NULL; ++ len[0] = 0; + } + + if (join_field_2 < line2->nfields) + { +- beg2 = line2->fields[join_field_2].beg; +- len2 = line2->fields[join_field_2].len; ++ beg[1] = line2->fields[join_field_2].beg; ++ len[1] = line2->fields[join_field_2].len; + } + else + { +- beg2 = NULL; +- len2 = 0; ++ beg[1] = NULL; ++ len[1] = 0; + } + +- if (len1 == 0) +- return len2 == 0 ? 0 : -1; +- if (len2 == 0) ++ if (len[0] == 0) ++ return len[1] == 0 ? 0 : -1; ++ if (len[1] == 0) + return 1; + + if (ignore_case) + { +- /* FIXME: ignore_case does not work with NLS (in particular, +- with multibyte chars). */ +- diff = memcasecmp (beg1, beg2, MIN (len1, len2)); ++#ifdef HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ size_t mblength; ++ wchar_t wc, uwc; ++ mbstate_t state, state_bak; ++ ++ memset (&state, '\0', sizeof (mbstate_t)); ++ ++ for (i = 0; i < 2; i++) ++ { ++ copy[i] = alloca (len[i] + 1); ++ ++ for (j = 0; j < MIN (len[0], len[1]);) ++ { ++ state_bak = state; ++ mblength = mbrtowc (&wc, beg[i] + j, len[i] - j, &state); ++ ++ switch (mblength) ++ { ++ case (size_t) -1: ++ case (size_t) -2: ++ state = state_bak; ++ /* Fall through */ ++ case 0: ++ mblength = 1; ++ break; ++ ++ default: ++ uwc = towupper (wc); ++ ++ if (uwc != wc) ++ { ++ mbstate_t state_wc; ++ ++ memset (&state_wc, '\0', sizeof (mbstate_t)); ++ wcrtomb (copy[i] + j, uwc, &state_wc); ++ } ++ else ++ memcpy (copy[i] + j, beg[i] + j, mblength); ++ } ++ j += mblength; ++ } ++ copy[i][j] = '\0'; ++ } ++ } ++ else ++#endif ++ { ++ for (i = 0; i < 2; i++) ++ { ++ copy[i] = alloca (len[i] + 1); ++ ++ for (j = 0; j < MIN (len[0], len[1]); j++) ++ copy[i][j] = toupper (beg[i][j]); ++ ++ copy[i][j] = '\0'; ++ } ++ } + } + else + { +- if (hard_LC_COLLATE) +- return xmemcoll (beg1, len1, beg2, len2); +- diff = memcmp (beg1, beg2, MIN (len1, len2)); ++ copy[0] = (unsigned char *) beg[0]; ++ copy[1] = (unsigned char *) beg[1]; + } + ++ if (hard_LC_COLLATE) ++ return xmemcoll ((char *) copy[0], len[0], (char *) copy[1], len[1]); ++ diff = memcmp (copy[0], copy[1], MIN (len[0], len[1])); ++ + if (diff) + return diff; +- return len1 < len2 ? -1 : len1 != len2; ++ return len[0] - len[1]; + } + + /* Print field N of LINE if it exists and is nonempty, otherwise +@@ -377,11 +601,18 @@ + + /* Print the join of LINE1 and LINE2. */ + ++#define PUT_TAB_CHAR \ ++ do \ ++ { \ ++ (tab != NULL) ? \ ++ fwrite(tab, sizeof(char), tablen, stdout) : putchar (' '); \ ++ } \ ++ while (0) ++ + static void + prjoin (struct line const *line1, struct line const *line2) + { + const struct outlist *outlist; +- char output_separator = tab < 0 ? ' ' : tab; + + outlist = outlist_head.next; + if (outlist) +@@ -397,12 +628,12 @@ + if (o->file == 0) + { + if (line1 == &uni_blank) +- { ++ { + line = line2; + field = join_field_2; + } + else +- { ++ { + line = line1; + field = join_field_1; + } +@@ -416,7 +647,7 @@ + o = o->next; + if (o == NULL) + break; +- putchar (output_separator); ++ PUT_TAB_CHAR; + } + putchar ('\n'); + } +@@ -434,23 +665,23 @@ + prfield (join_field_1, line1); + for (i = 0; i < join_field_1 && i < line1->nfields; ++i) + { +- putchar (output_separator); ++ PUT_TAB_CHAR; + prfield (i, line1); + } + for (i = join_field_1 + 1; i < line1->nfields; ++i) + { +- putchar (output_separator); ++ PUT_TAB_CHAR; + prfield (i, line1); + } + + for (i = 0; i < join_field_2 && i < line2->nfields; ++i) + { +- putchar (output_separator); ++ PUT_TAB_CHAR; + prfield (i, line2); + } + for (i = join_field_2 + 1; i < line2->nfields; ++i) + { +- putchar (output_separator); ++ PUT_TAB_CHAR; + prfield (i, line2); + } + putchar ('\n'); +@@ -859,20 +1090,41 @@ + + case 't': + { +- unsigned char newtab = optarg[0]; +- if (! newtab) ++ char *newtab; ++ size_t newtablen; ++ if (! optarg[0]) + error (EXIT_FAILURE, 0, _("empty tab")); +- if (optarg[1]) ++ newtab = xstrdup (optarg); ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ mbstate_t state; ++ ++ memset (&state, 0, sizeof (mbstate_t)); ++ newtablen = mbrtowc (NULL, newtab, ++ strnlen (newtab, MB_LEN_MAX), ++ &state); ++ if (newtablen == (size_t) 0 ++ || newtablen == (size_t) -1 ++ || newtablen == (size_t) -2) ++ newtablen = 1; ++ } ++ else ++#endif ++ newtablen = 1; ++ ++ if (newtablen == 1 && newtab[1]) ++ { ++ if (STREQ (newtab, "\\0")) ++ newtab[0] = '\0'; ++ } ++ if (tab != NULL && strcmp (tab, newtab)) + { +- if (STREQ (optarg, "\\0")) +- newtab = '\0'; +- else +- error (EXIT_FAILURE, 0, _("multi-character tab %s"), +- quote (optarg)); ++ free (newtab); ++ error (EXIT_FAILURE, 0, _("incompatible tabs")); + } +- if (0 <= tab && tab != newtab) +- error (EXIT_FAILURE, 0, _("incompatible tabs")); + tab = newtab; ++ tablen = newtablen; + } + break; + +--- coreutils-6.8+/src/uniq.c.i18n 2007-01-14 15:41:28.000000000 +0000 ++++ coreutils-6.8+/src/uniq.c 2007-03-01 15:08:24.000000000 +0000 +@@ -23,6 +23,16 @@ + #include <getopt.h> + #include <sys/types.h> + ++/* Get mbstate_t, mbrtowc(). */ |
