logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git
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:

Mcmd/basename.126++++++++++++++++++++++++++
Mcmd/basename.c111++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Mtest-cmd/basename.sh11+++++++----
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() {