root/tools/iso8601.c

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

DEFINITIONS

This source file includes following definitions.
  1. date_now_cb
  2. modifier_cb
  3. log_time_period
  4. build_arg_context
  5. main

   1 /*
   2  * Copyright 2005-2023 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 General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 #include <crm/crm.h>
  12 #include <crm/common/cmdline_internal.h>
  13 #include <crm/common/iso8601.h>
  14 #include <crm/common/util.h>  /* CRM_ASSERT */
  15 #include <unistd.h>
  16 
  17 #define SUMMARY "Display and parse ISO 8601 dates and times"
  18 
  19 struct {
  20     char *date_time_s;
  21     gchar *duration_s;
  22     gchar *expected_s;
  23     gchar *period_s;
  24     int print_options;
  25 } options;
  26 
  27 #define INDENT "                              "
  28 
  29 static gboolean
  30 date_now_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
  31     if (pcmk__str_any_of(option_name, "--now", "-n", NULL)) {
  32         pcmk__str_update(&options.date_time_s, "now");
  33     } else if (pcmk__str_any_of(option_name, "--date", "-d", NULL)) {
  34         pcmk__str_update(&options.date_time_s, optarg);
  35     }
  36 
  37     return TRUE;
  38 }
  39 
  40 static gboolean
  41 modifier_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
  42     if (pcmk__str_any_of(option_name, "--seconds", "-s", NULL)) {
  43         options.print_options |= crm_time_seconds;
  44     } else if (pcmk__str_any_of(option_name, "--epoch", "-S", NULL)) {
  45         options.print_options |= crm_time_epoch;
  46     } else if (pcmk__str_any_of(option_name, "--local", "-L", NULL)) {
  47         options.print_options |= crm_time_log_with_timezone;
  48     } else if (pcmk__str_any_of(option_name, "--ordinal", "-O", NULL)) {
  49         options.print_options |= crm_time_ordinal;
  50     } else if (pcmk__str_any_of(option_name, "--week", "-W", NULL)) {
  51         options.print_options |= crm_time_weeks;
  52     }
  53 
  54     return TRUE;
  55 }
  56 
  57 static GOptionEntry command_entries[] = {
  58     { "now", 'n', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, date_now_cb,
  59       "Display the current date/time",
  60       NULL },
  61 
  62     { "date", 'd', 0, G_OPTION_ARG_CALLBACK, date_now_cb,
  63       "Parse an ISO 8601 date/time (for example,\n"
  64       INDENT "'2019-09-24 00:30:00 +01:00' or '2019-040')",
  65       "DATE" },
  66 
  67     { "period", 'p', 0, G_OPTION_ARG_STRING, &options.period_s,
  68       "Parse an ISO 8601 period (interval) with start time (for example,\n"
  69       INDENT "'2005-040/2005-043')",
  70       "PERIOD" },
  71 
  72     { "duration", 'D', 0, G_OPTION_ARG_STRING, &options.duration_s,
  73       "Parse an ISO 8601 duration (for example, 'P1M')",
  74       "DURATION" },
  75 
  76     { "expected", 'E', 0, G_OPTION_ARG_STRING, &options.expected_s,
  77       "Exit with error status if result does not match this text.\n"
  78       INDENT "Requires: -n or -d",
  79       "TEXT" },
  80 
  81     { NULL }
  82 };
  83 
  84 static GOptionEntry modifier_entries[] = {
  85     { "seconds", 's', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, modifier_cb,
  86       "Show result as a seconds since 0000-001 00:00:00Z",
  87       NULL },
  88 
  89     { "epoch", 'S', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, modifier_cb,
  90       "Show result as a seconds since EPOCH (1970-001 00:00:00Z)",
  91       NULL },
  92 
  93     { "local", 'L', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, modifier_cb,
  94       "Show result as a 'local' date/time",
  95       NULL },
  96 
  97     { "ordinal", 'O', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, modifier_cb,
  98       "Show result as an 'ordinal' date/time",
  99       NULL },
 100 
 101     { "week", 'W', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, modifier_cb,
 102       "Show result as an 'calendar week' date/time",
 103       NULL },
 104 
 105     { NULL }
 106 };
 107 
 108 static void
 109 log_time_period(int log_level, crm_time_period_t * dtp, int flags)
     /* [previous][next][first][last][top][bottom][index][help] */
 110 {
 111     char *start = crm_time_as_string(dtp->start, flags);
 112     char *end = crm_time_as_string(dtp->end, flags);
 113 
 114     CRM_ASSERT(start != NULL && end != NULL);
 115     do_crm_log(log_level, "Period: %s to %s", start, end);
 116     free(start);
 117     free(end);
 118 }
 119 
 120 static GOptionContext *
 121 build_arg_context(pcmk__common_args_t *args) {
     /* [previous][next][first][last][top][bottom][index][help] */
 122     GOptionContext *context = NULL;
 123 
 124     const char *description = "For more information on the ISO 8601 standard, see " \
 125                               "https://en.wikipedia.org/wiki/ISO_8601";
 126 
 127     context = pcmk__build_arg_context(args, NULL, NULL, NULL);
 128     g_option_context_set_description(context, description);
 129 
 130     pcmk__add_arg_group(context, "commands", "Commands:",
 131                         "Show command options", command_entries);
 132     pcmk__add_arg_group(context, "modifiers", "Output modifiers:",
 133                         "Show output modifiers", modifier_entries);
 134 
 135     return context;
 136 }
 137 
 138 int
 139 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 140 {
 141     crm_exit_t exit_code = CRM_EX_OK;
 142     crm_time_t *duration = NULL;
 143     crm_time_t *date_time = NULL;
 144 
 145     GError *error = NULL;
 146 
 147     pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
 148     GOptionContext *context = build_arg_context(args);
 149     gchar **processed_args = pcmk__cmdline_preproc(argv, "dpDE");
 150 
 151     if (!g_option_context_parse_strv(context, &processed_args, &error)) {
 152         exit_code = CRM_EX_USAGE;
 153         goto done;
 154     }
 155 
 156     pcmk__cli_init_logging("iso8601", args->verbosity);
 157 
 158     if (args->version) {
 159         g_strfreev(processed_args);
 160         pcmk__free_arg_context(context);
 161         /* FIXME:  When iso8601 is converted to use formatted output, this can go. */
 162         pcmk__cli_help('v');
 163     }
 164 
 165     if (pcmk__str_eq("now", options.date_time_s, pcmk__str_casei)) {
 166         date_time = crm_time_new(NULL);
 167 
 168         if (date_time == NULL) {
 169             exit_code = CRM_EX_SOFTWARE;
 170             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 171                         "Internal error: couldn't determine 'now'!");
 172             goto done;
 173         }
 174 
 175         crm_time_log(LOG_TRACE, "Current date/time", date_time,
 176                      crm_time_ordinal | crm_time_log_date | crm_time_log_timeofday);
 177         crm_time_log(LOG_STDOUT, "Current date/time", date_time,
 178                      options.print_options | crm_time_log_date | crm_time_log_timeofday);
 179 
 180     } else if (options.date_time_s) {
 181         date_time = crm_time_new(options.date_time_s);
 182 
 183         if (date_time == NULL) {
 184             exit_code = CRM_EX_INVALID_PARAM;
 185             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 186                         "Invalid date/time specified: %s", options.date_time_s);
 187             goto done;
 188         }
 189 
 190         crm_time_log(LOG_TRACE, "Date", date_time,
 191                      crm_time_ordinal | crm_time_log_date | crm_time_log_timeofday);
 192         crm_time_log(LOG_STDOUT, "Date", date_time,
 193                      options.print_options | crm_time_log_date | crm_time_log_timeofday);
 194     }
 195 
 196     if (options.duration_s) {
 197         duration = crm_time_parse_duration(options.duration_s);
 198 
 199         if (duration == NULL) {
 200             exit_code = CRM_EX_INVALID_PARAM;
 201             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 202                         "Invalid duration specified: %s", options.duration_s);
 203             goto done;
 204         }
 205 
 206         crm_time_log(LOG_TRACE, "Duration", duration, crm_time_log_duration);
 207         crm_time_log(LOG_STDOUT, "Duration", duration,
 208                      options.print_options | crm_time_log_duration);
 209     }
 210 
 211     if (options.period_s) {
 212         crm_time_period_t *period = crm_time_parse_period(options.period_s);
 213 
 214         if (period == NULL) {
 215             exit_code = CRM_EX_INVALID_PARAM;
 216             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 217                         "Invalid interval specified: %s", options.period_s);
 218             goto done;
 219         }
 220 
 221         log_time_period(LOG_TRACE, period,
 222                         options.print_options | crm_time_log_date | crm_time_log_timeofday);
 223         log_time_period(LOG_STDOUT, period,
 224                         options.print_options | crm_time_log_date | crm_time_log_timeofday);
 225         crm_time_free_period(period);
 226     }
 227 
 228     if (date_time && duration) {
 229         crm_time_t *later = crm_time_add(date_time, duration);
 230 
 231         if (later == NULL) {
 232             exit_code = CRM_EX_SOFTWARE;
 233             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 234                         "Unable to calculate ending time of %s plus %s",
 235                         options.date_time_s, options.duration_s);
 236             goto done;
 237         }
 238 
 239         crm_time_log(LOG_TRACE, "Duration ends at", later,
 240                      crm_time_ordinal | crm_time_log_date | crm_time_log_timeofday);
 241         crm_time_log(LOG_STDOUT, "Duration ends at", later,
 242                      options.print_options | crm_time_log_date | crm_time_log_timeofday |
 243                      crm_time_log_with_timezone);
 244 
 245         if (options.expected_s) {
 246             char *dt_s = crm_time_as_string(later,
 247                                             options.print_options | crm_time_log_date |
 248                                             crm_time_log_timeofday);
 249             if (!pcmk__str_eq(options.expected_s, dt_s, pcmk__str_casei)) {
 250                 exit_code = CRM_EX_ERROR;
 251                 goto done;
 252             }
 253             free(dt_s);
 254         }
 255         crm_time_free(later);
 256 
 257     } else if (date_time && options.expected_s) {
 258         char *dt_s = crm_time_as_string(date_time,
 259                                         options.print_options | crm_time_log_date | crm_time_log_timeofday);
 260 
 261         if (!pcmk__str_eq(options.expected_s, dt_s, pcmk__str_casei)) {
 262             exit_code = CRM_EX_ERROR;
 263             goto done;
 264         }
 265         free(dt_s);
 266     }
 267 
 268 done:
 269     crm_time_free(date_time);
 270     crm_time_free(duration);
 271 
 272     g_strfreev(processed_args);
 273     pcmk__free_arg_context(context);
 274 
 275     free(options.date_time_s);
 276     g_free(options.duration_s);
 277     g_free(options.expected_s);
 278     g_free(options.period_s);
 279 
 280     pcmk__output_and_clear_error(&error, NULL);
 281     crm_exit(exit_code);
 282 }

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