X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fconf.c;h=81c280a405fcd85c7ac0062cc2923015887a9ae9;hb=bf5fc85f37af5698d477edc5dae250bf8984ed00;hp=13dc5d50c5cdeb1c4ddd8891c49560cf902944f3;hpb=e06ce8df076331c7a345627bab3e8a375f505fe1;p=ncmpc.git diff --git a/src/conf.c b/src/conf.c index 13dc5d5..81c280a 100644 --- a/src/conf.c +++ b/src/conf.c @@ -1,21 +1,21 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2009 The Music Player Daemon Project + * (c) 2004-2017 The Music Player Daemon Project * Project homepage: http://musicpd.org - + * * 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 2 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, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ + */ #include "conf.h" #include "config.h" @@ -24,30 +24,30 @@ #include "command.h" #include "colors.h" #include "screen_list.h" +#include "options.h" +#include #include #include #include #include -#include #include -#include -#include -#include #include +#include #define MAX_LINE_LENGTH 1024 #define COMMENT_TOKEN '#' /* configuration field names */ #define CONF_ENABLE_COLORS "enable-colors" +#define CONF_SCROLL_OFFSET "scroll-offset" #define CONF_AUTO_CENTER "auto-center" #define CONF_WIDE_CURSOR "wide-cursor" -#define CONF_ENABLE_BELL "enable-bell" #define CONF_KEY_DEFINITION "key" #define CONF_COLOR "color" #define CONF_COLOR_DEFINITION "colordef" #define CONF_LIST_FORMAT "list-format" +#define CONF_SEARCH_FORMAT "search-format" #define CONF_STATUS_FORMAT "status-format" #define CONF_XTERM_TITLE_FORMAT "xterm-title-format" #define CONF_LIST_WRAP "wrap-around" @@ -56,6 +56,7 @@ #define CONF_AUDIBLE_BELL "audible-bell" #define CONF_VISIBLE_BELL "visible-bell" #define CONF_BELL_ON_WRAP "bell-on-wrap" +#define CONF_STATUS_MESSAGE_TIME "status-message-time" #define CONF_XTERM_TITLE "set-xterm-title" #define CONF_ENABLE_MOUSE "enable-mouse" #define CONF_CROSSFADE_TIME "crossfade-time" @@ -67,13 +68,43 @@ #define CONF_HOST "host" #define CONF_PORT "port" #define CONF_PASSWORD "password" +#define CONF_TIMEOUT "timeout" #define CONF_LYRICS_TIMEOUT "lyrics-timeout" -#define CONF_SHOW_SPLASH "show-splash" #define CONF_SCROLL "scroll" #define CONF_SCROLL_SEP "scroll-sep" #define CONF_VISIBLE_BITRATE "visible-bitrate" +#define CONF_HARDWARE_CURSOR "hardware-cursor" #define CONF_WELCOME_SCREEN_LIST "welcome-screen-list" #define CONF_DISPLAY_TIME "display-time" +#define CONF_JUMP_PREFIX_ONLY "jump-prefix-only" +#define CONF_LYRICS_AUTOSAVE "lyrics-autosave" +#define CONF_LYRICS_SHOW_PLUGIN "lyrics-show-plugin" +#define CONF_TEXT_EDITOR "text-editor" +#define CONF_TEXT_EDITOR_ASK "text-editor-ask" +#define CONF_CHAT_PREFIX "chat-prefix" +#define CONF_SECOND_COLUMN "second-column" + +gcc_const +static bool +is_space_not_null(char ch) +{ + unsigned char uch = (unsigned char)ch; + return uch <= 0x20 && uch > 0; +} + +/** + * Returns the first non-space character (or a pointer to the null + * terminator). Similar to g_strchug(), but just moves the pointer + * forward without modifying the string contents. + */ +gcc_pure +static char * +skip_spaces(char *p) +{ + while (is_space_not_null(*p)) + ++p; + return p; +} static bool str2bool(char *str) @@ -90,6 +121,29 @@ print_error(const char *msg, const char *input) _("Error"), msg, input); } +gcc_const +static bool +is_word_char(char ch) +{ + return g_ascii_isalnum(ch) || ch == '-' || ch == '_'; +} + +static char * +after_unquoted_word(char *p) +{ + if (!is_word_char(*p)) { + print_error(_("Word expected"), p); + return NULL; + } + + ++p; + + while (is_word_char(*p)) + ++p; + + return p; +} + static int parse_key_value(char *str, char **end) { @@ -112,27 +166,24 @@ parse_key_value(char *str, char **end) } } -static int +static bool parse_key_definition(char *str) { - char buf[MAX_LINE_LENGTH]; - char *p; - size_t len = strlen(str), i; - int j,key; - int keys[MAX_COMMAND_KEYS]; - command_t cmd; - /* get the command name */ - i=0; - j=0; + const size_t len = strlen(str); + size_t i = 0; + int j = 0; + char buf[MAX_LINE_LENGTH]; memset(buf, 0, MAX_LINE_LENGTH); while (i < len && str[i] != '=' && !g_ascii_isspace(str[i])) buf[j++] = str[i++]; - if( (cmd=get_key_command_from_name(buf)) == CMD_NONE ) { + + command_t cmd = get_key_command_from_name(buf); + if(cmd == CMD_NONE) { /* the hotkey configuration contains an unknown command */ print_error(_("Unknown command"), buf); - return -1; + return false; } /* skip whitespace */ @@ -145,13 +196,15 @@ parse_key_definition(char *str) if (*buf == 0) { /* the hotkey configuration line is incomplete */ print_error(_("Incomplete hotkey configuration"), str); - return -1; + return false; } /* parse key values */ i = 0; - key = 0; - p = buf; + int key = 0; + char *p = buf; + + int keys[MAX_COMMAND_KEYS]; memset(keys, 0, sizeof(int)*MAX_COMMAND_KEYS); while (i < MAX_COMMAND_KEYS && *p != 0 && (key = parse_key_value(p, &p)) >= 0) { @@ -161,23 +214,25 @@ parse_key_definition(char *str) } if (key < 0) - return -1; + return false; return assign_keys(cmd, keys); } -static const char * +static bool parse_timedisplay_type(const char *str) { - if (!strcmp(str,"elapsed") || !strcmp(str,"remaining")) - return str; + if (strcmp(str, "elapsed") == 0) + return false; + else if (strcmp(str, "remaining") == 0) + return true; else { /* translators: ncmpc supports displaying the "elapsed" or "remaining" time of a song being played; in this case, the configuration file contained an invalid setting */ print_error(_("Bad time display type"), str); - return DEFAULT_TIMEDISPLAY_TYPE; + return false; } } @@ -185,9 +240,7 @@ parse_timedisplay_type(const char *str) static char * separate_value(char *p) { - char *value; - - value = strchr(p, '='); + char *value = strchr(p, '='); if (value == NULL) { /* an equals sign '=' was expected while parsing a configuration file line */ @@ -198,17 +251,15 @@ separate_value(char *p) *value++ = 0; g_strchomp(p); - return g_strchug(value); + return skip_spaces(value); } -static int +static bool parse_color(char *str) { - char *value; - - value = separate_value(str); + char *value = separate_value(str); if (value == NULL) - return -1; + return false; return colors_assign(str, value); } @@ -225,7 +276,7 @@ after_comma(char *p) if (comma != NULL) { *comma++ = 0; - comma = g_strchug(comma); + comma = skip_spaces(comma); } else comma = p + strlen(p); @@ -233,37 +284,35 @@ after_comma(char *p) return comma; } -static int +static bool parse_color_definition(char *str) { - char buf[MAX_LINE_LENGTH]; - char *value; - short color, rgb[3]; - - value = separate_value(str); + char *value = separate_value(str); if (value == NULL) - return -1; + return false; /* get the command name */ - color = colors_str2color(str); + short color = colors_str2color(str); if (color < 0) { + char buf[MAX_LINE_LENGTH]; print_error(_("Bad color name"), buf); - return -1; + return false; } /* parse r,g,b values */ + short rgb[3]; for (unsigned i = 0; i < 3; ++i) { char *next = after_comma(value), *endptr; if (*value == 0) { print_error(_("Incomplete color definition"), str); - return -1; + return false; } rgb[i] = strtol(value, &endptr, 0); if (endptr == value || *endptr != 0) { print_error(_("Invalid number"), value); - return -1; + return false; } value = next; @@ -271,7 +320,7 @@ parse_color_definition(char *str) if (*value != 0) { print_error(_("Malformed color definition"), str); - return -1; + return false; } return colors_define(str, rgb[0], rgb[1], rgb[2]); @@ -296,21 +345,21 @@ check_screen_list(char *value) { char **tmp = g_strsplit_set(value, " \t,", 100); char **screen = NULL; - int i,j; + int i = 0, j = 0; - i=0; - j=0; while( tmp && tmp[i] ) { char *name = g_ascii_strdown(tmp[i], -1); - if (screen_lookup_name(name) == NULL) { - /* an unknown screen name was specified in the - configuration file */ - print_error(_("Unknown screen name"), name); - free(name); - } else { - screen = g_realloc(screen, (j+2)*sizeof(char *)); - screen[j++] = name; - screen[j] = NULL; + if (*name != '\0') { + if (screen_lookup_name(name) == NULL) { + /* an unknown screen name was specified in the + configuration file */ + print_error(_("Unknown screen name"), name); + free(name); + } else { + screen = g_realloc(screen, (j+2)*sizeof(char *)); + screen[j++] = name; + screen[j] = NULL; + } } i++; } @@ -321,34 +370,68 @@ check_screen_list(char *value) return screen; } +static int +get_search_mode(char *value) +{ + char * test; + const int mode = strtol(value, &test, 10); + if (*test == '\0') + { + if (0 <= mode && mode <= 4) + return mode; + else + { + print_error(_("Invalid search mode"),value); + return 0; + } + } + else + { + for (int i = 0; value[i] != '\0'; i++) + value[i] = tolower(value[i]); + + // TODO: modify screen_search so that its own list of modes can be used + // for comparison instead of specifying them here + if (strcmp(value, "title") == 0) + return 0; + else if (strcmp(value, "artist") == 0) + return 1; + else if (strcmp(value, "album") == 0) + return 2; + else if (strcmp(value, "filename") == 0) + return 3; + else if (strcmp(value, "artist+album") == 0) + return 4; + else + { + print_error(_("Unknown search mode"),value); + return 0; + } + } +} + static bool parse_line(char *line) { - size_t len = strlen(line), i = 0, j; - char name[MAX_LINE_LENGTH]; - char value[MAX_LINE_LENGTH]; - bool match_found; - /* get the name part */ - j = 0; - while (i < len && line[i] != '=' && - !g_ascii_isspace(line[i])) { - name[j++] = line[i++]; + char *const name = line; + char *const name_end = after_unquoted_word(line); + if (name_end == NULL) + return false; + + line = skip_spaces(name_end); + if (*line == '=') { + ++line; + line = skip_spaces(line); + } else if (line == name_end) { + print_error(_("Missing '='"), name_end); + return false; } - name[j] = '\0'; - - /* skip '=' and whitespace */ - while (i < len && (line[i] == '=' || g_ascii_isspace(line[i]))) - i++; + *name_end = 0; /* get the value part */ - j = 0; - while (i < len) - value[j++] = line[i++]; - value[j] = '\0'; - - match_found = true; + char *const value = line; /* key definition */ if (!strcasecmp(CONF_KEY_DEFINITION, name)) @@ -360,6 +443,8 @@ parse_line(char *line) #else {} #endif + else if (!strcasecmp(CONF_SCROLL_OFFSET, name)) + options.scroll_offset = atoi(value); /* auto center */ else if (!strcasecmp(CONF_AUTO_CENTER, name)) options.auto_center = str2bool(value); @@ -373,6 +458,8 @@ parse_line(char *line) /* wide cursor */ else if (!strcasecmp(CONF_WIDE_CURSOR, name)) options.wide_cursor = str2bool(value); + else if (strcasecmp(name, CONF_HARDWARE_CURSOR) == 0) + options.hardware_cursor = str2bool(value); /* welcome screen list */ else if (!strcasecmp(CONF_WELCOME_SCREEN_LIST, name)) options.welcome_screen_list = str2bool(value); @@ -380,11 +467,10 @@ parse_line(char *line) else if (!strcasecmp(CONF_VISIBLE_BITRATE, name)) options.visible_bitrate = str2bool(value); /* timer display type */ - else if (!strcasecmp(CONF_TIMEDISPLAY_TYPE, name)) { - g_free(options.timedisplay_type); - options.timedisplay_type=g_strdup(parse_timedisplay_type(value)); + else if (!strcasecmp(CONF_TIMEDISPLAY_TYPE, name)) + options.display_remaining_time = parse_timedisplay_type(value); /* color definition */ - } else if (!strcasecmp(CONF_COLOR_DEFINITION, name)) + else if (!strcasecmp(CONF_COLOR_DEFINITION, name)) #ifdef ENABLE_COLORS parse_color_definition(value); #else @@ -394,6 +480,10 @@ parse_line(char *line) else if (!strcasecmp(CONF_LIST_FORMAT, name)) { g_free(options.list_format); options.list_format = get_format(value); + /* search format string */ + } else if (!strcasecmp(CONF_SEARCH_FORMAT, name)) { + g_free(options.search_format); + options.search_format = get_format(value); /* status format string */ } else if (!strcasecmp(CONF_STATUS_FORMAT, name)) { g_free(options.status_format); @@ -414,6 +504,8 @@ parse_line(char *line) options.visible_bell = str2bool(value); else if (!strcasecmp(CONF_BELL_ON_WRAP, name)) options.bell_on_wrap = str2bool(value); + else if (!strcasecmp(CONF_STATUS_MESSAGE_TIME, name)) + options.status_message_time = atoi(value); else if (!strcasecmp(CONF_XTERM_TITLE, name)) options.enable_xterm_title = str2bool(value); else if (!strcasecmp(CONF_ENABLE_MOUSE, name)) @@ -425,7 +517,7 @@ parse_line(char *line) else if (!strcasecmp(CONF_CROSSFADE_TIME, name)) options.crossfade_time = atoi(value); else if (!strcasecmp(CONF_SEARCH_MODE, name)) - options.search_mode = atoi(value); + options.search_mode = get_search_mode(value); else if (!strcasecmp(CONF_HIDE_CURSOR, name)) options.hide_cursor = atoi(value); else if (!strcasecmp(CONF_SEEK_TIME, name)) @@ -433,14 +525,15 @@ parse_line(char *line) else if (!strcasecmp(CONF_SCREEN_LIST, name)) { g_strfreev(options.screen_list); options.screen_list = check_screen_list(value); - } else if (!strcasecmp(CONF_SHOW_SPLASH, name)) { - /* the splash screen was removed */ } else if (!strcasecmp(CONF_HOST, name)) options.host = get_format(value); else if (!strcasecmp(CONF_PORT, name)) options.port = atoi(get_format(value)); else if (!strcasecmp(CONF_PASSWORD, name)) options.password = get_format(value); + else if (!strcasecmp(CONF_TIMEOUT, name)) + options.timeout_ms = atoi(get_format(value)) + * 1000 /* seconds -> milliseconds */; else if (!strcasecmp(CONF_LYRICS_TIMEOUT, name)) #ifdef ENABLE_LYRICS_SCREEN options.lyrics_timeout = atoi(get_format(value)); @@ -453,38 +546,75 @@ parse_line(char *line) g_free(options.scroll_sep); options.scroll_sep = get_format(value); } else if (!strcasecmp(CONF_DISPLAY_TIME, name)) + /* obsolete, ignore */ + {} + else if (!strcasecmp(CONF_JUMP_PREFIX_ONLY, name)) #ifdef NCMPC_MINI {} #else - options.display_time = str2bool(value); + options.jump_prefix_only = str2bool(value); #endif - else - match_found = false; - - if (!match_found) - print_error(_("Unknown configuration parameter"), - name); + else if (!strcasecmp(CONF_LYRICS_AUTOSAVE, name)) +#ifdef ENABLE_LYRICS_SCREEN + options.lyrics_autosave = str2bool(value); +#else + {} +#endif + else if (!strcasecmp(CONF_LYRICS_SHOW_PLUGIN, name)) +#ifdef ENABLE_LYRICS_SCREEN + options.lyrics_show_plugin = str2bool(value); +#else + {} +#endif + else if (!strcasecmp(name, CONF_TEXT_EDITOR)) +#ifdef ENABLE_LYRICS_SCREEN + { + g_free(options.text_editor); + options.text_editor = get_format(value); + } +#else + {} +#endif + else if (!strcasecmp(name, CONF_TEXT_EDITOR_ASK)) +#ifdef ENABLE_LYRICS_SCREEN + options.text_editor_ask = str2bool(value); +#else + {} +#endif + else if (!strcasecmp(name, CONF_CHAT_PREFIX)) +#ifdef ENABLE_CHAT_SCREEN + options.chat_prefix = get_format(value); +#else + {} +#endif + else if (!strcasecmp(CONF_SECOND_COLUMN, name)) +#ifdef NCMPC_MINI + {} +#else + options.second_column = str2bool(value); +#endif + else { + print_error(_("Unknown configuration parameter"), name); + return false; + } - return match_found; + return true; } static int read_rc_file(char *filename) { - FILE *file; - char line[MAX_LINE_LENGTH]; + assert(filename != NULL); - if (filename == NULL) - return -1; - - file = fopen(filename, "r"); + FILE *file = fopen(filename, "r"); if (file == NULL) { - perror(filename); - return -1; - } + perror(filename); + return -1; + } + char line[MAX_LINE_LENGTH]; while (fgets(line, sizeof(line), file) != NULL) { - char *p = g_strchug(line); + char *p = skip_spaces(line); if (*p != 0 && *p != COMMENT_TOKEN) parse_line(g_strchomp(p)); @@ -494,91 +624,153 @@ read_rc_file(char *filename) return 0; } -int +bool check_user_conf_dir(void) { - int retval; char *directory = g_build_filename(g_get_home_dir(), "." PACKAGE, NULL); if (g_file_test(directory, G_FILE_TEST_IS_DIR)) { g_free(directory); - return 0; + return true; } - retval = mkdir(directory, 0755); + bool success = g_mkdir(directory, 0755) == 0; g_free(directory); - return retval; + return success; +} + +char * +build_user_conf_filename(void) +{ +#ifdef WIN32 + return g_build_filename(g_get_user_config_dir(), PACKAGE, "ncmpc.conf", NULL); +#else + return g_build_filename(g_get_home_dir(), "." PACKAGE, "config", NULL); +#endif +} + +char * +build_system_conf_filename(void) +{ +#ifdef WIN32 + const gchar* const *system_data_dirs; + gchar *pathname = NULL; + + for (system_data_dirs = g_get_system_config_dirs (); *system_data_dirs != NULL; system_data_dirs++) + { + pathname = g_build_filename(*system_data_dirs, PACKAGE, "ncmpc.conf", NULL); + if (g_file_test(pathname, G_FILE_TEST_EXISTS)) + { + break; + } + else + { + g_free (pathname); + pathname = NULL; + } + } + return pathname; +#else + return g_build_filename(SYSCONFDIR, PACKAGE, "config", NULL); +#endif } char * -get_user_key_binding_filename(void) +build_user_key_binding_filename(void) { +#ifdef WIN32 + return g_build_filename(g_get_user_config_dir(), PACKAGE, "keys.conf", NULL); +#else return g_build_filename(g_get_home_dir(), "." PACKAGE, "keys", NULL); +#endif } -int -read_configuration(void) +static char * +g_build_system_key_binding_filename(void) { - char *filename = NULL; +#ifdef WIN32 + const gchar* const *system_data_dirs; + gchar *pathname = NULL; + + for (system_data_dirs = g_get_system_config_dirs (); *system_data_dirs != NULL; system_data_dirs++) + { + pathname = g_build_filename(*system_data_dirs, PACKAGE, "keys.conf", NULL); + if (g_file_test(pathname, G_FILE_TEST_EXISTS)) + { + break; + } + else + { + g_free (pathname); + pathname = NULL; + } + } + return pathname; +#else + return g_build_filename(SYSCONFDIR, PACKAGE, "keys", NULL); +#endif +} +static char * +find_config_file(void) +{ /* check for command line configuration file */ - if (options.config_file) - filename = g_strdup(options.config_file); + if (options.config_file != NULL) + return g_strdup(options.config_file); /* check for user configuration ~/.ncmpc/config */ - if (filename == NULL) { - filename = g_build_filename(g_get_home_dir(), - "." PACKAGE, "config", NULL); - if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { - g_free(filename); - filename = NULL; - } - } + char *filename = build_user_conf_filename(); + if (g_file_test(filename, G_FILE_TEST_IS_REGULAR)) + return filename; + + g_free(filename); /* check for global configuration SYSCONFDIR/ncmpc/config */ - if (filename == NULL) { - filename = g_build_filename(SYSCONFDIR, PACKAGE, "config", NULL); - if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { - g_free(filename); - filename = NULL; - } - } + filename = build_system_conf_filename(); + if (g_file_test(filename, G_FILE_TEST_IS_REGULAR)) + return filename; - /* load configuration */ - if (filename) { - read_rc_file(filename); - g_free(filename); - filename = NULL; - } + g_free(filename); + return NULL; +} +static char * +find_keys_file(void) +{ /* check for command line key binding file */ - if (options.key_file) - filename = g_strdup(options.key_file); + if (options.key_file != NULL) + return g_strdup(options.key_file); /* check for user key bindings ~/.ncmpc/keys */ - if (filename == NULL) { - filename = get_user_key_binding_filename(); - if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { - g_free(filename); - filename = NULL; - } - } + char *filename = build_user_key_binding_filename(); + if (g_file_test(filename, G_FILE_TEST_IS_REGULAR)) + return filename; + + g_free(filename); /* check for global key bindings SYSCONFDIR/ncmpc/keys */ - if (filename == NULL) { - filename = g_build_filename(SYSCONFDIR, PACKAGE, "keys", NULL); - if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { - g_free(filename); - filename = NULL; - } + filename = g_build_system_key_binding_filename(); + if (g_file_test(filename, G_FILE_TEST_IS_REGULAR)) + return filename; + + g_free(filename); + return NULL; +} + +void +read_configuration(void) +{ + /* load configuration */ + char *filename = find_config_file(); + if (filename != NULL) { + read_rc_file(filename); + g_free(filename); } /* load key bindings */ - if (filename) { + filename = find_keys_file(); + if (filename != NULL) { read_rc_file(filename); g_free(filename); - filename = NULL; } - - return 0; }