1 /* ncmpc (Ncurses MPD Client)
2 * (c) 2004-2010 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_SCROLL "scroll"
73 #define CONF_SCROLL_SEP "scroll-sep"
74 #define CONF_VISIBLE_BITRATE "visible-bitrate"
75 #define CONF_WELCOME_SCREEN_LIST "welcome-screen-list"
76 #define CONF_DISPLAY_TIME "display-time"
77 #define CONF_JUMP_PREFIX_ONLY "jump-prefix-only"
78 #define CONF_LYRICS_AUTOSAVE "lyrics-autosave"
79 #define CONF_SECOND_COLUMN "second-column"
84 return strcasecmp(str
, "yes") == 0 || strcasecmp(str
, "true") == 0 ||
85 strcasecmp(str
, "on") == 0 || strcasecmp(str
, "1") == 0;
89 print_error(const char *msg
, const char *input
)
91 fprintf(stderr
, "%s: %s ('%s')\n",
92 /* To translators: prefix for error messages */
93 _("Error"), msg
, input
);
97 parse_key_value(char *str
, char **end
)
100 if (str
[1] == '\'' || str
[2] != '\'') {
101 print_error(_("Malformed hotkey definition"), str
);
108 long value
= strtol(str
, end
, 0);
110 print_error(_("Malformed hotkey definition"), str
);
119 parse_key_definition(char *str
)
121 char buf
[MAX_LINE_LENGTH
];
123 size_t len
= strlen(str
), i
;
125 int keys
[MAX_COMMAND_KEYS
];
128 /* get the command name */
131 memset(buf
, 0, MAX_LINE_LENGTH
);
132 while (i
< len
&& str
[i
] != '=' && !g_ascii_isspace(str
[i
]))
134 if( (cmd
=get_key_command_from_name(buf
)) == CMD_NONE
) {
135 /* the hotkey configuration contains an unknown
137 print_error(_("Unknown command"), buf
);
141 /* skip whitespace */
142 while (i
< len
&& (str
[i
] == '=' || g_ascii_isspace(str
[i
])))
145 /* get the value part */
146 memset(buf
, 0, MAX_LINE_LENGTH
);
147 g_strlcpy(buf
, str
+i
, MAX_LINE_LENGTH
);
149 /* the hotkey configuration line is incomplete */
150 print_error(_("Incomplete hotkey configuration"), str
);
154 /* parse key values */
158 memset(keys
, 0, sizeof(int)*MAX_COMMAND_KEYS
);
159 while (i
< MAX_COMMAND_KEYS
&& *p
!= 0 &&
160 (key
= parse_key_value(p
, &p
)) >= 0) {
162 while (*p
==',' || *p
==' ' || *p
=='\t')
169 return assign_keys(cmd
, keys
);
173 parse_timedisplay_type(const char *str
)
175 if (strcmp(str
, "elapsed") == 0)
177 else if (strcmp(str
, "remaining") == 0)
180 /* translators: ncmpc supports displaying the
181 "elapsed" or "remaining" time of a song being
182 played; in this case, the configuration file
183 contained an invalid setting */
184 print_error(_("Bad time display type"), str
);
191 separate_value(char *p
)
195 value
= strchr(p
, '=');
197 /* an equals sign '=' was expected while parsing a
198 configuration file line */
199 fprintf(stderr
, "%s\n", _("Missing '='"));
206 return g_strchug(value
);
210 parse_color(char *str
)
214 value
= separate_value(str
);
218 return colors_assign(str
, value
);
222 * Returns the first non-whitespace character after the next comma
223 * character, or the end of the string. This is used to parse comma
229 char *comma
= strchr(p
, ',');
233 comma
= g_strchug(comma
);
235 comma
= p
+ strlen(p
);
242 parse_color_definition(char *str
)
244 char buf
[MAX_LINE_LENGTH
];
248 value
= separate_value(str
);
252 /* get the command name */
253 color
= colors_str2color(str
);
255 print_error(_("Bad color name"), buf
);
259 /* parse r,g,b values */
261 for (unsigned i
= 0; i
< 3; ++i
) {
262 char *next
= after_comma(value
), *endptr
;
264 print_error(_("Incomplete color definition"), str
);
268 rgb
[i
] = strtol(value
, &endptr
, 0);
269 if (endptr
== value
|| *endptr
!= 0) {
270 print_error(_("Invalid number"), value
);
278 print_error(_("Malformed color definition"), str
);
282 return colors_define(str
, rgb
[0], rgb
[1], rgb
[2]);
287 get_format(char *str
)
289 gsize len
= strlen(str
);
291 if (str
&& str
[0]=='\"' && str
[len
-1] == '\"') {
296 return g_strdup(str
);
300 check_screen_list(char *value
)
302 char **tmp
= g_strsplit_set(value
, " \t,", 100);
303 char **screen
= NULL
;
306 while( tmp
&& tmp
[i
] ) {
307 char *name
= g_ascii_strdown(tmp
[i
], -1);
309 if (screen_lookup_name(name
) == NULL
) {
310 /* an unknown screen name was specified in the
311 configuration file */
312 print_error(_("Unknown screen name"), name
);
315 screen
= g_realloc(screen
, (j
+2)*sizeof(char *));
324 return g_strsplit_set(DEFAULT_SCREEN_LIST
, " ", 0);
330 get_search_mode(char *value
)
334 mode
= strtol(value
, &test
, 10);
337 if (0 <= mode
&& mode
<= 4)
341 print_error(_("Invalid search mode"),value
);
347 for (int i
= 0; value
[i
] != '\0'; i
++)
348 value
[i
] = tolower(value
[i
]);
350 // TODO: modify screen_search so that its own list of modes can be used
351 // for comparison instead of specifying them here
352 if (strcmp(value
, "title") == 0)
354 else if (strcmp(value
, "artist") == 0)
356 else if (strcmp(value
, "album") == 0)
358 else if (strcmp(value
, "filename") == 0)
360 else if (strcmp(value
, "artist+album") == 0)
364 print_error(_("Unknown search mode"),value
);
371 parse_line(char *line
)
373 size_t len
= strlen(line
), i
= 0, j
= 0;
374 char name
[MAX_LINE_LENGTH
];
375 char value
[MAX_LINE_LENGTH
];
378 /* get the name part */
379 while (i
< len
&& line
[i
] != '=' &&
380 !g_ascii_isspace(line
[i
])) {
381 name
[j
++] = line
[i
++];
386 /* skip '=' and whitespace */
387 while (i
< len
&& (line
[i
] == '=' || g_ascii_isspace(line
[i
])))
390 /* get the value part */
393 value
[j
++] = line
[i
++];
399 if (!strcasecmp(CONF_KEY_DEFINITION
, name
))
400 parse_key_definition(value
);
402 else if(!strcasecmp(CONF_ENABLE_COLORS
, name
))
404 options
.enable_colors
= str2bool(value
);
408 else if (!strcasecmp(CONF_SCROLL_OFFSET
, name
))
409 options
.scroll_offset
= atoi(value
);
411 else if (!strcasecmp(CONF_AUTO_CENTER
, name
))
412 options
.auto_center
= str2bool(value
);
413 /* color assignment */
414 else if (!strcasecmp(CONF_COLOR
, name
))
421 else if (!strcasecmp(CONF_WIDE_CURSOR
, name
))
422 options
.wide_cursor
= str2bool(value
);
423 else if (strcasecmp(name
, "hardware-cursor") == 0)
424 options
.hardware_cursor
= str2bool(value
);
425 /* welcome screen list */
426 else if (!strcasecmp(CONF_WELCOME_SCREEN_LIST
, name
))
427 options
.welcome_screen_list
= str2bool(value
);
428 /* visible bitrate */
429 else if (!strcasecmp(CONF_VISIBLE_BITRATE
, name
))
430 options
.visible_bitrate
= str2bool(value
);
431 /* timer display type */
432 else if (!strcasecmp(CONF_TIMEDISPLAY_TYPE
, name
))
433 options
.display_remaining_time
= parse_timedisplay_type(value
);
434 /* color definition */
435 else if (!strcasecmp(CONF_COLOR_DEFINITION
, name
))
437 parse_color_definition(value
);
441 /* list format string */
442 else if (!strcasecmp(CONF_LIST_FORMAT
, name
)) {
443 g_free(options
.list_format
);
444 options
.list_format
= get_format(value
);
445 /* status format string */
446 } else if (!strcasecmp(CONF_STATUS_FORMAT
, name
)) {
447 g_free(options
.status_format
);
448 options
.status_format
= get_format(value
);
449 /* xterm title format string */
450 } else if (!strcasecmp(CONF_XTERM_TITLE_FORMAT
, name
)) {
451 g_free(options
.xterm_title_format
);
452 options
.xterm_title_format
= get_format(value
);
453 } else if (!strcasecmp(CONF_LIST_WRAP
, name
))
454 options
.list_wrap
= str2bool(value
);
455 else if (!strcasecmp(CONF_FIND_WRAP
, name
))
456 options
.find_wrap
= str2bool(value
);
457 else if (!strcasecmp(CONF_FIND_SHOW_LAST
,name
))
458 options
.find_show_last_pattern
= str2bool(value
);
459 else if (!strcasecmp(CONF_AUDIBLE_BELL
, name
))
460 options
.audible_bell
= str2bool(value
);
461 else if (!strcasecmp(CONF_VISIBLE_BELL
, name
))
462 options
.visible_bell
= str2bool(value
);
463 else if (!strcasecmp(CONF_BELL_ON_WRAP
, name
))
464 options
.bell_on_wrap
= str2bool(value
);
465 else if (!strcasecmp(CONF_STATUS_MESSAGE_TIME
, name
))
466 options
.status_message_time
= atoi(value
);
467 else if (!strcasecmp(CONF_XTERM_TITLE
, name
))
468 options
.enable_xterm_title
= str2bool(value
);
469 else if (!strcasecmp(CONF_ENABLE_MOUSE
, name
))
471 options
.enable_mouse
= str2bool(value
);
475 else if (!strcasecmp(CONF_CROSSFADE_TIME
, name
))
476 options
.crossfade_time
= atoi(value
);
477 else if (!strcasecmp(CONF_SEARCH_MODE
, name
))
478 options
.search_mode
= get_search_mode(value
);
479 else if (!strcasecmp(CONF_HIDE_CURSOR
, name
))
480 options
.hide_cursor
= atoi(value
);
481 else if (!strcasecmp(CONF_SEEK_TIME
, name
))
482 options
.seek_time
= atoi(value
);
483 else if (!strcasecmp(CONF_SCREEN_LIST
, name
)) {
484 g_strfreev(options
.screen_list
);
485 options
.screen_list
= check_screen_list(value
);
486 } else if (!strcasecmp(CONF_HOST
, name
))
487 options
.host
= get_format(value
);
488 else if (!strcasecmp(CONF_PORT
, name
))
489 options
.port
= atoi(get_format(value
));
490 else if (!strcasecmp(CONF_PASSWORD
, name
))
491 options
.password
= get_format(value
);
492 else if (!strcasecmp(CONF_LYRICS_TIMEOUT
, name
))
493 #ifdef ENABLE_LYRICS_SCREEN
494 options
.lyrics_timeout
= atoi(get_format(value
));
498 else if (!strcasecmp(CONF_SCROLL
, name
))
499 options
.scroll
= str2bool(value
);
500 else if (!strcasecmp(CONF_SCROLL_SEP
, name
)) {
501 g_free(options
.scroll_sep
);
502 options
.scroll_sep
= get_format(value
);
503 } else if (!strcasecmp(CONF_DISPLAY_TIME
, name
))
507 options
.display_time
= str2bool(value
);
509 else if (!strcasecmp(CONF_JUMP_PREFIX_ONLY
, name
))
513 options
.jump_prefix_only
= str2bool(value
);
515 else if (!strcasecmp(CONF_LYRICS_AUTOSAVE
, name
))
516 #ifdef ENABLE_LYRICS_SCREEN
517 options
.lyrics_autosave
= str2bool(value
);
521 else if (!strcasecmp(CONF_SECOND_COLUMN
, name
))
525 options
.second_column
= str2bool(value
);
531 print_error(_("Unknown configuration parameter"),
538 read_rc_file(char *filename
)
541 char line
[MAX_LINE_LENGTH
];
543 if (filename
== NULL
)
546 file
= fopen(filename
, "r");
552 while (fgets(line
, sizeof(line
), file
) != NULL
) {
553 char *p
= g_strchug(line
);
555 if (*p
!= 0 && *p
!= COMMENT_TOKEN
)
556 parse_line(g_strchomp(p
));
564 check_user_conf_dir(void)
567 char *directory
= g_build_filename(g_get_home_dir(), "." PACKAGE
, NULL
);
569 if (g_file_test(directory
, G_FILE_TEST_IS_DIR
)) {
574 retval
= mkdir(directory
, 0755);
580 get_user_key_binding_filename(void)
582 return g_build_filename(g_get_home_dir(), "." PACKAGE
, "keys", NULL
);
586 read_configuration(void)
588 char *filename
= NULL
;
590 /* check for command line configuration file */
591 if (options
.config_file
)
592 filename
= g_strdup(options
.config_file
);
594 /* check for user configuration ~/.ncmpc/config */
595 if (filename
== NULL
) {
596 filename
= g_build_filename(g_get_home_dir(),
597 "." PACKAGE
, "config", NULL
);
598 if (!g_file_test(filename
, G_FILE_TEST_IS_REGULAR
)) {
604 /* check for global configuration SYSCONFDIR/ncmpc/config */
605 if (filename
== NULL
) {
606 filename
= g_build_filename(SYSCONFDIR
, PACKAGE
, "config", NULL
);
607 if (!g_file_test(filename
, G_FILE_TEST_IS_REGULAR
)) {
613 /* load configuration */
615 read_rc_file(filename
);
620 /* check for command line key binding file */
621 if (options
.key_file
)
622 filename
= g_strdup(options
.key_file
);
624 /* check for user key bindings ~/.ncmpc/keys */
625 if (filename
== NULL
) {
626 filename
= get_user_key_binding_filename();
627 if (!g_file_test(filename
, G_FILE_TEST_IS_REGULAR
)) {
633 /* check for global key bindings SYSCONFDIR/ncmpc/keys */
634 if (filename
== NULL
) {
635 filename
= g_build_filename(SYSCONFDIR
, PACKAGE
, "keys", NULL
);
636 if (!g_file_test(filename
, G_FILE_TEST_IS_REGULAR
)) {
642 /* load key bindings */
644 read_rc_file(filename
);