/* -*- 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