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