diff options
author | David Kalnischkies <david@kalnischkies.de> | 2015-05-10 22:53:15 +0200 |
---|---|---|
committer | David Kalnischkies <david@kalnischkies.de> | 2015-05-11 17:22:32 +0200 |
commit | 8d058ea53b18348f81229049a27d14282bd8d8c1 (patch) | |
tree | f63e7b5df8776803692a2c4a27ef557848988c39 /apt-pkg/tagfile.cc | |
parent | d38926efe1e6d2511bd852607ff4f9c8b60dc76c (diff) |
implement a more c++-style TFRewrite alternative
TFRewrite is okay, but it has obscure limitations (256 Tags), even more
obscure bugs (order for renames is defined by the old name) and the
interface is very c-style encouraging bad usage like we do it in
apt-ftparchive passing massive amounts of c_str() from std::string in.
The old-style is marked as deprecated accordingly. The next commit will
fix all places in the apt code to not use the old-style anymore.
Diffstat (limited to 'apt-pkg/tagfile.cc')
-rw-r--r-- | apt-pkg/tagfile.cc | 148 |
1 files changed, 146 insertions, 2 deletions
diff --git a/apt-pkg/tagfile.cc b/apt-pkg/tagfile.cc index 2f7900d93..5ff495fbd 100644 --- a/apt-pkg/tagfile.cc +++ b/apt-pkg/tagfile.cc @@ -509,8 +509,6 @@ bool pkgTagSection::Find(const char *Tag,const char *&Start, } /*}}}*/ // TagSection::FindS - Find a string /*{{{*/ -// --------------------------------------------------------------------- -/* */ string pkgTagSection::FindS(const char *Tag) const { const char *Start; @@ -520,6 +518,24 @@ string pkgTagSection::FindS(const char *Tag) const return string(Start,End); } /*}}}*/ +// TagSection::FindRawS - Find a string /*{{{*/ +string pkgTagSection::FindRawS(const char *Tag) const +{ + unsigned int Pos; + if (Find(Tag, Pos) == false) + return ""; + + char const *Start = (char const *) memchr(Section + d->Tags[Pos].EndTag, ':', d->Tags[Pos].StartValue - d->Tags[Pos].EndTag); + ++Start; + char const *End = Section + d->Tags[Pos + 1].StartTag; + if (unlikely(Start > End)) + return ""; + + for (; isspace(End[-1]) != 0 && End > Start; --End); + + return std::string(Start, End - Start); +} + /*}}}*/ // TagSection::FindI - Find an integer /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -623,6 +639,132 @@ APT_PURE unsigned int pkgTagSection::Count() const { /*{{{*/ return d->Tags.size() - 1; } /*}}}*/ +// TagSection::Write - Ordered (re)writing of fields /*{{{*/ +pkgTagSection::Tag pkgTagSection::Tag::Remove(std::string const &Name) +{ + return Tag(REMOVE, Name, ""); +} +pkgTagSection::Tag pkgTagSection::Tag::Rename(std::string const &OldName, std::string const &NewName) +{ + return Tag(RENAME, OldName, NewName); +} +pkgTagSection::Tag pkgTagSection::Tag::Rewrite(std::string const &Name, std::string const &Data) +{ + if (Data.empty() == true) + return Tag(REMOVE, Name, ""); + else + return Tag(REWRITE, Name, Data); +} +static bool WriteTag(FileFd &File, std::string Tag, std::string const &Value) +{ + if (Value.empty() || isspace(Value[0]) != 0) + Tag.append(":"); + else + Tag.append(": "); + Tag.append(Value); + Tag.append("\n"); + return File.Write(Tag.c_str(), Tag.length()); +} +static bool RewriteTags(FileFd &File, pkgTagSection const * const This, char const * const Tag, + std::vector<pkgTagSection::Tag>::const_iterator &R, + std::vector<pkgTagSection::Tag>::const_iterator const &REnd) +{ + size_t const TagLen = strlen(Tag); + for (; R != REnd; ++R) + { + std::string data; + if (R->Name.length() == TagLen && strncasecmp(R->Name.c_str(), Tag, R->Name.length()) == 0) + { + if (R->Action != pkgTagSection::Tag::REWRITE) + break; + data = R->Data; + } + else if(R->Action == pkgTagSection::Tag::RENAME && R->Data.length() == TagLen && + strncasecmp(R->Data.c_str(), Tag, R->Data.length()) == 0) + data = This->FindRawS(R->Name.c_str()); + else + continue; + + return WriteTag(File, Tag, data); + } + return true; +} +bool pkgTagSection::Write(FileFd &File, char const * const * const Order, std::vector<Tag> const &Rewrite) const +{ + // first pass: Write everything we have an order for + if (Order != NULL) + { + for (unsigned int I = 0; Order[I] != 0; ++I) + { + std::vector<Tag>::const_iterator R = Rewrite.begin(); + if (RewriteTags(File, this, Order[I], R, Rewrite.end()) == false) + return false; + if (R != Rewrite.end()) + continue; + + if (Exists(Order[I]) == false) + continue; + + if (WriteTag(File, Order[I], FindRawS(Order[I])) == false) + return false; + } + } + // second pass: See if we have tags which aren't ordered + if (d->Tags.empty() == false) + { + for (std::vector<pkgTagSectionPrivate::TagData>::const_iterator T = d->Tags.begin(); T != d->Tags.end() - 1; ++T) + { + char const * const fieldname = Section + T->StartTag; + size_t fieldnamelen = T->EndTag - T->StartTag; + if (Order != NULL) + { + unsigned int I = 0; + for (; Order[I] != 0; ++I) + { + if (fieldnamelen == strlen(Order[I]) && strncasecmp(fieldname, Order[I], fieldnamelen) == 0) + break; + } + if (Order[I] != 0) + continue; + } + + std::string const name(fieldname, fieldnamelen); + std::vector<Tag>::const_iterator R = Rewrite.begin(); + if (RewriteTags(File, this, name.c_str(), R, Rewrite.end()) == false) + return false; + if (R != Rewrite.end()) + continue; + + if (WriteTag(File, name, FindRawS(name.c_str())) == false) + return false; + } + } + // last pass: see if there are any rewrites remaining we haven't done yet + for (std::vector<Tag>::const_iterator R = Rewrite.begin(); R != Rewrite.end(); ++R) + { + if (R->Action == Tag::REMOVE) + continue; + std::string const name = ((R->Action == Tag::RENAME) ? R->Data : R->Name); + if (Exists(name.c_str())) + continue; + if (Order != NULL) + { + unsigned int I = 0; + for (; Order[I] != 0; ++I) + { + if (strncasecmp(name.c_str(), Order[I], name.length()) == 0 && name.length() == strlen(Order[I])) + break; + } + if (Order[I] != 0) + continue; + } + + if (WriteTag(File, name, ((R->Action == Tag::RENAME) ? FindRawS(R->Name.c_str()) : R->Data)) == false) + return false; + } + return true; +} + /*}}}*/ #include "tagfile-order.c" @@ -631,6 +773,7 @@ APT_PURE unsigned int pkgTagSection::Count() const { /*{{{*/ /* This writes the control record to stdout rewriting it as necessary. The override map item specificies the rewriting rules to follow. This also takes the time to sort the feild list. */ +APT_IGNORE_DEPRECATED_PUSH bool TFRewrite(FILE *Output,pkgTagSection const &Tags,const char *Order[], TFRewriteData *Rewrite) { @@ -754,6 +897,7 @@ bool TFRewrite(FILE *Output,pkgTagSection const &Tags,const char *Order[], return true; } +APT_IGNORE_DEPRECATED_POP /*}}}*/ pkgTagSection::~pkgTagSection() { delete d; } |