mirror of
https://https.git.savannah.gnu.org/git/gnulib.git
synced 2026-06-15 23:35:50 +00:00
169 lines
5.1 KiB
C
169 lines
5.1 KiB
C
/* Parsing program options.
|
|
Copyright (C) 2025-2026 Free Software Foundation, Inc.
|
|
|
|
This file is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published
|
|
by the Free Software Foundation, either version 3 of the License,
|
|
or (at your option) any later version.
|
|
|
|
This file is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
|
|
/* Written by Bruno Haible <bruno@clisp.org>. */
|
|
|
|
#include <config.h>
|
|
|
|
/* Specification. */
|
|
#include "options.h"
|
|
|
|
#include <limits.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
/* State for communicating between _gl_start_options and get_next_option. */
|
|
static struct
|
|
{
|
|
int argc;
|
|
char **argv;
|
|
const struct program_option *options;
|
|
size_t n_options;
|
|
struct option *long_options;
|
|
char *short_options;
|
|
}
|
|
state;
|
|
|
|
void
|
|
_gl_start_options (int argc, char **argv,
|
|
const struct program_option *options, size_t n_options,
|
|
struct option *long_options, char *short_options,
|
|
enum non_option_handling nonopt_handling,
|
|
unsigned int error_handling)
|
|
{
|
|
/* Construct the long_options array. */
|
|
{
|
|
struct option *p = long_options;
|
|
|
|
for (size_t i = 0; i < n_options; i++)
|
|
if (options[i].name != NULL)
|
|
{
|
|
if (options[i].key == 0 && options[i].variable == NULL)
|
|
fprintf (stderr,
|
|
"start_options: warning: Option '--%s' has no action. Use the 'key' or the 'variable' field to specify an action.\n",
|
|
options[i].name);
|
|
|
|
p->name = options[i].name;
|
|
p->has_arg = options[i].has_arg;
|
|
if (options[i].key == 0 && options[i].variable != NULL)
|
|
{
|
|
p->flag = options[i].variable;
|
|
p->val = options[i].value;
|
|
}
|
|
else
|
|
{
|
|
p->flag = NULL;
|
|
p->val = options[i].key;
|
|
}
|
|
p++;
|
|
}
|
|
|
|
p->name = NULL;
|
|
p->has_arg = 0;
|
|
p->flag = NULL;
|
|
p->val = 0;
|
|
p++;
|
|
/* Verify that we haven't exceeded its allocated size. */
|
|
if (!(p - long_options <= _GL_LONG_OPTIONS_SIZE (n_options)))
|
|
abort ();
|
|
}
|
|
|
|
/* Construct the short_options string. */
|
|
{
|
|
char *p = short_options;
|
|
|
|
if (nonopt_handling == NON_OPTION_TERMINATES_OPTIONS)
|
|
*p++ = '+';
|
|
else if (nonopt_handling == PROCESS_NON_OPTIONS)
|
|
*p++ = '-';
|
|
|
|
if (error_handling & OPTIONS_MISSING_IS_COLON)
|
|
*p++ = ':';
|
|
|
|
for (size_t i = 0; i < n_options; i++)
|
|
if (options[i].key != 0 && options[i].key <= CHAR_MAX)
|
|
{
|
|
*p++ = options[i].key;
|
|
if (options[i].has_arg != no_argument)
|
|
{
|
|
*p++ = ':';
|
|
if (options[i].has_arg == optional_argument)
|
|
*p++ = ':';
|
|
}
|
|
}
|
|
|
|
*p++ = '\0';
|
|
/* Verify that we haven't exceeded its allocated size. */
|
|
if (!(p - short_options <= _GL_SHORT_OPTIONS_SIZE (n_options)))
|
|
abort ();
|
|
}
|
|
|
|
state.argc = argc;
|
|
state.argv = argv;
|
|
state.options = options;
|
|
state.n_options = n_options;
|
|
state.long_options = long_options;
|
|
state.short_options = short_options;
|
|
opterr = (error_handling & OPTIONS_ERRORS_SILENT) == 0;
|
|
}
|
|
|
|
int
|
|
#ifdef __MINGW32__
|
|
_gl_get_next_option (int *optind_p, char **optarg_p, int *optopt_p)
|
|
#else
|
|
get_next_option (void)
|
|
#endif
|
|
{
|
|
if (state.argv == NULL)
|
|
{
|
|
fprintf (stderr, "fatal: start_options has not been invoked\n");
|
|
abort ();
|
|
}
|
|
#ifdef __MINGW32__
|
|
/* See below for a general explanation. optind is not only an output of
|
|
getopt_long(), but also an input. */
|
|
optind = *optind_p;
|
|
#endif
|
|
int ret = getopt_long (state.argc, state.argv,
|
|
state.short_options, state.long_options, NULL);
|
|
if (ret > 1)
|
|
{
|
|
const struct program_option *options = state.options;
|
|
size_t n_options = state.n_options;
|
|
for (size_t i = 0; i < n_options; i++)
|
|
if (ret == options[i].key)
|
|
{
|
|
if (options[i].variable != NULL)
|
|
*(options[i].variable) = options[i].value;
|
|
}
|
|
}
|
|
#ifdef __MINGW32__
|
|
/* On mingw, when this file is compiled into a shared library, it pulls
|
|
mingw's getopt.o file (that defines getopt_long, opterr, optind, optarg,
|
|
optopt) into the same shared library. Since these variables are declared
|
|
and defined without any __declspec(dllexport) or __declspec(dllimport),
|
|
the effect is that there are two copies of the variables: one in the
|
|
shared library and one in the executable. Upon return from this function,
|
|
we need to copy the values of the output variables (optind, optarg, optopt)
|
|
from the shared library into the executable, where the main() function will
|
|
pick them up. */
|
|
*optind_p = optind;
|
|
*optarg_p = optarg;
|
|
*optopt_p = optopt;
|
|
#endif
|
|
return ret;
|
|
}
|