commit: 5efc5d6eb2d59e6f6e2f9076f33e6aa9e531fb8c
parent e904524ea5f50a8ea870fa62addb9a5d1f59c54e
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Thu, 24 Jul 2025 22:33:13 +0200
cmd/cut: add support for -z option
Diffstat:
3 files changed, 24 insertions(+), 15 deletions(-)
diff --git a/cmd/cut.1 b/cmd/cut.1
@@ -10,15 +10,16 @@
.Sh SYNOPSIS
.Nm
.Fl b Ar list
-.Op Fl n
+.Op Fl nz
.Op Ar file...
.Nm
.Fl c Ar list
+.Op Fl z
.Op Ar file...
.Nm
.Fl f Ar list
.Op Fl d Ar delim
-.Op Fl s
+.Op Fl sz
.Op Ar file...
.Sh DESCRIPTION
.Nm
@@ -77,6 +78,8 @@ Do not split codepoints. (Currently unsupported in this implementation)
.It Fl s
Suppress lines with no delimiter characters,
otherwise whole delimiter-less lines are printed as-is.
+.It Fl z
+Use NULL as line separator instead of newline.
.El
.Sh EXIT STATUS
.Ex -std
diff --git a/cmd/cut.c b/cmd/cut.c
@@ -30,6 +30,8 @@ enum cut_mode
};
char delim = '\t';
+char line_delim = '\n';
+wchar_t line_delim_w = L'\n';
bool opt_n = false, opt_s = false;
enum cut_mode mode = CUT_MODE_NONE;
bool *list = NULL;
@@ -152,7 +154,7 @@ cut_b(FILE *in, const char *filename)
while(err == 0)
{
errno = 0;
- ssize_t nread = getline(&line, &line_len, in);
+ ssize_t nread = getdelim(&line, &line_len, line_delim, in);
if(nread < 0)
{
@@ -167,7 +169,7 @@ cut_b(FILE *in, const char *filename)
if(nread == 0)
{
- fputc('\n', stdout);
+ fputc(line_delim, stdout);
continue;
}
@@ -178,7 +180,7 @@ cut_b(FILE *in, const char *filename)
if(nostop && (size_t)nread > list_len) fwrite(line + list_len, nread - list_len, 1, stdout);
- fputc('\n', stdout);
+ fputc(line_delim, stdout);
}
if(line_len != 0) free(line);
@@ -198,7 +200,7 @@ cut_c(FILE *in, const char *filename)
while(err == 0)
{
errno = 0;
- ssize_t nread = getline(&line, &line_len, in);
+ ssize_t nread = getdelim(&line, &line_len, line_delim, in);
if(nread < 0)
{
@@ -213,7 +215,7 @@ cut_c(FILE *in, const char *filename)
if(nread == 0)
{
- fputwc(L'\n', stdout);
+ fputwc(line_delim_w, stdout);
continue;
}
@@ -256,7 +258,7 @@ cut_c(FILE *in, const char *filename)
fputwc(line_w[i], stdout);
}
- fputwc(L'\n', stdout);
+ fputwc(line_delim_w, stdout);
}
if(line_len != 0) free(line);
@@ -274,7 +276,7 @@ cut_f(FILE *in, const char *filename)
while(err == 0)
{
errno = 0;
- ssize_t nread = getline(&line, &line_len, in);
+ ssize_t nread = getdelim(&line, &line_len, line_delim, in);
if(nread < 0)
{
@@ -289,7 +291,7 @@ cut_f(FILE *in, const char *filename)
if(nread == 0)
{
- fputc('\n', stdout);
+ fputc(line_delim, stdout);
continue;
}
@@ -335,7 +337,7 @@ cut_f(FILE *in, const char *filename)
c = line + pos + 1;
}
- fputc('\n', stdout);
+ fputc(line_delim, stdout);
}
if(line_len != 0) free(line);
@@ -377,7 +379,7 @@ main(int argc, char *argv[])
}
errno = 0;
- for(int c = -1; (c = getopt_nolong(argc, argv, ":b:c:d:f:ns")) != -1;)
+ for(int c = -1; (c = getopt_nolong(argc, argv, ":b:c:d:f:nsz")) != -1;)
{
switch(c)
{
@@ -425,6 +427,10 @@ main(int argc, char *argv[])
case 's':
opt_s = true;
break;
+ case 'z':
+ line_delim = '\0';
+ line_delim_w = L'\0';
+ break;
case ':':
fprintf(stderr, "%s: error: Option '-%c' requires an operand\n", argv0, optopt);
return 1;
diff --git a/test-cmd/cut.sh b/test-cmd/cut.sh
@@ -17,11 +17,11 @@ t_null_f2()
out="$("$target" -d '' -f2 "${WD}/test-cmd/inputs/strings/length" 2>&1)"
ret="$?"
if [ "$?" != 0 ]; then
- printf 'not ok %s - %s\n' "$count $name" "$out"
+ printf 'not ok %d - %s %s\n' "$count" "$name" "$out"
elif [ "$out" != "$exp" ]; then
- printf 'not ok %s - (%s != %s)\n' "$count $name" "$out" "$exp"
+ printf 'not ok %d - %s (%s != %s)\n' "$count" "$name" "$out" "$exp"
else
- printf 'ok %s\n' "$count $name"
+ printf 'ok %d - %s\n' "$count" "$name"
fi
}