Code

80f40db35fc44c98a92dfad3693d74459f024637
[ncmpc.git] / conf.c
1 #include <ctype.h>
2 #include <stdio.h>
3 #include <errno.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
11 #include <glib.h>
12 #include <ncurses.h>
14 #include "config.h"
15 #include "options.h"
16 #include "support.h"
17 #include "command.h"
18 #include "conf.h"
20 #ifdef DEBUG
21 #define D(x) x
22 #else
23 #define D(x)
24 #endif
26 #define RCFILE "." PACKAGE "rc"
28 #define MAX_LINE_LENGTH 1024
29 #define COMMENT_TOKEN   '#'
31 /* configuration field names */
32 #define CONF_ENABLE_COLORS           "enable_colors"
33 #define CONF_AUTO_CENTER             "auto_center"
35 /* configuration field names - colors */
36 #define CONF_COLOR_BACKGROUND        "background_color"
37 #define CONF_COLOR_TITLE             "title_color"
38 #define CONF_COLOR_LINE              "line_color"
39 #define CONF_COLOR_LIST              "list_color"
40 #define CONF_COLOR_PROGRESS          "progress_color"
41 #define CONF_COLOR_STATUS            "status_color"
42 #define CONF_COLOR_ALERT             "alert_color"
43 #define CONF_KEY_DEFINITION          "key"
45 typedef enum {
46   KEY_PARSER_UNKNOWN,
47   KEY_PARSER_CHAR,
48   KEY_PARSER_DEC,
49   KEY_PARSER_HEX,
50   KEY_PARSER_DONE
51 } key_parser_state_t;
53 static int
54 str2bool(char *str)
55 {
56   if( !strcasecmp(str,"no")  || !strcasecmp(str,"false") || 
57       !strcasecmp(str,"off") || !strcasecmp(str,"0") )
58     return 0;
59   return 1;
60 }
62 static int
63 str2color(char *str)
64 {
65   if( !strcasecmp(str,"black") )
66     return COLOR_BLACK;
67   else if( !strcasecmp(str,"red") )
68     return COLOR_RED;
69   else if( !strcasecmp(str,"green") )
70     return COLOR_GREEN;
71   else if( !strcasecmp(str,"yellow") )
72     return COLOR_YELLOW;
73   else if( !strcasecmp(str,"blue") )
74     return COLOR_BLUE;
75   else if( !strcasecmp(str,"magenta") )
76     return COLOR_MAGENTA;
77   else if( !strcasecmp(str,"cyan") )
78     return COLOR_CYAN;
79   else if( !strcasecmp(str,"white") )
80     return COLOR_WHITE;
81   fprintf(stderr,"Warning: unknown color %s\n", str);
82   return -1;
83 }
85 static int
86 parse_key_value(char *str, size_t len, char **end)
87 {
88   int i, value;
89   key_parser_state_t state;
91   i=0;
92   value=0;
93   state=KEY_PARSER_UNKNOWN;
94   *end = str;
96   while( i<len && state!=KEY_PARSER_DONE )
97     {
98       int next = 0;
99       int c = str[i];
101       if( i+1<len )
102         next = str[i+1];
104       switch(state)
105         {
106         case KEY_PARSER_UNKNOWN:
107           if( c=='\'' )
108             state = KEY_PARSER_CHAR;
109           else if( c=='0' && next=='x' )
110             state = KEY_PARSER_HEX;
111           else if( isdigit(c) )
112             state = KEY_PARSER_DEC;
113           else {
114             fprintf(stderr, "Error: Unsupported key definition - %s\n", str);
115             return -1;
116           }
117           break;
118         case KEY_PARSER_CHAR:
119           if( next!='\'' )
120             {
121               fprintf(stderr, "Error: Unsupported key definition - %s\n", str);
122               return -1;
123             }
124           value = c;
125           *end = str+i+2;
126           state = KEY_PARSER_DONE;
127           break;
128         case KEY_PARSER_DEC:
129           value = (int) strtol(str+(i-1), end, 10);
130           state = KEY_PARSER_DONE;
131           break;
132         case KEY_PARSER_HEX:
133           if( !isdigit(next) )
134             {
135               fprintf(stderr, "Error: Digit expexted after 0x - %s\n", str);
136               return -1;
137             }
138           value = (int) strtol(str+(i+1), end, 16);
139           state = KEY_PARSER_DONE;
140           break;
141         case KEY_PARSER_DONE:
142           break;
143         }
144       i++;
145     }
147   if( *end> str+len )
148     *end = str+len;
150   return value;
153 static int
154 parse_key_definition(char *str)
156   char buf[MAX_LINE_LENGTH];
157   char *p, *end;
158   size_t len = strlen(str);
159   int i,j,key;
160   int keys[MAX_COMMAND_KEYS];
161   command_t cmd;
163   /* get the command name */
164   i=0;
165   j=0;
166   memset(buf, 0, MAX_LINE_LENGTH);
167   while( i<len && str[i]!='=' && !IS_WHITESPACE(str[i]) )
168     buf[j++] = str[i++];
169   if( (cmd=get_key_command_from_name(buf)) == CMD_NONE )
170     {
171       fprintf(stderr, "Error: Unknown key command %s\n", buf);
172       return -1;
173     }
175   /* skip whitespace */
176   while( i<len && (str[i]=='=' || IS_WHITESPACE(str[i])) )
177     i++;
179   /* get the value part */
180   memset(buf, 0, MAX_LINE_LENGTH);
181   strncpy(buf, str+i, len-i);
182   len = strlen(buf);
183   if( len==0 )
184     {
185       fprintf(stderr,"Error: Incomplete key definition - %s\n", str);
186       return -1;
187     }
189   /* parse key values */
190   i = 0;
191   key = 0;
192   len = strlen(buf);
193   p = buf;
194   end = buf+len;
195   memset(keys, 0, sizeof(int)*MAX_COMMAND_KEYS);
196   while( i<MAX_COMMAND_KEYS && p<end && (key=parse_key_value(p,len+1,&p))>=0 )
197     {
198       keys[i++] = key;
199       while( p<end && (*p==',' || *p==' ' || *p=='\t') )
200         p++;
201       len = strlen(p);
202     } 
203   if( key<0 )
204     {
205       fprintf(stderr,"Error: Bad key definition - %s\n", str);
206       return -1;
207     }
209   return assign_keys(cmd, keys);
212 static int
213 read_rc_file(char *filename, options_t *options)
215   int fd;
216   int quit  = 0;
217   int color = -1;
218   int free_filename = 0;
220   if( filename==NULL )
221     return -1;
223   D(printf("Reading configuration file %s\n", filename));
224   if( (fd=open(filename,O_RDONLY)) <0 )
225     {
226       D(perror(filename));
227       if( free_filename )
228         g_free(filename);
229       return -1;
230     }
232   while( !quit )
233     {
234       int i,j;
235       int len;
236       int match_found;
237       char line[MAX_LINE_LENGTH];
238       char name[MAX_LINE_LENGTH];
239       char value[MAX_LINE_LENGTH];
241       line[0]  = '\0';
242       value[0] = '\0';
244       i = 0;
245       /* read a line ending with '\n' */
246       do {
247         len = read( fd, &line[i], 1 );
248         if( len == 1 )
249           i++;
250         else
251           quit = 1;
252       } while( !quit && i<MAX_LINE_LENGTH && line[i-1]!='\n' );
253       
254      
255       /* remove trailing whitespace */
256       line[i] = '\0';
257       i--;
258       while( i>=0 && IS_WHITESPACE(line[i]) )
259         {
260           line[i] = '\0';
261           i--;
262         }     
263       len = i+1;
265       if( len>0 )
266         {
267           i = 0;
268           /* skip whitespace */
269           while( i<len && IS_WHITESPACE(line[i]) )
270             i++;
271           
272           /* continue if this line is not a comment */
273           if( line[i] != COMMENT_TOKEN )
274             {
275               /* get the name part */
276               j=0;
277               while( i<len && line[i]!='=' && !IS_WHITESPACE(line[i]) )
278                 {
279                   name[j++] = line[i++];
280                 }
281               name[j] = '\0';
282               
283               /* skip '=' and whitespace */
284               while( i<len && (line[i]=='=' || IS_WHITESPACE(line[i])) )
285                 i++;
286               
287               /* get the value part */
288               j=0;
289               while( i<len )
290                 {
291                   value[j++] = line[i++];
292                 }
293               value[j] = '\0';
294               
295               match_found = 0;
296               
297               if( !strcasecmp(CONF_KEY_DEFINITION, name) )
298                 {
299                   parse_key_definition(value);
300                   match_found = 1;
301                 }
302               /* enable colors */
303               else if( !strcasecmp(CONF_ENABLE_COLORS, name) )
304                 {
305                   options->enable_colors = str2bool(value);
306                   match_found = 1;
307                 }
308               /* auto center */
309               else if( !strcasecmp(CONF_AUTO_CENTER, name) )
310                 {
311                   options->auto_center = str2bool(value);
312                   match_found = 1;
313                 }
314               /* background color */
315               else if( !strcasecmp(CONF_COLOR_BACKGROUND, name) )
316                 {
317                   if( (color=str2color(value)) >= 0 )
318                     options->bg_color = color;
319                   match_found = 1;
320                 }
321               /* color - top (title) window */
322               else if( !strcasecmp(CONF_COLOR_TITLE, name) )
323                 {
324                   if( (color=str2color(value)) >= 0 )
325                     options->title_color = color;
326                   match_found = 1;
327                 }
328               /* color - line (title) window */
329               else if( !strcasecmp(CONF_COLOR_LINE, name) )
330                 {
331                   if( (color=str2color(value)) >= 0 )
332                     options->line_color = color;
333                   match_found = 1;
334                 }
335               /* color - list window */
336               else if( !strcasecmp(CONF_COLOR_LIST, name) )
337                 {
338                   if( (color=str2color(value)) >= 0 )
339                     options->list_color = color;
340                   match_found = 1;
341                 }
342               /* color - progress bar */
343               else if( !strcasecmp(CONF_COLOR_PROGRESS, name) )
344                 {
345                   if( (color=str2color(value)) >= 0 )
346                     options->progress_color = color;
347                   match_found = 1;
348                 }
349               /* color - status window */
350               else if( !strcasecmp(CONF_COLOR_STATUS, name) )
351                 {
352                   if( (color=str2color(value)) >= 0 )
353                     options->status_color = color;
354                   match_found = 1;
355                 }
356               /* color - alerts */
357               else if( !strcasecmp(CONF_COLOR_ALERT, name) )
358                 {
359                   if( (color=str2color(value)) >= 0 )
360                     options->alert_color = color;
361                   match_found = 1;
362                 }
363               
365               if( !match_found )
366                 fprintf(stderr, 
367                         "Unknown configuration parameter: %s\n", 
368                         name);
369 #ifdef DEBUG
370               printf( "  %s = %s %s\n", 
371                       name, 
372                       value,
373                       match_found ? "" : "- UNKNOWN SETTING!" );
374 #endif
376             }
377         }         
378     }
380   D(printf( "--\n\n" ));
382   if( free_filename )
383     g_free(filename);
384  
385   return 0;
389 int
390 read_configuration(options_t *options)
392   char *filename = NULL;
394   /* check for user configuration ~/.ncmpc/config */
395   filename = g_build_filename(g_get_home_dir(), "." PACKAGE, "config", NULL);
396   if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
397     {
398       g_free(filename);
399       filename = NULL;
400     }
402   /* check for  global configuration SYSCONFDIR/ncmpc/config */
403   if( filename == NULL )
404     {
405       filename = g_build_filename(SYSCONFDIR, PACKAGE, "config", NULL);
406       if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
407         {
408           g_free(filename);
409           filename = NULL;
410         }
411     }
413   /* load configuration */
414   if( filename )
415     {
416       read_rc_file(filename, options);
417       g_free(filename);
418       filename = NULL;
419     }
421   /* check for  user key bindings ~/.ncmpc/keys */
422   filename = g_build_filename(g_get_home_dir(), "." PACKAGE, "keys", NULL);
423   if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
424     {
425       g_free(filename);
426       filename = NULL;
427     }
429   /* check for  global key bindings SYSCONFDIR/ncmpc/keys */
430   if( filename == NULL )
431     {
432       filename = g_build_filename(SYSCONFDIR, PACKAGE, "keys", NULL);
433       if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
434         {
435           g_free(filename);
436           filename = NULL;
437         }
438     }
440   /* load key bindings */
441   if( filename )
442     {
443       read_rc_file(filename, options);
444       g_free(filename);
445       filename = NULL;
446       //write_key_bindings(stderr);
447     }
449   return 0;