Code

314a0e98cc71c3a8948b551381c2b1c7daa0fa9b
[ncmpc.git] / src / options.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 <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <glib.h>
26 #include "config.h"
27 #include "ncmpc.h"
28 #include "support.h"
29 #include "options.h"
31 #define MAX_LONGOPT_LENGTH 32
33 #define ERROR_UNKNOWN_OPTION    0x01
34 #define ERROR_BAD_ARGUMENT      0x02
35 #define ERROR_GOT_ARGUMENT      0x03
36 #define ERROR_MISSING_ARGUMENT  0x04
38  
40 typedef struct
41 {
42   int  shortopt;
43   char *longopt;
44   char *argument;
45   char *descrition;
46 } arg_opt_t;
49 typedef void (*option_callback_fn_t)   (int c, char *arg);
52 options_t options;
53  
54 static arg_opt_t option_table[] = {
55   { '?', "help",     NULL,   "Show this help message" },
56   { 'V', "version",  NULL,   "Display version information" },
57   { 'c', "colors",   NULL,   "Enable colors" },
58   { 'C', "no-colors", NULL,  "Disable colors" },
59   { 'e', "exit",     NULL,   "Exit on connection errors" },
60   { 'p', "port",  "PORT", "Connect to server on port [" DEFAULT_PORT_STR "]" },
61   { 'h', "host",  "HOST", "Connect to server on host [" DEFAULT_HOST "]" },
62   { 'P', "password","PASSWORD", "Connect with password" },
63   { 'f', "config",  "FILE",     "Read configuration from file" },
64   { 'k', "key-file","FILE",     "Read configuration from file" },
65 #ifdef DEBUG
66   { 'D', "debug",   NULL,   "Enable debug output on stderr" },
67 #endif
68   { 0, NULL, NULL, NULL },
69 };
71 static arg_opt_t *
72 lookup_option(int s, char *l)
73 {
74   int i;
76   i=0;
77   while( option_table[i].descrition )
78     {
79       if( l && strcmp(l, option_table[i].longopt) == 0 )
80         return &option_table[i];;
81       if( s && s==option_table[i].shortopt )
82         return &option_table[i];;
83       i++;
84     }
85   return NULL;
86 }
88 static void
89 option_error(int error, char *option, char *arg)
90 {
91   switch(error)
92     {
93     case ERROR_UNKNOWN_OPTION:
94       fprintf(stderr, PACKAGE ": invalid option %s\n", option);
95       break;
96     case ERROR_BAD_ARGUMENT:
97       fprintf(stderr, PACKAGE ": bad argument: %s\n", option);
98       break;
99     case ERROR_GOT_ARGUMENT:
100       fprintf(stderr, PACKAGE ": invalid option %s=%s\n", option, arg);
101       break;
102     case ERROR_MISSING_ARGUMENT:
103       fprintf(stderr, PACKAGE ": missing value for %s\n", option);
104       break;
105     default:
106       fprintf(stderr, PACKAGE ": internal error %d\n", error);
107       break;
108     }
109   exit(EXIT_FAILURE);
112 static void 
113 display_help(void)
115   int i = 0;
117   printf("Usage: %s [OPTION]...\n", PACKAGE);
118   while( option_table[i].descrition )
119     {
120       char tmp[MAX_LONGOPT_LENGTH];
122       if( option_table[i].argument )
123         g_snprintf(tmp, MAX_LONGOPT_LENGTH, "%s=%s", 
124                    option_table[i].longopt, 
125                    option_table[i].argument);
126       else
127         g_strlcpy(tmp, option_table[i].longopt, 64);
129       printf("  -%c, --%-20s %s\n", 
130              option_table[i].shortopt, 
131              tmp,
132              option_table[i].descrition);
133       i++;
134     }
137 static void 
138 handle_option(int c, char *arg)
140   D("option callback -%c %s\n", c, arg);
141   switch(c)
142     {
143     case '?': /* --help */
144       display_help();
145       exit(EXIT_SUCCESS);
146     case 'V': /* --version */
147       printf("Version %s\n", VERSION);
148       exit(EXIT_SUCCESS);
149     case 'c': /* --colors */
150       options.enable_colors = TRUE;
151       break;
152     case 'C': /* --no-colors */
153       options.enable_colors = FALSE;
154       break;
155     case 'e': /* --exit */
156       options.reconnect = FALSE;
157       break;
158     case 'p': /* --port */
159       options.port = atoi(arg);
160       break;
161     case 'h': /* --host */
162       if( options.host )
163         g_free(options.host);
164       options.host = g_strdup(arg);
165       break;
166     case 'P': /* --password */
167       if( options.password )
168         g_free(options.password);
169       options.password = locale_to_utf8(arg);
170       break;
171     case 'f': /* --config */
172       if( options.config_file )
173         g_free(options.config_file);
174       options.config_file = g_strdup(arg);
175       break;
176     case 'k': /* --key-file */
177       if( options.key_file )
178         g_free(options.key_file);
179       options.key_file = g_strdup(arg);
180       break;
181     case 'D': /* --debug */
182       options.debug = TRUE;
183       break;
184     default:
185       fprintf(stderr,"Unknown Option %c = %s\n", c, arg);
186       break;
187     }
190 options_t *
191 options_get(void)
193   return &options;
196 options_t *
197 options_parse(int argc, const char *argv[])
199   int i;
200   arg_opt_t *opt = NULL;
201   option_callback_fn_t option_cb = handle_option;
203   i=1;
204   while( i<argc )
205     {
206       char *arg = (char *) argv[i];
207       size_t len=strlen(arg);
208       
209       /* check for a long option */
210       if( g_str_has_prefix(arg, "--") )
211         {
212           char *name, *value;
213           
214           /* make shure we got an argument for the previous option */
215           if( opt && opt->argument )
216             option_error(ERROR_MISSING_ARGUMENT, opt->longopt, opt->argument);
218           /* retreive a option argument */
219           if( (value=g_strrstr(arg+2, "=")) )
220             {
221               *value = '\0';
222               name = g_strdup(arg);
223               *value = '=';
224               value++;
225             }
226           else
227             name = g_strdup(arg);
229           /* check if the option exists */
230           if( (opt=lookup_option(0, name+2)) == NULL )
231             option_error(ERROR_UNKNOWN_OPTION, name, NULL);
232           g_free(name);
233           
234           /* abort if we got an argument to the option and dont want one */
235           if( value && opt->argument==NULL )
236             option_error(ERROR_GOT_ARGUMENT, arg, value);
237           
238           /* execute option callback */
239           if( value || opt->argument==NULL )
240             {
241               option_cb (opt->shortopt, value);
242               opt = NULL;
243             }
244         }
245       /* check for a short option */
246       else if( len==2 && g_str_has_prefix(arg, "-") )
247         {
248           /* make shure we got an argument for the previous option */
249           if( opt && opt->argument )
250             option_error(ERROR_MISSING_ARGUMENT, opt->longopt, opt->argument);
252           /* check if the option exists */
253           if( (opt=lookup_option(arg[1], NULL))==NULL )
254             option_error(ERROR_UNKNOWN_OPTION, arg, NULL);
256           /* if no option argument is needed execute callback */
257           if( opt->argument==NULL )
258             {
259               option_cb (opt->shortopt, NULL);
260               opt = NULL;
261             }
262         }
263       else
264         {
265           /* is this a option argument? */
266           if( opt && opt->argument)
267             {
268               option_cb (opt->shortopt, arg);
269               opt = NULL;
270             }
271           else 
272             option_error(ERROR_BAD_ARGUMENT, arg, NULL);          
273         }
274       i++;
275     }
276   
277   if( opt && opt->argument==NULL)
278     option_cb (opt->shortopt, NULL);
279   else if( opt && opt->argument )
280     option_error(ERROR_MISSING_ARGUMENT, opt->longopt, opt->argument);
282   return  &options;
286 options_t *
287 options_init( void )
289   const char *value;
290   char *tmp;
292   memset(&options, 0, sizeof(options_t));
294   /* get initial values for host and password from MPD_HOST (enviroment) */
295   if( (value=g_getenv(MPD_HOST_ENV)) )
296     options.host = g_strdup(value);
297   else
298     options.host = g_strdup(DEFAULT_HOST);
299   if( (tmp=g_strstr_len(options.host, strlen(options.host), "@")) )
300     {
301       char *oldhost = options.host;
302       *tmp  = '\0';
303       options.password = locale_to_utf8(oldhost);
304       options.host = g_strdup(tmp+1);
305       g_free(oldhost);
306     }
307   /* get initial values for port from MPD_PORT (enviroment) */
308   if( (value=g_getenv(MPD_PORT_ENV)) )
309     options.port = atoi(value);
310   else
311     options.port = DEFAULT_PORT;
313   /* default option values */
314   options.reconnect = TRUE;
315   options.find_wrap = TRUE;
316   options.wide_cursor = TRUE;
317   options.audible_bell = TRUE;
319   return &options;