Code

git-svn-id: https://svn.musicpd.org/ncmpc/trunk@763 09075e82-0dd4-0310-85a5-a0d7c8717e4f
[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_WIDE_CURSOR             "wide_cursor"
44 #define CONF_KEY_DEFINITION          "key"
46 typedef enum {
47   KEY_PARSER_UNKNOWN,
48   KEY_PARSER_CHAR,
49   KEY_PARSER_DEC,
50   KEY_PARSER_HEX,
51   KEY_PARSER_DONE
52 } key_parser_state_t;
54 static int
55 str2bool(char *str)
56 {
57   if( !strcasecmp(str,"no")  || !strcasecmp(str,"false") || 
58       !strcasecmp(str,"off") || !strcasecmp(str,"0") )
59     return 0;
60   return 1;
61 }
63 static int
64 str2color(char *str)
65 {
66   if( !strcasecmp(str,"black") )
67     return COLOR_BLACK;
68   else if( !strcasecmp(str,"red") )
69     return COLOR_RED;
70   else if( !strcasecmp(str,"green") )
71     return COLOR_GREEN;
72   else if( !strcasecmp(str,"yellow") )
73     return COLOR_YELLOW;
74   else if( !strcasecmp(str,"blue") )
75     return COLOR_BLUE;
76   else if( !strcasecmp(str,"magenta") )
77     return COLOR_MAGENTA;
78   else if( !strcasecmp(str,"cyan") )
79     return COLOR_CYAN;
80   else if( !strcasecmp(str,"white") )
81     return COLOR_WHITE;
82   fprintf(stderr,"Warning: unknown color %s\n", str);
83   return -1;
84 }
86 static int
87 parse_key_value(char *str, size_t len, char **end)
88 {
89   int i, value;
90   key_parser_state_t state;
92   i=0;
93   value=0;
94   state=KEY_PARSER_UNKNOWN;
95   *end = str;
97   while( i<len && state!=KEY_PARSER_DONE )
98     {
99       int next = 0;
100       int c = str[i];
102       if( i+1<len )
103         next = str[i+1];
105       switch(state)
106         {
107         case KEY_PARSER_UNKNOWN:
108           if( c=='\'' )
109             state = KEY_PARSER_CHAR;
110           else if( c=='0' && next=='x' )
111             state = KEY_PARSER_HEX;
112           else if( isdigit(c) )
113             state = KEY_PARSER_DEC;
114           else {
115             fprintf(stderr, "Error: Unsupported key definition - %s\n", str);
116             return -1;
117           }
118           break;
119         case KEY_PARSER_CHAR:
120           if( next!='\'' )
121             {
122               fprintf(stderr, "Error: Unsupported key definition - %s\n", str);
123               return -1;
124             }
125           value = c;
126           *end = str+i+2;
127           state = KEY_PARSER_DONE;
128           break;
129         case KEY_PARSER_DEC:
130           value = (int) strtol(str+(i-1), end, 10);
131           state = KEY_PARSER_DONE;
132           break;
133         case KEY_PARSER_HEX:
134           if( !isdigit(next) )
135             {
136               fprintf(stderr, "Error: Digit expexted after 0x - %s\n", str);
137               return -1;
138             }
139           value = (int) strtol(str+(i+1), end, 16);
140           state = KEY_PARSER_DONE;
141           break;
142         case KEY_PARSER_DONE:
143           break;
144         }
145       i++;
146     }
148   if( *end> str+len )
149     *end = str+len;
151   return value;
154 static int
155 parse_key_definition(char *str)
157   char buf[MAX_LINE_LENGTH];
158   char *p, *end;
159   size_t len = strlen(str);
160   int i,j,key;
161   int keys[MAX_COMMAND_KEYS];
162   command_t cmd;
164   /* get the command name */
165   i=0;
166   j=0;
167   memset(buf, 0, MAX_LINE_LENGTH);
168   while( i<len && str[i]!='=' && !IS_WHITESPACE(str[i]) )
169     buf[j++] = str[i++];
170   if( (cmd=get_key_command_from_name(buf)) == CMD_NONE )
171     {
172       fprintf(stderr, "Error: Unknown key command %s\n", buf);
173       return -1;
174     }
176   /* skip whitespace */
177   while( i<len && (str[i]=='=' || IS_WHITESPACE(str[i])) )
178     i++;
180   /* get the value part */
181   memset(buf, 0, MAX_LINE_LENGTH);
182   strncpy(buf, str+i, len-i);
183   len = strlen(buf);
184   if( len==0 )
185     {
186       fprintf(stderr,"Error: Incomplete key definition - %s\n", str);
187       return -1;
188     }
190   /* parse key values */
191   i = 0;
192   key = 0;
193   len = strlen(buf);
194   p = buf;
195   end = buf+len;
196   memset(keys, 0, sizeof(int)*MAX_COMMAND_KEYS);
197   while( i<MAX_COMMAND_KEYS && p<end && (key=parse_key_value(p,len+1,&p))>=0 )
198     {
199       keys[i++] = key;
200       while( p<end && (*p==',' || *p==' ' || *p=='\t') )
201         p++;
202       len = strlen(p);
203     } 
204   if( key<0 )
205     {
206       fprintf(stderr,"Error: Bad key definition - %s\n", str);
207       return -1;
208     }
210   return assign_keys(cmd, keys);
213 static int
214 read_rc_file(char *filename, options_t *options)
216   int fd;
217   int quit  = 0;
218   int color = -1;
219   int free_filename = 0;
221   if( filename==NULL )
222     return -1;
224   D(printf("Reading configuration file %s\n", filename));
225   if( (fd=open(filename,O_RDONLY)) <0 )
226     {
227       D(perror(filename));
228       if( free_filename )
229         g_free(filename);
230       return -1;
231     }
233   while( !quit )
234     {
235       int i,j;
236       int len;
237       int match_found;
238       char line[MAX_LINE_LENGTH];
239       char name[MAX_LINE_LENGTH];
240       char value[MAX_LINE_LENGTH];
242       line[0]  = '\0';
243       value[0] = '\0';
245       i = 0;
246       /* read a line ending with '\n' */
247       do {
248         len = read( fd, &line[i], 1 );
249         if( len == 1 )
250           i++;
251         else
252           quit = 1;
253       } while( !quit && i<MAX_LINE_LENGTH && line[i-1]!='\n' );
254       
255      
256       /* remove trailing whitespace */
257       line[i] = '\0';
258       i--;
259       while( i>=0 && IS_WHITESPACE(line[i]) )
260         {
261           line[i] = '\0';
262           i--;
263         }     
264       len = i+1;
266       if( len>0 )
267         {
268           i = 0;
269           /* skip whitespace */
270           while( i<len && IS_WHITESPACE(line[i]) )
271             i++;
272           
273           /* continue if this line is not a comment */
274           if( line[i] != COMMENT_TOKEN )
275             {
276               /* get the name part */
277               j=0;
278               while( i<len && line[i]!='=' && !IS_WHITESPACE(line[i]) )
279                 {
280                   name[j++] = line[i++];
281                 }
282               name[j] = '\0';
283               
284               /* skip '=' and whitespace */
285               while( i<len && (line[i]=='=' || IS_WHITESPACE(line[i])) )
286                 i++;
287               
288               /* get the value part */
289               j=0;
290               while( i<len )
291                 {
292                   value[j++] = line[i++];
293                 }
294               value[j] = '\0';
295               
296               match_found = 1;
297               
298               if( !strcasecmp(CONF_KEY_DEFINITION, name) )
299                 {
300                   parse_key_definition(value);
301                 }
302               /* enable colors */
303               else if( !strcasecmp(CONF_ENABLE_COLORS, name) )
304                 {
305                   options->enable_colors = str2bool(value);
306                 }
307               /* auto center */
308               else if( !strcasecmp(CONF_AUTO_CENTER, name) )
309                 {
310                   options->auto_center = str2bool(value);
311                 }
312               /* background color */
313               else if( !strcasecmp(CONF_COLOR_BACKGROUND, name) )
314                 {
315                   if( (color=str2color(value)) >= 0 )
316                     options->bg_color = color;
317                 }
318               /* color - top (title) window */
319               else if( !strcasecmp(CONF_COLOR_TITLE, name) )
320                 {
321                   if( (color=str2color(value)) >= 0 )
322                     options->title_color = color;
323                 }
324               /* color - line (title) window */
325               else if( !strcasecmp(CONF_COLOR_LINE, name) )
326                 {
327                   if( (color=str2color(value)) >= 0 )
328                     options->line_color = color;
329                 }
330               /* color - list window */
331               else if( !strcasecmp(CONF_COLOR_LIST, name) )
332                 {
333                   if( (color=str2color(value)) >= 0 )
334                     options->list_color = color;
335                 }
336               /* color - progress bar */
337               else if( !strcasecmp(CONF_COLOR_PROGRESS, name) )
338                 {
339                   if( (color=str2color(value)) >= 0 )
340                     options->progress_color = color;
341                 }
342               /* color - status window */
343               else if( !strcasecmp(CONF_COLOR_STATUS, name) )
344                 {
345                   if( (color=str2color(value)) >= 0 )
346                     options->status_color = color;
347                 }
348               /* color - alerts */
349               else if( !strcasecmp(CONF_COLOR_ALERT, name) )
350                 {
351                   if( (color=str2color(value)) >= 0 )
352                     options->alert_color = color;
353                 }
354               else if( !strcasecmp(CONF_WIDE_CURSOR, name) )
355                 {
356                   options->wide_cursor = str2bool(value);
357                 }
358               else
359                 {
360                   match_found = 0;
361                 }
362               
364               if( !match_found )
365                 fprintf(stderr, 
366                         "Unknown configuration parameter: %s\n", 
367                         name);
368 #ifdef DEBUG
369               printf( "  %s = %s %s\n", 
370                       name, 
371                       value,
372                       match_found ? "" : "- UNKNOWN SETTING!" );
373 #endif
375             }
376         }         
377     }
379   D(printf( "--\n\n" ));
381   if( free_filename )
382     g_free(filename);
383  
384   return 0;
388 int
389 read_configuration(options_t *options)
391   char *filename = NULL;
393   /* check for user configuration ~/.ncmpc/config */
394   filename = g_build_filename(g_get_home_dir(), "." PACKAGE, "config", NULL);
395   if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
396     {
397       g_free(filename);
398       filename = NULL;
399     }
401   /* check for  global configuration SYSCONFDIR/ncmpc/config */
402   if( filename == NULL )
403     {
404       filename = g_build_filename(SYSCONFDIR, PACKAGE, "config", NULL);
405       if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
406         {
407           g_free(filename);
408           filename = NULL;
409         }
410     }
412   /* load configuration */
413   if( filename )
414     {
415       read_rc_file(filename, options);
416       g_free(filename);
417       filename = NULL;
418     }
420   /* check for  user key bindings ~/.ncmpc/keys */
421   filename = g_build_filename(g_get_home_dir(), "." PACKAGE, "keys", NULL);
422   if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
423     {
424       g_free(filename);
425       filename = NULL;
426     }
428   /* check for  global key bindings SYSCONFDIR/ncmpc/keys */
429   if( filename == NULL )
430     {
431       filename = g_build_filename(SYSCONFDIR, PACKAGE, "keys", NULL);
432       if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
433         {
434           g_free(filename);
435           filename = NULL;
436         }
437     }
439   /* load key bindings */
440   if( filename )
441     {
442       read_rc_file(filename, options);
443       g_free(filename);
444       filename = NULL;
445       //write_key_bindings(stderr);
446     }
448   return 0;