[util] Use post_parse to validate

This commit is contained in:
Behdad Esfahbod 2021-08-11 18:30:08 -06:00
parent 9468e46998
commit c0ea4e2d33
5 changed files with 81 additions and 49 deletions

View File

@ -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);

View File

@ -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);

View File

@ -32,31 +32,12 @@
/* main() body for utilities taking font and processing text.*/
template <typename consumer_t, typename font_options_t, typename text_options_t>
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

View File

@ -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 <typename Type>
void add_main_group (GOptionEntry *entries,
Type *closure)
{
GOptionGroup *group = g_option_group_new (nullptr, nullptr, nullptr,
static_cast<gpointer>(closure), nullptr);
g_option_group_add_entries (group, entries);
g_option_group_set_parse_hooks (group, nullptr, post_parse<Type>);
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;

View File

@ -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,