lcFile.c revision 6cc2b21f
11ab64890Smrg/*
21ab64890Smrg *
31ab64890Smrg * Copyright IBM Corporation 1993
41ab64890Smrg *
51ab64890Smrg * All Rights Reserved
61ab64890Smrg *
71ab64890Smrg * License to use, copy, modify, and distribute this software and its
81ab64890Smrg * documentation for any purpose and without fee is hereby granted,
91ab64890Smrg * provided that the above copyright notice appear in all copies and that
101ab64890Smrg * both that copyright notice and this permission notice appear in
111ab64890Smrg * supporting documentation, and that the name of IBM not be
121ab64890Smrg * used in advertising or publicity pertaining to distribution of the
131ab64890Smrg * software without specific, written prior permission.
141ab64890Smrg *
151ab64890Smrg * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1661b2299dSmrg * ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS, AND
171ab64890Smrg * NONINFRINGEMENT OF THIRD PARTY RIGHTS, IN NO EVENT SHALL
181ab64890Smrg * IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
191ab64890Smrg * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
201ab64890Smrg * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
211ab64890Smrg * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
221ab64890Smrg * SOFTWARE.
231ab64890Smrg *
241ab64890Smrg*/
251ab64890Smrg
261ab64890Smrg#ifdef HAVE_CONFIG_H
271ab64890Smrg#include <config.h>
281ab64890Smrg#endif
291ab64890Smrg#include <stdlib.h>
301ab64890Smrg#include <stdio.h>
311ab64890Smrg#include <ctype.h>
321ab64890Smrg#include "Xlibint.h"
331ab64890Smrg#include "XlcPubI.h"
341ab64890Smrg#include <X11/Xos.h>
351ab64890Smrg#include <unistd.h>
361ab64890Smrg
371ab64890Smrg/************************************************************************/
381ab64890Smrg
391ab64890Smrg#ifdef __UNIXOS2__
401ab64890Smrg# define seteuid setuid
411ab64890Smrg#endif
421ab64890Smrg#define	iscomment(ch)	((ch) == '#' || (ch) == '\0')
431ab64890Smrg#if defined(WIN32)
441ab64890Smrg#define isreadable(f)	(_XAccessFile(f))
451ab64890Smrg#else
461ab64890Smrg#define isreadable(f)	((access((f), R_OK) != -1) ? 1 : 0)
471ab64890Smrg#endif
481ab64890Smrg
491ab64890Smrg#ifndef __UNIXOS2__
501ab64890Smrg#define LC_PATHDELIM ':'
511ab64890Smrg#else
521ab64890Smrg#define LC_PATHDELIM ';'
531ab64890Smrg#endif
541ab64890Smrg
551ab64890Smrg#define XLC_BUFSIZE 256
561ab64890Smrg
571ab64890Smrg#ifndef X_NOT_POSIX
581ab64890Smrg#ifdef _POSIX_SOURCE
591ab64890Smrg#include <limits.h>
601ab64890Smrg#else
611ab64890Smrg#define _POSIX_SOURCE
621ab64890Smrg#include <limits.h>
631ab64890Smrg#undef _POSIX_SOURCE
641ab64890Smrg#endif
651ab64890Smrg#endif
661ab64890Smrg#ifndef PATH_MAX
671ab64890Smrg#ifdef WIN32
681ab64890Smrg#define PATH_MAX 512
691ab64890Smrg#else
701ab64890Smrg#include <sys/param.h>
711ab64890Smrg#endif
721ab64890Smrg#ifndef PATH_MAX
731ab64890Smrg#ifdef MAXPATHLEN
741ab64890Smrg#define PATH_MAX MAXPATHLEN
751ab64890Smrg#else
761ab64890Smrg#define PATH_MAX 1024
771ab64890Smrg#endif
781ab64890Smrg#endif
791ab64890Smrg#endif
801ab64890Smrg
811ab64890Smrg#define NUM_LOCALEDIR	64
821ab64890Smrg
831ab64890Smrg/* Splits a NUL terminated line into constituents, at colons and newline
841ab64890Smrg   characters. Leading whitespace is removed from constituents. The
851ab64890Smrg   constituents are stored at argv[0..argsize-1]. The number of stored
861ab64890Smrg   constituents (<= argsize) is returned. The line is destructively
871ab64890Smrg   modified. */
881ab64890Smrgstatic int
891ab64890Smrgparse_line(
901ab64890Smrg    char *line,
911ab64890Smrg    char **argv,
921ab64890Smrg    int argsize)
931ab64890Smrg{
941ab64890Smrg    int argc = 0;
951ab64890Smrg    char *p = line;
961ab64890Smrg
971ab64890Smrg    while (argc < argsize) {
981ab64890Smrg	while (isspace(*p)) {
991ab64890Smrg	    ++p;
1001ab64890Smrg	}
1011ab64890Smrg	if (*p == '\0') {
1021ab64890Smrg	    break;
1031ab64890Smrg	}
1041ab64890Smrg	argv[argc++] = p;
1051ab64890Smrg	while (*p != ':' && *p != '\n' && *p != '\0') {
1061ab64890Smrg	    ++p;
1071ab64890Smrg	}
1081ab64890Smrg	if (*p == '\0') {
1091ab64890Smrg	    break;
1101ab64890Smrg	}
1111ab64890Smrg	*p++ = '\0';
1121ab64890Smrg    }
1131ab64890Smrg
1141ab64890Smrg    return argc;
1151ab64890Smrg}
1161ab64890Smrg
1171ab64890Smrg#ifdef __UNIXOS2__
1181ab64890Smrg
1191ab64890Smrg/* fg021216: entries in locale files are separated by colons while under
1201ab64890Smrg   OS/2, path entries are separated by semicolon, so we need two functions */
1211ab64890Smrg
1221ab64890Smrgstatic int
1231ab64890Smrgparse_line1(
1241ab64890Smrg    char *line,
1251ab64890Smrg    char **argv,
1261ab64890Smrg    int argsize)
1271ab64890Smrg{
1281ab64890Smrg    int argc = 0;
1291ab64890Smrg    char *p = line;
1301ab64890Smrg
1311ab64890Smrg    while (argc < argsize) {
1321ab64890Smrg	while (isspace(*p)) {
1331ab64890Smrg	    ++p;
1341ab64890Smrg	}
1351ab64890Smrg	if (*p == '\0') {
1361ab64890Smrg	    break;
1371ab64890Smrg	}
1381ab64890Smrg	argv[argc++] = p;
1391ab64890Smrg	while (*p != ';' && *p != '\n' && *p != '\0') {
1401ab64890Smrg	    ++p;
1411ab64890Smrg	}
1421ab64890Smrg	if (*p == '\0') {
1431ab64890Smrg	    break;
1441ab64890Smrg	}
1451ab64890Smrg	*p++ = '\0';
1461ab64890Smrg    }
1471ab64890Smrg
1481ab64890Smrg    return argc;
1491ab64890Smrg}
1501ab64890Smrg#elif defined(WIN32)
1511ab64890Smrg
1521ab64890Smrg/* this is parse_line but skips drive letters at the beginning of the entry */
1531ab64890Smrgstatic int
1541ab64890Smrgparse_line1(
1551ab64890Smrg    char *line,
1561ab64890Smrg    char **argv,
1571ab64890Smrg    int argsize)
1581ab64890Smrg{
1591ab64890Smrg    int argc = 0;
1601ab64890Smrg    char *p = line;
1611ab64890Smrg
1621ab64890Smrg    while (argc < argsize) {
1631ab64890Smrg	while (isspace(*p)) {
1641ab64890Smrg	    ++p;
1651ab64890Smrg	}
1661ab64890Smrg	if (*p == '\0') {
1671ab64890Smrg	    break;
1681ab64890Smrg	}
1691ab64890Smrg	argv[argc++] = p;
1701ab64890Smrg        if (isalpha(*p) && p[1] == ':') {
1711ab64890Smrg            p+= 2; /* skip drive letters */
1721ab64890Smrg        }
1731ab64890Smrg	while (*p != ':' && *p != '\n' && *p != '\0') {
1741ab64890Smrg	    ++p;
1751ab64890Smrg	}
1761ab64890Smrg	if (*p == '\0') {
1771ab64890Smrg	    break;
1781ab64890Smrg	}
1791ab64890Smrg	*p++ = '\0';
1801ab64890Smrg    }
1811ab64890Smrg
1821ab64890Smrg    return argc;
1831ab64890Smrg}
1841ab64890Smrg
1851ab64890Smrg#endif   /* __UNIXOS2__ */
1861ab64890Smrg
1871ab64890Smrg/* Splits a colon separated list of directories, and returns the constituent
1881ab64890Smrg   paths (without trailing slash). At most argsize constituents are stored
1891ab64890Smrg   at argv[0..argsize-1]. The number of stored constituents is returned. */
1901ab64890Smrgstatic int
1911ab64890Smrg_XlcParsePath(
1921ab64890Smrg    char *path,
1931ab64890Smrg    char **argv,
1941ab64890Smrg    int argsize)
1951ab64890Smrg{
1961ab64890Smrg    char *p = path;
1971ab64890Smrg    int n, i;
1981ab64890Smrg
1991ab64890Smrg#if !defined(__UNIXOS2__) && !defined(WIN32)
2001ab64890Smrg    n = parse_line(path, argv, argsize);
2011ab64890Smrg#else
2021ab64890Smrg    n = parse_line1(path, argv, argsize);
2031ab64890Smrg#endif
2041ab64890Smrg    for (i = 0; i < n; ++i) {
2051ab64890Smrg	int len;
2061ab64890Smrg	p = argv[i];
2071ab64890Smrg	len = strlen(p);
2081ab64890Smrg	if (len > 0 && p[len - 1] == '/') {
2091ab64890Smrg	    /* eliminate trailing slash */
2101ab64890Smrg	    p[len - 1] = '\0';
2111ab64890Smrg	}
2121ab64890Smrg    }
2131ab64890Smrg    return n;
2141ab64890Smrg}
2151ab64890Smrg
2161ab64890Smrg#ifndef XLOCALEDIR
2171ab64890Smrg#define XLOCALEDIR "/usr/lib/X11/locale"
2181ab64890Smrg#endif
2191ab64890Smrg
220b4ee4795Smrgvoid
2211ab64890Smrgxlocaledir(
2221ab64890Smrg    char *buf,
2231ab64890Smrg    int buf_len)
2241ab64890Smrg{
2251ab64890Smrg    char *p = buf;
2261ab64890Smrg    int len = 0;
2271ab64890Smrg
2281ab64890Smrg#ifndef NO_XLOCALEDIR
2291ab64890Smrg    char *dir;
2301ab64890Smrg    int priv = 1;
2311ab64890Smrg
2321ab64890Smrg    dir = getenv("XLOCALEDIR");
2331ab64890Smrg
2341ab64890Smrg    if (dir) {
2351ab64890Smrg#ifndef WIN32
2361ab64890Smrg	/*
2371ab64890Smrg	 * Only use the user-supplied path if the process isn't priviledged.
2381ab64890Smrg	 */
2391ab64890Smrg	if (getuid() == geteuid() && getgid() == getegid()) {
2401ab64890Smrg#if defined(HASSETUGID)
2411ab64890Smrg	    priv = issetugid();
2421ab64890Smrg#elif defined(HASGETRESUID)
2431ab64890Smrg	    {
2441ab64890Smrg		uid_t ruid, euid, suid;
2451ab64890Smrg		gid_t rgid, egid, sgid;
2461ab64890Smrg		if ((getresuid(&ruid, &euid, &suid) == 0) &&
2471ab64890Smrg		    (getresgid(&rgid, &egid, &sgid) == 0))
2481ab64890Smrg		    priv = (euid != suid) || (egid != sgid);
2491ab64890Smrg	    }
2501ab64890Smrg#else
2511ab64890Smrg	    /*
2521ab64890Smrg	     * If there are saved ID's the process might still be priviledged
2531ab64890Smrg	     * even though the above test succeeded.  If issetugid() and
2541ab64890Smrg	     * getresgid() aren't available, test this by trying to set
2551ab64890Smrg	     * euid to 0.
2561ab64890Smrg	     *
2571ab64890Smrg	     * Note: this only protects setuid-root clients.  It doesn't
2581ab64890Smrg	     * protect other setuid or any setgid clients.  If this tradeoff
2591ab64890Smrg	     * isn't acceptable, set DisableXLocaleDirEnv to YES in host.def.
2601ab64890Smrg	     */
2611ab64890Smrg	    unsigned int oldeuid;
2621ab64890Smrg	    oldeuid = geteuid();
2631ab64890Smrg	    if (seteuid(0) != 0) {
2641ab64890Smrg		priv = 0;
2651ab64890Smrg	    } else {
2661ab64890Smrg		if (seteuid(oldeuid) == -1) {
26761b2299dSmrg		    /* XXX ouch, coudn't get back to original uid
2681ab64890Smrg		     what can we do ??? */
2691ab64890Smrg		    _exit(127);
2701ab64890Smrg		}
2711ab64890Smrg		priv = 1;
2721ab64890Smrg	    }
2731ab64890Smrg#endif
2741ab64890Smrg	}
2751ab64890Smrg#else
2761ab64890Smrg	priv = 0;
2771ab64890Smrg#endif
2781ab64890Smrg	if (!priv) {
2791ab64890Smrg	    len = strlen(dir);
2801ab64890Smrg	    strncpy(p, dir, buf_len);
2811ab64890Smrg	    if (len < buf_len) {
2821ab64890Smrg	        p[len++] = LC_PATHDELIM;
2831ab64890Smrg	        p += len;
2841ab64890Smrg	    }
2851ab64890Smrg	}
2861ab64890Smrg    }
2871ab64890Smrg#endif /* NO_XLOCALEDIR */
2881ab64890Smrg
2891ab64890Smrg    if (len < buf_len)
2901ab64890Smrg#ifndef __UNIXOS2__
2911ab64890Smrg      strncpy(p, XLOCALEDIR, buf_len - len);
2921ab64890Smrg#else
2931ab64890Smrg      strncpy(p,__XOS2RedirRoot(XLOCALEDIR), buf_len - len);
2941ab64890Smrg#endif
2951ab64890Smrg    buf[buf_len-1] = '\0';
2961ab64890Smrg}
2971ab64890Smrg
2981ab64890Smrgstatic void
2991ab64890Smrgxlocalelibdir(
3001ab64890Smrg    char *buf,
3011ab64890Smrg    int buf_len)
3021ab64890Smrg{
3031ab64890Smrg    char *p = buf;
3041ab64890Smrg    int len = 0;
3051ab64890Smrg
3061ab64890Smrg#ifndef NO_XLOCALEDIR
3071ab64890Smrg    char *dir;
3081ab64890Smrg    int priv = 1;
3091ab64890Smrg
3101ab64890Smrg    dir = getenv("XLOCALELIBDIR");
3111ab64890Smrg
3121ab64890Smrg    if (dir) {
3131ab64890Smrg#ifndef WIN32
3141ab64890Smrg	/*
3151ab64890Smrg	 * Only use the user-supplied path if the process isn't priviledged.
3161ab64890Smrg	 */
3171ab64890Smrg	if (getuid() == geteuid() && getgid() == getegid()) {
3181ab64890Smrg#if defined(HASSETUGID)
3191ab64890Smrg	    priv = issetugid();
3201ab64890Smrg#elif defined(HASGETRESUID)
3211ab64890Smrg	    {
3221ab64890Smrg		uid_t ruid, euid, suid;
3231ab64890Smrg		gid_t rgid, egid, sgid;
3241ab64890Smrg		if ((getresuid(&ruid, &euid, &suid) == 0) &&
3251ab64890Smrg		    (getresgid(&rgid, &egid, &sgid) == 0))
3261ab64890Smrg		    priv = (euid != suid) || (egid != sgid);
3271ab64890Smrg	    }
3281ab64890Smrg#else
3291ab64890Smrg	    /*
3301ab64890Smrg	     * If there are saved ID's the process might still be priviledged
3311ab64890Smrg	     * even though the above test succeeded.  If issetugid() and
3321ab64890Smrg	     * getresgid() aren't available, test this by trying to set
3331ab64890Smrg	     * euid to 0.
3341ab64890Smrg	     *
3351ab64890Smrg	     * Note: this only protects setuid-root clients.  It doesn't
3361ab64890Smrg	     * protect other setuid or any setgid clients.  If this tradeoff
3371ab64890Smrg	     * isn't acceptable, set DisableXLocaleDirEnv to YES in host.def.
3381ab64890Smrg	     */
3391ab64890Smrg	    unsigned int oldeuid;
3401ab64890Smrg	    oldeuid = geteuid();
3411ab64890Smrg	    if (seteuid(0) != 0) {
3421ab64890Smrg		priv = 0;
3431ab64890Smrg	    } else {
3441ab64890Smrg		if (seteuid(oldeuid) == -1) {
34561b2299dSmrg		    /* XXX ouch, coudn't get back to original uid
3461ab64890Smrg		     what can we do ??? */
3471ab64890Smrg		    _exit(127);
3481ab64890Smrg		}
3491ab64890Smrg		priv = 1;
3501ab64890Smrg	    }
3511ab64890Smrg#endif
3521ab64890Smrg	}
3531ab64890Smrg#else
3541ab64890Smrg	priv = 0;
3551ab64890Smrg#endif
3561ab64890Smrg	if (!priv) {
3571ab64890Smrg	    len = strlen(dir);
3581ab64890Smrg	    strncpy(p, dir, buf_len);
3591ab64890Smrg	    if (len < buf_len) {
3601ab64890Smrg	        p[len++] = LC_PATHDELIM;
3611ab64890Smrg	        p += len;
3621ab64890Smrg	    }
3631ab64890Smrg	}
3641ab64890Smrg    }
3651ab64890Smrg#endif /* NO_XLOCALEDIR */
3661ab64890Smrg
3671ab64890Smrg    if (len < buf_len)
3681ab64890Smrg#ifndef __UNIXOS2__
3691ab64890Smrg      strncpy(p, XLOCALELIBDIR, buf_len - len);
3701ab64890Smrg#else
3711ab64890Smrg      strncpy(p,__XOS2RedirRoot(XLOCALELIBDIR), buf_len - len);
3721ab64890Smrg#endif
3731ab64890Smrg    buf[buf_len-1] = '\0';
3741ab64890Smrg}
3751ab64890Smrg
3761ab64890Smrg/* Mapping direction */
3771ab64890Smrgtypedef enum {
3781ab64890Smrg  LtoR,		/* Map first field to second field */
3791ab64890Smrg  RtoL		/* Map second field to first field */
3801ab64890Smrg} MapDirection;
3811ab64890Smrg
3821ab64890Smrgstatic char *
3831ab64890Smrgresolve_name(
3841ab64890Smrg    const char *lc_name,
3851ab64890Smrg    char *file_name,
3861ab64890Smrg    MapDirection direction)
3871ab64890Smrg{
3881ab64890Smrg    FILE *fp;
3891ab64890Smrg    char buf[XLC_BUFSIZE], *name = NULL;
3901ab64890Smrg
3911ab64890Smrg    fp = _XFopenFile (file_name, "r");
3921ab64890Smrg    if (fp == NULL)
3931ab64890Smrg	return NULL;
3941ab64890Smrg
3951ab64890Smrg    while (fgets(buf, XLC_BUFSIZE, fp) != NULL) {
3961ab64890Smrg	char *p = buf;
3971ab64890Smrg	int n;
3981ab64890Smrg	char *args[2], *from, *to;
3991ab64890Smrg#ifdef __UNIXOS2__  /* Take out CR under OS/2 */
4001ab64890Smrg	int len;
4011ab64890Smrg
4021ab64890Smrg	len = strlen(p);
4031ab64890Smrg	if (len > 1) {
4041ab64890Smrg	    if (*(p+len-2) == '\r' && *(p+len-1) == '\n') {
4051ab64890Smrg		*(p+len-2) = '\n';
4061ab64890Smrg		*(p+len-1) = '\0';
4071ab64890Smrg	    }
4081ab64890Smrg	}
4091ab64890Smrg#endif
4101ab64890Smrg	while (isspace(*p)) {
4111ab64890Smrg	    ++p;
4121ab64890Smrg	}
4131ab64890Smrg	if (iscomment(*p)) {
4141ab64890Smrg	    continue;
4151ab64890Smrg	}
4161ab64890Smrg	n = parse_line(p, args, 2);		/* get first 2 fields */
4171ab64890Smrg	if (n != 2) {
4181ab64890Smrg	    continue;
4191ab64890Smrg	}
4201ab64890Smrg	if (direction == LtoR) {
4211ab64890Smrg	    from = args[0], to = args[1];	/* left to right */
4221ab64890Smrg	} else {
4231ab64890Smrg	    from = args[1], to = args[0];	/* right to left */
4241ab64890Smrg	}
4251ab64890Smrg	if (! strcmp(from, lc_name)) {
4266cc2b21fSmrg	    name = strdup(to);
4271ab64890Smrg	    break;
4281ab64890Smrg	}
4291ab64890Smrg    }
4301ab64890Smrg    fclose(fp);
4311ab64890Smrg    return name;
4321ab64890Smrg}
4331ab64890Smrg
4341ab64890Smrg#define	c_tolower(ch)	((ch) >= 'A' && (ch) <= 'Z' ? (ch) - 'A' + 'a' : (ch))
4351ab64890Smrg
4361ab64890Smrgstatic char *
4371ab64890Smrglowercase(
4381ab64890Smrg    char *dst,
4391ab64890Smrg    const char *src)
4401ab64890Smrg{
4411ab64890Smrg    const char *s;
4421ab64890Smrg    char *t;
4431ab64890Smrg
4441ab64890Smrg    for (s = src, t = dst; *s; ++s, ++t)
4451ab64890Smrg	*t = c_tolower(*s);
4461ab64890Smrg    *t = '\0';
4471ab64890Smrg    return dst;
4481ab64890Smrg}
4491ab64890Smrg
4501ab64890Smrg/*
4511ab64890Smrg * normalize_lcname(): remove any '_' and '-' and convert any character
4521ab64890Smrg * to lower case after the <language>_<territory> part. If result is identical
4531ab64890Smrg * to argument, free result and
4541ab64890Smrg * return NULL.
4551ab64890Smrg */
4561ab64890Smrgstatic char *
4571ab64890Smrgnormalize_lcname (const char *name)
4581ab64890Smrg{
4591ab64890Smrg    char *p, *ret;
4601ab64890Smrg    const char *tmp = name;
46161b2299dSmrg
4621ab64890Smrg    p = ret = Xmalloc(strlen(name) + 1);
4631ab64890Smrg    if (!p)
4641ab64890Smrg	return NULL;
46561b2299dSmrg
4661ab64890Smrg    if (tmp) {
4671ab64890Smrg	while (*tmp && *tmp != '.' && *tmp != '@')
4681ab64890Smrg	    *p++ = *tmp++;
4691ab64890Smrg	while (*tmp) {
4701ab64890Smrg	    if (*tmp != '-')
4711ab64890Smrg		*p++ = c_tolower(*tmp);
4721ab64890Smrg	    tmp++;
4731ab64890Smrg	}
4741ab64890Smrg    }
4751ab64890Smrg    *p = '\0';
4761ab64890Smrg
4771ab64890Smrg    if (strcmp(ret, name) == 0) {
4781ab64890Smrg	Xfree(ret);
4791ab64890Smrg	return NULL;
4801ab64890Smrg    }
4811ab64890Smrg
4821ab64890Smrg    return ret;
4831ab64890Smrg}
4841ab64890Smrg
4851ab64890Smrg/************************************************************************/
4861ab64890Smrgchar *
4871ab64890Smrg_XlcFileName(
4881ab64890Smrg    XLCd lcd,
4891ab64890Smrg    const char *category)
4901ab64890Smrg{
4911ab64890Smrg    char *siname;
4921ab64890Smrg    char cat[XLC_BUFSIZE], dir[XLC_BUFSIZE];
4931ab64890Smrg    int i, n;
4941ab64890Smrg    char *args[NUM_LOCALEDIR];
4951ab64890Smrg    char *file_name = NULL;
4961ab64890Smrg
4971ab64890Smrg    if (lcd == (XLCd)NULL)
4981ab64890Smrg	return NULL;
4991ab64890Smrg
5001ab64890Smrg    siname = XLC_PUBLIC(lcd, siname);
5011ab64890Smrg
50261b2299dSmrg    if (category)
50361b2299dSmrg	lowercase(cat, category);
50461b2299dSmrg    else
50561b2299dSmrg	cat[0] = '\0';
5061ab64890Smrg    xlocaledir(dir,XLC_BUFSIZE);
5071ab64890Smrg    n = _XlcParsePath(dir, args, NUM_LOCALEDIR);
5081ab64890Smrg    for (i = 0; i < n; ++i) {
5091ab64890Smrg	char buf[PATH_MAX], *name;
5101ab64890Smrg
5111ab64890Smrg	name = NULL;
51261b2299dSmrg	if ((5 + (args[i] ? strlen (args[i]) : 0) + strlen(cat)) < PATH_MAX) {
5131ab64890Smrg	    sprintf(buf, "%s/%s.dir", args[i], cat);
5141ab64890Smrg	    name = resolve_name(siname, buf, RtoL);
5151ab64890Smrg	}
5161ab64890Smrg	if (name == NULL) {
5171ab64890Smrg	    continue;
5181ab64890Smrg	}
5191ab64890Smrg	if (*name == '/') {
5201ab64890Smrg	    /* supposed to be absolute path name */
5211ab64890Smrg	    file_name = name;
5221ab64890Smrg	} else {
5231ab64890Smrg	    file_name = Xmalloc(2 + (args[i] ? strlen (args[i]) : 0) +
5241ab64890Smrg				(name ? strlen (name) : 0));
5251ab64890Smrg	    if (file_name != NULL)
5261ab64890Smrg		sprintf(file_name, "%s/%s", args[i], name);
5271ab64890Smrg	    Xfree(name);
5281ab64890Smrg	}
5291ab64890Smrg	if (isreadable(file_name)) {
5301ab64890Smrg	    break;
5311ab64890Smrg	}
5321ab64890Smrg	Xfree(file_name);
5331ab64890Smrg	file_name = NULL;
5341ab64890Smrg	/* Then, try with next dir */
5351ab64890Smrg    }
5361ab64890Smrg    return file_name;
5371ab64890Smrg}
5381ab64890Smrg
5391ab64890Smrg/************************************************************************/
5401ab64890Smrg#ifndef LOCALE_ALIAS
5411ab64890Smrg#define LOCALE_ALIAS    "locale.alias"
5421ab64890Smrg#endif
5431ab64890Smrg
5441ab64890Smrgint
5451ab64890Smrg_XlcResolveLocaleName(
5461ab64890Smrg    const char* lc_name,
5471ab64890Smrg    XLCdPublicPart* pub)
5481ab64890Smrg{
5491ab64890Smrg    char dir[PATH_MAX], buf[PATH_MAX], *name = NULL;
5501ab64890Smrg    char *dst;
5511ab64890Smrg    int i, n, sinamelen;
5521ab64890Smrg    char *args[NUM_LOCALEDIR];
5531ab64890Smrg    static const char locale_alias[] = LOCALE_ALIAS;
5541ab64890Smrg    char *tmp_siname;
5551ab64890Smrg    char *nlc_name = NULL;
5561ab64890Smrg
5571ab64890Smrg    xlocaledir (dir, PATH_MAX);
5581ab64890Smrg    n = _XlcParsePath(dir, args, NUM_LOCALEDIR);
5591ab64890Smrg    for (i = 0; i < n; ++i) {
56061b2299dSmrg	if ((2 + (args[i] ? strlen (args[i]) : 0) +
5611ab64890Smrg	    strlen (locale_alias)) < PATH_MAX) {
5621ab64890Smrg	    sprintf (buf, "%s/%s", args[i], locale_alias);
5631ab64890Smrg	    name = resolve_name (lc_name, buf, LtoR);
5641ab64890Smrg	    if (!name) {
5651ab64890Smrg		if (!nlc_name)
5661ab64890Smrg		    nlc_name = normalize_lcname(lc_name);
5671ab64890Smrg		if (nlc_name)
5681ab64890Smrg		    name = resolve_name (nlc_name, buf, LtoR);
5691ab64890Smrg	    }
5701ab64890Smrg	}
5711ab64890Smrg	if (name != NULL) {
5721ab64890Smrg	    break;
5731ab64890Smrg	}
5741ab64890Smrg    }
5751ab64890Smrg    if (nlc_name) Xfree(nlc_name);
5761ab64890Smrg
5771ab64890Smrg    if (name == NULL) {
5781ab64890Smrg	/* vendor locale name == Xlocale name, no expansion of alias */
5796cc2b21fSmrg	pub->siname = strdup (lc_name);
5801ab64890Smrg    } else {
5811ab64890Smrg	pub->siname = name;
5821ab64890Smrg    }
5831ab64890Smrg
5841ab64890Smrg    sinamelen = strlen (pub->siname);
5851ab64890Smrg    if (sinamelen == 1 && pub->siname[0] == 'C') {
5861ab64890Smrg	pub->language = pub->siname;
5871ab64890Smrg	pub->territory = pub->codeset = NULL;
5881ab64890Smrg	return 1;
5891ab64890Smrg    }
5901ab64890Smrg
59161b2299dSmrg    /*
5921ab64890Smrg     * pub->siname is in the format <lang>_<terr>.<codeset>, typical would
5931ab64890Smrg     * be "en_US.ISO8859-1", "en_US.utf8", "ru_RU.KOI-8", or ja_JP.SJIS,
5941ab64890Smrg     * although it could be ja.SJIS too.
5951ab64890Smrg     */
5961ab64890Smrg    tmp_siname = Xrealloc (pub->siname, 2 * (sinamelen + 1));
5971ab64890Smrg    if (tmp_siname == NULL) {
5981ab64890Smrg	return 0;
5991ab64890Smrg    }
6001ab64890Smrg    pub->siname = tmp_siname;
6011ab64890Smrg
6021ab64890Smrg    /* language */
6031ab64890Smrg    dst = &pub->siname[sinamelen + 1];
6041ab64890Smrg    strcpy (dst, pub->siname);
6051ab64890Smrg    pub->language = dst;
6061ab64890Smrg
6071ab64890Smrg    /* territory */
6081ab64890Smrg    dst = strchr (dst, '_');
6091ab64890Smrg    if (dst) {
6101ab64890Smrg	*dst = '\0';
6111ab64890Smrg	pub->territory = ++dst;
6121ab64890Smrg    } else
6131ab64890Smrg	dst = &pub->siname[sinamelen + 1];
6141ab64890Smrg
6151ab64890Smrg    /* codeset */
6161ab64890Smrg    dst = strchr (dst, '.');
6171ab64890Smrg    if (dst) {
6181ab64890Smrg	*dst = '\0';
6191ab64890Smrg	pub->codeset = ++dst;
6201ab64890Smrg    }
6211ab64890Smrg
6221ab64890Smrg    return (pub->siname[0] != '\0') ? 1 : 0;
6231ab64890Smrg}
6241ab64890Smrg
6251ab64890Smrg/************************************************************************/
6261ab64890Smrgint
62761b2299dSmrg_XlcResolveI18NPath(char *buf, int buf_len)
6281ab64890Smrg{
6291ab64890Smrg    if (buf != NULL) {
6301ab64890Smrg	xlocaledir(buf, buf_len);
6311ab64890Smrg    }
6321ab64890Smrg    return 1;
6331ab64890Smrg}
6341ab64890Smrg
6351ab64890Smrgchar *
63661b2299dSmrg_XlcLocaleDirName(char *dir_name, size_t dir_len, char *lc_name)
6371ab64890Smrg{
6381ab64890Smrg    char dir[PATH_MAX], buf[PATH_MAX], *name = NULL;
6391ab64890Smrg    int i, n;
6401ab64890Smrg    char *args[NUM_LOCALEDIR];
6411ab64890Smrg    static char locale_alias[] = LOCALE_ALIAS;
6421ab64890Smrg    char *target_name = (char*)0;
6431ab64890Smrg    char *target_dir = (char*)0;
6441ab64890Smrg    char *nlc_name = NULL;
6451ab64890Smrg    static char*  last_dir_name = 0;
6461ab64890Smrg    static size_t last_dir_len = 0;
6471ab64890Smrg    static char*  last_lc_name = 0;
6481ab64890Smrg
6491ab64890Smrg    if (last_lc_name != 0 && strcmp (last_lc_name, lc_name) == 0
6501ab64890Smrg       && dir_len >= last_dir_len) {
6511ab64890Smrg        strcpy (dir_name, last_dir_name);
6521ab64890Smrg        return dir_name;
6531ab64890Smrg    }
6541ab64890Smrg
6551ab64890Smrg    xlocaledir (dir, PATH_MAX);
6561ab64890Smrg    n = _XlcParsePath(dir, args, 256);
6571ab64890Smrg    for (i = 0; i < n; ++i) {
65861b2299dSmrg
65961b2299dSmrg	if ((2 + (args[i] ? strlen(args[i]) : 0) +
6601ab64890Smrg 	     strlen(locale_alias)) < PATH_MAX) {
6611ab64890Smrg 	    sprintf (buf, "%s/%s", args[i], locale_alias);
6621ab64890Smrg 	    name = resolve_name(lc_name, buf, LtoR);
6631ab64890Smrg	    if (!name) {
6641ab64890Smrg		if (!nlc_name)
6651ab64890Smrg		    nlc_name = normalize_lcname(lc_name);
6661ab64890Smrg		if (nlc_name)
6671ab64890Smrg		    name = resolve_name (nlc_name, buf, LtoR);
6681ab64890Smrg	    }
6691ab64890Smrg 	}
67061b2299dSmrg
6711ab64890Smrg 	/* If name is not an alias, use lc_name for locale.dir search */
6721ab64890Smrg 	if (name == NULL)
6731ab64890Smrg 	    name = lc_name;
67461b2299dSmrg
6751ab64890Smrg 	/* look at locale.dir */
67661b2299dSmrg
6771ab64890Smrg 	target_dir = args[i];
6781ab64890Smrg 	if (!target_dir) {
6791ab64890Smrg 	    /* something wrong */
6801ab64890Smrg 	    if (name != lc_name)
6811ab64890Smrg 		Xfree(name);
6821ab64890Smrg 	    continue;
6831ab64890Smrg 	}
68457f47464Smrg 	if ((1 + strlen (target_dir) + strlen("locale.dir")) < PATH_MAX) {
6851ab64890Smrg 	    sprintf(buf, "%s/locale.dir", target_dir);
6861ab64890Smrg 	    target_name = resolve_name(name, buf, RtoL);
6871ab64890Smrg 	}
6881ab64890Smrg 	if (name != lc_name)
6891ab64890Smrg 	    Xfree(name);
6901ab64890Smrg 	if (target_name != NULL) {
6911ab64890Smrg 	    char *p = 0;
6921ab64890Smrg 	    if ((p = strstr(target_name, "/XLC_LOCALE"))) {
6931ab64890Smrg 		*p = '\0';
6941ab64890Smrg 		break;
6951ab64890Smrg 	    }
6961ab64890Smrg 	    Xfree(target_name);
6971ab64890Smrg 	    target_name = NULL;
6981ab64890Smrg 	}
6991ab64890Smrg 	name = NULL;
7001ab64890Smrg    }
7011ab64890Smrg    if (nlc_name) Xfree(nlc_name);
7021ab64890Smrg
7031ab64890Smrg    if (target_name == NULL) {
7041ab64890Smrg 	/* vendor locale name == Xlocale name, no expansion of alias */
7051ab64890Smrg 	target_dir = args[0];
7061ab64890Smrg 	target_name = lc_name;
7071ab64890Smrg    }
7081ab64890Smrg    /* snprintf(dir_name, dir_len, "%s/%", target_dir, target_name); */
7091ab64890Smrg    strncpy(dir_name, target_dir, dir_len - 1);
7101ab64890Smrg    if (strlen(target_dir) >= dir_len - 1) {
7111ab64890Smrg	dir_name[dir_len - 1] = '\0';
7121ab64890Smrg    } else  {
7131ab64890Smrg	strcat(dir_name, "/");
7141ab64890Smrg	strncat(dir_name, target_name, dir_len - strlen(dir_name) - 1);
71561b2299dSmrg	if (strlen(target_name) >= dir_len - strlen(dir_name) - 1)
7161ab64890Smrg	    dir_name[dir_len - 1] = '\0';
7171ab64890Smrg    }
7181ab64890Smrg    if (target_name != lc_name)
7191ab64890Smrg 	Xfree(target_name);
7201ab64890Smrg
7211ab64890Smrg    if (last_dir_name != 0)
7221ab64890Smrg	Xfree (last_dir_name);
7231ab64890Smrg    if (last_lc_name != 0)
7241ab64890Smrg	Xfree (last_lc_name);
7251ab64890Smrg    last_dir_len = strlen (dir_name) + 1;
7261ab64890Smrg    last_dir_name = Xmalloc (last_dir_len);
7271ab64890Smrg    strcpy (last_dir_name, dir_name);
7286cc2b21fSmrg    last_lc_name = strdup (lc_name);
7291ab64890Smrg
7301ab64890Smrg    return dir_name;
7311ab64890Smrg}
7321ab64890Smrg
7331ab64890Smrgchar *
73461b2299dSmrg_XlcLocaleLibDirName(char *dir_name, size_t dir_len, char *lc_name)
7351ab64890Smrg{
7361ab64890Smrg    char dir[PATH_MAX], buf[PATH_MAX], *name = NULL;
7371ab64890Smrg    int i, n;
7381ab64890Smrg    char *args[NUM_LOCALEDIR];
7391ab64890Smrg    static char locale_alias[] = LOCALE_ALIAS;
7401ab64890Smrg    char *target_name = (char*)0;
7411ab64890Smrg    char *target_dir = (char*)0;
7421ab64890Smrg    char *nlc_name = NULL;
7431ab64890Smrg    static char*  last_dir_name = 0;
7441ab64890Smrg    static size_t last_dir_len = 0;
7451ab64890Smrg    static char*  last_lc_name = 0;
7461ab64890Smrg
7471ab64890Smrg    if (last_lc_name != 0 && strcmp (last_lc_name, lc_name) == 0
7481ab64890Smrg       && dir_len >= last_dir_len) {
7491ab64890Smrg	strcpy (dir_name, last_dir_name);
7501ab64890Smrg	return dir_name;
7511ab64890Smrg    }
7521ab64890Smrg
7531ab64890Smrg    xlocalelibdir (dir, PATH_MAX);
7541ab64890Smrg    n = _XlcParsePath(dir, args, 256);
7551ab64890Smrg    for (i = 0; i < n; ++i) {
75661b2299dSmrg
75761b2299dSmrg	if ((2 + (args[i] ? strlen(args[i]) : 0) +
7581ab64890Smrg 	     strlen(locale_alias)) < PATH_MAX) {
7591ab64890Smrg 	    sprintf (buf, "%s/%s", args[i], locale_alias);
7601ab64890Smrg 	    name = resolve_name(lc_name, buf, LtoR);
7611ab64890Smrg	    if (!name) {
7621ab64890Smrg		if (!nlc_name)
7631ab64890Smrg		    nlc_name = normalize_lcname(lc_name);
7641ab64890Smrg		if (nlc_name)
7651ab64890Smrg		    name = resolve_name (nlc_name, buf, LtoR);
7661ab64890Smrg	    }
7671ab64890Smrg 	}
76861b2299dSmrg
7691ab64890Smrg 	/* If name is not an alias, use lc_name for locale.dir search */
7701ab64890Smrg 	if (name == NULL)
7711ab64890Smrg 	    name = lc_name;
77261b2299dSmrg
7731ab64890Smrg 	/* look at locale.dir */
77461b2299dSmrg
7751ab64890Smrg 	target_dir = args[i];
7761ab64890Smrg 	if (!target_dir) {
7771ab64890Smrg 	    /* something wrong */
7781ab64890Smrg 	    if (name != lc_name)
7791ab64890Smrg 		Xfree(name);
7801ab64890Smrg 	    continue;
7811ab64890Smrg 	}
78257f47464Smrg 	if ((1 + strlen (target_dir) + strlen("locale.dir")) < PATH_MAX) {
7831ab64890Smrg 	    sprintf(buf, "%s/locale.dir", target_dir);
7841ab64890Smrg 	    target_name = resolve_name(name, buf, RtoL);
7851ab64890Smrg 	}
7861ab64890Smrg 	if (name != lc_name)
7871ab64890Smrg 	    Xfree(name);
7881ab64890Smrg 	if (target_name != NULL) {
7891ab64890Smrg 	    char *p = 0;
7901ab64890Smrg 	    if ((p = strstr(target_name, "/XLC_LOCALE"))) {
7911ab64890Smrg 		*p = '\0';
7921ab64890Smrg 		break;
7931ab64890Smrg 	    }
7941ab64890Smrg 	    Xfree(target_name);
7951ab64890Smrg 	    target_name = NULL;
7961ab64890Smrg 	}
7971ab64890Smrg 	name = NULL;
7981ab64890Smrg    }
7991ab64890Smrg    if (nlc_name) Xfree(nlc_name);
8001ab64890Smrg
8011ab64890Smrg    if (target_name == NULL) {
8021ab64890Smrg 	/* vendor locale name == Xlocale name, no expansion of alias */
8031ab64890Smrg 	target_dir = args[0];
8041ab64890Smrg 	target_name = lc_name;
8051ab64890Smrg    }
8061ab64890Smrg    /* snprintf(dir_name, dir_len, "%s/%", target_dir, target_name); */
8071ab64890Smrg    strncpy(dir_name, target_dir, dir_len - 1);
8081ab64890Smrg    if (strlen(target_dir) >= dir_len - 1) {
8091ab64890Smrg	dir_name[dir_len - 1] = '\0';
8101ab64890Smrg    } else  {
8111ab64890Smrg	strcat(dir_name, "/");
8121ab64890Smrg	strncat(dir_name, target_name, dir_len - strlen(dir_name) - 1);
81361b2299dSmrg	if (strlen(target_name) >= dir_len - strlen(dir_name) - 1)
8141ab64890Smrg	    dir_name[dir_len - 1] = '\0';
8151ab64890Smrg    }
8161ab64890Smrg    if (target_name != lc_name)
8171ab64890Smrg 	Xfree(target_name);
8181ab64890Smrg
8191ab64890Smrg    if (last_dir_name != 0)
8201ab64890Smrg	Xfree (last_dir_name);
8211ab64890Smrg    if (last_lc_name != 0)
8221ab64890Smrg	Xfree (last_lc_name);
8231ab64890Smrg    last_dir_len = strlen (dir_name) + 1;
8241ab64890Smrg    last_dir_name = Xmalloc (last_dir_len);
8251ab64890Smrg    strcpy (last_dir_name, dir_name);
8266cc2b21fSmrg    last_lc_name = strdup (lc_name);
8271ab64890Smrg
8281ab64890Smrg    return dir_name;
8291ab64890Smrg}
830