/* Convert ASCII quotations to Unicode quotations. Copyright (C) 2014-2016 Free Software Foundation, Inc. Written by Daiki Ueno , 2014. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifdef HAVE_CONFIG_H # include #endif /* Specification. */ #include "filters.h" #include "quote.h" #include #include #include #include "xalloc.h" #define BOLD_START "\x1b[1m" #define BOLD_END "\x1b[0m" struct result { char *output; char *offset; bool bold; }; static void convert_quote_callback (char quote, const char *quoted, size_t quoted_length, void *data) { struct result *result = data; switch (quote) { case '\0': memcpy (result->offset, quoted, quoted_length); result->offset += quoted_length; break; case '"': /* U+201C: LEFT DOUBLE QUOTATION MARK */ memcpy (result->offset, "\xe2\x80\x9c", 3); result->offset += 3; if (result->bold) { memcpy (result->offset, BOLD_START, 4); result->offset += 4; } memcpy (result->offset, quoted, quoted_length); result->offset += quoted_length; if (result->bold) { memcpy (result->offset, BOLD_END, 4); result->offset += 4; } /* U+201D: RIGHT DOUBLE QUOTATION MARK */ memcpy (result->offset, "\xe2\x80\x9d", 3); result->offset += 3; break; case '\'': /* U+2018: LEFT SINGLE QUOTATION MARK */ memcpy (result->offset, "\xe2\x80\x98", 3); result->offset += 3; if (result->bold) { memcpy (result->offset, BOLD_START, 4); result->offset += 4; } memcpy (result->offset, quoted, quoted_length); result->offset += quoted_length; if (result->bold) { memcpy (result->offset, BOLD_END, 4); result->offset += 4; } /* U+2019: RIGHT SINGLE QUOTATION MARK */ memcpy (result->offset, "\xe2\x80\x99", 3); result->offset += 3; break; } } /* This is a direct translation of po/quot.sed and po/boldquot.sed. */ static void convert_ascii_quote_to_unicode (const char *input, size_t input_len, char **output_p, size_t *output_len_p, bool bold) { const char *p; size_t quote_count; struct result result; /* Count the number of quotation characters. */ quote_count = 0; for (p = input; p < input + input_len; p++) { size_t len; p = strpbrk (p, "`'\""); if (!p) break; len = strspn (p, "`'\""); quote_count += len; p += len; } /* Large enough. */ result.output = XNMALLOC (input_len - quote_count + (bold ? 7 : 3) * quote_count + 1, char); result.offset = result.output; result.bold = bold; scan_quoted (input, input_len, convert_quote_callback, &result); *output_p = result.output; *output_len_p = result.offset - result.output; } void ascii_quote_to_unicode (const char *input, size_t input_len, char **output_p, size_t *output_len_p) { convert_ascii_quote_to_unicode (input, input_len, output_p, output_len_p, false); } void ascii_quote_to_unicode_bold (const char *input, size_t input_len, char **output_p, size_t *output_len_p) { convert_ascii_quote_to_unicode (input, input_len, output_p, output_len_p, true); }