config: Access OPT_MUST_SAVE in the real option, not alias.
[elinks/elinks-j605.git] / src / config / options.c
blob61c77b17eff7665edf120b1222c431e85182da2b
1 /* Options variables manipulation core */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <ctype.h>
8 #include <string.h>
10 #include "elinks.h"
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
48 * come... */
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(
58 /* name: */ "",
59 /* flags: */ 0,
60 /* type: */ OPT_TREE,
61 /* min, max: */ 0, 0,
62 /* value: */ &options_root_tree,
63 /* desc: */ "",
64 /* capt: */ NULL
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);
73 #ifdef CONFIG_DEBUG
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))
79 static void
80 check_caption(unsigned char *caption)
82 int len;
83 unsigned char c;
85 if (!caption) return;
87 len = strlen(caption);
88 if (!len) return;
90 c = caption[len - 1];
91 if (isspace(c) || bad_punct(c))
92 DBG("bad char at end of caption [%s]", caption);
94 #ifdef CONFIG_NLS
95 caption = gettext(caption);
96 len = strlen(caption);
97 if (!len) return;
99 c = caption[len - 1];
100 if (isspace(c) || bad_punct(c))
101 DBG("bad char at end of i18n caption [%s]", caption);
102 #endif
105 #undef bad_punct
107 static void
108 check_description(unsigned char *desc)
110 int len;
111 unsigned char c;
113 if (!desc) return;
115 len = strlen(desc);
116 if (!len) return;
118 c = desc[len - 1];
119 if (isspace(c))
120 DBG("bad char at end of description [%s]", desc);
122 #ifdef CONFIG_NLS
123 desc = gettext(desc);
124 len = strlen(desc);
125 if (!len) return;
127 if (ispunct(c) != ispunct(desc[len - 1]))
128 DBG("punctuation char possibly missing at end of i18n description [%s]", desc);
130 c = desc[len - 1];
131 if (isspace(c))
132 DBG("bad char at end of i18n description [%s]", desc);
133 #endif
136 static void
137 debug_check_option_syntax(struct option *option)
139 if (!option) return;
140 check_caption(option->capt);
141 check_description(option->desc);
144 #else
145 #define debug_check_option_syntax(option)
146 #endif
149 /**********************************************************************
150 Options interface
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. */
157 /* Ugly kludge */
158 static int no_autocreate = 0;
160 /** Get record of option of given name, or NULL if there's no such option.
162 * If the specified option is an ::OPT_ALIAS, this function returns the
163 * alias, rather than the option to which the alias refers. It must
164 * work this way because the alias may have the ::OPT_ALIAS_NEGATE flag.
165 * Instead, if the caller tries to read or set the value of the alias,
166 * the functions associated with ::OPT_ALIAS will forward the operation
167 * to the underlying option. However, see indirect_option(). */
168 struct option *
169 get_opt_rec(struct option *tree, unsigned char *name_)
171 struct option *option;
172 unsigned char *aname = stracpy(name_);
173 unsigned char *name = aname;
174 unsigned char *sep;
176 if (!aname) return NULL;
178 /* We iteratively call get_opt_rec() each for path_elements-1, getting
179 * appropriate tree for it and then resolving [path_elements]. */
180 if ((sep = strrchr(name, '.'))) {
181 *sep = '\0';
183 tree = get_opt_rec(tree, name);
184 if (!tree || tree->type != OPT_TREE || tree->flags & OPT_HIDDEN) {
185 #if 0
186 DBG("ERROR in get_opt_rec() crawl: %s (%d) -> %s",
187 name, tree ? tree->type : -1, sep + 1);
188 #endif
189 mem_free(aname);
190 return NULL;
193 *sep = '.';
194 name = sep + 1;
197 foreach (option, *tree->value.tree) {
198 if (option->name && !strcmp(option->name, name)) {
199 mem_free(aname);
200 return option;
204 if (tree && tree->flags & OPT_AUTOCREATE && !no_autocreate) {
205 struct option *template = get_opt_rec(tree, "_template_");
207 assertm(template, "Requested %s should be autocreated but "
208 "%.*s._template_ is missing!", name_, sep - name_,
209 name_);
210 if_assert_failed {
211 mem_free(aname);
212 return NULL;
215 /* We will just create the option and return pointer to it
216 * automagically. And, we will create it by cloning _template_
217 * option. By having _template_ OPT_AUTOCREATE and _template_
218 * inside, you can have even multi-level autocreating. */
220 option = copy_option(template);
221 if (!option) {
222 mem_free(aname);
223 return NULL;
225 mem_free_set(&option->name, stracpy(name));
227 add_opt_rec(tree, "", option);
229 mem_free(aname);
230 return option;
233 mem_free(aname);
234 return NULL;
237 /* Get record of option of given name, or NULL if there's no such option. But
238 * do not create the option if it doesn't exist and there's autocreation
239 * enabled. */
240 struct option *
241 get_opt_rec_real(struct option *tree, unsigned char *name)
243 struct option *opt;
245 no_autocreate = 1;
246 opt = get_opt_rec(tree, name);
247 no_autocreate = 0;
248 return opt;
251 /** If @a opt is an alias, return the option to which it refers.
253 * @warning Because the alias may have the ::OPT_ALIAS_NEGATE flag,
254 * the caller must not access the value of the returned option as if
255 * it were also the value of the alias. However, it is safe to access
256 * flags such as ::OPT_MUST_SAVE and ::OPT_DELETED. */
257 struct option *
258 indirect_option(struct option *alias)
260 struct option *real;
262 if (alias->type != OPT_ALIAS) return alias; /* not an error */
264 real = get_opt_rec(config_options, alias->value.string);
265 assertm(real != NULL, "%s aliased to unknown option %s!",
266 alias->name, alias->value.string);
267 if_assert_failed return alias;
269 return real;
272 /* Fetch pointer to value of certain option. It is guaranteed to never return
273 * NULL. Note that you are supposed to use wrapper get_opt(). */
274 union option_value *
275 get_opt_(
276 #ifdef CONFIG_DEBUG
277 unsigned char *file, int line, enum option_type option_type,
278 #endif
279 struct option *tree, unsigned char *name)
281 struct option *opt = get_opt_rec(tree, name);
283 #ifdef CONFIG_DEBUG
284 errfile = file;
285 errline = line;
286 if (!opt) elinks_internal("Attempted to fetch nonexisting option %s!", name);
288 /* Various sanity checks. */
289 if (option_type != opt->type)
290 DBG("get_opt_*(\"%s\") @ %s:%d: call with wrapper for %s for option of type %s",
291 name, file, line,
292 get_option_type_name(option_type),
293 get_option_type_name(opt->type));
295 switch (opt->type) {
296 case OPT_TREE:
297 if (!opt->value.tree)
298 elinks_internal("Option %s has no value!", name);
299 break;
300 case OPT_ALIAS:
301 elinks_internal("Invalid use of alias %s for option %s!",
302 name, opt->value.string);
303 break;
304 case OPT_STRING:
305 if (!opt->value.string)
306 elinks_internal("Option %s has no value!", name);
307 break;
308 case OPT_BOOL:
309 case OPT_INT:
310 case OPT_LONG:
311 if (opt->value.number < opt->min
312 || opt->value.number > opt->max)
313 elinks_internal("Option %s has invalid value %d!", name, opt->value.number);
314 break;
315 case OPT_COMMAND:
316 if (!opt->value.command)
317 elinks_internal("Option %s has no value!", name);
318 break;
319 case OPT_CODEPAGE: /* TODO: check these too. */
320 case OPT_LANGUAGE:
321 case OPT_COLOR:
322 break;
324 #endif
326 return &opt->value;
329 static void
330 add_opt_sort(struct option *tree, struct option *option, int abi)
332 struct list_head *cat = tree->value.tree;
333 struct list_head *bcat = &tree->box_item->child;
334 struct option *pos;
336 /* The list is empty, just add it there. */
337 if (list_empty(*cat)) {
338 add_to_list(*cat, option);
339 if (abi) add_to_list(*bcat, option->box_item);
341 /* This fits as the last list entry, add it there. This
342 * optimizes the most expensive BUT most common case ;-). */
343 } else if ((option->type != OPT_TREE
344 || ((struct option *) cat->prev)->type == OPT_TREE)
345 && strcmp(((struct option *) cat->prev)->name,
346 option->name) <= 0) {
347 append:
348 add_to_list_end(*cat, option);
349 if (abi) add_to_list_end(*bcat, option->box_item);
351 /* At the end of the list is tree and we are ordinary. That's
352 * clear case then. */
353 } else if (option->type != OPT_TREE
354 && ((struct option *) cat->prev)->type == OPT_TREE) {
355 goto append;
357 /* Scan the list linearly. This could be probably optimized ie.
358 * to choose direction based on the first letter or so. */
359 } else {
360 struct listbox_item *bpos = (struct listbox_item *) bcat;
362 foreach (pos, *cat) {
363 /* First move the box item to the current position but
364 * only if the position has not been marked as deleted
365 * and actually has a box_item -- else we will end up
366 * 'overflowing' and causing assertion failure. */
367 if (!(pos->flags & OPT_DELETED) && pos->box_item) {
368 bpos = bpos->next;
369 assert(bpos != (struct listbox_item *) bcat);
372 if ((option->type != OPT_TREE
373 || pos->type == OPT_TREE)
374 && strcmp(pos->name, option->name) <= 0)
375 continue;
377 /* Ordinary options always sort behind trees. */
378 if (option->type != OPT_TREE
379 && pos->type == OPT_TREE)
380 continue;
382 /* The (struct option) add_at_pos() can mess up the
383 * order so that we add the box_item to itself, so
384 * better do it first. */
386 /* Always ensure that them _template_ options are
387 * before anything else so a lonely autocreated option
388 * (with _template_ options set to invisible) will be
389 * connected with an upper corner (ascii: `-) instead
390 * of a rotated T (ascii: +-) when displaying it. */
391 if (option->type == pos->type
392 && *option->name <= '_'
393 && !strcmp(pos->name, "_template_")) {
394 if (abi) add_at_pos(bpos, option->box_item);
395 add_at_pos(pos, option);
396 break;
399 if (abi) add_at_pos(bpos->prev, option->box_item);
400 add_at_pos(pos->prev, option);
401 break;
404 assert(pos != (struct option *) cat);
405 assert(bpos != (struct listbox_item *) bcat);
409 /* Add option to tree. */
410 static void
411 add_opt_rec(struct option *tree, unsigned char *path, struct option *option)
413 int abi = 0;
415 assert(path && option && tree);
416 if (*path) tree = get_opt_rec(tree, path);
418 assertm(tree, "Missing option tree for '%s'", path);
419 if (!tree->value.tree) return;
421 object_nolock(option, "option");
423 if (option->box_item && option->name && !strcmp(option->name, "_template_"))
424 option->box_item->visible = get_opt_bool("config.show_template");
426 if (tree->flags & OPT_AUTOCREATE && !option->desc) {
427 struct option *template = get_opt_rec(tree, "_template_");
429 assert(template);
430 option->desc = template->desc;
433 option->root = tree;
435 abi = (tree->box_item && option->box_item);
437 if (abi) {
438 /* The config_root tree is a just a placeholder for the
439 * box_items, it actually isn't a real box_item by itself;
440 * these ghosts are indicated by the fact that they have
441 * NULL @next. */
442 if (tree->box_item->next) {
443 option->box_item->depth = tree->box_item->depth + 1;
447 if (tree->flags & OPT_SORT) {
448 add_opt_sort(tree, option, abi);
450 } else {
451 add_to_list_end(*tree->value.tree, option);
452 if (abi) add_to_list_end(tree->box_item->child, option->box_item);
455 update_hierbox_browser(&option_browser);
458 static inline struct listbox_item *
459 init_option_listbox_item(struct option *option)
461 struct listbox_item *item = mem_calloc(1, sizeof(*item));
463 if (!item) return NULL;
465 init_list(item->child);
466 item->visible = 1;
467 item->udata = option;
468 item->type = (option->type == OPT_TREE) ? BI_FOLDER : BI_LEAF;
470 return item;
473 struct option *
474 add_opt(struct option *tree, unsigned char *path, unsigned char *capt,
475 unsigned char *name, enum option_flags flags, enum option_type type,
476 int min, int max, void *value, unsigned char *desc)
478 struct option *option = mem_calloc(1, sizeof(*option));
480 if (!option) return NULL;
482 option->name = stracpy(name);
483 if (!option->name) {
484 mem_free(option);
485 return NULL;
487 option->flags = (flags | OPT_ALLOC);
488 option->type = type;
489 option->min = min;
490 option->max = max;
491 option->capt = capt;
492 option->desc = desc;
494 debug_check_option_syntax(option);
496 if (option->type != OPT_ALIAS
497 && ((tree->flags & OPT_LISTBOX) || (option->flags & OPT_LISTBOX))) {
498 option->box_item = init_option_listbox_item(option);
499 if (!option->box_item) {
500 delete_option(option);
501 return NULL;
505 /* XXX: For allocated values we allocate in the add_opt_<type>() macro.
506 * This involves OPT_TREE and OPT_STRING. */
507 switch (type) {
508 case OPT_TREE:
509 if (!value) {
510 delete_option(option);
511 return NULL;
513 option->value.tree = value;
514 break;
515 case OPT_STRING:
516 if (!value) {
517 delete_option(option);
518 return NULL;
520 option->value.string = value;
521 break;
522 case OPT_ALIAS:
523 option->value.string = value;
524 break;
525 case OPT_BOOL:
526 case OPT_INT:
527 case OPT_CODEPAGE:
528 case OPT_LONG:
529 option->value.number = (long) value;
530 break;
531 case OPT_COLOR:
532 decode_color(value, strlen((unsigned char *) value),
533 &option->value.color);
534 break;
535 case OPT_COMMAND:
536 option->value.command = value;
537 break;
538 case OPT_LANGUAGE:
539 break;
542 add_opt_rec(tree, path, option);
543 return option;
546 static void
547 done_option(struct option *option)
549 switch (option->type) {
550 case OPT_STRING:
551 mem_free_if(option->value.string);
552 break;
553 case OPT_TREE:
554 mem_free_if(option->value.tree);
555 break;
556 default:
557 break;
560 if (option->box_item)
561 done_listbox_item(&option_browser, option->box_item);
563 if (option->flags & OPT_ALLOC) {
564 mem_free_if(option->name);
565 mem_free(option);
566 } else if (!option->capt) {
567 /* We are probably dealing with a built-in autocreated option
568 * that will be attempted to be deleted when shutting down. */
569 /* Clear it so nothing will be done later. */
570 memset(option, 0, sizeof(*option));
574 /* The namespace may start to seem a bit chaotic here; it indeed is, maybe the
575 * function names above should be renamed and only macros should keep their old
576 * short names. */
577 /* The simple rule I took as an apologize is that functions which take already
578 * completely filled (struct option *) have long name and functions which take
579 * only option specs have short name. */
581 static void
582 delete_option_do(struct option *option, int recursive)
584 if (option->next) {
585 del_from_list(option);
586 option->prev = option->next = NULL;
589 if (recursive == -1) {
590 ERROR("Orphaned option %s", option->name);
593 if (option->type == OPT_TREE && option->value.tree
594 && !list_empty(*option->value.tree)) {
595 if (!recursive) {
596 if (option->flags & OPT_AUTOCREATE) {
597 recursive = 1;
598 } else {
599 ERROR("Orphaned unregistered "
600 "option in subtree %s!",
601 option->name);
602 recursive = -1;
605 free_options_tree(option->value.tree, recursive);
608 done_option(option);
611 void
612 mark_option_as_deleted(struct option *option)
614 if (option->type == OPT_TREE) {
615 struct option *unmarked;
617 assert(option->value.tree);
619 foreach (unmarked, *option->value.tree)
620 mark_option_as_deleted(unmarked);
623 option->box_item->visible = 0;
625 option->flags |= (OPT_TOUCHED | OPT_DELETED);
628 void
629 delete_option(struct option *option)
631 delete_option_do(option, 1);
634 struct option *
635 copy_option(struct option *template)
637 struct option *option = mem_calloc(1, sizeof(*option));
639 if (!option) return NULL;
641 option->name = null_or_stracpy(template->name);
642 option->flags = (template->flags | OPT_ALLOC);
643 option->type = template->type;
644 option->min = template->min;
645 option->max = template->max;
646 option->capt = template->capt;
647 option->desc = template->desc;
648 option->change_hook = template->change_hook;
650 option->box_item = init_option_listbox_item(option);
651 if (option->box_item) {
652 if (template->box_item) {
653 option->box_item->type = template->box_item->type;
654 option->box_item->depth = template->box_item->depth;
658 if (option_types[template->type].dup) {
659 option_types[template->type].dup(option, template);
660 } else {
661 option->value = template->value;
664 return option;
667 struct list_head *
668 init_options_tree(void)
670 struct list_head *ptr = mem_alloc(sizeof(*ptr));
672 if (ptr) init_list(*ptr);
673 return ptr;
676 /* Some default pre-autocreated options. Doh. */
677 static inline void
678 register_autocreated_options(void)
680 /* TODO: Use table-driven initialization. --jonas */
681 get_opt_int("terminal.linux.type") = 2;
682 get_opt_int("terminal.linux.colors") = 1;
683 get_opt_bool("terminal.linux.m11_hack") = 1;
684 get_opt_int("terminal.vt100.type") = 1;
685 get_opt_int("terminal.vt110.type") = 1;
686 get_opt_int("terminal.xterm.type") = 1;
687 get_opt_bool("terminal.xterm.underline") = 1;
688 get_opt_int("terminal.xterm-color.type") = 1;
689 get_opt_int("terminal.xterm-color.colors") = COLOR_MODE_16;
690 get_opt_bool("terminal.xterm-color.underline") = 1;
691 #ifdef CONFIG_88_COLORS
692 get_opt_int("terminal.xterm-88color.type") = 1;
693 get_opt_int("terminal.xterm-88color.colors") = COLOR_MODE_88;
694 get_opt_bool("terminal.xterm-88color.underline") = 1;
695 #endif
696 #ifdef CONFIG_256_COLORS
697 get_opt_int("terminal.xterm-256color.type") = 1;
698 get_opt_int("terminal.xterm-256color.colors") = COLOR_MODE_256;
699 get_opt_bool("terminal.xterm-256color.underline") = 1;
700 #endif
703 static struct option_info config_options_info[];
704 extern struct option_info cmdline_options_info[];
705 static struct change_hook_info change_hooks[];
707 void
708 init_options(void)
710 cmdline_options = add_opt_tree_tree(&options_root, "", "",
711 "cmdline", 0, "");
712 register_options(cmdline_options_info, cmdline_options);
714 config_options = add_opt_tree_tree(&options_root, "", "",
715 "config", OPT_SORT, "");
716 config_options->flags |= OPT_LISTBOX;
717 config_options->box_item = &option_browser.root;
718 register_options(config_options_info, config_options);
720 register_autocreated_options();
721 register_change_hooks(change_hooks);
724 static void
725 free_options_tree(struct list_head *tree, int recursive)
727 while (!list_empty(*tree))
728 delete_option_do(tree->next, recursive);
731 void
732 done_options(void)
734 unregister_options(config_options_info, config_options);
735 unregister_options(cmdline_options_info, cmdline_options);
736 config_options->box_item = NULL;
737 free_options_tree(&options_root_tree, 0);
740 void
741 register_change_hooks(struct change_hook_info *change_hooks)
743 int i;
745 for (i = 0; change_hooks[i].name; i++) {
746 struct option *option = get_opt_rec(config_options,
747 change_hooks[i].name);
749 assert(option);
750 option->change_hook = change_hooks[i].change_hook;
754 void
755 prepare_mustsave_flags(struct list_head *tree, int set_all)
757 struct option *option;
759 foreach (option, *tree) {
760 /* XXX: OPT_LANGUAGE shouldn't have any bussiness
761 * here, but we're just weird in that area. */
762 if (set_all
763 || (option->flags & (OPT_TOUCHED | OPT_DELETED))
764 || option->type == OPT_LANGUAGE)
765 option->flags |= OPT_MUST_SAVE;
766 else
767 option->flags &= ~OPT_MUST_SAVE;
769 if (option->type == OPT_TREE)
770 prepare_mustsave_flags(option->value.tree, set_all);
774 void
775 untouch_options(struct list_head *tree)
777 struct option *option;
779 foreach (option, *tree) {
780 option->flags &= ~OPT_TOUCHED;
782 if (option->type == OPT_TREE)
783 untouch_options(option->value.tree);
787 static int
788 check_nonempty_tree(struct list_head *options)
790 struct option *opt;
792 foreach (opt, *options) {
793 if (opt->type == OPT_TREE) {
794 if (check_nonempty_tree(opt->value.tree))
795 return 1;
796 } else if (opt->flags & OPT_MUST_SAVE) {
797 return 1;
801 return 0;
804 void
805 smart_config_string(struct string *str, int print_comment, int i18n,
806 struct list_head *options, unsigned char *path, int depth,
807 void (*fn)(struct string *, struct option *,
808 unsigned char *, int, int, int, int))
810 struct option *option;
812 foreach (option, *options) {
813 int do_print_comment = 1;
815 if (option->flags & OPT_HIDDEN ||
816 option->type == OPT_ALIAS ||
817 !strcmp(option->name, "_template_"))
818 continue;
820 /* Is there anything to be printed anyway? */
821 if (option->type == OPT_TREE
822 ? !check_nonempty_tree(option->value.tree)
823 : !(option->flags & OPT_MUST_SAVE))
824 continue;
826 /* We won't pop out the description when we're in autocreate
827 * category and not template. It'd be boring flood of
828 * repetitive comments otherwise ;). */
830 /* This print_comment parameter is weird. If it is negative, it
831 * means that we shouldn't print comments at all. If it is 1,
832 * we shouldn't print comment UNLESS the option is _template_
833 * or not-an-autocreating-tree (it is set for the first-level
834 * autocreation tree). When it is 2, we can print out comments
835 * normally. */
836 /* It is still broken somehow, as it didn't work for terminal.*
837 * (the first autocreated level) by the time I wrote this. Good
838 * summer job for bored mad hackers with spare boolean mental
839 * power. I have better things to think about, personally.
840 * Maybe we should just mark autocreated options somehow ;). */
841 if (!print_comment || (print_comment == 1
842 && (strcmp(option->name, "_template_")
843 && (option->flags & OPT_AUTOCREATE
844 && option->type == OPT_TREE))))
845 do_print_comment = 0;
847 /* Pop out the comment */
849 /* For config file, we ignore do_print_comment everywhere
850 * except 1, but sometimes we want to skip the option totally.
852 fn(str, option, path, depth,
853 option->type == OPT_TREE ? print_comment
854 : do_print_comment,
855 0, i18n);
857 fn(str, option, path, depth, do_print_comment, 1, i18n);
859 /* And the option itself */
861 if (option_types[option->type].write) {
862 fn(str, option, path, depth,
863 do_print_comment, 2, i18n);
865 } else if (option->type == OPT_TREE) {
866 struct string newpath;
867 int pc = print_comment;
869 if (!init_string(&newpath)) continue; /* OK? */
871 if (pc == 2 && option->flags & OPT_AUTOCREATE)
872 pc = 1;
873 else if (pc == 1 && strcmp(option->name, "_template_"))
874 pc = 0;
876 fn(str, option, path, depth, /*pc*/1, 3, i18n);
878 if (path) {
879 add_to_string(&newpath, path);
880 add_char_to_string(&newpath, '.');
882 add_to_string(&newpath, option->name);
883 smart_config_string(str, pc, i18n, option->value.tree,
884 newpath.source, depth + 1, fn);
885 done_string(&newpath);
887 fn(str, option, path, depth, /*pc*/1, 3, i18n);
893 static int
894 change_hook_cache(struct session *ses, struct option *current, struct option *changed)
896 shrink_memory(0);
897 return 0;
900 static int
901 change_hook_connection(struct session *ses, struct option *current, struct option *changed)
903 register_check_queue();
904 return 0;
907 static int
908 change_hook_html(struct session *ses, struct option *current, struct option *changed)
910 foreach (ses, sessions) ses->tab->resize = 1;
912 return 0;
915 static int
916 change_hook_insert_mode(struct session *ses, struct option *current, struct option *changed)
918 update_status();
919 return 0;
922 static int
923 change_hook_active_link(struct session *ses, struct option *current, struct option *changed)
925 update_cached_document_options();
926 return 0;
929 static int
930 change_hook_terminal(struct session *ses, struct option *current, struct option *changed)
932 cls_redraw_all_terminals();
933 return 0;
936 static int
937 change_hook_ui(struct session *ses, struct option *current, struct option *changed)
939 update_status();
940 return 0;
943 /* Bit 2 of show means we should always set visibility, otherwise we set it
944 * only on templates. */
945 static void
946 update_visibility(struct list_head *tree, int show)
948 struct option *opt;
950 foreach (opt, *tree) {
951 if (opt->flags & OPT_DELETED) continue;
953 if (!strcmp(opt->name, "_template_")) {
954 if (opt->box_item)
955 opt->box_item->visible = (show & 1);
957 if (opt->type == OPT_TREE)
958 update_visibility(opt->value.tree, show | 2);
959 } else {
960 if (opt->box_item && (show & 2))
961 opt->box_item->visible = (show & 1);
963 if (opt->type == OPT_TREE)
964 update_visibility(opt->value.tree, show);
969 void
970 update_options_visibility(void)
972 update_visibility(config_options->value.tree,
973 get_opt_bool("config.show_template"));
976 void
977 toggle_option(struct session *ses, struct option *option)
979 long number = option->value.number + 1;
981 assert(option->type == OPT_BOOL || option->type == OPT_INT);
982 assert(option->max);
984 /* TODO: call change hooks. --jonas */
985 option->value.number = (number <= option->max) ? number : option->min;
986 option_changed(ses, option, option);
989 static int
990 change_hook_stemplate(struct session *ses, struct option *current, struct option *changed)
992 update_visibility(config_options->value.tree, changed->value.number);
993 return 0;
996 static int
997 change_hook_language(struct session *ses, struct option *current, struct option *changed)
999 #ifdef CONFIG_NLS
1000 set_language(changed->value.number);
1001 #endif
1002 return 0;
1005 static struct change_hook_info change_hooks[] = {
1006 { "config.show_template", change_hook_stemplate },
1007 { "connection", change_hook_connection },
1008 { "document.browse", change_hook_html },
1009 { "document.browse.forms.insert_mode",
1010 change_hook_insert_mode },
1011 { "document.browse.links.active_link",
1012 change_hook_active_link },
1013 { "document.cache", change_hook_cache },
1014 { "document.codepage", change_hook_html },
1015 { "document.colors", change_hook_html },
1016 { "document.html", change_hook_html },
1017 { "document.plain", change_hook_html },
1018 { "terminal", change_hook_terminal },
1019 { "ui.language", change_hook_language },
1020 { "ui", change_hook_ui },
1021 { NULL, NULL },
1024 void
1025 call_change_hooks(struct session *ses, struct option *current, struct option *option)
1027 /* This boolean thing can look a little weird - it
1028 * basically says that we should proceed when there's
1029 * no change_hook or there's one and its return value
1030 * was zero. */
1031 while (current && (!current->change_hook ||
1032 !current->change_hook(ses, current, option))) {
1033 if (!current->root)
1034 break;
1036 current = current->root;
1040 void
1041 option_changed(struct session *ses, struct option *current, struct option *option)
1043 option->flags |= OPT_TOUCHED;
1044 /* Notify everyone out there! */
1045 call_change_hooks(ses, current, option);
1049 commit_option_values(struct option_resolver *resolvers,
1050 struct option *root, union option_value *values, int size)
1052 int touched = 0;
1053 int i;
1055 assert(resolvers && root && values && size);
1057 for (i = 0; i < size; i++) {
1058 unsigned char *name = resolvers[i].name;
1059 struct option *option = get_opt_rec(root, name);
1060 int id = resolvers[i].id;
1062 if (memcmp(&option->value, &values[id], sizeof(union option_value))) {
1063 option->value = values[id];
1064 option->flags |= OPT_TOUCHED;
1065 /* Speed hack: Directly call the change-hook for each
1066 * option in resolvers and later call call_change_hooks
1067 * on the root; if we were to call call_change_hooks
1068 * on each option in resolvers, we would end up calling
1069 * the change-hooks of root, its parents, its
1070 * grandparents, and so on for each option in resolvers
1071 * because call_change_hooks is recursive. -- Miciah */
1072 if (option->change_hook)
1073 option->change_hook(NULL, option, NULL);
1074 touched++;
1078 /* See above 'Speed hack' comment. */
1079 call_change_hooks(NULL, root, NULL);
1081 return touched;
1084 void
1085 checkout_option_values(struct option_resolver *resolvers,
1086 struct option *root,
1087 union option_value *values, int size)
1089 int i;
1091 for (i = 0; i < size; i++) {
1092 unsigned char *name = resolvers[i].name;
1093 struct option *option = get_opt_rec(root, name);
1094 int id = resolvers[i].id;
1096 values[id] = option->value;
1100 /**********************************************************************
1101 Options values
1102 **********************************************************************/
1104 #include "config/options.inc"
1106 void
1107 register_options(struct option_info info[], struct option *tree)
1109 int i;
1111 for (i = 0; info[i].path; i++) {
1112 struct option *option = &info[i].option;
1113 unsigned char *string;
1115 debug_check_option_syntax(option);
1117 if (option->type != OPT_ALIAS
1118 && ((tree->flags & OPT_LISTBOX)
1119 || (option->flags & OPT_LISTBOX))) {
1120 option->box_item = init_option_listbox_item(option);
1121 if (!option->box_item) {
1122 delete_option(option);
1123 continue;
1127 switch (option->type) {
1128 case OPT_TREE:
1129 option->value.tree = init_options_tree();
1130 if (!option->value.tree) {
1131 delete_option(option);
1132 continue;
1134 break;
1135 case OPT_STRING:
1136 string = mem_alloc(MAX_STR_LEN);
1137 if (!string) {
1138 delete_option(option);
1139 continue;
1141 safe_strncpy(string, option->value.string, MAX_STR_LEN);
1142 option->value.string = string;
1143 break;
1144 case OPT_COLOR:
1145 string = option->value.string;
1146 assert(string);
1147 decode_color(string, strlen(string),
1148 &option->value.color);
1149 break;
1150 case OPT_CODEPAGE:
1151 string = option->value.string;
1152 assert(string);
1153 option->value.number = get_cp_index(string);
1154 break;
1155 case OPT_BOOL:
1156 case OPT_INT:
1157 case OPT_LONG:
1158 case OPT_LANGUAGE:
1159 case OPT_COMMAND:
1160 case OPT_ALIAS:
1161 break;
1164 add_opt_rec(tree, info[i].path, option);
1168 void
1169 unregister_options(struct option_info info[], struct option *tree)
1171 int i = 0;
1173 /* We need to remove the options in inverse order to the order how we
1174 * added them. */
1176 while (info[i].path) i++;
1178 for (i--; i >= 0; i--)
1179 delete_option_do(&info[i].option, 0);