ls: support --hyperlink to output file:// URIs
[coreutils.git] / src / basename.c
blob5c0f11d848379e082fef4fe79d772a06e4af2026
1 /* basename -- strip directory and suffix from file names
2 Copyright (C) 1990-2017 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 #include <config.h>
18 #include <getopt.h>
19 #include <stdio.h>
20 #include <sys/types.h>
22 #include "system.h"
23 #include "error.h"
24 #include "quote.h"
26 /* The official name of this program (e.g., no 'g' prefix). */
27 #define PROGRAM_NAME "basename"
29 #define AUTHORS proper_name ("David MacKenzie")
31 static struct option const longopts[] =
33 {"multiple", no_argument, NULL, 'a'},
34 {"suffix", required_argument, NULL, 's'},
35 {"zero", no_argument, NULL, 'z'},
36 {GETOPT_HELP_OPTION_DECL},
37 {GETOPT_VERSION_OPTION_DECL},
38 {NULL, 0, NULL, 0}
41 void
42 usage (int status)
44 if (status != EXIT_SUCCESS)
45 emit_try_help ();
46 else
48 printf (_("\
49 Usage: %s NAME [SUFFIX]\n\
50 or: %s OPTION... NAME...\n\
51 "),
52 program_name, program_name);
53 fputs (_("\
54 Print NAME with any leading directory components removed.\n\
55 If specified, also remove a trailing SUFFIX.\n\
56 "), stdout);
58 emit_mandatory_arg_note ();
60 fputs (_("\
61 -a, --multiple support multiple arguments and treat each as a NAME\n\
62 -s, --suffix=SUFFIX remove a trailing SUFFIX; implies -a\n\
63 -z, --zero end each output line with NUL, not newline\n\
64 "), stdout);
65 fputs (HELP_OPTION_DESCRIPTION, stdout);
66 fputs (VERSION_OPTION_DESCRIPTION, stdout);
67 printf (_("\
68 \n\
69 Examples:\n\
70 %s /usr/bin/sort -> \"sort\"\n\
71 %s include/stdio.h .h -> \"stdio\"\n\
72 %s -s .h include/stdio.h -> \"stdio\"\n\
73 %s -a any/str1 any/str2 -> \"str1\" followed by \"str2\"\n\
74 "),
75 program_name, program_name, program_name, program_name);
76 emit_ancillary_info (PROGRAM_NAME);
78 exit (status);
81 /* Remove SUFFIX from the end of NAME if it is there, unless NAME
82 consists entirely of SUFFIX. */
84 static void
85 remove_suffix (char *name, const char *suffix)
87 char *np;
88 const char *sp;
90 np = name + strlen (name);
91 sp = suffix + strlen (suffix);
93 while (np > name && sp > suffix)
94 if (*--np != *--sp)
95 return;
96 if (np > name)
97 *np = '\0';
100 /* Perform the basename operation on STRING. If SUFFIX is non-NULL, remove
101 the trailing SUFFIX. Finally, output the result string. */
103 static void
104 perform_basename (const char *string, const char *suffix, bool use_nuls)
106 char *name = base_name (string);
107 strip_trailing_slashes (name);
109 /* Per POSIX, 'basename // /' must return '//' on platforms with
110 distinct //. On platforms with drive letters, this generalizes
111 to making 'basename c: :' return 'c:'. This rule is captured by
112 skipping suffix stripping if base_name returned an absolute path
113 or a drive letter (only possible if name is a file-system
114 root). */
115 if (suffix && IS_RELATIVE_FILE_NAME (name) && ! FILE_SYSTEM_PREFIX_LEN (name))
116 remove_suffix (name, suffix);
118 fputs (name, stdout);
119 putchar (use_nuls ? '\0' : '\n');
120 free (name);
124 main (int argc, char **argv)
126 bool multiple_names = false;
127 bool use_nuls = false;
128 const char *suffix = NULL;
130 initialize_main (&argc, &argv);
131 set_program_name (argv[0]);
132 setlocale (LC_ALL, "");
133 bindtextdomain (PACKAGE, LOCALEDIR);
134 textdomain (PACKAGE);
136 atexit (close_stdout);
138 while (true)
140 int c = getopt_long (argc, argv, "+as:z", longopts, NULL);
142 if (c == -1)
143 break;
145 switch (c)
147 case 's':
148 suffix = optarg;
149 /* -s implies -a, so... */
150 FALLTHROUGH;
152 case 'a':
153 multiple_names = true;
154 break;
156 case 'z':
157 use_nuls = true;
158 break;
160 case_GETOPT_HELP_CHAR;
161 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
163 default:
164 usage (EXIT_FAILURE);
168 if (argc < optind + 1)
170 error (0, 0, _("missing operand"));
171 usage (EXIT_FAILURE);
174 if (!multiple_names && optind + 2 < argc)
176 error (0, 0, _("extra operand %s"), quote (argv[optind + 2]));
177 usage (EXIT_FAILURE);
180 if (multiple_names)
182 for (; optind < argc; optind++)
183 perform_basename (argv[optind], suffix, use_nuls);
185 else
186 perform_basename (argv[optind],
187 optind + 2 == argc ? argv[optind + 1] : NULL, use_nuls);
189 return EXIT_SUCCESS;