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
39eb411b4bSmrg#ifndef HAVE_SETEUID
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#define LC_PATHDELIM ':'
501ab64890Smrg
511ab64890Smrg#define XLC_BUFSIZE 256
521ab64890Smrg
53eb411b4bSmrg#include "pathmax.h"
541ab64890Smrg
551ab64890Smrg#define NUM_LOCALEDIR	64
561ab64890Smrg
571ab64890Smrg/* Splits a NUL terminated line into constituents, at colons and newline
581ab64890Smrg   characters. Leading whitespace is removed from constituents. The
591ab64890Smrg   constituents are stored at argv[0..argsize-1]. The number of stored
601ab64890Smrg   constituents (<= argsize) is returned. The line is destructively
611ab64890Smrg   modified. */
621ab64890Smrgstatic int
631ab64890Smrgparse_line(
641ab64890Smrg    char *line,
651ab64890Smrg    char **argv,
661ab64890Smrg    int argsize)
671ab64890Smrg{
681ab64890Smrg    int argc = 0;
691ab64890Smrg    char *p = line;
701ab64890Smrg
711ab64890Smrg    while (argc < argsize) {
721ab64890Smrg	while (isspace(*p)) {
731ab64890Smrg	    ++p;
741ab64890Smrg	}
751ab64890Smrg	if (*p == '\0') {
761ab64890Smrg	    break;
771ab64890Smrg	}
781ab64890Smrg	argv[argc++] = p;
791ab64890Smrg	while (*p != ':' && *p != '\n' && *p != '\0') {
801ab64890Smrg	    ++p;
811ab64890Smrg	}
821ab64890Smrg	if (*p == '\0') {
831ab64890Smrg	    break;
841ab64890Smrg	}
851ab64890Smrg	*p++ = '\0';
861ab64890Smrg    }
871ab64890Smrg
881ab64890Smrg    return argc;
891ab64890Smrg}
901ab64890Smrg
91ebe525bcSmrg#ifdef WIN32
921ab64890Smrg/* this is parse_line but skips drive letters at the beginning of the entry */
931ab64890Smrgstatic int
941ab64890Smrgparse_line1(
951ab64890Smrg    char *line,
961ab64890Smrg    char **argv,
971ab64890Smrg    int argsize)
981ab64890Smrg{
991ab64890Smrg    int argc = 0;
1001ab64890Smrg    char *p = line;
1011ab64890Smrg
1021ab64890Smrg    while (argc < argsize) {
1031ab64890Smrg	while (isspace(*p)) {
1041ab64890Smrg	    ++p;
1051ab64890Smrg	}
1061ab64890Smrg	if (*p == '\0') {
1071ab64890Smrg	    break;
1081ab64890Smrg	}
1091ab64890Smrg	argv[argc++] = p;
1101ab64890Smrg        if (isalpha(*p) && p[1] == ':') {
1111ab64890Smrg            p+= 2; /* skip drive letters */
1121ab64890Smrg        }
1131ab64890Smrg	while (*p != ':' && *p != '\n' && *p != '\0') {
1141ab64890Smrg	    ++p;
1151ab64890Smrg	}
1161ab64890Smrg	if (*p == '\0') {
1171ab64890Smrg	    break;
1181ab64890Smrg	}
1191ab64890Smrg	*p++ = '\0';
1201ab64890Smrg    }
1211ab64890Smrg
1221ab64890Smrg    return argc;
1231ab64890Smrg}
124ebe525bcSmrg#endif   /* WIN32 */
1251ab64890Smrg
1261ab64890Smrg/* Splits a colon separated list of directories, and returns the constituent
1271ab64890Smrg   paths (without trailing slash). At most argsize constituents are stored
1281ab64890Smrg   at argv[0..argsize-1]. The number of stored constituents is returned. */
1291ab64890Smrgstatic int
1301ab64890Smrg_XlcParsePath(
1311ab64890Smrg    char *path,
1321ab64890Smrg    char **argv,
1331ab64890Smrg    int argsize)
1341ab64890Smrg{
1351ab64890Smrg    char *p = path;
1361ab64890Smrg    int n, i;
1371ab64890Smrg
138ebe525bcSmrg#ifndef WIN32
1391ab64890Smrg    n = parse_line(path, argv, argsize);
1401ab64890Smrg#else
1411ab64890Smrg    n = parse_line1(path, argv, argsize);
1421ab64890Smrg#endif
1431ab64890Smrg    for (i = 0; i < n; ++i) {
1441ab64890Smrg	int len;
1451ab64890Smrg	p = argv[i];
1469c019ec5Smaya	len = (int) strlen(p);
1471ab64890Smrg	if (len > 0 && p[len - 1] == '/') {
1481ab64890Smrg	    /* eliminate trailing slash */
1491ab64890Smrg	    p[len - 1] = '\0';
1501ab64890Smrg	}
1511ab64890Smrg    }
1521ab64890Smrg    return n;
1531ab64890Smrg}
1541ab64890Smrg
1551ab64890Smrg#ifndef XLOCALEDIR
1561ab64890Smrg#define XLOCALEDIR "/usr/lib/X11/locale"
1571ab64890Smrg#endif
1581ab64890Smrg
159b4ee4795Smrgvoid
1601ab64890Smrgxlocaledir(
1611ab64890Smrg    char *buf,
1621ab64890Smrg    int buf_len)
1631ab64890Smrg{
1641ab64890Smrg    char *p = buf;
1651ab64890Smrg    int len = 0;
1661ab64890Smrg
1671ab64890Smrg#ifndef NO_XLOCALEDIR
1681ab64890Smrg    char *dir;
1691ab64890Smrg    int priv = 1;
1701ab64890Smrg
1711ab64890Smrg    dir = getenv("XLOCALEDIR");
1721ab64890Smrg
1731ab64890Smrg    if (dir) {
1741ab64890Smrg#ifndef WIN32
1751ab64890Smrg	/*
1769c019ec5Smaya	 * Only use the user-supplied path if the process isn't privileged.
1771ab64890Smrg	 */
1781ab64890Smrg	if (getuid() == geteuid() && getgid() == getegid()) {
1791ab64890Smrg#if defined(HASSETUGID)
1801ab64890Smrg	    priv = issetugid();
1811ab64890Smrg#elif defined(HASGETRESUID)
1821ab64890Smrg	    {
1831ab64890Smrg		uid_t ruid, euid, suid;
1841ab64890Smrg		gid_t rgid, egid, sgid;
1851ab64890Smrg		if ((getresuid(&ruid, &euid, &suid) == 0) &&
1861ab64890Smrg		    (getresgid(&rgid, &egid, &sgid) == 0))
1871ab64890Smrg		    priv = (euid != suid) || (egid != sgid);
1881ab64890Smrg	    }
1891ab64890Smrg#else
1901ab64890Smrg	    /*
1919c019ec5Smaya	     * If there are saved ID's the process might still be privileged
1921ab64890Smrg	     * even though the above test succeeded.  If issetugid() and
1931ab64890Smrg	     * getresgid() aren't available, test this by trying to set
1941ab64890Smrg	     * euid to 0.
1951ab64890Smrg	     *
1961ab64890Smrg	     * Note: this only protects setuid-root clients.  It doesn't
1971ab64890Smrg	     * protect other setuid or any setgid clients.  If this tradeoff
19814db512dSmrg	     * isn't acceptable, run configure with --disable-xlocaledir .
1991ab64890Smrg	     */
2001ab64890Smrg	    unsigned int oldeuid;
2011ab64890Smrg	    oldeuid = geteuid();
2021ab64890Smrg	    if (seteuid(0) != 0) {
2031ab64890Smrg		priv = 0;
2041ab64890Smrg	    } else {
2051ab64890Smrg		if (seteuid(oldeuid) == -1) {
2069c019ec5Smaya		    /* XXX ouch, couldn't get back to original uid
2071ab64890Smrg		     what can we do ??? */
2081ab64890Smrg		    _exit(127);
2091ab64890Smrg		}
2101ab64890Smrg		priv = 1;
2111ab64890Smrg	    }
2121ab64890Smrg#endif
2131ab64890Smrg	}
2141ab64890Smrg#else
2151ab64890Smrg	priv = 0;
2161ab64890Smrg#endif
2171ab64890Smrg	if (!priv) {
2189c019ec5Smaya	    len = (int) strlen(dir);
2199c019ec5Smaya	    strncpy(p, dir, (size_t) buf_len);
2201ab64890Smrg	    if (len < buf_len) {
2211ab64890Smrg	        p[len++] = LC_PATHDELIM;
2221ab64890Smrg	        p += len;
2231ab64890Smrg	    }
2241ab64890Smrg	}
2251ab64890Smrg    }
2261ab64890Smrg#endif /* NO_XLOCALEDIR */
2271ab64890Smrg
2281ab64890Smrg    if (len < buf_len)
2299c019ec5Smaya      strncpy(p, XLOCALEDIR, (size_t) (buf_len - len));
2301ab64890Smrg    buf[buf_len-1] = '\0';
2311ab64890Smrg}
2321ab64890Smrg
2331ab64890Smrgstatic void
2341ab64890Smrgxlocalelibdir(
2351ab64890Smrg    char *buf,
2361ab64890Smrg    int buf_len)
2371ab64890Smrg{
2381ab64890Smrg    char *p = buf;
2391ab64890Smrg    int len = 0;
2401ab64890Smrg
2411ab64890Smrg#ifndef NO_XLOCALEDIR
2421ab64890Smrg    char *dir;
2431ab64890Smrg    int priv = 1;
2441ab64890Smrg
2451ab64890Smrg    dir = getenv("XLOCALELIBDIR");
2461ab64890Smrg
2471ab64890Smrg    if (dir) {
2481ab64890Smrg#ifndef WIN32
2491ab64890Smrg	/*
2509c019ec5Smaya	 * Only use the user-supplied path if the process isn't privileged.
2511ab64890Smrg	 */
2521ab64890Smrg	if (getuid() == geteuid() && getgid() == getegid()) {
2531ab64890Smrg#if defined(HASSETUGID)
2541ab64890Smrg	    priv = issetugid();
2551ab64890Smrg#elif defined(HASGETRESUID)
2561ab64890Smrg	    {
2571ab64890Smrg		uid_t ruid, euid, suid;
2581ab64890Smrg		gid_t rgid, egid, sgid;
2591ab64890Smrg		if ((getresuid(&ruid, &euid, &suid) == 0) &&
2601ab64890Smrg		    (getresgid(&rgid, &egid, &sgid) == 0))
2611ab64890Smrg		    priv = (euid != suid) || (egid != sgid);
2621ab64890Smrg	    }
2631ab64890Smrg#else
2641ab64890Smrg	    /*
2659c019ec5Smaya	     * If there are saved ID's the process might still be privileged
2661ab64890Smrg	     * even though the above test succeeded.  If issetugid() and
2671ab64890Smrg	     * getresgid() aren't available, test this by trying to set
2681ab64890Smrg	     * euid to 0.
2691ab64890Smrg	     *
2701ab64890Smrg	     * Note: this only protects setuid-root clients.  It doesn't
2711ab64890Smrg	     * protect other setuid or any setgid clients.  If this tradeoff
27214db512dSmrg	     * isn't acceptable, run configure with --disable-xlocaledir .
2731ab64890Smrg	     */
2741ab64890Smrg	    unsigned int oldeuid;
2751ab64890Smrg	    oldeuid = geteuid();
2761ab64890Smrg	    if (seteuid(0) != 0) {
2771ab64890Smrg		priv = 0;
2781ab64890Smrg	    } else {
2791ab64890Smrg		if (seteuid(oldeuid) == -1) {
2809c019ec5Smaya		    /* XXX ouch, couldn't get back to original uid
2811ab64890Smrg		     what can we do ??? */
2821ab64890Smrg		    _exit(127);
2831ab64890Smrg		}
2841ab64890Smrg		priv = 1;
2851ab64890Smrg	    }
2861ab64890Smrg#endif
2871ab64890Smrg	}
2881ab64890Smrg#else
2891ab64890Smrg	priv = 0;
2901ab64890Smrg#endif
2911ab64890Smrg	if (!priv) {
2929c019ec5Smaya	    len = (int) strlen(dir);
2939c019ec5Smaya	    strncpy(p, dir, (size_t) buf_len);
2941ab64890Smrg	    if (len < buf_len) {
2951ab64890Smrg	        p[len++] = LC_PATHDELIM;
2961ab64890Smrg	        p += len;
2971ab64890Smrg	    }
2981ab64890Smrg	}
2991ab64890Smrg    }
3001ab64890Smrg#endif /* NO_XLOCALEDIR */
3011ab64890Smrg
3021ab64890Smrg    if (len < buf_len)
3039c019ec5Smaya      strncpy(p, XLOCALELIBDIR, (size_t) (buf_len - len));
3041ab64890Smrg    buf[buf_len-1] = '\0';
3051ab64890Smrg}
3061ab64890Smrg
3071ab64890Smrg/* Mapping direction */
3081ab64890Smrgtypedef enum {
3091ab64890Smrg  LtoR,		/* Map first field to second field */
3101ab64890Smrg  RtoL		/* Map second field to first field */
3111ab64890Smrg} MapDirection;
3121ab64890Smrg
3131ab64890Smrgstatic char *
3141ab64890Smrgresolve_name(
3151ab64890Smrg    const char *lc_name,
3161ab64890Smrg    char *file_name,
3171ab64890Smrg    MapDirection direction)
3181ab64890Smrg{
3191ab64890Smrg    FILE *fp;
3201ab64890Smrg    char buf[XLC_BUFSIZE], *name = NULL;
3211ab64890Smrg
3221ab64890Smrg    fp = _XFopenFile (file_name, "r");
3231ab64890Smrg    if (fp == NULL)
3241ab64890Smrg	return NULL;
3251ab64890Smrg
3261ab64890Smrg    while (fgets(buf, XLC_BUFSIZE, fp) != NULL) {
3271ab64890Smrg	char *p = buf;
3281ab64890Smrg	int n;
3291ab64890Smrg	char *args[2], *from, *to;
3301ab64890Smrg	while (isspace(*p)) {
3311ab64890Smrg	    ++p;
3321ab64890Smrg	}
3331ab64890Smrg	if (iscomment(*p)) {
3341ab64890Smrg	    continue;
3351ab64890Smrg	}
3361ab64890Smrg	n = parse_line(p, args, 2);		/* get first 2 fields */
3371ab64890Smrg	if (n != 2) {
3381ab64890Smrg	    continue;
3391ab64890Smrg	}
3401ab64890Smrg	if (direction == LtoR) {
3411ab64890Smrg	    from = args[0], to = args[1];	/* left to right */
3421ab64890Smrg	} else {
3431ab64890Smrg	    from = args[1], to = args[0];	/* right to left */
3441ab64890Smrg	}
3451ab64890Smrg	if (! strcmp(from, lc_name)) {
3466cc2b21fSmrg	    name = strdup(to);
3471ab64890Smrg	    break;
3481ab64890Smrg	}
3491ab64890Smrg    }
3501ab64890Smrg    fclose(fp);
3511ab64890Smrg    return name;
3521ab64890Smrg}
3531ab64890Smrg
3541ab64890Smrg#define	c_tolower(ch)	((ch) >= 'A' && (ch) <= 'Z' ? (ch) - 'A' + 'a' : (ch))
3551ab64890Smrg
3561ab64890Smrgstatic char *
3571ab64890Smrglowercase(
3581ab64890Smrg    char *dst,
3591ab64890Smrg    const char *src)
3601ab64890Smrg{
3611ab64890Smrg    const char *s;
3621ab64890Smrg    char *t;
3631ab64890Smrg
3641ab64890Smrg    for (s = src, t = dst; *s; ++s, ++t)
3659c019ec5Smaya	*t = (char) c_tolower(*s);
3661ab64890Smrg    *t = '\0';
3671ab64890Smrg    return dst;
3681ab64890Smrg}
3691ab64890Smrg
3701ab64890Smrg/*
3711ab64890Smrg * normalize_lcname(): remove any '_' and '-' and convert any character
3721ab64890Smrg * to lower case after the <language>_<territory> part. If result is identical
3731ab64890Smrg * to argument, free result and
3741ab64890Smrg * return NULL.
3751ab64890Smrg */
3761ab64890Smrgstatic char *
3771ab64890Smrgnormalize_lcname (const char *name)
3781ab64890Smrg{
3791ab64890Smrg    char *p, *ret;
3801ab64890Smrg    const char *tmp = name;
38161b2299dSmrg
3821ab64890Smrg    p = ret = Xmalloc(strlen(name) + 1);
3831ab64890Smrg    if (!p)
3841ab64890Smrg	return NULL;
38561b2299dSmrg
3861ab64890Smrg    if (tmp) {
3871ab64890Smrg	while (*tmp && *tmp != '.' && *tmp != '@')
3881ab64890Smrg	    *p++ = *tmp++;
3891ab64890Smrg	while (*tmp) {
3901ab64890Smrg	    if (*tmp != '-')
3919c019ec5Smaya		*p++ = (char) c_tolower(*tmp);
3921ab64890Smrg	    tmp++;
3931ab64890Smrg	}
3941ab64890Smrg    }
3951ab64890Smrg    *p = '\0';
3961ab64890Smrg
3971ab64890Smrg    if (strcmp(ret, name) == 0) {
3981ab64890Smrg	Xfree(ret);
3991ab64890Smrg	return NULL;
4001ab64890Smrg    }
4011ab64890Smrg
4021ab64890Smrg    return ret;
4031ab64890Smrg}
4041ab64890Smrg
4051ab64890Smrg/************************************************************************/
4061ab64890Smrgchar *
4071ab64890Smrg_XlcFileName(
4081ab64890Smrg    XLCd lcd,
4091ab64890Smrg    const char *category)
4101ab64890Smrg{
4111ab64890Smrg    char *siname;
4121ab64890Smrg    char cat[XLC_BUFSIZE], dir[XLC_BUFSIZE];
4131ab64890Smrg    int i, n;
4141ab64890Smrg    char *args[NUM_LOCALEDIR];
4151ab64890Smrg    char *file_name = NULL;
4161ab64890Smrg
4171ab64890Smrg    if (lcd == (XLCd)NULL)
4181ab64890Smrg	return NULL;
4191ab64890Smrg
4201ab64890Smrg    siname = XLC_PUBLIC(lcd, siname);
4211ab64890Smrg
42261b2299dSmrg    if (category)
42361b2299dSmrg	lowercase(cat, category);
42461b2299dSmrg    else
42561b2299dSmrg	cat[0] = '\0';
4261ab64890Smrg    xlocaledir(dir,XLC_BUFSIZE);
4271ab64890Smrg    n = _XlcParsePath(dir, args, NUM_LOCALEDIR);
4281ab64890Smrg    for (i = 0; i < n; ++i) {
4291ab64890Smrg	char buf[PATH_MAX], *name;
4301ab64890Smrg
431818534a1Smrg	if (args[i] == NULL)
432818534a1Smrg	    continue;
433818534a1Smrg
4341ab64890Smrg	name = NULL;
435818534a1Smrg	if (snprintf(buf, PATH_MAX, "%s/%s.dir", args[i], cat) < PATH_MAX) {
4361ab64890Smrg	    name = resolve_name(siname, buf, RtoL);
4371ab64890Smrg	}
4381ab64890Smrg	if (name == NULL) {
4391ab64890Smrg	    continue;
4401ab64890Smrg	}
4411ab64890Smrg	if (*name == '/') {
4421ab64890Smrg	    /* supposed to be absolute path name */
4431ab64890Smrg	    file_name = name;
4441ab64890Smrg	} else {
445818534a1Smrg	    if (snprintf(buf, PATH_MAX, "%s/%s", args[i], name) < PATH_MAX)
446818534a1Smrg		file_name = strdup(buf);
447818534a1Smrg	    else
448818534a1Smrg		file_name = NULL;
4491ab64890Smrg	    Xfree(name);
4501ab64890Smrg	}
451818534a1Smrg	if (file_name && isreadable(file_name)) {
4521ab64890Smrg	    break;
4531ab64890Smrg	}
4541ab64890Smrg	Xfree(file_name);
4551ab64890Smrg	file_name = NULL;
4561ab64890Smrg	/* Then, try with next dir */
4571ab64890Smrg    }
4581ab64890Smrg    return file_name;
4591ab64890Smrg}
4601ab64890Smrg
4611ab64890Smrg/************************************************************************/
4621ab64890Smrg#ifndef LOCALE_ALIAS
4631ab64890Smrg#define LOCALE_ALIAS    "locale.alias"
4641ab64890Smrg#endif
4651ab64890Smrg
4661ab64890Smrgint
4671ab64890Smrg_XlcResolveLocaleName(
4681ab64890Smrg    const char* lc_name,
4691ab64890Smrg    XLCdPublicPart* pub)
4701ab64890Smrg{
4711ab64890Smrg    char dir[PATH_MAX], buf[PATH_MAX], *name = NULL;
4721ab64890Smrg    char *dst;
4731ab64890Smrg    int i, n, sinamelen;
4741ab64890Smrg    char *args[NUM_LOCALEDIR];
4751ab64890Smrg    static const char locale_alias[] = LOCALE_ALIAS;
4761ab64890Smrg    char *tmp_siname;
4771ab64890Smrg    char *nlc_name = NULL;
4781ab64890Smrg
4791ab64890Smrg    xlocaledir (dir, PATH_MAX);
4801ab64890Smrg    n = _XlcParsePath(dir, args, NUM_LOCALEDIR);
4811ab64890Smrg    for (i = 0; i < n; ++i) {
482818534a1Smrg	if (args[i] == NULL)
483818534a1Smrg	    continue;
484818534a1Smrg
485818534a1Smrg	if (snprintf (buf, PATH_MAX, "%s/%s", args[i], locale_alias)
486818534a1Smrg	    < PATH_MAX) {
4871ab64890Smrg	    name = resolve_name (lc_name, buf, LtoR);
4881ab64890Smrg	    if (!name) {
4891ab64890Smrg		if (!nlc_name)
4901ab64890Smrg		    nlc_name = normalize_lcname(lc_name);
4911ab64890Smrg		if (nlc_name)
4921ab64890Smrg		    name = resolve_name (nlc_name, buf, LtoR);
4931ab64890Smrg	    }
4941ab64890Smrg	}
4951ab64890Smrg	if (name != NULL) {
4961ab64890Smrg	    break;
4971ab64890Smrg	}
4981ab64890Smrg    }
4990f8248bfSmrg    Xfree(nlc_name);
5001ab64890Smrg
5011ab64890Smrg    if (name == NULL) {
5021ab64890Smrg	/* vendor locale name == Xlocale name, no expansion of alias */
5036cc2b21fSmrg	pub->siname = strdup (lc_name);
5041ab64890Smrg    } else {
5051ab64890Smrg	pub->siname = name;
5061ab64890Smrg    }
5071ab64890Smrg
5089c019ec5Smaya    sinamelen = (int) strlen (pub->siname);
5091ab64890Smrg    if (sinamelen == 1 && pub->siname[0] == 'C') {
5101ab64890Smrg	pub->language = pub->siname;
5111ab64890Smrg	pub->territory = pub->codeset = NULL;
5121ab64890Smrg	return 1;
5131ab64890Smrg    }
5141ab64890Smrg
51561b2299dSmrg    /*
5161ab64890Smrg     * pub->siname is in the format <lang>_<terr>.<codeset>, typical would
5171ab64890Smrg     * be "en_US.ISO8859-1", "en_US.utf8", "ru_RU.KOI-8", or ja_JP.SJIS,
5181ab64890Smrg     * although it could be ja.SJIS too.
5191ab64890Smrg     */
5201ab64890Smrg    tmp_siname = Xrealloc (pub->siname, 2 * (sinamelen + 1));
5211ab64890Smrg    if (tmp_siname == NULL) {
5221ab64890Smrg	return 0;
5231ab64890Smrg    }
5241ab64890Smrg    pub->siname = tmp_siname;
5251ab64890Smrg
5261ab64890Smrg    /* language */
5271ab64890Smrg    dst = &pub->siname[sinamelen + 1];
5281ab64890Smrg    strcpy (dst, pub->siname);
5291ab64890Smrg    pub->language = dst;
5301ab64890Smrg
5311ab64890Smrg    /* territory */
5321ab64890Smrg    dst = strchr (dst, '_');
5331ab64890Smrg    if (dst) {
5341ab64890Smrg	*dst = '\0';
5351ab64890Smrg	pub->territory = ++dst;
5361ab64890Smrg    } else
5371ab64890Smrg	dst = &pub->siname[sinamelen + 1];
5381ab64890Smrg
5391ab64890Smrg    /* codeset */
5401ab64890Smrg    dst = strchr (dst, '.');
5411ab64890Smrg    if (dst) {
5421ab64890Smrg	*dst = '\0';
5431ab64890Smrg	pub->codeset = ++dst;
5441ab64890Smrg    }
5451ab64890Smrg
5461ab64890Smrg    return (pub->siname[0] != '\0') ? 1 : 0;
5471ab64890Smrg}
5481ab64890Smrg
5491ab64890Smrg/************************************************************************/
5501ab64890Smrgint
55161b2299dSmrg_XlcResolveI18NPath(char *buf, int buf_len)
5521ab64890Smrg{
5531ab64890Smrg    if (buf != NULL) {
5541ab64890Smrg	xlocaledir(buf, buf_len);
5551ab64890Smrg    }
5561ab64890Smrg    return 1;
5571ab64890Smrg}
5581ab64890Smrg
5591ab64890Smrgchar *
560818534a1Smrg_XlcLocaleDirName(char *dir_name, size_t dir_len, const char *lc_name)
5611ab64890Smrg{
562818534a1Smrg    char dir[PATH_MAX], buf[PATH_MAX];
5631ab64890Smrg    int i, n;
5641ab64890Smrg    char *args[NUM_LOCALEDIR];
5651ab64890Smrg    static char locale_alias[] = LOCALE_ALIAS;
566818534a1Smrg    char *target_name = NULL;
567818534a1Smrg    char *target_dir = NULL;
5681ab64890Smrg    char *nlc_name = NULL;
5691ab64890Smrg    static char*  last_dir_name = 0;
5701ab64890Smrg    static size_t last_dir_len = 0;
5711ab64890Smrg    static char*  last_lc_name = 0;
5721ab64890Smrg
5731ab64890Smrg    if (last_lc_name != 0 && strcmp (last_lc_name, lc_name) == 0
5741ab64890Smrg       && dir_len >= last_dir_len) {
5751ab64890Smrg        strcpy (dir_name, last_dir_name);
5761ab64890Smrg        return dir_name;
5771ab64890Smrg    }
5781ab64890Smrg
5791ab64890Smrg    xlocaledir (dir, PATH_MAX);
580818534a1Smrg    n = _XlcParsePath(dir, args, NUM_LOCALEDIR);
5811ab64890Smrg    for (i = 0; i < n; ++i) {
582818534a1Smrg	char *name = NULL;
58361b2299dSmrg
584818534a1Smrg	if (args[i] == NULL)
585818534a1Smrg	    continue;
586818534a1Smrg
587818534a1Smrg	if (snprintf (buf, PATH_MAX, "%s/%s", args[i], locale_alias)
588818534a1Smrg	    < PATH_MAX) {
5891ab64890Smrg 	    name = resolve_name(lc_name, buf, LtoR);
5901ab64890Smrg	    if (!name) {
5911ab64890Smrg		if (!nlc_name)
5921ab64890Smrg		    nlc_name = normalize_lcname(lc_name);
5931ab64890Smrg		if (nlc_name)
5941ab64890Smrg		    name = resolve_name (nlc_name, buf, LtoR);
5951ab64890Smrg	    }
5961ab64890Smrg 	}
59761b2299dSmrg
5981ab64890Smrg 	/* look at locale.dir */
59961b2299dSmrg
6001ab64890Smrg 	target_dir = args[i];
601818534a1Smrg	if (snprintf(buf, PATH_MAX, "%s/locale.dir", target_dir) < PATH_MAX) {
602818534a1Smrg	    /* If name is not an alias, use lc_name for locale.dir search */
603818534a1Smrg	    target_name = resolve_name(name ? name : lc_name, buf, RtoL);
6041ab64890Smrg 	}
605818534a1Smrg	Xfree(name);
606818534a1Smrg	name = NULL;
6071ab64890Smrg 	if (target_name != NULL) {
6081ab64890Smrg 	    char *p = 0;
6091ab64890Smrg 	    if ((p = strstr(target_name, "/XLC_LOCALE"))) {
6101ab64890Smrg 		*p = '\0';
6111ab64890Smrg 		break;
6121ab64890Smrg 	    }
6131ab64890Smrg 	    Xfree(target_name);
6141ab64890Smrg 	    target_name = NULL;
6151ab64890Smrg 	}
6161ab64890Smrg    }
6170f8248bfSmrg    Xfree(nlc_name);
6181ab64890Smrg
619818534a1Smrg    if (target_name == NULL)
6201ab64890Smrg 	/* vendor locale name == Xlocale name, no expansion of alias */
621818534a1Smrg	snprintf(dir_name, dir_len, "%s/%s", args[0], lc_name);
622818534a1Smrg    else
623818534a1Smrg	snprintf(dir_name, dir_len, "%s/%s", target_dir, target_name);
6240f8248bfSmrg
625818534a1Smrg    Xfree(target_name);
6260f8248bfSmrg    Xfree (last_dir_name);
6270f8248bfSmrg    Xfree (last_lc_name);
6281ab64890Smrg
6293b4ba46cSmrg    last_dir_name = strdup (dir_name);
6303b4ba46cSmrg    last_dir_len = (last_dir_name != NULL) ? strlen (last_dir_name) + 1 : 0;
6313b4ba46cSmrg
6326cc2b21fSmrg    last_lc_name = strdup (lc_name);
6331ab64890Smrg
6341ab64890Smrg    return dir_name;
6351ab64890Smrg}
6361ab64890Smrg
6371ab64890Smrgchar *
638818534a1Smrg_XlcLocaleLibDirName(char *dir_name, size_t dir_len, const char *lc_name)
6391ab64890Smrg{
640818534a1Smrg    char dir[PATH_MAX], buf[PATH_MAX];
6411ab64890Smrg    int i, n;
6421ab64890Smrg    char *args[NUM_LOCALEDIR];
6431ab64890Smrg    static char locale_alias[] = LOCALE_ALIAS;
644818534a1Smrg    char *target_name = NULL;
645818534a1Smrg    char *target_dir = NULL;
6461ab64890Smrg    char *nlc_name = NULL;
6471ab64890Smrg    static char*  last_dir_name = 0;
6481ab64890Smrg    static size_t last_dir_len = 0;
6491ab64890Smrg    static char*  last_lc_name = 0;
6501ab64890Smrg
6511ab64890Smrg    if (last_lc_name != 0 && strcmp (last_lc_name, lc_name) == 0
6521ab64890Smrg       && dir_len >= last_dir_len) {
6531ab64890Smrg	strcpy (dir_name, last_dir_name);
6541ab64890Smrg	return dir_name;
6551ab64890Smrg    }
6561ab64890Smrg
6571ab64890Smrg    xlocalelibdir (dir, PATH_MAX);
658818534a1Smrg    n = _XlcParsePath(dir, args, NUM_LOCALEDIR);
6591ab64890Smrg    for (i = 0; i < n; ++i) {
660818534a1Smrg	char *name = NULL;
661818534a1Smrg
662818534a1Smrg	if (args[i] == NULL)
663818534a1Smrg	    continue;
66461b2299dSmrg
665818534a1Smrg	if (snprintf (buf, PATH_MAX, "%s/%s", args[i], locale_alias)
666818534a1Smrg	    < PATH_MAX) {
6671ab64890Smrg 	    name = resolve_name(lc_name, buf, LtoR);
6681ab64890Smrg	    if (!name) {
6691ab64890Smrg		if (!nlc_name)
6701ab64890Smrg		    nlc_name = normalize_lcname(lc_name);
6711ab64890Smrg		if (nlc_name)
6721ab64890Smrg		    name = resolve_name (nlc_name, buf, LtoR);
6731ab64890Smrg	    }
6741ab64890Smrg 	}
67561b2299dSmrg
6761ab64890Smrg 	/* look at locale.dir */
67761b2299dSmrg
6781ab64890Smrg 	target_dir = args[i];
679818534a1Smrg	if (snprintf(buf, PATH_MAX, "%s/locale.dir", target_dir) < PATH_MAX) {
680818534a1Smrg	    /* If name is not an alias, use lc_name for locale.dir search */
681818534a1Smrg	    target_name = resolve_name(name ? name : lc_name, buf, RtoL);
6821ab64890Smrg 	}
683818534a1Smrg	Xfree(name);
684818534a1Smrg	name = NULL;
6851ab64890Smrg 	if (target_name != NULL) {
6861ab64890Smrg 	    char *p = 0;
6871ab64890Smrg 	    if ((p = strstr(target_name, "/XLC_LOCALE"))) {
6881ab64890Smrg 		*p = '\0';
6891ab64890Smrg 		break;
6901ab64890Smrg 	    }
6911ab64890Smrg 	    Xfree(target_name);
6921ab64890Smrg 	    target_name = NULL;
6931ab64890Smrg 	}
6941ab64890Smrg    }
6950f8248bfSmrg    Xfree(nlc_name);
6961ab64890Smrg
697818534a1Smrg    if (target_name == NULL)
6981ab64890Smrg 	/* vendor locale name == Xlocale name, no expansion of alias */
699818534a1Smrg	snprintf(dir_name, dir_len, "%s/%s", args[0], lc_name);
700818534a1Smrg    else
701818534a1Smrg	snprintf(dir_name, dir_len, "%s/%s", target_dir, target_name);
702818534a1Smrg    Xfree(target_name);
7030f8248bfSmrg    Xfree (last_dir_name);
7040f8248bfSmrg    Xfree (last_lc_name);
7051ab64890Smrg
7063b4ba46cSmrg    last_dir_name = strdup (dir_name);
7073b4ba46cSmrg    last_dir_len = (last_dir_name != NULL) ? strlen (last_dir_name) + 1 : 0;
7083b4ba46cSmrg
7096cc2b21fSmrg    last_lc_name = strdup (lc_name);
7101ab64890Smrg
7111ab64890Smrg    return dir_name;
7121ab64890Smrg}
713