From c0ea4e2d33e613eb4936a9cce85453a6b7a43ae5 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 11 Aug 2021 18:30:08 -0600 Subject: [PATCH] [util] Use post_parse to validate --- util/face-options.hh | 21 +++++++++--- util/font-options.hh | 1 - util/main-font-text.hh | 72 ++++++++++++++++++++++++++++-------------- util/options.hh | 33 ++++++++----------- util/text-options.hh | 3 ++ 5 files changed, 81 insertions(+), 49 deletions(-) diff --git a/util/face-options.hh b/util/face-options.hh index 12cfd3023..229c40e97 100644 --- a/util/face-options.hh +++ b/util/face-options.hh @@ -31,8 +31,20 @@ struct face_options_t { + ~face_options_t () + { + g_free (font_file); + } + void add_options (option_parser_t *parser); + void post_parse (GError **error) + { + if (!this->font_file) + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, + "No font file set"); + } + hb_blob_t *get_blob () const; hb_face_t *get_face () const; @@ -40,12 +52,12 @@ struct face_options_t { ~cache_t () { - free ((void *) font_path); + g_free (font_path); hb_blob_destroy (blob); hb_face_destroy (face); } - const char *font_path = nullptr; + char *font_path = nullptr; hb_blob_t *blob = nullptr; unsigned face_index = (unsigned) -1; hb_face_t *face = nullptr; @@ -73,8 +85,7 @@ face_options_t::get_face () const if (face) return face; - if (!font_file) - fail (true, "No font file set"); + assert (font_file); const char *font_path = font_file; @@ -94,7 +105,7 @@ face_options_t::get_face () const cache.blob = hb_blob_create_from_file_or_fail (font_path); free ((char *) cache.font_path); - cache.font_path = strdup (font_path); + cache.font_path = g_strdup (font_path); if (!cache.blob) fail (false, "%s: Failed reading file", font_path); diff --git a/util/font-options.hh b/util/font-options.hh index 4584bfea0..36bdd85f9 100644 --- a/util/font-options.hh +++ b/util/font-options.hh @@ -44,7 +44,6 @@ struct font_options_t : face_options_t { ~font_options_t () { - g_free (font_file); free (variations); g_free (font_funcs); hb_font_destroy (font); diff --git a/util/main-font-text.hh b/util/main-font-text.hh index 6f1827606..a2a439170 100644 --- a/util/main-font-text.hh +++ b/util/main-font-text.hh @@ -32,31 +32,12 @@ /* main() body for utilities taking font and processing text.*/ template -struct main_font_text_t : font_options_t, text_options_t, consumer_t +struct main_font_text_t : option_parser_t, font_options_t, text_options_t, consumer_t { - void add_options (struct option_parser_t *parser) + int operator () (int argc, char **argv) { - font_options_t::add_options (parser); - text_options_t::add_options (parser); - consumer_t::add_options (parser); - } - - int - operator () (int argc, char **argv) - { - option_parser_t options ("[FONT-FILE] [TEXT]"); - add_options (&options); - options.parse (&argc, &argv); - - argc--, argv++; - if (argc && !this->font_file) this->font_file = locale_to_utf8 (argv[0]), argc--, argv++; - if (argc && !this->text && !this->text_file) this->text = locale_to_utf8 (argv[0]), argc--, argv++; - if (argc) - fail (true, "Too many arguments on the command line"); - if (!this->font_file) - options.usage (); - if (!this->text && !this->text_file) - this->text_file = g_strdup ("-"); + add_options (); + parse (&argc, &argv); this->init (this); @@ -69,6 +50,51 @@ struct main_font_text_t : font_options_t, text_options_t, consumer_t return this->failed ? 1 : 0; } + + protected: + + void add_options () + { + font_options_t::add_options (this); + text_options_t::add_options (this); + consumer_t::add_options (this); + + GOptionEntry entries[] = + { + {G_OPTION_REMAINING, 0, G_OPTION_FLAG_IN_MAIN, + G_OPTION_ARG_CALLBACK, (gpointer) &collect_rest, nullptr, "[FONT-FILE] [TEXT]"}, + {nullptr} + }; + add_main_group (entries, this); + option_parser_t::add_options (); + } + + private: + + static gboolean + collect_rest (const char *name G_GNUC_UNUSED, + const char *arg, + gpointer data, + GError **error) + { + main_font_text_t *thiz = (main_font_text_t *) data; + + if (!thiz->font_file) + { + thiz->font_file = g_strdup (arg); + return true; + } + + if (!thiz->text && !thiz->text_file) + { + thiz->text = g_strdup (arg); + return true; + } + + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, + "Too many arguments on the command line"); + return false; + } }; #endif diff --git a/util/options.hh b/util/options.hh index 6a729036a..e9e82e722 100644 --- a/util/options.hh +++ b/util/options.hh @@ -70,25 +70,9 @@ fail (hb_bool_t suggest_help, const char *format, ...) exit (1); } -static inline char * -locale_to_utf8 (char *s) -{ - char *t; - GError *error = nullptr; - - t = g_locale_to_utf8 (s, -1, nullptr, nullptr, &error); - if (!t) - { - fail (true, "Failed converting text to UTF-8"); - } - - return t; -} - - struct option_parser_t { - option_parser_t (const char *usage) + option_parser_t (const char *usage = nullptr) : usage_str (usage), context (g_option_context_new (usage)), to_free (g_ptr_array_new ()) @@ -136,6 +120,17 @@ struct option_parser_t g_option_context_add_group (context, group); } + template + void add_main_group (GOptionEntry *entries, + Type *closure) + { + GOptionGroup *group = g_option_group_new (nullptr, nullptr, nullptr, + static_cast(closure), nullptr); + g_option_group_add_entries (group, entries); + g_option_group_set_parse_hooks (group, nullptr, post_parse); + g_option_context_set_main_group (context, group); + } + void free_later (char *p) { g_ptr_array_add (to_free, p); } @@ -147,7 +142,7 @@ struct option_parser_t exit (1); } - private: + protected: const char *usage_str; GOptionContext *context; GPtrArray *to_free; @@ -201,8 +196,6 @@ option_parser_t::add_options () inline void option_parser_t::parse (int *argc, char ***argv) { - add_options (); - setlocale (LC_ALL, ""); GError *parse_error = nullptr; diff --git a/util/text-options.hh b/util/text-options.hh index 83077ae9f..c9b04cb9a 100644 --- a/util/text-options.hh +++ b/util/text-options.hh @@ -17,6 +17,9 @@ struct text_options_t void post_parse (GError **error G_GNUC_UNUSED) { + if (!this->text && !this->text_file) + this->text_file = g_strdup ("-"); + if (text && text_file) g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,