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
)
46 pkgTagFilePrivate(FileFd
* const pFd
, unsigned long long const Size
)
55 unsigned long long iOffset
;
56 unsigned long long Size
;
59 class pkgTagSectionPrivate
62 pkgTagSectionPrivate()
66 unsigned int StartTag
;
68 unsigned int StartValue
;
69 unsigned int NextInBucket
;
71 explicit TagData(unsigned int const StartTag
) : StartTag(StartTag
), EndTag(0), StartValue(0), NextInBucket(0) {}
73 std::vector
<TagData
> Tags
;
76 static unsigned long AlphaHash(const char *Text
, size_t Length
) /*{{{*/
78 /* This very simple hash function for the last 8 letters gives
79 very good performance on the debian package files */
85 unsigned long Res
= 0;
86 for (size_t i
= 0; i
< Length
; ++i
)
87 Res
= ((unsigned long)(Text
[i
]) & 0xDF) ^ (Res
<< 1);
92 // TagFile::pkgTagFile - Constructor /*{{{*/
93 // ---------------------------------------------------------------------
95 pkgTagFile::pkgTagFile(FileFd
* const pFd
,unsigned long long const Size
)
96 : d(new pkgTagFilePrivate(pFd
, Size
+ 4))
100 void pkgTagFile::Init(FileFd
* const pFd
,unsigned long long Size
)
102 /* The size is increased by 4 because if we start with the Size of the
103 filename we need to try to read 1 char more to see an EOF faster, 1
104 char the end-pointer can be on and maybe 2 newlines need to be added
105 to the end of the file -> 4 extra chars */
109 if (d
->Fd
->IsOpen() == false)
110 d
->Start
= d
->End
= d
->Buffer
= 0;
112 d
->Buffer
= (char*)malloc(sizeof(char) * Size
);
114 if (d
->Buffer
== NULL
)
119 d
->Start
= d
->End
= d
->Buffer
;
121 if (d
->Done
== false)
125 // TagFile::~pkgTagFile - Destructor /*{{{*/
126 // ---------------------------------------------------------------------
128 pkgTagFile::~pkgTagFile()
134 // TagFile::Offset - Return the current offset in the buffer /*{{{*/
135 APT_PURE
unsigned long pkgTagFile::Offset()
140 // TagFile::Resize - Resize the internal buffer /*{{{*/
141 // ---------------------------------------------------------------------
142 /* Resize the internal buffer (double it in size). Fail if a maximum size
145 bool pkgTagFile::Resize()
147 // fail is the buffer grows too big
148 if(d
->Size
> 1024*1024+1)
151 return Resize(d
->Size
* 2);
153 bool pkgTagFile::Resize(unsigned long long const newSize
)
155 unsigned long long const EndSize
= d
->End
- d
->Start
;
157 // get new buffer and use it
158 char* newBuffer
= (char*)realloc(d
->Buffer
, sizeof(char) * newSize
);
159 if (newBuffer
== NULL
)
161 d
->Buffer
= newBuffer
;
164 // update the start/end pointers to the new buffer
165 d
->Start
= d
->Buffer
;
166 d
->End
= d
->Start
+ EndSize
;
170 // TagFile::Step - Advance to the next section /*{{{*/
171 // ---------------------------------------------------------------------
172 /* If the Section Scanner fails we refill the buffer and try again.
173 * If that fails too, double the buffer size and try again until a
174 * maximum buffer is reached.
176 bool pkgTagFile::Step(pkgTagSection
&Tag
)
178 if(Tag
.Scan(d
->Start
,d
->End
- d
->Start
) == false)
185 if(Tag
.Scan(d
->Start
,d
->End
- d
->Start
, false))
188 if (Resize() == false)
189 return _error
->Error(_("Unable to parse package file %s (%d)"),
190 d
->Fd
->Name().c_str(), 1);
192 } while (Tag
.Scan(d
->Start
,d
->End
- d
->Start
, false) == false);
195 d
->Start
+= Tag
.size();
196 d
->iOffset
+= Tag
.size();
202 // TagFile::Fill - Top up the buffer /*{{{*/
203 // ---------------------------------------------------------------------
204 /* This takes the bit at the end of the buffer and puts it at the start
205 then fills the rest from the file */
206 bool pkgTagFile::Fill()
208 unsigned long long EndSize
= d
->End
- d
->Start
;
209 unsigned long long Actual
= 0;
211 memmove(d
->Buffer
,d
->Start
,EndSize
);
212 d
->Start
= d
->Buffer
;
213 d
->End
= d
->Buffer
+ EndSize
;
215 if (d
->Done
== false)
217 // See if only a bit of the file is left
218 unsigned long long const dataSize
= d
->Size
- ((d
->End
- d
->Buffer
) + 1);
219 if (d
->Fd
->Read(d
->End
, dataSize
, &Actual
) == false)
221 if (Actual
!= dataSize
)
228 if (EndSize
<= 3 && Actual
== 0)
230 if (d
->Size
- (d
->End
- d
->Buffer
) < 4)
233 // Append a double new line if one does not exist
234 unsigned int LineCount
= 0;
235 for (const char *E
= d
->End
- 1; E
- d
->End
< 6 && (*E
== '\n' || *E
== '\r'); E
--)
240 if ((unsigned)(d
->End
- d
->Buffer
) >= d
->Size
)
242 for (; LineCount
< 2; LineCount
++)
252 // TagFile::Jump - Jump to a pre-recorded location in the file /*{{{*/
253 // ---------------------------------------------------------------------
254 /* This jumps to a pre-recorded file location and reads the record
256 bool pkgTagFile::Jump(pkgTagSection
&Tag
,unsigned long long Offset
)
258 // We are within a buffer space of the next hit..
259 if (Offset
>= d
->iOffset
&& d
->iOffset
+ (d
->End
- d
->Start
) > Offset
)
261 unsigned long long Dist
= Offset
- d
->iOffset
;
264 // if we have seen the end, don't ask for more
266 return Tag
.Scan(d
->Start
, d
->End
- d
->Start
);
271 // Reposition and reload..
274 if (d
->Fd
->Seek(Offset
) == false)
276 d
->End
= d
->Start
= d
->Buffer
;
281 if (Tag
.Scan(d
->Start
, d
->End
- d
->Start
) == true)
284 // This appends a double new line (for the real eof handling)
288 if (Tag
.Scan(d
->Start
, d
->End
- d
->Start
, false) == false)
289 return _error
->Error(_("Unable to parse package file %s (%d)"),d
->Fd
->Name().c_str(), 2);
294 // pkgTagSection::pkgTagSection - Constructor /*{{{*/
295 // ---------------------------------------------------------------------
297 APT_IGNORE_DEPRECATED_PUSH
298 pkgTagSection::pkgTagSection()
299 : Section(0), d(new pkgTagSectionPrivate()), Stop(0)
301 #if APT_PKG_ABI < 413
303 memset(&Indexes
, 0, sizeof(Indexes
));
305 memset(&AlphaIndexes
, 0, sizeof(AlphaIndexes
));
307 APT_IGNORE_DEPRECATED_POP
309 // TagSection::Scan - Scan for the end of the header information /*{{{*/
310 #if APT_PKG_ABI < 413
311 bool pkgTagSection::Scan(const char *Start
,unsigned long MaxLength
)
313 return Scan(Start
, MaxLength
, true);
316 bool pkgTagSection::Scan(const char *Start
,unsigned long MaxLength
, bool const Restart
)
319 const char *End
= Start
+ MaxLength
;
321 if (Restart
== false && d
->Tags
.empty() == false)
323 Stop
= Section
+ d
->Tags
.back().StartTag
;
326 Stop
= (const char *)memchr(Stop
,'\n',End
- Stop
);
334 if (d
->Tags
.empty() == false)
336 memset(&AlphaIndexes
, 0, sizeof(AlphaIndexes
));
339 d
->Tags
.reserve(0x100);
341 #if APT_PKG_ABI >= 413
342 unsigned int TagCount
= d
->Tags
.size();
344 APT_IGNORE_DEPRECATED(TagCount
= d
->Tags
.size();)
350 pkgTagSectionPrivate::TagData
lastTagData(0);
351 lastTagData
.EndTag
= 0;
352 unsigned long lastTagHash
= 0;
355 TrimRecord(true,End
);
357 // this can happen when TrimRecord trims away the entire Record
358 // (e.g. because it just contains comments)
362 // Start a new index and add it to the hash
363 if (isspace(Stop
[0]) == 0)
365 // store the last found tag
366 if (lastTagData
.EndTag
!= 0)
368 if (AlphaIndexes
[lastTagHash
] != 0)
369 lastTagData
.NextInBucket
= AlphaIndexes
[lastTagHash
];
370 APT_IGNORE_DEPRECATED_PUSH
371 AlphaIndexes
[lastTagHash
] = TagCount
;
372 #if APT_PKG_ABI < 413
373 if (d
->Tags
.size() < sizeof(Indexes
)/sizeof(Indexes
[0]))
374 Indexes
[d
->Tags
.size()] = lastTagData
.StartTag
;
376 APT_IGNORE_DEPRECATED_POP
377 d
->Tags
.push_back(lastTagData
);
380 APT_IGNORE_DEPRECATED(++TagCount
;)
381 lastTagData
= pkgTagSectionPrivate::TagData(Stop
- Section
);
382 // find the colon separating tag and value
383 char const * Colon
= (char const *) memchr(Stop
, ':', End
- Stop
);
386 // find the end of the tag (which might or might not be the colon)
387 char const * EndTag
= Colon
;
389 for (; EndTag
> Stop
&& isspace(*EndTag
) != 0; --EndTag
)
392 lastTagData
.EndTag
= EndTag
- Section
;
393 lastTagHash
= AlphaHash(Stop
, EndTag
- Stop
);
394 // find the beginning of the value
396 for (; isspace(*Stop
) != 0; ++Stop
);
399 lastTagData
.StartValue
= Stop
- Section
;
402 Stop
= (const char *)memchr(Stop
,'\n',End
- Stop
);
407 for (; Stop
+1 < End
&& Stop
[1] == '\r'; Stop
++)
411 // Double newline marks the end of the record
412 if (Stop
+1 < End
&& Stop
[1] == '\n')
414 if (lastTagData
.EndTag
!= 0)
416 if (AlphaIndexes
[lastTagHash
] != 0)
417 lastTagData
.NextInBucket
= AlphaIndexes
[lastTagHash
];
418 APT_IGNORE_DEPRECATED(AlphaIndexes
[lastTagHash
] = TagCount
;)
419 #if APT_PKG_ABI < 413
420 APT_IGNORE_DEPRECATED(Indexes
[d
->Tags
.size()] = lastTagData
.StartTag
;)
422 d
->Tags
.push_back(lastTagData
);
425 pkgTagSectionPrivate::TagData
const td(Stop
- Section
);
426 #if APT_PKG_ABI < 413
427 APT_IGNORE_DEPRECATED(Indexes
[d
->Tags
.size()] = td
.StartTag
;)
429 d
->Tags
.push_back(td
);
430 TrimRecord(false,End
);
440 // TagSection::TrimRecord - Trim off any garbage before/after a record /*{{{*/
441 // ---------------------------------------------------------------------
442 /* There should be exactly 2 newline at the end of the record, no more. */
443 void pkgTagSection::TrimRecord(bool BeforeRecord
, const char*& End
)
445 if (BeforeRecord
== true)
447 for (; Stop
< End
&& (Stop
[0] == '\n' || Stop
[0] == '\r'); Stop
++);
450 // TagSection::Trim - Trim off any trailing garbage /*{{{*/
451 // ---------------------------------------------------------------------
452 /* There should be exactly 1 newline at the end of the buffer, no more. */
453 void pkgTagSection::Trim()
455 for (; Stop
> Section
+ 2 && (Stop
[-2] == '\n' || Stop
[-2] == '\r'); Stop
--);
458 // TagSection::Exists - return True if a tag exists /*{{{*/
459 #if APT_PKG_ABI >= 413
460 bool pkgTagSection::Exists(const char* const Tag
) const
462 bool pkgTagSection::Exists(const char* const Tag
)
466 return Find(Tag
, tmp
);
469 // TagSection::Find - Locate a tag /*{{{*/
470 // ---------------------------------------------------------------------
471 /* This searches the section for a tag that matches the given string. */
472 bool pkgTagSection::Find(const char *Tag
,unsigned int &Pos
) const
474 size_t const Length
= strlen(Tag
);
475 unsigned int Bucket
= AlphaIndexes
[AlphaHash(Tag
, Length
)];
479 for (; Bucket
!= 0; Bucket
= d
->Tags
[Bucket
- 1].NextInBucket
)
481 if ((d
->Tags
[Bucket
- 1].EndTag
- d
->Tags
[Bucket
- 1].StartTag
) != Length
)
484 char const * const St
= Section
+ d
->Tags
[Bucket
- 1].StartTag
;
485 if (strncasecmp(Tag
,St
,Length
) != 0)
495 bool pkgTagSection::Find(const char *Tag
,const char *&Start
,
496 const char *&End
) const
499 if (Find(Tag
, Pos
) == false)
502 Start
= Section
+ d
->Tags
[Pos
].StartValue
;
503 // Strip off the gunk from the end
504 End
= Section
+ d
->Tags
[Pos
+ 1].StartTag
;
505 if (unlikely(Start
> End
))
506 return _error
->Error("Internal parsing error");
508 for (; isspace(End
[-1]) != 0 && End
> Start
; --End
);
513 // TagSection::FindS - Find a string /*{{{*/
514 string
pkgTagSection::FindS(const char *Tag
) const
518 if (Find(Tag
,Start
,End
) == false)
520 return string(Start
,End
);
523 // TagSection::FindRawS - Find a string /*{{{*/
524 string
pkgTagSection::FindRawS(const char *Tag
) const
527 if (Find(Tag
, Pos
) == false)
530 char const *Start
= (char const *) memchr(Section
+ d
->Tags
[Pos
].EndTag
, ':', d
->Tags
[Pos
].StartValue
- d
->Tags
[Pos
].EndTag
);
532 char const *End
= Section
+ d
->Tags
[Pos
+ 1].StartTag
;
533 if (unlikely(Start
> End
))
536 for (; isspace(End
[-1]) != 0 && End
> Start
; --End
);
538 return std::string(Start
, End
- Start
);
541 // TagSection::FindI - Find an integer /*{{{*/
542 // ---------------------------------------------------------------------
544 signed int pkgTagSection::FindI(const char *Tag
,signed long Default
) const
548 if (Find(Tag
,Start
,Stop
) == false)
551 // Copy it into a temp buffer so we can use strtol
553 if ((unsigned)(Stop
- Start
) >= sizeof(S
))
555 strncpy(S
,Start
,Stop
-Start
);
559 signed long Result
= strtol(S
,&End
,10);
565 // TagSection::FindULL - Find an unsigned long long integer /*{{{*/
566 // ---------------------------------------------------------------------
568 unsigned long long pkgTagSection::FindULL(const char *Tag
, unsigned long long const &Default
) const
572 if (Find(Tag
,Start
,Stop
) == false)
575 // Copy it into a temp buffer so we can use strtoull
577 if ((unsigned)(Stop
- Start
) >= sizeof(S
))
579 strncpy(S
,Start
,Stop
-Start
);
583 unsigned long long Result
= strtoull(S
,&End
,10);
589 // TagSection::FindB - Find boolean value /*{{{*/
590 // ---------------------------------------------------------------------
592 bool pkgTagSection::FindB(const char *Tag
, bool const &Default
) const
594 const char *Start
, *Stop
;
595 if (Find(Tag
, Start
, Stop
) == false)
597 return StringToBool(string(Start
, Stop
));
600 // TagSection::FindFlag - Locate a yes/no type flag /*{{{*/
601 // ---------------------------------------------------------------------
602 /* The bits marked in Flag are masked on/off in Flags */
603 bool pkgTagSection::FindFlag(const char *Tag
,unsigned long &Flags
,
604 unsigned long Flag
) const
608 if (Find(Tag
,Start
,Stop
) == false)
610 return FindFlag(Flags
, Flag
, Start
, Stop
);
612 bool pkgTagSection::FindFlag(unsigned long &Flags
, unsigned long Flag
,
613 char const* Start
, char const* Stop
)
615 switch (StringToBool(string(Start
, Stop
)))
626 _error
->Warning("Unknown flag value: %s",string(Start
,Stop
).c_str());
632 void pkgTagSection::Get(const char *&Start
,const char *&Stop
,unsigned int I
) const
634 Start
= Section
+ d
->Tags
[I
].StartTag
;
635 Stop
= Section
+ d
->Tags
[I
+1].StartTag
;
637 APT_PURE
unsigned int pkgTagSection::Count() const { /*{{{*/
638 if (d
->Tags
.empty() == true)
640 // the last element is just marking the end and isn't a real one
641 return d
->Tags
.size() - 1;
644 // TagSection::Write - Ordered (re)writing of fields /*{{{*/
645 pkgTagSection::Tag
pkgTagSection::Tag::Remove(std::string
const &Name
)
647 return Tag(REMOVE
, Name
, "");
649 pkgTagSection::Tag
pkgTagSection::Tag::Rename(std::string
const &OldName
, std::string
const &NewName
)
651 return Tag(RENAME
, OldName
, NewName
);
653 pkgTagSection::Tag
pkgTagSection::Tag::Rewrite(std::string
const &Name
, std::string
const &Data
)
655 if (Data
.empty() == true)
656 return Tag(REMOVE
, Name
, "");
658 return Tag(REWRITE
, Name
, Data
);
660 static bool WriteTag(FileFd
&File
, std::string Tag
, std::string
const &Value
)
662 if (Value
.empty() || isspace(Value
[0]) != 0)
668 return File
.Write(Tag
.c_str(), Tag
.length());
670 static bool RewriteTags(FileFd
&File
, pkgTagSection
const * const This
, char const * const Tag
,
671 std::vector
<pkgTagSection::Tag
>::const_iterator
&R
,
672 std::vector
<pkgTagSection::Tag
>::const_iterator
const &REnd
)
674 size_t const TagLen
= strlen(Tag
);
675 for (; R
!= REnd
; ++R
)
678 if (R
->Name
.length() == TagLen
&& strncasecmp(R
->Name
.c_str(), Tag
, R
->Name
.length()) == 0)
680 if (R
->Action
!= pkgTagSection::Tag::REWRITE
)
684 else if(R
->Action
== pkgTagSection::Tag::RENAME
&& R
->Data
.length() == TagLen
&&
685 strncasecmp(R
->Data
.c_str(), Tag
, R
->Data
.length()) == 0)
686 data
= This
->FindRawS(R
->Name
.c_str());
690 return WriteTag(File
, Tag
, data
);
694 bool pkgTagSection::Write(FileFd
&File
, char const * const * const Order
, std::vector
<Tag
> const &Rewrite
) const
696 // first pass: Write everything we have an order for
699 for (unsigned int I
= 0; Order
[I
] != 0; ++I
)
701 std::vector
<Tag
>::const_iterator R
= Rewrite
.begin();
702 if (RewriteTags(File
, this, Order
[I
], R
, Rewrite
.end()) == false)
704 if (R
!= Rewrite
.end())
707 if (Exists(Order
[I
]) == false)
710 if (WriteTag(File
, Order
[I
], FindRawS(Order
[I
])) == false)
714 // second pass: See if we have tags which aren't ordered
715 if (d
->Tags
.empty() == false)
717 for (std::vector
<pkgTagSectionPrivate::TagData
>::const_iterator T
= d
->Tags
.begin(); T
!= d
->Tags
.end() - 1; ++T
)
719 char const * const fieldname
= Section
+ T
->StartTag
;
720 size_t fieldnamelen
= T
->EndTag
- T
->StartTag
;
724 for (; Order
[I
] != 0; ++I
)
726 if (fieldnamelen
== strlen(Order
[I
]) && strncasecmp(fieldname
, Order
[I
], fieldnamelen
) == 0)
733 std::string
const name(fieldname
, fieldnamelen
);
734 std::vector
<Tag
>::const_iterator R
= Rewrite
.begin();
735 if (RewriteTags(File
, this, name
.c_str(), R
, Rewrite
.end()) == false)
737 if (R
!= Rewrite
.end())
740 if (WriteTag(File
, name
, FindRawS(name
.c_str())) == false)
744 // last pass: see if there are any rewrites remaining we haven't done yet
745 for (std::vector
<Tag
>::const_iterator R
= Rewrite
.begin(); R
!= Rewrite
.end(); ++R
)
747 if (R
->Action
== Tag::REMOVE
)
749 std::string
const name
= ((R
->Action
== Tag::RENAME
) ? R
->Data
: R
->Name
);
750 if (Exists(name
.c_str()))
755 for (; Order
[I
] != 0; ++I
)
757 if (strncasecmp(name
.c_str(), Order
[I
], name
.length()) == 0 && name
.length() == strlen(Order
[I
]))
764 if (WriteTag(File
, name
, ((R
->Action
== Tag::RENAME
) ? FindRawS(R
->Name
.c_str()) : R
->Data
)) == false)
771 #include "tagfile-order.c"
773 // TFRewrite - Rewrite a control record /*{{{*/
774 // ---------------------------------------------------------------------
775 /* This writes the control record to stdout rewriting it as necessary. The
776 override map item specificies the rewriting rules to follow. This also
777 takes the time to sort the feild list. */
778 APT_IGNORE_DEPRECATED_PUSH
779 bool TFRewrite(FILE *Output
,pkgTagSection
const &Tags
,const char *Order
[],
780 TFRewriteData
*Rewrite
)
782 unsigned char Visited
[256]; // Bit 1 is Order, Bit 2 is Rewrite
783 for (unsigned I
= 0; I
!= 256; I
++)
786 // Set new tag up as necessary.
787 for (unsigned int J
= 0; Rewrite
!= 0 && Rewrite
[J
].Tag
!= 0; J
++)
789 if (Rewrite
[J
].NewTag
== 0)
790 Rewrite
[J
].NewTag
= Rewrite
[J
].Tag
;
793 // Write all all of the tags, in order.
796 for (unsigned int I
= 0; Order
[I
] != 0; I
++)
798 bool Rewritten
= false;
800 // See if this is a field that needs to be rewritten
801 for (unsigned int J
= 0; Rewrite
!= 0 && Rewrite
[J
].Tag
!= 0; J
++)
803 if (strcasecmp(Rewrite
[J
].Tag
,Order
[I
]) == 0)
806 if (Rewrite
[J
].Rewrite
!= 0 && Rewrite
[J
].Rewrite
[0] != 0)
808 if (isspace(Rewrite
[J
].Rewrite
[0]))
809 fprintf(Output
,"%s:%s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
811 fprintf(Output
,"%s: %s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
818 // See if it is in the fragment
820 if (Tags
.Find(Order
[I
],Pos
) == false)
824 if (Rewritten
== true)
827 /* Write out this element, taking a moment to rewrite the tag
828 in case of changes of case. */
831 Tags
.Get(Start
,Stop
,Pos
);
833 if (fputs(Order
[I
],Output
) < 0)
834 return _error
->Errno("fputs","IO Error to output");
835 Start
+= strlen(Order
[I
]);
836 if (fwrite(Start
,Stop
- Start
,1,Output
) != 1)
837 return _error
->Errno("fwrite","IO Error to output");
838 if (Stop
[-1] != '\n')
839 fprintf(Output
,"\n");
843 // Now write all the old tags that were missed.
844 for (unsigned int I
= 0; I
!= Tags
.Count(); I
++)
846 if ((Visited
[I
] & 1) == 1)
851 Tags
.Get(Start
,Stop
,I
);
852 const char *End
= Start
;
853 for (; End
< Stop
&& *End
!= ':'; End
++);
855 // See if this is a field that needs to be rewritten
856 bool Rewritten
= false;
857 for (unsigned int J
= 0; Rewrite
!= 0 && Rewrite
[J
].Tag
!= 0; J
++)
859 if (stringcasecmp(Start
,End
,Rewrite
[J
].Tag
) == 0)
862 if (Rewrite
[J
].Rewrite
!= 0 && Rewrite
[J
].Rewrite
[0] != 0)
864 if (isspace(Rewrite
[J
].Rewrite
[0]))
865 fprintf(Output
,"%s:%s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
867 fprintf(Output
,"%s: %s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
875 if (Rewritten
== true)
878 // Write out this element
879 if (fwrite(Start
,Stop
- Start
,1,Output
) != 1)
880 return _error
->Errno("fwrite","IO Error to output");
881 if (Stop
[-1] != '\n')
882 fprintf(Output
,"\n");
885 // Now write all the rewrites that were missed
886 for (unsigned int J
= 0; Rewrite
!= 0 && Rewrite
[J
].Tag
!= 0; J
++)
888 if ((Visited
[J
] & 2) == 2)
891 if (Rewrite
[J
].Rewrite
!= 0 && Rewrite
[J
].Rewrite
[0] != 0)
893 if (isspace(Rewrite
[J
].Rewrite
[0]))
894 fprintf(Output
,"%s:%s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
896 fprintf(Output
,"%s: %s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
902 APT_IGNORE_DEPRECATED_POP
905 pkgTagSection::~pkgTagSection() { delete d
; }