+#define FORMAT_STRING " %s --%s%s%s%s%s%s%s "
+ /* short option ------' | | | | | | |
+ * option name ------------' | | | | | |
+ * <bra ---------------------' | | | | |
+ * option type or "" ----------' | | | |
+ * ket> -------------------------' | | |
+ * padding spaces -----------------' | |
+ * comment --------------------------' |
+ * comment suffix ---------------------'
+ *
+ * The purpose of having bra and ket is that we might i18n them as well.
+ */
+
+#define COLOR_FORMAT_STRING (WHITE" %s --%s"YELLOW"%s%s%s%s%s%s "GRAY)
+#define COLOR_FORMAT_STRING_BOOL (WHITE" %s --%s%s%s%s%s%s%s "GRAY)
+
+#define LINE_START 8
+#define PADDING_SPACES 25
+#ifdef WIN32
+# define OPTION_VALUE_SEP "="
+#else
+# define OPTION_VALUE_SEP " "
+#endif
+ vlc_list_t *p_list = NULL;
+ char psz_spaces_text[PADDING_SPACES+LINE_START+1];
+ char psz_spaces_longtext[LINE_START+3];
+ char psz_format[sizeof(COLOR_FORMAT_STRING)];
+ char psz_format_bool[sizeof(COLOR_FORMAT_STRING_BOOL)];
+ char psz_buffer[10000];
+ char psz_short[4];
+ int i_index;
+ int i_width = ConsoleWidth() - (PADDING_SPACES+LINE_START+1);
+ int i_width_description = i_width + PADDING_SPACES - 1;
+ bool b_advanced = config_GetInt( p_this, "advanced" ) > 0;
+ bool b_description = config_GetInt( p_this, "help-verbose" ) > 0;
+ bool b_description_hack;
+ bool b_color = config_GetInt( p_this, "color" ) > 0;
+ bool b_has_advanced = false;
+
+ memset( psz_spaces_text, ' ', PADDING_SPACES+LINE_START );
+ psz_spaces_text[PADDING_SPACES+LINE_START] = '\0';
+ memset( psz_spaces_longtext, ' ', LINE_START+2 );
+ psz_spaces_longtext[LINE_START+2] = '\0';
+#ifndef WIN32
+ if( !isatty( 1 ) )
+#endif
+ b_color = false; // don't put color control codes in a .txt file
+
+ if( b_color )
+ {
+ strcpy( psz_format, COLOR_FORMAT_STRING );
+ strcpy( psz_format_bool, COLOR_FORMAT_STRING_BOOL );
+ }
+ else
+ {
+ strcpy( psz_format, FORMAT_STRING );
+ strcpy( psz_format_bool, FORMAT_STRING );
+ }
+
+ /* List all modules */
+ p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
+
+ /* Ugly hack to make sure that the help options always come first
+ * (part 1) */
+ if( !psz_module_name )
+ Usage( p_this, "help" );
+
+ /* Enumerate the config for each module */
+ for( i_index = 0; i_index < p_list->i_count; i_index++ )
+ {
+ bool b_help_module;
+ module_t *p_parser = (module_t *)p_list->p_values[i_index].p_object;
+ module_config_t *p_item = NULL;
+ module_config_t *p_section = NULL;
+ module_config_t *p_end = p_parser->p_config + p_parser->confsize;
+
+ if( psz_module_name && strcmp( psz_module_name,
+ p_parser->psz_object_name ) )
+ {
+ char *const *pp_shortcut = p_parser->pp_shortcuts;
+ while( *pp_shortcut )
+ {
+ if( !strcmp( psz_module_name, *pp_shortcut ) )
+ break;
+ pp_shortcut ++;
+ }
+ if( !*pp_shortcut )
+ continue;
+ }
+
+ /* Ignore modules without config options */
+ if( !p_parser->i_config_items )
+ {
+ continue;
+ }
+
+ b_help_module = !strcmp( "help", p_parser->psz_object_name );
+ /* Ugly hack to make sure that the help options always come first
+ * (part 2) */
+ if( !psz_module_name && b_help_module )
+ continue;
+
+ /* Ignore modules with only advanced config options if requested */
+ if( !b_advanced )
+ {
+ for( p_item = p_parser->p_config;
+ p_item < p_end;
+ p_item++ )
+ {
+ if( (p_item->i_type & CONFIG_ITEM) &&
+ !p_item->b_advanced ) break;
+ }
+ }
+
+ /* Print name of module */
+ if( strcmp( "main", p_parser->psz_object_name ) )
+ {
+ if( b_color )
+ utf8_fprintf( stdout, "\n " GREEN "%s" GRAY "\n",
+ p_parser->psz_longname );
+ else
+ utf8_fprintf( stdout, "\n %s\n", p_parser->psz_longname );
+ }
+ if( p_parser->psz_help )
+ {
+ if( b_color )
+ utf8_fprintf( stdout, CYAN" %s\n"GRAY, p_parser->psz_help );
+ else
+ utf8_fprintf( stdout, " %s\n", p_parser->psz_help );
+ }
+
+ /* Print module options */
+ for( p_item = p_parser->p_config;
+ p_item < p_end;
+ p_item++ )
+ {
+ char *psz_text, *psz_spaces = psz_spaces_text;
+ const char *psz_bra = NULL, *psz_type = NULL, *psz_ket = NULL;
+ const char *psz_suf = "", *psz_prefix = NULL;
+ signed int i;
+ size_t i_cur_width;
+
+ /* Skip removed options */
+ if( p_item->b_removed )
+ {
+ continue;
+ }
+ /* Skip advanced options if requested */
+ if( p_item->b_advanced && !b_advanced )
+ {
+ b_has_advanced = true;
+ continue;
+ }
+
+ switch( p_item->i_type )
+ {
+ case CONFIG_HINT_CATEGORY:
+ case CONFIG_HINT_USAGE:
+ if( !strcmp( "main", p_parser->psz_object_name ) )
+ {
+ if( b_color )
+ utf8_fprintf( stdout, GREEN "\n %s\n" GRAY,
+ p_item->psz_text );
+ else
+ utf8_fprintf( stdout, "\n %s\n", p_item->psz_text );
+ }
+ if( b_description && p_item->psz_longtext )
+ {
+ if( b_color )
+ utf8_fprintf( stdout, CYAN " %s\n" GRAY,
+ p_item->psz_longtext );
+ else
+ utf8_fprintf( stdout, " %s\n", p_item->psz_longtext );
+ }
+ break;
+
+ case CONFIG_HINT_SUBCATEGORY:
+ if( strcmp( "main", p_parser->psz_object_name ) )
+ break;
+ case CONFIG_SECTION:
+ p_section = p_item;
+ break;
+
+ case CONFIG_ITEM_STRING:
+ case CONFIG_ITEM_FILE:
+ case CONFIG_ITEM_DIRECTORY:
+ case CONFIG_ITEM_MODULE: /* We could also have "=<" here */
+ case CONFIG_ITEM_MODULE_CAT:
+ case CONFIG_ITEM_MODULE_LIST:
+ case CONFIG_ITEM_MODULE_LIST_CAT:
+ case CONFIG_ITEM_FONT:
+ case CONFIG_ITEM_PASSWORD:
+ print_help_section( p_section, b_color, b_description );
+ p_section = NULL;
+ psz_bra = OPTION_VALUE_SEP "<";
+ psz_type = _("string");
+ psz_ket = ">";
+
+ if( p_item->ppsz_list )
+ {
+ psz_bra = OPTION_VALUE_SEP "{";
+ psz_type = psz_buffer;
+ psz_buffer[0] = '\0';
+ for( i = 0; p_item->ppsz_list[i]; i++ )
+ {
+ if( i ) strcat( psz_buffer, "," );
+ strcat( psz_buffer, p_item->ppsz_list[i] );
+ }
+ psz_ket = "}";
+ }
+ break;
+ case CONFIG_ITEM_INTEGER:
+ case CONFIG_ITEM_KEY: /* FIXME: do something a bit more clever */
+ print_help_section( p_section, b_color, b_description );
+ p_section = NULL;
+ psz_bra = OPTION_VALUE_SEP "<";
+ psz_type = _("integer");
+ psz_ket = ">";
+
+ if( p_item->min.i || p_item->max.i )
+ {
+ sprintf( psz_buffer, "%s [%i .. %i]", psz_type,
+ p_item->min.i, p_item->max.i );
+ psz_type = psz_buffer;
+ }
+
+ if( p_item->i_list )
+ {
+ psz_bra = OPTION_VALUE_SEP "{";
+ psz_type = psz_buffer;
+ psz_buffer[0] = '\0';
+ for( i = 0; p_item->ppsz_list_text[i]; i++ )
+ {
+ if( i ) strcat( psz_buffer, ", " );
+ sprintf( psz_buffer + strlen(psz_buffer), "%i (%s)",
+ p_item->pi_list[i],
+ p_item->ppsz_list_text[i] );
+ }
+ psz_ket = "}";
+ }
+ break;
+ case CONFIG_ITEM_FLOAT:
+ print_help_section( p_section, b_color, b_description );
+ p_section = NULL;
+ psz_bra = OPTION_VALUE_SEP "<";
+ psz_type = _("float");
+ psz_ket = ">";
+ if( p_item->min.f || p_item->max.f )
+ {
+ sprintf( psz_buffer, "%s [%f .. %f]", psz_type,
+ p_item->min.f, p_item->max.f );
+ psz_type = psz_buffer;
+ }
+ break;
+ case CONFIG_ITEM_BOOL:
+ print_help_section( p_section, b_color, b_description );
+ p_section = NULL;
+ psz_bra = ""; psz_type = ""; psz_ket = "";
+ if( !b_help_module )
+ {
+ psz_suf = p_item->value.i ? _(" (default enabled)") :
+ _(" (default disabled)");
+ }
+ break;
+ }
+
+ if( !psz_type )
+ {
+ continue;
+ }
+
+ /* Add short option if any */
+ if( p_item->i_short )
+ {
+ sprintf( psz_short, "-%c,", p_item->i_short );
+ }
+ else
+ {
+ strcpy( psz_short, " " );
+ }
+
+ i = PADDING_SPACES - strlen( p_item->psz_name )
+ - strlen( psz_bra ) - strlen( psz_type )
+ - strlen( psz_ket ) - 1;
+
+ if( p_item->i_type == CONFIG_ITEM_BOOL && !b_help_module )
+ {
+ psz_prefix = ", --no-";
+ i -= strlen( p_item->psz_name ) + strlen( psz_prefix );
+ }
+
+ if( i < 0 )
+ {
+ psz_spaces[0] = '\n';
+ i = 0;
+ }
+ else
+ {
+ psz_spaces[i] = '\0';
+ }
+
+ if( p_item->i_type == CONFIG_ITEM_BOOL && !b_help_module )
+ {
+ utf8_fprintf( stdout, psz_format_bool, psz_short,
+ p_item->psz_name, psz_prefix, p_item->psz_name,
+ psz_bra, psz_type, psz_ket, psz_spaces );
+ }
+ else
+ {
+ utf8_fprintf( stdout, psz_format, psz_short, p_item->psz_name,
+ "", "", psz_bra, psz_type, psz_ket, psz_spaces );
+ }
+
+ psz_spaces[i] = ' ';
+
+ /* We wrap the rest of the output */
+ sprintf( psz_buffer, "%s%s", p_item->psz_text, psz_suf );
+ b_description_hack = b_description;
+
+ description:
+ psz_text = psz_buffer;
+ i_cur_width = b_description && !b_description_hack
+ ? i_width_description
+ : i_width;
+ while( *psz_text )
+ {
+ char *psz_parser, *psz_word;
+ size_t i_end = strlen( psz_text );
+
+ /* If the remaining text fits in a line, print it. */
+ if( i_end <= i_cur_width )
+ {
+ if( b_color )
+ {
+ if( !b_description || b_description_hack )
+ utf8_fprintf( stdout, BLUE"%s\n"GRAY, psz_text );
+ else
+ utf8_fprintf( stdout, "%s\n", psz_text );
+ }
+ else
+ {
+ utf8_fprintf( stdout, "%s\n", psz_text );
+ }
+ break;
+ }
+
+ /* Otherwise, eat as many words as possible */
+ psz_parser = psz_text;
+ do
+ {
+ psz_word = psz_parser;
+ psz_parser = strchr( psz_word, ' ' );
+ /* If no space was found, we reached the end of the text
+ * block; otherwise, we skip the space we just found. */
+ psz_parser = psz_parser ? psz_parser + 1
+ : psz_text + i_end;
+
+ } while( (size_t)(psz_parser - psz_text) <= i_cur_width );
+
+ /* We cut a word in one of these cases:
+ * - it's the only word in the line and it's too long.
+ * - we used less than 80% of the width and the word we are
+ * going to wrap is longer than 40% of the width, and even
+ * if the word would have fit in the next line. */
+ if( psz_word == psz_text
+ || ( (size_t)(psz_word - psz_text) < 80 * i_cur_width / 100
+ && (size_t)(psz_parser - psz_word) > 40 * i_cur_width / 100 ) )
+ {
+ char c = psz_text[i_cur_width];
+ psz_text[i_cur_width] = '\0';
+ if( b_color )
+ {
+ if( !b_description || b_description_hack )
+ utf8_fprintf( stdout, BLUE"%s\n%s"GRAY,
+ psz_text, psz_spaces );
+ else
+ utf8_fprintf( stdout, "%s\n%s",
+ psz_text, psz_spaces );
+ }
+ else
+ {
+ utf8_fprintf( stdout, "%s\n%s", psz_text, psz_spaces );
+ }
+ psz_text += i_cur_width;
+ psz_text[0] = c;
+ }
+ else
+ {
+ psz_word[-1] = '\0';
+ if( b_color )
+ {
+ if( !b_description || b_description_hack )
+ utf8_fprintf( stdout, BLUE"%s\n%s"GRAY,
+ psz_text, psz_spaces );
+ else
+ utf8_fprintf( stdout, "%s\n%s",
+ psz_text, psz_spaces );
+ }
+ else
+ {
+ utf8_fprintf( stdout, "%s\n%s", psz_text, psz_spaces );
+ }
+ psz_text = psz_word;
+ }
+ }
+
+ if( b_description_hack && p_item->psz_longtext )
+ {
+ sprintf( psz_buffer, "%s%s", p_item->psz_longtext, psz_suf );
+ b_description_hack = false;
+ psz_spaces = psz_spaces_longtext;
+ utf8_fprintf( stdout, "%s", psz_spaces );
+ goto description;
+ }
+ }
+ }
+
+ if( b_has_advanced )
+ {
+ if( b_color )
+ utf8_fprintf( stdout, "\n" WHITE "%s" GRAY " %s\n", _( "Note:" ),
+ _( "add --advanced to your command line to see advanced options."));
+ else
+ utf8_fprintf( stdout, "\n %s %s\n", _( "Note:" ),
+ _( "add --advanced to your command line to see advanced options."));
+ }
+
+ /* Release the module list */
+ vlc_list_release( p_list );
+}
+
+/*****************************************************************************
+ * ListModules: list the available modules with their description
+ *****************************************************************************
+ * Print a list of all available modules (builtins and plugins) and a short
+ * description for each one.
+ *****************************************************************************/
+static void ListModules( libvlc_int_t *p_this, bool b_verbose )
+{
+ vlc_list_t *p_list = NULL;
+ module_t *p_parser = NULL;
+ char psz_spaces[22];
+ int i_index;
+
+ bool b_color = config_GetInt( p_this, "color" ) > 0;
+
+ memset( psz_spaces, ' ', 22 );
+
+#ifdef WIN32
+ ShowConsole( true );
+#endif
+
+ /* List all modules */
+ p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
+
+ /* Enumerate each module */
+ for( i_index = 0; i_index < p_list->i_count; i_index++ )
+ {
+ int i;
+
+ p_parser = (module_t *)p_list->p_values[i_index].p_object ;
+
+ /* Nasty hack, but right now I'm too tired to think about a nice
+ * solution */
+ i = 22 - strlen( p_parser->psz_object_name ) - 1;
+ if( i < 0 ) i = 0;
+ psz_spaces[i] = 0;
+
+ if( b_color )
+ utf8_fprintf( stdout, GREEN" %s%s "WHITE"%s\n"GRAY,
+ p_parser->psz_object_name,
+ psz_spaces,
+ p_parser->psz_longname );
+ else
+ utf8_fprintf( stdout, " %s%s %s\n",
+ p_parser->psz_object_name,
+ psz_spaces, p_parser->psz_longname );
+
+ if( b_verbose )
+ {
+ char *const *pp_shortcut = p_parser->pp_shortcuts;
+ while( *pp_shortcut )
+ {
+ if( strcmp( *pp_shortcut, p_parser->psz_object_name ) )
+ {
+ if( b_color )
+ utf8_fprintf( stdout, CYAN" s %s\n"GRAY,
+ *pp_shortcut );
+ else
+ utf8_fprintf( stdout, " s %s\n",
+ *pp_shortcut );
+ }
+ pp_shortcut++;
+ }
+ if( p_parser->psz_capability )
+ {
+ if( b_color )
+ utf8_fprintf( stdout, MAGENTA" c %s (%d)\n"GRAY,
+ p_parser->psz_capability,
+ p_parser->i_score );
+ else
+ utf8_fprintf( stdout, " c %s (%d)\n",
+ p_parser->psz_capability,
+ p_parser->i_score );
+ }
+ }
+
+ psz_spaces[i] = ' ';
+ }
+
+ vlc_list_release( p_list );
+
+#ifdef WIN32 /* Pause the console because it's destroyed when we exit */
+ PauseConsole();
+#endif
+}
+
+/*****************************************************************************
+ * Version: print complete program version
+ *****************************************************************************
+ * Print complete program version and build number.
+ *****************************************************************************/
+static void Version( void )
+{
+#ifdef WIN32
+ ShowConsole( true );
+#endif
+
+ utf8_fprintf( stdout, _("VLC version %s\n"), VLC_Version() );
+ utf8_fprintf( stdout, _("Compiled by %s@%s.%s\n"),
+ VLC_CompileBy(), VLC_CompileHost(), VLC_CompileDomain() );
+ utf8_fprintf( stdout, _("Compiler: %s\n"), VLC_Compiler() );
+ if( strcmp( VLC_Changeset(), "exported" ) )
+ utf8_fprintf( stdout, _("Based upon Git commit [%s]\n"),
+ VLC_Changeset() );
+ utf8_fprintf( stdout, LICENSE_MSG );
+
+#ifdef WIN32 /* Pause the console because it's destroyed when we exit */
+ PauseConsole();
+#endif
+}
+
+/*****************************************************************************
+ * ShowConsole: On Win32, create an output console for debug messages
+ *****************************************************************************
+ * This function is useful only on Win32.
+ *****************************************************************************/
+#ifdef WIN32 /* */
+static void ShowConsole( bool b_dofile )
+{
+# ifndef UNDER_CE
+ FILE *f_help = NULL;
+
+ if( getenv( "PWD" ) && getenv( "PS1" ) ) return; /* cygwin shell */
+
+ AllocConsole();
+ /* Use the ANSI code page (e.g. Windows-1252) as expected by the LibVLC
+ * Unicode/locale subsystem. By default, we have the obsolecent OEM code
+ * page (e.g. CP437 or CP850). */
+ SetConsoleOutputCP (GetACP ());
+ SetConsoleTitle ("VLC media player version "PACKAGE_VERSION);
+
+ freopen( "CONOUT$", "w", stderr );
+ freopen( "CONIN$", "r", stdin );
+
+ if( b_dofile && (f_help = fopen( "vlc-help.txt", "wt" )) )
+ {
+ fclose( f_help );
+ freopen( "vlc-help.txt", "wt", stdout );
+ utf8_fprintf( stderr, _("\nDumped content to vlc-help.txt file.\n") );
+ }
+ else freopen( "CONOUT$", "w", stdout );
+
+# endif