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;
152 }
154 static int
155 parse_key_definition(char *str)
156 {
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);
211 }
213 static int
214 read_rc_file(char *filename, options_t *options)
215 {
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' );
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++;
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';
284 /* skip '=' and whitespace */
285 while( i<len && (line[i]=='=' || IS_WHITESPACE(line[i])) )
286 i++;
288 /* get the value part */
289 j=0;
290 while( i<len )
291 {
292 value[j++] = line[i++];
293 }
294 value[j] = '\0';
296 match_found = 1;
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 }
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);
384 return 0;
385 }
388 int
389 read_configuration(options_t *options)
390 {
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;
449 }