[Box Backup-commit] COMMIT r3111 - box/trunk/bin/bbackupquery

subversion at boxbackup.org subversion at boxbackup.org
Sat May 26 19:13:01 BST 2012


Author: chris
Date: 2012-05-26 19:13:01 +0100 (Sat, 26 May 2012)
New Revision: 3111

Modified:
   box/trunk/bin/bbackupquery/BackupQueries.cpp
   box/trunk/bin/bbackupquery/BackupQueries.h
   box/trunk/bin/bbackupquery/CommandCompletion.cpp
   box/trunk/bin/bbackupquery/bbackupquery.cpp
Log:
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.


Modified: box/trunk/bin/bbackupquery/BackupQueries.cpp
===================================================================
--- box/trunk/bin/bbackupquery/BackupQueries.cpp	2012-05-24 20:01:14 UTC (rev 3110)
+++ box/trunk/bin/bbackupquery/BackupQueries.cpp	2012-05-26 18:13:01 UTC (rev 3111)
@@ -359,6 +359,11 @@
 void BackupQueries::List(int64_t DirID, const std::string &rListRoot,
 	const bool *opts, bool FirstLevel, std::ostream &out)
 {
+#ifdef WIN32
+	DWORD n_chars;
+	HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
+#endif
+	
 	// Generate exclude flags
 	int16_t excludeFlags = BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING;
 	if(!opts[LIST_OPTION_ALLOWOLD]) excludeFlags |= BackupProtocolListDirectory::Flags_OldVersion;
@@ -476,7 +481,9 @@
 			std::string listRootDecoded;
 			if(!ConvertUtf8ToConsole(rListRoot.c_str(), 
 				listRootDecoded)) return;
-			out << listRootDecoded << "/";
+			listRootDecoded = listRootDecoded + "/";
+			WriteConsole(hOut, listRootDecoded.c_str(),
+				strlen(listRootDecoded.c_str()), &n_chars, NULL);
 #else
 			out << rListRoot << "/";
 #endif
@@ -500,7 +507,11 @@
 		}
 #endif
 
+#ifdef WIN32
+		WriteConsole(hOut, fileName.c_str(), strlen(fileName.c_str()), &n_chars, NULL);
+#else
 		out << fileName;
+#endif
 		
 		if(!en->GetName().IsEncrypted())
 		{

Modified: box/trunk/bin/bbackupquery/BackupQueries.h
===================================================================
--- box/trunk/bin/bbackupquery/BackupQueries.h	2012-05-24 20:01:14 UTC (rev 3110)
+++ box/trunk/bin/bbackupquery/BackupQueries.h	2012-05-26 18:13:01 UTC (rev 3111)
@@ -73,9 +73,10 @@
 		// command, but if the command line ends in a space,
 		// e.g. during readline parsing, it can be one greater,
 		// to indicate that we should complete the next item instead.
-		size_t mArgCount;
+		size_t mCompleteArgCount;
 		ParsedCommand(const std::string& Command,
 			bool isFromCommandLine);
+		bool IsEmpty() { return mCmdElements.empty(); }
 	};
 
 	void DoCommand(ParsedCommand& rCommand);

Modified: box/trunk/bin/bbackupquery/CommandCompletion.cpp
===================================================================
--- box/trunk/bin/bbackupquery/CommandCompletion.cpp	2012-05-24 20:01:14 UTC (rev 3110)
+++ box/trunk/bin/bbackupquery/CommandCompletion.cpp	2012-05-26 18:13:01 UTC (rev 3111)
@@ -83,9 +83,12 @@
 
 #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::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::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,8 +270,32 @@
 				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);
 			}
 			else
@@ -428,7 +457,7 @@
 : mInOptions(false),
   mFailed(false),
   pSpec(NULL),
-  mArgCount(0)
+  mCompleteArgCount(0)
 {
 	mCompleteCommand = Command;
 	
@@ -451,77 +480,73 @@
 	}
 
 	// 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 @@
 		}
 	}
 
-	if(mCmdElements.size() == 0 || commands[cmd].name == 0)
+	if(commands[cmd].name == 0)
 	{
 		mFailed = true;
 		return;

Modified: box/trunk/bin/bbackupquery/bbackupquery.cpp
===================================================================
--- box/trunk/bin/bbackupquery/bbackupquery.cpp	2012-05-24 20:01:14 UTC (rev 3110)
+++ box/trunk/bin/bbackupquery/bbackupquery.cpp	2012-05-26 18:13:01 UTC (rev 3111)
@@ -109,8 +109,9 @@
 		std::string partialCommand(rl_line_buffer, rl_point);
 		sapCmd.reset(new BackupQueries::ParsedCommand(partialCommand,
 			false));
+		int currentArg = sapCmd->mCompleteArgCount;
 
-		if(sapCmd->mArgCount == 0) // incomplete command
+		if(currentArg == 0) // incomplete command
 		{
 			completions = CompleteCommand(*sapCmd, text, *pProtocol,
 				*pConfig, *pQueries);
@@ -120,11 +121,12 @@
 			completions = CompleteOptions(*sapCmd, text, *pProtocol,
 				*pConfig, *pQueries);
 		}
-		else if(sapCmd->mArgCount - 1 < MAX_COMPLETION_HANDLERS)
-		// sapCmd->mArgCount must be at least 1 if we're here
+		else if(currentArg - 1 < MAX_COMPLETION_HANDLERS)
+		// currentArg must be at least 1 if we're here
 		{
 			CompletionHandler handler =
-				sapCmd->pSpec->complete[sapCmd->mArgCount - 1];
+				sapCmd->pSpec->complete[currentArg - 1];
+
 			if(handler != NULL)
 			{
 				completions = handler(*sapCmd, text, *pProtocol,
@@ -477,13 +479,8 @@
 	// Get commands from input
 
 #ifdef HAVE_LIBREADLINE
-	if (useReadline)
+	if(useReadline)
 	{
-#else
-	if (false)
-	{
-#endif
-		#ifdef HAVE_LIBREADLINE
 		// Must initialise the locale before using editline's
 		// readline(), otherwise cannot enter international characters.
 		if (setlocale(LC_ALL, "") == NULL)
@@ -505,57 +502,70 @@
 		pProtocol = &connection;
 		pConfig = &conf;
 		pQueries = &context;
+	}
 
-		char *last_cmd = 0;
-		while(!context.Stop())
+	std::string last_cmd;
+#endif
+
+	std::auto_ptr<FdGetLine> apGetLine;
+	if(fileno(stdin) >= 0)
+	{
+		apGetLine.reset(new FdGetLine(fileno(stdin)));
+	}
+
+	while(!context.Stop() && fileno(stdin) >= 0)
+	{
+		std::string cmd_str;
+
+		#ifdef HAVE_LIBREADLINE
+		if(useReadline)
 		{
-			char *command = readline("query > ");
+			char *cmd_ptr = readline("query > ");
 			
-			if(command == NULL)
+			if(cmd_ptr == NULL)
 			{
 				// Ctrl-D pressed -- terminate now
 				break;
 			}
-			
-			BackupQueries::ParsedCommand cmd(command, false);
-			context.DoCommand(cmd);
 
-			if(last_cmd != 0 && ::strcmp(last_cmd, command) == 0)
+			cmd_str = cmd_ptr;
+			free(cmd_ptr);
+		}
+		else
+		#endif // HAVE_LIBREADLINE
+		{
+			printf("query > ");
+			fflush(stdout);
+
+			try
 			{
-				free(command);
+				cmd_str = apGetLine->GetLine();
 			}
-			else
+			catch(CommonException &e)
 			{
-				#ifdef HAVE_READLINE_HISTORY
-					add_history(command);
-				#else
-					free(last_cmd);
-				#endif
-				last_cmd = command;
+				if(e.GetSubType() == CommonException::GetLineEOF)
+				{
+					break;
+				}
+				throw;
 			}
 		}
-		#ifndef HAVE_READLINE_HISTORY
-			free(last_cmd);
-			last_cmd = 0;
-		#endif
-		#endif // HAVE_READLINE
-	}
-	else // !HAVE_LIBREADLINE || !useReadline
-	{
-		// Version for platforms which don't have readline by default
-		if(fileno(stdin) >= 0)
+
+		BackupQueries::ParsedCommand cmd_parsed(cmd_str, false);
+		if (cmd_parsed.IsEmpty())
 		{
-			FdGetLine getLine(fileno(stdin));
-			while(!context.Stop())
-			{
-				printf("query > ");
-				fflush(stdout);
-				std::string command(getLine.GetLine());
-				BackupQueries::ParsedCommand cmd(command,
-					false);
-				context.DoCommand(cmd);
-			}
+			continue;
 		}
+
+		context.DoCommand(cmd_parsed);
+
+		#ifdef HAVE_READLINE_HISTORY
+		if(last_cmd != cmd_str)
+		{
+			add_history(cmd_str.c_str());
+			last_cmd = cmd_str;
+		}
+		#endif // HAVE_READLINE_HISTORY
 	}
 	
 	// Done... stop nicely




More information about the Boxbackup-commit mailing list