summaryrefslogtreecommitdiff
path: root/bin/bbackupquery/CommandCompletion.cpp
diff options
context:
space:
mode:
authorChris Wilson <chris+github@qwirx.com>2012-05-26 18:13:01 +0000
committerChris Wilson <chris+github@qwirx.com>2012-05-26 18:13:01 +0000
commit4cff1ff674125dc4b543a4d2f3565403580822cc (patch)
treecec20019247f0d8ac48912714b1b67522dff0e90 /bin/bbackupquery/CommandCompletion.cpp
parent11608b5b3e6b23bd5aea683a987d7cfd2827a57e (diff)
bbackupquery readline improvements, thanks to Paolo Tosco:
Automatically quote filenames including spaces on the readline input. Ignore empty commands, don't generate a parse error message. Close cleanly and quietly when EOF is input (Ctrl+D). Simplify interactive mode code in bbackupquery.
Diffstat (limited to 'bin/bbackupquery/CommandCompletion.cpp')
-rw-r--r--bin/bbackupquery/CommandCompletion.cpp119
1 files changed, 72 insertions, 47 deletions
diff --git a/bin/bbackupquery/CommandCompletion.cpp b/bin/bbackupquery/CommandCompletion.cpp
index 6d6189b3..93c4d3fd 100644
--- a/bin/bbackupquery/CommandCompletion.cpp
+++ b/bin/bbackupquery/CommandCompletion.cpp
@@ -83,9 +83,12 @@ COMPLETION_FUNCTION(None,)
#ifdef HAVE_A_FILENAME_COMPLETION_FUNCTION
COMPLETION_FUNCTION(Default,
- while (const char *match = RL_FILENAME_COMPLETION_FUNCTION(prefix.c_str(), 0))
+ int i = 0;
+
+ while (const char *match = RL_FILENAME_COMPLETION_FUNCTION(prefix.c_str(), i))
{
completions.push_back(match);
+ ++i;
}
)
#else // !HAVE_A_FILENAME_COMPLETION_FUNCTION
@@ -177,7 +180,7 @@ std::vector<std::string> CompleteRemoteFileOrDirectory(
std::string searchPrefix;
std::string listDir = prefix;
- if(rCommand.mArgCount == rCommand.mCmdElements.size())
+ if(rCommand.mCompleteArgCount == rCommand.mCmdElements.size())
{
// completing an empty name, from the current directory
// nothing to change
@@ -257,6 +260,8 @@ std::vector<std::string> CompleteRemoteFileOrDirectory(
std::string name = clear.GetClearFilename().c_str();
if(name.compare(0, searchPrefix.length(), searchPrefix) == 0)
{
+ bool dir_added = false;
+
if(en->IsDir() &&
(includeFlags & BackupProtocolListDirectory::Flags_Dir) == 0)
{
@@ -265,7 +270,31 @@ std::vector<std::string> CompleteRemoteFileOrDirectory(
name += "/";
}
- if(listDir == "")
+ #ifdef HAVE_LIBREADLINE
+ if(strchr(name.c_str(), ' '))
+ {
+ int n_quote = 0;
+
+ for(int k = strlen(rl_line_buffer); k >= 0; k--)
+ {
+ if (rl_line_buffer[k] == '\"') {
+ ++n_quote;
+ }
+ }
+
+ dir_added = false;
+
+ if (!(n_quote % 2))
+ {
+ name = "\"" + (listDir == "" ? name : listDir + "/" + name);
+ dir_added = true;
+ }
+
+ name = name + "\"";
+ }
+ #endif
+
+ if(listDir == "" || dir_added)
{
completions.push_back(name);
}
@@ -428,7 +457,7 @@ BackupQueries::ParsedCommand::ParsedCommand(const std::string& Command,
: mInOptions(false),
mFailed(false),
pSpec(NULL),
- mArgCount(0)
+ mCompleteArgCount(0)
{
mCompleteCommand = Command;
@@ -451,77 +480,73 @@ BackupQueries::ParsedCommand::ParsedCommand(const std::string& Command,
}
// split command into components
- const char *c = Command.c_str();
bool inQuoted = false;
mInOptions = false;
- std::string s;
- while(*c != 0)
+ std::string currentArg;
+ for (std::string::const_iterator c = Command.begin();
+ c != Command.end(); c++)
{
// Terminating char?
if(*c == ((inQuoted)?'"':' '))
{
- if(!s.empty())
+ if(!currentArg.empty())
{
- mCmdElements.push_back(s);
+ mCmdElements.push_back(currentArg);
- // Because we just parsed a space, if this
- // wasn't an option word, then we're now
- // completing the next (or first) arg
- if(!mInOptions)
- {
- mArgCount++;
- }
+ // Because we just found a space, and the last
+ // word was not options (otherwise currentArg
+ // would be empty), we've received a complete
+ // command or non-option argument.
+ mCompleteArgCount++;
}
- s.resize(0);
+ currentArg.resize(0);
inQuoted = false;
mInOptions = false;
}
+ // Start of quoted parameter?
+ else if(currentArg.empty() && *c == '"')
+ {
+ inQuoted = true;
+ }
+ // Start of options?
+ else if(currentArg.empty() && *c == '-')
+ {
+ mInOptions = true;
+ }
+ else if(mInOptions)
+ {
+ // Option char
+ mOptions += *c;
+ }
else
{
- // No. Start of quoted parameter?
- if(s.empty() && *c == '"')
- {
- inQuoted = true;
- }
- // Start of options?
- else if(s.empty() && *c == '-')
- {
- mInOptions = true;
- }
- else
- {
- if(mInOptions)
- {
- // Option char
- mOptions += *c;
- }
- else
- {
- // Normal string char
- s += *c;
- }
- }
+ // Normal string char, part of current arg
+ currentArg += *c;
}
-
- ++c;
}
- if(!s.empty())
+ if(!currentArg.empty())
{
- mCmdElements.push_back(s);
+ mCmdElements.push_back(currentArg);
+ }
+
+ // If there are no commands then there's nothing to do except return
+ if(mCmdElements.empty())
+ {
+ return;
}
// Work out which command it is...
int cmd = 0;
- while(mCmdElements.size() > 0 && commands[cmd].name != 0 &&
+ while(commands[cmd].name != 0 &&
mCmdElements[0] != commands[cmd].name)
{
cmd++;
}
- if(mCmdElements.size() > 0 && commands[cmd].name == 0)
+ if(commands[cmd].name == 0)
{
// Check for aliases
int a;
@@ -536,7 +561,7 @@ BackupQueries::ParsedCommand::ParsedCommand(const std::string& Command,
}
}
- if(mCmdElements.size() == 0 || commands[cmd].name == 0)
+ if(commands[cmd].name == 0)
{
mFailed = true;
return;