1
/* gettext.c - gettext module */
3
* GRUB -- GRand Unified Bootloader
4
* Copyright (C) 2009 Free Software Foundation, Inc.
6
* GRUB is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
11
* GRUB is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20
#include <grub/list.h>
21
#include <grub/types.h>
22
#include <grub/misc.h>
26
#include <grub/normal.h>
27
#include <grub/file.h>
28
#include <grub/kernel.h>
29
#include <grub/i18n.h>
32
.mo file information from:
33
http://www.gnu.org/software/autoconf/manual/gettext/MO-Files.html .
37
static grub_file_t fd_mo;
39
static int grub_gettext_offsetoriginal;
40
static int grub_gettext_max;
42
static const char *(*grub_gettext_original) (const char *s);
44
struct grub_gettext_msg
46
struct grub_gettext_msg *next;
49
const char *translated;
52
struct grub_gettext_msg *grub_gettext_msg_list = NULL;
54
#define GETTEXT_MAGIC_NUMBER 0
55
#define GETTEXT_FILE_FORMAT 4
56
#define GETTEXT_NUMBER_OF_STRINGS 8
57
#define GETTEXT_OFFSET_ORIGINAL 12
58
#define GETTEXT_OFFSET_TRANSLATION 16
60
#define MO_MAGIC_NUMBER 0x950412de
63
grub_gettext_pread (grub_file_t file, void *buf, grub_size_t len,
66
if (grub_file_seek (file, offset) == (grub_off_t) - 1)
70
return grub_file_read (file, buf, len);
74
grub_gettext_get_info (int offset)
78
grub_gettext_pread (fd_mo, (char *) &value, 4, offset);
80
value = grub_cpu_to_le32 (value);
85
grub_gettext_getstring_from_offset (grub_uint32_t offset,
86
grub_uint32_t length, char *translation)
88
grub_gettext_pread (fd_mo, translation, length, offset);
89
translation[length] = '\0';
93
grub_gettext_gettranslation_from_position (int position)
95
int offsettranslation;
96
int internal_position;
97
grub_uint32_t length, offset;
100
offsettranslation = grub_gettext_get_info (GETTEXT_OFFSET_TRANSLATION);
102
internal_position = offsettranslation + position * 8;
104
grub_gettext_pread (fd_mo, (char *) &length, 4, internal_position);
105
length = grub_cpu_to_le32 (length);
107
grub_gettext_pread (fd_mo, (char *) &offset, 4, internal_position + 4);
108
offset = grub_cpu_to_le32 (offset);
110
translation = grub_malloc (length + 1);
111
grub_gettext_getstring_from_offset (offset, length, translation);
117
grub_gettext_getstring_from_position (int position)
119
int internal_position;
123
/* Get position for string i. */
124
internal_position = grub_gettext_offsetoriginal + (position * 8);
126
/* Get the length of the string i. */
127
grub_gettext_pread (fd_mo, (char *) &length, 4, internal_position);
129
/* Get the offset of the string i. */
130
grub_gettext_pread (fd_mo, (char *) &offset, 4, internal_position + 4);
132
/* Get the string i. */
133
original = grub_malloc (length + 1);
134
grub_gettext_getstring_from_offset (offset, length, original);
140
grub_gettext_translate (const char *orig)
142
char *current_string;
145
int min, max, current;
148
struct grub_gettext_msg *cur;
150
/* Make sure we can use grub_gettext_translate for error messages. Push
151
active error message to error stack and reset error message. */
154
cur = grub_named_list_find (GRUB_AS_NAMED_LIST (grub_gettext_msg_list),
160
return cur->translated;
170
max = grub_gettext_max;
172
current = (max + min) / 2;
174
while (current != min && current != max && found == 0)
176
current_string = grub_gettext_getstring_from_position (current);
178
/* Search by bisection. */
179
if (grub_strcmp (current_string, orig) < 0)
181
grub_free (current_string);
184
else if (grub_strcmp (current_string, orig) > 0)
186
grub_free (current_string);
189
else if (grub_strcmp (current_string, orig) == 0)
191
grub_free (current_string);
194
current = (max + min) / 2;
197
ret = found ? grub_gettext_gettranslation_from_position (current) : orig;
201
cur = grub_zalloc (sizeof (*cur));
205
cur->name = grub_strdup (orig);
208
cur->translated = ret;
209
grub_list_push (GRUB_AS_LIST_P (&grub_gettext_msg_list),
214
grub_errno = GRUB_ERR_NONE;
221
/* This is similar to grub_file_open. */
223
grub_mofile_open (const char *filename)
228
/* Using fd_mo and not another variable because
229
it's needed for grub_gettext_get_info. */
231
fd_mo = grub_file_open (filename);
232
grub_errno = GRUB_ERR_NONE;
236
grub_dprintf ("gettext", "Cannot read %s\n", filename);
240
magic = grub_gettext_get_info (GETTEXT_MAGIC_NUMBER);
242
if (magic != MO_MAGIC_NUMBER)
244
grub_error (GRUB_ERR_BAD_FILE_TYPE, "mo: invalid mo file: %s",
246
grub_file_close (fd_mo);
251
version = grub_gettext_get_info (GETTEXT_FILE_FORMAT);
255
grub_error (GRUB_ERR_BAD_FILE_TYPE,
256
"mo: invalid mo version in file: %s", filename);
265
grub_gettext_init_ext (const char *lang)
270
locale_dir = grub_env_get ("locale_dir");
271
if (locale_dir == NULL)
273
grub_dprintf ("gettext", "locale_dir variable is not set up.\n");
279
/* mo_file e.g.: /boot/grub/locale/ca.mo */
281
mo_file = grub_xasprintf ("%s/%s.mo", locale_dir, lang);
285
fd_mo = grub_mofile_open (mo_file);
287
/* Will try adding .gz as well. */
291
mo_file_old = mo_file;
292
mo_file = grub_xasprintf ("%s.gz", mo_file);
293
grub_free (mo_file_old);
296
fd_mo = grub_mofile_open (mo_file);
301
grub_gettext_offsetoriginal =
302
grub_gettext_get_info (GETTEXT_OFFSET_ORIGINAL);
303
grub_gettext_max = grub_gettext_get_info (GETTEXT_NUMBER_OF_STRINGS);
305
grub_gettext_original = grub_gettext;
306
grub_gettext = grub_gettext_translate;
311
grub_gettext_delete_list (void)
313
while (grub_gettext_msg_list)
315
grub_free ((char *) grub_gettext_msg_list->name);
316
grub_gettext_msg_list = grub_gettext_msg_list->next;
317
/* Don't delete the translated message because could be in use. */
322
grub_gettext_env_write_lang (struct grub_env_var *var
323
__attribute__ ((unused)), const char *val)
325
grub_gettext_init_ext (val);
327
grub_gettext_delete_list ();
329
return grub_strdup (val);
333
grub_cmd_translate (grub_command_t cmd __attribute__ ((unused)),
334
int argc, char **args)
337
return grub_error (GRUB_ERR_BAD_ARGUMENT, "text to translate required");
339
const char *translation;
340
translation = grub_gettext_translate (args[0]);
341
grub_printf ("%s\n", translation);
345
GRUB_MOD_INIT (gettext)
347
(void) mod; /* To stop warning. */
351
lang = grub_env_get ("lang");
353
grub_gettext_init_ext (lang);
355
grub_register_command_p1 ("gettext", grub_cmd_translate,
357
N_("Translates the string with the current settings."));
359
/* Reload .mo file information if lang changes. */
360
grub_register_variable_hook ("lang", NULL, grub_gettext_env_write_lang);
362
/* Preserve hooks after context changes. */
363
grub_env_export ("lang");
366
GRUB_MOD_FINI (gettext)
369
grub_file_close (fd_mo);
371
grub_gettext_delete_list ();
373
grub_gettext = grub_gettext_original;