1 diff -Naur coreutils-6.1.orig/lib/linebuffer.h coreutils-6.1/lib/linebuffer.h
2 --- coreutils-6.1.orig/lib/linebuffer.h 2005-05-14 07:58:06.000000000 +0000
3 +++ coreutils-6.1/lib/linebuffer.h 2006-08-23 20:08:12.000000000 +0000
13 /* A `struct linebuffer' holds a line of text. */
17 size_t size; /* Allocated. */
18 size_t length; /* Used. */
25 /* Initialize linebuffer LINEBUFFER for use. */
26 diff -Naur coreutils-6.1.orig/src/cut.c coreutils-6.1/src/cut.c
27 --- coreutils-6.1.orig/src/cut.c 2006-07-09 17:20:43.000000000 +0000
28 +++ coreutils-6.1/src/cut.c 2006-08-23 20:08:12.000000000 +0000
32 #include <sys/types.h>
34 +/* Get mbstate_t, mbrtowc(). */
45 +/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC
46 + installation; work around this configuration error. */
47 +#if !defined MB_LEN_MAX || MB_LEN_MAX < 2
49 +# define MB_LEN_MAX 16
52 +/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */
53 +#if HAVE_MBRTOWC && defined mbstate_t
54 +# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
57 /* The official name of this program (e.g., no `g' prefix). */
58 #define PROGRAM_NAME "cut"
64 +/* Refill the buffer BUF to get a multibyte character. */
65 +#define REFILL_BUFFER(BUF, BUFPOS, BUFLEN, STREAM) \
68 + if (BUFLEN < MB_LEN_MAX && !feof (STREAM) && !ferror (STREAM)) \
70 + memmove (BUF, BUFPOS, BUFLEN); \
71 + BUFLEN += fread (BUF + BUFLEN, sizeof(char), BUFSIZ, STREAM); \
77 +/* Get wide character on BUFPOS. BUFPOS is not included after that.
78 + If byte sequence is not valid as a character, CONVFAIL is 1. Otherwise 0. */
79 +#define GET_NEXT_WC_FROM_BUFFER(WC, BUFPOS, BUFLEN, MBLENGTH, STATE, CONVFAIL) \
82 + mbstate_t state_bak; \
90 + /* Get a wide character. */ \
92 + state_bak = STATE; \
93 + MBLENGTH = mbrtowc ((wchar_t *)&WC, BUFPOS, BUFLEN, &STATE); \
100 + STATE = state_bak; \
101 + /* Fall througn. */ \
114 /* The number of bytes allocated for FIELD_1_BUFFER. */
115 static size_t field_1_bufsize;
117 -/* The largest field or byte index used as an endpoint of a closed
118 +/* The largest byte, character or field index used as an endpoint of a closed
119 or degenerate range specification; this doesn't include the starting
120 index of right-open-ended ranges. For example, with either range spec
121 `2-5,9-', `2-3,5,9-' this variable would be set to 5. */
124 /* This is a bit vector.
125 In byte mode, which bytes to output.
126 + In character mode, which characters to output.
127 In field mode, which DELIM-separated fields to output.
128 - Both bytes and fields are numbered starting with 1,
129 + Bytes, characters and fields are numbered starting with 1,
130 so the zeroth bit of this array is unused.
131 - A field or byte K has been selected if
132 + A byte, character or field K has been selected if
133 (K <= MAX_RANGE_ENDPOINT and is_printable_field(K))
134 || (EOL_RANGE_START > 0 && K >= EOL_RANGE_START). */
135 static unsigned char *printable_field;
140 - /* Output characters that are in the given bytes. */
141 + /* Output bytes that are at the given positions. */
144 + /* Output characters that are at the given positions. */
147 /* Output the given delimeter-separated fields. */
152 static enum operating_mode operating_mode;
154 +/* If nonzero, when in byte mode, don't split multibyte characters. */
155 +static int byte_mode_character_aware;
157 +/* If nonzero, the function for single byte locale is work
158 + if this program runs on multibyte locale. */
159 +static int force_singlebyte_mode;
161 /* If true do not output lines containing no delimeter characters.
162 Otherwise, all such lines are printed. This option is valid only
166 /* The delimeter character for field mode. */
167 static unsigned char delim;
169 +static wchar_t wcdelim;
172 /* True if the --output-delimiter=STRING option was specified. */
173 static bool output_delimiter_specified;
175 -f, --fields=LIST select only these fields; also print any line\n\
176 that contains no delimiter character, unless\n\
177 the -s option is specified\n\
179 + -n with -b: don't split multibyte characters\n\
182 --complement complement the set of selected bytes, characters\n\
185 /* Starting a range. */
187 - FATAL_ERROR (_("invalid byte or field list"));
188 + FATAL_ERROR (_("invalid byte, character or field list"));
192 @@ -385,14 +462,16 @@
195 /* `n-'. From `initial' to end of line. */
196 - eol_range_start = initial;
197 + if (eol_range_start == 0 ||
198 + (eol_range_start != 0 && eol_range_start > initial))
199 + eol_range_start = initial;
204 /* `m-n' or `-n' (1-n). */
206 - FATAL_ERROR (_("invalid byte or field list"));
207 + FATAL_ERROR (_("invalid byte, character or field list"));
209 /* Is there already a range going to end of line? */
210 if (eol_range_start != 0)
212 if (operating_mode == byte_mode)
214 _("byte offset %s is too large"), quote (bad_num));
215 + else if (operating_mode == character_mode)
217 + _("character offset %s is too large"), quote (bad_num));
220 _("field number %s is too large"), quote (bad_num));
225 - FATAL_ERROR (_("invalid byte or field list"));
226 + FATAL_ERROR (_("invalid byte, character or field list"));
229 max_range_endpoint = 0;
235 +/* This function is in use for the following case.
237 + 1. Read from the stream STREAM, printing to standard output any selected
240 + 2. Read from stream STREAM, printing to standard output any selected bytes,
241 + without splitting multibyte characters. */
244 +cut_characters_or_cut_bytes_no_split (FILE *stream)
246 + int idx; /* number of bytes or characters in the line so far. */
247 + char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */
248 + char *bufpos; /* Next read position of BUF. */
249 + size_t buflen; /* The length of the byte sequence in buf. */
250 + wint_t wc; /* A gotten wide character. */
251 + size_t mblength; /* The byte size of a multibyte character which shows
252 + as same character as WC. */
253 + mbstate_t state; /* State of the stream. */
254 + int convfail; /* 1, when conversion is failed. Otherwise 0. */
259 + memset (&state, '\0', sizeof(mbstate_t));
263 + REFILL_BUFFER (buf, bufpos, buflen, stream);
265 + GET_NEXT_WC_FROM_BUFFER (wc, bufpos, buflen, mblength, state, convfail);
273 + else if (wc == L'\n')
280 + idx += (operating_mode == byte_mode) ? mblength : 1;
281 + if (print_kth (idx, NULL))
282 + fwrite (bufpos, mblength, sizeof(char), stdout);
285 + buflen -= mblength;
286 + bufpos += mblength;
291 /* Read from stream STREAM, printing to standard output any selected fields. */
294 @@ -689,13 +828,192 @@
300 +cut_fields_mb (FILE *stream)
303 + unsigned int field_idx;
304 + int found_any_selected_field;
305 + int buffer_first_field;
307 + char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */
308 + char *bufpos; /* Next read position of BUF. */
309 + size_t buflen; /* The length of the byte sequence in buf. */
310 + wint_t wc = 0; /* A gotten wide character. */
311 + size_t mblength; /* The byte size of a multibyte character which shows
312 + as same character as WC. */
313 + mbstate_t state; /* State of the stream. */
314 + int convfail; /* 1, when conversion is failed. Otherwise 0. */
316 + found_any_selected_field = 0;
320 + memset (&state, '\0', sizeof(mbstate_t));
323 + empty_input = (c == EOF);
325 + ungetc (c, stream);
329 + /* To support the semantics of the -s flag, we may have to buffer
330 + all of the first field to determine whether it is `delimited.'
331 + But that is unnecessary if all non-delimited lines must be printed
332 + and the first field has been selected, or if non-delimited lines
333 + must be suppressed and the first field has *not* been selected.
334 + That is because a non-delimited line has exactly one field. */
335 + buffer_first_field = (suppress_non_delimited ^ !print_kth (1, NULL));
339 + if (field_idx == 1 && buffer_first_field)
345 + REFILL_BUFFER (buf, bufpos, buflen, stream);
347 + GET_NEXT_WC_FROM_BUFFER
348 + (wc, bufpos, buflen, mblength, state, convfail);
353 + field_1_buffer = xrealloc (field_1_buffer, len + mblength);
354 + memcpy (field_1_buffer + len, bufpos, mblength);
356 + buflen -= mblength;
357 + bufpos += mblength;
359 + if (!convfail && (wc == L'\n' || wc == wcdelim))
366 + /* If the first field extends to the end of line (it is not
367 + delimited) and we are printing all non-delimited lines,
369 + if (convfail || (!convfail && wc != wcdelim))
371 + if (suppress_non_delimited)
377 + fwrite (field_1_buffer, sizeof (char), len, stdout);
378 + /* Make sure the output line is newline terminated. */
379 + if (convfail || (!convfail && wc != L'\n'))
385 + if (print_kth (1, NULL))
387 + /* Print the field, but not the trailing delimiter. */
388 + fwrite (field_1_buffer, sizeof (char), len - 1, stdout);
389 + found_any_selected_field = 1;
396 + if (print_kth (field_idx, NULL))
398 + if (found_any_selected_field)
400 + fwrite (output_delimiter_string, sizeof (char),
401 + output_delimiter_length, stdout);
403 + found_any_selected_field = 1;
408 + REFILL_BUFFER (buf, bufpos, buflen, stream);
410 + GET_NEXT_WC_FROM_BUFFER
411 + (wc, bufpos, buflen, mblength, state, convfail);
415 + else if (!convfail && (wc == wcdelim || wc == L'\n'))
417 + buflen -= mblength;
418 + bufpos += mblength;
422 + if (print_kth (field_idx, NULL))
423 + fwrite (bufpos, mblength, sizeof(char), stdout);
425 + buflen -= mblength;
426 + bufpos += mblength;
430 + if ((!convfail || wc == L'\n') && buflen < 1)
433 + if (!convfail && wc == wcdelim)
435 + else if (wc == WEOF || (!convfail && wc == L'\n'))
437 + if (found_any_selected_field
438 + || (!empty_input && !(suppress_non_delimited && field_idx == 1)))
443 + found_any_selected_field = 0;
450 cut_stream (FILE *stream)
452 - if (operating_mode == byte_mode)
453 - cut_bytes (stream);
455 + if (MB_CUR_MAX > 1 && !force_singlebyte_mode)
457 + switch (operating_mode)
460 + if (byte_mode_character_aware)
461 + cut_characters_or_cut_bytes_no_split (stream);
463 + cut_bytes (stream);
466 + case character_mode:
467 + cut_characters_or_cut_bytes_no_split (stream);
471 + cut_fields_mb (stream);
479 - cut_fields (stream);
482 + if (operating_mode == field_mode)
483 + cut_fields (stream);
485 + cut_bytes (stream);
489 /* Process file FILE to standard output.
492 bool delim_specified = false;
493 char *spec_list_string IF_LINT(= NULL);
494 + char mbdelim[MB_LEN_MAX + 1];
495 + size_t delimlen = 0;
497 initialize_main (&argc, &argv);
498 program_name = argv[0];
504 /* Build the byte list. */
505 if (operating_mode != undefined_mode)
506 FATAL_ERROR (_("only one type of list may be specified"));
507 @@ -775,6 +1094,14 @@
508 spec_list_string = optarg;
512 + /* Build the character list. */
513 + if (operating_mode != undefined_mode)
514 + FATAL_ERROR (_("only one type of list may be specified"));
515 + operating_mode = character_mode;
516 + spec_list_string = optarg;
520 /* Build the field list. */
521 if (operating_mode != undefined_mode)
522 @@ -786,10 +1113,35 @@
525 /* Interpret -d '' to mean `use the NUL byte as the delimiter.' */
526 - if (optarg[0] != '\0' && optarg[1] != '\0')
527 - FATAL_ERROR (_("the delimiter must be a single character"));
529 - delim_specified = true;
536 + memset (&state, '\0', sizeof(mbstate_t));
537 + delimlen = mbrtowc (&wcdelim, optarg, strnlen(optarg, MB_LEN_MAX), &state);
539 + if (delimlen == (size_t)-1 || delimlen == (size_t)-2)
540 + ++force_singlebyte_mode;
543 + delimlen = (delimlen < 1) ? 1 : delimlen;
544 + if (wcdelim != L'\0' && *(optarg + delimlen) != '\0')
545 + FATAL_ERROR (_("the delimiter must be a single character"));
546 + memcpy (mbdelim, optarg, delimlen);
550 + if (MB_CUR_MAX <= 1 || force_singlebyte_mode)
553 + if (optarg[0] != '\0' && optarg[1] != '\0')
554 + FATAL_ERROR (_("the delimiter must be a single character"));
555 + delim = (unsigned char) optarg[0];
557 + delim_specified = true;
561 case OUTPUT_DELIMITER_OPTION:
566 + byte_mode_character_aware = 1;
571 if (operating_mode == undefined_mode)
572 FATAL_ERROR (_("you must specify a list of bytes, characters, or fields"));
574 - if (delim != '\0' && operating_mode != field_mode)
575 + if (delim_specified && operating_mode != field_mode)
576 FATAL_ERROR (_("an input delimiter may be specified only\
577 when operating on fields"));
579 @@ -851,15 +1204,34 @@
582 if (!delim_specified)
594 if (output_delimiter_string == NULL)
596 - static char dummy[2];
599 - output_delimiter_string = dummy;
600 - output_delimiter_length = 1;
602 + if (MB_CUR_MAX > 1 && !force_singlebyte_mode)
604 + output_delimiter_string = xstrdup(mbdelim);
605 + output_delimiter_length = delimlen;
608 + if (MB_CUR_MAX <= 1 || force_singlebyte_mode)
611 + static char dummy[2];
614 + output_delimiter_string = dummy;
615 + output_delimiter_length = 1;
620 diff -Naur coreutils-6.1.orig/src/expand.c coreutils-6.1/src/expand.c
621 --- coreutils-6.1.orig/src/expand.c 2006-07-09 17:03:29.000000000 +0000
622 +++ coreutils-6.1/src/expand.c 2006-08-23 20:08:12.000000000 +0000
626 #include <sys/types.h>
628 +/* Get mbstate_t, mbrtowc(), wcwidth(). */
636 #include "xstrndup.h"
638 +/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC
639 + installation; work around this configuration error. */
640 +#if !defined MB_LEN_MAX || MB_LEN_MAX < 2
641 +# define MB_LEN_MAX 16
644 +/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */
645 +#if HAVE_MBRTOWC && defined mbstate_t
646 +# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
649 /* The official name of this program (e.g., no `g' prefix). */
650 #define PROGRAM_NAME "expand"
653 stops = num_start + len - 1;
659 error (0, 0, _("tab size contains invalid character(s): %s"),
660 @@ -365,6 +383,142 @@
666 +expand_multibyte (void)
668 + FILE *fp; /* Input strem. */
669 + mbstate_t i_state; /* Current shift state of the input stream. */
670 + mbstate_t i_state_bak; /* Back up the I_STATE. */
671 + mbstate_t o_state; /* Current shift state of the output stream. */
672 + char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */
673 + char *bufpos; /* Next read position of BUF. */
674 + size_t buflen = 0; /* The length of the byte sequence in buf. */
675 + wchar_t wc; /* A gotten wide character. */
676 + size_t mblength; /* The byte size of a multibyte character
677 + which shows as same character as WC. */
678 + int tab_index = 0; /* Index in `tab_list' of next tabstop. */
679 + int column = 0; /* Column on screen of the next char. */
680 + int next_tab_column; /* Column the next tab stop is on. */
681 + int convert = 1; /* If nonzero, perform translations. */
683 + fp = next_file ((FILE *) NULL);
687 + memset (&o_state, '\0', sizeof(mbstate_t));
688 + memset (&i_state, '\0', sizeof(mbstate_t));
692 + /* Refill the buffer BUF. */
693 + if (buflen < MB_LEN_MAX && !feof(fp) && !ferror(fp))
695 + memmove (buf, bufpos, buflen);
696 + buflen += fread (buf + buflen, sizeof(char), BUFSIZ, fp);
700 + /* No character is left in BUF. */
703 + fp = next_file (fp);
706 + break; /* No more files. */
709 + memset (&i_state, '\0', sizeof(mbstate_t));
714 + /* Get a wide character. */
715 + i_state_bak = i_state;
716 + mblength = mbrtowc (&wc, bufpos, buflen, &i_state);
720 + case (size_t)-1: /* illegal byte sequence. */
723 + i_state = i_state_bak;
727 + if (convert_entire_line == 0)
733 + case 0: /* null. */
735 + if (convert && convert_entire_line == 0)
741 + if (wc == L'\n') /* LF. */
748 + else if (wc == L'\t' && convert) /* Tab. */
752 + /* Do not let tab_index == first_free_tab;
753 + stop when it is 1 less. */
754 + while (tab_index < first_free_tab - 1
755 + && column >= tab_list[tab_index])
757 + next_tab_column = tab_list[tab_index];
758 + if (tab_index < first_free_tab - 1)
760 + if (column >= next_tab_column)
761 + next_tab_column = column + 1;
764 + next_tab_column = column + tab_size - column % tab_size;
766 + while (column < next_tab_column)
783 + int width; /* The width of WC. */
785 + width = wcwidth (wc);
786 + column += (width > 0) ? width : 0;
787 + if (convert_entire_line == 0)
791 + fwrite (bufpos, sizeof(char), mblength, stdout);
794 + buflen -= mblength;
795 + bufpos += mblength;
801 main (int argc, char **argv)
805 file_list = (optind < argc ? &argv[optind] : stdin_argv);
809 + if (MB_CUR_MAX > 1)
810 + expand_multibyte ();
815 if (have_read_stdin && fclose (stdin) != 0)
816 error (EXIT_FAILURE, errno, "-");
817 diff -Naur coreutils-6.1.orig/src/fold.c coreutils-6.1/src/fold.c
818 --- coreutils-6.1.orig/src/fold.c 2006-07-09 17:20:43.000000000 +0000
819 +++ coreutils-6.1/src/fold.c 2006-08-23 20:08:12.000000000 +0000
822 #include <sys/types.h>
824 +/* Get mbstate_t, mbrtowc(), wcwidth(). */
829 +/* Get iswprint(), iswblank(), wcwidth(). */
831 +# include <wctype.h>
839 +/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC
840 + installation; work around this configuration error. */
841 +#if !defined MB_LEN_MAX || MB_LEN_MAX < 2
843 +# define MB_LEN_MAX 16
846 +/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */
847 +#if HAVE_MBRTOWC && defined mbstate_t
848 +# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
853 /* The official name of this program (e.g., no `g' prefix). */
856 #define AUTHORS "David MacKenzie"
858 +#define FATAL_ERROR(Message) \
861 + error (0, 0, (Message)); \
868 + /* Fold texts by columns that are at the given positions. */
871 + /* Fold texts by bytes that are at the given positions. */
874 + /* Fold texts by characters that are at the given positions. */
878 /* The name this program was run with. */
881 +/* The argument shows current mode. (Default: column_mode) */
882 +static enum operating_mode operating_mode;
884 /* If nonzero, try to break on whitespace. */
885 static bool break_spaces;
887 -/* If nonzero, count bytes, not column positions. */
888 -static bool count_bytes;
890 /* If nonzero, at least one of the files we read was standard input. */
891 static bool have_read_stdin;
893 -static char const shortopts[] = "bsw:0::1::2::3::4::5::6::7::8::9::";
894 +static char const shortopts[] = "bcsw:0::1::2::3::4::5::6::7::8::9::";
896 static struct option const longopts[] =
898 {"bytes", no_argument, NULL, 'b'},
899 + {"characters", no_argument, NULL, 'c'},
900 {"spaces", no_argument, NULL, 's'},
901 {"width", required_argument, NULL, 'w'},
902 {GETOPT_HELP_OPTION_DECL},
906 -b, --bytes count bytes rather than columns\n\
907 + -c, --characters count characters rather than columns\n\
908 -s, --spaces break at spaces\n\
909 -w, --width=WIDTH use WIDTH columns instead of 80\n\
913 adjust_column (size_t column, char c)
916 + if (operating_mode != byte_mode)
920 @@ -117,35 +161,14 @@
924 -/* Fold file FILENAME, or standard input if FILENAME is "-",
925 - to stdout, with maximum line length WIDTH.
926 - Return true if successful. */
929 -fold_file (char *filename, size_t width)
931 +fold_text (FILE *istream, size_t width, int *saved_errno)
935 size_t column = 0; /* Screen column where next char will go. */
936 size_t offset_out = 0; /* Index in `line_out' for next char. */
937 static char *line_out = NULL;
938 static size_t allocated_out = 0;
941 - if (STREQ (filename, "-"))
944 - have_read_stdin = true;
947 - istream = fopen (filename, "r");
949 - if (istream == NULL)
951 - error (0, errno, "%s", filename);
955 while ((c = getc (istream)) != EOF)
957 if (offset_out + 1 >= allocated_out)
959 bool found_blank = false;
960 size_t logical_end = offset_out;
962 + /* If LINE_OUT has no wide character,
963 + put a new wide character in LINE_OUT
964 + if column is bigger than width. */
965 + if (offset_out == 0)
967 + line_out[offset_out++] = c;
971 /* Look for the last blank. */
974 @@ -218,11 +250,225 @@
975 line_out[offset_out++] = c;
978 - saved_errno = errno;
979 + *saved_errno = errno;
982 + fwrite (line_out, sizeof (char), (size_t) offset_out, stdout);
989 +fold_multibyte_text (FILE *istream, int width, int *saved_errno)
991 + char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */
992 + size_t buflen = 0; /* The length of the byte sequence in buf. */
993 + char *bufpos; /* Next read position of BUF. */
994 + wint_t wc; /* A gotten wide character. */
995 + size_t mblength; /* The byte size of a multibyte character which shows
996 + as same character as WC. */
997 + mbstate_t state, state_bak; /* State of the stream. */
998 + int convfail; /* 1, when conversion is failed. Otherwise 0. */
1000 + char *line_out = NULL;
1001 + size_t offset_out = 0; /* Index in `line_out' for next char. */
1002 + size_t allocated_out = 0;
1005 + size_t column = 0;
1007 + size_t last_blank_pos;
1008 + size_t last_blank_column;
1009 + int is_blank_seen;
1010 + int last_blank_increment;
1011 + int is_bs_following_last_blank;
1012 + size_t bs_following_last_blank_num;
1013 + int is_cr_after_last_blank;
1015 +#define CLEAR_FLAGS \
1018 + last_blank_pos = 0; \
1019 + last_blank_column = 0; \
1020 + is_blank_seen = 0; \
1021 + is_bs_following_last_blank = 0; \
1022 + bs_following_last_blank_num = 0; \
1023 + is_cr_after_last_blank = 0; \
1027 +#define START_NEW_LINE \
1038 + memset (&state, '\0', sizeof(mbstate_t));
1040 + for (;; bufpos += mblength, buflen -= mblength)
1042 + if (buflen < MB_LEN_MAX && !feof (istream) && !ferror (istream))
1044 + memmove (buf, bufpos, buflen);
1045 + buflen += fread (buf + buflen, sizeof(char), BUFSIZ, istream);
1052 + /* Get a wide character. */
1054 + state_bak = state;
1055 + mblength = mbrtowc ((wchar_t *)&wc, bufpos, buflen, &state);
1062 + state = state_bak;
1063 + /* Fall through. */
1071 + if (operating_mode == byte_mode) /* byte mode */
1072 + increment = mblength;
1073 + else if (operating_mode == character_mode) /* character mode */
1075 + else /* column mode */
1084 + fwrite (line_out, sizeof(char), offset_out, stdout);
1089 + increment = (column > 0) ? -1 : 0;
1093 + increment = -1 * column;
1097 + increment = 8 - column % 8;
1101 + increment = wcwidth (wc);
1102 + increment = (increment < 0) ? 0 : increment;
1107 + if (column + increment > width && break_spaces && last_blank_pos)
1109 + fwrite (line_out, sizeof(char), last_blank_pos, stdout);
1112 + offset_out = offset_out - last_blank_pos;
1113 + column = column - last_blank_column + ((is_cr_after_last_blank)
1114 + ? last_blank_increment : bs_following_last_blank_num);
1115 + memmove (line_out, line_out + last_blank_pos, offset_out);
1120 + if (column + increment > width && column != 0)
1122 + fwrite (line_out, sizeof(char), offset_out, stdout);
1127 + if (allocated_out < offset_out + mblength)
1129 + allocated_out += 1024;
1130 + line_out = xrealloc (line_out, allocated_out);
1133 + memcpy (line_out + offset_out, bufpos, mblength);
1134 + offset_out += mblength;
1135 + column += increment;
1137 + if (is_blank_seen && !convfail && wc == L'\r')
1138 + is_cr_after_last_blank = 1;
1140 + if (is_bs_following_last_blank && !convfail && wc == L'\b')
1141 + ++bs_following_last_blank_num;
1143 + is_bs_following_last_blank = 0;
1145 + if (break_spaces && !convfail && iswblank (wc))
1147 + last_blank_pos = offset_out;
1148 + last_blank_column = column;
1149 + is_blank_seen = 1;
1150 + last_blank_increment = increment;
1151 + is_bs_following_last_blank = 1;
1152 + bs_following_last_blank_num = 0;
1153 + is_cr_after_last_blank = 0;
1157 + *saved_errno = errno;
1160 fwrite (line_out, sizeof (char), (size_t) offset_out, stdout);
1166 +/* Fold file FILENAME, or standard input if FILENAME is "-",
1167 + to stdout, with maximum line length WIDTH.
1168 + Return 0 if successful, 1 if an error occurs. */
1171 +fold_file (char *filename, int width)
1176 + if (STREQ (filename, "-"))
1179 + have_read_stdin = 1;
1182 + istream = fopen (filename, "r");
1184 + if (istream == NULL)
1186 + error (0, errno, "%s", filename);
1190 + /* Define how ISTREAM is being folded. */
1192 + if (MB_CUR_MAX > 1)
1193 + fold_multibyte_text (istream, width, &saved_errno);
1196 + fold_text (istream, width, &saved_errno);
1198 if (ferror (istream))
1200 error (0, saved_errno, "%s", filename);
1203 atexit (close_stdout);
1205 - break_spaces = count_bytes = have_read_stdin = false;
1206 + operating_mode = column_mode;
1207 + break_spaces = have_read_stdin = false;
1209 while ((optc = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1)
1211 @@ -264,7 +511,15 @@
1214 case 'b': /* Count bytes rather than columns. */
1215 - count_bytes = true;
1216 + if (operating_mode != column_mode)
1217 + FATAL_ERROR (_("only one way of folding may be specified"));
1218 + operating_mode = byte_mode;
1222 + if (operating_mode != column_mode)
1223 + FATAL_ERROR (_("only one way of folding may be specified"));
1224 + operating_mode = character_mode;
1227 case 's': /* Break at word boundaries. */
1228 diff -Naur coreutils-6.1.orig/src/join.c coreutils-6.1/src/join.c
1229 --- coreutils-6.1.orig/src/join.c 2006-07-09 17:06:58.000000000 +0000
1230 +++ coreutils-6.1/src/join.c 2006-08-23 20:08:12.000000000 +0000
1232 #include <sys/types.h>
1235 +/* Get mbstate_t, mbrtowc(), mbrtowc(), wcwidth(). */
1237 +# include <wchar.h>
1240 +/* Get iswblank(), towupper. */
1242 +# include <wctype.h>
1247 #include "hard-locale.h"
1248 #include "linebuffer.h"
1249 -#include "memcasecmp.h"
1251 #include "stdio--.h"
1252 #include "xmemcoll.h"
1253 #include "xstrtol.h"
1255 +/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */
1256 +#if HAVE_MBRTOWC && defined mbstate_t
1257 +# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
1260 /* The official name of this program (e.g., no `g' prefix). */
1261 #define PROGRAM_NAME "join"
1263 @@ -104,10 +118,12 @@
1264 /* Last element in `outlist', where a new element can be added. */
1265 static struct outlist *outlist_end = &outlist_head;
1267 -/* Tab character separating fields. If negative, fields are separated
1268 - by any nonempty string of blanks, otherwise by exactly one
1269 - tab character whose value (when cast to unsigned char) equals TAB. */
1270 -static int tab = -1;
1271 +/* Tab character separating fields. If NULL, fields are separated
1272 + by any nonempty string of blanks. */
1273 +static char *tab = NULL;
1275 +/* The number of bytes used for tab. */
1276 +static size_t tablen = 0;
1278 static struct option const longopts[] =
1282 /* Fill in the `fields' structure in LINE. */
1284 +/* Fill in the `fields' structure in LINE. */
1287 xfields (struct line *line)
1289 @@ -199,10 +217,11 @@
1296 + unsigned char t = tab[0];
1298 - for (; (sep = memchr (ptr, tab, lim - ptr)) != NULL; ptr = sep + 1)
1299 + for (; (sep = memchr (ptr, t, lim - ptr)) != NULL; ptr = sep + 1)
1300 extract_field (line, ptr, sep - ptr);
1303 @@ -229,6 +248,148 @@
1304 extract_field (line, ptr, lim - ptr);
1309 +xfields_multibyte (struct line *line)
1311 + char *ptr = line->buf.buffer;
1312 + char const *lim = ptr + line->buf.length - 1;
1314 + size_t mblength = 1;
1315 + mbstate_t state, state_bak;
1317 + memset (&state, 0, sizeof (mbstate_t));
1324 + unsigned char t = tab[0];
1326 + for (; ptr < lim; ptr = sep + mblength)
1331 + state_bak = state;
1332 + mblength = mbrtowc (&wc, sep, lim - sep + 1, &state);
1334 + if (mblength == (size_t)-1 || mblength == (size_t)-2)
1337 + state = state_bak;
1339 + mblength = (mblength < 1) ? 1 : mblength;
1341 + if (mblength == tablen && !memcmp (sep, tab, mblength))
1353 + extract_field (line, ptr, sep - ptr);
1358 + /* Skip leading blanks before the first field. */
1361 + state_bak = state;
1362 + mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state);
1364 + if (mblength == (size_t)-1 || mblength == (size_t)-2)
1367 + state = state_bak;
1370 + mblength = (mblength < 1) ? 1 : mblength;
1372 + if (!iswblank(wc))
1380 + state_bak = state;
1381 + mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state);
1382 + if (mblength == (size_t)-1 || mblength == (size_t)-2)
1385 + state = state_bak;
1388 + mblength = (mblength < 1) ? 1 : mblength;
1390 + sep = ptr + mblength;
1391 + while (sep != lim)
1393 + state_bak = state;
1394 + mblength = mbrtowc (&wc, sep, lim - sep + 1, &state);
1395 + if (mblength == (size_t)-1 || mblength == (size_t)-2)
1398 + state = state_bak;
1401 + mblength = (mblength < 1) ? 1 : mblength;
1403 + if (iswblank (wc))
1409 + extract_field (line, ptr, sep - ptr);
1413 + state_bak = state;
1414 + mblength = mbrtowc (&wc, sep, lim - sep + 1, &state);
1415 + if (mblength == (size_t)-1 || mblength == (size_t)-2)
1418 + state = state_bak;
1421 + mblength = (mblength < 1) ? 1 : mblength;
1423 + ptr = sep + mblength;
1424 + while (ptr != lim)
1426 + state_bak = state;
1427 + mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state);
1428 + if (mblength == (size_t)-1 || mblength == (size_t)-2)
1431 + state = state_bak;
1434 + mblength = (mblength < 1) ? 1 : mblength;
1436 + if (!iswblank (wc))
1442 + while (ptr != lim);
1445 + extract_field (line, ptr, lim - ptr);
1449 /* Read a line from FP into LINE and split it into fields.
1450 Return true if successful. */
1452 @@ -249,6 +410,11 @@
1453 line->nfields_allocated = 0;
1455 line->fields = NULL;
1457 + if (MB_CUR_MAX > 1)
1458 + xfields_multibyte (line);
1464 @@ -303,56 +469,114 @@
1465 keycmp (struct line const *line1, struct line const *line2)
1467 /* Start of field to compare in each file. */
1472 - size_t len2; /* Length of fields to compare. */
1475 + size_t len[2]; /* Length of fields to compare. */
1479 if (join_field_1 < line1->nfields)
1481 - beg1 = line1->fields[join_field_1].beg;
1482 - len1 = line1->fields[join_field_1].len;
1483 + beg[0] = line1->fields[join_field_1].beg;
1484 + len[0] = line1->fields[join_field_1].len;
1494 if (join_field_2 < line2->nfields)
1496 - beg2 = line2->fields[join_field_2].beg;
1497 - len2 = line2->fields[join_field_2].len;
1498 + beg[1] = line2->fields[join_field_2].beg;
1499 + len[1] = line2->fields[join_field_2].len;
1510 - return len2 == 0 ? 0 : -1;
1513 + return len[1] == 0 ? 0 : -1;
1519 - /* FIXME: ignore_case does not work with NLS (in particular,
1520 - with multibyte chars). */
1521 - diff = memcasecmp (beg1, beg2, MIN (len1, len2));
1522 +#ifdef HAVE_MBRTOWC
1523 + if (MB_CUR_MAX > 1)
1527 + mbstate_t state, state_bak;
1529 + memset (&state, '\0', sizeof (mbstate_t));
1531 + for (i = 0; i < 2; i++)
1533 + copy[i] = alloca (len[i] + 1);
1535 + for (j = 0; j < MIN (len[0], len[1]);)
1537 + state_bak = state;
1538 + mblength = mbrtowc (&wc, beg[i] + j, len[i] - j, &state);
1544 + state = state_bak;
1545 + /* Fall through */
1551 + uwc = towupper (wc);
1555 + mbstate_t state_wc;
1557 + memset (&state_wc, '\0', sizeof (mbstate_t));
1558 + wcrtomb (copy[i] + j, uwc, &state_wc);
1561 + memcpy (copy[i] + j, beg[i] + j, mblength);
1565 + copy[i][j] = '\0';
1571 + for (i = 0; i < 2; i++)
1573 + copy[i] = alloca (len[i] + 1);
1575 + for (j = 0; j < MIN (len[0], len[1]); j++)
1576 + copy[i][j] = toupper (beg[i][j]);
1578 + copy[i][j] = '\0';
1584 - if (hard_LC_COLLATE)
1585 - return xmemcoll (beg1, len1, beg2, len2);
1586 - diff = memcmp (beg1, beg2, MIN (len1, len2));
1587 + copy[0] = (unsigned char *) beg[0];
1588 + copy[1] = (unsigned char *) beg[1];
1591 + if (HAVE_SETLOCALE && hard_LC_COLLATE)
1592 + return xmemcoll ((char *) copy[0], len[0], (char *) copy[1], len[1]);
1593 + diff = memcmp (copy[0], copy[1], MIN (len[0], len[1]));
1597 - return len1 < len2 ? -1 : len1 != len2;
1598 + return len[0] - len[1];
1601 /* Print field N of LINE if it exists and is nonempty, otherwise
1602 @@ -377,11 +601,18 @@
1604 /* Print the join of LINE1 and LINE2. */
1606 +#define PUT_TAB_CHAR \
1610 + fwrite(tab, sizeof(char), tablen, stdout) : putchar (' '); \
1615 prjoin (struct line const *line1, struct line const *line2)
1617 const struct outlist *outlist;
1618 - char output_separator = tab < 0 ? ' ' : tab;
1620 outlist = outlist_head.next;
1622 @@ -397,12 +628,12 @@
1625 if (line1 == &uni_blank)
1629 field = join_field_2;
1635 field = join_field_1;
1641 - putchar (output_separator);
1646 @@ -434,23 +665,23 @@
1647 prfield (join_field_1, line1);
1648 for (i = 0; i < join_field_1 && i < line1->nfields; ++i)
1650 - putchar (output_separator);
1654 for (i = join_field_1 + 1; i < line1->nfields; ++i)
1656 - putchar (output_separator);
1661 for (i = 0; i < join_field_2 && i < line2->nfields; ++i)
1663 - putchar (output_separator);
1667 for (i = join_field_2 + 1; i < line2->nfields; ++i)
1669 - putchar (output_separator);
1674 @@ -862,20 +1093,41 @@
1678 - unsigned char newtab = optarg[0];
1683 error (EXIT_FAILURE, 0, _("empty tab"));
1685 + newtab = xstrdup (optarg);
1687 + if (MB_CUR_MAX > 1)
1691 + memset (&state, 0, sizeof (mbstate_t));
1692 + newtablen = mbrtowc (NULL, newtab,
1693 + strnlen (newtab, MB_LEN_MAX),
1695 + if (newtablen == (size_t) 0
1696 + || newtablen == (size_t) -1
1697 + || newtablen == (size_t) -2)
1704 + if (newtablen == 1 && newtab[1])
1706 + if (STREQ (newtab, "\\0"))
1709 + if (tab != NULL && strcmp (tab, newtab))
1711 - if (STREQ (optarg, "\\0"))
1714 - error (EXIT_FAILURE, 0, _("multi-character tab %s"),
1717 + error (EXIT_FAILURE, 0, _("incompatible tabs"));
1719 - if (0 <= tab && tab != newtab)
1720 - error (EXIT_FAILURE, 0, _("incompatible tabs"));
1722 + tablen = newtablen;
1726 diff -Naur coreutils-6.1.orig/src/pr.c coreutils-6.1/src/pr.c
1727 --- coreutils-6.1.orig/src/pr.c 2006-07-09 17:20:43.000000000 +0000
1728 +++ coreutils-6.1/src/pr.c 2006-08-23 20:08:12.000000000 +0000
1729 @@ -313,6 +313,32 @@
1732 #include <sys/types.h>
1734 +/* Get MB_LEN_MAX. */
1735 +#include <limits.h>
1736 +/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC
1737 + installation; work around this configuration error. */
1738 +#if !defined MB_LEN_MAX || MB_LEN_MAX == 1
1739 +# define MB_LEN_MAX 16
1742 +/* Get MB_CUR_MAX. */
1743 +#include <stdlib.h>
1745 +/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */
1746 +/* Get mbstate_t, mbrtowc(), wcwidth(). */
1748 +# include <wchar.h>
1751 +/* Get iswprint(). -- for wcwidth(). */
1753 +# include <wctype.h>
1755 +#if !defined iswprint && !HAVE_ISWPRINT
1756 +# define iswprint(wc) 1
1761 #include "hard-locale.h"
1762 @@ -324,6 +350,18 @@
1763 #include "strftime.h"
1764 #include "xstrtol.h"
1766 +/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */
1767 +#if HAVE_MBRTOWC && defined mbstate_t
1768 +# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
1771 +#ifndef HAVE_DECL_WCWIDTH
1772 +"this configure-time declaration test was not run"
1774 +#if !HAVE_DECL_WCWIDTH
1775 +extern int wcwidth ();
1778 /* The official name of this program (e.g., no `g' prefix). */
1779 #define PROGRAM_NAME "pr"
1781 @@ -416,7 +454,20 @@
1783 #define NULLCOL (COLUMN *)0
1785 -static int char_to_clump (char c);
1786 +/* Funtion pointers to switch functions for single byte locale or for
1787 + multibyte locale. If multibyte functions do not exist in your sysytem,
1788 + these pointers always point the function for single byte locale. */
1789 +static void (*print_char) (char c);
1790 +static int (*char_to_clump) (char c);
1792 +/* Functions for single byte locale. */
1793 +static void print_char_single (char c);
1794 +static int char_to_clump_single (char c);
1796 +/* Functions for multibyte locale. */
1797 +static void print_char_multi (char c);
1798 +static int char_to_clump_multi (char c);
1800 static bool read_line (COLUMN *p);
1801 static bool print_page (void);
1802 static bool print_stored (COLUMN *p);
1804 static void pad_across_to (int position);
1805 static void add_line_number (COLUMN *p);
1806 static void getoptarg (char *arg, char switch_char, char *character,
1807 + int *character_length, int *character_width,
1809 void usage (int status);
1810 static void print_files (int number_of_files, char **av);
1812 static void pad_down (int lines);
1813 static void read_rest_of_line (COLUMN *p);
1814 static void skip_read (COLUMN *p, int column_number);
1815 -static void print_char (char c);
1816 static void cleanup (void);
1817 static void print_sep_string (void);
1818 static void separator_string (const char *optarg_S);
1820 we store the leftmost columns contiguously in buff.
1821 To print a line from buff, get the index of the first character
1822 from line_vector[i], and print up to line_vector[i + 1]. */
1824 +static unsigned char *buff;
1826 /* Index of the position in buff where the next character
1829 static bool untabify_input = false;
1831 /* (-e) The input tab character. */
1832 -static char input_tab_char = '\t';
1833 +static char input_tab_char[MB_LEN_MAX] = "\t";
1835 /* (-e) Tabstops are at chars_per_tab, 2*chars_per_tab, 3*chars_per_tab, ...
1836 where the leftmost column is 1. */
1837 @@ -569,7 +620,10 @@
1838 static bool tabify_output = false;
1840 /* (-i) The output tab character. */
1841 -static char output_tab_char = '\t';
1842 +static char output_tab_char[MB_LEN_MAX] = "\t";
1844 +/* (-i) The byte length of output tab character. */
1845 +static int output_tab_char_length = 1;
1847 /* (-i) The width of the output tab. */
1848 static int chars_per_output_tab = 8;
1849 @@ -643,7 +697,13 @@
1850 static bool numbered_lines = false;
1852 /* (-n) Character which follows each line number. */
1853 -static char number_separator = '\t';
1854 +static char number_separator[MB_LEN_MAX] = "\t";
1856 +/* (-n) The byte length of the character which follows each line number. */
1857 +static int number_separator_length = 1;
1859 +/* (-n) The character width of the character which follows each line number. */
1860 +static int number_separator_width = 0;
1862 /* (-n) line counting starts with 1st line of input file (not with 1st
1863 line of 1st page printed). */
1865 -a|COLUMN|-m is a `space' and with the -J option a `tab'. */
1866 static char *col_sep_string = "";
1867 static int col_sep_length = 0;
1868 +static int col_sep_width = 0;
1869 static char *column_separator = " ";
1870 static char *line_separator = "\t";
1872 @@ -852,6 +913,13 @@
1873 col_sep_length = (int) strlen (optarg_S);
1874 col_sep_string = xmalloc (col_sep_length + 1);
1875 strcpy (col_sep_string, optarg_S);
1878 + if (MB_CUR_MAX > 1)
1879 + col_sep_width = mbswidth (col_sep_string, 0);
1882 + col_sep_width = col_sep_length;
1886 @@ -877,6 +945,21 @@
1888 atexit (close_stdout);
1890 +/* Define which functions are used, the ones for single byte locale or the ones
1891 + for multibyte locale. */
1893 + if (MB_CUR_MAX > 1)
1895 + print_char = print_char_multi;
1896 + char_to_clump = char_to_clump_multi;
1901 + print_char = print_char_single;
1902 + char_to_clump = char_to_clump_single;
1906 file_names = (argc > 1
1907 ? xmalloc ((argc - 1) * sizeof (char *))
1908 @@ -949,8 +1032,12 @@
1912 - getoptarg (optarg, 'e', &input_tab_char,
1913 - &chars_per_input_tab);
1915 + int dummy_length, dummy_width;
1917 + getoptarg (optarg, 'e', input_tab_char, &dummy_length,
1918 + &dummy_width, &chars_per_input_tab);
1920 /* Could check tab width > 0. */
1921 untabify_input = true;
1923 @@ -963,8 +1050,12 @@
1927 - getoptarg (optarg, 'i', &output_tab_char,
1928 - &chars_per_output_tab);
1932 + getoptarg (optarg, 'i', output_tab_char, &output_tab_char_length,
1933 + &dummy_width, &chars_per_output_tab);
1935 /* Could check tab width > 0. */
1936 tabify_output = true;
1938 @@ -991,8 +1082,8 @@
1940 numbered_lines = true;
1942 - getoptarg (optarg, 'n', &number_separator,
1943 - &chars_per_number);
1944 + getoptarg (optarg, 'n', number_separator, &number_separator_length,
1945 + &number_separator_width, &chars_per_number);
1949 @@ -1031,7 +1122,7 @@
1951 /* Reset an additional input of -s, -S dominates -s */
1952 col_sep_string = "";
1953 - col_sep_length = 0;
1954 + col_sep_length = col_sep_width = 0;
1955 use_col_separator = true;
1957 separator_string (optarg);
1958 @@ -1188,10 +1279,45 @@
1962 -getoptarg (char *arg, char switch_char, char *character, int *number)
1963 +getoptarg (char *arg, char switch_char, char *character, int *character_length,
1964 + int *character_width, int *number)
1966 if (!ISDIGIT (*arg))
1967 - *character = *arg++;
1969 +#ifdef HAVE_MBRTOWC
1970 + if (MB_CUR_MAX > 1) /* for multibyte locale. */
1975 + mbstate_t state = {'\0'};
1977 + mblength = mbrtowc (&wc, arg, strnlen(arg, MB_LEN_MAX), &state);
1979 + if (mblength == (size_t)-1 || mblength == (size_t)-2)
1981 + *character_length = 1;
1982 + *character_width = 1;
1986 + *character_length = (mblength < 1) ? 1 : mblength;
1987 + width = wcwidth (wc);
1988 + *character_width = (width < 0) ? 0 : width;
1991 + strncpy (character, arg, *character_length);
1992 + arg += *character_length;
1994 + else /* for single byte locale. */
1997 + *character = *arg++;
1998 + *character_length = 1;
1999 + *character_width = 1;
2006 @@ -1256,7 +1382,7 @@
2008 col_sep_string = column_separator;
2010 - col_sep_length = 1;
2011 + col_sep_length = col_sep_width = 1;
2012 use_col_separator = true;
2014 /* It's rather pointless to define a TAB separator with column
2015 @@ -1288,11 +1414,11 @@
2016 TAB_WIDTH (chars_per_input_tab, chars_per_number); */
2018 /* Estimate chars_per_text without any margin and keep it constant. */
2019 - if (number_separator == '\t')
2020 + if (number_separator[0] == '\t')
2021 number_width = chars_per_number +
2022 TAB_WIDTH (chars_per_default_tab, chars_per_number);
2024 - number_width = chars_per_number + 1;
2025 + number_width = chars_per_number + number_separator_width;
2027 /* The number is part of the column width unless we are
2028 printing files in parallel. */
2029 @@ -1307,7 +1433,7 @@
2032 chars_per_column = (chars_per_line - chars_used_by_number -
2033 - (columns - 1) * col_sep_length) / columns;
2034 + (columns - 1) * col_sep_width) / columns;
2036 if (chars_per_column < 1)
2037 error (EXIT_FAILURE, 0, _("page width too narrow"));
2038 @@ -1432,7 +1558,7 @@
2040 /* Enlarge p->start_position of first column to use the same form of
2041 padding_not_printed with all columns. */
2042 - h = h + col_sep_length;
2043 + h = h + col_sep_width;
2045 /* This loop takes care of all but the rightmost column. */
2047 @@ -1466,7 +1592,7 @@
2051 - h = h_next + col_sep_length;
2052 + h = h_next + col_sep_width;
2053 h_next = h + chars_per_column;
2056 @@ -1756,9 +1882,9 @@
2057 align_column (COLUMN *p)
2059 padding_not_printed = p->start_position;
2060 - if (padding_not_printed - col_sep_length > 0)
2061 + if (padding_not_printed - col_sep_width > 0)
2063 - pad_across_to (padding_not_printed - col_sep_length);
2064 + pad_across_to (padding_not_printed - col_sep_width);
2065 padding_not_printed = ANYWHERE;
2068 @@ -2029,13 +2155,13 @@
2069 /* May be too generous. */
2070 buff = X2REALLOC (buff, &buff_allocated);
2072 - buff[buff_current++] = c;
2073 + buff[buff_current++] = (unsigned char) c;
2077 add_line_number (COLUMN *p)
2084 @@ -2058,22 +2184,24 @@
2085 /* Tabification is assumed for multiple columns, also for n-separators,
2086 but `default n-separator = TAB' hasn't been given priority over
2087 equal column_width also specified by POSIX. */
2088 - if (number_separator == '\t')
2089 + if (number_separator[0] == '\t')
2091 i = number_width - chars_per_number;
2093 (p->char_func) (' ');
2096 - (p->char_func) (number_separator);
2097 + for (j = 0; j < number_separator_length; j++)
2098 + (p->char_func) (number_separator[j]);
2101 /* To comply with POSIX, we avoid any expansion of default TAB
2102 separator with a single column output. No column_width requirement
2103 has to be considered. */
2105 - (p->char_func) (number_separator);
2106 - if (number_separator == '\t')
2107 + for (j = 0; j < number_separator_length; j++)
2108 + (p->char_func) (number_separator[j]);
2109 + if (number_separator[0] == '\t')
2110 output_position = POS_AFTER_TAB (chars_per_output_tab,
2113 @@ -2234,7 +2362,7 @@
2114 while (goal - h_old > 1
2115 && (h_new = POS_AFTER_TAB (chars_per_output_tab, h_old)) <= goal)
2117 - putchar (output_tab_char);
2118 + fwrite (output_tab_char, sizeof(char), output_tab_char_length, stdout);
2121 while (++h_old <= goal)
2122 @@ -2254,6 +2382,7 @@
2125 int l = col_sep_length;
2126 + int not_space_flag;
2130 @@ -2267,6 +2396,7 @@
2132 for (; separators_not_printed > 0; --separators_not_printed)
2134 + not_space_flag = 0;
2137 /* 3 types of sep_strings: spaces only, spaces and chars,
2138 @@ -2280,12 +2410,15 @@
2142 + not_space_flag = 1;
2143 if (spaces_not_printed > 0)
2144 print_white_space ();
2146 - ++output_position;
2149 + if (not_space_flag)
2150 + output_position += col_sep_width;
2152 /* sep_string ends with some spaces */
2153 if (spaces_not_printed > 0)
2154 print_white_space ();
2155 @@ -2313,7 +2446,7 @@
2156 required number of tabs and spaces. */
2159 -print_char (char c)
2160 +print_char_single (char c)
2164 @@ -2337,6 +2470,74 @@
2168 +#ifdef HAVE_MBRTOWC
2170 +print_char_multi (char c)
2172 + static size_t mbc_pos = 0;
2173 + static unsigned char mbc[MB_LEN_MAX] = {'\0'};
2174 + static mbstate_t state = {'\0'};
2175 + mbstate_t state_bak;
2180 + if (tabify_output)
2182 + state_bak = state;
2183 + mbc[mbc_pos++] = (unsigned char)c;
2184 + mblength = mbrtowc (&wc, mbc, mbc_pos, &state);
2186 + while (mbc_pos > 0)
2191 + state = state_bak;
2195 + state = state_bak;
2196 + ++output_position;
2198 + memmove (mbc, mbc + 1, MB_CUR_MAX - 1);
2208 + memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength);
2210 + ++spaces_not_printed;
2213 + else if (spaces_not_printed > 0)
2214 + print_white_space ();
2216 + /* Nonprintables are assumed to have width 0, except L'\b'. */
2217 + if ((width = wcwidth (wc)) < 1)
2220 + --output_position;
2223 + output_position += width;
2225 + fwrite (mbc, sizeof(char), mblength, stdout);
2226 + memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength);
2227 + mbc_pos -= mblength;
2236 /* Skip to page PAGE before printing.
2237 PAGE may be larger than total number of pages. */
2239 @@ -2517,9 +2718,9 @@
2240 align_empty_cols = false;
2243 - if (padding_not_printed - col_sep_length > 0)
2244 + if (padding_not_printed - col_sep_width > 0)
2246 - pad_across_to (padding_not_printed - col_sep_length);
2247 + pad_across_to (padding_not_printed - col_sep_width);
2248 padding_not_printed = ANYWHERE;
2251 @@ -2620,9 +2821,9 @@
2255 - if (padding_not_printed - col_sep_length > 0)
2256 + if (padding_not_printed - col_sep_width > 0)
2258 - pad_across_to (padding_not_printed - col_sep_length);
2259 + pad_across_to (padding_not_printed - col_sep_width);
2260 padding_not_printed = ANYWHERE;
2263 @@ -2635,8 +2836,8 @@
2264 if (spaces_not_printed == 0)
2266 output_position = p->start_position + end_vector[line];
2267 - if (p->start_position - col_sep_length == chars_per_margin)
2268 - output_position -= col_sep_length;
2269 + if (p->start_position - col_sep_width == chars_per_margin)
2270 + output_position -= col_sep_width;
2274 @@ -2655,7 +2856,7 @@
2275 number of characters is 1.) */
2278 -char_to_clump (char c)
2279 +char_to_clump_single (char c)
2281 unsigned char uc = c;
2282 char *s = clump_buff;
2283 @@ -2665,10 +2866,10 @@
2285 int chars_per_c = 8;
2287 - if (c == input_tab_char)
2288 + if (c == input_tab_char[0])
2289 chars_per_c = chars_per_input_tab;
2291 - if (c == input_tab_char || c == '\t')
2292 + if (c == input_tab_char[0] || c == '\t')
2294 width = TAB_WIDTH (chars_per_c, input_position);
2296 @@ -2739,6 +2940,154 @@
2300 +#ifdef HAVE_MBRTOWC
2302 +char_to_clump_multi (char c)
2304 + static size_t mbc_pos = 0;
2305 + static char mbc[MB_LEN_MAX] = {'\0'};
2306 + static mbstate_t state = {'\0'};
2307 + mbstate_t state_bak;
2311 + register int *s = clump_buff;
2312 + register int i, j;
2316 + int chars_per_c = 8;
2318 + state_bak = state;
2319 + mbc[mbc_pos++] = c;
2320 + mblength = mbrtowc (&wc, mbc, mbc_pos, &state);
2324 + while (mbc_pos > 0)
2329 + state = state_bak;
2333 + state = state_bak;
2336 + if (use_esc_sequence || use_cntrl_prefix)
2341 + sprintf (esc_buff, "%03o", mbc[0]);
2342 + for (i = 0; i <= 2; ++i)
2343 + *s++ = (int) esc_buff[i];
2355 + /* Fall through */
2358 + if (memcmp (mbc, input_tab_char, mblength) == 0)
2359 + chars_per_c = chars_per_input_tab;
2361 + if (memcmp (mbc, input_tab_char, mblength) == 0 || c == '\t')
2365 + width_inc = TAB_WIDTH (chars_per_c, input_position);
2366 + width += width_inc;
2368 + if (untabify_input)
2370 + for (i = width_inc; i; --i)
2372 + chars += width_inc;
2376 + for (i = 0; i < mblength; i++)
2378 + chars += mblength;
2381 + else if ((wc_width = wcwidth (wc)) < 1)
2383 + if (use_esc_sequence)
2385 + for (i = 0; i < mblength; i++)
2390 + sprintf (esc_buff, "%03o", c);
2391 + for (j = 0; j <= 2; ++j)
2392 + *s++ = (int) esc_buff[j];
2395 + else if (use_cntrl_prefix)
2406 + for (i = 0; i < mblength; i++)
2411 + sprintf (esc_buff, "%03o", c);
2412 + for (j = 0; j <= 2; ++j)
2413 + *s++ = (int) esc_buff[j];
2417 + else if (wc == L'\b')
2426 + chars += mblength;
2427 + for (i = 0; i < mblength; i++)
2433 + width += wc_width;
2434 + chars += mblength;
2435 + for (i = 0; i < mblength; i++)
2439 + memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength);
2440 + mbc_pos -= mblength;
2443 + input_position += width;
2448 /* We've just printed some files and need to clean up things before
2449 looking for more options and printing the next batch of files.
2451 diff -Naur coreutils-6.1.orig/src/sort.c coreutils-6.1/src/sort.c
2452 --- coreutils-6.1.orig/src/sort.c 2006-08-09 07:42:34.000000000 +0000
2453 +++ coreutils-6.1/src/sort.c 2006-08-23 20:08:12.000000000 +0000
2458 +#include <assert.h>
2460 #include <sys/types.h>
2463 +# include <wchar.h>
2465 +/* Get isw* functions. */
2467 +# include <wctype.h>
2472 #include "hard-locale.h"
2473 @@ -98,14 +107,38 @@
2474 /* Thousands separator; if -1, then there isn't one. */
2475 static int thousands_sep;
2477 +static int force_general_numcompare = 0;
2479 /* Nonzero if the corresponding locales are hard. */
2480 static bool hard_LC_COLLATE;
2481 -#if HAVE_NL_LANGINFO
2482 +#if HAVE_LANGINFO_CODESET
2483 static bool hard_LC_TIME;
2486 #define NONZERO(x) ((x) != 0)
2488 +/* get a multibyte character's byte length. */
2489 +#define GET_BYTELEN_OF_CHAR(LIM, PTR, MBLENGTH, STATE) \
2493 + mbstate_t state_bak; \
2495 + state_bak = STATE; \
2496 + mblength = mbrtowc (&wc, PTR, LIM - PTR, &STATE); \
2498 + switch (MBLENGTH) \
2500 + case (size_t)-1: \
2501 + case (size_t)-2: \
2502 + STATE = state_bak; \
2503 + /* Fall through. */ \
2510 /* The kind of blanks for '-b' to skip in various options. */
2511 enum blanktype { bl_start, bl_end, bl_both };
2513 @@ -243,13 +276,11 @@
2514 they were read if all keys compare equal. */
2517 -/* If TAB has this value, blanks separate fields. */
2518 -enum { TAB_DEFAULT = CHAR_MAX + 1 };
2520 -/* Tab character separating fields. If TAB_DEFAULT, then fields are
2521 +/* Tab character separating fields. If tab_length is 0, then fields are
2522 separated by the empty string between a non-blank character and a blank
2524 -static int tab = TAB_DEFAULT;
2525 +static char tab[MB_LEN_MAX + 1];
2526 +static size_t tab_length = 0;
2528 /* Flag to remove consecutive duplicate lines from the output.
2529 Only the last of a sequence of equal lines will be output. */
2530 @@ -408,6 +439,44 @@
2531 static struct tempnode *volatile temphead;
2532 static struct tempnode *volatile *temptail = &temphead;
2534 +/* Function pointers. */
2536 +(*inittables) (void);
2538 +(*begfield) (const struct line*, const struct keyfield *);
2540 +(*limfield) (const struct line*, const struct keyfield *);
2542 +(*getmonth) (char const *, size_t);
2544 +(*keycompare) (const struct line *, const struct line *);
2546 +(*numcompare) (const char *, const char *);
2548 +/* Test for white space multibyte character.
2549 + Set LENGTH the byte length of investigated multibyte character. */
2552 +ismbblank (const char *str, size_t len, size_t *length)
2558 + memset (&state, '\0', sizeof(mbstate_t));
2559 + mblength = mbrtowc (&wc, str, len, &state);
2561 + if (mblength == (size_t)-1 || mblength == (size_t)-2)
2567 + *length = (mblength < 1) ? 1 : mblength;
2568 + return iswblank (wc);
2572 /* Clean up any remaining temporary files. */
2579 -#if HAVE_NL_LANGINFO
2580 +#if HAVE_LANGINFO_CODESET
2583 struct_month_cmp (const void *m1, const void *m2)
2585 /* Initialize the character class tables. */
2589 +inittables_uni (void)
2594 fold_toupper[i] = toupper (i);
2597 -#if HAVE_NL_LANGINFO
2598 +#if HAVE_LANGINFO_CODESET
2599 /* If we're not in the "C" locale, read different names for months. */
2602 @@ -614,6 +683,64 @@
2608 +inittables_mb (void)
2612 + size_t s_len, mblength;
2613 + char mbc[MB_LEN_MAX];
2615 + mbstate_t state_mb, state_wc;
2617 + for (i = 0; i < MONTHS_PER_YEAR; i++)
2619 + s = (char *) nl_langinfo (ABMON_1 + i);
2620 + s_len = strlen (s);
2621 + monthtab[i].name = name = (char *) xmalloc (s_len + 1);
2622 + monthtab[i].val = i + 1;
2624 + memset (&state_mb, '\0', sizeof (mbstate_t));
2625 + memset (&state_wc, '\0', sizeof (mbstate_t));
2627 + for (j = 0; j < s_len;)
2629 + if (!ismbblank (s + j, s_len - j, &mblength))
2634 + for (k = 0; j < s_len;)
2636 + mblength = mbrtowc (&wc, (s + j), (s_len - j), &state_mb);
2637 + assert (mblength != (size_t)-1 && mblength != (size_t)-2);
2638 + if (mblength == 0)
2641 + pwc = towupper (wc);
2644 + memcpy (mbc, s + j, mblength);
2650 + mblength = wcrtomb (mbc, pwc, &state_wc);
2651 + assert (mblength != (size_t)0 && mblength != (size_t)-1);
2654 + for (l = 0; l < mblength; l++)
2655 + name[k++] = mbc[l];
2659 + qsort ((void *) monthtab, MONTHS_PER_YEAR,
2660 + sizeof (struct month), struct_month_cmp);
2664 /* Specify the amount of main memory to use when sorting. */
2666 specify_sort_size (char const *s)
2671 -begfield (const struct line *line, const struct keyfield *key)
2672 +begfield_uni (const struct line *line, const struct keyfield *key)
2674 char *ptr = line->text, *lim = ptr + line->length - 1;
2675 size_t sword = key->sword;
2676 @@ -834,10 +961,10 @@
2677 /* The leading field separator itself is included in a field when -t
2680 - if (tab != TAB_DEFAULT)
2682 while (ptr < lim && sword--)
2684 - while (ptr < lim && *ptr != tab)
2685 + while (ptr < lim && *ptr != tab[0])
2689 @@ -865,11 +992,70 @@
2695 +begfield_mb (const struct line *line, const struct keyfield *key)
2698 + char *ptr = line->text, *lim = ptr + line->length - 1;
2699 + size_t sword = key->sword;
2700 + size_t schar = key->schar;
2704 + memset (&state, '\0', sizeof(mbstate_t));
2707 + while (ptr < lim && sword--)
2709 + while (ptr < lim && memcmp (ptr, tab, tab_length) != 0)
2711 + GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
2716 + GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
2721 + while (ptr < lim && sword--)
2723 + while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength))
2727 + GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
2730 + while (ptr < lim && !ismbblank (ptr, lim - ptr, &mblength))
2734 + if (key->skipsblanks)
2735 + while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength))
2738 + for (i = 0; i < schar; i++)
2740 + GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
2742 + if (ptr + mblength > lim)
2752 /* Return the limit of (a pointer to the first character after) the field
2753 in LINE specified by KEY. */
2756 -limfield (const struct line *line, const struct keyfield *key)
2757 +limfield_uni (const struct line *line, const struct keyfield *key)
2759 char *ptr = line->text, *lim = ptr + line->length - 1;
2760 size_t eword = key->eword, echar = key->echar;
2761 @@ -882,10 +1068,10 @@
2762 `beginning' is the first character following the delimiting TAB.
2763 Otherwise, leave PTR pointing at the first `blank' character after
2764 the preceding field. */
2765 - if (tab != TAB_DEFAULT)
2767 while (ptr < lim && eword--)
2769 - while (ptr < lim && *ptr != tab)
2770 + while (ptr < lim && *ptr != tab[0])
2772 if (ptr < lim && (eword | echar))
2774 @@ -931,10 +1117,10 @@
2777 /* Make LIM point to the end of (one byte past) the current field. */
2778 - if (tab != TAB_DEFAULT)
2782 - newlim = memchr (ptr, tab, lim - ptr);
2783 + newlim = memchr (ptr, tab[0], lim - ptr);
2787 @@ -967,6 +1153,107 @@
2793 +limfield_mb (const struct line *line, const struct keyfield *key)
2795 + char *ptr = line->text, *lim = ptr + line->length - 1;
2796 + size_t eword = key->eword, echar = key->echar;
2801 + memset (&state, '\0', sizeof(mbstate_t));
2804 + while (ptr < lim && eword--)
2806 + while (ptr < lim && memcmp (ptr, tab, tab_length) != 0)
2808 + GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
2811 + if (ptr < lim && (eword | echar))
2813 + GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
2818 + while (ptr < lim && eword--)
2820 + while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength))
2824 + GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
2827 + while (ptr < lim && !ismbblank (ptr, lim - ptr, &mblength))
2832 +# ifdef POSIX_UNSPECIFIED
2833 + /* Make LIM point to the end of (one byte past) the current field. */
2839 + for (p = ptr; p < lim;)
2841 + if (memcmp (p, tab, tab_length) == 0)
2847 + GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
2856 + while (newlim < lim && ismbblank (newlim, lim - newlim, &mblength))
2857 + newlim += mblength;
2860 + GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
2863 + while (newlim < lim && !ismbblank (newlim, lim - newlim, &mblength))
2864 + newlim += mblength;
2869 + /* If we're skipping leading blanks, don't start counting characters
2870 + * until after skipping past any leading blanks. */
2871 + if (key->skipsblanks)
2872 + while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength))
2875 + memset (&state, '\0', sizeof(mbstate_t));
2877 + /* Advance PTR by ECHAR (if possible), but no further than LIM. */
2878 + for (i = 0; i < echar; i++)
2880 + GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
2882 + if (ptr + mblength > lim)
2892 /* Fill BUF reading from FP, moving buf->left bytes from the end
2893 of buf->buf to the beginning first. If EOF is reached and the
2894 file wasn't terminated by a newline, supply one. Set up BUF's line
2895 @@ -1083,7 +1370,7 @@
2899 -numcompare (const char *a, const char *b)
2900 +numcompare_uni (const char *a, const char *b)
2902 while (blanks[to_uchar (*a)])
2904 @@ -1093,6 +1380,25 @@
2905 return strnumcmp (a, b, decimal_point, thousands_sep);
2910 +numcompare_mb (const char *a, const char *b)
2912 + size_t mblength, len;
2913 + len = strlen (a); /* okay for UTF-8 */
2914 + while (*a && ismbblank (a, len > MB_CUR_MAX ? MB_CUR_MAX : len, &mblength))
2919 + len = strlen (b); /* okay for UTF-8 */
2920 + while (*b && ismbblank (b, len > MB_CUR_MAX ? MB_CUR_MAX : len, &mblength))
2923 + return strnumcmp (a, b, decimal_point, thousands_sep);
2925 +#endif /* HAV_EMBRTOWC */
2928 general_numcompare (const char *sa, const char *sb)
2930 @@ -1126,7 +1432,7 @@
2931 Return 0 if the name in S is not recognized. */
2934 -getmonth (char const *month, size_t len)
2935 +getmonth_uni (char const *month, size_t len)
2938 size_t hi = MONTHS_PER_YEAR;
2939 @@ -1281,11 +1587,79 @@
2945 +getmonth_mb (const char *s, size_t len)
2948 + register size_t i;
2949 + register int lo = 0, hi = MONTHS_PER_YEAR, result;
2951 + size_t wclength, mblength;
2953 + const wchar_t **wpp;
2954 + wchar_t *month_wcs;
2957 + while (len > 0 && ismbblank (s, len, &mblength))
2966 + month = (char *) alloca (len + 1);
2968 + tmp = (char *) alloca (len + 1);
2969 + memcpy (tmp, s, len);
2971 + pp = (const char **)&tmp;
2972 + month_wcs = (wchar_t *) alloca ((len + 1) * sizeof (wchar_t));
2973 + memset (&state, '\0', sizeof(mbstate_t));
2975 + wclength = mbsrtowcs (month_wcs, pp, len + 1, &state);
2976 + assert (wclength != (size_t)-1 && *pp == NULL);
2978 + for (i = 0; i < wclength; i++)
2980 + month_wcs[i] = towupper(month_wcs[i]);
2981 + if (iswblank (month_wcs[i]))
2983 + month_wcs[i] = L'\0';
2988 + wpp = (const wchar_t **)&month_wcs;
2990 + mblength = wcsrtombs (month, wpp, len + 1, &state);
2991 + assert (mblength != (-1) && *wpp == NULL);
2995 + int ix = (lo + hi) / 2;
2997 + if (strncmp (month, monthtab[ix].name, strlen (monthtab[ix].name)) < 0)
3002 + while (hi - lo > 1);
3004 + result = (!strncmp (month, monthtab[lo].name, strlen (monthtab[lo].name))
3005 + ? monthtab[lo].val : 0);
3011 /* Compare two lines A and B trying every key in sequence until there
3012 are no more keys or a difference is found. */
3015 -keycompare (const struct line *a, const struct line *b)
3016 +keycompare_uni (const struct line *a, const struct line *b)
3018 struct keyfield const *key = keylist;
3020 @@ -1458,6 +1832,177 @@
3021 return key->reverse ? -diff : diff;
3026 +keycompare_mb (const struct line *a, const struct line *b)
3028 + struct keyfield *key = keylist;
3030 + /* For the first iteration only, the key positions have been
3031 + precomputed for us. */
3032 + char *texta = a->keybeg;
3033 + char *textb = b->keybeg;
3034 + char *lima = a->keylim;
3035 + char *limb = b->keylim;
3037 + size_t mblength_a, mblength_b;
3038 + wchar_t wc_a, wc_b;
3039 + mbstate_t state_a, state_b;
3043 + memset (&state_a, '\0', sizeof(mbstate_t));
3044 + memset (&state_b, '\0', sizeof(mbstate_t));
3048 + unsigned char *translate = (unsigned char *) key->translate;
3049 + bool const *ignore = key->ignore;
3051 + /* Find the lengths. */
3052 + size_t lena = lima <= texta ? 0 : lima - texta;
3053 + size_t lenb = limb <= textb ? 0 : limb - textb;
3055 + /* Actually compare the fields. */
3056 + if (key->numeric | key->general_numeric)
3058 + char savea = *lima, saveb = *limb;
3060 + *lima = *limb = '\0';
3061 + if (force_general_numcompare)
3062 + diff = general_numcompare (texta, textb);
3064 + diff = ((key->numeric ? numcompare : general_numcompare)
3066 + *lima = savea, *limb = saveb;
3068 + else if (key->month)
3069 + diff = getmonth (texta, lena) - getmonth (textb, lenb);
3072 + if (ignore || translate)
3074 + char *copy_a = (char *) alloca (lena + 1 + lenb + 1);
3075 + char *copy_b = copy_a + lena + 1;
3076 + size_t new_len_a, new_len_b;
3079 + /* Ignore and/or translate chars before comparing. */
3080 +# define IGNORE_CHARS(NEW_LEN, LEN, TEXT, COPY, WC, MBLENGTH, STATE) \
3084 + char mbc[MB_LEN_MAX]; \
3085 + mbstate_t state_wc; \
3087 + for (NEW_LEN = i = 0; i < LEN;) \
3089 + mbstate_t state_bak; \
3091 + state_bak = STATE; \
3092 + MBLENGTH = mbrtowc (&WC, TEXT + i, LEN - i, &STATE); \
3094 + if (MBLENGTH == (size_t)-2 || MBLENGTH == (size_t)-1 \
3095 + || MBLENGTH == 0) \
3097 + if (MBLENGTH == (size_t)-2 || MBLENGTH == (size_t)-1) \
3098 + STATE = state_bak; \
3100 + COPY[NEW_LEN++] = TEXT[i++]; \
3106 + if ((ignore == nonprinting && !iswprint (WC)) \
3107 + || (ignore == nondictionary \
3108 + && !iswalnum (WC) && !iswblank (WC))) \
3118 + uwc = towupper(WC); \
3121 + memcpy (mbc, TEXT + i, MBLENGTH); \
3128 + memset (&state_wc, '\0', sizeof (mbstate_t)); \
3130 + MBLENGTH = wcrtomb (mbc, WC, &state_wc); \
3131 + assert (MBLENGTH != (size_t)-1 && MBLENGTH != 0); \
3134 + for (j = 0; j < MBLENGTH; j++) \
3135 + COPY[NEW_LEN++] = mbc[j]; \
3138 + for (j = 0; j < MBLENGTH; j++) \
3139 + COPY[NEW_LEN++] = TEXT[i++]; \
3141 + COPY[NEW_LEN] = '\0'; \
3144 + IGNORE_CHARS (new_len_a, lena, texta, copy_a,
3145 + wc_a, mblength_a, state_a);
3146 + IGNORE_CHARS (new_len_b, lenb, textb, copy_b,
3147 + wc_b, mblength_b, state_b);
3148 + diff = xmemcoll (copy_a, new_len_a, copy_b, new_len_b);
3150 + else if (lena == 0)
3151 + diff = - NONZERO (lenb);
3152 + else if (lenb == 0)
3155 + diff = xmemcoll (texta, lena, textb, lenb);
3165 + /* Find the beginning and limit of the next field. */
3166 + if (key->eword != -1)
3167 + lima = limfield (a, key), limb = limfield (b, key);
3169 + lima = a->text + a->length - 1, limb = b->text + b->length - 1;
3171 + if (key->sword != -1)
3172 + texta = begfield (a, key), textb = begfield (b, key);
3175 + texta = a->text, textb = b->text;
3176 + if (key->skipsblanks)
3178 + while (texta < lima && ismbblank (texta, lima - texta, &mblength_a))
3179 + texta += mblength_a;
3180 + while (textb < limb && ismbblank (textb, limb - textb, &mblength_b))
3181 + textb += mblength_b;
3191 + return key->reverse ? -diff : diff;
3195 /* Compare two lines A and B, returning negative, zero, or positive
3196 depending on whether A compares less than, equal to, or greater than B. */
3198 @@ -2307,7 +2852,7 @@
3199 atexit (close_stdout);
3201 hard_LC_COLLATE = hard_locale (LC_COLLATE);
3202 -#if HAVE_NL_LANGINFO
3203 +#if HAVE_LANGINFO_CODESET
3204 hard_LC_TIME = hard_locale (LC_TIME);
3207 @@ -2328,6 +2873,27 @@
3212 + if (MB_CUR_MAX > 1)
3214 + inittables = inittables_mb;
3215 + begfield = begfield_mb;
3216 + limfield = limfield_mb;
3217 + getmonth = getmonth_mb;
3218 + keycompare = keycompare_mb;
3219 + numcompare = numcompare_mb;
3224 + inittables = inittables_uni;
3225 + begfield = begfield_uni;
3226 + limfield = limfield_uni;
3227 + getmonth = getmonth_uni;
3228 + keycompare = keycompare_uni;
3229 + numcompare = numcompare_uni;
3232 have_read_stdin = false;
3235 @@ -2542,13 +3108,35 @@
3239 - char newtab = optarg[0];
3241 + char newtab[MB_LEN_MAX + 1];
3242 + size_t newtab_length = 1;
3243 + strncpy (newtab, optarg, MB_LEN_MAX);
3245 error (SORT_FAILURE, 0, _("empty tab"));
3248 + if (MB_CUR_MAX > 1)
3254 + memset (&state, '\0', sizeof (mbstate_t));
3255 + newtab_length = mbrtowc (&wc, newtab, strnlen (newtab,
3258 + switch (newtab_length)
3263 + newtab_length = 1;
3267 + if (newtab_length == 1 && optarg[1])
3269 if (STREQ (optarg, "\\0"))
3274 /* Provoke with `sort -txx'. Complain about
3275 @@ -2559,9 +3147,12 @@
3279 - if (tab != TAB_DEFAULT && tab != newtab)
3281 + && (tab_length != newtab_length
3282 + || memcmp (tab, newtab, tab_length) != 0))
3283 error (SORT_FAILURE, 0, _("incompatible tabs"));
3285 + memcpy (tab, newtab, newtab_length);
3286 + tab_length = newtab_length;
3290 diff -Naur coreutils-6.1.orig/src/unexpand.c coreutils-6.1/src/unexpand.c
3291 --- coreutils-6.1.orig/src/unexpand.c 2006-07-09 17:06:58.000000000 +0000
3292 +++ coreutils-6.1/src/unexpand.c 2006-08-23 20:08:12.000000000 +0000
3296 #include <sys/types.h>
3298 +/* Get mbstate_t, mbrtowc(), wcwidth(). */
3300 +# include <wchar.h>
3306 #include "xstrndup.h"
3308 +/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC
3309 + installation; work around this configuration error. */
3310 +#if !defined MB_LEN_MAX || MB_LEN_MAX < 2
3311 +# define MB_LEN_MAX 16
3314 +/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */
3315 +#if HAVE_MBRTOWC && defined mbstate_t
3316 +# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
3319 /* The official name of this program (e.g., no `g' prefix). */
3320 #define PROGRAM_NAME "unexpand"
3322 @@ -110,6 +127,208 @@
3326 +static FILE *next_file (FILE *fp);
3330 +unexpand_multibyte (void)
3332 + FILE *fp; /* Input stream. */
3333 + mbstate_t i_state; /* Current shift state of the input stream. */
3334 + mbstate_t i_state_bak; /* Back up the I_STATE. */
3335 + mbstate_t o_state; /* Current shift state of the output stream. */
3336 + char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */
3337 + char *bufpos; /* Next read position of BUF. */
3338 + size_t buflen = 0; /* The length of the byte sequence in buf. */
3339 + wint_t wc; /* A gotten wide character. */
3340 + size_t mblength; /* The byte size of a multibyte character
3341 + which shows as same character as WC. */
3343 + /* Index in `tab_list' of next tabstop: */
3344 + int tab_index = 0; /* For calculating width of pending tabs. */
3345 + int print_tab_index = 0; /* For printing as many tabs as possible. */
3346 + unsigned int column = 0; /* Column on screen of next char. */
3347 + int next_tab_column; /* Column the next tab stop is on. */
3348 + int convert = 1; /* If nonzero, perform translations. */
3349 + unsigned int pending = 0; /* Pending columns of blanks. */
3351 + fp = next_file ((FILE *) NULL);
3355 + memset (&o_state, '\0', sizeof(mbstate_t));
3356 + memset (&i_state, '\0', sizeof(mbstate_t));
3360 + if (buflen < MB_LEN_MAX && !feof(fp) && !ferror(fp))
3362 + memmove (buf, bufpos, buflen);
3363 + buflen += fread (buf + buflen, sizeof(char), BUFSIZ, fp);
3367 + /* Get a wide character. */
3375 + i_state_bak = i_state;
3376 + mblength = mbrtowc ((wchar_t *)&wc, bufpos, buflen, &i_state);
3379 + if (mblength == (size_t)-1 || mblength == (size_t)-2)
3381 + i_state = i_state_bak;
3385 + if (wc == L' ' && convert && column < INT_MAX)
3390 + else if (wc == L'\t' && convert)
3392 + if (tab_size == 0)
3394 + /* Do not let tab_index == first_free_tab;
3395 + stop when it is 1 less. */
3396 + while (tab_index < first_free_tab - 1
3397 + && column >= tab_list[tab_index])
3399 + next_tab_column = tab_list[tab_index];
3400 + if (tab_index < first_free_tab - 1)
3402 + if (column >= next_tab_column)
3404 + convert = 0; /* Ran out of tab stops. */
3405 + goto flush_pend_mb;
3410 + next_tab_column = column + tab_size - column % tab_size;
3412 + pending += next_tab_column - column;
3413 + column = next_tab_column;
3418 + /* Flush pending spaces. Print as many tabs as possible,
3419 + then print the rest as spaces. */
3425 + column -= pending;
3426 + while (pending > 0)
3428 + if (tab_size == 0)
3430 + /* Do not let print_tab_index == first_free_tab;
3431 + stop when it is 1 less. */
3432 + while (print_tab_index < first_free_tab - 1
3433 + && column >= tab_list[print_tab_index])
3434 + print_tab_index++;
3435 + next_tab_column = tab_list[print_tab_index];
3436 + if (print_tab_index < first_free_tab - 1)
3437 + print_tab_index++;
3442 + column + tab_size - column % tab_size;
3444 + if (next_tab_column - column <= pending)
3447 + pending -= next_tab_column - column;
3448 + column = next_tab_column;
3452 + --print_tab_index;
3453 + column += pending;
3454 + while (pending != 0)
3464 + fp = next_file (fp);
3466 + break; /* No more files. */
3469 + memset (&i_state, '\0', sizeof(mbstate_t));
3474 + if (mblength == (size_t)-1 || mblength == (size_t)-2)
3479 + if (convert_entire_line == 0)
3485 + else if (mblength == 0)
3487 + if (convert && convert_entire_line == 0)
3503 + int width; /* The width of WC. */
3505 + width = wcwidth (wc);
3506 + column += (width > 0) ? width : 0;
3507 + if (convert_entire_line == 0)
3514 + tab_index = print_tab_index = 0;
3515 + column = pending = 0;
3518 + fwrite (bufpos, sizeof(char), mblength, stdout);
3521 + buflen -= mblength;
3522 + bufpos += mblength;
3531 @@ -531,7 +750,12 @@
3533 file_list = (optind < argc ? &argv[optind] : stdin_argv);
3537 + if (MB_CUR_MAX > 1)
3538 + unexpand_multibyte ();
3543 if (have_read_stdin && fclose (stdin) != 0)
3544 error (EXIT_FAILURE, errno, "-");
3545 diff -Naur coreutils-6.1.orig/src/uniq.c coreutils-6.1/src/uniq.c
3546 --- coreutils-6.1.orig/src/uniq.c 2006-07-09 17:20:43.000000000 +0000
3547 +++ coreutils-6.1/src/uniq.c 2006-08-23 20:08:12.000000000 +0000
3550 #include <sys/types.h>
3552 +/* Get mbstate_t, mbrtowc(). */
3554 +# include <wchar.h>
3557 +/* Get isw* functions. */
3559 +# include <wctype.h>
3563 #include "argmatch.h"
3564 #include "linebuffer.h"
3567 #include "xmemcoll.h"
3568 #include "xstrtol.h"
3569 -#include "memcasecmp.h"
3570 +#include "xmemcoll.h"
3572 +/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC
3573 + installation; work around this configuration error. */
3574 +#if !defined MB_LEN_MAX || MB_LEN_MAX < 2
3575 +# define MB_LEN_MAX 16
3578 +/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */
3579 +#if HAVE_MBRTOWC && defined mbstate_t
3580 +# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
3584 /* The official name of this program (e.g., no `g' prefix). */
3585 #define PROGRAM_NAME "uniq"
3586 @@ -109,6 +131,10 @@
3587 /* Select whether/how to delimit groups of duplicate lines. */
3588 static enum delimit_method delimit_groups;
3590 +/* Function pointers. */
3592 +(*find_field) (struct linebuffer *line);
3594 static struct option const longopts[] =
3596 {"count", no_argument, NULL, 'c'},
3598 return a pointer to the beginning of the line's field to be compared. */
3601 -find_field (const struct linebuffer *line)
3602 +find_field_uni (struct linebuffer *line)
3605 char *lp = line->buffer;
3606 @@ -210,6 +236,83 @@
3612 +# define MBCHAR_TO_WCHAR(WC, MBLENGTH, LP, POS, SIZE, STATEP, CONVFAIL) \
3615 + mbstate_t state_bak; \
3618 + state_bak = *STATEP; \
3620 + MBLENGTH = mbrtowc (&WC, LP + POS, SIZE - POS, STATEP); \
3622 + switch (MBLENGTH) \
3624 + case (size_t)-2: \
3625 + case (size_t)-1: \
3626 + *STATEP = state_bak; \
3628 + /* Fall through */ \
3636 +find_field_multi (struct linebuffer *line)
3639 + char *lp = line->buffer;
3640 + size_t size = line->length - 1;
3644 + mbstate_t *statep;
3648 + statep = &(line->state);
3650 + /* skip fields. */
3651 + for (count = 0; count < skip_fields && pos < size; count++)
3653 + while (pos < size)
3655 + MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail);
3657 + if (convfail || !iswblank (wc))
3665 + while (pos < size)
3667 + MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail);
3669 + if (!convfail && iswblank (wc))
3676 + /* skip fields. */
3677 + for (count = 0; count < skip_chars && pos < size; count++)
3679 + MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail);
3687 /* Return false if two strings OLD and NEW match, true if not.
3688 OLD and NEW point not to the beginnings of the lines
3689 but rather to the beginnings of the fields to compare.
3692 different (char *old, char *new, size_t oldlen, size_t newlen)
3694 + char *copy_old, *copy_new;
3696 if (check_chars < oldlen)
3697 oldlen = check_chars;
3698 if (check_chars < newlen)
3699 @@ -225,14 +330,92 @@
3703 - /* FIXME: This should invoke strcoll somehow. */
3704 - return oldlen != newlen || memcasecmp (old, new, oldlen);
3707 + copy_old = alloca (oldlen + 1);
3708 + copy_new = alloca (oldlen + 1);
3710 + for (i = 0; i < oldlen; i++)
3712 + copy_old[i] = toupper (old[i]);
3713 + copy_new[i] = toupper (new[i]);
3716 - else if (hard_LC_COLLATE)
3717 - return xmemcoll (old, oldlen, new, newlen) != 0;
3719 - return oldlen != newlen || memcmp (old, new, oldlen);
3721 + copy_old = (char *)old;
3722 + copy_new = (char *)new;
3725 + return xmemcoll (copy_old, oldlen, copy_new, newlen);
3730 +different_multi (const char *old, const char *new, size_t oldlen, size_t newlen, mbstate_t oldstate, mbstate_t newstate)
3732 + size_t i, j, chars;
3733 + const char *str[2];
3736 + mbstate_t state[2];
3739 + mbstate_t state_bak;
3745 + state[0] = oldstate;
3746 + state[1] = newstate;
3748 + for (i = 0; i < 2; i++)
3750 + copy[i] = alloca (len[i] + 1);
3752 + for (j = 0, chars = 0; j < len[i] && chars < check_chars; chars++)
3754 + state_bak = state[i];
3755 + mblength = mbrtowc (&wc, str[i] + j, len[i] - j, &(state[i]));
3761 + state[i] = state_bak;
3762 + /* Fall through */
3770 + uwc = towupper (wc);
3774 + mbstate_t state_wc;
3776 + memset (&state_wc, '\0', sizeof(mbstate_t));
3777 + wcrtomb (copy[i] + j, uwc, &state_wc);
3780 + memcpy (copy[i] + j, str[i] + j, mblength);
3783 + memcpy (copy[i] + j, str[i] + j, mblength);
3787 + copy[i][j] = '\0';
3791 + return xmemcoll (copy[0], len[0], copy[1], len[1]);
3795 /* Output the line in linebuffer LINE to standard output
3796 provided that the switches say it should be output.
3797 @@ -286,15 +469,43 @@
3799 char *prevfield IF_LINT (= NULL);
3800 size_t prevlen IF_LINT (= 0);
3802 + mbstate_t prevstate;
3804 + memset (&prevstate, '\0', sizeof (mbstate_t));
3807 while (!feof (stdin))
3812 + mbstate_t thisstate;
3815 if (readlinebuffer (thisline, stdin) == 0)
3817 thisfield = find_field (thisline);
3818 thislen = thisline->length - 1 - (thisfield - thisline->buffer);
3820 + if (MB_CUR_MAX > 1)
3822 + thisstate = thisline->state;
3824 + if (prevline->length == 0 || different_multi
3825 + (thisfield, prevfield, thislen, prevlen, thisstate, prevstate))
3827 + fwrite (thisline->buffer, sizeof (char),
3828 + thisline->length, stdout);
3830 + SWAP_LINES (prevline, thisline);
3831 + prevfield = thisfield;
3832 + prevlen = thislen;
3833 + prevstate = thisstate;
3838 if (prevline->length == 0
3839 || different (thisfield, prevfield, thislen, prevlen))
3841 @@ -313,17 +524,26 @@
3843 uintmax_t match_count = 0;
3844 bool first_delimiter = true;
3846 + mbstate_t prevstate;
3849 if (readlinebuffer (prevline, stdin) == 0)
3851 prevfield = find_field (prevline);
3852 prevlen = prevline->length - 1 - (prevfield - prevline->buffer);
3854 + prevstate = prevline->state;
3857 while (!feof (stdin))
3863 + mbstate_t thisstate;
3865 if (readlinebuffer (thisline, stdin) == 0)
3868 @@ -332,6 +552,15 @@
3870 thisfield = find_field (thisline);
3871 thislen = thisline->length - 1 - (thisfield - thisline->buffer);
3873 + if (MB_CUR_MAX > 1)
3875 + thisstate = thisline->state;
3876 + match = !different_multi (thisfield, prevfield,
3877 + thislen, prevlen, thisstate, prevstate);
3881 match = !different (thisfield, prevfield, thislen, prevlen);
3882 match_count += match;
3885 SWAP_LINES (prevline, thisline);
3886 prevfield = thisfield;
3889 + prevstate = thisstate;
3894 @@ -408,6 +640,19 @@
3896 atexit (close_stdout);
3899 + if (MB_CUR_MAX > 1)
3901 + find_field = find_field_multi;
3906 + find_field = find_field_uni;
3913 check_chars = SIZE_MAX;
3914 diff -Naur coreutils-6.1.orig/tests/sort/Makefile.am coreutils-6.1/tests/sort/Makefile.am
3915 --- coreutils-6.1.orig/tests/sort/Makefile.am 2006-08-19 15:33:34.000000000 +0000
3916 +++ coreutils-6.1/tests/sort/Makefile.am 2006-08-23 20:11:34.000000000 +0000
3921 -EXTRA_DIST = Test.pm $x-tests $(explicit) $(maint_gen)
3922 -noinst_SCRIPTS = $x-tests
3923 +run_gen += mb1.O mb2.O
3925 +EXTRA_DIST = Test.pm $x-tests $(explicit) $(maint_gen) mb1.I mb1.X mb2.I mb2.X
3926 +noinst_SCRIPTS = $x-tests # $x-mb-tests
3927 TESTS_ENVIRONMENT = \
3928 PATH="$(VG_PATH_PREFIX)`pwd`/../../src$(PATH_SEPARATOR)$$PATH"
3930 editpl = sed -e 's,@''PERL''@,$(PERL),g' -e 's,@''srcdir''@,$(srcdir),g'
3933 +TESTS = $x-tests $x-mb-tests
3935 mk_script = $(srcdir)/../mk-script
3936 $(srcdir)/$x-tests: $(mk_script) Test.pm Makefile.am
3937 diff -Naur coreutils-6.1.orig/tests/sort/Makefile.in coreutils-6.1/tests/sort/Makefile.in
3938 --- coreutils-6.1.orig/tests/sort/Makefile.in 2006-08-19 17:42:34.000000000 +0000
3939 +++ coreutils-6.1/tests/sort/Makefile.in 2006-08-23 20:13:13.000000000 +0000
3940 @@ -402,13 +402,15 @@
3941 incompat2.E incompat3.O incompat3.E incompat4.O incompat4.E nul-tab.O \
3944 -EXTRA_DIST = Test.pm $x-tests $(explicit) $(maint_gen)
3945 -noinst_SCRIPTS = $x-tests
3946 +run_gen += mb1.O mb2.O
3948 +EXTRA_DIST = Test.pm $x-tests $(explicit) $(maint_gen) mb1.I mb1.X mb2.I mb2.X
3949 +noinst_SCRIPTS = $x-tests # $x-mb-tests
3950 TESTS_ENVIRONMENT = \
3951 PATH="$(VG_PATH_PREFIX)`pwd`/../../src$(PATH_SEPARATOR)$$PATH"
3953 editpl = sed -e 's,@''PERL''@,$(PERL),g' -e 's,@''srcdir''@,$(srcdir),g'
3955 +TESTS = $x-tests $x-mb-tests
3956 mk_script = $(srcdir)/../mk-script
3957 MAINTAINERCLEANFILES = $x-tests $(maint_gen)
3958 CLEANFILES = $(run_gen)
3959 diff -Naur coreutils-6.1.orig/tests/sort/mb1.I coreutils-6.1/tests/sort/mb1.I
3960 --- coreutils-6.1.orig/tests/sort/mb1.I 1970-01-01 00:00:00.000000000 +0000
3961 +++ coreutils-6.1/tests/sort/mb1.I 2006-08-23 20:08:12.000000000 +0000
3967 diff -Naur coreutils-6.1.orig/tests/sort/mb1.X coreutils-6.1/tests/sort/mb1.X
3968 --- coreutils-6.1.orig/tests/sort/mb1.X 1970-01-01 00:00:00.000000000 +0000
3969 +++ coreutils-6.1/tests/sort/mb1.X 2006-08-23 20:08:12.000000000 +0000
3975 diff -Naur coreutils-6.1.orig/tests/sort/mb2.I coreutils-6.1/tests/sort/mb2.I
3976 --- coreutils-6.1.orig/tests/sort/mb2.I 1970-01-01 00:00:00.000000000 +0000
3977 +++ coreutils-6.1/tests/sort/mb2.I 2006-08-23 20:08:12.000000000 +0000
3983 diff -Naur coreutils-6.1.orig/tests/sort/mb2.X coreutils-6.1/tests/sort/mb2.X
3984 --- coreutils-6.1.orig/tests/sort/mb2.X 1970-01-01 00:00:00.000000000 +0000
3985 +++ coreutils-6.1/tests/sort/mb2.X 2006-08-23 20:08:12.000000000 +0000
3991 diff -Naur coreutils-6.1.orig/tests/sort/sort-mb-tests coreutils-6.1/tests/sort/sort-mb-tests
3992 --- coreutils-6.1.orig/tests/sort/sort-mb-tests 1970-01-01 00:00:00.000000000 +0000
3993 +++ coreutils-6.1/tests/sort/sort-mb-tests 2006-08-23 20:08:12.000000000 +0000
3997 + 0) xx='../../src/sort';;
4000 +test "$VERBOSE" && echo=echo || echo=:
4001 +$echo testing program: $xx
4003 +test "$srcdir" || srcdir=.
4004 +test "$VERBOSE" && $xx --version 2> /dev/null
4006 +export LC_ALL=en_US.UTF-8
4007 +locale -k LC_CTYPE 2>&1 | grep -q charmap.*UTF-8 || exit 77
4010 +$xx -t @ -k2 -n mb1.I > mb1.O
4012 +if test $code != 0; then
4013 + $echo "Test mb1 failed: $xx return code $code differs from expected value 0" 1>&2
4014 + errors=`expr $errors + 1`
4016 + cmp mb1.O $srcdir/mb1.X > /dev/null 2>&1
4018 + 0) if test "$VERBOSE"; then $echo "passed mb1"; fi;;
4019 + 1) $echo "Test mb1 failed: files mb1.O and $srcdir/mb1.X differ" 1>&2
4020 + (diff -c mb1.O $srcdir/mb1.X) 2> /dev/null
4021 + errors=`expr $errors + 1`;;
4022 + 2) $echo "Test mb1 may have failed." 1>&2
4023 + $echo The command "cmp mb1.O $srcdir/mb1.X" failed. 1>&2
4024 + errors=`expr $errors + 1`;;
4028 +$xx -t @ -k4 -n mb2.I > mb2.O
4030 +if test $code != 0; then
4031 + $echo "Test mb2 failed: $xx return code $code differs from expected value 0" 1>&2
4032 + errors=`expr $errors + 1`
4034 + cmp mb2.O $srcdir/mb2.X > /dev/null 2>&1
4036 + 0) if test "$VERBOSE"; then $echo "passed mb2"; fi;;
4037 + 1) $echo "Test mb2 failed: files mb2.O and $srcdir/mb2.X differ" 1>&2
4038 + (diff -c mb2.O $srcdir/mb2.X) 2> /dev/null
4039 + errors=`expr $errors + 1`;;
4040 + 2) $echo "Test mb2 may have failed." 1>&2
4041 + $echo The command "cmp mb2.O $srcdir/mb2.X" failed. 1>&2
4042 + errors=`expr $errors + 1`;;
4046 +if test $errors = 0; then
4047 + $echo Passed all 113 tests. 1>&2
4049 + $echo Failed $errors tests. 1>&2
4051 +test $errors = 0 || errors=1