mirror of
https://github.com/apache/nuttx.git
synced 2026-08-20 21:18:23 +00:00
Make getopt function family more posix complaint
by porting Gregory Pietsch's version Change-Id: I9a792734b45278863630f060a20589b0d9ab8bed
This commit is contained in:
parent
865661585e
commit
dc176e2fb3
3 changed files with 809 additions and 255 deletions
233
include/getopt.h
Normal file
233
include/getopt.h
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
/****************************************************************************
|
||||
* include/getopt.h
|
||||
*
|
||||
* Copyright (C) 2018 Pinecone Inc. All rights reserved.
|
||||
* Author: Xiang Xiao <xiaoxiang@pinecone.net>
|
||||
*
|
||||
* 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 NuttX 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 COPYRIGHT HOLDERS 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
|
||||
* COPYRIGHT OWNER 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* AUTHOR: Gregory Pietsch
|
||||
* CREATED Thu Jan 09 22:37:00 1997
|
||||
*
|
||||
* COPYRIGHT NOTICE AND DISCLAIMER:
|
||||
*
|
||||
* Copyright (C) 1997 Gregory Pietsch
|
||||
*
|
||||
* This file and the accompanying getopt.c implementation file are hereby
|
||||
* placed in the public domain without restrictions. Just give the author
|
||||
* credit, don't claim you wrote it or prevent anyone else from using it.
|
||||
*
|
||||
* Gregory Pietsch's current e-mail address:
|
||||
* gpietsch@comcast.net
|
||||
***************************************************************************/
|
||||
|
||||
/* This is a glibc-extension header file. */
|
||||
|
||||
#ifndef __INCLUDE_GETOPT_H
|
||||
#define __INCLUDE_GETOPT_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/compiler.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Names for the values of the `has_arg' field of `struct option'. */
|
||||
|
||||
#define no_argument 0
|
||||
#define required_argument 1
|
||||
#define optional_argument 2
|
||||
|
||||
#define NO_ARG no_argument
|
||||
#define REQUIRED_ARG required_argument
|
||||
#define OPTIONAL_ARG optional_argument
|
||||
|
||||
/* The GETOPT_DATA_INITIALIZER macro is used to initialize a statically-
|
||||
* allocated variable of type struct getopt_data.
|
||||
*/
|
||||
|
||||
#define GETOPT_DATA_INITIALIZER {0, 0, 1, 0, 0, 0, 0}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/* Used by getopt (obviously NOT thread safe!). These variables cannot be
|
||||
* accessed directly by an external NXFLAT module. In that case, accessor
|
||||
* functions must be used.
|
||||
*/
|
||||
|
||||
#ifndef __NXFLAT__
|
||||
|
||||
/* For communication from `getopt' to the caller.
|
||||
* When `getopt' finds an option that takes an argument,
|
||||
* the argument value is returned here.
|
||||
* Also, when `ordering' is RETURN_IN_ORDER,
|
||||
* each non-option ARGV-element is returned here.
|
||||
*/
|
||||
|
||||
EXTERN FAR char *optarg;
|
||||
|
||||
/* Index in ARGV of the next element to be scanned.
|
||||
* This is used for communication to and from the caller
|
||||
* and for communication between successive calls to `getopt'.
|
||||
*
|
||||
* On entry to `getopt', zero means this is the first call; initialize.
|
||||
*
|
||||
* When `getopt' returns -1, this is the index of the first of the
|
||||
* non-option elements that the caller should itself scan.
|
||||
*
|
||||
* Otherwise, `optind' communicates from one call to the next
|
||||
* how much of ARGV has been scanned so far.
|
||||
*/
|
||||
|
||||
EXTERN int optind;
|
||||
|
||||
/* Callers store zero here to inhibit the error message `getopt' prints
|
||||
* for unrecognized options.
|
||||
*/
|
||||
|
||||
EXTERN int opterr;
|
||||
|
||||
/* Set to an option character which was unrecognized. */
|
||||
|
||||
EXTERN int optopt;
|
||||
#else
|
||||
# define optarg (*(getoptargp()))
|
||||
# define optind (*(getoptindp()))
|
||||
# define optopt (*(getoptoptp()))
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Type Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Describe the long-named options requested by the application.
|
||||
* The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
|
||||
* of `struct option' terminated by an element containing a name which is
|
||||
* zero.
|
||||
*
|
||||
* The field `has_arg' is:
|
||||
* no_argument (or 0) if the option does not take an argument,
|
||||
* required_argument (or 1) if the option requires an argument,
|
||||
* optional_argument (or 2) if the option takes an optional argument.
|
||||
*
|
||||
* If the field `flag' is not NULL, it points to a variable that is set
|
||||
* to the value given in the field `val' when the option is found, but
|
||||
* left unchanged if the option is not found.
|
||||
*
|
||||
* To have a long-named option do something other than set an `int' to
|
||||
* a compiled-in constant, such as set a value from `optarg', set the
|
||||
* option's `flag' field to zero and its `val' field to a nonzero
|
||||
* value (the equivalent single-letter option character, if there is
|
||||
* one). For long options that have a zero `flag' field, `getopt'
|
||||
* returns the contents of the `val' field.
|
||||
*/
|
||||
|
||||
struct option
|
||||
{
|
||||
FAR const char *name; /* The name of the long option */
|
||||
int has_arg; /* One of the above macros */
|
||||
FAR int *flag; /* Determines if getopt_long() returns a
|
||||
* value for a long option; if it is
|
||||
* non-NULL, 0 is returned as a function
|
||||
* value and the value of val is stored in
|
||||
* the area pointed to by flag. Otherwise,
|
||||
* val is returned.
|
||||
*/
|
||||
int val; /* Determines the value to return if flag is
|
||||
* NULL.
|
||||
*/
|
||||
};
|
||||
|
||||
/* The getopt_data structure is for reentrancy. Its members are similar to
|
||||
* the externally-defined variables.
|
||||
*/
|
||||
|
||||
typedef struct getopt_data
|
||||
{
|
||||
FAR char *optarg;
|
||||
int optind, opterr, optopt, optwhere;
|
||||
int permute_from, num_nonopts;
|
||||
} getopt_data;
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
int getopt(int argc, FAR char *const argv[], FAR const char *optstring);
|
||||
|
||||
int getopt_long(int argc, FAR char *const argv[], FAR const char *shortopts,
|
||||
FAR const struct option *longopts, FAR int *longind);
|
||||
|
||||
int getopt_long_only(int argc, FAR char *const argv[], FAR const char *shortopts,
|
||||
FAR const struct option *longopts, FAR int *longind);
|
||||
|
||||
int getopt_r(int argc, FAR char *const argv[], FAR const char *optstring,
|
||||
FAR struct getopt_data *data);
|
||||
|
||||
int getopt_long_r(int argc, FAR char *const argv[], FAR const char *shortopts,
|
||||
FAR const struct option *longopts, FAR int *longind,
|
||||
FAR struct getopt_data *data);
|
||||
|
||||
int getopt_long_only_r(int argc, FAR char *const argv[], FAR const char *shortopts,
|
||||
FAR const struct option *longopts, FAR int *longind,
|
||||
FAR struct getopt_data *data);
|
||||
|
||||
/* Accessor functions intended for use only by external NXFLAT
|
||||
* modules. The global variables optarg, optind, and optopt cannot
|
||||
* be referenced directly from external modules.
|
||||
*/
|
||||
|
||||
FAR char **getoptargp(void); /* Optional argument following option */
|
||||
FAR int *getoptindp(void); /* Index into argv */
|
||||
FAR int *getoptoptp(void); /* Unrecognized option character */
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INCLUDE_GETOPT_H */
|
||||
|
|
@ -44,6 +44,8 @@
|
|||
#include <sys/types.h>
|
||||
#include <nuttx/compiler.h>
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
|
@ -289,21 +291,6 @@ extern "C"
|
|||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/* Used by getopt (obviously NOT thread safe!). These variables cannot be
|
||||
* accessed directly by an external NXFLAT module. In that case, accessor
|
||||
* functions must be used.
|
||||
*/
|
||||
|
||||
#ifndef __NXFLAT__
|
||||
EXTERN FAR char *optarg; /* Optional argument following option */
|
||||
EXTERN int optind; /* Index into argv */
|
||||
EXTERN int optopt; /* Unrecognized option character */
|
||||
#else
|
||||
# define optarg (*(getoptargp()))
|
||||
# define optind (*(getoptindp()))
|
||||
# define optopt (*(getoptoptp()))
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
|
@ -379,19 +366,6 @@ int execv(FAR const char *path, FAR char * const argv[]);
|
|||
|
||||
void swab(FAR const void *src, FAR void *dest, ssize_t nbytes);
|
||||
|
||||
/* getopt and friends */
|
||||
|
||||
int getopt(int argc, FAR char * const argv[], FAR const char *optstring);
|
||||
|
||||
/* Accessor functions intended for use only by external NXFLAT
|
||||
* modules. The global variables optarg, optind, and optopt cannot
|
||||
* be referenced directly from external modules.
|
||||
*/
|
||||
|
||||
FAR char **getoptargp(void); /* Optional argument following option */
|
||||
FAR int *getoptindp(void); /* Index into argv */
|
||||
FAR int *getoptoptp(void); /* Unrecognized option character */
|
||||
|
||||
int gethostname(FAR char *name, size_t size);
|
||||
int sethostname(FAR const char *name, size_t size);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
/****************************************************************************
|
||||
* libs/libc/unistd/lib_getopt.c
|
||||
*
|
||||
* Copyright (C) 2007-2009, 2011, 2019 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
* Author: Xiang Xiao <xiaoxiang@pinecone.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
|
@ -33,263 +34,609 @@
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* AUTHOR: Gregory Pietsch
|
||||
* CREATED Fri Jan 10 21:13:05 1997
|
||||
*
|
||||
* Copyright (C) 1997 Gregory Pietsch
|
||||
*
|
||||
* This file and the accompanying getopt.h header file are hereby placed in the
|
||||
* public domain without restrictions. Just give the author credit, don't
|
||||
* claim you wrote it or prevent anyone else from using it.
|
||||
*
|
||||
* Gregory Pietsch's current e-mail address:
|
||||
* gpietsch@comcast.net
|
||||
***************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define PERMUTE 0
|
||||
#define RETURN_IN_ORDER 1
|
||||
#define REQUIRE_ORDER 2
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
FAR char *optarg; /* Optional argument following option */
|
||||
int optind = 1; /* Index into argv */
|
||||
int opterr = 1;
|
||||
int optopt = '?'; /* unrecognized option character */
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static FAR char *g_optptr = NULL;
|
||||
static FAR char * const *g_argv = NULL;
|
||||
static int g_argc = 0;
|
||||
static bool g_binitialized = false;
|
||||
static int optwhere = 1;
|
||||
static int permute_from = 0;
|
||||
static int num_nonopts = 0;
|
||||
|
||||
static int g_argc;
|
||||
static FAR char *const *g_argv;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/* reverse_argv_elements: reverses num elements starting at argv */
|
||||
|
||||
static void
|
||||
reverse_argv_elements(FAR char **argv, int num)
|
||||
{
|
||||
int i;
|
||||
FAR char *tmp;
|
||||
|
||||
for (i = 0; i < (num >> 1); i++)
|
||||
{
|
||||
tmp = argv[i];
|
||||
argv[i] = argv[num - i - 1];
|
||||
argv[num - i - 1] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* permute: swap two blocks of argv-elements given their lengths */
|
||||
|
||||
static void
|
||||
permute(FAR char *const argv[], int len1, int len2)
|
||||
{
|
||||
reverse_argv_elements((FAR char **)argv, len1);
|
||||
reverse_argv_elements((FAR char **)argv, len1 + len2);
|
||||
reverse_argv_elements((FAR char **)argv, len2);
|
||||
}
|
||||
|
||||
/* is_option: is this argv-element an option or the end of the option list? */
|
||||
|
||||
static int
|
||||
is_option(FAR char *argv_element, int only)
|
||||
{
|
||||
return ((argv_element == 0) ||
|
||||
(argv_element[0] == '-') || (only && argv_element[0] == '+'));
|
||||
}
|
||||
|
||||
/* read_globals: read the values from the globals into a getopt_data
|
||||
* structure
|
||||
*/
|
||||
|
||||
static void
|
||||
read_globals(int argc, FAR char *const argv[],
|
||||
FAR struct getopt_data *data)
|
||||
{
|
||||
bool reinit = false;
|
||||
|
||||
if (g_argc != argc || g_argv != argv)
|
||||
{
|
||||
g_argc = argc;
|
||||
g_argv = argv;
|
||||
reinit = true;
|
||||
}
|
||||
|
||||
data->optarg = optarg;
|
||||
data->optind = reinit ? 0 : optind;
|
||||
data->opterr = opterr;
|
||||
data->optopt = optopt;
|
||||
data->optwhere = optwhere;
|
||||
data->permute_from = permute_from;
|
||||
data->num_nonopts = num_nonopts;
|
||||
}
|
||||
|
||||
/* write_globals: write the values into the globals from a getopt_data
|
||||
* structure
|
||||
*/
|
||||
|
||||
static void
|
||||
write_globals(int r, FAR struct getopt_data *data)
|
||||
{
|
||||
if (r == EOF)
|
||||
{
|
||||
g_argc = 0;
|
||||
g_argv = NULL;
|
||||
}
|
||||
optarg = data->optarg;
|
||||
optind = data->optind;
|
||||
opterr = data->opterr;
|
||||
optopt = data->optopt;
|
||||
optwhere = data->optwhere;
|
||||
permute_from = data->permute_from;
|
||||
num_nonopts = data->num_nonopts;
|
||||
}
|
||||
|
||||
/* getopt_internal: the function that does all the dirty work
|
||||
* NOTE: to reduce the code and RAM footprint this function uses
|
||||
* fputs()/fputc() to do output to stderr instead of fprintf().
|
||||
*/
|
||||
|
||||
static int
|
||||
getopt_internal(int argc, FAR char *const argv[], FAR const char *shortopts,
|
||||
FAR const struct option *longopts, FAR int *longind, int only,
|
||||
FAR struct getopt_data *data)
|
||||
{
|
||||
int ordering = PERMUTE;
|
||||
int optindex = 0;
|
||||
size_t match_chars = 0;
|
||||
FAR char *possible_arg = 0;
|
||||
int longopt_match = -1;
|
||||
int has_arg = -1;
|
||||
FAR char *cp = 0;
|
||||
int arg_next = 0;
|
||||
int initial_colon = 0;
|
||||
|
||||
/* If this is our first time through */
|
||||
|
||||
if (data->optind < 1)
|
||||
{
|
||||
data->optind = 1;
|
||||
data->optwhere = 1;
|
||||
data->permute_from = 0;
|
||||
data->num_nonopts = 0;
|
||||
}
|
||||
|
||||
/* First, deal with silly parameters and easy stuff */
|
||||
|
||||
if (argc == 0 || argv == 0 || (shortopts == 0 && longopts == 0)
|
||||
|| data->optind >= argc || argv[data->optind] == 0)
|
||||
{
|
||||
return EOF;
|
||||
}
|
||||
if (strcmp(argv[data->optind], "--") == 0)
|
||||
{
|
||||
data->optind++;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
/* Define ordering */
|
||||
|
||||
if (shortopts != 0 && (*shortopts == '-' || *shortopts == '+'))
|
||||
{
|
||||
ordering = (*shortopts == '-') ? RETURN_IN_ORDER : REQUIRE_ORDER;
|
||||
shortopts++;
|
||||
}
|
||||
#ifndef CONFIG_DISABLE_ENVIRON
|
||||
else
|
||||
{
|
||||
ordering = (getenv("POSIXLY_CORRECT") != 0) ? REQUIRE_ORDER : PERMUTE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check for initial colon in shortopts */
|
||||
|
||||
if (shortopts != 0 && *shortopts == ':')
|
||||
{
|
||||
++shortopts;
|
||||
initial_colon = 1;
|
||||
}
|
||||
|
||||
/* Based on ordering, find our next option, if we're at the beginning of
|
||||
* one
|
||||
*/
|
||||
|
||||
if (data->optwhere == 1)
|
||||
{
|
||||
switch (ordering)
|
||||
{
|
||||
default: /* Shouldn't happen */
|
||||
case PERMUTE:
|
||||
data->permute_from = data->optind;
|
||||
data->num_nonopts = 0;
|
||||
while (!is_option(argv[data->optind], only))
|
||||
{
|
||||
data->optind++;
|
||||
data->num_nonopts++;
|
||||
}
|
||||
if (argv[data->optind] == 0)
|
||||
{
|
||||
/* No more options */
|
||||
|
||||
data->optind = data->permute_from;
|
||||
return EOF;
|
||||
}
|
||||
else if (strcmp(argv[data->optind], "--") == 0)
|
||||
{
|
||||
/* No more options, but have to get `--' out of the way */
|
||||
|
||||
permute(argv + data->permute_from, data->num_nonopts, 1);
|
||||
data->optind = data->permute_from + 1;
|
||||
return EOF;
|
||||
}
|
||||
break;
|
||||
|
||||
case RETURN_IN_ORDER:
|
||||
if (!is_option(argv[data->optind], only))
|
||||
{
|
||||
data->optarg = argv[data->optind++];
|
||||
return (data->optopt = 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case REQUIRE_ORDER:
|
||||
if (!is_option(argv[data->optind], only))
|
||||
{
|
||||
return EOF;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* We've got an option, so parse it */
|
||||
|
||||
/* First, is it a long option? */
|
||||
|
||||
if (longopts != 0 &&
|
||||
(memcmp(argv[data->optind], "--", 2) == 0 ||
|
||||
(only && argv[data->optind][0] == '+')) && data->optwhere == 1)
|
||||
{
|
||||
/* Handle long options */
|
||||
|
||||
if (memcmp(argv[data->optind], "--", 2) == 0)
|
||||
{
|
||||
data->optwhere = 2;
|
||||
}
|
||||
possible_arg = strchr(argv[data->optind] + data->optwhere, '=');
|
||||
if (possible_arg == 0)
|
||||
{
|
||||
/* No =, so next argv might be arg */
|
||||
|
||||
match_chars = strlen(argv[data->optind]);
|
||||
possible_arg = argv[data->optind] + match_chars;
|
||||
match_chars = match_chars - data->optwhere;
|
||||
}
|
||||
else
|
||||
{
|
||||
match_chars = (possible_arg - argv[data->optind]) - data->optwhere;
|
||||
}
|
||||
|
||||
for (optindex = 0; longopts[optindex].name != 0; ++optindex)
|
||||
{
|
||||
if (memcmp(argv[data->optind] + data->optwhere,
|
||||
longopts[optindex].name, match_chars) == 0)
|
||||
{
|
||||
/* Do we have an exact match? */
|
||||
|
||||
if (match_chars == strlen(longopts[optindex].name))
|
||||
{
|
||||
longopt_match = optindex;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Do any characters match? */
|
||||
|
||||
else
|
||||
{
|
||||
if (longopt_match < 0)
|
||||
{
|
||||
longopt_match = optindex;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have ambiguous options */
|
||||
|
||||
if (data->opterr)
|
||||
{
|
||||
fputs(argv[0], stderr);
|
||||
fputs(": option `", stderr);
|
||||
fputs(argv[data->optind], stderr);
|
||||
fputs("' is ambiguous (could be `--", stderr);
|
||||
fputs(longopts[longopt_match].name, stderr);
|
||||
fputs("' or `--", stderr);
|
||||
fputs(longopts[optindex].name, stderr);
|
||||
fputs("')\n", stderr);
|
||||
}
|
||||
data->optind++;
|
||||
return (data->optopt = '?');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (longopt_match >= 0)
|
||||
{
|
||||
has_arg = longopts[longopt_match].has_arg;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we didn't find a long option, is it a short option? */
|
||||
|
||||
if (longopt_match < 0 && shortopts != 0)
|
||||
{
|
||||
cp = strchr(shortopts, argv[data->optind][data->optwhere]);
|
||||
if (cp == 0)
|
||||
{
|
||||
/* Couldn't find option in shortopts */
|
||||
|
||||
if (data->opterr)
|
||||
{
|
||||
fputs(argv[0], stderr);
|
||||
fputs(": invalid option -- `-", stderr);
|
||||
fputc(argv[data->optind][data->optwhere], stderr);
|
||||
fputs("'\n", stderr);
|
||||
}
|
||||
data->optwhere++;
|
||||
if (argv[data->optind][data->optwhere] == '\0')
|
||||
{
|
||||
data->optind++;
|
||||
data->optwhere = 1;
|
||||
}
|
||||
return (data->optopt = '?');
|
||||
}
|
||||
has_arg = ((cp[1] == ':') ?
|
||||
((cp[2] == ':') ? OPTIONAL_ARG : REQUIRED_ARG) : NO_ARG);
|
||||
possible_arg = argv[data->optind] + data->optwhere + 1;
|
||||
data->optopt = *cp;
|
||||
}
|
||||
|
||||
/* Get argument and reset data->optwhere */
|
||||
|
||||
switch (has_arg)
|
||||
{
|
||||
case OPTIONAL_ARG:
|
||||
if (*possible_arg == '=')
|
||||
{
|
||||
possible_arg++;
|
||||
}
|
||||
data->optarg = (*possible_arg != '\0') ? possible_arg : 0;
|
||||
data->optwhere = 1;
|
||||
break;
|
||||
|
||||
case REQUIRED_ARG:
|
||||
if (*possible_arg == '=')
|
||||
{
|
||||
possible_arg++;
|
||||
}
|
||||
if (*possible_arg != '\0')
|
||||
{
|
||||
data->optarg = possible_arg;
|
||||
data->optwhere = 1;
|
||||
}
|
||||
else if (data->optind + 1 >= argc)
|
||||
{
|
||||
if (data->opterr)
|
||||
{
|
||||
fputs(argv[0], stderr);
|
||||
fputs(": argument required for option `-", stderr);
|
||||
if (longopt_match >= 0)
|
||||
{
|
||||
fputc('-', stderr);
|
||||
fputs(longopts[longopt_match].name, stderr);
|
||||
data->optopt = initial_colon ? ':' : '\?';
|
||||
}
|
||||
else
|
||||
{
|
||||
fputc(*cp, stderr);
|
||||
data->optopt = *cp;
|
||||
}
|
||||
fputs("'\n", stderr);
|
||||
}
|
||||
data->optind++;
|
||||
return initial_colon ? ':' : '\?';
|
||||
}
|
||||
else
|
||||
{
|
||||
data->optarg = argv[data->optind + 1];
|
||||
arg_next = 1;
|
||||
data->optwhere = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default: /* Shouldn't happen */
|
||||
case NO_ARG:
|
||||
if (longopt_match < 0)
|
||||
{
|
||||
data->optwhere++;
|
||||
if (argv[data->optind][data->optwhere] == '\0')
|
||||
{
|
||||
data->optwhere = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data->optwhere = 1;
|
||||
}
|
||||
data->optarg = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Do we have to permute or otherwise modify data->optind? */
|
||||
|
||||
if (ordering == PERMUTE && data->optwhere == 1 && data->num_nonopts != 0)
|
||||
{
|
||||
permute(argv + data->permute_from, data->num_nonopts, 1 + arg_next);
|
||||
data->optind = data->permute_from + 1 + arg_next;
|
||||
}
|
||||
else if (data->optwhere == 1)
|
||||
{
|
||||
data->optind = data->optind + 1 + arg_next;
|
||||
}
|
||||
|
||||
/* Finally return */
|
||||
|
||||
if (longopt_match >= 0)
|
||||
{
|
||||
if (longind != 0)
|
||||
{
|
||||
*longind = longopt_match;
|
||||
}
|
||||
if (longopts[longopt_match].flag != 0)
|
||||
{
|
||||
*(longopts[longopt_match].flag) = longopts[longopt_match].val;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return longopts[longopt_match].val;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return data->optopt;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: getopt
|
||||
*
|
||||
* Description:
|
||||
* getopt() parses command-line arguments. Its arguments argc and argv
|
||||
* are the argument count and array as passed to the main() function on
|
||||
* program invocation. An element of argv that starts with '-' is an
|
||||
* option element. The characters of this element (aside from the initial
|
||||
* '-') are option characters. If getopt() is called repeatedly, it
|
||||
* returns successively each of the option characters from each of the
|
||||
* option elements.
|
||||
*
|
||||
* If getopt() finds another option character, it returns that character,
|
||||
* updating the external variable optind and a static variable nextchar so
|
||||
* that the next call to getopt() can resume the scan with the following
|
||||
* option character or argv-element.
|
||||
*
|
||||
* If there are no more option characters, getopt() returns -1. Then optind
|
||||
* is the index in argv of the first argv-element that is not an option.
|
||||
*
|
||||
* The 'optstring' argument is a string containing the legitimate option
|
||||
* characters. If such a character is followed by a colon, this indicates
|
||||
* that the option requires an argument. If an argument is required for an
|
||||
* option so getopt() places a pointer to the following text in the same
|
||||
* argv-element, or the text of the following argv-element, in optarg.
|
||||
*
|
||||
* NOTES:
|
||||
* 1. opterr is not supported and this implementation of getopt() never
|
||||
* printfs error messages.
|
||||
* 2. getopt is NOT threadsafe!
|
||||
* 3. This version of getopt() does not reset global variables until
|
||||
* -1 is returned. As a result, your command line parsing loops
|
||||
* must call getopt() repeatedly and continue to parse if other
|
||||
* errors are returned ('?' or ':') until getopt() finally returns -1.
|
||||
* (You can also set optind to -1 to force a reset).
|
||||
*
|
||||
* Returned Value:
|
||||
* If an option was successfully found, then getopt() returns the option
|
||||
* character. If all command-line options have been parsed, then getopt()
|
||||
* returns -1. If getopt() encounters an option character that was not
|
||||
* in optstring, then '?' is returned. If getopt() encounters an option
|
||||
* with a missing argument, then the return value depends on the first
|
||||
* character in optstring: if it is ':', then ':' is returned; otherwise
|
||||
* '?' is returned.
|
||||
*
|
||||
****************************************************************************/
|
||||
The getopt() function parses the command line arguments. Its arguments argc
|
||||
and argv are the argument count and array as passed to the main() function
|
||||
on program invocation. The argument optstring is a list of available option
|
||||
characters. If such a character is followed by a colon (`:'), the option
|
||||
takes an argument, which is placed in optarg. If such a character is
|
||||
followed by two colons, the option takes an optional argument, which is
|
||||
placed in optarg. If the option does not take an argument, optarg is NULL.
|
||||
|
||||
int getopt(int argc, FAR char * const argv[], FAR const char *optstring)
|
||||
The external variable optind is the index of the next array element of argv
|
||||
to be processed; it communicates from one call to the next which element to
|
||||
process.
|
||||
|
||||
The getopt_long() function works like getopt() except that it also accepts
|
||||
long options started by two dashes `--'. If these take values, it is either
|
||||
in the form
|
||||
|
||||
--arg=value
|
||||
|
||||
or
|
||||
|
||||
--arg value
|
||||
|
||||
It takes the additional arguments longopts which is a pointer to the first
|
||||
element of an array of type struct option. The last element of the array
|
||||
has to be filled with NULL for the name field.
|
||||
|
||||
The longind pointer points to the index of the current long option relative
|
||||
to longopts if it is non-NULL.
|
||||
|
||||
The getopt() function returns the option character if the option was found
|
||||
successfully, `:' if there was a missing parameter for one of the options,
|
||||
`?' for an unknown option character, and EOF for the end of the option list.
|
||||
|
||||
The getopt_long() function's return value is described in the header file.
|
||||
|
||||
The function getopt_long_only() is identical to getopt_long(), except that a
|
||||
plus sign `+' can introduce long options as well as `--'.
|
||||
|
||||
The following describes how to deal with options that follow non-option
|
||||
argv-elements.
|
||||
|
||||
If the caller did not specify anything, the default is REQUIRE_ORDER if the
|
||||
environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise.
|
||||
|
||||
REQUIRE_ORDER means don't recognize them as options; stop option processing
|
||||
when the first non-option is seen. This is what Unix does. This mode of
|
||||
operation is selected by either setting the environment variable
|
||||
POSIXLY_CORRECT, or using `+' as the first character of the optstring
|
||||
parameter.
|
||||
|
||||
PERMUTE is the default. We permute the contents of ARGV as we scan, so that
|
||||
eventually all the non-options are at the end. This allows options to be
|
||||
given in any order, even with programs that were not written to expect this.
|
||||
|
||||
RETURN_IN_ORDER is an option available to programs that were written to
|
||||
expect options and other argv-elements in any order and that care about the
|
||||
ordering of the two. We describe each non-option argv-element as if it were
|
||||
the argument of an option with character code 1. Using `-' as the first
|
||||
character of the optstring parameter selects this mode of operation.
|
||||
|
||||
The special argument `--' forces an end of option-scanning regardless of the
|
||||
value of ordering. In the case of RETURN_IN_ORDER, only `--' can cause
|
||||
getopt() and friends to return EOF with optind != argc.
|
||||
|
||||
2012-08-26: Tried to make the error handling more sus4-like. The functions
|
||||
return a colon if getopt() and friends detect a missing argument and the
|
||||
first character of shortopts/optstring starts with a colon (`:'). If getopt()
|
||||
and friends detect a missing argument and shortopts/optstring does not start
|
||||
with a colon, the function returns a question mark (`?'). If it was a missing
|
||||
argument to a short option, optopt is set to the character in question. The
|
||||
colon goes after the ordering character (`+' or `-').
|
||||
****************************************************************************/
|
||||
|
||||
int
|
||||
getopt(int argc, FAR char *const argv[], FAR const char *optstring)
|
||||
{
|
||||
/* Were new argc or argv passed in? This detects misuse of getopt() by
|
||||
* applications that break out of the getopt() loop before getop() returns
|
||||
* -1.
|
||||
*/
|
||||
struct getopt_data data;
|
||||
int r;
|
||||
|
||||
if (argc != g_argc || argv != g_argv)
|
||||
{
|
||||
/* Yes, clear the internal state */
|
||||
|
||||
g_binitialized = false;
|
||||
g_argc = argc;
|
||||
g_argv = argv;
|
||||
}
|
||||
|
||||
/* Verify input parameters. */
|
||||
|
||||
if (argv != NULL && optstring != NULL && argc > 1)
|
||||
{
|
||||
FAR char *optchar;
|
||||
int noarg_ret = '?';
|
||||
|
||||
/* The initial value of optind is 1. If getopt() is called again in
|
||||
* the program, optind must be reset to some value <= 1.
|
||||
*/
|
||||
|
||||
if (optind < 1 || !g_binitialized)
|
||||
{
|
||||
optarg = NULL;
|
||||
optind = 1; /* Skip over the program name */
|
||||
optopt = '?';
|
||||
g_optptr = NULL; /* Start at the beginning of the first argument */
|
||||
g_binitialized = true; /* Now we are initialized */
|
||||
}
|
||||
|
||||
/* If the first character of opstring s ':', then ':' is in the event
|
||||
* of a missing argument. Otherwise '?' is returned.
|
||||
*/
|
||||
|
||||
if (*optstring == ':')
|
||||
{
|
||||
noarg_ret = ':';
|
||||
optstring++;
|
||||
}
|
||||
|
||||
/* Are we resuming in the middle, or at the end of a string of
|
||||
* arguments? g_optptr == NULL means that we are started at the
|
||||
* beginning of argv[optind]; *g_optptr == \0 means that we are
|
||||
* starting at the beginning of optind+1
|
||||
*/
|
||||
|
||||
while (!g_optptr || !*g_optptr)
|
||||
{
|
||||
/* We need to start at the beginning of the next argv. Check if we
|
||||
* need to increment optind
|
||||
*/
|
||||
|
||||
if (g_optptr)
|
||||
{
|
||||
/* Yes.. Increment it and check for the case where where we
|
||||
* have processed everything in the argv[] array.
|
||||
*/
|
||||
|
||||
optind++;
|
||||
}
|
||||
|
||||
/* Check for the end of the argument list */
|
||||
|
||||
g_optptr = argv[optind];
|
||||
if (!g_optptr)
|
||||
{
|
||||
/* There are no more arguments, we are finished */
|
||||
|
||||
g_binitialized = false;
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/* We are starting at the beginning of argv[optind]. In this case,
|
||||
* the first character must be '-'
|
||||
*/
|
||||
|
||||
if (*g_optptr != '-')
|
||||
{
|
||||
/* The argument does not start with '-', we are finished */
|
||||
|
||||
g_binitialized = false;
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/* Skip over the '-' */
|
||||
|
||||
g_optptr++;
|
||||
}
|
||||
|
||||
/* Special case handling of "-" and "-:" */
|
||||
|
||||
if (!*g_optptr)
|
||||
{
|
||||
optopt = '\0'; /* We'll fix up g_optptr the next time we are called */
|
||||
return '?';
|
||||
}
|
||||
|
||||
/* Handle the case of "-:" */
|
||||
|
||||
if (*g_optptr == ':')
|
||||
{
|
||||
optopt = ':';
|
||||
g_optptr++;
|
||||
return '?';
|
||||
}
|
||||
|
||||
/* g_optptr now points at the next option and it is not something
|
||||
* crazy. check if the option is in the list of valid options.
|
||||
*/
|
||||
|
||||
optchar = strchr(optstring, *g_optptr);
|
||||
if (!optchar)
|
||||
{
|
||||
/* No this character is not in the list of valid options */
|
||||
|
||||
optopt = *g_optptr;
|
||||
g_optptr++;
|
||||
return '?';
|
||||
}
|
||||
|
||||
/* Yes, the character is in the list of valid options. Does it have an
|
||||
* required argument?
|
||||
*/
|
||||
|
||||
if (optchar[1] != ':')
|
||||
{
|
||||
/* No, no arguments. Just return the character that we found */
|
||||
|
||||
g_optptr++;
|
||||
return *optchar;
|
||||
}
|
||||
|
||||
/* Yes, it has a required argument. Is the required argument
|
||||
* immediately after the command in this same argument?
|
||||
*/
|
||||
|
||||
if (g_optptr[1] != '\0')
|
||||
{
|
||||
/* Yes, return a pointer into the current argument */
|
||||
|
||||
optarg = &g_optptr[1];
|
||||
optind++;
|
||||
g_optptr = NULL;
|
||||
return *optchar;
|
||||
}
|
||||
|
||||
/* No.. is the optional argument the next argument in argv[] ? */
|
||||
|
||||
if (argv[optind + 1] && *argv[optind + 1] != '-')
|
||||
{
|
||||
/* Yes.. return that */
|
||||
|
||||
optarg = argv[optind + 1];
|
||||
optind += 2;
|
||||
g_optptr = NULL;
|
||||
return *optchar;
|
||||
}
|
||||
|
||||
/* No argument was supplied */
|
||||
|
||||
g_optptr = NULL;
|
||||
optarg = NULL;
|
||||
optopt = *optchar;
|
||||
optind++;
|
||||
return noarg_ret;
|
||||
}
|
||||
|
||||
/* Restore the initial, uninitialized state */
|
||||
|
||||
g_binitialized = false;
|
||||
return ERROR;
|
||||
read_globals(argc, argv, &data);
|
||||
r = getopt_internal(argc, argv, optstring, 0, 0, 0, &data);
|
||||
write_globals(r, &data);
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
getopt_long(int argc, FAR char *const argv[], FAR const char *shortopts,
|
||||
FAR const struct option *longopts, FAR int *longind)
|
||||
{
|
||||
struct getopt_data data;
|
||||
int r;
|
||||
|
||||
read_globals(argc, argv, &data);
|
||||
r = getopt_internal(argc, argv, shortopts, longopts, longind, 0, &data);
|
||||
write_globals(r, &data);
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
getopt_long_only(int argc, FAR char *const argv[], FAR const char *shortopts,
|
||||
FAR const struct option *longopts, FAR int *longind)
|
||||
{
|
||||
struct getopt_data data;
|
||||
int r;
|
||||
|
||||
read_globals(argc, argv, &data);
|
||||
r = getopt_internal(argc, argv, shortopts, longopts, longind, 1, &data);
|
||||
write_globals(r, &data);
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
getopt_r(int argc, FAR char *const argv[], FAR const char *optstring,
|
||||
FAR struct getopt_data *data)
|
||||
{
|
||||
return getopt_internal(argc, argv, optstring, 0, 0, 0, data);
|
||||
}
|
||||
|
||||
int
|
||||
getopt_long_r(int argc, FAR char *const argv[], FAR const char *shortopts,
|
||||
FAR const struct option *longopts, FAR int *longind,
|
||||
FAR struct getopt_data *data)
|
||||
{
|
||||
return getopt_internal(argc, argv, shortopts, longopts, longind, 0, data);
|
||||
}
|
||||
|
||||
int
|
||||
getopt_long_only_r(int argc, FAR char *const argv[], FAR const char *shortopts,
|
||||
FAR const struct option *longopts, FAR int *longind,
|
||||
FAR struct getopt_data *data)
|
||||
{
|
||||
return getopt_internal(argc, argv, shortopts, longopts, longind, 1, data);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue