Branch data Line data Source code
1 : : /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 : : *
3 : : * Copyright © 2018 Endless Mobile, Inc.
4 : : *
5 : : * This library is free software; you can redistribute it and/or
6 : : * modify it under the terms of the GNU Lesser General Public
7 : : * License as published by the Free Software Foundation; either
8 : : * version 2.1 of the License, or (at your option) any later version.
9 : : *
10 : : * This library is distributed in the hope that it will be useful,
11 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : : * Lesser General Public License for more details.
14 : : *
15 : : * You should have received a copy of the GNU Lesser General Public
16 : : * License along with this library; if not, write to the Free Software
17 : : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 : : *
19 : : * Authors:
20 : : * - Philip Withnall <withnall@endlessm.com>
21 : : */
22 : :
23 : : #include "config.h"
24 : :
25 : : #include <gio/gio.h>
26 : : #include <glib.h>
27 : : #include <glib/gi18n.h>
28 : : #include <glib-object.h>
29 : : #include <glib-unix.h>
30 : : #include <libmogwai-tariff/tariff-builder.h>
31 : : #include <libmogwai-tariff/tariff-loader.h>
32 : : #include <locale.h>
33 : : #include <signal.h>
34 : : #include <stdio.h>
35 : : #include <string.h>
36 : : #include <unistd.h>
37 : :
38 : :
39 : : /* FIXME: Add tests for this client. */
40 : :
41 : : /* Error handling. */
42 : : typedef enum
43 : : {
44 : : MWT_CLIENT_ERROR_INVALID_OPTIONS = 0,
45 : : MWT_CLIENT_ERROR_LOOKUP_FAILED,
46 : : } MwtClientError;
47 : : #define MWT_CLIENT_N_ERRORS (MWT_CLIENT_ERROR_INVALID_OPTIONS + 1)
48 : :
49 : : GQuark mwt_client_error_quark (void);
50 : : #define MWT_CLIENT_ERROR mwt_client_error_quark ()
51 : :
52 [ + + ]: 3 : G_DEFINE_QUARK (MwtClientError, mwt_client_error)
53 : :
54 : : /* Exit statuses. */
55 : : typedef enum
56 : : {
57 : : /* Success. */
58 : : EXIT_OK = 0,
59 : : /* Error parsing command line options. */
60 : : EXIT_INVALID_OPTIONS = 1,
61 : : /* Specified period couldn’t be found (for ‘lookup’ command). */
62 : : EXIT_LOOKUP_FAILED = 2,
63 : : /* Command failed. */
64 : : EXIT_FAILED = 3,
65 : : } ExitStatus;
66 : :
67 : : /* Main function stuff. */
68 : : typedef struct
69 : : {
70 : : GCancellable *cancellable; /* (owned) */
71 : : gint *signum_out;
72 : : guint handler_id;
73 : : } SignalData;
74 : :
75 : : static void
76 : 16 : signal_data_clear (SignalData *data)
77 : : {
78 [ + - ]: 16 : g_clear_object (&data->cancellable);
79 [ + - ]: 16 : g_clear_handle_id (&data->handler_id, g_source_remove);
80 : 16 : }
81 : :
82 : 16 : G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (SignalData, signal_data_clear)
83 : :
84 : : static gboolean
85 : 0 : handle_signal (SignalData *signal_data,
86 : : gint signum)
87 : : {
88 : 0 : *signal_data->signum_out = signum;
89 : 0 : g_cancellable_cancel (signal_data->cancellable);
90 : :
91 : : /* Remove the signal handler so when we raise again later, we don’t enter a
92 : : * loop. */
93 : 0 : signal_data->handler_id = 0;
94 : 0 : return G_SOURCE_REMOVE;
95 : : }
96 : :
97 : : static gboolean
98 : 0 : signal_sigint_cb (gpointer user_data)
99 : : {
100 : 0 : SignalData *signal_data = user_data;
101 : :
102 : 0 : return handle_signal (signal_data, SIGINT);
103 : : }
104 : :
105 : : static gboolean
106 : 0 : signal_sigterm_cb (gpointer user_data)
107 : : {
108 : 0 : SignalData *signal_data = user_data;
109 : :
110 : 0 : return handle_signal (signal_data, SIGTERM);
111 : : }
112 : :
113 : : /* Output handling functions. */
114 : : static gchar *
115 : 5 : dump_period (MwtPeriod *period,
116 : : gboolean use_colour)
117 : : {
118 : 10 : g_autoptr(GString) str = g_string_new ("");
119 : 5 : GDateTime *start = mwt_period_get_start (period);
120 : 5 : GDateTime *end = mwt_period_get_end (period);
121 : :
122 : 10 : g_autofree gchar *start_str = g_date_time_format (start, "%Y-%m-%dT%H:%M:%S%:::z");
123 : 10 : g_autofree gchar *end_str = g_date_time_format (end, "%Y-%m-%dT%H:%M:%S%:::z");
124 [ - + ]: 5 : if (use_colour)
125 : 0 : g_string_append (str, "\033[1m"); /* bold */
126 : 5 : g_string_append_printf (str, _("Period %s – %s:"), start_str, end_str);
127 [ - + ]: 5 : if (use_colour)
128 : 0 : g_string_append (str, "\033[0m"); /* reset */
129 : 5 : g_string_append_c (str, '\n');
130 : :
131 : 5 : g_autofree gchar *repeat_str = NULL;
132 : 5 : guint repeat_period = mwt_period_get_repeat_period (period);
133 [ + - + - : 5 : switch (mwt_period_get_repeat_type (period))
- + - ]
134 : : {
135 : 2 : case MWT_PERIOD_REPEAT_NONE:
136 : 2 : repeat_str = g_strdup (_("Never repeats"));
137 : 2 : break;
138 : 0 : case MWT_PERIOD_REPEAT_HOUR:
139 : 0 : repeat_str = g_strdup_printf (g_dngettext (NULL,
140 : : "Repeats every %u hour",
141 : : "Repeats every %u hours",
142 : : repeat_period),
143 : : repeat_period);
144 : 0 : break;
145 : 1 : case MWT_PERIOD_REPEAT_DAY:
146 : 1 : repeat_str = g_strdup_printf (g_dngettext (NULL,
147 : : "Repeats every %u day",
148 : : "Repeats every %u days",
149 : : repeat_period),
150 : : repeat_period);
151 : 1 : break;
152 : 0 : case MWT_PERIOD_REPEAT_WEEK:
153 : 0 : repeat_str = g_strdup_printf (g_dngettext (NULL,
154 : : "Repeats every %u week",
155 : : "Repeats every %u weeks",
156 : : repeat_period),
157 : : repeat_period);
158 : 0 : break;
159 : 0 : case MWT_PERIOD_REPEAT_MONTH:
160 : 0 : repeat_str = g_strdup_printf (g_dngettext (NULL,
161 : : "Repeats every %u month",
162 : : "Repeats every %u months",
163 : : repeat_period),
164 : : repeat_period);
165 : 0 : break;
166 : 2 : case MWT_PERIOD_REPEAT_YEAR:
167 : 2 : repeat_str = g_strdup_printf (g_dngettext (NULL,
168 : : "Repeats every %u year",
169 : : "Repeats every %u years",
170 : : repeat_period),
171 : : repeat_period);
172 : 2 : break;
173 : 0 : default:
174 : 0 : g_assert_not_reached ();
175 : : }
176 : :
177 : 5 : g_string_append_printf (str, " • %s\n", repeat_str);
178 : :
179 : : /* Properties. */
180 : 5 : guint64 capacity_limit = mwt_period_get_capacity_limit (period);
181 : 5 : g_autofree gchar *capacity_limit_str = NULL;
182 : 5 : g_autofree gchar *capacity_limit_value_str = NULL;
183 [ + + ]: 5 : if (capacity_limit == G_MAXUINT64)
184 : 2 : capacity_limit_value_str = g_strdup (_("unlimited"));
185 : : else
186 : 3 : capacity_limit_value_str = g_format_size_full (capacity_limit,
187 : : G_FORMAT_SIZE_LONG_FORMAT);
188 : 5 : capacity_limit_str = g_strdup_printf (_("Capacity limit: %s"),
189 : : capacity_limit_value_str);
190 : 5 : g_string_append_printf (str, " • %s\n", capacity_limit_str);
191 : :
192 : 5 : return g_string_free (g_steal_pointer (&str), FALSE);
193 : : }
194 : :
195 : : static gchar *
196 : 3 : dump_tariff (MwtTariff *tariff,
197 : : gboolean use_colour)
198 : : {
199 : 6 : g_autoptr(GString) str = g_string_new ("");
200 : :
201 : : /* Add a title and underline it. */
202 [ - + ]: 3 : if (use_colour)
203 : 0 : g_string_append (str, "\033[1;4m"); /* bold, underlined */
204 : :
205 : 6 : g_autofree gchar *title = g_strdup_printf (_("Tariff ‘%s’"), mwt_tariff_get_name (tariff));
206 : 3 : g_string_append (str, title);
207 : 3 : g_string_append_c (str, '\n');
208 : :
209 [ + - ]: 3 : if (!use_colour)
210 : : {
211 [ + + ]: 46 : for (gsize i = 0; i < (gsize) g_utf8_strlen (title, -1); i++)
212 : 43 : g_string_append_c (str, '-');
213 : 3 : g_string_append_c (str, '\n');
214 : : }
215 : :
216 [ - + ]: 3 : if (use_colour)
217 : 0 : g_string_append (str, "\033[0m"); /* reset */
218 : :
219 : 3 : g_string_append_c (str, '\n');
220 : :
221 : 3 : GPtrArray *periods = mwt_tariff_get_periods (tariff);
222 : :
223 [ + + ]: 7 : for (gsize i = 0; i < periods->len; i++)
224 : : {
225 : 4 : MwtPeriod *period = g_ptr_array_index (periods, i);
226 : 8 : g_autofree gchar *out = dump_period (period, use_colour);
227 : 4 : g_string_append (str, out);
228 : : }
229 : :
230 : 3 : return g_string_free (g_steal_pointer (&str), FALSE);
231 : : }
232 : :
233 : : /**
234 : : * load_tariff_from_file:
235 : : * @tariff_path: (type filename): tariff path, relative or absolute
236 : : *
237 : : * Returns: (transfer full): loaded tariff
238 : : */
239 : : static MwtTariff *
240 : 5 : load_tariff_from_file (const gchar *tariff_path,
241 : : GError **error)
242 : : {
243 : 10 : g_autofree gchar *tariff_path_utf8 = g_filename_display_name (tariff_path);
244 : :
245 : : /* Load the file. */
246 : 5 : g_autoptr(GMappedFile) mmap = NULL;
247 : :
248 : 5 : mmap = g_mapped_file_new (tariff_path, FALSE /* read-only */, error);
249 [ - + ]: 5 : if (mmap == NULL)
250 : : {
251 : 0 : g_prefix_error (error, _("Error loading tariff file ‘%s’: "),
252 : : tariff_path_utf8);
253 : 0 : return NULL;
254 : : }
255 : :
256 : 10 : g_autoptr(GBytes) bytes = g_mapped_file_get_bytes (mmap);
257 : :
258 : : /* Load the tariff. */
259 : 10 : g_autoptr(MwtTariffLoader) loader = mwt_tariff_loader_new ();
260 : :
261 [ - + ]: 5 : if (!mwt_tariff_loader_load_from_bytes (loader, bytes, error))
262 : : {
263 : 0 : g_prefix_error (error, _("Error loading tariff file ‘%s’: "),
264 : : tariff_path_utf8);
265 : 0 : return NULL;
266 : : }
267 : :
268 : 5 : MwtTariff *tariff = mwt_tariff_loader_get_tariff (loader);
269 [ - + ]: 5 : g_assert (tariff != NULL);
270 : :
271 : 5 : return g_object_ref (tariff);
272 : : }
273 : :
274 : : static GDateTime *
275 : 10 : date_time_from_string (const gchar *str,
276 : : GError **error)
277 : : {
278 : 10 : g_autoptr(GDateTime) date_time = NULL;
279 : 10 : date_time = g_date_time_new_from_iso8601 (str, NULL);
280 : :
281 [ - + ]: 10 : if (date_time == NULL)
282 : : {
283 : 0 : g_set_error (error, MWT_CLIENT_ERROR, MWT_CLIENT_ERROR_INVALID_OPTIONS,
284 : 0 : _("Invalid ISO 8601 date/time ‘%s’."), str);
285 : 0 : return NULL;
286 : : }
287 : :
288 : 10 : return g_steal_pointer (&date_time);
289 : : }
290 : :
291 : : static gboolean
292 : 4 : repeat_type_from_string (const gchar *str,
293 : : MwtPeriodRepeatType *repeat_type_out,
294 : : GError **error)
295 : : {
296 [ - + ]: 4 : g_return_val_if_fail (repeat_type_out != NULL, FALSE);
297 : :
298 : : const struct
299 : : {
300 : : MwtPeriodRepeatType repeat_type;
301 : : const gchar *str;
302 : : }
303 : 4 : repeat_types[] =
304 : : {
305 : : { MWT_PERIOD_REPEAT_NONE, "none" },
306 : : { MWT_PERIOD_REPEAT_HOUR, "hour" },
307 : : { MWT_PERIOD_REPEAT_DAY, "day" },
308 : : { MWT_PERIOD_REPEAT_WEEK, "week" },
309 : : { MWT_PERIOD_REPEAT_MONTH, "month" },
310 : : { MWT_PERIOD_REPEAT_YEAR, "year" },
311 : : };
312 : :
313 [ - + ]: 4 : if (str == NULL)
314 : 0 : str = "";
315 : :
316 [ + - ]: 11 : for (gsize i = 0; i < G_N_ELEMENTS (repeat_types); i++)
317 : : {
318 [ + + ]: 11 : if (g_str_equal (str, repeat_types[i].str))
319 : : {
320 : 4 : *repeat_type_out = repeat_types[i].repeat_type;
321 : 4 : return TRUE;
322 : : }
323 : : }
324 : :
325 : 0 : g_set_error (error, MWT_CLIENT_ERROR, MWT_CLIENT_ERROR_INVALID_OPTIONS,
326 : 0 : _("Unknown repeat type ‘%s’."), str);
327 : 0 : return FALSE;
328 : : }
329 : :
330 : : /* Accept an unsigned integer (to a guint64) or ‘unlimited’. */
331 : : static gboolean
332 : 4 : capacity_limit_from_string (const gchar *str,
333 : : guint64 *capacity_limit_out,
334 : : GError **error)
335 : : {
336 [ - + ]: 4 : g_return_val_if_fail (capacity_limit_out != NULL, FALSE);
337 : :
338 [ + - + + ]: 4 : if (str != NULL && g_str_equal (str, "unlimited"))
339 : : {
340 : 2 : *capacity_limit_out = G_MAXUINT64;
341 : 2 : return TRUE;
342 : : }
343 : :
344 : 2 : return g_ascii_string_to_unsigned (str, 10, 0, G_MAXUINT64,
345 : : capacity_limit_out, error);
346 : : }
347 : :
348 : : /* Handle a command like
349 : : * mogwai-tariff lookup tariff.file 2018-10-02T10:15:00Z
350 : : * by looking up which period applies at that time, and dumping its properties.
351 : : */
352 : : static gboolean
353 : 2 : handle_lookup (const gchar * const *args,
354 : : gboolean use_colour,
355 : : GError **error)
356 : : {
357 : : /* Parse arguments. */
358 [ + - - + ]: 2 : if (args == NULL || g_strv_length ((gchar **) args) != 2)
359 : : {
360 : 0 : g_set_error_literal (error, MWT_CLIENT_ERROR,
361 : : MWT_CLIENT_ERROR_INVALID_OPTIONS,
362 : 0 : _("A TARIFF and LOOKUP-TIME are required."));
363 : 0 : return FALSE;
364 : : }
365 : :
366 : : /* Note @tariff_path is (type filename) not (type utf8). */
367 : 2 : const gchar *tariff_path = args[0];
368 : 2 : const gchar *lookup_time_str = args[1];
369 : :
370 : 4 : g_autoptr(GDateTime) lookup_time = date_time_from_string (lookup_time_str, error);
371 [ - + ]: 2 : if (lookup_time == NULL)
372 : : {
373 : 0 : g_prefix_error (error, _("Invalid LOOKUP-TIME: "));
374 : 0 : return FALSE;
375 : : }
376 : :
377 : : /* Load the file. */
378 : 4 : g_autoptr(MwtTariff) tariff = load_tariff_from_file (tariff_path, error);
379 [ - + ]: 2 : if (tariff == NULL)
380 : 0 : return FALSE;
381 : :
382 : 2 : MwtPeriod *period = mwt_tariff_lookup_period (tariff, lookup_time);
383 : :
384 [ + + ]: 2 : if (period == NULL)
385 : : {
386 : 1 : g_set_error (error, MWT_CLIENT_ERROR, MWT_CLIENT_ERROR_LOOKUP_FAILED,
387 : 1 : _("No period matches the given date/time."));
388 : 1 : return FALSE;
389 : : }
390 : : else
391 : : {
392 : 2 : g_autofree gchar *out = dump_period (period, use_colour);
393 : 1 : g_print ("%s", out);
394 : : }
395 : :
396 : 1 : return TRUE;
397 : : }
398 : :
399 : : /* Handle a command like
400 : : * mogwai-tariff dump tariff.file
401 : : * by dumping all the periods from that file, plus the file metadata.
402 : : */
403 : : static gboolean
404 : 3 : handle_dump (const gchar * const *args,
405 : : gboolean use_colour,
406 : : GError **error)
407 : : {
408 : : /* Parse arguments. */
409 [ + - - + ]: 3 : if (args == NULL || g_strv_length ((gchar **) args) != 1)
410 : : {
411 : 0 : g_set_error_literal (error, MWT_CLIENT_ERROR,
412 : : MWT_CLIENT_ERROR_INVALID_OPTIONS,
413 : 0 : _("A TARIFF is required."));
414 : 0 : return FALSE;
415 : : }
416 : :
417 : 3 : const gchar *tariff_path = args[0];
418 : :
419 : 6 : g_autoptr(MwtTariff) tariff = load_tariff_from_file (tariff_path, error);
420 [ - + ]: 3 : if (tariff == NULL)
421 : 0 : return FALSE;
422 : :
423 : 3 : g_autofree gchar *out = dump_tariff (tariff, use_colour);
424 : 3 : g_print ("%s", out);
425 : :
426 : 3 : return TRUE;
427 : : }
428 : :
429 : : /* Handle a command like
430 : : * mogwai-tariff build tariff.file name \
431 : : * [start end repeat-type repeat-period capacity-limit] \
432 : : * …
433 : : * by building and saving the given tariff.
434 : : */
435 : : static gboolean
436 : 3 : handle_build (const gchar * const *args,
437 : : gboolean use_colour,
438 : : GError **error)
439 : : {
440 : : /* Parse arguments. */
441 : 3 : const guint n_args_per_period = 5;
442 [ + - ]: 3 : guint n_args = (args != NULL) ? g_strv_length ((gchar **) args) : 0;
443 [ + - + - ]: 3 : if (args == NULL || n_args < 2 + n_args_per_period ||
444 [ - + ]: 3 : ((n_args - 2) % n_args_per_period) != 0)
445 : : {
446 : 0 : g_set_error_literal (error, MWT_CLIENT_ERROR,
447 : : MWT_CLIENT_ERROR_INVALID_OPTIONS,
448 : 0 : _("A TARIFF and NAME and at least one PERIOD are required."));
449 : 0 : return FALSE;
450 : : }
451 : :
452 : 3 : const gchar *tariff_path = args[0];
453 : 3 : const gchar *tariff_name = args[1];
454 : :
455 : 6 : g_autoptr(MwtTariffBuilder) builder = mwt_tariff_builder_new ();
456 : :
457 : 3 : mwt_tariff_builder_set_name (builder, tariff_name);
458 : :
459 [ + + ]: 7 : for (gsize i = 2; i < n_args; i += n_args_per_period)
460 : : {
461 : : /* Parse the arguments for this period. */
462 : 4 : const gchar *start_str = args[i];
463 : 4 : const gchar *end_str = args[i + 1];
464 : 4 : const gchar *repeat_type_str = args[i + 2];
465 : 4 : const gchar *repeat_period_str = args[i + 3];
466 : 4 : const gchar *capacity_limit_str = args[i + 4];
467 : :
468 [ + - ]: 8 : g_autoptr(GDateTime) start = date_time_from_string (start_str, error);
469 [ - + ]: 4 : if (start == NULL)
470 : : {
471 : 0 : g_prefix_error (error, _("Invalid START: "));
472 : 0 : return FALSE;
473 : : }
474 : :
475 [ + - ]: 8 : g_autoptr(GDateTime) end = date_time_from_string (end_str, error);
476 [ - + ]: 4 : if (end == NULL)
477 : : {
478 : 0 : g_prefix_error (error, _("Invalid END: "));
479 : 0 : return FALSE;
480 : : }
481 : :
482 : : MwtPeriodRepeatType repeat_type;
483 [ - + ]: 4 : if (!repeat_type_from_string (repeat_type_str, &repeat_type, error))
484 : : {
485 : 0 : g_prefix_error (error, _("Invalid REPEAT-TYPE: "));
486 : 0 : return FALSE;
487 : : }
488 : :
489 : : guint64 repeat_period64;
490 [ - + ]: 4 : if (!g_ascii_string_to_unsigned (repeat_period_str, 10, 0, G_MAXUINT,
491 : : &repeat_period64, error))
492 : : {
493 : 0 : g_prefix_error (error, _("Invalid REPEAT-PERIOD: "));
494 : 0 : return FALSE;
495 : : }
496 [ - + ]: 4 : g_assert (repeat_period64 <= G_MAXUINT);
497 : 4 : guint repeat_period = repeat_period64;
498 : :
499 : : guint64 capacity_limit;
500 [ - + ]: 4 : if (!capacity_limit_from_string (capacity_limit_str, &capacity_limit, error))
501 : : {
502 : 0 : g_prefix_error (error, _("Invalid CAPACITY-LIMIT: "));
503 : 0 : return FALSE;
504 : : }
505 : :
506 [ - + ]: 4 : if (!mwt_period_validate (start, end, repeat_type, repeat_period, error))
507 : : {
508 : 0 : g_prefix_error (error, _("Error validating period %" G_GSIZE_FORMAT ": "),
509 : 0 : (i - 2) / n_args_per_period);
510 : 0 : return FALSE;
511 : : }
512 : :
513 : 4 : g_autoptr(MwtPeriod) period = NULL;
514 : 4 : period = mwt_period_new (start, end, repeat_type, repeat_period,
515 : : "capacity-limit", capacity_limit,
516 : : NULL);
517 : 4 : mwt_tariff_builder_add_period (builder, period);
518 : : }
519 : :
520 : : /* Save the tariff. */
521 : 6 : g_autoptr(GBytes) bytes = mwt_tariff_builder_get_tariff_as_bytes (builder);
522 [ - + ]: 3 : if (bytes == NULL)
523 : : {
524 : : /* FIXME: Would be good to change the #MwtTariffBuilder API to expose
525 : : * the validation error here. */
526 : 0 : g_set_error (error, MWT_CLIENT_ERROR, MWT_CLIENT_ERROR_INVALID_OPTIONS,
527 : 0 : _("Error building tariff: periods are invalid."));
528 : 0 : return FALSE;
529 : : }
530 : :
531 [ - + ]: 3 : if (!g_file_set_contents (tariff_path, g_bytes_get_data (bytes, NULL),
532 : 3 : g_bytes_get_size (bytes), error))
533 : : {
534 : 0 : g_autofree gchar *tariff_path_utf8 = g_filename_display_name (tariff_path);
535 : 0 : g_prefix_error (error, _("Error saving tariff file ‘%s’: "),
536 : : tariff_path_utf8);
537 : 0 : return FALSE;
538 : : }
539 : :
540 : 3 : return TRUE;
541 : : }
542 : :
543 : : int
544 : 8 : main (int argc,
545 : : char *argv[])
546 : : {
547 : 8 : g_autoptr(GError) error = NULL;
548 : :
549 : : /* Localisation */
550 : 8 : setlocale (LC_ALL, "");
551 : 8 : bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
552 : 8 : bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
553 : 8 : textdomain (GETTEXT_PACKAGE);
554 : :
555 : : /* Set up signal handlers. */
556 : 16 : g_autoptr(GCancellable) cancellable = g_cancellable_new ();
557 : 8 : gint signum = 0;
558 : :
559 : 8 : g_auto(SignalData) sigint_data = { NULL, &signum, 0 };
560 : 8 : sigint_data.cancellable = g_object_ref (cancellable);
561 : 8 : sigint_data.handler_id = g_unix_signal_add (SIGINT, signal_sigint_cb, &sigint_data);
562 : :
563 : 8 : g_auto(SignalData) sigterm_data = { NULL, &signum, 0 };
564 : 8 : sigterm_data.cancellable = g_object_ref (cancellable);
565 : 8 : sigterm_data.handler_id = g_unix_signal_add (SIGTERM, signal_sigterm_cb, &sigterm_data);
566 : :
567 : : /* Only valid for g_print() calls, not g_printerr(). */
568 : 8 : gboolean use_colour = g_log_writer_supports_color (fileno (stdout));
569 : :
570 : : /* Handle command line parameters. */
571 : 8 : g_auto (GStrv) args = NULL;
572 : :
573 : 8 : const GOptionEntry entries[] =
574 : : {
575 : : { G_OPTION_REMAINING, 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING_ARRAY,
576 : : &args, NULL, NULL },
577 : : { NULL, },
578 : : };
579 : :
580 : 8 : g_autoptr(GOptionContext) context = NULL;
581 : 8 : context = g_option_context_new (_("COMMAND ARGS"));
582 : 8 : g_option_context_set_summary (context, _("Create and view network connection tariffs"));
583 : 8 : g_option_context_set_description (context,
584 : 8 : _("Commands:\n"
585 : : " build TARIFF NAME START END REPEAT-TYPE REPEAT-PERIOD CAPACITY-LIMIT […]\n"
586 : : " Build a new tariff called NAME and save it to the TARIFF file.\n"
587 : : " Add one or more periods using the given arguments.\n"
588 : : " dump TARIFF\n"
589 : : " Dump all periods from the given TARIFF file.\n"
590 : : " lookup TARIFF LOOKUP-TIME\n"
591 : : " Look up the period which covers LOOKUP-TIME in the given TARIFF file.\n"));
592 : 8 : g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
593 : :
594 [ - + ]: 8 : if (!g_option_context_parse (context, &argc, &argv, &error))
595 : : {
596 : 0 : g_autofree gchar *message = NULL;
597 : 0 : message = g_strdup_printf (_("Option parsing failed: %s"),
598 : 0 : error->message);
599 : 0 : g_printerr ("%s: %s\n", argv[0], message);
600 : :
601 : 0 : return EXIT_INVALID_OPTIONS;
602 : : }
603 : :
604 [ + - - + ]: 8 : if (args == NULL || args[0] == NULL)
605 : : {
606 : 0 : g_autofree gchar *message = NULL;
607 : 0 : message = g_strdup_printf (_("Option parsing failed: %s"),
608 : : _("A COMMAND is required"));
609 : 0 : g_printerr ("%s: %s\n", argv[0], message);
610 : :
611 : 0 : return EXIT_INVALID_OPTIONS;
612 : : }
613 : :
614 : : /* Handle the different commands. */
615 [ + + ]: 8 : if (g_str_equal (args[0], "build"))
616 : 3 : handle_build ((const gchar * const *) args + 1, use_colour, &error);
617 [ + + ]: 5 : else if (g_str_equal (args[0], "dump"))
618 : 3 : handle_dump ((const gchar * const *) args + 1, use_colour, &error);
619 [ + - ]: 2 : else if (g_str_equal (args[0], "lookup"))
620 : 2 : handle_lookup ((const gchar * const *) args + 1, use_colour, &error);
621 : : else
622 : 0 : g_set_error (&error, MWT_CLIENT_ERROR, MWT_CLIENT_ERROR_INVALID_OPTIONS,
623 : 0 : _("Unrecognised command ‘%s’"), args[1]);
624 : :
625 [ + + ]: 8 : if (error != NULL)
626 : : {
627 : 1 : int exit_status = EXIT_FAILED;
628 : :
629 [ - + ]: 1 : if (g_error_matches (error, MWT_CLIENT_ERROR, MWT_CLIENT_ERROR_INVALID_OPTIONS))
630 : : {
631 : 0 : g_prefix_error (&error, _("Option parsing failed: "));
632 : 0 : exit_status = EXIT_INVALID_OPTIONS;
633 : : }
634 [ + - ]: 1 : else if (g_error_matches (error, MWT_CLIENT_ERROR, MWT_CLIENT_ERROR_LOOKUP_FAILED))
635 : : {
636 : 1 : exit_status = EXIT_LOOKUP_FAILED;
637 : : }
638 : :
639 : 1 : g_printerr ("%s: %s\n", argv[0], error->message);
640 : :
641 : 1 : return exit_status;
642 : : }
643 : :
644 : 7 : return EXIT_OK;
645 : : }
|