Bug Summary

File:src/xlibi18n/lcFile.c
Location:line 529, column 6
Description:Null pointer passed as an argument to a 'nonnull' parameter

Annotated Source Code

1/*
2 *
3 * Copyright IBM Corporation 1993
4 *
5 * All Rights Reserved
6 *
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.
14 *
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
22 * SOFTWARE.
23 *
24*/
25
26#ifdef HAVE_CONFIG_H1
27#include <config.h>
28#endif
29#include <stdlib.h>
30#include <stdio.h>
31#include <ctype.h>
32#include "Xlibint.h"
33#include "XlcPubI.h"
34#include <X11/Xos.h>
35#include <unistd.h>
36
37/************************************************************************/
38
39#ifndef HAVE_SETEUID1
40# define seteuid setuid
41#endif
42#define iscomment(ch)((ch) == '#' || (ch) == '\0') ((ch) == '#' || (ch) == '\0')
43#if defined(WIN32)
44#define isreadable(f)((access((f), 4) != -1) ? 1 : 0) (_XAccessFile(f))
45#else
46#define isreadable(f)((access((f), 4) != -1) ? 1 : 0) ((access((f), R_OK4) != -1) ? 1 : 0)
47#endif
48
49#ifndef __UNIXOS2__
50#define LC_PATHDELIM':' ':'
51#else
52#define LC_PATHDELIM':' ';'
53#endif
54
55#define XLC_BUFSIZE256 256
56
57#ifndef X_NOT_POSIX
58#ifdef _POSIX_SOURCE1
59#include <limits.h>
60#else
61#define _POSIX_SOURCE1
62#include <limits.h>
63#undef _POSIX_SOURCE1
64#endif
65#endif
66#ifndef PATH_MAX4096
67#ifdef WIN32
68#define PATH_MAX4096 512
69#else
70#include <sys/param.h>
71#endif
72#ifndef PATH_MAX4096
73#ifdef MAXPATHLEN
74#define PATH_MAX4096 MAXPATHLEN
75#else
76#define PATH_MAX4096 1024
77#endif
78#endif
79#endif
80
81#define NUM_LOCALEDIR64 64
82
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
87 modified. */
88static int
89parse_line(
90 char *line,
91 char **argv,
92 int argsize)
93{
94 int argc = 0;
95 char *p = line;
96
97 while (argc < argsize) {
98 while (isspace(*p)((*__ctype_b_loc ())[(int) ((*p))] & (unsigned short int)
_ISspace)
) {
99 ++p;
100 }
101 if (*p == '\0') {
102 break;
103 }
104 argv[argc++] = p;
105 while (*p != ':' && *p != '\n' && *p != '\0') {
106 ++p;
107 }
108 if (*p == '\0') {
109 break;
110 }
111 *p++ = '\0';
112 }
113
114 return argc;
115}
116
117#ifdef __UNIXOS2__
118
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 */
121
122static int
123parse_line1(
124 char *line,
125 char **argv,
126 int argsize)
127{
128 int argc = 0;
129 char *p = line;
130
131 while (argc < argsize) {
132 while (isspace(*p)((*__ctype_b_loc ())[(int) ((*p))] & (unsigned short int)
_ISspace)
) {
133 ++p;
134 }
135 if (*p == '\0') {
136 break;
137 }
138 argv[argc++] = p;
139 while (*p != ';' && *p != '\n' && *p != '\0') {
140 ++p;
141 }
142 if (*p == '\0') {
143 break;
144 }
145 *p++ = '\0';
146 }
147
148 return argc;
149}
150#elif defined(WIN32)
151
152/* this is parse_line but skips drive letters at the beginning of the entry */
153static int
154parse_line1(
155 char *line,
156 char **argv,
157 int argsize)
158{
159 int argc = 0;
160 char *p = line;
161
162 while (argc < argsize) {
163 while (isspace(*p)((*__ctype_b_loc ())[(int) ((*p))] & (unsigned short int)
_ISspace)
) {
164 ++p;
165 }
166 if (*p == '\0') {
167 break;
168 }
169 argv[argc++] = p;
170 if (isalpha(*p)((*__ctype_b_loc ())[(int) ((*p))] & (unsigned short int)
_ISalpha)
&& p[1] == ':') {
171 p+= 2; /* skip drive letters */
172 }
173 while (*p != ':' && *p != '\n' && *p != '\0') {
174 ++p;
175 }
176 if (*p == '\0') {
177 break;
178 }
179 *p++ = '\0';
180 }
181
182 return argc;
183}
184
185#endif /* __UNIXOS2__ */
186
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. */
190static int
191_XlcParsePath(
192 char *path,
193 char **argv,
194 int argsize)
195{
196 char *p = path;
197 int n, i;
198
199#if !defined(__UNIXOS2__) && !defined(WIN32)
200 n = parse_line(path, argv, argsize);
201#else
202 n = parse_line1(path, argv, argsize);
203#endif
204 for (i = 0; i < n; ++i) {
205 int len;
206 p = argv[i];
207 len = strlen(p);
208 if (len > 0 && p[len - 1] == '/') {
209 /* eliminate trailing slash */
210 p[len - 1] = '\0';
211 }
212 }
213 return n;
214}
215
216#ifndef XLOCALEDIR"/var/tmp/jhbuild/share/X11/locale"
217#define XLOCALEDIR"/var/tmp/jhbuild/share/X11/locale" "/usr/lib/X11/locale"
218#endif
219
220void
221xlocaledir(
222 char *buf,
223 int buf_len)
224{
225 char *p = buf;
226 int len = 0;
227
228#ifndef NO_XLOCALEDIR
229 char *dir;
230 int priv = 1;
231
232 dir = getenv("XLOCALEDIR");
233
234 if (dir) {
235#ifndef WIN32
236 /*
237 * Only use the user-supplied path if the process isn't priviledged.
238 */
239 if (getuid() == geteuid() && getgid() == getegid()) {
240#if defined(HASSETUGID)
241 priv = issetugid();
242#elif defined(HASGETRESUID1)
243 {
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);
249 }
250#else
251 /*
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
255 * euid to 0.
256 *
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.
260 */
261 unsigned int oldeuid;
262 oldeuid = geteuid();
263 if (seteuid(0) != 0) {
264 priv = 0;
265 } else {
266 if (seteuid(oldeuid) == -1) {
267 /* XXX ouch, coudn't get back to original uid
268 what can we do ??? */
269 _exit(127);
270 }
271 priv = 1;
272 }
273#endif
274 }
275#else
276 priv = 0;
277#endif
278 if (!priv) {
279 len = strlen(dir);
280 strncpy(p, dir, buf_len);
281 if (len < buf_len) {
282 p[len++] = LC_PATHDELIM':';
283 p += len;
284 }
285 }
286 }
287#endif /* NO_XLOCALEDIR */
288
289 if (len < buf_len)
290#ifndef __UNIXOS2__
291 strncpy(p, XLOCALEDIR"/var/tmp/jhbuild/share/X11/locale", buf_len - len);
292#else
293 strncpy(p,__XOS2RedirRoot(XLOCALEDIR"/var/tmp/jhbuild/share/X11/locale"), buf_len - len);
294#endif
295 buf[buf_len-1] = '\0';
296}
297
298static void
299xlocalelibdir(
300 char *buf,
301 int buf_len)
302{
303 char *p = buf;
304 int len = 0;
305
306#ifndef NO_XLOCALEDIR
307 char *dir;
308 int priv = 1;
309
310 dir = getenv("XLOCALELIBDIR");
311
312 if (dir) {
313#ifndef WIN32
314 /*
315 * Only use the user-supplied path if the process isn't priviledged.
316 */
317 if (getuid() == geteuid() && getgid() == getegid()) {
318#if defined(HASSETUGID)
319 priv = issetugid();
320#elif defined(HASGETRESUID1)
321 {
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);
327 }
328#else
329 /*
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
333 * euid to 0.
334 *
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.
338 */
339 unsigned int oldeuid;
340 oldeuid = geteuid();
341 if (seteuid(0) != 0) {
342 priv = 0;
343 } else {
344 if (seteuid(oldeuid) == -1) {
345 /* XXX ouch, coudn't get back to original uid
346 what can we do ??? */
347 _exit(127);
348 }
349 priv = 1;
350 }
351#endif
352 }
353#else
354 priv = 0;
355#endif
356 if (!priv) {
357 len = strlen(dir);
358 strncpy(p, dir, buf_len);
359 if (len < buf_len) {
360 p[len++] = LC_PATHDELIM':';
361 p += len;
362 }
363 }
364 }
365#endif /* NO_XLOCALEDIR */
366
367 if (len < buf_len)
368#ifndef __UNIXOS2__
369 strncpy(p, XLOCALELIBDIR"/var/tmp/jhbuild/lib64/X11/locale", buf_len - len);
370#else
371 strncpy(p,__XOS2RedirRoot(XLOCALELIBDIR"/var/tmp/jhbuild/lib64/X11/locale"), buf_len - len);
372#endif
373 buf[buf_len-1] = '\0';
374}
375
376/* Mapping direction */
377typedef enum {
378 LtoR, /* Map first field to second field */
379 RtoL /* Map second field to first field */
380} MapDirection;
381
382static char *
383resolve_name(
384 const char *lc_name,
385 char *file_name,
386 MapDirection direction)
387{
388 FILE *fp;
389 char buf[XLC_BUFSIZE256], *name = NULL((void*)0);
390
391 fp = _XFopenFile (file_name, "r")fopen(file_name,"r");
392 if (fp == NULL((void*)0))
393 return NULL((void*)0);
394
395 while (fgets(buf, XLC_BUFSIZE256, fp) != NULL((void*)0)) {
396 char *p = buf;
397 int n;
398 char *args[2], *from, *to;
399#ifdef __UNIXOS2__ /* Take out CR under OS/2 */
400 int len;
401
402 len = strlen(p);
403 if (len > 1) {
404 if (*(p+len-2) == '\r' && *(p+len-1) == '\n') {
405 *(p+len-2) = '\n';
406 *(p+len-1) = '\0';
407 }
408 }
409#endif
410 while (isspace(*p)((*__ctype_b_loc ())[(int) ((*p))] & (unsigned short int)
_ISspace)
) {
411 ++p;
412 }
413 if (iscomment(*p)((*p) == '#' || (*p) == '\0')) {
414 continue;
415 }
416 n = parse_line(p, args, 2); /* get first 2 fields */
417 if (n != 2) {
418 continue;
419 }
420 if (direction == LtoR) {
421 from = args[0], to = args[1]; /* left to right */
422 } else {
423 from = args[1], to = args[0]; /* right to left */
424 }
425 if (! strcmp(from, lc_name)) {
426 name = strdup(to);
427 break;
428 }
429 }
430 fclose(fp);
431 return name;
432}
433
434#define c_tolower(ch)((ch) >= 'A' && (ch) <= 'Z' ? (ch) - 'A' + 'a' :
(ch))
((ch) >= 'A' && (ch) <= 'Z' ? (ch) - 'A' + 'a' : (ch))
435
436static char *
437lowercase(
438 char *dst,
439 const char *src)
440{
441 const char *s;
442 char *t;
443
444 for (s = src, t = dst; *s; ++s, ++t)
445 *t = c_tolower(*s)((*s) >= 'A' && (*s) <= 'Z' ? (*s) - 'A' + 'a' :
(*s))
;
446 *t = '\0';
447 return dst;
448}
449
450/*
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
454 * return NULL.
455 */
456static char *
457normalize_lcname (const char *name)
458{
459 char *p, *ret;
460 const char *tmp = name;
461
462 p = ret = Xmalloc(strlen(name) + 1)malloc(((strlen(name) + 1) == 0 ? 1 : (strlen(name) + 1)));
463 if (!p)
464 return NULL((void*)0);
465
466 if (tmp) {
467 while (*tmp && *tmp != '.' && *tmp != '@')
468 *p++ = *tmp++;
469 while (*tmp) {
470 if (*tmp != '-')
471 *p++ = c_tolower(*tmp)((*tmp) >= 'A' && (*tmp) <= 'Z' ? (*tmp) - 'A' +
'a' : (*tmp))
;
472 tmp++;
473 }
474 }
475 *p = '\0';
476
477 if (strcmp(ret, name) == 0) {
478 Xfree(ret)free((ret));
479 return NULL((void*)0);
480 }
481
482 return ret;
483}
484
485/************************************************************************/
486char *
487_XlcFileName(
488 XLCd lcd,
489 const char *category)
490{
491 char *siname;
492 char cat[XLC_BUFSIZE256], dir[XLC_BUFSIZE256];
493 int i, n;
494 char *args[NUM_LOCALEDIR64];
495 char *file_name = NULL((void*)0);
496
497 if (lcd == (XLCd)NULL((void*)0))
1
Assuming 'lcd' is not equal to null
2
Taking false branch
498 return NULL((void*)0);
499
500 siname = XLC_PUBLIC(lcd, siname)(((XLCdPublic) lcd->core)->pub.siname);
501
502 if (category)
3
Assuming 'category' is null
4
Taking false branch
503 lowercase(cat, category);
504 else
505 cat[0] = '\0';
506 xlocaledir(dir,XLC_BUFSIZE256);
507 n = _XlcParsePath(dir, args, NUM_LOCALEDIR64);
508 for (i = 0; i < n; ++i) {
5
Assuming 'i' is < 'n'
6
Loop condition is true. Entering loop body
509 char buf[PATH_MAX4096], *name;
510
511 name = NULL((void*)0);
512 if ((5 + (args[i] ? strlen (args[i]) : 0) + strlen(cat)) < PATH_MAX4096) {
7
'?' condition is false
8
Taking true branch
513 sprintf(buf, "%s/%s.dir", args[i], cat);
514 name = resolve_name(siname, buf, RtoL);
515 }
516 if (name == NULL((void*)0)) {
9
Assuming 'name' is not equal to null
10
Taking false branch
517 continue;
518 }
519 if (*name == '/') {
11
Taking false branch
520 /* supposed to be absolute path name */
521 file_name = name;
522 } else {
523 file_name = Xmalloc(2 + (args[i] ? strlen (args[i]) : 0) +malloc(((2 + (args[i] ? strlen (args[i]) : 0) + (name ? strlen
(name) : 0)) == 0 ? 1 : (2 + (args[i] ? strlen (args[i]) : 0
) + (name ? strlen (name) : 0))))
524 (name ? strlen (name) : 0))malloc(((2 + (args[i] ? strlen (args[i]) : 0) + (name ? strlen
(name) : 0)) == 0 ? 1 : (2 + (args[i] ? strlen (args[i]) : 0
) + (name ? strlen (name) : 0))))
;
525 if (file_name != NULL((void*)0))
12
Assuming 'file_name' is equal to null
13
Taking false branch
526 sprintf(file_name, "%s/%s", args[i], name);
527 Xfree(name)free((name));
528 }
529 if (isreadable(file_name)((access((file_name), 4) != -1) ? 1 : 0)) {
14
Within the expansion of the macro 'isreadable':
a
Null pointer passed as an argument to a 'nonnull' parameter
530 break;
531 }
532 Xfree(file_name)free((file_name));
533 file_name = NULL((void*)0);
534 /* Then, try with next dir */
535 }
536 return file_name;
537}
538
539/************************************************************************/
540#ifndef LOCALE_ALIAS"locale.alias"
541#define LOCALE_ALIAS"locale.alias" "locale.alias"
542#endif
543
544int
545_XlcResolveLocaleName(
546 const char* lc_name,
547 XLCdPublicPart* pub)
548{
549 char dir[PATH_MAX4096], buf[PATH_MAX4096], *name = NULL((void*)0);
550 char *dst;
551 int i, n, sinamelen;
552 char *args[NUM_LOCALEDIR64];
553 static const char locale_alias[] = LOCALE_ALIAS"locale.alias";
554 char *tmp_siname;
555 char *nlc_name = NULL((void*)0);
556
557 xlocaledir (dir, PATH_MAX4096);
558 n = _XlcParsePath(dir, args, NUM_LOCALEDIR64);
559 for (i = 0; i < n; ++i) {
560 if ((2 + (args[i] ? strlen (args[i]) : 0) +
561 strlen (locale_alias)) < PATH_MAX4096) {
562 sprintf (buf, "%s/%s", args[i], locale_alias);
563 name = resolve_name (lc_name, buf, LtoR);
564 if (!name) {
565 if (!nlc_name)
566 nlc_name = normalize_lcname(lc_name);
567 if (nlc_name)
568 name = resolve_name (nlc_name, buf, LtoR);
569 }
570 }
571 if (name != NULL((void*)0)) {
572 break;
573 }
574 }
575 if (nlc_name) Xfree(nlc_name)free((nlc_name));
576
577 if (name == NULL((void*)0)) {
578 /* vendor locale name == Xlocale name, no expansion of alias */
579 pub->siname = strdup (lc_name);
580 } else {
581 pub->siname = name;
582 }
583
584 sinamelen = strlen (pub->siname);
585 if (sinamelen == 1 && pub->siname[0] == 'C') {
586 pub->language = pub->siname;
587 pub->territory = pub->codeset = NULL((void*)0);
588 return 1;
589 }
590
591 /*
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.
595 */
596 tmp_siname = Xrealloc (pub->siname, 2 * (sinamelen + 1))realloc((pub->siname), ((2 * (sinamelen + 1)) == 0 ? 1 : (
2 * (sinamelen + 1))))
;
597 if (tmp_siname == NULL((void*)0)) {
598 return 0;
599 }
600 pub->siname = tmp_siname;
601
602 /* language */
603 dst = &pub->siname[sinamelen + 1];
604 strcpy (dst, pub->siname);
605 pub->language = dst;
606
607 /* territory */
608 dst = strchr (dst, '_');
609 if (dst) {
610 *dst = '\0';
611 pub->territory = ++dst;
612 } else
613 dst = &pub->siname[sinamelen + 1];
614
615 /* codeset */
616 dst = strchr (dst, '.');
617 if (dst) {
618 *dst = '\0';
619 pub->codeset = ++dst;
620 }
621
622 return (pub->siname[0] != '\0') ? 1 : 0;
623}
624
625/************************************************************************/
626int
627_XlcResolveI18NPath(char *buf, int buf_len)
628{
629 if (buf != NULL((void*)0)) {
630 xlocaledir(buf, buf_len);
631 }
632 return 1;
633}
634
635char *
636_XlcLocaleDirName(char *dir_name, size_t dir_len, char *lc_name)
637{
638 char dir[PATH_MAX4096], buf[PATH_MAX4096], *name = NULL((void*)0);
639 int i, n;
640 char *args[NUM_LOCALEDIR64];
641 static char locale_alias[] = LOCALE_ALIAS"locale.alias";
642 char *target_name = (char*)0;
643 char *target_dir = (char*)0;
644 char *nlc_name = NULL((void*)0);
645 static char* last_dir_name = 0;
646 static size_t last_dir_len = 0;
647 static char* last_lc_name = 0;
648
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);
652 return dir_name;
653 }
654
655 xlocaledir (dir, PATH_MAX4096);
656 n = _XlcParsePath(dir, args, 256);
657 for (i = 0; i < n; ++i) {
658
659 if ((2 + (args[i] ? strlen(args[i]) : 0) +
660 strlen(locale_alias)) < PATH_MAX4096) {
661 sprintf (buf, "%s/%s", args[i], locale_alias);
662 name = resolve_name(lc_name, buf, LtoR);
663 if (!name) {
664 if (!nlc_name)
665 nlc_name = normalize_lcname(lc_name);
666 if (nlc_name)
667 name = resolve_name (nlc_name, buf, LtoR);
668 }
669 }
670
671 /* If name is not an alias, use lc_name for locale.dir search */
672 if (name == NULL((void*)0))
673 name = lc_name;
674
675 /* look at locale.dir */
676
677 target_dir = args[i];
678 if (!target_dir) {
679 /* something wrong */
680 if (name != lc_name)
681 Xfree(name)free((name));
682 continue;
683 }
684 if ((1 + strlen (target_dir) + strlen("locale.dir")) < PATH_MAX4096) {
685 sprintf(buf, "%s/locale.dir", target_dir);
686 target_name = resolve_name(name, buf, RtoL);
687 }
688 if (name != lc_name)
689 Xfree(name)free((name));
690 if (target_name != NULL((void*)0)) {
691 char *p = 0;
692 if ((p = strstr(target_name, "/XLC_LOCALE"))) {
693 *p = '\0';
694 break;
695 }
696 Xfree(target_name)free((target_name));
697 target_name = NULL((void*)0);
698 }
699 name = NULL((void*)0);
700 }
701 if (nlc_name) Xfree(nlc_name)free((nlc_name));
702
703 if (target_name == NULL((void*)0)) {
704 /* vendor locale name == Xlocale name, no expansion of alias */
705 target_dir = args[0];
706 target_name = lc_name;
707 }
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';
712 } else {
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';
717 }
718 if (target_name != lc_name)
719 Xfree(target_name)free((target_name));
720
721 if (last_dir_name != 0)
722 Xfree (last_dir_name)free((last_dir_name));
723 if (last_lc_name != 0)
724 Xfree (last_lc_name)free((last_lc_name));
725 last_dir_len = strlen (dir_name) + 1;
726 last_dir_name = Xmalloc (last_dir_len)malloc(((last_dir_len) == 0 ? 1 : (last_dir_len)));
727 strcpy (last_dir_name, dir_name);
728 last_lc_name = strdup (lc_name);
729
730 return dir_name;
731}
732
733char *
734_XlcLocaleLibDirName(char *dir_name, size_t dir_len, char *lc_name)
735{
736 char dir[PATH_MAX4096], buf[PATH_MAX4096], *name = NULL((void*)0);
737 int i, n;
738 char *args[NUM_LOCALEDIR64];
739 static char locale_alias[] = LOCALE_ALIAS"locale.alias";
740 char *target_name = (char*)0;
741 char *target_dir = (char*)0;
742 char *nlc_name = NULL((void*)0);
743 static char* last_dir_name = 0;
744 static size_t last_dir_len = 0;
745 static char* last_lc_name = 0;
746
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);
750 return dir_name;
751 }
752
753 xlocalelibdir (dir, PATH_MAX4096);
754 n = _XlcParsePath(dir, args, 256);
755 for (i = 0; i < n; ++i) {
756
757 if ((2 + (args[i] ? strlen(args[i]) : 0) +
758 strlen(locale_alias)) < PATH_MAX4096) {
759 sprintf (buf, "%s/%s", args[i], locale_alias);
760 name = resolve_name(lc_name, buf, LtoR);
761 if (!name) {
762 if (!nlc_name)
763 nlc_name = normalize_lcname(lc_name);
764 if (nlc_name)
765 name = resolve_name (nlc_name, buf, LtoR);
766 }
767 }
768
769 /* If name is not an alias, use lc_name for locale.dir search */
770 if (name == NULL((void*)0))
771 name = lc_name;
772
773 /* look at locale.dir */
774
775 target_dir = args[i];
776 if (!target_dir) {
777 /* something wrong */
778 if (name != lc_name)
779 Xfree(name)free((name));
780 continue;
781 }
782 if ((1 + strlen (target_dir) + strlen("locale.dir")) < PATH_MAX4096) {
783 sprintf(buf, "%s/locale.dir", target_dir);
784 target_name = resolve_name(name, buf, RtoL);
785 }
786 if (name != lc_name)
787 Xfree(name)free((name));
788 if (target_name != NULL((void*)0)) {
789 char *p = 0;
790 if ((p = strstr(target_name, "/XLC_LOCALE"))) {
791 *p = '\0';
792 break;
793 }
794 Xfree(target_name)free((target_name));
795 target_name = NULL((void*)0);
796 }
797 name = NULL((void*)0);
798 }
799 if (nlc_name) Xfree(nlc_name)free((nlc_name));
800
801 if (target_name == NULL((void*)0)) {
802 /* vendor locale name == Xlocale name, no expansion of alias */
803 target_dir = args[0];
804 target_name = lc_name;
805 }
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';
810 } else {
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';
815 }
816 if (target_name != lc_name)
817 Xfree(target_name)free((target_name));
818
819 if (last_dir_name != 0)
820 Xfree (last_dir_name)free((last_dir_name));
821 if (last_lc_name != 0)
822 Xfree (last_lc_name)free((last_lc_name));
823 last_dir_len = strlen (dir_name) + 1;
824 last_dir_name = Xmalloc (last_dir_len)malloc(((last_dir_len) == 0 ? 1 : (last_dir_len)));
825 strcpy (last_dir_name, dir_name);
826 last_lc_name = strdup (lc_name);
827
828 return dir_name;
829}