예제 #1
0
파일: options.c 프로젝트: Efreak/elinks
void
toggle_document_option(struct session *ses, unsigned char *option_name)
{
	struct option *option;

	assert(ses && ses->doc_view && ses->tab && ses->tab->term);
	if_assert_failed return;

	if (!ses->doc_view->vs) {
		nowhere_box(ses->tab->term, NULL);
		return;
	}

	option = get_opt_rec(config_options, option_name);
	assert(option);
	if_assert_failed return;

	if (ses->option)
		option = get_option_shadow(option, config_options, ses->option);
	if (!option) return;

	toggle_option(ses, option);

	draw_formatted(ses, 1);
}
예제 #2
0
static void
redir_wr(struct option *opt, struct string *string)
{
	struct option *real = get_opt_rec(config_options, opt->value.string);

	assertm(real, "%s aliased to unknown option %s!", opt->name, opt->value.string);
	if_assert_failed { return; }

	if (option_types[real->type].write)
		option_types[real->type].write(real, string);
}
예제 #3
0
static unsigned char *
redir_cmd(struct option *opt, unsigned char ***argv, int *argc)
{
	struct option *real = get_opt_rec(config_options, opt->value.string);
	unsigned char * ret = NULL;

	assertm(real, "%s aliased to unknown option %s!", opt->name, opt->value.string);
	if_assert_failed { return ret; }

	if (option_types[real->type].cmdline) {
		ret = option_types[real->type].cmdline(real, argv, argc);
		if ((opt->flags & OPT_ALIAS_NEGATE) && real->type == OPT_BOOL) {
			real->value.number = !real->value.number;
		}
	}

	return ret;
}
예제 #4
0
static unsigned char *
redir_rd(struct option *opt, unsigned char **file, int *line)
{
	struct option *real = get_opt_rec(config_options, opt->value.string);
	unsigned char *ret = NULL;

	assertm(real != NULL, "%s aliased to unknown option %s!", opt->name, opt->value.string);
	if_assert_failed { return ret; }

	if (option_types[real->type].read) {
		ret = option_types[real->type].read(real, file, line);
		if (ret && (opt->flags & OPT_ALIAS_NEGATE) && real->type == OPT_BOOL) {
			*(long *) ret = !*(long *) ret;
		}
	}

	return ret;
}
예제 #5
0
static int
redir_eq(struct option *opt, const unsigned char *str)
{
	struct option *real = get_opt_rec(config_options, opt->value.string);
	int ret = 0;

	assertm(real != NULL, "%s aliased to unknown option %s!", opt->name, opt->value.string);
	if_assert_failed { return ret; }

	if (option_types[real->type].equals) {
		long negated;

		if ((opt->flags & OPT_ALIAS_NEGATE) && real->type == OPT_BOOL) {
			negated = !*(const long *) str;
			str = (unsigned char *) &negated;
		}
		ret = option_types[real->type].equals(real, str);
	}

	return ret;
}
예제 #6
0
static enum parse_error
parse_set_common(struct option *opt_tree, struct conf_parsing_state *state,
		 struct string *mirror, int is_system_conf, int want_domain)
{
	const unsigned char *domain_orig = NULL;
	size_t domain_len = 0;
	unsigned char *domain_copy = NULL;
	const unsigned char *optname_orig;
	size_t optname_len;
	unsigned char *optname_copy;

	skip_white(&state->pos);
	if (!*state->pos.look) return show_parse_error(state, ERROR_PARSE);

	if (want_domain) {
		domain_orig = state->pos.look;
		while (isident(*state->pos.look) || *state->pos.look == '*'
		       || *state->pos.look == '.' || *state->pos.look == '+')
			state->pos.look++;
		domain_len = state->pos.look - domain_orig;

		skip_white(&state->pos);
	}

	/* Option name */
	optname_orig = state->pos.look;
	while (is_option_name_char(*state->pos.look)
	       || *state->pos.look == '.')
		state->pos.look++;
	optname_len = state->pos.look - optname_orig;

	skip_white(&state->pos);

	/* Equal sign */
	if (*state->pos.look != '=')
		return show_parse_error(state, ERROR_PARSE);
	state->pos.look++; /* '=' */
	skip_white(&state->pos);
	if (!*state->pos.look)
		return show_parse_error(state, ERROR_VALUE);

	optname_copy = memacpy(optname_orig, optname_len);
	if (!optname_copy) return show_parse_error(state, ERROR_NOMEM);
	if (want_domain) {
		domain_copy = memacpy(domain_orig, domain_len);
		if (!domain_copy) {
			mem_free(optname_copy);
			return show_parse_error(state, ERROR_NOMEM);
		}
	}

	/* Option value */
	{
		struct option *opt;
		unsigned char *val;
		const struct conf_parsing_pos pos_before_value = state->pos;

		if (want_domain && *domain_copy) {
			struct option *domain_tree;

			domain_tree = get_domain_tree(domain_copy);
			if (!domain_tree) {
				mem_free(domain_copy);
				mem_free(optname_copy);
				skip_option_value(&state->pos);
				return show_parse_error(state, ERROR_NOMEM);
			}

			if (mirror) {
				opt = get_opt_rec_real(domain_tree,
						       optname_copy);
			} else {
				opt = get_opt_rec(opt_tree, optname_copy);
				if (opt) {
					opt = get_option_shadow(opt, opt_tree,
								domain_tree);
					if (!opt) {
						mem_free(domain_copy);
						mem_free(optname_copy);
						skip_option_value(&state->pos);
						return show_parse_error(state,
									ERROR_NOMEM);
					}
				}
			}
		} else {
			opt = mirror
				? get_opt_rec_real(opt_tree, optname_copy)
				: get_opt_rec(opt_tree, optname_copy);
		}
		if (want_domain)
			mem_free(domain_copy);
		domain_copy = NULL;
		mem_free(optname_copy);
		optname_copy = NULL;

		if (!opt || (opt->flags & OPT_HIDDEN)) {
			show_parse_error(state, ERROR_OPTION);
			skip_option_value(&state->pos);
			return ERROR_OPTION;
			/* TODO: Distinguish between two scenarios:
			 * - A newer version of ELinks has saved an
			 *   option that this version does not recognize.
			 *   The option must be preserved.  (This works.)
			 * - The user has added an option, saved
			 *   elinks.conf, restarted ELinks, deleted the
			 *   option, and is now saving elinks.conf again.
			 *   The option should be rewritten to "unset".
			 *   (This does not work yet.)
			 * In both cases, ELinks has no struct option
			 * for that name.  Possible fixes:
			 * - If the tree has OPT_AUTOCREATE, then
			 *   assume the user had created that option,
			 *   and rewrite it to "unset".  Otherwise,
			 *   keep it.
			 * - When the user deletes an option, just mark
			 *   it with OPT_DELETED, and keep it in memory
			 *   as long as OPT_TOUCHED is set.  */
		}

		if (!option_types[opt->type].read) {
			show_parse_error(state, ERROR_VALUE);
			skip_option_value(&state->pos);
			return ERROR_VALUE;
		}

		val = option_types[opt->type].read(opt, &state->pos.look,
						   &state->pos.line);
		if (!val) {
			/* The reader function failed.  Jump back to
			 * the beginning of the value and skip it with
			 * the generic code.  For the error message,
			 * use the line number at the beginning of the
			 * value, because the ending position is not
			 * interesting if there is an unclosed quote.  */
			state->pos = pos_before_value;
			show_parse_error(state, ERROR_VALUE);
			skip_option_value(&state->pos);
			return ERROR_VALUE;
		}

		if (!mirror) {
			/* loading a configuration file */
			if (!option_types[opt->type].set
			    || !option_types[opt->type].set(opt, val)) {
				mem_free(val);
				return show_parse_error(state, ERROR_VALUE);
			}
		} else if (is_system_conf) {
			/* scanning a file that will not be rewritten */
			struct option *flagsite = indirect_option(opt);

			if (!(flagsite->flags & OPT_DELETED)
			    && option_types[opt->type].equals
			    && option_types[opt->type].equals(opt, val))
				flagsite->flags &= ~OPT_MUST_SAVE;
			else
				flagsite->flags |= OPT_MUST_SAVE;
		} else {
			/* rewriting a configuration file */
			struct option *flagsite = indirect_option(opt);

			if (flagsite->flags & OPT_DELETED) {
				/* Replace the "set" command with an
				 * "unset" command.  */
				add_to_string(mirror, "unset ");
				add_bytes_to_string(mirror, optname_orig,
						    optname_len);
				state->mirrored = state->pos.look;
			} else if (option_types[opt->type].write) {
				add_bytes_to_string(mirror, state->mirrored,
						    pos_before_value.look
						    - state->mirrored);
				option_types[opt->type].write(opt, mirror);
				state->mirrored = state->pos.look;
			}
			/* Remember that the option need not be
			 * written to the end of the file.  */
			flagsite->flags &= ~OPT_MUST_SAVE;
		}
		mem_free(val);
	}

	return ERROR_NONE;
}