#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "gettextP.h"
#ifdef _LIBC
# include <libintl.h>
#else
# include "libgnuintl.h"
#endif
#ifdef _LIBC
# include <bits/libc-lock.h>
# define gl_rwlock_define __libc_rwlock_define
# define gl_rwlock_wrlock __libc_rwlock_wrlock
# define gl_rwlock_unlock __libc_rwlock_unlock
#else
# include "lock.h"
#endif
#ifndef offsetof
# define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
#endif
gl_rwlock_define (extern, _nl_state_lock attribute_hidden)
#ifdef _LIBC
# define BINDTEXTDOMAIN __bindtextdomain
# define BIND_TEXTDOMAIN_CODESET __bind_textdomain_codeset
# ifndef strdup
# define strdup(str) __strdup (str)
# endif
#else
# define BINDTEXTDOMAIN libintl_bindtextdomain
# define BIND_TEXTDOMAIN_CODESET libintl_bind_textdomain_codeset
#endif
static void
set_binding_values (const char *domainname,
const char **dirnamep, const wchar_t **wdirnamep,
const char **codesetp)
{
struct binding *binding;
int modified;
if (domainname == NULL || domainname[0] == '\0')
{
if (dirnamep)
*dirnamep = NULL;
#if defined _WIN32 && !defined __CYGWIN__
if (wdirnamep)
*wdirnamep = NULL;
#endif
if (codesetp)
*codesetp = NULL;
return;
}
gl_rwlock_wrlock (_nl_state_lock);
modified = 0;
for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
{
int compare = strcmp (domainname, binding->domainname);
if (compare == 0)
break;
if (compare < 0)
{
binding = NULL;
break;
}
}
if (binding != NULL)
{
if (dirnamep)
{
const char *dirname = *dirnamep;
if (dirname == NULL)
*dirnamep = binding->dirname;
else
{
char *result = binding->dirname;
if (result == NULL || strcmp (dirname, result) != 0)
{
if (strcmp (dirname, _nl_default_dirname) == 0)
result = (char *) _nl_default_dirname;
else
result = strdup (dirname);
if (__builtin_expect (result != NULL, 1))
{
if (binding->dirname != _nl_default_dirname)
free (binding->dirname);
binding->dirname = result;
#if defined _WIN32 && !defined __CYGWIN__
free (binding->wdirname);
binding->wdirname = NULL;
#endif
modified = 1;
}
}
*dirnamep = result;
}
}
#if defined _WIN32 && !defined __CYGWIN__
if (wdirnamep)
{
const wchar_t *wdirname = *wdirnamep;
if (wdirname == NULL)
*wdirnamep = binding->wdirname;
else
{
wchar_t *result = binding->wdirname;
if (result == NULL || wcscmp (wdirname, result) != 0)
{
result = _wcsdup (wdirname);
if (__builtin_expect (result != NULL, 1))
{
if (binding->dirname != _nl_default_dirname)
free (binding->dirname);
binding->dirname = NULL;
free (binding->wdirname);
binding->wdirname = result;
modified = 1;
}
}
*wdirnamep = result;
}
}
#endif
if (codesetp)
{
const char *codeset = *codesetp;
if (codeset == NULL)
*codesetp = binding->codeset;
else
{
char *result = binding->codeset;
if (result == NULL || strcmp (codeset, result) != 0)
{
result = strdup (codeset);
if (__builtin_expect (result != NULL, 1))
{
free (binding->codeset);
binding->codeset = result;
modified = 1;
}
}
*codesetp = result;
}
}
}
else if ((dirnamep == NULL || *dirnamep == NULL)
#if defined _WIN32 && !defined __CYGWIN__
&& (wdirnamep == NULL || *wdirnamep == NULL)
#endif
&& (codesetp == NULL || *codesetp == NULL))
{
if (dirnamep)
*dirnamep = _nl_default_dirname;
#if defined _WIN32 && !defined __CYGWIN__
if (wdirnamep)
*wdirnamep = NULL;
#endif
if (codesetp)
*codesetp = NULL;
}
else
{
size_t len = strlen (domainname) + 1;
struct binding *new_binding =
(struct binding *) malloc (offsetof (struct binding, domainname) + len);
if (__builtin_expect (new_binding == NULL, 0))
goto failed;
memcpy (new_binding->domainname, domainname, len);
if (dirnamep)
{
const char *dirname = *dirnamep;
if (dirname == NULL)
{
#if defined _WIN32 && !defined __CYGWIN__
if (wdirnamep && *wdirnamep != NULL)
dirname = NULL;
else
#endif
dirname = _nl_default_dirname;
}
else
{
if (strcmp (dirname, _nl_default_dirname) == 0)
dirname = _nl_default_dirname;
else
{
char *result = strdup (dirname);
if (__builtin_expect (result == NULL, 0))
goto failed_dirname;
dirname = result;
}
}
*dirnamep = dirname;
new_binding->dirname = (char *) dirname;
}
else
{
#if defined _WIN32 && !defined __CYGWIN__
if (wdirnamep && *wdirnamep != NULL)
new_binding->dirname = NULL;
else
#endif
new_binding->dirname = (char *) _nl_default_dirname;
}
#if defined _WIN32 && !defined __CYGWIN__
if (wdirnamep)
{
const wchar_t *wdirname = *wdirnamep;
if (wdirname != NULL)
{
wchar_t *result = _wcsdup (wdirname);
if (__builtin_expect (result == NULL, 0))
goto failed_wdirname;
wdirname = result;
}
*wdirnamep = wdirname;
new_binding->wdirname = (wchar_t *) wdirname;
}
else
new_binding->wdirname = NULL;
#endif
if (codesetp)
{
const char *codeset = *codesetp;
if (codeset != NULL)
{
char *result = strdup (codeset);
if (__builtin_expect (result == NULL, 0))
goto failed_codeset;
codeset = result;
}
*codesetp = codeset;
new_binding->codeset = (char *) codeset;
}
else
new_binding->codeset = NULL;
if (_nl_domain_bindings == NULL
|| strcmp (domainname, _nl_domain_bindings->domainname) < 0)
{
new_binding->next = _nl_domain_bindings;
_nl_domain_bindings = new_binding;
}
else
{
binding = _nl_domain_bindings;
while (binding->next != NULL
&& strcmp (domainname, binding->next->domainname) > 0)
binding = binding->next;
new_binding->next = binding->next;
binding->next = new_binding;
}
modified = 1;
if (0)
{
failed_codeset:
#if defined _WIN32 && !defined __CYGWIN__
free (new_binding->wdirname);
failed_wdirname:
#endif
if (new_binding->dirname != _nl_default_dirname)
free (new_binding->dirname);
failed_dirname:
free (new_binding);
failed:
if (dirnamep)
*dirnamep = NULL;
#if defined _WIN32 && !defined __CYGWIN__
if (wdirnamep)
*wdirnamep = NULL;
#endif
if (codesetp)
*codesetp = NULL;
}
}
if (modified)
++_nl_msg_cat_cntr;
gl_rwlock_unlock (_nl_state_lock);
}
char *
BINDTEXTDOMAIN (const char *domainname, const char *dirname)
{
#ifdef __EMX__
const char *saved_dirname = dirname;
char dirname_with_drive[_MAX_PATH];
# ifdef __KLIBC__
if (dirname && strncmp (dirname, "/@unixroot", 10) == 0
&& (dirname[10] == '\0' || dirname[10] == '/' || dirname[10] == '\\'))
;
else
# endif
if (dirname && (dirname[0] == '/' || dirname[0] == '\\' ))
{
const char *unixroot = getenv ("UNIXROOT");
size_t len = strlen (dirname) + 1;
if (unixroot
&& unixroot[0] != '\0'
&& unixroot[1] == ':'
&& unixroot[2] == '\0'
&& 2 + len <= _MAX_PATH)
{
memcpy (dirname_with_drive, unixroot, 2);
memcpy (dirname_with_drive + 2, dirname, len);
dirname = dirname_with_drive;
}
}
#endif
set_binding_values (domainname, &dirname, NULL, NULL);
#ifdef __EMX__
dirname = saved_dirname;
#endif
return (char *) dirname;
}
#if defined _WIN32 && !defined __CYGWIN__
wchar_t *
libintl_wbindtextdomain (const char *domainname, const wchar_t *wdirname)
{
set_binding_values (domainname, NULL, &wdirname, NULL);
return (wchar_t *) wdirname;
}
#endif
char *
BIND_TEXTDOMAIN_CODESET (const char *domainname, const char *codeset)
{
set_binding_values (domainname, NULL, NULL, &codeset);
return (char *) codeset;
}
#ifdef _LIBC
weak_alias (__bindtextdomain, bindtextdomain);
weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
#endif