#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include "Xlibint.h"
#include "XlcPubI.h"
#include <X11/Xos.h>
#include <unistd.h>
#ifdef __UNIXOS2__
# define seteuid setuid
#endif
#define iscomment(ch) ((ch) == '#' || (ch) == '\0')
#if defined(WIN32)
#define isreadable(f) (_XAccessFile(f))
#else
#define isreadable(f) ((access((f), R_OK) != -1) ? 1 : 0)
#endif
#ifndef __UNIXOS2__
#define LC_PATHDELIM ':'
#else
#define LC_PATHDELIM ';'
#endif
#define XLC_BUFSIZE 256
#ifndef X_NOT_POSIX
#ifdef _POSIX_SOURCE
#include <limits.h>
#else
#define _POSIX_SOURCE
#include <limits.h>
#undef _POSIX_SOURCE
#endif
#endif
#ifndef PATH_MAX
#ifdef WIN32
#define PATH_MAX 512
#else
#include <sys/param.h>
#endif
#ifndef PATH_MAX
#ifdef MAXPATHLEN
#define PATH_MAX MAXPATHLEN
#else
#define PATH_MAX 1024
#endif
#endif
#endif
#define NUM_LOCALEDIR 64
static int
parse_line(
char *line,
char **argv,
int argsize)
{
int argc = 0;
char *p = line;
while (argc < argsize) {
while (isspace(*p)) {
++p;
}
if (*p == '\0') {
break;
}
argv[argc++] = p;
while (*p != ':' && *p != '\n' && *p != '\0') {
++p;
}
if (*p == '\0') {
break;
}
*p++ = '\0';
}
return argc;
}
#ifdef __UNIXOS2__
static int
parse_line1(
char *line,
char **argv,
int argsize)
{
int argc = 0;
char *p = line;
while (argc < argsize) {
while (isspace(*p)) {
++p;
}
if (*p == '\0') {
break;
}
argv[argc++] = p;
while (*p != ';' && *p != '\n' && *p != '\0') {
++p;
}
if (*p == '\0') {
break;
}
*p++ = '\0';
}
return argc;
}
#elif defined(WIN32)
static int
parse_line1(
char *line,
char **argv,
int argsize)
{
int argc = 0;
char *p = line;
while (argc < argsize) {
while (isspace(*p)) {
++p;
}
if (*p == '\0') {
break;
}
argv[argc++] = p;
if (isalpha(*p) && p[1] == ':') {
p+= 2;
}
while (*p != ':' && *p != '\n' && *p != '\0') {
++p;
}
if (*p == '\0') {
break;
}
*p++ = '\0';
}
return argc;
}
#endif
static int
_XlcParsePath(
char *path,
char **argv,
int argsize)
{
char *p = path;
int n, i;
#if !defined(__UNIXOS2__) && !defined(WIN32)
n = parse_line(path, argv, argsize);
#else
n = parse_line1(path, argv, argsize);
#endif
for (i = 0; i < n; ++i) {
int len;
p = argv[i];
len = strlen(p);
if (len > 0 && p[len - 1] == '/') {
p[len - 1] = '\0';
}
}
return n;
}
#ifndef XLOCALEDIR
#define XLOCALEDIR "/usr/lib/X11/locale"
#endif
static void
xlocaledir(
char *buf,
int buf_len)
{
char *p = buf;
int len = 0;
#ifndef NO_XLOCALEDIR
char *dir;
int priv = 1;
dir = getenv("XLOCALEDIR");
if (dir) {
#ifndef WIN32
if (getuid() == geteuid() && getgid() == getegid()) {
#if defined(HASSETUGID)
priv = issetugid();
#elif defined(HASGETRESUID)
{
uid_t ruid, euid, suid;
gid_t rgid, egid, sgid;
if ((getresuid(&ruid, &euid, &suid) == 0) &&
(getresgid(&rgid, &egid, &sgid) == 0))
priv = (euid != suid) || (egid != sgid);
}
#else
unsigned int oldeuid;
oldeuid = geteuid();
if (seteuid(0) != 0) {
priv = 0;
} else {
if (seteuid(oldeuid) == -1) {
_exit(127);
}
priv = 1;
}
#endif
}
#else
priv = 0;
#endif
if (!priv) {
len = strlen(dir);
strncpy(p, dir, buf_len);
if (len < buf_len) {
p[len++] = LC_PATHDELIM;
p += len;
}
}
}
#endif
if (len < buf_len)
#ifndef __UNIXOS2__
strncpy(p, XLOCALEDIR, buf_len - len);
#else
strncpy(p,__XOS2RedirRoot(XLOCALEDIR), buf_len - len);
#endif
buf[buf_len-1] = '\0';
}
static void
xlocalelibdir(
char *buf,
int buf_len)
{
char *p = buf;
int len = 0;
#ifndef NO_XLOCALEDIR
char *dir;
int priv = 1;
dir = getenv("XLOCALELIBDIR");
if (dir) {
#ifndef WIN32
if (getuid() == geteuid() && getgid() == getegid()) {
#if defined(HASSETUGID)
priv = issetugid();
#elif defined(HASGETRESUID)
{
uid_t ruid, euid, suid;
gid_t rgid, egid, sgid;
if ((getresuid(&ruid, &euid, &suid) == 0) &&
(getresgid(&rgid, &egid, &sgid) == 0))
priv = (euid != suid) || (egid != sgid);
}
#else
unsigned int oldeuid;
oldeuid = geteuid();
if (seteuid(0) != 0) {
priv = 0;
} else {
if (seteuid(oldeuid) == -1) {
_exit(127);
}
priv = 1;
}
#endif
}
#else
priv = 0;
#endif
if (!priv) {
len = strlen(dir);
strncpy(p, dir, buf_len);
if (len < buf_len) {
p[len++] = LC_PATHDELIM;
p += len;
}
}
}
#endif
if (len < buf_len)
#ifndef __UNIXOS2__
strncpy(p, XLOCALELIBDIR, buf_len - len);
#else
strncpy(p,__XOS2RedirRoot(XLOCALELIBDIR), buf_len - len);
#endif
buf[buf_len-1] = '\0';
}
typedef enum {
LtoR,
RtoL
} MapDirection;
static char *
resolve_name(
const char *lc_name,
char *file_name,
MapDirection direction)
{
FILE *fp;
char buf[XLC_BUFSIZE], *name = NULL;
fp = _XFopenFile (file_name, "r");
if (fp == NULL)
return NULL;
while (fgets(buf, XLC_BUFSIZE, fp) != NULL) {
char *p = buf;
int n;
char *args[2], *from, *to;
#ifdef __UNIXOS2__
int len;
len = strlen(p);
if (len > 1) {
if (*(p+len-2) == '\r' && *(p+len-1) == '\n') {
*(p+len-2) = '\n';
*(p+len-1) = '\0';
}
}
#endif
while (isspace(*p)) {
++p;
}
if (iscomment(*p)) {
continue;
}
n = parse_line(p, args, 2);
if (n != 2) {
continue;
}
if (direction == LtoR) {
from = args[0], to = args[1];
} else {
from = args[1], to = args[0];
}
if (! strcmp(from, lc_name)) {
name = Xmalloc(strlen(to) + 1);
if (name != NULL) {
strcpy(name, to);
}
break;
}
}
fclose(fp);
return name;
}
#define c_tolower(ch) ((ch) >= 'A' && (ch) <= 'Z' ? (ch) - 'A' + 'a' : (ch))
static char *
lowercase(
char *dst,
const char *src)
{
const char *s;
char *t;
for (s = src, t = dst; *s; ++s, ++t)
*t = c_tolower(*s);
*t = '\0';
return dst;
}
static char *
normalize_lcname (const char *name)
{
char *p, *ret;
const char *tmp = name;
p = ret = Xmalloc(strlen(name) + 1);
if (!p)
return NULL;
if (tmp) {
while (*tmp && *tmp != '.' && *tmp != '@')
*p++ = *tmp++;
while (*tmp) {
if (*tmp != '-')
*p++ = c_tolower(*tmp);
tmp++;
}
}
*p = '\0';
if (strcmp(ret, name) == 0) {
Xfree(ret);
return NULL;
}
return ret;
}
char *
_XlcFileName(
XLCd lcd,
const char *category)
{
char *siname;
char cat[XLC_BUFSIZE], dir[XLC_BUFSIZE];
int i, n;
char *args[NUM_LOCALEDIR];
char *file_name = NULL;
if (lcd == (XLCd)NULL)
return NULL;
siname = XLC_PUBLIC(lcd, siname);
lowercase(cat, category);
xlocaledir(dir,XLC_BUFSIZE);
n = _XlcParsePath(dir, args, NUM_LOCALEDIR);
for (i = 0; i < n; ++i) {
char buf[PATH_MAX], *name;
name = NULL;
if ((5 + (args[i] ? strlen (args[i]) : 0) +
(cat ? strlen (cat) : 0)) < PATH_MAX) {
sprintf(buf, "%s/%s.dir", args[i], cat);
name = resolve_name(siname, buf, RtoL);
}
if (name == NULL) {
continue;
}
if (*name == '/') {
file_name = name;
} else {
file_name = Xmalloc(2 + (args[i] ? strlen (args[i]) : 0) +
(name ? strlen (name) : 0));
if (file_name != NULL)
sprintf(file_name, "%s/%s", args[i], name);
Xfree(name);
}
if (isreadable(file_name)) {
break;
}
Xfree(file_name);
file_name = NULL;
}
return file_name;
}
#ifndef LOCALE_ALIAS
#define LOCALE_ALIAS "locale.alias"
#endif
int
_XlcResolveLocaleName(
const char* lc_name,
XLCdPublicPart* pub)
{
char dir[PATH_MAX], buf[PATH_MAX], *name = NULL;
char *dst;
int i, n, sinamelen;
char *args[NUM_LOCALEDIR];
static const char locale_alias[] = LOCALE_ALIAS;
char *tmp_siname;
char *nlc_name = NULL;
xlocaledir (dir, PATH_MAX);
n = _XlcParsePath(dir, args, NUM_LOCALEDIR);
for (i = 0; i < n; ++i) {
if ((2 + (args[i] ? strlen (args[i]) : 0) +
strlen (locale_alias)) < PATH_MAX) {
sprintf (buf, "%s/%s", args[i], locale_alias);
name = resolve_name (lc_name, buf, LtoR);
if (!name) {
if (!nlc_name)
nlc_name = normalize_lcname(lc_name);
if (nlc_name)
name = resolve_name (nlc_name, buf, LtoR);
}
}
if (name != NULL) {
break;
}
}
if (nlc_name) Xfree(nlc_name);
if (name == NULL) {
pub->siname = Xmalloc (strlen (lc_name) + 1);
strcpy (pub->siname, lc_name);
} else {
pub->siname = name;
}
sinamelen = strlen (pub->siname);
if (sinamelen == 1 && pub->siname[0] == 'C') {
pub->language = pub->siname;
pub->territory = pub->codeset = NULL;
return 1;
}
tmp_siname = Xrealloc (pub->siname, 2 * (sinamelen + 1));
if (tmp_siname == NULL) {
return 0;
}
pub->siname = tmp_siname;
dst = &pub->siname[sinamelen + 1];
strcpy (dst, pub->siname);
pub->language = dst;
dst = strchr (dst, '_');
if (dst) {
*dst = '\0';
pub->territory = ++dst;
} else
dst = &pub->siname[sinamelen + 1];
dst = strchr (dst, '.');
if (dst) {
*dst = '\0';
pub->codeset = ++dst;
}
return (pub->siname[0] != '\0') ? 1 : 0;
}
int
_XlcResolveI18NPath(buf, buf_len)
char *buf;
int buf_len;
{
if (buf != NULL) {
xlocaledir(buf, buf_len);
}
return 1;
}
char *
_XlcLocaleDirName(dir_name, dir_len, lc_name)
char *dir_name;
size_t dir_len;
char *lc_name;
{
char dir[PATH_MAX], buf[PATH_MAX], *name = NULL;
int i, n;
char *args[NUM_LOCALEDIR];
static char locale_alias[] = LOCALE_ALIAS;
char *target_name = (char*)0;
char *target_dir = (char*)0;
char *nlc_name = NULL;
static char* last_dir_name = 0;
static size_t last_dir_len = 0;
static char* last_lc_name = 0;
if (last_lc_name != 0 && strcmp (last_lc_name, lc_name) == 0
&& dir_len >= last_dir_len) {
strcpy (dir_name, last_dir_name);
return dir_name;
}
xlocaledir (dir, PATH_MAX);
n = _XlcParsePath(dir, args, 256);
for (i = 0; i < n; ++i) {
if ((2 + (args[i] ? strlen(args[i]) : 0) +
strlen(locale_alias)) < PATH_MAX) {
sprintf (buf, "%s/%s", args[i], locale_alias);
name = resolve_name(lc_name, buf, LtoR);
if (!name) {
if (!nlc_name)
nlc_name = normalize_lcname(lc_name);
if (nlc_name)
name = resolve_name (nlc_name, buf, LtoR);
}
}
if (name == NULL)
name = lc_name;
target_dir = args[i];
if (!target_dir) {
if (name != lc_name)
Xfree(name);
continue;
}
if ((1 + (target_dir ? strlen (target_dir) : 0) +
strlen("locale.dir")) < PATH_MAX) {
sprintf(buf, "%s/locale.dir", target_dir);
target_name = resolve_name(name, buf, RtoL);
}
if (name != lc_name)
Xfree(name);
if (target_name != NULL) {
char *p = 0;
if ((p = strstr(target_name, "/XLC_LOCALE"))) {
*p = '\0';
break;
}
Xfree(target_name);
target_name = NULL;
}
name = NULL;
}
if (nlc_name) Xfree(nlc_name);
if (target_name == NULL) {
target_dir = args[0];
target_name = lc_name;
}
strncpy(dir_name, target_dir, dir_len - 1);
if (strlen(target_dir) >= dir_len - 1) {
dir_name[dir_len - 1] = '\0';
} else {
strcat(dir_name, "/");
strncat(dir_name, target_name, dir_len - strlen(dir_name) - 1);
if (strlen(target_name) >= dir_len - strlen(dir_name) - 1)
dir_name[dir_len - 1] = '\0';
}
if (target_name != lc_name)
Xfree(target_name);
if (last_dir_name != 0)
Xfree (last_dir_name);
if (last_lc_name != 0)
Xfree (last_lc_name);
last_dir_len = strlen (dir_name) + 1;
last_dir_name = Xmalloc (last_dir_len);
strcpy (last_dir_name, dir_name);
last_lc_name = Xmalloc (strlen (lc_name) + 1);
strcpy (last_lc_name, lc_name);
return dir_name;
}
char *
_XlcLocaleLibDirName(dir_name, dir_len, lc_name)
char *dir_name;
size_t dir_len;
char *lc_name;
{
char dir[PATH_MAX], buf[PATH_MAX], *name = NULL;
int i, n;
char *args[NUM_LOCALEDIR];
static char locale_alias[] = LOCALE_ALIAS;
char *target_name = (char*)0;
char *target_dir = (char*)0;
char *nlc_name = NULL;
static char* last_dir_name = 0;
static size_t last_dir_len = 0;
static char* last_lc_name = 0;
if (last_lc_name != 0 && strcmp (last_lc_name, lc_name) == 0
&& dir_len >= last_dir_len) {
strcpy (dir_name, last_dir_name);
return dir_name;
}
xlocalelibdir (dir, PATH_MAX);
n = _XlcParsePath(dir, args, 256);
for (i = 0; i < n; ++i) {
if ((2 + (args[i] ? strlen(args[i]) : 0) +
strlen(locale_alias)) < PATH_MAX) {
sprintf (buf, "%s/%s", args[i], locale_alias);
name = resolve_name(lc_name, buf, LtoR);
if (!name) {
if (!nlc_name)
nlc_name = normalize_lcname(lc_name);
if (nlc_name)
name = resolve_name (nlc_name, buf, LtoR);
}
}
if (name == NULL)
name = lc_name;
target_dir = args[i];
if (!target_dir) {
if (name != lc_name)
Xfree(name);
continue;
}
if ((1 + (target_dir ? strlen (target_dir) : 0) +
strlen("locale.dir")) < PATH_MAX) {
sprintf(buf, "%s/locale.dir", target_dir);
target_name = resolve_name(name, buf, RtoL);
}
if (name != lc_name)
Xfree(name);
if (target_name != NULL) {
char *p = 0;
if ((p = strstr(target_name, "/XLC_LOCALE"))) {
*p = '\0';
break;
}
Xfree(target_name);
target_name = NULL;
}
name = NULL;
}
if (nlc_name) Xfree(nlc_name);
if (target_name == NULL) {
target_dir = args[0];
target_name = lc_name;
}
strncpy(dir_name, target_dir, dir_len - 1);
if (strlen(target_dir) >= dir_len - 1) {
dir_name[dir_len - 1] = '\0';
} else {
strcat(dir_name, "/");
strncat(dir_name, target_name, dir_len - strlen(dir_name) - 1);
if (strlen(target_name) >= dir_len - strlen(dir_name) - 1)
dir_name[dir_len - 1] = '\0';
}
if (target_name != lc_name)
Xfree(target_name);
if (last_dir_name != 0)
Xfree (last_dir_name);
if (last_lc_name != 0)
Xfree (last_lc_name);
last_dir_len = strlen (dir_name) + 1;
last_dir_name = Xmalloc (last_dir_len);
strcpy (last_dir_name, dir_name);
last_lc_name = Xmalloc (strlen (lc_name) + 1);
strcpy (last_lc_name, lc_name);
return dir_name;
}