Code

Added the strscroll function
[ncmpc.git] / src / 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>
31 #include "config.h"
32 #include "ncmpc.h"
33 #include "options.h"
34 #include "support.h"
35 #include "command.h"
36 #include "colors.h"
37 #include "conf.h"
39 #define ENABLE_OLD_COLOR_SYNTAX
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_KEY_DEFINITION          "key"
49 #define CONF_COLOR                   "color"
50 #define CONF_COLOR_DEFINITION        "colordef"
52 /* Deprecated - configuration field names */
53 #define CONF_COLOR_BACKGROUND        "background_color"
54 #define CONF_COLOR_TITLE             "title_color"
55 #define CONF_COLOR_LINE              "line_color"
56 #define CONF_COLOR_LIST              "list_color"
57 #define CONF_COLOR_PROGRESS          "progress_color"
58 #define CONF_COLOR_STATUS            "status_color"
59 #define CONF_COLOR_ALERT             "alert_color"
62 typedef enum {
63   KEY_PARSER_UNKNOWN,
64   KEY_PARSER_CHAR,
65   KEY_PARSER_DEC,
66   KEY_PARSER_HEX,
67   KEY_PARSER_DONE
68 } key_parser_state_t;
70 static int
71 str2bool(char *str)
72 {
73   if( !strcasecmp(str,"no")  || !strcasecmp(str,"false") || 
74       !strcasecmp(str,"off") || !strcasecmp(str,"0") )
75     return 0;
76   return 1;
77 }
79 static int
80 parse_key_value(char *str, size_t len, char **end)
81 {
82   int i, value;
83   key_parser_state_t state;
85   i=0;
86   value=0;
87   state=KEY_PARSER_UNKNOWN;
88   *end = str;
90   while( i<len && state!=KEY_PARSER_DONE )
91     {
92       int next = 0;
93       int c = str[i];
95       if( i+1<len )
96         next = str[i+1];
98       switch(state)
99         {
100         case KEY_PARSER_UNKNOWN:
101           if( c=='\'' )
102             state = KEY_PARSER_CHAR;
103           else if( c=='0' && next=='x' )
104             state = KEY_PARSER_HEX;
105           else if( isdigit(c) )
106             state = KEY_PARSER_DEC;
107           else {
108             fprintf(stderr,
109                     _("Error: Unsupported key definition - %s\n"), 
110                     str);
111             return -1;
112           }
113           break;
114         case KEY_PARSER_CHAR:
115           if( next!='\'' )
116             {
117               fprintf(stderr,
118                       _("Error: Unsupported key definition - %s\n"), 
119                       str);
120               return -1;
121             }
122           value = c;
123           *end = str+i+2;
124           state = KEY_PARSER_DONE;
125           break;
126         case KEY_PARSER_DEC:
127           value = (int) strtol(str+(i-1), end, 10);
128           state = KEY_PARSER_DONE;
129           break;
130         case KEY_PARSER_HEX:
131           if( !isdigit(next) )
132             {
133               fprintf(stderr,_("Error: Digit expexted after 0x - %s\n"), str);
134               return -1;
135             }
136           value = (int) strtol(str+(i+1), end, 16);
137           state = KEY_PARSER_DONE;
138           break;
139         case KEY_PARSER_DONE:
140           break;
141         }
142       i++;
143     }
145   if( *end> str+len )
146     *end = str+len;
148   return value;
151 static int
152 parse_key_definition(char *str)
154   char buf[MAX_LINE_LENGTH];
155   char *p, *end;
156   size_t len = strlen(str);
157   int i,j,key;
158   int keys[MAX_COMMAND_KEYS];
159   command_t cmd;
161   /* get the command name */
162   i=0;
163   j=0;
164   memset(buf, 0, MAX_LINE_LENGTH);
165   while( i<len && str[i]!='=' && !IS_WHITESPACE(str[i]) )
166     buf[j++] = str[i++];
167   if( (cmd=get_key_command_from_name(buf)) == CMD_NONE )
168     {
169       fprintf(stderr, _("Error: Unknown key command %s\n"), buf);
170       return -1;
171     }
173   /* skip whitespace */
174   while( i<len && (str[i]=='=' || IS_WHITESPACE(str[i])) )
175     i++;
177   /* get the value part */
178   memset(buf, 0, MAX_LINE_LENGTH);
179   strncpy(buf, str+i, len-i);
180   len = strlen(buf);
181   if( len==0 )
182     {
183       fprintf(stderr,_("Error: Incomplete key definition - %s\n"), str);
184       return -1;
185     }
187   /* parse key values */
188   i = 0;
189   key = 0;
190   len = strlen(buf);
191   p = buf;
192   end = buf+len;
193   memset(keys, 0, sizeof(int)*MAX_COMMAND_KEYS);
194   while( i<MAX_COMMAND_KEYS && p<end && (key=parse_key_value(p,len+1,&p))>=0 )
195     {
196       keys[i++] = key;
197       while( p<end && (*p==',' || *p==' ' || *p=='\t') )
198         p++;
199       len = strlen(p);
200     } 
201   if( key<0 )
202     {
203       fprintf(stderr,_("Error: Bad key definition - %s\n"), str);
204       return -1;
205     }
207   return assign_keys(cmd, keys);
210 static int
211 parse_color(char *str)
213   char *name = str;
214   char *value = NULL;
215   int len,i;
217   i=0;
218   len=strlen(str);
219   /* get the color name */
220   while( i<len && str[i]!='=' && !IS_WHITESPACE(str[i]) )
221     i++;
222   
223   /* skip whitespace */
224   while( i<len && (str[i]=='=' || IS_WHITESPACE(str[i])) )
225     {
226       str[i]='\0';
227       i++;
228     } 
229   
230   if( i<len )
231     value = str+i;
233   return colors_assign(name, value);
237 static int
238 parse_color_definition(char *str)
240   char buf[MAX_LINE_LENGTH];
241   char *p, *end, *name;
242   size_t len = strlen(str);
243   int i,j,value;
244   short color, rgb[3];
246   /* get the command name */
247   i=0;
248   j=0;
249   memset(buf, 0, MAX_LINE_LENGTH);
250   while( i<len && str[i]!='=' && !IS_WHITESPACE(str[i]) )
251     buf[j++] = str[i++];
252   color=colors_str2color(buf);
253   if( color<0 )
254     {
255       fprintf(stderr,_("Error: Bad color %s [%d]\n"), buf, color);
256       return -1;
257     }
258   name = g_strdup(buf);
260   /* skip whitespace */
261   while( i<len && (str[i]=='=' || IS_WHITESPACE(str[i])) )
262     i++;
264   /* get the value part */
265   memset(buf, 0, MAX_LINE_LENGTH);
266   strncpy(buf, str+i, len-i);
267   len = strlen(buf);
268   if( len==0 )
269     {
270       fprintf(stderr,_("Error: Incomplete color definition - %s\n"), str);
271       g_free(name);
272       return -1;
273     }
275   /* parse r,g.b values with the key definition parser */
276   i = 0;
277   value = 0;
278   len = strlen(buf);
279   p = buf;
280   end = buf+len;
281   memset(rgb, 0, sizeof(short)*3);
282   while( i<3 && p<end && (value=parse_key_value(p,len+1,&p))>=0 )
283     {
284       rgb[i++] = value;
285       while( p<end && (*p==',' || *p==' ' || *p=='\t') )
286         p++;
287       len = strlen(p);
288     } 
289   if( value<0 || i!=3)
290     {
291       fprintf(stderr,_("Error: Bad color definition - %s\n"), str);
292       g_free(name);
293       return -1;
294     }
295   value = colors_define(name, rgb[0], rgb[1], rgb[2]);
296   g_free(name);
297   return value;
301 static int
302 read_rc_file(char *filename, options_t *options)
304   int fd;
305   int quit  = 0;
306   int free_filename = 0;
308   if( filename==NULL )
309     return -1;
311   D(printf("Reading configuration file %s\n", filename));
312   if( (fd=open(filename,O_RDONLY)) <0 )
313     {
314       perror(filename);
315       if( free_filename )
316         g_free(filename);
317       return -1;
318     }
320   while( !quit )
321     {
322       int i,j;
323       int len;
324       int match_found;
325       char line[MAX_LINE_LENGTH];
326       char name[MAX_LINE_LENGTH];
327       char value[MAX_LINE_LENGTH];
329       line[0]  = '\0';
330       value[0] = '\0';
332       i = 0;
333       /* read a line ending with '\n' */
334       do {
335         len = read( fd, &line[i], 1 );
336         if( len == 1 )
337           i++;
338         else
339           quit = 1;
340       } while( !quit && i<MAX_LINE_LENGTH && line[i-1]!='\n' );
341       
342      
343       /* remove trailing whitespace */
344       line[i] = '\0';
345       i--;
346       while( i>=0 && IS_WHITESPACE(line[i]) )
347         {
348           line[i] = '\0';
349           i--;
350         }     
351       len = i+1;
353       if( len>0 )
354         {
355           i = 0;
356           /* skip whitespace */
357           while( i<len && IS_WHITESPACE(line[i]) )
358             i++;
359           
360           /* continue if this line is not a comment */
361           if( line[i] != COMMENT_TOKEN )
362             {
363               /* get the name part */
364               j=0;
365               while( i<len && line[i]!='=' && !IS_WHITESPACE(line[i]) )
366                 {
367                   name[j++] = line[i++];
368                 }
369               name[j] = '\0';
370               
371               /* skip '=' and whitespace */
372               while( i<len && (line[i]=='=' || IS_WHITESPACE(line[i])) )
373                 i++;
374               
375               /* get the value part */
376               j=0;
377               while( i<len )
378                 {
379                   value[j++] = line[i++];
380                 }
381               value[j] = '\0';
382               
383               match_found = 1;
385               /* key definition */
386               if( !strcasecmp(CONF_KEY_DEFINITION, name) )
387                 {
388                   parse_key_definition(value);
389                 }
390               /* enable colors */
391               else if( !strcasecmp(CONF_ENABLE_COLORS, name) )
392                 {
393                   options->enable_colors = str2bool(value);
394                 }
395               /* auto center */
396               else if( !strcasecmp(CONF_AUTO_CENTER, name) )
397                 {
398                   options->auto_center = str2bool(value);
399                 }
400               /* color assignment */
401               else if( !strcasecmp(CONF_COLOR, name) )
402                 {
403                   parse_color(value);
404                 }
405 #ifdef ENABLE_OLD_COLOR_SYNTAX
406               /* background color */
407               else if( !strcasecmp(CONF_COLOR_BACKGROUND, name) )
408                 {
409                   fprintf(stderr,"%s: %s - deprecated!\n", filename,name);
410                   colors_assign("background", value);
411                 }
412               /* color - top (title) window */
413               else if( !strcasecmp(CONF_COLOR_TITLE, name) )
414                 {
415                   fprintf(stderr,"%s: %s - deprecated!\n", filename,name);
416                   colors_assign("title", value);
417                   colors_assign("title2", value);
418                 }
419               /* color - line (title) window */
420               else if( !strcasecmp(CONF_COLOR_LINE, name) )
421                 {
422                   fprintf(stderr,"%s: %s - deprecated!\n", filename,name);
423                   colors_assign("line", value);
424                   colors_assign("line2", value);
425                 }
426               /* color - list window */
427               else if( !strcasecmp(CONF_COLOR_LIST, name) )
428                 {
429                   fprintf(stderr,"%s: %s - deprecated!\n", filename,name);
430                   colors_assign("list", value);
431                 }
432               /* color - progress bar */
433               else if( !strcasecmp(CONF_COLOR_PROGRESS, name) )
434                 {
435                   fprintf(stderr,"%s: %s - deprecated!\n", filename,name);
436                   colors_assign("progressbar", value);
437                 }
438               /* color - status window */
439               else if( !strcasecmp(CONF_COLOR_STATUS, name) )
440                 {
441                   fprintf(stderr,"%s: %s - deprecated!\n", filename,name);
442                   colors_assign("status", value);
443                   colors_assign("status2", value);
444                 }
445               /* color - alerts */
446               else if( !strcasecmp(CONF_COLOR_ALERT, name) )
447                 {
448                   fprintf(stderr,"%s: %s - deprecated!\n", filename,name);
449                   colors_assign("alert", value);
450                 }
451 #endif
452               /* wide cursor */
453               else if( !strcasecmp(CONF_WIDE_CURSOR, name) )
454                 {
455                   options->wide_cursor = str2bool(value);
456                 }
457               /* color definition */
458               else if( !strcasecmp(CONF_COLOR_DEFINITION, name) )
459                 {
460                   parse_color_definition(value);
461                 }
462               else
463                 {
464                   match_found = 0;
465                 }
466               
468               if( !match_found )
469                 fprintf(stderr, 
470                         _("Unknown configuration parameter: %s\n"), 
471                         name);
472 #ifdef DEBUG
473               printf( "  %s = %s %s\n", 
474                       name, 
475                       value,
476                       match_found ? "" : "- UNKNOWN SETTING!" );
477 #endif
479             }
480         }         
481     }
483   D(printf( "--\n\n" ));
485   if( free_filename )
486     g_free(filename);
487  
488   return 0;
491 int
492 check_user_conf_dir(void)
494   int retval;
495   char *dirname = g_build_filename(g_get_home_dir(), "." PACKAGE, NULL);
496   
497   if( g_file_test(dirname, G_FILE_TEST_IS_DIR) )
498     {
499       g_free(dirname);
500       return 0;
501     }
502   retval = mkdir(dirname, 0755);
503   g_free(dirname);
504   return retval;
507 char *
508 get_user_key_binding_filename(void)
510   return g_build_filename(g_get_home_dir(), "." PACKAGE, "keys", NULL);
514 int
515 read_configuration(options_t *options)
517   char *filename = NULL;
519   /* check for command line configuration file */
520   if( options->config_file )
521     filename = g_strdup(options->config_file);
523   /* check for user configuration ~/.ncmpc/config */
524   if( filename == NULL )
525     {
526       filename = g_build_filename(g_get_home_dir(), 
527                                   "." PACKAGE, "config", NULL);
528       if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
529         {
530           g_free(filename);
531           filename = NULL;
532         }
533     }
535   /* check for  global configuration SYSCONFDIR/ncmpc/config */
536   if( filename == NULL )
537     {
538       filename = g_build_filename(SYSCONFDIR, PACKAGE, "config", NULL);
539       if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
540         {
541           g_free(filename);
542           filename = NULL;
543         }
544     }
546   /* load configuration */
547   if( filename )
548     {
549       read_rc_file(filename, options);
550       g_free(filename);
551       filename = NULL;
552     }
554   /* check for command line key binding file */
555   if( options->key_file )
556     filename = g_strdup(options->key_file);
558   /* check for  user key bindings ~/.ncmpc/keys */
559   if( filename == NULL )
560     {
561       filename = get_user_key_binding_filename();
562       if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
563         {
564           g_free(filename);
565           filename = NULL;
566         }
567     }
569   /* check for  global key bindings SYSCONFDIR/ncmpc/keys */
570   if( filename == NULL )
571     {
572       filename = g_build_filename(SYSCONFDIR, PACKAGE, "keys", NULL);
573       if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
574         {
575           g_free(filename);
576           filename = NULL;
577         }
578     }
580   /* load key bindings */
581   if( filename )
582     {
583       read_rc_file(filename, options);
584       g_free(filename);
585       filename = NULL;
586     }
588   return 0;