[vlc-commits] [Git][videolan/vlc][master] 26 commits: getopt: remove stray form-feed (0xC) char
Jean-Baptiste Kempf (@jbk)
gitlab at videolan.org
Sat Dec 18 13:59:38 UTC 2021
Jean-Baptiste Kempf pushed to branch master at VideoLAN / VLC
Commits:
34fe1c70 by Lyndon Brown at 2021-12-18T12:32:29+00:00
getopt: remove stray form-feed (0xC) char
traces back to 2001
cfbe86907a89f937b79462cb2876ef7e3cfd4500
- - - - -
6c9127b7 by Lyndon Brown at 2021-12-18T12:32:29+00:00
cmdline: simplify short option array initialisation
- - - - -
6b7eee26 by Lyndon Brown at 2021-12-18T12:32:29+00:00
cmdline: use correct name for neg-bool options in depr warn
where negative variants of deprecated boolean options are used, the
warning would previously specify the positive variant instead, which is
silly and potentially confusing to a user.
- - - - -
3cf3bb4c by Lyndon Brown at 2021-12-18T12:32:29+00:00
cmdline: add error label to error message
clarifies that this is an error message; helps users find errors by
searching output for "error" in some situations maybe?; better
consistency; kinda expected; and combined with later work to add
colour highlighting, improves UX by helping to highlight problems
in terminal output.
- - - - -
0575b068 by Lyndon Brown at 2021-12-18T12:32:29+00:00
cmdline: drop 'vlc:' from error text
unnecessary and ugly for the vlc media player use case, hopefully
also unnecessary for other libvlc use cases.
note that for now at least, this error output is followed
immediately with another line that includes "vlc" in it.
- - - - -
77282fb8 by Lyndon Brown at 2021-12-18T12:32:29+00:00
cmdline: capitalise error messages
- - - - -
f104f95e by Lyndon Brown at 2021-12-18T12:32:29+00:00
cmdline: clarify missing option value error
for options that need an accompanying "value", users can either supply it
within the same command-line argument as the option itself, like
`--foo=bar`, or within the next argument, like `--foo bar`. (for short
options this would be `-fbar` and `-f bar` respectively).
it can be argued that it is possibly confusing to users to thus speak of
a missing "argument" when such an option "value" is missing. let's speak
of a missing option "value" instead.
- - - - -
251f67ec by Lyndon Brown at 2021-12-18T12:32:29+00:00
cmdline: reject short option chars with special getopt meaning
getopt can return ':' and '?' chars to indicate special conditions. there
is nothing to prevent such characters being assigned to options, and thus
there is a risk of misinterpretation, for instance misinterpreting a sign
of a missing option value error condition as a match for such a short
option. this change ensures that in the hypothetical event someone is
stupid enough to try to assign one of these chars to an option, we prevent
situations of misinterpretation of error conditions, at the acceptable
expense of that short option not being allowed to work at all.
- - - - -
5ba65ea2 by Lyndon Brown at 2021-12-18T12:32:29+00:00
plugins: reject a few obvious invalid short option char choices
null = obvious
':' and '?' have special getopt meaning
- - - - -
58244c94 by Lyndon Brown at 2021-12-18T12:32:29+00:00
cmdline: distinuish between 'unknown option' and 'missing option value' issues
- - - - -
4417e1fb by Lyndon Brown at 2021-12-18T12:32:29+00:00
cmdline: reorganise error handling
...to prepare for text translation and colour labels.
(i am not certain that tacking the option onto the end, as we were,
will be suitable for all translations).
i've avoided using allocation to construct the option name portion of the
output, since i expect that would not be liked, and i'm not convinced about
it myself. it can always be reconsidered later however.
- - - - -
0cacb2e6 by Lyndon Brown at 2021-12-18T12:32:29+00:00
cmdline: translate errors and warnings
- - - - -
863a19ed by Lyndon Brown at 2021-12-18T12:32:29+00:00
config: move some console stuff to new internal header
the terminal control code stuff is relevant to (and wanted by me for)
cmdline.c
- - - - -
077aa681 by Lyndon Brown at 2021-12-18T12:32:29+00:00
config: tweak terminal sequence set
- replaced use of `GRAY` and `WHITE` for resetting with `RESET` and
`RESET_BOLD` respectively.
- addressed hidden use of bold by creating separate colour and colour+bold
defines.
- added a `TS_` prefix to help clarify that the defines, where they are
used, are terminal sequences.
- - - - -
6900989f by Lyndon Brown at 2021-12-18T12:32:29+00:00
help: fix unnecessary use of `TS_RESET_BOLD`
- - - - -
e4fa5c37 by Lyndon Brown at 2021-12-18T12:32:29+00:00
config: remove duplicate include
- - - - -
e77ae919 by Lyndon Brown at 2021-12-18T12:32:29+00:00
cmdline: use colour error/warn labels
improves UX by helping to highlight problems in terminal output.
for now, as with the rest of the codebase, we rely upon only a
simple `isatty()` check for automatic colouring decisions, which
does not work for Windows. implementing `isatty()` for Windows to
could perhaps be tackled later.
---
note that user control over use of colour in terminal output via the
use of `--color`/`--no-color` options is deliberately ignored with
respect to the use of colour within error and warning output in
response to any problems encountered whilst processing the supplied
command-line arguments themselves (unknown option error; missing option
value error; obsolete option warning), having decided that this was the
best choice. this was questioned in review of this work, so i have
expanded/documented my thoughts on it here below.
1. default behaviour depends upon whether or not a detection routine
determines that output is connected to a tty. if so then we choose
to use colour in the hope that most users will appreciate the
highlighting of problems. if not, i.e. output is thus being
redirected into a log file or another application, we choose to
not use colour because embeddeding terminal sequences into the
output in such situations risks causing confusion due to the
likely possibility of them not being consumed as intended.
the only situations where users may want or need to change this
default behaviour, are when either:
a. they happen to dislike the use of colour.
b. they want to force use of colour on Windows, due to current
lack of a tty detection mechanism.
the latter of course becomes redundant as soon as we implement
an `isatty()` for Windows.
it is reasonable in my opinion to fail to honour such a user
preference for the limited circumstances of encountering a problem
with the very data-set in which the user communicates that
preference.
never-the-less, let's briefly explore the possible solutions
that could in theory be implemented to try to honour such user
preference for such output.
2. solution 1: "pre-scanning"
the concept was raised of "pre-scanning" the set of arguments to
try to learn the user's indicated preference ahead of properly
processing them, such that we can ensure that it is obeyed if/when
outputting such an error/warning for a problem encountered in
undertaking such processing. i.e. essentially walking through the
argument list looking out for arguments matching a few fixed
strings like "--color", and thus taking note of the preference
before we begin the proper argument processing work.
it should be understood that the rules of proper argument processing
dictate that you cannot with certainty know the nature of an
argument until you have processed fully all of those preceeding it.
options that take data values can be used with the value given
within the same argument or supplied within the next one, and so you
never know if an arbitrarily given argument must be consumed as a
data value rather than treated as a possible option until you've
processed all proceeding arguments; a special "early terminator"
(`--`) argument indicates that all subsequent arguments must be
treated as generic arguments (that must not be interpretted as
options); and an unknown option argument brings processing to a halt
since it is not possible to correctly interpret the nature of
anything subsequently given.
despite this, practically speaking we could get away with
pre-scanning - there are no "short" option forms of these toggle
options to complicate things; and making simple assumptions that
arguments matching "--color" or "--no-color" (or "--nocolor") are
actual uses of those options is pretty reasonable along with assuming
that a "--" argument is an actual early terminator, since such
assumptions are almost always likely to be correct except in certain
very unusual circumstances of broken CLI use or from users
deliberately looking for flaws.
however, i do not feel that it is worth adding a chunk of code
just to essentially ensure that a hypothetical and presumably rare
CLI user who dislikes colour will not see it should they happen to
make a mistake in their CLI usage.
(it might be noted that the vlc binaries do similarly flawed scans
to steal one or two options, but that's not readily avoidable).
3. solution 2: "updating as we go":
as an alternative concept, we could, upon successfully processing
each option, check if the option is `--color` or `--no-color` and if
so, update the `color` boolean accordingly, such that if we run into
a problem and thus need to output an optionally coloured error or
warning label, we might thus obey the user's preference when doing so.
however, we have equal chance that we do the opposite since there
could be a later argument that we did not yet get to that flips the
preference the other way (e.g. `vlc --no-color --foo --color`). in
a worst case scenario the user might end up with a mix of coloured
and non-coloured output that's messy and possibly confusing.
again, i do not feel that it is worth implementing code to do this,
to introduce an inefficiency into the option processing for such
little benefit, especially with the risk of this creating a mess
of inconsistency in some cases.
we (i) should endeavour to introduce `isatty()` support for Windows such
that Windows CLI users get the benefits of colour highlighting, but i
feel that it is perfectly reasonable to take a stance of not bothering to
try to enforce user no-color preference upon argument processing
errors/warnings.
- - - - -
8fb6f8d0 by Lyndon Brown at 2021-12-18T12:32:29+00:00
cmdline: track obsolete state in `vlc_option`
for subsequent use with suggestion matching.
- - - - -
86f9e53b by Lyndon Brown at 2021-12-18T12:32:29+00:00
cmdline: add jaro-winkler string measuring implementation
to be used with suggestion matching.
this implementation is based upon the implementation from the `strsim` Rust
crate, authored by Danny Guo, available at [1]; more specifically the (as
yet un-merged) optimised copy authored by myself, available at [2]. the
code is available under the MIT license.
one implementation difference is that we use floats rather than doubles
since we only intend to use this for suggestion matching in unknown option
error messages and we don't need the extra precision.
[1]: https://github.com/dguo/strsim-rs
[2]: https://github.com/dguo/strsim-rs/pull/31
- - - - -
4ad4a388 by Lyndon Brown at 2021-12-18T12:32:29+00:00
cmdline: add unknown long option suggestion matching
i.e. if a user tries a long option which does not exist, if it is a close
enough match to one or more available options, the error message can
include the best match as a helpful suggestion.
- - - - -
8fdcd829 by Lyndon Brown at 2021-12-18T12:32:29+00:00
cmdline: use cleaner 'see --help' text
old: "Try `vlc --help' for more information."
new: "For more information try `--help`"
in experiments, the new text proved much cleaner. it becomes yet more
clean, having dropped "vlc" from `vlc --help`, when we then drop the
quotes around the remaining `--help` in the commit after next.
note, we now no longer have "vlc" in any of the error output. this
is not a problem for the vlc app itself obviously; i hope it is not
a problem for any other libvlc use cases.
- - - - -
3df5e077 by Lyndon Brown at 2021-12-18T12:32:29+00:00
cmdline: colour highlight option names in error text
inspired by Rust's cargo output, IMO this adds a nice little
enhancement to UX along with the colour error/warn labels.
- - - - -
6319b067 by Lyndon Brown at 2021-12-18T12:32:29+00:00
cmdline: drop quotes for valid option names
experimenting with this i decided that it is cleaner to not use them, for
valid option names at least. they are still used for unknown option quoting
for instance, and where we are quoting multiple CLI arguments like
`--foo <VAL>` or `vlc --foo`.
- - - - -
4e691ef9 by Lyndon Brown at 2021-12-18T12:32:29+00:00
cmdline: simplify error handling code
creating the option label with `asprintf()` up front allows us to tidy
things up quite a bit, removing most notably the duplication of strings
that differ only between char and string format items.
- - - - -
5802f57c by Lyndon Brown at 2021-12-18T12:32:29+00:00
cmdline: add missing float case
i don't believe we have any short options assigned to float options
currently, but we should have this case here prepared to handle it.
- - - - -
dbf81e9a by Lyndon Brown at 2021-12-18T12:32:29+00:00
help: add explicit entries for skipped cases
to be clear about what we do for them.
- - - - -
10 changed files:
- src/Makefile.am
- + src/config/ansi_term.h
- src/config/cmdline.c
- src/config/getopt.c
- src/config/help.c
- + src/config/jaro_winkler.c
- src/config/vlc_getopt.h
- + src/config/vlc_jaro_winkler.h
- src/modules/entry.c
- + src/test/jaro_winkler.c
Changes:
=====================================
src/Makefile.am
=====================================
@@ -203,6 +203,7 @@ libvlccore_la_SOURCES = \
missing.c \
revision.c \
version.c \
+ config/ansi_term.h \
config/configuration.h \
config/core.c \
config/chain.c \
@@ -212,6 +213,8 @@ libvlccore_la_SOURCES = \
config/cmdline.c \
config/getopt.c \
config/vlc_getopt.h \
+ config/jaro_winkler.c \
+ config/vlc_jaro_winkler.h \
extras/libc.c \
media_source/media_source.c \
media_source/media_source.h \
@@ -595,6 +598,7 @@ check_PROGRAMS = \
test_executor \
test_i18n_atof \
test_interrupt \
+ test_jaro_winkler \
test_list \
test_md5 \
test_picture_pool \
@@ -625,6 +629,7 @@ test_executor_SOURCES = test/executor.c
test_i18n_atof_SOURCES = test/i18n_atof.c
test_interrupt_SOURCES = test/interrupt.c
test_interrupt_LDADD = $(LDADD) $(LIBS_libvlccore)
+test_jaro_winkler_SOURCES = test/jaro_winkler.c config/jaro_winkler.c
test_list_SOURCES = test/list.c
test_md5_SOURCES = test/md5.c
test_picture_pool_SOURCES = test/picture_pool.c
=====================================
src/config/ansi_term.h
=====================================
@@ -0,0 +1,122 @@
+/*****************************************************************************
+ * ansi_term.h: Common declarations and helpers for ANSI terminal handling
+ *****************************************************************************
+ * Copyright (C) 1998-2011 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef VLC_ANSI_TERM_H
+#define VLC_ANSI_TERM_H 1
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#if !defined( _WIN32 )
+# include <termios.h>
+# include <sys/ioctl.h>
+#endif
+
+/* ANSI terminal control ("escape") sequences */
+
+/* Terminal control sequence construction */
+#define term_seq(x) "\033[" #x "m"
+
+/**
+ * Codes:
+ *
+ * Effects:
+ * - Normal: 0 (reset)
+ * - Bold: 1
+ * - Dim: 2
+ * - Italic: 3
+ * - Underline: 4
+ * - Reverse: 7
+ * - Invisible: 8
+ * - Strike: 9 (Strike-through)
+ *
+ * Color set 1:
+ * - Black: 30
+ * - Red 31
+ * - Green 32
+ * - Yellow: 33
+ * - Blue: 34
+ * - Magenta: 35
+ * - Cyan: 36
+ * - White: 37
+ *
+ * Color set 2:
+ * - Black: 90
+ * - Red: 91
+ * - Green: 92
+ * - Yellow: 93
+ * - Blue: 94
+ * - Magenta: 95
+ * - Cyan: 96
+ * - White: 97
+ *
+ * Text background color highlighting, set 1:
+ * - Black: 40
+ * - Red: 41
+ * - Green: 42
+ * - Yellow: 43
+ * - Blue: 44
+ * - Magenta: 45
+ * - Cyan: 46
+ * - White: 47
+ *
+ * Text background color highlighting, set 2:
+ * - Black: 100
+ * - Red: 101
+ * - Green: 102
+ * - Yellow: 103
+ * - Blue: 104
+ * - Magenta: 105
+ * - Cyan: 106
+ * - White: 107
+ */
+
+#define TS_RESET term_seq(0)
+
+#define TS_RESET_BOLD term_seq(0;1)
+
+#define TS_BOLD term_seq(1)
+#define TS_DIM term_seq(2)
+#define TS_ITALIC term_seq(3)
+#define TS_UNDERSCORE term_seq(4)
+#define TS_REVERSE term_seq(7)
+#define TS_INVISIBLE term_seq(8)
+#define TS_STRIKE term_seq(9)
+
+#define TS_BLACK term_seq(30)
+#define TS_RED term_seq(31)
+#define TS_GREEN term_seq(32)
+#define TS_YELLOW term_seq(33)
+#define TS_BLUE term_seq(34)
+#define TS_MAGENTA term_seq(35)
+#define TS_CYAN term_seq(36)
+#define TS_WHITE term_seq(37)
+
+#define TS_BLACK_BOLD term_seq(30;1)
+#define TS_RED_BOLD term_seq(31;1)
+#define TS_GREEN_BOLD term_seq(32;1)
+#define TS_YELLOW_BOLD term_seq(33;1)
+#define TS_BLUE_BOLD term_seq(34;1)
+#define TS_MAGENTA_BOLD term_seq(35;1)
+#define TS_CYAN_BOLD term_seq(36;1)
+#define TS_WHITE_BOLD term_seq(37;1)
+
+#endif
=====================================
src/config/cmdline.c
=====================================
@@ -32,7 +32,9 @@
#include <vlc_plugin.h>
#include "vlc_getopt.h"
+#include "vlc_jaro_winkler.h"
+#include "ansi_term.h"
#include "configuration.h"
#include "modules/modules.h"
@@ -63,7 +65,8 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc,
#define b_ignore_errors (pindex == NULL)
/* Short options */
- const module_config_t *pp_shortopts[256];
+ i_shortopts = 0;
+ const module_config_t *pp_shortopts[256] = { NULL };
char *psz_shortopts;
/*
@@ -104,11 +107,10 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc,
ppsz_argv = argv_copy;
}
- i_shortopts = 0;
- for( i_index = 0; i_index < 256; i_index++ )
- {
- pp_shortopts[i_index] = NULL;
- }
+ /* Indicate that we want to know the difference between unknown option and
+ missing option value issues */
+ psz_shortopts[0] = ':';
+ i_shortopts = 1;
/* Fill the p_longopts and psz_shortopts structures */
i_index = 0;
@@ -128,6 +130,7 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc,
if( p_longopts[i_index].name == NULL ) continue;
p_longopts[i_index].flag = &flag;
p_longopts[i_index].val = 0;
+ p_longopts[i_index].is_obsolete = param->obsolete;
if( CONFIG_CLASS(p_item->i_type) != CONFIG_ITEM_BOOL )
p_longopts[i_index].has_arg = true;
@@ -143,6 +146,7 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc,
continue;
p_longopts[i_index].name = psz_name;
p_longopts[i_index].has_arg = false;
+ p_longopts[i_index].is_obsolete = param->obsolete;
p_longopts[i_index].flag = &flag;
p_longopts[i_index].val = 1;
i_index++;
@@ -151,6 +155,7 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc,
continue;
p_longopts[i_index].name = psz_name;
p_longopts[i_index].has_arg = false;
+ p_longopts[i_index].is_obsolete = param->obsolete;
p_longopts[i_index].flag = &flag;
p_longopts[i_index].val = 1;
}
@@ -177,6 +182,10 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc,
psz_shortopts[i_shortopts] = '\0';
int ret = -1;
+ bool color = false;
+#ifndef _WIN32
+ color = (isatty(STDERR_FILENO));
+#endif
/*
* Parse the command line options
@@ -191,10 +200,11 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc,
if( i_cmd == 0 )
{
module_config_t *p_conf;
- const char *psz_name = p_longopts[i_index].name;
+ const char *psz_full_name = p_longopts[i_index].name;
+ const char *psz_name = psz_full_name;
/* Check if we deal with a --nofoo or --no-foo long option */
- if( flag ) psz_name += psz_name[2] == '-' ? 3 : 2;
+ if( flag ) psz_name += psz_full_name[2] == '-' ? 3 : 2;
/* Store the configuration option */
p_conf = config_FindConfig( psz_name );
@@ -206,8 +216,10 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc,
if (param->obsolete)
{
fprintf(stderr,
- "Warning: option --%s no longer exists.\n",
- psz_name);
+ _( "%sWarning:%s Option --%s no longer exists.\n" ),
+ color ? TS_YELLOW_BOLD : "",
+ color ? TS_RESET : "",
+ psz_full_name);
continue;
}
@@ -242,7 +254,7 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc,
}
/* A short option has been recognized */
- if( pp_shortopts[i_cmd] != NULL )
+ if( i_cmd != '?' && i_cmd != ':' && pp_shortopts[i_cmd] != NULL )
{
const char *name = pp_shortopts[i_cmd]->psz_name;
switch( CONFIG_CLASS(pp_shortopts[i_cmd]->i_type) )
@@ -264,6 +276,10 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc,
strtoll(state.arg, NULL, 0) );
}
break;
+ case CONFIG_ITEM_FLOAT:
+ var_Create( p_this, name, VLC_VAR_FLOAT );
+ var_SetFloat( p_this, name, us_atof(state.arg) );
+ break;
case CONFIG_ITEM_BOOL:
var_Create( p_this, name, VLC_VAR_BOOL );
var_SetBool( p_this, name, true );
@@ -273,20 +289,54 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc,
continue;
}
- /* Internal error: unknown option */
+ /* Internal error: unknown option or missing option value */
if( !b_ignore_errors )
{
- fputs( "vlc: unknown option"
- " or missing mandatory argument ", stderr );
- if( state.opt )
+ char *optlabel;
+ if ( (state.opt && asprintf(&optlabel, "%s-%c%s",
+ color ? TS_YELLOW : "", state.opt,
+ color ? TS_RESET : "") < 0)
+ || (!state.opt && asprintf(&optlabel, "%s%s%s",
+ color ? TS_YELLOW : "", ppsz_argv[state.ind-1],
+ color ? TS_RESET : "") < 0) )
{
- fprintf( stderr, "`-%c'\n", state.opt );
+ /* just ignore failure - unlikely and not worth trying to handle in some way */
+ optlabel = NULL;
+ }
+
+ fprintf( stderr, _( "%sError:%s " ), color ? TS_RED_BOLD : "", color ? TS_RESET : "");
+ if (i_cmd == ':')
+ {
+ fprintf( stderr, _( "Missing mandatory value for option %s\n" ), optlabel );
}
else
{
- fprintf( stderr, "`%s'\n", ppsz_argv[state.ind-1] );
+ fprintf( stderr, _( "Unknown option `%s'\n" ), optlabel );
+
+ /* suggestion matching */
+ if( !state.opt )
+ {
+ float jw_filter = 0.8, best_metric = jw_filter, metric;
+ const char *best = NULL;
+ const char *jw_a = ppsz_argv[state.ind-1] + 2;
+ for (size_t i = 0; i < (size_t)i_opts; i++) {
+ if (p_longopts[i].is_obsolete)
+ continue;
+ const char *jw_b = p_longopts[i].name;
+ if (vlc_jaro_winkler(jw_a, jw_b, &metric) == 0) { //ignore failed malloc calls
+ if (metric > best_metric || (!best && metric >= jw_filter)) {
+ best = jw_b;
+ best_metric = metric;
+ }
+ }
+ }
+ if (best)
+ fprintf( stderr, _( " Did you mean %s--%s%s?\n" ),
+ color ? TS_GREEN : "", best, color ? TS_RESET : "" );
+ }
}
- fputs( "Try `vlc --help' for more information.\n", stderr );
+ fprintf( stderr, _( "For more information try %s--help%s\n" ),
+ color ? TS_GREEN : "", color ? TS_RESET : "" );
goto out;
}
}
=====================================
src/config/getopt.c
=====================================
@@ -92,7 +92,6 @@ static void exchange(char **argv, vlc_getopt_t *restrict state)
state->last_nonopt = state->ind;
}
-
/* Scan elements of ARGV (whose length is ARGC) for option characters
given in OPTSTRING.
=====================================
src/config/help.c
=====================================
@@ -35,17 +35,15 @@
#include <vlc_modules.h>
#include <vlc_plugin.h>
#include <vlc_charset.h>
+#include "ansi_term.h"
#include "modules/modules.h"
#include "config/configuration.h"
#include "libvlc.h"
#if defined( _WIN32 )
-# include <vlc_charset.h>
# define wcwidth(cp) ((void)(cp), 1) /* LOL */
#else
# include <unistd.h>
-# include <termios.h>
-# include <sys/ioctl.h>
#endif
#if defined( _WIN32 ) && !defined( VLC_WINSTORE_APP )
@@ -231,15 +229,6 @@ static void Help (vlc_object_t *p_this, char const *psz_help_name)
*****************************************************************************
* Print a short inline help. Message interface is initialized at this stage.
*****************************************************************************/
-# define COL(x) "\033[" #x ";1m"
-# define RED COL(31)
-# define GREEN COL(32)
-# define YELLOW COL(33)
-# define BLUE COL(34)
-# define MAGENTA COL(35)
-# define CYAN COL(36)
-# define WHITE COL(0)
-# define GRAY "\033[0m"
# define LINE_START 8
# define PADDING_SPACES 25
@@ -252,10 +241,10 @@ static void print_section(const module_t *m, const module_config_t **sect,
return;
*sect = NULL;
- printf(color ? RED" %s:\n"GRAY : " %s:\n",
+ printf(color ? TS_RED_BOLD " %s:\n" TS_RESET : " %s:\n",
module_gettext(m, item->psz_text));
if (desc && item->psz_longtext != NULL)
- printf(color ? MAGENTA" %s\n"GRAY : " %s\n",
+ printf(color ? TS_MAGENTA_BOLD " %s\n" TS_RESET : " %s\n",
module_gettext(m, item->psz_longtext));
}
@@ -264,7 +253,7 @@ static void print_desc(const char *str, unsigned margin, bool color)
unsigned width = ConsoleWidth() - margin;
if (color)
- fputs(BLUE, stdout);
+ fputs(TS_BLUE_BOLD, stdout);
const char *word = str;
int wordlen = 0, wordwidth = 0;
@@ -321,7 +310,7 @@ static void print_desc(const char *str, unsigned margin, bool color)
if (!newline)
putchar(' ');
- printf(color ? "%s\n"GRAY : "%s\n", word);
+ printf(color ? "%s\n" TS_RESET : "%s\n", word);
}
static int vlc_swidth(const char *str)
@@ -363,14 +352,19 @@ static void print_item(const module_t *m, const struct vlc_param *param,
switch (item->i_type)
{
case CONFIG_HINT_CATEGORY:
- printf(color ? GREEN "\n %s\n" GRAY : "\n %s\n",
+ printf(color ? TS_GREEN_BOLD "\n %s\n" TS_RESET : "\n %s\n",
module_gettext(m, item->psz_text));
if (desc && item->psz_longtext != NULL)
- printf(color ? CYAN " %s\n" GRAY : " %s\n",
+ printf(color ? TS_CYAN_BOLD " %s\n" TS_RESET : " %s\n",
module_gettext(m, item->psz_longtext));
break;
+ case CONFIG_CATEGORY:
+ case CONFIG_SUBCATEGORY:
+ /* We ignore these here, using 'hints' instead */
+ break;
+
case CONFIG_SECTION:
*section = item;
break;
@@ -503,11 +497,11 @@ static void print_item(const module_t *m, const struct vlc_param *param,
strcpy(shortopt, " ");
if (CONFIG_CLASS(item->i_type) == CONFIG_ITEM_BOOL)
- printf(color ? WHITE" %s --%s" "%s%s%s%s%s "GRAY
+ printf(color ? TS_BOLD " %s --%s" "%s%s%s%s%s " TS_RESET
: " %s --%s%s%s%s%s%s ", shortopt, item->psz_name,
prefix, item->psz_name, bra, type, ket);
else
- printf(color ? WHITE" %s --%s"YELLOW"%s%s%s%s%s "GRAY
+ printf(color ? TS_BOLD " %s --%s" TS_YELLOW_BOLD "%s%s%s%s%s " TS_RESET
: " %s --%s%s%s%s%s%s ", shortopt, item->psz_name,
"", "", /* XXX */ bra, type, ket);
@@ -615,10 +609,10 @@ static void Usage (vlc_object_t *p_this, char const *psz_search)
continue;
/* Print name of module */
- printf(color ? "\n " GREEN "%s" GRAY " (%s)\n" : "\n %s (%s)\n",
+ printf(color ? "\n " TS_GREEN_BOLD "%s" TS_RESET " (%s)\n" : "\n %s (%s)\n",
module_gettext(m, m->psz_longname), objname);
if (m->psz_help != NULL)
- printf(color ? CYAN" %s\n"GRAY : " %s\n",
+ printf(color ? TS_CYAN_BOLD" %s\n" TS_RESET : " %s\n",
module_gettext(m, m->psz_help));
if (psz_search != NULL && p->conf.count == 0)
@@ -637,7 +631,7 @@ static void Usage (vlc_object_t *p_this, char const *psz_search)
}
if (!found)
- printf(color ? "\n" WHITE "%s" GRAY "\n" : "\n%s\n",
+ printf(color ? "\n" TS_BOLD "%s" TS_RESET "\n" : "\n%s\n",
_("No matching module found. Use --list or "
"--list-verbose to list available modules."));
}
@@ -669,7 +663,7 @@ static void ListModules (vlc_object_t *p_this, bool b_verbose)
{
module_t *p_parser = list[j];
const char *objname = module_get_object (p_parser);
- printf(color ? GREEN" %-22s "WHITE"%s\n"GRAY : " %-22s %s\n",
+ printf(color ? TS_GREEN_BOLD " %-22s " TS_RESET_BOLD "%s\n" TS_RESET : " %-22s %s\n",
objname, module_gettext(p_parser, p_parser->psz_longname));
if( b_verbose )
@@ -677,10 +671,10 @@ static void ListModules (vlc_object_t *p_this, bool b_verbose)
const char *const *pp_shortcuts = p_parser->pp_shortcuts;
for( unsigned i = 0; i < p_parser->i_shortcuts; i++ )
if( strcmp( pp_shortcuts[i], objname ) )
- printf(color ? CYAN" s %s\n"GRAY : " s %s\n",
+ printf(color ? TS_CYAN_BOLD " s %s\n" TS_RESET : " s %s\n",
pp_shortcuts[i]);
if (p_parser->psz_capability != NULL)
- printf(color ? MAGENTA" c %s (%d)\n"GRAY : " c %s (%d)\n",
+ printf(color ? TS_MAGENTA_BOLD " c %s (%d)\n" TS_RESET : " c %s (%d)\n",
p_parser->psz_capability, p_parser->i_score);
}
}
=====================================
src/config/jaro_winkler.c
=====================================
@@ -0,0 +1,167 @@
+/*****************************************************************************
+ * jaro_winkler.c: jaro winkler string similarity algorithm implementation
+ *****************************************************************************
+ * Copyright 2015 Danny Guo
+ * Copyright 2018 Lyndon Brown
+ *
+ * Authors: Danny Guo <dguo at users.noreply.github.com>
+ * Lyndon Brown <jnqnfe at gmail.com>
+ *
+ * Licensed under the MIT license. You may not copy, modify, or distribute this
+ * file except in compliance with said license. You can find a copy of this
+ * license either in the LICENSE file, or alternatively at
+ * <http://opensource.org/licenses/MIT>.
+ *****************************************************************************
+ * This file is based upon the Jaro Winkler implementation of the `strsim`
+ * Rust crate, authored by Danny Guo, available at
+ * <https://github.com/dguo/strsim-rs>; more specifically the (as yet un-merged)
+ * optimised copy authored by myself (Lyndon Brown), available at
+ * <https://github.com/dguo/strsim-rs/pull/31>. The code is available under the
+ * MIT license.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+
+#include "vlc_jaro_winkler.h"
+
+#define MAX(a, b) ( ((a) > (b)) ? (a) : (b) )
+#define MIN(a, b) ( ((a) < (b)) ? (a) : (b) )
+
+/**
+ * Checks both strings for a common prefix, returning the number of matching
+ * bytes.
+ */
+static inline size_t split_on_common_prefix(const char *a, const char *b) {
+ size_t len = 0;
+ while (*(a) && *(b) && *(a++) == *(b++)) len++;
+ return len;
+}
+
+/**
+ * This is the inner Jaro algorithm, with a parameter for passing back the
+ * length of the prefix common to both strings, used for efficiency of the
+ * Jaro-Winkler implementation.
+ */
+static inline int jaro_inner(const char *a, const char *b, size_t *ret_prefix_cc, float* res) {
+ assert(a && b && ret_prefix_cc && res);
+
+ if ((a[0] == '\0') ^ (b[0] == '\0')) {
+ *res = 0.0;
+ return 0;
+ }
+
+ size_t prefix_char_count = split_on_common_prefix(a, b);
+ const char *a_suffix = a + prefix_char_count;
+ const char *b_suffix = b + prefix_char_count;
+
+ if (a_suffix[0] == '\0' && b_suffix[0] == '\0') {
+ *res = 1.0;
+ return 0;
+ }
+
+ *ret_prefix_cc = prefix_char_count;
+
+ size_t a_numchars = strlen(a_suffix) + prefix_char_count;
+ size_t b_numchars = strlen(b_suffix) + prefix_char_count;
+
+ // The check for lengths of one here is to prevent integer overflow when
+ // calculating the search range.
+ if (a_numchars == 1 && b_numchars == 1) {
+ *res = 0.0;
+ return 0;
+ }
+
+ size_t search_range = (MAX(a_numchars, b_numchars) / 2) - 1;
+
+ /* catch overflow */
+ assert(a_numchars <= INT_MAX);
+ assert(search_range <= INT_MAX);
+
+ bool *b_consumed = calloc(b_numchars, sizeof(*b_consumed));
+ if (!b_consumed) {
+ *res = 0.0;
+ return -1;
+ }
+
+ size_t matches = prefix_char_count;
+ size_t transpositions = 0;
+ size_t b_match_index = 0;
+
+ const char *a_char = a_suffix;
+ for (size_t i = 0; *a_char; i++) {
+ ssize_t tmp = (ssize_t)i - (ssize_t)search_range;
+ size_t bound_start = (tmp >= 0) ? tmp : 0;
+ size_t bound_end = MIN(b_numchars, i + search_range + 1);
+
+ if (bound_start >= bound_end) {
+ a_char++;
+ continue;
+ }
+
+ const char *b_char = b_suffix + bound_start;
+ for (size_t j = bound_start; *b_char && j < bound_end; j++) {
+ if (*a_char == *b_char && !b_consumed[j]) {
+ b_consumed[j] = true;
+ matches++;
+
+ if (j < b_match_index) {
+ transpositions++;
+ }
+ b_match_index = j;
+
+ break;
+ }
+ b_char++;
+ }
+ a_char++;
+ }
+
+ if (matches == 0) {
+ *res = 0.0;
+ return 0;
+ }
+
+ *res = (1.0 / 3.0) *
+ (((float)matches / (float)a_numchars) +
+ ((float)matches / (float)b_numchars) +
+ (((float)matches - (float)transpositions) / (float)matches));
+ return 0;
+}
+
+/**
+ * Calculate a “Jaro Winkler” metric.
+ *
+ * Algorithm: <http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance>
+ *
+ * Like “Jaro” but gives a boost to strings that have a common prefix.
+ *
+ * \note: This implementation does not place a limit on the common prefix
+ * length adjusted for.
+ *
+ * \param a string A
+ * \param b string B
+ * \param res [OUT] a pointer to a float to receive the result
+ * \return -1 on memory allocation failure, otherwise 0
+ */
+int vlc_jaro_winkler(const char *a, const char *b, float* res) {
+ size_t prefix_char_count = 0;
+ float jaro_distance;
+ if (jaro_inner(a, b, &prefix_char_count, &jaro_distance) != 0) {
+ return -1;
+ }
+
+ float jaro_winkler_distance =
+ jaro_distance + (0.1 * (float)prefix_char_count * (1.0 - jaro_distance));
+
+ *res = (jaro_winkler_distance <= 1.0) ? jaro_winkler_distance : 1.0;
+ return 0;
+}
=====================================
src/config/vlc_getopt.h
=====================================
@@ -77,6 +77,12 @@ typedef struct vlc_getopt_s
false if the option does not take an argument,
true if the option requires an argument.
+ The field `is_obsolete` is a custom VLC addition, tracking whether or not
+ an option is obsolete (such options in VLC remain in existence for some
+ time, with a different error printed compared to that used for unknown
+ options). We store this here as a convenience; it is read by the
+ 'suggestion matching' feature, which needs to ignore such options.
+
If the field `flag' is not NULL, it points to a variable that is set
to the value given in the field `val' when the option is found, but
left unchanged if the option is not found.
@@ -92,6 +98,7 @@ struct vlc_option
{
const char *name;
bool has_arg;
+ bool is_obsolete;
int *flag;
int val;
};
=====================================
src/config/vlc_jaro_winkler.h
=====================================
@@ -0,0 +1,43 @@
+/*****************************************************************************
+ * jaro_winkler.c: jaro winkler string similarity algorithm implementation
+ *****************************************************************************
+ * Copyright 2015 Danny Guo
+ * Copyright 2018, 2019 Lyndon Brown
+ *
+ * Authors: Danny Guo <dguo at users.noreply.github.com>
+ * Lyndon Brown <jnqnfe at gmail.com>
+ *
+ * Licensed under the MIT license. You may not copy, modify, or distribute this
+ * file except in compliance with said license. You can find a copy of this
+ * license either in the LICENSE file, or alternatively at
+ * <http://opensource.org/licenses/MIT>.
+ *****************************************************************************
+ * This file is based upon the Jaro Winkler implementation of the `strsim`
+ * Rust crate, authored by Danny Guo, available at
+ * <https://github.com/dguo/strsim-rs>; more specifically the (as yet un-merged)
+ * optimised copy authored by myself (Lyndon Brown), available at
+ * <https://github.com/dguo/strsim-rs/pull/31>. The code is available under the
+ * MIT license.
+ *****************************************************************************/
+
+#ifndef VLC_JARO_WINKLER_H
+#define VLC_JARO_WINKLER_H 1
+
+/**
+ * Calculate a “Jaro Winkler” metric.
+ *
+ * Algorithm: <http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance>
+ *
+ * Like “Jaro” but gives a boost to strings that have a common prefix.
+ *
+ * \note: This implementation does not place a limit the common prefix length
+ * adjusted for.
+ *
+ * \param a string A
+ * \param b string B
+ * \param res [OUT] a pointer to a float to receive the result
+ * \return -1 on memory allocation failure, otherwise 0
+ */
+int vlc_jaro_winkler(const char *a, const char *b, float *res);
+
+#endif
=====================================
src/modules/entry.c
=====================================
@@ -409,7 +409,9 @@ static int vlc_plugin_desc_cb(void *ctx, void *tgt, int propid, ...)
{
struct vlc_param *param = tgt;
- param->shortname = va_arg(ap, int);
+ char c = va_arg(ap, int);
+ assert(c != '\0' && c != '?' && c != ':');
+ param->shortname = c;
break;
}
=====================================
src/test/jaro_winkler.c
=====================================
@@ -0,0 +1,101 @@
+/*****************************************************************************
+ * jaro_winkler.c: Tests for our Jaro Winkler algorithm
+ *****************************************************************************
+ * Copyright 2015 Danny Guo
+ * Copyright 2018 Lyndon Brown
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <math.h> /* fabs() */
+
+#include <vlc_common.h>
+#include <vlc_strings.h>
+
+#include "../config/vlc_jaro_winkler.h"
+
+const char vlc_module_name[] = "test_jarowinkler";
+
+# define test1( expected, a, b ) \
+ assert(vlc_jaro_winkler(a, b, &actual) == 0); \
+ failed = (actual != expected); \
+ problems |= failed; \
+ printf("[TEST] expected: %f, actual: %f, accuracy: n/a, result: %s, (a: %s), (b: %s)\n", \
+ expected, actual, (failed) ? "FAIL" : "pass", a, b);
+
+# define test2( expected, a, b, accuracy ) \
+ assert(vlc_jaro_winkler(a, b, &actual) == 0); \
+ failed = (fabs(expected - actual) >= accuracy); \
+ problems |= failed; \
+ printf("[TEST] expected: %f, actual: %f, accuracy: %f, result: %s, (a: %s), (b: %s)\n", \
+ expected, actual, accuracy, (failed) ? "FAIL": "pass", a, b);
+
+int main( void )
+{
+ bool problems = false, failed = false;
+ float actual;
+
+ // both_empty
+ test1(1.0, "", "");
+
+ // first_empty
+ test1(0.0, "", "jaro-winkler");
+
+ // second_empty
+ test1(0.0, "distance", "");
+
+ // same
+ test1(1.0, "Jaro-Winkler", "Jaro-Winkler");
+
+ // diff_short
+ test2(0.813, "dixon", "dicksonx", 0.001);
+ test2(0.813, "dicksonx", "dixon", 0.001);
+
+ // same_one_character
+ test1(1.0, "a", "a");
+
+ // diff_one_character
+ test1(0.0, "a", "b");
+
+ // diff_no_transposition
+ test2(0.840, "dwayne", "duane", 0.001);
+
+ // diff_with_transposition
+ test2(0.961, "martha", "marhta", 0.001);
+
+ // names
+ test2(0.562, "Friedrich Nietzsche", "Fran-Paul Sartre", 0.001);
+
+ // long_prefix
+ test2(0.911, "cheeseburger", "cheese fries", 0.001);
+
+ // more_names
+ test2(0.868, "Thorkel", "Thorgier", 0.001);
+
+ // length_of_one
+ test2(0.738, "Dinsdale", "D", 0.001);
+
+ // very_long_prefix
+ test2(1.0, "thequickbrownfoxjumpedoverx", "thequickbrownfoxjumpedovery", 0.001);
+
+ return (problems) ? -1 : 0;
+}
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/12d1d54909037f44acd198de345197184c28c9c2...dbf81e9acc8ac90286defbc465f6eae5e6f52180
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/12d1d54909037f44acd198de345197184c28c9c2...dbf81e9acc8ac90286defbc465f6eae5e6f52180
You're receiving this email because of your account on code.videolan.org.
More information about the vlc-commits
mailing list