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