1 /* Options variables manipulation core */
12 #include "bfu/dialog.h"
13 #include "cache/cache.h"
14 #include "config/conf.h"
15 #include "config/dialogs.h"
16 #include "config/domain.h"
17 #include "config/options.h"
18 #include "config/opttypes.h"
19 #include "dialogs/status.h"
20 #include "document/document.h"
21 #include "globhist/globhist.h"
22 #include "intl/charsets.h"
23 #include "intl/gettext/libintl.h"
24 #include "main/main.h" /* shrink_memory() */
25 #include "main/select.h"
26 #include "network/connection.h"
27 #include "session/session.h"
28 #include "terminal/color.h"
29 #include "terminal/screen.h"
30 #include "terminal/terminal.h"
31 #include "util/color.h"
32 #include "util/error.h"
33 #include "util/memory.h"
34 #include "util/string.h"
35 #include "viewer/text/draw.h"
38 /* TODO? In the past, covered by shadow and legends, remembered only by the
39 * ELinks Elders now, options were in hashes (it was not for a long time, after
40 * we started to use dynamic options lists and before we really started to use
41 * hierarchic options). Hashes might be swift and deft, but they had a flaw and
42 * the flaw showed up as the fatal flaw. They were unsorted, and it was
43 * unfriendly to mere mortal users, without pasky's options handlers in their
44 * brain, but their own poor-written software. And thus pasky went and rewrote
45 * options so that they were in lists from then to now and for all the ages of
46 * men, to the glory of mankind. However, one true hero may arise in future
47 * fabulous and implement possibility to have both lists and hashes for trees,
48 * as it may be useful for some supernatural entities. And when that age will
52 /* TODO: We should remove special case for root options and use some auxiliary
53 * (struct option *) instead. This applies to bookmarks, global history and
54 * listbox items as well, though. --pasky */
56 static INIT_LIST_OF(struct option
, options_root_tree
);
58 static struct option options_root
= INIT_OPTION(
63 /* value: */ &options_root_tree
,
68 struct option
*config_options
;
69 struct option
*cmdline_options
;
71 static void add_opt_rec(struct option
*, unsigned char *, struct option
*);
72 static void free_options_tree(LIST_OF(struct option
) *, int recursive
);
75 /* Detect ending '.' (and some others) in options captions.
76 * It will emit a message in debug mode only. --Zas */
78 #define bad_punct(c) (c != ')' && c != '>' && !isquote(c) && ispunct(c))
81 check_caption(unsigned char *caption
)
88 len
= strlen(caption
);
92 if (isspace(c
) || bad_punct(c
))
93 DBG("bad char at end of caption [%s]", caption
);
96 caption
= gettext(caption
);
97 len
= strlen(caption
);
100 c
= caption
[len
- 1];
101 if (isspace(c
) || bad_punct(c
))
102 DBG("bad char at end of i18n caption [%s]", caption
);
109 check_description(unsigned char *desc
)
121 DBG("bad char at end of description [%s]", desc
);
124 desc
= gettext(desc
);
128 if (ispunct(c
) != ispunct(desc
[len
- 1]))
129 DBG("punctuation char possibly missing at end of i18n description [%s]", desc
);
133 DBG("bad char at end of i18n description [%s]", desc
);
137 /*! @relates option */
139 debug_check_option_syntax(struct option
*option
)
142 check_caption(option
->capt
);
143 check_description(option
->desc
);
147 #define debug_check_option_syntax(option)
151 /**********************************************************************
153 **********************************************************************/
155 /* If option name contains dots, they are created as "categories" - first,
156 * first category is retrieved from list, taken as a list, second category
157 * is retrieved etc. */
160 static int no_autocreate
= 0;
162 /** Get record of option of given name, or NULL if there's no such option.
164 * If the specified option is an ::OPT_ALIAS, this function returns the
165 * alias, rather than the option to which the alias refers. It must
166 * work this way because the alias may have the ::OPT_ALIAS_NEGATE flag.
167 * Instead, if the caller tries to read or set the value of the alias,
168 * the functions associated with ::OPT_ALIAS will forward the operation
169 * to the underlying option. However, see indirect_option().
173 get_opt_rec(struct option
*tree
, const unsigned char *name_
)
175 struct option
*option
;
176 unsigned char *aname
= stracpy(name_
);
177 unsigned char *name
= aname
;
180 if (!aname
) return NULL
;
182 /* We iteratively call get_opt_rec() each for path_elements-1, getting
183 * appropriate tree for it and then resolving [path_elements]. */
184 if ((sep
= strrchr((const char *)name
, '.'))) {
187 tree
= get_opt_rec(tree
, name
);
188 if (!tree
|| tree
->type
!= OPT_TREE
|| tree
->flags
& OPT_HIDDEN
) {
190 DBG("ERROR in get_opt_rec() crawl: %s (%d) -> %s",
191 name
, tree
? tree
->type
: -1, sep
+ 1);
201 foreach (option
, *tree
->value
.tree
) {
202 if (option
->name
&& !strcmp(option
->name
, name
)) {
208 if (tree
&& tree
->flags
& OPT_AUTOCREATE
&& !no_autocreate
) {
209 struct option
*template_
= get_opt_rec(tree
, "_template_");
211 assertm(template_
!= NULL
, "Requested %s should be autocreated but "
212 "%.*s._template_ is missing!", name_
, sep
- name_
,
219 /* We will just create the option and return pointer to it
220 * automagically. And, we will create it by cloning _template_
221 * option. By having _template_ OPT_AUTOCREATE and _template_
222 * inside, you can have even multi-level autocreating. */
224 option
= copy_option(template_
, 0);
229 mem_free_set(&option
->name
, stracpy(name
));
231 add_opt_rec(tree
, "", option
);
241 /** Get record of option of given name, or NULL if there's no such option. But
242 * do not create the option if it doesn't exist and there's autocreation
246 get_opt_rec_real(struct option
*tree
, const unsigned char *name
)
251 opt
= get_opt_rec(tree
, name
);
256 /** If @a opt is an alias, return the option to which it refers.
258 * @warning Because the alias may have the ::OPT_ALIAS_NEGATE flag,
259 * the caller must not access the value of the returned option as if
260 * it were also the value of the alias. However, it is safe to access
261 * flags such as ::OPT_MUST_SAVE and ::OPT_DELETED.
265 indirect_option(struct option
*alias
)
269 if (alias
->type
!= OPT_ALIAS
) return alias
; /* not an error */
271 real
= get_opt_rec(config_options
, alias
->value
.string
);
272 assertm(real
!= NULL
, "%s aliased to unknown option %s!",
273 alias
->name
, alias
->value
.string
);
274 if_assert_failed
return alias
;
279 /** Fetch pointer to value of certain option. It is guaranteed to never return
280 * NULL. Note that you are supposed to use wrapper get_opt().
285 unsigned char *file
, int line
, enum option_type option_type
,
287 struct option
*tree
, unsigned char *name
, struct session
*ses
)
289 struct option
*opt
= NULL
;
291 /* If given a session and the option is shadowed in that session's
292 * options tree, return the shadow. */
293 if (ses
&& ses
->option
)
294 opt
= get_opt_rec_real(ses
->option
, name
);
296 /* If given a session, no session-specific option was found, and the
297 * option has a shadow in the domain tree that matches the current
298 * document in that session, return that shadow. */
300 opt
= get_domain_option_from_session(name
, ses
);
302 /* Else, return the real option. */
304 opt
= get_opt_rec(tree
, name
);
309 if (!opt
) elinks_internal("Attempted to fetch nonexisting option %s!", name
);
311 /* Various sanity checks. */
312 if (option_type
!= opt
->type
)
313 DBG("get_opt_*(\"%s\") @ %s:%d: call with wrapper for %s for option of type %s",
315 get_option_type_name(option_type
),
316 get_option_type_name(opt
->type
));
320 if (!opt
->value
.tree
)
321 elinks_internal("Option %s has no value!", name
);
324 elinks_internal("Invalid use of alias %s for option %s!",
325 name
, opt
->value
.string
);
328 if (!opt
->value
.string
)
329 elinks_internal("Option %s has no value!", name
);
333 if (opt
->value
.number
< opt
->min
334 || opt
->value
.number
> opt
->max
)
335 elinks_internal("Option %s has invalid value %d!", name
, opt
->value
.number
);
338 if (opt
->value
.big_number
< opt
->min
339 || opt
->value
.big_number
> opt
->max
)
340 elinks_internal("Option %s has invalid value %ld!", name
, opt
->value
.big_number
);
343 if (!opt
->value
.command
)
344 elinks_internal("Option %s has no value!", name
);
346 case OPT_CODEPAGE
: /* TODO: check these too. */
356 /*! @relates option */
358 add_opt_sort(struct option
*tree
, struct option
*option
, int abi
)
360 LIST_OF(struct option
) *cat
= tree
->value
.tree
;
361 LIST_OF(struct listbox_item
) *bcat
= &tree
->box_item
->child
;
364 /* The list is empty, just add it there. */
365 if (list_empty(*cat
)) {
366 add_to_list(*cat
, option
);
367 if (abi
) add_to_list(*bcat
, option
->box_item
);
369 /* This fits as the last list entry, add it there. This
370 * optimizes the most expensive BUT most common case ;-). */
371 } else if ((option
->type
!= OPT_TREE
372 || ((struct option
*) cat
->prev
)->type
== OPT_TREE
)
373 && strcmp(((struct option
*) cat
->prev
)->name
,
374 option
->name
) <= 0) {
376 add_to_list_end(*cat
, option
);
377 if (abi
) add_to_list_end(*bcat
, option
->box_item
);
379 /* At the end of the list is tree and we are ordinary. That's
380 * clear case then. */
381 } else if (option
->type
!= OPT_TREE
382 && ((struct option
*) cat
->prev
)->type
== OPT_TREE
) {
385 /* Scan the list linearly. This could be probably optimized ie.
386 * to choose direction based on the first letter or so. */
388 struct listbox_item
*bpos
= (struct listbox_item
*) bcat
;
390 foreach (pos
, *cat
) {
391 /* First move the box item to the current position but
392 * only if the position has not been marked as deleted
393 * and actually has a box_item -- else we will end up
394 * 'overflowing' and causing assertion failure. */
395 if (!(pos
->flags
& OPT_DELETED
) && pos
->box_item
) {
397 assert(bpos
!= (struct listbox_item
*) bcat
);
400 if ((option
->type
!= OPT_TREE
401 || pos
->type
== OPT_TREE
)
402 && strcmp(pos
->name
, option
->name
) <= 0)
405 /* Ordinary options always sort behind trees. */
406 if (option
->type
!= OPT_TREE
407 && pos
->type
== OPT_TREE
)
410 /* The (struct option) add_at_pos() can mess up the
411 * order so that we add the box_item to itself, so
412 * better do it first. */
414 /* Always ensure that them _template_ options are
415 * before anything else so a lonely autocreated option
416 * (with _template_ options set to invisible) will be
417 * connected with an upper corner (ascii: `-) instead
418 * of a rotated T (ascii: +-) when displaying it. */
419 if (option
->type
== pos
->type
420 && *option
->name
<= '_'
421 && !strcmp(pos
->name
, "_template_")) {
422 if (abi
) add_at_pos(bpos
, option
->box_item
);
423 add_at_pos(pos
, option
);
427 if (abi
) add_at_pos(bpos
->prev
, option
->box_item
);
428 add_at_pos(pos
->prev
, option
);
432 assert(pos
!= (struct option
*) cat
);
433 assert(bpos
!= (struct listbox_item
*) bcat
);
437 /** Add option to tree.
440 add_opt_rec(struct option
*tree
, unsigned char *path
, struct option
*option
)
444 assert(path
&& option
&& tree
);
445 if (*path
) tree
= get_opt_rec(tree
, path
);
447 assertm(tree
!= NULL
, "Missing option tree for '%s'", path
);
448 if (!tree
->value
.tree
) return;
450 object_nolock(option
, "option");
452 if (option
->box_item
&& option
->name
&& !strcmp(option
->name
, "_template_"))
453 option
->box_item
->visible
= get_opt_bool("config.show_template", NULL
);
455 if (tree
->flags
& OPT_AUTOCREATE
&& !option
->desc
) {
456 struct option
*template_
= get_opt_rec(tree
, "_template_");
459 option
->desc
= template_
->desc
;
464 abi
= (tree
->box_item
&& option
->box_item
);
467 /* The config_root tree is a just a placeholder for the
468 * box_items, it actually isn't a real box_item by itself;
469 * these ghosts are indicated by the fact that they have
471 if (tree
->box_item
->next
) {
472 option
->box_item
->depth
= tree
->box_item
->depth
+ 1;
476 if (tree
->flags
& OPT_SORT
) {
477 add_opt_sort(tree
, option
, abi
);
480 add_to_list_end(*tree
->value
.tree
, option
);
481 if (abi
) add_to_list_end(tree
->box_item
->child
, option
->box_item
);
484 update_hierbox_browser(&option_browser
);
487 /*! @relates option */
488 static inline struct listbox_item
*
489 init_option_listbox_item(struct option
*option
)
491 struct listbox_item
*item
= mem_calloc(1, sizeof(*item
));
493 if (!item
) return NULL
;
495 init_list(item
->child
);
497 item
->udata
= option
;
498 item
->type
= (option
->type
== OPT_TREE
) ? BI_FOLDER
: BI_LEAF
;
503 /*! @relates option */
505 add_opt(struct option
*tree
, unsigned char *path
, unsigned char *capt
,
506 unsigned char *name
, enum option_flags flags
, enum option_type type
,
507 long min
, long max
, longptr_T value
, unsigned char *desc
)
509 struct option
*option
= mem_calloc(1, sizeof(*option
));
511 if (!option
) return NULL
;
513 option
->name
= stracpy(name
);
518 option
->flags
= (flags
| OPT_ALLOC
);
525 debug_check_option_syntax(option
);
527 /* XXX: For allocated values we allocate in the add_opt_<type>() macro.
528 * This involves OPT_TREE and OPT_STRING. */
535 option
->value
.tree
= (LIST_OF(struct option
) *) value
;
542 option
->value
.string
= (unsigned char *) value
;
545 option
->value
.string
= (unsigned char *) value
;
550 option
->value
.number
= (int) value
;
553 option
->value
.big_number
= (long) value
; /* FIXME: cast from void * */
556 decode_color((unsigned char *) value
, strlen((unsigned char *) value
),
557 &option
->value
.color
);
560 option
->value
.command
= (void *) value
;
566 if (option
->type
!= OPT_ALIAS
567 && ((tree
->flags
& OPT_LISTBOX
) || (option
->flags
& OPT_LISTBOX
))) {
568 option
->box_item
= init_option_listbox_item(option
);
569 if (!option
->box_item
) {
575 add_opt_rec(tree
, path
, option
);
579 /*! @relates option */
581 done_option(struct option
*option
)
583 switch (option
->type
) {
585 mem_free_if(option
->value
.string
);
588 mem_free_if(option
->value
.tree
);
594 if (option
->box_item
)
595 done_listbox_item(&option_browser
, option
->box_item
);
597 if (option
->flags
& OPT_ALLOC
) {
598 mem_free_if(option
->name
);
600 } else if (!option
->capt
) {
601 /* We are probably dealing with a built-in autocreated option
602 * that will be attempted to be deleted when shutting down. */
603 /* Clear it so nothing will be done later. */
604 memset(option
, 0, sizeof(*option
));
608 /* The namespace may start to seem a bit chaotic here; it indeed is, maybe the
609 * function names above should be renamed and only macros should keep their old
611 /* The simple rule I took as an apologize is that functions which take already
612 * completely filled (struct option *) have long name and functions which take
613 * only option specs have short name. */
615 /*! @relates option */
617 delete_option_do(struct option
*option
, int recursive
)
620 del_from_list(option
);
621 option
->prev
= option
->next
= NULL
;
624 if (recursive
== -1) {
625 ERROR("Orphaned option %s", option
->name
);
628 if (option
->type
== OPT_TREE
&& option
->value
.tree
629 && !list_empty(*option
->value
.tree
)) {
631 if (option
->flags
& OPT_AUTOCREATE
) {
634 ERROR("Orphaned unregistered "
635 "option in subtree %s!",
640 free_options_tree(option
->value
.tree
, recursive
);
646 /*! @relates option */
648 mark_option_as_deleted(struct option
*option
)
650 if (option
->type
== OPT_TREE
) {
651 struct option
*unmarked
;
653 assert(option
->value
.tree
);
655 foreach (unmarked
, *option
->value
.tree
)
656 mark_option_as_deleted(unmarked
);
659 option
->box_item
->visible
= 0;
661 option
->flags
|= (OPT_TOUCHED
| OPT_DELETED
);
664 /*! @relates option */
666 delete_option(struct option
*option
)
668 delete_option_do(option
, 1);
671 /*! @relates option */
673 copy_option(struct option
*template_
, int flags
)
675 struct option
*option
= mem_calloc(1, sizeof(*option
));
677 if (!option
) return NULL
;
679 option
->name
= null_or_stracpy(template_
->name
);
680 option
->flags
= (template_
->flags
| OPT_ALLOC
);
681 option
->type
= template_
->type
;
682 option
->min
= template_
->min
;
683 option
->max
= template_
->max
;
684 option
->capt
= template_
->capt
;
685 option
->desc
= template_
->desc
;
686 option
->change_hook
= template_
->change_hook
;
688 if (!(flags
& CO_NO_LISTBOX_ITEM
))
689 option
->box_item
= init_option_listbox_item(option
);
690 if (option
->box_item
) {
691 if (template_
->box_item
) {
692 option
->box_item
->type
= template_
->box_item
->type
;
693 option
->box_item
->depth
= template_
->box_item
->depth
;
697 if (option_types
[template_
->type
].dup
) {
698 option_types
[template_
->type
].dup(option
, template_
, flags
);
700 option
->value
= template_
->value
;
706 /** Return the shadow option in @a shadow_tree of @a option in @a tree.
707 * If @a option isn't yet shadowed in @a shadow_tree, shadow it
708 * (i.e. create a copy in @a shadow_tree) along with any ancestors
709 * that aren't shadowed. */
711 get_option_shadow(struct option
*option
, struct option
*tree
,
712 struct option
*shadow_tree
)
715 struct option
*shadow_option
= NULL
;
721 if (option
== tree
) {
722 shadow_option
= shadow_tree
;
723 } else if (option
->root
&& option
->name
) {
724 struct option
*shadow_root
;
726 shadow_root
= get_option_shadow(option
->root
, tree
,
728 if (!shadow_root
) return NULL
;
730 shadow_option
= get_opt_rec_real(shadow_root
, option
->name
);
731 if (!shadow_option
) {
732 shadow_option
= copy_option(option
,
734 | CO_NO_LISTBOX_ITEM
);
736 shadow_option
->root
= shadow_root
;
737 /* No need to sort, is there? It isn't shown
738 * in the options manager. -- Miciah */
739 add_to_list_end(*shadow_root
->value
.tree
,
742 shadow_option
->flags
|= OPT_TOUCHED
;
748 return shadow_option
;
752 /*! @relates option */
753 LIST_OF(struct option
) *
754 init_options_tree(void)
756 LIST_OF(struct option
) *ptr
= mem_alloc(sizeof(*ptr
));
758 if (ptr
) init_list(*ptr
);
762 /** Some default pre-autocreated options. Doh. */
764 register_autocreated_options(void)
766 /* TODO: Use table-driven initialization. --jonas */
767 get_opt_int("terminal.linux.type", NULL
) = TERM_LINUX
;
768 get_opt_int("terminal.linux.colors", NULL
) = COLOR_MODE_16
;
769 get_opt_bool("terminal.linux.m11_hack", NULL
) = 1;
770 get_opt_int("terminal.vt100.type", NULL
) = TERM_VT100
;
771 get_opt_int("terminal.vt110.type", NULL
) = TERM_VT100
;
772 get_opt_int("terminal.xterm.type", NULL
) = TERM_VT100
;
773 get_opt_bool("terminal.xterm.underline", NULL
) = 1;
774 get_opt_int("terminal.xterm-color.type", NULL
) = TERM_VT100
;
775 get_opt_int("terminal.xterm-color.colors", NULL
) = COLOR_MODE_16
;
776 get_opt_bool("terminal.xterm-color.underline", NULL
) = 1;
777 #ifdef CONFIG_88_COLORS
778 get_opt_int("terminal.xterm-88color.type", NULL
) = TERM_VT100
;
779 get_opt_int("terminal.xterm-88color.colors", NULL
) = COLOR_MODE_88
;
780 get_opt_bool("terminal.xterm-88color.underline", NULL
) = 1;
782 get_opt_int("terminal.rxvt-unicode.type", NULL
) = 1;
783 #ifdef CONFIG_88_COLORS
784 get_opt_int("terminal.rxvt-unicode.colors", NULL
) = COLOR_MODE_88
;
786 get_opt_int("terminal.rxvt-unicode.colors", NULL
) = COLOR_MODE_16
;
788 get_opt_bool("terminal.rxvt-unicode.italic", NULL
) = 1;
789 get_opt_bool("terminal.rxvt-unicode.underline", NULL
) = 1;
790 #ifdef CONFIG_256_COLORS
791 get_opt_int("terminal.xterm-256color.type", NULL
) = TERM_VT100
;
792 get_opt_int("terminal.xterm-256color.colors", NULL
) = COLOR_MODE_256
;
793 get_opt_bool("terminal.xterm-256color.underline", NULL
) = 1;
794 get_opt_int("terminal.fbterm.type", NULL
) = TERM_FBTERM
;
795 get_opt_int("terminal.fbterm.colors", NULL
) = COLOR_MODE_256
;
796 get_opt_bool("terminal.fbterm.underline", NULL
) = 0;
800 extern union option_info cmdline_options_info
[];
802 #include "config/options.inc"
805 change_hook_cache(struct session
*ses
, struct option
*current
, struct option
*changed
)
812 change_hook_connection(struct session
*ses
, struct option
*current
, struct option
*changed
)
814 register_check_queue();
819 change_hook_html(struct session
*ses
, struct option
*current
, struct option
*changed
)
821 foreach (ses
, sessions
) ses
->tab
->resize
= 1;
827 change_hook_insert_mode(struct session
*ses
, struct option
*current
, struct option
*changed
)
834 change_hook_active_link(struct session
*ses
, struct option
*current
, struct option
*changed
)
836 update_cached_document_options(ses
);
841 change_hook_terminal(struct session
*ses
, struct option
*current
, struct option
*changed
)
843 cls_redraw_all_terminals();
848 change_hook_ui(struct session
*ses
, struct option
*current
, struct option
*changed
)
854 /** Make option templates visible or invisible in the option manager.
855 * This is called once on startup, and then each time the value of the
856 * "config.show_template" option is changed.
859 * The option tree whose children should be affected.
863 * - The 0x01 bit means templates should be made visible.
864 * If the bit is clear, templates become invisible instead.
865 * - The 0x02 bit means @a tree is itself part of a template,
866 * and so all of its children should be affected, regardless
867 * of whether they are templates of their own.
869 * Deleted options are never visible.
873 update_visibility(LIST_OF(struct option
) *tree
, int show
)
877 foreach (opt
, *tree
) {
878 if (opt
->flags
& OPT_DELETED
) continue;
880 if (!strcmp(opt
->name
, "_template_")) {
882 opt
->box_item
->visible
= (show
& 1);
884 if (opt
->type
== OPT_TREE
)
885 update_visibility(opt
->value
.tree
, show
| 2);
887 if (opt
->box_item
&& (show
& 2))
888 opt
->box_item
->visible
= (show
& 1);
890 if (opt
->type
== OPT_TREE
)
891 update_visibility(opt
->value
.tree
, show
);
897 change_hook_stemplate(struct session
*ses
, struct option
*current
, struct option
*changed
)
899 update_visibility(config_options
->value
.tree
, changed
->value
.number
);
904 change_hook_language(struct session
*ses
, struct option
*current
, struct option
*changed
)
907 set_language(changed
->value
.number
);
912 static const struct change_hook_info change_hooks
[] = {
913 { "config.show_template", change_hook_stemplate
},
914 { "connection", change_hook_connection
},
915 { "document.browse", change_hook_html
},
916 { "document.browse.forms.insert_mode",
917 change_hook_insert_mode
},
918 { "document.browse.links.active_link",
919 change_hook_active_link
},
920 { "document.cache", change_hook_cache
},
921 { "document.codepage", change_hook_html
},
922 { "document.colors", change_hook_html
},
923 { "document.html", change_hook_html
},
924 { "document.plain", change_hook_html
},
925 { "terminal", change_hook_terminal
},
926 { "ui.language", change_hook_language
},
927 { "ui", change_hook_ui
},
934 cmdline_options
= add_opt_tree_tree(&options_root
, "", "",
936 register_options(cmdline_options_info
, cmdline_options
);
938 config_options
= add_opt_tree_tree(&options_root
, "", "",
939 "config", OPT_SORT
, "");
940 config_options
->flags
|= OPT_LISTBOX
;
941 config_options
->box_item
= &option_browser
.root
;
942 register_options(config_options_info
, config_options
);
944 register_autocreated_options();
945 register_change_hooks(change_hooks
);
948 /*! @relates option */
950 free_options_tree(LIST_OF(struct option
) *tree
, int recursive
)
952 while (!list_empty(*tree
))
953 delete_option_do(tree
->next
, recursive
);
960 unregister_options(config_options_info
, config_options
);
961 unregister_options(cmdline_options_info
, cmdline_options
);
962 config_options
->box_item
= NULL
;
963 free_options_tree(&options_root_tree
, 0);
966 /*! @relates change_hook_info */
968 register_change_hooks(const struct change_hook_info
*change_hooks
)
972 for (i
= 0; change_hooks
[i
].name
; i
++) {
973 struct option
*option
= get_opt_rec(config_options
,
974 change_hooks
[i
].name
);
977 option
->change_hook
= change_hooks
[i
].change_hook
;
981 /** Set or clear the ::OPT_MUST_SAVE flag in all descendants of @a tree.
984 * The option tree in which this function recursively sets or clears
988 * If true, set ::OPT_MUST_SAVE in all options of the tree.
989 * If false, set it only in touched or deleted options, and clear in others.
993 prepare_mustsave_flags(LIST_OF(struct option
) *tree
, int set_all
)
995 struct option
*option
;
997 foreach (option
, *tree
) {
998 /* XXX: OPT_LANGUAGE shouldn't have any bussiness
999 * here, but we're just weird in that area. */
1001 || (option
->flags
& (OPT_TOUCHED
| OPT_DELETED
))
1002 || option
->type
== OPT_LANGUAGE
)
1003 option
->flags
|= OPT_MUST_SAVE
;
1005 option
->flags
&= ~OPT_MUST_SAVE
;
1007 if (option
->type
== OPT_TREE
)
1008 prepare_mustsave_flags(option
->value
.tree
, set_all
);
1012 /** Clear the ::OPT_TOUCHED flag in all descendants of @a tree.
1013 * @relates option */
1015 untouch_options(LIST_OF(struct option
) *tree
)
1017 struct option
*option
;
1019 foreach (option
, *tree
) {
1020 option
->flags
&= ~OPT_TOUCHED
;
1022 if (option
->type
== OPT_TREE
)
1023 untouch_options(option
->value
.tree
);
1027 /*! @relates option */
1029 check_nonempty_tree(LIST_OF(struct option
) *options
)
1033 foreach (opt
, *options
) {
1034 if (opt
->type
== OPT_TREE
) {
1035 if (check_nonempty_tree(opt
->value
.tree
))
1037 } else if (opt
->flags
& OPT_MUST_SAVE
) {
1045 /*! @relates option */
1047 smart_config_string(struct string
*str
, int print_comment
, int i18n
,
1048 LIST_OF(struct option
) *options
,
1049 unsigned char *path
, int depth
,
1050 void (*fn
)(struct string
*, struct option
*,
1051 unsigned char *, int, int, int, int))
1053 struct option
*option
;
1055 foreach (option
, *options
) {
1056 int do_print_comment
= 1;
1058 if (option
->flags
& OPT_HIDDEN
||
1059 option
->type
== OPT_ALIAS
||
1060 !strcmp(option
->name
, "_template_"))
1063 /* Is there anything to be printed anyway? */
1064 if (option
->type
== OPT_TREE
1065 ? !check_nonempty_tree(option
->value
.tree
)
1066 : !(option
->flags
& OPT_MUST_SAVE
))
1069 /* We won't pop out the description when we're in autocreate
1070 * category and not template. It'd be boring flood of
1071 * repetitive comments otherwise ;). */
1073 /* This print_comment parameter is weird. If it is negative, it
1074 * means that we shouldn't print comments at all. If it is 1,
1075 * we shouldn't print comment UNLESS the option is _template_
1076 * or not-an-autocreating-tree (it is set for the first-level
1077 * autocreation tree). When it is 2, we can print out comments
1079 /* It is still broken somehow, as it didn't work for terminal.*
1080 * (the first autocreated level) by the time I wrote this. Good
1081 * summer job for bored mad hackers with spare boolean mental
1082 * power. I have better things to think about, personally.
1083 * Maybe we should just mark autocreated options somehow ;). */
1084 if (!print_comment
|| (print_comment
== 1
1085 && (strcmp(option
->name
, "_template_")
1086 && (option
->flags
& OPT_AUTOCREATE
1087 && option
->type
== OPT_TREE
))))
1088 do_print_comment
= 0;
1090 /* Pop out the comment */
1092 /* For config file, we ignore do_print_comment everywhere
1093 * except 1, but sometimes we want to skip the option totally.
1095 fn(str
, option
, path
, depth
,
1096 option
->type
== OPT_TREE
? print_comment
1100 fn(str
, option
, path
, depth
, do_print_comment
, 1, i18n
);
1102 /* And the option itself */
1104 if (option_types
[option
->type
].write
) {
1105 fn(str
, option
, path
, depth
,
1106 do_print_comment
, 2, i18n
);
1108 } else if (option
->type
== OPT_TREE
) {
1109 struct string newpath
;
1110 int pc
= print_comment
;
1112 if (!init_string(&newpath
)) continue; /* OK? */
1114 if (pc
== 2 && option
->flags
& OPT_AUTOCREATE
)
1116 else if (pc
== 1 && strcmp(option
->name
, "_template_"))
1119 fn(str
, option
, path
, depth
, /*pc*/1, 3, i18n
);
1122 add_to_string(&newpath
, path
);
1123 add_char_to_string(&newpath
, '.');
1125 add_to_string(&newpath
, option
->name
);
1126 smart_config_string(str
, pc
, i18n
, option
->value
.tree
,
1127 newpath
.source
, depth
+ 1, fn
);
1128 done_string(&newpath
);
1130 fn(str
, option
, path
, depth
, /*pc*/1, 3, i18n
);
1137 update_options_visibility(void)
1139 update_visibility(config_options
->value
.tree
,
1140 get_opt_bool("config.show_template", NULL
));
1144 toggle_option(struct session
*ses
, struct option
*option
)
1146 long number
= option
->value
.number
+ 1;
1148 assert(option
->type
== OPT_BOOL
|| option
->type
== OPT_INT
);
1149 assert(option
->max
);
1151 option
->value
.number
= (number
<= option
->max
) ? number
: option
->min
;
1152 option_changed(ses
, option
);
1158 call_change_hooks(struct session
*ses
, struct option
*current
, struct option
*option
)
1160 /* This boolean thing can look a little weird - it
1161 * basically says that we should proceed when there's
1162 * no change_hook or there's one and its return value
1164 while (current
&& (!current
->change_hook
||
1165 !current
->change_hook(ses
, current
, option
))) {
1169 current
= current
->root
;
1174 option_changed(struct session
*ses
, struct option
*option
)
1176 option
->flags
|= OPT_TOUCHED
;
1177 /* Notify everyone out there! */
1178 call_change_hooks(ses
, option
, option
);
1181 /*! @relates option_resolver */
1183 commit_option_values(struct option_resolver
*resolvers
,
1184 struct option
*root
, union option_value
*values
, int size
)
1189 assert(resolvers
&& root
&& values
&& size
);
1191 for (i
= 0; i
< size
; i
++) {
1192 unsigned char *name
= resolvers
[i
].name
;
1193 struct option
*option
= get_opt_rec(root
, name
);
1194 int id
= resolvers
[i
].id
;
1196 assertm(option
, "Bad option '%s' in options resolver", name
);
1198 if (memcmp(&option
->value
, &values
[id
], sizeof(union option_value
))) {
1199 option
->value
= values
[id
];
1200 option
->flags
|= OPT_TOUCHED
;
1201 /* Speed hack: Directly call the change-hook for each
1202 * option in resolvers and later call call_change_hooks
1203 * on the root; if we were to call call_change_hooks
1204 * on each option in resolvers, we would end up calling
1205 * the change-hooks of root, its parents, its
1206 * grandparents, and so on for each option in resolvers
1207 * because call_change_hooks is recursive. -- Miciah */
1208 if (option
->change_hook
)
1209 option
->change_hook(NULL
, option
, NULL
);
1214 /* See above 'Speed hack' comment. */
1215 call_change_hooks(NULL
, root
, NULL
);
1220 /*! @relates option_resolver */
1222 checkout_option_values(struct option_resolver
*resolvers
,
1223 struct option
*root
,
1224 union option_value
*values
, int size
)
1228 for (i
= 0; i
< size
; i
++) {
1229 unsigned char *name
= resolvers
[i
].name
;
1230 struct option
*option
= get_opt_rec(root
, name
);
1231 int id
= resolvers
[i
].id
;
1233 assertm(option
, "Bad option '%s' in options resolver", name
);
1235 values
[id
] = option
->value
;
1239 /**********************************************************************
1241 **********************************************************************/
1244 /*! @relates option_info */
1246 register_options(union option_info info
[], struct option
*tree
)
1249 static const struct option zero
= INIT_OPTION(
1250 NULL
, 0, 0, 0, 0, 0, NULL
, NULL
);
1252 /* To let unregister_options() correctly find the end of the
1253 * info[] array, this loop must convert every element from
1254 * struct option_init to struct option. That is, even if
1255 * there is not enough memory to fully initialize some option,
1256 * the loop must continue. */
1257 for (i
= 0; info
[i
].init
.path
; i
++) {
1258 /* Copy the value aside before it is overwritten
1259 * with the other member of the union. */
1260 const struct option_init init
= info
[i
].init
;
1262 struct option
*option
= &info
[i
].option
;
1263 unsigned char *string
;
1266 option
->name
= init
.name
;
1267 option
->capt
= init
.capt
;
1268 option
->desc
= init
.desc
;
1269 option
->flags
= init
.flags
;
1270 option
->type
= init
.type
;
1271 option
->min
= init
.min
;
1272 option
->max
= init
.max
;
1273 /* init.value_long, init.value_dataptr, or init.value_funcptr
1274 * is handled below as appropriate for each type. */
1276 debug_check_option_syntax(option
);
1278 if (option
->type
!= OPT_ALIAS
1279 && ((tree
->flags
& OPT_LISTBOX
)
1280 || (option
->flags
& OPT_LISTBOX
))) {
1281 option
->box_item
= init_option_listbox_item(option
);
1282 if (!option
->box_item
) {
1283 delete_option(option
);
1288 switch (option
->type
) {
1290 option
->value
.tree
= init_options_tree();
1291 if (!option
->value
.tree
) {
1292 delete_option(option
);
1297 string
= mem_alloc(MAX_STR_LEN
);
1299 delete_option(option
);
1302 safe_strncpy(string
, init
.value_dataptr
, MAX_STR_LEN
);
1303 option
->value
.string
= string
;
1306 string
= init
.value_dataptr
;
1308 decode_color(string
, strlen(string
),
1309 &option
->value
.color
);
1312 string
= init
.value_dataptr
;
1314 option
->value
.number
= get_cp_index(string
);
1318 option
->value
.number
= init
.value_long
;
1321 option
->value
.big_number
= init
.value_long
;
1324 /* INIT_OPT_LANGUAGE has no def parameter */
1325 option
->value
.number
= 0;
1328 option
->value
.command
= init
.value_funcptr
;
1331 option
->value
.string
= init
.value_dataptr
;
1335 add_opt_rec(tree
, init
.path
, option
);
1338 /* Convert the sentinel at the end of the array, too. */
1339 info
[i
].option
= zero
;
1342 /*! @relates option_info */
1344 unregister_options(union option_info info
[], struct option
*tree
)
1348 /* We need to remove the options in inverse order to the order how we
1351 while (info
[i
].option
.name
) i
++;
1353 for (i
--; i
>= 0; i
--)
1354 delete_option_do(&info
[i
].option
, 0);