2 * Copyright 2006 Timo Hirvonen
11 #include "ui_curses.h"
12 #include "format_print.h"
20 #include "command_mode.h"
24 #include "config/datadir.h"
30 /* initialized option variables */
32 char *output_plugin
= NULL
;
33 char *status_display_program
= NULL
;
34 int auto_reshuffle
= 0;
37 int show_remaining_time
= 0;
42 int colors
[NR_COLORS
] = {
46 COLOR_YELLOW
| BRIGHT
,
55 COLOR_YELLOW
| BRIGHT
,
58 COLOR_YELLOW
| BRIGHT
,
63 COLOR_YELLOW
| BRIGHT
,
73 /* uninitialized option variables */
74 char *track_win_format
= NULL
;
75 char *track_win_alt_format
= NULL
;
76 char *list_win_format
= NULL
;
77 char *list_win_alt_format
= NULL
;
78 char *current_format
= NULL
;
79 char *current_alt_format
= NULL
;
80 char *window_title_format
= NULL
;
81 char *window_title_alt_format
= NULL
;
82 char *id3_default_charset
= NULL
;
84 static void buf_int(char *buf
, int val
)
86 snprintf(buf
, OPTION_MAX_SIZE
, "%d", val
);
89 static int parse_int(const char *buf
, int minval
, int maxval
, int *val
)
93 if (str_to_int(buf
, &tmp
) == -1 || tmp
< minval
|| tmp
> maxval
) {
94 error_msg("integer in range %d..%d expected", minval
, maxval
);
101 int parse_enum(const char *buf
, int minval
, int maxval
, const char * const names
[], int *val
)
106 if (str_to_int(buf
, &tmp
) == 0) {
107 if (tmp
< minval
|| tmp
> maxval
)
113 for (i
= 0; names
[i
]; i
++) {
114 if (strcasecmp(buf
, names
[i
]) == 0) {
120 error_msg("name or integer in range %d..%d expected", minval
, maxval
);
124 static const char * const bool_names
[] = {
125 "false", "true", NULL
128 static int parse_bool(const char *buf
, int *val
)
130 return parse_enum(buf
, 0, 1, bool_names
, val
);
133 /* this is used as id in struct cmus_opt */
146 /* callbacks for normal options {{{ */
148 #define SECOND_SIZE (44100 * 16 / 8 * 2)
149 static void get_buffer_seconds(unsigned int id
, char *buf
)
151 buf_int(buf
, (player_get_buffer_chunks() * CHUNK_SIZE
+ SECOND_SIZE
/ 2) / SECOND_SIZE
);
154 static void set_buffer_seconds(unsigned int id
, const char *buf
)
158 if (parse_int(buf
, 1, 20, &sec
))
159 player_set_buffer_chunks((sec
* SECOND_SIZE
+ CHUNK_SIZE
/ 2) / CHUNK_SIZE
);
162 static void get_id3_default_charset(unsigned int id
, char *buf
)
164 strcpy(buf
, id3_default_charset
);
167 static void set_id3_default_charset(unsigned int id
, const char *buf
)
169 free(id3_default_charset
);
170 id3_default_charset
= xstrdup(buf
);
173 static const char * const valid_sort_keys
[] = {
185 static const char **parse_sort_keys(const char *value
)
193 keys
= xnew(const char *, size
);
204 while (*e
&& *e
!= ' ')
218 if (valid_sort_keys
[i
] == NULL
) {
219 error_msg("invalid sort key '%s'", buf
);
224 if (strcmp(buf
, valid_sort_keys
[i
]) == 0)
228 if (pos
== size
- 1) {
230 keys
= xrenew(const char *, keys
, size
);
232 keys
[pos
++] = valid_sort_keys
[i
];
238 static void get_lib_sort(unsigned int id
, char *buf
)
240 strcpy(buf
, lib_editable
.sort_str
);
243 static void set_lib_sort(unsigned int id
, const char *buf
)
245 const char **keys
= parse_sort_keys(buf
);
248 editable_set_sort_keys(&lib_editable
, keys
);
251 static void get_pl_sort(unsigned int id
, char *buf
)
253 strcpy(buf
, pl_editable
.sort_str
);
256 static void set_pl_sort(unsigned int id
, const char *buf
)
258 const char **keys
= parse_sort_keys(buf
);
261 editable_set_sort_keys(&pl_editable
, keys
);
264 static void get_output_plugin(unsigned int id
, char *buf
)
266 char *value
= player_get_op();
273 static void set_output_plugin(unsigned int id
, const char *buf
)
275 if (ui_initialized
) {
278 /* must set it later manually */
279 output_plugin
= xstrdup(buf
);
283 static void get_status_display_program(unsigned int id
, char *buf
)
285 if (status_display_program
)
286 strcpy(buf
, status_display_program
);
289 static void set_status_display_program(unsigned int id
, const char *buf
)
291 free(status_display_program
);
292 status_display_program
= NULL
;
294 status_display_program
= xstrdup(buf
);
299 /* callbacks for toggle options {{{ */
301 static void get_auto_reshuffle(unsigned int id
, char *buf
)
303 strcpy(buf
, bool_names
[auto_reshuffle
]);
306 static void set_auto_reshuffle(unsigned int id
, const char *buf
)
308 parse_bool(buf
, &auto_reshuffle
);
311 static void toggle_auto_reshuffle(unsigned int id
)
316 static void get_continue(unsigned int id
, char *buf
)
318 strcpy(buf
, bool_names
[player_cont
]);
321 static void set_continue(unsigned int id
, const char *buf
)
323 if (!parse_bool(buf
, &player_cont
))
328 static void toggle_continue(unsigned int id
)
334 static void get_confirm_run(unsigned int id
, char *buf
)
336 strcpy(buf
, bool_names
[confirm_run
]);
339 static void set_confirm_run(unsigned int id
, const char *buf
)
341 parse_bool(buf
, &confirm_run
);
344 static void toggle_confirm_run(unsigned int id
)
349 const char * const view_names
[NR_VIEWS
+ 1] = {
350 "tree", "sorted", "playlist", "queue", "browser", "filters", NULL
353 static void get_play_library(unsigned int id
, char *buf
)
355 strcpy(buf
, bool_names
[play_library
]);
358 static void set_play_library(unsigned int id
, const char *buf
)
360 if (!parse_bool(buf
, &play_library
))
365 static void toggle_play_library(unsigned int id
)
371 static void get_play_sorted(unsigned int id
, char *buf
)
373 strcpy(buf
, bool_names
[play_sorted
]);
376 static void set_play_sorted(unsigned int id
, const char *buf
)
380 if (!parse_bool(buf
, &tmp
))
387 static void toggle_play_sorted(unsigned int id
)
390 play_sorted
= play_sorted
^ 1;
392 /* shuffle would override play_sorted... */
394 /* play_sorted makes no sense in playlist */
403 const char * const aaa_mode_names
[] = {
404 "all", "artist", "album", NULL
407 static void get_aaa_mode(unsigned int id
, char *buf
)
409 strcpy(buf
, aaa_mode_names
[aaa_mode
]);
412 static void set_aaa_mode(unsigned int id
, const char *buf
)
416 if (!parse_enum(buf
, 0, 2, aaa_mode_names
, &tmp
))
423 static void toggle_aaa_mode(unsigned int id
)
427 /* aaa mode makes no sense in playlist */
436 static void get_repeat(unsigned int id
, char *buf
)
438 strcpy(buf
, bool_names
[repeat
]);
441 static void set_repeat(unsigned int id
, const char *buf
)
443 if (!parse_bool(buf
, &repeat
))
448 static void toggle_repeat(unsigned int id
)
454 static void get_show_hidden(unsigned int id
, char *buf
)
456 strcpy(buf
, bool_names
[show_hidden
]);
459 static void set_show_hidden(unsigned int id
, const char *buf
)
461 if (!parse_bool(buf
, &show_hidden
))
466 static void toggle_show_hidden(unsigned int id
)
472 static void get_show_remaining_time(unsigned int id
, char *buf
)
474 strcpy(buf
, bool_names
[show_remaining_time
]);
477 static void set_show_remaining_time(unsigned int id
, const char *buf
)
479 if (!parse_bool(buf
, &show_remaining_time
))
484 static void toggle_show_remaining_time(unsigned int id
)
486 show_remaining_time
^= 1;
490 static void get_shuffle(unsigned int id
, char *buf
)
492 strcpy(buf
, bool_names
[shuffle
]);
495 static void set_shuffle(unsigned int id
, const char *buf
)
497 if (!parse_bool(buf
, &shuffle
))
502 static void toggle_shuffle(unsigned int id
)
510 /* special callbacks (id set) {{{ */
512 static const char * const color_enum_names
[1 + 8 * 2 + 1] = {
514 "black", "red", "green", "yellow", "blue", "magenta", "cyan", "gray",
515 "darkgray", "lightred", "lightgreen", "lightyellow", "lightblue", "lightmagenta", "lightcyan", "white",
519 static void get_color(unsigned int id
, char *buf
)
525 strcpy(buf
, color_enum_names
[val
+ 1]);
531 static void set_color(unsigned int id
, const char *buf
)
535 if (!parse_enum(buf
, -1, 255, color_enum_names
, &color
))
543 static char **id_to_fmt(enum format_id id
)
546 case FMT_CURRENT_ALT
:
547 return ¤t_alt_format
;
548 case FMT_PLAYLIST_ALT
:
549 return &list_win_alt_format
;
551 return &window_title_alt_format
;
552 case FMT_TRACKWIN_ALT
:
553 return &track_win_alt_format
;
555 return ¤t_format
;
557 return &list_win_format
;
559 return &window_title_format
;
561 return &track_win_format
;
566 static void get_format(unsigned int id
, char *buf
)
568 char **fmtp
= id_to_fmt(id
);
573 static void set_format(unsigned int id
, const char *buf
)
575 char **fmtp
= id_to_fmt(id
);
577 if (!format_valid(buf
)) {
578 error_msg("invalid format string");
582 *fmtp
= xstrdup(buf
);
589 #define DN(name) { #name, get_ ## name, set_ ## name, NULL },
590 #define DT(name) { #name, get_ ## name, set_ ## name, toggle_ ## name },
592 static const struct {
596 opt_toggle_cb toggle
;
597 } simple_options
[] = {
603 DN(id3_default_charset
)
611 DT(show_remaining_time
)
613 DN(status_display_program
)
614 { NULL
, NULL
, NULL
, NULL
}
617 static const char * const color_names
[NR_COLORS
] = {
623 "color_statusline_bg",
624 "color_statusline_fg",
625 "color_titleline_bg",
626 "color_titleline_fg",
629 "color_win_cur_sel_bg",
630 "color_win_cur_sel_fg",
633 "color_win_inactive_cur_sel_bg",
634 "color_win_inactive_cur_sel_fg",
635 "color_win_inactive_sel_bg",
636 "color_win_inactive_sel_fg",
639 "color_win_title_bg",
643 /* default values for the variables which we must initialize but
644 * can't do it statically */
645 static const struct {
649 { "altformat_current", " %F " },
650 { "altformat_playlist", " %f%= %d " },
651 { "altformat_title", "%f" },
652 { "altformat_trackwin", " %f%= %d " },
653 { "format_current", " %a - %l - %02n. %t%= %y " },
654 { "format_playlist", " %a - %l - %02n. %t%= %y %d " },
655 { "format_title", "%a - %l - %t (%y)" },
656 { "format_trackwin", " %02n. %t%= %y %d " },
658 { "lib_sort" , "artist album discnumber tracknumber title filename" },
660 { "id3_default_charset","ISO-8859-1" },
664 LIST_HEAD(option_head
);
667 void option_add(const char *name
, unsigned int id
, opt_get_cb get
,
668 opt_set_cb set
, opt_toggle_cb toggle
)
670 struct cmus_opt
*opt
= xnew(struct cmus_opt
, 1);
671 struct list_head
*item
;
677 opt
->toggle
= toggle
;
679 item
= option_head
.next
;
680 while (item
!= &option_head
) {
681 struct cmus_opt
*o
= container_of(item
, struct cmus_opt
, node
);
683 if (strcmp(name
, o
->name
) < 0)
687 /* add before item */
688 list_add_tail(&opt
->node
, item
);
692 struct cmus_opt
*option_find(const char *name
)
694 struct cmus_opt
*opt
;
696 list_for_each_entry(opt
, &option_head
, node
) {
697 if (strcmp(name
, opt
->name
) == 0)
700 error_msg("no such option %s", name
);
704 void option_set(const char *name
, const char *value
)
706 struct cmus_opt
*opt
= option_find(name
);
709 opt
->set(opt
->id
, value
);
712 static void get_op_option(unsigned int id
, char *buf
)
716 player_get_op_option(id
, &val
);
723 static void set_op_option(unsigned int id
, const char *buf
)
725 int rc
= player_set_op_option(id
, buf
);
728 char *msg
= op_get_error_msg(rc
, "setting option");
729 error_msg("%s", msg
);
734 /* id is ((plugin_index << 16) | option_index) */
735 static void add_op_option(unsigned int id
, const char *name
)
737 option_add(xstrdup(name
), id
, get_op_option
, set_op_option
, NULL
);
740 void options_add(void)
746 for (i
= 0; simple_options
[i
].name
; i
++)
747 option_add(simple_options
[i
].name
, 0, simple_options
[i
].get
,
748 simple_options
[i
].set
, simple_options
[i
].toggle
);
750 for (i
= 0; i
< NR_FMTS
; i
++)
751 option_add(str_defaults
[i
].name
, i
, get_format
, set_format
, NULL
);
753 for (i
= 0; i
< NR_COLORS
; i
++)
754 option_add(color_names
[i
], i
, get_color
, set_color
, NULL
);
756 player_for_each_op_option(add_op_option
);
759 static int handle_line(void *data
, const char *line
)
765 int source_file(const char *filename
)
767 return file_for_each_line(filename
, handle_line
, NULL
);
770 void options_load(void)
777 /* initialize those that can't be statically initialized */
778 for (i
= 0; str_defaults
[i
].name
; i
++)
779 option_set(str_defaults
[i
].name
, str_defaults
[i
].value
);
781 /* load autosave config */
782 snprintf(filename
, sizeof(filename
), "%s/autosave", cmus_config_dir
);
783 if (source_file(filename
) == -1) {
784 const char *def
= DATADIR
"/cmus/rc";
787 warn_errno("loading %s", filename
);
790 if (source_file(def
) == -1)
791 die_errno("loading %s", def
);
794 /* load optional static config */
795 snprintf(filename
, sizeof(filename
), "%s/rc", cmus_config_dir
);
796 if (source_file(filename
) == -1) {
798 warn_errno("loading %s", filename
);
802 void options_exit(void)
804 struct cmus_opt
*opt
;
805 struct filter_entry
*filt
;
810 snprintf(filename
, sizeof(filename
), "%s/autosave", cmus_config_dir
);
811 f
= fopen(filename
, "w");
813 warn_errno("creating %s", filename
);
818 list_for_each_entry(opt
, &option_head
, node
) {
819 char buf
[OPTION_MAX_SIZE
];
822 opt
->get(opt
->id
, buf
);
823 fprintf(f
, "set %s=%s\n", opt
->name
, buf
);
826 /* save key bindings */
827 for (i
= 0; i
< NR_CTXS
; i
++) {
828 struct binding
*b
= key_bindings
[i
];
831 fprintf(f
, "bind %s %s %s\n", key_context_names
[i
], b
->key
->name
, b
->cmd
);
837 list_for_each_entry(filt
, &filters_head
, node
)
838 fprintf(f
, "fset %s=%s\n", filt
->name
, filt
->filter
);
839 fprintf(f
, "factivate");
840 list_for_each_entry(filt
, &filters_head
, node
) {
842 fprintf(f
, " %s", filt
->name
);