3 * Copyright IBM Corporation 1993
7 * License to use, copy, modify, and distribute this software and its
8 * documentation for any purpose and without fee is hereby granted,
9 * provided that the above copyright notice appear in all copies and that
10 * both that copyright notice and this permission notice appear in
11 * supporting documentation, and that the name of IBM not be
12 * used in advertising or publicity pertaining to distribution of the
13 * software without specific, written prior permission.
15 * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
16 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS, AND
17 * NONINFRINGEMENT OF THIRD PARTY RIGHTS, IN NO EVENT SHALL
18 * IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
19 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
37 /************************************************************************/
40 # define seteuid setuid
42 #define iscomment(ch) ((ch) == '#' || (ch) == '\0')
44 #define isreadable(f) (_XAccessFile(f))
46 #define isreadable(f) ((access((f), R_OK) != -1) ? 1 : 0)
50 #define LC_PATHDELIM ':'
52 #define LC_PATHDELIM ';'
55 #define XLC_BUFSIZE 256
70 #include <sys/param.h>
74 #define PATH_MAX MAXPATHLEN
81 #define NUM_LOCALEDIR 64
83 /* Splits a NUL terminated line into constituents, at colons and newline
84 characters. Leading whitespace is removed from constituents. The
85 constituents are stored at argv[0..argsize-1]. The number of stored
86 constituents (<= argsize) is returned. The line is destructively
97 while (argc < argsize) {
105 while (*p != ':' && *p != '\n' && *p != '\0') {
119 /* fg021216: entries in locale files are separated by colons while under
120 OS/2, path entries are separated by semicolon, so we need two functions */
131 while (argc < argsize) {
132 while (isspace(*p)) {
139 while (*p != ';' && *p != '\n' && *p != '\0') {
152 /* this is parse_line but skips drive letters at the beginning of the entry */
162 while (argc < argsize) {
163 while (isspace(*p)) {
170 if (isalpha(*p) && p[1] == ':') {
171 p+= 2; /* skip drive letters */
173 while (*p != ':' && *p != '\n' && *p != '\0') {
185 #endif /* __UNIXOS2__ */
187 /* Splits a colon separated list of directories, and returns the constituent
188 paths (without trailing slash). At most argsize constituents are stored
189 at argv[0..argsize-1]. The number of stored constituents is returned. */
199 #if !defined(__UNIXOS2__) && !defined(WIN32)
200 n = parse_line(path, argv, argsize);
202 n = parse_line1(path, argv, argsize);
204 for (i = 0; i < n; ++i) {
208 if (len > 0 && p[len - 1] == '/') {
209 /* eliminate trailing slash */
217 #define XLOCALEDIR "/usr/lib/X11/locale"
228 #ifndef NO_XLOCALEDIR
232 dir = getenv("XLOCALEDIR");
237 * Only use the user-supplied path if the process isn't priviledged.
239 if (getuid() == geteuid() && getgid() == getegid()) {
240 #if defined(HASSETUGID)
242 #elif defined(HASGETRESUID)
244 uid_t ruid, euid, suid;
245 gid_t rgid, egid, sgid;
246 if ((getresuid(&ruid, &euid, &suid) == 0) &&
247 (getresgid(&rgid, &egid, &sgid) == 0))
248 priv = (euid != suid) || (egid != sgid);
252 * If there are saved ID's the process might still be priviledged
253 * even though the above test succeeded. If issetugid() and
254 * getresgid() aren't available, test this by trying to set
257 * Note: this only protects setuid-root clients. It doesn't
258 * protect other setuid or any setgid clients. If this tradeoff
259 * isn't acceptable, set DisableXLocaleDirEnv to YES in host.def.
261 unsigned int oldeuid;
263 if (seteuid(0) != 0) {
266 if (seteuid(oldeuid) == -1) {
267 /* XXX ouch, coudn't get back to original uid
268 what can we do ??? */
280 strncpy(p, dir, buf_len);
282 p[len++] = LC_PATHDELIM;
287 #endif /* NO_XLOCALEDIR */
291 strncpy(p, XLOCALEDIR, buf_len - len);
293 strncpy(p,__XOS2RedirRoot(XLOCALEDIR), buf_len - len);
295 buf[buf_len-1] = '\0';
306 #ifndef NO_XLOCALEDIR
310 dir = getenv("XLOCALELIBDIR");
315 * Only use the user-supplied path if the process isn't priviledged.
317 if (getuid() == geteuid() && getgid() == getegid()) {
318 #if defined(HASSETUGID)
320 #elif defined(HASGETRESUID)
322 uid_t ruid, euid, suid;
323 gid_t rgid, egid, sgid;
324 if ((getresuid(&ruid, &euid, &suid) == 0) &&
325 (getresgid(&rgid, &egid, &sgid) == 0))
326 priv = (euid != suid) || (egid != sgid);
330 * If there are saved ID's the process might still be priviledged
331 * even though the above test succeeded. If issetugid() and
332 * getresgid() aren't available, test this by trying to set
335 * Note: this only protects setuid-root clients. It doesn't
336 * protect other setuid or any setgid clients. If this tradeoff
337 * isn't acceptable, set DisableXLocaleDirEnv to YES in host.def.
339 unsigned int oldeuid;
341 if (seteuid(0) != 0) {
344 if (seteuid(oldeuid) == -1) {
345 /* XXX ouch, coudn't get back to original uid
346 what can we do ??? */
358 strncpy(p, dir, buf_len);
360 p[len++] = LC_PATHDELIM;
365 #endif /* NO_XLOCALEDIR */
369 strncpy(p, XLOCALELIBDIR, buf_len - len);
371 strncpy(p,__XOS2RedirRoot(XLOCALELIBDIR), buf_len - len);
373 buf[buf_len-1] = '\0';
376 /* Mapping direction */
378 LtoR, /* Map first field to second field */
379 RtoL /* Map second field to first field */
386 MapDirection direction)
389 char buf[XLC_BUFSIZE], *name = NULL;
391 fp = _XFopenFile (file_name, "r");
395 while (fgets(buf, XLC_BUFSIZE, fp) != NULL) {
398 char *args[2], *from, *to;
399 #ifdef __UNIXOS2__ /* Take out CR under OS/2 */
404 if (*(p+len-2) == '\r' && *(p+len-1) == '\n') {
410 while (isspace(*p)) {
416 n = parse_line(p, args, 2); /* get first 2 fields */
420 if (direction == LtoR) {
421 from = args[0], to = args[1]; /* left to right */
423 from = args[1], to = args[0]; /* right to left */
425 if (! strcmp(from, lc_name)) {
434 #define c_tolower(ch) ((ch) >= 'A' && (ch) <= 'Z' ? (ch) - 'A' + 'a' : (ch))
444 for (s = src, t = dst; *s; ++s, ++t)
451 * normalize_lcname(): remove any '_' and '-' and convert any character
452 * to lower case after the <language>_<territory> part. If result is identical
453 * to argument, free result and
457 normalize_lcname (const char *name)
460 const char *tmp = name;
462 p = ret = Xmalloc(strlen(name) + 1);
467 while (*tmp && *tmp != '.' && *tmp != '@')
471 *p++ = c_tolower(*tmp);
477 if (strcmp(ret, name) == 0) {
485 /************************************************************************/
489 const char *category)
492 char cat[XLC_BUFSIZE], dir[XLC_BUFSIZE];
494 char *args[NUM_LOCALEDIR];
495 char *file_name = NULL;
497 if (lcd == (XLCd)NULL)
500 siname = XLC_PUBLIC(lcd, siname);
503 lowercase(cat, category);
506 xlocaledir(dir,XLC_BUFSIZE);
507 n = _XlcParsePath(dir, args, NUM_LOCALEDIR);
508 for (i = 0; i < n; ++i) {
509 char buf[PATH_MAX], *name;
512 if ((5 + (args[i] ? strlen (args[i]) : 0) + strlen(cat)) < PATH_MAX) {
513 sprintf(buf, "%s/%s.dir", args[i], cat);
514 name = resolve_name(siname, buf, RtoL);
520 /* supposed to be absolute path name */
523 file_name = Xmalloc(2 + (args[i] ? strlen (args[i]) : 0) +
524 (name ? strlen (name) : 0));
525 if (file_name != NULL)
526 sprintf(file_name, "%s/%s", args[i], name);
529 if (isreadable(file_name)) {
534 /* Then, try with next dir */
539 /************************************************************************/
541 #define LOCALE_ALIAS "locale.alias"
545 _XlcResolveLocaleName(
549 char dir[PATH_MAX], buf[PATH_MAX], *name = NULL;
552 char *args[NUM_LOCALEDIR];
553 static const char locale_alias[] = LOCALE_ALIAS;
555 char *nlc_name = NULL;
557 xlocaledir (dir, PATH_MAX);
558 n = _XlcParsePath(dir, args, NUM_LOCALEDIR);
559 for (i = 0; i < n; ++i) {
560 if ((2 + (args[i] ? strlen (args[i]) : 0) +
561 strlen (locale_alias)) < PATH_MAX) {
562 sprintf (buf, "%s/%s", args[i], locale_alias);
563 name = resolve_name (lc_name, buf, LtoR);
566 nlc_name = normalize_lcname(lc_name);
568 name = resolve_name (nlc_name, buf, LtoR);
575 if (nlc_name) Xfree(nlc_name);
578 /* vendor locale name == Xlocale name, no expansion of alias */
579 pub->siname = strdup (lc_name);
584 sinamelen = strlen (pub->siname);
585 if (sinamelen == 1 && pub->siname[0] == 'C') {
586 pub->language = pub->siname;
587 pub->territory = pub->codeset = NULL;
592 * pub->siname is in the format <lang>_<terr>.<codeset>, typical would
593 * be "en_US.ISO8859-1", "en_US.utf8", "ru_RU.KOI-8", or ja_JP.SJIS,
594 * although it could be ja.SJIS too.
596 tmp_siname = Xrealloc (pub->siname, 2 * (sinamelen + 1));
597 if (tmp_siname == NULL) {
600 pub->siname = tmp_siname;
603 dst = &pub->siname[sinamelen + 1];
604 strcpy (dst, pub->siname);
608 dst = strchr (dst, '_');
611 pub->territory = ++dst;
613 dst = &pub->siname[sinamelen + 1];
616 dst = strchr (dst, '.');
619 pub->codeset = ++dst;
622 return (pub->siname[0] != '\0') ? 1 : 0;
625 /************************************************************************/
627 _XlcResolveI18NPath(char *buf, int buf_len)
630 xlocaledir(buf, buf_len);
636 _XlcLocaleDirName(char *dir_name, size_t dir_len, char *lc_name)
638 char dir[PATH_MAX], buf[PATH_MAX], *name = NULL;
640 char *args[NUM_LOCALEDIR];
641 static char locale_alias[] = LOCALE_ALIAS;
642 char *target_name = (char*)0;
643 char *target_dir = (char*)0;
644 char *nlc_name = NULL;
645 static char* last_dir_name = 0;
646 static size_t last_dir_len = 0;
647 static char* last_lc_name = 0;
649 if (last_lc_name != 0 && strcmp (last_lc_name, lc_name) == 0
650 && dir_len >= last_dir_len) {
651 strcpy (dir_name, last_dir_name);
655 xlocaledir (dir, PATH_MAX);
656 n = _XlcParsePath(dir, args, 256);
657 for (i = 0; i < n; ++i) {
659 if ((2 + (args[i] ? strlen(args[i]) : 0) +
660 strlen(locale_alias)) < PATH_MAX) {
661 sprintf (buf, "%s/%s", args[i], locale_alias);
662 name = resolve_name(lc_name, buf, LtoR);
665 nlc_name = normalize_lcname(lc_name);
667 name = resolve_name (nlc_name, buf, LtoR);
671 /* If name is not an alias, use lc_name for locale.dir search */
675 /* look at locale.dir */
677 target_dir = args[i];
679 /* something wrong */
684 if ((1 + strlen (target_dir) + strlen("locale.dir")) < PATH_MAX) {
685 sprintf(buf, "%s/locale.dir", target_dir);
686 target_name = resolve_name(name, buf, RtoL);
690 if (target_name != NULL) {
692 if ((p = strstr(target_name, "/XLC_LOCALE"))) {
701 if (nlc_name) Xfree(nlc_name);
703 if (target_name == NULL) {
704 /* vendor locale name == Xlocale name, no expansion of alias */
705 target_dir = args[0];
706 target_name = lc_name;
708 /* snprintf(dir_name, dir_len, "%s/%", target_dir, target_name); */
709 strncpy(dir_name, target_dir, dir_len - 1);
710 if (strlen(target_dir) >= dir_len - 1) {
711 dir_name[dir_len - 1] = '\0';
713 strcat(dir_name, "/");
714 strncat(dir_name, target_name, dir_len - strlen(dir_name) - 1);
715 if (strlen(target_name) >= dir_len - strlen(dir_name) - 1)
716 dir_name[dir_len - 1] = '\0';
718 if (target_name != lc_name)
721 if (last_dir_name != 0)
722 Xfree (last_dir_name);
723 if (last_lc_name != 0)
724 Xfree (last_lc_name);
725 last_dir_len = strlen (dir_name) + 1;
726 last_dir_name = Xmalloc (last_dir_len);
727 strcpy (last_dir_name, dir_name);
728 last_lc_name = strdup (lc_name);
734 _XlcLocaleLibDirName(char *dir_name, size_t dir_len, char *lc_name)
736 char dir[PATH_MAX], buf[PATH_MAX], *name = NULL;
738 char *args[NUM_LOCALEDIR];
739 static char locale_alias[] = LOCALE_ALIAS;
740 char *target_name = (char*)0;
741 char *target_dir = (char*)0;
742 char *nlc_name = NULL;
743 static char* last_dir_name = 0;
744 static size_t last_dir_len = 0;
745 static char* last_lc_name = 0;
747 if (last_lc_name != 0 && strcmp (last_lc_name, lc_name) == 0
748 && dir_len >= last_dir_len) {
749 strcpy (dir_name, last_dir_name);
753 xlocalelibdir (dir, PATH_MAX);
754 n = _XlcParsePath(dir, args, 256);
755 for (i = 0; i < n; ++i) {
757 if ((2 + (args[i] ? strlen(args[i]) : 0) +
758 strlen(locale_alias)) < PATH_MAX) {
759 sprintf (buf, "%s/%s", args[i], locale_alias);
760 name = resolve_name(lc_name, buf, LtoR);
763 nlc_name = normalize_lcname(lc_name);
765 name = resolve_name (nlc_name, buf, LtoR);
769 /* If name is not an alias, use lc_name for locale.dir search */
773 /* look at locale.dir */
775 target_dir = args[i];
777 /* something wrong */
782 if ((1 + strlen (target_dir) + strlen("locale.dir")) < PATH_MAX) {
783 sprintf(buf, "%s/locale.dir", target_dir);
784 target_name = resolve_name(name, buf, RtoL);
788 if (target_name != NULL) {
790 if ((p = strstr(target_name, "/XLC_LOCALE"))) {
799 if (nlc_name) Xfree(nlc_name);
801 if (target_name == NULL) {
802 /* vendor locale name == Xlocale name, no expansion of alias */
803 target_dir = args[0];
804 target_name = lc_name;
806 /* snprintf(dir_name, dir_len, "%s/%", target_dir, target_name); */
807 strncpy(dir_name, target_dir, dir_len - 1);
808 if (strlen(target_dir) >= dir_len - 1) {
809 dir_name[dir_len - 1] = '\0';
811 strcat(dir_name, "/");
812 strncat(dir_name, target_name, dir_len - strlen(dir_name) - 1);
813 if (strlen(target_name) >= dir_len - strlen(dir_name) - 1)
814 dir_name[dir_len - 1] = '\0';
816 if (target_name != lc_name)
819 if (last_dir_name != 0)
820 Xfree (last_dir_name);
821 if (last_lc_name != 0)
822 Xfree (last_lc_name);
823 last_dir_len = strlen (dir_name) + 1;
824 last_dir_name = Xmalloc (last_dir_len);
825 strcpy (last_dir_name, dir_name);
826 last_lc_name = strdup (lc_name);