basename.c (2760B)
- // utils-std: Collection of commonly available Unix tools
 - // SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
 - // SPDX-License-Identifier: MPL-2.0
 - #define _POSIX_C_SOURCE 200809L
 - #include "../config.h"
 - #include "../libutils/getopt_nolong.h"
 - #include <libgen.h> // basename
 - #include <stdbool.h>
 - #include <stdio.h> // puts, perror
 - #include <string.h> // strlen, strncmp
 - #include <unistd.h> // getopt
 - #ifdef HAS_GETOPT_LONG
 - #include <getopt.h>
 - #endif
 - const char *argv0 = "basename";
 - #ifdef __GNUC__
 - #define _NonNull __attribute__((nonnull))
 - #else
 - #define _NonNull
 - #endif
 - _NonNull static char *
 - suffix_basename(char *name, char *suffix)
 - {
 - char *string = basename(name);
 - size_t suflen = strlen(suffix);
 - size_t len = strlen(string);
 - if(suflen < len && strcmp(&string[len - suflen], suffix) == 0)
 - {
 - string[len - suflen] = '\0';
 - }
 - return string;
 - }
 - static void
 - usage(void)
 - {
 - fputs("Usage: basename [-z] [path] [suffix]\n"
 - " basename [-az] [-s suffix] [path...]\n",
 - stderr);
 - }
 - int
 - main(int argc, char *argv[])
 - {
 - bool opt_a = false;
 - char *suffix = NULL;
 - char delim = '\n';
 - #ifdef HAS_GETOPT_LONG
 - // Strictly for GNUisms compatibility so no long-only options
 - // clang-format off
 - static struct option opts[] = {
 - {"multiple", no_argument, NULL, 'a'},
 - {"suffix", required_argument, NULL, 's'},
 - {"zero", no_argument, NULL, 'z'},
 - {0, 0, 0, 0},
 - };
 - // clang-format on
 - // Need + as first character to get POSIX-style option parsing
 - for(int c = -1; (c = getopt_long(argc, argv, "+:as:z", opts, NULL)) != -1;)
 - #else
 - for(int c = -1; (c = getopt_nolong(argc, argv, ":as:z")) != -1;)
 - #endif
 - {
 - 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 '?':
 - GETOPT_UNKNOWN_OPT
 - usage();
 - return 1;
 - }
 - }
 - argc -= optind;
 - argv += optind;
 - if(!opt_a || argc == 0)
 - {
 - 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;
 - }
 - for(int argi = 0; argi < argc; argi++)
 - {
 - 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;
 - }