]> git.sesse.net Git - vlc/blob - src/config/cmdline.c
Remove argv/argc from libvlc_t (not really needed here)
[vlc] / src / config / cmdline.c
1 /*****************************************************************************
2  * cmdline.c: command line parsing
3  *****************************************************************************
4  * Copyright (C) 2001-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #include <vlc/vlc.h>
29 #include "../libvlc.h"
30 #include "vlc_keys.h"
31 #include "vlc_charset.h"
32
33 #include <errno.h>                                                  /* errno */
34 #include <limits.h>
35
36 #ifdef HAVE_UNISTD_H
37 #    include <unistd.h>                                          /* getuid() */
38 #endif
39
40 #ifdef HAVE_GETOPT_LONG
41 #   ifdef HAVE_GETOPT_H
42 #       include <getopt.h>                                       /* getopt() */
43 #   endif
44 #else
45 #   include "../extras/getopt.h"
46 #endif
47
48 #if defined(HAVE_GETPWUID)
49 #   include <pwd.h>                                            /* getpwuid() */
50 #endif
51
52 #if defined( HAVE_SYS_STAT_H )
53 #   include <sys/stat.h>
54 #endif
55 #if defined( HAVE_SYS_TYPES_H )
56 #   include <sys/types.h>
57 #endif
58 #if defined( WIN32 )
59 #   if !defined( UNDER_CE )
60 #       include <direct.h>
61 #   endif
62 #include <tchar.h>
63 #endif
64
65 #include "configuration.h"
66 #include "modules/modules.h"
67
68 /*****************************************************************************
69  * config_LoadCmdLine: parse command line
70  *****************************************************************************
71  * Parse command line for configuration options.
72  * Now that the module_bank has been initialized, we can dynamically
73  * generate the longopts structure used by getops. We have to do it this way
74  * because we don't know (and don't want to know) in advance the configuration
75  * options used (ie. exported) by each module.
76  *****************************************************************************/
77 int __config_LoadCmdLine( vlc_object_t *p_this, int *pi_argc,
78                           const char *ppsz_argv[],
79                           vlc_bool_t b_ignore_errors )
80 {
81     int i_cmd, i_index, i_opts, i_shortopts, flag, i_verbose = 0;
82     module_t *p_parser;
83     vlc_list_t *p_list;
84     struct option *p_longopts;
85     int i_modules_index;
86     const char **argv_copy = NULL;
87
88     /* Short options */
89     module_config_t *pp_shortopts[256];
90     char *psz_shortopts;
91
92 #ifdef __APPLE__
93     /* When VLC.app is run by double clicking in Mac OS X, the 2nd arg
94      * is the PSN - process serial number (a unique PID-ish thingie)
95      * still ok for real Darwin & when run from command line */
96     if ( (*pi_argc > 1) && (strncmp( ppsz_argv[ 1 ] , "-psn" , 4 ) == 0) )
97                                         /* for example -psn_0_9306113 */
98     {
99         /* GDMF!... I can't do this or else the MacOSX window server will
100          * not pick up the PSN and not register the app and we crash...
101          * hence the following kludge otherwise we'll get confused w/ argv[1]
102          * being an input file name */
103 #if 0
104         ppsz_argv[ 1 ] = NULL;
105 #endif
106         *pi_argc = *pi_argc - 1;
107         pi_argc--;
108         return 0;
109     }
110 #endif
111
112     /* List all modules */
113     p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
114
115     /*
116      * Generate the longopts and shortopts structures used by getopt_long
117      */
118
119     i_opts = 0;
120     for( i_modules_index = 0; i_modules_index < p_list->i_count;
121          i_modules_index++ )
122     {
123         p_parser = (module_t *)p_list->p_values[i_modules_index].p_object ;
124
125         /* count the number of exported configuration options (to allocate
126          * longopts). We also need to allocate space for two options when
127          * dealing with boolean to allow for --foo and --no-foo */
128         i_opts += p_parser->i_config_items
129                      + 2 * p_parser->i_bool_items;
130     }
131
132     p_longopts = malloc( sizeof(struct option) * (i_opts + 1) );
133     if( p_longopts == NULL )
134     {
135         msg_Err( p_this, "out of memory" );
136         vlc_list_release( p_list );
137         return -1;
138     }
139
140     psz_shortopts = malloc( sizeof( char ) * (2 * i_opts + 1) );
141     if( psz_shortopts == NULL )
142     {
143         msg_Err( p_this, "out of memory" );
144         free( p_longopts );
145         vlc_list_release( p_list );
146         return -1;
147     }
148
149     /* If we are requested to ignore errors, then we must work on a copy
150      * of the ppsz_argv array, otherwise getopt_long will reorder it for
151      * us, ignoring the arity of the options */
152     if( b_ignore_errors )
153     {
154         argv_copy = (const char**)malloc( *pi_argc * sizeof(char *) );
155         if( argv_copy == NULL )
156         {
157             msg_Err( p_this, "out of memory" );
158             free( psz_shortopts );
159             free( p_longopts );
160             vlc_list_release( p_list );
161             return -1;
162         }
163         memcpy( argv_copy, ppsz_argv, *pi_argc * sizeof(char *) );
164         ppsz_argv = argv_copy;
165     }
166
167     i_shortopts = 0;
168     for( i_index = 0; i_index < 256; i_index++ )
169     {
170         pp_shortopts[i_index] = NULL;
171     }
172
173     /* Fill the p_longopts and psz_shortopts structures */
174     i_index = 0;
175     for( i_modules_index = 0; i_modules_index < p_list->i_count;
176          i_modules_index++ )
177     {
178         module_config_t *p_item, *p_end;
179         p_parser = (module_t *)p_list->p_values[i_modules_index].p_object ;
180
181         if( !p_parser->i_config_items )
182             continue;
183
184         for( p_item = p_parser->p_config, p_end = p_item + p_parser->confsize;
185              p_item < p_end;
186              p_item++ )
187         {
188             /* Ignore hints */
189             if( p_item->i_type & CONFIG_HINT )
190                 continue;
191
192             /* Add item to long options */
193             p_longopts[i_index].name = strdup( p_item->psz_name );
194             if( p_longopts[i_index].name == NULL ) continue;
195             p_longopts[i_index].has_arg =
196                 (p_item->i_type == CONFIG_ITEM_BOOL)?
197                                                no_argument : required_argument;
198             p_longopts[i_index].flag = &flag;
199             p_longopts[i_index].val = 0;
200             i_index++;
201
202             /* When dealing with bools we also need to add the --no-foo
203              * option */
204             if( p_item->i_type == CONFIG_ITEM_BOOL )
205             {
206                 char *psz_name = malloc( strlen(p_item->psz_name) + 3 );
207                 if( psz_name == NULL ) continue;
208                 strcpy( psz_name, "no" );
209                 strcat( psz_name, p_item->psz_name );
210
211                 p_longopts[i_index].name = psz_name;
212                 p_longopts[i_index].has_arg = no_argument;
213                 p_longopts[i_index].flag = &flag;
214                 p_longopts[i_index].val = 1;
215                 i_index++;
216
217                 psz_name = malloc( strlen(p_item->psz_name) + 4 );
218                 if( psz_name == NULL ) continue;
219                 strcpy( psz_name, "no-" );
220                 strcat( psz_name, p_item->psz_name );
221
222                 p_longopts[i_index].name = psz_name;
223                 p_longopts[i_index].has_arg = no_argument;
224                 p_longopts[i_index].flag = &flag;
225                 p_longopts[i_index].val = 1;
226                 i_index++;
227             }
228
229             /* If item also has a short option, add it */
230             if( p_item->i_short )
231             {
232                 pp_shortopts[(int)p_item->i_short] = p_item;
233                 psz_shortopts[i_shortopts] = p_item->i_short;
234                 i_shortopts++;
235                 if( p_item->i_type != CONFIG_ITEM_BOOL )
236                 {
237                     psz_shortopts[i_shortopts] = ':';
238                     i_shortopts++;
239
240                     if( p_item->i_short == 'v' )
241                     {
242                         psz_shortopts[i_shortopts] = ':';
243                         i_shortopts++;
244                     }
245                 }
246             }
247         }
248     }
249
250     /* We don't need the module list anymore */
251     vlc_list_release( p_list );
252
253     /* Close the longopts and shortopts structures */
254     memset( &p_longopts[i_index], 0, sizeof(struct option) );
255     psz_shortopts[i_shortopts] = '\0';
256
257     /*
258      * Parse the command line options
259      */
260     opterr = 0;
261     optind = 0; /* set to 0 to tell GNU getopt to reinitialize */
262     while( ( i_cmd = getopt_long( *pi_argc, (char **)ppsz_argv, psz_shortopts,
263                                   p_longopts, &i_index ) ) != -1 )
264     {
265         /* A long option has been recognized */
266         if( i_cmd == 0 )
267         {
268             module_config_t *p_conf;
269             char *psz_name = (char *)p_longopts[i_index].name;
270
271             /* Check if we deal with a --nofoo or --no-foo long option */
272             if( flag ) psz_name += psz_name[2] == '-' ? 3 : 2;
273
274             /* Store the configuration option */
275             p_conf = config_FindConfig( p_this, psz_name );
276             if( p_conf )
277             {
278                 /* Check if the option is deprecated */
279                 if( p_conf->b_removed )
280                 {
281                     fprintf(stderr,
282                             "Warning: option --%s no longer exists.\n",
283                             psz_name);
284                     continue;
285                 }
286
287                 if( p_conf->psz_oldname
288                  && !strcmp( p_conf->psz_oldname, psz_name) )
289                 {
290                     fprintf( stderr,
291                              "%s: option --%s is deprecated. Use --%s instead.\n",
292                              b_ignore_errors ? "Warning" : "Error",
293                              psz_name, p_conf->psz_name );
294                     if( !b_ignore_errors )
295                     {
296                         /*free */
297                         for( i_index = 0; p_longopts[i_index].name; i_index++ )
298                              free( (char *)p_longopts[i_index].name );
299
300                         free( p_longopts );
301                         free( psz_shortopts );
302                         return -1;
303                     }
304
305                     psz_name = p_conf->psz_name;
306                 }
307
308                 switch( p_conf->i_type )
309                 {
310                     case CONFIG_ITEM_STRING:
311                     case CONFIG_ITEM_PASSWORD:
312                     case CONFIG_ITEM_FILE:
313                     case CONFIG_ITEM_DIRECTORY:
314                     case CONFIG_ITEM_MODULE:
315                     case CONFIG_ITEM_MODULE_LIST:
316                     case CONFIG_ITEM_MODULE_LIST_CAT:
317                     case CONFIG_ITEM_MODULE_CAT:
318                         config_PutPsz( p_this, psz_name, optarg );
319                         break;
320                     case CONFIG_ITEM_INTEGER:
321                         config_PutInt( p_this, psz_name, strtol(optarg, 0, 0));
322                         break;
323                     case CONFIG_ITEM_FLOAT:
324                         config_PutFloat( p_this, psz_name, (float)atof(optarg) );
325                         break;
326                     case CONFIG_ITEM_KEY:
327                         config_PutInt( p_this, psz_name, ConfigStringToKey( optarg ) );
328                         break;
329                     case CONFIG_ITEM_BOOL:
330                         config_PutInt( p_this, psz_name, !flag );
331                         break;
332                 }
333                 continue;
334             }
335         }
336
337         /* A short option has been recognized */
338         if( pp_shortopts[i_cmd] != NULL )
339         {
340             switch( pp_shortopts[i_cmd]->i_type )
341             {
342                 case CONFIG_ITEM_STRING:
343                 case CONFIG_ITEM_PASSWORD:
344                 case CONFIG_ITEM_FILE:
345                 case CONFIG_ITEM_DIRECTORY:
346                 case CONFIG_ITEM_MODULE:
347                 case CONFIG_ITEM_MODULE_CAT:
348                 case CONFIG_ITEM_MODULE_LIST:
349                 case CONFIG_ITEM_MODULE_LIST_CAT:
350                     config_PutPsz( p_this, pp_shortopts[i_cmd]->psz_name, optarg );
351                     break;
352                 case CONFIG_ITEM_INTEGER:
353                     if( i_cmd == 'v' )
354                     {
355                         if( optarg )
356                         {
357                             if( *optarg == 'v' ) /* eg. -vvv */
358                             {
359                                 i_verbose++;
360                                 while( *optarg == 'v' )
361                                 {
362                                     i_verbose++;
363                                     optarg++;
364                                 }
365                             }
366                             else
367                             {
368                                 i_verbose += atoi( optarg ); /* eg. -v2 */
369                             }
370                         }
371                         else
372                         {
373                             i_verbose++; /* -v */
374                         }
375                         config_PutInt( p_this, pp_shortopts[i_cmd]->psz_name,
376                                                i_verbose );
377                     }
378                     else
379                     {
380                         config_PutInt( p_this, pp_shortopts[i_cmd]->psz_name,
381                                                strtol(optarg, 0, 0) );
382                     }
383                     break;
384                 case CONFIG_ITEM_BOOL:
385                     config_PutInt( p_this, pp_shortopts[i_cmd]->psz_name, 1 );
386                     break;
387             }
388
389             continue;
390         }
391
392         /* Internal error: unknown option */
393         if( !b_ignore_errors )
394         {
395             fprintf( stderr, "%s: unknown option"
396                      " or missing mandatory argument ",
397                      p_this->p_libvlc->psz_object_name );
398             if( optopt )
399             {
400                 fprintf( stderr, "`-%c'\n", optopt );
401             }
402             else
403             {
404                 fprintf( stderr, "`%s'\n", ppsz_argv[optind-1] );
405             }
406             fprintf( stderr, "Try `%s --help' for more information.\n",
407                              p_this->p_libvlc->psz_object_name );
408
409             for( i_index = 0; p_longopts[i_index].name; i_index++ )
410                 free( (char *)p_longopts[i_index].name );
411             free( p_longopts );
412             free( psz_shortopts );
413             return -1;
414         }
415     }
416
417     /* Free allocated resources */
418     for( i_index = 0; p_longopts[i_index].name; i_index++ )
419         free( (char *)p_longopts[i_index].name );
420     free( p_longopts );
421     free( psz_shortopts );
422     free( argv_copy );
423
424     return 0;
425 }
426