| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370 |
- /*
- * Copyright © 2011 Google, Inc.
- *
- * This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
- */
- #ifndef TEXT_OPTIONS_HH
- #define TEXT_OPTIONS_HH
- #include "options.hh"
- struct text_options_t
- {
- text_options_t ()
- : gs (g_string_new (nullptr))
- {}
- ~text_options_t ()
- {
- g_free (text);
- g_free (text_file);
- if (gs)
- g_string_free (gs, true);
- if (in_fp && in_fp != stdin)
- fclose (in_fp);
- }
- void add_options (option_parser_t *parser);
- void post_parse (GError **error G_GNUC_UNUSED)
- {
- if (!text && !text_file)
- text_file = g_strdup ("-");
- if (text && text_file)
- {
- g_set_error (error,
- G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
- "Only one of text and text-file can be set");
- return;
- }
- if (text_file)
- {
- if (0 != strcmp (text_file, "-"))
- in_fp = fopen (text_file, "r");
- else
- in_fp = stdin;
- if (!in_fp)
- g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
- "Failed opening text file `%s': %s",
- text_file, strerror (errno));
- }
- }
- const char *get_line (unsigned int *len);
- int text_len = -1;
- char *text = nullptr;
- char *text_file = nullptr;
- private:
- FILE *in_fp = nullptr;
- GString *gs = nullptr;
- char *line = nullptr;
- unsigned line_len = UINT_MAX;
- hb_bool_t single_par = false;
- };
- struct shape_text_options_t : text_options_t
- {
- ~shape_text_options_t ()
- {
- g_free (text_before);
- g_free (text_after);
- }
- void add_options (option_parser_t *parser);
- char *text_before = nullptr;
- char *text_after = nullptr;
- };
- static gboolean
- parse_text (const char *name G_GNUC_UNUSED,
- const char *arg,
- gpointer data,
- GError **error G_GNUC_UNUSED)
- {
- text_options_t *text_opts = (text_options_t *) data;
- if (text_opts->text)
- {
- g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
- "Either --text or --unicodes can be provided but not both");
- return false;
- }
- text_opts->text_len = -1;
- text_opts->text = g_strdup (arg);
- return true;
- }
- static bool
- encode_unicodes (const char *unicodes,
- GString *gs,
- GError **error)
- {
- #define DELIMITERS "<+-|>{},;&#\\xXuUnNiI\n\t\v\f\r "
- char *s = (char *) unicodes;
- char *p;
- while (s && *s)
- {
- while (*s && strchr (DELIMITERS, *s))
- s++;
- if (!*s)
- break;
- errno = 0;
- hb_codepoint_t u = strtoul (s, &p, 16);
- if (errno || s == p)
- {
- g_string_free (gs, TRUE);
- g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
- "Failed parsing Unicode value at: '%s'", s);
- return false;
- }
- g_string_append_unichar (gs, u);
- s = p;
- }
- #undef DELIMITERS
- return true;
- }
- static gboolean
- parse_unicodes (const char *name G_GNUC_UNUSED,
- const char *arg,
- gpointer data,
- GError **error G_GNUC_UNUSED)
- {
- text_options_t *text_opts = (text_options_t *) data;
- if (text_opts->text)
- {
- g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
- "Either --text or --unicodes can be provided but not both");
- return false;
- }
- GString *gs = g_string_new (nullptr);
- if (0 == strcmp (arg, "*"))
- g_string_append_c (gs, '*');
- else
- if (!encode_unicodes (arg, gs, error))
- return false;
- text_opts->text_len = gs->len;
- text_opts->text = g_string_free (gs, FALSE);
- return true;
- }
- static gboolean
- parse_text_before (const char *name G_GNUC_UNUSED,
- const char *arg,
- gpointer data,
- GError **error)
- {
- auto *opts = (shape_text_options_t *) data;
- if (opts->text_before)
- {
- g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
- "Either --text-before or --unicodes-before can be provided but not both");
- return false;
- }
- opts->text_before = g_strdup (arg);
- fprintf(stderr, "%s\n", opts->text_before);
- return true;
- }
- static gboolean
- parse_unicodes_before (const char *name G_GNUC_UNUSED,
- const char *arg,
- gpointer data,
- GError **error)
- {
- auto *opts = (shape_text_options_t *) data;
- if (opts->text_before)
- {
- g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
- "Either --text-before or --unicodes-before can be provided but not both");
- return false;
- }
- GString *gs = g_string_new (nullptr);
- if (!encode_unicodes (arg, gs, error))
- return false;
- opts->text_before = g_string_free (gs, FALSE);
- return true;
- }
- static gboolean
- parse_text_after (const char *name G_GNUC_UNUSED,
- const char *arg,
- gpointer data,
- GError **error)
- {
- auto *opts = (shape_text_options_t *) data;
- if (opts->text_after)
- {
- g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
- "Either --text-after or --unicodes-after can be provided but not both");
- return false;
- }
- opts->text_after = g_strdup (arg);
- return true;
- }
- static gboolean
- parse_unicodes_after (const char *name G_GNUC_UNUSED,
- const char *arg,
- gpointer data,
- GError **error)
- {
- auto *opts = (shape_text_options_t *) data;
- if (opts->text_after)
- {
- g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
- "Either --text-after or --unicodes-after can be provided but not both");
- return false;
- }
- GString *gs = g_string_new (nullptr);
- if (!encode_unicodes (arg, gs, error))
- return false;
- opts->text_after = g_string_free (gs, FALSE);
- return true;
- }
- const char *
- text_options_t::get_line (unsigned int *len)
- {
- if (text)
- {
- if (!line)
- {
- line = text;
- line_len = text_len;
- }
- if (line_len == UINT_MAX)
- line_len = strlen (line);
- if (!line_len)
- {
- *len = 0;
- return nullptr;
- }
- const char *ret = line;
- const char *p = single_par ? nullptr : (const char *) memchr (line, '\n', line_len);
- unsigned int ret_len;
- if (!p)
- {
- ret_len = line_len;
- line += ret_len;
- line_len = 0;
- }
- else
- {
- ret_len = p - ret;
- line += ret_len + 1;
- line_len -= ret_len + 1;
- }
- *len = ret_len;
- return ret;
- }
- g_string_set_size (gs, 0);
- char buf[BUFSIZ];
- while (fgets (buf, sizeof (buf), in_fp))
- {
- unsigned bytes = strlen (buf);
- if (!single_par && bytes && buf[bytes - 1] == '\n')
- {
- bytes--;
- g_string_append_len (gs, buf, bytes);
- break;
- }
- g_string_append_len (gs, buf, bytes);
- }
- if (ferror (in_fp))
- fail (false, "Failed reading text: %s", strerror (errno));
- *len = gs->len;
- return !*len && feof (in_fp) ? nullptr : gs->str;
- }
- void
- text_options_t::add_options (option_parser_t *parser)
- {
- GOptionEntry entries[] =
- {
- {"text", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text, "Set input text", "string"},
- {"text-file", 0, 0, G_OPTION_ARG_STRING, &this->text_file, "Set input text file-name", "filename"},
- {"unicodes", 'u', 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes, "Set input Unicode codepoints", "list of hex numbers"},
- {"single-par", 0, 0, G_OPTION_ARG_NONE, &this->single_par, "Treat text as single paragraph", nullptr},
- {nullptr}
- };
- parser->add_group (entries,
- "text",
- "Text options:\n\nIf no text is provided, standard input is used for input.\n",
- "Options for the input text",
- this);
- }
- void
- shape_text_options_t::add_options (option_parser_t *parser)
- {
- text_options_t::add_options (parser);
- GOptionEntry entries[] =
- {
- {"text-before", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text_before, "Set text context before each line", "string"},
- {"text-after", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text_after, "Set text context after each line", "string"},
- {"unicodes-before", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes_before, "Set Unicode codepoints context before each line", "list of hex numbers"},
- {"unicodes-after", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes_after, "Set Unicode codepoints context after each line", "list of hex numbers"},
- {nullptr}
- };
- parser->add_group (entries,
- "text-context",
- "Textual context options:",
- "Options for the input context text",
- this);
- }
- #endif
|