mirror of
https://github.com/rkd77/elinks.git
synced 2024-11-04 08:17:17 -05: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:
parent
5ada24f3ef
commit
06adbbc524
@ -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;
|
||||
|
||||
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");
|
||||
}
|
||||
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);
|
||||
|
@ -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;
|
||||
|
@ -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 *);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user