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