]> Zhao Yanbai Git Server - minix.git/commitdiff
Add getopt_long library function
authorErik van der Kouwe <erik@minix3.org>
Mon, 25 Jan 2010 18:11:21 +0000 (18:11 +0000)
committerErik van der Kouwe <erik@minix3.org>
Mon, 25 Jan 2010 18:11:21 +0000 (18:11 +0000)
include/err.h [new file with mode: 0644]
include/getopt.h [new file with mode: 0644]
lib/other/Makefile.in
lib/other/getopt_long.c [new file with mode: 0644]
lib/other/vwarnx.c [new file with mode: 0644]
lib/other/warnx.c [new file with mode: 0644]
man/man3/getopt_long.3 [new file with mode: 0644]

diff --git a/include/err.h b/include/err.h
new file mode 100644 (file)
index 0000000..988f5e4
--- /dev/null
@@ -0,0 +1,77 @@
+/*     $NetBSD: err.h,v 1.14 2005/02/03 04:39:32 perry Exp $   */
+
+/*-
+ * Copyright (c) 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)err.h       8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _ERR_H_
+#define        _ERR_H_
+
+#ifdef __minix
+#define __BEGIN_DECLS
+#define __dead
+#define __END_DECLS
+#define __attribute__(x) 
+#define _BSD_VA_LIST_ va_list
+#include <stdarg.h>
+#else
+/*
+ * Don't use va_list in the err/warn prototypes.   Va_list is typedef'd in two
+ * places (<machine/varargs.h> and <machine/stdarg.h>), so if we include one
+ * of them here we may collide with the utility's includes.  It's unreasonable
+ * for utilities to have to include one of them to include err.h, so we get
+ * _BSD_VA_LIST_ from <machine/ansi.h> and use it.
+ */
+#include <machine/ansi.h>
+#include <sys/cdefs.h>
+#endif
+
+__BEGIN_DECLS
+#ifndef __minix
+__dead void    err(int, const char *, ...)
+                   __attribute__((__noreturn__, __format__(__printf__, 2, 3)));
+__dead void    verr(int, const char *, _BSD_VA_LIST_)
+                   __attribute__((__noreturn__, __format__(__printf__, 2, 0)));
+__dead void    errx(int, const char *, ...)
+                   __attribute__((__noreturn__, __format__(__printf__, 2, 3)));
+__dead void    verrx(int, const char *, _BSD_VA_LIST_)
+                   __attribute__((__noreturn__, __format__(__printf__, 2, 0)));
+void           warn(const char *, ...)
+                   __attribute__((__format__(__printf__, 1, 2)));
+void           vwarn(const char *, _BSD_VA_LIST_)
+                   __attribute__((__format__(__printf__, 1, 0)));
+#endif
+void           warnx(const char *, ...)
+                   __attribute__((__format__(__printf__, 1, 2)));
+void           vwarnx(const char *, _BSD_VA_LIST_)
+                   __attribute__((__format__(__printf__, 1, 0)));
+__END_DECLS
+
+#endif /* !_ERR_H_ */
diff --git a/include/getopt.h b/include/getopt.h
new file mode 100644 (file)
index 0000000..1115548
--- /dev/null
@@ -0,0 +1,69 @@
+/*     $NetBSD: getopt.h,v 1.11 2008/04/28 20:22:54 martin Exp $       */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _GETOPT_H_
+#define _GETOPT_H_
+
+#ifdef __minix
+#define __BEGIN_DECLS
+#define __END_DECLS
+#else
+#include <sys/cdefs.h>
+#endif
+#include <unistd.h>
+
+/*
+ * Gnu like getopt_long() and BSD4.4 getsubopt()/optreset extensions
+ */
+#define no_argument        0
+#define required_argument  1
+#define optional_argument  2
+
+struct option {
+       /* name of long option */
+       const char *name;
+       /*
+        * one of no_argument, required_argument, and optional_argument:
+        * whether option takes an argument
+        */
+       int has_arg;
+       /* if not NULL, set *flag to val when option found */
+       int *flag;
+       /* if flag not NULL, value to set *flag to; else return value */
+       int val;
+};
+
+__BEGIN_DECLS
+int getopt_long(int, char * const *, const char *,
+    const struct option *, int *);
+__END_DECLS
+#endif /* !_GETOPT_H_ */
index ccc64ba3b1a090ca71915bc0700eda8ae082ab0e..40f65a98d613008508c11d5a9a343c09b5ea4969 100644 (file)
@@ -42,6 +42,7 @@ libc_FILES=" \
        crypt.c \
        ctermid.c \
        cuserid.c \
+       dirname.c \
        environ.c \
        errno.c \
        fdopen.c \
@@ -52,6 +53,7 @@ libc_FILES=" \
        fsversion.c \
        getgrent.c \
        getlogin.c \
+       getopt_long.c \
        getpagesize.c \
        getpass.c \
        getpwent.c \
@@ -98,6 +100,8 @@ libc_FILES=" \
        v8regerror.c \
        v8regexp.c \
        v8regsub.c \
-       vectorio.c"
+       vectorio.c \
+       vwarnx.c \
+       warnx.c"
 
 TYPE=both
diff --git a/lib/other/getopt_long.c b/lib/other/getopt_long.c
new file mode 100644 (file)
index 0000000..4c12283
--- /dev/null
@@ -0,0 +1,503 @@
+/*     $NetBSD: getopt_long.c,v 1.24 2007/11/09 03:29:20 christos Exp $        */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef __minix
+#define __P(x) x
+#define _DIAGASSERT assert
+#define __UNCONST(x) ((void *) (x))
+#else
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: getopt_long.c,v 1.24 2007/11/09 03:29:20 christos Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+#endif
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#if HAVE_NBTOOL_CONFIG_H
+#include "compat_getopt.h"
+#else
+#include <getopt.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_NBTOOL_CONFIG_H && !HAVE_GETOPT_LONG && !HAVE_DECL_OPTIND
+#define REPLACE_GETOPT
+#endif
+
+#ifdef REPLACE_GETOPT
+#ifdef __weak_alias
+__weak_alias(getopt,_getopt)
+#endif
+int    opterr = 1;             /* if error message should be printed */
+int    optind = 1;             /* index into parent argv vector */
+int    optopt = '?';           /* character checked for validity */
+int    optreset;               /* reset getopt */
+char    *optarg;               /* argument associated with option */
+#elif HAVE_NBTOOL_CONFIG_H && !HAVE_DECL_OPTRESET
+static int optreset;
+#endif
+
+#ifdef __weak_alias
+__weak_alias(getopt_long,_getopt_long)
+#endif
+
+#define IGNORE_FIRST   (*options == '-' || *options == '+')
+#define PRINT_ERROR    ((opterr) && ((*options != ':') \
+                                     || (IGNORE_FIRST && options[1] != ':')))
+#define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)
+#define PERMUTE         (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
+/* XXX: GNU ignores PC if *options == '-' */
+#define IN_ORDER        (!IS_POSIXLY_CORRECT && *options == '-')
+
+/* return values */
+#define        BADCH   (int)'?'
+#define        BADARG          ((IGNORE_FIRST && options[1] == ':') \
+                        || (*options == ':') ? (int)':' : (int)'?')
+#define INORDER (int)1
+
+#define        EMSG    ""
+
+static int getopt_internal __P((int, char **, const char *));
+static int gcd __P((int, int));
+static void permute_args __P((int, int, int, char **));
+
+static const char *place = EMSG; /* option letter processing */
+
+/* XXX: set optreset to 1 rather than these two */
+static int nonopt_start = -1; /* first non option argument (for permute) */
+static int nonopt_end = -1;   /* first option after non options (for permute) */
+
+/* Error messages */
+static const char recargchar[] = "option requires an argument -- %c";
+static const char recargstring[] = "option requires an argument -- %s";
+static const char ambig[] = "ambiguous option -- %.*s";
+static const char noarg[] = "option doesn't take an argument -- %.*s";
+static const char illoptchar[] = "unknown option -- %c";
+static const char illoptstring[] = "unknown option -- %s";
+
+
+/*
+ * Compute the greatest common divisor of a and b.
+ */
+static int
+gcd(a, b)
+       int a;
+       int b;
+{
+       int c;
+
+       c = a % b;
+       while (c != 0) {
+               a = b;
+               b = c;
+               c = a % b;
+       }
+          
+       return b;
+}
+
+/*
+ * Exchange the block from nonopt_start to nonopt_end with the block
+ * from nonopt_end to opt_end (keeping the same order of arguments
+ * in each block).
+ */
+static void
+permute_args(panonopt_start, panonopt_end, opt_end, nargv)
+       int panonopt_start;
+       int panonopt_end;
+       int opt_end;
+       char **nargv;
+{
+       int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
+       char *swap;
+
+       _DIAGASSERT(nargv != NULL);
+
+       /*
+        * compute lengths of blocks and number and size of cycles
+        */
+       nnonopts = panonopt_end - panonopt_start;
+       nopts = opt_end - panonopt_end;
+       ncycle = gcd(nnonopts, nopts);
+       cyclelen = (opt_end - panonopt_start) / ncycle;
+
+       for (i = 0; i < ncycle; i++) {
+               cstart = panonopt_end+i;
+               pos = cstart;
+               for (j = 0; j < cyclelen; j++) {
+                       if (pos >= panonopt_end)
+                               pos -= nnonopts;
+                       else
+                               pos += nopts;
+                       swap = nargv[pos];
+                       nargv[pos] = nargv[cstart];
+                       nargv[cstart] = swap;
+               }
+       }
+}
+
+/*
+ * getopt_internal --
+ *     Parse argc/argv argument vector.  Called by user level routines.
+ *  Returns -2 if -- is found (can be long option or end of options marker).
+ */
+static int
+getopt_internal(nargc, nargv, options)
+       int nargc;
+       char **nargv;
+       const char *options;
+{
+       char *oli;                              /* option letter list index */
+       int optchar;
+
+       _DIAGASSERT(nargv != NULL);
+       _DIAGASSERT(options != NULL);
+
+       optarg = NULL;
+
+       /*
+        * XXX Some programs (like rsyncd) expect to be able to
+        * XXX re-initialize optind to 0 and have getopt_long(3)
+        * XXX properly function again.  Work around this braindamage.
+        */
+       if (optind == 0)
+               optind = 1;
+
+       if (optreset)
+               nonopt_start = nonopt_end = -1;
+start:
+       if (optreset || !*place) {              /* update scanning pointer */
+               optreset = 0;
+               if (optind >= nargc) {          /* end of argument vector */
+                       place = EMSG;
+                       if (nonopt_end != -1) {
+                               /* do permutation, if we have to */
+                               permute_args(nonopt_start, nonopt_end,
+                                   optind, nargv);
+                               optind -= nonopt_end - nonopt_start;
+                       }
+                       else if (nonopt_start != -1) {
+                               /*
+                                * If we skipped non-options, set optind
+                                * to the first of them.
+                                */
+                               optind = nonopt_start;
+                       }
+                       nonopt_start = nonopt_end = -1;
+                       return -1;
+               }
+               if ((*(place = nargv[optind]) != '-')
+                   || (place[1] == '\0')) {    /* found non-option */
+                       place = EMSG;
+                       if (IN_ORDER) {
+                               /*
+                                * GNU extension: 
+                                * return non-option as argument to option 1
+                                */
+                               optarg = nargv[optind++];
+                               return INORDER;
+                       }
+                       if (!PERMUTE) {
+                               /*
+                                * if no permutation wanted, stop parsing
+                                * at first non-option
+                                */
+                               return -1;
+                       }
+                       /* do permutation */
+                       if (nonopt_start == -1)
+                               nonopt_start = optind;
+                       else if (nonopt_end != -1) {
+                               permute_args(nonopt_start, nonopt_end,
+                                   optind, nargv);
+                               nonopt_start = optind -
+                                   (nonopt_end - nonopt_start);
+                               nonopt_end = -1;
+                       }
+                       optind++;
+                       /* process next argument */
+                       goto start;
+               }
+               if (nonopt_start != -1 && nonopt_end == -1)
+                       nonopt_end = optind;
+               if (place[1] && *++place == '-') {      /* found "--" */
+                       place++;
+                       return -2;
+               }
+       }
+       if ((optchar = (int)*place++) == (int)':' ||
+           (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
+               /* option letter unknown or ':' */
+               if (!*place)
+                       ++optind;
+               if (PRINT_ERROR)
+                       warnx(illoptchar, optchar);
+               optopt = optchar;
+               return BADCH;
+       }
+       if (optchar == 'W' && oli[1] == ';') {          /* -W long-option */
+               /* XXX: what if no long options provided (called by getopt)? */
+               if (*place) 
+                       return -2;
+
+               if (++optind >= nargc) {        /* no arg */
+                       place = EMSG;
+                       if (PRINT_ERROR)
+                               warnx(recargchar, optchar);
+                       optopt = optchar;
+                       return BADARG;
+               } else                          /* white space */
+                       place = nargv[optind];
+               /*
+                * Handle -W arg the same as --arg (which causes getopt to
+                * stop parsing).
+                */
+               return -2;
+       }
+       if (*++oli != ':') {                    /* doesn't take argument */
+               if (!*place)
+                       ++optind;
+       } else {                                /* takes (optional) argument */
+               optarg = NULL;
+               if (*place)                     /* no white space */
+                       optarg = __UNCONST(place);
+               /* XXX: disable test for :: if PC? (GNU doesn't) */
+               else if (oli[1] != ':') {       /* arg not optional */
+                       if (++optind >= nargc) {        /* no arg */
+                               place = EMSG;
+                               if (PRINT_ERROR)
+                                       warnx(recargchar, optchar);
+                               optopt = optchar;
+                               return BADARG;
+                       } else
+                               optarg = nargv[optind];
+               }
+               place = EMSG;
+               ++optind;
+       }
+       /* dump back option letter */
+       return optchar;
+}
+
+#ifdef REPLACE_GETOPT
+/*
+ * getopt --
+ *     Parse argc/argv argument vector.
+ *
+ * [eventually this will replace the real getopt]
+ */
+int
+getopt(nargc, nargv, options)
+       int nargc;
+       char * const *nargv;
+       const char *options;
+{
+       int retval;
+
+       _DIAGASSERT(nargv != NULL);
+       _DIAGASSERT(options != NULL);
+
+       retval = getopt_internal(nargc, __UNCONST(nargv), options);
+       if (retval == -2) {
+               ++optind;
+               /*
+                * We found an option (--), so if we skipped non-options,
+                * we have to permute.
+                */
+               if (nonopt_end != -1) {
+                       permute_args(nonopt_start, nonopt_end, optind,
+                                      nargv);
+                       optind -= nonopt_end - nonopt_start;
+               }
+               nonopt_start = nonopt_end = -1;
+               retval = -1;
+       }
+       return retval;
+}
+#endif
+
+/*
+ * getopt_long --
+ *     Parse argc/argv argument vector.
+ */
+int
+getopt_long(nargc, nargv, options, long_options, idx)
+       int nargc;
+       char * const *nargv;
+       const char *options;
+       const struct option *long_options;
+       int *idx;
+{
+       int retval;
+
+#define IDENTICAL_INTERPRETATION(_x, _y)                               \
+       (long_options[(_x)].has_arg == long_options[(_y)].has_arg &&    \
+        long_options[(_x)].flag == long_options[(_y)].flag &&          \
+        long_options[(_x)].val == long_options[(_y)].val)
+
+       _DIAGASSERT(nargv != NULL);
+       _DIAGASSERT(options != NULL);
+       _DIAGASSERT(long_options != NULL);
+       /* idx may be NULL */
+
+       retval = getopt_internal(nargc, __UNCONST(nargv), options);
+       if (retval == -2) {
+               char *current_argv, *has_equal;
+               size_t current_argv_len;
+               int i, ambiguous, match;
+
+               current_argv = __UNCONST(place);
+               match = -1;
+               ambiguous = 0;
+
+               optind++;
+               place = EMSG;
+
+               if (*current_argv == '\0') {            /* found "--" */
+                       /*
+                        * We found an option (--), so if we skipped
+                        * non-options, we have to permute.
+                        */
+                       if (nonopt_end != -1) {
+                               permute_args(nonopt_start, nonopt_end,
+                                   optind, __UNCONST(nargv));
+                               optind -= nonopt_end - nonopt_start;
+                       }
+                       nonopt_start = nonopt_end = -1;
+                       return -1;
+               }
+               if ((has_equal = strchr(current_argv, '=')) != NULL) {
+                       /* argument found (--option=arg) */
+                       current_argv_len = has_equal - current_argv;
+                       has_equal++;
+               } else
+                       current_argv_len = strlen(current_argv);
+           
+               for (i = 0; long_options[i].name; i++) {
+                       /* find matching long option */
+                       if (strncmp(current_argv, long_options[i].name,
+                           current_argv_len))
+                               continue;
+
+                       if (strlen(long_options[i].name) ==
+                           (unsigned)current_argv_len) {
+                               /* exact match */
+                               match = i;
+                               ambiguous = 0;
+                               break;
+                       }
+                       if (match == -1)                /* partial match */
+                               match = i;
+                       else if (!IDENTICAL_INTERPRETATION(i, match))
+                               ambiguous = 1;
+               }
+               if (ambiguous) {
+                       /* ambiguous abbreviation */
+                       if (PRINT_ERROR)
+                               warnx(ambig, (int)current_argv_len,
+                                    current_argv);
+                       optopt = 0;
+                       return BADCH;
+               }
+               if (match != -1) {                      /* option found */
+                       if (long_options[match].has_arg == no_argument
+                           && has_equal) {
+                               if (PRINT_ERROR)
+                                       warnx(noarg, (int)current_argv_len,
+                                            current_argv);
+                               /*
+                                * XXX: GNU sets optopt to val regardless of
+                                * flag
+                                */
+                               if (long_options[match].flag == NULL)
+                                       optopt = long_options[match].val;
+                               else
+                                       optopt = 0;
+                               return BADARG;
+                       }
+                       if (long_options[match].has_arg == required_argument ||
+                           long_options[match].has_arg == optional_argument) {
+                               if (has_equal)
+                                       optarg = has_equal;
+                               else if (long_options[match].has_arg ==
+                                   required_argument) {
+                                       /*
+                                        * optional argument doesn't use
+                                        * next nargv
+                                        */
+                                       optarg = nargv[optind++];
+                               }
+                       }
+                       if ((long_options[match].has_arg == required_argument)
+                           && (optarg == NULL)) {
+                               /*
+                                * Missing argument; leading ':'
+                                * indicates no error should be generated
+                                */
+                               if (PRINT_ERROR)
+                                       warnx(recargstring, current_argv);
+                               /*
+                                * XXX: GNU sets optopt to val regardless
+                                * of flag
+                                */
+                               if (long_options[match].flag == NULL)
+                                       optopt = long_options[match].val;
+                               else
+                                       optopt = 0;
+                               --optind;
+                               return BADARG;
+                       }
+               } else {                        /* unknown option */
+                       if (PRINT_ERROR)
+                               warnx(illoptstring, current_argv);
+                       optopt = 0;
+                       return BADCH;
+               }
+               if (long_options[match].flag) {
+                       *long_options[match].flag = long_options[match].val;
+                       retval = 0;
+               } else 
+                       retval = long_options[match].val;
+               if (idx)
+                       *idx = match;
+       }
+       return retval;
+#undef IDENTICAL_INTERPRETATION
+}
diff --git a/lib/other/vwarnx.c b/lib/other/vwarnx.c
new file mode 100644 (file)
index 0000000..63a6cc3
--- /dev/null
@@ -0,0 +1,68 @@
+/*     $NetBSD: vwarnx.c,v 1.14 2007/06/18 14:13:54 ginsbach Exp $     */
+
+/*-
+ * Copyright (c) 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __minix
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)err.c      8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: vwarnx.c,v 1.14 2007/06/18 14:13:54 ginsbach Exp $");
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+#endif
+#include <err.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef __weak_alias
+__weak_alias(vwarnx, _vwarnx)
+#endif
+
+#if !HAVE_ERR_H
+void
+vwarnx(const char *fmt, _BSD_VA_LIST_ ap)
+{
+#ifndef __minix
+       (void)fprintf(stderr, "%s: ", getprogname());
+#endif
+       if (fmt != NULL)
+               (void)vfprintf(stderr, fmt, ap);
+       (void)fprintf(stderr, "\n");
+}
+#endif
diff --git a/lib/other/warnx.c b/lib/other/warnx.c
new file mode 100644 (file)
index 0000000..d0f0d7b
--- /dev/null
@@ -0,0 +1,65 @@
+/*     $NetBSD: warnx.c,v 1.14 2007/06/18 14:13:54 ginsbach Exp $      */
+
+/*-
+ * Copyright (c) 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __minix
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)err.c      8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: warnx.c,v 1.14 2007/06/18 14:13:54 ginsbach Exp $");
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+#endif
+#include <err.h>
+#include <stdarg.h>
+
+#ifdef __weak_alias
+__weak_alias(warnx, _warnx)
+#endif
+
+#if !HAVE_ERR_H
+void
+warnx(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       vwarnx(fmt, ap);
+       va_end(ap);
+}
+#endif
diff --git a/man/man3/getopt_long.3 b/man/man3/getopt_long.3
new file mode 100644 (file)
index 0000000..6d03631
--- /dev/null
@@ -0,0 +1,310 @@
+.\"    $NetBSD: getopt_long.3,v 1.18 2007/07/02 17:56:17 ginsbach Exp $
+.\"
+.\" Copyright (c) 1988, 1991, 1993
+.\"    The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)getopt.3   8.5 (Berkeley) 4/27/95
+.\"
+.Dd July 2, 2007
+.Dt GETOPT_LONG 3
+.Os
+.Sh NAME
+.Nm getopt_long
+.Nd get long options from command line argument list
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In getopt.h
+.Ft int
+.Fn getopt_long "int argc" "char * const *argv" "const char *optstring" "struct option *long_options" "int *index"
+.Sh DESCRIPTION
+The
+.Fn getopt_long
+function is similar to
+.Xr getopt 3
+but it accepts options in two forms: words and characters.
+The
+.Fn getopt_long
+function provides a superset of the functionality of
+.Xr getopt 3 .
+.Fn getopt_long
+can be used in two ways.
+In the first way, every long option understood by the program has a
+corresponding short option, and the option structure is only used to
+translate from long options to short options.
+When used in this fashion,
+.Fn getopt_long
+behaves identically to
+.Xr getopt 3 .
+This is a good way to add long option processing to an existing program
+with the minimum of rewriting.
+.Pp
+In the second mechanism, a long option sets a flag in the
+.Fa option
+structure passed, or will store a pointer to the command line argument
+in the
+.Fa option
+structure passed to it for options that take arguments.
+Additionally, the long option's argument may be specified as a single
+argument with an equal sign, e.g.
+.Bd -literal
+myprogram --myoption=somevalue
+.Ed
+.Pp
+When a long option is processed the call to
+.Fn getopt_long
+will return 0.
+For this reason, long option processing without
+shortcuts is not backwards compatible with
+.Xr getopt 3 .
+.Pp
+It is possible to combine these methods, providing for long options
+processing with short option equivalents for some options.
+Less frequently used options would be processed as long options only.
+.Pp
+Abbreviated long option names are accepted when
+.Fn getopt_long
+processes long options if the abbreviation is unique.
+An exact match is always preferred for a defined long option.
+.Pp
+The
+.Fn getopt_long
+call requires a structure to be initialized describing the long options.
+The structure is:
+.Bd -literal
+struct option {
+       char *name;
+       int has_arg;
+       int *flag;
+       int val;
+};
+.Ed
+.Pp
+The
+.Fa name
+field should contain the option name without the leading double dash.
+.Pp
+The
+.Fa has_arg
+field should be one of:
+.Bl -tag -width "optional_argument"
+.It Li no_argument
+no argument to the option is expect.
+.It Li required_argument
+an argument to the option is required.
+.It Li optional_argument
+an argument to the option may be presented.
+.El
+.Pp
+If
+.Fa flag
+is not
+.Dv NULL ,
+then the integer pointed to by it will be set to the value in the
+.Fa val
+field.
+If the
+.Fa flag
+field is
+.Dv NULL ,
+then the
+.Fa val
+field will be returned.
+Setting
+.Fa flag
+to
+.Dv NULL
+and setting
+.Fa val
+to the corresponding short option will make this function act just
+like
+.Xr getopt 3 .
+.Pp
+If the
+.Fa index
+field is not
+.Dv NULL ,
+the integer it points to will be set to the index of the long option
+in the
+.Fa long_options
+array.
+.Pp
+The last element of the
+.Fa long_options
+array has to be filled with zeroes (see
+.Sx EXAMPLES
+section).
+.Sh EXAMPLES
+.Bd -literal -compact
+extern char *optarg;
+extern int optind;
+int bflag, ch, fd;
+int daggerset;
+
+/* options descriptor */
+static struct option longopts[] = {
+       { "buffy",      no_argument,            0,              'b' },
+       { "fluoride",   required_argument,      0,              'f' },
+       { "daggerset",  no_argument,            \*[Am]daggerset,        1 },
+       { NULL,         0,                      NULL,           0 }
+};
+
+bflag = 0;
+while ((ch = getopt_long(argc, argv, "bf:", longopts, NULL)) != -1)
+       switch (ch) {
+       case 'b':
+               bflag = 1;
+               break;
+       case 'f':
+               if ((fd = open(optarg, O_RDONLY, 0)) \*[Lt] 0) {
+                       (void)fprintf(stderr,
+                           "myname: %s: %s\en", optarg, strerror(errno));
+                       exit(1);
+               }
+               break;
+       case 0:
+               if(daggerset) {
+                       fprintf(stderr,"Buffy will use her dagger to "
+                                      "apply fluoride to dracula's teeth\en");
+               }
+               break;
+       case '?':
+       default:
+               usage();
+}
+argc -= optind;
+argv += optind;
+.Ed
+.Sh IMPLEMENTATION DIFFERENCES
+This section describes differences to the GNU implementation
+found in glibc-2.1.3:
+.Bl -tag -width "xxx"
+.It Li o
+handling of - as first char of option string in presence of
+environment variable POSIXLY_CORRECT:
+.Bl -tag -width "NetBSD"
+.It Li GNU
+ignores POSIXLY_CORRECT and returns non-options as
+arguments to option '\e1'.
+.It Li NetBSD
+honors POSIXLY_CORRECT and stops at the first non-option.
+.El
+.It Li o
+handling of :: in options string in presence of POSIXLY_CORRECT:
+.Bl -tag -width "NetBSD"
+.It Li Both
+GNU and NetBSD ignore POSIXLY_CORRECT here and take :: to
+mean the preceding option takes an optional argument.
+.El
+.It Li o
+return value in case of missing argument if first character
+(after + or -) in option string is not ':':
+.Bl -tag -width "NetBSD"
+.It Li GNU
+returns '?'
+.It NetBSD
+returns ':' (since NetBSD's getopt does).
+.El
+.It Li o
+handling of --a in getopt:
+.Bl -tag -width "NetBSD"
+.It Li GNU
+parses this as option '-', option 'a'.
+.It Li NetBSD
+parses this as '--', and returns \-1 (ignoring the a).
+(Because the original getopt does.)
+.El
+.It Li o
+setting of optopt for long options with flag !=
+.Dv NULL :
+.Bl -tag -width "NetBSD"
+.It Li GNU
+sets optopt to val.
+.It Li NetBSD
+sets optopt to 0 (since val would never be returned).
+.El
+.It Li o
+handling of -W with W; in option string in getopt (not getopt_long):
+.Bl -tag -width "NetBSD"
+.It Li GNU
+causes a segfault.
+.It Li NetBSD
+returns \-1, with optind pointing past the argument of -W
+(as if `-W arg' were `--arg', and thus '--' had been found).
+.\" How should we treat W; in the option string when called via
+.\" getopt?  Ignore the ';' or treat it as a ':'? Issue a warning?
+.El
+.It Li o
+setting of optarg for long options without an argument that are
+invoked via -W (W; in option string):
+.Bl -tag -width "NetBSD"
+.It Li GNU
+sets optarg to the option name (the argument of -W).
+.It Li NetBSD
+sets optarg to
+.Dv NULL
+(the argument of the long option).
+.El
+.It Li o
+handling of -W with an argument that is not (a prefix to) a known
+long option (W; in option string):
+.Bl -tag -width "NetBSD"
+.It Li GNU
+returns -W with optarg set to the unknown option.
+.It Li NetBSD
+treats this as an error (unknown option) and returns '?' with
+optopt set to 0 and optarg set to
+.Dv NULL
+(as GNU's man page documents).
+.El
+.It Li o
+The error messages are different.
+.It Li o
+NetBSD does not permute the argument vector at the same points in
+the calling sequence as GNU does.
+The aspects normally used by the caller
+(ordering after \-1 is returned, value of optind relative
+to current positions) are the same, though.
+(We do fewer variable swaps.)
+.El
+.Sh SEE ALSO
+.Xr getopt 3
+.Sh HISTORY
+The
+.Fn getopt_long
+function first appeared in GNU libiberty.
+The first
+.Nx
+implementation appeared in 1.5.
+.Sh BUGS
+The implementation can completely replace
+.Xr getopt 3 ,
+but right now we are using separate code.
+.Pp
+The
+.Fa argv
+argument is not really const.