commit: 3ecb327180f95b6142c30996e2cf4e7e93000c19
parent 5a0c91fb4737b317ce5e1bed96eb55931574e8ef
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Sat, 12 Oct 2024 16:35:35 +0200
cmd/basename: add support for -a, -s and -z options
Diffstat:
3 files changed, 117 insertions(+), 31 deletions(-)
diff --git a/cmd/basename.1 b/cmd/basename.1
@@ -9,8 +9,13 @@
.Nd print last path component of a path
.Sh SYNOPSIS
.Nm
+.Op Fl z
.Op Ar path
.Op Ar suffix
+.Nm
+.Op Fl az
+.Op Fl s Ar suffix
+.Op Ar path...
.Sh DESCRIPTION
.Nm
prints the last path component of
@@ -24,6 +29,20 @@ When
isn't given or is an empty string
.Dq \&.
is printed.
+.Sh OPTIONS
+.Bl -tag -width _s_suffix
+.It Fl a
+Support multiple
+.Ar path
+arguments
+.It Fl s Ar suffix
+Set
+.Ar suffix ;
+implies
+.Fl a
+.It Fl z
+Use NULL as separator for each result instead of newline.
+.El
.Sh EXIT STATUS
.Ex -std
.Sh SEE ALSO
@@ -34,5 +53,12 @@ is printed.
should be compliant with the
IEEE Std 1003.1-2024 (“POSIX.1”)
specification.
+.Pp
+The
+.Fl a ,
+.Fl s
+and
+.Fl z
+options are extensions inspired by GNU coreutils.
.Sh AUTHORS
.An Haelwenn (lanodan) Monnier Aq Mt contact+utils@hacktivis.me
diff --git a/cmd/basename.c b/cmd/basename.c
@@ -4,9 +4,13 @@
#define _POSIX_C_SOURCE 200809L
-#include <libgen.h> // basename()
-#include <stdio.h> // puts(), perror()
-#include <string.h> // strlen(), strncmp()
+#include <libgen.h> // basename
+#include <stdbool.h>
+#include <stdio.h> // puts, perror
+#include <string.h> // strlen, strncmp
+#include <unistd.h> // getopt
+
+const char *argv0 = "basename";
#ifdef __GNUC__
#define _NonNull __attribute__((nonnull))
@@ -30,40 +34,93 @@ suffix_basename(char *name, char *suffix)
return string;
}
+static void
+usage()
+{
+ fputs("Usage: basename [-z] [path] [suffix]\n"
+ " basename [-az] [-s suffix] [path...]\n",
+ stderr);
+}
+
int
main(int argc, char *argv[])
{
- int ret = 0;
+ bool opt_a = false;
+ char *suffix = NULL;
+ char delim = '\n';
- if((argc > 1) && (strncmp(argv[1], "--", 3) == 0))
+ int c = -1;
+ while((c = getopt(argc, argv, ":as:z")) != -1)
{
- argv++;
- argc--;
+ switch(c)
+ {
+ case 'a':
+ opt_a = true;
+ break;
+ case 's':
+ opt_a = true;
+ suffix = optarg;
+ break;
+ case 'z':
+ delim = '\0';
+ break;
+ case ':':
+ fprintf(stderr, "%s: error: Missing operand for option '-%c'\n", argv0, optopt);
+ usage();
+ return 1;
+ case '?':
+ fprintf(stderr, "%s: error: Unrecognised option '-%c'\n", argv0, optopt);
+ usage();
+ return 1;
+ }
}
- switch(argc)
- {
- case 1:
- ret = puts(".");
- break;
- case 2:
- ret = puts(basename(argv[1]));
- break;
- case 3:
- ret = puts(suffix_basename(argv[1], argv[2]));
- break;
- default:
- fputs("usage: basename string [suffix]\n", stderr);
- return 1;
- }
+ argc -= optind;
+ argv += optind;
- if(ret < 0)
+ if(!opt_a || argc == 0)
{
- perror("basename: error: puts");
- return 1;
+ int ret = 0;
+
+ switch(argc)
+ {
+ case 0:
+ ret = printf(".%c", delim);
+ break;
+ case 1:
+ ret = printf("%s%c", basename(argv[0]), delim);
+ break;
+ case 2:
+ ret = printf("%s%c", suffix_basename(argv[0], argv[1]), delim);
+ break;
+ default:
+ usage();
+ return 1;
+ }
+
+ if(ret < 0)
+ {
+ perror("basename: error: Failed to print result");
+ return 1;
+ }
+
+ return 0;
}
- else
+
+ for(int argi = 0; argi < argc; argi++)
{
- return 0;
+ char *res = NULL;
+ if(suffix != NULL)
+ res = suffix_basename(argv[argi], suffix);
+ else
+ res = basename(argv[argi]);
+
+ if(printf("%s%c", res, delim) < 0)
+ {
+ perror("basename: error: Failed to print result");
+ return 1;
+ }
}
+
+ return 0;
}
diff --git a/test-cmd/basename.sh b/test-cmd/basename.sh
@@ -20,10 +20,13 @@ t dash '-' '-
'
t double-dash '--' '.
'
-t triple-dash '---' '---
-'
-t double-dash-letter '--a a' '--
-'
+t_args opt_a 'str1
+str2
+' -a any/str1 any/str2
+
+t_args opt_s 'stdio
+unistd
+' -s .h include/stdio.h include/unistd.h
#atf_test_case usage
#usage_body() {