Codebase list cdebconf / 0a7eafd
Add support for "debconf directives", written ${!DIRECTIVE} Directives are special variables written like ${!DIRECTIVE} which expansion are delegated to the frontends, through the new lookup_directive() "method". As the frontend object is now given to question_get_field(), a new function, question_get_raw_field() has been introduced to use in cdebconf core. Implementation details: * lookup_vars() returns NULL when variables start with '!' and strexpand() will skip the expansion in that case. * question_get_field() makes another call to strexpand() after having expanded variables in order to expand directives; giving it a wrapper around the lookup_directive "method" as the lookup function. * commands.c has been updated to use question_get_raw_* variants. * text, newt and gtk frontends have been updated to give question_get_field() proper arguments. * question_get_text() expands directives as it is only used in frontends. * The q_get_choice_vals() macro uses question_get_raw_field() as (multi)select results should not be processed by directive expansion. r52209 Jérémy Bobbio 16 years ago
15 changed file(s) with 122 addition(s) and 56 deletion(s). Raw diff Collapse all Expand all
0 debconf directives
1 ==================
2
3 cdebconf implements an extension to the Debconf specifications called
4 directives. Directives are written in templates or substitutions enclosed into
5 "${!" and "}", for example "${!DIRECTIVE}".
6
7 . Directives are not expanded like normal variables and will be given back
8 /!\ as is by GET and METAGET commands. This is the desired behaviour when,
9 ~~~ for examples, one implements a dynamic Choices field for select questions
10 with directives in SUBSTitutions.
11
12 Directives are expanded according to the result of the lookup_directive()
13 "method" implemented in the frontends when question_get_field() is called.
14 By default, they will be expanded to the empty string, removing them from the
15 returned value for unimplemented directives.
301301 Currently, the only capability supported is DCF_CAPB_BACKUP, which
302302 means the front end is capable of backing up, so return either
303303 0 of DCF_CAPB_BACKUP.
304 * const char * lookup_directive(struct frontend *, const char *)
305 Return the proper value for the given directive. If NULL is returned,
306 the directive is not expanded.
307 The default method always returns "" to remove unhandled directives from
308 queried question fields.
304309 * int add(struct frontend *, struct question *):
305310 Add question. Default implementation adds the question to "questions"
306311 attribute
462462 return out;
463463 }
464464
465 value = question_get_field(q, "", argv[1]);
465 value = question_get_raw_field(q, "", argv[1]);
466466 if (value == NULL)
467467 asprintf(&out, "%u %s does not exist", CMDSTATUS_BADQUESTION, argv[1]);
468468 else
651651 CMDSTATUS_BADQUESTION, argv[3]);
652652 return out;
653653 }
654 value = question_get_field(q, "", "description");
654 value = question_get_raw_field(q, "", "description");
655655 question_deref(q);
656656 if (value == NULL)
657657 {
695695 CMDSTATUS_BADQUESTION, argv[1]);
696696 return out;
697697 }
698 value = question_get_field(q, "", "description");
698 value = question_get_raw_field(q, "", "description");
699699 question_deref(q);
700700 if (value == NULL)
701701 {
744744 asprintf(&out, "%u %s does not exist", CMDSTATUS_BADQUESTION, arg);
745745 return out;
746746 }
747 value = question_get_field(q, "", "description");
747 value = question_get_raw_field(q, "", "description");
748748 question_deref(q);
749749 if (value == NULL)
750750 {
7272 return 0;
7373 }
7474
75 static const char * frontend_lookup_directive(struct frontend *obj,
76 const char *directive)
77 {
78 /* Remove unhandled directives. */
79 return "";
80 }
81
7582 static void frontend_set_title(struct frontend *f, const char *title)
7683 {
7784 DELETE(f->title);
199206 SETMETHOD(initialize);
200207 SETMETHOD(shutdown);
201208 SETMETHOD(query_capability);
209 SETMETHOD(lookup_directive);
202210 SETMETHOD(set_title);
203211 SETMETHOD(info);
204212 SETMETHOD(add);
77 #include <stdbool.h>
88
99 #include "constants.h"
10 #include "strutl.h"
1011
1112 #undef _
1213 #define _(x) (x)
2425 int (*initialize)(struct frontend *, struct configuration *);
2526 int (*shutdown)(struct frontend *);
2627 unsigned long (*query_capability)(struct frontend *);
28 const char * (*lookup_directive)(struct frontend *, const char *);
2729 void (*set_title)(struct frontend *, const char *title);
2830 void (*info)(struct frontend *, struct question *);
2931 int (*add)(struct frontend *, struct question *q);
8787 struct question * question = fe->qdb->methods.get(fe->qdb, template);
8888 char * text;
8989
90 text = question ? q_get_description(question) : g_strdup(fallback);
90 text = question ? q_get_description(fe, question) : g_strdup(fallback);
9191 question_deref(question);
9292 return text;
9393 }
140140 return NULL;
141141 };
142142
143 raw_indices = q_get_indices(question);
144 raw_choices = q_get_choices_vals(question);
145 raw_translated_choices = q_get_choices(question);
143 raw_indices = q_get_indices(fe, question);
144 raw_choices = q_get_choices_vals(fe, question);
145 raw_translated_choices = q_get_choices(fe, question);
146146 count = strgetargc(raw_choices);
147147 g_assert(0 < count);
148148 /* check NULLs! */
139139 GtkTextIter end;
140140 char * description;
141141
142 description = q_get_description(question);
142 description = q_get_description(fe, question);
143143 /* XXX: check NULL! */
144144 view = gtk_text_view_new();
145145 /* XXX: check NULL! */
184184 /* here is created the question's extended description, but only
185185 * if the question's extended description actually exists
186186 */
187 ext_description = q_get_extended_description(question);
187 ext_description = q_get_extended_description(fe, question);
188188 if ('\0' != ext_description[0]) {
189189 view = gtk_text_view_new();
190190 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
264264 hide_expanders(GTK_TREE_VIEW(view));
265265 }
266266
267 description = q_get_description(question);
267 description = q_get_description(fe, question);
268268 text_renderer = gtk_cell_renderer_text_new();
269269 gtk_tree_view_insert_column_with_attributes(
270270 GTK_TREE_VIEW(view), -1 /* insert at the end */,
103103 char * text;
104104
105105 if (NULL != fe->info) {
106 text = q_get_description(fe->info);
106 text = q_get_description(fe, fe->info);
107107 message = g_strdup_printf(
108108 "<b><span foreground=\"#ffffff\">%s</span></b>", text);
109109 layout = gtk_widget_create_pango_layout(
244244 }
245245
246246 static int
247 min_window_height(struct question *q, int win_width)
247 min_window_height(struct frontend *obj, struct question *q, int win_width)
248248 {
249249 int height = 3;
250250 char *type = q->template->type;
251251 char *q_ext_text;
252252
253 q_ext_text = q_get_extended_description(q);
253 q_ext_text = q_get_extended_description(obj, q);
254254 if (q_ext_text != NULL)
255255 height = cdebconf_newt_get_text_height(q_ext_text, win_width) + 1;
256256 if (strcmp(type, "multiselect") == 0 || strcmp(type, "select") == 0)
262262 }
263263
264264 static int
265 need_separate_window(struct question *q)
265 need_separate_window(struct frontend *obj, struct question *q)
266266 {
267267 int width = 80, height = 24;
268268 int x;
269269
270270 newtGetScreenSize(&width, &height);
271 x = min_window_height(q, width-7);
271 x = min_window_height(obj, q, width-7);
272272 return (x >= height-5);
273273 }
274274
275275 static char *
276 get_full_description(struct question *q)
276 get_full_description(struct frontend *obj, struct question *q)
277277 {
278278 char *res = NULL;
279 char *descr = q_get_description(q);
280 char *ext_descr = q_get_extended_description(q);
279 char *descr = q_get_description(obj, q);
280 char *ext_descr = q_get_extended_description(obj, q);
281281
282282 assert(descr);
283283 assert(ext_descr);
311311 #else
312312 int flags = NEWT_FLAG_WRAP;
313313 #endif
314 char *descr = q_get_description(q);
315 char *ext_descr = q_get_extended_description(q);
314 char *descr = q_get_description(obj, q);
315 char *ext_descr = q_get_extended_description(obj, q);
316316
317317 assert(descr);
318318 assert(ext_descr);
324324 full_description = strdup(ext_descr);
325325 }
326326 else
327 full_description = get_full_description(q);
327 full_description = get_full_description(obj, q);
328328
329329 newtGetScreenSize(&width, &height);
330330 win_width = width-7;
409409 #endif
410410 char *defval;
411411 const char *result;
412 char *full_description = get_full_description(q);
412 char *full_description = get_full_description(obj, q);
413413
414414 eflags |= NEWT_ENTRY_SCROLL | NEWT_FLAG_RETURNEXIT;
415415 newtGetScreenSize(&width, &height);
495495 size_t res;
496496 wchar_t c;
497497 int *tindex = NULL;
498 const char *indices = q_get_indices(q);
499 char *full_description = get_full_description(q);
498 const char *indices = q_get_indices(obj, q);
499 char *full_description = get_full_description(obj, q);
500500 #ifdef HAVE_LIBTEXTWRAP
501501 textwrap_t tw;
502502 char *wrappedtext;
508508 newtGetScreenSize(&width, &height);
509509 win_width = width-7;
510510 strtruncate(obj->title, win_width-9);
511 count = strgetargc(q_get_choices_vals(q));
511 count = strgetargc(q_get_choices_vals(obj, q));
512512 if (count <= 0)
513513 return DC_NOTOK;
514514 choices = malloc(sizeof(char *) * count);
515515 choices_trans = malloc(sizeof(char *) * count);
516516 tindex = malloc(sizeof(int) * count);
517 if (strchoicesplitsort(q_get_choices_vals(q), q_get_choices(q), indices, choices, choices_trans, tindex, count) != count)
517 if (strchoicesplitsort(q_get_choices_vals(obj, q), q_get_choices(obj, q), indices, choices, choices_trans, tindex, count) != count)
518518 return DC_NOTOK;
519519
520520 defvals = malloc(sizeof(char *) * count);
647647 char **choices, **choices_trans, *defval;
648648 int count = 0, i, ret, defchoice = -1;
649649 int *tindex = NULL;
650 const char *indices = q_get_indices(q);
651 char *full_description = get_full_description(q);
650 const char *indices = q_get_indices(obj, q);
651 char *full_description = get_full_description(obj, q);
652652 char *p;
653653 size_t res;
654654 int k;
664664 newtGetScreenSize(&width, &height);
665665 win_width = width-7;
666666 strtruncate(obj->title, win_width-9);
667 count = strgetargc(q_get_choices_vals(q));
667 count = strgetargc(q_get_choices_vals(obj, q));
668668 if (count <= 0)
669669 return DC_NOTOK;
670670 choices = malloc(sizeof(char *) * count);
671671 choices_trans = malloc(sizeof(char *) * count);
672672 tindex = malloc(sizeof(int) * count);
673 if (strchoicesplitsort(q_get_choices_vals(q), q_get_choices(q), indices, choices, choices_trans, tindex, count) != count)
673 if (strchoicesplitsort(q_get_choices_vals(obj, q), q_get_choices(obj, q), indices, choices, choices_trans, tindex, count) != count)
674674 return DC_NOTOK;
675675
676676 sel_height = count;
787787 #else
788788 int flags = NEWT_FLAG_WRAP;
789789 #endif
790 char *full_description = get_full_description(q);
790 char *full_description = get_full_description(obj, q);
791791
792792 newtGetScreenSize(&width, &height);
793793 win_width = width-7;
877877 {
878878 int separate_window, ret;
879879
880 separate_window = need_separate_window(q);
880 separate_window = need_separate_window(obj, q);
881881 while (1) {
882882 if (separate_window) {
883883 ret = show_separate_window(obj, q);
905905 {
906906 int separate_window, ret;
907907
908 separate_window = need_separate_window(q);
908 separate_window = need_separate_window(obj, q);
909909 while (1) {
910910 if (separate_window) {
911911 ret = show_separate_window(obj, q);
10941094 newtCls();
10951095 }
10961096 if (obj->info != NULL) {
1097 char *text = q_get_description(obj->info);
1097 char *text = q_get_description(obj, obj->info);
10981098 if (text)
10991099 newtDrawRootText(0, 0, text);
11001100 free(text);
12351235 newtSetColors(newtAltColorPalette);
12361236 newtCls();
12371237 if (obj->info != NULL) {
1238 char *text = q_get_description(obj->info);
1238 char *text = q_get_description(obj, obj->info);
12391239 if (text)
12401240 newtDrawRootText(0, 0, text);
12411241 free(text);
160160 */
161161 static void text_handler_displaydesc(struct frontend *obj, struct question *q)
162162 {
163 char *descr = q_get_description(q);
164 char *ext_descr = q_get_extended_description(q);
163 char *descr = q_get_description(obj, q);
164 char *ext_descr = q_get_extended_description(obj, q);
165165 if (strcmp(q->template->type, "note") == 0 ||
166166 strcmp(q->template->type, "error") == 0)
167167 {
193193 static void
194194 show_help (struct frontend *obj, struct question *q)
195195 {
196 char *descr = q_get_description(q);
196 char *descr = q_get_description(obj, q);
197197 printf("%s", question_get_text(obj, "debconf/text-help-keystrokes", "KEYSTROKES:"));
198198 printf("\n %c ", CHAR_HELP);
199199 printf("%s", question_get_text(obj, "debconf/text-help-help", "Display this help message"));
387387 int i, j, count = 0, dcount, choice;
388388 int *tindex = NULL;
389389 int ret = DC_OK;
390 const char *indices = q_get_indices(q);
391
392 count = strgetargc(q_get_choices_vals(q));
390 const char *indices = q_get_indices(obj, q);
391
392 count = strgetargc(q_get_choices_vals(obj, q));
393393 if (count <= 0)
394394 return DC_NOTOK;
395395 choices = malloc(sizeof(char *) * count);
399399 choices[i] = choices_translated[i] = NULL;
400400 }
401401 tindex = malloc(sizeof(int) * count);
402 if (strchoicesplitsort(q_get_choices_vals(q), q_get_choices(q), indices, choices, choices_translated, tindex, count) != count)
402 if (strchoicesplitsort(q_get_choices_vals(obj, q), q_get_choices(obj, q), indices, choices, choices_translated, tindex, count) != count)
403403 {
404404 ret = DC_NOTOK;
405405 goto CleanUp_TINDEX;
514514 const char *defval = question_getvalue(q, "");
515515 int *tindex = NULL;
516516 int ret = DC_OK;
517 const char *indices = q_get_indices(q);
518
519 count = strgetargc(q_get_choices_vals(q));
517 const char *indices = q_get_indices(obj, q);
518
519 count = strgetargc(q_get_choices_vals(obj, q));
520520 if (count <= 0)
521521 return DC_NOTOK;
522522 choices = malloc(sizeof(char *) * count);
526526 choices[i] = choices_translated[i] = NULL;
527527 }
528528 tindex = malloc(sizeof(int) * count);
529 if (strchoicesplitsort(q_get_choices_vals(q), q_get_choices(q), indices, choices, choices_translated, tindex, count) != count)
529 if (strchoicesplitsort(q_get_choices_vals(obj, q), q_get_choices(obj, q), indices, choices, choices_translated, tindex, count) != count)
530530 {
531531 ret = DC_NOTOK;
532532 goto CleanUp_TINDEX;
172172 {
173173 struct questionvariable * current;
174174
175 /* Skip directives */
176 if ('!' == name[0]) {
177 return NULL;
178 }
175179 for (current = variables; NULL != current; current = current->next) {
176180 if (0 == strcmp(current->variable, name)) {
177181 return current->value;
185189 return strexpand(field, LOOKUP_FUNCTION(lookup_vars), q->variables);
186190 }
187191
188 char *question_get_field(const struct question *q, const char *lang,
192 char *question_get_raw_field(const struct question *q, const char *lang,
189193 const char *field)
190194 {
191195 char *ret;
203207 return strdup("");
204208 else
205209 return ret;
210 }
211
212 static const char * lookup_directive(const char * directive, struct frontend * fe)
213 {
214 assert('!' == directive[0]);
215 return fe->methods.lookup_directive(fe, directive + 1 /* drop '!' */);
216 }
217
218 char * question_get_field(struct frontend * fe, const struct question * q,
219 const char * lang, const char * field)
220 {
221 char * raw;
222 char * ret;
223
224 raw = question_get_raw_field(q, lang, field);
225 ret = strexpand(raw, LOOKUP_FUNCTION(lookup_directive), fe);
226 free(raw);
227 return ret;
206228 }
207229
208230 /*
220242 {
221243 struct question *q = obj->qdb->methods.get(obj->qdb, template);
222244 const char *text;
223 text = (q ? q_get_description(q) : fallback);
245 text = (q ? q_get_description(obj, q) : fallback);
224246 question_deref(q);
225247 return text;
226248 }
77 #define DC_QFLAG_SEEN (1 << 0)
88 #define DC_QFLAG_DONTPARSE (1 << 1)
99
10 #define q_get_extended_description(q) question_get_field((q), "", "extended_description")
11 #define q_get_description(q) question_get_field((q), "", "description")
12 #define q_get_choices(q) question_get_field((q), "", "choices")
13 #define q_get_choices_vals(q) question_get_field((q), "C", "choices")
14 #define q_get_indices(q) question_get_field((q), "", "indices")
10 #define q_get_extended_description(fe, q) question_get_field((fe), (q), "", "extended_description")
11 #define q_get_description(fe, q) question_get_field((fe), (q), "", "description")
12 #define q_get_choices(fe, q) question_get_field((fe), (q), "", "choices")
13 #define q_get_choices_vals(fe, q) question_get_raw_field((q), "C", "choices")
14 #define q_get_indices(fe, q) question_get_field((fe), (q), "", "indices")
15 #define q_get_raw_extended_description(q) question_get_raw_field((q), "", "extended_description")
16 #define q_get_raw_description(q) question_get_raw_field((q), "", "description")
17 #define q_get_raw_choices(q) question_get_raw_field((q), "", "choices")
18 #define q_get_raw_choices_vals(q) question_get_raw_field((q), "C", "choices")
19 #define q_get_raw_indices(q) question_get_raw_field((q), "", "indices")
1520
1621 struct template;
1722 struct frontend;
6671
6772 void question_owner_add(struct question *q, const char *owner);
6873 void question_owner_delete(struct question *q, const char *owner);
69 char *question_get_field(const struct question *q, const char *lang,
74 char *question_get_raw_field(const struct question *q, const char *lang,
7075 const char *field);
76 char *question_get_field(struct frontend *obj, const struct question *q,
77 const char *lang, const char *field);
7178
7279 const char *question_get_text(struct frontend *obj, const char *template,
7380 const char *fallback);
607607 var[j] = '\0';
608608 dest_size += rope[rope_index++].len;
609609 rope[rope_index].str = func(var, user_data);
610 rope[rope_index].len = strlen(rope[rope_index].str);
610 /* Handle skips */
611 if (NULL == rope[rope_index].str) {
612 rope[rope_index].str = &src[i - j - 2 /* "${" */];
613 rope[rope_index].len = j + 3; /* "${}" */
614 } else {
615 rope[rope_index].len = strlen(rope[rope_index].str);
616 }
611617 dest_size += rope[rope_index++].len;
612618 /* skip '}' */
613619 rope[rope_index].str = &src[i + 1];