]> git.ipfire.org Git - thirdparty/util-linux.git/blame - misc-utils/getopt.c
dmesg: add --follow-new
[thirdparty/util-linux.git] / misc-utils / getopt.c
CommitLineData
2b6fc908 1/*
735a6603 2 * getopt.c - Enhanced implementation of BSD getopt(1)
b5f3078e 3 * Copyright (c) 1997-2014 Frodo Looijaard <frodo@frodo.looijaard.name>
735a6603
SK
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
7cebf0bb
SK
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
735a6603 18 */
2b6fc908 19
f9a20f0b 20/*
2b6fc908 21 * Version 1.0-b4: Tue Sep 23 1997. First public release.
f9a20f0b 22 * Version 1.0: Wed Nov 19 1997.
2b6fc908
KZ
23 * Bumped up the version number to 1.0
24 * Fixed minor typo (CSH instead of TCSH)
25 * Version 1.0.1: Tue Jun 3 1998
26 * Fixed sizeof instead of strlen bug
27 * Bumped up the version number to 1.0.1
28 * Version 1.0.2: Thu Jun 11 1998 (not present)
29 * Fixed gcc-2.8.1 warnings
30 * Fixed --version/-V option (not present)
66ee8158
KZ
31 * Version 1.0.5: Tue Jun 22 1999
32 * Make -u option work (not present)
33 * Version 1.0.6: Tue Jun 27 2000
34 * No important changes
35 * Version 1.1.0: Tue Jun 30 2000
b50945d4 36 * Added NLS support (partly written by Arkadiusz Miƛkiewicz
df1dddf9 37 * <misiek@pld.org.pl>)
cf6d7fae
KZ
38 * Version 1.1.4: Mon Nov 7 2005
39 * Fixed a few type's in the manpage
b5f3078e
SK
40 * Version 1.1.5: Sun Aug 12 2012
41 * Sync with util-linux-2.21, fixed build problems, many new translations
42 * Version 1.1.6: Mon Nov 24 2014
43 * Sync with util-linux git 20141120, detect ambiguous long options, fix
44 * backslash problem in tcsh
2b6fc908
KZ
45 */
46
d1d03b54 47/* Exit codes:
455fe9a0 48 * 0) No errors, successful operation.
d1d03b54
SK
49 * 1) getopt(3) returned an error.
50 * 2) A problem with parameter parsing for getopt(1).
51 * 3) Internal error, out of memory
52 * 4) Returned for -T
53 */
54#define GETOPT_EXIT_CODE 1
55#define PARAMETER_EXIT_CODE 2
56#define XALLOC_EXIT_CODE 3
090d8c76 57#define CLOSE_EXIT_CODE XALLOC_EXIT_CODE
d1d03b54
SK
58#define TEST_EXIT_CODE 4
59
2b6fc908
KZ
60#include <stdio.h>
61#include <stdlib.h>
62#include <string.h>
63#include <unistd.h>
64#include <ctype.h>
2b6fc908 65#include <getopt.h>
5c78d493
RM
66#ifdef HAVE_SYS_PARAM_H
67# include <sys/param.h> /* BSD */
68#endif
2b6fc908 69
3862f685 70#include "closestream.h"
df1dddf9 71#include "nls.h"
d1d03b54 72#include "xalloc.h"
66ee8158 73
d01f47f6
SK
74/* NON_OPT is the code that is returned getopt(3) when a non-option is
75 * found in 'char optstring[]="-abc...";', e.g., it begins by '-' */
2b6fc908
KZ
76#define NON_OPT 1
77/* LONG_OPT is the code that is returned when a long option is found. */
b5f3078e 78#define LONG_OPT 0
2b6fc908
KZ
79
80/* The shells recognized. */
735a6603 81typedef enum { BASH, TCSH } shell_t;
2b6fc908 82
1dacc901
SK
83struct getopt_control {
84 shell_t shell; /* the shell we generate output for */
85 char *optstr; /* getopt(3) optstring */
e402d6d3 86 char *name;
1dacc901
SK
87 struct option *long_options; /* long options */
88 int long_options_length; /* length of options array */
89 int long_options_nr; /* number of used elements in array */
90 unsigned int
91 compatible:1, /* compatibility mode for 'difficult' programs */
92 quiet_errors:1, /* print errors */
93 quiet_output:1, /* print output */
94 quote:1; /* quote output */
95};
96
97enum { REALLOC_INCREMENT = 8 };
4a898108 98
ae769172 99/* Allow changing which getopt is in use with function pointer. */
2ba641e5
SK
100static int (*getopt_long_fp) (int argc, char *const *argv, const char *optstr,
101 const struct option * longopts, int *longindex);
2b6fc908 102
2b6fc908 103/*
ae769172 104 * This function 'normalizes' a single argument: it puts single quotes
735a6603
SK
105 * around it and escapes other special characters. If quote is false, it
106 * just returns its argument.
107 *
2b6fc908 108 * Bash only needs special treatment for single quotes; tcsh also recognizes
735a6603
SK
109 * exclamation marks within single quotes, and nukes whitespace. This
110 * function returns a pointer to a buffer that is overwritten by each call.
2b6fc908 111 */
c29b090f 112static void print_normalized(const struct getopt_control *ctl, const char *arg)
2b6fc908 113{
eba520d8 114 char *buf;
735a6603 115 const char *argptr = arg;
2b6fc908
KZ
116 char *bufptr;
117
1dacc901 118 if (!ctl->quote) {
eba520d8
SK
119 printf(" %s", arg);
120 return;
2b6fc908
KZ
121 }
122
735a6603 123 /*
455fe9a0 124 * Each character in arg may take up to four characters in the
735a6603
SK
125 * result: For a quote we need a closing quote, a backslash, a quote
126 * and an opening quote! We need also the global opening and closing
127 * quote, and one extra character for '\0'.
128 */
eba520d8 129 buf = xmalloc(strlen(arg) * 4 + 3);
eba520d8 130 bufptr = buf;
2b6fc908 131
bb742d73
SK
132 for (*bufptr++ = '\''; *argptr; argptr++) {
133 if (ctl->shell == TCSH) {
134 switch (*argptr) {
135 case '\\':
136 /* Backslash: replace it with: '\\' */
137 *bufptr++ = '\\';
138 *bufptr++ = '\\';
139 continue;
140 case '!':
141 /* Exclamation mark: replace it with: \! */
142 *bufptr++ = '\'';
143 *bufptr++ = '\\';
144 *bufptr++ = '!';
145 *bufptr++ = '\'';
146 continue;
147 case '\n':
148 /* Newline: replace it with: \n */
149 *bufptr++ = '\\';
150 *bufptr++ = 'n';
151 continue;
152 }
153 if (isspace(*argptr)) {
154 /* Non-newline whitespace: replace it with \<ws> */
155 *bufptr++ = '\'';
156 *bufptr++ = '\\';
157 *bufptr++ = *argptr;
158 *bufptr++ = '\'';
159 continue;
160 }
161 }
2b6fc908
KZ
162 if (*argptr == '\'') {
163 /* Quote: replace it with: '\'' */
735a6603
SK
164 *bufptr++ = '\'';
165 *bufptr++ = '\\';
166 *bufptr++ = '\'';
167 *bufptr++ = '\'';
2b6fc908
KZ
168 } else
169 /* Just copy */
735a6603 170 *bufptr++ = *argptr;
2b6fc908 171 }
bb742d73 172
735a6603
SK
173 *bufptr++ = '\'';
174 *bufptr++ = '\0';
eba520d8
SK
175 printf(" %s", buf);
176 free(buf);
2b6fc908
KZ
177}
178
f9a20f0b 179/*
2b6fc908
KZ
180 * Generate the output. argv[0] is the program name (used for reporting errors).
181 * argv[1..] contains the options to be parsed. argc must be the number of
182 * elements in argv (ie. 1 if there are no options, only the program name),
183 * optstr must contain the short options, and longopts the long options.
184 * Other settings are found in global variables.
185 */
b13fedd4 186static int generate_output(struct getopt_control *ctl, char *argv[], int argc)
2b6fc908 187{
735a6603 188 int exit_code = EXIT_SUCCESS; /* Assume everything will be OK */
2b6fc908
KZ
189 int opt;
190 int longindex;
191 const char *charptr;
192
1dacc901 193 if (ctl->quiet_errors)
735a6603
SK
194 /* No error reporting from getopt(3) */
195 opterr = 0;
196 /* Reset getopt(3) */
197 optind = 0;
2b6fc908 198
735a6603 199 while ((opt =
b13fedd4
SK
200 (getopt_long_fp
201 (argc, argv, ctl->optstr,
202 (const struct option *)ctl->long_options, &longindex)))
203 != EOF) {
735a6603 204 if (opt == '?' || opt == ':')
d1d03b54 205 exit_code = GETOPT_EXIT_CODE;
1dacc901 206 else if (!ctl->quiet_output) {
bb742d73
SK
207 switch (opt) {
208 case LONG_OPT:
1dacc901
SK
209 printf(" --%s", ctl->long_options[longindex].name);
210 if (ctl->long_options[longindex].has_arg)
c29b090f 211 print_normalized(ctl, optarg ? optarg : "");
bb742d73
SK
212 break;
213 case NON_OPT:
c29b090f 214 print_normalized(ctl, optarg ? optarg : "");
bb742d73
SK
215 break;
216 default:
735a6603 217 printf(" -%c", opt);
1dacc901 218 charptr = strchr(ctl->optstr, opt);
2b6fc908 219 if (charptr != NULL && *++charptr == ':')
c29b090f 220 print_normalized(ctl, optarg ? optarg : "");
2b6fc908
KZ
221 }
222 }
b13fedd4 223 }
1dacc901 224 if (!ctl->quiet_output) {
2b6fc908 225 printf(" --");
735a6603 226 while (optind < argc)
c29b090f 227 print_normalized(ctl, argv[optind++]);
2b6fc908
KZ
228 printf("\n");
229 }
b13fedd4
SK
230 for (longindex = 0; longindex < ctl->long_options_nr; longindex++)
231 free((char *)ctl->long_options[longindex].name);
232 free(ctl->long_options);
233 free(ctl->optstr);
e402d6d3 234 free(ctl->name);
2b6fc908
KZ
235 return exit_code;
236}
237
238/*
735a6603
SK
239 * Report an error when parsing getopt's own arguments. If message is NULL,
240 * we already sent a message, we just exit with a helpful hint.
2b6fc908 241 */
735a6603 242static void __attribute__ ((__noreturn__)) parse_error(const char *message)
2b6fc908
KZ
243{
244 if (message)
735a6603 245 warnx("%s", message);
6d7bee26 246 errtryhelp(PARAMETER_EXIT_CODE);
2b6fc908
KZ
247}
248
2b6fc908
KZ
249
250/* Register a long option. The contents of name is copied. */
1dacc901 251static void add_longopt(struct getopt_control *ctl, const char *name, int has_arg)
2b6fc908 252{
b5f3078e 253 static int flag;
e1164591 254 int nr = ctl->long_options_nr;
b5f3078e 255
1dacc901
SK
256 if (ctl->long_options_nr == ctl->long_options_length) {
257 ctl->long_options_length += REALLOC_INCREMENT;
258 ctl->long_options = xrealloc(ctl->long_options,
259 sizeof(struct option) *
260 ctl->long_options_length);
2b6fc908 261 }
0640689c 262 if (name) {
735a6603 263 /* Not for init! */
e1164591
KZ
264 ctl->long_options[nr].has_arg = has_arg;
265 ctl->long_options[nr].flag = &flag;
266 ctl->long_options[nr].val = ctl->long_options_nr;
267 ctl->long_options[nr].name = xstrdup(name);
268 } else {
269 /* lets use add_longopt(ct, NULL, 0) to terminate the array */
270 ctl->long_options[nr].name = NULL;
271 ctl->long_options[nr].has_arg = 0;
272 ctl->long_options[nr].flag = NULL;
273 ctl->long_options[nr].val = 0;
2b6fc908 274 }
2b6fc908 275}
735a6603 276
2b6fc908 277
f9a20f0b 278/*
735a6603
SK
279 * Register several long options. options is a string of long options,
280 * separated by commas or whitespace. This nukes options!
2b6fc908 281 */
1dacc901 282static void add_long_options(struct getopt_control *ctl, char *options)
2b6fc908
KZ
283{
284 int arg_opt;
735a6603 285 char *tokptr = strtok(options, ", \t\n");
4b4e1b10 286
2b6fc908 287 while (tokptr) {
4b4e1b10
KZ
288 size_t len = strlen(tokptr);
289
735a6603 290 arg_opt = no_argument;
4b4e1b10
KZ
291 if (len > 0) {
292 if (tokptr[len - 1] == ':') {
293 if (tokptr[len - 2] == ':') {
294 tokptr[len - 2] = '\0';
735a6603 295 arg_opt = optional_argument;
2b6fc908 296 } else {
4b4e1b10 297 tokptr[len - 1] = '\0';
735a6603 298 arg_opt = required_argument;
2b6fc908 299 }
4b4e1b10 300 if (!*tokptr)
735a6603
SK
301 parse_error(_
302 ("empty long option after "
303 "-l or --long argument"));
2b6fc908 304 }
1dacc901 305 add_longopt(ctl, tokptr, arg_opt);
3aa14187 306 ctl->long_options_nr++;
2b6fc908 307 }
735a6603 308 tokptr = strtok(NULL, ", \t\n");
2b6fc908 309 }
f7b38b87 310 add_longopt(ctl, NULL, 0); /* ensure long_options[] is not full */
2b6fc908
KZ
311}
312
80dd38e9 313static shell_t shell_type(const char *new_shell)
2b6fc908 314{
735a6603 315 if (!strcmp(new_shell, "bash"))
80dd38e9
SK
316 return BASH;
317 if (!strcmp(new_shell, "sh"))
318 return BASH;
319 if (!strcmp(new_shell, "tcsh"))
320 return TCSH;
321 if (!strcmp(new_shell, "csh"))
322 return TCSH;
323 parse_error(_("unknown shell after -s or --shell argument"));
2b6fc908
KZ
324}
325
6d7bee26 326static void __attribute__((__noreturn__)) usage(void)
2b6fc908 327{
6d7bee26
RM
328 fputs(USAGE_HEADER, stdout);
329 printf(_(
ae769172
BS
330 " %1$s <optstring> <parameters>\n"
331 " %1$s [options] [--] <optstring> <parameters>\n"
332 " %1$s [options] -o|--options <optstring> [options] [--] <parameters>\n"),
283f8f02 333 program_invocation_short_name);
ca38f611 334
6d7bee26
RM
335 fputs(USAGE_SEPARATOR, stdout);
336 fputs(_("Parse command options.\n"), stdout);
337
338 fputs(USAGE_OPTIONS, stdout);
339 fputs(_(" -a, --alternative allow long options starting with single -\n"), stdout);
340 fputs(_(" -l, --longoptions <longopts> the long options to be recognized\n"), stdout);
341 fputs(_(" -n, --name <progname> the name under which errors are reported\n"), stdout);
342 fputs(_(" -o, --options <optstring> the short options to be recognized\n"), stdout);
343 fputs(_(" -q, --quiet disable error reporting by getopt(3)\n"), stdout);
344 fputs(_(" -Q, --quiet-output no normal output\n"), stdout);
345 fputs(_(" -s, --shell <shell> set quoting conventions to those of <shell>\n"), stdout);
346 fputs(_(" -T, --test test for getopt(1) version\n"), stdout);
347 fputs(_(" -u, --unquoted do not quote the output\n"), stdout);
348 fputs(USAGE_SEPARATOR, stdout);
f45f3ec3 349 printf(USAGE_HELP_OPTIONS(31));
6d7bee26
RM
350 printf(USAGE_MAN_TAIL("getopt(1)"));
351 exit(EXIT_SUCCESS);
2b6fc908 352}
2b6fc908
KZ
353
354int main(int argc, char *argv[])
355{
1dacc901
SK
356 struct getopt_control ctl = {
357 .shell = BASH,
358 .quote = 1
359 };
5c36a0eb 360 int opt;
2b6fc908 361
283f8f02
SK
362 /* Stop scanning as soon as a non-option argument is found! */
363 static const char *shortopts = "+ao:l:n:qQs:TuhV";
364 static const struct option longopts[] = {
365 {"options", required_argument, NULL, 'o'},
366 {"longoptions", required_argument, NULL, 'l'},
367 {"quiet", no_argument, NULL, 'q'},
368 {"quiet-output", no_argument, NULL, 'Q'},
369 {"shell", required_argument, NULL, 's'},
370 {"test", no_argument, NULL, 'T'},
371 {"unquoted", no_argument, NULL, 'u'},
372 {"help", no_argument, NULL, 'h'},
373 {"alternative", no_argument, NULL, 'a'},
374 {"name", required_argument, NULL, 'n'},
375 {"version", no_argument, NULL, 'V'},
376 {NULL, 0, NULL, 0}
377 };
378
735a6603 379 setlocale(LC_ALL, "");
7eda085c
KZ
380 bindtextdomain(PACKAGE, LOCALEDIR);
381 textdomain(PACKAGE);
2c308875 382 close_stdout_atexit();
7eda085c 383
735a6603 384 if (getenv("GETOPT_COMPATIBLE"))
1dacc901 385 ctl.compatible = 1;
2b6fc908 386
735a6603 387 if (argc == 1) {
1dacc901 388 if (ctl.compatible) {
735a6603
SK
389 /*
390 * For some reason, the original getopt gave no
391 * error when there were no arguments.
392 */
2b6fc908 393 printf(" --\n");
d1d03b54 394 return EXIT_SUCCESS;
042f62df
RP
395 }
396 parse_error(_("missing optstring argument"));
2b6fc908 397 }
735a6603 398
b13fedd4
SK
399 add_longopt(&ctl, NULL, 0); /* init */
400 getopt_long_fp = getopt_long;
401
1dacc901
SK
402 if (argv[1][0] != '-' || ctl.compatible) {
403 ctl.quote = 0;
404 ctl.optstr = xmalloc(strlen(argv[1]) + 1);
405 strcpy(ctl.optstr, argv[1] + strspn(argv[1], "-+"));
735a6603 406 argv[1] = argv[0];
1dacc901 407 return generate_output(&ctl, argv + 1, argc - 1);
2b6fc908 408 }
735a6603
SK
409
410 while ((opt =
411 getopt_long(argc, argv, shortopts, longopts, NULL)) != EOF)
2b6fc908
KZ
412 switch (opt) {
413 case 'a':
4a898108 414 getopt_long_fp = getopt_long_only;
2b6fc908 415 break;
2b6fc908 416 case 'o':
1dacc901 417 free(ctl.optstr);
05ac43f5 418 ctl.optstr = xstrdup(optarg);
2b6fc908
KZ
419 break;
420 case 'l':
1dacc901 421 add_long_options(&ctl, optarg);
2b6fc908
KZ
422 break;
423 case 'n':
e402d6d3
KZ
424 free(ctl.name);
425 ctl.name = xstrdup(optarg);
2b6fc908
KZ
426 break;
427 case 'q':
1dacc901 428 ctl.quiet_errors = 1;
2b6fc908
KZ
429 break;
430 case 'Q':
1dacc901 431 ctl.quiet_output = 1;
2b6fc908
KZ
432 break;
433 case 's':
80dd38e9 434 ctl.shell = shell_type(optarg);
2b6fc908
KZ
435 break;
436 case 'T':
b13fedd4 437 free(ctl.long_options);
d1d03b54 438 return TEST_EXIT_CODE;
66ee8158 439 case 'u':
1dacc901 440 ctl.quote = 0;
66ee8158 441 break;
2c308875 442
2b6fc908 443 case 'V':
2c308875 444 print_version(EXIT_SUCCESS);
2b6fc908
KZ
445 case '?':
446 case ':':
447 parse_error(NULL);
2c308875
KZ
448 case 'h':
449 usage();
2b6fc908 450 default:
7eda085c 451 parse_error(_("internal error, contact the author."));
2b6fc908 452 }
f9a20f0b 453
1dacc901 454 if (!ctl.optstr) {
2b6fc908 455 if (optind >= argc)
7eda085c 456 parse_error(_("missing optstring argument"));
2b6fc908 457 else {
05ac43f5 458 ctl.optstr = xstrdup(argv[optind]);
2b6fc908
KZ
459 optind++;
460 }
461 }
5c78d493 462
e402d6d3
KZ
463 if (ctl.name) {
464 argv[optind - 1] = ctl.name;
30fbf2f6 465#if defined (HAVE_SETPROGNAME) && !defined (__linux__)
e402d6d3 466 setprogname(ctl.name);
5c78d493
RM
467#endif
468 } else
735a6603
SK
469 argv[optind - 1] = argv[0];
470
1dacc901 471 return generate_output(&ctl, argv + optind - 1, argc - optind + 1);
2b6fc908 472}