source: patches/coreutils-6.12-i18n-1.patch@ fd15fb0

clfs-1.2 clfs-2.1 clfs-3.0.0-systemd clfs-3.0.0-sysvinit systemd sysvinit
Last change on this file since fd15fb0 was d33f80c, checked in by Jim Gifford <clfs@…>, 16 years ago

Put in Correct i18n patch for coreutils

  • Property mode set to 100644
File size: 100.4 KB
  • lib/linebuffer.h

    Submitted By: Jim Gifford <jim at cross-lfs dot org>
    Date: 2009-01-08
    Initial Package Version: 6.12
    Upstream Status: Unkown
    Origin: Mandriva
    Description: i18n Updates
    
    diff -Naur coreutils-6.12.orig/lib/linebuffer.h coreutils-6.12/lib/linebuffer.h
    old new  
    2121
    2222# include <stdio.h>
    2323
     24/* Get mbstate_t.  */
     25# if HAVE_WCHAR_H
     26#  include <wchar.h>
     27# endif
     28
    2429/* A `struct linebuffer' holds a line of text. */
    2530
    2631struct linebuffer
     
    2833  size_t size;                  /* Allocated. */
    2934  size_t length;                /* Used. */
    3035  char *buffer;
     36# if HAVE_WCHAR_H
     37  mbstate_t state;
     38# endif
    3139};
    3240
    3341/* Initialize linebuffer LINEBUFFER for use. */
  • coreutils-6.12

    diff -Naur coreutils-6.12.orig/src/cut.c coreutils-6.12/src/cut.c
    old new  
    2828#include <assert.h>
    2929#include <getopt.h>
    3030#include <sys/types.h>
     31
     32/* Get mbstate_t, mbrtowc().  */
     33#if HAVE_WCHAR_H
     34# include <wchar.h>
     35#endif
    3136#include "system.h"
    3237
    3338#include "error.h"
     
    3641#include "quote.h"
    3742#include "xstrndup.h"
    3843
     44/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC
     45   installation; work around this configuration error.  */
     46#if !defined MB_LEN_MAX || MB_LEN_MAX < 2
     47# undef MB_LEN_MAX
     48# define MB_LEN_MAX 16
     49#endif
     50
     51/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t.  */
     52#if HAVE_MBRTOWC && defined mbstate_t
     53# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
     54#endif
     55
    3956/* The official name of this program (e.g., no `g' prefix).  */
    4057#define PROGRAM_NAME "cut"
    4158
     
    7188    }                                                   \
    7289  while (0)
    7390
     91/* Refill the buffer BUF to get a multibyte character. */
     92#define REFILL_BUFFER(BUF, BUFPOS, BUFLEN, STREAM)                      \
     93  do                                                                    \
     94    {                                                                   \
     95      if (BUFLEN < MB_LEN_MAX && !feof (STREAM) && !ferror (STREAM))    \
     96        {                                                               \
     97          memmove (BUF, BUFPOS, BUFLEN);                                \
     98          BUFLEN += fread (BUF + BUFLEN, sizeof(char), BUFSIZ, STREAM); \
     99          BUFPOS = BUF;                                                 \
     100        }                                                               \
     101    }                                                                   \
     102  while (0)
     103
     104/* Get wide character on BUFPOS. BUFPOS is not included after that.
     105   If byte sequence is not valid as a character, CONVFAIL is 1. Otherwise 0. */
     106#define GET_NEXT_WC_FROM_BUFFER(WC, BUFPOS, BUFLEN, MBLENGTH, STATE, CONVFAIL) \
     107  do                                                                    \
     108    {                                                                   \
     109      mbstate_t state_bak;                                              \
     110                                                                        \
     111      if (BUFLEN < 1)                                                   \
     112        {                                                               \
     113          WC = WEOF;                                                    \
     114          break;                                                        \
     115        }                                                               \
     116                                                                        \
     117      /* Get a wide character. */                                       \
     118      CONVFAIL = 0;                                                     \
     119      state_bak = STATE;                                                \
     120      MBLENGTH = mbrtowc ((wchar_t *)&WC, BUFPOS, BUFLEN, &STATE);      \
     121                                                                        \
     122      switch (MBLENGTH)                                                 \
     123        {                                                               \
     124        case (size_t)-1:                                                \
     125        case (size_t)-2:                                                \
     126          CONVFAIL++;                                                   \
     127          STATE = state_bak;                                            \
     128          /* Fall througn. */                                           \
     129                                                                        \
     130        case 0:                                                         \
     131          MBLENGTH = 1;                                                 \
     132          break;                                                        \
     133        }                                                               \
     134    }                                                                   \
     135  while (0)
     136
    74137struct range_pair
    75138  {
    76139    size_t lo;
     
    89152/* The number of bytes allocated for FIELD_1_BUFFER.  */
    90153static size_t field_1_bufsize;
    91154
    92 /* The largest field or byte index used as an endpoint of a closed
     155/* The largest byte, character or field index used as an endpoint of a closed
    93156   or degenerate range specification;  this doesn't include the starting
    94157   index of right-open-ended ranges.  For example, with either range spec
    95158   `2-5,9-', `2-3,5,9-' this variable would be set to 5.  */
     
    101164
    102165/* This is a bit vector.
    103166   In byte mode, which bytes to output.
     167   In character mode, which characters to output.
    104168   In field mode, which DELIM-separated fields to output.
    105    Both bytes and fields are numbered starting with 1,
     169   Bytes, characters and fields are numbered starting with 1,
    106170   so the zeroth bit of this array is unused.
    107    A field or byte K has been selected if
     171   A byte, character or field K has been selected if
    108172   (K <= MAX_RANGE_ENDPOINT and is_printable_field(K))
    109173    || (EOL_RANGE_START > 0 && K >= EOL_RANGE_START).  */
    110174static unsigned char *printable_field;
     
    113177  {
    114178    undefined_mode,
    115179
    116     /* Output characters that are in the given bytes. */
     180    /* Output bytes that are at the given positions. */
    117181    byte_mode,
    118182
     183    /* Output characters that are at the given positions. */
     184    character_mode,
     185
    119186    /* Output the given delimeter-separated fields. */
    120187    field_mode
    121188  };
     
    125192
    126193static enum operating_mode operating_mode;
    127194
     195/* If nonzero, when in byte mode, don't split multibyte characters.  */
     196static int byte_mode_character_aware;
     197
     198/* If nonzero, the function for single byte locale is work
     199   if this program runs on multibyte locale. */
     200static int force_singlebyte_mode;
     201
    128202/* If true do not output lines containing no delimeter characters.
    129203   Otherwise, all such lines are printed.  This option is valid only
    130204   with field mode.  */
     
    136210
    137211/* The delimeter character for field mode. */
    138212static unsigned char delim;
     213#if HAVE_WCHAR_H
     214static wchar_t wcdelim;
     215#endif
    139216
    140217/* True if the --output-delimiter=STRING option was specified.  */
    141218static bool output_delimiter_specified;
     
    209286  -f, --fields=LIST       select only these fields;  also print any line\n\
    210287                            that contains no delimiter character, unless\n\
    211288                            the -s option is specified\n\
    212   -n                      (ignored)\n\
     289  -n                      with -b: don't split multibyte characters\n\
    213290"), stdout);
    214291      fputs (_("\
    215292      --complement        complement the set of selected bytes, characters\n\
     
    368445          in_digits = false;
    369446          /* Starting a range. */
    370447          if (dash_found)
    371             FATAL_ERROR (_("invalid byte or field list"));
     448            FATAL_ERROR (_("invalid byte, character or field list"));
    372449          dash_found = true;
    373450          fieldstr++;
    374451
     
    392469              if (!rhs_specified)
    393470                {
    394471                  /* `n-'.  From `initial' to end of line. */
    395                   eol_range_start = initial;
     472                  if (eol_range_start == 0 ||
     473                      (eol_range_start != 0 && eol_range_start > initial))
     474                    eol_range_start = initial;
    396475                  field_found = true;
    397476                }
    398477              else
    399478                {
    400479                  /* `m-n' or `-n' (1-n). */
    401480                  if (value < initial)
    402                     FATAL_ERROR (_("invalid decreasing range"));
     481                    FATAL_ERROR (_("invalid byte, character or field list"));
    403482
    404483                  /* Is there already a range going to end of line? */
    405484                  if (eol_range_start != 0)
     
    479558              if (operating_mode == byte_mode)
    480559                error (0, 0,
    481560                       _("byte offset %s is too large"), quote (bad_num));
     561              else if (operating_mode == character_mode)
     562                error (0, 0,
     563                       _("character offset %s is too large"), quote (bad_num));
    482564              else
    483565                error (0, 0,
    484566                       _("field number %s is too large"), quote (bad_num));
     
    489571          fieldstr++;
    490572        }
    491573      else
    492         FATAL_ERROR (_("invalid byte or field list"));
     574        FATAL_ERROR (_("invalid byte, character or field list"));
    493575    }
    494576
    495577  max_range_endpoint = 0;
     
    582664    }
    583665}
    584666
     667#if HAVE_MBRTOWC
     668/* This function is in use for the following case.
     669
     670   1. Read from the stream STREAM, printing to standard output any selected
     671   characters.
     672
     673   2. Read from stream STREAM, printing to standard output any selected bytes,
     674   without splitting multibyte characters.  */
     675 
     676static void
     677cut_characters_or_cut_bytes_no_split (FILE *stream)
     678{
     679  int idx;              /* number of bytes or characters in the line so far. */
     680  char buf[MB_LEN_MAX + BUFSIZ];  /* For spooling a read byte sequence. */
     681  char *bufpos;         /* Next read position of BUF. */
     682  size_t buflen;        /* The length of the byte sequence in buf. */
     683  wint_t wc;            /* A gotten wide character. */
     684  size_t mblength;      /* The byte size of a multibyte character which shows
     685                           as same character as WC. */
     686  mbstate_t state;      /* State of the stream. */
     687  int convfail;         /* 1, when conversion is failed. Otherwise 0. */
     688
     689  idx = 0;
     690  buflen = 0;
     691  bufpos = buf;
     692  memset (&state, '\0', sizeof(mbstate_t));
     693
     694  while (1)
     695    {
     696      REFILL_BUFFER (buf, bufpos, buflen, stream);
     697
     698      GET_NEXT_WC_FROM_BUFFER (wc, bufpos, buflen, mblength, state, convfail);
     699
     700      if (wc == WEOF)
     701        {
     702          if (idx > 0)
     703            putchar ('\n');
     704          break;
     705        }
     706      else if (wc == L'\n')
     707        {
     708          putchar ('\n');
     709          idx = 0;
     710        }
     711      else
     712        {
     713          idx += (operating_mode == byte_mode) ? mblength : 1;
     714          if (print_kth (idx, NULL))
     715            fwrite (bufpos, mblength, sizeof(char), stdout);
     716        }
     717
     718      buflen -= mblength;
     719      bufpos += mblength;
     720    }
     721}
     722#endif
     723                   
    585724/* Read from stream STREAM, printing to standard output any selected fields.  */
    586725
    587726static void
     
    704843    }
    705844}
    706845
     846#if HAVE_MBRTOWC
     847static void
     848cut_fields_mb (FILE *stream)
     849{
     850  int c;
     851  unsigned int field_idx;
     852  int found_any_selected_field;
     853  int buffer_first_field;
     854  int empty_input;
     855  char buf[MB_LEN_MAX + BUFSIZ];  /* For spooling a read byte sequence. */
     856  char *bufpos;         /* Next read position of BUF. */
     857  size_t buflen;        /* The length of the byte sequence in buf. */
     858  wint_t wc = 0;        /* A gotten wide character. */
     859  size_t mblength;      /* The byte size of a multibyte character which shows
     860                           as same character as WC. */
     861  mbstate_t state;      /* State of the stream. */
     862  int convfail;         /* 1, when conversion is failed. Otherwise 0. */
     863
     864  found_any_selected_field = 0;
     865  field_idx = 1;
     866  bufpos = buf;
     867  buflen = 0;
     868  memset (&state, '\0', sizeof(mbstate_t));
     869
     870  c = getc (stream);
     871  empty_input = (c == EOF);
     872  if (c != EOF)
     873    ungetc (c, stream);
     874  else
     875    wc = WEOF;
     876
     877  /* To support the semantics of the -s flag, we may have to buffer
     878     all of the first field to determine whether it is `delimited.'
     879     But that is unnecessary if all non-delimited lines must be printed
     880     and the first field has been selected, or if non-delimited lines
     881     must be suppressed and the first field has *not* been selected.
     882     That is because a non-delimited line has exactly one field.  */
     883  buffer_first_field = (suppress_non_delimited ^ !print_kth (1, NULL));
     884
     885  while (1)
     886    {
     887      if (field_idx == 1 && buffer_first_field)
     888        {
     889          int len = 0;
     890
     891          while (1)
     892            {
     893              REFILL_BUFFER (buf, bufpos, buflen, stream);
     894
     895              GET_NEXT_WC_FROM_BUFFER
     896                (wc, bufpos, buflen, mblength, state, convfail);
     897
     898              if (wc == WEOF)
     899                break;
     900
     901              field_1_buffer = xrealloc (field_1_buffer, len + mblength);
     902              memcpy (field_1_buffer + len, bufpos, mblength);
     903              len += mblength;
     904              buflen -= mblength;
     905              bufpos += mblength;
     906
     907              if (!convfail && (wc == L'\n' || wc == wcdelim))
     908                break;
     909            }
     910
     911          if (wc == WEOF)
     912            break;
     913
     914          /* If the first field extends to the end of line (it is not
     915             delimited) and we are printing all non-delimited lines,
     916             print this one.  */
     917          if (convfail || (!convfail && wc != wcdelim))
     918            {
     919              if (suppress_non_delimited)
     920                {
     921                  /* Empty.     */
     922                }
     923              else
     924                {
     925                  fwrite (field_1_buffer, sizeof (char), len, stdout);
     926                  /* Make sure the output line is newline terminated.  */
     927                  if (convfail || (!convfail && wc != L'\n'))
     928                    putchar ('\n');
     929                }
     930              continue;
     931            }
     932
     933          if (print_kth (1, NULL))
     934            {
     935              /* Print the field, but not the trailing delimiter.  */
     936              fwrite (field_1_buffer, sizeof (char), len - 1, stdout);
     937              found_any_selected_field = 1;
     938            }
     939          ++field_idx;
     940        }
     941
     942      if (wc != WEOF)
     943        {
     944          if (print_kth (field_idx, NULL))
     945            {
     946              if (found_any_selected_field)
     947                {
     948                  fwrite (output_delimiter_string, sizeof (char),
     949                          output_delimiter_length, stdout);
     950                }
     951              found_any_selected_field = 1;
     952            }
     953
     954          while (1)
     955            {
     956              REFILL_BUFFER (buf, bufpos, buflen, stream);
     957
     958              GET_NEXT_WC_FROM_BUFFER
     959                (wc, bufpos, buflen, mblength, state, convfail);
     960
     961              if (wc == WEOF)
     962                break;
     963              else if (!convfail && (wc == wcdelim || wc == L'\n'))
     964                {
     965                  buflen -= mblength;
     966                  bufpos += mblength;
     967                  break;
     968                }
     969
     970              if (print_kth (field_idx, NULL))
     971                fwrite (bufpos, mblength, sizeof(char), stdout);
     972
     973              buflen -= mblength;
     974              bufpos += mblength;
     975            }
     976        }
     977
     978      if ((!convfail || wc == L'\n') && buflen < 1)
     979        wc = WEOF;
     980
     981      if (!convfail && wc == wcdelim)
     982        ++field_idx;
     983      else if (wc == WEOF || (!convfail && wc == L'\n'))
     984        {
     985          if (found_any_selected_field
     986              || (!empty_input && !(suppress_non_delimited && field_idx == 1)))
     987            putchar ('\n');
     988          if (wc == WEOF)
     989            break;
     990          field_idx = 1;
     991          found_any_selected_field = 0;
     992        }
     993    }
     994}
     995#endif
     996
    707997static void
    708998cut_stream (FILE *stream)
    709999{
    710   if (operating_mode == byte_mode)
    711     cut_bytes (stream);
     1000#if HAVE_MBRTOWC
     1001  if (MB_CUR_MAX > 1 && !force_singlebyte_mode)
     1002    {
     1003      switch (operating_mode)
     1004        {
     1005        case byte_mode:
     1006          if (byte_mode_character_aware)
     1007            cut_characters_or_cut_bytes_no_split (stream);
     1008          else
     1009            cut_bytes (stream);
     1010          break;
     1011
     1012        case character_mode:
     1013          cut_characters_or_cut_bytes_no_split (stream);
     1014          break;
     1015
     1016        case field_mode:
     1017          cut_fields_mb (stream);
     1018          break;
     1019
     1020        default:
     1021          abort ();
     1022        }
     1023    }
    7121024  else
    713     cut_fields (stream);
     1025#endif
     1026    {
     1027      if (operating_mode == field_mode)
     1028        cut_fields (stream);
     1029      else
     1030        cut_bytes (stream);
     1031    }
    7141032}
    7151033
    7161034/* Process file FILE to standard output.
     
    7601078  bool ok;
    7611079  bool delim_specified = false;
    7621080  char *spec_list_string IF_LINT(= NULL);
     1081  char mbdelim[MB_LEN_MAX + 1];
     1082  size_t delimlen = 0;
    7631083
    7641084  initialize_main (&argc, &argv);
    7651085  program_name = argv[0];
     
    7821102      switch (optc)
    7831103        {
    7841104        case 'b':
    785         case 'c':
    7861105          /* Build the byte list. */
    7871106          if (operating_mode != undefined_mode)
    7881107            FATAL_ERROR (_("only one type of list may be specified"));
     
    7901109          spec_list_string = optarg;
    7911110          break;
    7921111
     1112        case 'c':
     1113          /* Build the character list. */
     1114          if (operating_mode != undefined_mode)
     1115            FATAL_ERROR (_("only one type of list may be specified"));
     1116          operating_mode = character_mode;
     1117          spec_list_string = optarg;
     1118          break;
     1119
    7931120        case 'f':
    7941121          /* Build the field list. */
    7951122          if (operating_mode != undefined_mode)
     
    8011128        case 'd':
    8021129          /* New delimiter. */
    8031130          /* Interpret -d '' to mean `use the NUL byte as the delimiter.'  */
    804           if (optarg[0] != '\0' && optarg[1] != '\0')
    805             FATAL_ERROR (_("the delimiter must be a single character"));
    806           delim = optarg[0];
    807           delim_specified = true;
     1131            {
     1132#if HAVE_MBRTOWC
     1133              if(MB_CUR_MAX > 1)
     1134                {
     1135                  mbstate_t state;
     1136
     1137                  memset (&state, '\0', sizeof(mbstate_t));
     1138                  delimlen = mbrtowc (&wcdelim, optarg, strnlen(optarg, MB_LEN_MAX), &state);
     1139
     1140                  if (delimlen == (size_t)-1 || delimlen == (size_t)-2)
     1141                    ++force_singlebyte_mode;
     1142                  else
     1143                    {
     1144                      delimlen = (delimlen < 1) ? 1 : delimlen;
     1145                      if (wcdelim != L'\0' && *(optarg + delimlen) != '\0')
     1146                        FATAL_ERROR (_("the delimiter must be a single character"));
     1147                      memcpy (mbdelim, optarg, delimlen);
     1148                    }
     1149                }
     1150
     1151              if (MB_CUR_MAX <= 1 || force_singlebyte_mode)
     1152#endif
     1153                {
     1154                  if (optarg[0] != '\0' && optarg[1] != '\0')
     1155                    FATAL_ERROR (_("the delimiter must be a single character"));
     1156                  delim = (unsigned char) optarg[0];
     1157                }
     1158            delim_specified = true;
     1159          }
    8081160          break;
    8091161
    8101162        case OUTPUT_DELIMITER_OPTION:
     
    8171169          break;
    8181170
    8191171        case 'n':
     1172          byte_mode_character_aware = 1;
    8201173          break;
    8211174
    8221175        case 's':
     
    8391192  if (operating_mode == undefined_mode)
    8401193    FATAL_ERROR (_("you must specify a list of bytes, characters, or fields"));
    8411194
    842   if (delim != '\0' && operating_mode != field_mode)
     1195  if (delim_specified && operating_mode != field_mode)
    8431196    FATAL_ERROR (_("an input delimiter may be specified only\
    8441197 when operating on fields"));
    8451198
     
    8661219    }
    8671220
    8681221  if (!delim_specified)
    869     delim = '\t';
     1222    {
     1223      delim = '\t';
     1224#ifdef HAVE_MBRTOWC
     1225      wcdelim = L'\t';
     1226      mbdelim[0] = '\t';
     1227      mbdelim[1] = '\0';
     1228      delimlen = 1;
     1229#endif
     1230    }
    8701231
    8711232  if (output_delimiter_string == NULL)
    8721233    {
    873       static char dummy[2];
    874       dummy[0] = delim;
    875       dummy[1] = '\0';
    876       output_delimiter_string = dummy;
    877       output_delimiter_length = 1;
     1234#ifdef HAVE_MBRTOWC
     1235      if (MB_CUR_MAX > 1 && !force_singlebyte_mode)
     1236        {
     1237          output_delimiter_string = xstrdup(mbdelim);
     1238          output_delimiter_length = delimlen;
     1239        }
     1240
     1241      if (MB_CUR_MAX <= 1 || force_singlebyte_mode)
     1242#endif
     1243        {
     1244          static char dummy[2];
     1245          dummy[0] = delim;
     1246          dummy[1] = '\0';
     1247          output_delimiter_string = dummy;
     1248          output_delimiter_length = 1;
     1249        }
    8781250    }
    8791251
    8801252  if (optind == argc)
  • coreutils-6.12

    diff -Naur coreutils-6.12.orig/src/expand.c coreutils-6.12/src/expand.c
    old new  
    3737#include <stdio.h>
    3838#include <getopt.h>
    3939#include <sys/types.h>
     40
     41/* Get mbstate_t, mbrtowc(), wcwidth(). */
     42#if HAVE_WCHAR_H
     43# include <wchar.h>
     44#endif
     45
    4046#include "system.h"
    4147#include "error.h"
    4248#include "quote.h"
    4349#include "xstrndup.h"
    4450
     51/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC
     52   installation; work around this configuration error.  */
     53#if !defined MB_LEN_MAX || MB_LEN_MAX < 2
     54# define MB_LEN_MAX 16
     55#endif
     56
     57/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t.  */
     58#if HAVE_MBRTOWC && defined mbstate_t
     59# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
     60#endif
     61
    4562/* The official name of this program (e.g., no `g' prefix).  */
    4663#define PROGRAM_NAME "expand"
    4764
     
    182199              stops = num_start + len - 1;
    183200            }
    184201        }
     202
    185203      else
    186204        {
    187205          error (0, 0, _("tab size contains invalid character(s): %s"),
     
    364382    }
    365383}
    366384
     385#if HAVE_MBRTOWC
     386static void
     387expand_multibyte (void)
     388{
     389  FILE *fp;                     /* Input strem. */
     390  mbstate_t i_state;            /* Current shift state of the input stream. */
     391  mbstate_t i_state_bak;        /* Back up the I_STATE. */
     392  mbstate_t o_state;            /* Current shift state of the output stream. */
     393  char buf[MB_LEN_MAX + BUFSIZ];  /* For spooling a read byte sequence. */
     394  char *bufpos;                 /* Next read position of BUF. */
     395  size_t buflen = 0;            /* The length of the byte sequence in buf. */
     396  wchar_t wc;                   /* A gotten wide character. */
     397  size_t mblength;              /* The byte size of a multibyte character
     398                                   which shows as same character as WC. */
     399  int tab_index = 0;            /* Index in `tab_list' of next tabstop. */
     400  int column = 0;               /* Column on screen of the next char. */
     401  int next_tab_column;          /* Column the next tab stop is on. */
     402  int convert = 1;              /* If nonzero, perform translations. */
     403
     404  fp = next_file ((FILE *) NULL);
     405  if (fp == NULL)
     406    return;
     407
     408  memset (&o_state, '\0', sizeof(mbstate_t));
     409  memset (&i_state, '\0', sizeof(mbstate_t));
     410
     411  for (;;)
     412    {
     413      /* Refill the buffer BUF. */
     414      if (buflen < MB_LEN_MAX && !feof(fp) && !ferror(fp))
     415        {
     416          memmove (buf, bufpos, buflen);
     417          buflen += fread (buf + buflen, sizeof(char), BUFSIZ, fp);
     418          bufpos = buf;
     419        }
     420
     421      /* No character is left in BUF. */
     422      if (buflen < 1)
     423        {
     424          fp = next_file (fp);
     425
     426          if (fp == NULL)
     427            break;              /* No more files. */
     428          else
     429            {
     430              memset (&i_state, '\0', sizeof(mbstate_t));
     431              continue;
     432            }
     433        }
     434
     435      /* Get a wide character. */
     436      i_state_bak = i_state;
     437      mblength = mbrtowc (&wc, bufpos, buflen, &i_state);
     438
     439      switch (mblength)
     440        {
     441        case (size_t)-1:        /* illegal byte sequence. */
     442        case (size_t)-2:
     443          mblength = 1;
     444          i_state = i_state_bak;
     445          if (convert)
     446            {
     447              ++column;
     448              if (convert_entire_line == 0)
     449                convert = 0;
     450            }
     451          putchar (*bufpos);
     452          break;
     453
     454        case 0:         /* null. */
     455          mblength = 1;
     456          if (convert && convert_entire_line == 0)
     457            convert = 0;
     458          putchar ('\0');
     459          break;
     460
     461        default:
     462          if (wc == L'\n')   /* LF. */
     463            {
     464              tab_index = 0;
     465              column = 0;
     466              convert = 1;
     467              putchar ('\n');
     468            }
     469          else if (wc == L'\t' && convert)      /* Tab. */
     470            {
     471              if (tab_size == 0)
     472                {
     473                  /* Do not let tab_index == first_free_tab;
     474                     stop when it is 1 less. */
     475                  while (tab_index < first_free_tab - 1
     476                      && column >= tab_list[tab_index])
     477                    tab_index++;
     478                  next_tab_column = tab_list[tab_index];
     479                  if (tab_index < first_free_tab - 1)
     480                    tab_index++;
     481                  if (column >= next_tab_column)
     482                    next_tab_column = column + 1;
     483                }
     484              else
     485                next_tab_column = column + tab_size - column % tab_size;
     486
     487              while (column < next_tab_column)
     488                {
     489                  putchar (' ');
     490                  ++column;
     491                }
     492            }
     493          else  /* Others. */
     494            {
     495              if (convert)
     496                {
     497                  if (wc == L'\b')
     498                    {
     499                      if (column > 0)
     500                        --column;
     501                    }
     502                  else
     503                    {
     504                      int width;                /* The width of WC. */
     505
     506                      width = wcwidth (wc);
     507                      column += (width > 0) ? width : 0;
     508                      if (convert_entire_line == 0)
     509                        convert = 0;
     510                    }
     511                }
     512              fwrite (bufpos, sizeof(char), mblength, stdout);
     513            }
     514        }
     515      buflen -= mblength;
     516      bufpos += mblength;
     517    }
     518}
     519#endif
     520
    367521int
    368522main (int argc, char **argv)
    369523{
     
    428582
    429583  file_list = (optind < argc ? &argv[optind] : stdin_argv);
    430584
    431   expand ();
     585#if HAVE_MBRTOWC
     586  if (MB_CUR_MAX > 1)
     587    expand_multibyte ();
     588  else
     589#endif
     590    expand ();
    432591
    433592  if (have_read_stdin && fclose (stdin) != 0)
    434593    error (EXIT_FAILURE, errno, "-");
  • coreutils-6.12

    diff -Naur coreutils-6.12.orig/src/fold.c coreutils-6.12/src/fold.c
    old new  
    2222#include <getopt.h>
    2323#include <sys/types.h>
    2424
     25/* Get mbstate_t, mbrtowc(), wcwidth().  */
     26#if HAVE_WCHAR_H
     27# include <wchar.h>
     28#endif
     29
     30/* Get iswprint(), iswblank(), wcwidth().  */
     31#if HAVE_WCTYPE_H
     32# include <wctype.h>
     33#endif
     34
    2535#include "system.h"
    2636#include "error.h"
    2737#include "quote.h"
    2838#include "xstrtol.h"
    2939
     40/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC
     41      installation; work around this configuration error.  */
     42#if !defined MB_LEN_MAX || MB_LEN_MAX < 2
     43# undef MB_LEN_MAX
     44# define MB_LEN_MAX 16
     45#endif
     46
     47/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t.  */
     48#if HAVE_MBRTOWC && defined mbstate_t
     49# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
     50#endif
     51
    3052#define TAB_WIDTH 8
    3153
    3254/* The official name of this program (e.g., no `g' prefix).  */
     
    3456
    3557#define AUTHORS proper_name ("David MacKenzie")
    3658
     59#define FATAL_ERROR(Message)                                            \
     60  do                                                                    \
     61    {                                                                   \
     62      error (0, 0, (Message));                                          \
     63      usage (2);                                                        \
     64    }                                                                   \
     65  while (0)
     66
     67enum operating_mode
     68{
     69  /* Fold texts by columns that are at the given positions. */
     70  column_mode,
     71
     72  /* Fold texts by bytes that are at the given positions. */
     73  byte_mode,
     74
     75  /* Fold texts by characters that are at the given positions. */
     76  character_mode,
     77};
     78
    3779/* The name this program was run with. */
    3880char *program_name;
    3981
     82/* The argument shows current mode. (Default: column_mode) */
     83static enum operating_mode operating_mode;
     84
    4085/* If nonzero, try to break on whitespace. */
    4186static bool break_spaces;
    4287
    43 /* If nonzero, count bytes, not column positions. */
    44 static bool count_bytes;
    45 
    4688/* If nonzero, at least one of the files we read was standard input. */
    4789static bool have_read_stdin;
    4890
    49 static char const shortopts[] = "bsw:0::1::2::3::4::5::6::7::8::9::";
     91static char const shortopts[] = "bcsw:0::1::2::3::4::5::6::7::8::9::";
    5092
    5193static struct option const longopts[] =
    5294{
    5395  {"bytes", no_argument, NULL, 'b'},
     96  {"characters", no_argument, NULL, 'c'},
    5497  {"spaces", no_argument, NULL, 's'},
    5598  {"width", required_argument, NULL, 'w'},
    5699  {GETOPT_HELP_OPTION_DECL},
     
    80123"), stdout);
    81124      fputs (_("\
    82125  -b, --bytes         count bytes rather than columns\n\
     126  -c, --characters    count characters rather than columns\n\
    83127  -s, --spaces        break at spaces\n\
    84128  -w, --width=WIDTH   use WIDTH columns instead of 80\n\
    85129"), stdout);
     
    97141static size_t
    98142adjust_column (size_t column, char c)
    99143{
    100   if (!count_bytes)
     144  if (operating_mode != byte_mode)
    101145    {
    102146      if (c == '\b')
    103147        {
     
    120164   to stdout, with maximum line length WIDTH.
    121165   Return true if successful.  */
    122166
    123 static bool
    124 fold_file (char const *filename, size_t width)
     167static void
     168fold_text (FILE *istream, size_t width, int *saved_errno)
    125169{
    126   FILE *istream;
    127170  int c;
    128171  size_t column = 0;            /* Screen column where next char will go. */
    129172  size_t offset_out = 0;        /* Index in `line_out' for next char. */
    130173  static char *line_out = NULL;
    131174  static size_t allocated_out = 0;
    132   int saved_errno;
    133 
    134   if (STREQ (filename, "-"))
    135     {
    136       istream = stdin;
    137       have_read_stdin = true;
    138     }
    139   else
    140     istream = fopen (filename, "r");
    141 
    142   if (istream == NULL)
    143     {
    144       error (0, errno, "%s", filename);
    145       return false;
    146     }
    147175
    148176  while ((c = getc (istream)) != EOF)
    149177    {
     
    171199              bool found_blank = false;
    172200              size_t logical_end = offset_out;
    173201
     202              /* If LINE_OUT has no wide character,
     203                 put a new wide character in LINE_OUT
     204                 if column is bigger than width. */
     205              if (offset_out == 0)
     206                {
     207                  line_out[offset_out++] = c;
     208                  continue;
     209                }
     210
    174211              /* Look for the last blank. */
    175212              while (logical_end)
    176213                {
     
    217254      line_out[offset_out++] = c;
    218255    }
    219256
    220   saved_errno = errno;
     257  *saved_errno = errno;
     258
     259  if (offset_out)
     260    fwrite (line_out, sizeof (char), (size_t) offset_out, stdout);
     261
     262  free(line_out);
     263}
     264
     265#if HAVE_MBRTOWC
     266static void
     267fold_multibyte_text (FILE *istream, size_t width, int *saved_errno)
     268{
     269  char buf[MB_LEN_MAX + BUFSIZ];  /* For spooling a read byte sequence. */
     270  size_t buflen = 0;    /* The length of the byte sequence in buf. */
     271  char *bufpos;         /* Next read position of BUF. */
     272  wint_t wc;            /* A gotten wide character. */
     273  size_t mblength;      /* The byte size of a multibyte character which shows
     274                           as same character as WC. */
     275  mbstate_t state, state_bak;   /* State of the stream. */
     276  int convfail;         /* 1, when conversion is failed. Otherwise 0. */
     277
     278  char *line_out = NULL;
     279  size_t offset_out = 0;        /* Index in `line_out' for next char. */
     280  size_t allocated_out = 0;
     281
     282  int increment;
     283  size_t column = 0;
     284
     285  size_t last_blank_pos;
     286  size_t last_blank_column;
     287  int is_blank_seen;
     288  int last_blank_increment;
     289  int is_bs_following_last_blank;
     290  size_t bs_following_last_blank_num;
     291  int is_cr_after_last_blank;
     292
     293#define CLEAR_FLAGS                             \
     294   do                                           \
     295     {                                          \
     296        last_blank_pos = 0;                     \
     297        last_blank_column = 0;                  \
     298        is_blank_seen = 0;                      \
     299        is_bs_following_last_blank = 0;         \
     300        bs_following_last_blank_num = 0;        \
     301        is_cr_after_last_blank = 0;             \
     302     }                                          \
     303   while (0)
     304
     305#define START_NEW_LINE                  \
     306   do                                   \
     307     {                                  \
     308      putchar ('\n');                   \
     309      column = 0;                       \
     310      offset_out = 0;                   \
     311      CLEAR_FLAGS;                      \
     312    }                                   \
     313   while (0)
     314
     315  CLEAR_FLAGS;
     316  memset (&state, '\0', sizeof(mbstate_t));
     317
     318  for (;; bufpos += mblength, buflen -= mblength)
     319    {
     320      if (buflen < MB_LEN_MAX && !feof (istream) && !ferror (istream))
     321        {
     322          memmove (buf, bufpos, buflen);
     323          buflen += fread (buf + buflen, sizeof(char), BUFSIZ, istream);
     324          bufpos = buf;
     325        }
     326
     327      if (buflen < 1)
     328        break;
     329
     330      /* Get a wide character. */
     331      convfail = 0;
     332      state_bak = state;
     333      mblength = mbrtowc ((wchar_t *)&wc, bufpos, buflen, &state);
     334
     335      switch (mblength)
     336        {
     337        case (size_t)-1:
     338        case (size_t)-2:
     339          convfail++;
     340          state = state_bak;
     341          /* Fall through. */
     342
     343        case 0:
     344          mblength = 1;
     345          break;
     346        }
     347
     348rescan:
     349      if (operating_mode == byte_mode)                  /* byte mode */
     350        increment = mblength;
     351      else if (operating_mode == character_mode)        /* character mode */
     352        increment = 1;
     353      else                                              /* column mode */
     354        {
     355          if (convfail)
     356            increment = 1;
     357          else
     358            {
     359              switch (wc)
     360                {
     361                case L'\n':
     362                  fwrite (line_out, sizeof(char), offset_out, stdout);
     363                  START_NEW_LINE;
     364                  continue;
     365                 
     366                case L'\b':
     367                  increment = (column > 0) ? -1 : 0;
     368                  break;
     369
     370                case L'\r':
     371                  increment = -1 * column;
     372                  break;
     373
     374                case L'\t':
     375                  increment = 8 - column % 8;
     376                  break;
     377
     378                default:
     379                  increment = wcwidth (wc);
     380                  increment = (increment < 0) ? 0 : increment;
     381                }
     382            }
     383        }
     384
     385      if (column + increment > width && break_spaces && last_blank_pos)
     386        {
     387          fwrite (line_out, sizeof(char), last_blank_pos, stdout);
     388          putchar ('\n');
     389
     390          offset_out = offset_out - last_blank_pos;
     391          column = column - last_blank_column + ((is_cr_after_last_blank)
     392              ? last_blank_increment : bs_following_last_blank_num);
     393          memmove (line_out, line_out + last_blank_pos, offset_out);
     394          CLEAR_FLAGS;
     395          goto rescan;
     396        }
     397
     398      if (column + increment > width && column != 0)
     399        {
     400          fwrite (line_out, sizeof(char), offset_out, stdout);
     401          START_NEW_LINE;
     402          goto rescan;
     403        }
     404
     405      if (allocated_out < offset_out + mblength)
     406        {
     407          allocated_out += 1024;
     408          line_out = xrealloc (line_out, allocated_out);
     409        }
     410
     411      memcpy (line_out + offset_out, bufpos, mblength);
     412      offset_out += mblength;
     413      column += increment;
     414
     415      if (is_blank_seen && !convfail && wc == L'\r')
     416        is_cr_after_last_blank = 1;
     417
     418      if (is_bs_following_last_blank && !convfail && wc == L'\b')
     419        ++bs_following_last_blank_num;
     420      else
     421        is_bs_following_last_blank = 0;
     422
     423      if (break_spaces && !convfail && iswblank (wc))
     424        {
     425          last_blank_pos = offset_out;
     426          last_blank_column = column;
     427          is_blank_seen = 1;
     428          last_blank_increment = increment;
     429          is_bs_following_last_blank = 1;
     430          bs_following_last_blank_num = 0;
     431          is_cr_after_last_blank = 0;
     432        }
     433    }
     434
     435  *saved_errno = errno;
    221436
    222437  if (offset_out)
    223438    fwrite (line_out, sizeof (char), (size_t) offset_out, stdout);
    224439
     440  free(line_out);
     441}
     442#endif
     443
     444/* Fold file FILENAME, or standard input if FILENAME is "-",
     445   to stdout, with maximum line length WIDTH.
     446   Return 0 if successful, 1 if an error occurs. */
     447
     448static bool
     449fold_file (char *filename, size_t width)
     450{
     451  FILE *istream;
     452  int saved_errno;
     453
     454  if (STREQ (filename, "-"))
     455    {
     456      istream = stdin;
     457      have_read_stdin = 1;
     458    }
     459  else
     460    istream = fopen (filename, "r");
     461
     462  if (istream == NULL)
     463    {
     464      error (0, errno, "%s", filename);
     465      return 1;
     466    }
     467
     468  /* Define how ISTREAM is being folded. */
     469#if HAVE_MBRTOWC
     470  if (MB_CUR_MAX > 1)
     471    fold_multibyte_text (istream, width, &saved_errno);
     472  else
     473#endif
     474    fold_text (istream, width, &saved_errno);
     475
    225476  if (ferror (istream))
    226477    {
    227478      error (0, saved_errno, "%s", filename);
     
    254505
    255506  atexit (close_stdout);
    256507
    257   break_spaces = count_bytes = have_read_stdin = false;
     508  operating_mode = column_mode;
     509  break_spaces = have_read_stdin = false;
    258510
    259511  while ((optc = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1)
    260512    {
     
    263515      switch (optc)
    264516        {
    265517        case 'b':               /* Count bytes rather than columns. */
    266           count_bytes = true;
     518          if (operating_mode != column_mode)
     519            FATAL_ERROR (_("only one way of folding may be specified"));
     520          operating_mode = byte_mode;
     521          break;
     522
     523        case 'c':
     524          if (operating_mode != column_mode)
     525            FATAL_ERROR (_("only one way of folding may be specified"));
     526          operating_mode = character_mode;
    267527          break;
    268528
    269529        case 's':               /* Break at word boundaries. */
  • coreutils-6.12

    diff -Naur coreutils-6.12.orig/src/join.c coreutils-6.12/src/join.c
    old new  
    2222#include <sys/types.h>
    2323#include <getopt.h>
    2424
     25/* Get mbstate_t, mbrtowc(), mbrtowc(), wcwidth().  */
     26#if HAVE_WCHAR_H
     27# include <wchar.h>
     28#endif
     29
     30/* Get iswblank(), towupper.  */
     31#if HAVE_WCTYPE_H
     32# include <wctype.h>
     33#endif
     34
    2535#include "system.h"
    2636#include "error.h"
    2737#include "hard-locale.h"
    2838#include "linebuffer.h"
    29 #include "memcasecmp.h"
    3039#include "quote.h"
    3140#include "stdio--.h"
    3241#include "xmemcoll.h"
    3342#include "xstrtol.h"
    3443#include "argmatch.h"
    3544
     45/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t.  */
     46#if HAVE_MBRTOWC && defined mbstate_t
     47# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
     48#endif
     49
    3650/* The official name of this program (e.g., no `g' prefix).  */
    3751#define PROGRAM_NAME "join"
    3852
     
    113127/* Last element in `outlist', where a new element can be added.  */
    114128static struct outlist *outlist_end = &outlist_head;
    115129
    116 /* Tab character separating fields.  If negative, fields are separated
    117    by any nonempty string of blanks, otherwise by exactly one
    118    tab character whose value (when cast to unsigned char) equals TAB.  */
    119 static int tab = -1;
     130/* Tab character separating fields.  If NULL, fields are separated
     131   by any nonempty string of blanks.  */
     132static char *tab = NULL;
     133
     134/* The number of bytes used for tab. */
     135static size_t tablen = 0;
    120136
    121137/* If nonzero, check that the input is correctly ordered. */
    122138static enum
     
    221237
    222238/* Fill in the `fields' structure in LINE.  */
    223239
     240/* Fill in the `fields' structure in LINE.  */
     241
    224242static void
    225243xfields (struct line *line)
    226244{
     
    230248  if (ptr == lim)
    231249    return;
    232250
    233   if (0 <= tab)
     251  if (tab != NULL)
    234252    {
     253      unsigned char t = tab[0];
    235254      char *sep;
    236       for (; (sep = memchr (ptr, tab, lim - ptr)) != NULL; ptr = sep + 1)
     255      for (; (sep = memchr (ptr, t, lim - ptr)) != NULL; ptr = sep + 1)
    237256        extract_field (line, ptr, sep - ptr);
    238257    }
    239258  else
     
    305324        size_t jf_1, size_t jf_2)
    306325{
    307326  /* Start of field to compare in each file.  */
    308   char *beg1;
    309   char *beg2;
    310 
    311   size_t len1;
    312   size_t len2;          /* Length of fields to compare.  */
     327  char *beg[2];
     328  char *copy[2];
     329  size_t len[2]; /* Length of fields to compare.  */
    313330  int diff;
     331  int i, j;
    314332
    315333  if (jf_1 < line1->nfields)
    316334    {
    317       beg1 = line1->fields[jf_1].beg;
    318       len1 = line1->fields[jf_1].len;
     335      beg[0] = line1->fields[jf_1].beg;
     336      len[0] = line1->fields[jf_1].len;
    319337    }
    320338  else
    321339    {
    322       beg1 = NULL;
    323       len1 = 0;
     340      beg[0] = NULL;
     341      len[0] = 0;
    324342    }
    325343
    326344  if (jf_2 < line2->nfields)
    327345    {
    328       beg2 = line2->fields[jf_2].beg;
    329       len2 = line2->fields[jf_2].len;
     346      beg[1] = line2->fields[jf_2].beg;
     347      len[1] = line2->fields[jf_2].len;
    330348    }
    331349  else
    332350    {
    333       beg2 = NULL;
    334       len2 = 0;
     351      beg[1] = NULL;
     352      len[1] = 0;
    335353    }
    336354
    337   if (len1 == 0)
    338     return len2 == 0 ? 0 : -1;
    339   if (len2 == 0)
     355  if (len[0] == 0)
     356    return len[1] == 0 ? 0 : -1;
     357  if (len[1] == 0)
    340358    return 1;
    341359
    342360  if (ignore_case)
    343361    {
    344       /* FIXME: ignore_case does not work with NLS (in particular,
    345          with multibyte chars).  */
    346       diff = memcasecmp (beg1, beg2, MIN (len1, len2));
     362#ifdef HAVE_MBRTOWC
     363      if (MB_CUR_MAX > 1)
     364      {
     365        size_t mblength;
     366        wchar_t wc, uwc;
     367        mbstate_t state, state_bak;
     368
     369        memset (&state, '\0', sizeof (mbstate_t));
     370
     371        for (i = 0; i < 2; i++)
     372          {
     373            copy[i] = alloca (len[i] + 1);
     374
     375            for (j = 0; j < MIN (len[0], len[1]);)
     376              {
     377                state_bak = state;
     378                mblength = mbrtowc (&wc, beg[i] + j, len[i] - j, &state);
     379
     380                switch (mblength)
     381                  {
     382                  case (size_t) -1:
     383                  case (size_t) -2:
     384                    state = state_bak;
     385                    /* Fall through */
     386                  case 0:
     387                    mblength = 1;
     388                    break;
     389
     390                  default:
     391                    uwc = towupper (wc);
     392
     393                    if (uwc != wc)
     394                      {
     395                        mbstate_t state_wc;
     396
     397                        memset (&state_wc, '\0', sizeof (mbstate_t));
     398                        wcrtomb (copy[i] + j, uwc, &state_wc);
     399                      }
     400                    else
     401                      memcpy (copy[i] + j, beg[i] + j, mblength);
     402                  }
     403                j += mblength;
     404              }
     405            copy[i][j] = '\0';
     406          }
     407      }
     408      else
     409#endif
     410      {
     411        for (i = 0; i < 2; i++)
     412          {
     413            copy[i] = alloca (len[i] + 1);
     414
     415            for (j = 0; j < MIN (len[0], len[1]); j++)
     416              copy[i][j] = toupper (beg[i][j]);
     417
     418            copy[i][j] = '\0';
     419          }
     420      }
    347421    }
    348422  else
    349423    {
    350       if (hard_LC_COLLATE)
    351         return xmemcoll (beg1, len1, beg2, len2);
    352       diff = memcmp (beg1, beg2, MIN (len1, len2));
     424      copy[0] = (unsigned char *) beg[0];
     425      copy[1] = (unsigned char *) beg[1]; 
    353426    }
    354427
     428  if (hard_LC_COLLATE)
     429    return xmemcoll ((char *) copy[0], len[0], (char *) copy[1], len[1]);
     430  diff = memcmp (copy[0], copy[1], MIN (len[0], len[1]));
     431
     432
    355433  if (diff)
    356434    return diff;
    357   return len1 < len2 ? -1 : len1 != len2;
     435  return len[0] - len[1];
    358436}
    359437
    360438/* Check that successive input lines PREV and CURRENT from input file
     
    393471    }
    394472}
    395473
     474#if HAVE_MBRTOWC
     475static void
     476xfields_multibyte (struct line *line)
     477{
     478  char *ptr = line->buf.buffer;
     479  char const *lim = ptr + line->buf.length - 1;
     480  wchar_t wc = 0;
     481  size_t mblength = 1;
     482  mbstate_t state, state_bak;
     483
     484  memset (&state, 0, sizeof (mbstate_t));
     485
     486  if (ptr == lim)
     487    return;
     488
     489  if (tab != NULL)
     490    {
     491      unsigned char t = tab[0];
     492      char *sep = ptr;
     493      for (; ptr < lim; ptr = sep + mblength)
     494        {
     495          sep = ptr;
     496          while (sep < lim)
     497            {
     498              state_bak = state;
     499              mblength = mbrtowc (&wc, sep, lim - sep + 1, &state);
     500
     501              if (mblength == (size_t)-1 || mblength == (size_t)-2)
     502                {
     503                  mblength = 1;
     504                  state = state_bak;
     505                }
     506              mblength = (mblength < 1) ? 1 : mblength;
     507
     508              if (mblength == tablen && !memcmp (sep, tab, mblength))
     509                break;
     510              else
     511                {
     512                  sep += mblength;
     513                  continue;
     514                }
     515            }
     516
     517          if (sep == lim)
     518            break;
     519
     520          extract_field (line, ptr, sep - ptr);
     521        }
     522    }
     523  else
     524    {
     525      /* Skip leading blanks before the first field.  */
     526      while(ptr < lim)
     527      {
     528        state_bak = state;
     529        mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state);
     530
     531        if (mblength == (size_t)-1 || mblength == (size_t)-2)
     532          {
     533            mblength = 1;
     534            state = state_bak;
     535            break;
     536          }
     537        mblength = (mblength < 1) ? 1 : mblength;
     538
     539        if (!iswblank(wc))
     540          break;
     541        ptr += mblength;
     542      }
     543
     544      do
     545        {
     546          char *sep;
     547          state_bak = state;
     548          mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state);
     549          if (mblength == (size_t)-1 || mblength == (size_t)-2)
     550            {
     551              mblength = 1;
     552              state = state_bak;
     553              break;
     554            }
     555          mblength = (mblength < 1) ? 1 : mblength;
     556
     557          sep = ptr + mblength;
     558          while (sep != lim)
     559            {
     560              state_bak = state;
     561              mblength = mbrtowc (&wc, sep, lim - sep + 1, &state);
     562              if (mblength == (size_t)-1 || mblength == (size_t)-2)
     563                {
     564                  mblength = 1;
     565                  state = state_bak;
     566                  break;
     567                }
     568              mblength = (mblength < 1) ? 1 : mblength;
     569
     570              if (iswblank (wc))
     571                break;
     572
     573              sep += mblength;
     574            }
     575
     576          extract_field (line, ptr, sep - ptr);
     577          if (sep == lim)
     578            return;
     579
     580          state_bak = state;
     581          mblength = mbrtowc (&wc, sep, lim - sep + 1, &state);
     582          if (mblength == (size_t)-1 || mblength == (size_t)-2)
     583            {
     584              mblength = 1;
     585              state = state_bak;
     586              break;
     587            }
     588          mblength = (mblength < 1) ? 1 : mblength;
     589
     590          ptr = sep + mblength;
     591          while (ptr != lim)
     592            {
     593              state_bak = state;
     594              mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state);
     595              if (mblength == (size_t)-1 || mblength == (size_t)-2)
     596                {
     597                  mblength = 1;
     598                  state = state_bak;
     599                  break;
     600                }
     601              mblength = (mblength < 1) ? 1 : mblength;
     602
     603              if (!iswblank (wc))
     604                break;
     605
     606              ptr += mblength;
     607            }
     608        }
     609      while (ptr != lim);
     610    }
     611
     612  extract_field (line, ptr, lim - ptr);
     613}
     614#endif
     615
    396616/* Read a line from FP into LINE and split it into fields.
    397617   Return true if successful.  */
    398618
     
    413633  line->nfields_allocated = 0;
    414634  line->nfields = 0;
    415635  line->fields = NULL;
     636#if HAVE_MBRTOWC
     637  if (MB_CUR_MAX > 1)
     638    xfields_multibyte (line);
     639  else
     640#endif
    416641  xfields (line);
    417642
    418643  if (prevline[which - 1])
     
    509734
    510735/* Print the join of LINE1 and LINE2.  */
    511736
     737#define PUT_TAB_CHAR                                                    \
     738  do                                                                    \
     739    {                                                                   \
     740      (tab != NULL) ?                                                   \
     741        fwrite(tab, sizeof(char), tablen, stdout) : putchar (' ');      \
     742    }                                                                   \
     743  while (0)                                                             
     744
    512745static void
    513746prjoin (struct line const *line1, struct line const *line2)
    514747{
    515748  const struct outlist *outlist;
    516   char output_separator = tab < 0 ? ' ' : tab;
    517749
    518750  outlist = outlist_head.next;
    519751  if (outlist)
     
    529761          if (o->file == 0)
    530762            {
    531763              if (line1 == &uni_blank)
    532                 {
     764                {
    533765                  line = line2;
    534766                  field = join_field_2;
    535767                }
    536768              else
    537                 {
     769                {
    538770                  line = line1;
    539771                  field = join_field_1;
    540772                }
     
    548780          o = o->next;
    549781          if (o == NULL)
    550782            break;
    551           putchar (output_separator);
     783          PUT_TAB_CHAR;
    552784        }
    553785      putchar ('\n');
    554786    }
     
    566798      prfield (join_field_1, line1);
    567799      for (i = 0; i < join_field_1 && i < line1->nfields; ++i)
    568800        {
    569           putchar (output_separator);
     801          PUT_TAB_CHAR;
    570802          prfield (i, line1);
    571803        }
    572804      for (i = join_field_1 + 1; i < line1->nfields; ++i)
    573805        {
    574           putchar (output_separator);
     806          PUT_TAB_CHAR;
    575807          prfield (i, line1);
    576808        }
    577809
    578810      for (i = 0; i < join_field_2 && i < line2->nfields; ++i)
    579811        {
    580           putchar (output_separator);
     812          PUT_TAB_CHAR;
    581813          prfield (i, line2);
    582814        }
    583815      for (i = join_field_2 + 1; i < line2->nfields; ++i)
    584816        {
    585           putchar (output_separator);
     817          PUT_TAB_CHAR;
    586818          prfield (i, line2);
    587819        }
    588820      putchar ('\n');
     
    10161248
    10171249        case 't':
    10181250          {
    1019             unsigned char newtab = optarg[0];
    1020             if (! newtab)
     1251            char *newtab;
     1252            size_t newtablen;
     1253            if (! optarg[0])
    10211254              error (EXIT_FAILURE, 0, _("empty tab"));
    1022             if (optarg[1])
     1255            newtab = xstrdup (optarg);
     1256#if HAVE_MBRTOWC
     1257            if (MB_CUR_MAX > 1)
     1258              {
     1259                mbstate_t state;
     1260
     1261                memset (&state, 0, sizeof (mbstate_t));
     1262                newtablen = mbrtowc (NULL, newtab,
     1263                                     strnlen (newtab, MB_LEN_MAX),
     1264                                     &state);
     1265                if (newtablen == (size_t) 0
     1266                    || newtablen == (size_t) -1
     1267                    || newtablen == (size_t) -2)
     1268                  newtablen = 1;
     1269              }
     1270            else
     1271#endif
     1272              newtablen = 1;
     1273               
     1274            if (newtablen == 1 && newtab[1])
     1275              {
     1276                if (STREQ (newtab, "\\0"))
     1277                  newtab[0] = '\0';
     1278              }
     1279            if (tab != NULL && strcmp (tab, newtab))
    10231280              {
    1024                 if (STREQ (optarg, "\\0"))
    1025                   newtab = '\0';
    1026                 else
    1027                   error (EXIT_FAILURE, 0, _("multi-character tab %s"),
    1028                          quote (optarg));
     1281                free (newtab);
     1282                error (EXIT_FAILURE, 0, _("incompatible tabs"));
    10291283              }
    1030             if (0 <= tab && tab != newtab)
    1031               error (EXIT_FAILURE, 0, _("incompatible tabs"));
    10321284            tab = newtab;
     1285            tablen = newtablen;
    10331286          }
    10341287          break;
    10351288
  • coreutils-6.12

    diff -Naur coreutils-6.12.orig/src/pr.c coreutils-6.12/src/pr.c
    old new  
    312312
    313313#include <getopt.h>
    314314#include <sys/types.h>
     315
     316/* Get MB_LEN_MAX.  */
     317#include <limits.h>
     318/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC
     319   installation; work around this configuration error.  */
     320#if !defined MB_LEN_MAX || MB_LEN_MAX == 1
     321# define MB_LEN_MAX 16
     322#endif
     323
     324/* Get MB_CUR_MAX.  */
     325#include <stdlib.h>
     326
     327/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>.  */
     328/* Get mbstate_t, mbrtowc(), wcwidth().  */
     329#if HAVE_WCHAR_H
     330# include <wchar.h>
     331#endif
     332
     333/* Get iswprint(). -- for wcwidth().  */
     334#if HAVE_WCTYPE_H
     335# include <wctype.h>
     336#endif
     337#if !defined iswprint && !HAVE_ISWPRINT
     338# define iswprint(wc) 1
     339#endif
     340
    315341#include "system.h"
    316342#include "error.h"
    317343#include "hard-locale.h"
     
    322348#include "strftime.h"
    323349#include "xstrtol.h"
    324350
     351/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t.  */
     352#if HAVE_MBRTOWC && defined mbstate_t
     353# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
     354#endif
     355
     356#ifndef HAVE_DECL_WCWIDTH
     357"this configure-time declaration test was not run"
     358#endif
     359#if !HAVE_DECL_WCWIDTH
     360extern int wcwidth ();
     361#endif
     362
    325363/* The official name of this program (e.g., no `g' prefix).  */
    326364#define PROGRAM_NAME "pr"
    327365
     
    416454
    417455#define NULLCOL (COLUMN *)0
    418456
    419 static int char_to_clump (char c);
     457/* Funtion pointers to switch functions for single byte locale or for
     458   multibyte locale. If multibyte functions do not exist in your sysytem,
     459   these pointers always point the function for single byte locale. */
     460static void (*print_char) (char c);
     461static int (*char_to_clump) (char c);
     462
     463/* Functions for single byte locale. */
     464static void print_char_single (char c);
     465static int char_to_clump_single (char c);
     466
     467/* Functions for multibyte locale. */
     468static void print_char_multi (char c);
     469static int char_to_clump_multi (char c);
     470
    420471static bool read_line (COLUMN *p);
    421472static bool print_page (void);
    422473static bool print_stored (COLUMN *p);
     
    426477static void pad_across_to (int position);
    427478static void add_line_number (COLUMN *p);
    428479static void getoptarg (char *arg, char switch_char, char *character,
     480                       int *character_length, int *character_width,
    429481                       int *number);
    430482void usage (int status);
    431483static void print_files (int number_of_files, char **av);
     
    440492static void pad_down (int lines);
    441493static void read_rest_of_line (COLUMN *p);
    442494static void skip_read (COLUMN *p, int column_number);
    443 static void print_char (char c);
    444495static void cleanup (void);
    445496static void print_sep_string (void);
    446497static void separator_string (const char *optarg_S);
     
    455506   we store the leftmost columns contiguously in buff.
    456507   To print a line from buff, get the index of the first character
    457508   from line_vector[i], and print up to line_vector[i + 1]. */
    458 static char *buff;
     509static unsigned char *buff;
    459510
    460511/* Index of the position in buff where the next character
    461512   will be stored. */
     
    559610static bool untabify_input = false;
    560611
    561612/* (-e) The input tab character. */
    562 static char input_tab_char = '\t';
     613static char input_tab_char[MB_LEN_MAX] = "\t";
    563614
    564615/* (-e) Tabstops are at chars_per_tab, 2*chars_per_tab, 3*chars_per_tab, ...
    565616   where the leftmost column is 1. */
     
    569620static bool tabify_output = false;
    570621
    571622/* (-i) The output tab character. */
    572 static char output_tab_char = '\t';
     623static char output_tab_char[MB_LEN_MAX] = "\t";
     624
     625/* (-i) The byte length of output tab character. */
     626static int output_tab_char_length = 1;
    573627
    574628/* (-i) The width of the output tab. */
    575629static int chars_per_output_tab = 8;
     
    643697static bool numbered_lines = false;
    644698
    645699/* (-n) Character which follows each line number. */
    646 static char number_separator = '\t';
     700static char number_separator[MB_LEN_MAX] = "\t";
     701
     702/* (-n) The byte length of the character which follows each line number. */
     703static int number_separator_length = 1;
     704
     705/* (-n) The character width of the character which follows each line number. */
     706static int number_separator_width = 0;
    647707
    648708/* (-n) line counting starts with 1st line of input file (not with 1st
    649709   line of 1st page printed). */
     
    696756   -a|COLUMN|-m is a `space' and with the -J option a `tab'. */
    697757static char *col_sep_string = "";
    698758static int col_sep_length = 0;
     759static int col_sep_width = 0;
    699760static char *column_separator = " ";
    700761static char *line_separator = "\t";
    701762
     
    852913  col_sep_length = (int) strlen (optarg_S);
    853914  col_sep_string = xmalloc (col_sep_length + 1);
    854915  strcpy (col_sep_string, optarg_S);
     916
     917#if HAVE_MBRTOWC
     918  if (MB_CUR_MAX > 1)
     919    col_sep_width = mbswidth (col_sep_string, 0);
     920  else
     921#endif
     922    col_sep_width = col_sep_length;
    855923}
    856924
    857925int
     
    876944
    877945  atexit (close_stdout);
    878946
     947/* Define which functions are used, the ones for single byte locale or the ones
     948   for multibyte locale. */
     949#if HAVE_MBRTOWC
     950  if (MB_CUR_MAX > 1)
     951    {
     952      print_char = print_char_multi;
     953      char_to_clump = char_to_clump_multi;
     954    }
     955  else
     956#endif
     957    {
     958      print_char = print_char_single;
     959      char_to_clump = char_to_clump_single;
     960    }
     961
    879962  n_files = 0;
    880963  file_names = (argc > 1
    881964                ? xmalloc ((argc - 1) * sizeof (char *))
     
    9521035          break;
    9531036        case 'e':
    9541037          if (optarg)
    955             getoptarg (optarg, 'e', &input_tab_char,
    956                        &chars_per_input_tab);
     1038            {
     1039              int dummy_length, dummy_width;
     1040
     1041              getoptarg (optarg, 'e', input_tab_char, &dummy_length,
     1042                         &dummy_width, &chars_per_input_tab);
     1043            }
    9571044          /* Could check tab width > 0. */
    9581045          untabify_input = true;
    9591046          break;
     
    9661053          break;
    9671054        case 'i':
    9681055          if (optarg)
    969             getoptarg (optarg, 'i', &output_tab_char,
    970                        &chars_per_output_tab);
     1056            {
     1057              int dummy_width;
     1058
     1059              getoptarg (optarg, 'i', output_tab_char, &output_tab_char_length,
     1060                         &dummy_width, &chars_per_output_tab);
     1061            }
    9711062          /* Could check tab width > 0. */
    9721063          tabify_output = true;
    9731064          break;
     
    9941085        case 'n':
    9951086          numbered_lines = true;
    9961087          if (optarg)
    997             getoptarg (optarg, 'n', &number_separator,
    998                        &chars_per_number);
     1088            getoptarg (optarg, 'n', number_separator, &number_separator_length,
     1089                       &number_separator_width, &chars_per_number);
    9991090          break;
    10001091        case 'N':
    10011092          skip_count = false;
     
    10341125          old_s = false;
    10351126          /* Reset an additional input of -s, -S dominates -s */
    10361127          col_sep_string = "";
    1037           col_sep_length = 0;
     1128          col_sep_length = col_sep_width = 0;
    10381129          use_col_separator = true;
    10391130          if (optarg)
    10401131            separator_string (optarg);
     
    11911282   a number. */
    11921283
    11931284static void
    1194 getoptarg (char *arg, char switch_char, char *character, int *number)
     1285getoptarg (char *arg, char switch_char, char *character, int *character_length,
     1286           int *character_width, int *number)
    11951287{
    11961288  if (!ISDIGIT (*arg))
    1197     *character = *arg++;
     1289    {
     1290#ifdef HAVE_MBRTOWC
     1291      if (MB_CUR_MAX > 1)       /* for multibyte locale. */
     1292        {
     1293          wchar_t wc;
     1294          size_t mblength;
     1295          int width;
     1296          mbstate_t state = {'\0'};
     1297
     1298          mblength = mbrtowc (&wc, arg, strnlen(arg, MB_LEN_MAX), &state);
     1299
     1300          if (mblength == (size_t)-1 || mblength == (size_t)-2)
     1301            {
     1302              *character_length = 1;
     1303              *character_width = 1;
     1304            }
     1305          else
     1306            {
     1307              *character_length = (mblength < 1) ? 1 : mblength;
     1308              width = wcwidth (wc);
     1309              *character_width = (width < 0) ? 0 : width;
     1310            }
     1311
     1312          strncpy (character, arg, *character_length);
     1313          arg += *character_length;
     1314        }
     1315      else                      /* for single byte locale. */
     1316#endif
     1317        {
     1318          *character = *arg++;
     1319          *character_length = 1;
     1320          *character_width = 1;
     1321        }
     1322    }
     1323
    11981324  if (*arg)
    11991325    {
    12001326      long int tmp_long;
     
    12531379          else
    12541380            col_sep_string = column_separator;
    12551381
    1256           col_sep_length = 1;
     1382          col_sep_length = col_sep_width = 1;
    12571383          use_col_separator = true;
    12581384        }
    12591385      /* It's rather pointless to define a TAB separator with column
     
    12841410             TAB_WIDTH (chars_per_input_tab, chars_per_number);   */
    12851411
    12861412      /* Estimate chars_per_text without any margin and keep it constant. */
    1287       if (number_separator == '\t')
     1413      if (number_separator[0] == '\t')
    12881414        number_width = chars_per_number +
    12891415          TAB_WIDTH (chars_per_default_tab, chars_per_number);
    12901416      else
    1291         number_width = chars_per_number + 1;
     1417        number_width = chars_per_number + number_separator_width;
    12921418
    12931419      /* The number is part of the column width unless we are
    12941420         printing files in parallel. */
     
    13031429    }
    13041430
    13051431  chars_per_column = (chars_per_line - chars_used_by_number -
    1306                      (columns - 1) * col_sep_length) / columns;
     1432                     (columns - 1) * col_sep_width) / columns;
    13071433
    13081434  if (chars_per_column < 1)
    13091435    error (EXIT_FAILURE, 0, _("page width too narrow"));
     
    14281554
    14291555  /* Enlarge p->start_position of first column to use the same form of
    14301556     padding_not_printed with all columns. */
    1431   h = h + col_sep_length;
     1557  h = h + col_sep_width;
    14321558
    14331559  /* This loop takes care of all but the rightmost column. */
    14341560
     
    14621588        }
    14631589      else
    14641590        {
    1465           h = h_next + col_sep_length;
     1591          h = h_next + col_sep_width;
    14661592          h_next = h + chars_per_column;
    14671593        }
    14681594    }
     
    17521878align_column (COLUMN *p)
    17531879{
    17541880  padding_not_printed = p->start_position;
    1755   if (padding_not_printed - col_sep_length > 0)
     1881  if (padding_not_printed - col_sep_width > 0)
    17561882    {
    1757       pad_across_to (padding_not_printed - col_sep_length);
     1883      pad_across_to (padding_not_printed - col_sep_width);
    17581884      padding_not_printed = ANYWHERE;
    17591885    }
    17601886
     
    20252151      /* May be too generous. */
    20262152      buff = X2REALLOC (buff, &buff_allocated);
    20272153    }
    2028   buff[buff_current++] = c;
     2154  buff[buff_current++] = (unsigned char) c;
    20292155}
    20302156
    20312157static void
    20322158add_line_number (COLUMN *p)
    20332159{
    2034   int i;
     2160  int i, j;
    20352161  char *s;
    20362162  int left_cut;
    20372163
     
    20542180      /* Tabification is assumed for multiple columns, also for n-separators,
    20552181         but `default n-separator = TAB' hasn't been given priority over
    20562182         equal column_width also specified by POSIX. */
    2057       if (number_separator == '\t')
     2183      if (number_separator[0] == '\t')
    20582184        {
    20592185          i = number_width - chars_per_number;
    20602186          while (i-- > 0)
    20612187            (p->char_func) (' ');
    20622188        }
    20632189      else
    2064         (p->char_func) (number_separator);
     2190        for (j = 0; j < number_separator_length; j++)
     2191          (p->char_func) (number_separator[j]);
    20652192    }
    20662193  else
    20672194    /* To comply with POSIX, we avoid any expansion of default TAB
    20682195       separator with a single column output. No column_width requirement
    20692196       has to be considered. */
    20702197    {
    2071       (p->char_func) (number_separator);
    2072       if (number_separator == '\t')
     2198      for (j = 0; j < number_separator_length; j++)
     2199        (p->char_func) (number_separator[j]);
     2200      if (number_separator[0] == '\t')
    20732201        output_position = POS_AFTER_TAB (chars_per_output_tab,
    20742202                          output_position);
    20752203    }
     
    22302358  while (goal - h_old > 1
    22312359         && (h_new = POS_AFTER_TAB (chars_per_output_tab, h_old)) <= goal)
    22322360    {
    2233       putchar (output_tab_char);
     2361      fwrite (output_tab_char, sizeof(char), output_tab_char_length, stdout);
    22342362      h_old = h_new;
    22352363    }
    22362364  while (++h_old <= goal)
     
    22502378{
    22512379  char *s;
    22522380  int l = col_sep_length;
     2381  int not_space_flag;
    22532382
    22542383  s = col_sep_string;
    22552384
     
    22632392    {
    22642393      for (; separators_not_printed > 0; --separators_not_printed)
    22652394        {
     2395          not_space_flag = 0;
    22662396          while (l-- > 0)
    22672397            {
    22682398              /* 3 types of sep_strings: spaces only, spaces and chars,
     
    22762406                }
    22772407              else
    22782408                {
     2409                  not_space_flag = 1;
    22792410                  if (spaces_not_printed > 0)
    22802411                    print_white_space ();
    22812412                  putchar (*s++);
    2282                   ++output_position;
    22832413                }
    22842414            }
     2415          if (not_space_flag)
     2416            output_position += col_sep_width;
     2417
    22852418          /* sep_string ends with some spaces */
    22862419          if (spaces_not_printed > 0)
    22872420            print_white_space ();
     
    23092442   required number of tabs and spaces. */
    23102443
    23112444static void
    2312 print_char (char c)
     2445print_char_single (char c)
    23132446{
    23142447  if (tabify_output)
    23152448    {
     
    23332466  putchar (c);
    23342467}
    23352468
     2469#ifdef HAVE_MBRTOWC
     2470static void
     2471print_char_multi (char c)
     2472{
     2473  static size_t mbc_pos = 0;
     2474  static char mbc[MB_LEN_MAX] = {'\0'};
     2475  static mbstate_t state = {'\0'};
     2476  mbstate_t state_bak;
     2477  wchar_t wc;
     2478  size_t mblength;
     2479  int width;
     2480
     2481  if (tabify_output)
     2482    {
     2483      state_bak = state;
     2484      mbc[mbc_pos++] = c;
     2485      mblength = mbrtowc (&wc, mbc, mbc_pos, &state);
     2486
     2487      while (mbc_pos > 0)
     2488        {
     2489          switch (mblength)
     2490            {
     2491            case (size_t)-2:
     2492              state = state_bak;
     2493              return;
     2494
     2495            case (size_t)-1:
     2496              state = state_bak;
     2497              ++output_position;
     2498              putchar (mbc[0]);
     2499              memmove (mbc, mbc + 1, MB_CUR_MAX - 1);
     2500              --mbc_pos;
     2501              break;
     2502
     2503            case 0:
     2504              mblength = 1;
     2505
     2506            default:
     2507              if (wc == L' ')
     2508                {
     2509                  memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength);
     2510                  --mbc_pos;
     2511                  ++spaces_not_printed;
     2512                  return;
     2513                }
     2514              else if (spaces_not_printed > 0)
     2515                print_white_space ();
     2516
     2517              /* Nonprintables are assumed to have width 0, except L'\b'. */
     2518              if ((width = wcwidth (wc)) < 1)
     2519                {
     2520                  if (wc == L'\b')
     2521                    --output_position;
     2522                }
     2523              else
     2524                output_position += width;
     2525
     2526              fwrite (mbc, sizeof(char), mblength, stdout);
     2527              memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength);
     2528              mbc_pos -= mblength;
     2529            }
     2530        }
     2531      return;
     2532    }
     2533  putchar (c);
     2534}
     2535#endif
     2536
    23362537/* Skip to page PAGE before printing.
    23372538   PAGE may be larger than total number of pages. */
    23382539
     
    25102711          align_empty_cols = false;
    25112712        }
    25122713
    2513       if (padding_not_printed - col_sep_length > 0)
     2714      if (padding_not_printed - col_sep_width > 0)
    25142715        {
    2515           pad_across_to (padding_not_printed - col_sep_length);
     2716          pad_across_to (padding_not_printed - col_sep_width);
    25162717          padding_not_printed = ANYWHERE;
    25172718        }
    25182719
     
    26132814        }
    26142815    }
    26152816
    2616   if (padding_not_printed - col_sep_length > 0)
     2817  if (padding_not_printed - col_sep_width > 0)
    26172818    {
    2618       pad_across_to (padding_not_printed - col_sep_length);
     2819      pad_across_to (padding_not_printed - col_sep_width);
    26192820      padding_not_printed = ANYWHERE;
    26202821    }
    26212822
     
    26282829  if (spaces_not_printed == 0)
    26292830    {
    26302831      output_position = p->start_position + end_vector[line];
    2631       if (p->start_position - col_sep_length == chars_per_margin)
    2632         output_position -= col_sep_length;
     2832      if (p->start_position - col_sep_width == chars_per_margin)
     2833        output_position -= col_sep_width;
    26332834    }
    26342835
    26352836  return true;
     
    26482849   number of characters is 1.) */
    26492850
    26502851static int
    2651 char_to_clump (char c)
     2852char_to_clump_single (char c)
    26522853{
    26532854  unsigned char uc = c;
    26542855  char *s = clump_buff;
     
    26582859  int chars;
    26592860  int chars_per_c = 8;
    26602861
    2661   if (c == input_tab_char)
     2862  if (c == input_tab_char[0])
    26622863    chars_per_c = chars_per_input_tab;
    26632864
    2664   if (c == input_tab_char || c == '\t')
     2865  if (c == input_tab_char[0] || c == '\t')
    26652866    {
    26662867      width = TAB_WIDTH (chars_per_c, input_position);
    26672868
     
    27422943  return chars;
    27432944}
    27442945
     2946#ifdef HAVE_MBRTOWC
     2947static int
     2948char_to_clump_multi (char c)
     2949{
     2950  static size_t mbc_pos = 0;
     2951  static char mbc[MB_LEN_MAX] = {'\0'};
     2952  static mbstate_t state = {'\0'};
     2953  mbstate_t state_bak;
     2954  wchar_t wc;
     2955  size_t mblength;
     2956  int wc_width;
     2957  register char *s = clump_buff;
     2958  register int i, j;
     2959  char esc_buff[4];
     2960  int width;
     2961  int chars;
     2962  int chars_per_c = 8;
     2963
     2964  state_bak = state;
     2965  mbc[mbc_pos++] = c;
     2966  mblength = mbrtowc (&wc, mbc, mbc_pos, &state);
     2967
     2968  width = 0;
     2969  chars = 0;
     2970  while (mbc_pos > 0)
     2971    {
     2972      switch (mblength)
     2973        {
     2974        case (size_t)-2:
     2975          state = state_bak;
     2976          return 0;
     2977
     2978        case (size_t)-1:
     2979          state = state_bak;
     2980          mblength = 1;
     2981
     2982          if (use_esc_sequence || use_cntrl_prefix)
     2983            {
     2984              width = +4;
     2985              chars = +4;
     2986              *s++ = '\\';
     2987              sprintf (esc_buff, "%03o", mbc[0]);
     2988              for (i = 0; i <= 2; ++i)
     2989                *s++ = (int) esc_buff[i];
     2990            }
     2991          else
     2992            {
     2993              width += 1;
     2994              chars += 1;
     2995              *s++ = mbc[0];
     2996            }
     2997          break;
     2998
     2999        case 0:
     3000          mblength = 1;
     3001                /* Fall through */
     3002
     3003        default:
     3004          if (memcmp (mbc, input_tab_char, mblength) == 0)
     3005            chars_per_c = chars_per_input_tab;
     3006
     3007          if (memcmp (mbc, input_tab_char, mblength) == 0 || c == '\t')
     3008            {
     3009              int  width_inc;
     3010
     3011              width_inc = TAB_WIDTH (chars_per_c, input_position);
     3012              width += width_inc;
     3013
     3014              if (untabify_input)
     3015                {
     3016                  for (i = width_inc; i; --i)
     3017                    *s++ = ' ';
     3018                  chars += width_inc;
     3019                }
     3020              else
     3021                {
     3022                  for (i = 0; i <  mblength; i++)
     3023                    *s++ = mbc[i];
     3024                  chars += mblength;
     3025                }
     3026            }
     3027          else if ((wc_width = wcwidth (wc)) < 1)
     3028            {
     3029              if (use_esc_sequence)
     3030                {
     3031                  for (i = 0; i < mblength; i++)
     3032                    {
     3033                      width += 4;
     3034                      chars += 4;
     3035                      *s++ = '\\';
     3036                      sprintf (esc_buff, "%03o", c);
     3037                      for (j = 0; j <= 2; ++j)
     3038                        *s++ = (int) esc_buff[j];
     3039                    }
     3040                }
     3041              else if (use_cntrl_prefix)
     3042                {
     3043                  if (wc < 0200)
     3044                    {
     3045                      width += 2;
     3046                      chars += 2;
     3047                      *s++ = '^';
     3048                      *s++ = wc ^ 0100;
     3049                    }
     3050                  else
     3051                    {
     3052                      for (i = 0; i < mblength; i++)
     3053                        {
     3054                          width += 4;
     3055                          chars += 4;
     3056                          *s++ = '\\';
     3057                          sprintf (esc_buff, "%03o", c);
     3058                          for (j = 0; j <= 2; ++j)
     3059                            *s++ = (int) esc_buff[j];
     3060                        }
     3061                    }
     3062                }
     3063              else if (wc == L'\b')
     3064                {
     3065                  width += -1;
     3066                  chars += 1;
     3067                  *s++ = c;
     3068                }
     3069              else
     3070                {
     3071                  width += 0;
     3072                  chars += mblength;
     3073                  for (i = 0; i < mblength; i++)
     3074                    *s++ = mbc[i];
     3075                }
     3076            }
     3077          else
     3078            {
     3079              width += wc_width;
     3080              chars += mblength;
     3081              for (i = 0; i < mblength; i++)
     3082                *s++ = mbc[i];
     3083            }
     3084        }
     3085      memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength);
     3086      mbc_pos -= mblength;
     3087    }
     3088
     3089  input_position += width;
     3090  return chars;
     3091}
     3092#endif
     3093
    27453094/* We've just printed some files and need to clean up things before
    27463095   looking for more options and printing the next batch of files.
    27473096
  • coreutils-6.12

    diff -Naur coreutils-6.12.orig/src/sort.c coreutils-6.12/src/sort.c
    old new  
    2222
    2323#include <config.h>
    2424
     25#include <assert.h>
    2526#include <getopt.h>
    2627#include <sys/types.h>
    2728#include <sys/wait.h>
    2829#include <signal.h>
     30#if HAVE_WCHAR_H
     31# include <wchar.h>
     32#endif
     33/* Get isw* functions. */
     34#if HAVE_WCTYPE_H
     35# include <wctype.h>
     36#endif
     37
    2938#include "system.h"
    3039#include "argmatch.h"
    3140#include "error.h"
     
    117126/* Thousands separator; if -1, then there isn't one.  */
    118127static int thousands_sep;
    119128
     129static int force_general_numcompare = 0;
     130
    120131/* Nonzero if the corresponding locales are hard.  */
    121132static bool hard_LC_COLLATE;
    122 #if HAVE_NL_LANGINFO
     133#if HAVE_LANGINFO_CODESET
    123134static bool hard_LC_TIME;
    124135#endif
    125136
    126137#define NONZERO(x) ((x) != 0)
    127138
     139/* get a multibyte character's byte length. */
     140#define GET_BYTELEN_OF_CHAR(LIM, PTR, MBLENGTH, STATE)                  \
     141  do                                                                    \
     142    {                                                                   \
     143      wchar_t wc;                                                       \
     144      mbstate_t state_bak;                                              \
     145                                                                        \
     146      state_bak = STATE;                                                \
     147      mblength = mbrtowc (&wc, PTR, LIM - PTR, &STATE);                 \
     148                                                                        \
     149      switch (MBLENGTH)                                                 \
     150        {                                                               \
     151        case (size_t)-1:                                                \
     152        case (size_t)-2:                                                \
     153          STATE = state_bak;                                            \
     154                /* Fall through. */                                     \
     155        case 0:                                                         \
     156          MBLENGTH = 1;                                                 \
     157      }                                                                 \
     158    }                                                                   \
     159  while (0)
     160
    128161/* The kind of blanks for '-b' to skip in various options. */
    129162enum blanktype { bl_start, bl_end, bl_both };
    130163
     
    262295   they were read if all keys compare equal.  */
    263296static bool stable;
    264297
    265 /* If TAB has this value, blanks separate fields.  */
    266 enum { TAB_DEFAULT = CHAR_MAX + 1 };
    267 
    268 /* Tab character separating fields.  If TAB_DEFAULT, then fields are
     298/* Tab character separating fields.  If tab_length is 0, then fields are
    269299   separated by the empty string between a non-blank character and a blank
    270300   character. */
    271 static int tab = TAB_DEFAULT;
     301static char tab[MB_LEN_MAX + 1];
     302static size_t tab_length = 0;
    272303
    273304/* Flag to remove consecutive duplicate lines from the output.
    274305   Only the last of a sequence of equal lines will be output. */
     
    655686    update_proc (pid);
    656687}
    657688
     689/* Function pointers. */
     690static void
     691(*inittables) (void);
     692static char *
     693(*begfield) (const struct line*, const struct keyfield *);
     694static char *
     695(*limfield) (const struct line*, const struct keyfield *);
     696static int
     697(*getmonth) (char const *, size_t);
     698static int
     699(*keycompare) (const struct line *, const struct line *);
     700static int
     701(*numcompare) (const char *, const char *);
     702
     703/* Test for white space multibyte character.
     704   Set LENGTH the byte length of investigated multibyte character. */
     705#if HAVE_MBRTOWC
     706static int
     707ismbblank (const char *str, size_t len, size_t *length)
     708{
     709  size_t mblength;
     710  wchar_t wc;
     711  mbstate_t state;
     712
     713  memset (&state, '\0', sizeof(mbstate_t));
     714  mblength = mbrtowc (&wc, str, len, &state);
     715
     716  if (mblength == (size_t)-1 || mblength == (size_t)-2)
     717    {
     718      *length = 1;
     719      return 0;
     720    }
     721
     722  *length = (mblength < 1) ? 1 : mblength;
     723  return iswblank (wc);
     724}
     725#endif
     726
    658727/* Clean up any remaining temporary files.  */
    659728
    660729static void
     
    9941063  free (node);
    9951064}
    9961065
    997 #if HAVE_NL_LANGINFO
     1066#if HAVE_LANGINFO_CODESET
    9981067
    9991068static int
    10001069struct_month_cmp (const void *m1, const void *m2)
     
    10091078/* Initialize the character class tables. */
    10101079
    10111080static void
    1012 inittables (void)
     1081inittables_uni (void)
    10131082{
    10141083  size_t i;
    10151084
     
    10211090      fold_toupper[i] = toupper (i);
    10221091    }
    10231092
    1024 #if HAVE_NL_LANGINFO
     1093#if HAVE_LANGINFO_CODESET
    10251094  /* If we're not in the "C" locale, read different names for months.  */
    10261095  if (hard_LC_TIME)
    10271096    {
     
    10471116#endif
    10481117}
    10491118
     1119#if HAVE_MBRTOWC
     1120static void
     1121inittables_mb (void)
     1122{
     1123  int i, j, k, l;
     1124  char *name, *s;
     1125  size_t s_len, mblength;
     1126  char mbc[MB_LEN_MAX];
     1127  wchar_t wc, pwc;
     1128  mbstate_t state_mb, state_wc;
     1129
     1130  for (i = 0; i < MONTHS_PER_YEAR; i++)
     1131    {
     1132      s = (char *) nl_langinfo (ABMON_1 + i);
     1133      s_len = strlen (s);
     1134      monthtab[i].name = name = (char *) xmalloc (s_len + 1);
     1135      monthtab[i].val = i + 1;
     1136
     1137      memset (&state_mb, '\0', sizeof (mbstate_t));
     1138      memset (&state_wc, '\0', sizeof (mbstate_t));
     1139
     1140      for (j = 0; j < s_len;)
     1141        {
     1142          if (!ismbblank (s + j, s_len - j, &mblength))
     1143            break;
     1144          j += mblength;
     1145        }
     1146
     1147      for (k = 0; j < s_len;)
     1148        {
     1149          mblength = mbrtowc (&wc, (s + j), (s_len - j), &state_mb);
     1150          assert (mblength != (size_t)-1 && mblength != (size_t)-2);
     1151          if (mblength == 0)
     1152            break;
     1153
     1154          pwc = towupper (wc);
     1155          if (pwc == wc)
     1156            {
     1157              memcpy (mbc, s + j, mblength);
     1158              j += mblength;
     1159            }
     1160          else
     1161            {
     1162              j += mblength;
     1163              mblength = wcrtomb (mbc, pwc, &state_wc);
     1164              assert (mblength != (size_t)0 && mblength != (size_t)-1);
     1165            }
     1166
     1167          for (l = 0; l < mblength; l++)
     1168            name[k++] = mbc[l];
     1169        }
     1170      name[k] = '\0';
     1171    }
     1172  qsort ((void *) monthtab, MONTHS_PER_YEAR,
     1173      sizeof (struct month), struct_month_cmp);
     1174}
     1175#endif
     1176
    10501177/* Specify the amount of main memory to use when sorting.  */
    10511178static void
    10521179specify_sort_size (int oi, char c, char const *s)
     
    12571384   by KEY in LINE. */
    12581385
    12591386static char *
    1260 begfield (const struct line *line, const struct keyfield *key)
     1387begfield_uni (const struct line *line, const struct keyfield *key)
    12611388{
    12621389  char *ptr = line->text, *lim = ptr + line->length - 1;
    12631390  size_t sword = key->sword;
     
    12671394  /* The leading field separator itself is included in a field when -t
    12681395     is absent.  */
    12691396
    1270   if (tab != TAB_DEFAULT)
     1397  if (tab_length)
    12711398    while (ptr < lim && sword--)
    12721399      {
    1273         while (ptr < lim && *ptr != tab)
     1400        while (ptr < lim && *ptr != tab[0])
    12741401          ++ptr;
    12751402        if (ptr < lim)
    12761403          ++ptr;
     
    12981425  return ptr;
    12991426}
    13001427
     1428#if HAVE_MBRTOWC
     1429static char *
     1430begfield_mb (const struct line *line, const struct keyfield *key)
     1431{
     1432  int i;
     1433  char *ptr = line->text, *lim = ptr + line->length - 1;
     1434  size_t sword = key->sword;
     1435  size_t schar = key->schar;
     1436  size_t mblength;
     1437  mbstate_t state;
     1438
     1439  memset (&state, '\0', sizeof(mbstate_t));
     1440
     1441  if (tab_length)
     1442    while (ptr < lim && sword--)
     1443      {
     1444        while (ptr < lim && memcmp (ptr, tab, tab_length) != 0)
     1445          {
     1446            GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
     1447            ptr += mblength;
     1448          }
     1449        if (ptr < lim)
     1450          {
     1451            GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
     1452            ptr += mblength;
     1453          }
     1454      }
     1455  else
     1456    while (ptr < lim && sword--)
     1457      {
     1458        while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength))
     1459          ptr += mblength;
     1460        if (ptr < lim)
     1461          {
     1462            GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
     1463            ptr += mblength;
     1464          }
     1465        while (ptr < lim && !ismbblank (ptr, lim - ptr, &mblength))
     1466          ptr += mblength;
     1467      }
     1468
     1469  if (key->skipsblanks)
     1470    while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength))
     1471      ptr += mblength;
     1472
     1473  for (i = 0; i < schar; i++)
     1474    {
     1475      GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
     1476
     1477      if (ptr + mblength > lim)
     1478        break;
     1479      else
     1480        ptr += mblength;
     1481    }
     1482
     1483  return ptr;
     1484}
     1485#endif
     1486
    13011487/* Return the limit of (a pointer to the first character after) the field
    13021488   in LINE specified by KEY. */
    13031489
    13041490static char *
    1305 limfield (const struct line *line, const struct keyfield *key)
     1491limfield_uni (const struct line *line, const struct keyfield *key)
    13061492{
    13071493  char *ptr = line->text, *lim = ptr + line->length - 1;
    13081494  size_t eword = key->eword, echar = key->echar;
     
    13151501     `beginning' is the first character following the delimiting TAB.
    13161502     Otherwise, leave PTR pointing at the first `blank' character after
    13171503     the preceding field.  */
    1318   if (tab != TAB_DEFAULT)
     1504  if (tab_length)
    13191505    while (ptr < lim && eword--)
    13201506      {
    1321         while (ptr < lim && *ptr != tab)
     1507        while (ptr < lim && *ptr != tab[0])
    13221508          ++ptr;
    13231509        if (ptr < lim && (eword | echar))
    13241510          ++ptr;
     
    13641550     */
    13651551
    13661552  /* Make LIM point to the end of (one byte past) the current field.  */
    1367   if (tab != TAB_DEFAULT)
     1553  if (tab_length)
    13681554    {
    13691555      char *newlim;
    1370       newlim = memchr (ptr, tab, lim - ptr);
     1556      newlim = memchr (ptr, tab[0], lim - ptr);
    13711557      if (newlim)
    13721558        lim = newlim;
    13731559    }
     
    14001586  return ptr;
    14011587}
    14021588
     1589#if HAVE_MBRTOWC
     1590static char *
     1591limfield_mb (const struct line *line, const struct keyfield *key)
     1592{
     1593  char *ptr = line->text, *lim = ptr + line->length - 1;
     1594  size_t eword = key->eword, echar = key->echar;
     1595  int i;
     1596  size_t mblength;
     1597  mbstate_t state;
     1598
     1599  memset (&state, '\0', sizeof(mbstate_t));
     1600
     1601  if (tab_length)
     1602    while (ptr < lim && eword--)
     1603      {
     1604        while (ptr < lim && memcmp (ptr, tab, tab_length) != 0)
     1605          {
     1606            GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
     1607            ptr += mblength;
     1608          }
     1609        if (ptr < lim && (eword | echar))
     1610          {
     1611            GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
     1612            ptr += mblength;
     1613          }
     1614      }
     1615  else
     1616    while (ptr < lim && eword--)
     1617      {
     1618        while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength))
     1619          ptr += mblength;
     1620        if (ptr < lim)
     1621          {
     1622            GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
     1623            ptr += mblength;
     1624          }
     1625        while (ptr < lim && !ismbblank (ptr, lim - ptr, &mblength))
     1626          ptr += mblength;
     1627      }
     1628
     1629
     1630# ifdef POSIX_UNSPECIFIED
     1631  /* Make LIM point to the end of (one byte past) the current field.  */
     1632  if (tab_length)
     1633    {
     1634      char *newlim, *p;
     1635
     1636      newlim = NULL;
     1637      for (p = ptr; p < lim;)
     1638        {
     1639          if (memcmp (p, tab, tab_length) == 0)
     1640            {
     1641              newlim = p;
     1642              break;
     1643            }
     1644
     1645          GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
     1646          p += mblength;
     1647        }
     1648    }
     1649  else
     1650    {
     1651      char *newlim;
     1652      newlim = ptr;
     1653
     1654      while (newlim < lim && ismbblank (newlim, lim - newlim, &mblength))
     1655        newlim += mblength;
     1656      if (ptr < lim)
     1657        {
     1658          GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
     1659          ptr += mblength;
     1660        }
     1661      while (newlim < lim && !ismbblank (newlim, lim - newlim, &mblength))
     1662        newlim += mblength;
     1663      lim = newlim;
     1664    }
     1665# endif
     1666
     1667  /* If we're skipping leading blanks, don't start counting characters
     1668   *      until after skipping past any leading blanks.  */
     1669  if (key->skipsblanks)
     1670    while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength))
     1671      ptr += mblength;
     1672
     1673  memset (&state, '\0', sizeof(mbstate_t));
     1674
     1675  /* Advance PTR by ECHAR (if possible), but no further than LIM.  */
     1676  for (i = 0; i < echar; i++)
     1677    {
     1678      GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
     1679
     1680      if (ptr + mblength > lim)
     1681        break;
     1682      else
     1683        ptr += mblength;
     1684    }
     1685
     1686  return ptr;
     1687}
     1688#endif
     1689
    14031690/* Fill BUF reading from FP, moving buf->left bytes from the end
    14041691   of buf->buf to the beginning first.  If EOF is reached and the
    14051692   file wasn't terminated by a newline, supply one.  Set up BUF's line
     
    14821769                  else
    14831770                    {
    14841771                      if (key->skipsblanks)
    1485                         while (blanks[to_uchar (*line_start)])
    1486                           line_start++;
     1772                        {
     1773#if HAVE_MBRTOWC
     1774                          if (MB_CUR_MAX > 1)
     1775                            {
     1776                              size_t mblength;
     1777                              mbstate_t state;
     1778                              memset (&state, '\0', sizeof(mbstate_t));
     1779                              while (line_start < line->keylim &&
     1780                                     ismbblank (line_start,
     1781                                                line->keylim - line_start,
     1782                                                &mblength))
     1783                                line_start += mblength;
     1784                            }
     1785                          else
     1786#endif
     1787                          while (blanks[to_uchar (*line_start)])
     1788                            line_start++;
     1789                        }
    14871790                      line->keybeg = line_start;
    14881791                    }
    14891792                }
     
    15211824   hideously fast. */
    15221825
    15231826static int
    1524 numcompare (const char *a, const char *b)
     1827numcompare_uni (const char *a, const char *b)
    15251828{
    15261829  while (blanks[to_uchar (*a)])
    15271830    a++;
     
    15311834  return strnumcmp (a, b, decimal_point, thousands_sep);
    15321835}
    15331836
     1837#if HAVE_MBRTOWC
     1838static int
     1839numcompare_mb (const char *a, const char *b)
     1840{
     1841  size_t mblength, len;
     1842  len = strlen (a); /* okay for UTF-8 */
     1843  while (*a && ismbblank (a, len > MB_CUR_MAX ? MB_CUR_MAX : len, &mblength))
     1844    {
     1845      a += mblength;
     1846      len -= mblength;
     1847    }
     1848  len = strlen (b); /* okay for UTF-8 */
     1849  while (*b && ismbblank (b, len > MB_CUR_MAX ? MB_CUR_MAX : len, &mblength))
     1850    b += mblength;
     1851
     1852  return strnumcmp (a, b, decimal_point, thousands_sep);
     1853}
     1854#endif /* HAV_EMBRTOWC */
     1855
    15341856static int
    15351857general_numcompare (const char *sa, const char *sb)
    15361858{
     
    15641886   Return 0 if the name in S is not recognized.  */
    15651887
    15661888static int
    1567 getmonth (char const *month, size_t len)
     1889getmonth_uni (char const *month, size_t len)
    15681890{
    15691891  size_t lo = 0;
    15701892  size_t hi = MONTHS_PER_YEAR;
     
    17192041  return diff;
    17202042}
    17212043
     2044#if HAVE_MBRTOWC
     2045static int
     2046getmonth_mb (const char *s, size_t len)
     2047{
     2048  char *month;
     2049  register size_t i;
     2050  register int lo = 0, hi = MONTHS_PER_YEAR, result;
     2051  char *tmp;
     2052  size_t wclength, mblength;
     2053  const char **pp;
     2054  const wchar_t **wpp;
     2055  wchar_t *month_wcs;
     2056  mbstate_t state;
     2057
     2058  while (len > 0 && ismbblank (s, len, &mblength))
     2059    {
     2060      s += mblength;
     2061      len -= mblength;
     2062    }
     2063
     2064  if (len == 0)
     2065    return 0;
     2066
     2067  month = (char *) alloca (len + 1);
     2068
     2069  tmp = (char *) alloca (len + 1);
     2070  memcpy (tmp, s, len);
     2071  tmp[len] = '\0';
     2072  pp = (const char **)&tmp;
     2073  month_wcs = (wchar_t *) alloca ((len + 1) * sizeof (wchar_t));
     2074  memset (&state, '\0', sizeof(mbstate_t));
     2075
     2076  wclength = mbsrtowcs (month_wcs, pp, len + 1, &state);
     2077  assert (wclength != (size_t)-1 && *pp == NULL);
     2078
     2079  for (i = 0; i < wclength; i++)
     2080    {
     2081      month_wcs[i] = towupper(month_wcs[i]);
     2082      if (iswblank (month_wcs[i]))
     2083        {
     2084          month_wcs[i] = L'\0';
     2085          break;
     2086        }
     2087    }
     2088
     2089  wpp = (const wchar_t **)&month_wcs;
     2090
     2091  mblength = wcsrtombs (month, wpp, len + 1, &state);
     2092  assert (mblength != (-1) && *wpp == NULL);
     2093
     2094  do
     2095    {
     2096      int ix = (lo + hi) / 2;
     2097
     2098      if (strncmp (month, monthtab[ix].name, strlen (monthtab[ix].name)) < 0)
     2099        hi = ix;
     2100      else
     2101        lo = ix;
     2102    }
     2103  while (hi - lo > 1);
     2104
     2105  result = (!strncmp (month, monthtab[lo].name, strlen (monthtab[lo].name))
     2106      ? monthtab[lo].val : 0);
     2107
     2108  return result;
     2109}
     2110#endif
     2111
    17222112/* Compare two lines A and B trying every key in sequence until there
    17232113   are no more keys or a difference is found. */
    17242114
    17252115static int
    1726 keycompare (const struct line *a, const struct line *b)
     2116keycompare_uni (const struct line *a, const struct line *b)
    17272117{
    17282118  struct keyfield const *key = keylist;
    17292119
     
    18962286  return key->reverse ? -diff : diff;
    18972287}
    18982288
     2289#if HAVE_MBRTOWC
     2290static int
     2291keycompare_mb (const struct line *a, const struct line *b)
     2292{
     2293  struct keyfield *key = keylist;
     2294
     2295  /* For the first iteration only, the key positions have been
     2296     precomputed for us. */
     2297  char *texta = a->keybeg;
     2298  char *textb = b->keybeg;
     2299  char *lima = a->keylim;
     2300  char *limb = b->keylim;
     2301
     2302  size_t mblength_a, mblength_b;
     2303  wchar_t wc_a, wc_b;
     2304  mbstate_t state_a, state_b;
     2305
     2306  int diff;
     2307
     2308  memset (&state_a, '\0', sizeof(mbstate_t));
     2309  memset (&state_b, '\0', sizeof(mbstate_t));
     2310
     2311  for (;;)
     2312    {
     2313      unsigned char *translate = (unsigned char *) key->translate;
     2314      bool const *ignore = key->ignore;
     2315
     2316      /* Find the lengths. */
     2317      size_t lena = lima <= texta ? 0 : lima - texta;
     2318      size_t lenb = limb <= textb ? 0 : limb - textb;
     2319
     2320      /* Actually compare the fields. */
     2321      if (key->random)
     2322        diff = compare_random (texta, lena, textb, lenb);
     2323      else if (key->numeric | key->general_numeric)
     2324        {
     2325          char savea = *lima, saveb = *limb;
     2326
     2327          *lima = *limb = '\0';
     2328          if (force_general_numcompare)
     2329            diff = general_numcompare (texta, textb);
     2330          else
     2331            diff = ((key->numeric ? numcompare : general_numcompare)
     2332                (texta, textb));
     2333          *lima = savea, *limb = saveb;
     2334        }
     2335      else if (key->month)
     2336        diff = getmonth (texta, lena) - getmonth (textb, lenb);
     2337      else
     2338        {
     2339          if (ignore || translate)
     2340            {
     2341              char *copy_a = (char *) alloca (lena + 1 + lenb + 1);
     2342              char *copy_b = copy_a + lena + 1;
     2343              size_t new_len_a, new_len_b;
     2344              size_t i, j;
     2345
     2346              /* Ignore and/or translate chars before comparing.  */
     2347# define IGNORE_CHARS(NEW_LEN, LEN, TEXT, COPY, WC, MBLENGTH, STATE)    \
     2348  do                                                                    \
     2349    {                                                                   \
     2350      wchar_t uwc;                                                      \
     2351      char mbc[MB_LEN_MAX];                                             \
     2352      mbstate_t state_wc;                                               \
     2353                                                                        \
     2354      for (NEW_LEN = i = 0; i < LEN;)                                   \
     2355        {                                                               \
     2356          mbstate_t state_bak;                                          \
     2357                                                                        \
     2358          state_bak = STATE;                                            \
     2359          MBLENGTH = mbrtowc (&WC, TEXT + i, LEN - i, &STATE);          \
     2360                                                                        \
     2361          if (MBLENGTH == (size_t)-2 || MBLENGTH == (size_t)-1          \
     2362              || MBLENGTH == 0)                                         \
     2363            {                                                           \
     2364              if (MBLENGTH == (size_t)-2 || MBLENGTH == (size_t)-1)     \
     2365                STATE = state_bak;                                      \
     2366              if (!ignore)                                              \
     2367                COPY[NEW_LEN++] = TEXT[i++];                            \
     2368              continue;                                                 \
     2369            }                                                           \
     2370                                                                        \
     2371          if (ignore)                                                   \
     2372            {                                                           \
     2373              if ((ignore == nonprinting && !iswprint (WC))             \
     2374                   || (ignore == nondictionary                          \
     2375                       && !iswalnum (WC) && !iswblank (WC)))            \
     2376                {                                                       \
     2377                  i += MBLENGTH;                                        \
     2378                  continue;                                             \
     2379                }                                                       \
     2380            }                                                           \
     2381                                                                        \
     2382          if (translate)                                                \
     2383            {                                                           \
     2384                                                                        \
     2385              uwc = towupper(WC);                                       \
     2386              if (WC == uwc)                                            \
     2387                {                                                       \
     2388                  memcpy (mbc, TEXT + i, MBLENGTH);                     \
     2389                  i += MBLENGTH;                                        \
     2390                }                                                       \
     2391              else                                                      \
     2392                {                                                       \
     2393                  i += MBLENGTH;                                        \
     2394                  WC = uwc;                                             \
     2395                  memset (&state_wc, '\0', sizeof (mbstate_t));         \
     2396                                                                        \
     2397                  MBLENGTH = wcrtomb (mbc, WC, &state_wc);              \
     2398                  assert (MBLENGTH != (size_t)-1 && MBLENGTH != 0);     \
     2399                }                                                       \
     2400                                                                        \
     2401              for (j = 0; j < MBLENGTH; j++)                            \
     2402                COPY[NEW_LEN++] = mbc[j];                               \
     2403            }                                                           \
     2404          else                                                          \
     2405            for (j = 0; j < MBLENGTH; j++)                              \
     2406              COPY[NEW_LEN++] = TEXT[i++];                              \
     2407        }                                                               \
     2408      COPY[NEW_LEN] = '\0';                                             \
     2409    }                                                                   \
     2410  while (0)
     2411              IGNORE_CHARS (new_len_a, lena, texta, copy_a,
     2412                            wc_a, mblength_a, state_a);
     2413              IGNORE_CHARS (new_len_b, lenb, textb, copy_b,
     2414                            wc_b, mblength_b, state_b);
     2415              diff = xmemcoll (copy_a, new_len_a, copy_b, new_len_b);
     2416            }
     2417          else if (lena == 0)
     2418            diff = - NONZERO (lenb);
     2419          else if (lenb == 0)
     2420            goto greater;
     2421          else
     2422            diff = xmemcoll (texta, lena, textb, lenb);
     2423        }
     2424
     2425      if (diff)
     2426        goto not_equal;
     2427
     2428      key = key->next;
     2429      if (! key)
     2430        break;
     2431
     2432      /* Find the beginning and limit of the next field.  */
     2433      if (key->eword != -1)
     2434        lima = limfield (a, key), limb = limfield (b, key);
     2435      else
     2436        lima = a->text + a->length - 1, limb = b->text + b->length - 1;
     2437
     2438      if (key->sword != -1)
     2439        texta = begfield (a, key), textb = begfield (b, key);
     2440      else
     2441        {
     2442          texta = a->text, textb = b->text;
     2443          if (key->skipsblanks)
     2444            {
     2445              while (texta < lima && ismbblank (texta, lima - texta, &mblength_a))
     2446                texta += mblength_a;
     2447              while (textb < limb && ismbblank (textb, limb - textb, &mblength_b))
     2448                textb += mblength_b;
     2449            }
     2450        }
     2451    }
     2452
     2453  return 0;
     2454
     2455greater:
     2456  diff = 1;
     2457not_equal:
     2458  return key->reverse ? -diff : diff;
     2459}
     2460#endif
     2461
    18992462/* Compare two lines A and B, returning negative, zero, or positive
    19002463   depending on whether A compares less than, equal to, or greater than B. */
    19012464
     
    27653328  initialize_exit_failure (SORT_FAILURE);
    27663329
    27673330  hard_LC_COLLATE = hard_locale (LC_COLLATE);
    2768 #if HAVE_NL_LANGINFO
     3331#if HAVE_LANGINFO_CODESET
    27693332  hard_LC_TIME = hard_locale (LC_TIME);
    27703333#endif
    27713334
     
    27863349      thousands_sep = -1;
    27873350  }
    27883351
     3352#if HAVE_MBRTOWC
     3353  if (MB_CUR_MAX > 1)
     3354    {
     3355      inittables = inittables_mb;
     3356      begfield = begfield_mb;
     3357      limfield = limfield_mb;
     3358      getmonth = getmonth_mb;
     3359      keycompare = keycompare_mb;
     3360      numcompare = numcompare_mb;
     3361    }
     3362  else
     3363#endif
     3364    {
     3365      inittables = inittables_uni;
     3366      begfield = begfield_uni;
     3367      limfield = limfield_uni;
     3368      getmonth = getmonth_uni;
     3369      keycompare = keycompare_uni;
     3370      numcompare = numcompare_uni;
     3371    }
     3372
    27893373  have_read_stdin = false;
    27903374  inittables ();
    27913375
     
    30373621
    30383622        case 't':
    30393623          {
    3040             char newtab = optarg[0];
    3041             if (! newtab)
     3624            char newtab[MB_LEN_MAX + 1];
     3625            size_t newtab_length = 1;
     3626            strncpy (newtab, optarg, MB_LEN_MAX);
     3627            if (! newtab[0])
    30423628              error (SORT_FAILURE, 0, _("empty tab"));
    3043             if (optarg[1])
     3629#if HAVE_MBRTOWC
     3630            if (MB_CUR_MAX > 1)
     3631              {
     3632                wchar_t wc;
     3633                mbstate_t state;
     3634                size_t i;
     3635
     3636                memset (&state, '\0', sizeof (mbstate_t));
     3637                newtab_length = mbrtowc (&wc, newtab, strnlen (newtab,
     3638                                                               MB_LEN_MAX),
     3639                                         &state);
     3640                switch (newtab_length)
     3641                  {
     3642                  case (size_t) -1:
     3643                  case (size_t) -2:
     3644                  case 0:
     3645                    newtab_length = 1;
     3646                  }
     3647              }
     3648#endif
     3649            if (newtab_length == 1 && optarg[1])
    30443650              {
    30453651                if (STREQ (optarg, "\\0"))
    3046                   newtab = '\0';
     3652                  newtab[0] = '\0';
    30473653                else
    30483654                  {
    30493655                    /* Provoke with `sort -txx'.  Complain about
     
    30543660                           quote (optarg));
    30553661                  }
    30563662              }
    3057             if (tab != TAB_DEFAULT && tab != newtab)
     3663            if (tab_length
     3664                && (tab_length != newtab_length
     3665                    || memcmp (tab, newtab, tab_length) != 0))
    30583666              error (SORT_FAILURE, 0, _("incompatible tabs"));
    3059             tab = newtab;
     3667            memcpy (tab, newtab, newtab_length);
     3668            tab_length = newtab_length;
    30603669          }
    30613670          break;
    30623671
  • src/unexpand.c

    diff -Naur coreutils-6.12.orig/src/unexpand.c coreutils-6.12/src/unexpand.c
    old new  
    3838#include <stdio.h>
    3939#include <getopt.h>
    4040#include <sys/types.h>
     41
     42/* Get mbstate_t, mbrtowc(), wcwidth(). */
     43#if HAVE_WCHAR_H
     44# include <wchar.h>
     45#endif
     46
    4147#include "system.h"
    4248#include "error.h"
    4349#include "quote.h"
    4450#include "xstrndup.h"
    4551
     52/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC
     53      installation; work around this configuration error.  */
     54#if !defined MB_LEN_MAX || MB_LEN_MAX < 2
     55# define MB_LEN_MAX 16
     56#endif
     57
     58/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t.  */
     59#if HAVE_MBRTOWC && defined mbstate_t
     60# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
     61#endif
     62
    4663/* The official name of this program (e.g., no `g' prefix).  */
    4764#define PROGRAM_NAME "unexpand"
    4865
     
    109126  {NULL, 0, NULL, 0}
    110127};
    111128
     129static FILE *next_file (FILE *fp);
     130
     131#if HAVE_MBRTOWC
     132static void
     133unexpand_multibyte (void)
     134{
     135  FILE *fp;                     /* Input stream. */
     136  mbstate_t i_state;            /* Current shift state of the input stream. */
     137  mbstate_t i_state_bak;        /* Back up the I_STATE. */
     138  mbstate_t o_state;            /* Current shift state of the output stream. */
     139  char buf[MB_LEN_MAX + BUFSIZ];  /* For spooling a read byte sequence. */
     140  char *bufpos;                 /* Next read position of BUF. */
     141  size_t buflen = 0;            /* The length of the byte sequence in buf. */
     142  wint_t wc;                    /* A gotten wide character. */
     143  size_t mblength;              /* The byte size of a multibyte character
     144                                   which shows as same character as WC. */
     145
     146  /* Index in `tab_list' of next tabstop: */
     147  int tab_index = 0;            /* For calculating width of pending tabs. */
     148  int print_tab_index = 0;      /* For printing as many tabs as possible. */
     149  unsigned int column = 0;      /* Column on screen of next char. */
     150  int next_tab_column;          /* Column the next tab stop is on. */
     151  int convert = 1;              /* If nonzero, perform translations. */
     152  unsigned int pending = 0;     /* Pending columns of blanks. */
     153
     154  fp = next_file ((FILE *) NULL);
     155  if (fp == NULL)
     156    return;
     157
     158  memset (&o_state, '\0', sizeof(mbstate_t));
     159  memset (&i_state, '\0', sizeof(mbstate_t));
     160
     161  for (;;)
     162    {
     163      if (buflen < MB_LEN_MAX && !feof(fp) && !ferror(fp))
     164        {
     165          memmove (buf, bufpos, buflen);
     166          buflen += fread (buf + buflen, sizeof(char), BUFSIZ, fp);
     167          bufpos = buf;
     168        }
     169
     170      /* Get a wide character. */
     171      if (buflen < 1)
     172        {
     173          mblength = 1;
     174          wc = WEOF;
     175        }
     176      else
     177        {
     178          i_state_bak = i_state;
     179          mblength = mbrtowc ((wchar_t *)&wc, bufpos, buflen, &i_state);
     180        }
     181
     182      if (mblength == (size_t)-1 || mblength == (size_t)-2)
     183        {
     184          i_state = i_state_bak;
     185          wc = L'\0';
     186        }
     187
     188      if (wc == L' ' && convert && column < INT_MAX)
     189        {
     190          ++pending;
     191          ++column;
     192        }
     193      else if (wc == L'\t' && convert)
     194        {
     195          if (tab_size == 0)
     196            {
     197              /* Do not let tab_index == first_free_tab;
     198                 stop when it is 1 less. */
     199              while (tab_index < first_free_tab - 1
     200                  && column >= tab_list[tab_index])
     201                tab_index++;
     202              next_tab_column = tab_list[tab_index];
     203              if (tab_index < first_free_tab - 1)
     204                tab_index++;
     205              if (column >= next_tab_column)
     206                {
     207                  convert = 0;  /* Ran out of tab stops. */
     208                  goto flush_pend_mb;
     209                }
     210            }
     211          else
     212            {
     213              next_tab_column = column + tab_size - column % tab_size;
     214            }
     215          pending += next_tab_column - column;
     216          column = next_tab_column;
     217        }
     218      else
     219        {
     220flush_pend_mb:
     221          /* Flush pending spaces.  Print as many tabs as possible,
     222             then print the rest as spaces. */
     223          if (pending == 1)
     224            {
     225              putchar (' ');
     226              pending = 0;
     227            }
     228          column -= pending;
     229          while (pending > 0)
     230            {
     231              if (tab_size == 0)
     232                {
     233                  /* Do not let print_tab_index == first_free_tab;
     234                     stop when it is 1 less. */
     235                  while (print_tab_index < first_free_tab - 1
     236                      && column >= tab_list[print_tab_index])
     237                    print_tab_index++;
     238                  next_tab_column = tab_list[print_tab_index];
     239                  if (print_tab_index < first_free_tab - 1)
     240                    print_tab_index++;
     241                }
     242              else
     243                {
     244                  next_tab_column =
     245                    column + tab_size - column % tab_size;
     246                }
     247              if (next_tab_column - column <= pending)
     248                {
     249                  putchar ('\t');
     250                  pending -= next_tab_column - column;
     251                  column = next_tab_column;
     252                }
     253              else
     254                {
     255                  --print_tab_index;
     256                  column += pending;
     257                  while (pending != 0)
     258                    {
     259                      putchar (' ');
     260                      pending--;
     261                    }
     262                }
     263            }
     264
     265          if (wc == WEOF)
     266            {
     267              fp = next_file (fp);
     268              if (fp == NULL)
     269                break;          /* No more files. */
     270              else
     271                {
     272                  memset (&i_state, '\0', sizeof(mbstate_t));
     273                  continue;
     274                }
     275            }
     276
     277          if (mblength == (size_t)-1 || mblength == (size_t)-2)
     278            {
     279              if (convert)
     280                {
     281                  ++column;
     282                  if (convert_entire_line == 0)
     283                    convert = 0;
     284                }
     285              mblength = 1;
     286              putchar (buf[0]);
     287            }
     288          else if (mblength == 0)
     289            {
     290              if (convert && convert_entire_line == 0)
     291                convert = 0;
     292              mblength = 1;
     293              putchar ('\0');
     294            }
     295          else
     296            {
     297              if (convert)
     298                {
     299                  if (wc == L'\b')
     300                    {
     301                      if (column > 0)
     302                        --column;
     303                    }
     304                  else
     305                    {
     306                      int width;            /* The width of WC. */
     307
     308                      width = wcwidth (wc);
     309                      column += (width > 0) ? width : 0;
     310                      if (convert_entire_line == 0)
     311                        convert = 0;
     312                    }
     313                }
     314
     315              if (wc == L'\n')
     316                {
     317                  tab_index = print_tab_index = 0;
     318                  column = pending = 0;
     319                  convert = 1;
     320                }
     321              fwrite (bufpos, sizeof(char), mblength, stdout);
     322            }
     323        }
     324      buflen -= mblength;
     325      bufpos += mblength;
     326    }
     327}
     328#endif
     329
     330
    112331void
    113332usage (int status)
    114333{
     
    530749
    531750  file_list = (optind < argc ? &argv[optind] : stdin_argv);
    532751
    533   unexpand ();
     752#if HAVE_MBRTOWC
     753  if (MB_CUR_MAX > 1)
     754    unexpand_multibyte ();
     755  else
     756#endif
     757    unexpand ();
    534758
    535759  if (have_read_stdin && fclose (stdin) != 0)
    536760    error (EXIT_FAILURE, errno, "-");
  • coreutils-6.12

    diff -Naur coreutils-6.12.orig/src/uniq.c coreutils-6.12/src/uniq.c
    old new  
    2222#include <getopt.h>
    2323#include <sys/types.h>
    2424
     25/* Get mbstate_t, mbrtowc(). */
     26#if HAVE_WCHAR_H
     27# include <wchar.h>
     28#endif
     29
     30/* Get isw* functions. */
     31#if HAVE_WCTYPE_H
     32# include <wctype.h>
     33#endif
     34
    2535#include "system.h"
    2636#include "argmatch.h"
    2737#include "linebuffer.h"
     
    3141#include "quote.h"
    3242#include "xmemcoll.h"
    3343#include "xstrtol.h"
    34 #include "memcasecmp.h"
     44#include "xmemcoll.h"
     45
     46/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC
     47   installation; work around this configuration error.  */
     48#if !defined MB_LEN_MAX || MB_LEN_MAX < 2
     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
    3557
    3658/* The official name of this program (e.g., no `g' prefix).  */
    3759#define PROGRAM_NAME "uniq"
     
    110132/* Select whether/how to delimit groups of duplicate lines.  */
    111133static enum delimit_method delimit_groups;
    112134
     135/* Function pointers. */
     136static char *
     137(*find_field) (struct linebuffer *line);
     138
    113139static struct option const longopts[] =
    114140{
    115141  {"count", no_argument, NULL, 'c'},
     
    206232   return a pointer to the beginning of the line's field to be compared. */
    207233
    208234static char *
    209 find_field (const struct linebuffer *line)
     235find_field_uni (struct linebuffer *line)
    210236{
    211237  size_t count;
    212238  char *lp = line->buffer;
     
    227253  return lp + i;
    228254}
    229255
     256#if HAVE_MBRTOWC
     257
     258# define MBCHAR_TO_WCHAR(WC, MBLENGTH, LP, POS, SIZE, STATEP, CONVFAIL)  \
     259  do                                                                    \
     260    {                                                                   \
     261      mbstate_t state_bak;                                              \
     262                                                                        \
     263      CONVFAIL = 0;                                                     \
     264      state_bak = *STATEP;                                              \
     265                                                                        \
     266      MBLENGTH = mbrtowc (&WC, LP + POS, SIZE - POS, STATEP);           \
     267                                                                        \
     268      switch (MBLENGTH)                                                 \
     269        {                                                               \
     270        case (size_t)-2:                                                \
     271        case (size_t)-1:                                                \
     272          *STATEP = state_bak;                                          \
     273          CONVFAIL++;                                                   \
     274          /* Fall through */                                            \
     275        case 0:                                                         \
     276          MBLENGTH = 1;                                                 \
     277        }                                                               \
     278    }                                                                   \
     279  while (0)
     280
     281static char *
     282find_field_multi (struct linebuffer *line)
     283{
     284  size_t count;
     285  char *lp = line->buffer;
     286  size_t size = line->length - 1;
     287  size_t pos;
     288  size_t mblength;
     289  wchar_t wc;
     290  mbstate_t *statep;
     291  int convfail;
     292
     293  pos = 0;
     294  statep = &(line->state);
     295
     296  /* skip fields. */
     297  for (count = 0; count < skip_fields && pos < size; count++)
     298    {
     299      while (pos < size)
     300        {
     301          MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail);
     302 
     303          if (convfail || !iswblank (wc))
     304            {
     305              pos += mblength;
     306              break;
     307            }
     308          pos += mblength;
     309        }
     310
     311      while (pos < size)
     312        {
     313          MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail);
     314
     315          if (!convfail && iswblank (wc))
     316            break;
     317
     318          pos += mblength;
     319        }
     320    }
     321
     322  /* skip fields. */
     323  for (count = 0; count < skip_chars && pos < size; count++)
     324    {
     325      MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail);
     326      pos += mblength;
     327    }
     328
     329  return lp + pos;
     330}
     331#endif
     332
    230333/* Return false if two strings OLD and NEW match, true if not.
    231334   OLD and NEW point not to the beginnings of the lines
    232335   but rather to the beginnings of the fields to compare.
     
    235338static bool
    236339different (char *old, char *new, size_t oldlen, size_t newlen)
    237340{
     341  char *copy_old, *copy_new;
     342
    238343  if (check_chars < oldlen)
    239344    oldlen = check_chars;
    240345  if (check_chars < newlen)
     
    242347
    243348  if (ignore_case)
    244349    {
    245       /* FIXME: This should invoke strcoll somehow.  */
    246       return oldlen != newlen || memcasecmp (old, new, oldlen);
     350      size_t i;
     351
     352      copy_old = alloca (oldlen + 1);
     353      copy_new = alloca (oldlen + 1);
     354
     355      for (i = 0; i < oldlen; i++)
     356        {
     357          copy_old[i] = toupper (old[i]);
     358          copy_new[i] = toupper (new[i]);
     359        }
    247360    }
    248   else if (hard_LC_COLLATE)
    249     return xmemcoll (old, oldlen, new, newlen) != 0;
    250361  else
    251     return oldlen != newlen || memcmp (old, new, oldlen);
     362    {
     363      copy_old = (char *)old;
     364      copy_new = (char *)new;
     365    }
     366
     367  return xmemcoll (copy_old, oldlen, copy_new, newlen);
     368}
     369
     370#if HAVE_MBRTOWC
     371static int
     372different_multi (const char *old, const char *new, size_t oldlen, size_t newlen, mbstate_t oldstate, mbstate_t newstate)
     373{
     374  size_t i, j, chars;
     375  const char *str[2];
     376  char *copy[2];
     377  size_t len[2];
     378  mbstate_t state[2];
     379  size_t mblength;
     380  wchar_t wc, uwc;
     381  mbstate_t state_bak;
     382
     383  str[0] = old;
     384  str[1] = new;
     385  len[0] = oldlen;
     386  len[1] = newlen;
     387  state[0] = oldstate;
     388  state[1] = newstate;
     389
     390  for (i = 0; i < 2; i++)
     391    {
     392      copy[i] = alloca (len[i] + 1);
     393
     394      for (j = 0, chars = 0; j < len[i] && chars < check_chars; chars++)
     395        {
     396          state_bak = state[i];
     397          mblength = mbrtowc (&wc, str[i] + j, len[i] - j, &(state[i]));
     398
     399          switch (mblength)
     400            {
     401            case (size_t)-1:
     402            case (size_t)-2:
     403              state[i] = state_bak;
     404              /* Fall through */
     405            case 0:
     406              mblength = 1;
     407              break;
     408
     409            default:
     410              if (ignore_case)
     411                {
     412                  uwc = towupper (wc);
     413
     414                  if (uwc != wc)
     415                    {
     416                      mbstate_t state_wc;
     417
     418                      memset (&state_wc, '\0', sizeof(mbstate_t));
     419                      wcrtomb (copy[i] + j, uwc, &state_wc);
     420                    }
     421                  else
     422                    memcpy (copy[i] + j, str[i] + j, mblength);
     423                }
     424              else
     425                memcpy (copy[i] + j, str[i] + j, mblength);
     426            }
     427          j += mblength;
     428        }
     429      copy[i][j] = '\0';
     430      len[i] = j;
     431    }
     432
     433  return xmemcoll (copy[0], len[0], copy[1], len[1]);
    252434}
     435#endif
    253436
    254437/* Output the line in linebuffer LINE to standard output
    255438   provided that the switches say it should be output.
     
    303486    {
    304487      char *prevfield IF_LINT (= NULL);
    305488      size_t prevlen IF_LINT (= 0);
     489#if HAVE_MBRTOWC
     490      mbstate_t prevstate;
     491
     492      memset (&prevstate, '\0', sizeof (mbstate_t));
     493#endif
    306494
    307495      while (!feof (stdin))
    308496        {
    309497          char *thisfield;
    310498          size_t thislen;
     499#if HAVE_MBRTOWC
     500          mbstate_t thisstate;
     501#endif
     502
    311503          if (readlinebuffer_delim (thisline, stdin, delimiter) == 0)
    312504            break;
    313505          thisfield = find_field (thisline);
    314506          thislen = thisline->length - 1 - (thisfield - thisline->buffer);
     507#if HAVE_MBRTOWC
     508          if (MB_CUR_MAX > 1)
     509            {
     510            thisstate = thisline->state;
     511
     512            if (prevline->length == 0 || different_multi
     513              (thisfield, prevfield, thislen, prevlen, thisstate, prevstate))
     514              {
     515                fwrite (thisline->buffer, sizeof (char),
     516                        thisline->length, stdout);
     517
     518                SWAP_LINES (prevline, thisline);
     519                prevfield = thisfield;
     520                prevlen = thislen;
     521                prevstate = thisstate;
     522              }
     523          }
     524        else
     525#endif
    315526          if (prevline->length == 0
    316527              || different (thisfield, prevfield, thislen, prevlen))
    317528            {
     
    330541      size_t prevlen;
    331542      uintmax_t match_count = 0;
    332543      bool first_delimiter = true;
     544#if HAVE_MBRTOWC
     545      mbstate_t prevstate;
     546#endif
    333547
    334548      if (readlinebuffer_delim (prevline, stdin, delimiter) == 0)
    335549        goto closefiles;
    336550      prevfield = find_field (prevline);
    337551      prevlen = prevline->length - 1 - (prevfield - prevline->buffer);
     552#if HAVE_MBRTOWC
     553      prevstate = prevline->state;
     554#endif
    338555
    339556      while (!feof (stdin))
    340557        {
    341558          bool match;
    342559          char *thisfield;
    343560          size_t thislen;
     561#if HAVE_MBRTOWC
     562          mbstate_t thisstate;
     563#endif
    344564          if (readlinebuffer_delim (thisline, stdin, delimiter) == 0)
    345565            {
    346566              if (ferror (stdin))
     
    349569            }
    350570          thisfield = find_field (thisline);
    351571          thislen = thisline->length - 1 - (thisfield - thisline->buffer);
     572#if HAVE_MBRTOWC
     573          if (MB_CUR_MAX > 1)
     574            {
     575              thisstate = thisline->state;
     576              match = !different_multi (thisfield, prevfield,
     577                                thislen, prevlen, thisstate, prevstate);
     578            }
     579          else
     580#endif
    352581          match = !different (thisfield, prevfield, thislen, prevlen);
    353582          match_count += match;
    354583
     
    381610              SWAP_LINES (prevline, thisline);
    382611              prevfield = thisfield;
    383612              prevlen = thislen;
     613#if HAVE_MBRTOWC
     614              prevstate = thisstate;
     615#endif
    384616              if (!match)
    385617                match_count = 0;
    386618            }
     
    426658
    427659  atexit (close_stdout);
    428660
     661#if HAVE_MBRTOWC
     662  if (MB_CUR_MAX > 1)
     663    {
     664      find_field = find_field_multi;
     665    }
     666  else
     667#endif
     668    {
     669      find_field = find_field_uni;
     670    }
     671
     672
     673
    429674  skip_chars = 0;
    430675  skip_fields = 0;
    431676  check_chars = SIZE_MAX;
  • tests/Makefile.am

    diff -Naur coreutils-6.12.orig/tests/Makefile.am coreutils-6.12/tests/Makefile.am
    old new  
    191191  misc/shuf                                     \
    192192  misc/sort                                     \
    193193  misc/sort-compress                            \
     194  misc/sort-mb-tests                            \
    194195  misc/sort-merge                               \
    195196  misc/sort-rand                                \
    196197  misc/split-a                                  \
     
    391392  $(root_tests)
    392393
    393394pr_data =                                       \
     395  misc/mb1.X                    \
     396  misc/mb1.I                    \
     397  misc/mb2.X                    \
     398  misc/mb2.I                    \
    394399  pr/0F                                         \
    395400  pr/0FF                                        \
    396401  pr/0FFnt                                      \
  • tests/misc/mb1.I

    diff -Naur coreutils-6.12.orig/tests/misc/mb1.I coreutils-6.12/tests/misc/mb1.I
    old new  
     1AppleïŒ 10
     2BananaïŒ 5
     3CitrusïŒ 20
     4CherryïŒ 30
  • tests/misc/mb1.X

    diff -Naur coreutils-6.12.orig/tests/misc/mb1.X coreutils-6.12/tests/misc/mb1.X
    old new  
     1BananaïŒ 5
     2AppleïŒ 10
     3CitrusïŒ 20
     4CherryïŒ 30
  • tests/misc/mb2.I

    diff -Naur coreutils-6.12.orig/tests/misc/mb2.I coreutils-6.12/tests/misc/mb2.I
    old new  
     1AppleïŒ ïŒ¡ïŒ¡10ïŒ ïŒ 20
     2BananaïŒ ïŒ¡ïŒ¡5ïŒ ïŒ 30
     3CitrusïŒ ïŒ¡ïŒ¡20ïŒ ïŒ 5
     4CherryïŒ ïŒ¡ïŒ¡30ïŒ ïŒ 10
  • tests/misc/mb2.X

    diff -Naur coreutils-6.12.orig/tests/misc/mb2.X coreutils-6.12/tests/misc/mb2.X
    old new  
     1CitrusïŒ ïŒ¡ïŒ¡20ïŒ ïŒ 5
     2CherryïŒ ïŒ¡ïŒ¡30ïŒ ïŒ 10
     3AppleïŒ ïŒ¡ïŒ¡10ïŒ ïŒ 20
     4BananaïŒ ïŒ¡ïŒ¡5ïŒ ïŒ 30
  • tests/misc/sort-mb-tests

    diff -Naur coreutils-6.12.orig/tests/misc/sort-mb-tests coreutils-6.12/tests/misc/sort-mb-tests
    old new  
     1#! /bin/sh
     2case $# in
     3  0) xx='../src/sort';;
     4  *) xx="$1";;
     5esac
     6test "$VERBOSE" && echo=echo || echo=:
     7$echo testing program: $xx
     8errors=0
     9test "$srcdir" || srcdir=.
     10test "$VERBOSE" && $xx --version 2> /dev/null
     11
     12export LC_ALL=en_US.UTF-8
     13locale -k LC_CTYPE 2>&1 | grep -q charmap.*UTF-8 || exit 77
     14errors=0
     15
     16$xx -t  -k2 -n misc/mb1.I > misc/mb1.O
     17code=$?
     18if test $code != 0; then
     19  $echo "Test mb1 failed: $xx return code $code differs from expected value 0" 1>&2
     20  errors=`expr $errors + 1`
     21else
     22  cmp misc/mb1.O $srcdir/misc/mb1.X > /dev/null 2>&1
     23  case $? in
     24    0) if test "$VERBOSE"; then $echo "passed mb1"; fi;;
     25    1) $echo "Test mb1 failed: files misc/mb1.O and $srcdir/misc/mb1.X differ" 1>&2
     26       (diff -c misc/mb1.O $srcdir/misc/mb1.X) 2> /dev/null
     27       errors=`expr $errors + 1`;;
     28    2) $echo "Test mb1 may have failed." 1>&2
     29       $echo The command "cmp misc/mb1.O $srcdir/misc/mb1.X" failed. 1>&2
     30       errors=`expr $errors + 1`;;
     31  esac
     32fi
     33
     34$xx -t  -k4 -n misc/mb2.I > misc/mb2.O
     35code=$?
     36if test $code != 0; then
     37  $echo "Test mb2 failed: $xx return code $code differs from expected value 0" 1>&2
     38  errors=`expr $errors + 1`
     39else
     40  cmp misc/mb2.O $srcdir/misc/mb2.X > /dev/null 2>&1
     41  case $? in
     42    0) if test "$VERBOSE"; then $echo "passed mb2"; fi;;
     43    1) $echo "Test mb2 failed: files misc/mb2.O and $srcdir/misc/mb2.X differ" 1>&2
     44       (diff -c misc/mb2.O $srcdir/misc/mb2.X) 2> /dev/null
     45       errors=`expr $errors + 1`;;
     46    2) $echo "Test mb2 may have failed." 1>&2
     47       $echo The command "cmp misc/mb2.O $srcdir/misc/mb2.X" failed. 1>&2
     48       errors=`expr $errors + 1`;;
     49  esac
     50fi
     51
     52if test $errors = 0; then
     53  $echo Passed all 113 tests. 1>&2
     54else
     55  $echo Failed $errors tests. 1>&2
     56fi
     57test $errors = 0 || errors=1
     58exit $errors
Note: See TracBrowser for help on using the repository browser.