reactos/sdk/lib/crt/misc/getopt.c

395 lines
7.6 KiB
C

#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <stdarg.h>
#include <stdio.h>
#define REPLACE_GETOPT
#define _DIAGASSERT(x) do {} while (0)
#ifdef REPLACE_GETOPT
#ifdef __weak_alias
__weak_alias(getopt,_getopt)
#endif
int opterr = 1;
int optind = 1;
int optopt = '?';
int optreset;
char *optarg;
#endif
#ifdef __weak_alias
__weak_alias(getopt_long,_getopt_long)
#endif
#ifndef __CYGWIN__
#define __progname __argv[0]
#else
extern char __declspec(dllimport) *__progname;
#endif
#define IGNORE_FIRST (*options == '-' || *options == '+')
#define PRINT_ERROR ((opterr) && ((*options != ':') || (IGNORE_FIRST && options[1] != ':')))
#ifndef IS_POSIXLY_CORRECT
#define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)
#endif
#define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
#define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-')
#define BADCH (int)'?'
#define BADARG ((IGNORE_FIRST && options[1] == ':') || (*options == ':') ? (int)':' : (int)'?')
#define INORDER (int)1
static char EMSG[1];
static int getopt_internal (int,char * const *,const char *);
static int gcd (int,int);
static void permute_args (int,int,int,char * const *);
static char *place = EMSG;
static int nonopt_start = -1;
static int nonopt_end = -1;
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";
static void
_vwarnx(const char *fmt,va_list ap)
{
(void)fprintf(stderr,"%s: ",__progname);
if (fmt != NULL)
(void)vfprintf(stderr,fmt,ap);
(void)fprintf(stderr,"\n");
}
static void
warnx(const char *fmt,...)
{
va_list ap;
va_start(ap,fmt);
_vwarnx(fmt,ap);
va_end(ap);
}
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;
}
static void
permute_args(panonopt_start,panonopt_end,opt_end,nargv)
int panonopt_start;
int panonopt_end;
int opt_end;
char * const *nargv;
{
int cstart,cyclelen,i,j,ncycle,nnonopts,nopts,pos;
char *swap;
_DIAGASSERT(nargv != NULL);
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];
((char **) nargv)[pos] = nargv[cstart];
((char **)nargv)[cstart] = swap;
}
}
}
static int
getopt_internal(nargc,nargv,options)
int nargc;
char * const *nargv;
const char *options;
{
char *oli;
int optchar;
_DIAGASSERT(nargv != NULL);
_DIAGASSERT(options != NULL);
optarg = NULL;
if (optind == 0)
optind = 1;
if (optreset)
nonopt_start = nonopt_end = -1;
start:
if (optreset || !*place) {
optreset = 0;
if (optind >= nargc) {
place = EMSG;
if (nonopt_end != -1) {
permute_args(nonopt_start,nonopt_end,optind,nargv);
optind -= nonopt_end - nonopt_start;
}
else if (nonopt_start != -1) {
optind = nonopt_start;
}
nonopt_start = nonopt_end = -1;
return -1;
}
if ((*(place = nargv[optind]) != '-')
|| (place[1] == '\0')) {
place = EMSG;
if (IN_ORDER) {
optarg = nargv[optind++];
return INORDER;
}
if (!PERMUTE) {
return -1;
}
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++;
goto start;
}
if (nonopt_start != -1 && nonopt_end == -1)
nonopt_end = optind;
if (place[1] && *++place == '-') {
place++;
return -2;
}
}
if ((optchar = (int)*place++) == (int)':' ||
(oli = strchr(options + (IGNORE_FIRST ? 1 : 0),optchar)) == NULL) {
if (!*place)
++optind;
if (PRINT_ERROR)
warnx(illoptchar,optchar);
optopt = optchar;
return BADCH;
}
if (optchar == 'W' && oli[1] == ';') {
if (*place)
return -2;
if (++optind >= nargc) {
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar,optchar);
optopt = optchar;
return BADARG;
} else
place = nargv[optind];
return -2;
}
if (*++oli != ':') {
if (!*place)
++optind;
} else {
optarg = NULL;
if (*place)
optarg = place;
else if (oli[1] != ':') {
if (++optind >= nargc) {
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar,optchar);
optopt = optchar;
return BADARG;
} else
optarg = nargv[optind];
}
place = EMSG;
++optind;
}
return optchar;
}
#ifdef REPLACE_GETOPT
int
getopt(nargc,nargv,options)
int nargc;
char * const *nargv;
const char *options;
{
int retval;
_DIAGASSERT(nargv != NULL);
_DIAGASSERT(options != NULL);
if ((retval = getopt_internal(nargc,nargv,options)) == -2) {
++optind;
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
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;
_DIAGASSERT(nargv != NULL);
_DIAGASSERT(options != NULL);
_DIAGASSERT(long_options != NULL);
if ((retval = getopt_internal(nargc,nargv,options)) == -2) {
char *current_argv,*has_equal;
size_t current_argv_len;
int i,match;
current_argv = place;
match = -1;
optind++;
place = EMSG;
if (*current_argv == '\0') {
if (nonopt_end != -1) {
permute_args(nonopt_start,nonopt_end,optind,nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
return -1;
}
if ((has_equal = strchr(current_argv,'=')) != NULL) {
current_argv_len = has_equal - current_argv;
has_equal++;
} else
current_argv_len = strlen(current_argv);
for (i = 0; long_options[i].name; i++) {
if (strncmp(current_argv,long_options[i].name,current_argv_len))
continue;
if (strlen(long_options[i].name) ==
(unsigned)current_argv_len) {
match = i;
break;
}
if (match == -1)
match = i;
else {
if (PRINT_ERROR)
warnx(ambig,(int)current_argv_len,current_argv);
optopt = 0;
return BADCH;
}
}
if (match != -1) {
if (long_options[match].has_arg == no_argument
&& has_equal) {
if (PRINT_ERROR)
warnx(noarg,(int)current_argv_len,current_argv);
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) {
optarg = nargv[optind++];
}
}
if ((long_options[match].has_arg == required_argument)
&& (optarg == NULL)) {
if (PRINT_ERROR)
warnx(recargstring,current_argv);
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
--optind;
return BADARG;
}
} else {
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;
}