Kamil Dudka 8d9eac
diff --git a/src/cut.c b/src/cut.c
Kamil Dudka 8d9eac
index 7ab6be4..022d0ad 100644
Kamil Dudka 8d9eac
--- a/src/cut.c
Kamil Dudka 8d9eac
+++ b/src/cut.c
Ondřej Vašík b0302e
@@ -28,6 +28,11 @@
Ondřej Vašík b0302e
 #include <assert.h>
Ondřej Vašík b0302e
 #include <getopt.h>
Ondřej Vašík b0302e
 #include <sys/types.h>
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+/* Get mbstate_t, mbrtowc().  */
Ondřej Vašík b0302e
+#if HAVE_WCHAR_H
Ondřej Vašík b0302e
+# include <wchar.h>
Ondřej Vašík b0302e
+#endif
Ondřej Vašík b0302e
 #include "system.h"
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
 #include "error.h"
Ondřej Vašík b0302e
@@ -38,6 +43,18 @@
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
 #include "set-fields.h"
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
+/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC
Ondřej Vašík b0302e
+   installation; work around this configuration error.        */
Ondřej Vašík b0302e
+#if !defined MB_LEN_MAX || MB_LEN_MAX < 2
Ondřej Vašík b0302e
+# undef MB_LEN_MAX
Ondřej Vašík b0302e
+# define MB_LEN_MAX 16
Ondřej Vašík b0302e
+#endif
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t.  */
Ondřej Vašík b0302e
+#if HAVE_MBRTOWC && defined mbstate_t
Ondřej Vašík b0302e
+# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
Ondřej Vašík b0302e
+#endif
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
 /* The official name of this program (e.g., no 'g' prefix).  */
Ondřej Vašík b0302e
 #define PROGRAM_NAME "cut"
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
@@ -54,6 +71,52 @@
Ondřej Vašík b0302e
     }									\
Ondřej Vašík b0302e
   while (0)
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
+/* Refill the buffer BUF to get a multibyte character. */
Ondřej Vašík b0302e
+#define REFILL_BUFFER(BUF, BUFPOS, BUFLEN, STREAM)                        \
Ondřej Vašík b0302e
+  do                                                                        \
Ondřej Vašík b0302e
+    {                                                                        \
Ondřej Vašík b0302e
+      if (BUFLEN < MB_LEN_MAX && !feof (STREAM) && !ferror (STREAM))        \
Ondřej Vašík b0302e
+        {                                                                \
Ondřej Vašík b0302e
+          memmove (BUF, BUFPOS, BUFLEN);                                \
Ondřej Vašík b0302e
+          BUFLEN += fread (BUF + BUFLEN, sizeof(char), BUFSIZ, STREAM); \
Ondřej Vašík b0302e
+          BUFPOS = BUF;                                                        \
Ondřej Vašík b0302e
+        }                                                                \
Ondřej Vašík b0302e
+    }                                                                        \
Ondřej Vašík b0302e
+  while (0)
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+/* Get wide character on BUFPOS. BUFPOS is not included after that.
Ondřej Vašík b0302e
+   If byte sequence is not valid as a character, CONVFAIL is true. Otherwise false. */
Ondřej Vašík b0302e
+#define GET_NEXT_WC_FROM_BUFFER(WC, BUFPOS, BUFLEN, MBLENGTH, STATE, CONVFAIL) \
Ondřej Vašík b0302e
+  do                                                                        \
Ondřej Vašík b0302e
+    {                                                                        \
Ondřej Vašík b0302e
+      mbstate_t state_bak;                                                \
Ondřej Vašík b0302e
+                                                                        \
Ondřej Vašík b0302e
+      if (BUFLEN < 1)                                                        \
Ondřej Vašík b0302e
+        {                                                                \
Ondřej Vašík b0302e
+          WC = WEOF;                                                        \
Ondřej Vašík b0302e
+          break;                                                        \
Ondřej Vašík b0302e
+        }                                                                \
Ondřej Vašík b0302e
+                                                                        \
Ondřej Vašík b0302e
+      /* Get a wide character. */                                        \
Ondřej Vašík b0302e
+      CONVFAIL = false;                                                        \
Ondřej Vašík b0302e
+      state_bak = STATE;                                                \
Ondřej Vašík b0302e
+      MBLENGTH = mbrtowc ((wchar_t *)&WC, BUFPOS, BUFLEN, &STATE);        \
Ondřej Vašík b0302e
+                                                                        \
Ondřej Vašík b0302e
+      switch (MBLENGTH)                                                        \
Ondřej Vašík b0302e
+        {                                                                \
Ondřej Vašík b0302e
+        case (size_t)-1:                                                \
Ondřej Vašík b0302e
+        case (size_t)-2:                                                \
Ondřej Vašík b0302e
+          CONVFAIL = true;                                                        \
Ondřej Vašík b0302e
+          STATE = state_bak;                                                \
Ondřej Vašík b0302e
+          /* Fall througn. */                                                \
Ondřej Vašík b0302e
+                                                                        \
Ondřej Vašík b0302e
+        case 0:                                                                \
Ondřej Vašík b0302e
+          MBLENGTH = 1;                                                        \
Ondřej Vašík b0302e
+          break;                                                        \
Ondřej Vašík b0302e
+        }                                                                \
Ondřej Vašík b0302e
+    }                                                                        \
Ondřej Vašík b0302e
+  while (0)
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
 /* Pointer inside RP.  When checking if a byte or field is selected
Ondřej Vašík b0302e
    by a finite range, we check if it is between CURRENT_RP.LO
Ondřej Vašík b0302e
@@ -61,6 +124,9 @@
Ondřej Vašík b0302e
    CURRENT_RP.HI then we make CURRENT_RP to point to the next range pair. */
Ondřej Vašík b0302e
 static struct field_range_pair *current_rp;
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
+/* Length of the delimiter given as argument to -d.  */
Ondřej Vašík b0302e
+size_t delimlen;
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
 /* This buffer is used to support the semantics of the -s option
Ondřej Vašík b0302e
    (or lack of same) when the specified field list includes (does
Ondřej Vašík b0302e
    not include) the first field.  In both of those cases, the entire
Ondřej Vašík b0302e
@@ -77,15 +143,25 @@ enum operating_mode
Ondřej Vašík b0302e
   {
Ondřej Vašík b0302e
     undefined_mode,
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
-    /* Output characters that are in the given bytes. */
Ondřej Vašík b0302e
+    /* Output bytes that are at the given positions. */
Ondřej Vašík b0302e
     byte_mode,
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
+    /* Output characters that are at the given positions. */
Ondřej Vašík b0302e
+    character_mode,
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
     /* Output the given delimiter-separated fields. */
Ondřej Vašík b0302e
     field_mode
Ondřej Vašík b0302e
   };
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
 static enum operating_mode operating_mode;
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
+/* If nonzero, when in byte mode, don't split multibyte characters.  */
Ondřej Vašík b0302e
+static int byte_mode_character_aware;
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+/* If nonzero, the function for single byte locale is work
Ondřej Vašík b0302e
+   if this program runs on multibyte locale. */
Ondřej Vašík b0302e
+static int force_singlebyte_mode;
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
 /* If true do not output lines containing no delimiter characters.
Ondřej Vašík b0302e
    Otherwise, all such lines are printed.  This option is valid only
Ondřej Vašík b0302e
    with field mode.  */
Ondřej Vašík b0302e
@@ -97,6 +173,9 @@ static bool complement;
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
 /* The delimiter character for field mode. */
Ondřej Vašík b0302e
 static unsigned char delim;
Ondřej Vašík b0302e
+#if HAVE_WCHAR_H
Ondřej Vašík b0302e
+static wchar_t wcdelim;
Ondřej Vašík b0302e
+#endif
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
 /* The delimiter for each line/record. */
Ondřej Vašík b0302e
 static unsigned char line_delim = '\n';
Kamil Dudka d3849c
@@ -164,7 +243,7 @@ Print selected parts of lines from each FILE to standard output.\n\
Ondřej Vašík b0302e
   -f, --fields=LIST       select only these fields;  also print any line\n\
Ondřej Vašík b0302e
                             that contains no delimiter character, unless\n\
Ondřej Vašík b0302e
                             the -s option is specified\n\
Ondřej Vašík b0302e
-  -n                      (ignored)\n\
Ondřej Vašík b0302e
+  -n                      with -b: don't split multibyte characters\n\
Ondřej Vašík b0302e
 "), stdout);
Ondřej Vašík b0302e
       fputs (_("\
Ondřej Vašík b0302e
       --complement        complement the set of selected bytes, characters\n\
Ondřej Vašík b0302e
@@ -280,6 +359,82 @@ cut_bytes (FILE *stream)
Ondřej Vašík b0302e
     }
Ondřej Vašík b0302e
 }
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
+#if HAVE_MBRTOWC
Ondřej Vašík b0302e
+/* This function is in use for the following case.
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+   1. Read from the stream STREAM, printing to standard output any selected
Ondřej Vašík b0302e
+   characters.
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+   2. Read from stream STREAM, printing to standard output any selected bytes,
Ondřej Vašík b0302e
+   without splitting multibyte characters.  */
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+static void
Ondřej Vašík b0302e
+cut_characters_or_cut_bytes_no_split (FILE *stream)
Ondřej Vašík b0302e
+{
Ondřej Vašík b0302e
+  size_t idx;                /* number of bytes or characters in the line so far. */
Ondřej Vašík b0302e
+  char buf[MB_LEN_MAX + BUFSIZ];  /* For spooling a read byte sequence. */
Ondřej Vašík b0302e
+  char *bufpos;                /* Next read position of BUF. */
Ondřej Vašík b0302e
+  size_t buflen;        /* The length of the byte sequence in buf. */
Ondřej Vašík b0302e
+  wint_t wc;                /* A gotten wide character. */
Ondřej Vašík b0302e
+  size_t mblength;        /* The byte size of a multibyte character which shows
Ondřej Vašík b0302e
+                           as same character as WC. */
Ondřej Vašík b0302e
+  mbstate_t state;        /* State of the stream. */
Ondřej Vašík b0302e
+  bool convfail = false;  /* true, when conversion failed. Otherwise false. */
Ondřej Vašík b0302e
+  /* Whether to begin printing delimiters between ranges for the current line.
Ondřej Vašík b0302e
+     Set after we've begun printing data corresponding to the first range.  */
Ondřej Vašík b0302e
+  bool print_delimiter = false;
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+  idx = 0;
Ondřej Vašík b0302e
+  buflen = 0;
Ondřej Vašík b0302e
+  bufpos = buf;
Ondřej Vašík b0302e
+  memset (&state, '\0', sizeof(mbstate_t));
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+  current_rp = frp;
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+  while (1)
Ondřej Vašík b0302e
+    {
Ondřej Vašík b0302e
+      REFILL_BUFFER (buf, bufpos, buflen, stream);
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+      GET_NEXT_WC_FROM_BUFFER (wc, bufpos, buflen, mblength, state, convfail);
Ondřej Vašík b0302e
+      (void) convfail;  /* ignore unused */
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+      if (wc == WEOF)
Ondřej Vašík b0302e
+        {
Ondřej Vašík b0302e
+          if (idx > 0)
Ondřej Vašík b0302e
+            putchar (line_delim);
Ondřej Vašík b0302e
+          break;
Ondřej Vašík b0302e
+        }
Ondřej Vašík b0302e
+      else if (wc == line_delim)
Ondřej Vašík b0302e
+        {
Ondřej Vašík b0302e
+          putchar (line_delim);
Ondřej Vašík b0302e
+          idx = 0;
Ondřej Vašík b0302e
+          print_delimiter = false;
Ondřej Vašík b0302e
+          current_rp = frp;
Ondřej Vašík b0302e
+        }
Ondřej Vašík b0302e
+      else
Ondřej Vašík b0302e
+        {
Ondřej Vašík b0302e
+          next_item (&idx);
Ondřej Vašík b0302e
+          if (print_kth (idx))
Ondřej Vašík b0302e
+            {
Ondřej Vašík b0302e
+              if (output_delimiter_specified)
Ondřej Vašík b0302e
+                {
Ondřej Vašík b0302e
+                  if (print_delimiter && is_range_start_index (idx))
Ondřej Vašík b0302e
+                    {
Ondřej Vašík b0302e
+                      fwrite (output_delimiter_string, sizeof (char),
Ondřej Vašík b0302e
+                              output_delimiter_length, stdout);
Ondřej Vašík b0302e
+                    }
Ondřej Vašík b0302e
+                  print_delimiter = true;
Ondřej Vašík b0302e
+                }
Ondřej Vašík b0302e
+              fwrite (bufpos, mblength, sizeof(char), stdout);
Ondřej Vašík b0302e
+            }
Ondřej Vašík b0302e
+        }
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+      buflen -= mblength;
Ondřej Vašík b0302e
+      bufpos += mblength;
Ondřej Vašík b0302e
+    }
Ondřej Vašík b0302e
+}
Ondřej Vašík b0302e
+#endif
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
 /* Read from stream STREAM, printing to standard output any selected fields.  */
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
 static void
Ondřej Vašík b0302e
@@ -425,13 +580,211 @@ cut_fields (FILE *stream)
Ondřej Vašík b0302e
     }
Ondřej Vašík b0302e
 }
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
+#if HAVE_MBRTOWC
Ondřej Vašík b0302e
+static void
Ondřej Vašík b0302e
+cut_fields_mb (FILE *stream)
Ondřej Vašík b0302e
+{
Ondřej Vašík b0302e
+  int c;
Ondřej Vašík b0302e
+  size_t field_idx;
Ondřej Vašík b0302e
+  int found_any_selected_field;
Ondřej Vašík b0302e
+  int buffer_first_field;
Ondřej Vašík b0302e
+  int empty_input;
Ondřej Vašík b0302e
+  char buf[MB_LEN_MAX + BUFSIZ];  /* For spooling a read byte sequence. */
Ondřej Vašík b0302e
+  char *bufpos;                /* Next read position of BUF. */
Ondřej Vašík b0302e
+  size_t buflen;        /* The length of the byte sequence in buf. */
Ondřej Vašík b0302e
+  wint_t wc = 0;        /* A gotten wide character. */
Ondřej Vašík b0302e
+  size_t mblength;        /* The byte size of a multibyte character which shows
Ondřej Vašík b0302e
+                           as same character as WC. */
Ondřej Vašík b0302e
+  mbstate_t state;        /* State of the stream. */
Ondřej Vašík b0302e
+  bool convfail = false;  /* true, when conversion failed. Otherwise false. */
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+  current_rp = frp;
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+  found_any_selected_field = 0;
Ondřej Vašík b0302e
+  field_idx = 1;
Ondřej Vašík b0302e
+  bufpos = buf;
Ondřej Vašík b0302e
+  buflen = 0;
Ondřej Vašík b0302e
+  memset (&state, '\0', sizeof(mbstate_t));
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+  c = getc (stream);
Ondřej Vašík b0302e
+  empty_input = (c == EOF);
Ondřej Vašík b0302e
+  if (c != EOF)
Ondřej Vašík b0302e
+  {
Ondřej Vašík b0302e
+    ungetc (c, stream);
Ondřej Vašík b0302e
+    wc = 0;
Ondřej Vašík b0302e
+  }
Ondřej Vašík b0302e
+  else
Ondřej Vašík b0302e
+    wc = WEOF;
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+  /* To support the semantics of the -s flag, we may have to buffer
Ondřej Vašík b0302e
+     all of the first field to determine whether it is `delimited.'
Ondřej Vašík b0302e
+     But that is unnecessary if all non-delimited lines must be printed
Ondřej Vašík b0302e
+     and the first field has been selected, or if non-delimited lines
Ondřej Vašík b0302e
+     must be suppressed and the first field has *not* been selected.
Ondřej Vašík b0302e
+     That is because a non-delimited line has exactly one field.  */
Ondřej Vašík b0302e
+  buffer_first_field = (suppress_non_delimited ^ !print_kth (1));
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+  while (1)
Ondřej Vašík b0302e
+    {
Ondřej Vašík b0302e
+      if (field_idx == 1 && buffer_first_field)
Ondřej Vašík b0302e
+        {
Ondřej Vašík b0302e
+          int len = 0;
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+          while (1)
Ondřej Vašík b0302e
+            {
Ondřej Vašík b0302e
+              REFILL_BUFFER (buf, bufpos, buflen, stream);
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+              GET_NEXT_WC_FROM_BUFFER
Ondřej Vašík b0302e
+                (wc, bufpos, buflen, mblength, state, convfail);
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+              if (wc == WEOF)
Ondřej Vašík b0302e
+                break;
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+              field_1_buffer = xrealloc (field_1_buffer, len + mblength);
Ondřej Vašík b0302e
+              memcpy (field_1_buffer + len, bufpos, mblength);
Ondřej Vašík b0302e
+              len += mblength;
Ondřej Vašík b0302e
+              buflen -= mblength;
Ondřej Vašík b0302e
+              bufpos += mblength;
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+              if (!convfail && (wc == line_delim || wc == wcdelim))
Ondřej Vašík b0302e
+                break;
Ondřej Vašík b0302e
+            }
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+          if (len <= 0 && wc == WEOF)
Ondřej Vašík b0302e
+            break;
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+          /* If the first field extends to the end of line (it is not
Ondřej Vašík b0302e
+             delimited) and we are printing all non-delimited lines,
Ondřej Vašík b0302e
+             print this one.  */
Ondřej Vašík b0302e
+          if (convfail || (!convfail && wc != wcdelim))
Ondřej Vašík b0302e
+            {
Ondřej Vašík b0302e
+              if (suppress_non_delimited)
Ondřej Vašík b0302e
+                {
Ondřej Vašík b0302e
+                  /* Empty.        */
Ondřej Vašík b0302e
+                }
Ondřej Vašík b0302e
+              else
Ondřej Vašík b0302e
+                {
Ondřej Vašík b0302e
+                  fwrite (field_1_buffer, sizeof (char), len, stdout);
Ondřej Vašík b0302e
+                  /* Make sure the output line is newline terminated.  */
Ondřej Vašík b0302e
+                  if (convfail || (!convfail && wc != line_delim))
Ondřej Vašík b0302e
+                    putchar (line_delim);
Ondřej Vašík b0302e
+                }
Ondřej Vašík b0302e
+              continue;
Ondřej Vašík b0302e
+            }
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+          if (print_kth (1))
Ondřej Vašík b0302e
+            {
Ondřej Vašík b0302e
+              /* Print the field, but not the trailing delimiter.  */
Ondřej Vašík b0302e
+              fwrite (field_1_buffer, sizeof (char), len - 1, stdout);
Ondřej Vašík b0302e
+              found_any_selected_field = 1;
Ondřej Vašík b0302e
+            }
Ondřej Vašík b0302e
+          next_item (&field_idx);
Ondřej Vašík b0302e
+        }
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+      if (wc != WEOF)
Ondřej Vašík b0302e
+        {
Ondřej Vašík b0302e
+          if (print_kth (field_idx))
Ondřej Vašík b0302e
+            {
Ondřej Vašík b0302e
+              if (found_any_selected_field)
Ondřej Vašík b0302e
+                {
Ondřej Vašík b0302e
+                  fwrite (output_delimiter_string, sizeof (char),
Ondřej Vašík b0302e
+                          output_delimiter_length, stdout);
Ondřej Vašík b0302e
+                }
Ondřej Vašík b0302e
+              found_any_selected_field = 1;
Ondřej Vašík b0302e
+            }
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+          while (1)
Ondřej Vašík b0302e
+            {
Ondřej Vašík b0302e
+              REFILL_BUFFER (buf, bufpos, buflen, stream);
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+              GET_NEXT_WC_FROM_BUFFER
Ondřej Vašík b0302e
+                (wc, bufpos, buflen, mblength, state, convfail);
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+              if (wc == WEOF)
Ondřej Vašík b0302e
+                break;
Ondřej Vašík b0302e
+              else if (!convfail && (wc == wcdelim || wc == line_delim))
Ondřej Vašík b0302e
+                {
Ondřej Vašík b0302e
+                  buflen -= mblength;
Ondřej Vašík b0302e
+                  bufpos += mblength;
Ondřej Vašík b0302e
+                  break;
Ondřej Vašík b0302e
+                }
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+              if (print_kth (field_idx))
Ondřej Vašík b0302e
+                fwrite (bufpos, mblength, sizeof(char), stdout);
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+              buflen -= mblength;
Ondřej Vašík b0302e
+              bufpos += mblength;
Ondřej Vašík b0302e
+            }
Ondřej Vašík b0302e
+        }
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+      if ((!convfail || wc == line_delim) && buflen < 1)
Ondřej Vašík b0302e
+        wc = WEOF;
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+      if (!convfail && wc == wcdelim)
Ondřej Vašík b0302e
+        next_item (&field_idx);
Ondřej Vašík b0302e
+      else if (wc == WEOF || (!convfail && wc == line_delim))
Ondřej Vašík b0302e
+        {
Ondřej Vašík b0302e
+          if (found_any_selected_field
Ondřej Vašík b0302e
+              || (!empty_input && !(suppress_non_delimited && field_idx == 1)))
Ondřej Vašík b0302e
+            putchar (line_delim);
Ondřej Vašík b0302e
+          if (wc == WEOF)
Ondřej Vašík b0302e
+            break;
Ondřej Vašík b0302e
+          field_idx = 1;
Ondřej Vašík b0302e
+          current_rp = frp;
Ondřej Vašík b0302e
+          found_any_selected_field = 0;
Ondřej Vašík b0302e
+        }
Ondřej Vašík b0302e
+    }
Ondřej Vašík b0302e
+}
Ondřej Vašík b0302e
+#endif
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
 static void
Ondřej Vašík b0302e
 cut_stream (FILE *stream)
Ondřej Vašík b0302e
 {
Ondřej Vašík b0302e
-  if (operating_mode == byte_mode)
Ondřej Vašík b0302e
-    cut_bytes (stream);
Ondřej Vašík b0302e
+#if HAVE_MBRTOWC
Ondřej Vašík b0302e
+  if (MB_CUR_MAX > 1 && !force_singlebyte_mode)
Ondřej Vašík b0302e
+    {
Ondřej Vašík b0302e
+      switch (operating_mode)
Ondřej Vašík b0302e
+        {
Ondřej Vašík b0302e
+        case byte_mode:
Ondřej Vašík b0302e
+          if (byte_mode_character_aware)
Ondřej Vašík b0302e
+            cut_characters_or_cut_bytes_no_split (stream);
Ondřej Vašík b0302e
+          else
Ondřej Vašík b0302e
+            cut_bytes (stream);
Ondřej Vašík b0302e
+          break;
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+        case character_mode:
Ondřej Vašík b0302e
+          cut_characters_or_cut_bytes_no_split (stream);
Ondřej Vašík b0302e
+          break;
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+        case field_mode:
Ondřej Vašík b0302e
+          if (delimlen == 1)
Ondřej Vašík b0302e
+            {
Ondřej Vašík b0302e
+              /* Check if we have utf8 multibyte locale, so we can use this
Ondřej Vašík b0302e
+                 optimization because of uniqueness of characters, which is
Ondřej Vašík b0302e
+                 not true for e.g. SJIS */
Ondřej Vašík b0302e
+              char * loc = setlocale(LC_CTYPE, NULL);
Ondřej Vašík b0302e
+              if (loc && (strstr (loc, "UTF-8") || strstr (loc, "utf-8") ||
Ondřej Vašík b0302e
+                  strstr (loc, "UTF8") || strstr (loc, "utf8")))
Ondřej Vašík b0302e
+                {
Ondřej Vašík b0302e
+                  cut_fields (stream);
Ondřej Vašík b0302e
+                  break;
Ondřej Vašík b0302e
+                }
Ondřej Vašík b0302e
+            }
Ondřej Vašík b0302e
+          cut_fields_mb (stream);
Ondřej Vašík b0302e
+          break;
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+        default:
Ondřej Vašík b0302e
+          abort ();
Ondřej Vašík b0302e
+        }
Ondřej Vašík b0302e
+    }
Ondřej Vašík b0302e
   else
Ondřej Vašík b0302e
-    cut_fields (stream);
Ondřej Vašík b0302e
+#endif
Ondřej Vašík b0302e
+    {
Ondřej Vašík b0302e
+      if (operating_mode == field_mode)
Ondřej Vašík b0302e
+        cut_fields (stream);
Ondřej Vašík b0302e
+      else
Ondřej Vašík b0302e
+        cut_bytes (stream);
Ondřej Vašík b0302e
+    }
Ondřej Vašík b0302e
 }
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
 /* Process file FILE to standard output.
Ondřej Vašík b0302e
@@ -483,6 +836,7 @@ main (int argc, char **argv)
Ondřej Vašík b0302e
   bool ok;
Ondřej Vašík b0302e
   bool delim_specified = false;
Ondřej Vašík b0302e
   char *spec_list_string IF_LINT ( = NULL);
Ondřej Vašík b0302e
+  char mbdelim[MB_LEN_MAX + 1];
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
   initialize_main (&argc, &argv);
Ondřej Vašík b0302e
   set_program_name (argv[0]);
Ondřej Vašík b0302e
@@ -505,7 +859,6 @@ main (int argc, char **argv)
Ondřej Vašík b0302e
       switch (optc)
Ondřej Vašík b0302e
         {
Ondřej Vašík b0302e
         case 'b':
Ondřej Vašík b0302e
-        case 'c':
Ondřej Vašík b0302e
           /* Build the byte list. */
Ondřej Vašík b0302e
           if (operating_mode != undefined_mode)
Ondřej Vašík b0302e
             FATAL_ERROR (_("only one type of list may be specified"));
Ondřej Vašík b0302e
@@ -513,6 +866,14 @@ main (int argc, char **argv)
Ondřej Vašík b0302e
           spec_list_string = optarg;
Ondřej Vašík b0302e
           break;
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
+        case 'c':
Ondřej Vašík b0302e
+          /* Build the character list. */
Ondřej Vašík b0302e
+          if (operating_mode != undefined_mode)
Ondřej Vašík b0302e
+            FATAL_ERROR (_("only one type of list may be specified"));
Ondřej Vašík b0302e
+          operating_mode = character_mode;
Ondřej Vašík b0302e
+          spec_list_string = optarg;
Ondřej Vašík b0302e
+          break;
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
         case 'f':
Ondřej Vašík b0302e
           /* Build the field list. */
Ondřej Vašík b0302e
           if (operating_mode != undefined_mode)
Ondřej Vašík b0302e
@@ -524,10 +885,38 @@ main (int argc, char **argv)
Ondřej Vašík b0302e
         case 'd':
Ondřej Vašík b0302e
           /* New delimiter. */
Ondřej Vašík b0302e
           /* Interpret -d '' to mean 'use the NUL byte as the delimiter.'  */
Ondřej Vašík b0302e
-          if (optarg[0] != '\0' && optarg[1] != '\0')
Ondřej Vašík b0302e
-            FATAL_ERROR (_("the delimiter must be a single character"));
Ondřej Vašík b0302e
-          delim = optarg[0];
Ondřej Vašík b0302e
-          delim_specified = true;
Ondřej Vašík b0302e
+            {
Ondřej Vašík b0302e
+#if HAVE_MBRTOWC
Ondřej Vašík b0302e
+              if(MB_CUR_MAX > 1)
Ondřej Vašík b0302e
+                {
Ondřej Vašík b0302e
+                  mbstate_t state;
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+                  memset (&state, '\0', sizeof(mbstate_t));
Ondřej Vašík b0302e
+                  delimlen = mbrtowc (&wcdelim, optarg, strnlen(optarg, MB_LEN_MAX), &state);
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+                  if (delimlen == (size_t)-1 || delimlen == (size_t)-2)
Ondřej Vašík b0302e
+                    ++force_singlebyte_mode;
Ondřej Vašík b0302e
+                  else
Ondřej Vašík b0302e
+                    {
Ondřej Vašík b0302e
+                      delimlen = (delimlen < 1) ? 1 : delimlen;
Ondřej Vašík b0302e
+                      if (wcdelim != L'\0' && *(optarg + delimlen) != '\0')
Ondřej Vašík b0302e
+                        FATAL_ERROR (_("the delimiter must be a single character"));
Ondřej Vašík b0302e
+                      memcpy (mbdelim, optarg, delimlen);
Ondřej Vašík b0302e
+                      mbdelim[delimlen] = '\0';
Ondřej Vašík b0302e
+                      if (delimlen == 1)
Ondřej Vašík b0302e
+                        delim = *optarg;
Ondřej Vašík b0302e
+                    }
Ondřej Vašík b0302e
+                }
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+              if (MB_CUR_MAX <= 1 || force_singlebyte_mode)
Ondřej Vašík b0302e
+#endif
Ondřej Vašík b0302e
+                {
Ondřej Vašík b0302e
+                  if (optarg[0] != '\0' && optarg[1] != '\0')
Ondřej Vašík b0302e
+                    FATAL_ERROR (_("the delimiter must be a single character"));
Ondřej Vašík b0302e
+                  delim = (unsigned char) optarg[0];
Ondřej Vašík b0302e
+                }
Ondřej Vašík b0302e
+            delim_specified = true;
Ondřej Vašík b0302e
+          }
Ondřej Vašík b0302e
           break;
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
         case OUTPUT_DELIMITER_OPTION:
Ondřej Vašík b0302e
@@ -540,6 +929,7 @@ main (int argc, char **argv)
Ondřej Vašík b0302e
           break;
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
         case 'n':
Ondřej Vašík b0302e
+          byte_mode_character_aware = 1;
Ondřej Vašík b0302e
           break;
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
         case 's':
Ondřej Vašík b0302e
@@ -579,15 +969,34 @@ main (int argc, char **argv)
Ondřej Vašík b0302e
               | (complement ? SETFLD_COMPLEMENT : 0) );
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
   if (!delim_specified)
Ondřej Vašík b0302e
-    delim = '\t';
Ondřej Vašík b0302e
+    {
Ondřej Vašík b0302e
+      delim = '\t';
Ondřej Vašík b0302e
+#ifdef HAVE_MBRTOWC
Ondřej Vašík b0302e
+      wcdelim = L'\t';
Ondřej Vašík b0302e
+      mbdelim[0] = '\t';
Ondřej Vašík b0302e
+      mbdelim[1] = '\0';
Ondřej Vašík b0302e
+      delimlen = 1;
Ondřej Vašík b0302e
+#endif
Ondřej Vašík b0302e
+    }
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
   if (output_delimiter_string == NULL)
Ondřej Vašík b0302e
     {
Ondřej Vašík b0302e
-      static char dummy[2];
Ondřej Vašík b0302e
-      dummy[0] = delim;
Ondřej Vašík b0302e
-      dummy[1] = '\0';
Ondřej Vašík b0302e
-      output_delimiter_string = dummy;
Ondřej Vašík b0302e
-      output_delimiter_length = 1;
Ondřej Vašík b0302e
+#ifdef HAVE_MBRTOWC
Ondřej Vašík b0302e
+      if (MB_CUR_MAX > 1 && !force_singlebyte_mode)
Ondřej Vašík b0302e
+        {
Ondřej Vašík b0302e
+          output_delimiter_string = xstrdup(mbdelim);
Ondřej Vašík b0302e
+          output_delimiter_length = delimlen;
Ondřej Vašík b0302e
+        }
Ondřej Vašík b0302e
+
Ondřej Vašík b0302e
+      if (MB_CUR_MAX <= 1 || force_singlebyte_mode)
Ondřej Vašík b0302e
+#endif
Ondřej Vašík b0302e
+        {
Ondřej Vašík b0302e
+          static char dummy[2];
Ondřej Vašík b0302e
+          dummy[0] = delim;
Ondřej Vašík b0302e
+          dummy[1] = '\0';
Ondřej Vašík b0302e
+          output_delimiter_string = dummy;
Ondřej Vašík b0302e
+          output_delimiter_length = 1;
Ondřej Vašík b0302e
+        }
Ondřej Vašík b0302e
     }
Ondřej Vašík b0302e
 
Ondřej Vašík b0302e
   if (optind == argc)