1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
|
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
* University Research and Technology
* Corporation. All rights reserved.
* Copyright (c) 2004-2005 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
* University of Stuttgart. All rights reserved.
* Copyright (c) 2004-2005 The Regents of the University of California.
* All rights reserved.
* Copyright (c) 2012-2022 Cisco Systems, Inc. All rights reserved
* Copyright (c) 2015-2016 Intel, Inc. All rights reserved.
* Copyright (c) 2016-2017 Los Alamos National Security, LLC. All rights
* reserved.
* Copyright (c) 2017 IBM Corporation. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
/**
* @file
*
* General command line parsing facility for use throughout Open MPI.
*
* This scheme is inspired by the GNU getopt package. Command line
* options are registered. Each option can have up to three different
* matching tokens: a "short" name, a "single dash" name, and a "long"
* name. Each option can also take 0 or more arguments. Finally,
* each option can be repeated on the command line an arbitrary number
* of times.
*
* The "short" name can only be a single letter, and will be found
* after a single dash (e.g., "-a"). Multiple "short" names can be
* combined into a single command line argument (e.g., "-abc" can be
* equivalent to "-a -b -c").
*
* The "single dash" name is a multi-character name that only
* requires a single dash. This only exists to provide backwards
* compatibility for some well-known command line options in prior
* MPI implementations (e.g., "mpirun -np 3"). It should be used
* sparingly.
*
* The "long" name is a multi-character name that is found after a
* pair of dashes. For example, "--some-option-name".
*
* A command line option is a combination of 1 or more of a short
* name, single dash name, and a long name. Any of the names may be
* used on the command line; they are treated as synonyms. For
* example, say the following was used in for an executable named
* "foo":
*
* \code
* opal_cmd_line_make_opt3(cmd, 'a', NULL, 'add', 1, "Add a user");
* \endcode
*
* In this case, the following command lines are exactly equivalent:
*
* \verbatim
* shell$ foo -a jsmith
* shell$ foo --add jsmith
* \endverbatim
*
* Note that this interface can also track multiple invocations of the
* same option. For example, the following is both legal and able to
* be retrieved through this interface:
*
* \verbatim
* shell$ foo -a jsmith -add bjones
* \endverbatim
*
* The caller to this interface creates a command line handle
* (opal_cmd_line_t) with OBJ_NEW() and then uses it to register the
* desired parameters via opal_cmd_line_make_opt3(). Once all the
* parameters have been registered, the user invokes
* opal_cmd_line_parse() with the command line handle and the argv/argc
* pair to be parsed (typically the arguments from main()). The parser
* will examine the argv and find registered options and parameters.
* It will stop parsing when it runs into an recognized string token or
* the special "--" token.
*
* After the parse has occurred, various accessor functions can be
* used to determine which options were selected, what parameters were
* passed to them, etc.:
*
* - opal_cmd_line_get_usage_msg() returns a string suitable for "help"
* kinds of messages.
* - opal_cmd_line_is_taken() returns a true or false indicating
* whether a given command line option was found on the command
* line.
* - opal_cmd_line_get_argc() returns the number of tokens parsed on
* the handle.
* - opal_cmd_line_get_argv() returns any particular string from the
* original argv.
* - opal_cmd_line_get_ninsts() returns the number of times a
* particular option was found on a command line.
* - opal_cmd_line_get_param() returns the Nth parameter in the Mth
* instance of a given parameter.
* - opal_cmd_line_get_tail() returns an array of tokens not parsed
* (i.e., if the parser ran into "--" or an unrecognized token).
*
* Note that a shortcut to creating a large number of options exists
* -- one can make a table of opal_cmd_line_init_t instances and the
* table to opal_cmd_line_create(). This creates an opal_cmd_line_t
* handle that is pre-seeded with all the options from the table
* without the need to repeatedly invoke opal_cmd_line_make_opt3() (or
* equivalent). This opal_cmd_line_t instance is just like any other;
* it is still possible to add more options via
* opal_cmd_line_make_opt3(), etc.
*/
#ifndef OPAL_CMD_LINE_H
#define OPAL_CMD_LINE_H
#include "opal_config.h"
#include "opal/class/opal_list.h"
#include "opal/class/opal_object.h"
#include "opal/mca/threads/mutex.h"
BEGIN_C_DECLS
/**
* \internal
*
* Main top-level handle. This interface should not be used by users!
*/
struct opal_cmd_line_t {
/** Make this an OBJ handle */
opal_object_t super;
/** Thread safety */
opal_recursive_mutex_t lcl_mutex;
/** List of ompi_cmd_line_option_t's (defined internally) */
opal_list_t lcl_options;
/** Duplicate of argc from opal_cmd_line_parse() */
int lcl_argc;
/** Duplicate of argv from opal_cmd_line_parse() */
char **lcl_argv;
/** Parsed output; list of ompi_cmd_line_param_t's (defined internally) */
opal_list_t lcl_params;
/** List of tail (unprocessed) arguments */
int lcl_tail_argc;
/** List of tail (unprocessed) arguments */
char **lcl_tail_argv;
};
/**
* \internal
*
* Convenience typedef
*/
typedef struct opal_cmd_line_t opal_cmd_line_t;
/**
* Data types supported by the parser
*/
enum opal_cmd_line_type_t {
OPAL_CMD_LINE_TYPE_NULL,
OPAL_CMD_LINE_TYPE_STRING,
OPAL_CMD_LINE_TYPE_INT,
OPAL_CMD_LINE_TYPE_SIZE_T,
OPAL_CMD_LINE_TYPE_BOOL,
OPAL_CMD_LINE_TYPE_MAX
};
/**
* \internal
*
* Convenience typedef
*/
typedef enum opal_cmd_line_type_t opal_cmd_line_type_t;
/**
* Command line option type, for use in
* mpirun --help output.
*/
enum opal_cmd_line_otype_t {
OPAL_CMD_LINE_OTYPE_GENERAL, /* This type is shown via --help by
default (i.e., if no arg is
specified to narrow the help
scope) */
OPAL_CMD_LINE_OTYPE_DEBUG,
OPAL_CMD_LINE_OTYPE_OUTPUT,
OPAL_CMD_LINE_OTYPE_INPUT,
OPAL_CMD_LINE_OTYPE_MAPPING,
OPAL_CMD_LINE_OTYPE_RANKING,
OPAL_CMD_LINE_OTYPE_BINDING,
OPAL_CMD_LINE_OTYPE_DEVEL,
OPAL_CMD_LINE_OTYPE_COMPAT, /* Backwards compatibility */
OPAL_CMD_LINE_OTYPE_LAUNCH,
OPAL_CMD_LINE_OTYPE_DVM,
OPAL_CMD_LINE_OTYPE_UNSUPPORTED,
OPAL_CMD_LINE_OTYPE_PARSABLE,
OPAL_CMD_LINE_OTYPE_NULL /* include in full help only */
};
/**
* \internal
*
* Convenience typedef
*/
typedef enum opal_cmd_line_otype_t opal_cmd_line_otype_t;
/**
* Datatype used to construct a command line handle; see
* opal_cmd_line_create().
*/
struct opal_cmd_line_init_t {
/** If want to set an MCA parameter, set its parameter name
here. */
const char *ocl_mca_param_name;
/** "Short" name (i.e., "-X", where "X" is a single letter) */
char ocl_cmd_short_name;
/** "Single dash" name (i.e., "-foo"). The use of these are
discouraged. */
const char *ocl_cmd_single_dash_name;
/** Long name (i.e., "--foo"). */
const char *ocl_cmd_long_name;
/** Number of parameters that this option takes */
int ocl_num_params;
/** If this parameter is encountered, its *first* parameter it
saved here. If the parameter is encountered again, the
value is overwritten. */
void *ocl_variable_dest;
/** If an ocl_variable_dest is given, its datatype must be
supplied as well. */
opal_cmd_line_type_t ocl_variable_type;
/** Description of the command line option, to be used with
opal_cmd_line_get_usage_msg(). */
const char *ocl_description;
/** Category for mpirun --help output */
opal_cmd_line_otype_t ocl_otype;
};
/**
* \internal
*
* Convenience typedef
*/
typedef struct opal_cmd_line_init_t opal_cmd_line_init_t;
/**
* Top-level command line handle.
*
* This handle is used for accessing all command line functionality
* (i.e., all opal_cmd_line*() functions). Multiple handles can be
* created and simultaneously processed; each handle is independent
* from others.
*
* The opal_cmd_line_t handles are [simplisticly] thread safe;
* processing is guaranteed to be mutually exclusive if multiple
* threads invoke functions on the same handle at the same time --
* access will be serialized in an unspecified order.
*
* Once finished, handles should be released with OBJ_RELEASE(). The
* destructor for opal_cmd_line_t handles will free all memory
* associated with the handle.
*/
OPAL_DECLSPEC OBJ_CLASS_DECLARATION(opal_cmd_line_t);
/**
* Make a command line handle from a table of initializers.
*
* @param cmd OPAL command line handle.
* @param table Table of opal_cmd_line_init_t instances for all
* the options to be included in the resulting command line
* handler.
*
* @retval OPAL_SUCCESS Upon success.
*
* This function takes a table of opal_cmd_line_init_t instances
* to pre-seed an OPAL command line handle. The last instance in
* the table must have '\0' for the short name and NULL for the
* single-dash and long names. The handle is expected to have
* been OBJ_NEW'ed or OBJ_CONSTRUCT'ed already.
*
* Upon return, the command line handle is just like any other. A
* sample using this syntax:
*
* \code
* opal_cmd_line_init_t cmd_line_init[] = {
* { NULL, 'h', NULL, "help", 0,
* &orterun_globals.help, OPAL_CMD_LINE_TYPE_BOOL,
* "This help message", OPAL_CMD_LINE_OTYPE_GENERAL },
*
* { NULL, '\0', NULL, "wd", 1,
* &orterun_globals.wd, OPAL_CMD_LINE_TYPE_STRING,
* "Set the working directory of the started processes",
* OPAL_CMD_LINE_OTYPE_LAUNCH },
*
* { NULL, '\0', NULL, NULL, 0,
* NULL, OPAL_CMD_LINE_TYPE_NULL, NULL, OPAL_CMD_LINE_OTYPE_NULL }
* };
* \endcode
*/
OPAL_DECLSPEC int opal_cmd_line_create(opal_cmd_line_t *cmd, opal_cmd_line_init_t *table);
/* Add a table of opal_cmd_line_init_t instances
* to an existing OPAL command line handle.
*
* Multiple calls to opal_cmd_line_add are permitted - each
* subsequent call will simply append new options to the existing
* handle. Note that any duplicates will return an error.
*/
OPAL_DECLSPEC int opal_cmd_line_add(opal_cmd_line_t *cmd, opal_cmd_line_init_t *table);
/**
* Create a command line option.
*
* @param cmd OPAL command line handle.
* @param entry Command line entry to add to the command line.
*
* @retval OPAL_SUCCESS Upon success.
*
*/
OPAL_DECLSPEC int opal_cmd_line_make_opt_mca(opal_cmd_line_t *cmd, opal_cmd_line_init_t entry);
/**
* Create a command line option.
*
* @param cmd OPAL command line handle.
* @param short_name "Short" name of the command line option.
* @param sd_name "Single dash" name of the command line option.
* @param long_name "Long" name of the command line option.
* @param num_params How many parameters this option takes.
* @param dest Short string description of this option.
*
* @retval OPAL_ERR_OUT_OF_RESOURCE If out of memory.
* @retval OPAL_ERR_BAD_PARAM If bad parameters passed.
* @retval OPAL_SUCCESS Upon success.
*
* Adds a command line option to the list of options that an OPAL
* command line handle will accept. The short_name may take the
* special value '\0' to not have a short name. Likewise, the
* sd_name and long_name may take the special value NULL to not have
* a single dash or long name, respectively. However, one of the
* three must have a name.
*
* num_params indicates how many parameters this option takes. It
* must be greater than or equal to 0.
*
* Finally, desc is a short string description of this option. It is
* used to generate the output from opal_cmd_line_get_usage_msg().
*
*/
OPAL_DECLSPEC int opal_cmd_line_make_opt3(opal_cmd_line_t *cmd, char short_name,
const char *sd_name, const char *long_name,
int num_params, const char *desc);
/**
* Parse a command line according to a pre-built OPAL command line
* handle.
*
* @param cmd OPAL command line handle.
* @param ignore_unknown Whether to print an error message upon
* finding an unknown token or not
* @param ignore_unknown_option Whether to print an error message upon
* finding an unknown option or not
* @param argc Length of the argv array.
* @param argv Array of strings from the command line.
*
* @retval OPAL_SUCCESS Upon success.
* @retval OPAL_ERR_SILENT If an error message was printed. This
* value will only be returned if the command line was not
* successfully parsed.
*
* Parse a series of command line tokens according to the option
* descriptions from a OPAL command line handle. The OPAL command line
* handle can then be queried to see what options were used, what
* their parameters were, etc.
*
* If an unknown token is found in the command line (i.e., a token
* that is not a parameter or a registered option), the parsing will
* stop (see below). If ignore_unknown is false, an error message
* is displayed. If ignore_unknown is true, the error message is
* not displayed.
*
* Error messages are always displayed regardless of the value
* of ignore_unknown (to stderr, and OPAL_ERR_SILENT is
* returned) if:
*
* 1. A token was encountered that required N parameters, but <N
* parameters were found (e.g., "cmd --param foo", but --param was
* registered to require 2 option tokens).
*
* 2. An unknown token beginning with "-" is encountered. For
* example, if "--fo" is specified, and no "fo" option is
* registered (e.g., perhaps the user meant to type "--foo"), an
* error message is always printed, UNLESS this unknown token
* happens after a "--" token (see below).
*
* The contents of argc and argv are not changed during parsing.
* argv[0] is assumed to be the executable name, and is ignored during
* parsing, except when printing error messages.
*
* Parsing will stop in the following conditions:
*
* - all argv tokens are processed
* - the token "--" is found
* - an unrecognized token is found
* - a parameter registered with an integer type option finds a
* non-integer option token
* - a parameted registered N option tokens, but finds less then
* <N tokens available
*
* Upon any of these conditions, any remaining tokens will be placed
* in the "tail" (and therefore not examined by the parser),
* regardless of the value of ignore_unknown. The set of tail
* tokens is available from the opal_cmd_line_get_tail() function.
*
* Note that "--" is ignored if it is found in the middle an expected
* number of arguments. For example, if "--foo" is expected to have 3
* arguments, and the command line is:
*
* executable --foo a b -- other arguments
*
* This will result in an error, because "--" will be parsed as the
* third parameter to the first instance of "foo", and "other" will be
* an unrecognized option.
*
* Note that -- can be used to allow unknown tokens that begin
* with "-". For example, if a user wants to mpirun an executable
* named "-my-mpi-program", the "usual" way:
*
* mpirun -my-mpi-program
*
* will cause an error, because mpirun won't find single-letter
* options registered for some/all of those letters. But two
* workarounds are possible:
*
* mpirun -- -my-mpi-program
* or
* mpirun ./-my-mpi-program
*
* Finally, note that invoking this function multiple times on
* different sets of argv tokens is safe, but will erase any
* previous parsing results.
*/
OPAL_DECLSPEC int opal_cmd_line_parse(opal_cmd_line_t *cmd, bool ignore_unknown,
bool ignore_unknown_option, int argc, char **argv);
/**
* Return a consolidated "usage" message for a OPAL command line handle.
*
* @param cmd OPAL command line handle.
*
* @retval str Usage message.
*
* Returns a formatted string suitable for printing that lists the
* expected usage message and a short description of each option on
* the OPAL command line handle. Options that passed a NULL
* description to opal_cmd_line_make_opt3() will not be included in the
* display (to allow for undocumented options).
*
* This function is typically only invoked internally by the
* opal_show_help() function.
*
* This function should probably be fixed up to produce prettier
* output.
*
* The returned string must be freed by the caller.
*/
OPAL_DECLSPEC char *opal_cmd_line_get_usage_msg(opal_cmd_line_t *cmd)
__opal_attribute_malloc__ __opal_attribute_warn_unused_result__;
/**
* Test if a given option was taken on the parsed command line.
*
* @param cmd OPAL command line handle.
* @param opt Short or long name of the option to check for.
*
* @retval true If the command line option was found during
* opal_cmd_line_parse().
*
* @retval false If the command line option was not found during
* opal_cmd_line_parse(), or opal_cmd_line_parse() was not invoked on
* this handle.
*
* This function should only be called after opal_cmd_line_parse().
*
* The function will return true if the option matching opt was found
* (either by its short or long name) during token parsing.
* Otherwise, it will return false.
*/
OPAL_DECLSPEC bool opal_cmd_line_is_taken(opal_cmd_line_t *cmd, const char *opt)
__opal_attribute_nonnull__(1) __opal_attribute_nonnull__(2);
/**
* Return the number of arguments parsed on a OPAL command line handle.
*
* @param cmd A pointer to the OPAL command line handle.
*
* @retval OPAL_ERROR If cmd is NULL.
* @retval argc Number of arguments previously added to the handle.
*
* Arguments are added to the handle via the opal_cmd_line_parse()
* function.
*/
OPAL_DECLSPEC int opal_cmd_line_get_argc(opal_cmd_line_t *cmd) __opal_attribute_unused__;
/**
* Return a string argument parsed on a OPAL command line handle.
*
* @param cmd A pointer to the OPAL command line handle.
* @param index The nth argument from the command line (0 is
* argv[0], etc.).
*
* @retval NULL If cmd is NULL or index is invalid
* @retval argument String of original argv[index]
*
* This function returns a single token from the arguments parsed
* on this handle. Arguments are added bia the
* opal_cmd_line_parse() function.
*
* What is returned is a pointer to the actual string that is on
* the handle; it should not be modified or freed.
*/
OPAL_DECLSPEC char *opal_cmd_line_get_argv(opal_cmd_line_t *cmd, int index);
/**
* Return the number of instances of an option found during parsing.
*
* @param cmd OPAL command line handle.
* @param opt Short or long name of the option to check for.
*
* @retval num Number of instances (to include 0) of a given potion
* found during opal_cmd_line_parse().
*
* @retval OPAL_ERR If the command line option was not found during
* opal_cmd_line_parse(), or opal_cmd_line_parse() was not invoked on
* this handle.
*
* This function should only be called after opal_cmd_line_parse().
*
* The function will return the number of instances of a given option
* (either by its short or long name) -- to include 0 -- or OPAL_ERR if
* either the option was not specified as part of the OPAL command line
* handle, or opal_cmd_line_parse() was not invoked on this handle.
*/
OPAL_DECLSPEC int opal_cmd_line_get_ninsts(opal_cmd_line_t *cmd, const char *opt)
__opal_attribute_nonnull__(1) __opal_attribute_nonnull__(2);
/**
* Return a specific parameter for a specific instance of a option
* from the parsed command line.
*
* @param cmd OPAL command line handle.
* @param opt Short or long name of the option to check for.
* @param instance_num Instance number of the option to query.
* @param param_num Which parameter to return.
*
* @retval param String of the parameter.
* @retval NULL If any of the input values are invalid.
*
* This function should only be called after opal_cmd_line_parse().
*
* This function returns the Nth parameter for the Ith instance of a
* given option on the parsed command line (both N and I are
* zero-indexed). For example, on the command line:
*
* executable --foo bar1 bar2 --foo bar3 bar4
*
* The call to opal_cmd_line_get_param(cmd, "foo", 1, 1) would return
* "bar4". opal_cmd_line_get_param(cmd, "bar", 0, 0) would return
* NULL, as would opal_cmd_line_get_param(cmd, "foo", 2, 2);
*
* The returned string should \em not be modified or freed by the
* caller.
*/
OPAL_DECLSPEC char *opal_cmd_line_get_param(opal_cmd_line_t *cmd, const char *opt, int instance_num,
int param_num);
/**
* Return the entire "tail" of unprocessed argv from a OPAL
* command line handle.
*
* @param cmd A pointer to the OPAL command line handle.
* @param tailc Pointer to the output length of the null-terminated
* tail argv array.
* @param tailv Pointer to the output null-terminated argv of all
* unprocessed arguments from the command line.
*
* @retval OPAL_ERROR If cmd is NULL or otherwise invalid.
* @retval OPAL_SUCCESS Upon success.
*
* The "tail" is all the arguments on the command line that were
* not processed for some reason. Reasons for not processing
* arguments include:
*
* \sa The argument was not recognized
* \sa The argument "--" was seen, and therefore all arguments
* following it were not processed
*
* The output tailc parameter will be filled in with the integer
* length of the null-terminated tailv array (length including the
* final NULL entry). The output tailv parameter will be a copy
* of the tail parameters, and must be freed (likely with a call
* to opal_argv_free()) by the caller.
*/
OPAL_DECLSPEC int opal_cmd_line_get_tail(opal_cmd_line_t *cmd, int *tailc, char ***tailv);
END_C_DECLS
#endif /* OPAL_CMD_LINE_H */
|