Added getopt(1) from "Alfred M. Szmidt" <ams@trillian.itslinux.org>
 -Erik
diff --git a/getopt.c b/getopt.c
new file mode 100644
index 0000000..fb75790
--- /dev/null
+++ b/getopt.c
@@ -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:
+*/