root/opal/util/cmd_line.c

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

DEFINITIONS

This source file includes following definitions.
  1. find_option
  2. opal_cmd_line_add
  3. opal_cmd_line_make_opt_mca
  4. opal_cmd_line_make_opt3
  5. opal_cmd_line_parse
  6. opal_cmd_line_get_usage_msg
  7. opal_cmd_line_is_taken
  8. opal_cmd_line_get_ninsts
  9. opal_cmd_line_get_param
  10. opal_cmd_line_get_argc
  11. opal_cmd_line_get_argv
  12. opal_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-2017 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 "opal_config.h"
  28 
  29 #include <stdio.h>
  30 #include <string.h>
  31 #include <ctype.h>
  32 
  33 #include "opal/class/opal_object.h"
  34 #include "opal/class/opal_list.h"
  35 #include "opal/threads/mutex.h"
  36 #include "opal/util/argv.h"
  37 #include "opal/util/cmd_line.h"
  38 #include "opal/util/output.h"
  39 #include "opal/util/opal_environ.h"
  40 
  41 #include "opal/mca/base/mca_base_var.h"
  42 #include "opal/constants.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 ompi_cmd_line_option_t {
  61     opal_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     opal_cmd_line_type_t clo_type;
  71     char *clo_mca_param_env_var;
  72     void *clo_variable_dest;
  73     bool clo_variable_set;
  74     opal_cmd_line_otype_t clo_otype;
  75 };
  76 typedef struct ompi_cmd_line_option_t ompi_cmd_line_option_t;
  77 static void option_constructor(ompi_cmd_line_option_t *cmd);
  78 static void option_destructor(ompi_cmd_line_option_t *cmd);
  79 
  80 OBJ_CLASS_INSTANCE(ompi_cmd_line_option_t,
  81                    opal_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 ompi_cmd_line_param_t {
  88     opal_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     ompi_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 ompi_cmd_line_param_t ompi_cmd_line_param_t;
 109 static void param_constructor(ompi_cmd_line_param_t *cmd);
 110 static void param_destructor(ompi_cmd_line_param_t *cmd);
 111 OBJ_CLASS_INSTANCE(ompi_cmd_line_param_t,
 112                    opal_list_item_t,
 113                    param_constructor, param_destructor);
 114 
 115 /*
 116  * Instantiate the opal_cmd_line_t class
 117  */
 118 static void cmd_line_constructor(opal_cmd_line_t *cmd);
 119 static void cmd_line_destructor(opal_cmd_line_t *cmd);
 120 OBJ_CLASS_INSTANCE(opal_cmd_line_t,
 121                    opal_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(opal_cmd_line_t *cmd, opal_cmd_line_init_t *e);
 136 static void free_parse_results(opal_cmd_line_t *cmd);
 137 static int split_shorts(opal_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 ompi_cmd_line_option_t *find_option(opal_cmd_line_t *cmd,
 142                                       const char *option_name) __opal_attribute_nonnull__(1) __opal_attribute_nonnull__(2);
 143 static int set_dest(ompi_cmd_line_option_t *option, char *sval);
 144 static void fill(const ompi_cmd_line_option_t *a, char result[3][BUFSIZ]);
 145 static int qsort_callback(const void *a, const void *b);
 146 static opal_cmd_line_otype_t get_help_otype(opal_cmd_line_t *cmd);
 147 static char *build_parsable(ompi_cmd_line_option_t *option);
 148 
 149 
 150 /*
 151  * Create an entire command line handle from a table
 152  */
 153 int opal_cmd_line_create(opal_cmd_line_t *cmd,
 154                          opal_cmd_line_init_t *table)
 155 {
 156     int ret = OPAL_SUCCESS;
 157 
 158     /* Check bozo case */
 159 
 160     if (NULL == cmd) {
 161         return OPAL_ERR_BAD_PARAM;
 162     }
 163     OBJ_CONSTRUCT(cmd, opal_cmd_line_t);
 164 
 165     if (NULL != table) {
 166         ret = opal_cmd_line_add(cmd, table);
 167     }
 168     return ret;
 169 }
 170 
 171 /* Add a table to an existing cmd line object */
 172 int opal_cmd_line_add(opal_cmd_line_t *cmd,
 173                       opal_cmd_line_init_t *table)
 174 {
 175     int i, ret;
 176 
 177     /* Ensure we got a table */
 178     if (NULL == table) {
 179         return OPAL_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 (OPAL_SUCCESS != ret) {
 195             return ret;
 196         }
 197     }
 198 
 199     return OPAL_SUCCESS;
 200 }
 201 /*
 202  * Append a command line entry to the previously constructed command line
 203  */
 204 int opal_cmd_line_make_opt_mca(opal_cmd_line_t *cmd,
 205                                opal_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 OPAL_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 opal_cmd_line_make_opt3(opal_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     opal_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 = OPAL_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 OPAL command line
 246  * handle.
 247  */
 248 int opal_cmd_line_parse(opal_cmd_line_t *cmd, bool ignore_unknown, bool ignore_unknown_option,
 249                         int argc, char **argv)
 250 {
 251     int i, j, orig, ret;
 252     ompi_cmd_line_option_t *option;
 253     ompi_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 OPAL_SUCCESS;
 268     }
 269 
 270     /* Thread serialization */
 271 
 272     opal_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 = opal_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                 opal_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 (OPAL_SUCCESS == ret) {
 351                     option = find_option(cmd, shortsv[0] + 1);
 352 
 353                     if (NULL != option) {
 354                         opal_argv_delete(&cmd->lcl_argc,
 355                                          &cmd->lcl_argv, i,
 356                                          1 + num_args_used);
 357                         opal_argv_insert(&cmd->lcl_argv, i, shortsv);
 358                         cmd->lcl_argc = opal_argv_count(cmd->lcl_argv);
 359                     } else {
 360                         is_unknown_option = true;
 361                     }
 362                     opal_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 = OBJ_NEW(ompi_cmd_line_param_t);
 390                 if (NULL == param) {
 391                     opal_mutex_unlock(&cmd->lcl_mutex);
 392                     return OPAL_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                         OBJ_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                                 opal_argv_free(param->clp_argv);
 439                             }
 440                             OBJ_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                             opal_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 (OPAL_SUCCESS != (ret = set_dest(option, cmd->lcl_argv[i]))) {
 461                                     opal_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 (OPAL_SUCCESS != (ret = set_dest(option, "1"))) {
 475                         opal_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 opal_cmd_line_t handle */
 482 
 483                 if (NULL != param) {
 484                     opal_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                 opal_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     opal_mutex_unlock(&cmd->lcl_mutex);
 517 
 518     /* All done */
 519     if (printed_error) {
 520         return OPAL_ERR_SILENT;
 521     }
 522 
 523     return OPAL_SUCCESS;
 524 }
 525 
 526 
 527 /*
 528  * Return a consolidated "usage" message for a OPAL command line handle.
 529  */
 530 char *opal_cmd_line_get_usage_msg(opal_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     opal_list_item_t *item;
 539     ompi_cmd_line_option_t *option, **sorted;
 540     opal_cmd_line_otype_t otype;
 541 
 542     /* Thread serialization */
 543 
 544     opal_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 = (ompi_cmd_line_option_t**)malloc(sizeof(ompi_cmd_line_option_t *) *
 555                                          opal_list_get_size(&cmd->lcl_options));
 556     if (NULL == sorted) {
 557         opal_mutex_unlock(&cmd->lcl_mutex);
 558         return NULL;
 559     }
 560     i = 0;
 561     OPAL_LIST_FOREACH(item, &cmd->lcl_options, opal_list_item_t) {
 562         sorted[i++] = (ompi_cmd_line_option_t *) item;
 563     }
 564     qsort(sorted, i, sizeof(ompi_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 < opal_list_get_size(&cmd->lcl_options); ++j) {
 573         option = sorted[j];
 574         if(otype == OPAL_CMD_LINE_OTYPE_PARSABLE) {
 575             ret = build_parsable(option);
 576             opal_argv_append(&argc, &argv, ret);
 577             free(ret);
 578             ret = NULL;
 579         } else if(otype == OPAL_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                     opal_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 compiler
 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                     opal_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                         opal_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                             opal_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                                 opal_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                             opal_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(otype == OPAL_CMD_LINE_OTYPE_NULL || otype == OPAL_CMD_LINE_OTYPE_GENERAL) {
 730         char *argument_line = "\nFor additional mpirun arguments, run 'mpirun --help <category>'\n\nThe following categories exist: general (Defaults to this option), debug,\n    output, input, mapping, ranking, binding, devel (arguments useful to OMPI\n    Developers), compatibility (arguments supported for backwards compatibility),\n    launch (arguments to modify launch options), and dvm (Distributed Virtual\n    Machine arguments).";
 731 
 732         opal_argv_append(&argc, &argv, argument_line);
 733     }
 734     if (NULL != argv) {
 735         ret = opal_argv_join(argv, '\n');
 736         opal_argv_free(argv);
 737     } else {
 738         ret = strdup("");
 739     }
 740     free(sorted);
 741 
 742     /* Thread serialization */
 743     opal_mutex_unlock(&cmd->lcl_mutex);
 744 
 745     /* All done */
 746     return ret;
 747 }
 748 
 749 
 750 /*
 751  * Test if a given option was taken on the parsed command line.
 752  */
 753 bool opal_cmd_line_is_taken(opal_cmd_line_t *cmd, const char *opt)
 754 {
 755     return (opal_cmd_line_get_ninsts(cmd, opt) > 0);
 756 }
 757 
 758 
 759 /*
 760  * Return the number of instances of an option found during parsing.
 761  */
 762 int opal_cmd_line_get_ninsts(opal_cmd_line_t *cmd, const char *opt)
 763 {
 764     int ret;
 765     ompi_cmd_line_param_t *param;
 766     ompi_cmd_line_option_t *option;
 767 
 768     /* Thread serialization */
 769 
 770     opal_mutex_lock(&cmd->lcl_mutex);
 771 
 772     /* Find the corresponding option.  If we find it, look through all
 773        the parsed params and see if we have any matches. */
 774 
 775     ret = 0;
 776     option = find_option(cmd, opt);
 777     if (NULL != option) {
 778         OPAL_LIST_FOREACH(param, &cmd->lcl_params, ompi_cmd_line_param_t) {
 779             if (param->clp_option == option) {
 780                 ++ret;
 781             }
 782         }
 783     }
 784 
 785     /* Thread serialization */
 786 
 787     opal_mutex_unlock(&cmd->lcl_mutex);
 788 
 789     /* All done */
 790 
 791     return ret;
 792 }
 793 
 794 
 795 /*
 796  * Return a specific parameter for a specific instance of a option
 797  * from the parsed command line.
 798  */
 799 char *opal_cmd_line_get_param(opal_cmd_line_t *cmd, const char *opt, int inst,
 800                               int idx)
 801 {
 802     int num_found;
 803     ompi_cmd_line_param_t *param;
 804     ompi_cmd_line_option_t *option;
 805 
 806     /* Thread serialization */
 807 
 808     opal_mutex_lock(&cmd->lcl_mutex);
 809 
 810     /* Find the corresponding option.  If we find it, look through all
 811        the parsed params and see if we have any matches. */
 812 
 813     num_found = 0;
 814     option = find_option(cmd, opt);
 815     if (NULL != option) {
 816 
 817         /* Ensure to check for the case where the user has asked for a
 818            parameter index greater than we will have */
 819 
 820         if (idx < option->clo_num_params) {
 821             OPAL_LIST_FOREACH(param, &cmd->lcl_params, ompi_cmd_line_param_t) {
 822                 if (param->clp_argc > 0 && param->clp_option == option) {
 823                     if (num_found == inst) {
 824                         opal_mutex_unlock(&cmd->lcl_mutex);
 825                         return param->clp_argv[idx];
 826                     }
 827                     ++num_found;
 828                 }
 829             }
 830         }
 831     }
 832 
 833     /* Thread serialization */
 834 
 835     opal_mutex_unlock(&cmd->lcl_mutex);
 836 
 837     /* All done */
 838 
 839     return NULL;
 840 }
 841 
 842 
 843 /*
 844  * Return the number of arguments parsed on a OPAL command line handle.
 845  */
 846 int opal_cmd_line_get_argc(opal_cmd_line_t *cmd)
 847 {
 848     return (NULL != cmd) ? cmd->lcl_argc : OPAL_ERROR;
 849 }
 850 
 851 
 852 /*
 853  * Return a string argument parsed on a OPAL command line handle.
 854  */
 855 char *opal_cmd_line_get_argv(opal_cmd_line_t *cmd, int index)
 856 {
 857     return (NULL == cmd) ? NULL :
 858         (index >= cmd->lcl_argc || index < 0) ? NULL : cmd->lcl_argv[index];
 859 }
 860 
 861 
 862 /*
 863  * Return the entire "tail" of unprocessed argv from a OPAL command
 864  * line handle.
 865  */
 866 int opal_cmd_line_get_tail(opal_cmd_line_t *cmd, int *tailc, char ***tailv)
 867 {
 868     if (NULL != cmd) {
 869         opal_mutex_lock(&cmd->lcl_mutex);
 870         *tailc = cmd->lcl_tail_argc;
 871         *tailv = opal_argv_copy(cmd->lcl_tail_argv);
 872         opal_mutex_unlock(&cmd->lcl_mutex);
 873         return OPAL_SUCCESS;
 874     } else {
 875         return OPAL_ERROR;
 876     }
 877 }
 878 
 879 
 880 /**************************************************************************
 881  * Static functions
 882  **************************************************************************/
 883 
 884 static void option_constructor(ompi_cmd_line_option_t *o)
 885 {
 886     o->clo_short_name = '\0';
 887     o->clo_single_dash_name = NULL;
 888     o->clo_long_name = NULL;
 889     o->clo_num_params = 0;
 890     o->clo_description = NULL;
 891 
 892     o->clo_type = OPAL_CMD_LINE_TYPE_NULL;
 893     o->clo_mca_param_env_var = NULL;
 894     o->clo_variable_dest = NULL;
 895     o->clo_variable_set = false;
 896     o->clo_otype = OPAL_CMD_LINE_OTYPE_NULL;
 897 }
 898 
 899 
 900 static void option_destructor(ompi_cmd_line_option_t *o)
 901 {
 902     if (NULL != o->clo_single_dash_name) {
 903         free(o->clo_single_dash_name);
 904     }
 905     if (NULL != o->clo_long_name) {
 906         free(o->clo_long_name);
 907     }
 908     if (NULL != o->clo_description) {
 909         free(o->clo_description);
 910     }
 911     if (NULL != o->clo_mca_param_env_var) {
 912         free(o->clo_mca_param_env_var);
 913     }
 914 }
 915 
 916 
 917 static void param_constructor(ompi_cmd_line_param_t *p)
 918 {
 919     p->clp_arg = NULL;
 920     p->clp_option = NULL;
 921     p->clp_argc = 0;
 922     p->clp_argv = NULL;
 923 }
 924 
 925 
 926 static void param_destructor(ompi_cmd_line_param_t *p)
 927 {
 928     if (NULL != p->clp_argv) {
 929         opal_argv_free(p->clp_argv);
 930     }
 931 }
 932 
 933 
 934 static void cmd_line_constructor(opal_cmd_line_t *cmd)
 935 {
 936     /* Initialize the mutex.  Since we're creating (and therefore the
 937        only thread that has this instance), there's no need to lock it
 938        right now. */
 939 
 940     OBJ_CONSTRUCT(&cmd->lcl_mutex, opal_recursive_mutex_t);
 941 
 942     /* Initialize the lists */
 943 
 944     OBJ_CONSTRUCT(&cmd->lcl_options, opal_list_t);
 945     OBJ_CONSTRUCT(&cmd->lcl_params, opal_list_t);
 946 
 947     /* Initialize the argc/argv pairs */
 948 
 949     cmd->lcl_argc = 0;
 950     cmd->lcl_argv = NULL;
 951     cmd->lcl_tail_argc = 0;
 952     cmd->lcl_tail_argv = NULL;
 953 }
 954 
 955 
 956 static void cmd_line_destructor(opal_cmd_line_t *cmd)
 957 {
 958     opal_list_item_t *item;
 959 
 960     /* Free the contents of the options list (do not free the list
 961        itself; it was not allocated from the heap) */
 962 
 963     for (item = opal_list_remove_first(&cmd->lcl_options);
 964          NULL != item;
 965          item = opal_list_remove_first(&cmd->lcl_options)) {
 966         OBJ_RELEASE(item);
 967     }
 968 
 969     /* Free any parsed results */
 970 
 971     free_parse_results(cmd);
 972 
 973     /* Destroy the lists */
 974 
 975     OBJ_DESTRUCT(&cmd->lcl_options);
 976     OBJ_DESTRUCT(&cmd->lcl_params);
 977 
 978     /* Destroy the mutex */
 979 
 980     OBJ_DESTRUCT(&cmd->lcl_mutex);
 981 }
 982 
 983 
 984 static int make_opt(opal_cmd_line_t *cmd, opal_cmd_line_init_t *e)
 985 {
 986     ompi_cmd_line_option_t *option;
 987 
 988     /* Bozo checks */
 989 
 990     if (NULL == cmd) {
 991         return OPAL_ERR_BAD_PARAM;
 992     } else if ('\0' == e->ocl_cmd_short_name &&
 993                NULL == e->ocl_cmd_single_dash_name &&
 994                NULL == e->ocl_cmd_long_name) {
 995         return OPAL_ERR_BAD_PARAM;
 996     } else if (e->ocl_num_params < 0) {
 997         return OPAL_ERR_BAD_PARAM;
 998     }
 999 
1000     /* see if the option already exists */
1001     if (NULL != e->ocl_cmd_single_dash_name &&
1002         NULL != find_option(cmd, e->ocl_cmd_single_dash_name)) {
1003         opal_output(0, "Duplicate cmd line entry %s", e->ocl_cmd_single_dash_name);
1004         return OPAL_ERR_BAD_PARAM;
1005     }
1006     if (NULL != e->ocl_cmd_long_name &&
1007         NULL != find_option(cmd, e->ocl_cmd_long_name)) {
1008         opal_output(0, "Duplicate cmd line entry %s", e->ocl_cmd_long_name);
1009         return OPAL_ERR_BAD_PARAM;
1010     }
1011 
1012     /* Allocate and fill an option item */
1013     option = OBJ_NEW(ompi_cmd_line_option_t);
1014     if (NULL == option) {
1015         return OPAL_ERR_OUT_OF_RESOURCE;
1016     }
1017 
1018     option->clo_short_name = e->ocl_cmd_short_name;
1019     if (NULL != e->ocl_cmd_single_dash_name) {
1020         option->clo_single_dash_name = strdup(e->ocl_cmd_single_dash_name);
1021     }
1022     if (NULL != e->ocl_cmd_long_name) {
1023         option->clo_long_name = strdup(e->ocl_cmd_long_name);
1024     }
1025     option->clo_num_params = e->ocl_num_params;
1026     if (NULL != e->ocl_description) {
1027         option->clo_description = strdup(e->ocl_description);
1028     }
1029 
1030     option->clo_type = e->ocl_variable_type;
1031     option->clo_variable_dest = e->ocl_variable_dest;
1032     if (NULL != e->ocl_mca_param_name) {
1033         (void) mca_base_var_env_name (e->ocl_mca_param_name,
1034                                      &option->clo_mca_param_env_var);
1035     }
1036 
1037     option->clo_otype = e->ocl_otype;
1038 
1039     /* Append the item, serializing thread access */
1040 
1041     opal_mutex_lock(&cmd->lcl_mutex);
1042     opal_list_append(&cmd->lcl_options, &option->super);
1043     opal_mutex_unlock(&cmd->lcl_mutex);
1044 
1045     /* All done */
1046 
1047     return OPAL_SUCCESS;
1048 }
1049 
1050 
1051 static void free_parse_results(opal_cmd_line_t *cmd)
1052 {
1053     opal_list_item_t *item;
1054 
1055     /* Free the contents of the params list (do not free the list
1056        itself; it was not allocated from the heap) */
1057 
1058     for (item = opal_list_remove_first(&cmd->lcl_params);
1059          NULL != item;
1060          item = opal_list_remove_first(&cmd->lcl_params)) {
1061         OBJ_RELEASE(item);
1062     }
1063 
1064     /* Free the argv's */
1065 
1066     if (NULL != cmd->lcl_argv) {
1067         opal_argv_free(cmd->lcl_argv);
1068     }
1069     cmd->lcl_argv = NULL;
1070     cmd->lcl_argc = 0;
1071 
1072     if (NULL != cmd->lcl_tail_argv) {
1073         opal_argv_free(cmd->lcl_tail_argv);
1074     }
1075     cmd->lcl_tail_argv = NULL;
1076     cmd->lcl_tail_argc = 0;
1077 }
1078 
1079 
1080 /*
1081  * Traverse a token and split it into individual letter options (the
1082  * token has already been certified to not be a long name and not be a
1083  * short name).  Ensure to differentiate the resulting options from
1084  * "single dash" names.
1085  */
1086 static int split_shorts(opal_cmd_line_t *cmd, char *token, char **args,
1087                         int *output_argc, char ***output_argv,
1088                         int *num_args_used, bool ignore_unknown)
1089 {
1090     int i, j, len;
1091     ompi_cmd_line_option_t *option;
1092     char fake_token[3];
1093     int num_args;
1094 
1095     /* Setup that we didn't use any of the args */
1096 
1097     num_args = opal_argv_count(args);
1098     *num_args_used = 0;
1099 
1100     /* Traverse the token.  If it's empty (e.g., if someone passes a
1101        "-" token, which, since the upper level calls this function as
1102        (argv[i] + 1), will be empty by the time it gets down here),
1103        just return that we didn't find a short option. */
1104 
1105     len = (int)strlen(token);
1106     if (0 == len) {
1107         return OPAL_ERR_BAD_PARAM;
1108     }
1109     fake_token[0] = '-';
1110     fake_token[2] = '\0';
1111     for (i = 0; i < len; ++i) {
1112         fake_token[1] = token[i];
1113         option = find_option(cmd, fake_token + 1);
1114 
1115         /* If we don't find the option, either return an error or pass
1116            it through unmodified to the new argv */
1117 
1118         if (NULL == option) {
1119             if (!ignore_unknown) {
1120                 return OPAL_ERR_BAD_PARAM;
1121             } else {
1122                 opal_argv_append(output_argc, output_argv, fake_token);
1123             }
1124         }
1125 
1126         /* If we do find the option, copy it and all of its parameters
1127            to the output args.  If we run out of paramters (i.e., no
1128            more tokens in the original argv), that error will be
1129            handled at a higher level) */
1130 
1131         else {
1132             opal_argv_append(output_argc, output_argv, fake_token);
1133             for (j = 0; j < option->clo_num_params; ++j) {
1134                 if (*num_args_used < num_args) {
1135                     opal_argv_append(output_argc, output_argv,
1136                                      args[*num_args_used]);
1137                     ++(*num_args_used);
1138                 } else {
1139                     opal_argv_append(output_argc, output_argv,
1140                                      special_empty_token);
1141                 }
1142             }
1143         }
1144     }
1145 
1146     /* All done */
1147 
1148     return OPAL_SUCCESS;
1149 }
1150 
1151 
1152 static ompi_cmd_line_option_t *find_option(opal_cmd_line_t *cmd,
1153                                       const char *option_name)
1154 {
1155     ompi_cmd_line_option_t *option;
1156 
1157     /* Iterate through the list of options hanging off the
1158        opal_cmd_line_t and see if we find a match in either the short
1159        or long names */
1160 
1161     OPAL_LIST_FOREACH(option, &cmd->lcl_options, ompi_cmd_line_option_t) {
1162         if ((NULL != option->clo_long_name &&
1163              0 == strcmp(option_name, option->clo_long_name)) ||
1164             (NULL != option->clo_single_dash_name &&
1165              0 == strcmp(option_name, option->clo_single_dash_name)) ||
1166             (strlen(option_name) == 1 &&
1167              option_name[0] == option->clo_short_name)) {
1168             return option;
1169         }
1170     }
1171 
1172     /* Not found */
1173 
1174     return NULL;
1175 }
1176 
1177 
1178 static int set_dest(ompi_cmd_line_option_t *option, char *sval)
1179 {
1180     int ival = atol(sval);
1181     long lval = strtoul(sval, NULL, 10);
1182     size_t i;
1183 
1184     /* Set MCA param.  We do this in the environment because the MCA
1185        parameter may not have been registered yet -- and if it isn't
1186        registered, we don't really want to register a dummy one
1187        because we don't know what it's type and default value should
1188        be.  These are solvable problems (e.g., make a re-registration
1189        overwrite everything), but it's far simpler to just leave the
1190        registered table alone and set an environment variable with the
1191        desired value.  The environment variable will get picked up
1192        during a nromal parameter lookup, and all will be well. */
1193 
1194     if (NULL != option->clo_mca_param_env_var) {
1195         switch(option->clo_type) {
1196         case OPAL_CMD_LINE_TYPE_STRING:
1197         case OPAL_CMD_LINE_TYPE_INT:
1198         case OPAL_CMD_LINE_TYPE_SIZE_T:
1199             opal_setenv(option->clo_mca_param_env_var, sval, true, &environ);
1200             break;
1201         case OPAL_CMD_LINE_TYPE_BOOL:
1202             opal_setenv(option->clo_mca_param_env_var, "1", true, &environ);
1203             break;
1204         default:
1205             break;
1206         }
1207     }
1208 
1209     /* Set variable */
1210 
1211     if (NULL != option->clo_variable_dest) {
1212         switch(option->clo_type) {
1213         case OPAL_CMD_LINE_TYPE_STRING:
1214             *((char**) option->clo_variable_dest) = strdup(sval);
1215             break;
1216         case OPAL_CMD_LINE_TYPE_INT:
1217             /* check to see that the value given to us truly is an int */
1218             for (i=0; i < strlen(sval); i++) {
1219                 if (!isdigit(sval[i]) && '-' != sval[i]) {
1220                     /* show help isn't going to be available yet, so just
1221                      * print the msg
1222                      */
1223                     fprintf(stderr, "----------------------------------------------------------------------------\n");
1224                     fprintf(stderr, "Open MPI has detected that a parameter given to a command line\n");
1225                     fprintf(stderr, "option does not match the expected format:\n\n");
1226                     if (NULL != option->clo_long_name) {
1227                         fprintf(stderr, "  Option: %s\n", option->clo_long_name);
1228                     } else if ('\0' != option->clo_short_name) {
1229                         fprintf(stderr, "  Option: %c\n", option->clo_short_name);
1230                     } else {
1231                         fprintf(stderr, "  Option: <unknown>\n");
1232                     }
1233                     fprintf(stderr, "  Param:  %s\n\n", sval);
1234                     fprintf(stderr, "This is frequently caused by omitting to provide the parameter\n");
1235                     fprintf(stderr, "to an option that requires one. Please check the command line and try again.\n");
1236                     fprintf(stderr, "----------------------------------------------------------------------------\n");
1237                     return OPAL_ERR_SILENT;
1238                 }
1239             }
1240             *((int*) option->clo_variable_dest) = ival;
1241             break;
1242         case OPAL_CMD_LINE_TYPE_SIZE_T:
1243             /* check to see that the value given to us truly is a size_t */
1244             for (i=0; i < strlen(sval); i++) {
1245                 if (!isdigit(sval[i]) && '-' != sval[i]) {
1246                     /* show help isn't going to be available yet, so just
1247                      * print the msg
1248                      */
1249                     fprintf(stderr, "----------------------------------------------------------------------------\n");
1250                     fprintf(stderr, "Open MPI has detected that a parameter given to a command line\n");
1251                     fprintf(stderr, "option does not match the expected format:\n\n");
1252                     if (NULL != option->clo_long_name) {
1253                         fprintf(stderr, "  Option: %s\n", option->clo_long_name);
1254                     } else if ('\0' != option->clo_short_name) {
1255                         fprintf(stderr, "  Option: %c\n", option->clo_short_name);
1256                     } else {
1257                         fprintf(stderr, "  Option: <unknown>\n");
1258                     }
1259                     fprintf(stderr, "  Param:  %s\n\n", sval);
1260                     fprintf(stderr, "This is frequently caused by omitting to provide the parameter\n");
1261                     fprintf(stderr, "to an option that requires one. Please check the command line and try again.\n");
1262                     fprintf(stderr, "----------------------------------------------------------------------------\n");
1263                     return OPAL_ERR_SILENT;
1264                 }
1265             }
1266             *((size_t*) option->clo_variable_dest) = lval;
1267             break;
1268         case OPAL_CMD_LINE_TYPE_BOOL:
1269             *((bool*) option->clo_variable_dest) = 1;
1270             break;
1271         default:
1272             break;
1273         }
1274     }
1275     return OPAL_SUCCESS;
1276 }
1277 
1278 
1279 /*
1280  * Helper function to qsort_callback
1281  */
1282 static void fill(const ompi_cmd_line_option_t *a, char result[3][BUFSIZ])
1283 {
1284     int i = 0;
1285 
1286     result[0][0] = '\0';
1287     result[1][0] = '\0';
1288     result[2][0] = '\0';
1289 
1290     if ('\0' != a->clo_short_name) {
1291         snprintf(&result[i][0], BUFSIZ, "%c", a->clo_short_name);
1292         ++i;
1293     }
1294     if (NULL != a->clo_single_dash_name) {
1295         snprintf(&result[i][0], BUFSIZ, "%s", a->clo_single_dash_name);
1296         ++i;
1297     }
1298     if (NULL != a->clo_long_name) {
1299         snprintf(&result[i][0], BUFSIZ, "%s", a->clo_long_name);
1300         ++i;
1301     }
1302 }
1303 
1304 
1305 static int qsort_callback(const void *aa, const void *bb)
1306 {
1307     int ret, i;
1308     char str1[3][BUFSIZ], str2[3][BUFSIZ];
1309     const ompi_cmd_line_option_t *a = *((const ompi_cmd_line_option_t**) aa);
1310     const ompi_cmd_line_option_t *b = *((const ompi_cmd_line_option_t**) bb);
1311 
1312     /* Icky comparison of command line options.  There are multiple
1313        forms of each command line option, so we first have to check
1314        which forms each option has.  Compare, in order: short name,
1315        single-dash name, long name. */
1316 
1317     fill(a, str1);
1318     fill(b, str2);
1319 
1320     for (i = 0; i < 3; ++i) {
1321         if (0 != (ret = strcasecmp(str1[i], str2[i]))) {
1322             return ret;
1323         }
1324     }
1325 
1326     /* Shrug -- they must be equal */
1327 
1328     return 0;
1329 }
1330 
1331 
1332 /*
1333  * Helper function to find the option type specified in the help
1334  * command.
1335  */
1336 static opal_cmd_line_otype_t get_help_otype(opal_cmd_line_t *cmd)
1337 {
1338     /* Initialize to NULL, if it remains so, the user asked for
1339        "full" help output */
1340     opal_cmd_line_otype_t otype = OPAL_CMD_LINE_OTYPE_NULL;
1341     char *arg;
1342 
1343     arg = opal_cmd_line_get_param(cmd, "help", 0, 0);
1344 
1345     /* If not "help", check for "h" */
1346     if(NULL == arg) {
1347         arg = opal_cmd_line_get_param(cmd, "h", 0, 0);
1348     }
1349 
1350     /* If arg is still NULL, give them the General info by default */
1351     if(NULL == arg) {
1352         arg = "general";
1353     }
1354 
1355     if (0 == strcmp(arg, "debug")) {
1356         otype = OPAL_CMD_LINE_OTYPE_DEBUG;
1357     } else if (0 == strcmp(arg, "output")) {
1358         otype = OPAL_CMD_LINE_OTYPE_OUTPUT;
1359     } else if (0 == strcmp(arg, "input")) {
1360         otype = OPAL_CMD_LINE_OTYPE_INPUT;
1361     } else if (0 == strcmp(arg, "mapping")) {
1362         otype = OPAL_CMD_LINE_OTYPE_MAPPING;
1363     } else if (0 == strcmp(arg, "ranking")) {
1364         otype = OPAL_CMD_LINE_OTYPE_RANKING;
1365     } else if (0 == strcmp(arg, "binding")) {
1366         otype = OPAL_CMD_LINE_OTYPE_BINDING;
1367     } else if (0 == strcmp(arg, "devel")) {
1368         otype = OPAL_CMD_LINE_OTYPE_DEVEL;
1369     } else if (0 == strcmp(arg, "compatibility")) {
1370         otype = OPAL_CMD_LINE_OTYPE_COMPAT;
1371     } else if (0 == strcmp(arg, "launch")) {
1372         otype = OPAL_CMD_LINE_OTYPE_LAUNCH;
1373     } else if (0 == strcmp(arg, "dvm")) {
1374         otype = OPAL_CMD_LINE_OTYPE_DVM;
1375     } else if (0 == strcmp(arg, "general")) {
1376         otype = OPAL_CMD_LINE_OTYPE_GENERAL;
1377     } else if (0 == strcmp(arg, "parsable")) {
1378         otype = OPAL_CMD_LINE_OTYPE_PARSABLE;
1379     }
1380 
1381     return otype;
1382 }
1383 
1384 /*
1385  * Helper function to build a parsable string for the help
1386  * output.
1387  */
1388 static char *build_parsable(ompi_cmd_line_option_t *option) {
1389     char *line;
1390     int length;
1391 
1392     length = snprintf(NULL, 0, "%c:%s:%s:%d:%s\n", option->clo_short_name, option->clo_single_dash_name,
1393                       option->clo_long_name, option->clo_num_params, option->clo_description);
1394 
1395     line = (char *)malloc(length * sizeof(char));
1396 
1397     if('\0' == option->clo_short_name) {
1398         snprintf(line, length, "0:%s:%s:%d:%s\n", option->clo_single_dash_name, option->clo_long_name,
1399                  option->clo_num_params, option->clo_description);
1400     } else {
1401         snprintf(line, length, "%c:%s:%s:%d:%s\n", option->clo_short_name, option->clo_single_dash_name,
1402                  option->clo_long_name, option->clo_num_params, option->clo_description);
1403     }
1404 
1405     return line;
1406 }

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