Added getopt(1) from "Alfred M. Szmidt" <ams@trillian.itslinux.org>
-Erik
This commit is contained in:
parent
e2205f093b
commit
a1f16bba72
@ -100,6 +100,9 @@ const struct BB_applet applets[] = {
|
||||
#ifdef BB_FSCK_MINIX
|
||||
{"fsck.minix", fsck_minix_main, _BB_DIR_SBIN, fsck_minix_usage},
|
||||
#endif
|
||||
#ifdef BB_GETOPT
|
||||
{"getopt", getopt_main, _BB_DIR_BIN},
|
||||
#endif
|
||||
#ifdef BB_GREP
|
||||
{"grep", grep_main, _BB_DIR_BIN, grep_usage},
|
||||
#endif
|
||||
|
@ -100,6 +100,9 @@ const struct BB_applet applets[] = {
|
||||
#ifdef BB_FSCK_MINIX
|
||||
{"fsck.minix", fsck_minix_main, _BB_DIR_SBIN, fsck_minix_usage},
|
||||
#endif
|
||||
#ifdef BB_GETOPT
|
||||
{"getopt", getopt_main, _BB_DIR_BIN},
|
||||
#endif
|
||||
#ifdef BB_GREP
|
||||
{"grep", grep_main, _BB_DIR_BIN, grep_usage},
|
||||
#endif
|
||||
|
@ -33,6 +33,7 @@
|
||||
#define BB_FREE
|
||||
#define BB_FREERAMDISK
|
||||
#define BB_FSCK_MINIX
|
||||
#define BB_GETOPT
|
||||
#define BB_GREP
|
||||
#define BB_GUNZIP
|
||||
#define BB_GZIP
|
||||
|
@ -57,7 +57,7 @@ Currently defined functions include:
|
||||
|
||||
ar, basename, cat, chgrp, chmod, chown, chroot, chvt, clear, cp, cut, date,
|
||||
dc, dd, deallocvt, df, dirname, dmesg, du, dumpkmap, dutmp, echo, false, fbset,
|
||||
fdflush, find, free, freeramdisk, fsck.minix, grep, gunzip, gzip, halt,
|
||||
fdflush, find, free, freeramdisk, fsck.minix, getopt, grep, gunzip, gzip, halt,
|
||||
head, hostid, hostname, id, init, insmod, kill, killall, length, ln,
|
||||
loadacm, loadfont, loadkmap, logger, logname, ls, lsmod, makedevs, mkdir,
|
||||
mkfifo, mkfs.minix, mknod, mkswap, mktemp, more, mount, mt, mv, nc,
|
||||
@ -614,6 +614,48 @@ Options:
|
||||
|
||||
-------------------------------
|
||||
|
||||
=item getopt
|
||||
|
||||
Usage: getopt [OPTIONS]...
|
||||
|
||||
Parse command options
|
||||
|
||||
Options:
|
||||
|
||||
-a, --alternative Allow long options starting with single -\n"
|
||||
-l, --longoptions=longopts Long options to be recognized\n"
|
||||
-n, --name=progname The name under which errors are reported\n"
|
||||
-o, --options=optstring Short options to be recognized\n"
|
||||
-q, --quiet Disable error reporting by getopt(3)\n"
|
||||
-Q, --quiet-output No normal output\n"
|
||||
-s, --shell=shell Set shell quoting conventions\n"
|
||||
-T, --test Test for getopt(1) version\n"
|
||||
-u, --unqote Do not quote the output\n"
|
||||
|
||||
Example:
|
||||
$ cat getopt.test
|
||||
#!/bin/sh
|
||||
GETOPT=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \
|
||||
-n 'example.busybox' -- "$@"`
|
||||
if [ $? != 0 ] ; then exit 1 ; fi
|
||||
eval set -- "$GETOPT"
|
||||
while true ; do
|
||||
case $1 in
|
||||
-a|--a-long) echo "Option a" ; shift ;;
|
||||
-b|--b-long) echo "Option b, argument \`$2'" ; shift 2 ;;
|
||||
-c|--c-long)
|
||||
case "$2" in
|
||||
"") echo "Option c, no argument"; shift 2 ;;
|
||||
*) echo "Option c, argument \`$2'" ; shift 2 ;;
|
||||
esac ;;
|
||||
--) shift ; break ;;
|
||||
*) echo "Internal error!" ; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
-------------------------------
|
||||
|
||||
=item grep
|
||||
|
||||
Usage: grep [OPTIONS]... PATTERN [FILE]...
|
||||
@ -2052,4 +2094,4 @@ Enrique Zanardi <ezanardi@ull.es>
|
||||
|
||||
=cut
|
||||
|
||||
# $Id: busybox.pod,v 1.61 2000/08/21 21:18:52 andersen Exp $
|
||||
# $Id: busybox.pod,v 1.62 2000/08/21 22:02:34 andersen Exp $
|
||||
|
@ -1063,6 +1063,61 @@
|
||||
</screen>
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="getopt">
|
||||
<title>getopt</title>
|
||||
|
||||
<para>
|
||||
Usage: getopt [OPTIONS]...
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Parse command options
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<screen>
|
||||
-a, --alternative Allow long options starting with single -\n"
|
||||
-l, --longoptions=longopts Long options to be recognized\n"
|
||||
-n, --name=progname The name under which errors are reported\n"
|
||||
-o, --options=optstring Short options to be recognized\n"
|
||||
-q, --quiet Disable error reporting by getopt(3)\n"
|
||||
-Q, --quiet-output No normal output\n"
|
||||
-s, --shell=shell Set shell quoting conventions\n"
|
||||
-T, --test Test for getopt(1) version\n"
|
||||
-u, --unqote Do not quote the output\n"
|
||||
</screen>
|
||||
</para>
|
||||
|
||||
|
||||
<para>
|
||||
Example:
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<screen>
|
||||
$ cat getopt.test
|
||||
#!/bin/sh
|
||||
GETOPT=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \
|
||||
-n 'example.busybox' -- "$@"`
|
||||
if [ $? != 0 ] ; then exit 1 ; fi
|
||||
eval set -- "$GETOPT"
|
||||
while true ; do
|
||||
case $1 in
|
||||
-a|--a-long) echo "Option a" ; shift ;;
|
||||
-b|--b-long) echo "Option b, argument \`$2'" ; shift 2 ;;
|
||||
-c|--c-long)
|
||||
case "$2" in
|
||||
"") echo "Option c, no argument"; shift 2 ;;
|
||||
*) echo "Option c, argument \`$2'" ; shift 2 ;;
|
||||
esac ;;
|
||||
--) shift ; break ;;
|
||||
*) echo "Internal error!" ; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
</screen>
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="grep">
|
||||
<title>grep</title>
|
||||
|
416
getopt.c
Normal file
416
getopt.c
Normal file
@ -0,0 +1,416 @@
|
||||
/*
|
||||
* getopt.c - Enhanced implementation of BSD getopt(1)
|
||||
* Copyright (c) 1997, 1998, 1999, 2000 Frodo Looijaard <frodol@dds.nl>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Version 1.0-b4: Tue Sep 23 1997. First public release.
|
||||
* Version 1.0: Wed Nov 19 1997.
|
||||
* Bumped up the version number to 1.0
|
||||
* Fixed minor typo (CSH instead of TCSH)
|
||||
* Version 1.0.1: Tue Jun 3 1998
|
||||
* Fixed sizeof instead of strlen bug
|
||||
* Bumped up the version number to 1.0.1
|
||||
* Version 1.0.2: Thu Jun 11 1998 (not present)
|
||||
* Fixed gcc-2.8.1 warnings
|
||||
* Fixed --version/-V option (not present)
|
||||
* Version 1.0.5: Tue Jun 22 1999
|
||||
* Make -u option work (not present)
|
||||
* Version 1.0.6: Tue Jun 27 2000
|
||||
* No important changes
|
||||
* Version 1.1.0: Tue Jun 30 2000
|
||||
* Added NLS support (partly written by Arkadiusz Mi<B6>kiewicz
|
||||
* <misiek@misiek.eu.org>)
|
||||
* Ported to Busybox - Alfred M. Szmidt <ams@trillian.itslinux.org>
|
||||
* Removed --version/-V and --help/-h in
|
||||
* Removed prase_error(), using errorMsg() from Busybox instead
|
||||
* Replaced our_malloc with xmalloc and our_realloc with xrealloc
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
/* NON_OPT is the code that is returned when a non-option is found in '+'
|
||||
mode */
|
||||
#define NON_OPT 1
|
||||
/* LONG_OPT is the code that is returned when a long option is found. */
|
||||
#define LONG_OPT 2
|
||||
|
||||
/* The shells recognized. */
|
||||
typedef enum {BASH,TCSH} shell_t;
|
||||
|
||||
|
||||
/* Some global variables that tells us how to parse. */
|
||||
shell_t shell=BASH; /* The shell we generate output for. */
|
||||
int quiet_errors=0; /* 0 is not quiet. */
|
||||
int quiet_output=0; /* 0 is not quiet. */
|
||||
int quote=1; /* 1 is do quote. */
|
||||
int alternative=0; /* 0 is getopt_long, 1 is getopt_long_only */
|
||||
|
||||
/* Function prototypes */
|
||||
const char *normalize(const char *arg);
|
||||
int generate_output(char * argv[],int argc,const char *optstr,
|
||||
const struct option *longopts);
|
||||
void add_long_options(char *options);
|
||||
void add_longopt(const char *name,int has_arg);
|
||||
void set_shell(const char *new_shell);
|
||||
void set_initial_shell(void);
|
||||
|
||||
|
||||
/*
|
||||
* This function 'normalizes' a single argument: it puts single quotes around
|
||||
* it and escapes other special characters. If quote is false, it just
|
||||
* returns its argument.
|
||||
* Bash only needs special treatment for single quotes; tcsh also recognizes
|
||||
* exclamation marks within single quotes, and nukes whitespace.
|
||||
* This function returns a pointer to a buffer that is overwritten by
|
||||
* each call.
|
||||
*/
|
||||
const char *normalize(const char *arg)
|
||||
{
|
||||
static char *BUFFER=NULL;
|
||||
const char *argptr=arg;
|
||||
char *bufptr;
|
||||
|
||||
if (BUFFER != NULL)
|
||||
free(BUFFER);
|
||||
|
||||
if (!quote) { /* Just copy arg */
|
||||
BUFFER=xmalloc(strlen(arg)+1);
|
||||
|
||||
strcpy(BUFFER,arg);
|
||||
return BUFFER;
|
||||
}
|
||||
|
||||
/* Each character in arg may take upto four characters in the result:
|
||||
For a quote we need a closing quote, a backslash, a quote and an
|
||||
opening quote! We need also the global opening and closing quote,
|
||||
and one extra character for '\0'. */
|
||||
BUFFER=xmalloc(strlen(arg)*4+3);
|
||||
|
||||
bufptr=BUFFER;
|
||||
*bufptr++='\'';
|
||||
|
||||
while (*argptr) {
|
||||
if (*argptr == '\'') {
|
||||
/* Quote: replace it with: '\'' */
|
||||
*bufptr++='\'';
|
||||
*bufptr++='\\';
|
||||
*bufptr++='\'';
|
||||
*bufptr++='\'';
|
||||
} else if (shell==TCSH && *argptr=='!') {
|
||||
/* Exclamation mark: replace it with: \! */
|
||||
*bufptr++='\'';
|
||||
*bufptr++='\\';
|
||||
*bufptr++='!';
|
||||
*bufptr++='\'';
|
||||
} else if (shell==TCSH && *argptr=='\n') {
|
||||
/* Newline: replace it with: \n */
|
||||
*bufptr++='\\';
|
||||
*bufptr++='n';
|
||||
} else if (shell==TCSH && isspace(*argptr)) {
|
||||
/* Non-newline whitespace: replace it with \<ws> */
|
||||
*bufptr++='\'';
|
||||
*bufptr++='\\';
|
||||
*bufptr++=*argptr;
|
||||
*bufptr++='\'';
|
||||
} else
|
||||
/* Just copy */
|
||||
*bufptr++=*argptr;
|
||||
argptr++;
|
||||
}
|
||||
*bufptr++='\'';
|
||||
*bufptr++='\0';
|
||||
return BUFFER;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate the output. argv[0] is the program name (used for reporting errors).
|
||||
* argv[1..] contains the options to be parsed. argc must be the number of
|
||||
* elements in argv (ie. 1 if there are no options, only the program name),
|
||||
* optstr must contain the short options, and longopts the long options.
|
||||
* Other settings are found in global variables.
|
||||
*/
|
||||
int generate_output(char * argv[],int argc,const char *optstr,
|
||||
const struct option *longopts)
|
||||
{
|
||||
int exit_code = 0; /* We assume everything will be OK */
|
||||
int opt;
|
||||
int longindex;
|
||||
const char *charptr;
|
||||
|
||||
if (quiet_errors) /* No error reporting from getopt(3) */
|
||||
opterr=0;
|
||||
optind=0; /* Reset getopt(3) */
|
||||
|
||||
while ((opt = (alternative?
|
||||
getopt_long_only(argc,argv,optstr,longopts,&longindex):
|
||||
getopt_long(argc,argv,optstr,longopts,&longindex)))
|
||||
!= EOF)
|
||||
if (opt == '?' || opt == ':' )
|
||||
exit_code = 1;
|
||||
else if (!quiet_output) {
|
||||
if (opt == LONG_OPT) {
|
||||
printf(" --%s",longopts[longindex].name);
|
||||
if (longopts[longindex].has_arg)
|
||||
printf(" %s",
|
||||
normalize(optarg?optarg:""));
|
||||
} else if (opt == NON_OPT)
|
||||
printf(" %s",normalize(optarg));
|
||||
else {
|
||||
printf(" -%c",opt);
|
||||
charptr = strchr(optstr,opt);
|
||||
if (charptr != NULL && *++charptr == ':')
|
||||
printf(" %s",
|
||||
normalize(optarg?optarg:""));
|
||||
}
|
||||
}
|
||||
|
||||
if (! quiet_output) {
|
||||
printf(" --");
|
||||
while (optind < argc)
|
||||
printf(" %s",normalize(argv[optind++]));
|
||||
printf("\n");
|
||||
}
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
static struct option *long_options=NULL;
|
||||
static int long_options_length=0; /* Length of array */
|
||||
static int long_options_nr=0; /* Nr of used elements in array */
|
||||
#define LONG_OPTIONS_INCR 10
|
||||
#define init_longopt() add_longopt(NULL,0)
|
||||
|
||||
/* Register a long option. The contents of name is copied. */
|
||||
void add_longopt(const char *name,int has_arg)
|
||||
{
|
||||
char *tmp;
|
||||
if (!name) { /* init */
|
||||
free(long_options);
|
||||
long_options=NULL;
|
||||
long_options_length=0;
|
||||
long_options_nr=0;
|
||||
}
|
||||
|
||||
if (long_options_nr == long_options_length) {
|
||||
long_options_length += LONG_OPTIONS_INCR;
|
||||
long_options=xrealloc(long_options,
|
||||
sizeof(struct option) *
|
||||
long_options_length);
|
||||
}
|
||||
|
||||
long_options[long_options_nr].name=NULL;
|
||||
long_options[long_options_nr].has_arg=0;
|
||||
long_options[long_options_nr].flag=NULL;
|
||||
long_options[long_options_nr].val=0;
|
||||
|
||||
if (long_options_nr) { /* Not for init! */
|
||||
long_options[long_options_nr-1].has_arg=has_arg;
|
||||
long_options[long_options_nr-1].flag=NULL;
|
||||
long_options[long_options_nr-1].val=LONG_OPT;
|
||||
tmp = xmalloc(strlen(name)+1);
|
||||
strcpy(tmp,name);
|
||||
long_options[long_options_nr-1].name=tmp;
|
||||
}
|
||||
long_options_nr++;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Register several long options. options is a string of long options,
|
||||
* separated by commas or whitespace.
|
||||
* This nukes options!
|
||||
*/
|
||||
void add_long_options(char *options)
|
||||
{
|
||||
int arg_opt;
|
||||
char *tokptr=strtok(options,", \t\n");
|
||||
while (tokptr) {
|
||||
arg_opt=no_argument;
|
||||
if (strlen(tokptr) > 0) {
|
||||
if (tokptr[strlen(tokptr)-1] == ':') {
|
||||
if (tokptr[strlen(tokptr)-2] == ':') {
|
||||
tokptr[strlen(tokptr)-2]='\0';
|
||||
arg_opt=optional_argument;
|
||||
} else {
|
||||
tokptr[strlen(tokptr)-1]='\0';
|
||||
arg_opt=required_argument;
|
||||
}
|
||||
if (strlen(tokptr) == 0)
|
||||
errorMsg("empty long option after -l or --long argument\n");
|
||||
}
|
||||
add_longopt(tokptr,arg_opt);
|
||||
}
|
||||
tokptr=strtok(NULL,", \t\n");
|
||||
}
|
||||
}
|
||||
|
||||
void set_shell(const char *new_shell)
|
||||
{
|
||||
if (!strcmp(new_shell,"bash"))
|
||||
shell=BASH;
|
||||
else if (!strcmp(new_shell,"tcsh"))
|
||||
shell=TCSH;
|
||||
else if (!strcmp(new_shell,"sh"))
|
||||
shell=BASH;
|
||||
else if (!strcmp(new_shell,"csh"))
|
||||
shell=TCSH;
|
||||
else
|
||||
errorMsg("unknown shell after -s or --shell argument\n");
|
||||
}
|
||||
|
||||
|
||||
/* Exit codes:
|
||||
* 0) No errors, succesful operation.
|
||||
* 1) getopt(3) returned an error.
|
||||
* 2) A problem with parameter parsing for getopt(1).
|
||||
* 3) Internal error, out of memory
|
||||
* 4) Returned for -T
|
||||
*/
|
||||
|
||||
static struct option longopts[]=
|
||||
{
|
||||
{"options",required_argument,NULL,'o'},
|
||||
{"longoptions",required_argument,NULL,'l'},
|
||||
{"quiet",no_argument,NULL,'q'},
|
||||
{"quiet-output",no_argument,NULL,'Q'},
|
||||
{"shell",required_argument,NULL,'s'},
|
||||
{"test",no_argument,NULL,'T'},
|
||||
{"unquoted",no_argument,NULL,'u'},
|
||||
{"alternative",no_argument,NULL,'a'},
|
||||
{"name",required_argument,NULL,'n'},
|
||||
{NULL,0,NULL,0}
|
||||
};
|
||||
|
||||
/* Stop scanning as soon as a non-option argument is found! */
|
||||
static const char *shortopts="+ao:l:n:qQs:Tu";
|
||||
|
||||
static const char getopt_usage[] =
|
||||
"getopt [OPTIONS]...\n"
|
||||
#ifndef BB_FEATURE_TRIVIAL_HELP
|
||||
"Parse command options\n"
|
||||
" -a, --alternative Allow long options starting with single -\n"
|
||||
" -l, --longoptions=longopts Long options to be recognized\n"
|
||||
" -n, --name=progname The name under which errors are reported\n"
|
||||
" -o, --options=optstring Short options to be recognized\n"
|
||||
" -q, --quiet Disable error reporting by getopt(3)\n"
|
||||
" -Q, --quiet-output No normal output\n"
|
||||
" -s, --shell=shell Set shell quoting conventions\n"
|
||||
" -T, --test Test for getopt(1) version\n"
|
||||
" -u, --unqote Do not quote the output\n"
|
||||
#endif
|
||||
;
|
||||
|
||||
|
||||
int getopt_main(int argc, char *argv[])
|
||||
{
|
||||
char *optstr=NULL;
|
||||
char *name=NULL;
|
||||
int opt;
|
||||
int compatible=0;
|
||||
|
||||
init_longopt();
|
||||
|
||||
if (getenv("GETOPT_COMPATIBLE"))
|
||||
compatible=1;
|
||||
|
||||
if (argc == 1) {
|
||||
if (compatible) {
|
||||
/* For some reason, the original getopt gave no error
|
||||
when there were no arguments. */
|
||||
printf(" --\n");
|
||||
exit(0);
|
||||
} else
|
||||
fatalError("missing optstring argument\n");
|
||||
}
|
||||
|
||||
if (argv[1][0] != '-' || compatible) {
|
||||
quote=0;
|
||||
optstr=xmalloc(strlen(argv[1])+1);
|
||||
strcpy(optstr,argv[1]+strspn(argv[1],"-+"));
|
||||
argv[1]=argv[0];
|
||||
exit(generate_output(argv+1,argc-1,optstr,long_options));
|
||||
}
|
||||
|
||||
while ((opt=getopt_long(argc,argv,shortopts,longopts,NULL)) != EOF)
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
alternative=1;
|
||||
break;
|
||||
case 'o':
|
||||
if (optstr)
|
||||
free(optstr);
|
||||
optstr=xmalloc(strlen(optarg)+1);
|
||||
strcpy(optstr,optarg);
|
||||
break;
|
||||
case 'l':
|
||||
add_long_options(optarg);
|
||||
break;
|
||||
case 'n':
|
||||
if (name)
|
||||
free(name);
|
||||
name=xmalloc(strlen(optarg)+1);
|
||||
strcpy(name,optarg);
|
||||
break;
|
||||
case 'q':
|
||||
quiet_errors=1;
|
||||
break;
|
||||
case 'Q':
|
||||
quiet_output=1;
|
||||
break;
|
||||
case 's':
|
||||
set_shell(optarg);
|
||||
break;
|
||||
case 'T':
|
||||
exit(4);
|
||||
case 'u':
|
||||
quote=0;
|
||||
break;
|
||||
default:
|
||||
usage(getopt_usage);
|
||||
}
|
||||
|
||||
if (!optstr) {
|
||||
if (optind >= argc)
|
||||
fatalError("missing optstring argument\n");
|
||||
else {
|
||||
optstr=xmalloc(strlen(argv[optind])+1);
|
||||
strcpy(optstr,argv[optind]);
|
||||
optind++;
|
||||
}
|
||||
}
|
||||
if (name)
|
||||
argv[optind-1]=name;
|
||||
else
|
||||
argv[optind-1]=argv[0];
|
||||
exit(generate_output(argv+optind-1,argc-optind+1,optstr,long_options));
|
||||
}
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
c-file-style: "linux"
|
||||
c-basic-offset: 4
|
||||
tab-width: 4
|
||||
End:
|
||||
*/
|
@ -137,6 +137,7 @@ extern int fsck_minix_main(int argc, char **argv);
|
||||
extern int find_main(int argc, char** argv);
|
||||
extern int free_main(int argc, char** argv);
|
||||
extern int freeramdisk_main(int argc, char** argv);
|
||||
extern int getopt_main(int argc, char** argv);
|
||||
extern int grep_main(int argc, char** argv);
|
||||
extern int gunzip_main (int argc, char** argv);
|
||||
extern int gzip_main(int argc, char** argv);
|
||||
|
416
util-linux/getopt.c
Normal file
416
util-linux/getopt.c
Normal file
@ -0,0 +1,416 @@
|
||||
/*
|
||||
* getopt.c - Enhanced implementation of BSD getopt(1)
|
||||
* Copyright (c) 1997, 1998, 1999, 2000 Frodo Looijaard <frodol@dds.nl>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Version 1.0-b4: Tue Sep 23 1997. First public release.
|
||||
* Version 1.0: Wed Nov 19 1997.
|
||||
* Bumped up the version number to 1.0
|
||||
* Fixed minor typo (CSH instead of TCSH)
|
||||
* Version 1.0.1: Tue Jun 3 1998
|
||||
* Fixed sizeof instead of strlen bug
|
||||
* Bumped up the version number to 1.0.1
|
||||
* Version 1.0.2: Thu Jun 11 1998 (not present)
|
||||
* Fixed gcc-2.8.1 warnings
|
||||
* Fixed --version/-V option (not present)
|
||||
* Version 1.0.5: Tue Jun 22 1999
|
||||
* Make -u option work (not present)
|
||||
* Version 1.0.6: Tue Jun 27 2000
|
||||
* No important changes
|
||||
* Version 1.1.0: Tue Jun 30 2000
|
||||
* Added NLS support (partly written by Arkadiusz Mi<B6>kiewicz
|
||||
* <misiek@misiek.eu.org>)
|
||||
* Ported to Busybox - Alfred M. Szmidt <ams@trillian.itslinux.org>
|
||||
* Removed --version/-V and --help/-h in
|
||||
* Removed prase_error(), using errorMsg() from Busybox instead
|
||||
* Replaced our_malloc with xmalloc and our_realloc with xrealloc
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
/* NON_OPT is the code that is returned when a non-option is found in '+'
|
||||
mode */
|
||||
#define NON_OPT 1
|
||||
/* LONG_OPT is the code that is returned when a long option is found. */
|
||||
#define LONG_OPT 2
|
||||
|
||||
/* The shells recognized. */
|
||||
typedef enum {BASH,TCSH} shell_t;
|
||||
|
||||
|
||||
/* Some global variables that tells us how to parse. */
|
||||
shell_t shell=BASH; /* The shell we generate output for. */
|
||||
int quiet_errors=0; /* 0 is not quiet. */
|
||||
int quiet_output=0; /* 0 is not quiet. */
|
||||
int quote=1; /* 1 is do quote. */
|
||||
int alternative=0; /* 0 is getopt_long, 1 is getopt_long_only */
|
||||
|
||||
/* Function prototypes */
|
||||
const char *normalize(const char *arg);
|
||||
int generate_output(char * argv[],int argc,const char *optstr,
|
||||
const struct option *longopts);
|
||||
void add_long_options(char *options);
|
||||
void add_longopt(const char *name,int has_arg);
|
||||
void set_shell(const char *new_shell);
|
||||
void set_initial_shell(void);
|
||||
|
||||
|
||||
/*
|
||||
* This function 'normalizes' a single argument: it puts single quotes around
|
||||
* it and escapes other special characters. If quote is false, it just
|
||||
* returns its argument.
|
||||
* Bash only needs special treatment for single quotes; tcsh also recognizes
|
||||
* exclamation marks within single quotes, and nukes whitespace.
|
||||
* This function returns a pointer to a buffer that is overwritten by
|
||||
* each call.
|
||||
*/
|
||||
const char *normalize(const char *arg)
|
||||
{
|
||||
static char *BUFFER=NULL;
|
||||
const char *argptr=arg;
|
||||
char *bufptr;
|
||||
|
||||
if (BUFFER != NULL)
|
||||
free(BUFFER);
|
||||
|
||||
if (!quote) { /* Just copy arg */
|
||||
BUFFER=xmalloc(strlen(arg)+1);
|
||||
|
||||
strcpy(BUFFER,arg);
|
||||
return BUFFER;
|
||||
}
|
||||
|
||||
/* Each character in arg may take upto four characters in the result:
|
||||
For a quote we need a closing quote, a backslash, a quote and an
|
||||
opening quote! We need also the global opening and closing quote,
|
||||
and one extra character for '\0'. */
|
||||
BUFFER=xmalloc(strlen(arg)*4+3);
|
||||
|
||||
bufptr=BUFFER;
|
||||
*bufptr++='\'';
|
||||
|
||||
while (*argptr) {
|
||||
if (*argptr == '\'') {
|
||||
/* Quote: replace it with: '\'' */
|
||||
*bufptr++='\'';
|
||||
*bufptr++='\\';
|
||||
*bufptr++='\'';
|
||||
*bufptr++='\'';
|
||||
} else if (shell==TCSH && *argptr=='!') {
|
||||
/* Exclamation mark: replace it with: \! */
|
||||
*bufptr++='\'';
|
||||
*bufptr++='\\';
|
||||
*bufptr++='!';
|
||||
*bufptr++='\'';
|
||||
} else if (shell==TCSH && *argptr=='\n') {
|
||||
/* Newline: replace it with: \n */
|
||||
*bufptr++='\\';
|
||||
*bufptr++='n';
|
||||
} else if (shell==TCSH && isspace(*argptr)) {
|
||||
/* Non-newline whitespace: replace it with \<ws> */
|
||||
*bufptr++='\'';
|
||||
*bufptr++='\\';
|
||||
*bufptr++=*argptr;
|
||||
*bufptr++='\'';
|
||||
} else
|
||||
/* Just copy */
|
||||
*bufptr++=*argptr;
|
||||
argptr++;
|
||||
}
|
||||
*bufptr++='\'';
|
||||
*bufptr++='\0';
|
||||
return BUFFER;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate the output. argv[0] is the program name (used for reporting errors).
|
||||
* argv[1..] contains the options to be parsed. argc must be the number of
|
||||
* elements in argv (ie. 1 if there are no options, only the program name),
|
||||
* optstr must contain the short options, and longopts the long options.
|
||||
* Other settings are found in global variables.
|
||||
*/
|
||||
int generate_output(char * argv[],int argc,const char *optstr,
|
||||
const struct option *longopts)
|
||||
{
|
||||
int exit_code = 0; /* We assume everything will be OK */
|
||||
int opt;
|
||||
int longindex;
|
||||
const char *charptr;
|
||||
|
||||
if (quiet_errors) /* No error reporting from getopt(3) */
|
||||
opterr=0;
|
||||
optind=0; /* Reset getopt(3) */
|
||||
|
||||
while ((opt = (alternative?
|
||||
getopt_long_only(argc,argv,optstr,longopts,&longindex):
|
||||
getopt_long(argc,argv,optstr,longopts,&longindex)))
|
||||
!= EOF)
|
||||
if (opt == '?' || opt == ':' )
|
||||
exit_code = 1;
|
||||
else if (!quiet_output) {
|
||||
if (opt == LONG_OPT) {
|
||||
printf(" --%s",longopts[longindex].name);
|
||||
if (longopts[longindex].has_arg)
|
||||
printf(" %s",
|
||||
normalize(optarg?optarg:""));
|
||||
} else if (opt == NON_OPT)
|
||||
printf(" %s",normalize(optarg));
|
||||
else {
|
||||
printf(" -%c",opt);
|
||||
charptr = strchr(optstr,opt);
|
||||
if (charptr != NULL && *++charptr == ':')
|
||||
printf(" %s",
|
||||
normalize(optarg?optarg:""));
|
||||
}
|
||||
}
|
||||
|
||||
if (! quiet_output) {
|
||||
printf(" --");
|
||||
while (optind < argc)
|
||||
printf(" %s",normalize(argv[optind++]));
|
||||
printf("\n");
|
||||
}
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
static struct option *long_options=NULL;
|
||||
static int long_options_length=0; /* Length of array */
|
||||
static int long_options_nr=0; /* Nr of used elements in array */
|
||||
#define LONG_OPTIONS_INCR 10
|
||||
#define init_longopt() add_longopt(NULL,0)
|
||||
|
||||
/* Register a long option. The contents of name is copied. */
|
||||
void add_longopt(const char *name,int has_arg)
|
||||
{
|
||||
char *tmp;
|
||||
if (!name) { /* init */
|
||||
free(long_options);
|
||||
long_options=NULL;
|
||||
long_options_length=0;
|
||||
long_options_nr=0;
|
||||
}
|
||||
|
||||
if (long_options_nr == long_options_length) {
|
||||
long_options_length += LONG_OPTIONS_INCR;
|
||||
long_options=xrealloc(long_options,
|
||||
sizeof(struct option) *
|
||||
long_options_length);
|
||||
}
|
||||
|
||||
long_options[long_options_nr].name=NULL;
|
||||
long_options[long_options_nr].has_arg=0;
|
||||
long_options[long_options_nr].flag=NULL;
|
||||
long_options[long_options_nr].val=0;
|
||||
|
||||
if (long_options_nr) { /* Not for init! */
|
||||
long_options[long_options_nr-1].has_arg=has_arg;
|
||||
long_options[long_options_nr-1].flag=NULL;
|
||||
long_options[long_options_nr-1].val=LONG_OPT;
|
||||
tmp = xmalloc(strlen(name)+1);
|
||||
strcpy(tmp,name);
|
||||
long_options[long_options_nr-1].name=tmp;
|
||||
}
|
||||
long_options_nr++;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Register several long options. options is a string of long options,
|
||||
* separated by commas or whitespace.
|
||||
* This nukes options!
|
||||
*/
|
||||
void add_long_options(char *options)
|
||||
{
|
||||
int arg_opt;
|
||||
char *tokptr=strtok(options,", \t\n");
|
||||
while (tokptr) {
|
||||
arg_opt=no_argument;
|
||||
if (strlen(tokptr) > 0) {
|
||||
if (tokptr[strlen(tokptr)-1] == ':') {
|
||||
if (tokptr[strlen(tokptr)-2] == ':') {
|
||||
tokptr[strlen(tokptr)-2]='\0';
|
||||
arg_opt=optional_argument;
|
||||
} else {
|
||||
tokptr[strlen(tokptr)-1]='\0';
|
||||
arg_opt=required_argument;
|
||||
}
|
||||
if (strlen(tokptr) == 0)
|
||||
errorMsg("empty long option after -l or --long argument\n");
|
||||
}
|
||||
add_longopt(tokptr,arg_opt);
|
||||
}
|
||||
tokptr=strtok(NULL,", \t\n");
|
||||
}
|
||||
}
|
||||
|
||||
void set_shell(const char *new_shell)
|
||||
{
|
||||
if (!strcmp(new_shell,"bash"))
|
||||
shell=BASH;
|
||||
else if (!strcmp(new_shell,"tcsh"))
|
||||
shell=TCSH;
|
||||
else if (!strcmp(new_shell,"sh"))
|
||||
shell=BASH;
|
||||
else if (!strcmp(new_shell,"csh"))
|
||||
shell=TCSH;
|
||||
else
|
||||
errorMsg("unknown shell after -s or --shell argument\n");
|
||||
}
|
||||
|
||||
|
||||
/* Exit codes:
|
||||
* 0) No errors, succesful operation.
|
||||
* 1) getopt(3) returned an error.
|
||||
* 2) A problem with parameter parsing for getopt(1).
|
||||
* 3) Internal error, out of memory
|
||||
* 4) Returned for -T
|
||||
*/
|
||||
|
||||
static struct option longopts[]=
|
||||
{
|
||||
{"options",required_argument,NULL,'o'},
|
||||
{"longoptions",required_argument,NULL,'l'},
|
||||
{"quiet",no_argument,NULL,'q'},
|
||||
{"quiet-output",no_argument,NULL,'Q'},
|
||||
{"shell",required_argument,NULL,'s'},
|
||||
{"test",no_argument,NULL,'T'},
|
||||
{"unquoted",no_argument,NULL,'u'},
|
||||
{"alternative",no_argument,NULL,'a'},
|
||||
{"name",required_argument,NULL,'n'},
|
||||
{NULL,0,NULL,0}
|
||||
};
|
||||
|
||||
/* Stop scanning as soon as a non-option argument is found! */
|
||||
static const char *shortopts="+ao:l:n:qQs:Tu";
|
||||
|
||||
static const char getopt_usage[] =
|
||||
"getopt [OPTIONS]...\n"
|
||||
#ifndef BB_FEATURE_TRIVIAL_HELP
|
||||
"Parse command options\n"
|
||||
" -a, --alternative Allow long options starting with single -\n"
|
||||
" -l, --longoptions=longopts Long options to be recognized\n"
|
||||
" -n, --name=progname The name under which errors are reported\n"
|
||||
" -o, --options=optstring Short options to be recognized\n"
|
||||
" -q, --quiet Disable error reporting by getopt(3)\n"
|
||||
" -Q, --quiet-output No normal output\n"
|
||||
" -s, --shell=shell Set shell quoting conventions\n"
|
||||
" -T, --test Test for getopt(1) version\n"
|
||||
" -u, --unqote Do not quote the output\n"
|
||||
#endif
|
||||
;
|
||||
|
||||
|
||||
int getopt_main(int argc, char *argv[])
|
||||
{
|
||||
char *optstr=NULL;
|
||||
char *name=NULL;
|
||||
int opt;
|
||||
int compatible=0;
|
||||
|
||||
init_longopt();
|
||||
|
||||
if (getenv("GETOPT_COMPATIBLE"))
|
||||
compatible=1;
|
||||
|
||||
if (argc == 1) {
|
||||
if (compatible) {
|
||||
/* For some reason, the original getopt gave no error
|
||||
when there were no arguments. */
|
||||
printf(" --\n");
|
||||
exit(0);
|
||||
} else
|
||||
fatalError("missing optstring argument\n");
|
||||
}
|
||||
|
||||
if (argv[1][0] != '-' || compatible) {
|
||||
quote=0;
|
||||
optstr=xmalloc(strlen(argv[1])+1);
|
||||
strcpy(optstr,argv[1]+strspn(argv[1],"-+"));
|
||||
argv[1]=argv[0];
|
||||
exit(generate_output(argv+1,argc-1,optstr,long_options));
|
||||
}
|
||||
|
||||
while ((opt=getopt_long(argc,argv,shortopts,longopts,NULL)) != EOF)
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
alternative=1;
|
||||
break;
|
||||
case 'o':
|
||||
if (optstr)
|
||||
free(optstr);
|
||||
optstr=xmalloc(strlen(optarg)+1);
|
||||
strcpy(optstr,optarg);
|
||||
break;
|
||||
case 'l':
|
||||
add_long_options(optarg);
|
||||
break;
|
||||
case 'n':
|
||||
if (name)
|
||||
free(name);
|
||||
name=xmalloc(strlen(optarg)+1);
|
||||
strcpy(name,optarg);
|
||||
break;
|
||||
case 'q':
|
||||
quiet_errors=1;
|
||||
break;
|
||||
case 'Q':
|
||||
quiet_output=1;
|
||||
break;
|
||||
case 's':
|
||||
set_shell(optarg);
|
||||
break;
|
||||
case 'T':
|
||||
exit(4);
|
||||
case 'u':
|
||||
quote=0;
|
||||
break;
|
||||
default:
|
||||
usage(getopt_usage);
|
||||
}
|
||||
|
||||
if (!optstr) {
|
||||
if (optind >= argc)
|
||||
fatalError("missing optstring argument\n");
|
||||
else {
|
||||
optstr=xmalloc(strlen(argv[optind])+1);
|
||||
strcpy(optstr,argv[optind]);
|
||||
optind++;
|
||||
}
|
||||
}
|
||||
if (name)
|
||||
argv[optind-1]=name;
|
||||
else
|
||||
argv[optind-1]=argv[0];
|
||||
exit(generate_output(argv+optind-1,argc-optind+1,optstr,long_options));
|
||||
}
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
c-file-style: "linux"
|
||||
c-basic-offset: 4
|
||||
tab-width: 4
|
||||
End:
|
||||
*/
|
Loading…
Reference in New Issue
Block a user