Code

The background color can now be assigned to 'none' (use the current color).
[ncmpc.git] / conf.c
1 /* 
2  * (c) 2004 by Kalle Wallin (kaw@linux.se)
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  *
17  */
19 #include <ctype.h>
20 #include <stdio.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
29 #include <glib.h>
30 #include <ncurses.h>
32 #include "config.h"
33 #include "options.h"
34 #include "support.h"
35 #include "command.h"
36 #include "conf.h"
38 #ifdef DEBUG
39 #define D(x) x
40 #else
41 #define D(x)
42 #endif
44 #define RCFILE "." PACKAGE "rc"
46 #define MAX_LINE_LENGTH 1024
47 #define COMMENT_TOKEN   '#'
49 /* configuration field names */
50 #define CONF_ENABLE_COLORS           "enable_colors"
51 #define CONF_AUTO_CENTER             "auto_center"
53 /* configuration field names - colors */
54 #define CONF_COLOR_BACKGROUND        "background_color"
55 #define CONF_COLOR_TITLE             "title_color"
56 #define CONF_COLOR_LINE              "line_color"
57 #define CONF_COLOR_LIST              "list_color"
58 #define CONF_COLOR_PROGRESS          "progress_color"
59 #define CONF_COLOR_STATUS            "status_color"
60 #define CONF_COLOR_ALERT             "alert_color"
61 #define CONF_WIDE_CURSOR             "wide_cursor"
62 #define CONF_KEY_DEFINITION          "key"
64 typedef enum {
65   KEY_PARSER_UNKNOWN,
66   KEY_PARSER_CHAR,
67   KEY_PARSER_DEC,
68   KEY_PARSER_HEX,
69   KEY_PARSER_DONE
70 } key_parser_state_t;
72 static int
73 str2bool(char *str)
74 {
75   if( !strcasecmp(str,"no")  || !strcasecmp(str,"false") || 
76       !strcasecmp(str,"off") || !strcasecmp(str,"0") )
77     return 0;
78   return 1;
79 }
81 static int
82 str2color(char *str)
83 {
84   if( !strcasecmp(str,"black") )
85     return COLOR_BLACK;
86   else if( !strcasecmp(str,"red") )
87     return COLOR_RED;
88   else if( !strcasecmp(str,"green") )
89     return COLOR_GREEN;
90   else if( !strcasecmp(str,"yellow") )
91     return COLOR_YELLOW;
92   else if( !strcasecmp(str,"blue") )
93     return COLOR_BLUE;
94   else if( !strcasecmp(str,"magenta") )
95     return COLOR_MAGENTA;
96   else if( !strcasecmp(str,"cyan") )
97     return COLOR_CYAN;
98   else if( !strcasecmp(str,"white") )
99     return COLOR_WHITE;
100   else if( !strcasecmp(str,"default") || !strcasecmp(str,"none") )
101     return -1;
102   fprintf(stderr,"Warning: unknown color %s\n", str);
103   return -2;
106 static int
107 parse_key_value(char *str, size_t len, char **end)
109   int i, value;
110   key_parser_state_t state;
112   i=0;
113   value=0;
114   state=KEY_PARSER_UNKNOWN;
115   *end = str;
117   while( i<len && state!=KEY_PARSER_DONE )
118     {
119       int next = 0;
120       int c = str[i];
122       if( i+1<len )
123         next = str[i+1];
125       switch(state)
126         {
127         case KEY_PARSER_UNKNOWN:
128           if( c=='\'' )
129             state = KEY_PARSER_CHAR;
130           else if( c=='0' && next=='x' )
131             state = KEY_PARSER_HEX;
132           else if( isdigit(c) )
133             state = KEY_PARSER_DEC;
134           else {
135             fprintf(stderr, "Error: Unsupported key definition - %s\n", str);
136             return -1;
137           }
138           break;
139         case KEY_PARSER_CHAR:
140           if( next!='\'' )
141             {
142               fprintf(stderr, "Error: Unsupported key definition - %s\n", str);
143               return -1;
144             }
145           value = c;
146           *end = str+i+2;
147           state = KEY_PARSER_DONE;
148           break;
149         case KEY_PARSER_DEC:
150           value = (int) strtol(str+(i-1), end, 10);
151           state = KEY_PARSER_DONE;
152           break;
153         case KEY_PARSER_HEX:
154           if( !isdigit(next) )
155             {
156               fprintf(stderr, "Error: Digit expexted after 0x - %s\n", str);
157               return -1;
158             }
159           value = (int) strtol(str+(i+1), end, 16);
160           state = KEY_PARSER_DONE;
161           break;
162         case KEY_PARSER_DONE:
163           break;
164         }
165       i++;
166     }
168   if( *end> str+len )
169     *end = str+len;
171   return value;
174 static int
175 parse_key_definition(char *str)
177   char buf[MAX_LINE_LENGTH];
178   char *p, *end;
179   size_t len = strlen(str);
180   int i,j,key;
181   int keys[MAX_COMMAND_KEYS];
182   command_t cmd;
184   /* get the command name */
185   i=0;
186   j=0;
187   memset(buf, 0, MAX_LINE_LENGTH);
188   while( i<len && str[i]!='=' && !IS_WHITESPACE(str[i]) )
189     buf[j++] = str[i++];
190   if( (cmd=get_key_command_from_name(buf)) == CMD_NONE )
191     {
192       fprintf(stderr, "Error: Unknown key command %s\n", buf);
193       return -1;
194     }
196   /* skip whitespace */
197   while( i<len && (str[i]=='=' || IS_WHITESPACE(str[i])) )
198     i++;
200   /* get the value part */
201   memset(buf, 0, MAX_LINE_LENGTH);
202   strncpy(buf, str+i, len-i);
203   len = strlen(buf);
204   if( len==0 )
205     {
206       fprintf(stderr,"Error: Incomplete key definition - %s\n", str);
207       return -1;
208     }
210   /* parse key values */
211   i = 0;
212   key = 0;
213   len = strlen(buf);
214   p = buf;
215   end = buf+len;
216   memset(keys, 0, sizeof(int)*MAX_COMMAND_KEYS);
217   while( i<MAX_COMMAND_KEYS && p<end && (key=parse_key_value(p,len+1,&p))>=0 )
218     {
219       keys[i++] = key;
220       while( p<end && (*p==',' || *p==' ' || *p=='\t') )
221         p++;
222       len = strlen(p);
223     } 
224   if( key<0 )
225     {
226       fprintf(stderr,"Error: Bad key definition - %s\n", str);
227       return -1;
228     }
230   return assign_keys(cmd, keys);
233 static int
234 read_rc_file(char *filename, options_t *options)
236   int fd;
237   int quit  = 0;
238   int color = -1;
239   int free_filename = 0;
241   if( filename==NULL )
242     return -1;
244   D(printf("Reading configuration file %s\n", filename));
245   if( (fd=open(filename,O_RDONLY)) <0 )
246     {
247       D(perror(filename));
248       if( free_filename )
249         g_free(filename);
250       return -1;
251     }
253   while( !quit )
254     {
255       int i,j;
256       int len;
257       int match_found;
258       char line[MAX_LINE_LENGTH];
259       char name[MAX_LINE_LENGTH];
260       char value[MAX_LINE_LENGTH];
262       line[0]  = '\0';
263       value[0] = '\0';
265       i = 0;
266       /* read a line ending with '\n' */
267       do {
268         len = read( fd, &line[i], 1 );
269         if( len == 1 )
270           i++;
271         else
272           quit = 1;
273       } while( !quit && i<MAX_LINE_LENGTH && line[i-1]!='\n' );
274       
275      
276       /* remove trailing whitespace */
277       line[i] = '\0';
278       i--;
279       while( i>=0 && IS_WHITESPACE(line[i]) )
280         {
281           line[i] = '\0';
282           i--;
283         }     
284       len = i+1;
286       if( len>0 )
287         {
288           i = 0;
289           /* skip whitespace */
290           while( i<len && IS_WHITESPACE(line[i]) )
291             i++;
292           
293           /* continue if this line is not a comment */
294           if( line[i] != COMMENT_TOKEN )
295             {
296               /* get the name part */
297               j=0;
298               while( i<len && line[i]!='=' && !IS_WHITESPACE(line[i]) )
299                 {
300                   name[j++] = line[i++];
301                 }
302               name[j] = '\0';
303               
304               /* skip '=' and whitespace */
305               while( i<len && (line[i]=='=' || IS_WHITESPACE(line[i])) )
306                 i++;
307               
308               /* get the value part */
309               j=0;
310               while( i<len )
311                 {
312                   value[j++] = line[i++];
313                 }
314               value[j] = '\0';
315               
316               match_found = 1;
317               
318               if( !strcasecmp(CONF_KEY_DEFINITION, name) )
319                 {
320                   parse_key_definition(value);
321                 }
322               /* enable colors */
323               else if( !strcasecmp(CONF_ENABLE_COLORS, name) )
324                 {
325                   options->enable_colors = str2bool(value);
326                 }
327               /* auto center */
328               else if( !strcasecmp(CONF_AUTO_CENTER, name) )
329                 {
330                   options->auto_center = str2bool(value);
331                 }
332               /* background color */
333               else if( !strcasecmp(CONF_COLOR_BACKGROUND, name) )
334                 {
335                   if( (color=str2color(value)) >= -1 )
336                     options->bg_color = color;
337                 }
338               /* color - top (title) window */
339               else if( !strcasecmp(CONF_COLOR_TITLE, name) )
340                 {
341                   if( (color=str2color(value)) >= 0 )
342                     options->title_color = color;
343                 }
344               /* color - line (title) window */
345               else if( !strcasecmp(CONF_COLOR_LINE, name) )
346                 {
347                   if( (color=str2color(value)) >= 0 )
348                     options->line_color = color;
349                 }
350               /* color - list window */
351               else if( !strcasecmp(CONF_COLOR_LIST, name) )
352                 {
353                   if( (color=str2color(value)) >= 0 )
354                     options->list_color = color;
355                 }
356               /* color - progress bar */
357               else if( !strcasecmp(CONF_COLOR_PROGRESS, name) )
358                 {
359                   if( (color=str2color(value)) >= 0 )
360                     options->progress_color = color;
361                 }
362               /* color - status window */
363               else if( !strcasecmp(CONF_COLOR_STATUS, name) )
364                 {
365                   if( (color=str2color(value)) >= 0 )
366                     options->status_color = color;
367                 }
368               /* color - alerts */
369               else if( !strcasecmp(CONF_COLOR_ALERT, name) )
370                 {
371                   if( (color=str2color(value)) >= 0 )
372                     options->alert_color = color;
373                 }
374               else if( !strcasecmp(CONF_WIDE_CURSOR, name) )
375                 {
376                   options->wide_cursor = str2bool(value);
377                 }
378               else
379                 {
380                   match_found = 0;
381                 }
382               
384               if( !match_found )
385                 fprintf(stderr, 
386                         "Unknown configuration parameter: %s\n", 
387                         name);
388 #ifdef DEBUG
389               printf( "  %s = %s %s\n", 
390                       name, 
391                       value,
392                       match_found ? "" : "- UNKNOWN SETTING!" );
393 #endif
395             }
396         }         
397     }
399   D(printf( "--\n\n" ));
401   if( free_filename )
402     g_free(filename);
403  
404   return 0;
407 int
408 check_user_conf_dir(void)
410   int retval;
411   char *dirname = g_build_filename(g_get_home_dir(), "." PACKAGE, NULL);
412   
413   if( g_file_test(dirname, G_FILE_TEST_IS_DIR) )
414     {
415       g_free(dirname);
416       return 0;
417     }
418   retval = mkdir(dirname, 0755);
419   g_free(dirname);
420   return retval;
423 char *
424 get_user_key_binding_filename(void)
426   return g_build_filename(g_get_home_dir(), "." PACKAGE, "keys", NULL);
430 int
431 read_configuration(options_t *options)
433   char *filename = NULL;
435   /* check for user configuration ~/.ncmpc/config */
436   filename = g_build_filename(g_get_home_dir(), "." PACKAGE, "config", NULL);
437   if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
438     {
439       g_free(filename);
440       filename = NULL;
441     }
443   /* check for  global configuration SYSCONFDIR/ncmpc/config */
444   if( filename == NULL )
445     {
446       filename = g_build_filename(SYSCONFDIR, PACKAGE, "config", NULL);
447       if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
448         {
449           g_free(filename);
450           filename = NULL;
451         }
452     }
454   /* load configuration */
455   if( filename )
456     {
457       read_rc_file(filename, options);
458       g_free(filename);
459       filename = NULL;
460     }
462   /* check for  user key bindings ~/.ncmpc/keys */
463   filename = get_user_key_binding_filename();
464   if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
465     {
466       g_free(filename);
467       filename = NULL;
468     }
470   /* check for  global key bindings SYSCONFDIR/ncmpc/keys */
471   if( filename == NULL )
472     {
473       filename = g_build_filename(SYSCONFDIR, PACKAGE, "keys", NULL);
474       if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
475         {
476           g_free(filename);
477           filename = NULL;
478         }
479     }
481   /* load key bindings */
482   if( filename )
483     {
484       read_rc_file(filename, options);
485       g_free(filename);
486       filename = NULL;
487     }
489   return 0;