[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[patch] cdebconf and i18n



Here is an improved patch, it has been tested and looks fine.
Currently language choice is performed by a DEBCONF_LANG environment
variable.
In src/modules/db/textdb/textdb.c, the textdb_template_get_real needs
more work.

Denis
Index: debian/changelog
===================================================================
RCS file: /cvs/debian-boot/debian-installer/tools/cdebconf/debian/changelog,v
retrieving revision 1.40
diff -u -r1.40 changelog
--- debian/changelog	6 Nov 2002 10:11:37 -0000	1.40
+++ debian/changelog	9 Nov 2002 01:21:18 -0000
@@ -29,6 +29,13 @@
     - fix confmodule.c and commands.c to not use fixed-size
       buffers. (closes: #167312)
   * Denis Barbier:
+    - change internal template structure in src/template.h in order
+      to help managing localized fields, and fix doc/modules.txt
+      accordingly
+    - define accessors to get and set template values, should be used
+      everywhere instead of direct access to structure members
+    - partially handle localized fields, only UTF-8 templates files
+      are considered
     - convert to po-debconf, set Build-Depends: debhelper (>= 4.1.13)
       to ensure that generated templates are right, and set output encoding
       to UTF-8.
Index: doc/modules.txt
===================================================================
RCS file: /cvs/debian-boot/debian-installer/tools/cdebconf/doc/modules.txt,v
retrieving revision 1.7
diff -u -r1.7 modules.txt
--- doc/modules.txt	1 Jul 2002 06:58:37 -0000	1.7
+++ doc/modules.txt	9 Nov 2002 01:21:18 -0000
@@ -36,20 +36,37 @@
 A template has the following publically accessible fields:
 
 - char *tag: the template's tag
-- char *type: the template's type XXX can be one of ...
-- char *defaultval: the template's default value, as a string
-- char *choices: if the template's type is choices based, here the choices
-                 are listed in a single string, seperated by commas XXX right?
-- char *description: a description of the template XXX must be under ... chars?
-- char *extended_description: a longer description 
-- struct language_description *localized descriptions - has following fields:
-  - struct language_description *next: NULL or another localized description
-  - char *language: ISO tag for language XXX right?
-  - char *choices, char *description, char *extended_description: as above,
-    only in specified language
-  
+- char *type: the template's type, can be one of select, multiselect,
+              string, boolean, note, text and password
+- struct template_l10n_fields *fields - has following fields:
+  - struct template_l10n_fields *next: NULL or another localized field
+                                       structure
+  - char *language: ISO code for language (ll or ll_LL)
+  - char *defaultval: the template's default value, as a string
+  - char *choices: if the template's type is choices based, here the choices
+                   are listed in a single string, seperated by commas
+  - char *description: a description of the template XXX must be under ... chars?
+  - char *extended_description: a longer description 
+
+The first template_l10n_fields structure must always be in English, and
+its ISO code is set to C.
+
 XXX not covering "next", I assume it is private
 XXX not covering memory management or deletion
+
+Publically accessible methods:
+
+const char *lget(struct template *, const char *lang, const char *field):
+   Return a string value for given field in a language, or NULL if not found
+
+void lset(struct template *, const char *lang, const char *field, const char *value):
+   Save string value at field for a given language
+
+const char *get(struct template *, const char *field):
+   Return a string value for given field in English
+
+void set(struct template *, const char *field, const char *value):
+   Save string value at English field
 
 question API
 ~~~~~~~~~~~~
Index: src/commands.c
===================================================================
RCS file: /cvs/debian-boot/debian-installer/tools/cdebconf/src/commands.c,v
retrieving revision 1.24
diff -u -r1.24 commands.c
--- src/commands.c	5 Nov 2002 02:55:13 -0000	1.24
+++ src/commands.c	9 Nov 2002 01:21:18 -0000
@@ -614,14 +614,14 @@
 		if (strcmp(field, "value") == 0)
 			snprintf(out, outsize, "%u %s", CMDSTATUS_SUCCESS, q->value);
 		else if (strcmp(field, "description") == 0)
-			snprintf(out, outsize, "%u %s", CMDSTATUS_SUCCESS, question_description(q));
+			snprintf(out, outsize, "%u %s", CMDSTATUS_SUCCESS, question_get_translated_field(q, field));
 		else if (strcmp(field, "extended_description") == 0)
 			/* NOTE: this probably is wrong, because the extended
 			 * description is likely multiline
 			 */
-			snprintf(out, outsize, "%u %s", CMDSTATUS_SUCCESS, question_extended_description(q));
+			snprintf(out, outsize, "%u %s", CMDSTATUS_SUCCESS, question_get_translated_field(q, field));
 		else if (strcmp(field, "choices") == 0)
-			snprintf(out, outsize, "%u %s", CMDSTATUS_SUCCESS, question_choices(q));
+			snprintf(out, outsize, "%u %s", CMDSTATUS_SUCCESS, question_get_translated_field(q, field));
 		else
 			snprintf(out, outsize, "%u %s does not exist", CMDSTATUS_BADPARAM, field);
 	}
Index: src/question.c
===================================================================
RCS file: /cvs/debian-boot/debian-installer/tools/cdebconf/src/question.c,v
retrieving revision 1.12
diff -u -r1.12 question.c
--- src/question.c	7 Aug 2002 16:34:01 -0000	1.12
+++ src/question.c	9 Nov 2002 01:21:18 -0000
@@ -43,6 +43,8 @@
 #include "configuration.h"
 #include "database.h"
 
+static char cur_lang[6] = {0};
+
 struct question *question_new(const char *tag)
 {
 	struct question *q;
@@ -228,126 +230,44 @@
 	return DC_OK;
 }
 
-/*
- * Function: getlanguage
- * Input: none
- * Output: const char* (size == 3) the language code of the currently 
- *         selected language
- * Description: find the currently selected language
- * Assumptions: config_new and database_new succeeds, 
- *              debian-installer/language exists
- */
-
-const char *getlanguage()
-{
-#if 0   /* FIXME */
-    static struct database *db = NULL;
-    static struct configuration *config = NULL;
-	static char language[3];
-	/* We need to directly access the configuration, since I couldn't
-	   get debconfclient to work from in here. */
-	struct question *q2 = NULL;
-        memset(language,'\0',3);
-
-	if (! config) /* Then db isn't set either.. */
-	{
-		config = config_new();
-                if (config == 0) 
-                        DIE("Error initializing configuration item (%s %d)", __FILE__,__LINE__);
-		if (config->read(config, DEBCONFCONFIG) == 0)
-			DIE("Error reading configuration information");
-		if ((db = database_new(config)) == 0)
-			DIE("Cannot initialize DebConf database");
-		db->load(db);
-	}
-	q2 = db->question_get(db, "debian-installer/language");
-        if (q2 != NULL) {
-                if (q2->value != NULL)
-                        snprintf(language,3,"%.2s",q2->value);
-                question_deref(q2);
-        }
-	return language;
-#else
-    return "";
-#endif
-}
-
-const char *question_description(struct question *q)
-{
-	static char buf[4096] = {0};
-	struct language_description *langdesc;
-
-	langdesc = q->template->localized_descriptions;
-	while (langdesc)
-	{
-		if (strcmp(langdesc->language,getlanguage()) == 0) 
-		{
-			question_expand_vars(q, langdesc->description, buf, sizeof(buf));
-			return buf;
-		}
-		langdesc = langdesc->next;
-	}
-	question_expand_vars(q, q->template->description, buf, sizeof(buf));
-	return buf;
-}
-
-const char *question_extended_description(struct question *q)
-{
-	static char buf[4096] = {0};
-	question_expand_vars(q, q->template->extended_description, buf, sizeof(buf));
-	return buf;
-}
-
-const char *question_extended_description_translated(struct question *q)
+const char *getlanguage(void)
 {
-	static char buf[4096] = {0};
-	struct language_description *langdesc;
-
-	langdesc = q->template->localized_descriptions;
-	while (langdesc)
+	if (cur_lang[0] == 0)
 	{
-		if (strcmp(langdesc->language,getlanguage()) == 0 && langdesc->description != NULL)
-		{
-			question_expand_vars(q, langdesc->extended_description, buf, sizeof(buf));
-			return buf;
-		}
-		langdesc = langdesc->next;
+		if (getenv("DEBCONF_LANG")) 
+			strncpy(cur_lang, getenv("DEBCONF_LANG"), 5);
+		else
+			strcpy(cur_lang, "C");
 	}
-	question_expand_vars(q, q->template->extended_description, buf, sizeof(buf));
-	return buf;
+	return cur_lang;
 }
 
-const char *question_choices_translated(struct question *q)
+const char *question_get_field(struct question *q, const char *field)
 {
 	static char buf[4096] = {0};
-	struct language_description *langdesc;
-
-	langdesc = q->template->localized_descriptions;
-	while (langdesc)
-	{
-		if (strcmp(langdesc->language,getlanguage()) == 0 && langdesc->choices != NULL)
-		{
-			question_expand_vars(q, langdesc->choices, buf, sizeof(buf));
-			return buf;
-		}
-		langdesc = langdesc->next;
-	}
-	question_expand_vars(q, q->template->choices, buf, sizeof(buf));
+	if (strcmp(field, "default") == 0) {
+		if (q->value != 0 && *q->value != 0)
+			return q->value;
+		else
+			return q->template->get(q->template, field);
+	}
+	question_expand_vars(q,
+		q->template->get(q->template, field),
+		buf, sizeof(buf));
 	return buf;
 }
 
-const char *question_choices(struct question *q)
+const char *question_get_translated_field(struct question *q, const char *field)
 {
 	static char buf[4096] = {0};
-	question_expand_vars(q, q->template->choices, buf, sizeof(buf));
+	if (strcmp(field, "default") == 0) {
+		if (q->value != 0 && *q->value != 0)
+			return q->value;
+		else
+			return q->template->lget(q->template, getlanguage(), field);
+	}
+	question_expand_vars(q,
+		q->template->lget(q->template, getlanguage(), field),
+		buf, sizeof(buf));
 	return buf;
 }
-
-const char *question_defaultval(struct question *q)
-{
-	if (q->value != 0 && *q->value != 0)
-		return q->value;
-	else
-		return q->template->defaultval;
-}
-
Index: src/question.h
===================================================================
RCS file: /cvs/debian-boot/debian-installer/tools/cdebconf/src/question.h,v
retrieving revision 1.9
diff -u -r1.9 question.h
--- src/question.h	12 Aug 2002 13:38:34 -0000	1.9
+++ src/question.h	9 Nov 2002 01:21:18 -0000
@@ -45,10 +45,7 @@
 	const char *value);
 void question_owner_add(struct question *q, const char *owner);
 void question_owner_delete(struct question *q, const char *owner);
-const char *question_description(struct question *q);
-const char *question_extended_description(struct question *q);
-const char *question_choices_translated(struct question *q);
-const char *question_choices(struct question *q);
-const char *question_defaultval(struct question *q);
+const char *question_get_field(struct question *q, const char *field);
+const char *question_get_translated_field(struct question *q, const char *field);
 
 #endif
Index: src/template.c
===================================================================
RCS file: /cvs/debian-boot/debian-installer/tools/cdebconf/src/template.c,v
retrieving revision 1.8
diff -u -r1.8 template.c
--- src/template.c	1 Jul 2002 06:58:37 -0000	1.8
+++ src/template.c	9 Nov 2002 01:21:19 -0000
@@ -42,11 +42,31 @@
 
 #include <stdio.h>
 
+static const char *template_lget(struct template *t, const char *lang,
+                const char *field);
+static const char *template_get(struct template *t, const char *field);
+static void template_lset(struct template *t, const char *lang,
+                const char *field, const char *value);
+static void template_set(struct template *t, const char *field,
+                const char *value);
+static const char *template_next_lang(struct template *t, const char *l);
+
+const char *template_fields_list[] = {
+        "tag",
+        "type",
+        "default",
+        "choices",
+        "description",
+        "extended_description",
+        NULL
+};
+
 /*
  * Function: template_new
  * Input: a tag, describing which template this is.  Can be null.
  * Output: a blank template struct.  Tag is strdup-ed, so the original
            string may change without harm.
+           The fields structure is also allocated to store English fields
  * Description: allocate a new, empty struct template.
  * Assumptions: NEW succeeds
  * Todo: 
@@ -54,22 +74,40 @@
 
 struct template *template_new(const char *tag)
 {
+	struct template_l10n_fields *f = NEW(struct template_l10n_fields);
 	struct template *t = NEW(struct template);
+	memset(f, 0, sizeof(struct template_l10n_fields));
+	f->language = STRDUP("C");
 	memset(t, 0, sizeof(struct template));
 	t->ref = 1;
 	t->tag = STRDUP(tag);
+	t->get = template_get;
+	t->set = template_set;
+	t->lget = template_lget;
+	t->lset = template_lset;
+	t->next_lang = template_next_lang;
+	t->fields = f;
 	return t;
 }
 
 void template_delete(struct template *t)
 {
+	struct template_l10n_fields *p, *q;
+
 	DELETE(t->tag);
 	DELETE(t->type);
-	DELETE(t->defaultval);
-	DELETE(t->choices);
-	DELETE(t->description);
-	DELETE(t->extended_description);
+	p = t->fields;
 	DELETE(t);
+	while (p != NULL)
+	{
+		q = p->next;
+		DELETE(p->defaultval);
+		DELETE(p->choices);
+		DELETE(p->description);
+		DELETE(p->extended_description);
+		DELETE(p);
+		p = q;
+	}
 }
 
 void template_ref(struct template *t)
@@ -89,23 +127,251 @@
  * Output: a copy of the template passed as input
  * Description: duplicate a template
  * Assumptions: template_new succeeds, STRDUP succeeds.
- * Todo: Handle localization
  */
 
 struct template *template_dup(struct template *t)
 {
         struct template *ret = template_new(t->tag);
+        struct template_l10n_fields *from, *to;
+
         ret->type = STRDUP(t->type);
-        ret->defaultval = STRDUP(t->defaultval);
-        ret->choices = STRDUP(t->choices);
-        ret->description = STRDUP(t->description);
-        ret->extended_description = STRDUP(t->extended_description);
+        if (t->fields == NULL)
+                return ret;
+
+        ret->fields = NEW(struct template_l10n_fields);
+
+        from = t->fields;
+        to = ret->fields;
+        /*  Iterate over available languages  */
+        while (1)
+        {
+                to->defaultval = STRDUP(from->defaultval);
+                to->choices = STRDUP(from->choices);
+                to->description = STRDUP(from->description);
+                to->extended_description = STRDUP(from->extended_description);
+
+                if (from->next == NULL)
+                {
+                        to->next = NULL;
+                        break;
+                }
+                to->next = NEW(struct template_l10n_fields);
+                from = from->next;
+                to = to->next;
+        }
+        return ret;
+}
+
+static const char *template_field_get(struct template_l10n_fields *p,
+                const char *field)
+{
+    if (strcasecmp(field, "default") == 0)
+        return p->defaultval;
+    else if (strcasecmp(field, "choices") == 0)
+        return p->choices;
+    else if (strcasecmp(field, "description") == 0)
+        return p->description;
+    else if (strcasecmp(field, "extended_description") == 0)
+        return p->extended_description;
+    return NULL;
+}
+
+static void template_field_set(struct template_l10n_fields *p,
+                const char *field, const char *value)
+{
+    if (strcasecmp(field, "default") == 0)
+    {
+        DELETE(p->defaultval);
+        p->defaultval = STRDUP(value);
+    }
+    else if (strcasecmp(field, "choices") == 0)
+    {
+        DELETE(p->choices);
+        p->choices = STRDUP(value);
+    }
+    else if (strcasecmp(field, "description") == 0)
+    {
+        DELETE(p->description);
+        p->description = STRDUP(value);
+    }
+    else if (strcasecmp(field, "extended_description") == 0)
+    {
+        DELETE(p->extended_description);
+        p->extended_description = STRDUP(value);
+    }
+}
+
+/*
+ * Function: template_get
+ * Input: a template
+ * Input: a language name
+ * Input: a field name
+ * Output: the value of the given field in the given language, field
+ *         name may be any of type, default, choices, description and
+ *         extended_description
+ * Description: get field value
+ * Assumptions: 
+ */
+
+static const char *template_lget(struct template *t, const char *lang,
+                const char *field)
+{
+    struct template_l10n_fields *p;
+    const char *ret = NULL, *altret = NULL;
+
+    if (strcmp(lang, "C") == 0 && strcasecmp(field, "tag") == 0)
+        return t->tag;
+    else if (strcmp(lang, "C") == 0 && strcasecmp(field, "type") == 0)
+        return t->type;
+
+    p = t->fields;
+    while (p != NULL)
+    {
+        /*  Exact match  */
+        if (strcmp(p->language, lang) == 0)
+            return template_field_get(p, field);
+
+        /*  Language is xx_XX and a xx field is found  */
+        if (strlen(p->language) == 2 && strncmp(lang, p->language, 2) == 0)
+            altret = template_field_get(p, field);
+
+        p = p->next;
+    }
+    if (altret != NULL)
+        return altret;
+    if (ret)
         return ret;
+    /*  Default value  */
+    return template_field_get(t->fields, field);
+}
+
+static const char *template_get(struct template *t, const char *field)
+{
+    char *orig_field;
+    char *lang;
+    char *p;
+    const char *ret = NULL;
+
+    p = strchr(field, '-');
+    if (p == NULL)
+        return template_lget(t, "C", field);
+
+    orig_field = strdup(field);
+    lang = strchr(orig_field, '-');
+    *lang = 0;
+    lang++;
+    if (strstr(lang, ".UTF-8") == lang + 2)
+    {
+        *(lang+2) = 0;
+        ret = template_lget(t, lang, orig_field);
+    }
+    else if (strstr(lang, ".UTF-8") == lang + 5)
+    {
+        *(lang+5) = 0;
+        ret = template_lget(t, lang, orig_field);
+    }
+#ifndef NODEBUG
+    else
+        fprintf(stderr, "Unknown localized field:\n%s\n", p);
+#endif
+    free(orig_field);
+    return ret;
+}
+
+static void template_lset(struct template *t, const char *lang,
+                const char *field, const char *value)
+{
+    struct template_l10n_fields *p, *last;
+
+    if (strcmp(lang, "C") == 0 && strcasecmp(field, "tag") == 0)
+    {
+        t->tag = STRDUP(value);
+        return;
+    }
+    else if (strcmp(lang, "C") == 0 && strcasecmp(field, "type") == 0)
+    {
+        t->type = STRDUP(value);
+        return;
+    }
+
+    p = t->fields;
+    last = p;
+    while (p != NULL)
+    {
+        if (strcmp(p->language, lang) == 0)
+        {
+            template_field_set(p, field, value);
+            return;
+        }
+        last = p;
+        p = p->next;
+    }
+    p = NEW(struct template_l10n_fields);
+    memset(p, 0, sizeof(struct template_l10n_fields));
+    p->language = STRDUP(lang);
+    last->next = p;
+    template_field_set(p, field, value);
+}
+
+static void template_set(struct template *t, const char *field,
+                const char *value)
+{
+    char *orig_field;
+    char *lang;
+    char *p;
+
+    p = strchr(field, '-');
+    if (p == NULL)
+        template_lset(t, "C", field, value);
+    else
+    {
+        orig_field = strdup(field);
+        lang = strchr(orig_field, '-');
+        *lang = 0;
+        lang++;
+        if (strstr(lang, ".UTF-8") == lang + 2)
+        {
+            *(lang+2) = 0;
+            template_lset(t, lang, orig_field, value);
+        }
+        else if (strstr(lang, ".UTF-8") == lang + 5)
+        {
+            *(lang+5) = 0;
+            template_lset(t, lang, orig_field, value);
+        }
+#ifndef NODEBUG
+        else
+            fprintf(stderr, "Unknown localized field:\n%s\n", p);
+#endif
+        free(orig_field);
+    }
+}
+
+static const char *template_next_lang(struct template *t, const char *lang)
+{
+    struct template_l10n_fields *p;
+
+    if (lang == NULL)
+        return NULL;
+
+    p = t->fields;
+    while (p != NULL)
+    {
+        if (strcmp(p->language, lang) == 0)
+        {
+            if (p->next == NULL)
+                return NULL;
+            return p->next->language;
+        }
+        p = p->next;
+    }
+    return NULL;
 }
 
 struct template *template_load(const char *filename)
 {
 	char buf[2048], extdesc[8192];
+	char lang[6];
 	char *p, *bufp;
 	FILE *fp;
 	struct template *tlist = NULL, *t = 0;
@@ -130,55 +396,36 @@
 			t = template_new(p+10);
 		}
 		else if (strstr(p, "Type: ") == p && t != 0)
-			t->type = strdup(p+6);
+			template_set(t, "type", p+6);
 		else if (strstr(p, "Default: ") == p && t != 0)
-			t->defaultval = strdup(p+9);
+			template_set(t, "default", p+9);
 		else if (strstr(p, "Choices: ") == p && t != 0)
-			t->choices = strdup(p+9);
+			template_set(t, "choices", p+9);
 		else if (strstr(p, "Choices-") == p && t != 0) 
 		{
-			struct language_description *langdesc = malloc(sizeof(struct language_description));
-			struct language_description *lng_tmp = 0;
-			memset(langdesc,0,sizeof(struct language_description));
-			/* We assume that the language codes are
-			   always 2 characters long, */
-
-			langdesc->language = malloc(3);
-			snprintf(langdesc->language,3,"%.2s",p+8);
-			
-			langdesc->choices = strdup(p+11);
-
-			if (t->localized_descriptions == NULL) 
+			if (strstr(p, ".UTF-8: ") == p + 10)
+			{
+				strncpy(lang, p+8, 2);
+				lang[2] = 0;
+				template_lset(t, lang, "choices", p+18);
+			}
+			else if (strstr(p, ".UTF-8: ") == p + 13)
 			{
-				t->localized_descriptions = langdesc;
+				strncpy(lang, p+8, 5);
+				lang[5] = 0;
+				template_lset(t, lang, "choices", p+21);
 			}
 			else
 			{
-				lng_tmp = t->localized_descriptions;
-				while (lng_tmp != NULL)
-				{
-					if (strcmp(lng_tmp->language,langdesc->language) == 0)
-					{
-						if (lng_tmp->choices)
-							free(lng_tmp->choices);
-						lng_tmp->choices = langdesc->choices;
-						free(langdesc->language);
-						free(langdesc);
-						langdesc = NULL;
-						break;
-					}
-					lng_tmp = lng_tmp->next;
-				}
-				if (langdesc != NULL) 
-				{
-					langdesc->next = t->localized_descriptions;
-					t->localized_descriptions = langdesc;
-				}
+#ifndef NODEBUG
+				fprintf(stderr, "Unknown localized field:\n%s\n", p);
+#endif
+                                continue;
 			}
 		}
 		else if (strstr(p, "Description: ") == p && t != 0)
 		{
-			t->description = strdup(p+13);
+			template_set(t, "description", p+13);
 			extdesc[0] = 0;
 			i = fgetc(fp);
 			/* Don't use fgets unless you _need_ to, a
@@ -219,22 +466,31 @@
 							*bufp = ' ';
 					}
 					
-				t->extended_description = strdup(extdesc);
+				template_set(t, "extended_description", extdesc);
 			}
 		}
 		else if (strstr(p, "Description-") == p && t != 0)
 		{
-			struct language_description *langdesc = malloc(sizeof(struct language_description));
-			struct language_description *lng_tmp = 0;
-			memset(langdesc,0,sizeof(struct language_description));
-
-			/* We assume that the language codes are
-			   always 2 characters long, */
-
-			langdesc->language = malloc(3);
-			snprintf(langdesc->language,3,"%.2s",p+12);
-			langdesc->description = strdup(p+16);
-
+			if (strstr(p, ".UTF-8: ") == p + 14)
+			{
+				strncpy(lang, p+12, 2);
+				lang[2] = 0;
+				template_lset(t, lang, "description", p+22);
+			}
+			else if (strstr(p, ".UTF-8: ") == p + 17)
+			{
+				strncpy(lang, p+12, 5);
+				lang[5] = 0;
+				template_lset(t, lang, "description", p+25);
+			}
+			else
+			{
+#ifndef NODEBUG
+				fprintf(stderr, "Unknown localized field:\n%s\n", p);
+#endif
+                                /*  Skip extended description  */
+                                lang[0] = 0;
+			}
 			extdesc[0] = 0;
 			i = fgetc(fp);
 			/* Don't use fgets unless you _need_ to, a
@@ -273,37 +529,8 @@
 							*bufp = ' ';
 					}
 				
-				langdesc->extended_description = strdup(extdesc);
-			}
-			if (t->localized_descriptions == NULL) 
-			{
-				t->localized_descriptions = langdesc;
-			}
-			else
-			{
-				lng_tmp = t->localized_descriptions;
-				while (lng_tmp != NULL)
-				{
-					if (strcmp(lng_tmp->language,langdesc->language) == 0)
-					{
-						if (lng_tmp->description != NULL)
-							free(lng_tmp->description);
-						if (lng_tmp->extended_description != NULL)
-							free(lng_tmp->extended_description);
-						lng_tmp->description = langdesc->description;
-						lng_tmp->extended_description = langdesc->extended_description;
-						free(langdesc->language);
-						free(langdesc);
-						langdesc = NULL;
-						break;
-					}
-					lng_tmp = lng_tmp->next;
-				}
-				if (langdesc != NULL) 
-				{
-					langdesc->next = t->localized_descriptions;
-					t->localized_descriptions = langdesc;
-				}
+				if (lang[0] != 0)
+					template_lset(t, lang, "extended_description", extdesc);
 			}
 		}
 	}
Index: src/template.h
===================================================================
RCS file: /cvs/debian-boot/debian-installer/tools/cdebconf/src/template.h,v
retrieving revision 1.3
diff -u -r1.3 template.h
--- src/template.h	12 Aug 2002 13:38:34 -0000	1.3
+++ src/template.h	9 Nov 2002 01:21:19 -0000
@@ -1,13 +1,14 @@
 #ifndef _TEMPLATE_H_
 #define _TEMPLATE_H_
 
-struct language_description 
+struct template_l10n_fields
 {
 	char *language;
+	char *defaultval;
+	char *choices;
 	char *description;
 	char *extended_description;
-	char *choices;
-	struct language_description *next;
+	struct template_l10n_fields *next;
 };
 
 struct template
@@ -15,13 +16,17 @@
 	char *tag;
 	unsigned int ref;
 	char *type;
-	char *defaultval;
-	char *choices;
-	char *description;
-	char *extended_description;
-	struct language_description *localized_descriptions;
+	struct template_l10n_fields *fields;
 	struct template *next;
+	const char *(*lget)(struct template *, const char *l, const char *f);
+	const char *(*get)(struct template *, const char *f);
+        void (*lset)(struct template *, const char *l, const char *f,
+                        const char *v);
+        void (*set)(struct template *, const char *f, const char *v);
+	const char *(*next_lang)(struct template *, const char *l);
 };
+
+extern const char *template_fields_list[];
 
 struct template *template_new(const char *tag);
 void template_delete(struct template *t);
Index: src/modules/db/rfc822db/rfc822db.c
===================================================================
RCS file: /cvs/debian-boot/debian-installer/tools/cdebconf/src/modules/db/rfc822db/rfc822db.c,v
retrieving revision 1.9
diff -u -r1.9 rfc822db.c
--- src/modules/db/rfc822db/rfc822db.c	3 Nov 2002 14:58:19 -0000	1.9
+++ src/modules/db/rfc822db/rfc822db.c	9 Nov 2002 01:21:19 -0000
@@ -239,7 +239,6 @@
  * Output: DC_OK/DC_NOTOK
  * Description: parse a template db file and put it into the cache
  * Assumptions: the file is in valid rfc822 format
- * TODO: handle localized templates
  */
 static int rfc822db_template_load(struct template_db *db)
 {
@@ -262,8 +261,7 @@
     {
         struct template *tmp;
         const char *name;
-        char tbuf[1024];
-        memset(&tbuf,0,1024);
+        struct rfc822_header *h;
 
         name = rfc822db_header_lookup(header, "name");
         if (name == NULL)
@@ -274,13 +272,10 @@
         }
 
         tmp = template_new(name);
+        for (h = header; h != NULL; h = h->next)
+            if (strcmp(h->header, "Name") != 0)
+                tmp->set(tmp, h->header, h->value);
 
-        tmp->type = rfc822db_header_lookup(header, "type");
-        tmp->defaultval = rfc822db_header_lookup(header, "default");
-        tmp->choices = rfc822db_header_lookup(header, "choices");
-        tmp->description = rfc822db_header_lookup(header, "description");
-        tmp->extended_description = rfc822db_header_lookup(header, "extended_description");
-/*  struct language_description *localized_descriptions; */
         tmp->next = NULL;
         tsearch(tmp, &dbdata->root, nodetemplatecomp);
     }
@@ -292,52 +287,54 @@
 
 void rfc822db_template_dump(const void *node, const VISIT which, const int depth)
 {
-  struct language_description *langdesc;
-  const struct template *t = (*(struct template **) node);
-  switch (which) {
-  case preorder:
-    break;
-  case endorder:
-    break;
-  case postorder: 
-  case leaf:
-        INFO(INFO_VERBOSE, "dumping template %s\n", (t)->tag);
-        
-        fprintf(outf, "Name: %s\n", escapestr((t)->tag));
-        fprintf(outf, "Type: %s\n", escapestr((t)->type));
-        if ((t)->defaultval != NULL)
-            fprintf(outf, "Default: %s\n", escapestr((t)->defaultval));
-        if ((t)->choices != NULL)
-            fprintf(outf, "Choices: %s\n", escapestr((t)->choices));
-        if ((t)->description != NULL)
-            fprintf(outf, "Description: %s\n", escapestr((t)->description));
-        if ((t)->extended_description != NULL)
-            fprintf(outf, "Extended_description: %s\n", escapestr((t)->extended_description));
-        
-        langdesc = (t)->localized_descriptions;
-        while (langdesc) 
+    const char *p, *lang;
+    const char **field;
+    const struct template *t = (*(struct template **) node);
+
+    switch (which) {
+    case preorder:
+        break;
+    case endorder:
+        break;
+    case postorder: 
+    case leaf:
+        p = t->get((struct template *) t, "tag");
+        INFO(INFO_VERBOSE, "dumping template %s\n", p);
+
+        for (field = template_fields_list; *field != NULL; field++)
         {
-            if (langdesc->description != NULL) 
-                fprintf(outf, "Description-%s: %s\n", 
-                    langdesc->language, 
-                    escapestr(langdesc->description));
-            
-            if (langdesc->extended_description != NULL)
-                fprintf(outf, "Extended_description-%s: %s\n", 
-                    langdesc->language, 
-                    escapestr(langdesc->extended_description));
-            
-            if (langdesc->choices != NULL) 
-                fprintf(outf, "Choices-%s: %s\n", 
-                    langdesc->language, 
-                    escapestr(langdesc->choices));
-            
-            langdesc = langdesc->next;
+            p = t->get((struct template *) t, *field);
+            if (p != NULL)
+            {
+                if (strcmp(*field, "tag") == 0)
+                    fprintf(outf, "Name: %s\n", escapestr(p));
+                            else
+                    fprintf(outf, "%c%s: %s\n",
+                        toupper((*field)[0]),
+                        (*field)+1, escapestr(p));
+            }
+        }
+    
+        lang = t->next_lang((struct template *) t, "C");
+        while (lang) 
+        {
+            for (field = template_fields_list; *field != NULL; field++)
+            {
+                p = t->lget((struct template *) t, lang, *field);
+                if (p != NULL)
+                {
+                    if (strcmp(*field, "tag") != 0)
+                        fprintf(outf, "%c%s-%s.UTF-8: %s\n",
+                            toupper((*field)[0]), (*field)+1,
+                            lang, escapestr(p));
+                }
+            }
+            lang = t->next_lang((struct template *) t, lang);
         }
         fprintf(outf, "\n");
-  }
-  
+    }
 }
+  
 static int rfc822db_template_save(struct template_db *db)
 {
     struct template_db_cache *dbdata = db->data;
@@ -596,7 +593,7 @@
     struct question *q, q2;
 
     memset(&q2, 0, sizeof (struct question));
-    q2.tag = ltag;
+    q2.tag = (char *) ltag;
     q = tfind(&q2, &dbdata->root, nodequestioncomp);
     if (q != NULL)
     {
Index: src/modules/db/textdb/textdb.c
===================================================================
RCS file: /cvs/debian-boot/debian-installer/tools/cdebconf/src/modules/db/textdb/textdb.c,v
retrieving revision 1.5
diff -u -r1.5 textdb.c
--- src/modules/db/textdb/textdb.c	30 Jul 2002 05:55:27 -0000	1.5
+++ src/modules/db/textdb/textdb.c	9 Nov 2002 01:21:19 -0000
@@ -135,38 +135,35 @@
 {
 	FILE *outf;
 	char *filename;
-	struct language_description *langdesc;
+	const char *p, *lang;
+	const char **field;
 
-	if (t->tag == NULL) return DC_NOTOK;
-	filename = template_filename(db, t->tag);
+	if (t->get(t, "tag") == NULL) return DC_NOTOK;
+	filename = template_filename(db, t->get(t, "tag"));
 	
 	if ((outf = fopen(filename, "w")) == NULL)
 		return DC_NOTOK;
 
 	fprintf(outf, "template {\n");
 
-	fprintf(outf, "\ttag \"%s\";\n", escapestr(t->tag));
-	fprintf(outf, "\ttype \"%s\";\n", escapestr(t->type));
-	if (t->defaultval != NULL)
-		fprintf(outf, "\tdefault \"%s\";\n", escapestr(t->defaultval));
-	if (t->choices != NULL)
-		fprintf(outf, "\tchoices \"%s\";\n", escapestr(t->choices));
-	if (t->description != NULL)
-		fprintf(outf, "\tdescription \"%s\";\n", escapestr(t->description));
-	if (t->extended_description != NULL)
-		fprintf(outf, "\textended_description \"%s\";\n", escapestr(t->extended_description));
-
-	langdesc = t->localized_descriptions;
-	while (langdesc) 
+	for (field = template_fields_list; *field != NULL; field++)
 	{
-		if (langdesc->description != NULL) 
-			fprintf(outf, "\tdescription-%s \"%s\";\n", langdesc->language, escapestr(langdesc->description));
-		if (langdesc->extended_description != NULL)
-			fprintf(outf, "\textended_description-%s \"%s\";\n", langdesc->language, escapestr(langdesc->extended_description));
-		if (langdesc->choices != NULL) 
-			fprintf(outf, "\tchoices-%s \"%s\";\n", langdesc->language, escapestr(langdesc->choices));
+		p = t->get(t, *field);
+		if (p != NULL)
+			fprintf(outf, "\t%s \"%s\";\n", *field, escapestr(p));
+	}
 
-		langdesc = langdesc->next;
+	lang = t->next_lang(t, "C");
+	while (lang) 
+	{
+		for (field = template_fields_list; *field != NULL; field++)
+		{
+			p = t->lget(t, lang, *field);
+			if (p != NULL)
+				fprintf(outf, "\t%s-%s \"%s\";\n", *field,
+                                                lang, escapestr(p));
+		}
+		lang = t->next_lang(t, lang);
 	}
 
 	fprintf(outf, "};\n");
@@ -204,16 +201,17 @@
 	}
 	else
 	{
-		t->type = STRDUP(unescapestr(rec->get(rec, "template::type", "string")));
-		t->defaultval = STRDUP(unescapestr(rec->get(rec, "template::default", 0)));
-		t->choices = STRDUP(unescapestr(rec->get(rec, "template::choices", 0)));
-		t->description = STRDUP(unescapestr(rec->get(rec, "template::description", 0)));
-		t->extended_description = STRDUP(unescapestr(rec->get(rec, "template::extended_description", 0)));
+		t->set(t, "type", STRDUP(unescapestr(rec->get(rec, "template::type", "string"))));
+		t->set(t, "default", STRDUP(unescapestr(rec->get(rec, "template::default", 0))));
+		t->set(t, "choices", STRDUP(unescapestr(rec->get(rec, "template::choices", 0))));
+		t->set(t, "description", STRDUP(unescapestr(rec->get(rec, "template::description", 0))));
+		t->set(t, "extended_description", STRDUP(unescapestr(rec->get(rec, "template::extended_description", 0))));
 
 		/* We can't ask for all the localized descriptions so we need to
 		 * brute-force this.
 		 * This is stupid and ugly and should be fixed, FIXME
 		 */
+#if 0
 		for (a = 'a'; a <= 'z'; a++)
 			for (b = 'a'; b <= 'z'; b++)
 			{
@@ -239,6 +237,7 @@
 					t->localized_descriptions = langdesc;
 				}
 			}
+#endif
 	}
 		
 
Index: src/modules/frontend/bogl/bogl.c
===================================================================
RCS file: /cvs/debian-boot/debian-installer/tools/cdebconf/src/modules/frontend/bogl/bogl.c,v
retrieving revision 1.4
diff -u -r1.4 bogl.c
--- src/modules/frontend/bogl/bogl.c	2 Jul 2002 06:53:47 -0000	1.4
+++ src/modules/frontend/bogl/bogl.c	9 Nov 2002 01:21:19 -0000
@@ -58,12 +58,12 @@
 static void drawdesctop(struct frontend *ui, struct question *q)
 {
 	bowl_title(ui->title);
-	bowl_new_text(question_description(q));
+	bowl_new_text(question_get_translated_field(q, "description"));
 }
 
 static void drawdescbot(struct frontend *ui, struct question *q)
 {
-	bowl_new_text(question_extended_description(q));
+	bowl_new_text(question_get_translated_field(q, "extended_description"));
 }
 
 /* boolean requires a new widget, the radio button :( */
@@ -71,7 +71,7 @@
 int bogl_handler_boolean(struct frontend *ui, struct question *q)
 {
 	/* Should just make bowl_new_checkbox be properly const-qualified. */
-	char *desc = strdup(question_description(q));
+	char *desc = strdup(question_get_translated_field(q, "description"));
 	int ret;
 	
 #if 0
@@ -120,40 +120,50 @@
 
 int bogl_handler_multiselect(struct frontend *ui, struct question *q)
 {
-	int nchoices, ndefs, ret, i, j;
+	char **choices, **choices_translated, **defaults, *selected;
+	int i, j, count, dcount, ret;
 	const char *p;
-	char **choices, **defaults, *selected;
-	
-	nchoices = 1;
-	for(p = question_choices(q); *p; p++)
-		if(*p == ',')
-		  	nchoices++;
-	choices = malloc(sizeof(char *) * nchoices);
-	nchoices = strchoicesplit(question_choices(q), choices, nchoices);
-	selected = malloc(sizeof(char) * nchoices);
-	memset(selected, ' ', nchoices);
 
-	ndefs = 1;
-	for(p = question_defaultval(q); *p; p++)
+	count = 0;
+	p = question_get_field(q, "choices");
+	if (*p)
+	{
+		count++;
+		for(; *p; p++)
+			if(*p == ',')
+				count++;
+	}
+
+	if (count <= 0) return DC_NOTOK;
+
+	choices = malloc(sizeof(char *) * count);
+	strchoicesplit(question_get_field(q, "choices"), choices, count);
+	choices_translated = malloc(sizeof(char *) * count);
+	strchoicesplit(question_get_field(q, "choices"), choices_translated, count);
+	selected = malloc(sizeof(char) * count);
+	memset(selected, ' ', count);
+
+	dcount = 1;
+	for(p = question_get_field(q, "default"); *p; p++)
 		if(*p == ',')
-		  	ndefs++;
-	defaults = malloc(sizeof(char *) * ndefs);
-	ndefs = strchoicesplit(question_defaultval(q), defaults, ndefs);
-	for(i = 0; i < ndefs; i++)
+		  	dcount++;
+	defaults = malloc(sizeof(char *) * dcount);
+	dcount = strchoicesplit(question_get_field(q, "default"), defaults, dcount);
+	for(j = 0; j < dcount; j++)
 	{
-		for(j = 0; j < nchoices; j++)
-			if(strcmp(choices[j], defaults[i]) == 0)
+		for(i = 0; i < count; i++)
+			if(strcmp(choices[i], defaults[j]) == 0)
 			{
-				selected[j] = '*';
+				selected[i] = '*';
 				break;
 			}
-		free(defaults[i]);
+		free(defaults[j]);
 	}
 	free(defaults);
 
 	bowl_flush();
 	drawdesctop(ui, q);
-	bowl_new_checkbox(choices, selected, nchoices, (nchoices > 15) ? 15 : nchoices);
+	bowl_new_checkbox(choices, selected, count, (count > 15) ? 15 : count);
 	drawnavbuttons(ui, q);
 	drawdescbot(ui, q);
 	
@@ -163,19 +173,19 @@
 	if(ret == DC_OK)
 	{
 		/* Be safe - allow for commas and spaces. */
-		char *answer = malloc(strlen(question_choices(q)) + 1 + nchoices);
+		char *answer = malloc(strlen(question_get_translated_field(q, "choices")) + 1 + count);
 		answer[0] = 0;
-		for(i = 0; i < nchoices; i++)
+		for(i = 0; i < count; i++)
 			if (selected[i] == '*')
 			{
 				if(answer[0] != 0)
 					strcat(answer, ", ");
-				strcat(answer, choices[i]);
+				strcat(answer, choices_translated[i]);
 			}
 		question_setvalue(q, answer);
 	}
 
-	for(i = 0; i < nchoices; i++)
+	for(i = 0; i < count; i++)
 		free(choices[i]);
 	free(choices);
 
@@ -189,7 +199,7 @@
 
 	bowl_flush();
 	drawdesctop(ui, q);
-	bowl_new_input(&s, question_defaultval(q));
+	bowl_new_input(&s, question_get_field(q, "default"));
 	drawnavbuttons(ui, q);
 	drawdescbot(ui, q);
 	bowl_layout();
Index: src/modules/frontend/ncurses/ncurses.c
===================================================================
RCS file: /cvs/debian-boot/debian-installer/tools/cdebconf/src/modules/frontend/ncurses/ncurses.c,v
retrieving revision 1.9
diff -u -r1.9 ncurses.c
--- src/modules/frontend/ncurses/ncurses.c	9 Jul 2002 05:25:04 -0000	1.9
+++ src/modules/frontend/ncurses/ncurses.c	9 Nov 2002 01:21:19 -0000
@@ -223,8 +223,8 @@
 	WINDOW *descwin = UIDATA(ui)->descwin;
 
 	drawframe(ui, WIN_QUERY, ui->title);
-	wrapprint(qrywin, question_description(q), 0, COLS-2);
-	wrapprint(descwin, question_extended_description(q), 0, COLS-2);
+	wrapprint(qrywin, question_get_translated_field(q, "description"), 0, COLS-2);
+	wrapprint(descwin, question_get_translated_field(q, "extended_description"), 0, COLS-2);
 	wclrtobot(qrywin);
 	wclrtobot(descwin);
 	wrefresh(stdscr);
@@ -237,12 +237,17 @@
 	char *value = "true";
 	int ret = 0, ans, pos = 2;
 	int ybut = UIDATA(ui)->qrylines - 6;
+	char *dft;
 	WINDOW *win = UIDATA(ui)->qrywin;
 
 	if (q->value != 0 && *q->value != 0)
 		value = q->value;
-	else if (q->template->defaultval != 0 && *q->template->defaultval != 0)
-		value = q->template->defaultval;
+	else
+	{
+		dft = (char *) q->template->get(q->template, "default");
+		if (dft != 0 && *dft != 0)
+			value = dft;
+	}
 
 	ans = (strcmp(value, "true") == 0);
 
@@ -351,29 +356,33 @@
 
 static int nchandler_select(struct frontend *ui, struct question *q)
 {
-	char *value = NULL;
 	char *choices[100] = {0};
-	int i, count, ret = 0, val = 0, pos = 2, xpos, ypos;
+	char *choices_translated[100] = {0};
+	char *defaults[100] = {0};
+	const char *defval = question_get_field(q, "default");
+
+	int i, count, dcount, ret = 0, def = -1, pos = 2, xpos, ypos;
 	int top, bottom, longest;
 	WINDOW *win = UIDATA(ui)->qrywin;
 
 	/* Parse out all the choices */
-	count = strchoicesplit((char *)question_choices(q), choices, DIM(choices));
+	count = strchoicesplit(question_get_field(q, "choices"), choices, DIM(choices));
 	if (count <= 0) return DC_NOTOK;
 
+	strchoicesplit(question_get_translated_field(q, "choices"), choices_translated, DIM(choices_translated));
+	dcount = strchoicesplit(question_get_field(q, "default"), defaults, DIM(defaults));
+
 	/* See what the currently selected value should be -- either a
 	 * previously selected value, or the default for the question
 	 */
-	if ((q->value != 0 && *q->value != 0 && (value = q->value)) ||
-	    (q->template->defaultval != 0 && *q->template->defaultval != 0 && 
-		(value = q->template->defaultval)))
+	if (defval != NULL)
 	{
 		for (i = 0; i < count; i++)
-			if (strcmp(choices[i], value) == 0)
-				val = i;
+			if (strcmp(choices[i], defval) == 0)
+				def = i + 1;
 	}
 
-	longest = longestlen(choices, count);
+	longest = longestlen(choices_translated, count);
 	top = 0; bottom = MIN(count, UIDATA(ui)->qrylines-5);
 	xpos = (COLS-longest)/2-1;
 
@@ -382,11 +391,11 @@
 		ypos = 2;
 		for (i = top; i < bottom; i++)
 		{
-			if (pos == 2 && i == val) 
+			if (pos == 2 && i == def) 
 				wstandout(win); 
 			else 
 				wstandend(win);
-			mvwprintw(win, ypos++, xpos, " %-*s ", longest, choices[i]);
+			mvwprintw(win, ypos++, xpos, " %-*s ", longest, choices_translated[i]);
 		}
 		wstandend(win);
 
@@ -398,17 +407,17 @@
 		{
 		case KEY_LEFT:
 		case KEY_UP:
-			val--;
-			if (val < 0) val = count-1;
+			def--;
+			if (def < 0) def = count-1;
 
-			/* check val against top/bottom */
+			/* check def against top/bottom */
 			break;
 		case KEY_RIGHT:
 		case KEY_DOWN:
-			val++;
-			if (val >= count) val = 0;
+			def++;
+			if (def >= count) def = 0;
 
-			/* check val against top/bottom */
+			/* check def against top/bottom */
 			break;
 		case 9: /* TAB */
 			pos++;
@@ -432,7 +441,7 @@
 		}
 	}
 	if (ret == DC_OK)
-		question_setvalue(q, choices[val]);
+		question_setvalue(q, choices[def]);
 	return ret;
 }
 
Index: src/modules/frontend/slang/slang.c
===================================================================
RCS file: /cvs/debian-boot/debian-installer/tools/cdebconf/src/modules/frontend/slang/slang.c,v
retrieving revision 1.11
diff -u -r1.11 slang.c
--- src/modules/frontend/slang/slang.c	9 Jul 2002 05:25:04 -0000	1.11
+++ src/modules/frontend/slang/slang.c	9 Nov 2002 01:21:20 -0000
@@ -197,8 +197,8 @@
 	slang_drawwin(&uid->qrywin);
 	slang_drawwin(&uid->descwin);
 	/* Draw in the descriptions */
-	slang_wrapprint(&uid->qrywin, question_description(q), 0);
-	slang_wrapprint(&uid->descwin, question_extended_description(q),
+	slang_wrapprint(&uid->qrywin, question_get_translated_field(q, "description"), 0);
+	slang_wrapprint(&uid->descwin, question_get_translated_field(q, "extended_description"),
 		uid->descstart);
 
 	/* caller should call slang_flush() ! */
@@ -319,7 +319,7 @@
 	const char *value = "true";
 	int ret = 0, ans, pos = 2;
 
-	value = question_defaultval(q);
+	value = question_get_field(q, "default");
 
 	ans = (strcmp(value, "true") == 0);
 
@@ -373,6 +373,7 @@
 static int slang_getselect(struct frontend *ui, struct question *q, int multi)
 {
 	char *choices[100] = {0};
+	char *choices_translated[100] = {0};
 	char *defaults[100] = {0};
 	char selected[100] = {0};
 	char answer[1024] = {0};
@@ -382,8 +383,9 @@
 	struct slwindow *win = &uid->qrywin;
 
 	/* Parse out all the choices */
-	count = strchoicesplit(question_choices(q), choices, DIM(choices));
-	dcount = strchoicesplit(question_defaultval(q), defaults, DIM(defaults));
+	count = strchoicesplit(question_get_field(q, "choices"), choices, DIM(choices));
+	strchoicesplit(question_get_translated_field(q, "choices"), choices_translated, DIM(choices_translated));
+	dcount = strchoicesplit(question_get_field(q, "default"), defaults, DIM(defaults));
 	INFO(INFO_VERBOSE, "Parsed out %d choices, %d defaults\n", count, dcount);
 	if (count <= 0) return DC_NOTOK;
 
@@ -391,11 +393,9 @@
 	 * previously selected value, or the default for the question
 	 */
 	for (j = 0; j < dcount; j++)
-	{
 		for (i = 0; i < count; i++)
 			if (strcmp(choices[i], defaults[j]) == 0)
 				selected[i] = 1;
-	}
 
 	longest = strlongest(choices, count);
 	top = 0;
@@ -414,10 +414,10 @@
 			slang_printf(ypos++, xpos, ((pos == 2 && i == val) ?
 				win->selectedcolor : win->drawcolor),
 				"(%c) %-*s ", (selected[i] ? '*' : ' '), 
-				longest, choices[i]);
+				longest, choices_translated[i]);
 
 			INFO(INFO_VERBOSE, "(%c) %-*s\n", (selected[i] ? '*' : 
-				' '), longest, choices[i]);
+				' '), longest, choices_translated[i]);
 		}
 
 		slang_navbuttons(ui, q, pos);
@@ -454,7 +454,7 @@
 			case 0: ret = DC_GOBACK; break;
 			case 1: ret = DC_OK; break;
 			default: 
-				if (multi == 0)
+				if (multi == 1)
 				{
 					memset(selected, 0, sizeof(selected));
 					selected[val] = 1;
@@ -477,10 +477,12 @@
 			strvacat(answer, sizeof(answer), choices[i], NULL);
 		}
 		free(choices[i]);
+		free(choices_translated[i]);
 	}
 	for (i = 0; i < dcount; i++)
 		free(defaults[i]);
 	question_setvalue(q, answer);
+
 	return DC_OK;
 }
 
@@ -505,7 +507,7 @@
 	int cursor;
 	char *tmp;
 
-	STRCPY(value, question_defaultval(q));
+	STRCPY(value, question_get_field(q, "default"));
 	cursor = strlen(value);
 
 	/* TODO: scrolling */
Index: src/modules/frontend/text/text.c
===================================================================
RCS file: /cvs/debian-boot/debian-installer/tools/cdebconf/src/modules/frontend/text/text.c,v
retrieving revision 1.15
diff -u -r1.15 text.c
--- src/modules/frontend/text/text.c	5 Nov 2002 03:01:51 -0000	1.15
+++ src/modules/frontend/text/text.c	9 Nov 2002 01:21:20 -0000
@@ -119,8 +119,8 @@
  */
 static void texthandler_displaydesc(struct frontend *obj, struct question *q) 
 {
-	wrap_print(question_description(q));
-	wrap_print(question_extended_description(q));
+	wrap_print(question_get_translated_field(q, "description"));
+	wrap_print(question_get_translated_field(q, "extended_description"));
 }
 
 /*
@@ -138,7 +138,7 @@
 	int def = -1;
 	const char *defval;
 
-	defval = question_defaultval(q);
+	defval = question_get_field(q, "default");
 	if (defval)
 	{
 		if (strcmp(defval, "true") == 0)
@@ -180,25 +180,28 @@
 static int texthandler_multiselect(struct frontend *obj, struct question *q)
 {
 	char *choices[100] = {0};
+	char *choices_translated[100] = {0};
 	char *defaults[100] = {0};
 	char selected[100] = {0};
-	char answer[1024];
+	char answer[1024] = {0};
 	int i, j, count, dcount, choice;
 
-	count = strchoicesplit(question_choices(q), choices, DIM(choices));
-	dcount = strchoicesplit(question_defaultval(q), defaults, DIM(defaults));
+	count = strchoicesplit(question_get_field(q, "choices"), choices, DIM(choices));
+	if (count <= 0) return DC_NOTOK;
+
+	strchoicesplit(question_get_translated_field(q, "choices"), choices_translated, DIM(choices_translated));
+	dcount = strchoicesplit(question_get_field(q, "default"), defaults, DIM(defaults));
 
-	if (dcount > 0)
+	for (j = 0; j < dcount; j++)
 		for (i = 0; i < count; i++)
-			for (j = 0; j < dcount; j++)
-				if (strcmp(choices[i], defaults[j]) == 0)
-					selected[i] = 1;
+			if (strcmp(choices[i], defaults[j]) == 0)
+				selected[i] = 1;
 
 	while(1)
 	{
 		for (i = 0; i < count; i++)
 		{
-			printf("%3d. %s%s\n", i+1, choices[i], 
+			printf("%3d. %s%s\n", i+1, choices_translated[i], 
 				(selected[i] ? _(" (selected)") : ""));
 			
 		}
@@ -217,7 +220,6 @@
 		}
 	}
 
-	answer[0] = 0;
 	for (i = 0; i < count; i++)
 	{
 		if (selected[i])
@@ -227,6 +229,7 @@
 			strvacat(answer, sizeof(answer), choices[i], NULL);
 		}
 		free(choices[i]);
+		free(choices_translated[i]);
 	}
 	for (i = 0; i < dcount; i++)
 		free(defaults[i]);
@@ -301,34 +304,33 @@
 	char *choices_translated[100] = {0};
 	char answer[10];
 	int i, count, choice = 1, def = -1;
-	const char *defval = question_defaultval(q);
+	const char *defval = question_get_field(q, "default");
+
+	count = strchoicesplit(question_get_field(q, "choices"), choices, DIM(choices));
+	if (count <= 0) return DC_NOTOK;
 
-	count = strchoicesplit(question_choices(q), choices, DIM(choices));
-	strchoicesplit(question_choices_translated(q), choices_translated, DIM(choices_translated));
+	strchoicesplit(question_get_translated_field(q, "choices"), choices_translated, DIM(choices_translated));
         /* fprintf(stderr,"In texthandler_select, count is: %d\n", count);*/
-	if (count > 1)
+	if (defval != NULL)
 	{
-		if (defval != NULL)
-		{
-			for (i = 0; i < count; i++)
-				if (strcmp(choices[i], defval) == 0)
-					def = i + 1;
-		}
-
-		do
-		{
-			for (i = 0; i < count; i++)
-				printf("%3d. %s%s\n", i+1, choices_translated[i],
-					(def == i + 1 ? _(" (default)") : ""));
-
-			printf(_("Prompt: 1 - %d> "), count);
-			fgets(answer, sizeof(answer), stdin);
-			if (answer[0] == '\n')
-				choice = def;
-			else
-				choice = atoi(answer);
-		} while (choice <= 0 || choice > count);
+		for (i = 0; i < count; i++)
+			if (strcmp(choices[i], defval) == 0)
+				def = i + 1;
 	}
+
+	do
+	{
+		for (i = 0; i < count; i++)
+			printf("%3d. %s%s\n", i+1, choices_translated[i],
+				(def == i + 1 ? _(" (default)") : ""));
+
+		printf(_("Prompt: 1 - %d> "), count);
+		fgets(answer, sizeof(answer), stdin);
+		if (answer[0] == '\n')
+			choice = def;
+		else
+			choice = atoi(answer);
+	} while (choice <= 0 || choice > count);
 	/*	fprintf(stderr,"In %s, line: %d\n\tanswer: %s, choice[choice]: %s\n",
 		__FILE__,__LINE__,answer, choices[choice - 1]);*/
 	question_setvalue(q, choices[choice - 1]);
@@ -352,7 +354,7 @@
 static int texthandler_string(struct frontend *obj, struct question *q)
 {
 	char buf[1024] = {0};
-	const char *defval = question_defaultval(q);
+	const char *defval = question_get_field(q, "default");
 	if (defval)
 		printf(_("[default = %s]"), defval);
 	printf("> "); fflush(stdout);

Reply to: