eal/windows: add getopt implementation

Adding getopt files to support parsing option on
Windows.

The original contribution is under BSD-2 license.
https://github.com/greenplum-db/libusual/blob/master/usual/getopt.c
https://github.com/greenplum-db/libusual/blob/master/usual/getopt.h

Signed-off-by: Antara Ganesh Kolar <antara.ganesh.kolar@intel.com>
Signed-off-by: Pallavi Kadam <pallavi.kadam@intel.com>
Reviewed-by: Ranjit Menon <ranjit.menon@intel.com>
Reviewed-by: Keith Wiles <keith.wiles@intel.com>
Reviewed-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
Tested-by: Narcisa Ana Maria Vasile <narcisa.vasile@microsoft.com>
Acked-by: Narcisa Ana Maria Vasile <narcisa.vasile@microsoft.com>
This commit is contained in:
Pallavi Kadam 2020-02-06 19:14:32 -08:00 committed by Thomas Monjalon
parent e8428a9d89
commit 5e373e456e
3 changed files with 563 additions and 0 deletions

View File

@ -0,0 +1,470 @@
/* SPDX-License-Identifier: ISC AND BSD-2-Clause
* Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
*
* 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.
*/
#include <getopt.h>
#ifdef NEED_USUAL_GETOPT
#include <string.h>
#include <stdlib.h>
const char *optarg; /* argument associated with option */
int opterr = 1; /* if error message should be printed */
int optind = 1; /* index into parent argv vector */
int optopt = '?'; /* character checked for validity */
static void pass(void) {}
#define warnx(a, ...) pass()
#define PRINT_ERROR ((opterr) && (*options != ':'))
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
/* return values */
#define BADCH ((int)'?')
#define BADARG ((*options == ':') ? (int)':' : (int)'?')
#define INORDER 1
#define EMSG ""
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(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(int panonopt_start, int panonopt_end, int opt_end,
char **nargv)
{
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap;
/*
* 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];
/* LINTED const cast */
((char **) nargv)[pos] = nargv[cstart];
/* LINTED const cast */
((char **)nargv)[cstart] = swap;
}
}
}
/*
* 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
parse_long_options(char **nargv, const char *options,
const struct option *long_options, int *idx, int short_too)
{
const char *current_argv;
char *has_equal;
size_t current_argv_len;
int i, match;
current_argv = place;
match = -1;
optind++;
has_equal = strchr(current_argv, '=');
if (has_equal != 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 {
/* 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 (short_too) {
--optind;
return (-1);
}
if (PRINT_ERROR)
warnx(illoptstring, current_argv);
optopt = 0;
return 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);
}
/*
* getopt_internal --
* Parse argc/argv argument vector. Called by user level routines.
*/
static int
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 posixly_correct = -1;
char *buf;
size_t len;
int optreset = 0;
if (options == NULL)
return (-1);
/*
* Disable GNU extensions if POSIXLY_CORRECT is set or options
* string begins with a '+'.
*/
if (posixly_correct == -1)
posixly_correct = _dupenv_s(&buf, &len, "POSIXLY_CORRECT");
if (!posixly_correct || *options == '+')
flags &= ~FLAG_PERMUTE;
else if (*options == '-')
flags |= FLAG_ALLARGS;
if (*options == '+' || *options == '-')
options++;
if (!posixly_correct)
free(buf);
/*
* reset if requested
*/
if (optind == 0)
optind = optreset = 1;
optarg = NULL;
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);
}
place = nargv[optind];
if (*place != '-' ||
(place[1] == '\0' && strchr(options, '-') == NULL)) {
place = EMSG; /* found non-option */
if (flags & FLAG_ALLARGS) {
/*
* GNU extension:
* return non-option as argument to option 1
*/
optarg = nargv[optind++];
return INORDER;
}
if (!(flags & FLAG_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 we have "-" do nothing, if "--" we are done.
*/
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
optind++;
place = EMSG;
/*
* 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;
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 getopt_long_only()
*/
if (long_options != NULL && place != nargv[optind] &&
(*place == '-' || (flags & FLAG_LONGONLY))) {
short_too = 0;
if (*place == '-')
place++; /* --foo long option */
else if (*place != ':' && strchr(options, *place) != NULL)
short_too = 1; /* could be short option too */
optchar = parse_long_options(nargv, options, long_options,
idx, short_too);
if (optchar != -1) {
place = EMSG;
return optchar;
}
}
optchar = (int)*place++;
oli = strchr(options, optchar);
if (optchar == (int)':' ||
(optchar == (int)'-' && *place != '\0') ||
oli == 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)'-' && *place == '\0')
return (-1);
if (!*place)
++optind;
if (PRINT_ERROR)
warnx(illoptchar, optchar);
optopt = optchar;
return BADCH;
}
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
/* -W long-option */
if (*place)
;
else if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return BADARG;
} /* white space */
place = nargv[optind];
optchar = parse_long_options(nargv, options, long_options,
idx, 0);
place = EMSG;
return optchar;
}
if (*++oli != ':') { /* doesn't take argument */
if (!*place)
++optind;
} else { /* takes (optional) argument */
optarg = NULL;
if (*place) /* no white space */
optarg = place;
else if (oli[1] != ':') { /* arg not optional */
if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return BADARG;
}
optarg = nargv[optind];
}
place = EMSG;
++optind;
}
/* dump back option letter */
return optchar;
}
/*
* getopt --
* Parse argc/argv argument vector.
*/
int
getopt(int nargc, char *nargv[], const char *options)
{
return getopt_internal(nargc, nargv, options, NULL, NULL,
FLAG_PERMUTE);
}
/*
* getopt_long --
* Parse argc/argv argument vector.
*/
int
getopt_long(int nargc, char *nargv[], const char *options,
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE));
}
/*
* getopt_long_only --
* Parse argc/argv argument vector.
*/
int
getopt_long_only(int nargc, char *nargv[], const char *options,
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE|FLAG_LONGONLY));
}
#endif /* NEED_USUAL_GETOPT */

View File

@ -0,0 +1,92 @@
/* SPDX-License-Identifier: BSD-2-Clause
* 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.
*/
/**
* @file
* getopt compat.
*
* This module provides getopt() and getopt_long().
*/
#ifndef _USUAL_GETOPT_H_
#define _USUAL_GETOPT_H_
#ifndef NEED_USUAL_GETOPT
#if !defined(HAVE_GETOPT_H) || !defined(HAVE_GETOPT) || \
!defined(HAVE_GETOPT_LONG)
#define NEED_USUAL_GETOPT
#endif
#endif
#ifndef NEED_USUAL_GETOPT
/* Use system getopt */
#include <getopt.h>
#else /* NEED_USUAL_GETOPT */
/* avoid name collision */
#define optarg usual_optarg
#define opterr usual_opterr
#define optind usual_optind
#define optopt usual_optopt
#define getopt(a, b, c) usual_getopt(a, b, c)
#define getopt_long(a, b, c, d, e) usual_getopt_long(a, b, c, d, e)
/** argument to current option, or NULL if it has none */
extern const char *optarg;
/** Current position in arg string. Starts from 1.
* Setting to 0 resets state.
*/
extern int optind;
/** whether getopt() should print error messages on problems. Default: 1. */
extern int opterr;
/** Option char which caused error */
extern int optopt;
/** long option takes no argument */
#define no_argument 0
/** long option requires argument */
#define required_argument 1
/** long option has optional argument */
#define optional_argument 2
/** Long option description */
struct option {
/** name of long option */
const char *name;
/**
* whether option takes an argument.
* One of no_argument, required_argument, and optional_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;
};
/** Compat: getopt */
int getopt(int argc, char *argv[], const char *options);
/** Compat: getopt_long */
int getopt_long(int argc, char *argv[], const char *options,
const struct option *longopts, int *longindex);
/** Compat: getopt_long_only */
int getopt_long_only(int nargc, char *argv[], const char *options,
const struct option *long_options, int *idx);
#endif /* NEED_USUAL_GETOPT */
#endif /* !_USUAL_GETOPT_H_ */

View File

@ -17,4 +17,5 @@ env_sources = files('eal.c',
'eal_debug.c',
'eal_lcore.c',
'eal_thread.c',
'getopt.c',
)