]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
cut: support single byte -d that may be part of multi-byte
authorPádraig Brady <P@draigBrady.com>
Wed, 11 Mar 2026 21:23:24 +0000 (21:23 +0000)
committerPádraig Brady <P@draigBrady.com>
Sun, 5 Apr 2026 12:15:55 +0000 (13:15 +0100)
Note this is a slight divergence from the i18n patch
as that switched to uni-byte for any single byte delimiter
that is not valid multi-byte.

That results in possibly splitting in the middle of
a valid multi-byte character.

Instead we only split on a single byte when they're
not part of a multi-byte character.

* src/cut.c

src/cut.c

index 6b391a384606c8597cbdfb017e19b99184a76aa5..39626fd9077fe93457ba9a91c90ce9976db6f1b6 100644 (file)
--- a/src/cut.c
+++ b/src/cut.c
@@ -246,6 +246,18 @@ is_range_start_index (uintmax_t k)
   return k == current_rp->lo;
 }
 
+static inline bool
+single_byte_field_delim_ok (void)
+{
+  return delim_length == 1 && (MB_CUR_MAX <= 1 || mcel_isbasic (delim_bytes[0]));
+}
+
+static inline bool
+field_delim_eq (mcel_t g)
+{
+  return delim_mcel.err ? g.err == delim_mcel.err : mcel_eq (g, delim_mcel);
+}
+
 static void
 write_bytes (char const *buf, size_t n_bytes)
 {
@@ -435,7 +447,7 @@ cut_fields_mb (FILE *stream)
                   break;
                 }
 
-              if (!g.err && mcel_eq (g, delim_mcel))
+              if (field_delim_eq (g))
                 {
                   terminator = FIELD_DELIMITER;
                   break;
@@ -485,8 +497,7 @@ cut_fields_mb (FILE *stream)
               g = mbbuf_get_char (&mbbuf);
               if (g.ch != MBBUF_EOF)
                 have_pending_line = true;
-              if (g.ch == MBBUF_EOF || g.ch == line_delim
-                  || (!g.err && mcel_eq (g, delim_mcel)))
+              if (g.ch == MBBUF_EOF || g.ch == line_delim || field_delim_eq (g))
                 break;
               write_bytes (mbbuf_char_offset (&mbbuf, g), g.len);
             }
@@ -498,13 +509,12 @@ cut_fields_mb (FILE *stream)
               g = mbbuf_get_char (&mbbuf);
               if (g.ch != MBBUF_EOF)
                 have_pending_line = true;
-              if (g.ch == MBBUF_EOF || g.ch == line_delim
-                  || (!g.err && mcel_eq (g, delim_mcel)))
+              if (g.ch == MBBUF_EOF || g.ch == line_delim || field_delim_eq (g))
                 break;
             }
         }
 
-      if (!g.err && mcel_eq (g, delim_mcel))
+      if (field_delim_eq (g))
         next_item (&field_idx);
       else if (g.ch == line_delim || g.ch == MBBUF_EOF)
         {
@@ -869,7 +879,7 @@ main (int argc, char **argv)
       break;
 
     case CUT_MODE_FIELDS:
-      cut_stream = delim_length == 1 ? cut_fields : cut_fields_mb;
+      cut_stream = single_byte_field_delim_ok () ? cut_fields : cut_fields_mb;
       break;
     }
   affirm (cut_stream);