1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-10-01 03:36:26 -04:00

Add domain-specific options saving and look-up

Note that this is the infrastructure, but all relevant get_opt_* calls must be changed to pass the session so that the domain-specific options are looked up.

Add @want_domain parameter to parse_set_common and read in the domain-name if the flag is set.

Add parse_set_domain wrapper for parse_set_common.

Add "set_domain" configuration directive with the following syntax: set_domain domain option = value

Modify create_config_string and smart_config_output_fn to spit out domain-specific option trees.

Add @smart_config_output_fn_domain global variable to facilitate this.

Define structure domain_tree and define list @domain_trees.

Add routine get_domain_tree to find or, if necessary, create the shadow tree for the given domain name.

Add routine get_domain_option search for an option in all domain shadow-trees and return the option in the best matching domain tree.

Modify get_opt_ to use get_domain_option to check for domain-specific options.

Add clean-up routine done_domain_trees, called on exit, to free any domain trees.
This commit is contained in:
Miciah Dashiel Butler Masters 2007-08-30 20:29:40 +00:00 committed by Miciah Dashiel Butler Masters
parent 5ada24f3ef
commit 06adbbc524
3 changed files with 184 additions and 5 deletions

View File

@ -88,15 +88,30 @@ skip_white(unsigned char *start, int *line)
static enum parse_error
parse_set_common(struct option *opt_tree, unsigned char **file, int *line,
struct string *mirror, int is_system_conf)
struct string *mirror, int is_system_conf, int want_domain)
{
unsigned char *orig_pos = *file;
unsigned char *domain_name;
unsigned char *optname;
unsigned char bin;
*file = skip_white(*file, line);
if (!**file) return ERROR_PARSE;
if (want_domain) {
domain_name = *file;
while (isident(**file) || **file == '*' || **file == '.' || **file == '+')
(*file)++;
bin = **file;
**file = '\0';
domain_name = stracpy(domain_name);
**file = bin;
if (!domain_name) return ERROR_NOMEM;
*file = skip_white(*file, line);
}
/* Option name */
optname = *file;
while (isident(**file) || **file == '*' || **file == '.' || **file == '+')
@ -124,7 +139,35 @@ parse_set_common(struct option *opt_tree, unsigned char **file, int *line,
struct option *opt;
unsigned char *val;
opt = mirror ? get_opt_rec_real(opt_tree, optname) : get_opt_rec(opt_tree, optname);
if (want_domain && *domain_name) {
struct option *domain_tree;
domain_tree = get_domain_tree(domain_name);
if (!domain_tree) {
mem_free(domain_name);
mem_free(optname);
return ERROR_NOMEM;
}
if (mirror) {
opt = get_opt_rec_real(domain_tree, optname);
} else {
opt = get_opt_rec(opt_tree, optname);
if (opt) {
opt = get_option_shadow(opt, opt_tree,
domain_tree);
if (!opt) {
mem_free(domain_name);
mem_free(optname);
return ERROR_NOMEM;
}
}
}
} else {
opt = mirror ? get_opt_rec_real(opt_tree, optname) : get_opt_rec(opt_tree, optname);
}
if (want_domain)
mem_free(domain_name);
mem_free(optname);
if (!opt || (opt->flags & OPT_HIDDEN))
@ -158,11 +201,18 @@ parse_set_common(struct option *opt_tree, unsigned char **file, int *line,
return ERROR_NONE;
}
static enum parse_error
parse_set_domain(struct option *opt_tree, unsigned char **file, int *line,
struct string *mirror, int is_system_conf)
{
return parse_set_common(opt_tree, file, line, mirror, is_system_conf, 1);
}
static enum parse_error
parse_set(struct option *opt_tree, unsigned char **file, int *line,
struct string *mirror, int is_system_conf)
{
return parse_set_common(opt_tree, file, line, mirror, is_system_conf);
return parse_set_common(opt_tree, file, line, mirror, is_system_conf, 0);
}
@ -344,6 +394,7 @@ struct parse_handler {
};
static struct parse_handler parse_handlers[] = {
{ "set_domain", parse_set_domain },
{ "set", parse_set },
{ "unset", parse_unset },
{ "bind", parse_bind },
@ -570,6 +621,8 @@ add_indent_to_string(struct string *string, int depth)
add_xchar_to_string(string, ' ', depth * indentation);
}
static unsigned char *smart_config_output_fn_domain;
static void
smart_config_output_fn(struct string *string, struct option *option,
unsigned char *path, int depth, int do_print_comment,
@ -652,7 +705,13 @@ split:
if (option->flags & OPT_DELETED) {
add_to_string(string, "un");
}
add_to_string(string, "set ");
if (smart_config_output_fn_domain) {
add_to_string(string, "set_domain ");
add_to_string(string, smart_config_output_fn_domain);
add_char_to_string(string, ' ');
} else {
add_to_string(string, "set ");
}
if (path) {
add_to_string(string, path);
add_char_to_string(string, '.');
@ -774,6 +833,22 @@ create_config_string(unsigned char *prefix, unsigned char *name)
origlen = tmpstring.length;
smart_config_string(&tmpstring, 2, i18n, options->value.tree, NULL, 0,
smart_config_output_fn);
{
struct domain_tree *domain;
foreach (domain, domain_trees) {
smart_config_output_fn_domain = domain->name;
smart_config_string(&tmpstring, 2, i18n,
domain->tree->value.tree,
NULL, 0,
smart_config_output_fn);
unmark_options_tree(domain->tree->value.tree);
}
smart_config_output_fn_domain = NULL;
}
if (tmpstring.length > origlen)
add_string_to_string(&config, &tmpstring);
done_string(&tmpstring);

View File

@ -23,6 +23,8 @@
#include "main/main.h" /* shrink_memory() */
#include "main/select.h"
#include "network/connection.h"
#include "protocol/uri.h"
#include "session/location.h"
#include "session/session.h"
#include "terminal/color.h"
#include "terminal/screen.h"
@ -32,6 +34,7 @@
#include "util/memory.h"
#include "util/string.h"
#include "viewer/text/draw.h"
#include "viewer/text/vs.h"
/* TODO? In the past, covered by shadow and legends, remembered only by the
@ -241,6 +244,8 @@ get_opt_rec_real(struct option *tree, const unsigned char *name)
return opt;
}
static struct option *get_domain_option(unsigned char *, int, unsigned char *);
/* Fetch pointer to value of certain option. It is guaranteed to never return
* NULL. Note that you are supposed to use wrapper get_opt(). */
union option_value *
@ -257,7 +262,14 @@ get_opt_(
if (ses && ses->option)
opt = get_opt_rec_real(ses->option, name);
/* TODO: Look for a domain-specific option. */
/* If given a session, the session has a location, and we can find
* an options tree for the location's domain, return the shadow. */
if (ses && have_location(ses)) {
struct uri *uri = cur_loc(ses)->vs.uri;
if (uri->host && uri->hostlen)
opt = get_domain_option(uri->host, uri->hostlen, name);
}
/* Else, return the real option. */
if (!opt)
@ -698,6 +710,82 @@ get_option_shadow(struct option *option, struct option *tree,
return shadow_option;
}
INIT_LIST_OF(struct domain_tree, domain_trees);
/* Look for the option with the given name in all domain shadow-trees that
* match the given domain-name. Return the option from the the shadow tree
* that best matches the given domain name. */
static struct option *
get_domain_option(unsigned char *domain_name, int domain_len,
unsigned char *name)
{
struct option *opt, *longest_match_opt = NULL;
struct domain_tree *longest_match = NULL;
struct domain_tree *domain;
assert(domain_name);
assert(*domain_name);
foreach (domain, domain_trees)
if ((!longest_match || domain->len > longest_match->len)
&& is_in_domain(domain->name, domain_name, domain_len)
&& (opt = get_opt_rec_real(domain->tree, name))) {
longest_match = domain;
longest_match_opt = opt;
}
return longest_match_opt;
}
/* Return the shadow shadow tree for the given domain name, and
* if the domain does not yet have a shadow tree, create it. */
struct option *
get_domain_tree(unsigned char *domain_name)
{
struct domain_tree *domain;
int domain_len;
assert(domain_name);
assert(*domain_name);
foreach (domain, domain_trees)
if (!strcasecmp(domain->name, domain_name))
return domain->tree;
domain_len = strlen(domain_name);
/* One byte is reserved for domain in struct domain_tree. */
domain = mem_alloc(sizeof(*domain) + domain_len);
if (!domain) return NULL;
domain->tree = copy_option(config_options, CO_SHALLOW
| CO_NO_LISTBOX_ITEM);
if (!domain->tree) {
mem_free(domain);
return NULL;
}
memcpy(domain->name, domain_name, domain_len + 1);
domain->len = domain_len;
add_to_list(domain_trees, domain);
return domain->tree;
}
void
done_domain_trees(void)
{
struct domain_tree *domain, *next;
foreachsafe (domain, next, domain_trees) {
delete_option(domain->tree);
domain->tree = NULL;
del_from_list(domain);
mem_free(domain);
}
}
LIST_OF(struct option) *
init_options_tree(void)
{
@ -765,6 +853,7 @@ free_options_tree(LIST_OF(struct option) *tree, int recursive)
void
done_options(void)
{
done_domain_trees();
unregister_options(config_options_info, config_options);
unregister_options(cmdline_options_info, cmdline_options);
config_options->box_item = NULL;

View File

@ -178,8 +178,23 @@ enum copy_option_flags {
};
extern struct option *copy_option(struct option *, int);
struct option *get_option_shadow(struct option *, struct option *,
struct option *);
struct domain_tree {
LIST_HEAD(struct domain_tree);
struct option *tree;
int len;
unsigned char name[1]; /* Must be at end of struct. */
};
extern LIST_OF(struct domain_tree) domain_trees;
struct option *get_domain_tree(unsigned char *);
extern void delete_option(struct option *);
void mark_option_as_deleted(struct option *);