1 /* ncmpc (Ncurses MPD Client)
2 * (c) 2004-2009 The Music Player Daemon Project
3 * Project homepage: http://musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "screen_list.h"
34 #include <sys/types.h>
39 #define MAX_LINE_LENGTH 1024
40 #define COMMENT_TOKEN '#'
42 /* configuration field names */
43 #define CONF_ENABLE_COLORS "enable-colors"
44 #define CONF_SCROLL_OFFSET "scroll-offset"
45 #define CONF_AUTO_CENTER "auto-center"
46 #define CONF_WIDE_CURSOR "wide-cursor"
47 #define CONF_KEY_DEFINITION "key"
48 #define CONF_COLOR "color"
49 #define CONF_COLOR_DEFINITION "colordef"
50 #define CONF_LIST_FORMAT "list-format"
51 #define CONF_STATUS_FORMAT "status-format"
52 #define CONF_XTERM_TITLE_FORMAT "xterm-title-format"
53 #define CONF_LIST_WRAP "wrap-around"
54 #define CONF_FIND_WRAP "find-wrap"
55 #define CONF_FIND_SHOW_LAST "find-show-last"
56 #define CONF_AUDIBLE_BELL "audible-bell"
57 #define CONF_VISIBLE_BELL "visible-bell"
58 #define CONF_BELL_ON_WRAP "bell-on-wrap"
59 #define CONF_STATUS_MESSAGE_TIME "status-message-time"
60 #define CONF_XTERM_TITLE "set-xterm-title"
61 #define CONF_ENABLE_MOUSE "enable-mouse"
62 #define CONF_CROSSFADE_TIME "crossfade-time"
63 #define CONF_SEARCH_MODE "search-mode"
64 #define CONF_HIDE_CURSOR "hide-cursor"
65 #define CONF_SEEK_TIME "seek-time"
66 #define CONF_SCREEN_LIST "screen-list"
67 #define CONF_TIMEDISPLAY_TYPE "timedisplay-type"
68 #define CONF_HOST "host"
69 #define CONF_PORT "port"
70 #define CONF_PASSWORD "password"
71 #define CONF_LYRICS_TIMEOUT "lyrics-timeout"
72 #define CONF_SHOW_SPLASH "show-splash"
73 #define CONF_SCROLL "scroll"
74 #define CONF_SCROLL_SEP "scroll-sep"
75 #define CONF_VISIBLE_BITRATE "visible-bitrate"
76 #define CONF_WELCOME_SCREEN_LIST "welcome-screen-list"
77 #define CONF_DISPLAY_TIME "display-time"
78 #define CONF_JUMP_PREFIX_ONLY "jump-prefix-only"
79 #define CONF_LYRICS_AUTOSAVE "lyrics-autosave"
80 #define CONF_SECOND_COLUMN "second-column"
85 return strcasecmp(str
, "yes") == 0 || strcasecmp(str
, "true") == 0 ||
86 strcasecmp(str
, "on") == 0 || strcasecmp(str
, "1") == 0;
90 print_error(const char *msg
, const char *input
)
92 fprintf(stderr
, "%s: %s ('%s')\n",
93 /* To translators: prefix for error messages */
94 _("Error"), msg
, input
);
98 parse_key_value(char *str
, char **end
)
101 if (str
[1] == '\'' || str
[2] != '\'') {
102 print_error(_("Malformed hotkey definition"), str
);
109 long value
= strtol(str
, end
, 0);
111 print_error(_("Malformed hotkey definition"), str
);
120 parse_key_definition(char *str
)
122 char buf
[MAX_LINE_LENGTH
];
124 size_t len
= strlen(str
), i
;
126 int keys
[MAX_COMMAND_KEYS
];
129 /* get the command name */
132 memset(buf
, 0, MAX_LINE_LENGTH
);
133 while (i
< len
&& str
[i
] != '=' && !g_ascii_isspace(str
[i
]))
135 if( (cmd
=get_key_command_from_name(buf
)) == CMD_NONE
) {
136 /* the hotkey configuration contains an unknown
138 print_error(_("Unknown command"), buf
);
142 /* skip whitespace */
143 while (i
< len
&& (str
[i
] == '=' || g_ascii_isspace(str
[i
])))
146 /* get the value part */
147 memset(buf
, 0, MAX_LINE_LENGTH
);
148 g_strlcpy(buf
, str
+i
, MAX_LINE_LENGTH
);
150 /* the hotkey configuration line is incomplete */
151 print_error(_("Incomplete hotkey configuration"), str
);
155 /* parse key values */
159 memset(keys
, 0, sizeof(int)*MAX_COMMAND_KEYS
);
160 while (i
< MAX_COMMAND_KEYS
&& *p
!= 0 &&
161 (key
= parse_key_value(p
, &p
)) >= 0) {
163 while (*p
==',' || *p
==' ' || *p
=='\t')
170 return assign_keys(cmd
, keys
);
174 parse_timedisplay_type(const char *str
)
176 if (strcmp(str
, "elapsed") == 0)
178 else if (strcmp(str
, "remaining") == 0)
181 /* translators: ncmpc supports displaying the
182 "elapsed" or "remaining" time of a song being
183 played; in this case, the configuration file
184 contained an invalid setting */
185 print_error(_("Bad time display type"), str
);
192 separate_value(char *p
)
196 value
= strchr(p
, '=');
198 /* an equals sign '=' was expected while parsing a
199 configuration file line */
200 fprintf(stderr
, "%s\n", _("Missing '='"));
207 return g_strchug(value
);
211 parse_color(char *str
)
215 value
= separate_value(str
);
219 return colors_assign(str
, value
);
223 * Returns the first non-whitespace character after the next comma
224 * character, or the end of the string. This is used to parse comma
230 char *comma
= strchr(p
, ',');
234 comma
= g_strchug(comma
);
236 comma
= p
+ strlen(p
);
243 parse_color_definition(char *str
)
245 char buf
[MAX_LINE_LENGTH
];
249 value
= separate_value(str
);
253 /* get the command name */
254 color
= colors_str2color(str
);
256 print_error(_("Bad color name"), buf
);
260 /* parse r,g,b values */
262 for (unsigned i
= 0; i
< 3; ++i
) {
263 char *next
= after_comma(value
), *endptr
;
265 print_error(_("Incomplete color definition"), str
);
269 rgb
[i
] = strtol(value
, &endptr
, 0);
270 if (endptr
== value
|| *endptr
!= 0) {
271 print_error(_("Invalid number"), value
);
279 print_error(_("Malformed color definition"), str
);
283 return colors_define(str
, rgb
[0], rgb
[1], rgb
[2]);
288 get_format(char *str
)
290 gsize len
= strlen(str
);
292 if (str
&& str
[0]=='\"' && str
[len
-1] == '\"') {
297 return g_strdup(str
);
301 check_screen_list(char *value
)
303 char **tmp
= g_strsplit_set(value
, " \t,", 100);
304 char **screen
= NULL
;
307 while( tmp
&& tmp
[i
] ) {
308 char *name
= g_ascii_strdown(tmp
[i
], -1);
310 if (screen_lookup_name(name
) == NULL
) {
311 /* an unknown screen name was specified in the
312 configuration file */
313 print_error(_("Unknown screen name"), name
);
316 screen
= g_realloc(screen
, (j
+2)*sizeof(char *));
325 return g_strsplit_set(DEFAULT_SCREEN_LIST
, " ", 0);
331 get_search_mode(char *value
)
335 mode
= strtol(value
, &test
, 10);
338 if (0 <= mode
&& mode
<= 4)
342 print_error(_("Invalid search mode"),value
);
348 for (int i
= 0; value
[i
] != '\0'; i
++)
349 value
[i
] = tolower(value
[i
]);
351 // TODO: modify screen_search so that its own list of modes can be used
352 // for comparison instead of specifying them here
353 if (strcmp(value
, "title") == 0)
355 else if (strcmp(value
, "artist") == 0)
357 else if (strcmp(value
, "album") == 0)
359 else if (strcmp(value
, "filename") == 0)
361 else if (strcmp(value
, "artist+album") == 0)
365 print_error(_("Unknown search mode"),value
);
372 parse_line(char *line
)
374 size_t len
= strlen(line
), i
= 0, j
= 0;
375 char name
[MAX_LINE_LENGTH
];
376 char value
[MAX_LINE_LENGTH
];
379 /* get the name part */
380 while (i
< len
&& line
[i
] != '=' &&
381 !g_ascii_isspace(line
[i
])) {
382 name
[j
++] = line
[i
++];
387 /* skip '=' and whitespace */
388 while (i
< len
&& (line
[i
] == '=' || g_ascii_isspace(line
[i
])))
391 /* get the value part */
394 value
[j
++] = line
[i
++];
400 if (!strcasecmp(CONF_KEY_DEFINITION
, name
))
401 parse_key_definition(value
);
403 else if(!strcasecmp(CONF_ENABLE_COLORS
, name
))
405 options
.enable_colors
= str2bool(value
);
409 else if (!strcasecmp(CONF_SCROLL_OFFSET
, name
))
410 options
.scroll_offset
= atoi(value
);
412 else if (!strcasecmp(CONF_AUTO_CENTER
, name
))
413 options
.auto_center
= str2bool(value
);
414 /* color assignment */
415 else if (!strcasecmp(CONF_COLOR
, name
))
422 else if (!strcasecmp(CONF_WIDE_CURSOR
, name
))
423 options
.wide_cursor
= str2bool(value
);
424 else if (strcasecmp(name
, "hardware-cursor") == 0)
425 options
.hardware_cursor
= str2bool(value
);
426 /* welcome screen list */
427 else if (!strcasecmp(CONF_WELCOME_SCREEN_LIST
, name
))
428 options
.welcome_screen_list
= str2bool(value
);
429 /* visible bitrate */
430 else if (!strcasecmp(CONF_VISIBLE_BITRATE
, name
))
431 options
.visible_bitrate
= str2bool(value
);
432 /* timer display type */
433 else if (!strcasecmp(CONF_TIMEDISPLAY_TYPE
, name
))
434 options
.display_remaining_time
= parse_timedisplay_type(value
);
435 /* color definition */
436 else if (!strcasecmp(CONF_COLOR_DEFINITION
, name
))
438 parse_color_definition(value
);
442 /* list format string */
443 else if (!strcasecmp(CONF_LIST_FORMAT
, name
)) {
444 g_free(options
.list_format
);
445 options
.list_format
= get_format(value
);
446 /* status format string */
447 } else if (!strcasecmp(CONF_STATUS_FORMAT
, name
)) {
448 g_free(options
.status_format
);
449 options
.status_format
= get_format(value
);
450 /* xterm title format string */
451 } else if (!strcasecmp(CONF_XTERM_TITLE_FORMAT
, name
)) {
452 g_free(options
.xterm_title_format
);
453 options
.xterm_title_format
= get_format(value
);
454 } else if (!strcasecmp(CONF_LIST_WRAP
, name
))
455 options
.list_wrap
= str2bool(value
);
456 else if (!strcasecmp(CONF_FIND_WRAP
, name
))
457 options
.find_wrap
= str2bool(value
);
458 else if (!strcasecmp(CONF_FIND_SHOW_LAST
,name
))
459 options
.find_show_last_pattern
= str2bool(value
);
460 else if (!strcasecmp(CONF_AUDIBLE_BELL
, name
))
461 options
.audible_bell
= str2bool(value
);
462 else if (!strcasecmp(CONF_VISIBLE_BELL
, name
))
463 options
.visible_bell
= str2bool(value
);
464 else if (!strcasecmp(CONF_BELL_ON_WRAP
, name
))
465 options
.bell_on_wrap
= str2bool(value
);
466 else if (!strcasecmp(CONF_STATUS_MESSAGE_TIME
, name
))
467 options
.status_message_time
= atoi(value
);
468 else if (!strcasecmp(CONF_XTERM_TITLE
, name
))
469 options
.enable_xterm_title
= str2bool(value
);
470 else if (!strcasecmp(CONF_ENABLE_MOUSE
, name
))
472 options
.enable_mouse
= str2bool(value
);
476 else if (!strcasecmp(CONF_CROSSFADE_TIME
, name
))
477 options
.crossfade_time
= atoi(value
);
478 else if (!strcasecmp(CONF_SEARCH_MODE
, name
))
479 options
.search_mode
= get_search_mode(value
);
480 else if (!strcasecmp(CONF_HIDE_CURSOR
, name
))
481 options
.hide_cursor
= atoi(value
);
482 else if (!strcasecmp(CONF_SEEK_TIME
, name
))
483 options
.seek_time
= atoi(value
);
484 else if (!strcasecmp(CONF_SCREEN_LIST
, name
)) {
485 g_strfreev(options
.screen_list
);
486 options
.screen_list
= check_screen_list(value
);
487 } else if (!strcasecmp(CONF_SHOW_SPLASH
, name
)) {
488 /* the splash screen was removed */
489 } else if (!strcasecmp(CONF_HOST
, name
))
490 options
.host
= get_format(value
);
491 else if (!strcasecmp(CONF_PORT
, name
))
492 options
.port
= atoi(get_format(value
));
493 else if (!strcasecmp(CONF_PASSWORD
, name
))
494 options
.password
= get_format(value
);
495 else if (!strcasecmp(CONF_LYRICS_TIMEOUT
, name
))
496 #ifdef ENABLE_LYRICS_SCREEN
497 options
.lyrics_timeout
= atoi(get_format(value
));
501 else if (!strcasecmp(CONF_SCROLL
, name
))
502 options
.scroll
= str2bool(value
);
503 else if (!strcasecmp(CONF_SCROLL_SEP
, name
)) {
504 g_free(options
.scroll_sep
);
505 options
.scroll_sep
= get_format(value
);
506 } else if (!strcasecmp(CONF_DISPLAY_TIME
, name
))
510 options
.display_time
= str2bool(value
);
512 else if (!strcasecmp(CONF_JUMP_PREFIX_ONLY
, name
))
516 options
.jump_prefix_only
= str2bool(value
);
518 else if (!strcasecmp(CONF_LYRICS_AUTOSAVE
, name
))
519 #ifdef ENABLE_LYRICS_SCREEN
520 options
.lyrics_autosave
= str2bool(value
);
524 else if (!strcasecmp(CONF_SECOND_COLUMN
, name
))
528 options
.second_column
= str2bool(value
);
534 print_error(_("Unknown configuration parameter"),
541 read_rc_file(char *filename
)
544 char line
[MAX_LINE_LENGTH
];
546 if (filename
== NULL
)
549 file
= fopen(filename
, "r");
555 while (fgets(line
, sizeof(line
), file
) != NULL
) {
556 char *p
= g_strchug(line
);
558 if (*p
!= 0 && *p
!= COMMENT_TOKEN
)
559 parse_line(g_strchomp(p
));
567 check_user_conf_dir(void)
570 char *directory
= g_build_filename(g_get_home_dir(), "." PACKAGE
, NULL
);
572 if (g_file_test(directory
, G_FILE_TEST_IS_DIR
)) {
577 retval
= mkdir(directory
, 0755);
583 get_user_key_binding_filename(void)
585 return g_build_filename(g_get_home_dir(), "." PACKAGE
, "keys", NULL
);
589 read_configuration(void)
591 char *filename
= NULL
;
593 /* check for command line configuration file */
594 if (options
.config_file
)
595 filename
= g_strdup(options
.config_file
);
597 /* check for user configuration ~/.ncmpc/config */
598 if (filename
== NULL
) {
599 filename
= g_build_filename(g_get_home_dir(),
600 "." PACKAGE
, "config", NULL
);
601 if (!g_file_test(filename
, G_FILE_TEST_IS_REGULAR
)) {
607 /* check for global configuration SYSCONFDIR/ncmpc/config */
608 if (filename
== NULL
) {
609 filename
= g_build_filename(SYSCONFDIR
, PACKAGE
, "config", NULL
);
610 if (!g_file_test(filename
, G_FILE_TEST_IS_REGULAR
)) {
616 /* load configuration */
618 read_rc_file(filename
);
623 /* check for command line key binding file */
624 if (options
.key_file
)
625 filename
= g_strdup(options
.key_file
);
627 /* check for user key bindings ~/.ncmpc/keys */
628 if (filename
== NULL
) {
629 filename
= get_user_key_binding_filename();
630 if (!g_file_test(filename
, G_FILE_TEST_IS_REGULAR
)) {
636 /* check for global key bindings SYSCONFDIR/ncmpc/keys */
637 if (filename
== NULL
) {
638 filename
= g_build_filename(SYSCONFDIR
, PACKAGE
, "keys", NULL
);
639 if (!g_file_test(filename
, G_FILE_TEST_IS_REGULAR
)) {
645 /* load key bindings */
647 read_rc_file(filename
);