Skip to content

Commit

Permalink
Brings the tools getopt(3) replacement into the main library (HDFGrou…
Browse files Browse the repository at this point in the history
…p#803)

* Moves get_option from the tools library to the C library

* Adds H5 prefix to get_option call and variables

* Renames the H5_get_option long options struct and enum
  • Loading branch information
derobins committed Jun 30, 2021
1 parent f87219f commit 9550a98
Show file tree
Hide file tree
Showing 24 changed files with 1,270 additions and 1,268 deletions.
60 changes: 30 additions & 30 deletions hl/tools/h5watch/h5watch.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,27 +58,27 @@ static void parse_command_line(int argc, const char *argv[]);
* The long-named ones can be partially spelled. When
* adding more, make sure that they don't clash with each other.
*/
static const char * s_opts = "?";
static struct long_options l_opts[] = {{"help", no_arg, 'h'}, {"hel", no_arg, 'h'},
{"dim", no_arg, 'd'}, {"di", no_arg, 'd'},
{"label", no_arg, 'l'}, {"labe", no_arg, 'l'},
{"lab", no_arg, 'l'}, {"la", no_arg, 'l'},
{"simple", no_arg, 'S'}, {"simpl", no_arg, 'S'},
{"simp", no_arg, 'S'}, {"sim", no_arg, 'S'},
{"si", no_arg, 'S'}, {"hexdump", no_arg, 'x'},
{"hexdum", no_arg, 'x'}, {"hexdu", no_arg, 'x'},
{"hexd", no_arg, 'x'}, {"hex", no_arg, 'x'},
{"width", require_arg, 'w'}, {"widt", require_arg, 'w'},
{"wid", require_arg, 'w'}, {"wi", require_arg, 'w'},
{"polling", require_arg, 'p'}, {"pollin", require_arg, 'p'},
{"polli", require_arg, 'p'}, {"poll", require_arg, 'p'},
{"pol", require_arg, 'p'}, {"po", require_arg, 'p'},
{"fields", require_arg, 'f'}, {"field", require_arg, 'f'},
{"fiel", require_arg, 'f'}, {"fie", require_arg, 'f'},
{"fi", require_arg, 'f'}, {"version", no_arg, 'V'},
{"versio", no_arg, 'V'}, {"versi", no_arg, 'V'},
{"vers", no_arg, 'V'}, {"ver", no_arg, 'V'},
{"ve", no_arg, 'V'}, {NULL, 0, '\0'}};
static const char * s_opts = "?";
static struct h5_long_options l_opts[] = {{"help", no_arg, 'h'}, {"hel", no_arg, 'h'},
{"dim", no_arg, 'd'}, {"di", no_arg, 'd'},
{"label", no_arg, 'l'}, {"labe", no_arg, 'l'},
{"lab", no_arg, 'l'}, {"la", no_arg, 'l'},
{"simple", no_arg, 'S'}, {"simpl", no_arg, 'S'},
{"simp", no_arg, 'S'}, {"sim", no_arg, 'S'},
{"si", no_arg, 'S'}, {"hexdump", no_arg, 'x'},
{"hexdum", no_arg, 'x'}, {"hexdu", no_arg, 'x'},
{"hexd", no_arg, 'x'}, {"hex", no_arg, 'x'},
{"width", require_arg, 'w'}, {"widt", require_arg, 'w'},
{"wid", require_arg, 'w'}, {"wi", require_arg, 'w'},
{"polling", require_arg, 'p'}, {"pollin", require_arg, 'p'},
{"polli", require_arg, 'p'}, {"poll", require_arg, 'p'},
{"pol", require_arg, 'p'}, {"po", require_arg, 'p'},
{"fields", require_arg, 'f'}, {"field", require_arg, 'f'},
{"fiel", require_arg, 'f'}, {"fie", require_arg, 'f'},
{"fi", require_arg, 'f'}, {"version", no_arg, 'V'},
{"versio", no_arg, 'V'}, {"versi", no_arg, 'V'},
{"vers", no_arg, 'V'}, {"ver", no_arg, 'V'},
{"ve", no_arg, 'V'}, {NULL, 0, '\0'}};

/*-------------------------------------------------------------------------
* Function: doprint()
Expand Down Expand Up @@ -677,7 +677,7 @@ parse_command_line(int argc, const char *argv[])
}

/* parse command line options */
while ((opt = get_option(argc, argv, s_opts, l_opts)) != EOF) {
while ((opt = H5_get_option(argc, argv, s_opts, l_opts)) != EOF) {
switch ((char)opt) {
case '?':
case 'h': /* --help */
Expand All @@ -691,7 +691,7 @@ parse_command_line(int argc, const char *argv[])
break;

case 'w': /* --width=N */
g_display_width = (int)HDstrtol(opt_arg, NULL, 0);
g_display_width = (int)HDstrtol(H5_optarg, NULL, 0);
if (g_display_width < 0) {
usage(h5tools_getprogname());
leave(EXIT_FAILURE);
Expand All @@ -711,8 +711,8 @@ parse_command_line(int argc, const char *argv[])
break;

case 'p': /* --polling=N */
/* g_polling_interval = HDstrtod(opt_arg, NULL); */
if ((tmp = (int)HDstrtol(opt_arg, NULL, 10)) <= 0) {
/* g_polling_interval = HDstrtod(H5_optarg, NULL); */
if ((tmp = (int)HDstrtol(H5_optarg, NULL, 10)) <= 0) {
usage(h5tools_getprogname());
leave(EXIT_FAILURE);
}
Expand All @@ -721,15 +721,15 @@ parse_command_line(int argc, const char *argv[])

case 'f': /* --fields=<list_of_fields> */
if (g_list_of_fields == NULL) {
if ((g_list_of_fields = HDstrdup(opt_arg)) == NULL) {
if ((g_list_of_fields = HDstrdup(H5_optarg)) == NULL) {
error_msg("memory allocation failed (file %s:line %d)\n", __FILE__, __LINE__);
leave(EXIT_FAILURE);
}
}
else {
char *str;

if ((str = HDstrdup(opt_arg)) == NULL) {
if ((str = HDstrdup(H5_optarg)) == NULL) {
error_msg("memory allocation failed (file %s:line %d)\n", __FILE__, __LINE__);
leave(EXIT_FAILURE);
}
Expand All @@ -751,7 +751,7 @@ parse_command_line(int argc, const char *argv[])
}

/* check for object to be processed */
if (argc <= opt_ind) {
if (argc <= H5_optind) {
error_msg("missing dataset name\n");
usage(h5tools_getprogname());
leave(EXIT_FAILURE);
Expand Down Expand Up @@ -821,7 +821,7 @@ main(int argc, const char *argv[])
/* parse command line options */
parse_command_line(argc, argv);

if (argc <= opt_ind) {
if (argc <= H5_optind) {
error_msg("missing dataset name\n");
usage(h5tools_getprogname());
leave(EXIT_FAILURE);
Expand All @@ -845,7 +845,7 @@ main(int argc, const char *argv[])
* then there must have been something wrong with the file (perhaps it
* doesn't exist).
*/
if ((fname = HDstrdup(argv[opt_ind])) == NULL) {
if ((fname = HDstrdup(argv[H5_optind])) == NULL) {
error_msg("memory allocation failed (file %s:line %d)\n", __FILE__, __LINE__);
h5tools_setstatus(EXIT_FAILURE);
goto done;
Expand Down
51 changes: 51 additions & 0 deletions src/H5private.h
Original file line number Diff line number Diff line change
Expand Up @@ -2713,6 +2713,57 @@ H5_DLL herr_t H5_combine_path(const char *path1, const char *path2, char **full_
H5_DLL herr_t H5_dirname(const char *path, char **dirname /*out*/);
H5_DLL herr_t H5_basename(const char *path, char **basename /*out*/);

/* getopt(3) equivalent that papers over the lack of long options on BSD
* and lack of Windows support.
*/
H5_DLLVAR int H5_opterr; /* get_option prints errors if this is on */
H5_DLLVAR int H5_optind; /* token pointer */
H5_DLLVAR const char *H5_optarg; /* flag argument (or value) */

enum h5_arg_level {
no_arg = 0, /* doesn't take an argument */
require_arg, /* requires an argument */
optional_arg /* argument is optional */
};

/*
* get_option determines which options are specified on the command line and
* returns a pointer to any arguments possibly associated with the option in
* the ``H5_optarg'' variable. get_option returns the shortname equivalent of
* the option. The long options are specified in the following way:
*
* struct h5_long_options foo[] = {
* { "filename", require_arg, 'f' },
* { "append", no_arg, 'a' },
* { "width", require_arg, 'w' },
* { NULL, 0, 0 }
* };
*
* Long named options can have arguments specified as either:
*
* ``--param=arg'' or ``--param arg''
*
* Short named options can have arguments specified as either:
*
* ``-w80'' or ``-w 80''
*
* and can have more than one short named option specified at one time:
*
* -aw80
*
* in which case those options which expect an argument need to come at the
* end.
*/
struct h5_long_options {
const char * name; /* Name of the long option */
enum h5_arg_level has_arg; /* Whether we should look for an arg */
char shortval; /* The shortname equivalent of long arg
* this gets returned from get_option
*/
};

H5_DLL int H5_get_option(int argc, const char **argv, const char *opt, const struct h5_long_options *l_opt);

#ifdef H5_HAVE_PARALLEL
/* Generic MPI functions */
H5_DLL hsize_t H5_mpi_set_bigio_count(hsize_t new_count);
Expand Down
164 changes: 164 additions & 0 deletions src/H5system.c
Original file line number Diff line number Diff line change
Expand Up @@ -1076,3 +1076,167 @@ H5_basename(const char *path, char **basename)

FUNC_LEAVE_NOAPI(ret_value)
} /* end H5_basename() */

/* Global variables */
int H5_opterr = 1; /* Get_option prints errors if this is on */
int H5_optind = 1; /* Token pointer */
const char *H5_optarg; /* Flag argument (or value) */

/*-------------------------------------------------------------------------
* Function: H5_get_option
*
* Purpose: Determine the command-line options a user specified. We can
* accept both short and long type command-lines.
*
* Return: Success: The short valued "name" of the command line
* parameter or EOF if there are no more
* parameters to process.
*
* Failure: A question mark.
*-------------------------------------------------------------------------
*/
int
H5_get_option(int argc, const char **argv, const char *opts, const struct h5_long_options *l_opts)
{
static int sp = 1; /* character index in current token */
int optopt = '?'; /* option character passed back to user */

if (sp == 1) {
/* check for more flag-like tokens */
if (H5_optind >= argc || argv[H5_optind][0] != '-' || argv[H5_optind][1] == '\0') {
return EOF;
}
else if (HDstrcmp(argv[H5_optind], "--") == 0) {
H5_optind++;
return EOF;
}
}

if (sp == 1 && argv[H5_optind][0] == '-' && argv[H5_optind][1] == '-') {
/* long command line option */
int i;
const char ch = '=';
char * arg = HDstrdup(&argv[H5_optind][2]);
size_t arg_len = 0;

H5_optarg = strchr(&argv[H5_optind][2], ch);
arg_len = HDstrlen(&argv[H5_optind][2]);
if (H5_optarg) {
arg_len -= HDstrlen(H5_optarg);
H5_optarg++; /* skip the equal sign */
}
arg[arg_len] = 0;

for (i = 0; l_opts && l_opts[i].name; i++) {
if (HDstrcmp(arg, l_opts[i].name) == 0) {
/* we've found a matching long command line flag */
optopt = l_opts[i].shortval;

if (l_opts[i].has_arg != no_arg) {
if (H5_optarg == NULL) {
if (l_opts[i].has_arg != optional_arg) {
if (H5_optind < (argc - 1))
if (argv[H5_optind + 1][0] != '-')
H5_optarg = argv[++H5_optind];
}
else if (l_opts[i].has_arg == require_arg) {
if (H5_opterr)
HDfprintf(stderr, "%s: option required for \"--%s\" flag\n", argv[0], arg);

optopt = '?';
}
}
}
else {
if (H5_optarg) {
if (H5_opterr)
HDfprintf(stderr, "%s: no option required for \"%s\" flag\n", argv[0], arg);

optopt = '?';
}
}
break;
}
}

if (l_opts[i].name == NULL) {
/* exhausted all of the l_opts we have and still didn't match */
if (H5_opterr)
HDfprintf(stderr, "%s: unknown option \"%s\"\n", argv[0], arg);

optopt = '?';
}

H5_optind++;
sp = 1;

HDfree(arg);
}
else {
register char *cp; /* pointer into current token */

/* short command line option */
optopt = argv[H5_optind][sp];

if (optopt == ':' || (cp = HDstrchr(opts, optopt)) == 0) {
if (H5_opterr)
HDfprintf(stderr, "%s: unknown option \"%c\"\n", argv[0], optopt);

/* if no chars left in this token, move to next token */
if (argv[H5_optind][++sp] == '\0') {
H5_optind++;
sp = 1;
}
return '?';
}

if (*++cp == ':') {
/* if a value is expected, get it */
if (argv[H5_optind][sp + 1] != '\0') {
/* flag value is rest of current token */
H5_optarg = &argv[H5_optind++][sp + 1];
}
else if (++H5_optind >= argc) {
if (H5_opterr)
HDfprintf(stderr, "%s: value expected for option \"%c\"\n", argv[0], optopt);

optopt = '?';
}
else {
/* flag value is next token */
H5_optarg = argv[H5_optind++];
}

sp = 1;
}
/* wildcard argument */
else if (*cp == '*') {
/* check the next argument */
H5_optind++;
/* we do have an extra argument, check if not last */
if ((H5_optind + 1) < argc) {
if (argv[H5_optind][0] != '-') {
H5_optarg = argv[H5_optind++];
}
else {
H5_optarg = NULL;
}
}
else {
H5_optarg = NULL;
}
}
else {
/* set up to look at next char in token, next time */
if (argv[H5_optind][++sp] == '\0') {
/* no more in current token, so setup next token */
H5_optind++;
sp = 1;
}
H5_optarg = NULL;
}
}

/* return the current flag character found */
return optopt;
}
Loading

0 comments on commit 9550a98

Please sign in to comment.