50{
51 DIR *localedir;
52 struct dirent *dent;
54 struct timeval tv;
55 const char *orig_locale;
56 char origlocalformat[200] = "", localformat[200] = "";
57 struct test_locales {
59 char *localformat;
63 int varies = 0, all_successful = 1, count = 0, count_fail = 0;
64
65 switch (cmd) {
69 "Usage: test locale\n"
70 " Test thread safety of locale functions.\n";
74 }
75
76 if (
a->argc != e->
args) {
78 }
79
80
81 if (!(localedir = opendir(
82#
if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(
__APPLE__)
83 "/usr/share/locale"
84#else
85 "/usr/lib/locale"
86#endif
87 ))) {
88 ast_cli(
a->fd,
"No locales seem to exist on this platform.\n");
90 }
91
94 orig_locale = setlocale(LC_ALL,
NULL);
96
97
98 ast_strftime(origlocalformat,
sizeof(origlocalformat),
"%c", &atm);
99
100 while ((dent = readdir(localedir))) {
101 size_t locallen;
102 size_t namelen;
103
104 if (dent->d_name[0] == '.') {
105 continue;
106 }
107
108 setlocale(LC_ALL, dent->d_name);
109 ast_strftime(localformat,
sizeof(localformat),
"%c", &atm);
110
111 locallen = strlen(localformat) + 1;
112 namelen = strlen(dent->d_name) + 1;
113
114
115 if (!(tl =
ast_calloc(1,
sizeof(*tl) + locallen + namelen))) {
116 continue;
117 }
118
120 tl->localformat = tl->name + namelen;
122
124
125
126 if (!varies && strcmp(
AST_LIST_FIRST(&locales)->localformat, localformat)) {
127 varies = 1;
128 }
129 }
130
131 setlocale(LC_ALL, orig_locale);
132
133 closedir(localedir);
134
135 if (!varies) {
136 if (!strcmp(origlocalformat, localformat)) {
137 ast_cli(
a->fd,
"WARNING: the locales on your system don't differ. Install more locales if you want this test to mean something.\n");
138 }
139 }
140
142
145 ast_strftime(localformat,
sizeof(localformat),
"%c", &atm);
146 if (strcmp(localformat, tl->localformat)) {
147 ast_cli(
a->fd,
"WARNING: locale test fails for locale %s\n", tl->
name);
148 all_successful = 0;
149 count_fail++;
150 }
152 count++;
153 }
154
156
157 if (all_successful) {
158 ast_cli(
a->fd,
"All %d locale tests successful\n", count);
159 } else if (count_fail == count && count > 0) {
160 ast_cli(
a->fd,
"No locale tests successful out of %d tries\n", count);
161 } else if (count > 0) {
162 ast_cli(
a->fd,
"Partial failure (%d/%d) for a %.0f%% failure rate\n", count_fail, count, count_fail * 100.0 / count);
163 } else {
164 ast_cli(
a->fd,
"No locales tested. Install more locales.\n");
165 }
166
168}
#define ast_calloc(num, len)
A wrapper for calloc()
void ast_cli(int fd, const char *fmt,...)
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
#define AST_LIST_HEAD_SET_NOLOCK(head, entry)
Initializes a list head structure with a specified first entry.
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
const char * ast_setlocale(const char *locale)
Set the thread-local representation of the current locale.
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
int args
This gets set in ast_cli_register()
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().