#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef GETOPT_H
#include "getopt.h"
#endif
typedef enum GETOPT_ORDERING_T
{
PERMUTE,
RETURN_IN_ORDER,
REQUIRE_ORDER
} GETOPT_ORDERING_T;
char *optarg = NULL;
int optind = 0;
int opterr = 1;
int optopt = '?';
static void
reverse_argv_elements (char **argv, int num)
{
int i;
char *tmp;
for (i = 0; i < (num >> 1); i++)
{
tmp = argv[i];
argv[i] = argv[num - i - 1];
argv[num - i - 1] = tmp;
}
}
static void
permute (char **argv, int len1, int len2)
{
reverse_argv_elements (argv, len1);
reverse_argv_elements (argv, len1 + len2);
reverse_argv_elements (argv, len2);
}
static int
is_option (char *argv_element, int only)
{
return ((argv_element == NULL)
|| (argv_element[0] == '-') || (only && argv_element[0] == '+'));
}
static int
getopt_internal (int argc, char **argv, char *shortopts,
GETOPT_LONG_OPTION_T * longopts, int *longind, int only)
{
GETOPT_ORDERING_T ordering = PERMUTE;
static size_t optwhere = 0;
size_t permute_from = 0;
int num_nonopts = 0;
int optindex = 0;
size_t match_chars = 0;
char *possible_arg = NULL;
int longopt_match = -1;
int has_arg = -1;
char *cp = NULL;
int arg_next = 0;
if (argc == 0 || argv == NULL || (shortopts == NULL && longopts == NULL))
return (optopt = '?');
if (optind >= argc || argv[optind] == NULL)
return EOF;
if (strcmp (argv[optind], "--") == 0)
{
optind++;
return EOF;
}
if (optind == 0)
optind = optwhere = 1;
if (shortopts != NULL && (*shortopts == '-' || *shortopts == '+'))
{
ordering = (*shortopts == '-') ? RETURN_IN_ORDER : REQUIRE_ORDER;
shortopts++;
}
else
ordering = (getenv ("POSIXLY_CORRECT") != NULL) ? REQUIRE_ORDER : PERMUTE;
if (optwhere == 1)
{
switch (ordering)
{
case PERMUTE:
permute_from = optind;
num_nonopts = 0;
while (!is_option (argv[optind], only))
{
optind++;
num_nonopts++;
}
if (argv[optind] == NULL)
{
optind = permute_from;
return EOF;
}
else if (strcmp (argv[optind], "--") == 0)
{
permute (argv + permute_from, num_nonopts, 1);
optind = permute_from + 1;
return EOF;
}
break;
case RETURN_IN_ORDER:
if (!is_option (argv[optind], only))
{
optarg = argv[optind++];
return (optopt = 1);
}
break;
case REQUIRE_ORDER:
if (!is_option (argv[optind], only))
return EOF;
break;
}
}
if (longopts != NULL
&& (memcmp (argv[optind], "--", 2) == 0
|| (only && argv[optind][0] == '+')) && optwhere == 1)
{
if (memcmp (argv[optind], "--", 2) == 0)
optwhere = 2;
longopt_match = -1;
possible_arg = strchr (argv[optind] + optwhere, '=');
if (possible_arg == NULL)
{
match_chars = strlen (argv[optind]);
possible_arg = argv[optind] + match_chars;
match_chars = match_chars - optwhere;
}
else
match_chars = (possible_arg - argv[optind]) - optwhere;
for (optindex = 0; longopts[optindex].name != NULL; optindex++)
{
if (memcmp (argv[optind] + optwhere,
longopts[optindex].name, match_chars) == 0)
{
if (match_chars == strlen (longopts[optindex].name))
{
longopt_match = optindex;
break;
}
else
{
if (longopt_match < 0)
longopt_match = optindex;
else
{
if (opterr)
fprintf (stderr, "%s: option `%s' is ambiguous "
"(could be `--%s' or `--%s')\n",
argv[0],
argv[optind],
longopts[longopt_match].name,
longopts[optindex].name);
return (optopt = '?');
}
}
}
}
if (longopt_match >= 0)
has_arg = longopts[longopt_match].has_arg;
}
if (longopt_match < 0 && shortopts != NULL)
{
cp = strchr (shortopts, argv[optind][optwhere]);
if (cp == NULL)
{
if (opterr)
fprintf (stderr,
"%s: invalid option -- `-%c'\n",
argv[0], argv[optind][optwhere]);
optwhere++;
if (argv[optind][optwhere] == '\0')
{
optind++;
optwhere = 1;
}
return (optopt = '?');
}
has_arg = ((cp[1] == ':')
? ((cp[2] == ':') ? OPTIONAL_ARG : required_argument) : no_argument);
possible_arg = argv[optind] + optwhere + 1;
optopt = *cp;
}
arg_next = 0;
switch (has_arg)
{
case OPTIONAL_ARG:
if (*possible_arg == '=')
possible_arg++;
if (*possible_arg != '\0')
{
optarg = possible_arg;
optwhere = 1;
}
else
optarg = NULL;
break;
case required_argument:
if (*possible_arg == '=')
possible_arg++;
if (*possible_arg != '\0')
{
optarg = possible_arg;
optwhere = 1;
}
else if (optind + 1 >= argc)
{
if (opterr)
{
fprintf (stderr, "%s: argument required for option `", argv[0]);
if (longopt_match >= 0)
fprintf (stderr, "--%s'\n", longopts[longopt_match].name);
else
fprintf (stderr, "-%c'\n", *cp);
}
optind++;
return (optopt = ':');
}
else
{
optarg = argv[optind + 1];
arg_next = 1;
optwhere = 1;
}
break;
case no_argument:
if (longopt_match < 0)
{
optwhere++;
if (argv[optind][optwhere] == '\0')
optwhere = 1;
}
else
optwhere = 1;
optarg = NULL;
break;
}
if (ordering == PERMUTE && optwhere == 1 && num_nonopts != 0)
{
permute (argv + permute_from, num_nonopts, 1 + arg_next);
optind = permute_from + 1 + arg_next;
}
else if (optwhere == 1)
optind = optind + 1 + arg_next;
if (longopt_match >= 0)
{
if (longind != NULL)
*longind = longopt_match;
if (longopts[longopt_match].flag != NULL)
{
*(longopts[longopt_match].flag) = longopts[longopt_match].val;
return 0;
}
else
return longopts[longopt_match].val;
}
else
return optopt;
}
#ifndef _AIX
int
getopt (int argc, char **argv, char *optstring)
{
return getopt_internal (argc, argv, optstring, NULL, NULL, 0);
}
#endif
int
getopt_long (int argc, char **argv, const char *shortopts,
const GETOPT_LONG_OPTION_T * longopts, int *longind)
{
return getopt_internal (argc, argv, (char*)shortopts, (GETOPT_LONG_OPTION_T*)longopts, longind, 0);
}
int
getopt_long_only (int argc, char **argv, const char *shortopts,
const GETOPT_LONG_OPTION_T * longopts, int *longind)
{
return getopt_internal (argc, argv, (char*)shortopts, (GETOPT_LONG_OPTION_T*)longopts, longind, 1);
}