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/options.h"
17 #include "config/opttypes.h"
18 #include "dialogs/status.h"
19 #include "document/document.h"
20 #include "globhist/globhist.h"
21 #include "intl/charsets.h"
22 #include "intl/gettext/libintl.h"
23 #include "main/main.h" /* shrink_memory() */
24 #include "main/select.h"
25 #include "network/connection.h"
26 #include "session/session.h"
27 #include "terminal/color.h"
28 #include "terminal/screen.h"
29 #include "terminal/terminal.h"
30 #include "util/color.h"
31 #include "util/error.h"
32 #include "util/memory.h"
33 #include "util/string.h"
34 #include "viewer/text/draw.h"
37 /* TODO? In the past, covered by shadow and legends, remembered only by the
38 * ELinks Elders now, options were in hashes (it was not for a long time, after
39 * we started to use dynamic options lists and before we really started to use
40 * hierarchic options). Hashes might be swift and deft, but they had a flaw and
41 * the flaw showed up as the fatal flaw. They were unsorted, and it was
42 * unfriendly to mere mortal users, without pasky's options handlers in their
43 * brain, but their own poor-written software. And thus pasky went and rewrote
44 * options so that they were in lists from then to now and for all the ages of
45 * men, to the glory of mankind. However, one true hero may arise in future
46 * fabulous and implement possibility to have both lists and hashes for trees,
47 * as it may be useful for some supernatural entities. And when that age will
51 /* TODO: We should remove special case for root options and use some auxiliary
52 * (struct option *) instead. This applies to bookmarks, global history and
53 * listbox items as well, though. --pasky */
55 static INIT_LIST_HEAD(options_root_tree
);
57 static struct option options_root
= INIT_OPTION(
62 /* value: */ &options_root_tree
,
67 struct option
*config_options
;
68 struct option
*cmdline_options
;
70 static void add_opt_rec(struct option
*, unsigned char *, struct option
*);
71 static void free_options_tree(struct list_head
*, int recursive
);
74 /* Detect ending '.' (and some others) in options captions.
75 * It will emit a message in debug mode only. --Zas */
77 #define bad_punct(c) (c != ')' && c != '>' && !isquote(c) && ispunct(c))
80 check_caption(unsigned char *caption
)
87 len
= strlen(caption
);
91 if (isspace(c
) || bad_punct(c
))
92 DBG("bad char at end of caption [%s]", caption
);
95 caption
= gettext(caption
);
96 len
= strlen(caption
);
100 if (isspace(c
) || bad_punct(c
))
101 DBG("bad char at end of i18n caption [%s]", caption
);
108 check_description(unsigned char *desc
)
120 DBG("bad char at end of description [%s]", desc
);
123 desc
= gettext(desc
);
127 if (ispunct(c
) != ispunct(desc
[len
- 1]))
128 DBG("punctuation char possibly missing at end of i18n description [%s]", desc
);
132 DBG("bad char at end of i18n description [%s]", desc
);
137 debug_check_option_syntax(struct option
*option
)
140 check_caption(option
->capt
);
141 check_description(option
->desc
);
145 #define debug_check_option_syntax(option)
149 /**********************************************************************
151 **********************************************************************/
153 /* If option name contains dots, they are created as "categories" - first,
154 * first category is retrieved from list, taken as a list, second category
155 * is retrieved etc. */
158 static int no_autocreate
= 0;
160 /* Get record of option of given name, or NULL if there's no such option. */
162 get_opt_rec(struct option
*tree
, unsigned char *name_
)
164 struct option
*option
;
165 unsigned char *aname
= stracpy(name_
);
166 unsigned char *name
= aname
;
169 if (!aname
) return NULL
;
171 /* We iteratively call get_opt_rec() each for path_elements-1, getting
172 * appropriate tree for it and then resolving [path_elements]. */
173 if ((sep
= strrchr(name
, '.'))) {
176 tree
= get_opt_rec(tree
, name
);
177 if (!tree
|| tree
->type
!= OPT_TREE
|| tree
->flags
& OPT_HIDDEN
) {
179 DBG("ERROR in get_opt_rec() crawl: %s (%d) -> %s",
180 name
, tree
? tree
->type
: -1, sep
+ 1);
190 foreach (option
, *tree
->value
.tree
) {
191 if (option
->name
&& !strcmp(option
->name
, name
)) {
197 if (tree
&& tree
->flags
& OPT_AUTOCREATE
&& !no_autocreate
) {
198 struct option
*template = get_opt_rec(tree
, "_template_");
200 assertm(template, "Requested %s should be autocreated but "
201 "%.*s._template_ is missing!", name_
, sep
- name_
,
208 /* We will just create the option and return pointer to it
209 * automagically. And, we will create it by cloning _template_
210 * option. By having _template_ OPT_AUTOCREATE and _template_
211 * inside, you can have even multi-level autocreating. */
213 option
= copy_option(template);
218 mem_free_set(&option
->name
, stracpy(name
));
220 add_opt_rec(tree
, "", option
);
230 /* Get record of option of given name, or NULL if there's no such option. But
231 * do not create the option if it doesn't exist and there's autocreation
234 get_opt_rec_real(struct option
*tree
, unsigned char *name
)
239 opt
= get_opt_rec(tree
, name
);
244 /* Fetch pointer to value of certain option. It is guaranteed to never return
245 * NULL. Note that you are supposed to use wrapper get_opt(). */
249 unsigned char *file
, int line
, enum option_type option_type
,
251 struct option
*tree
, unsigned char *name
)
253 struct option
*opt
= get_opt_rec(tree
, name
);
258 if (!opt
) elinks_internal("Attempted to fetch nonexisting option %s!", name
);
260 /* Various sanity checks. */
261 if (option_type
!= opt
->type
)
262 DBG("get_opt_*(\"%s\") @ %s:%d: call with wrapper for %s for option of type %s",
264 get_option_type_name(option_type
),
265 get_option_type_name(opt
->type
));
269 if (!opt
->value
.tree
)
270 elinks_internal("Option %s has no value!", name
);
273 elinks_internal("Invalid use of alias %s for option %s!",
274 name
, opt
->value
.string
);
277 if (!opt
->value
.string
)
278 elinks_internal("Option %s has no value!", name
);
282 if (opt
->value
.number
< opt
->min
283 || opt
->value
.number
> opt
->max
)
284 elinks_internal("Option %s has invalid value %d!", name
, opt
->value
.number
);
287 if (opt
->value
.big_number
< opt
->min
288 || opt
->value
.big_number
> opt
->max
)
289 elinks_internal("Option %s has invalid value %ld!", name
, opt
->value
.big_number
);
292 if (!opt
->value
.command
)
293 elinks_internal("Option %s has no value!", name
);
295 case OPT_CODEPAGE
: /* TODO: check these too. */
306 add_opt_sort(struct option
*tree
, struct option
*option
, int abi
)
308 struct list_head
*cat
= tree
->value
.tree
;
309 struct list_head
*bcat
= &tree
->box_item
->child
;
312 /* The list is empty, just add it there. */
313 if (list_empty(*cat
)) {
314 add_to_list(*cat
, option
);
315 if (abi
) add_to_list(*bcat
, option
->box_item
);
317 /* This fits as the last list entry, add it there. This
318 * optimizes the most expensive BUT most common case ;-). */
319 } else if ((option
->type
!= OPT_TREE
320 || ((struct option
*) cat
->prev
)->type
== OPT_TREE
)
321 && strcmp(((struct option
*) cat
->prev
)->name
,
322 option
->name
) <= 0) {
324 add_to_list_end(*cat
, option
);
325 if (abi
) add_to_list_end(*bcat
, option
->box_item
);
327 /* At the end of the list is tree and we are ordinary. That's
328 * clear case then. */
329 } else if (option
->type
!= OPT_TREE
330 && ((struct option
*) cat
->prev
)->type
== OPT_TREE
) {
333 /* Scan the list linearly. This could be probably optimized ie.
334 * to choose direction based on the first letter or so. */
336 struct listbox_item
*bpos
= (struct listbox_item
*) bcat
;
338 foreach (pos
, *cat
) {
339 /* First move the box item to the current position but
340 * only if the position has not been marked as deleted
341 * and actually has a box_item -- else we will end up
342 * 'overflowing' and causing assertion failure. */
343 if (!(pos
->flags
& OPT_DELETED
) && pos
->box_item
) {
345 assert(bpos
!= (struct listbox_item
*) bcat
);
348 if ((option
->type
!= OPT_TREE
349 || pos
->type
== OPT_TREE
)
350 && strcmp(pos
->name
, option
->name
) <= 0)
353 /* Ordinary options always sort behind trees. */
354 if (option
->type
!= OPT_TREE
355 && pos
->type
== OPT_TREE
)
358 /* The (struct option) add_at_pos() can mess up the
359 * order so that we add the box_item to itself, so
360 * better do it first. */
362 /* Always ensure that them _template_ options are
363 * before anything else so a lonely autocreated option
364 * (with _template_ options set to invisible) will be
365 * connected with an upper corner (ascii: `-) instead
366 * of a rotated T (ascii: +-) when displaying it. */
367 if (option
->type
== pos
->type
368 && *option
->name
<= '_'
369 && !strcmp(pos
->name
, "_template_")) {
370 if (abi
) add_at_pos(bpos
, option
->box_item
);
371 add_at_pos(pos
, option
);
375 if (abi
) add_at_pos(bpos
->prev
, option
->box_item
);
376 add_at_pos(pos
->prev
, option
);
380 assert(pos
!= (struct option
*) cat
);
381 assert(bpos
!= (struct listbox_item
*) bcat
);
385 /* Add option to tree. */
387 add_opt_rec(struct option
*tree
, unsigned char *path
, struct option
*option
)
391 assert(path
&& option
&& tree
);
392 if (*path
) tree
= get_opt_rec(tree
, path
);
394 assertm(tree
, "Missing option tree for '%s'", path
);
395 if (!tree
->value
.tree
) return;
397 object_nolock(option
, "option");
399 if (option
->box_item
&& option
->name
&& !strcmp(option
->name
, "_template_"))
400 option
->box_item
->visible
= get_opt_bool("config.show_template");
402 if (tree
->flags
& OPT_AUTOCREATE
&& !option
->desc
) {
403 struct option
*template = get_opt_rec(tree
, "_template_");
406 option
->desc
= template->desc
;
411 abi
= (tree
->box_item
&& option
->box_item
);
414 /* The config_root tree is a just a placeholder for the
415 * box_items, it actually isn't a real box_item by itself;
416 * these ghosts are indicated by the fact that they have
418 if (tree
->box_item
->next
) {
419 option
->box_item
->depth
= tree
->box_item
->depth
+ 1;
423 if (tree
->flags
& OPT_SORT
) {
424 add_opt_sort(tree
, option
, abi
);
427 add_to_list_end(*tree
->value
.tree
, option
);
428 if (abi
) add_to_list_end(tree
->box_item
->child
, option
->box_item
);
431 update_hierbox_browser(&option_browser
);
434 static inline struct listbox_item
*
435 init_option_listbox_item(struct option
*option
)
437 struct listbox_item
*item
= mem_calloc(1, sizeof(*item
));
439 if (!item
) return NULL
;
441 init_list(item
->child
);
443 item
->udata
= option
;
444 item
->type
= (option
->type
== OPT_TREE
) ? BI_FOLDER
: BI_LEAF
;
450 add_opt(struct option
*tree
, unsigned char *path
, unsigned char *capt
,
451 unsigned char *name
, enum option_flags flags
, enum option_type type
,
452 long min
, long max
, longptr_T value
, unsigned char *desc
)
454 struct option
*option
= mem_calloc(1, sizeof(*option
));
456 if (!option
) return NULL
;
458 option
->name
= stracpy(name
);
463 option
->flags
= (flags
| OPT_ALLOC
);
470 debug_check_option_syntax(option
);
472 /* XXX: For allocated values we allocate in the add_opt_<type>() macro.
473 * This involves OPT_TREE and OPT_STRING. */
480 option
->value
.tree
= (struct list_head
*) value
;
487 option
->value
.string
= (unsigned char *) value
;
490 option
->value
.string
= (unsigned char *) value
;
495 option
->value
.number
= (int) value
;
498 option
->value
.big_number
= (long) value
; /* FIXME: cast from void * */
501 decode_color((unsigned char *) value
, strlen((unsigned char *) value
),
502 &option
->value
.color
);
505 option
->value
.command
= (void *) value
;
511 if (option
->type
!= OPT_ALIAS
512 && ((tree
->flags
& OPT_LISTBOX
) || (option
->flags
& OPT_LISTBOX
))) {
513 option
->box_item
= init_option_listbox_item(option
);
514 if (!option
->box_item
) {
520 add_opt_rec(tree
, path
, option
);
525 done_option(struct option
*option
)
527 switch (option
->type
) {
529 mem_free_if(option
->value
.string
);
532 mem_free_if(option
->value
.tree
);
538 if (option
->box_item
)
539 done_listbox_item(&option_browser
, option
->box_item
);
541 if (option
->flags
& OPT_ALLOC
) {
542 mem_free_if(option
->name
);
544 } else if (!option
->capt
) {
545 /* We are probably dealing with a built-in autocreated option
546 * that will be attempted to be deleted when shutting down. */
547 /* Clear it so nothing will be done later. */
548 memset(option
, 0, sizeof(*option
));
552 /* The namespace may start to seem a bit chaotic here; it indeed is, maybe the
553 * function names above should be renamed and only macros should keep their old
555 /* The simple rule I took as an apologize is that functions which take already
556 * completely filled (struct option *) have long name and functions which take
557 * only option specs have short name. */
560 delete_option_do(struct option
*option
, int recursive
)
563 del_from_list(option
);
564 option
->prev
= option
->next
= NULL
;
567 if (recursive
== -1) {
568 ERROR("Orphaned option %s", option
->name
);
571 if (option
->type
== OPT_TREE
&& option
->value
.tree
572 && !list_empty(*option
->value
.tree
)) {
574 if (option
->flags
& OPT_AUTOCREATE
) {
577 ERROR("Orphaned unregistered "
578 "option in subtree %s!",
583 free_options_tree(option
->value
.tree
, recursive
);
590 mark_option_as_deleted(struct option
*option
)
592 if (option
->type
== OPT_TREE
) {
593 struct option
*unmarked
;
595 assert(option
->value
.tree
);
597 foreach (unmarked
, *option
->value
.tree
)
598 mark_option_as_deleted(unmarked
);
601 option
->box_item
->visible
= 0;
603 option
->flags
|= (OPT_TOUCHED
| OPT_DELETED
);
607 delete_option(struct option
*option
)
609 delete_option_do(option
, 1);
613 copy_option(struct option
*template)
615 struct option
*option
= mem_calloc(1, sizeof(*option
));
617 if (!option
) return NULL
;
619 option
->name
= null_or_stracpy(template->name
);
620 option
->flags
= (template->flags
| OPT_ALLOC
);
621 option
->type
= template->type
;
622 option
->min
= template->min
;
623 option
->max
= template->max
;
624 option
->capt
= template->capt
;
625 option
->desc
= template->desc
;
626 option
->change_hook
= template->change_hook
;
628 option
->box_item
= init_option_listbox_item(option
);
629 if (option
->box_item
) {
630 if (template->box_item
) {
631 option
->box_item
->type
= template->box_item
->type
;
632 option
->box_item
->depth
= template->box_item
->depth
;
636 if (option_types
[template->type
].dup
) {
637 option_types
[template->type
].dup(option
, template);
639 option
->value
= template->value
;
646 init_options_tree(void)
648 struct list_head
*ptr
= mem_alloc(sizeof(*ptr
));
650 if (ptr
) init_list(*ptr
);
654 /* Some default pre-autocreated options. Doh. */
656 register_autocreated_options(void)
658 /* TODO: Use table-driven initialization. --jonas */
659 get_opt_int("terminal.linux.type") = 2;
660 get_opt_int("terminal.linux.colors") = 1;
661 get_opt_bool("terminal.linux.m11_hack") = 1;
662 get_opt_int("terminal.vt100.type") = 1;
663 get_opt_int("terminal.vt110.type") = 1;
664 get_opt_int("terminal.xterm.type") = 1;
665 get_opt_bool("terminal.xterm.underline") = 1;
666 get_opt_int("terminal.xterm-color.type") = 1;
667 get_opt_int("terminal.xterm-color.colors") = COLOR_MODE_16
;
668 get_opt_bool("terminal.xterm-color.underline") = 1;
669 #ifdef CONFIG_88_COLORS
670 get_opt_int("terminal.xterm-88color.type") = 1;
671 get_opt_int("terminal.xterm-88color.colors") = COLOR_MODE_88
;
672 get_opt_bool("terminal.xterm-88color.underline") = 1;
674 #ifdef CONFIG_256_COLORS
675 get_opt_int("terminal.xterm-256color.type") = 1;
676 get_opt_int("terminal.xterm-256color.colors") = COLOR_MODE_256
;
677 get_opt_bool("terminal.xterm-256color.underline") = 1;
681 static struct option_info config_options_info
[];
682 extern struct option_info cmdline_options_info
[];
683 static struct change_hook_info change_hooks
[];
688 cmdline_options
= add_opt_tree_tree(&options_root
, "", "",
690 register_options(cmdline_options_info
, cmdline_options
);
692 config_options
= add_opt_tree_tree(&options_root
, "", "",
693 "config", OPT_SORT
, "");
694 config_options
->flags
|= OPT_LISTBOX
;
695 config_options
->box_item
= &option_browser
.root
;
696 register_options(config_options_info
, config_options
);
698 register_autocreated_options();
699 register_change_hooks(change_hooks
);
703 free_options_tree(struct list_head
*tree
, int recursive
)
705 while (!list_empty(*tree
))
706 delete_option_do(tree
->next
, recursive
);
712 unregister_options(config_options_info
, config_options
);
713 unregister_options(cmdline_options_info
, cmdline_options
);
714 config_options
->box_item
= NULL
;
715 free_options_tree(&options_root_tree
, 0);
719 register_change_hooks(struct change_hook_info
*change_hooks
)
723 for (i
= 0; change_hooks
[i
].name
; i
++) {
724 struct option
*option
= get_opt_rec(config_options
,
725 change_hooks
[i
].name
);
728 option
->change_hook
= change_hooks
[i
].change_hook
;
733 unmark_options_tree(struct list_head
*tree
)
735 struct option
*option
;
737 foreach (option
, *tree
) {
738 option
->flags
&= ~OPT_WATERMARK
;
739 if (option
->type
== OPT_TREE
)
740 unmark_options_tree(option
->value
.tree
);
745 watermark_deleted_options(struct list_head
*tree
)
747 struct option
*option
;
749 foreach (option
, *tree
) {
750 if (option
->flags
& OPT_DELETED
)
751 option
->flags
|= OPT_WATERMARK
;
752 else if (option
->type
== OPT_TREE
)
753 watermark_deleted_options(option
->value
.tree
);
758 check_nonempty_tree(struct list_head
*options
)
762 foreach (opt
, *options
) {
763 if (opt
->type
== OPT_TREE
) {
764 if (check_nonempty_tree(opt
->value
.tree
))
766 } else if (!(opt
->flags
& OPT_WATERMARK
)) {
775 smart_config_string(struct string
*str
, int print_comment
, int i18n
,
776 struct list_head
*options
, unsigned char *path
, int depth
,
777 void (*fn
)(struct string
*, struct option
*,
778 unsigned char *, int, int, int, int))
780 struct option
*option
;
782 foreach (option
, *options
) {
783 int do_print_comment
= 1;
785 if (option
->flags
& OPT_HIDDEN
||
786 option
->flags
& OPT_WATERMARK
||
787 option
->type
== OPT_ALIAS
||
788 !strcmp(option
->name
, "_template_"))
791 /* Is there anything to be printed anyway? */
792 if (option
->type
== OPT_TREE
793 && !check_nonempty_tree(option
->value
.tree
))
796 /* We won't pop out the description when we're in autocreate
797 * category and not template. It'd be boring flood of
798 * repetitive comments otherwise ;). */
800 /* This print_comment parameter is weird. If it is negative, it
801 * means that we shouldn't print comments at all. If it is 1,
802 * we shouldn't print comment UNLESS the option is _template_
803 * or not-an-autocreating-tree (it is set for the first-level
804 * autocreation tree). When it is 2, we can print out comments
806 /* It is still broken somehow, as it didn't work for terminal.*
807 * (the first autocreated level) by the time I wrote this. Good
808 * summer job for bored mad hackers with spare boolean mental
809 * power. I have better things to think about, personally.
810 * Maybe we should just mark autocreated options somehow ;). */
811 if (!print_comment
|| (print_comment
== 1
812 && (strcmp(option
->name
, "_template_")
813 && (option
->flags
& OPT_AUTOCREATE
814 && option
->type
== OPT_TREE
))))
815 do_print_comment
= 0;
817 /* Pop out the comment */
819 /* For config file, we ignore do_print_comment everywhere
820 * except 1, but sometimes we want to skip the option totally.
822 fn(str
, option
, path
, depth
,
823 option
->type
== OPT_TREE
? print_comment
827 fn(str
, option
, path
, depth
, do_print_comment
, 1, i18n
);
829 /* And the option itself */
831 if (option_types
[option
->type
].write
) {
832 fn(str
, option
, path
, depth
,
833 do_print_comment
, 2, i18n
);
835 } else if (option
->type
== OPT_TREE
) {
836 struct string newpath
;
837 int pc
= print_comment
;
839 if (!init_string(&newpath
)) continue; /* OK? */
841 if (pc
== 2 && option
->flags
& OPT_AUTOCREATE
)
843 else if (pc
== 1 && strcmp(option
->name
, "_template_"))
846 fn(str
, option
, path
, depth
, /*pc*/1, 3, i18n
);
849 add_to_string(&newpath
, path
);
850 add_char_to_string(&newpath
, '.');
852 add_to_string(&newpath
, option
->name
);
853 smart_config_string(str
, pc
, i18n
, option
->value
.tree
,
854 newpath
.source
, depth
+ 1, fn
);
855 done_string(&newpath
);
857 fn(str
, option
, path
, depth
, /*pc*/1, 3, i18n
);
860 /* TODO: We should maybe clear the touched flag only when really
861 * saving the stuff...? --pasky */
862 option
->flags
&= ~OPT_TOUCHED
;
868 change_hook_cache(struct session
*ses
, struct option
*current
, struct option
*changed
)
875 change_hook_connection(struct session
*ses
, struct option
*current
, struct option
*changed
)
877 register_check_queue();
882 change_hook_html(struct session
*ses
, struct option
*current
, struct option
*changed
)
884 foreach (ses
, sessions
) ses
->tab
->resize
= 1;
890 change_hook_insert_mode(struct session
*ses
, struct option
*current
, struct option
*changed
)
897 change_hook_active_link(struct session
*ses
, struct option
*current
, struct option
*changed
)
899 update_cached_document_options();
904 change_hook_terminal(struct session
*ses
, struct option
*current
, struct option
*changed
)
906 cls_redraw_all_terminals();
911 change_hook_ui(struct session
*ses
, struct option
*current
, struct option
*changed
)
917 /* Bit 2 of show means we should always set visibility, otherwise we set it
918 * only on templates. */
920 update_visibility(struct list_head
*tree
, int show
)
924 foreach (opt
, *tree
) {
925 if (opt
->flags
& OPT_DELETED
) continue;
927 if (!strcmp(opt
->name
, "_template_")) {
929 opt
->box_item
->visible
= (show
& 1);
931 if (opt
->type
== OPT_TREE
)
932 update_visibility(opt
->value
.tree
, show
| 2);
934 if (opt
->box_item
&& (show
& 2))
935 opt
->box_item
->visible
= (show
& 1);
937 if (opt
->type
== OPT_TREE
)
938 update_visibility(opt
->value
.tree
, show
);
944 update_options_visibility(void)
946 update_visibility(config_options
->value
.tree
,
947 get_opt_bool("config.show_template"));
951 toggle_option(struct session
*ses
, struct option
*option
)
953 long number
= option
->value
.number
+ 1;
955 assert(option
->type
== OPT_BOOL
|| option
->type
== OPT_INT
);
958 /* TODO: call change hooks. --jonas */
959 option
->value
.number
= (number
<= option
->max
) ? number
: option
->min
;
960 option_changed(ses
, option
, option
);
964 change_hook_stemplate(struct session
*ses
, struct option
*current
, struct option
*changed
)
966 update_visibility(config_options
->value
.tree
, changed
->value
.number
);
971 change_hook_language(struct session
*ses
, struct option
*current
, struct option
*changed
)
974 set_language(changed
->value
.number
);
979 static struct change_hook_info change_hooks
[] = {
980 { "config.show_template", change_hook_stemplate
},
981 { "connection", change_hook_connection
},
982 { "document.browse", change_hook_html
},
983 { "document.browse.forms.insert_mode",
984 change_hook_insert_mode
},
985 { "document.browse.links.active_link",
986 change_hook_active_link
},
987 { "document.cache", change_hook_cache
},
988 { "document.codepage", change_hook_html
},
989 { "document.colors", change_hook_html
},
990 { "document.html", change_hook_html
},
991 { "document.plain", change_hook_html
},
992 { "terminal", change_hook_terminal
},
993 { "ui.language", change_hook_language
},
994 { "ui", change_hook_ui
},
999 call_change_hooks(struct session
*ses
, struct option
*current
, struct option
*option
)
1001 /* This boolean thing can look a little weird - it
1002 * basically says that we should proceed when there's
1003 * no change_hook or there's one and its return value
1005 while (current
&& (!current
->change_hook
||
1006 !current
->change_hook(ses
, current
, option
))) {
1010 current
= current
->root
;
1015 option_changed(struct session
*ses
, struct option
*current
, struct option
*option
)
1017 option
->flags
|= OPT_TOUCHED
;
1018 /* Notify everyone out there! */
1019 call_change_hooks(ses
, current
, option
);
1023 commit_option_values(struct option_resolver
*resolvers
,
1024 struct option
*root
, union option_value
*values
, int size
)
1029 assert(resolvers
&& root
&& values
&& size
);
1031 for (i
= 0; i
< size
; i
++) {
1032 unsigned char *name
= resolvers
[i
].name
;
1033 struct option
*option
= get_opt_rec(root
, name
);
1034 int id
= resolvers
[i
].id
;
1036 if (memcmp(&option
->value
, &values
[id
], sizeof(union option_value
))) {
1037 option
->value
= values
[id
];
1038 option
->flags
|= OPT_TOUCHED
;
1039 /* Speed hack: Directly call the change-hook for each
1040 * option in resolvers and later call call_change_hooks
1041 * on the root; if we were to call call_change_hooks
1042 * on each option in resolvers, we would end up calling
1043 * the change-hooks of root, its parents, its
1044 * grandparents, and so on for each option in resolvers
1045 * because call_change_hooks is recursive. -- Miciah */
1046 if (option
->change_hook
)
1047 option
->change_hook(NULL
, option
, NULL
);
1052 /* See above 'Speed hack' comment. */
1053 call_change_hooks(NULL
, root
, NULL
);
1059 checkout_option_values(struct option_resolver
*resolvers
,
1060 struct option
*root
,
1061 union option_value
*values
, int size
)
1065 for (i
= 0; i
< size
; i
++) {
1066 unsigned char *name
= resolvers
[i
].name
;
1067 struct option
*option
= get_opt_rec(root
, name
);
1068 int id
= resolvers
[i
].id
;
1070 values
[id
] = option
->value
;
1074 /**********************************************************************
1076 **********************************************************************/
1078 #include "config/options.inc"
1081 register_options(struct option_info info
[], struct option
*tree
)
1085 for (i
= 0; info
[i
].path
; i
++) {
1086 struct option
*option
= &info
[i
].option
;
1087 unsigned char *string
;
1089 debug_check_option_syntax(option
);
1091 if (option
->type
!= OPT_ALIAS
1092 && ((tree
->flags
& OPT_LISTBOX
)
1093 || (option
->flags
& OPT_LISTBOX
))) {
1094 option
->box_item
= init_option_listbox_item(option
);
1095 if (!option
->box_item
) {
1096 delete_option(option
);
1101 switch (option
->type
) {
1103 option
->value
.tree
= init_options_tree();
1104 if (!option
->value
.tree
) {
1105 delete_option(option
);
1110 string
= mem_alloc(MAX_STR_LEN
);
1112 delete_option(option
);
1115 safe_strncpy(string
, option
->value
.string
, MAX_STR_LEN
);
1116 option
->value
.string
= string
;
1119 string
= option
->value
.string
;
1121 decode_color(string
, strlen(string
),
1122 &option
->value
.color
);
1125 string
= option
->value
.string
;
1127 option
->value
.number
= get_cp_index(string
);
1138 add_opt_rec(tree
, info
[i
].path
, option
);
1143 unregister_options(struct option_info info
[], struct option
*tree
)
1147 /* We need to remove the options in inverse order to the order how we
1150 while (info
[i
].path
) i
++;
1152 for (i
--; i
>= 0; i
--)
1153 delete_option_do(&info
[i
].option
, 0);