/*
* Gregorio is a program that translates gabc files to GregorioTeX
* This file contains functions providing UTF-8 support.
*
* Copyright (C) 2008-2021 The Gregorio Project (see CONTRIBUTORS.md)
*
* This file is part of Gregorio.
*
* Gregorio 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.
*
* Gregorio 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 Gregorio. If not, see .
*/
#include "config.h"
#include
#include /* for strlen */
#include
#include "struct.h"
#include "unicode.h"
#include "messages.h"
#include "support.h"
/*
*
* This file contains some functions to handle UTF-8 correctly. We chose to
* embed them instead of relying on locale or glib, for simplification: with
* these functions we don't rely on anything locale-dependant (such as
* wchar_t). The reason is that Windows XP (...) is not UTF-8 and thus would
* need the glib in oder to run, which make dependencies much bigger.
*
*/
/* an utf8 version of mbstowcs */
/* expects a buffer of size n + 1 */
static bool gregorio_mbstowcs(grewchar *dest, const char *src, size_t n)
{
bool success = true;
unsigned char bytes_to_come;
grewchar result = 0;
unsigned char c;
size_t res = 0; /* number of bytes we've done so far */
gregorio_not_null(src, gregorio_mbstowcs, return false);
gregorio_not_null(dest, gregorio_mbstowcs, return false);
while (success && *src && res < n) {
c = (unsigned char) (*src);
if (c < 128) { /* 0100xxxx */
/* one-byte symbol */
bytes_to_come = 0;
result = c;
} else if (c >= 240) { /* 1111xxxx */
/* start of a four-byte symbol */
/* printf("%d\n", c); */
bytes_to_come = 3;
result = (result << 3) | (c & 7);
} else if (c >= 224) { /* 1110xxxx */
/* start of a three-byte symbol */
/* printf("%d\n", c); */
bytes_to_come = 2;
result = (result << 4) | (c & 15);
} else if (c >= 192) { /* 1100xxxx */
/* start of a two-byte symbol */
/* printf("%d\n", c); */
bytes_to_come = 1;
result = (result << 5) | (c & 31);
} else {
/* printf("%s %d %d\n", src, res, c); */
gregorio_message(_("malformed UTF-8 sequence1"),
"gregorio_mbstowcs", VERBOSITY_ERROR, 0);
success = false;
break;
}
while (bytes_to_come > 0) {
bytes_to_come--;
src++;
c = (unsigned char) (*src);
if (c < 192 && c >= 128) /* 1000xxxx */
{
result = (result << 6) | (c & 63);
} else {
gregorio_message(_("malformed UTF-8 sequence2"),
"gregorio_mbstowcs", VERBOSITY_ERROR, 0);
success = false;
break;
}
}
dest[res] = result;
res++;
result = 0;
src++;
}
dest[res] = 0;
return success;
}
/* the value returned by this function must be freed! */
grewchar *gregorio_build_grewchar_string_from_buf(const char *const buf)
{
size_t len;
grewchar *gwstring;
/* this doesn't currently happen, but it's safer to keep this check */
if (buf == NULL) {
return NULL; /* LCOV_EXCL_LINE */
}
len = strlen(buf); /* to get the length of the syllable in ASCII */
gwstring = (grewchar *) gregorio_malloc((len + 1) * sizeof(grewchar));
gregorio_mbstowcs(gwstring, buf, len); /* converting into grewchar */
/* no need to check the return code; if it failed, the error state would
* already be in place */
return gwstring;
}
/* the function to build a gregorio_character list from a buffer. */
gregorio_character *gregorio_build_char_list_from_buf(const char *const buf)
{
int i = 0;
grewchar *gwstring;
gregorio_character *current_character = NULL;
/* this doesn't currently happen, but it's safer to keep this check */
if (buf == NULL) {
return NULL; /* LCOV_EXCL_LINE */
}
gwstring = gregorio_build_grewchar_string_from_buf(buf);
/* we add the corresponding characters in the list of gregorio_characters */
while (gwstring[i]) {
gregorio_add_character(¤t_character, gwstring[i]);
i++;
}
free(gwstring);
gregorio_go_to_first_character_c(¤t_character);
return current_character;
}
void gregorio_print_unichar(FILE *f, const grewchar to_print)
{
if (to_print <= 0x7F) {
fprintf(f, "%c", (unsigned char) to_print);
return;
}
if (to_print >= 0x80 && to_print <= 0x7FF) {
fprintf(f, "%c%c", 0xC0 | (to_print >> 6), 0x80 | (to_print & 0x3F));
return;
}
if ((to_print >= 0x800 && to_print <= 0xD7FF) ||
(to_print >= 0xE000 && to_print <= 0xFFFF)) {
fprintf(f, "%c%c%c", 0xE0 | (to_print >> 12),
0x80 | ((to_print >> 6) & 0x3F), 0x80 | (to_print & 0x3F));
return;
}
if (to_print >= 0x10000 && to_print <= 0x10FFFF) {
fprintf(f, "%c%c%c%c", 0xF0 | (to_print >> 18),
0x80 | ((to_print >> 12) & 0x3F),
0x80 | ((to_print >> 6) & 0x3F), 0x80 | (to_print & 0x3F));
}
}
void gregorio_print_unistring(FILE *f, const grewchar *first_char)
{
while (*first_char != 0) {
gregorio_print_unichar(f, *first_char);
first_char++;
}
}