more toolchain + stage 1 updates
[hdw-linux/hdw-linux.git] / packages / base / coreutils / coreutils_i18n.patch
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
4 @@ -22,6 +22,11 @@
5  
6  # include <stdio.h>
7  
8 +/* Get mbstate_t.  */
9 +# if HAVE_WCHAR_H
10 +#  include <wchar.h>
11 +# endif
12 +
13  /* A `struct linebuffer' holds a line of text. */
14  
15  struct linebuffer
16 @@ -29,6 +34,9 @@
17    size_t size;                 /* Allocated. */
18    size_t length;               /* Used. */
19    char *buffer;
20 +# if HAVE_WCHAR_H
21 +  mbstate_t state;
22 +# endif
23  };
24  
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
29 @@ -29,6 +29,11 @@
30  #include <assert.h>
31  #include <getopt.h>
32  #include <sys/types.h>
33 +
34 +/* Get mbstate_t, mbrtowc().  */
35 +#if HAVE_WCHAR_H
36 +# include <wchar.h>
37 +#endif
38  #include "system.h"
39  
40  #include "error.h"
41 @@ -37,6 +42,18 @@
42  #include "quote.h"
43  #include "xstrndup.h"
44  
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
48 +# undef MB_LEN_MAX
49 +# define MB_LEN_MAX 16
50 +#endif
51 +
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)
55 +#endif
56 +
57  /* The official name of this program (e.g., no `g' prefix).  */
58  #define PROGRAM_NAME "cut"
59  
60 @@ -67,6 +84,52 @@
61      }                                                  \
62    while (0)
63  
64 +/* Refill the buffer BUF to get a multibyte character. */
65 +#define REFILL_BUFFER(BUF, BUFPOS, BUFLEN, STREAM)                     \
66 +  do                                                                   \
67 +    {                                                                  \
68 +      if (BUFLEN < MB_LEN_MAX && !feof (STREAM) && !ferror (STREAM))   \
69 +       {                                                               \
70 +         memmove (BUF, BUFPOS, BUFLEN);                                \
71 +         BUFLEN += fread (BUF + BUFLEN, sizeof(char), BUFSIZ, STREAM); \
72 +         BUFPOS = BUF;                                                 \
73 +       }                                                               \
74 +    }                                                                  \
75 +  while (0)
76 +
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) \
80 +  do                                                                   \
81 +    {                                                                  \
82 +      mbstate_t state_bak;                                             \
83 +                                                                       \
84 +      if (BUFLEN < 1)                                                  \
85 +       {                                                               \
86 +         WC = WEOF;                                                    \
87 +         break;                                                        \
88 +       }                                                               \
89 +                                                                       \
90 +      /* Get a wide character. */                                      \
91 +      CONVFAIL = 0;                                                    \
92 +      state_bak = STATE;                                               \
93 +      MBLENGTH = mbrtowc ((wchar_t *)&WC, BUFPOS, BUFLEN, &STATE);     \
94 +                                                                       \
95 +      switch (MBLENGTH)                                                        \
96 +       {                                                               \
97 +       case (size_t)-1:                                                \
98 +       case (size_t)-2:                                                \
99 +         CONVFAIL++;                                                   \
100 +         STATE = state_bak;                                            \
101 +         /* Fall througn. */                                           \
102 +                                                                       \
103 +       case 0:                                                         \
104 +         MBLENGTH = 1;                                                 \
105 +         break;                                                        \
106 +       }                                                               \
107 +    }                                                                  \
108 +  while (0)
109 +
110  struct range_pair
111    {
112      size_t lo;
113 @@ -85,7 +148,7 @@
114  /* The number of bytes allocated for FIELD_1_BUFFER.  */
115  static size_t field_1_bufsize;
116  
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.  */
122 @@ -97,10 +160,11 @@
123  
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;
136 @@ -109,9 +173,12 @@
137    {
138      undefined_mode,
139  
140 -    /* Output characters that are in the given bytes. */
141 +    /* Output bytes that are at the given positions. */
142      byte_mode,
143  
144 +    /* Output characters that are at the given positions. */
145 +    character_mode,
146 +
147      /* Output the given delimeter-separated fields. */
148      field_mode
149    };
150 @@ -121,6 +188,13 @@
151  
152  static enum operating_mode operating_mode;
153  
154 +/* If nonzero, when in byte mode, don't split multibyte characters.  */
155 +static int byte_mode_character_aware;
156 +
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;
160 +
161  /* If true do not output lines containing no delimeter characters.
162     Otherwise, all such lines are printed.  This option is valid only
163     with field mode.  */
164 @@ -132,6 +206,9 @@
165  
166  /* The delimeter character for field mode. */
167  static unsigned char delim;
168 +#if HAVE_WCHAR_H
169 +static wchar_t wcdelim;
170 +#endif
171  
172  /* True if the --output-delimiter=STRING option was specified.  */
173  static bool output_delimiter_specified;
174 @@ -205,7 +282,7 @@
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\
178 -  -n                      (ignored)\n\
179 +  -n                      with -b: don't split multibyte characters\n\
180  "), stdout);
181        fputs (_("\
182        --complement        complement the set of selected bytes, characters\n\
183 @@ -360,7 +437,7 @@
184           in_digits = false;
185           /* Starting a range. */
186           if (dash_found)
187 -           FATAL_ERROR (_("invalid byte or field list"));
188 +           FATAL_ERROR (_("invalid byte, character or field list"));
189           dash_found = true;
190           fieldstr++;
191  
192 @@ -385,14 +462,16 @@
193               if (value == 0)
194                 {
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;
200                   field_found = true;
201                 }
202               else
203                 {
204                   /* `m-n' or `-n' (1-n). */
205                   if (value < initial)
206 -                   FATAL_ERROR (_("invalid byte or field list"));
207 +                   FATAL_ERROR (_("invalid byte, character or field list"));
208  
209                   /* Is there already a range going to end of line? */
210                   if (eol_range_start != 0)
211 @@ -465,6 +544,9 @@
212               if (operating_mode == byte_mode)
213                 error (0, 0,
214                        _("byte offset %s is too large"), quote (bad_num));
215 +             else if (operating_mode == character_mode)
216 +               error (0, 0,
217 +                      _("character offset %s is too large"), quote (bad_num));
218               else
219                 error (0, 0,
220                        _("field number %s is too large"), quote (bad_num));
221 @@ -475,7 +557,7 @@
222           fieldstr++;
223         }
224        else
225 -       FATAL_ERROR (_("invalid byte or field list"));
226 +       FATAL_ERROR (_("invalid byte, character or field list"));
227      }
228  
229    max_range_endpoint = 0;
230 @@ -568,6 +650,63 @@
231      }
232  }
233  
234 +#if HAVE_MBRTOWC
235 +/* This function is in use for the following case.
236 +
237 +   1. Read from the stream STREAM, printing to standard output any selected
238 +   characters. 
239 +
240 +   2. Read from stream STREAM, printing to standard output any selected bytes,
241 +   without splitting multibyte characters.  */
242
243 +static void
244 +cut_characters_or_cut_bytes_no_split (FILE *stream)
245 +{
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. */
255 +
256 +  idx = 0;
257 +  buflen = 0;
258 +  bufpos = buf;
259 +  memset (&state, '\0', sizeof(mbstate_t));
260 +
261 +  while (1)
262 +    {
263 +      REFILL_BUFFER (buf, bufpos, buflen, stream);
264 +
265 +      GET_NEXT_WC_FROM_BUFFER (wc, bufpos, buflen, mblength, state, convfail);
266 +
267 +      if (wc == WEOF)
268 +       {
269 +         if (idx > 0)
270 +           putchar ('\n');
271 +         break;
272 +       }
273 +      else if (wc == L'\n')
274 +       {
275 +         putchar ('\n');
276 +         idx = 0;
277 +       }
278 +      else
279 +       {
280 +         idx += (operating_mode == byte_mode) ? mblength : 1;
281 +         if (print_kth (idx, NULL))
282 +           fwrite (bufpos, mblength, sizeof(char), stdout);
283 +       }
284 +
285 +      buflen -= mblength;
286 +      bufpos += mblength;
287 +    }
288 +}
289 +#endif
290 +                  
291  /* Read from stream STREAM, printing to standard output any selected fields.  */
292  
293  static void
294 @@ -689,13 +828,192 @@
295      }
296  }
297  
298 +#if HAVE_MBRTOWC
299 +static void
300 +cut_fields_mb (FILE *stream)
301 +{
302 +  int c;
303 +  unsigned int field_idx;
304 +  int found_any_selected_field;
305 +  int buffer_first_field;
306 +  int empty_input;
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. */
315 +
316 +  found_any_selected_field = 0;
317 +  field_idx = 1;
318 +  bufpos = buf;
319 +  buflen = 0;
320 +  memset (&state, '\0', sizeof(mbstate_t));
321 +
322 +  c = getc (stream);
323 +  empty_input = (c == EOF);
324 +  if (c != EOF)
325 +    ungetc (c, stream);
326 +  else
327 +    wc = WEOF;
328 +
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));
336 +
337 +  while (1)
338 +    {
339 +      if (field_idx == 1 && buffer_first_field)
340 +       {
341 +         int len = 0;
342 +
343 +         while (1)
344 +           {
345 +             REFILL_BUFFER (buf, bufpos, buflen, stream);
346 +
347 +             GET_NEXT_WC_FROM_BUFFER
348 +               (wc, bufpos, buflen, mblength, state, convfail);
349 +
350 +             if (wc == WEOF)
351 +               break;
352 +
353 +             field_1_buffer = xrealloc (field_1_buffer, len + mblength);
354 +             memcpy (field_1_buffer + len, bufpos, mblength);
355 +             len += mblength;
356 +             buflen -= mblength;
357 +             bufpos += mblength;
358 +
359 +             if (!convfail && (wc == L'\n' || wc == wcdelim))
360 +               break;
361 +           }
362 +
363 +         if (wc == WEOF)
364 +           break;
365 +
366 +         /* If the first field extends to the end of line (it is not
367 +            delimited) and we are printing all non-delimited lines,
368 +            print this one.  */
369 +         if (convfail || (!convfail && wc != wcdelim))
370 +           {
371 +             if (suppress_non_delimited)
372 +               {
373 +                 /* Empty.     */
374 +               }
375 +             else
376 +               {
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'))
380 +                   putchar ('\n');
381 +               }
382 +             continue;
383 +           }
384 +
385 +         if (print_kth (1, NULL))
386 +           {
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;
390 +           }
391 +         ++field_idx;
392 +       }
393 +
394 +      if (wc != WEOF)
395 +       {
396 +         if (print_kth (field_idx, NULL))
397 +           {
398 +             if (found_any_selected_field)
399 +               {
400 +                 fwrite (output_delimiter_string, sizeof (char),
401 +                         output_delimiter_length, stdout);
402 +               }
403 +             found_any_selected_field = 1;
404 +           }
405 +
406 +         while (1)
407 +           {
408 +             REFILL_BUFFER (buf, bufpos, buflen, stream);
409 +
410 +             GET_NEXT_WC_FROM_BUFFER
411 +               (wc, bufpos, buflen, mblength, state, convfail);
412 +
413 +             if (wc == WEOF)
414 +               break;
415 +             else if (!convfail && (wc == wcdelim || wc == L'\n'))
416 +               {
417 +                 buflen -= mblength;
418 +                 bufpos += mblength;
419 +                 break;
420 +               }
421 +
422 +             if (print_kth (field_idx, NULL))
423 +               fwrite (bufpos, mblength, sizeof(char), stdout);
424 +
425 +             buflen -= mblength;
426 +             bufpos += mblength;
427 +           }
428 +       }
429 +
430 +      if ((!convfail || wc == L'\n') && buflen < 1)
431 +       wc = WEOF;
432 +
433 +      if (!convfail && wc == wcdelim)
434 +       ++field_idx;
435 +      else if (wc == WEOF || (!convfail && wc == L'\n'))
436 +       {
437 +         if (found_any_selected_field
438 +             || (!empty_input && !(suppress_non_delimited && field_idx == 1)))
439 +           putchar ('\n');
440 +         if (wc == WEOF)
441 +           break;
442 +         field_idx = 1;
443 +         found_any_selected_field = 0;
444 +       }
445 +    }
446 +}
447 +#endif
448 +
449  static void
450  cut_stream (FILE *stream)
451  {
452 -  if (operating_mode == byte_mode)
453 -    cut_bytes (stream);
454 +#if HAVE_MBRTOWC
455 +  if (MB_CUR_MAX > 1 && !force_singlebyte_mode)
456 +    {
457 +      switch (operating_mode)
458 +       {
459 +       case byte_mode:
460 +         if (byte_mode_character_aware)
461 +           cut_characters_or_cut_bytes_no_split (stream);
462 +         else
463 +           cut_bytes (stream);
464 +         break;
465 +
466 +       case character_mode:
467 +         cut_characters_or_cut_bytes_no_split (stream);
468 +         break;
469 +
470 +       case field_mode:
471 +         cut_fields_mb (stream);
472 +         break;
473 +
474 +       default:
475 +         abort ();
476 +       }
477 +    }
478    else
479 -    cut_fields (stream);
480 +#endif
481 +    {
482 +      if (operating_mode == field_mode)
483 +       cut_fields (stream);
484 +      else
485 +       cut_bytes (stream);
486 +    }
487  }
488  
489  /* Process file FILE to standard output.
490 @@ -745,6 +1063,8 @@
491    bool ok;
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;
496  
497    initialize_main (&argc, &argv);
498    program_name = argv[0];
499 @@ -767,7 +1087,6 @@
500        switch (optc)
501         {
502         case 'b':
503 -       case 'c':
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;
509           break;
510  
511 +       case 'c':
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;
517 +         break;
518 +
519         case 'f':
520           /* Build the field list. */
521           if (operating_mode != undefined_mode)
522 @@ -786,10 +1113,35 @@
523         case 'd':
524           /* New delimiter. */
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"));
528 -         delim = optarg[0];
529 -         delim_specified = true;
530 +#if HAVE_MBRTOWC
531 +           {
532 +             if(MB_CUR_MAX > 1)
533 +               {
534 +                 mbstate_t state;
535 +
536 +                 memset (&state, '\0', sizeof(mbstate_t));
537 +                 delimlen = mbrtowc (&wcdelim, optarg, strnlen(optarg, MB_LEN_MAX), &state);
538 +
539 +                 if (delimlen == (size_t)-1 || delimlen == (size_t)-2)
540 +                   ++force_singlebyte_mode;
541 +                 else
542 +                   {
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);
547 +                   }
548 +               }
549 +
550 +             if (MB_CUR_MAX <= 1 || force_singlebyte_mode)
551 +#endif
552 +               {
553 +                 if (optarg[0] != '\0' && optarg[1] != '\0')
554 +                   FATAL_ERROR (_("the delimiter must be a single character"));
555 +                 delim = (unsigned char) optarg[0];
556 +               }
557 +           delim_specified = true;
558 +         }
559           break;
560  
561         case OUTPUT_DELIMITER_OPTION:
562 @@ -802,6 +1154,7 @@
563           break;
564  
565         case 'n':
566 +         byte_mode_character_aware = 1;
567           break;
568  
569         case 's':
570 @@ -824,7 +1177,7 @@
571    if (operating_mode == undefined_mode)
572      FATAL_ERROR (_("you must specify a list of bytes, characters, or fields"));
573  
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"));
578  
579 @@ -851,15 +1204,34 @@
580      }
581  
582    if (!delim_specified)
583 -    delim = '\t';
584 +    {
585 +      delim = '\t';
586 +#ifdef HAVE_MBRTOWC
587 +      wcdelim = L'\t';
588 +      mbdelim[0] = '\t';
589 +      mbdelim[1] = '\0';
590 +      delimlen = 1;
591 +#endif
592 +    }
593  
594    if (output_delimiter_string == NULL)
595      {
596 -      static char dummy[2];
597 -      dummy[0] = delim;
598 -      dummy[1] = '\0';
599 -      output_delimiter_string = dummy;
600 -      output_delimiter_length = 1;
601 +#ifdef HAVE_MBRTOWC
602 +      if (MB_CUR_MAX > 1 && !force_singlebyte_mode)
603 +       {
604 +         output_delimiter_string = xstrdup(mbdelim);
605 +         output_delimiter_length = delimlen;
606 +       }
607 +
608 +      if (MB_CUR_MAX <= 1 || force_singlebyte_mode)
609 +#endif
610 +       {
611 +         static char dummy[2]; 
612 +         dummy[0] = delim;
613 +         dummy[1] = '\0';
614 +         output_delimiter_string = dummy;
615 +         output_delimiter_length = 1;
616 +       }
617      }
618  
619    if (optind == argc)
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
623 @@ -38,11 +38,28 @@
624  #include <stdio.h>
625  #include <getopt.h>
626  #include <sys/types.h>
627 +
628 +/* Get mbstate_t, mbrtowc(), wcwidth(). */
629 +#if HAVE_WCHAR_H
630 +# include <wchar.h>
631 +#endif
632 +
633  #include "system.h"
634  #include "error.h"
635  #include "quote.h"
636  #include "xstrndup.h"
637  
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
642 +#endif
643 +
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)
647 +#endif
648 +
649  /* The official name of this program (e.g., no `g' prefix).  */
650  #define PROGRAM_NAME "expand"
651  
652 @@ -183,6 +200,7 @@
653               stops = num_start + len - 1;
654             }
655         }
656 +
657        else
658         {
659           error (0, 0, _("tab size contains invalid character(s): %s"),
660 @@ -365,6 +383,142 @@
661      }
662  }
663  
664 +#if HAVE_MBRTOWC
665 +static void
666 +expand_multibyte (void)
667 +{
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. */
682 +
683 +  fp = next_file ((FILE *) NULL);
684 +  if (fp == NULL)
685 +    return;
686 +
687 +  memset (&o_state, '\0', sizeof(mbstate_t));
688 +  memset (&i_state, '\0', sizeof(mbstate_t));
689 +
690 +  for (;;)
691 +    {
692 +      /* Refill the buffer BUF. */
693 +      if (buflen < MB_LEN_MAX && !feof(fp) && !ferror(fp))
694 +       {
695 +         memmove (buf, bufpos, buflen);
696 +         buflen += fread (buf + buflen, sizeof(char), BUFSIZ, fp);
697 +         bufpos = buf;
698 +       }
699 +
700 +      /* No character is left in BUF. */
701 +      if (buflen < 1)
702 +       {
703 +         fp = next_file (fp);
704 +
705 +         if (fp == NULL)
706 +           break;              /* No more files. */
707 +         else
708 +           {
709 +             memset (&i_state, '\0', sizeof(mbstate_t));
710 +             continue;
711 +           }
712 +       }
713 +
714 +      /* Get a wide character. */
715 +      i_state_bak = i_state;
716 +      mblength = mbrtowc (&wc, bufpos, buflen, &i_state);
717 +
718 +      switch (mblength)
719 +       {
720 +       case (size_t)-1:        /* illegal byte sequence. */
721 +       case (size_t)-2:
722 +         mblength = 1;
723 +         i_state = i_state_bak;
724 +         if (convert)
725 +           {
726 +             ++column;
727 +             if (convert_entire_line == 0)
728 +               convert = 0;
729 +           }
730 +         putchar (*bufpos);
731 +         break;
732 +
733 +       case 0:         /* null. */
734 +         mblength = 1;
735 +         if (convert && convert_entire_line == 0)
736 +           convert = 0;
737 +         putchar ('\0');
738 +         break;
739 +
740 +       default:
741 +         if (wc == L'\n')   /* LF. */
742 +           {
743 +             tab_index = 0;
744 +             column = 0;
745 +             convert = 1;
746 +             putchar ('\n');
747 +           }
748 +         else if (wc == L'\t' && convert)      /* Tab. */
749 +           {
750 +             if (tab_size == 0)
751 +               {
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])
756 +                   tab_index++;
757 +                 next_tab_column = tab_list[tab_index];
758 +                 if (tab_index < first_free_tab - 1)
759 +                   tab_index++;
760 +                 if (column >= next_tab_column)
761 +                   next_tab_column = column + 1;
762 +               }
763 +             else
764 +               next_tab_column = column + tab_size - column % tab_size;
765 +
766 +             while (column < next_tab_column)
767 +               {
768 +                 putchar (' ');
769 +                 ++column;
770 +               }
771 +           }
772 +         else  /* Others. */
773 +           {
774 +             if (convert)
775 +               {
776 +                 if (wc == L'\b')
777 +                   {
778 +                     if (column > 0)
779 +                       --column;
780 +                   }
781 +                 else
782 +                   {
783 +                     int width;                /* The width of WC. */
784 +
785 +                     width = wcwidth (wc);
786 +                     column += (width > 0) ? width : 0;
787 +                     if (convert_entire_line == 0)
788 +                       convert = 0;
789 +                   }
790 +               }
791 +             fwrite (bufpos, sizeof(char), mblength, stdout);
792 +           }
793 +       }
794 +      buflen -= mblength;
795 +      bufpos += mblength;
796 +    }
797 +}
798 +#endif
799 +
800  int
801  main (int argc, char **argv)
802  {
803 @@ -429,7 +583,12 @@
804  
805    file_list = (optind < argc ? &argv[optind] : stdin_argv);
806  
807 -  expand ();
808 +#if HAVE_MBRTOWC
809 +  if (MB_CUR_MAX > 1)
810 +    expand_multibyte ();
811 +  else
812 +#endif
813 +    expand ();
814  
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
820 @@ -23,11 +23,33 @@
821  #include <getopt.h>
822  #include <sys/types.h>
823  
824 +/* Get mbstate_t, mbrtowc(), wcwidth().  */
825 +#if HAVE_WCHAR_H
826 +# include <wchar.h>
827 +#endif
828 +
829 +/* Get iswprint(), iswblank(), wcwidth().  */
830 +#if HAVE_WCTYPE_H
831 +# include <wctype.h>
832 +#endif
833 +
834  #include "system.h"
835  #include "error.h"
836  #include "quote.h"
837  #include "xstrtol.h"
838  
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
842 +# undef MB_LEN_MAX
843 +# define MB_LEN_MAX 16
844 +#endif
845 +
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)
849 +#endif
850 +
851  #define TAB_WIDTH 8
852  
853  /* The official name of this program (e.g., no `g' prefix).  */
854 @@ -35,23 +57,44 @@
855  
856  #define AUTHORS "David MacKenzie"
857  
858 +#define FATAL_ERROR(Message)                                            \
859 +  do                                                                    \
860 +    {                                                                   \
861 +      error (0, 0, (Message));                                          \
862 +      usage (2);                                                        \
863 +    }                                                                   \
864 +  while (0)
865 +
866 +enum operating_mode
867 +{
868 +  /* Fold texts by columns that are at the given positions. */
869 +  column_mode,
870 +
871 +  /* Fold texts by bytes that are at the given positions. */
872 +  byte_mode,
873 +
874 +  /* Fold texts by characters that are at the given positions. */
875 +  character_mode,
876 +};
877 +
878  /* The name this program was run with. */
879  char *program_name;
880  
881 +/* The argument shows current mode. (Default: column_mode) */
882 +static enum operating_mode operating_mode;
883 +
884  /* If nonzero, try to break on whitespace. */
885  static bool break_spaces;
886  
887 -/* If nonzero, count bytes, not column positions. */
888 -static bool count_bytes;
889 -
890  /* If nonzero, at least one of the files we read was standard input. */
891  static bool have_read_stdin;
892  
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::";
895  
896  static struct option const longopts[] =
897  {
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},
903 @@ -81,6 +124,7 @@
904  "), stdout);
905        fputs (_("\
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\
910  "), stdout);
911 @@ -98,7 +142,7 @@
912  static size_t
913  adjust_column (size_t column, char c)
914  {
915 -  if (!count_bytes)
916 +  if (operating_mode != byte_mode)
917      {
918        if (c == '\b')
919         {
920 @@ -117,35 +161,14 @@
921    return column;
922  }
923  
924 -/* Fold file FILENAME, or standard input if FILENAME is "-",
925 -   to stdout, with maximum line length WIDTH.
926 -   Return true if successful.  */
927 -
928 -static bool
929 -fold_file (char *filename, size_t width)
930 +static void
931 +fold_text (FILE *istream, size_t width, int *saved_errno)
932  {
933 -  FILE *istream;
934    int c;
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;
939 -  int saved_errno;
940 -
941 -  if (STREQ (filename, "-"))
942 -    {
943 -      istream = stdin;
944 -      have_read_stdin = true;
945 -    }
946 -  else
947 -    istream = fopen (filename, "r");
948 -
949 -  if (istream == NULL)
950 -    {
951 -      error (0, errno, "%s", filename);
952 -      return false;
953 -    }
954 -
955    while ((c = getc (istream)) != EOF)
956      {
957        if (offset_out + 1 >= allocated_out)
958 @@ -172,6 +195,15 @@
959               bool found_blank = false;
960               size_t logical_end = offset_out;
961  
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)
966 +               {
967 +                 line_out[offset_out++] = c;
968 +                 continue;
969 +               }
970 +
971               /* Look for the last blank. */
972               while (logical_end)
973                 {
974 @@ -218,11 +250,225 @@
975        line_out[offset_out++] = c;
976      }
977  
978 -  saved_errno = errno;
979 +  *saved_errno = errno;
980 +
981 +  if (offset_out)
982 +    fwrite (line_out, sizeof (char), (size_t) offset_out, stdout);
983 +
984 +  free(line_out);
985 +}
986 +
987 +#if HAVE_MBRTOWC
988 +static void
989 +fold_multibyte_text (FILE *istream, int width, int *saved_errno)
990 +{
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. */
999 +
1000 +  char *line_out = NULL;
1001 +  size_t offset_out = 0;       /* Index in `line_out' for next char. */
1002 +  size_t allocated_out = 0;
1003 +
1004 +  int increment;
1005 +  size_t column = 0;
1006 +
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;
1014 +
1015 +#define CLEAR_FLAGS                            \
1016 +   do                                          \
1017 +     {                                         \
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;             \
1024 +     }                                         \
1025 +   while (0)
1026 +
1027 +#define START_NEW_LINE                 \
1028 +   do                                  \
1029 +     {                                 \
1030 +      putchar ('\n');                  \
1031 +      column = 0;                      \
1032 +      offset_out = 0;                  \
1033 +      CLEAR_FLAGS;                     \
1034 +    }                                  \
1035 +   while (0)
1036 +
1037 +  CLEAR_FLAGS;
1038 +  memset (&state, '\0', sizeof(mbstate_t));
1039 +
1040 +  for (;; bufpos += mblength, buflen -= mblength)
1041 +    {
1042 +      if (buflen < MB_LEN_MAX && !feof (istream) && !ferror (istream))
1043 +       {
1044 +         memmove (buf, bufpos, buflen);
1045 +         buflen += fread (buf + buflen, sizeof(char), BUFSIZ, istream);
1046 +         bufpos = buf;
1047 +       }
1048 +
1049 +      if (buflen < 1)
1050 +       break;
1051 +
1052 +      /* Get a wide character. */
1053 +      convfail = 0;
1054 +      state_bak = state;
1055 +      mblength = mbrtowc ((wchar_t *)&wc, bufpos, buflen, &state);
1056 +
1057 +      switch (mblength)
1058 +       {
1059 +       case (size_t)-1:
1060 +       case (size_t)-2:
1061 +         convfail++;
1062 +         state = state_bak;
1063 +         /* Fall through. */
1064 +
1065 +       case 0:
1066 +         mblength = 1;
1067 +         break;
1068 +       }
1069 +
1070 +rescan:
1071 +      if (operating_mode == byte_mode)                 /* byte mode */
1072 +       increment = mblength;
1073 +      else if (operating_mode == character_mode)       /* character mode */
1074 +       increment = 1;
1075 +      else                                             /* column mode */
1076 +       {
1077 +         if (convfail)
1078 +           increment = 1;
1079 +         else
1080 +           {
1081 +             switch (wc)
1082 +               {
1083 +               case L'\n':
1084 +                 fwrite (line_out, sizeof(char), offset_out, stdout);
1085 +                 START_NEW_LINE;
1086 +                 continue;
1087 +                 
1088 +               case L'\b':
1089 +                 increment = (column > 0) ? -1 : 0;
1090 +                 break;
1091 +
1092 +               case L'\r':
1093 +                 increment = -1 * column;
1094 +                 break;
1095 +
1096 +               case L'\t':
1097 +                 increment = 8 - column % 8;
1098 +                 break;
1099 +
1100 +               default:
1101 +                 increment = wcwidth (wc);
1102 +                 increment = (increment < 0) ? 0 : increment;
1103 +               }
1104 +           }
1105 +       }
1106 +
1107 +      if (column + increment > width && break_spaces && last_blank_pos)
1108 +       {
1109 +         fwrite (line_out, sizeof(char), last_blank_pos, stdout);
1110 +         putchar ('\n');
1111 +
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);
1116 +         CLEAR_FLAGS;
1117 +         goto rescan;
1118 +       }
1119 +
1120 +      if (column + increment > width && column != 0)
1121 +       {
1122 +         fwrite (line_out, sizeof(char), offset_out, stdout);
1123 +         START_NEW_LINE;
1124 +         goto rescan;
1125 +       }
1126 +
1127 +      if (allocated_out < offset_out + mblength)
1128 +       {
1129 +         allocated_out += 1024;
1130 +         line_out = xrealloc (line_out, allocated_out);
1131 +       }
1132 +
1133 +      memcpy (line_out + offset_out, bufpos, mblength);
1134 +      offset_out += mblength;
1135 +      column += increment;
1136 +
1137 +      if (is_blank_seen && !convfail && wc == L'\r')
1138 +       is_cr_after_last_blank = 1;
1139 +
1140 +      if (is_bs_following_last_blank && !convfail && wc == L'\b')
1141 +       ++bs_following_last_blank_num;
1142 +      else
1143 +       is_bs_following_last_blank = 0;
1144 +
1145 +      if (break_spaces && !convfail && iswblank (wc))
1146 +       {
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;
1154 +       }
1155 +    }
1156 +
1157 +  *saved_errno = errno;
1158  
1159    if (offset_out)
1160      fwrite (line_out, sizeof (char), (size_t) offset_out, stdout);
1161  
1162 +  free(line_out);
1163 +}
1164 +#endif
1165 +
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. */
1169 +
1170 +static int
1171 +fold_file (char *filename, int width)
1172 +{
1173 +  FILE *istream;
1174 +  int saved_errno;
1175 +
1176 +  if (STREQ (filename, "-"))
1177 +    {
1178 +      istream = stdin;
1179 +      have_read_stdin = 1;
1180 +    }
1181 +  else
1182 +    istream = fopen (filename, "r");
1183 +
1184 +  if (istream == NULL)
1185 +    {
1186 +      error (0, errno, "%s", filename);
1187 +      return 1;
1188 +    }
1189 +
1190 +  /* Define how ISTREAM is being folded. */
1191 +#if HAVE_MBRTOWC
1192 +  if (MB_CUR_MAX > 1)
1193 +    fold_multibyte_text (istream, width, &saved_errno);
1194 +  else
1195 +#endif
1196 +    fold_text (istream, width, &saved_errno);
1197 +
1198    if (ferror (istream))
1199      {
1200        error (0, saved_errno, "%s", filename);
1201 @@ -255,7 +501,8 @@
1202  
1203    atexit (close_stdout);
1204  
1205 -  break_spaces = count_bytes = have_read_stdin = false;
1206 +  operating_mode = column_mode;
1207 +  break_spaces = have_read_stdin = false;
1208  
1209    while ((optc = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1)
1210      {
1211 @@ -264,7 +511,15 @@
1212        switch (optc)
1213         {
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;
1219 +         break;
1220 +
1221 +       case 'c':
1222 +         if (operating_mode != column_mode)
1223 +           FATAL_ERROR (_("only one way of folding may be specified"));
1224 +         operating_mode = character_mode;
1225           break;
1226  
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
1231 @@ -23,16 +23,30 @@
1232  #include <sys/types.h>
1233  #include <getopt.h>
1234  
1235 +/* Get mbstate_t, mbrtowc(), mbrtowc(), wcwidth().  */
1236 +#if HAVE_WCHAR_H
1237 +# include <wchar.h>
1238 +#endif
1239 +
1240 +/* Get iswblank(), towupper.  */
1241 +#if HAVE_WCTYPE_H
1242 +# include <wctype.h>
1243 +#endif
1244 +
1245  #include "system.h"
1246  #include "error.h"
1247  #include "hard-locale.h"
1248  #include "linebuffer.h"
1249 -#include "memcasecmp.h"
1250  #include "quote.h"
1251  #include "stdio--.h"
1252  #include "xmemcoll.h"
1253  #include "xstrtol.h"
1254  
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)
1258 +#endif
1259 +
1260  /* The official name of this program (e.g., no `g' prefix).  */
1261  #define PROGRAM_NAME "join"
1262  
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;
1266  
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;
1274 +
1275 +/* The number of bytes used for tab. */
1276 +static size_t tablen = 0;
1277  
1278  static struct option const longopts[] =
1279  {
1280 @@ -190,6 +206,8 @@
1281  
1282  /* Fill in the `fields' structure in LINE.  */
1283  
1284 +/* Fill in the `fields' structure in LINE.  */
1285 +
1286  static void
1287  xfields (struct line *line)
1288  {
1289 @@ -199,10 +217,11 @@
1290    if (ptr == lim)
1291      return;
1292  
1293 -  if (0 <= tab)
1294 +  if (tab != NULL)
1295      {
1296 +      unsigned char t = tab[0];
1297        char *sep;
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);
1301      }
1302    else
1303 @@ -229,6 +248,148 @@
1304    extract_field (line, ptr, lim - ptr);
1305  }
1306  
1307 +#if HAVE_MBRTOWC
1308 +static void
1309 +xfields_multibyte (struct line *line)
1310 +{
1311 +  char *ptr = line->buf.buffer;
1312 +  char const *lim = ptr + line->buf.length - 1;
1313 +  wchar_t wc = 0;
1314 +  size_t mblength = 1;
1315 +  mbstate_t state, state_bak;
1316 +
1317 +  memset (&state, 0, sizeof (mbstate_t));
1318 +
1319 +  if (ptr == lim)
1320 +    return;
1321 +
1322 +  if (tab != NULL)
1323 +    {
1324 +      unsigned char t = tab[0];
1325 +      char *sep = ptr;
1326 +      for (; ptr < lim; ptr = sep + mblength)
1327 +       {
1328 +         sep = ptr;
1329 +         while (sep < lim)
1330 +           {
1331 +             state_bak = state;
1332 +             mblength = mbrtowc (&wc, sep, lim - sep + 1, &state);
1333 +
1334 +             if (mblength == (size_t)-1 || mblength == (size_t)-2)
1335 +               {
1336 +                 mblength = 1;
1337 +                 state = state_bak;
1338 +               }
1339 +             mblength = (mblength < 1) ? 1 : mblength;
1340 +
1341 +             if (mblength == tablen && !memcmp (sep, tab, mblength))
1342 +               break;
1343 +             else
1344 +               {
1345 +                 sep += mblength;
1346 +                 continue;
1347 +               }
1348 +           }
1349 +
1350 +         if (sep == lim)
1351 +           break;
1352 +
1353 +         extract_field (line, ptr, sep - ptr);
1354 +       }
1355 +    }
1356 +  else
1357 +    {
1358 +      /* Skip leading blanks before the first field.  */
1359 +      while(ptr < lim)
1360 +      {
1361 +        state_bak = state;
1362 +        mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state);
1363 +
1364 +        if (mblength == (size_t)-1 || mblength == (size_t)-2)
1365 +          {
1366 +            mblength = 1;
1367 +            state = state_bak;
1368 +            break;
1369 +          }
1370 +        mblength = (mblength < 1) ? 1 : mblength;
1371 +
1372 +        if (!iswblank(wc))
1373 +          break;
1374 +        ptr += mblength;
1375 +      }
1376 +
1377 +      do
1378 +       {
1379 +         char *sep;
1380 +         state_bak = state;
1381 +         mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state);
1382 +         if (mblength == (size_t)-1 || mblength == (size_t)-2)
1383 +           {
1384 +             mblength = 1;
1385 +             state = state_bak;
1386 +             break;
1387 +           }
1388 +         mblength = (mblength < 1) ? 1 : mblength;
1389 +
1390 +         sep = ptr + mblength;
1391 +         while (sep != lim)
1392 +           {
1393 +             state_bak = state;
1394 +             mblength = mbrtowc (&wc, sep, lim - sep + 1, &state);
1395 +             if (mblength == (size_t)-1 || mblength == (size_t)-2)
1396 +               {
1397 +                 mblength = 1;
1398 +                 state = state_bak;
1399 +                 break;
1400 +               }
1401 +             mblength = (mblength < 1) ? 1 : mblength;
1402 +
1403 +             if (iswblank (wc))
1404 +               break;
1405 +
1406 +             sep += mblength;
1407 +           }
1408 +
1409 +         extract_field (line, ptr, sep - ptr);
1410 +         if (sep == lim)
1411 +           return;
1412 +
1413 +         state_bak = state;
1414 +         mblength = mbrtowc (&wc, sep, lim - sep + 1, &state);
1415 +         if (mblength == (size_t)-1 || mblength == (size_t)-2)
1416 +           {
1417 +             mblength = 1;
1418 +             state = state_bak;
1419 +             break;
1420 +           }
1421 +         mblength = (mblength < 1) ? 1 : mblength;
1422 +
1423 +         ptr = sep + mblength;
1424 +         while (ptr != lim)
1425 +           {
1426 +             state_bak = state;
1427 +             mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state);
1428 +             if (mblength == (size_t)-1 || mblength == (size_t)-2)
1429 +               {
1430 +                 mblength = 1;
1431 +                 state = state_bak;
1432 +                 break;
1433 +               }
1434 +             mblength = (mblength < 1) ? 1 : mblength;
1435 +
1436 +             if (!iswblank (wc))
1437 +               break;
1438 +
1439 +             ptr += mblength;
1440 +           }
1441 +       }
1442 +      while (ptr != lim);
1443 +    }
1444 +
1445 +  extract_field (line, ptr, lim - ptr);
1446 +}
1447 +#endif
1448 +
1449  /* Read a line from FP into LINE and split it into fields.
1450     Return true if successful.  */
1451  
1452 @@ -249,6 +410,11 @@
1453    line->nfields_allocated = 0;
1454    line->nfields = 0;
1455    line->fields = NULL;
1456 +#if HAVE_MBRTOWC
1457 +  if (MB_CUR_MAX > 1)
1458 +    xfields_multibyte (line);
1459 +  else
1460 +#endif
1461    xfields (line);
1462    return true;
1463  }
1464 @@ -303,56 +469,114 @@
1465  keycmp (struct line const *line1, struct line const *line2)
1466  {
1467    /* Start of field to compare in each file.  */
1468 -  char *beg1;
1469 -  char *beg2;
1470 -
1471 -  size_t len1;
1472 -  size_t len2;         /* Length of fields to compare.  */
1473 +  char *beg[2];
1474 +  char *copy[2];
1475 +  size_t len[2];       /* Length of fields to compare.  */
1476    int diff;
1477 +  int i, j;
1478  
1479    if (join_field_1 < line1->nfields)
1480      {
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;
1485      }
1486    else
1487      {
1488 -      beg1 = NULL;
1489 -      len1 = 0;
1490 +      beg[0] = NULL;
1491 +      len[0] = 0;
1492      }
1493  
1494    if (join_field_2 < line2->nfields)
1495      {
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;
1500      }
1501    else
1502      {
1503 -      beg2 = NULL;
1504 -      len2 = 0;
1505 +      beg[1] = NULL;
1506 +      len[1] = 0;
1507      }
1508  
1509 -  if (len1 == 0)
1510 -    return len2 == 0 ? 0 : -1;
1511 -  if (len2 == 0)
1512 +  if (len[0] == 0)
1513 +    return len[1] == 0 ? 0 : -1;
1514 +  if (len[1] == 0)
1515      return 1;
1516  
1517    if (ignore_case)
1518      {
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)
1524 +      {
1525 +        size_t mblength;
1526 +        wchar_t wc, uwc;
1527 +        mbstate_t state, state_bak;
1528 +
1529 +        memset (&state, '\0', sizeof (mbstate_t));
1530 +
1531 +        for (i = 0; i < 2; i++)
1532 +          {
1533 +            copy[i] = alloca (len[i] + 1);
1534 +
1535 +            for (j = 0; j < MIN (len[0], len[1]);)
1536 +              {
1537 +                state_bak = state;
1538 +                mblength = mbrtowc (&wc, beg[i] + j, len[i] - j, &state);
1539 +
1540 +                switch (mblength)
1541 +                  {
1542 +                  case (size_t) -1:
1543 +                  case (size_t) -2:
1544 +                    state = state_bak;
1545 +                    /* Fall through */
1546 +                  case 0:
1547 +                    mblength = 1;
1548 +                    break;
1549 +
1550 +                  default:
1551 +                    uwc = towupper (wc);
1552 +
1553 +                    if (uwc != wc)
1554 +                      {
1555 +                        mbstate_t state_wc;
1556 +
1557 +                        memset (&state_wc, '\0', sizeof (mbstate_t));
1558 +                        wcrtomb (copy[i] + j, uwc, &state_wc);
1559 +                      }
1560 +                    else
1561 +                      memcpy (copy[i] + j, beg[i] + j, mblength);
1562 +                  }
1563 +                j += mblength;
1564 +              }
1565 +            copy[i][j] = '\0';
1566 +          }
1567 +      }
1568 +      else
1569 +#endif
1570 +      {
1571 +        for (i = 0; i < 2; i++)
1572 +          {
1573 +            copy[i] = alloca (len[i] + 1);
1574 +
1575 +            for (j = 0; j < MIN (len[0], len[1]); j++)
1576 +              copy[i][j] = toupper (beg[i][j]);
1577 +
1578 +            copy[i][j] = '\0';
1579 +          }
1580 +      }
1581      }
1582    else
1583      {
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];
1589      }
1590  
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]));
1594 +
1595    if (diff)
1596      return diff;
1597 -  return len1 < len2 ? -1 : len1 != len2;
1598 +  return len[0] - len[1];
1599  }
1600  
1601  /* Print field N of LINE if it exists and is nonempty, otherwise
1602 @@ -377,11 +601,18 @@
1603  
1604  /* Print the join of LINE1 and LINE2.  */
1605  
1606 +#define PUT_TAB_CHAR                                                   \
1607 +  do                                                                   \
1608 +    {                                                                  \
1609 +      (tab != NULL) ?                                                  \
1610 +       fwrite(tab, sizeof(char), tablen, stdout) : putchar (' ');      \
1611 +    }                                                                  \
1612 +  while (0)                                                            
1613 +
1614  static void
1615  prjoin (struct line const *line1, struct line const *line2)
1616  {
1617    const struct outlist *outlist;
1618 -  char output_separator = tab < 0 ? ' ' : tab;
1619  
1620    outlist = outlist_head.next;
1621    if (outlist)
1622 @@ -397,12 +628,12 @@
1623           if (o->file == 0)
1624             {
1625               if (line1 == &uni_blank)
1626 -               {
1627 +               {
1628                   line = line2;
1629                   field = join_field_2;
1630                 }
1631               else
1632 -               {
1633 +               {
1634                   line = line1;
1635                   field = join_field_1;
1636                 }
1637 @@ -416,7 +647,7 @@
1638           o = o->next;
1639           if (o == NULL)
1640             break;
1641 -         putchar (output_separator);
1642 +         PUT_TAB_CHAR;
1643         }
1644        putchar ('\n');
1645      }
1646 @@ -434,23 +665,23 @@
1647        prfield (join_field_1, line1);
1648        for (i = 0; i < join_field_1 && i < line1->nfields; ++i)
1649         {
1650 -         putchar (output_separator);
1651 +         PUT_TAB_CHAR;
1652           prfield (i, line1);
1653         }
1654        for (i = join_field_1 + 1; i < line1->nfields; ++i)
1655         {
1656 -         putchar (output_separator);
1657 +         PUT_TAB_CHAR;
1658           prfield (i, line1);
1659         }
1660  
1661        for (i = 0; i < join_field_2 && i < line2->nfields; ++i)
1662         {
1663 -         putchar (output_separator);
1664 +         PUT_TAB_CHAR;
1665           prfield (i, line2);
1666         }
1667        for (i = join_field_2 + 1; i < line2->nfields; ++i)
1668         {
1669 -         putchar (output_separator);
1670 +         PUT_TAB_CHAR;
1671           prfield (i, line2);
1672         }
1673        putchar ('\n');
1674 @@ -862,20 +1093,41 @@
1675  
1676         case 't':
1677           {
1678 -           unsigned char newtab = optarg[0];
1679 -           if (! newtab)
1680 +           char *newtab;
1681 +           size_t newtablen;
1682 +           if (! optarg[0])
1683               error (EXIT_FAILURE, 0, _("empty tab"));
1684 -           if (optarg[1])
1685 +           newtab = xstrdup (optarg);
1686 +#if HAVE_MBRTOWC
1687 +           if (MB_CUR_MAX > 1)
1688 +             {
1689 +               mbstate_t state;
1690 +
1691 +               memset (&state, 0, sizeof (mbstate_t));
1692 +               newtablen = mbrtowc (NULL, newtab,
1693 +                                    strnlen (newtab, MB_LEN_MAX),
1694 +                                    &state);
1695 +               if (newtablen == (size_t) 0
1696 +                   || newtablen == (size_t) -1
1697 +                   || newtablen == (size_t) -2)
1698 +                 newtablen = 1;
1699 +             }
1700 +           else
1701 +#endif
1702 +             newtablen = 1;
1703 +               
1704 +           if (newtablen == 1 && newtab[1])
1705 +             {
1706 +               if (STREQ (newtab, "\\0"))
1707 +                 newtab[0] = '\0';
1708 +             }
1709 +           if (tab != NULL && strcmp (tab, newtab))
1710               {
1711 -               if (STREQ (optarg, "\\0"))
1712 -                 newtab = '\0';
1713 -               else
1714 -                 error (EXIT_FAILURE, 0, _("multi-character tab %s"),
1715 -                        quote (optarg));
1716 +               free (newtab);
1717 +               error (EXIT_FAILURE, 0, _("incompatible tabs"));
1718               }
1719 -           if (0 <= tab && tab != newtab)
1720 -             error (EXIT_FAILURE, 0, _("incompatible tabs"));
1721             tab = newtab;
1722 +           tablen = newtablen;
1723           }
1724           break;
1725  
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 @@
1730  
1731  #include <getopt.h>
1732  #include <sys/types.h>
1733 +
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
1740 +#endif
1741 +
1742 +/* Get MB_CUR_MAX.  */
1743 +#include <stdlib.h>
1744 +
1745 +/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>.  */
1746 +/* Get mbstate_t, mbrtowc(), wcwidth().  */
1747 +#if HAVE_WCHAR_H
1748 +# include <wchar.h>
1749 +#endif
1750 +
1751 +/* Get iswprint(). -- for wcwidth().  */
1752 +#if HAVE_WCTYPE_H
1753 +# include <wctype.h>
1754 +#endif
1755 +#if !defined iswprint && !HAVE_ISWPRINT
1756 +# define iswprint(wc) 1
1757 +#endif
1758 +
1759  #include "system.h"
1760  #include "error.h"
1761  #include "hard-locale.h"
1762 @@ -324,6 +350,18 @@
1763  #include "strftime.h"
1764  #include "xstrtol.h"
1765  
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)
1769 +#endif
1770 +
1771 +#ifndef HAVE_DECL_WCWIDTH
1772 +"this configure-time declaration test was not run"
1773 +#endif
1774 +#if !HAVE_DECL_WCWIDTH
1775 +extern int wcwidth ();
1776 +#endif
1777 +
1778  /* The official name of this program (e.g., no `g' prefix).  */
1779  #define PROGRAM_NAME "pr"
1780  
1781 @@ -416,7 +454,20 @@
1782  
1783  #define NULLCOL (COLUMN *)0
1784  
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);
1791 +
1792 +/* Functions for single byte locale. */
1793 +static void print_char_single (char c);
1794 +static int char_to_clump_single (char c);
1795 +
1796 +/* Functions for multibyte locale. */
1797 +static void print_char_multi (char c);
1798 +static int char_to_clump_multi (char c);
1799 +
1800  static bool read_line (COLUMN *p);
1801  static bool print_page (void);
1802  static bool print_stored (COLUMN *p);
1803 @@ -426,6 +477,7 @@
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,
1808                        int *number);
1809  void usage (int status);
1810  static void print_files (int number_of_files, char **av);
1811 @@ -440,7 +492,6 @@
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);
1819 @@ -455,7 +506,7 @@
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]. */
1823 -static char *buff;
1824 +static unsigned char *buff;
1825  
1826  /* Index of the position in buff where the next character
1827     will be stored. */
1828 @@ -559,7 +610,7 @@
1829  static bool untabify_input = false;
1830  
1831  /* (-e) The input tab character. */
1832 -static char input_tab_char = '\t';
1833 +static char input_tab_char[MB_LEN_MAX] = "\t";
1834  
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;
1839  
1840  /* (-i) The output tab character. */
1841 -static char output_tab_char = '\t';
1842 +static char output_tab_char[MB_LEN_MAX] = "\t";
1843 +
1844 +/* (-i) The byte length of output tab character. */
1845 +static int output_tab_char_length = 1;
1846  
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;
1851  
1852  /* (-n) Character which follows each line number. */
1853 -static char number_separator = '\t';
1854 +static char number_separator[MB_LEN_MAX] = "\t";
1855 +
1856 +/* (-n) The byte length of the character which follows each line number. */
1857 +static int number_separator_length = 1;
1858 +
1859 +/* (-n) The character width of the character which follows each line number. */
1860 +static int number_separator_width = 0;
1861  
1862  /* (-n) line counting starts with 1st line of input file (not with 1st
1863     line of 1st page printed). */
1864 @@ -696,6 +756,7 @@
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";
1871  
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);
1876 +
1877 +#if HAVE_MBRTOWC
1878 +  if (MB_CUR_MAX > 1)
1879 +    col_sep_width = mbswidth (col_sep_string, 0);
1880 +  else
1881 +#endif
1882 +    col_sep_width = col_sep_length;
1883  }
1884  
1885  int
1886 @@ -877,6 +945,21 @@
1887  
1888    atexit (close_stdout);
1889  
1890 +/* Define which functions are used, the ones for single byte locale or the ones
1891 +   for multibyte locale. */
1892 +#if HAVE_MBRTOWC
1893 +  if (MB_CUR_MAX > 1)
1894 +    {
1895 +      print_char = print_char_multi;
1896 +      char_to_clump = char_to_clump_multi;
1897 +    }
1898 +  else
1899 +#endif
1900 +    {
1901 +      print_char = print_char_single;
1902 +      char_to_clump = char_to_clump_single;
1903 +    }
1904 +
1905    n_files = 0;
1906    file_names = (argc > 1
1907                 ? xmalloc ((argc - 1) * sizeof (char *))
1908 @@ -949,8 +1032,12 @@
1909           break;
1910         case 'e':
1911           if (optarg)
1912 -           getoptarg (optarg, 'e', &input_tab_char,
1913 -                      &chars_per_input_tab);
1914 +           {
1915 +             int dummy_length, dummy_width;
1916 +
1917 +             getoptarg (optarg, 'e', input_tab_char, &dummy_length,
1918 +                        &dummy_width, &chars_per_input_tab);
1919 +           }
1920           /* Could check tab width > 0. */
1921           untabify_input = true;
1922           break;
1923 @@ -963,8 +1050,12 @@
1924           break;
1925         case 'i':
1926           if (optarg)
1927 -           getoptarg (optarg, 'i', &output_tab_char,
1928 -                      &chars_per_output_tab);
1929 +           {
1930 +             int dummy_width;
1931 +
1932 +             getoptarg (optarg, 'i', output_tab_char, &output_tab_char_length,
1933 +                        &dummy_width, &chars_per_output_tab);
1934 +           }
1935           /* Could check tab width > 0. */
1936           tabify_output = true;
1937           break;
1938 @@ -991,8 +1082,8 @@
1939         case 'n':
1940           numbered_lines = true;
1941           if (optarg)
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);
1946           break;
1947         case 'N':
1948           skip_count = false;
1949 @@ -1031,7 +1122,7 @@
1950           old_s = false;
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;
1956           if (optarg)
1957             separator_string (optarg);
1958 @@ -1188,10 +1279,45 @@
1959     a number. */
1960  
1961  static void
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)
1965  {
1966    if (!ISDIGIT (*arg))
1967 -    *character = *arg++;
1968 +    {
1969 +#ifdef HAVE_MBRTOWC
1970 +      if (MB_CUR_MAX > 1)      /* for multibyte locale. */
1971 +       {
1972 +         wchar_t wc;
1973 +         size_t mblength;
1974 +         int width;
1975 +         mbstate_t state = {'\0'};
1976 +
1977 +         mblength = mbrtowc (&wc, arg, strnlen(arg, MB_LEN_MAX), &state);
1978 +
1979 +         if (mblength == (size_t)-1 || mblength == (size_t)-2)
1980 +           {
1981 +             *character_length = 1;
1982 +             *character_width = 1;
1983 +           }
1984 +         else
1985 +           {
1986 +             *character_length = (mblength < 1) ? 1 : mblength;
1987 +             width = wcwidth (wc);
1988 +             *character_width = (width < 0) ? 0 : width;
1989 +           }
1990 +
1991 +         strncpy (character, arg, *character_length);
1992 +         arg += *character_length;
1993 +       }
1994 +      else                     /* for single byte locale. */
1995 +#endif
1996 +       {
1997 +         *character = *arg++;
1998 +         *character_length = 1;
1999 +         *character_width = 1;
2000 +       }
2001 +    }
2002 +
2003    if (*arg)
2004      {
2005        long int tmp_long;
2006 @@ -1256,7 +1382,7 @@
2007           else
2008             col_sep_string = column_separator;
2009  
2010 -         col_sep_length = 1;
2011 +         col_sep_length = col_sep_width = 1;
2012           use_col_separator = true;
2013         }
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);   */
2017  
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);
2023        else
2024 -       number_width = chars_per_number + 1;
2025 +       number_width = chars_per_number + number_separator_width;
2026  
2027        /* The number is part of the column width unless we are
2028          printing files in parallel. */
2029 @@ -1307,7 +1433,7 @@
2030      }
2031  
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;
2035  
2036    if (chars_per_column < 1)
2037      error (EXIT_FAILURE, 0, _("page width too narrow"));
2038 @@ -1432,7 +1558,7 @@
2039  
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;
2044  
2045    /* This loop takes care of all but the rightmost column. */
2046  
2047 @@ -1466,7 +1592,7 @@
2048         }
2049        else
2050         {
2051 -         h = h_next + col_sep_length;
2052 +         h = h_next + col_sep_width;
2053           h_next = h + chars_per_column;
2054         }
2055      }
2056 @@ -1756,9 +1882,9 @@
2057  align_column (COLUMN *p)
2058  {
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)
2062      {
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;
2066      }
2067  
2068 @@ -2029,13 +2155,13 @@
2069        /* May be too generous. */
2070        buff = X2REALLOC (buff, &buff_allocated);
2071      }
2072 -  buff[buff_current++] = c;
2073 +  buff[buff_current++] = (unsigned char) c;
2074  }
2075  
2076  static void
2077  add_line_number (COLUMN *p)
2078  {
2079 -  int i;
2080 +  int i, j;
2081    char *s;
2082    int left_cut;
2083  
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')
2090          {
2091            i = number_width - chars_per_number;
2092            while (i-- > 0)
2093             (p->char_func) (' ');
2094          }
2095        else
2096 -        (p->char_func) (number_separator);
2097 +       for (j = 0; j < number_separator_length; j++)
2098 +         (p->char_func) (number_separator[j]);
2099      }
2100    else
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. */
2104      {
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,
2111                           output_position);
2112      }
2113 @@ -2234,7 +2362,7 @@
2114    while (goal - h_old > 1
2115          && (h_new = POS_AFTER_TAB (chars_per_output_tab, h_old)) <= goal)
2116      {
2117 -      putchar (output_tab_char);
2118 +      fwrite (output_tab_char, sizeof(char), output_tab_char_length, stdout);
2119        h_old = h_new;
2120      }
2121    while (++h_old <= goal)
2122 @@ -2254,6 +2382,7 @@
2123  {
2124    char *s;
2125    int l = col_sep_length;
2126 +  int not_space_flag;
2127  
2128    s = col_sep_string;
2129  
2130 @@ -2267,6 +2396,7 @@
2131      {
2132        for (; separators_not_printed > 0; --separators_not_printed)
2133         {
2134 +         not_space_flag = 0;
2135           while (l-- > 0)
2136             {
2137               /* 3 types of sep_strings: spaces only, spaces and chars,
2138 @@ -2280,12 +2410,15 @@
2139                 }
2140               else
2141                 {
2142 +                 not_space_flag = 1;
2143                   if (spaces_not_printed > 0)
2144                     print_white_space ();
2145                   putchar (*s++);
2146 -                 ++output_position;
2147                 }
2148             }
2149 +         if (not_space_flag)
2150 +           output_position += col_sep_width;
2151 +
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. */
2157  
2158  static void
2159 -print_char (char c)
2160 +print_char_single (char c)
2161  {
2162    if (tabify_output)
2163      {
2164 @@ -2337,6 +2470,74 @@
2165    putchar (c);
2166  }
2167  
2168 +#ifdef HAVE_MBRTOWC
2169 +static void
2170 +print_char_multi (char c)
2171 +{
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;
2176 +  wchar_t wc;
2177 +  size_t mblength;
2178 +  int width;
2179 +
2180 +  if (tabify_output)
2181 +    {
2182 +      state_bak = state;
2183 +      mbc[mbc_pos++] = (unsigned char)c;
2184 +      mblength = mbrtowc (&wc, mbc, mbc_pos, &state);
2185 +
2186 +      while (mbc_pos > 0)
2187 +       {
2188 +         switch (mblength)
2189 +           {
2190 +           case (size_t)-2:
2191 +             state = state_bak;
2192 +             return;
2193 +
2194 +           case (size_t)-1:
2195 +             state = state_bak;
2196 +             ++output_position;
2197 +             putchar (mbc[0]);
2198 +             memmove (mbc, mbc + 1, MB_CUR_MAX - 1);
2199 +             --mbc_pos;
2200 +             break;
2201 +
2202 +           case 0:
2203 +             mblength = 1;
2204 +
2205 +           default:
2206 +             if (wc == L' ')
2207 +               {
2208 +                 memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength);
2209 +                 --mbc_pos;
2210 +                 ++spaces_not_printed;
2211 +                 return;
2212 +               }
2213 +             else if (spaces_not_printed > 0)
2214 +               print_white_space ();
2215 +
2216 +             /* Nonprintables are assumed to have width 0, except L'\b'. */
2217 +             if ((width = wcwidth (wc)) < 1)
2218 +               {
2219 +                 if (wc == L'\b')
2220 +                   --output_position;
2221 +               }
2222 +             else
2223 +               output_position += width;
2224 +
2225 +             fwrite (mbc, sizeof(char), mblength, stdout);
2226 +             memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength);
2227 +             mbc_pos -= mblength;
2228 +           }
2229 +       }
2230 +      return;
2231 +    }
2232 +  putchar (c);
2233 +}
2234 +#endif
2235 +
2236  /* Skip to page PAGE before printing.
2237     PAGE may be larger than total number of pages. */
2238  
2239 @@ -2517,9 +2718,9 @@
2240           align_empty_cols = false;
2241         }
2242  
2243 -      if (padding_not_printed - col_sep_length > 0)
2244 +      if (padding_not_printed - col_sep_width > 0)
2245         {
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;
2249         }
2250  
2251 @@ -2620,9 +2821,9 @@
2252         }
2253      }
2254  
2255 -  if (padding_not_printed - col_sep_length > 0)
2256 +  if (padding_not_printed - col_sep_width > 0)
2257      {
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;
2261      }
2262  
2263 @@ -2635,8 +2836,8 @@
2264    if (spaces_not_printed == 0)
2265      {
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;
2271      }
2272  
2273    return true;
2274 @@ -2655,7 +2856,7 @@
2275     number of characters is 1.) */
2276  
2277  static int
2278 -char_to_clump (char c)
2279 +char_to_clump_single (char c)
2280  {
2281    unsigned char uc = c;
2282    char *s = clump_buff;
2283 @@ -2665,10 +2866,10 @@
2284    int chars;
2285    int chars_per_c = 8;
2286  
2287 -  if (c == input_tab_char)
2288 +  if (c == input_tab_char[0])
2289      chars_per_c = chars_per_input_tab;
2290  
2291 -  if (c == input_tab_char || c == '\t')
2292 +  if (c == input_tab_char[0] || c == '\t')
2293      {
2294        width = TAB_WIDTH (chars_per_c, input_position);
2295  
2296 @@ -2739,6 +2940,154 @@
2297    return chars;
2298  }
2299  
2300 +#ifdef HAVE_MBRTOWC
2301 +static int
2302 +char_to_clump_multi (char c)
2303 +{
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;
2308 +  wchar_t wc;
2309 +  size_t mblength;
2310 +  int wc_width;
2311 +  register int *s = clump_buff;
2312 +  register int i, j;
2313 +  char esc_buff[4];
2314 +  int width;
2315 +  int chars;
2316 +  int chars_per_c = 8;
2317 +
2318 +  state_bak = state;
2319 +  mbc[mbc_pos++] = c;
2320 +  mblength = mbrtowc (&wc, mbc, mbc_pos, &state);
2321 +
2322 +  width = 0;
2323 +  chars = 0;
2324 +  while (mbc_pos > 0)
2325 +    {
2326 +      switch (mblength)
2327 +       {
2328 +       case (size_t)-2:
2329 +         state = state_bak;
2330 +         return 0;
2331 +
2332 +       case (size_t)-1:
2333 +         state = state_bak;
2334 +         mblength = 1;
2335 +
2336 +         if (use_esc_sequence || use_cntrl_prefix)
2337 +           {
2338 +             width = +4;
2339 +             chars = +4;
2340 +             *s++ = '\\';
2341 +             sprintf (esc_buff, "%03o", mbc[0]);
2342 +             for (i = 0; i <= 2; ++i)
2343 +               *s++ = (int) esc_buff[i];
2344 +           }
2345 +         else
2346 +           {
2347 +             width += 1;
2348 +             chars += 1;
2349 +             *s++ = mbc[0];
2350 +           }
2351 +         break;
2352 +
2353 +       case 0:
2354 +         mblength = 1;
2355 +               /* Fall through */
2356 +
2357 +       default:
2358 +         if (memcmp (mbc, input_tab_char, mblength) == 0)
2359 +           chars_per_c = chars_per_input_tab;
2360 +
2361 +         if (memcmp (mbc, input_tab_char, mblength) == 0 || c == '\t')
2362 +           {
2363 +             int  width_inc;
2364 +
2365 +             width_inc = TAB_WIDTH (chars_per_c, input_position);
2366 +             width += width_inc;
2367 +
2368 +             if (untabify_input)
2369 +               {
2370 +                 for (i = width_inc; i; --i)
2371 +                   *s++ = ' ';
2372 +                 chars += width_inc;
2373 +               }
2374 +             else
2375 +               {
2376 +                 for (i = 0; i <  mblength; i++)
2377 +                   *s++ = mbc[i];
2378 +                 chars += mblength;
2379 +               }
2380 +           }
2381 +         else if ((wc_width = wcwidth (wc)) < 1)
2382 +           {
2383 +             if (use_esc_sequence)
2384 +               {
2385 +                 for (i = 0; i < mblength; i++)
2386 +                   {
2387 +                     width += 4;
2388 +                     chars += 4;
2389 +                     *s++ = '\\';
2390 +                     sprintf (esc_buff, "%03o", c);
2391 +                     for (j = 0; j <= 2; ++j)
2392 +                       *s++ = (int) esc_buff[j];
2393 +                   }
2394 +               }
2395 +             else if (use_cntrl_prefix)
2396 +               {
2397 +                 if (wc < 0200)
2398 +                   {
2399 +                     width += 2;
2400 +                     chars += 2;
2401 +                     *s++ = '^';
2402 +                     *s++ = wc ^ 0100;
2403 +                   }
2404 +                 else
2405 +                   {
2406 +                     for (i = 0; i < mblength; i++)
2407 +                       {
2408 +                         width += 4;
2409 +                         chars += 4;
2410 +                         *s++ = '\\';
2411 +                         sprintf (esc_buff, "%03o", c);
2412 +                         for (j = 0; j <= 2; ++j)
2413 +                           *s++ = (int) esc_buff[j];
2414 +                       }
2415 +                   }
2416 +               }
2417 +             else if (wc == L'\b')
2418 +               {
2419 +                 width += -1;
2420 +                 chars += 1;
2421 +                 *s++ = c;
2422 +               }
2423 +             else
2424 +               {
2425 +                 width += 0;
2426 +                 chars += mblength;
2427 +                 for (i = 0; i < mblength; i++)
2428 +                   *s++ = mbc[i];
2429 +               }
2430 +           }
2431 +         else
2432 +           {
2433 +             width += wc_width;
2434 +             chars += mblength;
2435 +             for (i = 0; i < mblength; i++)
2436 +               *s++ = mbc[i];
2437 +           }
2438 +       }
2439 +      memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength);
2440 +      mbc_pos -= mblength;
2441 +    }
2442 +
2443 +  input_position += width;
2444 +  return chars;
2445 +}
2446 +#endif
2447 +
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.
2450  
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
2454 @@ -23,9 +23,18 @@
2455  
2456  #include <config.h>
2457  
2458 +#include <assert.h>
2459  #include <getopt.h>
2460  #include <sys/types.h>
2461  #include <signal.h>
2462 +#if HAVE_WCHAR_H
2463 +# include <wchar.h>
2464 +#endif
2465 +/* Get isw* functions. */
2466 +#if HAVE_WCTYPE_H
2467 +# include <wctype.h>
2468 +#endif
2469 +
2470  #include "system.h"
2471  #include "error.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;
2476  
2477 +static int force_general_numcompare = 0;
2478 +
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;
2484  #endif
2485  
2486  #define NONZERO(x) ((x) != 0)
2487  
2488 +/* get a multibyte character's byte length. */
2489 +#define GET_BYTELEN_OF_CHAR(LIM, PTR, MBLENGTH, STATE)                 \
2490 +  do                                                                   \
2491 +    {                                                                  \
2492 +      wchar_t wc;                                                      \
2493 +      mbstate_t state_bak;                                             \
2494 +                                                                       \
2495 +      state_bak = STATE;                                               \
2496 +      mblength = mbrtowc (&wc, PTR, LIM - PTR, &STATE);                        \
2497 +                                                                       \
2498 +      switch (MBLENGTH)                                                        \
2499 +       {                                                               \
2500 +       case (size_t)-1:                                                \
2501 +       case (size_t)-2:                                                \
2502 +         STATE = state_bak;                                            \
2503 +               /* Fall through. */                                     \
2504 +       case 0:                                                         \
2505 +         MBLENGTH = 1;                                                 \
2506 +      }                                                                        \
2507 +    }                                                                  \
2508 +  while (0)
2509 +
2510  /* The kind of blanks for '-b' to skip in various options. */
2511  enum blanktype { bl_start, bl_end, bl_both };
2512  
2513 @@ -243,13 +276,11 @@
2514     they were read if all keys compare equal.  */
2515  static bool stable;
2516  
2517 -/* If TAB has this value, blanks separate fields.  */
2518 -enum { TAB_DEFAULT = CHAR_MAX + 1 };
2519 -
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
2523     character. */
2524 -static int tab = TAB_DEFAULT;
2525 +static char tab[MB_LEN_MAX + 1];
2526 +static size_t tab_length = 0;
2527  
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;
2533  
2534 +/* Function pointers. */
2535 +static void
2536 +(*inittables) (void);
2537 +static char *
2538 +(*begfield) (const struct line*, const struct keyfield *);
2539 +static char *
2540 +(*limfield) (const struct line*, const struct keyfield *);
2541 +static int
2542 +(*getmonth) (char const *, size_t);
2543 +static int
2544 +(*keycompare) (const struct line *, const struct line *);
2545 +static int
2546 +(*numcompare) (const char *, const char *);
2547 +
2548 +/* Test for white space multibyte character.
2549 +   Set LENGTH the byte length of investigated multibyte character. */
2550 +#if HAVE_MBRTOWC
2551 +static int
2552 +ismbblank (const char *str, size_t len, size_t *length)
2553 +{
2554 +  size_t mblength;
2555 +  wchar_t wc;
2556 +  mbstate_t state;
2557 +
2558 +  memset (&state, '\0', sizeof(mbstate_t));
2559 +  mblength = mbrtowc (&wc, str, len, &state);
2560 +
2561 +  if (mblength == (size_t)-1 || mblength == (size_t)-2)
2562 +    {
2563 +      *length = 1;
2564 +      return 0;
2565 +    }
2566 +
2567 +  *length = (mblength < 1) ? 1 : mblength;
2568 +  return iswblank (wc);
2569 +}
2570 +#endif
2571 +
2572  /* Clean up any remaining temporary files.  */
2573  
2574  static void
2575 @@ -561,7 +630,7 @@
2576    free (node);
2577  }
2578  
2579 -#if HAVE_NL_LANGINFO
2580 +#if HAVE_LANGINFO_CODESET
2581  
2582  static int
2583  struct_month_cmp (const void *m1, const void *m2)
2584 @@ -576,7 +645,7 @@
2585  /* Initialize the character class tables. */
2586  
2587  static void
2588 -inittables (void)
2589 +inittables_uni (void)
2590  {
2591    size_t i;
2592  
2593 @@ -588,7 +657,7 @@
2594        fold_toupper[i] = toupper (i);
2595      }
2596  
2597 -#if HAVE_NL_LANGINFO
2598 +#if HAVE_LANGINFO_CODESET
2599    /* If we're not in the "C" locale, read different names for months.  */
2600    if (hard_LC_TIME)
2601      {
2602 @@ -614,6 +683,64 @@
2603  #endif
2604  }
2605  
2606 +#if HAVE_MBRTOWC
2607 +static void
2608 +inittables_mb (void)
2609 +{
2610 +  int i, j, k, l;
2611 +  char *name, *s;
2612 +  size_t s_len, mblength;
2613 +  char mbc[MB_LEN_MAX];
2614 +  wchar_t wc, pwc;
2615 +  mbstate_t state_mb, state_wc;
2616 +
2617 +  for (i = 0; i < MONTHS_PER_YEAR; i++)
2618 +    {
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;
2623 +
2624 +      memset (&state_mb, '\0', sizeof (mbstate_t));
2625 +      memset (&state_wc, '\0', sizeof (mbstate_t));
2626 +
2627 +      for (j = 0; j < s_len;)
2628 +       {
2629 +         if (!ismbblank (s + j, s_len - j, &mblength))
2630 +           break;
2631 +         j += mblength;
2632 +       }
2633 +
2634 +      for (k = 0; j < s_len;)
2635 +       {
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)
2639 +           break;
2640 +
2641 +         pwc = towupper (wc);
2642 +         if (pwc == wc)
2643 +           {
2644 +             memcpy (mbc, s + j, mblength);
2645 +             j += mblength;
2646 +           }
2647 +         else
2648 +           {
2649 +             j += mblength;
2650 +             mblength = wcrtomb (mbc, pwc, &state_wc);
2651 +             assert (mblength != (size_t)0 && mblength != (size_t)-1);
2652 +           }
2653 +
2654 +         for (l = 0; l < mblength; l++)
2655 +           name[k++] = mbc[l];
2656 +       }
2657 +      name[k] = '\0';
2658 +    }
2659 +  qsort ((void *) monthtab, MONTHS_PER_YEAR,
2660 +      sizeof (struct month), struct_month_cmp);
2661 +}
2662 +#endif
2663 +
2664  /* Specify the amount of main memory to use when sorting.  */
2665  static void
2666  specify_sort_size (char const *s)
2667 @@ -824,7 +951,7 @@
2668     by KEY in LINE. */
2669  
2670  static char *
2671 -begfield (const struct line *line, const struct keyfield *key)
2672 +begfield_uni (const struct line *line, const struct keyfield *key)
2673  {
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
2678       is absent.  */
2679  
2680 -  if (tab != TAB_DEFAULT)
2681 +  if (tab_length)
2682      while (ptr < lim && sword--)
2683        {
2684 -       while (ptr < lim && *ptr != tab)
2685 +       while (ptr < lim && *ptr != tab[0])
2686           ++ptr;
2687         if (ptr < lim)
2688           ++ptr;
2689 @@ -865,11 +992,70 @@
2690    return ptr;
2691  }
2692  
2693 +#if HAVE_MBRTOWC
2694 +static char *
2695 +begfield_mb (const struct line *line, const struct keyfield *key)
2696 +{
2697 +  int i;
2698 +  char *ptr = line->text, *lim = ptr + line->length - 1;
2699 +  size_t sword = key->sword;
2700 +  size_t schar = key->schar;
2701 +  size_t mblength;
2702 +  mbstate_t state;
2703 +
2704 +  memset (&state, '\0', sizeof(mbstate_t));
2705 +
2706 +  if (tab_length)
2707 +    while (ptr < lim && sword--)
2708 +      {
2709 +       while (ptr < lim && memcmp (ptr, tab, tab_length) != 0)
2710 +         {
2711 +           GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
2712 +           ptr += mblength;
2713 +         }
2714 +       if (ptr < lim)
2715 +         {
2716 +           GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
2717 +           ptr += mblength;
2718 +         }
2719 +      }
2720 +  else
2721 +    while (ptr < lim && sword--)
2722 +      {
2723 +       while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength))
2724 +         ptr += mblength;
2725 +       if (ptr < lim)
2726 +         {
2727 +           GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
2728 +           ptr += mblength;
2729 +         }
2730 +       while (ptr < lim && !ismbblank (ptr, lim - ptr, &mblength))
2731 +         ptr += mblength;
2732 +      }
2733 +
2734 +  if (key->skipsblanks)
2735 +    while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength))
2736 +      ptr += mblength;
2737 +
2738 +  for (i = 0; i < schar; i++)
2739 +    {
2740 +      GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
2741 +
2742 +      if (ptr + mblength > lim)
2743 +       break;
2744 +      else
2745 +       ptr += mblength;
2746 +    }
2747 +
2748 +  return ptr;
2749 +}
2750 +#endif
2751 +
2752  /* Return the limit of (a pointer to the first character after) the field
2753     in LINE specified by KEY. */
2754  
2755  static char *
2756 -limfield (const struct line *line, const struct keyfield *key)
2757 +limfield_uni (const struct line *line, const struct keyfield *key)
2758  {
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)
2766 +  if (tab_length)
2767      while (ptr < lim && eword--)
2768        {
2769 -       while (ptr < lim && *ptr != tab)
2770 +       while (ptr < lim && *ptr != tab[0])
2771           ++ptr;
2772         if (ptr < lim && (eword | echar))
2773           ++ptr;
2774 @@ -931,10 +1117,10 @@
2775       */
2776  
2777    /* Make LIM point to the end of (one byte past) the current field.  */
2778 -  if (tab != TAB_DEFAULT)
2779 +  if (tab_length)
2780      {
2781        char *newlim;
2782 -      newlim = memchr (ptr, tab, lim - ptr);
2783 +      newlim = memchr (ptr, tab[0], lim - ptr);
2784        if (newlim)
2785         lim = newlim;
2786      }
2787 @@ -967,6 +1153,107 @@
2788    return ptr;
2789  }
2790  
2791 +#if HAVE_MBRTOWC
2792 +static char *
2793 +limfield_mb (const struct line *line, const struct keyfield *key)
2794 +{
2795 +  char *ptr = line->text, *lim = ptr + line->length - 1;
2796 +  size_t eword = key->eword, echar = key->echar;
2797 +  int i;
2798 +  size_t mblength;
2799 +  mbstate_t state;
2800 +
2801 +  memset (&state, '\0', sizeof(mbstate_t));
2802 +
2803 +  if (tab_length)
2804 +    while (ptr < lim && eword--)
2805 +      {
2806 +       while (ptr < lim && memcmp (ptr, tab, tab_length) != 0)
2807 +         {
2808 +           GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
2809 +           ptr += mblength;
2810 +         }
2811 +       if (ptr < lim && (eword | echar))
2812 +         {
2813 +           GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
2814 +           ptr += mblength;
2815 +         }
2816 +      }
2817 +  else
2818 +    while (ptr < lim && eword--)
2819 +      {
2820 +       while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength))
2821 +         ptr += mblength;
2822 +       if (ptr < lim)
2823 +         {
2824 +           GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
2825 +           ptr += mblength;
2826 +         }
2827 +       while (ptr < lim && !ismbblank (ptr, lim - ptr, &mblength))
2828 +         ptr += mblength;
2829 +      }
2830 +
2831 +
2832 +# ifdef POSIX_UNSPECIFIED
2833 +  /* Make LIM point to the end of (one byte past) the current field.  */
2834 +  if (tab_length)
2835 +    {
2836 +      char *newlim, *p;
2837 +
2838 +      newlim = NULL;
2839 +      for (p = ptr; p < lim;)
2840 +       {
2841 +         if (memcmp (p, tab, tab_length) == 0)
2842 +           {
2843 +             newlim = p;
2844 +             break;
2845 +           }
2846 +
2847 +         GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
2848 +         p += mblength;
2849 +       }
2850 +    }
2851 +  else
2852 +    {
2853 +      char *newlim;
2854 +      newlim = ptr;
2855 +
2856 +      while (newlim < lim && ismbblank (newlim, lim - newlim, &mblength))
2857 +       newlim += mblength;
2858 +      if (ptr < lim)
2859 +       {
2860 +         GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
2861 +         ptr += mblength;
2862 +       }
2863 +      while (newlim < lim && !ismbblank (newlim, lim - newlim, &mblength))
2864 +       newlim += mblength;
2865 +      lim = newlim;
2866 +    }
2867 +# endif
2868 +
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))
2873 +      ptr += mblength;
2874 +
2875 +  memset (&state, '\0', sizeof(mbstate_t));
2876 +
2877 +  /* Advance PTR by ECHAR (if possible), but no further than LIM.  */
2878 +  for (i = 0; i < echar; i++)
2879 +    {
2880 +      GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
2881 +
2882 +      if (ptr + mblength > lim)
2883 +       break;
2884 +      else
2885 +       ptr += mblength;
2886 +    }
2887 +
2888 +  return ptr;
2889 +}
2890 +#endif
2891 +
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 @@
2896     hideously fast. */
2897  
2898  static int
2899 -numcompare (const char *a, const char *b)
2900 +numcompare_uni (const char *a, const char *b)
2901  {
2902    while (blanks[to_uchar (*a)])
2903      a++;
2904 @@ -1093,6 +1380,25 @@
2905    return strnumcmp (a, b, decimal_point, thousands_sep);
2906  }
2907  
2908 +#if HAVE_MBRTOWC
2909 +static int
2910 +numcompare_mb (const char *a, const char *b)
2911 +{
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))
2915 +    {
2916 +      a += mblength;
2917 +      len -= mblength;
2918 +    }
2919 +  len = strlen (b); /* okay for UTF-8 */
2920 +  while (*b && ismbblank (b, len > MB_CUR_MAX ? MB_CUR_MAX : len, &mblength))
2921 +    b += mblength;
2922 +
2923 +  return strnumcmp (a, b, decimal_point, thousands_sep);
2924 +}
2925 +#endif /* HAV_EMBRTOWC */
2926 +
2927  static int
2928  general_numcompare (const char *sa, const char *sb)
2929  {
2930 @@ -1126,7 +1432,7 @@
2931     Return 0 if the name in S is not recognized.  */
2932  
2933  static int
2934 -getmonth (char const *month, size_t len)
2935 +getmonth_uni (char const *month, size_t len)
2936  {
2937    size_t lo = 0;
2938    size_t hi = MONTHS_PER_YEAR;
2939 @@ -1281,11 +1587,79 @@
2940    return diff;
2941  }
2942  
2943 +#if HAVE_MBRTOWC
2944 +static int
2945 +getmonth_mb (const char *s, size_t len)
2946 +{
2947 +  char *month;
2948 +  register size_t i;
2949 +  register int lo = 0, hi = MONTHS_PER_YEAR, result;
2950 +  char *tmp;
2951 +  size_t wclength, mblength;
2952 +  const char **pp;
2953 +  const wchar_t **wpp;
2954 +  wchar_t *month_wcs;
2955 +  mbstate_t state;
2956 +
2957 +  while (len > 0 && ismbblank (s, len, &mblength))
2958 +    {
2959 +      s += mblength;
2960 +      len -= mblength;
2961 +    }
2962 +
2963 +  if (len == 0)
2964 +    return 0;
2965 +
2966 +  month = (char *) alloca (len + 1);
2967 +
2968 +  tmp = (char *) alloca (len + 1);
2969 +  memcpy (tmp, s, len);
2970 +  tmp[len] = '\0';
2971 +  pp = (const char **)&tmp;
2972 +  month_wcs = (wchar_t *) alloca ((len + 1) * sizeof (wchar_t));
2973 +  memset (&state, '\0', sizeof(mbstate_t));
2974 +
2975 +  wclength = mbsrtowcs (month_wcs, pp, len + 1, &state);
2976 +  assert (wclength != (size_t)-1 && *pp == NULL);
2977 +
2978 +  for (i = 0; i < wclength; i++)
2979 +    {
2980 +      month_wcs[i] = towupper(month_wcs[i]);
2981 +      if (iswblank (month_wcs[i]))
2982 +       {
2983 +         month_wcs[i] = L'\0';
2984 +         break;
2985 +       }
2986 +    }
2987 +
2988 +  wpp = (const wchar_t **)&month_wcs;
2989 +
2990 +  mblength = wcsrtombs (month, wpp, len + 1, &state);
2991 +  assert (mblength != (-1) && *wpp == NULL);
2992 +
2993 +  do
2994 +    {
2995 +      int ix = (lo + hi) / 2;
2996 +
2997 +      if (strncmp (month, monthtab[ix].name, strlen (monthtab[ix].name)) < 0)
2998 +       hi = ix;
2999 +      else
3000 +       lo = ix;
3001 +    }
3002 +  while (hi - lo > 1);
3003 +
3004 +  result = (!strncmp (month, monthtab[lo].name, strlen (monthtab[lo].name))
3005 +      ? monthtab[lo].val : 0);
3006 +
3007 +  return result;
3008 +}
3009 +#endif
3010 +
3011  /* Compare two lines A and B trying every key in sequence until there
3012     are no more keys or a difference is found. */
3013  
3014  static int
3015 -keycompare (const struct line *a, const struct line *b)
3016 +keycompare_uni (const struct line *a, const struct line *b)
3017  {
3018    struct keyfield const *key = keylist;
3019  
3020 @@ -1458,6 +1832,177 @@
3021    return key->reverse ? -diff : diff;
3022  }
3023  
3024 +#if HAVE_MBRTOWC
3025 +static int
3026 +keycompare_mb (const struct line *a, const struct line *b)
3027 +{
3028 +  struct keyfield *key = keylist;
3029 +
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;
3036 +
3037 +  size_t mblength_a, mblength_b;
3038 +  wchar_t wc_a, wc_b;
3039 +  mbstate_t state_a, state_b;
3040 +
3041 +  int diff;
3042 +
3043 +  memset (&state_a, '\0', sizeof(mbstate_t));
3044 +  memset (&state_b, '\0', sizeof(mbstate_t));
3045 +
3046 +  for (;;)
3047 +    {
3048 +      unsigned char *translate = (unsigned char *) key->translate;
3049 +      bool const *ignore = key->ignore;
3050 +
3051 +      /* Find the lengths. */
3052 +      size_t lena = lima <= texta ? 0 : lima - texta;
3053 +      size_t lenb = limb <= textb ? 0 : limb - textb;
3054 +
3055 +      /* Actually compare the fields. */
3056 +      if (key->numeric | key->general_numeric)
3057 +       {
3058 +         char savea = *lima, saveb = *limb;
3059 +
3060 +         *lima = *limb = '\0';
3061 +         if (force_general_numcompare)
3062 +           diff = general_numcompare (texta, textb);
3063 +         else
3064 +           diff = ((key->numeric ? numcompare : general_numcompare)
3065 +               (texta, textb));
3066 +         *lima = savea, *limb = saveb;
3067 +       }
3068 +      else if (key->month)
3069 +       diff = getmonth (texta, lena) - getmonth (textb, lenb);
3070 +      else
3071 +       {
3072 +         if (ignore || translate)
3073 +           {
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;
3077 +             size_t i, j;
3078 +
3079 +             /* Ignore and/or translate chars before comparing.  */
3080 +# define IGNORE_CHARS(NEW_LEN, LEN, TEXT, COPY, WC, MBLENGTH, STATE)   \
3081 +  do                                                                   \
3082 +    {                                                                  \
3083 +      wchar_t uwc;                                                     \
3084 +      char mbc[MB_LEN_MAX];                                            \
3085 +      mbstate_t state_wc;                                              \
3086 +                                                                       \
3087 +      for (NEW_LEN = i = 0; i < LEN;)                                  \
3088 +       {                                                               \
3089 +         mbstate_t state_bak;                                          \
3090 +                                                                       \
3091 +         state_bak = STATE;                                            \
3092 +         MBLENGTH = mbrtowc (&WC, TEXT + i, LEN - i, &STATE);          \
3093 +                                                                       \
3094 +         if (MBLENGTH == (size_t)-2 || MBLENGTH == (size_t)-1          \
3095 +             || MBLENGTH == 0)                                         \
3096 +           {                                                           \
3097 +             if (MBLENGTH == (size_t)-2 || MBLENGTH == (size_t)-1)     \
3098 +               STATE = state_bak;                                      \
3099 +             if (!ignore)                                              \
3100 +               COPY[NEW_LEN++] = TEXT[i++];                            \
3101 +             continue;                                                 \
3102 +           }                                                           \
3103 +                                                                       \
3104 +         if (ignore)                                                   \
3105 +           {                                                           \
3106 +             if ((ignore == nonprinting && !iswprint (WC))             \
3107 +                  || (ignore == nondictionary                          \
3108 +                      && !iswalnum (WC) && !iswblank (WC)))            \
3109 +               {                                                       \
3110 +                 i += MBLENGTH;                                        \
3111 +                 continue;                                             \
3112 +               }                                                       \
3113 +           }                                                           \
3114 +                                                                       \
3115 +         if (translate)                                                \
3116 +           {                                                           \
3117 +                                                                       \
3118 +             uwc = towupper(WC);                                       \
3119 +             if (WC == uwc)                                            \
3120 +               {                                                       \
3121 +                 memcpy (mbc, TEXT + i, MBLENGTH);                     \
3122 +                 i += MBLENGTH;                                        \
3123 +               }                                                       \
3124 +             else                                                      \
3125 +               {                                                       \
3126 +                 i += MBLENGTH;                                        \
3127 +                 WC = uwc;                                             \
3128 +                 memset (&state_wc, '\0', sizeof (mbstate_t));         \
3129 +                                                                       \
3130 +                 MBLENGTH = wcrtomb (mbc, WC, &state_wc);              \
3131 +                 assert (MBLENGTH != (size_t)-1 && MBLENGTH != 0);     \
3132 +               }                                                       \
3133 +                                                                       \
3134 +             for (j = 0; j < MBLENGTH; j++)                            \
3135 +               COPY[NEW_LEN++] = mbc[j];                               \
3136 +           }                                                           \
3137 +         else                                                          \
3138 +           for (j = 0; j < MBLENGTH; j++)                              \
3139 +             COPY[NEW_LEN++] = TEXT[i++];                              \
3140 +       }                                                               \
3141 +      COPY[NEW_LEN] = '\0';                                            \
3142 +    }                                                                  \
3143 +  while (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);
3149 +           }
3150 +         else if (lena == 0)
3151 +           diff = - NONZERO (lenb);
3152 +         else if (lenb == 0)
3153 +           goto greater;
3154 +         else
3155 +           diff = xmemcoll (texta, lena, textb, lenb);
3156 +       }
3157 +
3158 +      if (diff)
3159 +       goto not_equal;
3160 +
3161 +      key = key->next;
3162 +      if (! key)
3163 +       break;
3164 +
3165 +      /* Find the beginning and limit of the next field.  */
3166 +      if (key->eword != -1)
3167 +       lima = limfield (a, key), limb = limfield (b, key);
3168 +      else
3169 +       lima = a->text + a->length - 1, limb = b->text + b->length - 1;
3170 +
3171 +      if (key->sword != -1)
3172 +       texta = begfield (a, key), textb = begfield (b, key);
3173 +      else
3174 +       {
3175 +         texta = a->text, textb = b->text;
3176 +         if (key->skipsblanks)
3177 +           {
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;
3182 +           }
3183 +       }
3184 +    }
3185 +
3186 +  return 0;
3187 +
3188 +greater:
3189 +  diff = 1;
3190 +not_equal:
3191 +  return key->reverse ? -diff : diff;
3192 +}
3193 +#endif
3194 +
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. */
3197  
3198 @@ -2307,7 +2852,7 @@
3199    atexit (close_stdout);
3200  
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);
3205  #endif
3206  
3207 @@ -2328,6 +2873,27 @@
3208        thousands_sep = -1;
3209    }
3210  
3211 +#if HAVE_MBRTOWC
3212 +  if (MB_CUR_MAX > 1)
3213 +    {
3214 +      inittables = inittables_mb;
3215 +      begfield = begfield_mb;
3216 +      limfield = limfield_mb;
3217 +      getmonth = getmonth_mb;
3218 +      keycompare = keycompare_mb;
3219 +      numcompare = numcompare_mb;
3220 +    }
3221 +  else
3222 +#endif
3223 +    {
3224 +      inittables = inittables_uni;
3225 +      begfield = begfield_uni;
3226 +      limfield = limfield_uni;
3227 +      getmonth = getmonth_uni;
3228 +      keycompare = keycompare_uni;
3229 +      numcompare = numcompare_uni;
3230 +    }
3231 +
3232    have_read_stdin = false;
3233    inittables ();
3234  
3235 @@ -2542,13 +3108,35 @@
3236  
3237         case 't':
3238           {
3239 -           char newtab = optarg[0];
3240 -           if (! newtab)
3241 +           char newtab[MB_LEN_MAX + 1];
3242 +           size_t newtab_length = 1;
3243 +           strncpy (newtab, optarg, MB_LEN_MAX);
3244 +           if (! newtab[0])
3245               error (SORT_FAILURE, 0, _("empty tab"));
3246 -           if (optarg[1])
3247 +#if HAVE_MBRTOWC
3248 +           if (MB_CUR_MAX > 1)
3249 +             {
3250 +               wchar_t wc;
3251 +               mbstate_t state;
3252 +               size_t i;
3253 +
3254 +               memset (&state, '\0', sizeof (mbstate_t));
3255 +               newtab_length = mbrtowc (&wc, newtab, strnlen (newtab,
3256 +                                                              MB_LEN_MAX),
3257 +                                        &state);
3258 +               switch (newtab_length)
3259 +                 {
3260 +                 case (size_t) -1:
3261 +                 case (size_t) -2:
3262 +                 case 0:
3263 +                   newtab_length = 1;
3264 +                 }
3265 +             }
3266 +#endif
3267 +           if (newtab_length == 1 && optarg[1])
3268               {
3269                 if (STREQ (optarg, "\\0"))
3270 -                 newtab = '\0';
3271 +                 newtab[0] = '\0';
3272                 else
3273                   {
3274                     /* Provoke with `sort -txx'.  Complain about
3275 @@ -2559,9 +3147,12 @@
3276                            quote (optarg));
3277                   }
3278               }
3279 -           if (tab != TAB_DEFAULT && tab != newtab)
3280 +           if (tab_length
3281 +               && (tab_length != newtab_length
3282 +                   || memcmp (tab, newtab, tab_length) != 0))
3283               error (SORT_FAILURE, 0, _("incompatible tabs"));
3284 -           tab = newtab;
3285 +           memcpy (tab, newtab, newtab_length);
3286 +           tab_length = newtab_length;
3287           }
3288           break;
3289  
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
3293 @@ -39,11 +39,28 @@
3294  #include <stdio.h>
3295  #include <getopt.h>
3296  #include <sys/types.h>
3297 +
3298 +/* Get mbstate_t, mbrtowc(), wcwidth(). */
3299 +#if HAVE_WCHAR_H
3300 +# include <wchar.h>
3301 +#endif
3302 +
3303  #include "system.h"
3304  #include "error.h"
3305  #include "quote.h"
3306  #include "xstrndup.h"
3307  
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
3312 +#endif
3313 +
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)
3317 +#endif
3318 +
3319  /* The official name of this program (e.g., no `g' prefix).  */
3320  #define PROGRAM_NAME "unexpand"
3321  
3322 @@ -110,6 +127,208 @@
3323    {NULL, 0, NULL, 0}
3324  };
3325  
3326 +static FILE *next_file (FILE *fp);
3327 +
3328 +#if HAVE_MBRTOWC
3329 +static void
3330 +unexpand_multibyte (void)
3331 +{
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. */
3342 +
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. */
3350 +
3351 +  fp = next_file ((FILE *) NULL);
3352 +  if (fp == NULL)
3353 +    return;
3354 +
3355 +  memset (&o_state, '\0', sizeof(mbstate_t));
3356 +  memset (&i_state, '\0', sizeof(mbstate_t));
3357 +
3358 +  for (;;)
3359 +    {
3360 +      if (buflen < MB_LEN_MAX && !feof(fp) && !ferror(fp))
3361 +       {
3362 +         memmove (buf, bufpos, buflen);
3363 +         buflen += fread (buf + buflen, sizeof(char), BUFSIZ, fp);
3364 +         bufpos = buf;
3365 +       }
3366 +
3367 +      /* Get a wide character. */
3368 +      if (buflen < 1)
3369 +       {
3370 +         mblength = 1;
3371 +         wc = WEOF;
3372 +       }
3373 +      else
3374 +       {
3375 +         i_state_bak = i_state;
3376 +         mblength = mbrtowc ((wchar_t *)&wc, bufpos, buflen, &i_state);
3377 +       }
3378 +
3379 +      if (mblength == (size_t)-1 || mblength == (size_t)-2)
3380 +       {
3381 +         i_state = i_state_bak;
3382 +         wc = L'\0';
3383 +       }
3384 +
3385 +      if (wc == L' ' && convert && column < INT_MAX)
3386 +       {
3387 +         ++pending;
3388 +         ++column;
3389 +       }
3390 +      else if (wc == L'\t' && convert)
3391 +       {
3392 +         if (tab_size == 0)
3393 +           {
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])
3398 +               tab_index++;
3399 +             next_tab_column = tab_list[tab_index];
3400 +             if (tab_index < first_free_tab - 1)
3401 +               tab_index++;
3402 +             if (column >= next_tab_column)
3403 +               {
3404 +                 convert = 0;  /* Ran out of tab stops. */
3405 +                 goto flush_pend_mb;
3406 +               }
3407 +           }
3408 +         else
3409 +           {
3410 +             next_tab_column = column + tab_size - column % tab_size;
3411 +           }
3412 +         pending += next_tab_column - column;
3413 +         column = next_tab_column;
3414 +       }
3415 +      else
3416 +       {
3417 +flush_pend_mb:
3418 +         /* Flush pending spaces.  Print as many tabs as possible,
3419 +            then print the rest as spaces. */
3420 +         if (pending == 1)
3421 +           {
3422 +             putchar (' ');
3423 +             pending = 0;
3424 +           }
3425 +         column -= pending;
3426 +         while (pending > 0)
3427 +           {
3428 +             if (tab_size == 0)
3429 +               {
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++;
3438 +               }
3439 +             else
3440 +               {
3441 +                 next_tab_column =
3442 +                   column + tab_size - column % tab_size;
3443 +               }
3444 +             if (next_tab_column - column <= pending)
3445 +               {
3446 +                 putchar ('\t');
3447 +                 pending -= next_tab_column - column;
3448 +                 column = next_tab_column;
3449 +               }
3450 +             else
3451 +               {
3452 +                 --print_tab_index;
3453 +                 column += pending;
3454 +                 while (pending != 0)
3455 +                   {
3456 +                     putchar (' ');
3457 +                     pending--;
3458 +                   }
3459 +               }
3460 +           }
3461 +
3462 +         if (wc == WEOF)
3463 +           {
3464 +             fp = next_file (fp);
3465 +             if (fp == NULL)
3466 +               break;          /* No more files. */
3467 +             else
3468 +               {
3469 +                 memset (&i_state, '\0', sizeof(mbstate_t));
3470 +                 continue;
3471 +               }
3472 +           }
3473 +
3474 +         if (mblength == (size_t)-1 || mblength == (size_t)-2)
3475 +           {
3476 +             if (convert)
3477 +               {
3478 +                 ++column;
3479 +                 if (convert_entire_line == 0)
3480 +                   convert = 0;
3481 +               }
3482 +             mblength = 1;
3483 +             putchar (buf[0]);
3484 +           }
3485 +         else if (mblength == 0)
3486 +           {
3487 +             if (convert && convert_entire_line == 0)
3488 +               convert = 0;
3489 +             mblength = 1;
3490 +             putchar ('\0');
3491 +           }
3492 +         else
3493 +           {
3494 +             if (convert)
3495 +               {
3496 +                 if (wc == L'\b')
3497 +                   {
3498 +                     if (column > 0)
3499 +                       --column;
3500 +                   }
3501 +                 else
3502 +                   {
3503 +                     int width;            /* The width of WC. */
3504 +
3505 +                     width = wcwidth (wc);
3506 +                     column += (width > 0) ? width : 0;
3507 +                     if (convert_entire_line == 0)
3508 +                       convert = 0;
3509 +                   }
3510 +               }
3511 +
3512 +             if (wc == L'\n')
3513 +               {
3514 +                 tab_index = print_tab_index = 0;
3515 +                 column = pending = 0;
3516 +                 convert = 1;
3517 +               }
3518 +             fwrite (bufpos, sizeof(char), mblength, stdout);
3519 +           }
3520 +       }
3521 +      buflen -= mblength;
3522 +      bufpos += mblength;
3523 +    }
3524 +}
3525 +#endif
3526 +
3527 +
3528  void
3529  usage (int status)
3530  {
3531 @@ -531,7 +750,12 @@
3532  
3533    file_list = (optind < argc ? &argv[optind] : stdin_argv);
3534  
3535 -  unexpand ();
3536 +#if HAVE_MBRTOWC
3537 +  if (MB_CUR_MAX > 1)
3538 +    unexpand_multibyte ();
3539 +  else
3540 +#endif
3541 +    unexpand ();
3542  
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
3548 @@ -23,6 +23,16 @@
3549  #include <getopt.h>
3550  #include <sys/types.h>
3551  
3552 +/* Get mbstate_t, mbrtowc(). */
3553 +#if HAVE_WCHAR_H
3554 +# include <wchar.h>
3555 +#endif
3556 +
3557 +/* Get isw* functions. */
3558 +#if HAVE_WCTYPE_H
3559 +# include <wctype.h>
3560 +#endif
3561 +
3562  #include "system.h"
3563  #include "argmatch.h"
3564  #include "linebuffer.h"
3565 @@ -32,7 +42,19 @@
3566  #include "quote.h"
3567  #include "xmemcoll.h"
3568  #include "xstrtol.h"
3569 -#include "memcasecmp.h"
3570 +#include "xmemcoll.h"
3571 +
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
3576 +#endif
3577 +
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)
3581 +#endif
3582 +
3583  
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;
3589  
3590 +/* Function pointers. */
3591 +static char *
3592 +(*find_field) (struct linebuffer *line);
3593 +
3594  static struct option const longopts[] =
3595  {
3596    {"count", no_argument, NULL, 'c'},
3597 @@ -189,7 +215,7 @@
3598     return a pointer to the beginning of the line's field to be compared. */
3599  
3600  static char *
3601 -find_field (const struct linebuffer *line)
3602 +find_field_uni (struct linebuffer *line)
3603  {
3604    size_t count;
3605    char *lp = line->buffer;
3606 @@ -210,6 +236,83 @@
3607    return lp + i;
3608  }
3609  
3610 +#if HAVE_MBRTOWC
3611 +
3612 +# define MBCHAR_TO_WCHAR(WC, MBLENGTH, LP, POS, SIZE, STATEP, CONVFAIL)  \
3613 +  do                                                                   \
3614 +    {                                                                  \
3615 +      mbstate_t state_bak;                                             \
3616 +                                                                       \
3617 +      CONVFAIL = 0;                                                    \
3618 +      state_bak = *STATEP;                                             \
3619 +                                                                       \
3620 +      MBLENGTH = mbrtowc (&WC, LP + POS, SIZE - POS, STATEP);          \
3621 +                                                                       \
3622 +      switch (MBLENGTH)                                                        \
3623 +       {                                                               \
3624 +       case (size_t)-2:                                                \
3625 +       case (size_t)-1:                                                \
3626 +         *STATEP = state_bak;                                          \
3627 +         CONVFAIL++;                                                   \
3628 +         /* Fall through */                                            \
3629 +       case 0:                                                         \
3630 +         MBLENGTH = 1;                                                 \
3631 +       }                                                               \
3632 +    }                                                                  \
3633 +  while (0)
3634 +
3635 +static char *
3636 +find_field_multi (struct linebuffer *line)
3637 +{
3638 +  size_t count;
3639 +  char *lp = line->buffer;
3640 +  size_t size = line->length - 1;
3641 +  size_t pos;
3642 +  size_t mblength;
3643 +  wchar_t wc;
3644 +  mbstate_t *statep;
3645 +  int convfail;
3646 +
3647 +  pos = 0;
3648 +  statep = &(line->state);
3649 +
3650 +  /* skip fields. */
3651 +  for (count = 0; count < skip_fields && pos < size; count++)
3652 +    {
3653 +      while (pos < size)
3654 +       {
3655 +         MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail);
3656
3657 +         if (convfail || !iswblank (wc))
3658 +           {
3659 +             pos += mblength;
3660 +             break;
3661 +           }
3662 +         pos += mblength;
3663 +       }
3664 +
3665 +      while (pos < size)
3666 +       {
3667 +         MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail);
3668 +
3669 +         if (!convfail && iswblank (wc))
3670 +           break;
3671 +
3672 +         pos += mblength;
3673 +       }
3674 +    }
3675 +
3676 +  /* skip fields. */
3677 +  for (count = 0; count < skip_chars && pos < size; count++)
3678 +    {
3679 +      MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail);
3680 +      pos += mblength;
3681 +    }
3682 +
3683 +  return lp + pos;
3684 +}
3685 +#endif
3686 +
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.
3690 @@ -218,6 +321,8 @@
3691  static bool
3692  different (char *old, char *new, size_t oldlen, size_t newlen)
3693  {
3694 +  char *copy_old, *copy_new;
3695 +
3696    if (check_chars < oldlen)
3697      oldlen = check_chars;
3698    if (check_chars < newlen)
3699 @@ -225,14 +330,92 @@
3700  
3701    if (ignore_case)
3702      {
3703 -      /* FIXME: This should invoke strcoll somehow.  */
3704 -      return oldlen != newlen || memcasecmp (old, new, oldlen);
3705 +      size_t i;
3706 +
3707 +      copy_old = alloca (oldlen + 1);
3708 +      copy_new = alloca (oldlen + 1);
3709 +
3710 +      for (i = 0; i < oldlen; i++)
3711 +       {
3712 +         copy_old[i] = toupper (old[i]);
3713 +         copy_new[i] = toupper (new[i]);
3714 +       }
3715      }
3716 -  else if (hard_LC_COLLATE)
3717 -    return xmemcoll (old, oldlen, new, newlen) != 0;
3718    else
3719 -    return oldlen != newlen || memcmp (old, new, oldlen);
3720 +    {
3721 +      copy_old = (char *)old;
3722 +      copy_new = (char *)new;
3723 +    }
3724 +
3725 +  return xmemcoll (copy_old, oldlen, copy_new, newlen);
3726 +}
3727 +
3728 +#if HAVE_MBRTOWC
3729 +static int
3730 +different_multi (const char *old, const char *new, size_t oldlen, size_t newlen, mbstate_t oldstate, mbstate_t newstate)
3731 +{
3732 +  size_t i, j, chars;
3733 +  const char *str[2];
3734 +  char *copy[2];
3735 +  size_t len[2];
3736 +  mbstate_t state[2];
3737 +  size_t mblength;
3738 +  wchar_t wc, uwc;
3739 +  mbstate_t state_bak;
3740 +
3741 +  str[0] = old;
3742 +  str[1] = new;
3743 +  len[0] = oldlen;
3744 +  len[1] = newlen;
3745 +  state[0] = oldstate;
3746 +  state[1] = newstate;
3747 +
3748 +  for (i = 0; i < 2; i++)
3749 +    {
3750 +      copy[i] = alloca (len[i] + 1);
3751 +
3752 +      for (j = 0, chars = 0; j < len[i] && chars < check_chars; chars++)
3753 +       {
3754 +         state_bak = state[i];
3755 +         mblength = mbrtowc (&wc, str[i] + j, len[i] - j, &(state[i]));
3756 +
3757 +         switch (mblength)
3758 +           {
3759 +           case (size_t)-1:
3760 +           case (size_t)-2:
3761 +             state[i] = state_bak;
3762 +             /* Fall through */
3763 +           case 0:
3764 +             mblength = 1;
3765 +             break;
3766 +
3767 +           default:
3768 +             if (ignore_case)
3769 +               {
3770 +                 uwc = towupper (wc);
3771 +
3772 +                 if (uwc != wc)
3773 +                   {
3774 +                     mbstate_t state_wc;
3775 +
3776 +                     memset (&state_wc, '\0', sizeof(mbstate_t));
3777 +                     wcrtomb (copy[i] + j, uwc, &state_wc);
3778 +                   }
3779 +                 else
3780 +                   memcpy (copy[i] + j, str[i] + j, mblength);
3781 +               }
3782 +             else
3783 +               memcpy (copy[i] + j, str[i] + j, mblength);
3784 +           }
3785 +         j += mblength;
3786 +       }
3787 +      copy[i][j] = '\0';
3788 +      len[i] = j;
3789 +    }
3790 +
3791 +  return xmemcoll (copy[0], len[0], copy[1], len[1]);
3792  }
3793 +#endif
3794  
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 @@
3798      {
3799        char *prevfield IF_LINT (= NULL);
3800        size_t prevlen IF_LINT (= 0);
3801 +#if HAVE_MBRTOWC
3802 +      mbstate_t prevstate;
3803 +
3804 +      memset (&prevstate, '\0', sizeof (mbstate_t));
3805 +#endif
3806  
3807        while (!feof (stdin))
3808         {
3809           char *thisfield;
3810           size_t thislen;
3811 +#if HAVE_MBRTOWC
3812 +         mbstate_t thisstate;
3813 +#endif
3814 +
3815           if (readlinebuffer (thisline, stdin) == 0)
3816             break;
3817           thisfield = find_field (thisline);
3818           thislen = thisline->length - 1 - (thisfield - thisline->buffer);
3819 +#if HAVE_MBRTOWC
3820 +         if (MB_CUR_MAX > 1)
3821 +            {
3822 +            thisstate = thisline->state;
3823 +
3824 +            if (prevline->length == 0 || different_multi
3825 +              (thisfield, prevfield, thislen, prevlen, thisstate, prevstate))
3826 +              {
3827 +                fwrite (thisline->buffer, sizeof (char),
3828 +                        thisline->length, stdout);
3829 +
3830 +                SWAP_LINES (prevline, thisline);
3831 +                prevfield = thisfield;
3832 +                prevlen = thislen;
3833 +                prevstate = thisstate;
3834 +              }
3835 +          }
3836 +       else
3837 +#endif
3838           if (prevline->length == 0
3839               || different (thisfield, prevfield, thislen, prevlen))
3840             {
3841 @@ -313,17 +524,26 @@
3842        size_t prevlen;
3843        uintmax_t match_count = 0;
3844        bool first_delimiter = true;
3845 +#if HAVE_MBRTOWC
3846 +      mbstate_t prevstate;
3847 +#endif
3848  
3849        if (readlinebuffer (prevline, stdin) == 0)
3850         goto closefiles;
3851        prevfield = find_field (prevline);
3852        prevlen = prevline->length - 1 - (prevfield - prevline->buffer);
3853 +#if HAVE_MBRTOWC
3854 +      prevstate = prevline->state;
3855 +#endif
3856  
3857        while (!feof (stdin))
3858         {
3859           bool match;
3860           char *thisfield;
3861           size_t thislen;
3862 +#if HAVE_MBRTOWC
3863 +         mbstate_t thisstate;
3864 +#endif
3865           if (readlinebuffer (thisline, stdin) == 0)
3866             {
3867               if (ferror (stdin))
3868 @@ -332,6 +552,15 @@
3869             }
3870           thisfield = find_field (thisline);
3871           thislen = thisline->length - 1 - (thisfield - thisline->buffer);
3872 +#if HAVE_MBRTOWC
3873 +         if (MB_CUR_MAX > 1)
3874 +           {
3875 +              thisstate = thisline->state;
3876 +              match = !different_multi (thisfield, prevfield,
3877 +                                thislen, prevlen, thisstate, prevstate);
3878 +            }
3879 +         else
3880 +#endif
3881           match = !different (thisfield, prevfield, thislen, prevlen);
3882           match_count += match;
3883  
3884 @@ -364,6 +593,9 @@
3885               SWAP_LINES (prevline, thisline);
3886               prevfield = thisfield;
3887               prevlen = thislen;
3888 +#if HAVE_MBRTOWC
3889 +             prevstate = thisstate;
3890 +#endif
3891               if (!match)
3892                 match_count = 0;
3893             }
3894 @@ -408,6 +640,19 @@
3895  
3896    atexit (close_stdout);
3897  
3898 +#if HAVE_MBRTOWC
3899 +  if (MB_CUR_MAX > 1)
3900 +    {
3901 +      find_field = find_field_multi;
3902 +    }
3903 +  else
3904 +#endif
3905 +    {
3906 +      find_field = find_field_uni;
3907 +    }
3908 +
3909 +
3910 +
3911    skip_chars = 0;
3912    skip_fields = 0;
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
3917 @@ -64,14 +64,16 @@
3918  nul-tab.E
3919  ##test-files-end
3920  
3921 -EXTRA_DIST = Test.pm $x-tests $(explicit) $(maint_gen)
3922 -noinst_SCRIPTS = $x-tests
3923 +run_gen += mb1.O mb2.O
3924 +
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"
3929  
3930  editpl = sed -e 's,@''PERL''@,$(PERL),g' -e 's,@''srcdir''@,$(srcdir),g'
3931  
3932 -TESTS = $x-tests
3933 +TESTS = $x-tests $x-mb-tests
3934  
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 \
3942  nul-tab.E
3943  
3944 -EXTRA_DIST = Test.pm $x-tests $(explicit) $(maint_gen)
3945 -noinst_SCRIPTS = $x-tests
3946 +run_gen += mb1.O mb2.O
3947 +
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"
3952  
3953  editpl = sed -e 's,@''PERL''@,$(PERL),g' -e 's,@''srcdir''@,$(srcdir),g'
3954 -TESTS = $x-tests
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
3962 @@ -0,0 +1,4 @@
3963 +Apple@10
3964 +Banana@5
3965 +Citrus@20
3966 +Cherry@30
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
3970 @@ -0,0 +1,4 @@
3971 +Banana@5
3972 +Apple@10
3973 +Citrus@20
3974 +Cherry@30
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
3978 @@ -0,0 +1,4 @@
3979 +Apple@AA10@@20
3980 +Banana@AA5@@30
3981 +Citrus@AA20@@5
3982 +Cherry@AA30@@10
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
3986 @@ -0,0 +1,4 @@
3987 +Citrus@AA20@@5
3988 +Cherry@AA30@@10
3989 +Apple@AA10@@20
3990 +Banana@AA5@@30
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
3994 @@ -0,0 +1,58 @@
3995 +#! /bin/sh
3996 +case $# in
3997 +  0) xx='../../src/sort';;
3998 +  *) xx="$1";;
3999 +esac
4000 +test "$VERBOSE" && echo=echo || echo=:
4001 +$echo testing program: $xx
4002 +errors=0
4003 +test "$srcdir" || srcdir=.
4004 +test "$VERBOSE" && $xx --version 2> /dev/null
4005 +
4006 +export LC_ALL=en_US.UTF-8
4007 +locale -k LC_CTYPE 2>&1 | grep -q charmap.*UTF-8 || exit 77
4008 +errors=0
4009 +
4010 +$xx -t @ -k2 -n mb1.I > mb1.O
4011 +code=$?
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`
4015 +else
4016 +  cmp mb1.O $srcdir/mb1.X > /dev/null 2>&1
4017 +  case $? in
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`;;
4025 +  esac
4026 +fi
4027 +
4028 +$xx -t @ -k4 -n mb2.I > mb2.O
4029 +code=$?
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`
4033 +else
4034 +  cmp mb2.O $srcdir/mb2.X > /dev/null 2>&1
4035 +  case $? in
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`;;
4043 +  esac
4044 +fi
4045 +
4046 +if test $errors = 0; then
4047 +  $echo Passed all 113 tests. 1>&2
4048 +else
4049 +  $echo Failed $errors tests. 1>&2
4050 +fi
4051 +test $errors = 0 || errors=1
4052 +exit $errors