⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 conf.c

📁 一个很有名的浏览器
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Config file manipulation *//* $Id: conf.c,v 1.152.2.3 2005/05/02 14:44:34 jonas Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h> /* OS/2 needs this after sys/types.h */#ifdef HAVE_FCNTL_H#include <fcntl.h> /* OS/2 needs this after sys/types.h */#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include "elinks.h"#include "config/conf.h"#include "config/dialogs.h"#include "config/kbdbind.h"#include "config/options.h"#include "config/opttypes.h"#include "intl/gettext/libintl.h"#include "lowlevel/home.h"#include "osdep/osdep.h"#include "terminal/terminal.h"#include "util/error.h"#include "util/memory.h"#include "util/secsave.h"#include "util/string.h"/* Config file has only very simple grammar: * * /set *option *= *value/ * /bind *keymap *keystroke *= *action/ * /include *file/ * /#.*$/ * * Where option consists from any number of categories separated by dots and * name of the option itself. Both category and option name consists from * [a-zA-Z0-9_-*] - using uppercase letters is not recommended, though. '*' is * reserved and is used only as escape character in place of '.' originally in * option name. * * Value can consist from: * - number (it will be converted to int/long) * - enum (like on, off; true, fake, last_url; etc ;) - in planning state yet * - string - "blah blah" (keymap, keystroke and action and file looks like that too) * * "set" command is parsed first, and then type-specific function is called, * with option as one parameter and value as a second. Usually it just assigns * value to an option, but sometimes you may want to first create the option * ;). Then this will come handy. *//* Skip comments and whitespace, * setting *@line to the number of lines skipped. */static unsigned char *skip_white(unsigned char *start, int *line){	while (*start) {		while (isspace(*start)) {			if (*start == '\n') {				(*line)++;			}			start++;		}		if (*start == '#') {			start += strcspn(start, "\n");		} else {			return start;		}	}	return start;}/* Parse a command. Returns error code. *//* If dynamic string credentials are supplied, we will mirror the command at * the end of the string; however, we won't load the option value to the tree, * and we will even write option value from the tree to the output string. We * will only possibly set OPT_WATERMARK flag to the option (if enabled). */static enum parse_errorparse_set(struct option *opt_tree, unsigned char **file, int *line,	  struct string *mirror){	unsigned char *orig_pos = *file;	unsigned char *optname;	unsigned char bin;	*file = skip_white(*file, line);	if (!**file) return ERROR_PARSE;	/* Option name */	optname = *file;	while (isident(**file) || **file == '*' || **file == '.') (*file)++;	bin = **file;	**file = '\0';	optname = stracpy(optname);	if (!optname) return ERROR_NOMEM;	**file = bin;	*file = skip_white(*file, line);	/* Equal sign */	if (**file != '=') { mem_free(optname); return ERROR_PARSE; }	(*file)++; /* '=' */	*file = skip_white(*file, line);	if (!**file) { mem_free(optname); return ERROR_VALUE; }	/* Mirror what we already have */	if (mirror) add_bytes_to_string(mirror, orig_pos, *file - orig_pos);	/* Option value */	{		struct option *opt;		unsigned char *val;		opt = mirror ? get_opt_rec_real(opt_tree, optname) : get_opt_rec(opt_tree, optname);		mem_free(optname);		if (!opt || (opt->flags & OPT_HIDDEN))			return ERROR_OPTION;		if (!option_types[opt->type].read)			return ERROR_VALUE;		val = option_types[opt->type].read(opt, file, line);		if (!val) return ERROR_VALUE;		if (mirror) {			if (opt->flags & OPT_DELETED)				opt->flags &= ~OPT_WATERMARK;			else				opt->flags |= OPT_WATERMARK;			if (option_types[opt->type].write) {				option_types[opt->type].write(opt, mirror);			}		} else if (!option_types[opt->type].set			   || !option_types[opt->type].set(opt, val)) {			mem_free(val);			return ERROR_VALUE;		}		/* This is not needed since this will be WATERMARK'd when		 * saving it. We won't need to save it as touched. */		/* if (!str) opt->flags |= OPT_TOUCHED; */		mem_free(val);	}	return ERROR_NONE;}static enum parse_errorparse_unset(struct option *opt_tree, unsigned char **file, int *line,	    struct string *mirror){	unsigned char *orig_pos = *file;	unsigned char *optname;	unsigned char bin;	/* XXX: This does not handle the autorewriting well and is mostly a	 * quick hack than anything now. --pasky */	*file = skip_white(*file, line);	if (!**file) return ERROR_PARSE;	/* Option name */	optname = *file;	while (isident(**file) || **file == '*' || **file == '.') (*file)++;	bin = **file;	**file = '\0';	optname = stracpy(optname);	if (!optname) return ERROR_NOMEM;	**file = bin;	/* Mirror what we have */	if (mirror) add_bytes_to_string(mirror, orig_pos, *file - orig_pos);	{		struct option *opt;		opt = get_opt_rec_real(opt_tree, optname);		mem_free(optname);		if (!opt || (opt->flags & OPT_HIDDEN))			return ERROR_OPTION;		if (!mirror) {			if (opt->flags & OPT_ALLOC) delete_option(opt);		} else {			if (opt->flags & OPT_DELETED)				opt->flags |= OPT_WATERMARK;			else				opt->flags &= ~OPT_WATERMARK;		}	}	return ERROR_NONE;}static enum parse_errorparse_bind(struct option *opt_tree, unsigned char **file, int *line,	   struct string *mirror){	unsigned char *orig_pos = *file, *next_pos;	unsigned char *keymap, *keystroke, *action;	enum parse_error err = ERROR_NONE;	*file = skip_white(*file, line);	if (!*file) return ERROR_PARSE;	/* Keymap */	keymap = option_types[OPT_STRING].read(NULL, file, line);	*file = skip_white(*file, line);	if (!keymap || !**file)		return ERROR_OPTION;	/* Keystroke */	keystroke = option_types[OPT_STRING].read(NULL, file, line);	*file = skip_white(*file, line);	if (!keystroke || !**file) {		mem_free(keymap);		return ERROR_OPTION;	}	/* Equal sign */	*file = skip_white(*file, line);	if (**file != '=') {		mem_free(keymap); mem_free(keystroke);		return ERROR_PARSE;	}	(*file)++; /* '=' */	*file = skip_white(*file, line);	if (!**file) {		mem_free(keymap); mem_free(keystroke);		return ERROR_PARSE;	}	/* Action */	next_pos = *file;	action = option_types[OPT_STRING].read(NULL, file, line);	if (!action) {		mem_free(keymap);		return ERROR_VALUE;	}	if (mirror) {		/* Mirror what we already have */		unsigned char *act_str = bind_act(keymap, keystroke);		if (act_str) {			add_bytes_to_string(mirror, orig_pos,					    next_pos - orig_pos);			add_to_string(mirror, act_str);			mem_free(act_str);		} else {			err = ERROR_VALUE;		}	} else {		/* We don't bother to bind() if -default-keys. */		if (!get_cmd_opt_bool("default-keys")		    && bind_do(keymap, keystroke, action)) {			/* bind_do() tried but failed. */			err = ERROR_VALUE;		} else {			err = ERROR_NONE;		}	}	mem_free(keymap); mem_free(keystroke); mem_free(action);	return err;}static int load_config_file(unsigned char *, unsigned char *, struct option *,			    struct string *);static enum parse_errorparse_include(struct option *opt_tree, unsigned char **file, int *line,	      struct string *mirror){	unsigned char *orig_pos = *file;	unsigned char *fname;	struct string dumbstring;	if (!init_string(&dumbstring)) return ERROR_NOMEM;	*file = skip_white(*file, line);	if (!*file) return ERROR_PARSE;	/* File name */	fname = option_types[OPT_STRING].read(NULL, file, line);	if (!fname)		return ERROR_VALUE;	/* Mirror what we already have */	if (mirror) add_bytes_to_string(mirror, orig_pos, *file - orig_pos);	/* We want load_config_file() to watermark stuff, but not to load	 * anything, polluting our beloved options tree - thus, we will feed it	 * with some dummy string which we will destroy later; still better	 * than cloning whole options tree or polluting interface with another	 * rarely-used option ;). */	/* XXX: We should try CONFDIR/<file> when proceeding	 * CONFDIR/<otherfile> ;). --pasky */	if (load_config_file(fname[0] == '/' ? (unsigned char *) ""					     : elinks_home,			     fname, opt_tree, &dumbstring)) {		done_string(&dumbstring);		mem_free(fname);		return ERROR_VALUE;	}	done_string(&dumbstring);	mem_free(fname);	return ERROR_NONE;}struct parse_handler {	unsigned char *command;	enum parse_error (*handler)(struct option *opt_tree,				    unsigned char **file, int *line,				    struct string *mirror);};static struct parse_handler parse_handlers[] = {	{ "set", parse_set },	{ "unset", parse_unset },	{ "bind", parse_bind },	{ "include", parse_include },	{ NULL, NULL }};enum parse_errorparse_config_command(struct option *options, unsigned char **file, int *line,		     struct string *mirror){	struct parse_handler *handler;	for (handler = parse_handlers; handler->command;	     handler++) {		int cmdlen = strlen(handler->command);		if (!strncmp(*file, handler->command, cmdlen)		    && isspace((*file)[cmdlen])) {			enum parse_error err;			struct string mirror2 = NULL_STRING;			struct string *m2 = NULL;			/* Mirror what we already have */			if (mirror && init_string(&mirror2)) {				m2 = &mirror2;				add_bytes_to_string(m2, *file, cmdlen);			}			*file += cmdlen;			err = handler->handler(options, file, line, m2);			if (!err && mirror && m2) {				add_string_to_string(mirror, m2);			}			if (m2)	done_string(m2);			return err;		}	}	return ERROR_COMMAND;}voidparse_config_file(struct option *options, unsigned char *name,		  unsigned char *file, struct string *mirror){	int line = 1;	int error_occured = 0;	enum parse_error err = 0;	enum verbose_level verbose = get_cmd_opt_int("verbose");	unsigned char error_msg[][40] = {		"no error",		"parse error",		"unknown command",		"unknown option",		"bad value",		"no memory left",	};	while (file && *file) {		unsigned char *orig_pos = file;		/* Skip all possible comments and whitespace. */		file = skip_white(file, &line);		/* Mirror what we already have */		if (mirror)			add_bytes_to_string(mirror, orig_pos, file - orig_pos);		/* Second chance to escape from the hell. */		if (!*file) break;		err = parse_config_command(options, &file, &line, mirror);		if (err == ERROR_COMMAND) {			orig_pos = file;			/* Jump over this crap we can't understand. */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -