On Tue, Mar 14, 2017 at 01:01:23AM -0400, Scott Kostyshak wrote: > I have a patch and it seems to work well. I want to clean it up before > posting. I will post it again for review because even though it seems to > work well, I wonder if there is a cleaner way of doing it. I will post > a cleaned up version in a couple of days.
Attached are two patches. Are they what you had in mind? Because I edit splitArg(), this could cause problems with other LFUNs. Scott
From d49881c637e29b28536c9a37dceadb0a6bb21a00 Mon Sep 17 00:00:00 2001 From: Scott Kostyshak <skost...@lyx.org> Date: Sat, 18 Mar 2017 09:44:47 -0400 Subject: [PATCH 1/2] Allow LFUNs to escape/unescape quotes LFUNs can now use addArg() to add an argument in a way that nested quotes and backslashes will be correctly handled. This argument can then be correctly split by splitArg(). For a use case, see the next commit involving spaces in branch names. A new string helper function is created, nTrailing(), which returns the number of trailing backslashes. --- src/FuncRequest.cpp | 35 ++++++++++++++++++++++++++++++++++- src/FuncRequest.h | 3 +++ src/support/lstrings.cpp | 15 +++++++++++++++ src/support/lstrings.h | 3 +++ 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/FuncRequest.cpp b/src/FuncRequest.cpp index 224ba27..670a18e 100644 --- a/src/FuncRequest.cpp +++ b/src/FuncRequest.cpp @@ -88,9 +88,30 @@ void splitArg(vector<string> & args, string const & str, string s; is >> c; if (is) { - if (c == '"') + if (c == '"') { // get quote delimited argument getline(is, s, '"'); + + // Allow for escaped double quotes. + // If lastch is a backslash and if it is part of + // an odd number of trailing backslashes, then + // lastch is escaping the double quote, so we + // put the double quote back. + unsigned int ntb = nTrailing(s); + char lastch = *s.rbegin(); + while (lastch == '\\' && ntb % 2) { + s.pop_back(); + s.append("\""); + string s2; + getline(is, s2, '"'); + s.append(s2); + lastch = *s.rbegin(); + ntb = nTrailing(s); + } + + // unescape backslashes + s = subst(s, "\\\\", "\\"); + } else { // get whitespace delimited argument is.putback(c); @@ -119,6 +140,18 @@ string FuncRequest::getLongArg(unsigned int i) const } +void FuncRequest::addArg(docstring const & str) +{ + if (!argument_.empty()) + argument_ += ' '; + // first escape backslashes + docstring strQuoted = subst(str, from_ascii("\\"), from_ascii("\\\\")); + // then escape double quotes + strQuoted = subst(strQuoted, from_ascii("\""), from_ascii("\\\"")); + argument_ += '"' + strQuoted + '"'; +} + + bool operator==(FuncRequest const & lhs, FuncRequest const & rhs) { return lhs.action() == rhs.action() && lhs.argument() == rhs.argument(); diff --git a/src/FuncRequest.h b/src/FuncRequest.h index a5822f4..0b4321b 100644 --- a/src/FuncRequest.h +++ b/src/FuncRequest.h @@ -85,6 +85,9 @@ public: /// argument parsing, extract argument i as std::string, /// eating all characters up to the end of the command line std::string getLongArg(unsigned int i) const; + /// Adds an argument, escaping double quotes and backslashes, which + /// are correctly parsed by splitArg() + void addArg(docstring const &); /// static FuncRequest const unknown; diff --git a/src/support/lstrings.cpp b/src/support/lstrings.cpp index 8ffab19..744c888 100644 --- a/src/support/lstrings.cpp +++ b/src/support/lstrings.cpp @@ -1066,6 +1066,21 @@ docstring const ltrim(docstring const & a, char const * p) return a.substr(l, docstring::npos); } +unsigned int nTrailing(string const & str, char const * c) { + string::const_reverse_iterator sit = str.rbegin(); + int n = 0; + char ch; + while (sit != str.rend()) { + ch = *sit; + if (ch == *c) + n += 1; + else + break; + ++sit; + } + return n; +} + namespace { template<typename String, typename Char> inline diff --git a/src/support/lstrings.h b/src/support/lstrings.h index 36ba09f..c5eee10 100644 --- a/src/support/lstrings.h +++ b/src/support/lstrings.h @@ -241,6 +241,9 @@ docstring const rtrim(docstring const & a, char const * p = " "); std::string const ltrim(std::string const & a, char const * p = " "); docstring const ltrim(docstring const & a, char const * p = " "); +// Returns the number of (consecutive) trailing c in a string. +unsigned int nTrailing(std::string const & str, char const * c = "\\"); + /** Splits the string given in the first argument at the first occurence of the third argument, delim. What precedes delim is returned in the second argument, piece; this -- 2.7.4
From 223845648e694be9b78c6527df456a40f494a1d2 Mon Sep 17 00:00:00 2001 From: Scott Kostyshak <skost...@lyx.org> Date: Sat, 18 Mar 2017 09:49:42 -0400 Subject: [PATCH 2/2] Allow branch names to contain spaces The functions addArg() and splitArg() are used to automatically take care of any embedded spaces. Also, use Lexer for reading and writing branch names. --- src/Buffer.cpp | 6 ++++-- src/frontends/qt4/GuiApplication.cpp | 4 ++-- src/frontends/qt4/GuiDocument.cpp | 12 ++++++++---- src/insets/InsetBranch.cpp | 5 +++-- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/Buffer.cpp b/src/Buffer.cpp index a20b4da..42e3c82 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -2797,10 +2797,12 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr) } else { undo().recordUndoBufferParams(CursorData()); branch_list.add(branch_name); + FuncRequest fr(LFUN_SET_COLOR); branch = branch_list.find(branch_name); + fr.addArg(branch_name); string const x11hexname = X11hexname(branch->color()); - docstring const str = branch_name + ' ' + from_ascii(x11hexname); - lyx::dispatch(FuncRequest(LFUN_SET_COLOR, str)); + fr.addArg(from_ascii(x11hexname)); + lyx::dispatch(fr); dr.setError(false); dr.screenUpdate(Update::Force); } diff --git a/src/frontends/qt4/GuiApplication.cpp b/src/frontends/qt4/GuiApplication.cpp index 05b7a25..85d0ea6 100644 --- a/src/frontends/qt4/GuiApplication.cpp +++ b/src/frontends/qt4/GuiApplication.cpp @@ -1736,8 +1736,8 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr) } case LFUN_SET_COLOR: { - string lyx_name; - string const x11_name = split(to_utf8(cmd.argument()), lyx_name, ' '); + string lyx_name = cmd.getArg(0); + string x11_name = cmd.getArg(1); if (lyx_name.empty() || x11_name.empty()) { if (current_view_) current_view_->message( diff --git a/src/frontends/qt4/GuiDocument.cpp b/src/frontends/qt4/GuiDocument.cpp index 2293ce3..25594cd 100644 --- a/src/frontends/qt4/GuiDocument.cpp +++ b/src/frontends/qt4/GuiDocument.cpp @@ -4129,8 +4129,10 @@ void GuiDocument::dispatchParams() Branch const * branch = branchlist.find(current_branch); string const x11hexname = X11hexname(branch->color()); // display the new color - docstring const str = current_branch + ' ' + from_ascii(x11hexname); - dispatch(FuncRequest(LFUN_SET_COLOR, str)); + FuncRequest fr(LFUN_SET_COLOR); + fr.addArg(current_branch); + fr.addArg(from_ascii(x11hexname)); + dispatch(fr); } // Open insets of selected branches, close deselected ones @@ -4152,8 +4154,10 @@ void GuiDocument::dispatchParams() Index const * index = indiceslist.findShortcut(current_index); string const x11hexname = X11hexname(index->color()); // display the new color - docstring const str = current_index + ' ' + from_ascii(x11hexname); - dispatch(FuncRequest(LFUN_SET_COLOR, str)); + FuncRequest fr(LFUN_SET_COLOR); + fr.addArg(current_index); + fr.addArg(from_ascii(x11hexname)); + dispatch(fr); } } // FIXME LFUN diff --git a/src/insets/InsetBranch.cpp b/src/insets/InsetBranch.cpp index 3cde061..4a31706 100644 --- a/src/insets/InsetBranch.cpp +++ b/src/insets/InsetBranch.cpp @@ -394,7 +394,7 @@ void InsetBranch::updateBuffer(ParIterator const & it, UpdateType utype) void InsetBranchParams::write(ostream & os) const { - os << to_utf8(branch) + os << Lexer::quoteString(to_utf8(branch)) << '\n' << "inverted " << inverted; @@ -403,7 +403,8 @@ void InsetBranchParams::write(ostream & os) const void InsetBranchParams::read(Lexer & lex) { - lex >> branch; + lex.next(true); + branch = lex.getDocString(); lex >> "inverted" >> inverted; } -- 2.7.4
signature.asc
Description: PGP signature