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);