Code

Use my_wgetch() instead of wgetch(), added --[no-]mouse option
[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 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_ENABLE_BELL             "enable-bell"
49 #define CONF_KEY_DEFINITION          "key"
50 #define CONF_COLOR                   "color"
51 #define CONF_COLOR_DEFINITION        "colordef"
52 #define CONF_LIST_FORMAT             "list-format"
53 #define CONF_STATUS_FORMAT           "status-format"
54 #define CONF_XTERM_TITLE_FORMAT      "xterm-title-format"
55 #define CONF_LIST_WRAP               "wrap-around"
56 #define CONF_FIND_WRAP               "find-wrap"
57 #define CONF_AUDIBLE_BELL            "audible-bell"
58 #define CONF_VISIBLE_BELL            "visible-bell"
59 #define CONF_XTERM_TITLE             "set-xterm-title"
60 #define CONF_ENABLE_MOUSE            "enable-mouse"
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 gboolean
71 str2bool(char *str)
72 {
73   if( !strcasecmp(str,"yes")  || !strcasecmp(str,"true") || 
74       !strcasecmp(str,"on")   || !strcasecmp(str,"1") )
75     return TRUE;
76   return FALSE;
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   g_strlcpy(buf, str+i, MAX_LINE_LENGTH);
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   g_strlcpy(buf, str+i, MAX_LINE_LENGTH);
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;
300 static char *
301 get_format(char *str)
303   gsize len = strlen(str);
305   if( str && str[0]=='\"' && str[len-1] == '\"' )
306     {
307       str[len-1] = '\0';
308       str++;
309     }
310   return g_strdup(str);
314 static int
315 read_rc_file(char *filename, options_t *options)
317   int fd;
318   int quit  = 0;
319   int free_filename = 0;
321   if( filename==NULL )
322     return -1;
324   D("Reading configuration file %s\n", filename);
325   if( (fd=open(filename,O_RDONLY)) <0 )
326     {
327       perror(filename);
328       if( free_filename )
329         g_free(filename);
330       return -1;
331     }
333   while( !quit )
334     {
335       int i,j;
336       int len;
337       int match_found;
338       char line[MAX_LINE_LENGTH];
339       char name[MAX_LINE_LENGTH];
340       char value[MAX_LINE_LENGTH];
342       line[0]  = '\0';
343       value[0] = '\0';
345       i = 0;
346       /* read a line ending with '\n' */
347       do {
348         len = read( fd, &line[i], 1 );
349         if( len == 1 )
350           i++;
351         else
352           quit = 1;
353       } while( !quit && i<MAX_LINE_LENGTH && line[i-1]!='\n' );
354       
355      
356       /* remove trailing whitespace */
357       line[i] = '\0';
358       i--;
359       while( i>=0 && IS_WHITESPACE(line[i]) )
360         {
361           line[i] = '\0';
362           i--;
363         }     
364       len = i+1;
366       if( len>0 )
367         {
368           i = 0;
369           /* skip whitespace */
370           while( i<len && IS_WHITESPACE(line[i]) )
371             i++;
372           
373           /* continue if this line is not a comment */
374           if( line[i] != COMMENT_TOKEN )
375             {
376               /* get the name part */
377               j=0;
378               while( i<len && line[i]!='=' && !IS_WHITESPACE(line[i]) )
379                 {
380                   name[j++] = line[i++];
381                 }
382               name[j] = '\0';
383               
384               /* skip '=' and whitespace */
385               while( i<len && (line[i]=='=' || IS_WHITESPACE(line[i])) )
386                 i++;
387               
388               /* get the value part */
389               j=0;
390               while( i<len )
391                 {
392                   value[j++] = line[i++];
393                 }
394               value[j] = '\0';
395               
396               match_found = 1;
398               /* key definition */
399               if( !strcasecmp(CONF_KEY_DEFINITION, name) )
400                 {
401                   parse_key_definition(value);
402                 }
403               /* enable colors */
404               else if( !strcasecmp(CONF_ENABLE_COLORS, name) )
405                 {
406                   options->enable_colors = str2bool(value);
407                 }
408               /* auto center */
409               else if( !strcasecmp(CONF_AUTO_CENTER, name) )
410                 {
411                   options->auto_center = str2bool(value);
412                 }
413               /* color assignment */
414               else if( !strcasecmp(CONF_COLOR, name) )
415                 {
416                   parse_color(value);
417                 }
418               /* wide cursor */
419               else if( !strcasecmp(CONF_WIDE_CURSOR, name) )
420                 {
421                   options->wide_cursor = str2bool(value);
422                 }
423               /* color definition */
424               else if( !strcasecmp(CONF_COLOR_DEFINITION, name) )
425                 {
426                   parse_color_definition(value);
427                 }
428               /* list format string */
429               else if( !strcasecmp(CONF_LIST_FORMAT, name) )
430                 {
431                   g_free(options->list_format);
432                   options->list_format = get_format(value);
433                 }
434               /* status format string */
435               else if( !strcasecmp(CONF_STATUS_FORMAT, name) )
436                 {
437                   g_free(options->status_format);
438                   options->status_format = get_format(value);
439                 }
440               /* xterm title format string */
441               else if( !strcasecmp(CONF_XTERM_TITLE_FORMAT, name) )
442                 {
443                   g_free(options->xterm_title_format);
444                   options->xterm_title_format = get_format(value);
445                 }
446               else if( !strcasecmp(CONF_LIST_WRAP, name) )
447                 {
448                   options->list_wrap = str2bool(value);
449                 }
450               else if( !strcasecmp(CONF_FIND_WRAP, name) )
451                 {
452                   options->find_wrap = str2bool(value);
453                 }
454               else if( !strcasecmp(CONF_AUDIBLE_BELL, name) )
455                 {
456                   options->audible_bell = str2bool(value);
457                 }
458               else if( !strcasecmp(CONF_VISIBLE_BELL, name) )
459                 {
460                   options->visible_bell = str2bool(value);
461                 }
462               else if( !strcasecmp(CONF_XTERM_TITLE, name) )
463                 {
464                   options->enable_xterm_title = str2bool(value);
465                 }
466               else if( !strcasecmp(CONF_ENABLE_MOUSE, name) )
467                 {
468                   options->enable_mouse = str2bool(value);
469                 }
470               else
471                 {
472                   match_found = 0;
473                 }
474               
476               if( !match_found )
477                 fprintf(stderr, 
478                         _("Unknown configuration parameter: %s\n"), 
479                         name);
480               D("conf>  %s = %s %s\n", name, value,
481                 match_found ? "" : "- UNKNOWN SETTING!" );
482             }
483         }         
484     }
486   D("--\n\n");
488   if( free_filename )
489     g_free(filename);
490  
491   return 0;
494 int
495 check_user_conf_dir(void)
497   int retval;
498   char *dirname = g_build_filename(g_get_home_dir(), "." PACKAGE, NULL);
499   
500   if( g_file_test(dirname, G_FILE_TEST_IS_DIR) )
501     {
502       g_free(dirname);
503       return 0;
504     }
505   retval = mkdir(dirname, 0755);
506   g_free(dirname);
507   return retval;
510 char *
511 get_user_key_binding_filename(void)
513   return g_build_filename(g_get_home_dir(), "." PACKAGE, "keys", NULL);
517 int
518 read_configuration(options_t *options)
520   char *filename = NULL;
522   /* check for command line configuration file */
523   if( options->config_file )
524     filename = g_strdup(options->config_file);
526   /* check for user configuration ~/.ncmpc/config */
527   if( filename == NULL )
528     {
529       filename = g_build_filename(g_get_home_dir(), 
530                                   "." PACKAGE, "config", NULL);
531       if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
532         {
533           g_free(filename);
534           filename = NULL;
535         }
536     }
538   /* check for  global configuration SYSCONFDIR/ncmpc/config */
539   if( filename == NULL )
540     {
541       filename = g_build_filename(SYSCONFDIR, PACKAGE, "config", NULL);
542       if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
543         {
544           g_free(filename);
545           filename = NULL;
546         }
547     }
549   /* load configuration */
550   if( filename )
551     {
552       read_rc_file(filename, options);
553       g_free(filename);
554       filename = NULL;
555     }
557   /* check for command line key binding file */
558   if( options->key_file )
559     filename = g_strdup(options->key_file);
561   /* check for  user key bindings ~/.ncmpc/keys */
562   if( filename == NULL )
563     {
564       filename = get_user_key_binding_filename();
565       if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
566         {
567           g_free(filename);
568           filename = NULL;
569         }
570     }
572   /* check for  global key bindings SYSCONFDIR/ncmpc/keys */
573   if( filename == NULL )
574     {
575       filename = g_build_filename(SYSCONFDIR, PACKAGE, "keys", NULL);
576       if( !g_file_test(filename, G_FILE_TEST_IS_REGULAR) )
577         {
578           g_free(filename);
579           filename = NULL;
580         }
581     }
583   /* load key bindings */
584   if( filename )
585     {
586       read_rc_file(filename, options);
587       g_free(filename);
588       filename = NULL;
589     }
591   return 0;