1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
/*
* Nasty preload hack to allow message catalogs to be read from the "po"
* subdir of the build tree.
*
* export LD_PRELOAD="hacklocaledir.so preloadable_libintl.so"
* export TEXTDOMAIN=program
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <dlfcn.h>
#define PRELOAD "hacklocaledir.so"
static void *xmalloc(size_t len)
{
void *r = malloc(len);
if (!r)
{
fprintf(stderr, PRELOAD ": can't malloc %d bytes (%s)\n", len,
strerror(errno));
exit(1);
}
return r;
}
int __open(char const *path, int flags, mode_t mode)
{
static int (*open)(char const *, int, mode_t) = 0;
static char const *textdomain = 0;
static char const *localedir = 0;
static size_t localedirlen;
static char *match = 0;
static size_t matchlen;
char *newpath = 0;
int r;
if (!open && !(open = dlsym(RTLD_NEXT, "open")))
{
fprintf(stderr, PRELOAD ": can't find open(): %s\n", dlerror());
return -1;
}
if (textdomain || (textdomain = getenv("TEXTDOMAIN")))
{
size_t pathlen = strlen(path);
char const *check;
if (!localedir)
{
if (!(localedir = getenv("LOCALEDIR")))
localedir = "po";
localedirlen = strlen(localedir);
}
if (!match)
{
matchlen = sizeof("/LC_MESSAGES/")-1 + strlen(textdomain)
+ sizeof(".mo")-1;
match = xmalloc(matchlen + 1);
strcpy(match, "/LC_MESSAGES/");
strcat(match, textdomain);
strcat(match, ".mo");
}
if (*path == '/' && pathlen > matchlen &&
!strcmp(check = (path + pathlen - matchlen), match))
{
char const *p = path;
char const *locale = 0;
do {
locale = p + 1;
p = strchr(locale, '/');
} while (p && p < check);
if (locale)
{
size_t len = strcspn(locale, "/");
newpath = xmalloc(localedirlen + 1 + len + sizeof(".gmo"));
strcpy(newpath, localedir);
strcat(newpath, "/");
strncat(newpath, locale, len);
strcat(newpath, ".gmo");
if (access(newpath, R_OK))
{
free(newpath);
newpath = 0;
}
}
}
}
r = (*open)(newpath ? newpath : path, flags, mode);
if (newpath)
{
fprintf(stderr, "note: mapped %s to %s\n", path, newpath);
free(newpath);
}
return r;
}
int open(char const *path, int flags, mode_t mode)
__attribute__((weak, alias("__open")));
|