blob: f6571c4af32e26e78baada4ee2d83b77aceb91e4 [file] [log] [blame]
/* Convert ASCII quotations to Unicode quotations.
Copyright (C) 2014-2016 Free Software Foundation, Inc.
Written by Daiki Ueno <ueno@gnu.org>, 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 <https://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
/* Specification. */
#include "filters.h"
#include "quote.h"
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#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);
}