aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'loader/lang.c')
-rw-r--r--loader/lang.c399
1 files changed, 399 insertions, 0 deletions
diff --git a/loader/lang.c b/loader/lang.c
new file mode 100644
index 0000000..31749fc
--- /dev/null
+++ b/loader/lang.c
@@ -0,0 +1,399 @@
+/*
+ * lang.c - determines language, handles translations
+ *
+ * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Erik Troan <ewt@redhat.com>
+ * Matt Wilson <msw@redhat.com>
+ * Michael Fulbright <msf@redhat.com>
+ * Jeremy Katz <katzj@redhat.com>
+ */
+
+#include <alloca.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <newt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <wchar.h>
+
+#include "loader.h"
+#include "lang.h"
+#include "loadermisc.h"
+#include "windows.h"
+
+#include "../isys/stubs.h"
+#include "../isys/cpio.h"
+#include "../isys/lang.h"
+#include "../isys/isys.h"
+#include "../isys/log.h"
+
+/* boot flags */
+extern uint64_t flags;
+
+struct aString {
+ unsigned int hash;
+ short length;
+ char * str;
+} ;
+
+struct aString * strings = NULL;
+int numStrings = 0, allocedStrings = 0;
+
+static int english = 0;
+
+static char * topLineWelcome = N_("Welcome to %s for %s");
+static char * topLineWelcomeRescue = N_("Welcome to %s for %s - Rescue Mode");
+static char * bottomHelpLine = N_(" <Tab>/<Alt-Tab> between elements | <Space> selects | <F12> next screen ");
+
+static int aStringCmp(const void * a, const void * b) {
+ const struct aString * first = a;
+ const struct aString * second = b;
+
+ if (first->hash < second->hash)
+ return -1;
+ else if (first->hash == second->hash)
+ return 0;
+
+ return 1;
+}
+
+char * translateString(char * str) {
+ unsigned int sum = 0, xor = 0;
+ int len = 0;
+ char * chptr;
+ struct aString * match;
+ struct aString key;
+
+ for (chptr = str; *chptr; chptr++) {
+ sum += *chptr;
+ xor ^= *chptr;
+ len++;
+ }
+
+ key.hash = (sum << 16) | ((xor & 0xFF) << 8) | (len & 0xFF);
+ match = bsearch(&key, strings, numStrings, sizeof(*strings), aStringCmp);
+ if (!match)
+ return str;
+
+ return match->str;
+}
+
+static struct langInfo * languages = NULL;
+static int numLanguages = 0;
+
+static void loadLanguageList(void) {
+ char * file = "/etc/lang-table";
+ FILE * f;
+ char line[256];
+ char name[256], key[256], font[256], code[256],
+ keyboard[256], timezone[256];
+ int lineNum = 0;
+
+ wcwidth(0);
+ f = fopen(file, "r");
+ if (!f) {
+ newtWinMessage(_("Error"), _("OK"), "cannot open %s: %m", file);
+ return;
+ }
+
+ while (fgets(line, sizeof(line), f)) {
+ lineNum++;
+ languages = realloc(languages, sizeof(*languages) * (numLanguages + 1));
+ if (sscanf(line, "%[^\t]\t%[^\t]\t%[^\t]\t%[^\t]\t%[^\t]\t%[^\t]\n",
+ name, key, font, code, keyboard, timezone) != 6) {
+ printf("bad line %d in lang-table", lineNum);
+ logMessage(WARNING, "bad line %d in lang-table", lineNum);
+ } else {
+ languages[numLanguages].lang = strdup(name);
+ languages[numLanguages].key = strdup(key);
+ languages[numLanguages].font = strdup(font);
+ languages[numLanguages].lc_all = strdup(code);
+ languages[numLanguages++].keyboard = strdup(keyboard);
+ }
+ }
+ fclose(f);
+}
+
+int getLangInfo(struct langInfo ** langs) {
+ if (!languages)
+ loadLanguageList();
+
+ *langs = languages;
+ return numLanguages;
+}
+
+void loadLanguage (char * file) {
+ char filename[200];
+ gzFile stream;
+ int fd, hash, rc;
+ char * key = getenv("LANGKEY");
+
+ if (strings) {
+ free(strings), strings = NULL;
+ numStrings = allocedStrings = 0;
+ }
+
+ /* english requires no files */
+ if (!strcmp(key, "en"))
+ return;
+
+ if (!file) {
+ file = filename;
+ sprintf(filename, "/etc/loader.tr");
+ }
+
+ stream = gunzip_open(file);
+
+ if (!stream) {
+ newtWinMessage("Error", "OK", "Translation for %s is not available. "
+ "The Installation will proceed in English.", key);
+ return ;
+ }
+
+ sprintf(filename, "%s.tr", key);
+
+ rc = installCpioFile(stream, filename, "/tmp/translation", 1);
+ gunzip_close(stream);
+
+ if (rc || access("/tmp/translation", R_OK)) {
+ newtWinMessage("Error", "OK", "Cannot get translation file %s.\n",
+ filename);
+ return;
+ }
+
+ fd = open("/tmp/translation", O_RDONLY);
+ if (fd < 0) {
+ newtWinMessage("Error", "OK", "Failed to open /tmp/translation: %m\n");
+ return;
+ }
+
+ while (read(fd, &hash, 4) == 4) {
+ if (allocedStrings == numStrings) {
+ allocedStrings += 10;
+ strings = realloc(strings, sizeof(*strings) * allocedStrings);
+ }
+
+ strings[numStrings].hash = ntohl(hash);
+ rc = read(fd, &strings[numStrings].length, 2);
+ strings[numStrings].length = ntohs(strings[numStrings].length);
+ strings[numStrings].str = malloc(strings[numStrings].length + 1);
+ rc = read(fd, strings[numStrings].str, strings[numStrings].length);
+ strings[numStrings].str[strings[numStrings].length] = '\0';
+ numStrings++;
+ }
+
+ close(fd);
+ unlink("/tmp/translation");
+
+ qsort(strings, numStrings, sizeof(*strings), aStringCmp);
+}
+
+
+/* give the index of the language to set to -- sets the appropriate
+ * lang variables if we have a font.
+ *
+ * ASSUMPTION: languages exists
+ */
+static void setLangEnv (int i) {
+ if (i > numLanguages)
+ return;
+
+ if (strcmp(languages[i].font, "latarcyrheb-sun16"))
+ return;
+ logMessage(INFO, "setting language to %s", languages[i].lc_all);
+
+ setenv("LANG", languages[i].lc_all, 1);
+ setenv("LANGKEY", languages[i].key, 1);
+ setenv("LINGUAS", languages[i].lang, 1);
+ loadLanguage (NULL);
+}
+
+/* choice is the index of the chosen language in languages */
+static int setupLanguage(int choice, int forced) {
+ char * buf;
+ int i;
+
+ logMessage(DEBUGLVL, "going to set language to %s", languages[choice].lc_all);
+ /* load the language only if it is displayable. if they're using
+ * a serial console or iSeries vioconsole, we hope it's smart enough */
+ if ((strcmp(languages[choice].font, "latarcyrheb-sun16") && !FL_SERIAL(flags) &&
+ !FL_VIRTPCONSOLE(flags) && !isVioConsole())) {
+ if (forced == 1) return 0;
+
+ newtWinMessage("Language Unavailable", "OK",
+ "%s display is unavailable in text mode. The "
+ "installation will continue in English until the "
+ "display of %s is possible.", languages[choice].lang,
+ languages[choice].lang);
+ setLangEnv(english);
+ return 0;
+ }
+
+ setLangEnv (choice);
+ isysLoadFont();
+
+ /* clear out top line */
+ buf = alloca(81); /* reserve one byte for \0 */
+ for (i=0; i < 80; i++)
+ buf[i] = ' ';
+ buf[80] = 0; /* and set the \0 */
+ newtDrawRootText(0, 0, buf);
+
+ char *fmt = FL_RESCUE(flags) ? _(topLineWelcomeRescue) : _(topLineWelcome);
+ checked_asprintf(&buf, fmt, getProductName(), getProductArch());
+
+ newtDrawRootText(0, 0, buf);
+ free(buf);
+ newtPopHelpLine();
+ newtPushHelpLine(_(bottomHelpLine));
+
+ return 0;
+
+}
+
+/* this is pretty simple. we want to break down the language specifier
+ * into its short form (eg, en_US)
+ */
+static char * getLangShortForm(char * oldLang) {
+ char * lang;
+ char * c;
+
+ lang = strdup(oldLang);
+
+ c = strchr(lang, '@');
+ if (c) {
+ *c = '\0';
+ }
+
+ c = strchr(lang, '.');
+ if (c) {
+ *c = '\0';
+ }
+
+ return lang;
+}
+
+/* return the nick of a language -- eg en_US -> en */
+static char * getLangNick(char * oldLang) {
+ char * lang;
+ char * c;
+
+ lang = strdup(oldLang);
+
+ c = strchr(lang, '_');
+ if (c) {
+ *c = '\0';
+ }
+
+ return lang;
+}
+
+int setLanguage (char * key, int forced) {
+ int i;
+
+ if (!languages) loadLanguageList();
+
+ for (i = 0; i < numLanguages; i++) {
+ if (!strcmp(languages[i].lc_all, key)) {
+ return setupLanguage(i, forced | !FL_KICKSTART(flags));
+ }
+ }
+
+ /* we didn't specify anything that's exactly in the lang-table. check
+ * against short forms and nicks */
+ for (i = 0; i < numLanguages; i++) {
+ if (!strcmp(getLangShortForm(languages[i].lc_all), key)) {
+ return setupLanguage(i, forced | !FL_KICKSTART(flags));
+ }
+ }
+
+ for (i = 0; i < numLanguages; i++) {
+ if (!strcmp(getLangNick(languages[i].lc_all), key)) {
+ return setupLanguage(i, forced | !FL_KICKSTART(flags));
+ }
+ }
+
+ logMessage(ERROR, "unable to set to requested language %s", key);
+ return -1;
+}
+
+int chooseLanguage(char ** lang) {
+ int choice = 0;
+ char ** langs;
+ int i;
+ int current = -1;
+ char * currentLangName = getenv("LANG");
+ int numLangs = 0;
+ char * langPicked;
+
+ if (!languages) loadLanguageList();
+
+ langs = alloca(sizeof(*langs) * (numLanguages + 1));
+
+ for (i = 0; i < numLanguages; i++) {
+ if (!strncmp(languages[i].key, "en", 2))
+ english = numLangs;
+ if (currentLangName &&
+ !strcmp(languages[i].lang, currentLangName))
+ current = numLangs;
+
+ langs[numLangs++] = languages[i].lang;
+ }
+
+ langs[numLangs] = NULL;
+
+ if (current >= 0)
+ choice = current;
+ else
+ choice = english;
+
+ if (!FL_CMDLINE(flags))
+ newtWinMenu(_("Choose a Language"),
+ _("What language would you like to use during the "
+ "installation process?"), 40, 5, 5, 8,
+ langs, &choice, _("OK"), NULL);
+
+ langPicked = langs[choice];
+ for (i = 0; i < numLanguages; i++) {
+ if (!strcmp(langPicked, languages[i].lang)) {
+ *lang = languages[i].lc_all;
+ choice = i;
+ break;
+ }
+ }
+
+ /* this can't happen */
+ if (i == numLanguages) abort();
+
+ return setupLanguage(choice, 0);
+}
+
+void setKickstartLanguage(struct loaderData_s * loaderData, int argc,
+ char ** argv) {
+ if (argc < 2) {
+ logMessage(ERROR, "no argument passed to lang kickstart command");
+ return;
+ }
+
+ loaderData->lang = argv[1];
+ loaderData->lang_set = 1;
+}