Elinks currently only support GB2312 as Chinese encoding, but GBK and
[elinks.git] / src / config / options.c
blob3e0a3a773bc4044610e9cf49f301543b318c980d
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/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
49 * come... */
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(
59 /* name: */ "",
60 /* flags: */ 0,
61 /* type: */ OPT_TREE,
62 /* min, max: */ 0, 0,
63 /* value: */ &options_root_tree,
64 /* desc: */ "",
65 /* capt: */ NULL
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);
74 #ifdef CONFIG_DEBUG
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))
80 static void
81 check_caption(unsigned char *caption)
83 int len;
84 unsigned char c;
86 if (!caption) return;
88 len = strlen(caption);
89 if (!len) return;
91 c = caption[len - 1];
92 if (isspace(c) || bad_punct(c))
93 DBG("bad char at end of caption [%s]", caption);
95 #ifdef CONFIG_NLS
96 caption = gettext(caption);
97 len = strlen(caption);
98 if (!len) return;
100 c = caption[len - 1];
101 if (isspace(c) || bad_punct(c))
102 DBG("bad char at end of i18n caption [%s]", caption);
103 #endif
106 #undef bad_punct
108 static void
109 check_description(unsigned char *desc)
111 int len;
112 unsigned char c;
114 if (!desc) return;
116 len = strlen(desc);
117 if (!len) return;
119 c = desc[len - 1];
120 if (isspace(c))
121 DBG("bad char at end of description [%s]", desc);
123 #ifdef CONFIG_NLS
124 desc = gettext(desc);
125 len = strlen(desc);
126 if (!len) return;
128 if (ispunct(c) != ispunct(desc[len - 1]))
129 DBG("punctuation char possibly missing at end of i18n description [%s]", desc);
131 c = desc[len - 1];
132 if (isspace(c))
133 DBG("bad char at end of i18n description [%s]", desc);
134 #endif
137 /*! @relates option */
138 static void
139 debug_check_option_syntax(struct option *option)
141 if (!option) return;
142 check_caption(option->capt);
143 check_description(option->desc);
146 #else
147 #define debug_check_option_syntax(option)
148 #endif
151 /**********************************************************************
152 Options interface
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. */
159 /* Ugly kludge */
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().
171 * @relates option */
172 struct 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;
178 unsigned char *sep;
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(name, '.'))) {
185 *sep = '\0';
187 tree = get_opt_rec(tree, name);
188 if (!tree || tree->type != OPT_TREE || tree->flags & OPT_HIDDEN) {
189 #if 0
190 DBG("ERROR in get_opt_rec() crawl: %s (%d) -> %s",
191 name, tree ? tree->type : -1, sep + 1);
192 #endif
193 mem_free(aname);
194 return NULL;
197 *sep = '.';
198 name = sep + 1;
201 foreach (option, *tree->value.tree) {
202 if (option->name && !strcmp(option->name, name)) {
203 mem_free(aname);
204 return option;
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_,
213 name_);
214 if_assert_failed {
215 mem_free(aname);
216 return NULL;
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);
225 if (!option) {
226 mem_free(aname);
227 return NULL;
229 mem_free_set(&option->name, stracpy(name));
231 add_opt_rec(tree, "", option);
233 mem_free(aname);
234 return option;
237 mem_free(aname);
238 return NULL;
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
243 * enabled.
244 * @relates option */
245 struct option *
246 get_opt_rec_real(struct option *tree, const unsigned char *name)
248 struct option *opt;
250 no_autocreate = 1;
251 opt = get_opt_rec(tree, name);
252 no_autocreate = 0;
253 return opt;
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.
263 * @relates option */
264 struct option *
265 indirect_option(struct option *alias)
267 struct option *real;
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;
276 return real;
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().
281 * @relates option */
282 union option_value *
283 get_opt_(
284 #ifdef CONFIG_DEBUG
285 unsigned char *file, int line, enum option_type option_type,
286 #endif
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. */
299 if (!opt && ses)
300 opt = get_domain_option_from_session(name, ses);
302 /* Else, return the real option. */
303 if (!opt)
304 opt = get_opt_rec(tree, name);
306 #ifdef CONFIG_DEBUG
307 errfile = file;
308 errline = line;
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",
314 name, file, line,
315 get_option_type_name(option_type),
316 get_option_type_name(opt->type));
318 switch (opt->type) {
319 case OPT_TREE:
320 if (!opt->value.tree)
321 elinks_internal("Option %s has no value!", name);
322 break;
323 case OPT_ALIAS:
324 elinks_internal("Invalid use of alias %s for option %s!",
325 name, opt->value.string);
326 break;
327 case OPT_STRING:
328 if (!opt->value.string)
329 elinks_internal("Option %s has no value!", name);
330 break;
331 case OPT_BOOL:
332 case OPT_INT:
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);
336 break;
337 case OPT_LONG:
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);
341 break;
342 case OPT_COMMAND:
343 if (!opt->value.command)
344 elinks_internal("Option %s has no value!", name);
345 break;
346 case OPT_CODEPAGE: /* TODO: check these too. */
347 case OPT_LANGUAGE:
348 case OPT_COLOR:
349 break;
351 #endif
353 return &opt->value;
356 /*! @relates option */
357 static void
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;
362 struct option *pos;
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) {
375 append:
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) {
383 goto append;
385 /* Scan the list linearly. This could be probably optimized ie.
386 * to choose direction based on the first letter or so. */
387 } else {
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) {
396 bpos = bpos->next;
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)
403 continue;
405 /* Ordinary options always sort behind trees. */
406 if (option->type != OPT_TREE
407 && pos->type == OPT_TREE)
408 continue;
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);
424 break;
427 if (abi) add_at_pos(bpos->prev, option->box_item);
428 add_at_pos(pos->prev, option);
429 break;
432 assert(pos != (struct option *) cat);
433 assert(bpos != (struct listbox_item *) bcat);
437 /** Add option to tree.
438 * @relates option */
439 static void
440 add_opt_rec(struct option *tree, unsigned char *path, struct option *option)
442 int abi = 0;
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_");
458 assert(template);
459 option->desc = template->desc;
462 option->root = tree;
464 abi = (tree->box_item && option->box_item);
466 if (abi) {
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
470 * NULL @next. */
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);
479 } else {
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);
496 item->visible = 1;
497 item->udata = option;
498 item->type = (option->type == OPT_TREE) ? BI_FOLDER : BI_LEAF;
500 return item;
503 /*! @relates option */
504 struct 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);
514 if (!option->name) {
515 mem_free(option);
516 return NULL;
518 option->flags = (flags | OPT_ALLOC);
519 option->type = type;
520 option->min = min;
521 option->max = max;
522 option->capt = capt;
523 option->desc = desc;
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. */
529 switch (type) {
530 case OPT_TREE:
531 if (!value) {
532 mem_free(option);
533 return NULL;
535 option->value.tree = (LIST_OF(struct option) *) value;
536 break;
537 case OPT_STRING:
538 if (!value) {
539 mem_free(option);
540 return NULL;
542 option->value.string = (unsigned char *) value;
543 break;
544 case OPT_ALIAS:
545 option->value.string = (unsigned char *) value;
546 break;
547 case OPT_BOOL:
548 case OPT_INT:
549 case OPT_CODEPAGE:
550 option->value.number = (int) value;
551 break;
552 case OPT_LONG:
553 option->value.big_number = (long) value; /* FIXME: cast from void * */
554 break;
555 case OPT_COLOR:
556 decode_color((unsigned char *) value, strlen((unsigned char *) value),
557 &option->value.color);
558 break;
559 case OPT_COMMAND:
560 option->value.command = (void *) value;
561 break;
562 case OPT_LANGUAGE:
563 break;
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) {
570 mem_free(option);
571 return NULL;
575 add_opt_rec(tree, path, option);
576 return option;
579 /*! @relates option */
580 static void
581 done_option(struct option *option)
583 switch (option->type) {
584 case OPT_STRING:
585 mem_free_if(option->value.string);
586 break;
587 case OPT_TREE:
588 mem_free_if(option->value.tree);
589 break;
590 default:
591 break;
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);
599 mem_free(option);
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
610 * short names. */
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 */
616 static void
617 delete_option_do(struct option *option, int recursive)
619 if (option->next) {
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)) {
630 if (!recursive) {
631 if (option->flags & OPT_AUTOCREATE) {
632 recursive = 1;
633 } else {
634 ERROR("Orphaned unregistered "
635 "option in subtree %s!",
636 option->name);
637 recursive = -1;
640 free_options_tree(option->value.tree, recursive);
643 done_option(option);
646 /*! @relates option */
647 void
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 */
665 void
666 delete_option(struct option *option)
668 delete_option_do(option, 1);
671 /*! @relates option */
672 struct 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);
699 } else {
700 option->value = template->value;
703 return option;
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. */
710 struct option *
711 get_option_shadow(struct option *option, struct option *tree,
712 struct option *shadow_tree)
715 struct option *shadow_option = NULL;
717 assert(option);
718 assert(tree);
719 assert(shadow_tree);
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,
727 shadow_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,
733 CO_SHALLOW
734 | CO_NO_LISTBOX_ITEM);
735 if (shadow_option) {
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,
740 shadow_option);
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);
759 return ptr;
762 /** Some default pre-autocreated options. Doh. */
763 static inline void
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;
781 #endif
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;
785 #else
786 get_opt_int("terminal.rxvt-unicode.colors", NULL) = COLOR_MODE_16;
787 #endif
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;
797 #endif
800 static union option_info config_options_info[];
801 extern union option_info cmdline_options_info[];
802 static const struct change_hook_info change_hooks[];
804 void
805 init_options(void)
807 cmdline_options = add_opt_tree_tree(&options_root, "", "",
808 "cmdline", 0, "");
809 register_options(cmdline_options_info, cmdline_options);
811 config_options = add_opt_tree_tree(&options_root, "", "",
812 "config", OPT_SORT, "");
813 config_options->flags |= OPT_LISTBOX;
814 config_options->box_item = &option_browser.root;
815 register_options(config_options_info, config_options);
817 register_autocreated_options();
818 register_change_hooks(change_hooks);
821 /*! @relates option */
822 static void
823 free_options_tree(LIST_OF(struct option) *tree, int recursive)
825 while (!list_empty(*tree))
826 delete_option_do(tree->next, recursive);
829 void
830 done_options(void)
832 done_domain_trees();
833 unregister_options(config_options_info, config_options);
834 unregister_options(cmdline_options_info, cmdline_options);
835 config_options->box_item = NULL;
836 free_options_tree(&options_root_tree, 0);
839 /*! @relates change_hook_info */
840 void
841 register_change_hooks(const struct change_hook_info *change_hooks)
843 int i;
845 for (i = 0; change_hooks[i].name; i++) {
846 struct option *option = get_opt_rec(config_options,
847 change_hooks[i].name);
849 assert(option);
850 option->change_hook = change_hooks[i].change_hook;
854 /** Set or clear the ::OPT_MUST_SAVE flag in all descendants of @a tree.
856 * @param tree
857 * The option tree in which this function recursively sets or clears
858 * the flag.
860 * @param set_all
861 * If true, set ::OPT_MUST_SAVE in all options of the tree.
862 * If false, set it only in touched or deleted options, and clear in others.
864 * @relates option */
865 void
866 prepare_mustsave_flags(LIST_OF(struct option) *tree, int set_all)
868 struct option *option;
870 foreach (option, *tree) {
871 /* XXX: OPT_LANGUAGE shouldn't have any bussiness
872 * here, but we're just weird in that area. */
873 if (set_all
874 || (option->flags & (OPT_TOUCHED | OPT_DELETED))
875 || option->type == OPT_LANGUAGE)
876 option->flags |= OPT_MUST_SAVE;
877 else
878 option->flags &= ~OPT_MUST_SAVE;
880 if (option->type == OPT_TREE)
881 prepare_mustsave_flags(option->value.tree, set_all);
885 /** Clear the ::OPT_TOUCHED flag in all descendants of @a tree.
886 * @relates option */
887 void
888 untouch_options(LIST_OF(struct option) *tree)
890 struct option *option;
892 foreach (option, *tree) {
893 option->flags &= ~OPT_TOUCHED;
895 if (option->type == OPT_TREE)
896 untouch_options(option->value.tree);
900 /*! @relates option */
901 static int
902 check_nonempty_tree(LIST_OF(struct option) *options)
904 struct option *opt;
906 foreach (opt, *options) {
907 if (opt->type == OPT_TREE) {
908 if (check_nonempty_tree(opt->value.tree))
909 return 1;
910 } else if (opt->flags & OPT_MUST_SAVE) {
911 return 1;
915 return 0;
918 /*! @relates option */
919 void
920 smart_config_string(struct string *str, int print_comment, int i18n,
921 LIST_OF(struct option) *options,
922 unsigned char *path, int depth,
923 void (*fn)(struct string *, struct option *,
924 unsigned char *, int, int, int, int))
926 struct option *option;
928 foreach (option, *options) {
929 int do_print_comment = 1;
931 if (option->flags & OPT_HIDDEN ||
932 option->type == OPT_ALIAS ||
933 !strcmp(option->name, "_template_"))
934 continue;
936 /* Is there anything to be printed anyway? */
937 if (option->type == OPT_TREE
938 ? !check_nonempty_tree(option->value.tree)
939 : !(option->flags & OPT_MUST_SAVE))
940 continue;
942 /* We won't pop out the description when we're in autocreate
943 * category and not template. It'd be boring flood of
944 * repetitive comments otherwise ;). */
946 /* This print_comment parameter is weird. If it is negative, it
947 * means that we shouldn't print comments at all. If it is 1,
948 * we shouldn't print comment UNLESS the option is _template_
949 * or not-an-autocreating-tree (it is set for the first-level
950 * autocreation tree). When it is 2, we can print out comments
951 * normally. */
952 /* It is still broken somehow, as it didn't work for terminal.*
953 * (the first autocreated level) by the time I wrote this. Good
954 * summer job for bored mad hackers with spare boolean mental
955 * power. I have better things to think about, personally.
956 * Maybe we should just mark autocreated options somehow ;). */
957 if (!print_comment || (print_comment == 1
958 && (strcmp(option->name, "_template_")
959 && (option->flags & OPT_AUTOCREATE
960 && option->type == OPT_TREE))))
961 do_print_comment = 0;
963 /* Pop out the comment */
965 /* For config file, we ignore do_print_comment everywhere
966 * except 1, but sometimes we want to skip the option totally.
968 fn(str, option, path, depth,
969 option->type == OPT_TREE ? print_comment
970 : do_print_comment,
971 0, i18n);
973 fn(str, option, path, depth, do_print_comment, 1, i18n);
975 /* And the option itself */
977 if (option_types[option->type].write) {
978 fn(str, option, path, depth,
979 do_print_comment, 2, i18n);
981 } else if (option->type == OPT_TREE) {
982 struct string newpath;
983 int pc = print_comment;
985 if (!init_string(&newpath)) continue; /* OK? */
987 if (pc == 2 && option->flags & OPT_AUTOCREATE)
988 pc = 1;
989 else if (pc == 1 && strcmp(option->name, "_template_"))
990 pc = 0;
992 fn(str, option, path, depth, /*pc*/1, 3, i18n);
994 if (path) {
995 add_to_string(&newpath, path);
996 add_char_to_string(&newpath, '.');
998 add_to_string(&newpath, option->name);
999 smart_config_string(str, pc, i18n, option->value.tree,
1000 newpath.source, depth + 1, fn);
1001 done_string(&newpath);
1003 fn(str, option, path, depth, /*pc*/1, 3, i18n);
1009 static int
1010 change_hook_cache(struct session *ses, struct option *current, struct option *changed)
1012 shrink_memory(0);
1013 return 0;
1016 static int
1017 change_hook_connection(struct session *ses, struct option *current, struct option *changed)
1019 register_check_queue();
1020 return 0;
1023 static int
1024 change_hook_html(struct session *ses, struct option *current, struct option *changed)
1026 foreach (ses, sessions) ses->tab->resize = 1;
1028 return 0;
1031 static int
1032 change_hook_insert_mode(struct session *ses, struct option *current, struct option *changed)
1034 update_status();
1035 return 0;
1038 static int
1039 change_hook_active_link(struct session *ses, struct option *current, struct option *changed)
1041 update_cached_document_options(ses);
1042 return 0;
1045 static int
1046 change_hook_terminal(struct session *ses, struct option *current, struct option *changed)
1048 cls_redraw_all_terminals();
1049 return 0;
1052 static int
1053 change_hook_ui(struct session *ses, struct option *current, struct option *changed)
1055 update_status();
1056 return 0;
1059 /** Make option templates visible or invisible in the option manager.
1060 * This is called once on startup, and then each time the value of the
1061 * "config.show_template" option is changed.
1063 * @param tree
1064 * The option tree whose children should be affected.
1066 * @param show
1067 * A set of bits:
1068 * - The 0x01 bit means templates should be made visible.
1069 * If the bit is clear, templates become invisible instead.
1070 * - The 0x02 bit means @a tree is itself part of a template,
1071 * and so all of its children should be affected, regardless
1072 * of whether they are templates of their own.
1074 * Deleted options are never visible.
1076 * @relates option */
1077 static void
1078 update_visibility(LIST_OF(struct option) *tree, int show)
1080 struct option *opt;
1082 foreach (opt, *tree) {
1083 if (opt->flags & OPT_DELETED) continue;
1085 if (!strcmp(opt->name, "_template_")) {
1086 if (opt->box_item)
1087 opt->box_item->visible = (show & 1);
1089 if (opt->type == OPT_TREE)
1090 update_visibility(opt->value.tree, show | 2);
1091 } else {
1092 if (opt->box_item && (show & 2))
1093 opt->box_item->visible = (show & 1);
1095 if (opt->type == OPT_TREE)
1096 update_visibility(opt->value.tree, show);
1101 void
1102 update_options_visibility(void)
1104 update_visibility(config_options->value.tree,
1105 get_opt_bool("config.show_template", NULL));
1108 void
1109 toggle_option(struct session *ses, struct option *option)
1111 long number = option->value.number + 1;
1113 assert(option->type == OPT_BOOL || option->type == OPT_INT);
1114 assert(option->max);
1116 option->value.number = (number <= option->max) ? number : option->min;
1117 option_changed(ses, option);
1120 static int
1121 change_hook_stemplate(struct session *ses, struct option *current, struct option *changed)
1123 update_visibility(config_options->value.tree, changed->value.number);
1124 return 0;
1127 static int
1128 change_hook_language(struct session *ses, struct option *current, struct option *changed)
1130 #ifdef CONFIG_NLS
1131 set_language(changed->value.number);
1132 #endif
1133 return 0;
1136 static const struct change_hook_info change_hooks[] = {
1137 { "config.show_template", change_hook_stemplate },
1138 { "connection", change_hook_connection },
1139 { "document.browse", change_hook_html },
1140 { "document.browse.forms.insert_mode",
1141 change_hook_insert_mode },
1142 { "document.browse.links.active_link",
1143 change_hook_active_link },
1144 { "document.cache", change_hook_cache },
1145 { "document.codepage", change_hook_html },
1146 { "document.colors", change_hook_html },
1147 { "document.html", change_hook_html },
1148 { "document.plain", change_hook_html },
1149 { "terminal", change_hook_terminal },
1150 { "ui.language", change_hook_language },
1151 { "ui", change_hook_ui },
1152 { NULL, NULL },
1155 void
1156 call_change_hooks(struct session *ses, struct option *current, struct option *option)
1158 /* This boolean thing can look a little weird - it
1159 * basically says that we should proceed when there's
1160 * no change_hook or there's one and its return value
1161 * was zero. */
1162 while (current && (!current->change_hook ||
1163 !current->change_hook(ses, current, option))) {
1164 if (!current->root)
1165 break;
1167 current = current->root;
1171 void
1172 option_changed(struct session *ses, struct option *option)
1174 option->flags |= OPT_TOUCHED;
1175 /* Notify everyone out there! */
1176 call_change_hooks(ses, option, option);
1179 /*! @relates option_resolver */
1181 commit_option_values(struct option_resolver *resolvers,
1182 struct option *root, union option_value *values, int size)
1184 int touched = 0;
1185 int i;
1187 assert(resolvers && root && values && size);
1189 for (i = 0; i < size; i++) {
1190 unsigned char *name = resolvers[i].name;
1191 struct option *option = get_opt_rec(root, name);
1192 int id = resolvers[i].id;
1194 assertm(option, "Bad option '%s' in options resolver", name);
1196 if (memcmp(&option->value, &values[id], sizeof(union option_value))) {
1197 option->value = values[id];
1198 option->flags |= OPT_TOUCHED;
1199 /* Speed hack: Directly call the change-hook for each
1200 * option in resolvers and later call call_change_hooks
1201 * on the root; if we were to call call_change_hooks
1202 * on each option in resolvers, we would end up calling
1203 * the change-hooks of root, its parents, its
1204 * grandparents, and so on for each option in resolvers
1205 * because call_change_hooks is recursive. -- Miciah */
1206 if (option->change_hook)
1207 option->change_hook(NULL, option, NULL);
1208 touched++;
1212 /* See above 'Speed hack' comment. */
1213 call_change_hooks(NULL, root, NULL);
1215 return touched;
1218 /*! @relates option_resolver */
1219 void
1220 checkout_option_values(struct option_resolver *resolvers,
1221 struct option *root,
1222 union option_value *values, int size)
1224 int i;
1226 for (i = 0; i < size; i++) {
1227 unsigned char *name = resolvers[i].name;
1228 struct option *option = get_opt_rec(root, name);
1229 int id = resolvers[i].id;
1231 assertm(option, "Bad option '%s' in options resolver", name);
1233 values[id] = option->value;
1237 /**********************************************************************
1238 Options values
1239 **********************************************************************/
1241 #include "config/options.inc"
1243 /*! @relates option_info */
1244 void
1245 register_options(union option_info info[], struct option *tree)
1247 int i;
1248 static const struct option zero = INIT_OPTION(
1249 NULL, 0, 0, 0, 0, 0, NULL, NULL);
1251 /* To let unregister_options() correctly find the end of the
1252 * info[] array, this loop must convert every element from
1253 * struct option_init to struct option. That is, even if
1254 * there is not enough memory to fully initialize some option,
1255 * the loop must continue. */
1256 for (i = 0; info[i].init.path; i++) {
1257 /* Copy the value aside before it is overwritten
1258 * with the other member of the union. */
1259 const struct option_init init = info[i].init;
1261 struct option *option = &info[i].option;
1262 unsigned char *string;
1264 *option = zero;
1265 option->name = init.name;
1266 option->capt = init.capt;
1267 option->desc = init.desc;
1268 option->flags = init.flags;
1269 option->type = init.type;
1270 option->min = init.min;
1271 option->max = init.max;
1272 /* init.value_long, init.value_dataptr, or init.value_funcptr
1273 * is handled below as appropriate for each type. */
1275 debug_check_option_syntax(option);
1277 if (option->type != OPT_ALIAS
1278 && ((tree->flags & OPT_LISTBOX)
1279 || (option->flags & OPT_LISTBOX))) {
1280 option->box_item = init_option_listbox_item(option);
1281 if (!option->box_item) {
1282 delete_option(option);
1283 continue;
1287 switch (option->type) {
1288 case OPT_TREE:
1289 option->value.tree = init_options_tree();
1290 if (!option->value.tree) {
1291 delete_option(option);
1292 continue;
1294 break;
1295 case OPT_STRING:
1296 string = mem_alloc(MAX_STR_LEN);
1297 if (!string) {
1298 delete_option(option);
1299 continue;
1301 safe_strncpy(string, init.value_dataptr, MAX_STR_LEN);
1302 option->value.string = string;
1303 break;
1304 case OPT_COLOR:
1305 string = init.value_dataptr;
1306 assert(string);
1307 decode_color(string, strlen(string),
1308 &option->value.color);
1309 break;
1310 case OPT_CODEPAGE:
1311 string = init.value_dataptr;
1312 assert(string);
1313 option->value.number = get_cp_index(string);
1314 break;
1315 case OPT_BOOL:
1316 case OPT_INT:
1317 option->value.number = init.value_long;
1318 break;
1319 case OPT_LONG:
1320 option->value.big_number = init.value_long;
1321 break;
1322 case OPT_LANGUAGE:
1323 /* INIT_OPT_LANGUAGE has no def parameter */
1324 option->value.number = 0;
1325 break;
1326 case OPT_COMMAND:
1327 option->value.command = init.value_funcptr;
1328 break;
1329 case OPT_ALIAS:
1330 option->value.string = init.value_dataptr;
1331 break;
1334 add_opt_rec(tree, init.path, option);
1337 /* Convert the sentinel at the end of the array, too. */
1338 info[i].option = zero;
1341 /*! @relates option_info */
1342 void
1343 unregister_options(union option_info info[], struct option *tree)
1345 int i = 0;
1347 /* We need to remove the options in inverse order to the order how we
1348 * added them. */
1350 while (info[i].option.name) i++;
1352 for (i--; i >= 0; i--)
1353 delete_option_do(&info[i].option, 0);