options.hh 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /*
  2. * Copyright © 2011 Google, Inc.
  3. *
  4. * This is part of HarfBuzz, a text shaping library.
  5. *
  6. * Permission is hereby granted, without written agreement and without
  7. * license or royalty fees, to use, copy, modify, and distribute this
  8. * software and its documentation for any purpose, provided that the
  9. * above copyright notice and the following two paragraphs appear in
  10. * all copies of this software.
  11. *
  12. * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
  13. * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
  14. * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
  15. * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
  16. * DAMAGE.
  17. *
  18. * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
  19. * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  20. * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
  21. * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  22. * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  23. *
  24. * Google Author(s): Behdad Esfahbod
  25. */
  26. #ifndef OPTIONS_HH
  27. #define OPTIONS_HH
  28. #include "hb.hh"
  29. #include <stdlib.h>
  30. #include <stddef.h>
  31. #include <string.h>
  32. #include <stdio.h>
  33. #include <assert.h>
  34. #include <math.h>
  35. #include <locale.h>
  36. #include <errno.h>
  37. #include <fcntl.h>
  38. #if defined(_WIN32) || defined(__CYGWIN__)
  39. #include <io.h> /* for setmode() under Windows */
  40. #endif
  41. #ifdef HAVE_UNISTD_H
  42. #include <unistd.h> /* for isatty() */
  43. #endif
  44. #include <hb-features.h>
  45. #include <hb.h>
  46. #include <hb-ot.h>
  47. #include <glib.h>
  48. #include <glib/gprintf.h>
  49. static inline void fail (hb_bool_t suggest_help, const char *format, ...) G_GNUC_NORETURN G_GNUC_PRINTF (2, 3);
  50. static inline void
  51. fail (hb_bool_t suggest_help, const char *format, ...)
  52. {
  53. const char *msg;
  54. va_list vap;
  55. va_start (vap, format);
  56. msg = g_strdup_vprintf (format, vap);
  57. va_end (vap);
  58. const char *prgname = g_get_prgname ();
  59. g_printerr ("%s: %s\n", prgname, msg);
  60. if (suggest_help)
  61. g_printerr ("Try `%s --help' for more information.\n", prgname);
  62. exit (1);
  63. }
  64. struct option_parser_t
  65. {
  66. option_parser_t (const char *parameter_string = nullptr)
  67. : context (g_option_context_new (parameter_string)),
  68. to_free (g_ptr_array_new ())
  69. {}
  70. static void _g_free_g_func (void *p, void * G_GNUC_UNUSED) { g_free (p); }
  71. ~option_parser_t ()
  72. {
  73. g_option_context_free (context);
  74. g_ptr_array_foreach (to_free, _g_free_g_func, nullptr);
  75. g_ptr_array_free (to_free, TRUE);
  76. }
  77. void add_options ();
  78. static void
  79. post_parse_ (void *thiz, GError **error) {}
  80. template <typename Type>
  81. static auto
  82. post_parse_ (Type *thiz, GError **error) -> decltype (thiz->post_parse (error))
  83. { thiz->post_parse (error); }
  84. template <typename Type>
  85. static gboolean
  86. post_parse (GOptionContext *context G_GNUC_UNUSED,
  87. GOptionGroup *group G_GNUC_UNUSED,
  88. gpointer data,
  89. GError **error)
  90. {
  91. option_parser_t::post_parse_ (static_cast<Type *> (data), error);
  92. return !*error;
  93. }
  94. template <typename Type>
  95. void add_group (GOptionEntry *entries,
  96. const gchar *name,
  97. const gchar *description,
  98. const gchar *help_description,
  99. Type *closure,
  100. bool add_parse_hooks = true)
  101. {
  102. GOptionGroup *group = g_option_group_new (name, description, help_description,
  103. static_cast<gpointer>(closure), nullptr);
  104. g_option_group_add_entries (group, entries);
  105. if (add_parse_hooks)
  106. g_option_group_set_parse_hooks (group, nullptr, post_parse<Type>);
  107. g_option_context_add_group (context, group);
  108. }
  109. template <typename Type>
  110. void add_main_group (GOptionEntry *entries,
  111. Type *closure)
  112. {
  113. GOptionGroup *group = g_option_group_new (nullptr, nullptr, nullptr,
  114. static_cast<gpointer>(closure), nullptr);
  115. g_option_group_add_entries (group, entries);
  116. /* https://gitlab.gnome.org/GNOME/glib/-/issues/2460 */
  117. //g_option_group_set_parse_hooks (group, nullptr, post_parse<Type>);
  118. g_option_context_set_main_group (context, group);
  119. }
  120. void set_summary (const char *summary)
  121. {
  122. g_option_context_set_summary (context, summary);
  123. }
  124. void set_description (const char *description)
  125. {
  126. g_option_context_set_description (context, description);
  127. }
  128. void free_later (char *p) {
  129. g_ptr_array_add (to_free, p);
  130. }
  131. bool parse (int *argc, char ***argv, bool ignore_error = false);
  132. GOptionContext *context;
  133. protected:
  134. GPtrArray *to_free;
  135. };
  136. static inline gchar *
  137. shapers_to_string ()
  138. {
  139. GString *shapers = g_string_new (nullptr);
  140. const char **shaper_list = hb_shape_list_shapers ();
  141. for (; *shaper_list; shaper_list++) {
  142. g_string_append (shapers, *shaper_list);
  143. g_string_append_c (shapers, ',');
  144. }
  145. g_string_truncate (shapers, MAX (0, (gint)shapers->len - 1));
  146. return g_string_free (shapers, false);
  147. }
  148. static G_GNUC_NORETURN gboolean
  149. show_version (const char *name G_GNUC_UNUSED,
  150. const char *arg G_GNUC_UNUSED,
  151. gpointer data G_GNUC_UNUSED,
  152. GError **error G_GNUC_UNUSED)
  153. {
  154. g_printf ("%s (%s) %s\n", g_get_prgname (), PACKAGE_NAME, PACKAGE_VERSION);
  155. char *shapers = shapers_to_string ();
  156. g_printf ("Available shapers: %s\n", shapers);
  157. g_free (shapers);
  158. if (strcmp (HB_VERSION_STRING, hb_version_string ()))
  159. g_printf ("Linked HarfBuzz library has a different version: %s\n", hb_version_string ());
  160. exit(0);
  161. }
  162. inline void
  163. option_parser_t::add_options ()
  164. {
  165. GOptionEntry entries[] =
  166. {
  167. {"version", 0, G_OPTION_FLAG_NO_ARG,
  168. G_OPTION_ARG_CALLBACK, (gpointer) &show_version, "Show version numbers", nullptr},
  169. {nullptr}
  170. };
  171. g_option_context_add_main_entries (context, entries, nullptr);
  172. }
  173. inline bool
  174. option_parser_t::parse (int *argc, char ***argv, bool ignore_error)
  175. {
  176. setlocale (LC_ALL, "");
  177. GError *parse_error = nullptr;
  178. if (!g_option_context_parse (context, argc, argv, &parse_error))
  179. {
  180. if (parse_error)
  181. {
  182. if (!ignore_error)
  183. fail (true, "%s", parse_error->message);
  184. g_error_free (parse_error);
  185. }
  186. else
  187. {
  188. if (!ignore_error)
  189. fail (true, "Option parse error");
  190. }
  191. return false;
  192. }
  193. return true;
  194. }
  195. /* fallback implementation for scalbn()/scalbnf() for pre-2013 MSVC */
  196. #if defined (_MSC_VER) && (_MSC_VER < 1800)
  197. #ifndef FLT_RADIX
  198. #define FLT_RADIX 2
  199. #endif
  200. __inline long double scalbn (long double x, int exp)
  201. {
  202. return x * (pow ((long double) FLT_RADIX, exp));
  203. }
  204. __inline float scalbnf (float x, int exp)
  205. {
  206. return x * (pow ((float) FLT_RADIX, exp));
  207. }
  208. #endif
  209. static inline bool
  210. parse_color (const char *s,
  211. unsigned &r,
  212. unsigned &g,
  213. unsigned &b,
  214. unsigned &a)
  215. {
  216. bool ret = false;
  217. while (*s == ' ') s++;
  218. if (*s == '#') s++;
  219. unsigned sr, sg, sb, sa;
  220. sa = 255;
  221. if (sscanf (s, "%2x%2x%2x%2x", &sr, &sg, &sb, &sa) <= 2)
  222. {
  223. if (sscanf (s, "%1x%1x%1x%1x", &sr, &sg, &sb, &sa) >= 3)
  224. {
  225. sr *= 17;
  226. sg *= 17;
  227. sb *= 17;
  228. sa *= 17;
  229. ret = true;
  230. }
  231. }
  232. else
  233. ret = true;
  234. if (ret)
  235. {
  236. r = sr;
  237. g = sg;
  238. b = sb;
  239. a = sa;
  240. }
  241. return ret;
  242. }
  243. #endif