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

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