blob: df61aca46f90de7f7a0a619e48cf0333593824cf [file]
/* Copyright 2010-2026 Free Software Foundation, Inc.
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/>. */
/* Avoid namespace conflicts. */
#define context perl_context
#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#undef context
/* for BYTES_STRING */
#include "document_types.h"
/*
#include "tree_types.h"
#include "converter_types.h"
*/
/* non_perl_* has_perl_interpreter */
#include "xs_utils.h"
#include "call_perl_function.h"
/* See the NOTE in build_perl_info.c on use of functions related to
memory allocation */
/* Used to create a "Perl-internal" string that represents a sequence
of Unicode codepoints with no specific encoding. */
SV *
newSVpv_utf8 (const char *str, STRLEN len)
{
SV *sv;
dTHX;
sv = newSVpv (str, len);
SvUTF8_on (sv);
return sv;
}
/* Used to create a string considered as bytes by perl */
SV *
newSVpv_byte (const char *str, STRLEN len)
{
SV *sv;
dTHX;
sv = newSVpv (str, len);
SvUTF8_off (sv);
return sv;
}
char *
call_nodenamenormalization_unicode_to_transliterate (const char *text,
int in_test, int no_unidecode)
{
int count;
char *result;
char *result_ret;
STRLEN len;
SV *result_sv;
dTHX;
/* this happens if the customization variable TEST is set while there
is no embedded Perl */
if (!has_perl_interpreter ())
return 0;
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
EXTEND(SP, 3);
PUSHs(sv_2mortal (newSVpv_utf8 (text, 0)));
PUSHs(sv_2mortal (newSViv (in_test)));
PUSHs(sv_2mortal (newSViv (no_unidecode)));
PUTBACK;
count = call_pv (
"Texinfo::Convert::NodeNameNormalization::_unicode_to_transliterate",
G_SCALAR);
SPAGAIN;
if (count != 1)
croak ("_unicode_to_transliterate should return 1 item\n");
result_sv = POPs;
result_ret = SvPVutf8 (result_sv, len);
result = non_perl_strndup (result_ret, len);
PUTBACK;
FREETMPS;
LEAVE;
return result;
}
char *
call_translations_translate_string (const char *string,
const char *language_env,
const char *translation_context)
{
int count;
char *result;
const char *result_ret;
STRLEN len;
SV *result_sv;
dTHX;
/* this happens if USE_LIBINTL_PERL_IN_XS is set while there is no
embedded Perl */
if (!has_perl_interpreter ())
return 0;
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
EXTEND(SP, 3);
PUSHs(sv_2mortal (newSVpv_utf8 (string, 0)));
PUSHs(sv_2mortal (newSVpv_byte (language_env, 0)));
PUSHs(sv_2mortal (newSVpv_utf8 (translation_context, 0)));
PUTBACK;
count = call_pv (
"Texinfo::Translations::translate_string",
G_SCALAR);
SPAGAIN;
if (count != 1)
croak ("translate_string should return 1 item\n");
result_sv = POPs;
result_ret = SvPVutf8 (result_sv, len);
result = non_perl_strndup (result_ret, len);
PUTBACK;
FREETMPS;
LEAVE;
return result;
}
void *
call_setup_collator (int use_unicode_collation, const char *locale_lang)
{
int count;
void *result = 0;
SV *collator_sv = 0;
dTHX;
/* this happens if XS_STRXFRM_COLLATION_LOCALE=undef while there is
no embedded Perl */
if (!has_perl_interpreter ())
return 0;
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
EXTEND(SP, 2);
PUSHs(sv_2mortal (newSViv (use_unicode_collation)));
PUSHs(sv_2mortal (newSVpv (locale_lang, 0)));
PUTBACK;
count = call_pv ("Texinfo::Indices::_setup_collator",
G_SCALAR);
SPAGAIN;
if (count != 1)
croak ("_setup_collator should return 1 item\n");
collator_sv = POPs;
if (SvOK (collator_sv))
{
SvREFCNT_inc (collator_sv);
result = (void *) collator_sv;
}
PUTBACK;
FREETMPS;
LEAVE;
return result;
}
BYTES_STRING *
call_collator_getSortKey (const void *collator_sv, const char *string)
{
BYTES_STRING *result;
unsigned char *result_ret;
STRLEN len;
SV *result_sv;
int count;
dTHX;
result = (BYTES_STRING *) non_perl_malloc (sizeof (BYTES_STRING));
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
EXTEND(SP, 2);
PUSHs((SV *) collator_sv);
PUSHs(sv_2mortal (newSVpv_utf8 (string, 0)));
PUTBACK;
count = call_method ("getSortKey",
G_SCALAR);
SPAGAIN;
if (count != 1)
croak ("getSortKey should return 1 item\n");
result_sv = POPs;
result_ret = (unsigned char *)SvPVbyte (result_sv, len);
result->len = (size_t) len;
result->bytes = (unsigned char *)
non_perl_malloc (sizeof (unsigned char) * len);
memcpy (result->bytes, result_ret, result->len);
PUTBACK;
FREETMPS;
LEAVE;
return result;
}
/* Used to load the Texinfo modules similar to texi2any.pl or
load_txi_modules.pl, but trimmed down and from C. This is used
from the SWIG Perl interface to allow calls to Perl functions from C */
static void
call_modulepath_init (int updirs, const char *perl_modules_dir,
const char *converter_libdir,
const char *datadir)
{
int count;
dTHX;
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
EXTEND(SP, 5);
/* call to Modulepath init for the in-build case */
if (updirs >= 0)
{
PUSHs(newSV (0));
PUSHs(newSV (0));
PUSHs(newSV (0));
PUSHs(sv_2mortal (newSVpv ("updirs", 0)));
PUSHs(sv_2mortal (newSViv (updirs)));
}
else
{
/* call to Modulepath init for the installed modules case */
PUSHs(sv_2mortal (newSVpv_byte (perl_modules_dir, 0)));
PUSHs(sv_2mortal (newSVpv_byte (converter_libdir, 0)));
PUSHs(sv_2mortal (newSVpv_byte (datadir, 0)));
PUSHs(sv_2mortal (newSVpv ("installed", 0)));
PUSHs(sv_2mortal (newSViv (1)));
}
PUTBACK;
count = call_pv ("Texinfo::ModulePath::init",
G_DISCARD|G_SCALAR);
SPAGAIN;
if (count != 0)
croak ("ModulePath init should return 0 item\n");
PUTBACK;
FREETMPS;
LEAVE;
}
/* Initializations similar to those in texi2any.pl or load_txi_modules.pl
but simplified, as we want to initialize only the modules called from
libtexinfo. */
/* return -1 (or croak/die) if something unexpected happened.
return 0 in case of regular errors.
return 1 for success.
*/
int
call_eval_load_texinfo_modules (int texinfo_uninstalled,
const char *t2a_builddir, int updirs, const char *modules_dir,
const char *converter_libdir, const char *datadir)
{
SV *sv_inc_str;
char *str;
AV *INC;
dTHX;
INC = get_av ("INC", 0);
if (!INC)
return -1;
av_unshift (INC, 1);
if (texinfo_uninstalled)
sv_inc_str = newSVpvf("%s/perl", t2a_builddir);
else
sv_inc_str = newSVpv_byte(modules_dir, 0);
av_store (INC, 0, sv_inc_str);
str = "require Texinfo::ModulePath;\n";
eval_pv (str, TRUE);
if (texinfo_uninstalled)
call_modulepath_init (updirs, 0, 0, 0);
else
call_modulepath_init (-1, modules_dir, converter_libdir,
datadir);
str = "use Texinfo::XSLoader;\n"
"Texinfo::XSLoader::set_XS_mandatory();\n";
eval_pv (str, TRUE);
/* Since XS modules are mandatory, XSLoader dies if they are not
properly loaded. This means that DocumentXS init should be
called if the function returns.
*/
str = "use Texinfo::Document;\n"
"use Texinfo::Translations;\n"
"use Texinfo::Convert::NodeNameNormalization;\n"
"use Texinfo::Indices;\n";
eval_pv (str, TRUE);
/* TODO add more from load_txi_modules.pl when there is code to test?
For example loading messages for error messages translation and
loading translated strings from LocaleData?
*/
return 1;
}