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
);
138 debug_check_option_syntax(struct option
*option
)
141 check_caption(option
->capt
);
142 check_description(option
->desc
);
146 #define debug_check_option_syntax(option)
150 /**********************************************************************
152 **********************************************************************/
154 /* If option name contains dots, they are created as "categories" - first,
155 * first category is retrieved from list, taken as a list, second category
156 * is retrieved etc. */
159 static int no_autocreate
= 0;
161 /** Get record of option of given name, or NULL if there's no such option.
163 * If the specified option is an ::OPT_ALIAS, this function returns the
164 * alias, rather than the option to which the alias refers. It must
165 * work this way because the alias may have the ::OPT_ALIAS_NEGATE flag.
166 * Instead, if the caller tries to read or set the value of the alias,
167 * the functions associated with ::OPT_ALIAS will forward the operation
168 * to the underlying option. However, see indirect_option(). */
170 get_opt_rec(struct option
*tree
, const unsigned char *name_
)
172 struct option
*option
;
173 unsigned char *aname
= stracpy(name_
);
174 unsigned char *name
= aname
;
177 if (!aname
) return NULL
;
179 /* We iteratively call get_opt_rec() each for path_elements-1, getting
180 * appropriate tree for it and then resolving [path_elements]. */
181 if ((sep
= strrchr(name
, '.'))) {
184 tree
= get_opt_rec(tree
, name
);
185 if (!tree
|| tree
->type
!= OPT_TREE
|| tree
->flags
& OPT_HIDDEN
) {
187 DBG("ERROR in get_opt_rec() crawl: %s (%d) -> %s",
188 name
, tree
? tree
->type
: -1, sep
+ 1);
198 foreach (option
, *tree
->value
.tree
) {
199 if (option
->name
&& !strcmp(option
->name
, name
)) {
205 if (tree
&& tree
->flags
& OPT_AUTOCREATE
&& !no_autocreate
) {
206 struct option
*template = get_opt_rec(tree
, "_template_");
208 assertm(template != NULL
, "Requested %s should be autocreated but "
209 "%.*s._template_ is missing!", name_
, sep
- name_
,
216 /* We will just create the option and return pointer to it
217 * automagically. And, we will create it by cloning _template_
218 * option. By having _template_ OPT_AUTOCREATE and _template_
219 * inside, you can have even multi-level autocreating. */
221 option
= copy_option(template, 0);
226 mem_free_set(&option
->name
, stracpy(name
));
228 add_opt_rec(tree
, "", option
);
238 /* Get record of option of given name, or NULL if there's no such option. But
239 * do not create the option if it doesn't exist and there's autocreation
242 get_opt_rec_real(struct option
*tree
, const unsigned char *name
)
247 opt
= get_opt_rec(tree
, name
);
252 /** If @a opt is an alias, return the option to which it refers.
254 * @warning Because the alias may have the ::OPT_ALIAS_NEGATE flag,
255 * the caller must not access the value of the returned option as if
256 * it were also the value of the alias. However, it is safe to access
257 * flags such as ::OPT_MUST_SAVE and ::OPT_DELETED. */
259 indirect_option(struct option
*alias
)
263 if (alias
->type
!= OPT_ALIAS
) return alias
; /* not an error */
265 real
= get_opt_rec(config_options
, alias
->value
.string
);
266 assertm(real
!= NULL
, "%s aliased to unknown option %s!",
267 alias
->name
, alias
->value
.string
);
268 if_assert_failed
return alias
;
273 /* Fetch pointer to value of certain option. It is guaranteed to never return
274 * NULL. Note that you are supposed to use wrapper get_opt(). */
278 unsigned char *file
, int line
, enum option_type option_type
,
280 struct option
*tree
, unsigned char *name
, struct session
*ses
)
282 struct option
*opt
= NULL
;
284 /* If given a session and the option is shadowed in that session's
285 * options tree, return the shadow. */
286 if (ses
&& ses
->option
)
287 opt
= get_opt_rec_real(ses
->option
, name
);
289 /* If given a session, no session-specific option was found, and the
290 * option has a shadow in the domain tree that matches the current
291 * document in that session, return that shadow. */
293 opt
= get_domain_option_from_session(name
, ses
);
295 /* Else, return the real option. */
297 opt
= get_opt_rec(tree
, name
);
302 if (!opt
) elinks_internal("Attempted to fetch nonexisting option %s!", name
);
304 /* Various sanity checks. */
305 if (option_type
!= opt
->type
)
306 DBG("get_opt_*(\"%s\") @ %s:%d: call with wrapper for %s for option of type %s",
308 get_option_type_name(option_type
),
309 get_option_type_name(opt
->type
));
313 if (!opt
->value
.tree
)
314 elinks_internal("Option %s has no value!", name
);
317 elinks_internal("Invalid use of alias %s for option %s!",
318 name
, opt
->value
.string
);
321 if (!opt
->value
.string
)
322 elinks_internal("Option %s has no value!", name
);
326 if (opt
->value
.number
< opt
->min
327 || opt
->value
.number
> opt
->max
)
328 elinks_internal("Option %s has invalid value %d!", name
, opt
->value
.number
);
331 if (opt
->value
.big_number
< opt
->min
332 || opt
->value
.big_number
> opt
->max
)
333 elinks_internal("Option %s has invalid value %ld!", name
, opt
->value
.big_number
);
336 if (!opt
->value
.command
)
337 elinks_internal("Option %s has no value!", name
);
339 case OPT_CODEPAGE
: /* TODO: check these too. */
350 add_opt_sort(struct option
*tree
, struct option
*option
, int abi
)
352 LIST_OF(struct option
) *cat
= tree
->value
.tree
;
353 LIST_OF(struct listbox_item
) *bcat
= &tree
->box_item
->child
;
356 /* The list is empty, just add it there. */
357 if (list_empty(*cat
)) {
358 add_to_list(*cat
, option
);
359 if (abi
) add_to_list(*bcat
, option
->box_item
);
361 /* This fits as the last list entry, add it there. This
362 * optimizes the most expensive BUT most common case ;-). */
363 } else if ((option
->type
!= OPT_TREE
364 || ((struct option
*) cat
->prev
)->type
== OPT_TREE
)
365 && strcmp(((struct option
*) cat
->prev
)->name
,
366 option
->name
) <= 0) {
368 add_to_list_end(*cat
, option
);
369 if (abi
) add_to_list_end(*bcat
, option
->box_item
);
371 /* At the end of the list is tree and we are ordinary. That's
372 * clear case then. */
373 } else if (option
->type
!= OPT_TREE
374 && ((struct option
*) cat
->prev
)->type
== OPT_TREE
) {
377 /* Scan the list linearly. This could be probably optimized ie.
378 * to choose direction based on the first letter or so. */
380 struct listbox_item
*bpos
= (struct listbox_item
*) bcat
;
382 foreach (pos
, *cat
) {
383 /* First move the box item to the current position but
384 * only if the position has not been marked as deleted
385 * and actually has a box_item -- else we will end up
386 * 'overflowing' and causing assertion failure. */
387 if (!(pos
->flags
& OPT_DELETED
) && pos
->box_item
) {
389 assert(bpos
!= (struct listbox_item
*) bcat
);
392 if ((option
->type
!= OPT_TREE
393 || pos
->type
== OPT_TREE
)
394 && strcmp(pos
->name
, option
->name
) <= 0)
397 /* Ordinary options always sort behind trees. */
398 if (option
->type
!= OPT_TREE
399 && pos
->type
== OPT_TREE
)
402 /* The (struct option) add_at_pos() can mess up the
403 * order so that we add the box_item to itself, so
404 * better do it first. */
406 /* Always ensure that them _template_ options are
407 * before anything else so a lonely autocreated option
408 * (with _template_ options set to invisible) will be
409 * connected with an upper corner (ascii: `-) instead
410 * of a rotated T (ascii: +-) when displaying it. */
411 if (option
->type
== pos
->type
412 && *option
->name
<= '_'
413 && !strcmp(pos
->name
, "_template_")) {
414 if (abi
) add_at_pos(bpos
, option
->box_item
);
415 add_at_pos(pos
, option
);
419 if (abi
) add_at_pos(bpos
->prev
, option
->box_item
);
420 add_at_pos(pos
->prev
, option
);
424 assert(pos
!= (struct option
*) cat
);
425 assert(bpos
!= (struct listbox_item
*) bcat
);
429 /* Add option to tree. */
431 add_opt_rec(struct option
*tree
, unsigned char *path
, struct option
*option
)
435 assert(path
&& option
&& tree
);
436 if (*path
) tree
= get_opt_rec(tree
, path
);
438 assertm(tree
!= NULL
, "Missing option tree for '%s'", path
);
439 if (!tree
->value
.tree
) return;
441 object_nolock(option
, "option");
443 if (option
->box_item
&& option
->name
&& !strcmp(option
->name
, "_template_"))
444 option
->box_item
->visible
= get_opt_bool("config.show_template", NULL
);
446 if (tree
->flags
& OPT_AUTOCREATE
&& !option
->desc
) {
447 struct option
*template = get_opt_rec(tree
, "_template_");
450 option
->desc
= template->desc
;
455 abi
= (tree
->box_item
&& option
->box_item
);
458 /* The config_root tree is a just a placeholder for the
459 * box_items, it actually isn't a real box_item by itself;
460 * these ghosts are indicated by the fact that they have
462 if (tree
->box_item
->next
) {
463 option
->box_item
->depth
= tree
->box_item
->depth
+ 1;
467 if (tree
->flags
& OPT_SORT
) {
468 add_opt_sort(tree
, option
, abi
);
471 add_to_list_end(*tree
->value
.tree
, option
);
472 if (abi
) add_to_list_end(tree
->box_item
->child
, option
->box_item
);
475 update_hierbox_browser(&option_browser
);
478 static inline struct listbox_item
*
479 init_option_listbox_item(struct option
*option
)
481 struct listbox_item
*item
= mem_calloc(1, sizeof(*item
));
483 if (!item
) return NULL
;
485 init_list(item
->child
);
487 item
->udata
= option
;
488 item
->type
= (option
->type
== OPT_TREE
) ? BI_FOLDER
: BI_LEAF
;
494 add_opt(struct option
*tree
, unsigned char *path
, unsigned char *capt
,
495 unsigned char *name
, enum option_flags flags
, enum option_type type
,
496 long min
, long max
, longptr_T value
, unsigned char *desc
)
498 struct option
*option
= mem_calloc(1, sizeof(*option
));
500 if (!option
) return NULL
;
502 option
->name
= stracpy(name
);
507 option
->flags
= (flags
| OPT_ALLOC
);
514 debug_check_option_syntax(option
);
516 /* XXX: For allocated values we allocate in the add_opt_<type>() macro.
517 * This involves OPT_TREE and OPT_STRING. */
524 option
->value
.tree
= (LIST_OF(struct option
) *) value
;
531 option
->value
.string
= (unsigned char *) value
;
534 option
->value
.string
= (unsigned char *) value
;
539 option
->value
.number
= (int) value
;
542 option
->value
.big_number
= (long) value
; /* FIXME: cast from void * */
545 decode_color((unsigned char *) value
, strlen((unsigned char *) value
),
546 &option
->value
.color
);
549 option
->value
.command
= (void *) value
;
555 if (option
->type
!= OPT_ALIAS
556 && ((tree
->flags
& OPT_LISTBOX
) || (option
->flags
& OPT_LISTBOX
))) {
557 option
->box_item
= init_option_listbox_item(option
);
558 if (!option
->box_item
) {
564 add_opt_rec(tree
, path
, option
);
569 done_option(struct option
*option
)
571 switch (option
->type
) {
573 mem_free_if(option
->value
.string
);
576 mem_free_if(option
->value
.tree
);
582 if (option
->box_item
)
583 done_listbox_item(&option_browser
, option
->box_item
);
585 if (option
->flags
& OPT_ALLOC
) {
586 mem_free_if(option
->name
);
588 } else if (!option
->capt
) {
589 /* We are probably dealing with a built-in autocreated option
590 * that will be attempted to be deleted when shutting down. */
591 /* Clear it so nothing will be done later. */
592 memset(option
, 0, sizeof(*option
));
596 /* The namespace may start to seem a bit chaotic here; it indeed is, maybe the
597 * function names above should be renamed and only macros should keep their old
599 /* The simple rule I took as an apologize is that functions which take already
600 * completely filled (struct option *) have long name and functions which take
601 * only option specs have short name. */
604 delete_option_do(struct option
*option
, int recursive
)
607 del_from_list(option
);
608 option
->prev
= option
->next
= NULL
;
611 if (recursive
== -1) {
612 ERROR("Orphaned option %s", option
->name
);
615 if (option
->type
== OPT_TREE
&& option
->value
.tree
616 && !list_empty(*option
->value
.tree
)) {
618 if (option
->flags
& OPT_AUTOCREATE
) {
621 ERROR("Orphaned unregistered "
622 "option in subtree %s!",
627 free_options_tree(option
->value
.tree
, recursive
);
634 mark_option_as_deleted(struct option
*option
)
636 if (option
->type
== OPT_TREE
) {
637 struct option
*unmarked
;
639 assert(option
->value
.tree
);
641 foreach (unmarked
, *option
->value
.tree
)
642 mark_option_as_deleted(unmarked
);
645 option
->box_item
->visible
= 0;
647 option
->flags
|= (OPT_TOUCHED
| OPT_DELETED
);
651 delete_option(struct option
*option
)
653 delete_option_do(option
, 1);
657 copy_option(struct option
*template, int flags
)
659 struct option
*option
= mem_calloc(1, sizeof(*option
));
661 if (!option
) return NULL
;
663 option
->name
= null_or_stracpy(template->name
);
664 option
->flags
= (template->flags
| OPT_ALLOC
);
665 option
->type
= template->type
;
666 option
->min
= template->min
;
667 option
->max
= template->max
;
668 option
->capt
= template->capt
;
669 option
->desc
= template->desc
;
670 option
->change_hook
= template->change_hook
;
672 if (!(flags
& CO_NO_LISTBOX_ITEM
))
673 option
->box_item
= init_option_listbox_item(option
);
674 if (option
->box_item
) {
675 if (template->box_item
) {
676 option
->box_item
->type
= template->box_item
->type
;
677 option
->box_item
->depth
= template->box_item
->depth
;
681 if (option_types
[template->type
].dup
) {
682 option_types
[template->type
].dup(option
, template, flags
);
684 option
->value
= template->value
;
690 /* Return the shadow option in @shadow_tree of @option in @tree. If @option
691 * isn't yet shadowed in @shadow_tree, shadow it (i.e. create a copy
692 * in @shadow_tree) along with any ancestors that aren't shadowed. */
694 get_option_shadow(struct option
*option
, struct option
*tree
,
695 struct option
*shadow_tree
)
698 struct option
*shadow_option
= NULL
;
704 if (option
== tree
) {
705 shadow_option
= shadow_tree
;
706 } else if (option
->root
&& option
->name
) {
707 struct option
*shadow_root
;
709 shadow_root
= get_option_shadow(option
->root
, tree
,
711 if (!shadow_root
) return NULL
;
713 shadow_option
= get_opt_rec_real(shadow_root
, option
->name
);
714 if (!shadow_option
) {
715 shadow_option
= copy_option(option
,
717 | CO_NO_LISTBOX_ITEM
);
719 shadow_option
->root
= shadow_root
;
720 /* No need to sort, is there? It isn't shown
721 * in the options manager. -- Miciah */
722 add_to_list_end(*shadow_root
->value
.tree
,
725 shadow_option
->flags
|= OPT_TOUCHED
;
731 return shadow_option
;
735 LIST_OF(struct option
) *
736 init_options_tree(void)
738 LIST_OF(struct option
) *ptr
= mem_alloc(sizeof(*ptr
));
740 if (ptr
) init_list(*ptr
);
744 /* Some default pre-autocreated options. Doh. */
746 register_autocreated_options(void)
748 /* TODO: Use table-driven initialization. --jonas */
749 get_opt_int("terminal.linux.type", NULL
) = 2;
750 get_opt_int("terminal.linux.colors", NULL
) = 1;
751 get_opt_bool("terminal.linux.m11_hack", NULL
) = 1;
752 get_opt_int("terminal.vt100.type", NULL
) = 1;
753 get_opt_int("terminal.vt110.type", NULL
) = 1;
754 get_opt_int("terminal.xterm.type", NULL
) = 1;
755 get_opt_bool("terminal.xterm.underline", NULL
) = 1;
756 get_opt_int("terminal.xterm-color.type", NULL
) = 1;
757 get_opt_int("terminal.xterm-color.colors", NULL
) = COLOR_MODE_16
;
758 get_opt_bool("terminal.xterm-color.underline", NULL
) = 1;
759 #ifdef CONFIG_88_COLORS
760 get_opt_int("terminal.xterm-88color.type", NULL
) = 1;
761 get_opt_int("terminal.xterm-88color.colors", NULL
) = COLOR_MODE_88
;
762 get_opt_bool("terminal.xterm-88color.underline", NULL
) = 1;
764 #ifdef CONFIG_256_COLORS
765 get_opt_int("terminal.xterm-256color.type", NULL
) = 1;
766 get_opt_int("terminal.xterm-256color.colors", NULL
) = COLOR_MODE_256
;
767 get_opt_bool("terminal.xterm-256color.underline", NULL
) = 1;
771 static struct option_info config_options_info
[];
772 extern struct option_info cmdline_options_info
[];
773 static const struct change_hook_info change_hooks
[];
778 cmdline_options
= add_opt_tree_tree(&options_root
, "", "",
780 register_options(cmdline_options_info
, cmdline_options
);
782 config_options
= add_opt_tree_tree(&options_root
, "", "",
783 "config", OPT_SORT
, "");
784 config_options
->flags
|= OPT_LISTBOX
;
785 config_options
->box_item
= &option_browser
.root
;
786 register_options(config_options_info
, config_options
);
788 register_autocreated_options();
789 register_change_hooks(change_hooks
);
793 free_options_tree(LIST_OF(struct option
) *tree
, int recursive
)
795 while (!list_empty(*tree
))
796 delete_option_do(tree
->next
, recursive
);
803 unregister_options(config_options_info
, config_options
);
804 unregister_options(cmdline_options_info
, cmdline_options
);
805 config_options
->box_item
= NULL
;
806 free_options_tree(&options_root_tree
, 0);
810 register_change_hooks(const struct change_hook_info
*change_hooks
)
814 for (i
= 0; change_hooks
[i
].name
; i
++) {
815 struct option
*option
= get_opt_rec(config_options
,
816 change_hooks
[i
].name
);
819 option
->change_hook
= change_hooks
[i
].change_hook
;
824 prepare_mustsave_flags(LIST_OF(struct option
) *tree
, int set_all
)
826 struct option
*option
;
828 foreach (option
, *tree
) {
829 /* XXX: OPT_LANGUAGE shouldn't have any bussiness
830 * here, but we're just weird in that area. */
832 || (option
->flags
& (OPT_TOUCHED
| OPT_DELETED
))
833 || option
->type
== OPT_LANGUAGE
)
834 option
->flags
|= OPT_MUST_SAVE
;
836 option
->flags
&= ~OPT_MUST_SAVE
;
838 if (option
->type
== OPT_TREE
)
839 prepare_mustsave_flags(option
->value
.tree
, set_all
);
844 untouch_options(LIST_OF(struct option
) *tree
)
846 struct option
*option
;
848 foreach (option
, *tree
) {
849 option
->flags
&= ~OPT_TOUCHED
;
851 if (option
->type
== OPT_TREE
)
852 untouch_options(option
->value
.tree
);
857 check_nonempty_tree(LIST_OF(struct option
) *options
)
861 foreach (opt
, *options
) {
862 if (opt
->type
== OPT_TREE
) {
863 if (check_nonempty_tree(opt
->value
.tree
))
865 } else if (opt
->flags
& OPT_MUST_SAVE
) {
874 smart_config_string(struct string
*str
, int print_comment
, int i18n
,
875 LIST_OF(struct option
) *options
,
876 unsigned char *path
, int depth
,
877 void (*fn
)(struct string
*, struct option
*,
878 unsigned char *, int, int, int, int))
880 struct option
*option
;
882 foreach (option
, *options
) {
883 int do_print_comment
= 1;
885 if (option
->flags
& OPT_HIDDEN
||
886 option
->type
== OPT_ALIAS
||
887 !strcmp(option
->name
, "_template_"))
890 /* Is there anything to be printed anyway? */
891 if (option
->type
== OPT_TREE
892 ? !check_nonempty_tree(option
->value
.tree
)
893 : !(option
->flags
& OPT_MUST_SAVE
))
896 /* We won't pop out the description when we're in autocreate
897 * category and not template. It'd be boring flood of
898 * repetitive comments otherwise ;). */
900 /* This print_comment parameter is weird. If it is negative, it
901 * means that we shouldn't print comments at all. If it is 1,
902 * we shouldn't print comment UNLESS the option is _template_
903 * or not-an-autocreating-tree (it is set for the first-level
904 * autocreation tree). When it is 2, we can print out comments
906 /* It is still broken somehow, as it didn't work for terminal.*
907 * (the first autocreated level) by the time I wrote this. Good
908 * summer job for bored mad hackers with spare boolean mental
909 * power. I have better things to think about, personally.
910 * Maybe we should just mark autocreated options somehow ;). */
911 if (!print_comment
|| (print_comment
== 1
912 && (strcmp(option
->name
, "_template_")
913 && (option
->flags
& OPT_AUTOCREATE
914 && option
->type
== OPT_TREE
))))
915 do_print_comment
= 0;
917 /* Pop out the comment */
919 /* For config file, we ignore do_print_comment everywhere
920 * except 1, but sometimes we want to skip the option totally.
922 fn(str
, option
, path
, depth
,
923 option
->type
== OPT_TREE
? print_comment
927 fn(str
, option
, path
, depth
, do_print_comment
, 1, i18n
);
929 /* And the option itself */
931 if (option_types
[option
->type
].write
) {
932 fn(str
, option
, path
, depth
,
933 do_print_comment
, 2, i18n
);
935 } else if (option
->type
== OPT_TREE
) {
936 struct string newpath
;
937 int pc
= print_comment
;
939 if (!init_string(&newpath
)) continue; /* OK? */
941 if (pc
== 2 && option
->flags
& OPT_AUTOCREATE
)
943 else if (pc
== 1 && strcmp(option
->name
, "_template_"))
946 fn(str
, option
, path
, depth
, /*pc*/1, 3, i18n
);
949 add_to_string(&newpath
, path
);
950 add_char_to_string(&newpath
, '.');
952 add_to_string(&newpath
, option
->name
);
953 smart_config_string(str
, pc
, i18n
, option
->value
.tree
,
954 newpath
.source
, depth
+ 1, fn
);
955 done_string(&newpath
);
957 fn(str
, option
, path
, depth
, /*pc*/1, 3, i18n
);
964 change_hook_cache(struct session
*ses
, struct option
*current
, struct option
*changed
)
971 change_hook_connection(struct session
*ses
, struct option
*current
, struct option
*changed
)
973 register_check_queue();
978 change_hook_html(struct session
*ses
, struct option
*current
, struct option
*changed
)
980 foreach (ses
, sessions
) ses
->tab
->resize
= 1;
986 change_hook_insert_mode(struct session
*ses
, struct option
*current
, struct option
*changed
)
993 change_hook_active_link(struct session
*ses
, struct option
*current
, struct option
*changed
)
995 update_cached_document_options(ses
);
1000 change_hook_terminal(struct session
*ses
, struct option
*current
, struct option
*changed
)
1002 cls_redraw_all_terminals();
1007 change_hook_ui(struct session
*ses
, struct option
*current
, struct option
*changed
)
1013 /* Bit 2 of show means we should always set visibility, otherwise we set it
1014 * only on templates. */
1016 update_visibility(LIST_OF(struct option
) *tree
, int show
)
1020 foreach (opt
, *tree
) {
1021 if (opt
->flags
& OPT_DELETED
) continue;
1023 if (!strcmp(opt
->name
, "_template_")) {
1025 opt
->box_item
->visible
= (show
& 1);
1027 if (opt
->type
== OPT_TREE
)
1028 update_visibility(opt
->value
.tree
, show
| 2);
1030 if (opt
->box_item
&& (show
& 2))
1031 opt
->box_item
->visible
= (show
& 1);
1033 if (opt
->type
== OPT_TREE
)
1034 update_visibility(opt
->value
.tree
, show
);
1040 update_options_visibility(void)
1042 update_visibility(config_options
->value
.tree
,
1043 get_opt_bool("config.show_template", NULL
));
1047 toggle_option(struct session
*ses
, struct option
*option
)
1049 long number
= option
->value
.number
+ 1;
1051 assert(option
->type
== OPT_BOOL
|| option
->type
== OPT_INT
);
1052 assert(option
->max
);
1054 option
->value
.number
= (number
<= option
->max
) ? number
: option
->min
;
1055 option_changed(ses
, option
);
1059 change_hook_stemplate(struct session
*ses
, struct option
*current
, struct option
*changed
)
1061 update_visibility(config_options
->value
.tree
, changed
->value
.number
);
1066 change_hook_language(struct session
*ses
, struct option
*current
, struct option
*changed
)
1069 set_language(changed
->value
.number
);
1074 static const struct change_hook_info change_hooks
[] = {
1075 { "config.show_template", change_hook_stemplate
},
1076 { "connection", change_hook_connection
},
1077 { "document.browse", change_hook_html
},
1078 { "document.browse.forms.insert_mode",
1079 change_hook_insert_mode
},
1080 { "document.browse.links.active_link",
1081 change_hook_active_link
},
1082 { "document.cache", change_hook_cache
},
1083 { "document.codepage", change_hook_html
},
1084 { "document.colors", change_hook_html
},
1085 { "document.html", change_hook_html
},
1086 { "document.plain", change_hook_html
},
1087 { "terminal", change_hook_terminal
},
1088 { "ui.language", change_hook_language
},
1089 { "ui", change_hook_ui
},
1094 call_change_hooks(struct session
*ses
, struct option
*current
, struct option
*option
)
1096 /* This boolean thing can look a little weird - it
1097 * basically says that we should proceed when there's
1098 * no change_hook or there's one and its return value
1100 while (current
&& (!current
->change_hook
||
1101 !current
->change_hook(ses
, current
, option
))) {
1105 current
= current
->root
;
1110 option_changed(struct session
*ses
, struct option
*option
)
1112 option
->flags
|= OPT_TOUCHED
;
1113 /* Notify everyone out there! */
1114 call_change_hooks(ses
, option
, option
);
1118 commit_option_values(struct option_resolver
*resolvers
,
1119 struct option
*root
, union option_value
*values
, int size
)
1124 assert(resolvers
&& root
&& values
&& size
);
1126 for (i
= 0; i
< size
; i
++) {
1127 unsigned char *name
= resolvers
[i
].name
;
1128 struct option
*option
= get_opt_rec(root
, name
);
1129 int id
= resolvers
[i
].id
;
1131 assertm(option
, "Bad option '%s' in options resolver", name
);
1133 if (memcmp(&option
->value
, &values
[id
], sizeof(union option_value
))) {
1134 option
->value
= values
[id
];
1135 option
->flags
|= OPT_TOUCHED
;
1136 /* Speed hack: Directly call the change-hook for each
1137 * option in resolvers and later call call_change_hooks
1138 * on the root; if we were to call call_change_hooks
1139 * on each option in resolvers, we would end up calling
1140 * the change-hooks of root, its parents, its
1141 * grandparents, and so on for each option in resolvers
1142 * because call_change_hooks is recursive. -- Miciah */
1143 if (option
->change_hook
)
1144 option
->change_hook(NULL
, option
, NULL
);
1149 /* See above 'Speed hack' comment. */
1150 call_change_hooks(NULL
, root
, NULL
);
1156 checkout_option_values(struct option_resolver
*resolvers
,
1157 struct option
*root
,
1158 union option_value
*values
, int size
)
1162 for (i
= 0; i
< size
; i
++) {
1163 unsigned char *name
= resolvers
[i
].name
;
1164 struct option
*option
= get_opt_rec(root
, name
);
1165 int id
= resolvers
[i
].id
;
1167 assertm(option
, "Bad option '%s' in options resolver", name
);
1169 values
[id
] = option
->value
;
1173 /**********************************************************************
1175 **********************************************************************/
1177 #include "config/options.inc"
1180 register_options(struct option_info info
[], struct option
*tree
)
1184 for (i
= 0; info
[i
].path
; i
++) {
1185 struct option
*option
= &info
[i
].option
;
1186 unsigned char *string
;
1188 debug_check_option_syntax(option
);
1190 if (option
->type
!= OPT_ALIAS
1191 && ((tree
->flags
& OPT_LISTBOX
)
1192 || (option
->flags
& OPT_LISTBOX
))) {
1193 option
->box_item
= init_option_listbox_item(option
);
1194 if (!option
->box_item
) {
1195 delete_option(option
);
1200 switch (option
->type
) {
1202 option
->value
.tree
= init_options_tree();
1203 if (!option
->value
.tree
) {
1204 delete_option(option
);
1209 string
= mem_alloc(MAX_STR_LEN
);
1211 delete_option(option
);
1214 safe_strncpy(string
, option
->value
.string
, MAX_STR_LEN
);
1215 option
->value
.string
= string
;
1218 string
= option
->value
.string
;
1220 decode_color(string
, strlen(string
),
1221 &option
->value
.color
);
1224 string
= option
->value
.string
;
1226 option
->value
.number
= get_cp_index(string
);
1237 add_opt_rec(tree
, info
[i
].path
, option
);
1242 unregister_options(struct option_info info
[], struct option
*tree
)
1246 /* We need to remove the options in inverse order to the order how we
1249 while (info
[i
].path
) i
++;
1251 for (i
--; i
>= 0; i
--)
1252 delete_option_do(&info
[i
].option
, 0);