LGPL
[vlc.git] / src / config / help.c
1 /*****************************************************************************
2  * help.c: command line help
3  *****************************************************************************
4  * Copyright (C) 1998-2011 VLC authors and VideoLAN
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19  *****************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #include <vlc_common.h>
26 #include <vlc_charset.h>
27 #include <vlc_modules.h>
28 #include "modules/modules.h"
29 #include "config/configuration.h"
30 #include "libvlc.h"
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #if defined( WIN32 ) && !defined( UNDER_CE )
36 static void ShowConsole (void);
37 static void PauseConsole (void);
38 #else
39 # define ShowConsole() (void)0
40 # define PauseConsole() (void)0
41 # include <unistd.h>
42 #endif
43
44 static void Help (vlc_object_t *, const char *);
45 static void Usage (vlc_object_t *, const char *);
46 static void Version (void);
47 static void ListModules (vlc_object_t *, bool);
48 static int ConsoleWidth (void);
49
50 /**
51  * Checks for help command line options such as --help or --version.
52  * If one is found, print the corresponding text.
53  * \return true if a command line options caused some help message to be
54  * printed, false otherwise. 
55  */
56 bool config_PrintHelp (vlc_object_t *obj)
57 {
58     char *str;
59
60     /* Check for short help option */
61     if (var_InheritBool (obj, "help"))
62     {
63         Help (obj, "help");
64         return true;
65     }
66
67     /* Check for version option */
68     if (var_InheritBool (obj, "version"))
69     {
70         Version();
71         return true;
72     }
73
74     /* Check for help on modules */
75     str = var_InheritString (obj, "module");
76     if (str != NULL)
77     {
78         Help (obj, str);
79         free (str);
80         return true;
81     }
82
83     /* Check for full help option */
84     if (var_InheritBool (obj, "full-help"))
85     {
86         var_Create (obj, "advanced", VLC_VAR_BOOL);
87         var_SetBool (obj, "advanced", true);
88         var_Create (obj, "help-verbose", VLC_VAR_BOOL);
89         var_SetBool (obj, "help-verbose", true);
90         Help (obj, "full-help");
91         return true;
92     }
93
94     /* Check for long help option */
95     if (var_InheritBool (obj, "longhelp"))
96     {
97         Help (obj, "longhelp");
98         return true;
99     }
100
101     /* Check for module list option */
102     if (var_InheritBool (obj, "list"))
103     {
104         ListModules (obj, false );
105         return true;
106     }
107
108     if (var_InheritBool (obj, "list-verbose"))
109     {
110         ListModules (obj, true);
111         return true;
112     }
113
114     return false;
115 }
116
117 /*****************************************************************************
118  * Help: print program help
119  *****************************************************************************
120  * Print a short inline help. Message interface is initialized at this stage.
121  *****************************************************************************/
122 static inline void print_help_on_full_help( void )
123 {
124     utf8_fprintf( stdout, "\n" );
125     utf8_fprintf( stdout, "%s\n", _("To get exhaustive help, use '-H'.") );
126 }
127
128 static const char vlc_usage[] = N_(
129   "Usage: %s [options] [stream] ...\n"
130   "You can specify multiple streams on the commandline.\n"
131   "They will be enqueued in the playlist.\n"
132   "The first item specified will be played first.\n"
133   "\n"
134   "Options-styles:\n"
135   "  --option  A global option that is set for the duration of the program.\n"
136   "   -option  A single letter version of a global --option.\n"
137   "   :option  An option that only applies to the stream directly before it\n"
138   "            and that overrides previous settings.\n"
139   "\n"
140   "Stream MRL syntax:\n"
141   "  [[access][/demux]://]URL[#[title][:chapter][-[title][:chapter]]]\n"
142   "  [:option=value ...]\n"
143   "\n"
144   "  Many of the global --options can also be used as MRL specific :options.\n"
145   "  Multiple :option=value pairs can be specified.\n"
146   "\n"
147   "URL syntax:\n"
148   "  file:///path/file              Plain media file\n"
149   "  http://host[:port]/file        HTTP URL\n"
150   "  ftp://host[:port]/file         FTP URL\n"
151   "  mms://host[:port]/file         MMS URL\n"
152   "  screen://                      Screen capture\n"
153   "  dvd://[device]                 DVD device\n"
154   "  vcd://[device]                 VCD device\n"
155   "  cdda://[device]                Audio CD device\n"
156   "  udp://[[<source address>]@[<bind address>][:<bind port>]]\n"
157   "                                 UDP stream sent by a streaming server\n"
158   "  vlc://pause:<seconds>          Pause the playlist for a certain time\n"
159   "  vlc://quit                     Special item to quit VLC\n"
160   "\n");
161
162 static void Help (vlc_object_t *p_this, char const *psz_help_name)
163 {
164     ShowConsole();
165
166     if( psz_help_name && !strcmp( psz_help_name, "help" ) )
167     {
168         utf8_fprintf( stdout, vlc_usage, "vlc" );
169         Usage( p_this, "=help" );
170         Usage( p_this, "=main" );
171         print_help_on_full_help();
172     }
173     else if( psz_help_name && !strcmp( psz_help_name, "longhelp" ) )
174     {
175         utf8_fprintf( stdout, vlc_usage, "vlc" );
176         Usage( p_this, NULL );
177         print_help_on_full_help();
178     }
179     else if( psz_help_name && !strcmp( psz_help_name, "full-help" ) )
180     {
181         utf8_fprintf( stdout, vlc_usage, "vlc" );
182         Usage( p_this, NULL );
183     }
184     else if( psz_help_name )
185     {
186         Usage( p_this, psz_help_name );
187     }
188
189     PauseConsole();
190 }
191
192 /*****************************************************************************
193  * Usage: print module usage
194  *****************************************************************************
195  * Print a short inline help. Message interface is initialized at this stage.
196  *****************************************************************************/
197 #   define COL(x)  "\033[" #x ";1m"
198 #   define RED     COL(31)
199 #   define GREEN   COL(32)
200 #   define YELLOW  COL(33)
201 #   define BLUE    COL(34)
202 #   define MAGENTA COL(35)
203 #   define CYAN    COL(36)
204 #   define WHITE   COL(0)
205 #   define GRAY    "\033[0m"
206 static void
207 print_help_section( const module_t *m, const module_config_t *p_item,
208                     bool b_color, bool b_description )
209 {
210     if( !p_item ) return;
211     if( b_color )
212     {
213         utf8_fprintf( stdout, RED"   %s:\n"GRAY,
214                       module_gettext( m, p_item->psz_text ) );
215         if( b_description && p_item->psz_longtext )
216             utf8_fprintf( stdout, MAGENTA"   %s\n"GRAY,
217                           module_gettext( m, p_item->psz_longtext ) );
218     }
219     else
220     {
221         utf8_fprintf( stdout, "   %s:\n",
222                       module_gettext( m, p_item->psz_text ) );
223         if( b_description && p_item->psz_longtext )
224             utf8_fprintf( stdout, "   %s\n",
225                           module_gettext(m, p_item->psz_longtext ) );
226     }
227 }
228
229 static void Usage (vlc_object_t *p_this, char const *psz_search)
230 {
231 #define FORMAT_STRING "  %s --%s%s%s%s%s%s%s "
232     /* short option ------'    | | | | | | |
233      * option name ------------' | | | | | |
234      * <bra ---------------------' | | | | |
235      * option type or "" ----------' | | | |
236      * ket> -------------------------' | | |
237      * padding spaces -----------------' | |
238      * comment --------------------------' |
239      * comment suffix ---------------------'
240      *
241      * The purpose of having bra and ket is that we might i18n them as well.
242      */
243
244 #define COLOR_FORMAT_STRING (WHITE"  %s --%s"YELLOW"%s%s%s%s%s%s "GRAY)
245 #define COLOR_FORMAT_STRING_BOOL (WHITE"  %s --%s%s%s%s%s%s%s "GRAY)
246
247 #define LINE_START 8
248 #define PADDING_SPACES 25
249 #ifdef WIN32
250 #   define OPTION_VALUE_SEP "="
251 #else
252 #   define OPTION_VALUE_SEP " "
253 #endif
254     char psz_spaces_text[PADDING_SPACES+LINE_START+1];
255     char psz_spaces_longtext[LINE_START+3];
256     char psz_format[sizeof(COLOR_FORMAT_STRING)];
257     char psz_format_bool[sizeof(COLOR_FORMAT_STRING_BOOL)];
258     char psz_buffer[10000];
259     char psz_short[4];
260     int i_width = ConsoleWidth() - (PADDING_SPACES+LINE_START+1);
261     int i_width_description = i_width + PADDING_SPACES - 1;
262     bool b_advanced    = var_InheritBool( p_this, "advanced" );
263     bool b_description = var_InheritBool( p_this, "help-verbose" );
264     bool b_description_hack;
265     bool b_color       = var_InheritBool( p_this, "color" );
266     bool b_has_advanced = false;
267     bool b_found       = false;
268     int  i_only_advanced = 0; /* Number of modules ignored because they
269                                * only have advanced options */
270     bool b_strict = psz_search && *psz_search == '=';
271     if( b_strict ) psz_search++;
272
273     memset( psz_spaces_text, ' ', PADDING_SPACES+LINE_START );
274     psz_spaces_text[PADDING_SPACES+LINE_START] = '\0';
275     memset( psz_spaces_longtext, ' ', LINE_START+2 );
276     psz_spaces_longtext[LINE_START+2] = '\0';
277 #ifndef WIN32
278     if( !isatty( 1 ) )
279 #endif
280         b_color = false; // don't put color control codes in a .txt file
281
282     if( b_color )
283     {
284         strcpy( psz_format, COLOR_FORMAT_STRING );
285         strcpy( psz_format_bool, COLOR_FORMAT_STRING_BOOL );
286     }
287     else
288     {
289         strcpy( psz_format, FORMAT_STRING );
290         strcpy( psz_format_bool, FORMAT_STRING );
291     }
292
293     /* List all modules */
294     module_t **list = module_list_get (NULL);
295     if (!list)
296         return;
297
298     /* Ugly hack to make sure that the help options always come first
299      * (part 1) */
300     if( !psz_search )
301         Usage( p_this, "help" );
302
303     /* Enumerate the config for each module */
304     for (size_t i = 0; list[i]; i++)
305     {
306         bool b_help_module;
307         module_t *p_parser = list[i];
308         module_config_t *p_item = NULL;
309         module_config_t *p_section = NULL;
310         module_config_t *p_end = p_parser->p_config + p_parser->confsize;
311         const char *objname = module_get_object (p_parser);
312
313         if( psz_search &&
314             ( b_strict ? strcmp( objname, psz_search )
315                        : !strstr( objname, psz_search ) ) )
316         {
317             char *const *pp_shortcuts = p_parser->pp_shortcuts;
318             unsigned i;
319             for( i = 0; i < p_parser->i_shortcuts; i++ )
320             {
321                 if( b_strict ? !strcmp( psz_search, pp_shortcuts[i] )
322                              : !!strstr( pp_shortcuts[i], psz_search ) )
323                     break;
324             }
325             if( i == p_parser->i_shortcuts )
326                 continue;
327         }
328
329         /* Ignore modules without config options */
330         if( !p_parser->i_config_items )
331         {
332             continue;
333         }
334
335         b_help_module = !strcmp( "help", objname );
336         /* Ugly hack to make sure that the help options always come first
337          * (part 2) */
338         if( !psz_search && b_help_module )
339             continue;
340
341         /* Ignore modules with only advanced config options if requested */
342         if( !b_advanced )
343         {
344             for( p_item = p_parser->p_config;
345                  p_item < p_end;
346                  p_item++ )
347             {
348                 if( CONFIG_ITEM(p_item->i_type) &&
349                     !p_item->b_advanced && !p_item->b_removed ) break;
350             }
351
352             if( p_item == p_end )
353             {
354                 i_only_advanced++;
355                 continue;
356             }
357         }
358
359         b_found = true;
360
361         /* Print name of module */
362         if( strcmp( "main", objname ) )
363         {
364             if( b_color )
365                 utf8_fprintf( stdout, "\n " GREEN "%s" GRAY " (%s)\n",
366                               module_gettext( p_parser, p_parser->psz_longname ),
367                               objname );
368             else
369                 utf8_fprintf( stdout, "\n %s\n",
370                               module_gettext(p_parser, p_parser->psz_longname ) );
371         }
372         if( p_parser->psz_help )
373         {
374             if( b_color )
375                 utf8_fprintf( stdout, CYAN" %s\n"GRAY,
376                               module_gettext( p_parser, p_parser->psz_help ) );
377             else
378                 utf8_fprintf( stdout, " %s\n",
379                               module_gettext( p_parser, p_parser->psz_help ) );
380         }
381
382         /* Print module options */
383         for( p_item = p_parser->p_config;
384              p_item < p_end;
385              p_item++ )
386         {
387             char *psz_text, *psz_spaces = psz_spaces_text;
388             const char *psz_bra = NULL, *psz_type = NULL, *psz_ket = NULL;
389             const char *psz_suf = "", *psz_prefix = NULL;
390             signed int i;
391             size_t i_cur_width;
392
393             /* Skip removed options */
394             if( p_item->b_removed )
395             {
396                 continue;
397             }
398             /* Skip advanced options if requested */
399             if( p_item->b_advanced && !b_advanced )
400             {
401                 b_has_advanced = true;
402                 continue;
403             }
404
405             switch( CONFIG_CLASS(p_item->i_type) )
406             {
407             case 0: // hint class
408                 switch( p_item->i_type )
409                 {
410                 case CONFIG_HINT_CATEGORY:
411                 case CONFIG_HINT_USAGE:
412                     if( !strcmp( "main", objname ) )
413                     {
414                         if( b_color )
415                             utf8_fprintf( stdout, GREEN "\n %s\n" GRAY,
416                                           module_gettext( p_parser, p_item->psz_text ) );
417                         else
418                             utf8_fprintf( stdout, "\n %s\n",
419                                           module_gettext( p_parser, p_item->psz_text ) );
420                     }
421                     if( b_description && p_item->psz_longtext )
422                     {
423                         if( b_color )
424                             utf8_fprintf( stdout, CYAN " %s\n" GRAY,
425                                           module_gettext( p_parser, p_item->psz_longtext ) );
426                         else
427                             utf8_fprintf( stdout, " %s\n",
428                                           module_gettext( p_parser, p_item->psz_longtext ) );
429                 }
430                 break;
431
432                 case CONFIG_HINT_SUBCATEGORY:
433                     if( strcmp( "main", objname ) )
434                         break;
435                 case CONFIG_SECTION:
436                     p_section = p_item;
437                     break;
438                 }
439                 break;
440
441             case CONFIG_ITEM_STRING:
442                 print_help_section( p_parser, p_section, b_color,
443                                     b_description );
444                 p_section = NULL;
445                 psz_bra = OPTION_VALUE_SEP "<";
446                 psz_type = _("string");
447                 psz_ket = ">";
448
449                 if( p_item->ppsz_list )
450                 {
451                     psz_bra = OPTION_VALUE_SEP "{";
452                     psz_type = psz_buffer;
453                     psz_buffer[0] = '\0';
454                     for( i = 0; p_item->ppsz_list[i]; i++ )
455                     {
456                         if( i ) strcat( psz_buffer, "," );
457                         strcat( psz_buffer, p_item->ppsz_list[i] );
458                     }
459                     psz_ket = "}";
460                 }
461                 break;
462             case CONFIG_ITEM_INTEGER:
463                 print_help_section( p_parser, p_section, b_color,
464                                     b_description );
465                 p_section = NULL;
466                 psz_bra = OPTION_VALUE_SEP "<";
467                 psz_type = _("integer");
468                 psz_ket = ">";
469
470                 if( p_item->min.i || p_item->max.i )
471                 {
472                     sprintf( psz_buffer, "%s [%"PRId64" .. %"PRId64"]",
473                              psz_type, p_item->min.i, p_item->max.i );
474                     psz_type = psz_buffer;
475                 }
476
477                 if( p_item->i_list )
478                 {
479                     psz_bra = OPTION_VALUE_SEP "{";
480                     psz_type = psz_buffer;
481                     psz_buffer[0] = '\0';
482                     for( i = 0; p_item->ppsz_list_text[i]; i++ )
483                     {
484                         if( i ) strcat( psz_buffer, ", " );
485                         sprintf( psz_buffer + strlen(psz_buffer), "%i (%s)",
486                                  p_item->pi_list[i],
487                                  module_gettext( p_parser, p_item->ppsz_list_text[i] ) );
488                     }
489                     psz_ket = "}";
490                 }
491                 break;
492             case CONFIG_ITEM_FLOAT:
493                 print_help_section( p_parser, p_section, b_color,
494                                     b_description );
495                 p_section = NULL;
496                 psz_bra = OPTION_VALUE_SEP "<";
497                 psz_type = _("float");
498                 psz_ket = ">";
499                 if( p_item->min.f || p_item->max.f )
500                 {
501                     sprintf( psz_buffer, "%s [%f .. %f]", psz_type,
502                              p_item->min.f, p_item->max.f );
503                     psz_type = psz_buffer;
504                 }
505                 break;
506             case CONFIG_ITEM_BOOL:
507                 print_help_section( p_parser, p_section, b_color,
508                                     b_description );
509                 p_section = NULL;
510                 psz_bra = ""; psz_type = ""; psz_ket = "";
511                 if( !b_help_module )
512                 {
513                     psz_suf = p_item->value.i ? _(" (default enabled)") :
514                                                 _(" (default disabled)");
515                 }
516                 break;
517             }
518
519             if( !psz_type )
520             {
521                 continue;
522             }
523
524             /* Add short option if any */
525             if( p_item->i_short )
526             {
527                 sprintf( psz_short, "-%c,", p_item->i_short );
528             }
529             else
530             {
531                 strcpy( psz_short, "   " );
532             }
533
534             i = PADDING_SPACES - strlen( p_item->psz_name )
535                  - strlen( psz_bra ) - strlen( psz_type )
536                  - strlen( psz_ket ) - 1;
537
538             if( CONFIG_CLASS(p_item->i_type) == CONFIG_ITEM_BOOL
539              && !b_help_module )
540             {
541                 psz_prefix =  ", --no-";
542                 i -= strlen( p_item->psz_name ) + strlen( psz_prefix );
543             }
544
545             if( i < 0 )
546             {
547                 psz_spaces[0] = '\n';
548                 i = 0;
549             }
550             else
551             {
552                 psz_spaces[i] = '\0';
553             }
554
555             if( CONFIG_CLASS(p_item->i_type) == CONFIG_ITEM_BOOL
556              && !b_help_module )
557             {
558                 utf8_fprintf( stdout, psz_format_bool, psz_short,
559                               p_item->psz_name, psz_prefix, p_item->psz_name,
560                               psz_bra, psz_type, psz_ket, psz_spaces );
561             }
562             else
563             {
564                 utf8_fprintf( stdout, psz_format, psz_short, p_item->psz_name,
565                          "", "", psz_bra, psz_type, psz_ket, psz_spaces );
566             }
567
568             psz_spaces[i] = ' ';
569
570             /* We wrap the rest of the output */
571             sprintf( psz_buffer, "%s%s", module_gettext( p_parser, p_item->psz_text ),
572                      psz_suf );
573             b_description_hack = b_description;
574
575  description:
576             psz_text = psz_buffer;
577             i_cur_width = b_description && !b_description_hack
578                           ? i_width_description
579                           : i_width;
580             if( !*psz_text ) strcpy(psz_text, " ");
581             while( *psz_text )
582             {
583                 char *psz_parser, *psz_word;
584                 size_t i_end = strlen( psz_text );
585
586                 /* If the remaining text fits in a line, print it. */
587                 if( i_end <= i_cur_width )
588                 {
589                     if( b_color )
590                     {
591                         if( !b_description || b_description_hack )
592                             utf8_fprintf( stdout, BLUE"%s\n"GRAY, psz_text );
593                         else
594                             utf8_fprintf( stdout, "%s\n", psz_text );
595                     }
596                     else
597                     {
598                         utf8_fprintf( stdout, "%s\n", psz_text );
599                     }
600                     break;
601                 }
602
603                 /* Otherwise, eat as many words as possible */
604                 psz_parser = psz_text;
605                 do
606                 {
607                     psz_word = psz_parser;
608                     psz_parser = strchr( psz_word, ' ' );
609                     /* If no space was found, we reached the end of the text
610                      * block; otherwise, we skip the space we just found. */
611                     psz_parser = psz_parser ? psz_parser + 1
612                                             : psz_text + i_end;
613
614                 } while( (size_t)(psz_parser - psz_text) <= i_cur_width );
615
616                 /* We cut a word in one of these cases:
617                  *  - it's the only word in the line and it's too long.
618                  *  - we used less than 80% of the width and the word we are
619                  *    going to wrap is longer than 40% of the width, and even
620                  *    if the word would have fit in the next line. */
621                 if( psz_word == psz_text
622              || ( (size_t)(psz_word - psz_text) < 80 * i_cur_width / 100
623              && (size_t)(psz_parser - psz_word) > 40 * i_cur_width / 100 ) )
624                 {
625                     char c = psz_text[i_cur_width];
626                     psz_text[i_cur_width] = '\0';
627                     if( b_color )
628                     {
629                         if( !b_description || b_description_hack )
630                             utf8_fprintf( stdout, BLUE"%s\n%s"GRAY,
631                                           psz_text, psz_spaces );
632                         else
633                             utf8_fprintf( stdout, "%s\n%s",
634                                           psz_text, psz_spaces );
635                     }
636                     else
637                     {
638                         utf8_fprintf( stdout, "%s\n%s", psz_text, psz_spaces );
639                     }
640                     psz_text += i_cur_width;
641                     psz_text[0] = c;
642                 }
643                 else
644                 {
645                     psz_word[-1] = '\0';
646                     if( b_color )
647                     {
648                         if( !b_description || b_description_hack )
649                             utf8_fprintf( stdout, BLUE"%s\n%s"GRAY,
650                                           psz_text, psz_spaces );
651                         else
652                             utf8_fprintf( stdout, "%s\n%s",
653                                           psz_text, psz_spaces );
654                     }
655                     else
656                     {
657                         utf8_fprintf( stdout, "%s\n%s", psz_text, psz_spaces );
658                     }
659                     psz_text = psz_word;
660                 }
661             }
662
663             if( b_description_hack && p_item->psz_longtext )
664             {
665                 sprintf( psz_buffer, "%s%s",
666                          module_gettext( p_parser, p_item->psz_longtext ),
667                          psz_suf );
668                 b_description_hack = false;
669                 psz_spaces = psz_spaces_longtext;
670                 utf8_fprintf( stdout, "%s", psz_spaces );
671                 goto description;
672             }
673         }
674     }
675
676     if( b_has_advanced )
677     {
678         if( b_color )
679             utf8_fprintf( stdout, "\n" WHITE "%s" GRAY " %s\n", _( "Note:" ),
680            _( "add --advanced to your command line to see advanced options."));
681         else
682             utf8_fprintf( stdout, "\n%s %s\n", _( "Note:" ),
683            _( "add --advanced to your command line to see advanced options."));
684     }
685
686     if( i_only_advanced > 0 )
687     {
688         if( b_color )
689         {
690             utf8_fprintf( stdout, "\n" WHITE "%s" GRAY " ", _( "Note:" ) );
691             utf8_fprintf( stdout, _( "%d module(s) were not displayed because they only have advanced options.\n" ), i_only_advanced );
692         }
693         else
694         {
695             utf8_fprintf( stdout, "\n%s ", _( "Note:" ) );
696             utf8_fprintf( stdout, _( "%d module(s) were not displayed because they only have advanced options.\n" ), i_only_advanced );
697         }
698     }
699     else if( !b_found )
700     {
701         if( b_color )
702             utf8_fprintf( stdout, "\n" WHITE "%s" GRAY "\n",
703                        _( "No matching module found. Use --list or " \
704                           "--list-verbose to list available modules." ) );
705         else
706             utf8_fprintf( stdout, "\n%s\n",
707                        _( "No matching module found. Use --list or " \
708                           "--list-verbose to list available modules." ) );
709     }
710
711     /* Release the module list */
712     module_list_free (list);
713 }
714
715 /*****************************************************************************
716  * ListModules: list the available modules with their description
717  *****************************************************************************
718  * Print a list of all available modules (builtins and plugins) and a short
719  * description for each one.
720  *****************************************************************************/
721 static void ListModules (vlc_object_t *p_this, bool b_verbose)
722 {
723     module_t *p_parser;
724
725     bool b_color = var_InheritBool( p_this, "color" );
726
727     ShowConsole();
728 #ifdef WIN32
729     b_color = false; // don't put color control codes in a .txt file
730 #else
731     if( !isatty( 1 ) )
732         b_color = false;
733 #endif
734
735     /* List all modules */
736     module_t **list = module_list_get (NULL);
737
738     /* Enumerate each module */
739     for (size_t j = 0; (p_parser = list[j]) != NULL; j++)
740     {
741         const char *objname = module_get_object (p_parser);
742         if( b_color )
743             utf8_fprintf( stdout, GREEN"  %-22s "WHITE"%s\n"GRAY, objname,
744                           module_gettext( p_parser, p_parser->psz_longname ) );
745         else
746             utf8_fprintf( stdout, "  %-22s %s\n", objname,
747                           module_gettext( p_parser, p_parser->psz_longname ) );
748
749         if( b_verbose )
750         {
751             char *const *pp_shortcuts = p_parser->pp_shortcuts;
752             for( unsigned i = 0; i < p_parser->i_shortcuts; i++ )
753             {
754                 if( strcmp( pp_shortcuts[i], objname ) )
755                 {
756                     if( b_color )
757                         utf8_fprintf( stdout, CYAN"   s %s\n"GRAY,
758                                       pp_shortcuts[i] );
759                     else
760                         utf8_fprintf( stdout, "   s %s\n",
761                                       pp_shortcuts[i] );
762                 }
763             }
764             if( p_parser->psz_capability )
765             {
766                 if( b_color )
767                     utf8_fprintf( stdout, MAGENTA"   c %s (%d)\n"GRAY,
768                                   p_parser->psz_capability,
769                                   p_parser->i_score );
770                 else
771                     utf8_fprintf( stdout, "   c %s (%d)\n",
772                                   p_parser->psz_capability,
773                                   p_parser->i_score );
774             }
775         }
776     }
777     module_list_free (list);
778     PauseConsole();
779 }
780
781 /*****************************************************************************
782  * Version: print complete program version
783  *****************************************************************************
784  * Print complete program version and build number.
785  *****************************************************************************/
786 static void Version( void )
787 {
788     ShowConsole();
789     utf8_fprintf( stdout, _("VLC version %s (%s)\n"), VERSION_MESSAGE,
790                   psz_vlc_changeset );
791     utf8_fprintf( stdout, _("Compiled by %s on %s (%s)\n"),
792              VLC_CompileBy(), VLC_CompileHost(), __DATE__" "__TIME__ );
793     utf8_fprintf( stdout, _("Compiler: %s\n"), VLC_Compiler() );
794     utf8_fprintf( stdout, "%s", LICENSE_MSG );
795     PauseConsole();
796 }
797
798 #if defined (WIN32) && !defined (UNDER_CE)
799 /*****************************************************************************
800  * ShowConsole: On Win32, create an output console for debug messages
801  *****************************************************************************
802  * This function is useful only on Win32.
803  *****************************************************************************/
804 static void ShowConsole( void )
805 {
806     FILE *f_help = NULL;
807
808     if( getenv( "PWD" ) ) return; /* Cygwin shell or Wine */
809
810     AllocConsole();
811     /* Use the ANSI code page (e.g. Windows-1252) as expected by the LibVLC
812      * Unicode/locale subsystem. By default, we have the obsolecent OEM code
813      * page (e.g. CP437 or CP850). */
814     SetConsoleOutputCP (GetACP ());
815     SetConsoleTitle ("VLC media player version "PACKAGE_VERSION);
816
817     freopen( "CONOUT$", "w", stderr );
818     freopen( "CONIN$", "r", stdin );
819
820     f_help = fopen( "vlc-help.txt", "wt" );
821     if( f_help != NULL )
822     {
823         fclose( f_help );
824         freopen( "vlc-help.txt", "wt", stdout );
825         utf8_fprintf( stderr, _("\nDumped content to vlc-help.txt file.\n") );
826     }
827     else freopen( "CONOUT$", "w", stdout );
828 }
829
830 /*****************************************************************************
831  * PauseConsole: On Win32, wait for a key press before closing the console
832  *****************************************************************************
833  * This function is useful only on Win32.
834  *****************************************************************************/
835 static void PauseConsole( void )
836 {
837     if( getenv( "PWD" ) ) return; /* Cygwin shell or Wine */
838
839     utf8_fprintf( stderr, _("\nPress the RETURN key to continue...\n") );
840     getchar();
841     fclose( stdout );
842 }
843 #endif
844
845 /*****************************************************************************
846  * ConsoleWidth: Return the console width in characters
847  *****************************************************************************
848  * We use the stty shell command to get the console width; if this fails or
849  * if the width is less than 80, we default to 80.
850  *****************************************************************************/
851 static int ConsoleWidth( void )
852 {
853     unsigned i_width = 80;
854
855 #ifndef WIN32
856     FILE *file = popen( "stty size 2>/dev/null", "r" );
857     if (file != NULL)
858     {
859         if (fscanf (file, "%*u %u", &i_width) <= 0)
860             i_width = 80;
861         pclose( file );
862     }
863 #elif !defined (UNDER_CE)
864     CONSOLE_SCREEN_BUFFER_INFO buf;
865
866     if (GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &buf))
867         i_width = buf.dwSize.X;
868 #endif
869
870     return i_width;
871 }