root/lib/common/cmdline.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bump_verbosity
  2. pcmk__new_common_args
  3. free_common_args
  4. pcmk__build_arg_context
  5. pcmk__free_arg_context
  6. pcmk__add_main_args
  7. pcmk__add_arg_group
  8. pcmk__cmdline_preproc
  9. G_GNUC_PRINTF

   1 /*
   2  * Copyright 2019 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU Lesser General Public License
   7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #ifndef _GNU_SOURCE
  11 #  define _GNU_SOURCE
  12 #endif
  13 
  14 #ifndef PCMK__CONFIG_H
  15 #  define PCMK__CONFIG_H
  16 #  include <config.h>
  17 #endif
  18 
  19 #include <glib.h>
  20 
  21 #include <crm/crm.h>
  22 #include <crm/common/cmdline_internal.h>
  23 #include <crm/common/strings_internal.h>
  24 #include <crm/common/util.h>
  25 
  26 static gboolean
  27 bump_verbosity(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
  28     pcmk__common_args_t *common_args = (pcmk__common_args_t *) data;
  29     common_args->verbosity++;
  30     return TRUE;
  31 }
  32 
  33 pcmk__common_args_t *
  34 pcmk__new_common_args(const char *summary)
     /* [previous][next][first][last][top][bottom][index][help] */
  35 {
  36     pcmk__common_args_t *args = NULL;
  37 
  38     args = calloc(1, sizeof(pcmk__common_args_t));
  39     if (args == NULL) {
  40         crm_exit(crm_errno2exit(-ENOMEM));
  41     }
  42 
  43     args->summary = strdup(summary);
  44     if (args->summary == NULL) {
  45         crm_exit(crm_errno2exit(-ENOMEM));
  46     }
  47 
  48     return args;
  49 }
  50 
  51 static void
  52 free_common_args(gpointer data) {
     /* [previous][next][first][last][top][bottom][index][help] */
  53     pcmk__common_args_t *common_args = (pcmk__common_args_t *) data;
  54 
  55     free(common_args->summary);
  56     free(common_args->output_ty);
  57     free(common_args->output_dest);
  58 
  59     if (common_args->output_as_descr != NULL) {
  60         free(common_args->output_as_descr);
  61     }
  62 
  63     free(common_args);
  64 }
  65 
  66 GOptionContext *
  67 pcmk__build_arg_context(pcmk__common_args_t *common_args, const char *fmts,
     /* [previous][next][first][last][top][bottom][index][help] */
  68                         GOptionGroup **output_group, const char *param_string) {
  69     char *desc = crm_strdup_printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
  70     GOptionContext *context;
  71     GOptionGroup *main_group;
  72 
  73     GOptionEntry main_entries[3] = {
  74         { "version", '$', 0, G_OPTION_ARG_NONE, &(common_args->version),
  75           "Display software version and exit",
  76           NULL },
  77         { "verbose", 'V', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, bump_verbosity,
  78           "Increase debug output (may be specified multiple times)",
  79           NULL },
  80 
  81         { NULL }
  82     };
  83 
  84     main_group = g_option_group_new(NULL, "Application Options:", NULL, common_args, free_common_args);
  85     g_option_group_add_entries(main_group, main_entries);
  86 
  87     context = g_option_context_new(param_string);
  88     g_option_context_set_summary(context, common_args->summary);
  89     g_option_context_set_description(context, desc);
  90     g_option_context_set_main_group(context, main_group);
  91 
  92     if (fmts != NULL) {
  93         GOptionEntry output_entries[3] = {
  94             { "output-as", 0, 0, G_OPTION_ARG_STRING, &(common_args->output_ty),
  95               NULL,
  96               "FORMAT" },
  97             { "output-to", 0, 0, G_OPTION_ARG_STRING, &(common_args->output_dest),
  98               "Specify file name for output (or \"-\" for stdout)", "DEST" },
  99 
 100             { NULL }
 101         };
 102 
 103         if (*output_group == NULL) {
 104             *output_group = g_option_group_new("output", "Output Options:", "Show output help", NULL, NULL);
 105         }
 106 
 107         common_args->output_as_descr = crm_strdup_printf("Specify output format as one of: %s", fmts);
 108         output_entries[0].description = common_args->output_as_descr;
 109         g_option_group_add_entries(*output_group, output_entries);
 110         g_option_context_add_group(context, *output_group);
 111     }
 112 
 113     free(desc);
 114 
 115     // main_group is now owned by context, we don't free it here
 116     // cppcheck-suppress memleak
 117     return context;
 118 }
 119 
 120 void
 121 pcmk__free_arg_context(GOptionContext *context) {
     /* [previous][next][first][last][top][bottom][index][help] */
 122     if (context == NULL) {
 123         return;
 124     }
 125 
 126     g_option_context_free(context);
 127 }
 128 
 129 void
 130 pcmk__add_main_args(GOptionContext *context, GOptionEntry entries[])
     /* [previous][next][first][last][top][bottom][index][help] */
 131 {
 132     GOptionGroup *main_group = g_option_context_get_main_group(context);
 133 
 134     g_option_group_add_entries(main_group, entries);
 135 }
 136 
 137 void
 138 pcmk__add_arg_group(GOptionContext *context, const char *name,
     /* [previous][next][first][last][top][bottom][index][help] */
 139                     const char *header, const char *desc,
 140                     GOptionEntry entries[])
 141 {
 142     GOptionGroup *group = NULL;
 143 
 144     group = g_option_group_new(name, header, desc, NULL, NULL);
 145     g_option_group_add_entries(group, entries);
 146     g_option_context_add_group(context, group);
 147     // group is now owned by context, we don't free it here
 148     // cppcheck-suppress memleak
 149 }
 150 
 151 gchar **
 152 pcmk__cmdline_preproc(char **argv, const char *special) {
     /* [previous][next][first][last][top][bottom][index][help] */
 153     gchar **retval = NULL;
 154     GPtrArray *arr = NULL;
 155     bool saw_dash_dash = false;
 156 
 157     if (argv == NULL) {
 158         return retval;
 159     }
 160 
 161     if (g_get_prgname() == NULL && argv && *argv) {
 162         gchar *basename = g_path_get_basename(*argv);
 163 
 164         g_set_prgname(basename);
 165         g_free(basename);
 166     }
 167 
 168     arr = g_ptr_array_new();
 169 
 170     for (int i = 0; argv[i] != NULL; i++) {
 171         /* If this is the first time we saw "--" in the command line, set
 172          * a flag so we know to just copy everything after it over.  We also
 173          * want to copy the "--" over so whatever actually parses the command
 174          * line when we're done knows where arguments end.
 175          */
 176         if (saw_dash_dash == false && strcmp(argv[i], "--") == 0) {
 177             saw_dash_dash = true;
 178         }
 179 
 180         if (saw_dash_dash == true) {
 181             g_ptr_array_add(arr, g_strdup(argv[i]));
 182             continue;
 183         }
 184 
 185         /* This is just a dash by itself.  That could indicate stdin/stdout, or
 186          * it could be user error.  Copy it over and let glib figure it out.
 187          */
 188         if (pcmk__str_eq(argv[i], "-", pcmk__str_casei)) {
 189             g_ptr_array_add(arr, g_strdup(argv[i]));
 190             continue;
 191         }
 192 
 193         /* This is a short argument, or perhaps several.  Iterate over it
 194          * and explode them out into individual arguments.
 195          */
 196         if (g_str_has_prefix(argv[i], "-") && !g_str_has_prefix(argv[i], "--")) {
 197             /* Skip over leading dash */
 198             char *ch = argv[i]+1;
 199 
 200             while (*ch != '\0') {
 201                 /* This is a special short argument that takes an option.  getopt
 202                  * allows values to be interspersed with a list of arguments, but
 203                  * glib does not.  Grab both the argument and its value and
 204                  * separate them into a new argument.
 205                  */
 206                 if (strchr(special, *ch) != NULL) {
 207                     /* The argument does not occur at the end of this string of
 208                      * arguments.  Take everything through the end as its value.
 209                      */
 210                     if (*(ch+1) != '\0') {
 211                         g_ptr_array_add(arr, g_strdup_printf("-%c", *ch));
 212                         g_ptr_array_add(arr, g_strdup(ch+1));
 213                         break;
 214 
 215                     /* The argument occurs at the end of this string.  Hopefully
 216                      * whatever comes next in argv is its value.  It may not be,
 217                      * but that is not for us to decide.
 218                      */
 219                     } else {
 220                         g_ptr_array_add(arr, g_strdup_printf("-%c", *ch));
 221                         ch++;
 222                     }
 223 
 224                 /* This is a regular short argument.  Just copy it over. */
 225                 } else {
 226                     g_ptr_array_add(arr, g_strdup_printf("-%c", *ch));
 227                     ch++;
 228                 }
 229             }
 230 
 231         /* This is a long argument, or an option, or something else.
 232          * Copy it over - everything else is copied, so this keeps it easy for
 233          * the caller to know what to do with the memory when it's done.
 234          */
 235         } else {
 236             g_ptr_array_add(arr, g_strdup(argv[i]));
 237         }
 238     }
 239 
 240     /* Convert the GPtrArray into a gchar **, which the command line parsing
 241      * code knows how to deal with.  Then we can free the array (but not its
 242      * contents).
 243      */
 244     retval = calloc(arr->len+1, sizeof(char *));
 245     for (int i = 0; i < arr->len; i++) {
 246         retval[i] = (gchar *) g_ptr_array_index(arr, i);
 247     }
 248 
 249     g_ptr_array_free(arr, FALSE);
 250 
 251     return retval;
 252 }
 253 
 254 G_GNUC_PRINTF(3, 4)
     /* [previous][next][first][last][top][bottom][index][help] */
 255 gboolean
 256 pcmk__force_args(GOptionContext *context, GError **error, const char *format, ...) {
 257     int len = 0;
 258     char *buf = NULL;
 259     gchar **extra_args = NULL;
 260     va_list ap;
 261     gboolean retval = TRUE;
 262 
 263     va_start(ap, format);
 264     len = vasprintf(&buf, format, ap);
 265     CRM_ASSERT(len > 0);
 266     va_end(ap);
 267 
 268     if (!g_shell_parse_argv(buf, NULL, &extra_args, error)) {
 269         g_strfreev(extra_args);
 270         free(buf);
 271         return FALSE;
 272     }
 273 
 274     retval = g_option_context_parse_strv(context, &extra_args, error);
 275 
 276     g_strfreev(extra_args);
 277     free(buf);
 278     return retval;
 279 }

/* [previous][next][first][last][top][bottom][index][help] */