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

Re: [patch] cdebconf and i18n



Hi, 

[ Just lurking on d-i for a while, to get up to speed on the design
before contributing].

Why do you use DEBCONF_LANG rather than LANG or LC_ALL ?

Similarly, in some parts of the installer, there is a need to find the
Country. Shouldn't that be found from LC_ALL as well?

Regards,
Alastair McKinstry


On Sat, 2002-11-09 at 03:05, Denis Barbier wrote:
> 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);
-- 
Alastair McKinstry <mckinstry@debian.org>
GPG Key fingerprint = 9E64 E714 8E08 81F9 F3DC  1020 FA8E 3790 9051 38F4

He that would make his own liberty secure must guard even his enemy from
oppression; for if he violates this duty he establishes a precedent that
will reach to himself.

- --Thomas Paine

Attachment: signature.asc
Description: This is a digitally signed message part


Reply to: