lcFile.c revision eb411b4b
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#ifndef __UNIXOS2__
501ab64890Smrg#define LC_PATHDELIM ':'
511ab64890Smrg#else
521ab64890Smrg#define LC_PATHDELIM ';'
531ab64890Smrg#endif
541ab64890Smrg
551ab64890Smrg#define XLC_BUFSIZE 256
561ab64890Smrg
57eb411b4bSmrg#include "pathmax.h"
581ab64890Smrg
591ab64890Smrg#define NUM_LOCALEDIR	64
601ab64890Smrg
611ab64890Smrg/* Splits a NUL terminated line into constituents, at colons and newline
621ab64890Smrg   characters. Leading whitespace is removed from constituents. The
631ab64890Smrg   constituents are stored at argv[0..argsize-1]. The number of stored
641ab64890Smrg   constituents (<= argsize) is returned. The line is destructively
651ab64890Smrg   modified. */
661ab64890Smrgstatic int
671ab64890Smrgparse_line(
681ab64890Smrg    char *line,
691ab64890Smrg    char **argv,
701ab64890Smrg    int argsize)
711ab64890Smrg{
721ab64890Smrg    int argc = 0;
731ab64890Smrg    char *p = line;
741ab64890Smrg
751ab64890Smrg    while (argc < argsize) {
761ab64890Smrg	while (isspace(*p)) {
771ab64890Smrg	    ++p;
781ab64890Smrg	}
791ab64890Smrg	if (*p == '\0') {
801ab64890Smrg	    break;
811ab64890Smrg	}
821ab64890Smrg	argv[argc++] = p;
831ab64890Smrg	while (*p != ':' && *p != '\n' && *p != '\0') {
841ab64890Smrg	    ++p;
851ab64890Smrg	}
861ab64890Smrg	if (*p == '\0') {
871ab64890Smrg	    break;
881ab64890Smrg	}
891ab64890Smrg	*p++ = '\0';
901ab64890Smrg    }
911ab64890Smrg
921ab64890Smrg    return argc;
931ab64890Smrg}
941ab64890Smrg
951ab64890Smrg#ifdef __UNIXOS2__
961ab64890Smrg
971ab64890Smrg/* fg021216: entries in locale files are separated by colons while under
981ab64890Smrg   OS/2, path entries are separated by semicolon, so we need two functions */
991ab64890Smrg
1001ab64890Smrgstatic int
1011ab64890Smrgparse_line1(
1021ab64890Smrg    char *line,
1031ab64890Smrg    char **argv,
1041ab64890Smrg    int argsize)
1051ab64890Smrg{
1061ab64890Smrg    int argc = 0;
1071ab64890Smrg    char *p = line;
1081ab64890Smrg
1091ab64890Smrg    while (argc < argsize) {
1101ab64890Smrg	while (isspace(*p)) {
1111ab64890Smrg	    ++p;
1121ab64890Smrg	}
1131ab64890Smrg	if (*p == '\0') {
1141ab64890Smrg	    break;
1151ab64890Smrg	}
1161ab64890Smrg	argv[argc++] = p;
1171ab64890Smrg	while (*p != ';' && *p != '\n' && *p != '\0') {
1181ab64890Smrg	    ++p;
1191ab64890Smrg	}
1201ab64890Smrg	if (*p == '\0') {
1211ab64890Smrg	    break;
1221ab64890Smrg	}
1231ab64890Smrg	*p++ = '\0';
1241ab64890Smrg    }
1251ab64890Smrg
1261ab64890Smrg    return argc;
1271ab64890Smrg}
1281ab64890Smrg#elif defined(WIN32)
1291ab64890Smrg
1301ab64890Smrg/* this is parse_line but skips drive letters at the beginning of the entry */
1311ab64890Smrgstatic int
1321ab64890Smrgparse_line1(
1331ab64890Smrg    char *line,
1341ab64890Smrg    char **argv,
1351ab64890Smrg    int argsize)
1361ab64890Smrg{
1371ab64890Smrg    int argc = 0;
1381ab64890Smrg    char *p = line;
1391ab64890Smrg
1401ab64890Smrg    while (argc < argsize) {
1411ab64890Smrg	while (isspace(*p)) {
1421ab64890Smrg	    ++p;
1431ab64890Smrg	}
1441ab64890Smrg	if (*p == '\0') {
1451ab64890Smrg	    break;
1461ab64890Smrg	}
1471ab64890Smrg	argv[argc++] = p;
1481ab64890Smrg        if (isalpha(*p) && p[1] == ':') {
1491ab64890Smrg            p+= 2; /* skip drive letters */
1501ab64890Smrg        }
1511ab64890Smrg	while (*p != ':' && *p != '\n' && *p != '\0') {
1521ab64890Smrg	    ++p;
1531ab64890Smrg	}
1541ab64890Smrg	if (*p == '\0') {
1551ab64890Smrg	    break;
1561ab64890Smrg	}
1571ab64890Smrg	*p++ = '\0';
1581ab64890Smrg    }
1591ab64890Smrg
1601ab64890Smrg    return argc;
1611ab64890Smrg}
1621ab64890Smrg
1631ab64890Smrg#endif   /* __UNIXOS2__ */
1641ab64890Smrg
1651ab64890Smrg/* Splits a colon separated list of directories, and returns the constituent
1661ab64890Smrg   paths (without trailing slash). At most argsize constituents are stored
1671ab64890Smrg   at argv[0..argsize-1]. The number of stored constituents is returned. */
1681ab64890Smrgstatic int
1691ab64890Smrg_XlcParsePath(
1701ab64890Smrg    char *path,
1711ab64890Smrg    char **argv,
1721ab64890Smrg    int argsize)
1731ab64890Smrg{
1741ab64890Smrg    char *p = path;
1751ab64890Smrg    int n, i;
1761ab64890Smrg
1771ab64890Smrg#if !defined(__UNIXOS2__) && !defined(WIN32)
1781ab64890Smrg    n = parse_line(path, argv, argsize);
1791ab64890Smrg#else
1801ab64890Smrg    n = parse_line1(path, argv, argsize);
1811ab64890Smrg#endif
1821ab64890Smrg    for (i = 0; i < n; ++i) {
1831ab64890Smrg	int len;
1841ab64890Smrg	p = argv[i];
1851ab64890Smrg	len = strlen(p);
1861ab64890Smrg	if (len > 0 && p[len - 1] == '/') {
1871ab64890Smrg	    /* eliminate trailing slash */
1881ab64890Smrg	    p[len - 1] = '\0';
1891ab64890Smrg	}
1901ab64890Smrg    }
1911ab64890Smrg    return n;
1921ab64890Smrg}
1931ab64890Smrg
1941ab64890Smrg#ifndef XLOCALEDIR
1951ab64890Smrg#define XLOCALEDIR "/usr/lib/X11/locale"
1961ab64890Smrg#endif
1971ab64890Smrg
198b4ee4795Smrgvoid
1991ab64890Smrgxlocaledir(
2001ab64890Smrg    char *buf,
2011ab64890Smrg    int buf_len)
2021ab64890Smrg{
2031ab64890Smrg    char *p = buf;
2041ab64890Smrg    int len = 0;
2051ab64890Smrg
2061ab64890Smrg#ifndef NO_XLOCALEDIR
2071ab64890Smrg    char *dir;
2081ab64890Smrg    int priv = 1;
2091ab64890Smrg
2101ab64890Smrg    dir = getenv("XLOCALEDIR");
2111ab64890Smrg
2121ab64890Smrg    if (dir) {
2131ab64890Smrg#ifndef WIN32
2141ab64890Smrg	/*
2151ab64890Smrg	 * Only use the user-supplied path if the process isn't priviledged.
2161ab64890Smrg	 */
2171ab64890Smrg	if (getuid() == geteuid() && getgid() == getegid()) {
2181ab64890Smrg#if defined(HASSETUGID)
2191ab64890Smrg	    priv = issetugid();
2201ab64890Smrg#elif defined(HASGETRESUID)
2211ab64890Smrg	    {
2221ab64890Smrg		uid_t ruid, euid, suid;
2231ab64890Smrg		gid_t rgid, egid, sgid;
2241ab64890Smrg		if ((getresuid(&ruid, &euid, &suid) == 0) &&
2251ab64890Smrg		    (getresgid(&rgid, &egid, &sgid) == 0))
2261ab64890Smrg		    priv = (euid != suid) || (egid != sgid);
2271ab64890Smrg	    }
2281ab64890Smrg#else
2291ab64890Smrg	    /*
2301ab64890Smrg	     * If there are saved ID's the process might still be priviledged
2311ab64890Smrg	     * even though the above test succeeded.  If issetugid() and
2321ab64890Smrg	     * getresgid() aren't available, test this by trying to set
2331ab64890Smrg	     * euid to 0.
2341ab64890Smrg	     *
2351ab64890Smrg	     * Note: this only protects setuid-root clients.  It doesn't
2361ab64890Smrg	     * protect other setuid or any setgid clients.  If this tradeoff
2371ab64890Smrg	     * isn't acceptable, set DisableXLocaleDirEnv to YES in host.def.
2381ab64890Smrg	     */
2391ab64890Smrg	    unsigned int oldeuid;
2401ab64890Smrg	    oldeuid = geteuid();
2411ab64890Smrg	    if (seteuid(0) != 0) {
2421ab64890Smrg		priv = 0;
2431ab64890Smrg	    } else {
2441ab64890Smrg		if (seteuid(oldeuid) == -1) {
24561b2299dSmrg		    /* XXX ouch, coudn't get back to original uid
2461ab64890Smrg		     what can we do ??? */
2471ab64890Smrg		    _exit(127);
2481ab64890Smrg		}
2491ab64890Smrg		priv = 1;
2501ab64890Smrg	    }
2511ab64890Smrg#endif
2521ab64890Smrg	}
2531ab64890Smrg#else
2541ab64890Smrg	priv = 0;
2551ab64890Smrg#endif
2561ab64890Smrg	if (!priv) {
2571ab64890Smrg	    len = strlen(dir);
2581ab64890Smrg	    strncpy(p, dir, buf_len);
2591ab64890Smrg	    if (len < buf_len) {
2601ab64890Smrg	        p[len++] = LC_PATHDELIM;
2611ab64890Smrg	        p += len;
2621ab64890Smrg	    }
2631ab64890Smrg	}
2641ab64890Smrg    }
2651ab64890Smrg#endif /* NO_XLOCALEDIR */
2661ab64890Smrg
2671ab64890Smrg    if (len < buf_len)
2681ab64890Smrg#ifndef __UNIXOS2__
2691ab64890Smrg      strncpy(p, XLOCALEDIR, buf_len - len);
2701ab64890Smrg#else
2711ab64890Smrg      strncpy(p,__XOS2RedirRoot(XLOCALEDIR), buf_len - len);
2721ab64890Smrg#endif
2731ab64890Smrg    buf[buf_len-1] = '\0';
2741ab64890Smrg}
2751ab64890Smrg
2761ab64890Smrgstatic void
2771ab64890Smrgxlocalelibdir(
2781ab64890Smrg    char *buf,
2791ab64890Smrg    int buf_len)
2801ab64890Smrg{
2811ab64890Smrg    char *p = buf;
2821ab64890Smrg    int len = 0;
2831ab64890Smrg
2841ab64890Smrg#ifndef NO_XLOCALEDIR
2851ab64890Smrg    char *dir;
2861ab64890Smrg    int priv = 1;
2871ab64890Smrg
2881ab64890Smrg    dir = getenv("XLOCALELIBDIR");
2891ab64890Smrg
2901ab64890Smrg    if (dir) {
2911ab64890Smrg#ifndef WIN32
2921ab64890Smrg	/*
2931ab64890Smrg	 * Only use the user-supplied path if the process isn't priviledged.
2941ab64890Smrg	 */
2951ab64890Smrg	if (getuid() == geteuid() && getgid() == getegid()) {
2961ab64890Smrg#if defined(HASSETUGID)
2971ab64890Smrg	    priv = issetugid();
2981ab64890Smrg#elif defined(HASGETRESUID)
2991ab64890Smrg	    {
3001ab64890Smrg		uid_t ruid, euid, suid;
3011ab64890Smrg		gid_t rgid, egid, sgid;
3021ab64890Smrg		if ((getresuid(&ruid, &euid, &suid) == 0) &&
3031ab64890Smrg		    (getresgid(&rgid, &egid, &sgid) == 0))
3041ab64890Smrg		    priv = (euid != suid) || (egid != sgid);
3051ab64890Smrg	    }
3061ab64890Smrg#else
3071ab64890Smrg	    /*
3081ab64890Smrg	     * If there are saved ID's the process might still be priviledged
3091ab64890Smrg	     * even though the above test succeeded.  If issetugid() and
3101ab64890Smrg	     * getresgid() aren't available, test this by trying to set
3111ab64890Smrg	     * euid to 0.
3121ab64890Smrg	     *
3131ab64890Smrg	     * Note: this only protects setuid-root clients.  It doesn't
3141ab64890Smrg	     * protect other setuid or any setgid clients.  If this tradeoff
3151ab64890Smrg	     * isn't acceptable, set DisableXLocaleDirEnv to YES in host.def.
3161ab64890Smrg	     */
3171ab64890Smrg	    unsigned int oldeuid;
3181ab64890Smrg	    oldeuid = geteuid();
3191ab64890Smrg	    if (seteuid(0) != 0) {
3201ab64890Smrg		priv = 0;
3211ab64890Smrg	    } else {
3221ab64890Smrg		if (seteuid(oldeuid) == -1) {
32361b2299dSmrg		    /* XXX ouch, coudn't get back to original uid
3241ab64890Smrg		     what can we do ??? */
3251ab64890Smrg		    _exit(127);
3261ab64890Smrg		}
3271ab64890Smrg		priv = 1;
3281ab64890Smrg	    }
3291ab64890Smrg#endif
3301ab64890Smrg	}
3311ab64890Smrg#else
3321ab64890Smrg	priv = 0;
3331ab64890Smrg#endif
3341ab64890Smrg	if (!priv) {
3351ab64890Smrg	    len = strlen(dir);
3361ab64890Smrg	    strncpy(p, dir, buf_len);
3371ab64890Smrg	    if (len < buf_len) {
3381ab64890Smrg	        p[len++] = LC_PATHDELIM;
3391ab64890Smrg	        p += len;
3401ab64890Smrg	    }
3411ab64890Smrg	}
3421ab64890Smrg    }
3431ab64890Smrg#endif /* NO_XLOCALEDIR */
3441ab64890Smrg
3451ab64890Smrg    if (len < buf_len)
3461ab64890Smrg#ifndef __UNIXOS2__
3471ab64890Smrg      strncpy(p, XLOCALELIBDIR, buf_len - len);
3481ab64890Smrg#else
3491ab64890Smrg      strncpy(p,__XOS2RedirRoot(XLOCALELIBDIR), buf_len - len);
3501ab64890Smrg#endif
3511ab64890Smrg    buf[buf_len-1] = '\0';
3521ab64890Smrg}
3531ab64890Smrg
3541ab64890Smrg/* Mapping direction */
3551ab64890Smrgtypedef enum {
3561ab64890Smrg  LtoR,		/* Map first field to second field */
3571ab64890Smrg  RtoL		/* Map second field to first field */
3581ab64890Smrg} MapDirection;
3591ab64890Smrg
3601ab64890Smrgstatic char *
3611ab64890Smrgresolve_name(
3621ab64890Smrg    const char *lc_name,
3631ab64890Smrg    char *file_name,
3641ab64890Smrg    MapDirection direction)
3651ab64890Smrg{
3661ab64890Smrg    FILE *fp;
3671ab64890Smrg    char buf[XLC_BUFSIZE], *name = NULL;
3681ab64890Smrg
3691ab64890Smrg    fp = _XFopenFile (file_name, "r");
3701ab64890Smrg    if (fp == NULL)
3711ab64890Smrg	return NULL;
3721ab64890Smrg
3731ab64890Smrg    while (fgets(buf, XLC_BUFSIZE, fp) != NULL) {
3741ab64890Smrg	char *p = buf;
3751ab64890Smrg	int n;
3761ab64890Smrg	char *args[2], *from, *to;
3771ab64890Smrg#ifdef __UNIXOS2__  /* Take out CR under OS/2 */
3781ab64890Smrg	int len;
3791ab64890Smrg
3801ab64890Smrg	len = strlen(p);
3811ab64890Smrg	if (len > 1) {
3821ab64890Smrg	    if (*(p+len-2) == '\r' && *(p+len-1) == '\n') {
3831ab64890Smrg		*(p+len-2) = '\n';
3841ab64890Smrg		*(p+len-1) = '\0';
3851ab64890Smrg	    }
3861ab64890Smrg	}
3871ab64890Smrg#endif
3881ab64890Smrg	while (isspace(*p)) {
3891ab64890Smrg	    ++p;
3901ab64890Smrg	}
3911ab64890Smrg	if (iscomment(*p)) {
3921ab64890Smrg	    continue;
3931ab64890Smrg	}
3941ab64890Smrg	n = parse_line(p, args, 2);		/* get first 2 fields */
3951ab64890Smrg	if (n != 2) {
3961ab64890Smrg	    continue;
3971ab64890Smrg	}
3981ab64890Smrg	if (direction == LtoR) {
3991ab64890Smrg	    from = args[0], to = args[1];	/* left to right */
4001ab64890Smrg	} else {
4011ab64890Smrg	    from = args[1], to = args[0];	/* right to left */
4021ab64890Smrg	}
4031ab64890Smrg	if (! strcmp(from, lc_name)) {
4046cc2b21fSmrg	    name = strdup(to);
4051ab64890Smrg	    break;
4061ab64890Smrg	}
4071ab64890Smrg    }
4081ab64890Smrg    fclose(fp);
4091ab64890Smrg    return name;
4101ab64890Smrg}
4111ab64890Smrg
4121ab64890Smrg#define	c_tolower(ch)	((ch) >= 'A' && (ch) <= 'Z' ? (ch) - 'A' + 'a' : (ch))
4131ab64890Smrg
4141ab64890Smrgstatic char *
4151ab64890Smrglowercase(
4161ab64890Smrg    char *dst,
4171ab64890Smrg    const char *src)
4181ab64890Smrg{
4191ab64890Smrg    const char *s;
4201ab64890Smrg    char *t;
4211ab64890Smrg
4221ab64890Smrg    for (s = src, t = dst; *s; ++s, ++t)
4231ab64890Smrg	*t = c_tolower(*s);
4241ab64890Smrg    *t = '\0';
4251ab64890Smrg    return dst;
4261ab64890Smrg}
4271ab64890Smrg
4281ab64890Smrg/*
4291ab64890Smrg * normalize_lcname(): remove any '_' and '-' and convert any character
4301ab64890Smrg * to lower case after the <language>_<territory> part. If result is identical
4311ab64890Smrg * to argument, free result and
4321ab64890Smrg * return NULL.
4331ab64890Smrg */
4341ab64890Smrgstatic char *
4351ab64890Smrgnormalize_lcname (const char *name)
4361ab64890Smrg{
4371ab64890Smrg    char *p, *ret;
4381ab64890Smrg    const char *tmp = name;
43961b2299dSmrg
4401ab64890Smrg    p = ret = Xmalloc(strlen(name) + 1);
4411ab64890Smrg    if (!p)
4421ab64890Smrg	return NULL;
44361b2299dSmrg
4441ab64890Smrg    if (tmp) {
4451ab64890Smrg	while (*tmp && *tmp != '.' && *tmp != '@')
4461ab64890Smrg	    *p++ = *tmp++;
4471ab64890Smrg	while (*tmp) {
4481ab64890Smrg	    if (*tmp != '-')
4491ab64890Smrg		*p++ = c_tolower(*tmp);
4501ab64890Smrg	    tmp++;
4511ab64890Smrg	}
4521ab64890Smrg    }
4531ab64890Smrg    *p = '\0';
4541ab64890Smrg
4551ab64890Smrg    if (strcmp(ret, name) == 0) {
4561ab64890Smrg	Xfree(ret);
4571ab64890Smrg	return NULL;
4581ab64890Smrg    }
4591ab64890Smrg
4601ab64890Smrg    return ret;
4611ab64890Smrg}
4621ab64890Smrg
4631ab64890Smrg/************************************************************************/
4641ab64890Smrgchar *
4651ab64890Smrg_XlcFileName(
4661ab64890Smrg    XLCd lcd,
4671ab64890Smrg    const char *category)
4681ab64890Smrg{
4691ab64890Smrg    char *siname;
4701ab64890Smrg    char cat[XLC_BUFSIZE], dir[XLC_BUFSIZE];
4711ab64890Smrg    int i, n;
4721ab64890Smrg    char *args[NUM_LOCALEDIR];
4731ab64890Smrg    char *file_name = NULL;
4741ab64890Smrg
4751ab64890Smrg    if (lcd == (XLCd)NULL)
4761ab64890Smrg	return NULL;
4771ab64890Smrg
4781ab64890Smrg    siname = XLC_PUBLIC(lcd, siname);
4791ab64890Smrg
48061b2299dSmrg    if (category)
48161b2299dSmrg	lowercase(cat, category);
48261b2299dSmrg    else
48361b2299dSmrg	cat[0] = '\0';
4841ab64890Smrg    xlocaledir(dir,XLC_BUFSIZE);
4851ab64890Smrg    n = _XlcParsePath(dir, args, NUM_LOCALEDIR);
4861ab64890Smrg    for (i = 0; i < n; ++i) {
4871ab64890Smrg	char buf[PATH_MAX], *name;
4881ab64890Smrg
4891ab64890Smrg	name = NULL;
49061b2299dSmrg	if ((5 + (args[i] ? strlen (args[i]) : 0) + strlen(cat)) < PATH_MAX) {
4911ab64890Smrg	    sprintf(buf, "%s/%s.dir", args[i], cat);
4921ab64890Smrg	    name = resolve_name(siname, buf, RtoL);
4931ab64890Smrg	}
4941ab64890Smrg	if (name == NULL) {
4951ab64890Smrg	    continue;
4961ab64890Smrg	}
4971ab64890Smrg	if (*name == '/') {
4981ab64890Smrg	    /* supposed to be absolute path name */
4991ab64890Smrg	    file_name = name;
5001ab64890Smrg	} else {
5011ab64890Smrg	    file_name = Xmalloc(2 + (args[i] ? strlen (args[i]) : 0) +
5021ab64890Smrg				(name ? strlen (name) : 0));
5031ab64890Smrg	    if (file_name != NULL)
5041ab64890Smrg		sprintf(file_name, "%s/%s", args[i], name);
5051ab64890Smrg	    Xfree(name);
5061ab64890Smrg	}
5071ab64890Smrg	if (isreadable(file_name)) {
5081ab64890Smrg	    break;
5091ab64890Smrg	}
5101ab64890Smrg	Xfree(file_name);
5111ab64890Smrg	file_name = NULL;
5121ab64890Smrg	/* Then, try with next dir */
5131ab64890Smrg    }
5141ab64890Smrg    return file_name;
5151ab64890Smrg}
5161ab64890Smrg
5171ab64890Smrg/************************************************************************/
5181ab64890Smrg#ifndef LOCALE_ALIAS
5191ab64890Smrg#define LOCALE_ALIAS    "locale.alias"
5201ab64890Smrg#endif
5211ab64890Smrg
5221ab64890Smrgint
5231ab64890Smrg_XlcResolveLocaleName(
5241ab64890Smrg    const char* lc_name,
5251ab64890Smrg    XLCdPublicPart* pub)
5261ab64890Smrg{
5271ab64890Smrg    char dir[PATH_MAX], buf[PATH_MAX], *name = NULL;
5281ab64890Smrg    char *dst;
5291ab64890Smrg    int i, n, sinamelen;
5301ab64890Smrg    char *args[NUM_LOCALEDIR];
5311ab64890Smrg    static const char locale_alias[] = LOCALE_ALIAS;
5321ab64890Smrg    char *tmp_siname;
5331ab64890Smrg    char *nlc_name = NULL;
5341ab64890Smrg
5351ab64890Smrg    xlocaledir (dir, PATH_MAX);
5361ab64890Smrg    n = _XlcParsePath(dir, args, NUM_LOCALEDIR);
5371ab64890Smrg    for (i = 0; i < n; ++i) {
53861b2299dSmrg	if ((2 + (args[i] ? strlen (args[i]) : 0) +
5391ab64890Smrg	    strlen (locale_alias)) < PATH_MAX) {
5401ab64890Smrg	    sprintf (buf, "%s/%s", args[i], locale_alias);
5411ab64890Smrg	    name = resolve_name (lc_name, buf, LtoR);
5421ab64890Smrg	    if (!name) {
5431ab64890Smrg		if (!nlc_name)
5441ab64890Smrg		    nlc_name = normalize_lcname(lc_name);
5451ab64890Smrg		if (nlc_name)
5461ab64890Smrg		    name = resolve_name (nlc_name, buf, LtoR);
5471ab64890Smrg	    }
5481ab64890Smrg	}
5491ab64890Smrg	if (name != NULL) {
5501ab64890Smrg	    break;
5511ab64890Smrg	}
5521ab64890Smrg    }
5531ab64890Smrg    if (nlc_name) Xfree(nlc_name);
5541ab64890Smrg
5551ab64890Smrg    if (name == NULL) {
5561ab64890Smrg	/* vendor locale name == Xlocale name, no expansion of alias */
5576cc2b21fSmrg	pub->siname = strdup (lc_name);
5581ab64890Smrg    } else {
5591ab64890Smrg	pub->siname = name;
5601ab64890Smrg    }
5611ab64890Smrg
5621ab64890Smrg    sinamelen = strlen (pub->siname);
5631ab64890Smrg    if (sinamelen == 1 && pub->siname[0] == 'C') {
5641ab64890Smrg	pub->language = pub->siname;
5651ab64890Smrg	pub->territory = pub->codeset = NULL;
5661ab64890Smrg	return 1;
5671ab64890Smrg    }
5681ab64890Smrg
56961b2299dSmrg    /*
5701ab64890Smrg     * pub->siname is in the format <lang>_<terr>.<codeset>, typical would
5711ab64890Smrg     * be "en_US.ISO8859-1", "en_US.utf8", "ru_RU.KOI-8", or ja_JP.SJIS,
5721ab64890Smrg     * although it could be ja.SJIS too.
5731ab64890Smrg     */
5741ab64890Smrg    tmp_siname = Xrealloc (pub->siname, 2 * (sinamelen + 1));
5751ab64890Smrg    if (tmp_siname == NULL) {
5761ab64890Smrg	return 0;
5771ab64890Smrg    }
5781ab64890Smrg    pub->siname = tmp_siname;
5791ab64890Smrg
5801ab64890Smrg    /* language */
5811ab64890Smrg    dst = &pub->siname[sinamelen + 1];
5821ab64890Smrg    strcpy (dst, pub->siname);
5831ab64890Smrg    pub->language = dst;
5841ab64890Smrg
5851ab64890Smrg    /* territory */
5861ab64890Smrg    dst = strchr (dst, '_');
5871ab64890Smrg    if (dst) {
5881ab64890Smrg	*dst = '\0';
5891ab64890Smrg	pub->territory = ++dst;
5901ab64890Smrg    } else
5911ab64890Smrg	dst = &pub->siname[sinamelen + 1];
5921ab64890Smrg
5931ab64890Smrg    /* codeset */
5941ab64890Smrg    dst = strchr (dst, '.');
5951ab64890Smrg    if (dst) {
5961ab64890Smrg	*dst = '\0';
5971ab64890Smrg	pub->codeset = ++dst;
5981ab64890Smrg    }
5991ab64890Smrg
6001ab64890Smrg    return (pub->siname[0] != '\0') ? 1 : 0;
6011ab64890Smrg}
6021ab64890Smrg
6031ab64890Smrg/************************************************************************/
6041ab64890Smrgint
60561b2299dSmrg_XlcResolveI18NPath(char *buf, int buf_len)
6061ab64890Smrg{
6071ab64890Smrg    if (buf != NULL) {
6081ab64890Smrg	xlocaledir(buf, buf_len);
6091ab64890Smrg    }
6101ab64890Smrg    return 1;
6111ab64890Smrg}
6121ab64890Smrg
6131ab64890Smrgchar *
61461b2299dSmrg_XlcLocaleDirName(char *dir_name, size_t dir_len, char *lc_name)
6151ab64890Smrg{
6161ab64890Smrg    char dir[PATH_MAX], buf[PATH_MAX], *name = NULL;
6171ab64890Smrg    int i, n;
6181ab64890Smrg    char *args[NUM_LOCALEDIR];
6191ab64890Smrg    static char locale_alias[] = LOCALE_ALIAS;
6201ab64890Smrg    char *target_name = (char*)0;
6211ab64890Smrg    char *target_dir = (char*)0;
6221ab64890Smrg    char *nlc_name = NULL;
6231ab64890Smrg    static char*  last_dir_name = 0;
6241ab64890Smrg    static size_t last_dir_len = 0;
6251ab64890Smrg    static char*  last_lc_name = 0;
6261ab64890Smrg
6271ab64890Smrg    if (last_lc_name != 0 && strcmp (last_lc_name, lc_name) == 0
6281ab64890Smrg       && dir_len >= last_dir_len) {
6291ab64890Smrg        strcpy (dir_name, last_dir_name);
6301ab64890Smrg        return dir_name;
6311ab64890Smrg    }
6321ab64890Smrg
6331ab64890Smrg    xlocaledir (dir, PATH_MAX);
6341ab64890Smrg    n = _XlcParsePath(dir, args, 256);
6351ab64890Smrg    for (i = 0; i < n; ++i) {
63661b2299dSmrg
63761b2299dSmrg	if ((2 + (args[i] ? strlen(args[i]) : 0) +
6381ab64890Smrg 	     strlen(locale_alias)) < PATH_MAX) {
6391ab64890Smrg 	    sprintf (buf, "%s/%s", args[i], locale_alias);
6401ab64890Smrg 	    name = resolve_name(lc_name, buf, LtoR);
6411ab64890Smrg	    if (!name) {
6421ab64890Smrg		if (!nlc_name)
6431ab64890Smrg		    nlc_name = normalize_lcname(lc_name);
6441ab64890Smrg		if (nlc_name)
6451ab64890Smrg		    name = resolve_name (nlc_name, buf, LtoR);
6461ab64890Smrg	    }
6471ab64890Smrg 	}
64861b2299dSmrg
6491ab64890Smrg 	/* If name is not an alias, use lc_name for locale.dir search */
6501ab64890Smrg 	if (name == NULL)
6511ab64890Smrg 	    name = lc_name;
65261b2299dSmrg
6531ab64890Smrg 	/* look at locale.dir */
65461b2299dSmrg
6551ab64890Smrg 	target_dir = args[i];
6561ab64890Smrg 	if (!target_dir) {
6571ab64890Smrg 	    /* something wrong */
6581ab64890Smrg 	    if (name != lc_name)
6591ab64890Smrg 		Xfree(name);
6601ab64890Smrg 	    continue;
6611ab64890Smrg 	}
66257f47464Smrg 	if ((1 + strlen (target_dir) + strlen("locale.dir")) < PATH_MAX) {
6631ab64890Smrg 	    sprintf(buf, "%s/locale.dir", target_dir);
6641ab64890Smrg 	    target_name = resolve_name(name, buf, RtoL);
6651ab64890Smrg 	}
6661ab64890Smrg 	if (name != lc_name)
6671ab64890Smrg 	    Xfree(name);
6681ab64890Smrg 	if (target_name != NULL) {
6691ab64890Smrg 	    char *p = 0;
6701ab64890Smrg 	    if ((p = strstr(target_name, "/XLC_LOCALE"))) {
6711ab64890Smrg 		*p = '\0';
6721ab64890Smrg 		break;
6731ab64890Smrg 	    }
6741ab64890Smrg 	    Xfree(target_name);
6751ab64890Smrg 	    target_name = NULL;
6761ab64890Smrg 	}
6771ab64890Smrg 	name = NULL;
6781ab64890Smrg    }
6791ab64890Smrg    if (nlc_name) Xfree(nlc_name);
6801ab64890Smrg
6811ab64890Smrg    if (target_name == NULL) {
6821ab64890Smrg 	/* vendor locale name == Xlocale name, no expansion of alias */
6831ab64890Smrg 	target_dir = args[0];
6841ab64890Smrg 	target_name = lc_name;
6851ab64890Smrg    }
6861ab64890Smrg    /* snprintf(dir_name, dir_len, "%s/%", target_dir, target_name); */
6871ab64890Smrg    strncpy(dir_name, target_dir, dir_len - 1);
6881ab64890Smrg    if (strlen(target_dir) >= dir_len - 1) {
6891ab64890Smrg	dir_name[dir_len - 1] = '\0';
6901ab64890Smrg    } else  {
6911ab64890Smrg	strcat(dir_name, "/");
6921ab64890Smrg	strncat(dir_name, target_name, dir_len - strlen(dir_name) - 1);
69361b2299dSmrg	if (strlen(target_name) >= dir_len - strlen(dir_name) - 1)
6941ab64890Smrg	    dir_name[dir_len - 1] = '\0';
6951ab64890Smrg    }
6961ab64890Smrg    if (target_name != lc_name)
6971ab64890Smrg 	Xfree(target_name);
6981ab64890Smrg
6991ab64890Smrg    if (last_dir_name != 0)
7001ab64890Smrg	Xfree (last_dir_name);
7011ab64890Smrg    if (last_lc_name != 0)
7021ab64890Smrg	Xfree (last_lc_name);
7031ab64890Smrg    last_dir_len = strlen (dir_name) + 1;
7041ab64890Smrg    last_dir_name = Xmalloc (last_dir_len);
7051ab64890Smrg    strcpy (last_dir_name, dir_name);
7066cc2b21fSmrg    last_lc_name = strdup (lc_name);
7071ab64890Smrg
7081ab64890Smrg    return dir_name;
7091ab64890Smrg}
7101ab64890Smrg
7111ab64890Smrgchar *
71261b2299dSmrg_XlcLocaleLibDirName(char *dir_name, size_t dir_len, char *lc_name)
7131ab64890Smrg{
7141ab64890Smrg    char dir[PATH_MAX], buf[PATH_MAX], *name = NULL;
7151ab64890Smrg    int i, n;
7161ab64890Smrg    char *args[NUM_LOCALEDIR];
7171ab64890Smrg    static char locale_alias[] = LOCALE_ALIAS;
7181ab64890Smrg    char *target_name = (char*)0;
7191ab64890Smrg    char *target_dir = (char*)0;
7201ab64890Smrg    char *nlc_name = NULL;
7211ab64890Smrg    static char*  last_dir_name = 0;
7221ab64890Smrg    static size_t last_dir_len = 0;
7231ab64890Smrg    static char*  last_lc_name = 0;
7241ab64890Smrg
7251ab64890Smrg    if (last_lc_name != 0 && strcmp (last_lc_name, lc_name) == 0
7261ab64890Smrg       && dir_len >= last_dir_len) {
7271ab64890Smrg	strcpy (dir_name, last_dir_name);
7281ab64890Smrg	return dir_name;
7291ab64890Smrg    }
7301ab64890Smrg
7311ab64890Smrg    xlocalelibdir (dir, PATH_MAX);
7321ab64890Smrg    n = _XlcParsePath(dir, args, 256);
7331ab64890Smrg    for (i = 0; i < n; ++i) {
73461b2299dSmrg
73561b2299dSmrg	if ((2 + (args[i] ? strlen(args[i]) : 0) +
7361ab64890Smrg 	     strlen(locale_alias)) < PATH_MAX) {
7371ab64890Smrg 	    sprintf (buf, "%s/%s", args[i], locale_alias);
7381ab64890Smrg 	    name = resolve_name(lc_name, buf, LtoR);
7391ab64890Smrg	    if (!name) {
7401ab64890Smrg		if (!nlc_name)
7411ab64890Smrg		    nlc_name = normalize_lcname(lc_name);
7421ab64890Smrg		if (nlc_name)
7431ab64890Smrg		    name = resolve_name (nlc_name, buf, LtoR);
7441ab64890Smrg	    }
7451ab64890Smrg 	}
74661b2299dSmrg
7471ab64890Smrg 	/* If name is not an alias, use lc_name for locale.dir search */
7481ab64890Smrg 	if (name == NULL)
7491ab64890Smrg 	    name = lc_name;
75061b2299dSmrg
7511ab64890Smrg 	/* look at locale.dir */
75261b2299dSmrg
7531ab64890Smrg 	target_dir = args[i];
7541ab64890Smrg 	if (!target_dir) {
7551ab64890Smrg 	    /* something wrong */
7561ab64890Smrg 	    if (name != lc_name)
7571ab64890Smrg 		Xfree(name);
7581ab64890Smrg 	    continue;
7591ab64890Smrg 	}
76057f47464Smrg 	if ((1 + strlen (target_dir) + strlen("locale.dir")) < PATH_MAX) {
7611ab64890Smrg 	    sprintf(buf, "%s/locale.dir", target_dir);
7621ab64890Smrg 	    target_name = resolve_name(name, buf, RtoL);
7631ab64890Smrg 	}
7641ab64890Smrg 	if (name != lc_name)
7651ab64890Smrg 	    Xfree(name);
7661ab64890Smrg 	if (target_name != NULL) {
7671ab64890Smrg 	    char *p = 0;
7681ab64890Smrg 	    if ((p = strstr(target_name, "/XLC_LOCALE"))) {
7691ab64890Smrg 		*p = '\0';
7701ab64890Smrg 		break;
7711ab64890Smrg 	    }
7721ab64890Smrg 	    Xfree(target_name);
7731ab64890Smrg 	    target_name = NULL;
7741ab64890Smrg 	}
7751ab64890Smrg 	name = NULL;
7761ab64890Smrg    }
7771ab64890Smrg    if (nlc_name) Xfree(nlc_name);
7781ab64890Smrg
7791ab64890Smrg    if (target_name == NULL) {
7801ab64890Smrg 	/* vendor locale name == Xlocale name, no expansion of alias */
7811ab64890Smrg 	target_dir = args[0];
7821ab64890Smrg 	target_name = lc_name;
7831ab64890Smrg    }
7841ab64890Smrg    /* snprintf(dir_name, dir_len, "%s/%", target_dir, target_name); */
7851ab64890Smrg    strncpy(dir_name, target_dir, dir_len - 1);
7861ab64890Smrg    if (strlen(target_dir) >= dir_len - 1) {
7871ab64890Smrg	dir_name[dir_len - 1] = '\0';
7881ab64890Smrg    } else  {
7891ab64890Smrg	strcat(dir_name, "/");
7901ab64890Smrg	strncat(dir_name, target_name, dir_len - strlen(dir_name) - 1);
79161b2299dSmrg	if (strlen(target_name) >= dir_len - strlen(dir_name) - 1)
7921ab64890Smrg	    dir_name[dir_len - 1] = '\0';
7931ab64890Smrg    }
7941ab64890Smrg    if (target_name != lc_name)
7951ab64890Smrg 	Xfree(target_name);
7961ab64890Smrg
7971ab64890Smrg    if (last_dir_name != 0)
7981ab64890Smrg	Xfree (last_dir_name);
7991ab64890Smrg    if (last_lc_name != 0)
8001ab64890Smrg	Xfree (last_lc_name);
8011ab64890Smrg    last_dir_len = strlen (dir_name) + 1;
8021ab64890Smrg    last_dir_name = Xmalloc (last_dir_len);
8031ab64890Smrg    strcpy (last_dir_name, dir_name);
8046cc2b21fSmrg    last_lc_name = strdup (lc_name);
8051ab64890Smrg
8061ab64890Smrg    return dir_name;
8071ab64890Smrg}
808