add getopt_long
authorgit <redacted>
Sat, 18 Apr 2026 15:30:02 +0000 (11:30 -0400)
committergit <redacted>
Sat, 18 Apr 2026 15:30:02 +0000 (11:30 -0400)
README.md
asprintf.h
getopt_long.h [new file with mode: 0644]

index 59cf6d6de00bd3017b5006185debb460e5ec1628..46ea40c2336230ebc9219165f636fda5a8a6470e 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,24 +1,24 @@
-A (WIP) collection of portable, strict C99, single-header implementations of common libc extensions.
+A (WIP) collection of portable, (mostly) strict C99, single-header implementations of common libc extensions.
 
 ### How to
 
 Include the header in every file needed as usual:
 
 ```
-#include "<ext-func-name.h>"
+#include "<ext-func-name>.h"
 ```
 
 In the file chosen for the function implementation:
 
 ```
-#define <EXT-FUNC-NAME>_IMPLEMENTATION_
+#define <EXT-FUNC-NAME>_IMPLEMENTATION
 #include "<ext-func-name.h>"
 ```
 
-By default, the header won't have any includes, change that with:
+By default, the header won't have any stdlib includes, change that with:
 
 ```
-#define <EXT-FUNC-NAME>_INCLUDE_LIBC_
+#define <EXT-FUNC-NAME>_INCLUDE_LIBC
 ```
 
 Or disable function override with:
@@ -26,3 +26,16 @@ Or disable function override with:
 ```
 #define HAVE_<EXT-FUNC-NAME>
 ```
+
+## Specifics
+
+### getopt\_long
+
+`getopt_long.h` has additional macros related to argument
+permuting, defining those enables it (GNU behaviour):
+
+```
+#define GETOPT_PERMUTE_ARGS
+#define GETOPT_LONG_PERMUTE_ARGS
+#define GETOPT_LONG_ONLY_PERMUTE_ARGS
+```
index dc944df384cceed12d21c5aed606a7c0c07bf6d5..a22a6fbbade4ec97be6a3212f14f0bf605bc8983 100644 (file)
@@ -1,22 +1,56 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <https://unlicense.org>
+ */
+
 /* https://git.datadissipation.net */
 #ifndef ASPRINTF_H_
  #define ASPRINTF_H_ 1
 
- #ifdef ASPRINTF_INCLUDE_LIBC_
+ #ifdef ASPRINTF_INCLUDE_LIBC
   #include <stdarg.h>
   #include <stdio.h>
   #include <stdlib.h>
  #endif
 
  #ifndef HAVE_ASPRINTF
-  int vasprintf_(char **strp, const char *fmt, va_list ap);
-  int asprintf_(char **strp, const char *fmt, ...);
+  #define HAVE_ASPRINTF 1
+  int i_vasprintf_(char **restrict strp, const char *restrict fmt, va_list ap);
+  int i_asprintf_(char **restrict strp, const char *restrict fmt, ...);
   /* 
    * Credit for a big part of the macro madness:
    * Jens Gustedt
    * https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
    */
-  #define vasprintf(s, f, a)   vasprintf_(s, f, a)
+
+  /*
+   * This isn't strict C99, because C99 requires at least one argument in "..."
+   * for macros. Still, I haven't encountered a compiler that won't preprocess 
+   * this right (out of the popular ones, MSVC wasn't tested)
+   */
+  #define vasprintf(s, f, a)   i_vasprintf_(s, f, a)
   #define I_COND_COMMA_(...) ,
   #define I_PICK_ARG_(_1, _2, ARG, ...) ARG
   #define I_HAS_COMMA_(...) I_PICK_ARG_(__VA_ARGS__, 1, 0)
 
   #define I_GET_ARG_(...) I_PICK_ARG_(__VA_ARGS__)
   #define asprintf(s, f, ...)\
-  asprintf_(s, f I_PASTE_(I_ISEMPTY_(I_GET_ARG_(, , __VA_ARGS__))) __VA_ARGS__)
+  i_asprintf_(s, f I_PASTE_(I_ISEMPTY_(I_GET_ARG_(, , __VA_ARGS__))) __VA_ARGS__)
   #define I_EMPTY_1
   #define I_EMPTY_0 I_COND_COMMA_()
- #endif
+ #endif /* !HAVE_ASPRINTF */
 
- #ifdef ASPRINTF_IMPLEMENTATION_
+ #ifdef ASPRINTF_IMPLEMENTATION
  int
vasprintf_(char **strp, const char *fmt, va_list ap)
i_vasprintf_(char **restrict strp, const char *restrict fmt, va_list ap)
  {
         int size, ret;
         va_list tp;
  }
 
  int
asprintf_(char **strp, const char *fmt, ...)
i_asprintf_(char **restrict strp, const char *restrict fmt, ...)
  {
         int ret;
         va_list ap;
 
         va_start(ap, fmt);
-        ret = vasprintf(strp, fmt, ap);
+        ret = i_vasprintf_(strp, fmt, ap);
         va_end(ap);
 
         return ret;
  }
- #endif
-#endif
+ #endif /* ASPRINTF_IMPLEMENTATION */
+#endif /* !ASPRINTF_H_ */
diff --git a/getopt_long.h b/getopt_long.h
new file mode 100644 (file)
index 0000000..f26dd57
--- /dev/null
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+/*
+ * 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.
+ */
+
+/* https://git.datadissipation.net */
+#ifndef GETOPT_LONG_H_
+ #define GETOPT_LONG_H_ 1
+
+ #ifdef GETOPT_LONG_INCLUDE_LIBC
+  #include <stdlib.h>
+  #include <string.h>
+  #include <stdarg.h>
+ #endif
+
+ #ifndef HAVE_GETOPT_LONG
+  #define HAVE_GETOPT_LONG 1
+  /* 
+   * structs are in their own namespace, so this should be OK
+   * the worst it can do is make compiler messages worse
+   */
+  #define option i_option_
+
+  struct i_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;
+  };
+
+  int  i_getopt_(int argc, char *argv[], const char *optstring);
+  int  i_getsubopt_(char *restrict optionp[], const char *restrict tokens[],
+                     char *restrict valuep[]);
+  int  i_getopt_long_(int argc, char *argv[], const char *optstring,
+                      const struct option *longopts, int *longindex);
+  int  i_getopt_long_only_(int argc, char *argv[], const char *optstring,
+                           const struct option *longopts, int *longindex);
+
+  #define no_argument        0
+  #define required_argument  1
+  #define optional_argument  2
+
+  #define getopt(c,v,o)               i_getopt_(c,v,o)
+  #define getsubopt(o,t,v)            i_getsubopt_(o,t,v)
+  #define getopt_long(c,v,o,l,i)      i_getopt_long_(c,v,o,l,i)
+  #define getopt_long_only(c,v,o,l,i) i_getopt_long_only_(c,v,o,l,i)
+
+ #endif /* !HAVE_GETOPT_LONG */
+ #ifdef GETOPT_LONG_IMPLEMENTATION
+  #define I_PRINT_ERROR_       ((i_opterr_) && (*options != ':'))
+
+  #define I_FLAG_PERMUTE_      0x01    /* permute non-options to the end of argv */
+  #define I_FLAG_ALLARGS_      0x02    /* treat non-options as args to option "-1" */
+  #define I_FLAG_LONGONLY_     0x04    /* operate as i_getopt_long_only */
+
+  /* return values */
+  #define      I_BADCH_                (int)'?'
+  #define      I_BADARG_               ((*options == ':') ? (int)':' : (int)'?')
+  #define      I_INORDER_              (int)1
+
+  #define      I_EMSG_                 ""
+
+  static void i_warnx_(const char *, ...);
+  static int i_getopt_internal_(int, char **, const char *,
+                            const struct option *, int *, int);
+  static int i_parse_long_options__(char * const *, const char *,
+                              const struct option *, int *, int);
+  static int i_gcd_(int, int);
+  static void i_permute_args_(int, int, int, char * const *);
+
+
+  /* XXX: set i_optreeset_ to 1 rather than these two */
+  static int   i_nonopt_start_ = -1;   /* first non option argument (for permute) */
+  static int   i_nonopt_end_ = -1;     /* first option after non options (for permute) */
+  static int   i_opterr_ = 1;          /* if error message should be printed */
+  static int   i_optind_ = 1;          /* index into parent argv vector */
+  static int   i_optopt_ = '?';        /* character checked for validity */
+  static int   i_optreeset_;           /* reset getopt */
+  static char   *i_optarg_;            /* argument associated with option */
+  static char   *i_place_ = I_EMSG_;    /* option letter processing */
+  
+  /* Error messages */
+  static const char i_recargchar_[] = "option requires an argument -- %c";
+  static const char i_recargstring_[] = "option requires an argument -- %s";
+  static const char i_ambig_[] = "i_ambig_uous option -- %.*s";
+  static const char i_noarg_[] = "option doesn't take an argument -- %.*s";
+  static const char i_illoptchar_[] = "unknown option -- %c";
+  static const char i_illoptstring_[] = "unknown option -- %s";
+
+  /*
+   * Own warnx() for portability
+   */
+  void
+  i_warnx_(const char *fmt, ...)
+  {
+         va_list args;
+
+         #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+          #define I_GET_PROG_NAME_() getprogname()
+         #elif defined(__linux__)
+          #include <errno.h>
+          #define I_GET_PROG_NAME_() program_invocation_short_name
+         #else
+          #define I_GET_PROG_NAME_() "warnx"
+         #endif
+
+         va_start(args, fmt);
+         fprintf(stderr, "%s: ", I_GET_PROG_NAME_());
+         vfprintf(stderr, fmt, args);
+         fputc('\n', stderr);
+         va_end(args);
+  }
+
+  /*
+   * Compute the greatest common divisor of a and b.
+   */
+  static int
+  i_gcd_(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 i_nonopt_start_ to i_nonopt_end_ with the block
+   * from i_nonopt_end_ to opt_end (keeping the same order of arguments
+   * in each block).
+   */
+  static void
+  i_permute_args_(int pai_nonopt_start_, int pai_nonopt_end_, int opt_end,
+                  char * const *nargv)
+  {
+         int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
+         char *swap;
+
+         /*
+          * compute lengths of blocks and number and size of cycles
+          */
+         nnonopts = pai_nonopt_end_ - pai_nonopt_start_;
+         nopts = opt_end - pai_nonopt_end_;
+         ncycle = i_gcd_(nnonopts, nopts);
+         cyclelen = (opt_end - pai_nonopt_start_) / ncycle;
+
+         for (i = 0; i < ncycle; i++) {
+               cstart = pai_nonopt_end_+i;
+               pos = cstart;
+               for (j = 0; j < cyclelen; j++) {
+                     if (pos >= pai_nonopt_end_)
+                         pos -= nnonopts;
+                     else
+                         pos += nopts;
+                     swap = nargv[pos];
+                     /* LINTED const cast */
+                     ((char **) nargv)[pos] = nargv[cstart];
+                     /* LINTED const cast */
+                     ((char **)nargv)[cstart] = swap;
+                     }
+         }
+  }
+
+  /*
+   * i_parse_long_options__ --
+   *   Parse long options in argc/argv argument vector.
+   * Returns -1 if short_too is set and the option does not match long_options.
+   */
+  static int
+  i_parse_long_options__(char * const *nargv, const char *options,
+         const struct option *long_options, int *idx, int short_too)
+  {
+         char *current_argv, *has_equal;
+         size_t current_argv_len;
+         int i, match;
+
+         current_argv = i_place_;
+         match = -1;
+
+         i_optind_++;
+
+         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) == current_argv_len) {
+                     /* exact match */
+                     match = i;
+                     break;
+                 }
+                 /*
+                  * If this is a known short option, don't allow
+                  * a partial match of a single character.
+                  */
+                 if (short_too && current_argv_len == 1)
+                     continue;
+
+                 if (match == -1) {    /* partial match */
+                     match = i;
+                 } else {
+                     /* i_ambig_uous abbreviation */
+                     if (I_PRINT_ERROR_)
+                         i_warnx_(i_ambig_, (int)current_argv_len,
+                                    current_argv);
+                     i_optopt_ = 0;
+                     return (I_BADCH_);
+                 }
+         }
+         if (match != -1) {            /* option found */
+                 if (long_options[match].has_arg == no_argument
+                      && has_equal) {
+                     if (I_PRINT_ERROR_)
+                         i_warnx_(i_noarg_, (int)current_argv_len,
+                                  current_argv);
+                     /*
+                      * XXX: GNU sets i_optopt_ to val regardless of flag
+                      */
+                     if (long_options[match].flag == NULL)
+                         i_optopt_ = long_options[match].val;
+                     else
+                         i_optopt_ = 0;
+                     return (I_BADARG_);
+                 }
+                 if (long_options[match].has_arg == required_argument ||
+                     long_options[match].has_arg == optional_argument) {
+                     if (has_equal)
+                         i_optarg_ = has_equal;
+                     else if (long_options[match].has_arg ==
+                              required_argument) {
+                               /*
+                                * optional argument doesn't use next nargv
+                                */
+                         i_optarg_ = nargv[i_optind_++];
+                     }
+                 }
+                 if ((long_options[match].has_arg == required_argument)
+                      && (i_optarg_ == NULL)) {
+                       /*
+                        * Missing argument; leading ':' indicates no error
+                        * should be generated.
+                        */
+                       if (I_PRINT_ERROR_)
+                               i_warnx_(i_recargstring_,
+                                   current_argv);
+                       /*
+                        * XXX: GNU sets i_optopt_ to val regardless of flag
+                        */
+                       if (long_options[match].flag == NULL)
+                               i_optopt_ = long_options[match].val;
+                       else
+                               i_optopt_ = 0;
+                       --i_optind_;
+                       return (I_BADARG_);
+                 }
+         } else {                      /* unknown option */
+                 if (short_too) {
+                     --i_optind_;
+                     return (-1);
+                 }
+                 if (I_PRINT_ERROR_)
+                     i_warnx_(i_illoptstring_, current_argv);
+                 i_optopt_ = 0;
+                 return (I_BADCH_);
+         }
+         if (idx)
+                 *idx = match;
+         if (long_options[match].flag) {
+                 *long_options[match].flag = long_options[match].val;
+                 return (0);
+         } else
+                 return (long_options[match].val);
+  }
+
+  /*
+   * i_getopt_internal_ --
+   *   Parse argc/argv argument vector.  Called by user level routines.
+   */
+  static int
+  i_getopt_internal_(int nargc, char **nargv, const char *options,
+                const struct option *long_options, int *idx, int flags)
+  {
+         char *oli;                            /* option letter list index */
+         int optchar, short_too;
+         static int posix_me_harder = -1;
+
+         if (options == NULL)
+                 return (-1);
+
+         /*
+          * XXX Some GNU programs (like cvs) set optind to 0 instead of
+          * XXX using optreeset. Work around this braindamage.
+          */
+         if (i_optind_ == 0)
+                 i_optind_ = i_optreeset_ = 1;
+
+         /*
+          * Disable GNU extensions if POSIXLY_CORRECT is set or options
+          * string begins with a '+'.
+          */
+         if (posix_me_harder == -1 || i_optreeset_)
+                 posix_me_harder = (getenv("POSIXLY_CORRECT") != NULL);
+         if (*options == '-')
+                 flags |= I_FLAG_ALLARGS_;
+         else if (posix_me_harder || *options == '+')
+                 flags &= ~I_FLAG_PERMUTE_;
+         if (*options == '+' || *options == '-')
+                 options++;
+
+         i_optarg_ = NULL;
+         if (i_optreeset_)
+                 i_nonopt_start_ = i_nonopt_end_ = -1;
+         start:
+         if (i_optreeset_ || !*i_place_) {             /* update scanning pointer */
+                 i_optreeset_ = 0;
+                 if (i_optind_ >= nargc) {          /* end of argument vector */
+                     i_place_ = I_EMSG_;
+                     if (i_nonopt_end_ != -1) {
+                         /* do permutation, if we have to */
+                         i_permute_args_(i_nonopt_start_, i_nonopt_end_,
+                                         i_optind_, nargv);
+                         i_optind_ -= i_nonopt_end_ - i_nonopt_start_;
+                     } else if (i_nonopt_start_ != -1) {
+                         /*
+                          * If we skipped non-options, set i_optind_
+                          * to the first of them.
+                          */
+                         i_optind_ = i_nonopt_start_;
+                     }
+                     i_nonopt_start_ = i_nonopt_end_ = -1;
+                     return (-1);
+                 }
+                 if (*(i_place_ = nargv[i_optind_]) != '-' ||
+                    (i_place_[1] == '\0' && strchr(options, '-') == NULL)) {
+                     i_place_ = I_EMSG_;               /* found non-option */
+                     if (flags & I_FLAG_ALLARGS_) {
+                         /*
+                          * GNU extension:
+                          * return non-option as argument to option 1
+                          */
+                         i_optarg_ = nargv[i_optind_++];
+                         return (I_INORDER_);
+                     }
+                     if (!(flags & I_FLAG_PERMUTE_)) {
+                               /*
+                                * If no permutation wanted, stop parsing
+                                * at first non-option.
+                                */
+                               return (-1);
+                     }
+                     /* do permutation */
+                     if (i_nonopt_start_ == -1) {
+                         i_nonopt_start_ = i_optind_;
+                     } else if (i_nonopt_end_ != -1) {
+                         i_permute_args_(i_nonopt_start_, i_nonopt_end_,
+                                         i_optind_, nargv);
+                         i_nonopt_start_ = i_optind_ -
+                                       (i_nonopt_end_ - i_nonopt_start_);
+                         i_nonopt_end_ = -1;
+                     }
+                     i_optind_++;
+                     /* process next argument */
+                     goto start;
+                 }
+                 if (i_nonopt_start_ != -1 && i_nonopt_end_ == -1)
+                     i_nonopt_end_ = i_optind_;
+
+                 /*
+                  * If we have "-" do nothing, if "--" we are done.
+                  */
+                 if (i_place_[1] != '\0' && *++i_place_ == '-' && i_place_[1] == '\0') {
+                     i_optind_++;
+                     i_place_ = I_EMSG_;
+                     /*
+                      * We found an option (--), so if we skipped
+                      * non-options, we have to permute.
+                      */
+                 if (i_nonopt_end_ != -1) {
+                     i_permute_args_(i_nonopt_start_, i_nonopt_end_,
+                                     i_optind_, nargv);
+                     i_optind_ -= i_nonopt_end_ - i_nonopt_start_;
+                 }
+                     i_nonopt_start_ = i_nonopt_end_ = -1;
+                     return (-1);
+                 }
+         }
+
+         /*
+          * Check long options if:
+          *  1) we were passed some
+          *  2) the arg is not just "-"
+          *  3) either the arg starts with -- we are i_getopt_long_only()
+          */
+         if (long_options != NULL && i_place_ != nargv[i_optind_] &&
+            (*i_place_ == '-' || (flags & I_FLAG_LONGONLY_))) {
+                 short_too = 0;
+                 if (*i_place_ == '-')
+                     i_place_++;               /* --foo long option */
+                 else if (*i_place_ != ':' 
+                          && strchr(options, *i_place_) != NULL)
+                     short_too = 1;    /* could be short option too */
+
+                 optchar = i_parse_long_options__(nargv, options, long_options,
+                                                idx, short_too);
+                 if (optchar != -1) {
+                     i_place_ = I_EMSG_;
+                 return (optchar);
+             }
+         }
+
+         if ((optchar = (int)*i_place_++) == (int)':' ||
+           (optchar == (int)'-' && *i_place_ != '\0') ||
+           (oli = strchr(options, optchar)) == NULL) {
+                 /*
+                  * If the user specified "-" and  '-' isn't listed in
+                  * options, return -1 (non-option) as per POSIX.
+                  * Otherwise, it is an unknown option character (or ':').
+                  */
+                 if (optchar == (int)'-' && *i_place_ == '\0')
+                     return (-1);
+                 if (!*i_place_)
+                     ++i_optind_;
+                 if (I_PRINT_ERROR_)
+                     i_warnx_(i_illoptchar_, optchar);
+                 i_optopt_ = optchar;
+                 return (I_BADCH_);
+         }
+         if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
+                 /* -W long-option */
+                 if (*i_place_) {                      /* no space */
+                     /* NOTHING */;
+                 } else if (++i_optind_ >= nargc) {    /* no arg */
+                     i_place_ = I_EMSG_;
+                     if (I_PRINT_ERROR_)
+                         i_warnx_(i_recargchar_, optchar);
+                     i_optopt_ = optchar;
+                     return (I_BADARG_);
+                 } else {                              /* white space */
+                     i_place_ = nargv[i_optind_];
+                 }
+                 optchar = i_parse_long_options__(nargv, options, long_options,
+                                                  idx, 0);
+                 i_place_ = I_EMSG_;
+                 return (optchar);
+         }
+         if (*++oli != ':') {                  /* doesn't take argument */
+                 if (!*i_place_)
+                     ++i_optind_;
+         } else {                              /* takes (optional) argument */
+                 i_optarg_ = NULL;
+                 if (*i_place_)                /* no white space */
+                     i_optarg_ = i_place_;
+                 else if (oli[1] != ':') {     /* arg not optional */
+                     if (++i_optind_ >= nargc) {       /* no arg */
+                         i_place_ = I_EMSG_;
+                         if (I_PRINT_ERROR_)
+                             i_warnx_(i_recargchar_, optchar);
+                         i_optopt_ = optchar;
+                         return (I_BADARG_);
+                     } else {
+                         i_optarg_ = nargv[i_optind_];
+                     }
+                 }
+                 i_place_ = I_EMSG_;
+                 ++i_optind_;
+         }
+         /* dump back option letter */
+         return (optchar);
+  }
+
+  int
+  i_getopt_(int argc, char *argv[], const char *optstring)
+  {
+         #ifdef GETOPT_PERMUTE_ARGS
+          return (i_getopt_internal_(argc, argv, optstring, NULL, NULL,
+                  I_FLAG_PERMUTE_));
+         #else
+          return (i_getopt_internal_(argc, argv, optstring, NULL, NULL, 0));
+         #endif
+  }
+
+  int
+  i_getopt_long_(int argc, char *argv[], const char *optstring,
+            const struct option *longopts, int *longindex)
+  {  
+         #ifdef GETOPT_LONG_PERMUTE_ARGS
+          return (i_getopt_internal_(argc, argv, optstring, longopts, longindex,
+                  I_FLAG_PERMUTE_));
+         #else
+          return (i_getopt_internal_(argc, argv, optstring, longopts, longindex, 0));
+         #endif
+
+  }
+
+  int
+  i_getopt_long_only_(int argc, char *argv[], const char *optstring,
+                   const struct option *longopts, int *longindex)
+  {
+         #ifdef GETOPT_LONG_ONLY_PERMUTE_ARGS
+          return (i_getopt_internal_(argc, argv, optstring, longopts, longindex,
+                  I_FLAG_PERMUTE_ | I_FLAG_LONGONLY_));
+         #else
+          return (i_getopt_internal_(argc, argv, optstring, longopts, longindex,
+                  I_FLAG_LONGONLY_));
+         #endif
+  }
+ #endif /* GETOPT_LONG_IMPLEMENTATION */
+#endif /* !GETOPT_LONG_H_ */