Code

Added list-format and status-format conf options
[ncmpc.git] / src / conf.c
1 /* 
2  * $Id$
3  *
4  * (c) 2004 by Kalle Wallin <kaw@linux.se>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
21 #include <ctype.h>
22 #include <stdio.h>
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
31 #include <glib.h>
32 #include <ncurses.h>
33 #include "config.h"
34 #include "ncmpc.h"
35 #include "options.h"
36 #include "support.h"
37 #include "command.h"
38 #include "colors.h"
39 #include "conf.h"
41 #define ENABLE_OLD_SYNTAX
43 #define MAX_LINE_LENGTH 1024
44 #define COMMENT_TOKEN   '#'
46 /* configuration field names */
47 #define CONF_ENABLE_COLORS           "enable-colors"
48 #define CONF_AUTO_CENTER             "auto-center"
49 #define CONF_WIDE_CURSOR             "wide-cursor"
50 #define CONF_ENABLE_BELL             "enable-bell"
51 #define CONF_KEY_DEFINITION          "key"
52 #define CONF_COLOR                   "color"
53 #define CONF_COLOR_DEFINITION        "colordef"
54 #define CONF_LIST_FORMAT             "list-format"
55 #define CONF_STATUS_FORMAT           "status-format"
57 /* Deprecated - configuration field names */
58 #define OLD_CONF_ENABLE_COLORS       "enable_colors"
59 #define OLD_CONF_AUTO_CENTER         "auto_center"
60 #define OLD_CONF_WIDE_CURSOR         "wide_cursor"
61 #define CONF_COLOR_BACKGROUND        "background_color"
62 #define CONF_COLOR_TITLE             "title_color"
63 #define CONF_COLOR_LINE              "line_color"
64 #define CONF_COLOR_LIST              "list_color"
65 #define CONF_COLOR_PROGRESS          "progress_color"
66 #define CONF_COLOR_STATUS            "status_color"
67 #define CONF_COLOR_ALERT             "alert_color"
70 typedef enum {
71   KEY_PARSER_UNKNOWN,
72   KEY_PARSER_CHAR,
73   KEY_PARSER_DEC,
74   KEY_PARSER_HEX,
75   KEY_PARSER_DONE
76 } key_parser_state_t;
78 static int
79 str2bool(char *str)
80 {
81   if( !strcasecmp(str,"no")  || !strcasecmp(str,"false") || 
82       !strcasecmp(str,"off") || !strcasecmp(str,"0") )
83     return 0;
84   return 1;
85 }
87 static int
88 parse_key_value(char *str, size_t len, char **end)
89 {
90   int i, value;
91   key_parser_state_t state;
93   i=0;
94   value=0;
95   state=KEY_PARSER_UNKNOWN;
96   *end = str;
98   while( i<len && state!=KEY_PARSER_DONE )
99     {
100       int next = 0;
101       int c = str[i];
103       if( i+1<len )
104         next = str[i+1];
106       switch(state)
107         {
108         case KEY_PARSER_UNKNOWN:
109           if( c=='\'' )
110             state = KEY_PARSER_CHAR;
111           else if( c=='0' && next=='x' )
112             state = KEY_PARSER_HEX;
113           else if( isdigit(c) )
114             state = KEY_PARSER_DEC;
115           else {
116             fprintf(stderr,
117                     _("Error: Unsupported key definition - %s\n"), 
118                     str);
119             return -1;
120           }
121           break;
122         case KEY_PARSER_CHAR:
123           if( next!='\'' )
124             {
125               fprintf(stderr,
126                       _("Error: Unsupported key definition - %s\n"), 
127                       str);
128               return -1;
129             }
130           value = c;
131           *end = str+i+2;
132           state = KEY_PARSER_DONE;
133           break;
134         case KEY_PARSER_DEC:
135           value = (int) strtol(str+(i-1), end, 10);
136           state = KEY_PARSER_DONE;
137           break;
138         case KEY_PARSER_HEX:
139           if( !isdigit(next) )
140             {
141               fprintf(stderr,_("Error: Digit expexted after 0x - %s\n"), str);
142               return -1;
143             }
144           value = (int) strtol(str+(i+1), end, 16);
145           state = KEY_PARSER_DONE;
146           break;
147         case KEY_PARSER_DONE:
148           break;
149         }
150       i++;
151     }
153   if( *end> str+len )
154     *end = str+len;
156   return value;
159 static int
160 parse_key_definition(char *str)
162   char buf[MAX_LINE_LENGTH];
163   char *p, *end;
164   size_t len = strlen(str);
165   int i,j,key;
166   int keys[MAX_COMMAND_KEYS];
167   command_t cmd;
169   /* get the command name */
170   i=0;
171   j=0;
172   memset(buf, 0, MAX_LINE_LENGTH);
173   while( i<len && str[i]!='=' && !IS_WHITESPACE(str[i]) )
174     buf[j++] = str[i++];
175   if( (cmd=get_key_command_from_name(buf)) == CMD_NONE )
176     {
177       fprintf(stderr, _("Error: Unknown key command %s\n"), buf);
178       return -1;
179     }
181   /* skip whitespace */
182   while( i<len && (str[i]=='=' || IS_WHITESPACE(str[i])) )
183     i++;
185   /* get the value part */
186   memset(buf, 0, MAX_LINE_LENGTH);
187   strncpy(buf, str+i, len-i);
188   len = strlen(buf);
189   if( len==0 )
190     {
191       fprintf(stderr,_("Error: Incomplete key definition - %s\n"), str);
192       return -1;
193     }
195   /* parse key values */
196   i = 0;
197   key = 0;
198   len = strlen(buf);
199   p = buf;
200   end = buf+len;
201   memset(keys, 0, sizeof(int)*MAX_COMMAND_KEYS);
202   while( i<MAX_COMMAND_KEYS && p<end && (key=parse_key_value(p,len+1,&p))>=0 )
203     {
204       keys[i++] = key;
205       while( p<end && (*p==',' || *p==' ' || *p=='\t') )
206         p++;
207       len = strlen(p);
208     } 
209   if( key<0 )
210     {
211       fprintf(stderr,_("Error: Bad key definition - %s\n"), str);
212       return -1;
213     }
215   return assign_keys(cmd, keys);
218 static int
219 parse_color(char *str)
221   char *name = str;
222   char *value = NULL;
223   int len,i;
225   i=0;
226   len=strlen(str);
227   /* get the color name */
228   while( i<len && str[i]!='=' && !IS_WHITESPACE(str[i]) )
229     i++;
230   
231   /* skip whitespace */
232   while( i<len && (str[i]=='=' || IS_WHITESPACE(str[i])) )
233     {
234       str[i]='\0';
235       i++;
236     } 
237   
238   if( i<len )
239     value = str+i;
241   return colors_assign(name, value);
245 static int
246 parse_color_definition(char *str)
248   char buf[MAX_LINE_LENGTH];
249   char *p, *end, *name;
250   size_t len = strlen(str);
251   int i,j,value;
252   short color, rgb[3];
254   /* get the command name */
255   i=0;
256   j=0;
257   memset(buf, 0, MAX_LINE_LENGTH);
258   while( i<len && str[i]!='=' && !IS_WHITESPACE(str[i]) )
259     buf[j++] = str[i++];
260   color=colors_str2color(buf);
261   if( color<0 )
262     {
263       fprintf(stderr,_("Error: Bad color %s [%d]\n"), buf, color);
264       return -1;
265     }
266   name = g_strdup(buf);
268   /* skip whitespace */
269   while( i<len && (str[i]=='=' || IS_WHITESPACE(str[i])) )
270     i++;
272   /* get the value part */
273   memset(buf, 0, MAX_LINE_LENGTH);
274   strncpy(buf, str+i, len-i);
275   len = strlen(buf);
276   if( len==0 )
277     {
278       fprintf(stderr,_("Error: Incomplete color definition - %s\n"), str);
279       g_free(name);
280       return -1;
281     }
283   /* parse r,g.b values with the key definition parser */
284   i = 0;
285   value = 0;
286   len = strlen(buf);
287   p = buf;
288   end = buf+len;
289   memset(rgb, 0, sizeof(short)*3);
290   while( i<3 && p<end && (value=parse_key_value(p,len+1,&p))>=0 )
291     {
292       rgb[i++] = value;
293       while( p<end && (*p==',' || *p==' ' || *p=='\t') )
294         p++;
295       len = strlen(p);
296     } 
297   if( value<0 || i!=3)
298     {
299       fprintf(stderr,_("Error: Bad color definition - %s\n"), str);
300       g_free(name);
301       return -1;
302     }
303   value = colors_define(name, rgb[0], rgb[1], rgb[2]);
304   g_free(name);
305   return value;
308 static char *
309 get_format(char *str)
311   gsize len = strlen(str);
313   if( str && str[0]=='\"' && str[len-1] == '\"' )
314     {
315       str[len-1] = '\0';
316       str++;
317     }
318   return g_strdup(str);
322 static int
323 read_rc_file(char *filename, options_t *options)
325   int fd;
326   int quit  = 0;
327   int free_filename = 0;
329   if( filename==NULL )
330     return -1;
332   D("Reading configuration file %s\n", filename);
333   if( (fd=open(filename,O_RDONLY)) <0 )
334     {
335       perror(filename);
336       if( free_filename )
337         g_free(filename);
338       return -1;
339     }
341   while( !quit )
342     {
343       int i,j;
344       int len;
345       int match_found;
346       char line[MAX_LINE_LENGTH];
347       char name[MAX_LINE_LENGTH];
348       char value[MAX_LINE_LENGTH];
350       line[0]  = '\0';
351       value[0] = '\0';
353       i = 0;
354       /* read a line ending with '\n' */
355       do {
356         len = read( fd, &line[i], 1 );
357         if( len == 1 )
358           i++;
359         else
360           quit = 1;
361       } while( !quit && i<MAX_LINE_LENGTH && line[i-1]!='\n' );
362       
363      
364       /* remove trailing whitespace */
365       line[i] = '\0';
366       i--;
367       while( i>=0 && IS_WHITESPACE(line[i]) )
368         {
369           line[i] = '\0';
370           i--;
371         }     
372       len = i+1;
374       if( len>0 )
375         {
376           i = 0;
377           /* skip whitespace */
378           while( i<len && IS_WHITESPACE(line[i]) )
379             i++;
380           
381           /* continue if this line is not a comment */
382           if( line[i] != COMMENT_TOKEN )
383             {
384               /* get the name part */
385               j=0;
386               while( i<len && line[i]!='=' && !IS_WHITESPACE(line[i]) )
387                 {
388                   name[j++] = line[i++];
389                 }
390               name[j] = '\0';
391               
392               /* skip '=' and whitespace */
393               while( i<len && (line[i]=='=' || IS_WHITESPACE(line[i])) )
394                 i++;
395               
396               /* get the value part */
397               j=0;
398               while( i<len )
399                 {
400                   value[j++] = line[i++];
401                 }
402               value[j] = '\0';
403               
404               match_found = 1;
406               /* key definition */
407               if( !strcasecmp(CONF_KEY_DEFINITION, name) )
408                 {
409                   parse_key_definition(value);
410                 }
411               /* enable colors */
412               else if( !strcasecmp(CONF_ENABLE_COLORS, name) )
413                 {
414                   options->enable_colors = str2bool(value);
415                 }
416               /* auto center */
417               else if( !strcasecmp(CONF_AUTO_CENTER, name) )
418                 {
419                   options->auto_center = str2bool(value);
420                 }
421               /* color assignment */
422               else if( !strcasecmp(CONF_COLOR, name) )
423                 {
424                   parse_color(value);
425                 }
426 #ifdef ENABLE_OLD_SYNTAX
427               /* background color */
428               else if( !strcasecmp(CONF_COLOR_BACKGROUND, name) )
429                 {
430                   fprintf(stderr,"%s: %s deprecated!\n", filename,name);
431                   colors_assign("background", value);
432                 }
433               /* color - top (title) window */
434               else if( !strcasecmp(CONF_COLOR_TITLE, name) )
435                 {
436                   fprintf(stderr,"%s: %s deprecated!\n", filename,name);
437                   colors_assign("title", value);
438                   colors_assign("title2", value);
439                 }
440               /* color - line (title) window */
441               else if( !strcasecmp(CONF_COLOR_LINE, name) )
442                 {
443                   fprintf(stderr,"%s: %s deprecated!\n", filename,name);
444                   colors_assign("line", value);
445                   colors_assign("line2", value);
446                 }
447               /* color - list window */
448               else if( !strcasecmp(CONF_COLOR_LIST, name) )
449                 {
450                   fprintf(stderr,"%s: %s deprecated!\n", filename,name);
451                   colors_assign("list", value);
452                 }
453               /* color - progress bar */
454               else if( !strcasecmp(CONF_COLOR_PROGRESS, name) )
455                 {
456                   fprintf(stderr,"%s: %s deprecated!\n", filename,name);
457                   colors_assign("progressbar", value);
458                 }
459               /* color - status window */
460               else if( !strcasecmp(CONF_COLOR_STATUS, name) )
461                 {
462                   fprintf(stderr,"%s: %s deprecated!\n", filename,name);
463                   colors_assign("status", value);
464                   colors_assign("status2", value);
465                 }
466               /* color - alerts */
467               else if( !strcasecmp(CONF_COLOR_ALERT, name) )
468                 {
469                   fprintf(stderr,"%s: %s deprecated!\n", filename,name);
470                   colors_assign("alert", value);
471                 }
472               /* enable colors */
473               else if( !strcasecmp(OLD_CONF_ENABLE_COLORS, name) )
474                 {
475                   fprintf(stderr,"%s: %s deprecated - use %s!\n", filename, name, CONF_ENABLE_COLORS);
476                   options->enable_colors = str2bool(value);
477                 }
478               /* auto center */
479               else if( !strcasecmp(OLD_CONF_AUTO_CENTER, name) )
480                 {
481                   fprintf(stderr,"%s: %s deprecated - use %s!\n", filename, name, CONF_AUTO_CENTER);
482                   options->auto_center = str2bool(value);
483                 }
484               /* wide cursor */
485               else if( !strcasecmp(OLD_CONF_WIDE_CURSOR, name) )
486                 {
487                   fprintf(stderr,"%s: %s deprecated - use %s!\n", filename, name, CONF_WIDE_CURSOR);
488                   options->wide_cursor = str2bool(value);
489                 }
490 #endif
491               /* wide cursor */
492               else if( !strcasecmp(CONF_WIDE_CURSOR, name) )
493                 {
494                   options->wide_cursor = str2bool(value);
495                 }
496               /* color definition */
497               else if( !strcasecmp(CONF_COLOR_DEFINITION, name) )
498                 {
499                   parse_color_definition(value);
500                 }
501               /* list format string */
502               else if( !strcasecmp(CONF_LIST_FORMAT, name) )
503                 {
504                   g_free(options->list_format);
505                   options->list_format = get_format(value);
506                   fprintf(stderr, "list-format = \'%s\'\n", options->list_format);
507                 }
508               /* status format string */
509               else if( !strcasecmp(CONF_STATUS_FORMAT, name) )
510                 {
511                   g_free(options->status_format);
512                   options->status_format = get_format(value);
513                   fprintf(stderr, "status-format = \'%s\'\n", options->status_format);
514                 }
515               else
516                 {
517                   match_found = 0;
518                 }
519               
521               if( !match_found )
522                 fprintf(stderr, 
523                         _("Unknown configuration parameter: %s\n"), 
524                         name);
525 #ifdef DEBUG
526               printf( "  %s = %s %s\n", 
527                       name, 
528                       value,
529                       match_found ? "" : "- UNKNOWN SETTING!" );
530 #endif
532             }
533         }         
534     }
536   D("--\n\n");
538   if( free_filename )
539     g_free(filename);
540  
541   return 0;
544 int
545 check_user_conf_dir(void)
547   int retval;
548   char *dirname = g_build_filename(g_get_home_dir(), "." PACKAGE, NULL);
549   
550   if( g_file_test(dirname, G_FILE_TEST_IS_DIR) )
551     {
552       g_free(dirname);
553       return 0;
554     }
555   retval = mkdir(dirname, 0755);
556   g_free(dirname);
557   return retval;
560 char *
561 get_user_key_binding_filename(void)
563   return g_build_filename(g_get_home_dir(), "." PACKAGE, "keys", NULL);
567 int
568 read_configuration(options_t *options)
570   char *filename = NULL;
572   /* check for command line configuration file */
573   if( options->config_file )
574     filename = g_strdup(options->config_file);
576   /* check for user configuration ~/.ncmpc/config */
577   if( filename == NULL )
578     {
579       filename = g_build_filename(g_get_home_dir(), 
580                                   "." PACKAGE, "config", NULL);
581       if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
582         {
583           g_free(filename);
584           filename = NULL;
585         }
586     }
588   /* check for  global configuration SYSCONFDIR/ncmpc/config */
589   if( filename == NULL )
590     {
591       filename = g_build_filename(SYSCONFDIR, PACKAGE, "config", NULL);
592       if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
593         {
594           g_free(filename);
595           filename = NULL;
596         }
597     }
599   /* load configuration */
600   if( filename )
601     {
602       read_rc_file(filename, options);
603       g_free(filename);
604       filename = NULL;
605     }
607   /* check for command line key binding file */
608   if( options->key_file )
609     filename = g_strdup(options->key_file);
611   /* check for  user key bindings ~/.ncmpc/keys */
612   if( filename == NULL )
613     {
614       filename = get_user_key_binding_filename();
615       if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
616         {
617           g_free(filename);
618           filename = NULL;
619         }
620     }
622   /* check for  global key bindings SYSCONFDIR/ncmpc/keys */
623   if( filename == NULL )
624     {
625       filename = g_build_filename(SYSCONFDIR, PACKAGE, "keys", NULL);
626       if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
627         {
628           g_free(filename);
629           filename = NULL;
630         }
631     }
633   /* load key bindings */
634   if( filename )
635     {
636       read_rc_file(filename, options);
637       g_free(filename);
638       filename = NULL;
639     }
641   return 0;