From 8d058ea53b18348f81229049a27d14282bd8d8c1 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sun, 10 May 2015 22:53:15 +0200 Subject: 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. --- apt-pkg/tagfile.cc | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 146 insertions(+), 2 deletions(-) (limited to 'apt-pkg/tagfile.cc') 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::const_iterator &R, + std::vector::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 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::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::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::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::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; } -- cgit v1.2.3