Code

Crossfade time can now be definied in the rc file (crossfade-time)
[ncmpc.git] / src / conf.c
1 /* 
2  * $Id$
3  *
4  * (c) 2004 by Kalle Wallin <kaw@linux.se>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
21 #include <ctype.h>
22 #include <stdio.h>
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
31 #include <glib.h>
32 #include <ncurses.h>
33 #include "config.h"
34 #include "ncmpc.h"
35 #include "options.h"
36 #include "support.h"
37 #include "command.h"
38 #include "colors.h"
39 #include "conf.h"
41 #define MAX_LINE_LENGTH 1024
42 #define COMMENT_TOKEN   '#'
44 /* configuration field names */
45 #define CONF_ENABLE_COLORS           "enable-colors"
46 #define CONF_AUTO_CENTER             "auto-center"
47 #define CONF_WIDE_CURSOR             "wide-cursor"
48 #define CONF_ENABLE_BELL             "enable-bell"
49 #define CONF_KEY_DEFINITION          "key"
50 #define CONF_COLOR                   "color"
51 #define CONF_COLOR_DEFINITION        "colordef"
52 #define CONF_LIST_FORMAT             "list-format"
53 #define CONF_STATUS_FORMAT           "status-format"
54 #define CONF_XTERM_TITLE_FORMAT      "xterm-title-format"
55 #define CONF_LIST_WRAP               "wrap-around"
56 #define CONF_FIND_WRAP               "find-wrap"
57 #define CONF_AUDIBLE_BELL            "audible-bell"
58 #define CONF_VISIBLE_BELL            "visible-bell"
59 #define CONF_XTERM_TITLE             "set-xterm-title"
60 #define CONF_ENABLE_MOUSE            "enable-mouse"
61 #define CONF_CROSSFADE_TIME          "crossfade-time"
63 typedef enum {
64   KEY_PARSER_UNKNOWN,
65   KEY_PARSER_CHAR,
66   KEY_PARSER_DEC,
67   KEY_PARSER_HEX,
68   KEY_PARSER_DONE
69 } key_parser_state_t;
71 static gboolean
72 str2bool(char *str)
73 {
74   if( !strcasecmp(str,"yes")  || !strcasecmp(str,"true") || 
75       !strcasecmp(str,"on")   || !strcasecmp(str,"1") )
76     return TRUE;
77   return FALSE;
78 }
80 static int
81 parse_key_value(char *str, size_t len, char **end)
82 {
83   int i, value;
84   key_parser_state_t state;
86   i=0;
87   value=0;
88   state=KEY_PARSER_UNKNOWN;
89   *end = str;
91   while( i<len && state!=KEY_PARSER_DONE )
92     {
93       int next = 0;
94       int c = str[i];
96       if( i+1<len )
97         next = str[i+1];
99       switch(state)
100         {
101         case KEY_PARSER_UNKNOWN:
102           if( c=='\'' )
103             state = KEY_PARSER_CHAR;
104           else if( c=='0' && next=='x' )
105             state = KEY_PARSER_HEX;
106           else if( isdigit(c) )
107             state = KEY_PARSER_DEC;
108           else {
109             fprintf(stderr,
110                     _("Error: Unsupported key definition - %s\n"), 
111                     str);
112             return -1;
113           }
114           break;
115         case KEY_PARSER_CHAR:
116           if( next!='\'' )
117             {
118               fprintf(stderr,
119                       _("Error: Unsupported key definition - %s\n"), 
120                       str);
121               return -1;
122             }
123           value = c;
124           *end = str+i+2;
125           state = KEY_PARSER_DONE;
126           break;
127         case KEY_PARSER_DEC:
128           value = (int) strtol(str+(i-1), end, 10);
129           state = KEY_PARSER_DONE;
130           break;
131         case KEY_PARSER_HEX:
132           if( !isdigit(next) )
133             {
134               fprintf(stderr,_("Error: Digit expexted after 0x - %s\n"), str);
135               return -1;
136             }
137           value = (int) strtol(str+(i+1), end, 16);
138           state = KEY_PARSER_DONE;
139           break;
140         case KEY_PARSER_DONE:
141           break;
142         }
143       i++;
144     }
146   if( *end> str+len )
147     *end = str+len;
149   return value;
152 static int
153 parse_key_definition(char *str)
155   char buf[MAX_LINE_LENGTH];
156   char *p, *end;
157   size_t len = strlen(str);
158   int i,j,key;
159   int keys[MAX_COMMAND_KEYS];
160   command_t cmd;
162   /* get the command name */
163   i=0;
164   j=0;
165   memset(buf, 0, MAX_LINE_LENGTH);
166   while( i<len && str[i]!='=' && !IS_WHITESPACE(str[i]) )
167     buf[j++] = str[i++];
168   if( (cmd=get_key_command_from_name(buf)) == CMD_NONE )
169     {
170       fprintf(stderr, _("Error: Unknown key command %s\n"), buf);
171       return -1;
172     }
174   /* skip whitespace */
175   while( i<len && (str[i]=='=' || IS_WHITESPACE(str[i])) )
176     i++;
178   /* get the value part */
179   memset(buf, 0, MAX_LINE_LENGTH);
180   g_strlcpy(buf, str+i, MAX_LINE_LENGTH);
181   len = strlen(buf);
182   if( len==0 )
183     {
184       fprintf(stderr,_("Error: Incomplete key definition - %s\n"), str);
185       return -1;
186     }
188   /* parse key values */
189   i = 0;
190   key = 0;
191   len = strlen(buf);
192   p = buf;
193   end = buf+len;
194   memset(keys, 0, sizeof(int)*MAX_COMMAND_KEYS);
195   while( i<MAX_COMMAND_KEYS && p<end && (key=parse_key_value(p,len+1,&p))>=0 )
196     {
197       keys[i++] = key;
198       while( p<end && (*p==',' || *p==' ' || *p=='\t') )
199         p++;
200       len = strlen(p);
201     } 
202   if( key<0 )
203     {
204       fprintf(stderr,_("Error: Bad key definition - %s\n"), str);
205       return -1;
206     }
208   return assign_keys(cmd, keys);
211 static int
212 parse_color(char *str)
214   char *name = str;
215   char *value = NULL;
216   int len,i;
218   i=0;
219   len=strlen(str);
220   /* get the color name */
221   while( i<len && str[i]!='=' && !IS_WHITESPACE(str[i]) )
222     i++;
223   
224   /* skip whitespace */
225   while( i<len && (str[i]=='=' || IS_WHITESPACE(str[i])) )
226     {
227       str[i]='\0';
228       i++;
229     } 
230   
231   if( i<len )
232     value = str+i;
234   return colors_assign(name, value);
238 static int
239 parse_color_definition(char *str)
241   char buf[MAX_LINE_LENGTH];
242   char *p, *end, *name;
243   size_t len = strlen(str);
244   int i,j,value;
245   short color, rgb[3];
247   /* get the command name */
248   i=0;
249   j=0;
250   memset(buf, 0, MAX_LINE_LENGTH);
251   while( i<len && str[i]!='=' && !IS_WHITESPACE(str[i]) )
252     buf[j++] = str[i++];
253   color=colors_str2color(buf);
254   if( color<0 )
255     {
256       fprintf(stderr,_("Error: Bad color %s [%d]\n"), buf, color);
257       return -1;
258     }
259   name = g_strdup(buf);
261   /* skip whitespace */
262   while( i<len && (str[i]=='=' || IS_WHITESPACE(str[i])) )
263     i++;
265   /* get the value part */
266   memset(buf, 0, MAX_LINE_LENGTH);
267   g_strlcpy(buf, str+i, MAX_LINE_LENGTH);
268   len = strlen(buf);
269   if( len==0 )
270     {
271       fprintf(stderr,_("Error: Incomplete color definition - %s\n"), str);
272       g_free(name);
273       return -1;
274     }
276   /* parse r,g.b values with the key definition parser */
277   i = 0;
278   value = 0;
279   len = strlen(buf);
280   p = buf;
281   end = buf+len;
282   memset(rgb, 0, sizeof(short)*3);
283   while( i<3 && p<end && (value=parse_key_value(p,len+1,&p))>=0 )
284     {
285       rgb[i++] = value;
286       while( p<end && (*p==',' || *p==' ' || *p=='\t') )
287         p++;
288       len = strlen(p);
289     } 
290   if( value<0 || i!=3)
291     {
292       fprintf(stderr,_("Error: Bad color definition - %s\n"), str);
293       g_free(name);
294       return -1;
295     }
296   value = colors_define(name, rgb[0], rgb[1], rgb[2]);
297   g_free(name);
298   return value;
301 static char *
302 get_format(char *str)
304   gsize len = strlen(str);
306   if( str && str[0]=='\"' && str[len-1] == '\"' )
307     {
308       str[len-1] = '\0';
309       str++;
310     }
311   return g_strdup(str);
315 static int
316 read_rc_file(char *filename, options_t *options)
318   int fd;
319   int quit  = 0;
320   int free_filename = 0;
322   if( filename==NULL )
323     return -1;
325   D("Reading configuration file %s\n", filename);
326   if( (fd=open(filename,O_RDONLY)) <0 )
327     {
328       perror(filename);
329       if( free_filename )
330         g_free(filename);
331       return -1;
332     }
334   while( !quit )
335     {
336       int i,j;
337       int len;
338       int match_found;
339       char line[MAX_LINE_LENGTH];
340       char name[MAX_LINE_LENGTH];
341       char value[MAX_LINE_LENGTH];
343       line[0]  = '\0';
344       value[0] = '\0';
346       i = 0;
347       /* read a line ending with '\n' */
348       do {
349         len = read( fd, &line[i], 1 );
350         if( len == 1 )
351           i++;
352         else
353           quit = 1;
354       } while( !quit && i<MAX_LINE_LENGTH && line[i-1]!='\n' );
355       
356      
357       /* remove trailing whitespace */
358       line[i] = '\0';
359       i--;
360       while( i>=0 && IS_WHITESPACE(line[i]) )
361         {
362           line[i] = '\0';
363           i--;
364         }     
365       len = i+1;
367       if( len>0 )
368         {
369           i = 0;
370           /* skip whitespace */
371           while( i<len && IS_WHITESPACE(line[i]) )
372             i++;
373           
374           /* continue if this line is not a comment */
375           if( line[i] != COMMENT_TOKEN )
376             {
377               /* get the name part */
378               j=0;
379               while( i<len && line[i]!='=' && !IS_WHITESPACE(line[i]) )
380                 {
381                   name[j++] = line[i++];
382                 }
383               name[j] = '\0';
384               
385               /* skip '=' and whitespace */
386               while( i<len && (line[i]=='=' || IS_WHITESPACE(line[i])) )
387                 i++;
388               
389               /* get the value part */
390               j=0;
391               while( i<len )
392                 {
393                   value[j++] = line[i++];
394                 }
395               value[j] = '\0';
396               
397               match_found = 1;
399               /* key definition */
400               if( !strcasecmp(CONF_KEY_DEFINITION, name) )
401                 {
402                   parse_key_definition(value);
403                 }
404               /* enable colors */
405               else if( !strcasecmp(CONF_ENABLE_COLORS, name) )
406                 {
407                   options->enable_colors = str2bool(value);
408                 }
409               /* auto center */
410               else if( !strcasecmp(CONF_AUTO_CENTER, name) )
411                 {
412                   options->auto_center = str2bool(value);
413                 }
414               /* color assignment */
415               else if( !strcasecmp(CONF_COLOR, name) )
416                 {
417                   parse_color(value);
418                 }
419               /* wide cursor */
420               else if( !strcasecmp(CONF_WIDE_CURSOR, name) )
421                 {
422                   options->wide_cursor = str2bool(value);
423                 }
424               /* color definition */
425               else if( !strcasecmp(CONF_COLOR_DEFINITION, name) )
426                 {
427                   parse_color_definition(value);
428                 }
429               /* list format string */
430               else if( !strcasecmp(CONF_LIST_FORMAT, name) )
431                 {
432                   g_free(options->list_format);
433                   options->list_format = get_format(value);
434                 }
435               /* status format string */
436               else if( !strcasecmp(CONF_STATUS_FORMAT, name) )
437                 {
438                   g_free(options->status_format);
439                   options->status_format = get_format(value);
440                 }
441               /* xterm title format string */
442               else if( !strcasecmp(CONF_XTERM_TITLE_FORMAT, name) )
443                 {
444                   g_free(options->xterm_title_format);
445                   options->xterm_title_format = get_format(value);
446                 }
447               else if( !strcasecmp(CONF_LIST_WRAP, name) )
448                 {
449                   options->list_wrap = str2bool(value);
450                 }
451               else if( !strcasecmp(CONF_FIND_WRAP, name) )
452                 {
453                   options->find_wrap = str2bool(value);
454                 }
455               else if( !strcasecmp(CONF_AUDIBLE_BELL, name) )
456                 {
457                   options->audible_bell = str2bool(value);
458                 }
459               else if( !strcasecmp(CONF_VISIBLE_BELL, name) )
460                 {
461                   options->visible_bell = str2bool(value);
462                 }
463               else if( !strcasecmp(CONF_XTERM_TITLE, name) )
464                 {
465                   options->enable_xterm_title = str2bool(value);
466                 }
467               else if( !strcasecmp(CONF_ENABLE_MOUSE, name) )
468                 {
469                   options->enable_mouse = str2bool(value);
470                 }
471               else if( !strcasecmp(CONF_CROSSFADE_TIME, name) )
472                 {
473                   options->crossfade_time = atoi(value);
474                 }
475               else
476                 {
477                   match_found = 0;
478                 }
479               
481               if( !match_found )
482                 fprintf(stderr, 
483                         _("Unknown configuration parameter: %s\n"), 
484                         name);
485               D("conf>  %s = %s %s\n", name, value,
486                 match_found ? "" : "- UNKNOWN SETTING!" );
487             }
488         }         
489     }
491   D("--\n\n");
493   if( free_filename )
494     g_free(filename);
495  
496   return 0;
499 int
500 check_user_conf_dir(void)
502   int retval;
503   char *dirname = g_build_filename(g_get_home_dir(), "." PACKAGE, NULL);
504   
505   if( g_file_test(dirname, G_FILE_TEST_IS_DIR) )
506     {
507       g_free(dirname);
508       return 0;
509     }
510   retval = mkdir(dirname, 0755);
511   g_free(dirname);
512   return retval;
515 char *
516 get_user_key_binding_filename(void)
518   return g_build_filename(g_get_home_dir(), "." PACKAGE, "keys", NULL);
522 int
523 read_configuration(options_t *options)
525   char *filename = NULL;
527   /* check for command line configuration file */
528   if( options->config_file )
529     filename = g_strdup(options->config_file);
531   /* check for user configuration ~/.ncmpc/config */
532   if( filename == NULL )
533     {
534       filename = g_build_filename(g_get_home_dir(), 
535                                   "." PACKAGE, "config", NULL);
536       if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
537         {
538           g_free(filename);
539           filename = NULL;
540         }
541     }
543   /* check for  global configuration SYSCONFDIR/ncmpc/config */
544   if( filename == NULL )
545     {
546       filename = g_build_filename(SYSCONFDIR, PACKAGE, "config", NULL);
547       if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
548         {
549           g_free(filename);
550           filename = NULL;
551         }
552     }
554   /* load configuration */
555   if( filename )
556     {
557       read_rc_file(filename, options);
558       g_free(filename);
559       filename = NULL;
560     }
562   /* check for command line key binding file */
563   if( options->key_file )
564     filename = g_strdup(options->key_file);
566   /* check for  user key bindings ~/.ncmpc/keys */
567   if( filename == NULL )
568     {
569       filename = get_user_key_binding_filename();
570       if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
571         {
572           g_free(filename);
573           filename = NULL;
574         }
575     }
577   /* check for  global key bindings SYSCONFDIR/ncmpc/keys */
578   if( filename == NULL )
579     {
580       filename = g_build_filename(SYSCONFDIR, PACKAGE, "keys", NULL);
581       if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
582         {
583           g_free(filename);
584           filename = NULL;
585         }
586     }
588   /* load key bindings */
589   if( filename )
590     {
591       read_rc_file(filename, options);
592       g_free(filename);
593       filename = NULL;
594     }
596   return 0;