35
34
http://www.gnu.org/software/autoconf/manual/gettext/MO-Files.html .
39
static grub_file_t fd_mo;
41
static int grub_gettext_offsetoriginal;
42
static int grub_gettext_max;
37
static struct grub_gettext_context main_context, secondary_context;
44
39
static const char *(*grub_gettext_original) (const char *s);
46
41
struct grub_gettext_msg
48
struct grub_gettext_msg *next;
51
const char *translated;
54
static struct grub_gettext_msg *grub_gettext_msg_list = NULL;
56
#define GETTEXT_MAGIC_NUMBER 0
57
#define GETTEXT_FILE_FORMAT 4
58
#define GETTEXT_NUMBER_OF_STRINGS 8
59
#define GETTEXT_OFFSET_ORIGINAL 12
60
#define GETTEXT_OFFSET_TRANSLATION 16
50
grub_uint32_t version;
51
grub_uint32_t number_of_strings;
52
grub_uint32_t offset_original;
53
grub_uint32_t offset_translation;
56
struct string_descriptor
62
struct grub_gettext_context
65
grub_off_t grub_gettext_offset_original;
66
grub_off_t grub_gettext_offset_translation;
67
grub_size_t grub_gettext_max;
68
int grub_gettext_max_log;
69
struct grub_gettext_msg *grub_gettext_msg_list;
62
72
#define MO_MAGIC_NUMBER 0x950412de
65
75
grub_gettext_pread (grub_file_t file, void *buf, grub_size_t len,
68
80
if (grub_file_seek (file, offset) == (grub_off_t) - 1)
82
if (grub_file_read (file, buf, len) != (grub_ssize_t) len)
85
grub_error (GRUB_ERR_READ_ERROR, N_("premature end of file"));
72
return grub_file_read (file, buf, len);
76
grub_gettext_get_info (int offset)
80
grub_gettext_pread (fd_mo, (char *) &value, 4, offset);
82
value = grub_cpu_to_le32 (value);
87
grub_gettext_getstring_from_offset (grub_uint32_t offset,
88
grub_uint32_t length, char *translation)
90
grub_gettext_pread (fd_mo, translation, length, offset);
91
translation[length] = '\0';
95
grub_gettext_gettranslation_from_position (int position)
97
int offsettranslation;
98
int internal_position;
99
grub_uint32_t length, offset;
92
grub_gettext_getstr_from_position (struct grub_gettext_context *ctx,
96
grub_off_t internal_position;
100
99
char *translation;
102
offsettranslation = grub_gettext_get_info (GETTEXT_OFFSET_TRANSLATION);
104
internal_position = offsettranslation + position * 8;
106
grub_gettext_pread (fd_mo, (char *) &length, 4, internal_position);
107
length = grub_cpu_to_le32 (length);
109
grub_gettext_pread (fd_mo, (char *) &offset, 4, internal_position + 4);
110
offset = grub_cpu_to_le32 (offset);
100
struct string_descriptor desc;
103
internal_position = (off + position * sizeof (desc));
105
err = grub_gettext_pread (ctx->fd_mo, (char *) &desc,
106
sizeof (desc), internal_position);
109
length = grub_cpu_to_le32 (desc.length);
110
offset = grub_cpu_to_le32 (desc.offset);
112
112
translation = grub_malloc (length + 1);
113
grub_gettext_getstring_from_offset (offset, length, translation);
116
err = grub_gettext_pread (ctx->fd_mo, translation, length, offset);
119
grub_free (translation);
122
translation[length] = '\0';
115
124
return translation;
119
grub_gettext_getstring_from_position (int position)
121
int internal_position;
125
/* Get position for string i. */
126
internal_position = grub_gettext_offsetoriginal + (position * 8);
128
/* Get the length of the string i. */
129
grub_gettext_pread (fd_mo, (char *) &length, 4, internal_position);
131
/* Get the offset of the string i. */
132
grub_gettext_pread (fd_mo, (char *) &offset, 4, internal_position + 4);
134
/* Get the string i. */
135
original = grub_malloc (length + 1);
136
grub_gettext_getstring_from_offset (offset, length, original);
142
grub_gettext_translate (const char *orig)
144
char *current_string;
147
int min, max, current;
150
struct grub_gettext_msg *cur;
128
grub_gettext_gettranslation_from_position (struct grub_gettext_context *ctx,
129
grub_size_t position)
131
if (!ctx->grub_gettext_msg_list[position].translated)
132
ctx->grub_gettext_msg_list[position].translated
133
= grub_gettext_getstr_from_position (ctx,
134
ctx->grub_gettext_offset_translation,
136
return ctx->grub_gettext_msg_list[position].translated;
140
grub_gettext_getstring_from_position (struct grub_gettext_context *ctx,
141
grub_size_t position)
143
if (!ctx->grub_gettext_msg_list[position].name)
144
ctx->grub_gettext_msg_list[position].name
145
= grub_gettext_getstr_from_position (ctx,
146
ctx->grub_gettext_offset_original,
148
return ctx->grub_gettext_msg_list[position].name;
152
grub_gettext_translate_real (struct grub_gettext_context *ctx,
155
grub_size_t current = 0;
157
const char *current_string;
158
static int depth = 0;
160
if (!ctx->grub_gettext_msg_list || !ctx->fd_mo)
163
/* Shouldn't happen. Just a precaution if our own code
164
calls gettext somehow. */
152
169
/* Make sure we can use grub_gettext_translate for error messages. Push
153
170
active error message to error stack and reset error message. */
154
171
grub_error_push ();
156
cur = grub_named_list_find (GRUB_AS_NAMED_LIST (grub_gettext_msg_list),
162
return cur->translated;
172
max = grub_gettext_max;
174
current = (max + min) / 2;
176
while (current != min && current != max && found == 0)
178
current_string = grub_gettext_getstring_from_position (current);
173
for (i = ctx->grub_gettext_max_log; i >= 0; i--)
178
test = current | (1 << i);
179
if (test >= ctx->grub_gettext_max)
182
current_string = grub_gettext_getstring_from_position (ctx, test);
186
grub_errno = GRUB_ERR_NONE;
180
192
/* Search by bisection. */
181
if (grub_strcmp (current_string, orig) < 0)
183
grub_free (current_string);
186
else if (grub_strcmp (current_string, orig) > 0)
188
grub_free (current_string);
191
else if (grub_strcmp (current_string, orig) == 0)
193
grub_free (current_string);
196
current = (max + min) / 2;
193
cmp = grub_strcmp (current_string, orig);
199
ret = grub_gettext_gettranslation_from_position (ctx, current);
202
grub_errno = GRUB_ERR_NONE;
199
ret = found ? grub_gettext_gettranslation_from_position (current) : orig;
213
if (current == 0 && ctx->grub_gettext_max != 0)
203
cur = grub_zalloc (sizeof (*cur));
207
cur->name = grub_strdup (orig);
215
current_string = grub_gettext_getstring_from_position (ctx, 0);
219
grub_errno = GRUB_ERR_NONE;
225
if (grub_strcmp (current_string, orig) == 0)
228
ret = grub_gettext_gettranslation_from_position (ctx, current);
210
cur->translated = ret;
211
grub_list_push (GRUB_AS_LIST_P (&grub_gettext_msg_list),
231
grub_errno = GRUB_ERR_NONE;
216
grub_errno = GRUB_ERR_NONE;
219
242
grub_error_pop ();
248
grub_gettext_translate (const char *orig)
254
ret = grub_gettext_translate_real (&main_context, orig);
257
ret = grub_gettext_translate_real (&secondary_context, orig);
264
grub_gettext_delete_list (struct grub_gettext_context *ctx)
266
struct grub_gettext_msg *l = ctx->grub_gettext_msg_list;
271
ctx->grub_gettext_msg_list = 0;
272
for (i = 0; i < ctx->grub_gettext_max; i++)
273
grub_free (l[i].name);
274
/* Don't delete the translated message because could be in use. */
277
grub_file_close (ctx->fd_mo);
279
grub_memset (ctx, 0, sizeof (*ctx));
223
282
/* This is similar to grub_file_open. */
225
grub_mofile_open (const char *filename)
284
grub_mofile_open (struct grub_gettext_context *ctx,
285
const char *filename)
230
291
/* Using fd_mo and not another variable because
231
292
it's needed for grub_gettext_get_info. */
233
fd_mo = grub_file_open (filename);
234
grub_errno = GRUB_ERR_NONE;
238
grub_dprintf ("gettext", "Cannot read %s\n", filename);
242
magic = grub_gettext_get_info (GETTEXT_MAGIC_NUMBER);
244
if (magic != MO_MAGIC_NUMBER)
246
grub_error (GRUB_ERR_BAD_FILE_TYPE, "mo: invalid mo file: %s",
248
grub_file_close (fd_mo);
253
version = grub_gettext_get_info (GETTEXT_FILE_FORMAT);
257
grub_error (GRUB_ERR_BAD_FILE_TYPE,
258
"mo: invalid mo version in file: %s", filename);
294
fd = grub_file_open (filename);
299
err = grub_gettext_pread (fd, &head, sizeof (head), 0);
302
grub_file_close (fd);
306
if (head.magic != grub_cpu_to_le32_compile_time (MO_MAGIC_NUMBER))
308
grub_file_close (fd);
309
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
310
"mo: invalid mo magic in file: %s", filename);
313
if (head.version != 0)
315
grub_file_close (fd);
316
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
317
"mo: invalid mo version in file: %s", filename);
320
ctx->grub_gettext_offset_original = grub_le_to_cpu32 (head.offset_original);
321
ctx->grub_gettext_offset_translation = grub_le_to_cpu32 (head.offset_translation);
322
ctx->grub_gettext_max = grub_le_to_cpu32 (head.number_of_strings);
323
for (ctx->grub_gettext_max_log = 0; ctx->grub_gettext_max >> ctx->grub_gettext_max_log;
324
ctx->grub_gettext_max_log++);
326
ctx->grub_gettext_msg_list = grub_zalloc (ctx->grub_gettext_max
327
* sizeof (ctx->grub_gettext_msg_list[0]));
328
if (!ctx->grub_gettext_msg_list)
330
grub_file_close (fd);
334
if (grub_gettext != grub_gettext_translate)
336
grub_gettext_original = grub_gettext;
337
grub_gettext = grub_gettext_translate;
266
342
/* Returning grub_file_t would be more natural, but grub_mofile_open assigns
267
343
to fd_mo anyway ... */
269
grub_mofile_open_lang (const char *locale_dir, const char *locale)
345
grub_mofile_open_lang (struct grub_gettext_context *ctx,
346
const char *part1, const char *part2, const char *locale)
273
351
/* mo_file e.g.: /boot/grub/locale/ca.mo */
275
mo_file = grub_xasprintf ("%s/%s.mo", locale_dir, locale);
353
mo_file = grub_xasprintf ("%s%s/%s.mo", part1, part2, locale);
279
fd_mo = grub_mofile_open (mo_file);
357
err = grub_mofile_open (ctx, mo_file);
281
359
/* Will try adding .gz as well. */
284
362
char *mo_file_old;
363
grub_errno = GRUB_ERR_NONE;
285
364
mo_file_old = mo_file;
286
365
mo_file = grub_xasprintf ("%s.gz", mo_file);
287
366
grub_free (mo_file_old);
290
fd_mo = grub_mofile_open (mo_file);
369
err = grub_mofile_open (ctx, mo_file);
295
grub_gettext_init_ext (const char *locale)
375
grub_gettext_init_ext (struct grub_gettext_context *ctx,
377
const char *locale_dir, const char *prefix)
299
locale_dir = grub_env_get ("locale_dir");
300
if (locale_dir == NULL)
379
const char *part1, *part2;
382
grub_gettext_delete_list (ctx);
384
if (!locale || locale[0] == 0)
389
if (!part1 || part1[0] == 0)
302
grub_dprintf ("gettext", "locale_dir variable is not set up.\n");
395
if (!part1 || part1[0] == 0)
308
grub_mofile_open_lang (locale_dir, locale);
398
err = grub_mofile_open_lang (ctx, part1, part2, locale);
310
400
/* ll_CC didn't work, so try ll. */
313
403
char *lang = grub_strdup (locale);
314
char *underscore = grub_strchr (lang, '_');
404
char *underscore = lang ? grub_strchr (lang, '_') : 0;
318
408
*underscore = '\0';
319
grub_mofile_open_lang (locale_dir, lang);
409
grub_errno = GRUB_ERR_NONE;
410
err = grub_mofile_open_lang (ctx, part1, part2, lang);
322
413
grub_free (lang);
327
grub_gettext_offsetoriginal =
328
grub_gettext_get_info (GETTEXT_OFFSET_ORIGINAL);
329
grub_gettext_max = grub_gettext_get_info (GETTEXT_NUMBER_OF_STRINGS);
331
grub_gettext_original = grub_gettext;
332
grub_gettext = grub_gettext_translate;
337
grub_gettext_delete_list (void)
339
while (grub_gettext_msg_list)
341
grub_free ((char *) grub_gettext_msg_list->name);
342
grub_gettext_msg_list = grub_gettext_msg_list->next;
343
/* Don't delete the translated message because could be in use. */
348
419
grub_gettext_env_write_lang (struct grub_env_var *var
349
420
__attribute__ ((unused)), const char *val)
351
grub_gettext_init_ext (val);
353
grub_gettext_delete_list ();
423
err = grub_gettext_init_ext (&main_context, val, grub_env_get ("locale_dir"),
424
grub_env_get ("prefix"));
428
err = grub_gettext_init_ext (&secondary_context, val,
429
grub_env_get ("secondary_locale_dir"), 0);
433
return grub_strdup (val);
437
grub_gettext_reread_prefix (const char *val)
440
err = grub_gettext_init_ext (&main_context, grub_env_get ("lang"),
441
grub_env_get ("locale_dir"),
448
read_main (struct grub_env_var *var
449
__attribute__ ((unused)), const char *val)
452
err = grub_gettext_init_ext (&main_context, grub_env_get ("lang"), val,
453
grub_env_get ("prefix"));
456
return grub_strdup (val);
460
read_secondary (struct grub_env_var *var
461
__attribute__ ((unused)), const char *val)
464
err = grub_gettext_init_ext (&secondary_context, grub_env_get ("lang"), val,
355
469
return grub_strdup (val);