diff options
Diffstat (limited to 'src/core/wee-config-file.c')
-rw-r--r-- | src/core/wee-config-file.c | 539 |
1 files changed, 539 insertions, 0 deletions
diff --git a/src/core/wee-config-file.c b/src/core/wee-config-file.c new file mode 100644 index 000000000..5cabd5a07 --- /dev/null +++ b/src/core/wee-config-file.c @@ -0,0 +1,539 @@ +/* + * Copyright (c) 2003-2007 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* wee-config-file.c: I/O functions to read/write options in a config file */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include <time.h> +#include <pwd.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "weechat.h" +#include "wee-config-file.h" +#include "wee-config-option.h" +#include "wee-log.h" +#include "wee-string.h" +#include "wee-utf8.h" +#include "../gui/gui-chat.h" +#include "../gui/gui-color.h" + + +/* + * config_file_read_option: read an option for a section in config file + * This function is called when a new section begins + * or for an option of a section + * if options == NULL, then option is out of section + * if option_name == NULL, it's beginning of section + * otherwise it's an option for a section + * Return: 0 = successful + * -1 = option not found + * -2 = bad format/value + */ + +int +config_file_read_option (struct t_config_option *options, + char *option_name, char *value) +{ + struct t_config_option *ptr_option; + + if (option_name) + { + /* no option allowed outside a section by default */ + if (!options) + return -1; + + /* search option in list of options for section */ + ptr_option = config_option_search (options, option_name); + if (!ptr_option) + return -1; + + /* set value for option found */ + if (config_option_set (ptr_option, value) < 0) + return -2; + } + else + { + /* by default, does nothing for a new section */ + } + + /* all ok */ + return 0; +} + +/* + * config_file_read: read a configuration file + * return: 0 = successful + * -1 = config file file not found + * -2 = error in config file + */ + +int +config_file_read (char **config_sections, struct t_config_option **options, + t_config_func_read_option **read_functions, + t_config_func_read_option *read_function_default, + t_config_func_write_options **write_default_functions, + char *config_filename) +{ + int filename_length; + char *filename; + FILE *file; + int section, line_number, rc; + char line[1024], *ptr_line, *ptr_line2, *pos, *pos2; + + filename_length = strlen (weechat_home) + strlen (config_filename) + 2; + filename = (char *) malloc (filename_length * sizeof (char)); + if (!filename) + return -2; + snprintf (filename, filename_length, "%s%s%s", + weechat_home, DIR_SEPARATOR, config_filename); + if ((file = fopen (filename, "r")) == NULL) + { + /* if no default write functions provided and that config file + is not here, then return without doing anything */ + if (!write_default_functions) + return 0; + + /* create default config, then go on with reading */ + config_file_write_default (config_sections, options, + write_default_functions, + config_filename); + if ((file = fopen (filename, "r")) == NULL) + { + gui_chat_printf (NULL, _("%s config file \"%s\" not found.\n"), + WEECHAT_WARNING, filename); + free (filename); + return -1; + } + } + + config_option_section_option_set_default_values (config_sections, options); + + section = -1; + line_number = 0; + while (!feof (file)) + { + ptr_line = fgets (line, sizeof (line) - 1, file); + line_number++; + if (ptr_line) + { + /* encode line to internal charset */ + ptr_line2 = string_iconv_to_internal (NULL, ptr_line); + if (ptr_line2) + { + snprintf (line, sizeof (line) - 1, "%s", ptr_line2); + free (ptr_line2); + } + + /* skip spaces */ + while (ptr_line[0] == ' ') + ptr_line++; + /* not a comment and not an empty line */ + if ((ptr_line[0] != '#') && (ptr_line[0] != '\r') + && (ptr_line[0] != '\n')) + { + /* beginning of section */ + if (ptr_line[0] == '[') + { + pos = strchr (line, ']'); + if (pos == NULL) + gui_chat_printf (NULL, + _("%s %s, line %d: invalid syntax, " + "missing \"]\"\n"), + WEECHAT_WARNING, filename, + line_number); + else + { + pos[0] = '\0'; + pos = ptr_line + 1; + section = config_option_section_get_index (config_sections, pos); + if (section < 0) + gui_chat_printf (NULL, + _("%s %s, line %d: unknown section " + "identifier (\"%s\")\n"), + WEECHAT_WARNING, filename, + line_number, pos); + else + { + rc = ((int) (read_functions[section]) (options[section], + NULL, NULL)); + if (rc < 0) + gui_chat_printf (NULL, + _("%s %s, line %d: error " + "reading new section \"%s\"\n"), + WEECHAT_WARNING, filename, + line_number, pos); + } + } + } + else + { + pos = strchr (line, '='); + if (pos == NULL) + gui_chat_printf (NULL, + _("%s %s, line %d: invalid syntax, " + "missing \"=\"\n"), + WEECHAT_WARNING, filename, + line_number); + else + { + pos[0] = '\0'; + pos++; + + /* remove spaces before '=' */ + pos2 = pos - 2; + while ((pos2 > line) && (pos2[0] == ' ')) + { + pos2[0] = '\0'; + pos2--; + } + + /* skip spaces after '=' */ + while (pos[0] && (pos[0] == ' ')) + { + pos++; + } + + /* remove CR/LF */ + pos2 = strchr (pos, '\r'); + if (pos2 != NULL) + pos2[0] = '\0'; + pos2 = strchr (pos, '\n'); + if (pos2 != NULL) + pos2[0] = '\0'; + + /* remove simple or double quotes + and spaces at the end */ + if (strlen(pos) > 1) + { + pos2 = pos + strlen (pos) - 1; + while ((pos2 > pos) && (pos2[0] == ' ')) + { + pos2[0] = '\0'; + pos2--; + } + pos2 = pos + strlen (pos) - 1; + if (((pos[0] == '\'') && + (pos2[0] == '\'')) || + ((pos[0] == '"') && + (pos2[0] == '"'))) + { + pos2[0] = '\0'; + pos++; + } + } + + if (section < 0) + rc = ((int) (read_function_default) (NULL, line, pos)); + else + rc = ((int) (read_functions[section]) (options[section], + line, pos)); + if (rc < 0) + { + switch (rc) + { + case -1: + if (section < 0) + gui_chat_printf (NULL, + _("%s %s, line %d: unknown " + "option \"%s\" " + "(outside a section)\n"), + WEECHAT_WARNING, + filename, + line_number, line); + else + gui_chat_printf (NULL, + _("%s %s, line %d: option " + "\"%s\" unknown for " + "section \"%s\"\n"), + WEECHAT_WARNING, filename, + line_number, line, + config_sections[section]); + break; + case -2: + gui_chat_printf (NULL, + _("%s %s, line %d: invalid " + "value for option \"%s\"\n"), + WEECHAT_WARNING, filename, + line_number, line); + break; + } + } + } + } + } + } + } + + fclose (file); + free (filename); + + return 0; +} + +/* + * config_file_write_options: write a section with options in a config file + * This function is called when config is saved, + * for a section with standard options + * Return: 0 = successful + * -1 = write error + */ + +int +config_file_write_options (FILE *file, char *section_name, + struct t_config_option *options) +{ + int i; + + string_iconv_fprintf (file, "\n[%s]\n", section_name); + + for (i = 0; options[i].name; i++) + { + switch (options[i].type) + { + case OPTION_TYPE_BOOLEAN: + string_iconv_fprintf (file, "%s = %s\n", + options[i].name, + (options[i].ptr_int && + *options[i].ptr_int) ? + "on" : "off"); + break; + case OPTION_TYPE_INT: + string_iconv_fprintf (file, "%s = %d\n", + options[i].name, + (options[i].ptr_int) ? + *options[i].ptr_int : + options[i].default_int); + break; + case OPTION_TYPE_INT_WITH_STRING: + string_iconv_fprintf (file, "%s = %s\n", + options[i].name, + (options[i].ptr_int) ? + options[i].array_values[*options[i].ptr_int] : + options[i].array_values[options[i].default_int]); + break; + case OPTION_TYPE_COLOR: + string_iconv_fprintf (file, "%s = %s\n", + options[i].name, + (options[i].ptr_int) ? + gui_color_get_name (*options[i].ptr_int) : + options[i].default_string); + break; + case OPTION_TYPE_STRING: + string_iconv_fprintf (file, "%s = \"%s\"\n", + options[i].name, + (options[i].ptr_string) ? + *options[i].ptr_string : + options[i].default_string); + break; + } + } + + /* all ok */ + return 0; +} + +/* + * config_file_write_options_default_values: write a section with options in a config file + * This function is called when new config file + * is created, with default values, for a + * section with standard options + * Return: 0 = successful + * -1 = write error + */ + +int +config_file_write_options_default_values (FILE *file, char *section_name, + struct t_config_option *options) +{ + int i; + + string_iconv_fprintf (file, "\n[%s]\n", section_name); + + for (i = 0; options[i].name; i++) + { + switch (options[i].type) + { + case OPTION_TYPE_BOOLEAN: + string_iconv_fprintf (file, "%s = %s\n", + options[i].name, + (options[i].default_int) ? + "on" : "off"); + break; + case OPTION_TYPE_INT: + string_iconv_fprintf (file, "%s = %d\n", + options[i].name, + options[i].default_int); + break; + case OPTION_TYPE_INT_WITH_STRING: + case OPTION_TYPE_COLOR: + string_iconv_fprintf (file, "%s = %s\n", + options[i].name, + options[i].default_string); + break; + case OPTION_TYPE_STRING: + string_iconv_fprintf (file, "%s = \"%s\"\n", + options[i].name, + options[i].default_string); + break; + } + } + + /* all ok */ + return 0; +} + +/* + * config_file_write_header: write header in a config file + */ + +void +config_file_write_header (FILE *file) +{ + time_t current_time; + + current_time = time (NULL); + string_iconv_fprintf (file, _("#\n# %s configuration file, created by " + "%s v%s on %s"), + PACKAGE_NAME, PACKAGE_NAME, PACKAGE_VERSION, + ctime (¤t_time)); + string_iconv_fprintf (file, _("# WARNING! Be careful when editing this file, " + "WeeChat may write it at any time.\n#\n")); +} + +/* + * config_file_write_default: create a default configuration file + * return: 0 if ok + * < 0 if error + */ + +int +config_file_write_default (char **config_sections, struct t_config_option **options, + t_config_func_write_options **write_functions, + char *config_filename) +{ + int filename_length, i, rc; + char *filename; + FILE *file; + + filename_length = strlen (weechat_home) + + strlen (config_filename) + 2; + filename = + (char *) malloc (filename_length * sizeof (char)); + if (!filename) + return -2; + snprintf (filename, filename_length, "%s%s%s", + weechat_home, DIR_SEPARATOR, config_filename); + if ((file = fopen (filename, "w")) == NULL) + { + gui_chat_printf (NULL, _("%s cannot create file \"%s\"\n"), + WEECHAT_ERROR, filename); + free (filename); + return -1; + } + + string_iconv_fprintf (stdout, + _("%s: creating default config file \"%s\"...\n"), + PACKAGE_NAME, + config_filename); + weechat_log_printf (_("Creating default config file \"%s\"\n"), + config_filename); + + config_file_write_header (file); + + for (i = 0; config_sections[i]; i++) + { + rc = ((int) (write_functions[i]) (file, config_sections[i], + options[i])); + } + + fclose (file); + chmod (filename, 0600); + free (filename); + return 0; +} + +/* + * config_file_write: write a configurtion file + * return: 0 if ok + * < 0 if error + */ + +int +config_file_write (char **config_sections, struct t_config_option **options, + t_config_func_write_options **write_functions, + char *config_filename) +{ + int filename_length, i, rc; + char *filename, *filename2; + FILE *file; + + filename_length = strlen (weechat_home) + + strlen (config_filename) + 2; + filename = + (char *) malloc (filename_length * sizeof (char)); + if (!filename) + return -2; + snprintf (filename, filename_length, "%s%s%s", + weechat_home, DIR_SEPARATOR, config_filename); + + filename2 = (char *) malloc ((filename_length + 32) * sizeof (char)); + if (!filename2) + { + free (filename); + return -2; + } + snprintf (filename2, filename_length + 32, "%s.weechattmp", filename); + + if ((file = fopen (filename2, "w")) == NULL) + { + gui_chat_printf (NULL, _("%s cannot create file \"%s\"\n"), + WEECHAT_ERROR, filename2); + free (filename); + free (filename2); + return -1; + } + + config_file_write_header (file); + + for (i = 0; config_sections[i]; i++) + { + rc = ((int) (write_functions[i]) (file, config_sections[i], + options[i])); + } + + fclose (file); + chmod (filename2, 0600); + unlink (filename); + rc = rename (filename2, filename); + free (filename); + free (filename2); + if (rc != 0) + return -1; + return 0; +} |