summaryrefslogtreecommitdiff
path: root/apt-pkg
diff options
context:
space:
mode:
Diffstat (limited to 'apt-pkg')
-rw-r--r--apt-pkg/contrib/strutl.cc92
1 files changed, 69 insertions, 23 deletions
diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc
index f2fc0b6a6..638f09e9d 100644
--- a/apt-pkg/contrib/strutl.cc
+++ b/apt-pkg/contrib/strutl.cc
@@ -694,34 +694,80 @@ int stringcasecmp(string::const_iterator A,string::const_iterator AEnd,
/*}}}*/
// LookupTag - Lookup the value of a tag in a taged string /*{{{*/
// ---------------------------------------------------------------------
-/* The format is like those used in package files and the method
+/* The format is like those used in package files and the method
communication system */
-string LookupTag(const string &Message,const char *Tag,const char *Default)
+std::string LookupTag(const std::string &Message, const char *TagC, const char *Default)
{
- // Look for a matching tag.
- int Length = strlen(Tag);
- for (string::const_iterator I = Message.begin(); I + Length < Message.end(); ++I)
+ std::string tag = std::string("\n") + TagC + ":";
+ if (Default == nullptr)
+ Default = "";
+ if (Message.length() < tag.length())
+ return Default;
+ std::transform(tag.begin(), tag.end(), tag.begin(), tolower_ascii);
+ auto valuestart = Message.cbegin();
+ // maybe the message starts directly with tag
+ if (Message[tag.length() - 2] == ':')
{
- // Found the tag
- if (I[Length] == ':' && stringcasecmp(I,I+Length,Tag) == 0)
+ std::string lowstart = std::string("\n") + Message.substr(0, tag.length() - 1);
+ std::transform(lowstart.begin(), lowstart.end(), lowstart.begin(), tolower_ascii);
+ if (lowstart == tag)
+ valuestart = std::next(valuestart, tag.length() - 1);
+ }
+ // the tag is somewhere in the message
+ if (valuestart == Message.cbegin())
+ {
+ auto const tagbegin = std::search(Message.cbegin(), Message.cend(), tag.cbegin(), tag.cend(),
+ [](char const a, char const b) { return tolower_ascii(a) == b; });
+ if (tagbegin == Message.cend())
+ return Default;
+ valuestart = std::next(tagbegin, tag.length());
+ }
+ auto const is_whitespace = [](char const c) { return isspace_ascii(c) != 0 && c != '\n'; };
+ auto const is_newline = [](char const c) { return c == '\n'; };
+ std::string result;
+ valuestart = std::find_if_not(valuestart, Message.cend(), is_whitespace);
+ // is the first line of the value empty?
+ if (valuestart != Message.cend() && *valuestart == '\n')
+ {
+ valuestart = std::next(valuestart);
+ if (valuestart != Message.cend() && *valuestart == ' ')
+ valuestart = std::next(valuestart);
+ }
+ // extract the value over multiple lines removing trailing whitespace
+ while (valuestart < Message.cend())
+ {
+ auto const linebreak = std::find_if(valuestart, Message.cend(), is_newline);
+ auto valueend = std::prev(linebreak);
+ // skip spaces at the end of the line
+ while (valueend > valuestart && is_whitespace(*valueend))
+ valueend = std::prev(valueend);
+ // append found line to result
{
- // Find the end of line and strip the leading/trailing spaces
- string::const_iterator J;
- I += Length + 1;
- for (; isspace_ascii(*I) != 0 && I < Message.end(); ++I);
- for (J = I; *J != '\n' && J < Message.end(); ++J);
- for (; J > I && isspace_ascii(J[-1]) != 0; --J);
-
- return string(I,J);
+ std::string tmp(valuestart, std::next(valueend));
+ if (tmp != ".")
+ {
+ if (result.empty())
+ result.assign(std::move(tmp));
+ else
+ result.append(tmp);
+ }
}
-
- for (; *I != '\n' && I < Message.end(); ++I);
- }
-
- // Failed to find a match
- if (Default == 0)
- return string();
- return Default;
+ // see if the value is multiline
+ if (linebreak == Message.cend())
+ break;
+ valuestart = std::next(linebreak);
+ if (valuestart == Message.cend() || *valuestart != ' ')
+ break;
+ result.append("\n");
+ // skip the space leading a multiline (Keep all other whitespaces in the value)
+ valuestart = std::next(valuestart);
+ }
+ auto const valueend = result.find_last_not_of("\n");
+ if (valueend == std::string::npos)
+ result.clear();
+ else
+ result.erase(valueend + 1);
+ return result;
}
/*}}}*/
// StringToBool - Converts a string into a boolean /*{{{*/