2 * Copyright © 2011 Google, Inc.
4 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
24 * Google Author(s): Behdad Esfahbod
27 #ifndef TEXT_OPTIONS_HH
28 #define TEXT_OPTIONS_HH
35 : gs (g_string_new (nullptr))
42 g_string_free (gs, true);
43 if (in_fp && in_fp != stdin)
47 void add_options (option_parser_t *parser);
49 void post_parse (GError **error G_GNUC_UNUSED)
51 if (!text && !text_file)
52 text_file = g_strdup ("-");
54 if (text && text_file)
57 G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
58 "Only one of text and text-file can be set");
64 if (0 != strcmp (text_file, "-"))
65 in_fp = fopen (text_file, "r");
70 g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
71 "Failed opening text file `%s': %s",
72 text_file, strerror (errno));
76 const char *get_line (unsigned int *len);
80 char *text_file = nullptr;
83 FILE *in_fp = nullptr;
84 GString *gs = nullptr;
86 unsigned line_len = UINT_MAX;
87 hb_bool_t single_par = false;
90 struct shape_text_options_t : text_options_t
92 ~shape_text_options_t ()
98 void add_options (option_parser_t *parser);
100 char *text_before = nullptr;
101 char *text_after = nullptr;
106 parse_text (const char *name G_GNUC_UNUSED,
109 GError **error G_GNUC_UNUSED)
111 text_options_t *text_opts = (text_options_t *) data;
115 g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
116 "Either --text or --unicodes can be provided but not both");
120 text_opts->text_len = -1;
121 text_opts->text = g_strdup (arg);
126 encode_unicodes (const char *unicodes,
130 #define DELIMITERS "<+-|>{},;&#\\xXuUnNiI\n\t\v\f\r "
132 char *s = (char *) unicodes;
137 while (*s && strchr (DELIMITERS, *s))
143 hb_codepoint_t u = strtoul (s, &p, 16);
146 g_string_free (gs, TRUE);
147 g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
148 "Failed parsing Unicode value at: '%s'", s);
152 g_string_append_unichar (gs, u);
163 parse_unicodes (const char *name G_GNUC_UNUSED,
166 GError **error G_GNUC_UNUSED)
168 text_options_t *text_opts = (text_options_t *) data;
172 g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
173 "Either --text or --unicodes can be provided but not both");
177 GString *gs = g_string_new (nullptr);
178 if (0 == strcmp (arg, "*"))
179 g_string_append_c (gs, '*');
181 if (!encode_unicodes (arg, gs, error))
184 text_opts->text_len = gs->len;
185 text_opts->text = g_string_free (gs, FALSE);
190 parse_text_before (const char *name G_GNUC_UNUSED,
195 auto *opts = (shape_text_options_t *) data;
197 if (opts->text_before)
199 g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
200 "Either --text-before or --unicodes-before can be provided but not both");
204 opts->text_before = g_strdup (arg);
205 fprintf(stderr, "%s\n", opts->text_before);
210 parse_unicodes_before (const char *name G_GNUC_UNUSED,
215 auto *opts = (shape_text_options_t *) data;
217 if (opts->text_before)
219 g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
220 "Either --text-before or --unicodes-before can be provided but not both");
224 GString *gs = g_string_new (nullptr);
225 if (!encode_unicodes (arg, gs, error))
228 opts->text_before = g_string_free (gs, FALSE);
233 parse_text_after (const char *name G_GNUC_UNUSED,
238 auto *opts = (shape_text_options_t *) data;
240 if (opts->text_after)
242 g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
243 "Either --text-after or --unicodes-after can be provided but not both");
247 opts->text_after = g_strdup (arg);
252 parse_unicodes_after (const char *name G_GNUC_UNUSED,
257 auto *opts = (shape_text_options_t *) data;
259 if (opts->text_after)
261 g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
262 "Either --text-after or --unicodes-after can be provided but not both");
266 GString *gs = g_string_new (nullptr);
267 if (!encode_unicodes (arg, gs, error))
270 opts->text_after = g_string_free (gs, FALSE);
275 text_options_t::get_line (unsigned int *len)
284 if (line_len == UINT_MAX)
285 line_len = strlen (line);
293 const char *ret = line;
294 const char *p = single_par ? nullptr : (const char *) memchr (line, '\n', line_len);
295 unsigned int ret_len;
306 line_len -= ret_len + 1;
313 g_string_set_size (gs, 0);
315 while (fgets (buf, sizeof (buf), in_fp))
317 unsigned bytes = strlen (buf);
318 if (!single_par && bytes && buf[bytes - 1] == '\n')
321 g_string_append_len (gs, buf, bytes);
324 g_string_append_len (gs, buf, bytes);
327 fail (false, "Failed reading text: %s", strerror (errno));
329 return !*len && feof (in_fp) ? nullptr : gs->str;
333 text_options_t::add_options (option_parser_t *parser)
335 GOptionEntry entries[] =
337 {"text", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text, "Set input text", "string"},
338 {"text-file", 0, 0, G_OPTION_ARG_STRING, &this->text_file, "Set input text file-name", "filename"},
339 {"unicodes", 'u', 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes, "Set input Unicode codepoints", "list of hex numbers"},
340 {"single-par", 0, 0, G_OPTION_ARG_NONE, &this->single_par, "Treat text as single paragraph", nullptr},
343 parser->add_group (entries,
345 "Text options:\n\nIf no text is provided, standard input is used for input.\n",
346 "Options for the input text",
351 shape_text_options_t::add_options (option_parser_t *parser)
353 text_options_t::add_options (parser);
355 GOptionEntry entries[] =
357 {"text-before", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text_before, "Set text context before each line", "string"},
358 {"text-after", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text_after, "Set text context after each line", "string"},
359 {"unicodes-before", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes_before, "Set Unicode codepoints context before each line", "list of hex numbers"},
360 {"unicodes-after", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes_after, "Set Unicode codepoints context after each line", "list of hex numbers"},
363 parser->add_group (entries,
365 "Textual context options:",
366 "Options for the input context text",