2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-12-23 03:18:59 +00:00

Slightly improve bash completion arg parsing

This commit is contained in:
Jay Berkenbilt 2018-12-22 23:16:46 -05:00
parent 6b90f3db4d
commit 52a0b767c8
4 changed files with 75 additions and 12 deletions

View File

@ -1414,32 +1414,87 @@ void
ArgParser::handleBashArguments() ArgParser::handleBashArguments()
{ {
// Do a minimal job of parsing bash_line into arguments. This // Do a minimal job of parsing bash_line into arguments. This
// doesn't do everything the shell does, but it should be good // doesn't do everything the shell does (e.g. $(...), variable
// enough for purposes of handling completion. We can't use // expansion, arithmetic, globs, etc.), but it should be good
// new_argv because this has to interoperate with @file arguments. // enough for purposes of handling completion. As we build up the
// new argv, we can't use this->new_argv because this code has to
// interoperate with @file arguments, so memory for both ways of
// fabricating argv has to be protected.
enum { st_top, st_quote } state = st_top; bool last_was_backslash = false;
enum { st_top, st_squote, st_dquote } state = st_top;
std::string arg; std::string arg;
for (std::string::iterator iter = bash_line.begin(); for (std::string::iterator iter = bash_line.begin();
iter != bash_line.end(); ++iter) iter != bash_line.end(); ++iter)
{ {
char ch = (*iter); char ch = (*iter);
if ((state == st_top) && QUtil::is_space(ch) && (! arg.empty())) if (last_was_backslash)
{
arg.append(1, ch);
last_was_backslash = false;
}
else if (ch == '\\')
{
last_was_backslash = true;
}
else
{
bool append = false;
switch (state)
{
case st_top:
if (QUtil::is_space(ch))
{
if (! arg.empty())
{ {
bash_argv.push_back( bash_argv.push_back(
PointerHolder<char>( PointerHolder<char>(
true, QUtil::copy_string(arg.c_str()))); true, QUtil::copy_string(arg.c_str())));
arg.clear(); arg.clear();
} }
}
else if (ch == '"')
{
state = st_dquote;
}
else if (ch == '\'')
{
state = st_squote;
}
else else
{ {
append = true;
}
break;
case st_squote:
if (ch == '\'')
{
state = st_top;
}
else
{
append = true;
}
break;
case st_dquote:
if (ch == '"') if (ch == '"')
{ {
state = (state == st_top ? st_quote : st_top); state = st_top;
} }
else
{
append = true;
}
break;
}
if (append)
{
arg.append(1, ch); arg.append(1, ch);
} }
} }
}
if (bash_argv.empty()) if (bash_argv.empty())
{ {
// This can't happen if properly invoked by bash, but ensure // This can't happen if properly invoked by bash, but ensure

View File

@ -117,6 +117,12 @@ my @completion_tests = (
['qpdf --decode-lzzz', 15, 'decode-l'], ['qpdf --decode-lzzz', 15, 'decode-l'],
['qpdf --decode-level=', undef, 'decode-level'], ['qpdf --decode-level=', undef, 'decode-level'],
['qpdf --check -', undef, 'later-arg'], ['qpdf --check -', undef, 'later-arg'],
['qpdf infile outfile oops --ch', undef, 'usage-empty'],
['qpdf --encrypt \'user " password\' ', undef, 'quoting'],
['qpdf --encrypt \'user password\' ', undef, 'quoting'],
['qpdf --encrypt "user password" ', undef, 'quoting'],
['qpdf --encrypt "user pass\'word" ', undef, 'quoting'],
['qpdf --encrypt user\ password ', undef, 'quoting'],
); );
$n_tests += scalar(@completion_tests); $n_tests += scalar(@completion_tests);
foreach my $c (@completion_tests) foreach my $c (@completion_tests)

View File

@ -0,0 +1 @@
owner-password

View File

@ -0,0 +1 @@
!--check