root/opal/mca/pmix/pmix4x/pmix/src/util/cmd_line.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. find_option
  2. pmix_cmd_line_add
  3. pmix_cmd_line_make_opt_mca
  4. pmix_cmd_line_make_opt3
  5. pmix_cmd_line_parse
  6. pmix_cmd_line_get_usage_msg
  7. pmix_cmd_line_is_taken
  8. pmix_cmd_line_get_ninsts
  9. pmix_cmd_line_get_param
  10. pmix_cmd_line_get_argc
  11. pmix_cmd_line_get_argv
  12. pmix_cmd_line_get_tail
  13. option_constructor
  14. option_destructor
  15. param_constructor
  16. param_destructor
  17. cmd_line_constructor
  18. cmd_line_destructor
  19. make_opt
  20. free_parse_results
  21. split_shorts
  22. find_option
  23. set_dest
  24. fill
  25. qsort_callback
  26. get_help_otype
  27. build_parsable

   1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
   2 /*
   3  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
   4  *                         University Research and Technology
   5  *                         Corporation.  All rights reserved.
   6  * Copyright (c) 2004-2013 The University of Tennessee and The University
   7  *                         of Tennessee Research Foundation.  All rights
   8  *                         reserved.
   9  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
  10  *                         University of Stuttgart.  All rights reserved.
  11  * Copyright (c) 2004-2005 The Regents of the University of California.
  12  *                         All rights reserved.
  13  * Copyright (c) 2012-2017 Los Alamos National Security, LLC. All rights
  14  *                         reserved.
  15  * Copyright (c) 2012-2015 Cisco Systems, Inc.  All rights reserved.
  16  * Copyright (c) 2015-2017 Research Organization for Information Science
  17  *                         and Technology (RIST). All rights reserved.
  18  * Copyright (c) 2016-2019 Intel, Inc.  All rights reserved.
  19  * Copyright (c) 2017      IBM Corporation. All rights reserved.
  20  * $COPYRIGHT$
  21  *
  22  * Additional copyrights may follow
  23  *
  24  * $HEADER$
  25  */
  26 
  27 #include "pmix_config.h"
  28 
  29 #include <stdio.h>
  30 #include <string.h>
  31 #include <ctype.h>
  32 
  33 #include "src/class/pmix_object.h"
  34 #include "src/class/pmix_list.h"
  35 #include "src/threads/mutex.h"
  36 #include "src/util/argv.h"
  37 #include "src/util/cmd_line.h"
  38 #include "src/util/output.h"
  39 #include "src/util/pmix_environ.h"
  40 
  41 #include "src/mca/base/pmix_mca_base_var.h"
  42 #include "pmix_common.h"
  43 
  44 
  45 /*
  46  * Some usage message constants
  47  *
  48  * Max width for param listings before the description will be listed
  49  * on the next line
  50  */
  51 #define PARAM_WIDTH 25
  52 /*
  53  * Max length of any line in the usage message
  54  */
  55 #define MAX_WIDTH 76
  56 
  57 /*
  58  * Description of a command line option
  59  */
  60 struct pmix_cmd_line_option_t {
  61     pmix_list_item_t super;
  62 
  63     char clo_short_name;
  64     char *clo_single_dash_name;
  65     char *clo_long_name;
  66 
  67     int clo_num_params;
  68     char *clo_description;
  69 
  70     pmix_cmd_line_type_t clo_type;
  71     char *clo_mca_param_env_var;
  72     void *clo_variable_dest;
  73     bool clo_variable_set;
  74     pmix_cmd_line_otype_t clo_otype;
  75 };
  76 typedef struct pmix_cmd_line_option_t pmix_cmd_line_option_t;
  77 static void option_constructor(pmix_cmd_line_option_t *cmd);
  78 static void option_destructor(pmix_cmd_line_option_t *cmd);
  79 
  80 PMIX_CLASS_INSTANCE(pmix_cmd_line_option_t,
  81                     pmix_list_item_t,
  82                     option_constructor, option_destructor);
  83 
  84 /*
  85  * An option that was used in the argv that was parsed
  86  */
  87 struct pmix_cmd_line_param_t {
  88     pmix_list_item_t super;
  89 
  90     /* Note that clp_arg points to storage "owned" by someone else; it
  91        has the original option string by referene, not by value.
  92        Hence, it should not be free()'ed. */
  93 
  94     char *clp_arg;
  95 
  96     /* Pointer to the existing option.  This is also by reference; it
  97        should not be free()ed. */
  98 
  99     pmix_cmd_line_option_t *clp_option;
 100 
 101     /* This argv array is a list of all the parameters of this option.
 102        It is owned by this parameter, and should be freed when this
 103        param_t is freed. */
 104 
 105     int clp_argc;
 106     char **clp_argv;
 107 };
 108 typedef struct pmix_cmd_line_param_t pmix_cmd_line_param_t;
 109 static void param_constructor(pmix_cmd_line_param_t *cmd);
 110 static void param_destructor(pmix_cmd_line_param_t *cmd);
 111 PMIX_CLASS_INSTANCE(pmix_cmd_line_param_t,
 112                     pmix_list_item_t,
 113                     param_constructor, param_destructor);
 114 
 115 /*
 116  * Instantiate the pmix_cmd_line_t class
 117  */
 118 static void cmd_line_constructor(pmix_cmd_line_t *cmd);
 119 static void cmd_line_destructor(pmix_cmd_line_t *cmd);
 120 PMIX_CLASS_INSTANCE(pmix_cmd_line_t,
 121                     pmix_object_t,
 122                     cmd_line_constructor,
 123                     cmd_line_destructor);
 124 
 125 /*
 126  * Private variables
 127  */
 128 static char special_empty_token[] = {
 129     1, 2, 3, 4, 5, 6, 7, 8, 9, 10, '\0'
 130 };
 131 
 132 /*
 133  * Private functions
 134  */
 135 static int make_opt(pmix_cmd_line_t *cmd, pmix_cmd_line_init_t *e);
 136 static void free_parse_results(pmix_cmd_line_t *cmd);
 137 static int split_shorts(pmix_cmd_line_t *cmd,
 138                         char *token, char **args,
 139                         int *output_argc, char ***output_argv,
 140                         int *num_args_used, bool ignore_unknown);
 141 static pmix_cmd_line_option_t *find_option(pmix_cmd_line_t *cmd,
 142                                            const char *option_name) __pmix_attribute_nonnull__(1) __pmix_attribute_nonnull__(2);
 143 static int set_dest(pmix_cmd_line_option_t *option, char *sval);
 144 static void fill(const pmix_cmd_line_option_t *a, char result[3][BUFSIZ]);
 145 static int qsort_callback(const void *a, const void *b);
 146 static pmix_cmd_line_otype_t get_help_otype(pmix_cmd_line_t *cmd);
 147 static char *build_parsable(pmix_cmd_line_option_t *option);
 148 
 149 
 150 /*
 151  * Create an entire command line handle from a table
 152  */
 153 int pmix_cmd_line_create(pmix_cmd_line_t *cmd,
 154                          pmix_cmd_line_init_t *table)
 155 {
 156     int ret = PMIX_SUCCESS;
 157 
 158     /* Check bozo case */
 159 
 160     if (NULL == cmd) {
 161         return PMIX_ERR_BAD_PARAM;
 162     }
 163     PMIX_CONSTRUCT(cmd, pmix_cmd_line_t);
 164 
 165     if (NULL != table) {
 166         ret = pmix_cmd_line_add(cmd, table);
 167     }
 168     return ret;
 169 }
 170 
 171 /* Add a table to an existing cmd line object */
 172 int pmix_cmd_line_add(pmix_cmd_line_t *cmd,
 173                       pmix_cmd_line_init_t *table)
 174 {
 175     int i, ret;
 176 
 177     /* Ensure we got a table */
 178     if (NULL == table) {
 179         return PMIX_SUCCESS;
 180     }
 181 
 182     /* Loop through the table */
 183 
 184     for (i = 0; ; ++i) {
 185         /* Is this the end? */
 186         if ('\0' == table[i].ocl_cmd_short_name &&
 187             NULL == table[i].ocl_cmd_single_dash_name &&
 188             NULL == table[i].ocl_cmd_long_name) {
 189             break;
 190         }
 191 
 192         /* Nope -- it's an entry.  Process it. */
 193         ret = make_opt(cmd, &table[i]);
 194         if (PMIX_SUCCESS != ret) {
 195             return ret;
 196         }
 197     }
 198 
 199     return PMIX_SUCCESS;
 200 }
 201 /*
 202  * Append a command line entry to the previously constructed command line
 203  */
 204 int pmix_cmd_line_make_opt_mca(pmix_cmd_line_t *cmd,
 205                                pmix_cmd_line_init_t entry)
 206 {
 207     /* Ensure we got an entry */
 208     if ('\0' == entry.ocl_cmd_short_name &&
 209         NULL == entry.ocl_cmd_single_dash_name &&
 210         NULL == entry.ocl_cmd_long_name) {
 211         return PMIX_SUCCESS;
 212     }
 213 
 214     return make_opt(cmd, &entry);
 215 }
 216 
 217 
 218 /*
 219  * Create a command line option, --long-name and/or -s (short name).
 220  */
 221 int pmix_cmd_line_make_opt3(pmix_cmd_line_t *cmd, char short_name,
 222                             const char *sd_name, const char *long_name,
 223                             int num_params, const char *desc)
 224 {
 225     pmix_cmd_line_init_t e;
 226 
 227     e.ocl_mca_param_name = NULL;
 228 
 229     e.ocl_cmd_short_name = short_name;
 230     e.ocl_cmd_single_dash_name = sd_name;
 231     e.ocl_cmd_long_name = long_name;
 232 
 233     e.ocl_num_params = num_params;
 234 
 235     e.ocl_variable_dest = NULL;
 236     e.ocl_variable_type = PMIX_CMD_LINE_TYPE_NULL;
 237 
 238     e.ocl_description = desc;
 239 
 240     return make_opt(cmd, &e);
 241 }
 242 
 243 
 244 /*
 245  * Parse a command line according to a pre-built PMIX command line
 246  * handle.
 247  */
 248 int pmix_cmd_line_parse(pmix_cmd_line_t *cmd, bool ignore_unknown, bool ignore_unknown_option,
 249                         int argc, char **argv)
 250 {
 251     int i, j, orig, ret;
 252     pmix_cmd_line_option_t *option;
 253     pmix_cmd_line_param_t *param;
 254     bool is_unknown_option;
 255     bool is_unknown_token;
 256     bool is_option;
 257     char **shortsv;
 258     int shortsc;
 259     int num_args_used;
 260     bool have_help_option = false;
 261     bool printed_error = false;
 262     bool help_without_arg = false;
 263 
 264     /* Bozo check */
 265 
 266     if (0 == argc || NULL == argv) {
 267         return PMIX_SUCCESS;
 268     }
 269 
 270     /* Thread serialization */
 271 
 272     pmix_mutex_lock(&cmd->lcl_mutex);
 273 
 274     /* Free any parsed results that are already on this handle */
 275 
 276     free_parse_results(cmd);
 277 
 278     /* Analyze each token */
 279 
 280     cmd->lcl_argc = argc;
 281     cmd->lcl_argv = pmix_argv_copy(argv);
 282 
 283     /* Check up front: do we have a --help option? */
 284 
 285     option = find_option(cmd, "help");
 286     if (NULL != option) {
 287         have_help_option = true;
 288     }
 289 
 290     /* Now traverse the easy-to-parse sequence of tokens.  Note that
 291        incrementing i must happen elsehwere; it can't be the third
 292        clause in the "if" statement. */
 293 
 294     param = NULL;
 295     option = NULL;
 296     for (i = 1; i < cmd->lcl_argc; ) {
 297         is_unknown_option = false;
 298         is_unknown_token = false;
 299         is_option = false;
 300 
 301         /* Are we done?  i.e., did we find the special "--" token?  If
 302            so, copy everying beyond it into the tail (i.e., don't
 303            bother copying the "--" into the tail). */
 304 
 305         if (0 == strcmp(cmd->lcl_argv[i], "--")) {
 306             ++i;
 307             while (i < cmd->lcl_argc) {
 308                 pmix_argv_append(&cmd->lcl_tail_argc, &cmd->lcl_tail_argv,
 309                                  cmd->lcl_argv[i]);
 310                 ++i;
 311             }
 312 
 313             break;
 314         }
 315 
 316         /* If it's not an option, then this is an error.  Note that
 317            this is different than an unrecognized token; an
 318            unrecognized option is *always* an error. */
 319 
 320         else if ('-' != cmd->lcl_argv[i][0]) {
 321             is_unknown_token = true;
 322         }
 323 
 324         /* Nope, this is supposedly an option.  Is it a long name? */
 325 
 326         else if (0 == strncmp(cmd->lcl_argv[i], "--", 2)) {
 327             is_option = true;
 328             option = find_option(cmd, cmd->lcl_argv[i] + 2);
 329         }
 330 
 331         /* It could be a short name.  Is it? */
 332 
 333         else {
 334             option = find_option(cmd, cmd->lcl_argv[i] + 1);
 335 
 336             /* If we didn't find it, try to split it into shorts.  If
 337                we find the short option, replace lcl_argv[i] and
 338                insert the rest into lcl_argv starting after position
 339                i.  If we don't find the short option, don't do
 340                anything to lcl_argv so that it can fall through to the
 341                error condition, below. */
 342 
 343             if (NULL == option) {
 344                 shortsv = NULL;
 345                 shortsc = 0;
 346                 ret = split_shorts(cmd, cmd->lcl_argv[i] + 1,
 347                                    &(cmd->lcl_argv[i + 1]),
 348                                    &shortsc, &shortsv,
 349                                    &num_args_used, ignore_unknown);
 350                 if (PMIX_SUCCESS == ret) {
 351                     option = find_option(cmd, shortsv[0] + 1);
 352 
 353                     if (NULL != option) {
 354                         pmix_argv_delete(&cmd->lcl_argc,
 355                                          &cmd->lcl_argv, i,
 356                                          1 + num_args_used);
 357                         pmix_argv_insert(&cmd->lcl_argv, i, shortsv);
 358                         cmd->lcl_argc = pmix_argv_count(cmd->lcl_argv);
 359                     } else {
 360                         is_unknown_option = true;
 361                     }
 362                     pmix_argv_free(shortsv);
 363                 } else {
 364                     is_unknown_option = true;
 365                 }
 366             }
 367 
 368             if (NULL != option) {
 369                 is_option = true;
 370             }
 371         }
 372 
 373         /* If we figured out above that this is an option, handle it */
 374 
 375         if (is_option) {
 376             if (NULL == option) {
 377                 is_unknown_option = true;
 378             } else {
 379                 is_unknown_option = false;
 380                 orig = i;
 381                 ++i;
 382 
 383                 /* Suck down the following parameters that belong to
 384                    this option.  If we run out of parameters, or find
 385                    that any of them are the special_empty_param
 386                    (insertted by split_shorts()), then print an error
 387                    and return. */
 388 
 389                 param = PMIX_NEW(pmix_cmd_line_param_t);
 390                 if (NULL == param) {
 391                     pmix_mutex_unlock(&cmd->lcl_mutex);
 392                     return PMIX_ERR_OUT_OF_RESOURCE;
 393                 }
 394                 param->clp_arg = cmd->lcl_argv[i];
 395                 param->clp_option = option;
 396 
 397                 /* If we have any parameters to this option, suck down
 398                    tokens starting one beyond the token that we just
 399                    recognized */
 400 
 401                 for (j = 0; j < option->clo_num_params; ++j, ++i) {
 402                     /* If we run out of parameters, error, unless its a help request
 403                        which can have 0 or 1 arguments */
 404                     if (i >= cmd->lcl_argc) {
 405                     /* If this is a help request, can have no arguments */
 406                         if((NULL != option->clo_single_dash_name &&
 407                            0 == strcmp(option->clo_single_dash_name, "h")) ||
 408                            (NULL != option->clo_long_name &&
 409                            0 == strcmp(option->clo_long_name, "help"))) {
 410                             help_without_arg = true;
 411                             continue;
 412                         }
 413                         fprintf(stderr, "%s: Error: option \"%s\" did not "
 414                                 "have enough parameters (%d)\n",
 415                                 cmd->lcl_argv[0],
 416                                 cmd->lcl_argv[orig],
 417                                 option->clo_num_params);
 418                         if (have_help_option) {
 419                             fprintf(stderr, "Type '%s --help' for usage.\n",
 420                                     cmd->lcl_argv[0]);
 421                         }
 422                         PMIX_RELEASE(param);
 423                         printed_error = true;
 424                         goto error;
 425                     } else {
 426                         if (0 == strcmp(cmd->lcl_argv[i],
 427                                         special_empty_token)) {
 428                             fprintf(stderr, "%s: Error: option \"%s\" did not "
 429                                     "have enough parameters (%d)\n",
 430                                     cmd->lcl_argv[0],
 431                                     cmd->lcl_argv[orig],
 432                                     option->clo_num_params);
 433                             if (have_help_option) {
 434                                 fprintf(stderr, "Type '%s --help' for usage.\n",
 435                                         cmd->lcl_argv[0]);
 436                             }
 437                             if (NULL != param->clp_argv) {
 438                                 pmix_argv_free(param->clp_argv);
 439                             }
 440                             PMIX_RELEASE(param);
 441                             printed_error = true;
 442                             goto error;
 443                         }
 444 
 445                         /* Otherwise, save this parameter */
 446 
 447                         else {
 448                             /* Save in the argv on the param entry */
 449 
 450                             pmix_argv_append(&param->clp_argc,
 451                                              &param->clp_argv,
 452                                              cmd->lcl_argv[i]);
 453 
 454                             /* If it's the first, save it in the
 455                                variable dest and/or MCA parameter */
 456 
 457                             if (0 == j &&
 458                                 (NULL != option->clo_mca_param_env_var ||
 459                                  NULL != option->clo_variable_dest)) {
 460                                 if (PMIX_SUCCESS != (ret = set_dest(option, cmd->lcl_argv[i]))) {
 461                                     pmix_mutex_unlock(&cmd->lcl_mutex);
 462                                     return ret;
 463                                 }
 464                             }
 465                         }
 466                     }
 467                 }
 468 
 469                 /* If there are no options to this command or it is
 470                    a help request with no argument, see if we need to
 471                    set a boolean value to "true". */
 472 
 473                 if (0 == option->clo_num_params || help_without_arg) {
 474                     if (PMIX_SUCCESS != (ret = set_dest(option, "1"))) {
 475                         pmix_mutex_unlock(&cmd->lcl_mutex);
 476                         return ret;
 477                     }
 478                 }
 479 
 480                 /* If we succeeded in all that, save the param to the
 481                    list on the pmix_cmd_line_t handle */
 482 
 483                 if (NULL != param) {
 484                     pmix_list_append(&cmd->lcl_params, &param->super);
 485                 }
 486             }
 487         }
 488 
 489         /* If we figured out above that this was an unknown option,
 490            handle it.  Copy everything (including the current token)
 491            into the tail.  If we're not ignoring unknowns, then print
 492            an error and return. */
 493         if (is_unknown_option || is_unknown_token) {
 494             if (!ignore_unknown || (is_unknown_option && !ignore_unknown_option)) {
 495                 fprintf(stderr, "%s: Error: unknown option \"%s\"\n",
 496                         cmd->lcl_argv[0], cmd->lcl_argv[i]);
 497                 printed_error = true;
 498                 if (have_help_option) {
 499                     fprintf(stderr, "Type '%s --help' for usage.\n",
 500                             cmd->lcl_argv[0]);
 501                 }
 502             }
 503         error:
 504             while (i < cmd->lcl_argc) {
 505                 pmix_argv_append(&cmd->lcl_tail_argc, &cmd->lcl_tail_argv,
 506                                  cmd->lcl_argv[i]);
 507                 ++i;
 508             }
 509 
 510             /* Because i has advanced, we'll fall out of the loop */
 511         }
 512     }
 513 
 514     /* Thread serialization */
 515 
 516     pmix_mutex_unlock(&cmd->lcl_mutex);
 517 
 518     /* All done */
 519     if (printed_error) {
 520         return PMIX_ERR_SILENT;
 521     }
 522 
 523     return PMIX_SUCCESS;
 524 }
 525 
 526 
 527 /*
 528  * Return a consolidated "usage" message for a PMIX command line handle.
 529  */
 530 char *pmix_cmd_line_get_usage_msg(pmix_cmd_line_t *cmd)
 531 {
 532     size_t i, len;
 533     int argc;
 534     size_t j;
 535     char **argv;
 536     char *ret, temp[MAX_WIDTH * 2], line[MAX_WIDTH * 2];
 537     char *start, *desc, *ptr;
 538     pmix_list_item_t *item;
 539     pmix_cmd_line_option_t *option, **sorted;
 540     pmix_cmd_line_otype_t otype;
 541 
 542     /* Thread serialization */
 543 
 544     pmix_mutex_lock(&cmd->lcl_mutex);
 545 
 546     /* Make an argv of all the usage strings */
 547 
 548     argc = 0;
 549     argv = NULL;
 550     ret = NULL;
 551 
 552     /* First, take the original list and sort it */
 553 
 554     sorted = (pmix_cmd_line_option_t**)malloc(sizeof(pmix_cmd_line_option_t *) *
 555                                          pmix_list_get_size(&cmd->lcl_options));
 556     if (NULL == sorted) {
 557         pmix_mutex_unlock(&cmd->lcl_mutex);
 558         return NULL;
 559     }
 560     i = 0;
 561     PMIX_LIST_FOREACH(item, &cmd->lcl_options, pmix_list_item_t) {
 562         sorted[i++] = (pmix_cmd_line_option_t *) item;
 563     }
 564     qsort(sorted, i, sizeof(pmix_cmd_line_option_t*), qsort_callback);
 565 
 566     /* Find if a help argument was passed, and return its type if it was. */
 567 
 568     otype = get_help_otype(cmd);
 569 
 570     /* Now go through the sorted array and make the strings */
 571 
 572     for (j = 0; j < pmix_list_get_size(&cmd->lcl_options); ++j) {
 573         option = sorted[j];
 574         if(otype == PMIX_CMD_LINE_OTYPE_PARSABLE) {
 575             ret = build_parsable(option);
 576             pmix_argv_append(&argc, &argv, ret);
 577             free(ret);
 578             ret = NULL;
 579         } else if(otype == PMIX_CMD_LINE_OTYPE_NULL || option->clo_otype == otype) {
 580             if (NULL != option->clo_description) {
 581                 bool filled = false;
 582 
 583                 /* Build up the output line */
 584 
 585                 memset(line, 0, sizeof(line));
 586                 if ('\0' != option->clo_short_name) {
 587                     line[0] = '-';
 588                     line[1] = option->clo_short_name;
 589                     filled = true;
 590                 } else {
 591                     line[0] = ' ';
 592                     line[1] = ' ';
 593                 }
 594                 if (NULL != option->clo_single_dash_name) {
 595                     line[2] = (filled) ? '|' : ' ';
 596                     strncat(line, "-", sizeof(line) - 1);
 597                     strncat(line, option->clo_single_dash_name, sizeof(line) - 1);
 598                     filled = true;
 599                 }
 600                 if (NULL != option->clo_long_name) {
 601                     if (filled) {
 602                         strncat(line, "|", sizeof(line) - 1);
 603                     } else {
 604                         strncat(line, " ", sizeof(line) - 1);
 605                     }
 606                     strncat(line, "--", sizeof(line) - 1);
 607                     strncat(line, option->clo_long_name, sizeof(line) - 1);
 608                 }
 609                 strncat(line, " ", sizeof(line) - 1);
 610                 for (i = 0; (int)i < option->clo_num_params; ++i) {
 611                     len = sizeof(temp);
 612                     snprintf(temp, len, "<arg%d> ", (int)i);
 613                     strncat(line, temp, sizeof(line) - 1);
 614                 }
 615                 if (option->clo_num_params > 0) {
 616                     strncat(line, " ", sizeof(line) - 1);
 617                 }
 618 
 619                 /* If we're less than param width, then start adding the
 620                    description to this line.  Otherwise, finish this line
 621                    and start adding the description on the next line. */
 622 
 623                 if (strlen(line) > PARAM_WIDTH) {
 624                     pmix_argv_append(&argc, &argv, line);
 625 
 626                     /* Now reset the line to be all blanks up to
 627                        PARAM_WIDTH so that we can start adding the
 628                        description */
 629 
 630                     memset(line, ' ', PARAM_WIDTH);
 631                     line[PARAM_WIDTH] = '\0';
 632                 } else {
 633 
 634                     /* Add enough blanks to the end of the line so that we
 635                        can start adding the description */
 636 
 637                     for (i = strlen(line); i < PARAM_WIDTH; ++i) {
 638                         line[i] = ' ';
 639                     }
 640                     line[i] = '\0';
 641                 }
 642 
 643                 /* Loop over adding the description to the array, breaking
 644                    the string at most at MAX_WIDTH characters.  We need a
 645                    modifyable description (for simplicity), so strdup the
 646                    clo_description (because it's likely a cpmixler
 647                    constant, and may barf if we write temporary \0's in
 648                    the middle). */
 649 
 650                 desc = strdup(option->clo_description);
 651                 if (NULL == desc) {
 652                     free(sorted);
 653                     pmix_mutex_unlock(&cmd->lcl_mutex);
 654                     return strdup("");
 655                 }
 656                 start = desc;
 657                 len = strlen(desc);
 658                 do {
 659 
 660                     /* Trim off leading whitespace */
 661 
 662                     while (isspace(*start) && start < desc + len) {
 663                         ++start;
 664                     }
 665                     if (start >= desc + len) {
 666                         break;
 667                     }
 668 
 669                     /* Last line */
 670 
 671                     if (strlen(start) < (MAX_WIDTH - PARAM_WIDTH)) {
 672                         strncat(line, start, sizeof(line) - 1);
 673                         pmix_argv_append(&argc, &argv, line);
 674                         break;
 675                     }
 676 
 677                     /* We have more than 1 line's worth left -- find this
 678                        line's worth and add it to the array.  Then reset
 679                        and loop around to get the next line's worth. */
 680 
 681                     for (ptr = start + (MAX_WIDTH - PARAM_WIDTH);
 682                          ptr > start; --ptr) {
 683                         if (isspace(*ptr)) {
 684                             *ptr = '\0';
 685                             strncat(line, start, sizeof(line) - 1);
 686                             pmix_argv_append(&argc, &argv, line);
 687 
 688                             start = ptr + 1;
 689                             memset(line, ' ', PARAM_WIDTH);
 690                             line[PARAM_WIDTH] = '\0';
 691                             break;
 692                         }
 693                     }
 694 
 695                     /* If we got all the way back to the beginning of the
 696                        string, then go forward looking for a whitespace
 697                        and break there. */
 698 
 699                     if (ptr == start) {
 700                         for (ptr = start + (MAX_WIDTH - PARAM_WIDTH);
 701                              ptr < start + len; ++ptr) {
 702                             if (isspace(*ptr)) {
 703                                 *ptr = '\0';
 704 
 705                                 strncat(line, start, sizeof(line) - 1);
 706                                 pmix_argv_append(&argc, &argv, line);
 707 
 708                                 start = ptr + 1;
 709                                 memset(line, ' ', PARAM_WIDTH);
 710                                 line[PARAM_WIDTH] = '\0';
 711                                 break;
 712                             }
 713                         }
 714 
 715                         /* If we reached the end of the string with no
 716                            whitespace, then just add it on and be done */
 717 
 718                         if (ptr >= start + len) {
 719                             strncat(line, start, sizeof(line) - 1);
 720                             pmix_argv_append(&argc, &argv, line);
 721                             start = desc + len + 1;
 722                         }
 723                     }
 724                 } while (start < desc + len);
 725                 free(desc);
 726             }
 727         }
 728     }
 729     if (NULL != argv) {
 730         ret = pmix_argv_join(argv, '\n');
 731         pmix_argv_free(argv);
 732     } else {
 733         ret = strdup("");
 734     }
 735     free(sorted);
 736 
 737     /* Thread serialization */
 738     pmix_mutex_unlock(&cmd->lcl_mutex);
 739 
 740     /* All done */
 741     return ret;
 742 }
 743 
 744 
 745 /*
 746  * Test if a given option was taken on the parsed command line.
 747  */
 748 bool pmix_cmd_line_is_taken(pmix_cmd_line_t *cmd, const char *opt)
 749 {
 750     return (pmix_cmd_line_get_ninsts(cmd, opt) > 0);
 751 }
 752 
 753 
 754 /*
 755  * Return the number of instances of an option found during parsing.
 756  */
 757 int pmix_cmd_line_get_ninsts(pmix_cmd_line_t *cmd, const char *opt)
 758 {
 759     int ret;
 760     pmix_cmd_line_param_t *param;
 761     pmix_cmd_line_option_t *option;
 762 
 763     /* Thread serialization */
 764 
 765     pmix_mutex_lock(&cmd->lcl_mutex);
 766 
 767     /* Find the corresponding option.  If we find it, look through all
 768        the parsed params and see if we have any matches. */
 769 
 770     ret = 0;
 771     option = find_option(cmd, opt);
 772     if (NULL != option) {
 773         PMIX_LIST_FOREACH(param, &cmd->lcl_params, pmix_cmd_line_param_t) {
 774             if (param->clp_option == option) {
 775                 ++ret;
 776             }
 777         }
 778     }
 779 
 780     /* Thread serialization */
 781 
 782     pmix_mutex_unlock(&cmd->lcl_mutex);
 783 
 784     /* All done */
 785 
 786     return ret;
 787 }
 788 
 789 
 790 /*
 791  * Return a specific parameter for a specific instance of a option
 792  * from the parsed command line.
 793  */
 794 char *pmix_cmd_line_get_param(pmix_cmd_line_t *cmd, const char *opt, int inst,
 795                               int idx)
 796 {
 797     int num_found;
 798     pmix_cmd_line_param_t *param;
 799     pmix_cmd_line_option_t *option;
 800 
 801     /* Thread serialization */
 802 
 803     pmix_mutex_lock(&cmd->lcl_mutex);
 804 
 805     /* Find the corresponding option.  If we find it, look through all
 806        the parsed params and see if we have any matches. */
 807 
 808     num_found = 0;
 809     option = find_option(cmd, opt);
 810     if (NULL != option) {
 811 
 812         /* Ensure to check for the case where the user has asked for a
 813            parameter index greater than we will have */
 814 
 815         if (idx < option->clo_num_params) {
 816             PMIX_LIST_FOREACH(param, &cmd->lcl_params, pmix_cmd_line_param_t) {
 817                 if (param->clp_argc > 0 && param->clp_option == option) {
 818                     if (num_found == inst) {
 819                         pmix_mutex_unlock(&cmd->lcl_mutex);
 820                         return param->clp_argv[idx];
 821                     }
 822                     ++num_found;
 823                 }
 824             }
 825         }
 826     }
 827 
 828     /* Thread serialization */
 829 
 830     pmix_mutex_unlock(&cmd->lcl_mutex);
 831 
 832     /* All done */
 833 
 834     return NULL;
 835 }
 836 
 837 
 838 /*
 839  * Return the number of arguments parsed on a PMIX command line handle.
 840  */
 841 int pmix_cmd_line_get_argc(pmix_cmd_line_t *cmd)
 842 {
 843     return (NULL != cmd) ? cmd->lcl_argc : PMIX_ERROR;
 844 }
 845 
 846 
 847 /*
 848  * Return a string argument parsed on a PMIX command line handle.
 849  */
 850 char *pmix_cmd_line_get_argv(pmix_cmd_line_t *cmd, int index)
 851 {
 852     return (NULL == cmd) ? NULL :
 853         (index >= cmd->lcl_argc || index < 0) ? NULL : cmd->lcl_argv[index];
 854 }
 855 
 856 
 857 /*
 858  * Return the entire "tail" of unprocessed argv from a PMIX command
 859  * line handle.
 860  */
 861 int pmix_cmd_line_get_tail(pmix_cmd_line_t *cmd, int *tailc, char ***tailv)
 862 {
 863     if (NULL != cmd) {
 864         pmix_mutex_lock(&cmd->lcl_mutex);
 865         *tailc = cmd->lcl_tail_argc;
 866         *tailv = pmix_argv_copy(cmd->lcl_tail_argv);
 867         pmix_mutex_unlock(&cmd->lcl_mutex);
 868         return PMIX_SUCCESS;
 869     } else {
 870         return PMIX_ERROR;
 871     }
 872 }
 873 
 874 
 875 /**************************************************************************
 876  * Static functions
 877  **************************************************************************/
 878 
 879 static void option_constructor(pmix_cmd_line_option_t *o)
 880 {
 881     o->clo_short_name = '\0';
 882     o->clo_single_dash_name = NULL;
 883     o->clo_long_name = NULL;
 884     o->clo_num_params = 0;
 885     o->clo_description = NULL;
 886 
 887     o->clo_type = PMIX_CMD_LINE_TYPE_NULL;
 888     o->clo_mca_param_env_var = NULL;
 889     o->clo_variable_dest = NULL;
 890     o->clo_variable_set = false;
 891     o->clo_otype = PMIX_CMD_LINE_OTYPE_NULL;
 892 }
 893 
 894 
 895 static void option_destructor(pmix_cmd_line_option_t *o)
 896 {
 897     if (NULL != o->clo_single_dash_name) {
 898         free(o->clo_single_dash_name);
 899     }
 900     if (NULL != o->clo_long_name) {
 901         free(o->clo_long_name);
 902     }
 903     if (NULL != o->clo_description) {
 904         free(o->clo_description);
 905     }
 906     if (NULL != o->clo_mca_param_env_var) {
 907         free(o->clo_mca_param_env_var);
 908     }
 909 }
 910 
 911 
 912 static void param_constructor(pmix_cmd_line_param_t *p)
 913 {
 914     p->clp_arg = NULL;
 915     p->clp_option = NULL;
 916     p->clp_argc = 0;
 917     p->clp_argv = NULL;
 918 }
 919 
 920 
 921 static void param_destructor(pmix_cmd_line_param_t *p)
 922 {
 923     if (NULL != p->clp_argv) {
 924         pmix_argv_free(p->clp_argv);
 925     }
 926 }
 927 
 928 
 929 static void cmd_line_constructor(pmix_cmd_line_t *cmd)
 930 {
 931     /* Initialize the mutex.  Since we're creating (and therefore the
 932        only thread that has this instance), there's no need to lock it
 933        right now. */
 934 
 935     PMIX_CONSTRUCT(&cmd->lcl_mutex, pmix_recursive_mutex_t);
 936 
 937     /* Initialize the lists */
 938 
 939     PMIX_CONSTRUCT(&cmd->lcl_options, pmix_list_t);
 940     PMIX_CONSTRUCT(&cmd->lcl_params, pmix_list_t);
 941 
 942     /* Initialize the argc/argv pairs */
 943 
 944     cmd->lcl_argc = 0;
 945     cmd->lcl_argv = NULL;
 946     cmd->lcl_tail_argc = 0;
 947     cmd->lcl_tail_argv = NULL;
 948 }
 949 
 950 
 951 static void cmd_line_destructor(pmix_cmd_line_t *cmd)
 952 {
 953     pmix_list_item_t *item;
 954 
 955     /* Free the contents of the options list (do not free the list
 956        itself; it was not allocated from the heap) */
 957 
 958     for (item = pmix_list_remove_first(&cmd->lcl_options);
 959          NULL != item;
 960          item = pmix_list_remove_first(&cmd->lcl_options)) {
 961         PMIX_RELEASE(item);
 962     }
 963 
 964     /* Free any parsed results */
 965 
 966     free_parse_results(cmd);
 967 
 968     /* Destroy the lists */
 969 
 970     PMIX_DESTRUCT(&cmd->lcl_options);
 971     PMIX_DESTRUCT(&cmd->lcl_params);
 972 
 973     /* Destroy the mutex */
 974 
 975     PMIX_DESTRUCT(&cmd->lcl_mutex);
 976 }
 977 
 978 
 979 static int make_opt(pmix_cmd_line_t *cmd, pmix_cmd_line_init_t *e)
 980 {
 981     pmix_cmd_line_option_t *option;
 982 
 983     /* Bozo checks */
 984 
 985     if (NULL == cmd) {
 986         return PMIX_ERR_BAD_PARAM;
 987     } else if ('\0' == e->ocl_cmd_short_name &&
 988                NULL == e->ocl_cmd_single_dash_name &&
 989                NULL == e->ocl_cmd_long_name) {
 990         return PMIX_ERR_BAD_PARAM;
 991     } else if (e->ocl_num_params < 0) {
 992         return PMIX_ERR_BAD_PARAM;
 993     }
 994 
 995     /* see if the option already exists */
 996     if (NULL != e->ocl_cmd_single_dash_name &&
 997         NULL != find_option(cmd, e->ocl_cmd_single_dash_name)) {
 998         pmix_output(0, "Duplicate cmd line entry %s", e->ocl_cmd_single_dash_name);
 999         return PMIX_ERR_BAD_PARAM;
1000     }
1001     if (NULL != e->ocl_cmd_long_name &&
1002         NULL != find_option(cmd, e->ocl_cmd_long_name)) {
1003         pmix_output(0, "Duplicate cmd line entry %s", e->ocl_cmd_long_name);
1004         return PMIX_ERR_BAD_PARAM;
1005     }
1006 
1007     /* Allocate and fill an option item */
1008     option = PMIX_NEW(pmix_cmd_line_option_t);
1009     if (NULL == option) {
1010         return PMIX_ERR_OUT_OF_RESOURCE;
1011     }
1012 
1013     option->clo_short_name = e->ocl_cmd_short_name;
1014     if (NULL != e->ocl_cmd_single_dash_name) {
1015         option->clo_single_dash_name = strdup(e->ocl_cmd_single_dash_name);
1016     }
1017     if (NULL != e->ocl_cmd_long_name) {
1018         option->clo_long_name = strdup(e->ocl_cmd_long_name);
1019     }
1020     option->clo_num_params = e->ocl_num_params;
1021     if (NULL != e->ocl_description) {
1022         option->clo_description = strdup(e->ocl_description);
1023     }
1024 
1025     option->clo_type = e->ocl_variable_type;
1026     option->clo_variable_dest = e->ocl_variable_dest;
1027     if (NULL != e->ocl_mca_param_name) {
1028         (void) pmix_mca_base_var_env_name (e->ocl_mca_param_name,
1029                                            &option->clo_mca_param_env_var);
1030     }
1031 
1032     option->clo_otype = e->ocl_otype;
1033 
1034     /* Append the item, serializing thread access */
1035 
1036     pmix_mutex_lock(&cmd->lcl_mutex);
1037     pmix_list_append(&cmd->lcl_options, &option->super);
1038     pmix_mutex_unlock(&cmd->lcl_mutex);
1039 
1040     /* All done */
1041 
1042     return PMIX_SUCCESS;
1043 }
1044 
1045 
1046 static void free_parse_results(pmix_cmd_line_t *cmd)
1047 {
1048     pmix_list_item_t *item;
1049 
1050     /* Free the contents of the params list (do not free the list
1051        itself; it was not allocated from the heap) */
1052 
1053     for (item = pmix_list_remove_first(&cmd->lcl_params);
1054          NULL != item;
1055          item = pmix_list_remove_first(&cmd->lcl_params)) {
1056         PMIX_RELEASE(item);
1057     }
1058 
1059     /* Free the argv's */
1060 
1061     if (NULL != cmd->lcl_argv) {
1062         pmix_argv_free(cmd->lcl_argv);
1063     }
1064     cmd->lcl_argv = NULL;
1065     cmd->lcl_argc = 0;
1066 
1067     if (NULL != cmd->lcl_tail_argv) {
1068         pmix_argv_free(cmd->lcl_tail_argv);
1069     }
1070     cmd->lcl_tail_argv = NULL;
1071     cmd->lcl_tail_argc = 0;
1072 }
1073 
1074 
1075 /*
1076  * Traverse a token and split it into individual letter options (the
1077  * token has already been certified to not be a long name and not be a
1078  * short name).  Ensure to differentiate the resulting options from
1079  * "single dash" names.
1080  */
1081 static int split_shorts(pmix_cmd_line_t *cmd, char *token, char **args,
1082                         int *output_argc, char ***output_argv,
1083                         int *num_args_used, bool ignore_unknown)
1084 {
1085     int i, j, len;
1086     pmix_cmd_line_option_t *option;
1087     char fake_token[3];
1088     int num_args;
1089 
1090     /* Setup that we didn't use any of the args */
1091 
1092     num_args = pmix_argv_count(args);
1093     *num_args_used = 0;
1094 
1095     /* Traverse the token.  If it's empty (e.g., if someone passes a
1096        "-" token, which, since the upper level calls this function as
1097        (argv[i] + 1), will be empty by the time it gets down here),
1098        just return that we didn't find a short option. */
1099 
1100     len = (int)strlen(token);
1101     if (0 == len) {
1102         return PMIX_ERR_BAD_PARAM;
1103     }
1104     fake_token[0] = '-';
1105     fake_token[2] = '\0';
1106     for (i = 0; i < len; ++i) {
1107         fake_token[1] = token[i];
1108         option = find_option(cmd, fake_token + 1);
1109 
1110         /* If we don't find the option, either return an error or pass
1111            it through unmodified to the new argv */
1112 
1113         if (NULL == option) {
1114             if (!ignore_unknown) {
1115                 return PMIX_ERR_BAD_PARAM;
1116             } else {
1117                 pmix_argv_append(output_argc, output_argv, fake_token);
1118             }
1119         }
1120 
1121         /* If we do find the option, copy it and all of its parameters
1122            to the output args.  If we run out of paramters (i.e., no
1123            more tokens in the original argv), that error will be
1124            handled at a higher level) */
1125 
1126         else {
1127             pmix_argv_append(output_argc, output_argv, fake_token);
1128             for (j = 0; j < option->clo_num_params; ++j) {
1129                 if (*num_args_used < num_args) {
1130                     pmix_argv_append(output_argc, output_argv,
1131                                      args[*num_args_used]);
1132                     ++(*num_args_used);
1133                 } else {
1134                     pmix_argv_append(output_argc, output_argv,
1135                                      special_empty_token);
1136                 }
1137             }
1138         }
1139     }
1140 
1141     /* All done */
1142 
1143     return PMIX_SUCCESS;
1144 }
1145 
1146 
1147 static pmix_cmd_line_option_t *find_option(pmix_cmd_line_t *cmd,
1148                                            const char *option_name)
1149 {
1150     pmix_cmd_line_option_t *option;
1151 
1152     /* Iterate through the list of options hanging off the
1153        pmix_cmd_line_t and see if we find a match in either the short
1154        or long names */
1155 
1156     PMIX_LIST_FOREACH(option, &cmd->lcl_options, pmix_cmd_line_option_t) {
1157         if ((NULL != option->clo_long_name &&
1158              0 == strcmp(option_name, option->clo_long_name)) ||
1159             (NULL != option->clo_single_dash_name &&
1160              0 == strcmp(option_name, option->clo_single_dash_name)) ||
1161             (strlen(option_name) == 1 &&
1162              option_name[0] == option->clo_short_name)) {
1163             return option;
1164         }
1165     }
1166 
1167     /* Not found */
1168 
1169     return NULL;
1170 }
1171 
1172 
1173 static int set_dest(pmix_cmd_line_option_t *option, char *sval)
1174 {
1175     int ival = atol(sval);
1176     long lval = strtoul(sval, NULL, 10);
1177     size_t i;
1178 
1179     /* Set MCA param.  We do this in the environment because the MCA
1180        parameter may not have been registered yet -- and if it isn't
1181        registered, we don't really want to register a dummy one
1182        because we don't know what it's type and default value should
1183        be.  These are solvable problems (e.g., make a re-registration
1184        overwrite everything), but it's far simpler to just leave the
1185        registered table alone and set an environment variable with the
1186        desired value.  The environment variable will get picked up
1187        during a nromal parameter lookup, and all will be well. */
1188 
1189     if (NULL != option->clo_mca_param_env_var) {
1190         switch(option->clo_type) {
1191         case PMIX_CMD_LINE_TYPE_STRING:
1192         case PMIX_CMD_LINE_TYPE_INT:
1193         case PMIX_CMD_LINE_TYPE_SIZE_T:
1194             pmix_setenv(option->clo_mca_param_env_var, sval, true, &environ);
1195             break;
1196         case PMIX_CMD_LINE_TYPE_BOOL:
1197             pmix_setenv(option->clo_mca_param_env_var, "1", true, &environ);
1198             break;
1199         default:
1200             break;
1201         }
1202     }
1203 
1204     /* Set variable */
1205 
1206     if (NULL != option->clo_variable_dest) {
1207         switch(option->clo_type) {
1208         case PMIX_CMD_LINE_TYPE_STRING:
1209             *((char**) option->clo_variable_dest) = strdup(sval);
1210             break;
1211         case PMIX_CMD_LINE_TYPE_INT:
1212             /* check to see that the value given to us truly is an int */
1213             for (i=0; i < strlen(sval); i++) {
1214                 if (!isdigit(sval[i]) && '-' != sval[i]) {
1215                     /* show help isn't going to be available yet, so just
1216                      * print the msg
1217                      */
1218                     fprintf(stderr, "----------------------------------------------------------------------------\n");
1219                     fprintf(stderr, "Open MPI has detected that a parameter given to a command line\n");
1220                     fprintf(stderr, "option does not match the expected format:\n\n");
1221                     if (NULL != option->clo_long_name) {
1222                         fprintf(stderr, "  Option: %s\n", option->clo_long_name);
1223                     } else if ('\0' != option->clo_short_name) {
1224                         fprintf(stderr, "  Option: %c\n", option->clo_short_name);
1225                     } else {
1226                         fprintf(stderr, "  Option: <unknown>\n");
1227                     }
1228                     fprintf(stderr, "  Param:  %s\n\n", sval);
1229                     fprintf(stderr, "This is frequently caused by omitting to provide the parameter\n");
1230                     fprintf(stderr, "to an option that requires one. Please check the command line and try again.\n");
1231                     fprintf(stderr, "----------------------------------------------------------------------------\n");
1232                     return PMIX_ERR_SILENT;
1233                 }
1234             }
1235             *((int*) option->clo_variable_dest) = ival;
1236             break;
1237         case PMIX_CMD_LINE_TYPE_SIZE_T:
1238             /* check to see that the value given to us truly is a size_t */
1239             for (i=0; i < strlen(sval); i++) {
1240                 if (!isdigit(sval[i]) && '-' != sval[i]) {
1241                     /* show help isn't going to be available yet, so just
1242                      * print the msg
1243                      */
1244                     fprintf(stderr, "----------------------------------------------------------------------------\n");
1245                     fprintf(stderr, "Open MPI has detected that a parameter given to a command line\n");
1246                     fprintf(stderr, "option does not match the expected format:\n\n");
1247                     if (NULL != option->clo_long_name) {
1248                         fprintf(stderr, "  Option: %s\n", option->clo_long_name);
1249                     } else if ('\0' != option->clo_short_name) {
1250                         fprintf(stderr, "  Option: %c\n", option->clo_short_name);
1251                     } else {
1252                         fprintf(stderr, "  Option: <unknown>\n");
1253                     }
1254                     fprintf(stderr, "  Param:  %s\n\n", sval);
1255                     fprintf(stderr, "This is frequently caused by omitting to provide the parameter\n");
1256                     fprintf(stderr, "to an option that requires one. Please check the command line and try again.\n");
1257                     fprintf(stderr, "----------------------------------------------------------------------------\n");
1258                     return PMIX_ERR_SILENT;
1259                 }
1260             }
1261             *((size_t*) option->clo_variable_dest) = lval;
1262             break;
1263         case PMIX_CMD_LINE_TYPE_BOOL:
1264             *((bool*) option->clo_variable_dest) = 1;
1265             break;
1266         default:
1267             break;
1268         }
1269     }
1270     return PMIX_SUCCESS;
1271 }
1272 
1273 
1274 /*
1275  * Helper function to qsort_callback
1276  */
1277 static void fill(const pmix_cmd_line_option_t *a, char result[3][BUFSIZ])
1278 {
1279     int i = 0;
1280 
1281     result[0][0] = '\0';
1282     result[1][0] = '\0';
1283     result[2][0] = '\0';
1284 
1285     if ('\0' != a->clo_short_name) {
1286         snprintf(&result[i][0], BUFSIZ, "%c", a->clo_short_name);
1287         ++i;
1288     }
1289     if (NULL != a->clo_single_dash_name) {
1290         snprintf(&result[i][0], BUFSIZ, "%s", a->clo_single_dash_name);
1291         ++i;
1292     }
1293     if (NULL != a->clo_long_name) {
1294         snprintf(&result[i][0], BUFSIZ, "%s", a->clo_long_name);
1295         ++i;
1296     }
1297 }
1298 
1299 
1300 static int qsort_callback(const void *aa, const void *bb)
1301 {
1302     int ret, i;
1303     char str1[3][BUFSIZ], str2[3][BUFSIZ];
1304     const pmix_cmd_line_option_t *a = *((const pmix_cmd_line_option_t**) aa);
1305     const pmix_cmd_line_option_t *b = *((const pmix_cmd_line_option_t**) bb);
1306 
1307     /* Icky comparison of command line options.  There are multiple
1308        forms of each command line option, so we first have to check
1309        which forms each option has.  Compare, in order: short name,
1310        single-dash name, long name. */
1311 
1312     fill(a, str1);
1313     fill(b, str2);
1314 
1315     for (i = 0; i < 3; ++i) {
1316         if (0 != (ret = strcasecmp(str1[i], str2[i]))) {
1317             return ret;
1318         }
1319     }
1320 
1321     /* Shrug -- they must be equal */
1322 
1323     return 0;
1324 }
1325 
1326 
1327 /*
1328  * Helper function to find the option type specified in the help
1329  * command.
1330  */
1331 static pmix_cmd_line_otype_t get_help_otype(pmix_cmd_line_t *cmd)
1332 {
1333     /* Initialize to NULL, if it remains so, the user asked for
1334        "full" help output */
1335     pmix_cmd_line_otype_t otype = PMIX_CMD_LINE_OTYPE_NULL;
1336     char *arg;
1337 
1338     arg = pmix_cmd_line_get_param(cmd, "help", 0, 0);
1339 
1340     /* If not "help", check for "h" */
1341     if(NULL == arg) {
1342         arg = pmix_cmd_line_get_param(cmd, "h", 0, 0);
1343     }
1344 
1345     /* If arg is still NULL, give them the General info by default */
1346     if(NULL == arg) {
1347         arg = "general";
1348     }
1349 
1350     if (0 == strcmp(arg, "debug")) {
1351         otype = PMIX_CMD_LINE_OTYPE_DEBUG;
1352     } else if (0 == strcmp(arg, "output")) {
1353         otype = PMIX_CMD_LINE_OTYPE_OUTPUT;
1354     } else if (0 == strcmp(arg, "input")) {
1355         otype = PMIX_CMD_LINE_OTYPE_INPUT;
1356     } else if (0 == strcmp(arg, "mapping")) {
1357         otype = PMIX_CMD_LINE_OTYPE_MAPPING;
1358     } else if (0 == strcmp(arg, "ranking")) {
1359         otype = PMIX_CMD_LINE_OTYPE_RANKING;
1360     } else if (0 == strcmp(arg, "binding")) {
1361         otype = PMIX_CMD_LINE_OTYPE_BINDING;
1362     } else if (0 == strcmp(arg, "devel")) {
1363         otype = PMIX_CMD_LINE_OTYPE_DEVEL;
1364     } else if (0 == strcmp(arg, "compatibility")) {
1365         otype = PMIX_CMD_LINE_OTYPE_COMPAT;
1366     } else if (0 == strcmp(arg, "launch")) {
1367         otype = PMIX_CMD_LINE_OTYPE_LAUNCH;
1368     } else if (0 == strcmp(arg, "dvm")) {
1369         otype = PMIX_CMD_LINE_OTYPE_DVM;
1370     } else if (0 == strcmp(arg, "general")) {
1371         otype = PMIX_CMD_LINE_OTYPE_GENERAL;
1372     } else if (0 == strcmp(arg, "parsable")) {
1373         otype = PMIX_CMD_LINE_OTYPE_PARSABLE;
1374     }
1375 
1376     return otype;
1377 }
1378 
1379 /*
1380  * Helper function to build a parsable string for the help
1381  * output.
1382  */
1383 static char *build_parsable(pmix_cmd_line_option_t *option) {
1384     char *line;
1385     int length;
1386 
1387     length = snprintf(NULL, 0, "%c:%s:%s:%d:%s\n", option->clo_short_name, option->clo_single_dash_name,
1388                       option->clo_long_name, option->clo_num_params, option->clo_description);
1389 
1390     line = (char *)malloc(length * sizeof(char));
1391 
1392     if('\0' == option->clo_short_name) {
1393         snprintf(line, length, "0:%s:%s:%d:%s\n", option->clo_single_dash_name, option->clo_long_name,
1394                  option->clo_num_params, option->clo_description);
1395     } else {
1396         snprintf(line, length, "%c:%s:%s:%d:%s\n", option->clo_short_name, option->clo_single_dash_name,
1397                  option->clo_long_name, option->clo_num_params, option->clo_description);
1398     }
1399 
1400     return line;
1401 }

/* [<][>][^][v][top][bottom][index][help] */