1 // -*- mode: cpp; mode: fold -*-
3 // $Id: tagfile.cc,v 1.37.2.2 2003/12/31 16:02:30 mdz Exp $
4 /* ######################################################################
6 Fast scanner for RFC-822 type header information
8 This uses a rotating buffer to load the package information into.
9 The scanner runs over it and isolates and indexes a single section.
11 ##################################################################### */
13 // Include Files /*{{{*/
16 #include <apt-pkg/tagfile.h>
17 #include <apt-pkg/error.h>
18 #include <apt-pkg/strutl.h>
19 #include <apt-pkg/fileutl.h>
32 class pkgTagFilePrivate
35 void Reset(FileFd
* const pFd
, unsigned long long const pSize
)
48 pkgTagFilePrivate(FileFd
* const pFd
, unsigned long long const Size
) : Buffer(NULL
)
57 unsigned long long iOffset
;
58 unsigned long long Size
;
67 class pkgTagSectionPrivate
70 pkgTagSectionPrivate()
74 unsigned int StartTag
;
76 unsigned int StartValue
;
77 unsigned int NextInBucket
;
79 explicit TagData(unsigned int const StartTag
) : StartTag(StartTag
), EndTag(0), StartValue(0), NextInBucket(0) {}
81 std::vector
<TagData
> Tags
;
84 static unsigned long AlphaHash(const char *Text
, size_t Length
) /*{{{*/
86 /* This very simple hash function for the last 8 letters gives
87 very good performance on the debian package files */
93 unsigned long Res
= 0;
94 for (size_t i
= 0; i
< Length
; ++i
)
95 Res
= ((unsigned long)(Text
[i
]) & 0xDF) ^ (Res
<< 1);
100 // TagFile::pkgTagFile - Constructor /*{{{*/
101 // ---------------------------------------------------------------------
103 pkgTagFile::pkgTagFile(FileFd
* const pFd
,unsigned long long const Size
)
104 : d(new pkgTagFilePrivate(pFd
, Size
+ 4))
108 void pkgTagFile::Init(FileFd
* const pFd
,unsigned long long Size
)
110 /* The size is increased by 4 because if we start with the Size of the
111 filename we need to try to read 1 char more to see an EOF faster, 1
112 char the end-pointer can be on and maybe 2 newlines need to be added
113 to the end of the file -> 4 extra chars */
117 if (d
->Fd
->IsOpen() == false)
118 d
->Start
= d
->End
= d
->Buffer
= 0;
120 d
->Buffer
= (char*)malloc(sizeof(char) * Size
);
122 if (d
->Buffer
== NULL
)
127 d
->Start
= d
->End
= d
->Buffer
;
129 if (d
->Done
== false)
133 // TagFile::~pkgTagFile - Destructor /*{{{*/
134 // ---------------------------------------------------------------------
136 pkgTagFile::~pkgTagFile()
141 // TagFile::Offset - Return the current offset in the buffer /*{{{*/
142 APT_PURE
unsigned long pkgTagFile::Offset()
147 // TagFile::Resize - Resize the internal buffer /*{{{*/
148 // ---------------------------------------------------------------------
149 /* Resize the internal buffer (double it in size). Fail if a maximum size
152 bool pkgTagFile::Resize()
154 // fail is the buffer grows too big
155 if(d
->Size
> 1024*1024+1)
158 return Resize(d
->Size
* 2);
160 bool pkgTagFile::Resize(unsigned long long const newSize
)
162 unsigned long long const EndSize
= d
->End
- d
->Start
;
164 // get new buffer and use it
165 char* newBuffer
= (char*)realloc(d
->Buffer
, sizeof(char) * newSize
);
166 if (newBuffer
== NULL
)
168 d
->Buffer
= newBuffer
;
171 // update the start/end pointers to the new buffer
172 d
->Start
= d
->Buffer
;
173 d
->End
= d
->Start
+ EndSize
;
177 // TagFile::Step - Advance to the next section /*{{{*/
178 // ---------------------------------------------------------------------
179 /* If the Section Scanner fails we refill the buffer and try again.
180 * If that fails too, double the buffer size and try again until a
181 * maximum buffer is reached.
183 bool pkgTagFile::Step(pkgTagSection
&Tag
)
185 if(Tag
.Scan(d
->Start
,d
->End
- d
->Start
) == false)
192 if(Tag
.Scan(d
->Start
,d
->End
- d
->Start
, false))
195 if (Resize() == false)
196 return _error
->Error(_("Unable to parse package file %s (%d)"),
197 d
->Fd
->Name().c_str(), 1);
199 } while (Tag
.Scan(d
->Start
,d
->End
- d
->Start
, false) == false);
202 d
->Start
+= Tag
.size();
203 d
->iOffset
+= Tag
.size();
209 // TagFile::Fill - Top up the buffer /*{{{*/
210 // ---------------------------------------------------------------------
211 /* This takes the bit at the end of the buffer and puts it at the start
212 then fills the rest from the file */
213 bool pkgTagFile::Fill()
215 unsigned long long EndSize
= d
->End
- d
->Start
;
216 unsigned long long Actual
= 0;
218 memmove(d
->Buffer
,d
->Start
,EndSize
);
219 d
->Start
= d
->Buffer
;
220 d
->End
= d
->Buffer
+ EndSize
;
222 if (d
->Done
== false)
224 // See if only a bit of the file is left
225 unsigned long long const dataSize
= d
->Size
- ((d
->End
- d
->Buffer
) + 1);
226 if (d
->Fd
->Read(d
->End
, dataSize
, &Actual
) == false)
228 if (Actual
!= dataSize
)
235 if (EndSize
<= 3 && Actual
== 0)
237 if (d
->Size
- (d
->End
- d
->Buffer
) < 4)
240 // Append a double new line if one does not exist
241 unsigned int LineCount
= 0;
242 for (const char *E
= d
->End
- 1; E
- d
->End
< 6 && (*E
== '\n' || *E
== '\r'); E
--)
247 if ((unsigned)(d
->End
- d
->Buffer
) >= d
->Size
)
249 for (; LineCount
< 2; LineCount
++)
259 // TagFile::Jump - Jump to a pre-recorded location in the file /*{{{*/
260 // ---------------------------------------------------------------------
261 /* This jumps to a pre-recorded file location and reads the record
263 bool pkgTagFile::Jump(pkgTagSection
&Tag
,unsigned long long Offset
)
265 // We are within a buffer space of the next hit..
266 if (Offset
>= d
->iOffset
&& d
->iOffset
+ (d
->End
- d
->Start
) > Offset
)
268 unsigned long long Dist
= Offset
- d
->iOffset
;
271 // if we have seen the end, don't ask for more
273 return Tag
.Scan(d
->Start
, d
->End
- d
->Start
);
278 // Reposition and reload..
281 if (d
->Fd
->Seek(Offset
) == false)
283 d
->End
= d
->Start
= d
->Buffer
;
288 if (Tag
.Scan(d
->Start
, d
->End
- d
->Start
) == true)
291 // This appends a double new line (for the real eof handling)
295 if (Tag
.Scan(d
->Start
, d
->End
- d
->Start
, false) == false)
296 return _error
->Error(_("Unable to parse package file %s (%d)"),d
->Fd
->Name().c_str(), 2);
301 // pkgTagSection::pkgTagSection - Constructor /*{{{*/
302 // ---------------------------------------------------------------------
304 APT_IGNORE_DEPRECATED_PUSH
305 pkgTagSection::pkgTagSection()
306 : Section(0), d(new pkgTagSectionPrivate()), Stop(0)
308 #if APT_PKG_ABI < 413
310 memset(&Indexes
, 0, sizeof(Indexes
));
312 memset(&AlphaIndexes
, 0, sizeof(AlphaIndexes
));
314 APT_IGNORE_DEPRECATED_POP
316 // TagSection::Scan - Scan for the end of the header information /*{{{*/
317 #if APT_PKG_ABI < 413
318 bool pkgTagSection::Scan(const char *Start
,unsigned long MaxLength
)
320 return Scan(Start
, MaxLength
, true);
323 bool pkgTagSection::Scan(const char *Start
,unsigned long MaxLength
, bool const Restart
)
326 const char *End
= Start
+ MaxLength
;
328 if (Restart
== false && d
->Tags
.empty() == false)
330 Stop
= Section
+ d
->Tags
.back().StartTag
;
333 Stop
= (const char *)memchr(Stop
,'\n',End
- Stop
);
341 if (d
->Tags
.empty() == false)
343 memset(&AlphaIndexes
, 0, sizeof(AlphaIndexes
));
346 d
->Tags
.reserve(0x100);
348 #if APT_PKG_ABI >= 413
349 unsigned int TagCount
= d
->Tags
.size();
351 APT_IGNORE_DEPRECATED(TagCount
= d
->Tags
.size();)
357 pkgTagSectionPrivate::TagData
lastTagData(0);
358 lastTagData
.EndTag
= 0;
359 unsigned long lastTagHash
= 0;
362 TrimRecord(true,End
);
364 // this can happen when TrimRecord trims away the entire Record
365 // (e.g. because it just contains comments)
369 // Start a new index and add it to the hash
370 if (isspace(Stop
[0]) == 0)
372 // store the last found tag
373 if (lastTagData
.EndTag
!= 0)
375 if (AlphaIndexes
[lastTagHash
] != 0)
376 lastTagData
.NextInBucket
= AlphaIndexes
[lastTagHash
];
377 APT_IGNORE_DEPRECATED_PUSH
378 AlphaIndexes
[lastTagHash
] = TagCount
;
379 #if APT_PKG_ABI < 413
380 if (d
->Tags
.size() < sizeof(Indexes
)/sizeof(Indexes
[0]))
381 Indexes
[d
->Tags
.size()] = lastTagData
.StartTag
;
383 APT_IGNORE_DEPRECATED_POP
384 d
->Tags
.push_back(lastTagData
);
387 APT_IGNORE_DEPRECATED(++TagCount
;)
388 lastTagData
= pkgTagSectionPrivate::TagData(Stop
- Section
);
389 // find the colon separating tag and value
390 char const * Colon
= (char const *) memchr(Stop
, ':', End
- Stop
);
393 // find the end of the tag (which might or might not be the colon)
394 char const * EndTag
= Colon
;
396 for (; EndTag
> Stop
&& isspace(*EndTag
) != 0; --EndTag
)
399 lastTagData
.EndTag
= EndTag
- Section
;
400 lastTagHash
= AlphaHash(Stop
, EndTag
- Stop
);
401 // find the beginning of the value
403 for (; isspace(*Stop
) != 0; ++Stop
);
406 lastTagData
.StartValue
= Stop
- Section
;
409 Stop
= (const char *)memchr(Stop
,'\n',End
- Stop
);
414 for (; Stop
+1 < End
&& Stop
[1] == '\r'; Stop
++)
418 // Double newline marks the end of the record
419 if (Stop
+1 < End
&& Stop
[1] == '\n')
421 if (lastTagData
.EndTag
!= 0)
423 if (AlphaIndexes
[lastTagHash
] != 0)
424 lastTagData
.NextInBucket
= AlphaIndexes
[lastTagHash
];
425 APT_IGNORE_DEPRECATED(AlphaIndexes
[lastTagHash
] = TagCount
;)
426 #if APT_PKG_ABI < 413
427 APT_IGNORE_DEPRECATED(Indexes
[d
->Tags
.size()] = lastTagData
.StartTag
;)
429 d
->Tags
.push_back(lastTagData
);
432 pkgTagSectionPrivate::TagData
const td(Stop
- Section
);
433 #if APT_PKG_ABI < 413
434 APT_IGNORE_DEPRECATED(Indexes
[d
->Tags
.size()] = td
.StartTag
;)
436 d
->Tags
.push_back(td
);
437 TrimRecord(false,End
);
447 // TagSection::TrimRecord - Trim off any garbage before/after a record /*{{{*/
448 // ---------------------------------------------------------------------
449 /* There should be exactly 2 newline at the end of the record, no more. */
450 void pkgTagSection::TrimRecord(bool BeforeRecord
, const char*& End
)
452 if (BeforeRecord
== true)
454 for (; Stop
< End
&& (Stop
[0] == '\n' || Stop
[0] == '\r'); Stop
++);
457 // TagSection::Trim - Trim off any trailing garbage /*{{{*/
458 // ---------------------------------------------------------------------
459 /* There should be exactly 1 newline at the end of the buffer, no more. */
460 void pkgTagSection::Trim()
462 for (; Stop
> Section
+ 2 && (Stop
[-2] == '\n' || Stop
[-2] == '\r'); Stop
--);
465 // TagSection::Exists - return True if a tag exists /*{{{*/
466 #if APT_PKG_ABI >= 413
467 bool pkgTagSection::Exists(const char* const Tag
) const
469 bool pkgTagSection::Exists(const char* const Tag
)
473 return Find(Tag
, tmp
);
476 // TagSection::Find - Locate a tag /*{{{*/
477 // ---------------------------------------------------------------------
478 /* This searches the section for a tag that matches the given string. */
479 bool pkgTagSection::Find(const char *Tag
,unsigned int &Pos
) const
481 size_t const Length
= strlen(Tag
);
482 unsigned int Bucket
= AlphaIndexes
[AlphaHash(Tag
, Length
)];
486 for (; Bucket
!= 0; Bucket
= d
->Tags
[Bucket
- 1].NextInBucket
)
488 if ((d
->Tags
[Bucket
- 1].EndTag
- d
->Tags
[Bucket
- 1].StartTag
) != Length
)
491 char const * const St
= Section
+ d
->Tags
[Bucket
- 1].StartTag
;
492 if (strncasecmp(Tag
,St
,Length
) != 0)
502 bool pkgTagSection::Find(const char *Tag
,const char *&Start
,
503 const char *&End
) const
506 if (Find(Tag
, Pos
) == false)
509 Start
= Section
+ d
->Tags
[Pos
].StartValue
;
510 // Strip off the gunk from the end
511 End
= Section
+ d
->Tags
[Pos
+ 1].StartTag
;
512 if (unlikely(Start
> End
))
513 return _error
->Error("Internal parsing error");
515 for (; isspace(End
[-1]) != 0 && End
> Start
; --End
);
520 // TagSection::FindS - Find a string /*{{{*/
521 string
pkgTagSection::FindS(const char *Tag
) const
525 if (Find(Tag
,Start
,End
) == false)
527 return string(Start
,End
);
530 // TagSection::FindRawS - Find a string /*{{{*/
531 string
pkgTagSection::FindRawS(const char *Tag
) const
534 if (Find(Tag
, Pos
) == false)
537 char const *Start
= (char const *) memchr(Section
+ d
->Tags
[Pos
].EndTag
, ':', d
->Tags
[Pos
].StartValue
- d
->Tags
[Pos
].EndTag
);
539 char const *End
= Section
+ d
->Tags
[Pos
+ 1].StartTag
;
540 if (unlikely(Start
> End
))
543 for (; isspace(End
[-1]) != 0 && End
> Start
; --End
);
545 return std::string(Start
, End
- Start
);
548 // TagSection::FindI - Find an integer /*{{{*/
549 // ---------------------------------------------------------------------
551 signed int pkgTagSection::FindI(const char *Tag
,signed long Default
) const
555 if (Find(Tag
,Start
,Stop
) == false)
558 // Copy it into a temp buffer so we can use strtol
560 if ((unsigned)(Stop
- Start
) >= sizeof(S
))
562 strncpy(S
,Start
,Stop
-Start
);
566 signed long Result
= strtol(S
,&End
,10);
572 // TagSection::FindULL - Find an unsigned long long integer /*{{{*/
573 // ---------------------------------------------------------------------
575 unsigned long long pkgTagSection::FindULL(const char *Tag
, unsigned long long const &Default
) const
579 if (Find(Tag
,Start
,Stop
) == false)
582 // Copy it into a temp buffer so we can use strtoull
584 if ((unsigned)(Stop
- Start
) >= sizeof(S
))
586 strncpy(S
,Start
,Stop
-Start
);
590 unsigned long long Result
= strtoull(S
,&End
,10);
596 // TagSection::FindB - Find boolean value /*{{{*/
597 // ---------------------------------------------------------------------
599 bool pkgTagSection::FindB(const char *Tag
, bool const &Default
) const
601 const char *Start
, *Stop
;
602 if (Find(Tag
, Start
, Stop
) == false)
604 return StringToBool(string(Start
, Stop
));
607 // TagSection::FindFlag - Locate a yes/no type flag /*{{{*/
608 // ---------------------------------------------------------------------
609 /* The bits marked in Flag are masked on/off in Flags */
610 bool pkgTagSection::FindFlag(const char *Tag
,unsigned long &Flags
,
611 unsigned long Flag
) const
615 if (Find(Tag
,Start
,Stop
) == false)
617 return FindFlag(Flags
, Flag
, Start
, Stop
);
619 bool pkgTagSection::FindFlag(unsigned long &Flags
, unsigned long Flag
,
620 char const* Start
, char const* Stop
)
622 switch (StringToBool(string(Start
, Stop
)))
633 _error
->Warning("Unknown flag value: %s",string(Start
,Stop
).c_str());
639 void pkgTagSection::Get(const char *&Start
,const char *&Stop
,unsigned int I
) const
641 Start
= Section
+ d
->Tags
[I
].StartTag
;
642 Stop
= Section
+ d
->Tags
[I
+1].StartTag
;
644 APT_PURE
unsigned int pkgTagSection::Count() const { /*{{{*/
645 if (d
->Tags
.empty() == true)
647 // the last element is just marking the end and isn't a real one
648 return d
->Tags
.size() - 1;
651 // TagSection::Write - Ordered (re)writing of fields /*{{{*/
652 pkgTagSection::Tag
pkgTagSection::Tag::Remove(std::string
const &Name
)
654 return Tag(REMOVE
, Name
, "");
656 pkgTagSection::Tag
pkgTagSection::Tag::Rename(std::string
const &OldName
, std::string
const &NewName
)
658 return Tag(RENAME
, OldName
, NewName
);
660 pkgTagSection::Tag
pkgTagSection::Tag::Rewrite(std::string
const &Name
, std::string
const &Data
)
662 if (Data
.empty() == true)
663 return Tag(REMOVE
, Name
, "");
665 return Tag(REWRITE
, Name
, Data
);
667 static bool WriteTag(FileFd
&File
, std::string Tag
, std::string
const &Value
)
669 if (Value
.empty() || isspace(Value
[0]) != 0)
675 return File
.Write(Tag
.c_str(), Tag
.length());
677 static bool RewriteTags(FileFd
&File
, pkgTagSection
const * const This
, char const * const Tag
,
678 std::vector
<pkgTagSection::Tag
>::const_iterator
&R
,
679 std::vector
<pkgTagSection::Tag
>::const_iterator
const &REnd
)
681 size_t const TagLen
= strlen(Tag
);
682 for (; R
!= REnd
; ++R
)
685 if (R
->Name
.length() == TagLen
&& strncasecmp(R
->Name
.c_str(), Tag
, R
->Name
.length()) == 0)
687 if (R
->Action
!= pkgTagSection::Tag::REWRITE
)
691 else if(R
->Action
== pkgTagSection::Tag::RENAME
&& R
->Data
.length() == TagLen
&&
692 strncasecmp(R
->Data
.c_str(), Tag
, R
->Data
.length()) == 0)
693 data
= This
->FindRawS(R
->Name
.c_str());
697 return WriteTag(File
, Tag
, data
);
701 bool pkgTagSection::Write(FileFd
&File
, char const * const * const Order
, std::vector
<Tag
> const &Rewrite
) const
703 // first pass: Write everything we have an order for
706 for (unsigned int I
= 0; Order
[I
] != 0; ++I
)
708 std::vector
<Tag
>::const_iterator R
= Rewrite
.begin();
709 if (RewriteTags(File
, this, Order
[I
], R
, Rewrite
.end()) == false)
711 if (R
!= Rewrite
.end())
714 if (Exists(Order
[I
]) == false)
717 if (WriteTag(File
, Order
[I
], FindRawS(Order
[I
])) == false)
721 // second pass: See if we have tags which aren't ordered
722 if (d
->Tags
.empty() == false)
724 for (std::vector
<pkgTagSectionPrivate::TagData
>::const_iterator T
= d
->Tags
.begin(); T
!= d
->Tags
.end() - 1; ++T
)
726 char const * const fieldname
= Section
+ T
->StartTag
;
727 size_t fieldnamelen
= T
->EndTag
- T
->StartTag
;
731 for (; Order
[I
] != 0; ++I
)
733 if (fieldnamelen
== strlen(Order
[I
]) && strncasecmp(fieldname
, Order
[I
], fieldnamelen
) == 0)
740 std::string
const name(fieldname
, fieldnamelen
);
741 std::vector
<Tag
>::const_iterator R
= Rewrite
.begin();
742 if (RewriteTags(File
, this, name
.c_str(), R
, Rewrite
.end()) == false)
744 if (R
!= Rewrite
.end())
747 if (WriteTag(File
, name
, FindRawS(name
.c_str())) == false)
751 // last pass: see if there are any rewrites remaining we haven't done yet
752 for (std::vector
<Tag
>::const_iterator R
= Rewrite
.begin(); R
!= Rewrite
.end(); ++R
)
754 if (R
->Action
== Tag::REMOVE
)
756 std::string
const name
= ((R
->Action
== Tag::RENAME
) ? R
->Data
: R
->Name
);
757 if (Exists(name
.c_str()))
762 for (; Order
[I
] != 0; ++I
)
764 if (strncasecmp(name
.c_str(), Order
[I
], name
.length()) == 0 && name
.length() == strlen(Order
[I
]))
771 if (WriteTag(File
, name
, ((R
->Action
== Tag::RENAME
) ? FindRawS(R
->Name
.c_str()) : R
->Data
)) == false)
778 #include "tagfile-order.c"
780 // TFRewrite - Rewrite a control record /*{{{*/
781 // ---------------------------------------------------------------------
782 /* This writes the control record to stdout rewriting it as necessary. The
783 override map item specificies the rewriting rules to follow. This also
784 takes the time to sort the feild list. */
785 APT_IGNORE_DEPRECATED_PUSH
786 bool TFRewrite(FILE *Output
,pkgTagSection
const &Tags
,const char *Order
[],
787 TFRewriteData
*Rewrite
)
789 unsigned char Visited
[256]; // Bit 1 is Order, Bit 2 is Rewrite
790 for (unsigned I
= 0; I
!= 256; I
++)
793 // Set new tag up as necessary.
794 for (unsigned int J
= 0; Rewrite
!= 0 && Rewrite
[J
].Tag
!= 0; J
++)
796 if (Rewrite
[J
].NewTag
== 0)
797 Rewrite
[J
].NewTag
= Rewrite
[J
].Tag
;
800 // Write all all of the tags, in order.
803 for (unsigned int I
= 0; Order
[I
] != 0; I
++)
805 bool Rewritten
= false;
807 // See if this is a field that needs to be rewritten
808 for (unsigned int J
= 0; Rewrite
!= 0 && Rewrite
[J
].Tag
!= 0; J
++)
810 if (strcasecmp(Rewrite
[J
].Tag
,Order
[I
]) == 0)
813 if (Rewrite
[J
].Rewrite
!= 0 && Rewrite
[J
].Rewrite
[0] != 0)
815 if (isspace(Rewrite
[J
].Rewrite
[0]))
816 fprintf(Output
,"%s:%s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
818 fprintf(Output
,"%s: %s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
825 // See if it is in the fragment
827 if (Tags
.Find(Order
[I
],Pos
) == false)
831 if (Rewritten
== true)
834 /* Write out this element, taking a moment to rewrite the tag
835 in case of changes of case. */
838 Tags
.Get(Start
,Stop
,Pos
);
840 if (fputs(Order
[I
],Output
) < 0)
841 return _error
->Errno("fputs","IO Error to output");
842 Start
+= strlen(Order
[I
]);
843 if (fwrite(Start
,Stop
- Start
,1,Output
) != 1)
844 return _error
->Errno("fwrite","IO Error to output");
845 if (Stop
[-1] != '\n')
846 fprintf(Output
,"\n");
850 // Now write all the old tags that were missed.
851 for (unsigned int I
= 0; I
!= Tags
.Count(); I
++)
853 if ((Visited
[I
] & 1) == 1)
858 Tags
.Get(Start
,Stop
,I
);
859 const char *End
= Start
;
860 for (; End
< Stop
&& *End
!= ':'; End
++);
862 // See if this is a field that needs to be rewritten
863 bool Rewritten
= false;
864 for (unsigned int J
= 0; Rewrite
!= 0 && Rewrite
[J
].Tag
!= 0; J
++)
866 if (stringcasecmp(Start
,End
,Rewrite
[J
].Tag
) == 0)
869 if (Rewrite
[J
].Rewrite
!= 0 && Rewrite
[J
].Rewrite
[0] != 0)
871 if (isspace(Rewrite
[J
].Rewrite
[0]))
872 fprintf(Output
,"%s:%s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
874 fprintf(Output
,"%s: %s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
882 if (Rewritten
== true)
885 // Write out this element
886 if (fwrite(Start
,Stop
- Start
,1,Output
) != 1)
887 return _error
->Errno("fwrite","IO Error to output");
888 if (Stop
[-1] != '\n')
889 fprintf(Output
,"\n");
892 // Now write all the rewrites that were missed
893 for (unsigned int J
= 0; Rewrite
!= 0 && Rewrite
[J
].Tag
!= 0; J
++)
895 if ((Visited
[J
] & 2) == 2)
898 if (Rewrite
[J
].Rewrite
!= 0 && Rewrite
[J
].Rewrite
[0] != 0)
900 if (isspace(Rewrite
[J
].Rewrite
[0]))
901 fprintf(Output
,"%s:%s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
903 fprintf(Output
,"%s: %s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
909 APT_IGNORE_DEPRECATED_POP
912 pkgTagSection::~pkgTagSection() { delete d
; }