summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Kalnischkies <david@kalnischkies.de>2015-05-10 22:53:15 +0200
committerDavid Kalnischkies <david@kalnischkies.de>2015-05-11 17:22:32 +0200
commit8d058ea53b18348f81229049a27d14282bd8d8c1 (patch)
treef63e7b5df8776803692a2c4a27ef557848988c39
parentd38926efe1e6d2511bd852607ff4f9c8b60dc76c (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.
-rw-r--r--apt-pkg/tagfile.cc148
-rw-r--r--apt-pkg/tagfile.h47
-rw-r--r--test/libapt/tagfile_test.cc6
3 files changed, 187 insertions, 14 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; }
diff --git a/apt-pkg/tagfile.h b/apt-pkg/tagfile.h
index d09e7046c..118954541 100644
--- a/apt-pkg/tagfile.h
+++ b/apt-pkg/tagfile.h
@@ -54,13 +54,14 @@ class pkgTagSection
const char *Stop;
public:
-
+
inline bool operator ==(const pkgTagSection &rhs) {return Section == rhs.Section;};
inline bool operator !=(const pkgTagSection &rhs) {return Section != rhs.Section;};
-
+
bool Find(const char *Tag,const char *&Start, const char *&End) const;
bool Find(const char *Tag,unsigned int &Pos) const;
std::string FindS(const char *Tag) const;
+ std::string FindRawS(const char *Tag) const;
signed int FindI(const char *Tag,signed long Default = 0) const;
bool FindB(const char *Tag, bool const &Default = false) const;
unsigned long long FindULL(const char *Tag, unsigned long long const &Default = 0) const;
@@ -115,9 +116,32 @@ class pkgTagSection
Start = Section;
Stop = this->Stop;
};
-
+
pkgTagSection();
virtual ~pkgTagSection();
+
+ struct Tag
+ {
+ enum ActionType { REMOVE, RENAME, REWRITE } Action;
+ std::string Name;
+ std::string Data;
+
+ static Tag Remove(std::string const &Name);
+ static Tag Rename(std::string const &OldName, std::string const &NewName);
+ static Tag Rewrite(std::string const &Name, std::string const &Data);
+ private:
+ Tag(ActionType const Action, std::string const &Name, std::string const &Data) :
+ Action(Action), Name(Name), Data(Data) {}
+ };
+
+ /** Write this section (with optional rewrites) to a file
+ *
+ * @param File to write the section to
+ * @param Order in which tags should appear in the file
+ * @param Rewrite is a set of tags to be renamed, rewitten and/or removed
+ * @return \b true if successful, otherwise \b false
+ */
+ bool Write(FileFd &File, char const * const * const Order = NULL, std::vector<Tag> const &Rewrite = std::vector<Tag>()) const;
};
class pkgTagFilePrivate;
@@ -141,20 +165,19 @@ class pkgTagFile
virtual ~pkgTagFile();
};
-/* This is the list of things to rewrite. The rewriter
- goes through and changes or adds each of these headers
- to suit. A zero forces the header to be erased, an empty string
- causes the old value to be used. (rewrite rule ignored) */
-struct TFRewriteData
+extern const char **TFRewritePackageOrder;
+extern const char **TFRewriteSourceOrder;
+
+// Use pkgTagSection::Tag and pkgTagSection::Write() instead
+APT_IGNORE_DEPRECATED_PUSH
+struct APT_DEPRECATED TFRewriteData
{
const char *Tag;
const char *Rewrite;
const char *NewTag;
};
-extern const char **TFRewritePackageOrder;
-extern const char **TFRewriteSourceOrder;
-
-bool TFRewrite(FILE *Output,pkgTagSection const &Tags,const char *Order[],
+APT_DEPRECATED bool TFRewrite(FILE *Output,pkgTagSection const &Tags,const char *Order[],
TFRewriteData *Rewrite);
+APT_IGNORE_DEPRECATED_POP
#endif
diff --git a/test/libapt/tagfile_test.cc b/test/libapt/tagfile_test.cc
index df618ea16..d7030f41a 100644
--- a/test/libapt/tagfile_test.cc
+++ b/test/libapt/tagfile_test.cc
@@ -34,6 +34,12 @@ TEST(TagFileTest,SingleField)
EXPECT_FALSE(section.Exists("FieldB-12345678"));
// There is only one section in this tag file
EXPECT_FALSE(tfile.Step(section));
+
+ // Now we scan an empty section to test reset
+ ASSERT_TRUE(section.Scan("\n\n", 2, true));
+ EXPECT_EQ(0, section.Count());
+ EXPECT_FALSE(section.Exists("FieldA-12345678"));
+ EXPECT_FALSE(section.Exists("FieldB-12345678"));
}
TEST(TagFileTest,MultipleSections)