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 memset(&AlphaIndexes
, 0, sizeof(AlphaIndexes
));
310 APT_IGNORE_DEPRECATED_POP
312 // TagSection::Scan - Scan for the end of the header information /*{{{*/
313 bool pkgTagSection::Scan(const char *Start
,unsigned long MaxLength
, bool const Restart
)
316 const char *End
= Start
+ MaxLength
;
318 if (Restart
== false && d
->Tags
.empty() == false)
320 Stop
= Section
+ d
->Tags
.back().StartTag
;
323 Stop
= (const char *)memchr(Stop
,'\n',End
- Stop
);
331 if (d
->Tags
.empty() == false)
333 memset(&AlphaIndexes
, 0, sizeof(AlphaIndexes
));
336 d
->Tags
.reserve(0x100);
338 unsigned int TagCount
= d
->Tags
.size();
343 pkgTagSectionPrivate::TagData
lastTagData(0);
344 lastTagData
.EndTag
= 0;
345 unsigned long lastTagHash
= 0;
348 TrimRecord(true,End
);
350 // this can happen when TrimRecord trims away the entire Record
351 // (e.g. because it just contains comments)
355 // Start a new index and add it to the hash
356 if (isspace_ascii(Stop
[0]) == 0)
358 // store the last found tag
359 if (lastTagData
.EndTag
!= 0)
361 if (AlphaIndexes
[lastTagHash
] != 0)
362 lastTagData
.NextInBucket
= AlphaIndexes
[lastTagHash
];
363 APT_IGNORE_DEPRECATED_PUSH
364 AlphaIndexes
[lastTagHash
] = TagCount
;
365 APT_IGNORE_DEPRECATED_POP
366 d
->Tags
.push_back(lastTagData
);
369 APT_IGNORE_DEPRECATED(++TagCount
;)
370 lastTagData
= pkgTagSectionPrivate::TagData(Stop
- Section
);
371 // find the colon separating tag and value
372 char const * Colon
= (char const *) memchr(Stop
, ':', End
- Stop
);
375 // find the end of the tag (which might or might not be the colon)
376 char const * EndTag
= Colon
;
378 for (; EndTag
> Stop
&& isspace_ascii(*EndTag
) != 0; --EndTag
)
381 lastTagData
.EndTag
= EndTag
- Section
;
382 lastTagHash
= AlphaHash(Stop
, EndTag
- Stop
);
383 // find the beginning of the value
385 for (; isspace_ascii(*Stop
) != 0; ++Stop
);
388 lastTagData
.StartValue
= Stop
- Section
;
391 Stop
= (const char *)memchr(Stop
,'\n',End
- Stop
);
396 for (; Stop
+1 < End
&& Stop
[1] == '\r'; Stop
++)
400 // Double newline marks the end of the record
401 if (Stop
+1 < End
&& Stop
[1] == '\n')
403 if (lastTagData
.EndTag
!= 0)
405 if (AlphaIndexes
[lastTagHash
] != 0)
406 lastTagData
.NextInBucket
= AlphaIndexes
[lastTagHash
];
407 APT_IGNORE_DEPRECATED(AlphaIndexes
[lastTagHash
] = TagCount
;)
408 d
->Tags
.push_back(lastTagData
);
411 pkgTagSectionPrivate::TagData
const td(Stop
- Section
);
412 d
->Tags
.push_back(td
);
413 TrimRecord(false,End
);
423 // TagSection::TrimRecord - Trim off any garbage before/after a record /*{{{*/
424 // ---------------------------------------------------------------------
425 /* There should be exactly 2 newline at the end of the record, no more. */
426 void pkgTagSection::TrimRecord(bool BeforeRecord
, const char*& End
)
428 if (BeforeRecord
== true)
430 for (; Stop
< End
&& (Stop
[0] == '\n' || Stop
[0] == '\r'); Stop
++);
433 // TagSection::Trim - Trim off any trailing garbage /*{{{*/
434 // ---------------------------------------------------------------------
435 /* There should be exactly 1 newline at the end of the buffer, no more. */
436 void pkgTagSection::Trim()
438 for (; Stop
> Section
+ 2 && (Stop
[-2] == '\n' || Stop
[-2] == '\r'); Stop
--);
441 // TagSection::Exists - return True if a tag exists /*{{{*/
442 bool pkgTagSection::Exists(const char* const Tag
) const
445 return Find(Tag
, tmp
);
448 // TagSection::Find - Locate a tag /*{{{*/
449 // ---------------------------------------------------------------------
450 /* This searches the section for a tag that matches the given string. */
451 bool pkgTagSection::Find(const char *Tag
,unsigned int &Pos
) const
453 size_t const Length
= strlen(Tag
);
454 unsigned int Bucket
= AlphaIndexes
[AlphaHash(Tag
, Length
)];
458 for (; Bucket
!= 0; Bucket
= d
->Tags
[Bucket
- 1].NextInBucket
)
460 if ((d
->Tags
[Bucket
- 1].EndTag
- d
->Tags
[Bucket
- 1].StartTag
) != Length
)
463 char const * const St
= Section
+ d
->Tags
[Bucket
- 1].StartTag
;
464 if (strncasecmp(Tag
,St
,Length
) != 0)
474 bool pkgTagSection::Find(const char *Tag
,const char *&Start
,
475 const char *&End
) const
478 if (Find(Tag
, Pos
) == false)
481 Start
= Section
+ d
->Tags
[Pos
].StartValue
;
482 // Strip off the gunk from the end
483 End
= Section
+ d
->Tags
[Pos
+ 1].StartTag
;
484 if (unlikely(Start
> End
))
485 return _error
->Error("Internal parsing error");
487 for (; isspace_ascii(End
[-1]) != 0 && End
> Start
; --End
);
492 // TagSection::FindS - Find a string /*{{{*/
493 string
pkgTagSection::FindS(const char *Tag
) const
497 if (Find(Tag
,Start
,End
) == false)
499 return string(Start
,End
);
502 // TagSection::FindRawS - Find a string /*{{{*/
503 string
pkgTagSection::FindRawS(const char *Tag
) const
506 if (Find(Tag
, Pos
) == false)
509 char const *Start
= (char const *) memchr(Section
+ d
->Tags
[Pos
].EndTag
, ':', d
->Tags
[Pos
].StartValue
- d
->Tags
[Pos
].EndTag
);
511 char const *End
= Section
+ d
->Tags
[Pos
+ 1].StartTag
;
512 if (unlikely(Start
> End
))
515 for (; isspace_ascii(End
[-1]) != 0 && End
> Start
; --End
);
517 return std::string(Start
, End
- Start
);
520 // TagSection::FindI - Find an integer /*{{{*/
521 // ---------------------------------------------------------------------
523 signed int pkgTagSection::FindI(const char *Tag
,signed long Default
) const
527 if (Find(Tag
,Start
,Stop
) == false)
530 // Copy it into a temp buffer so we can use strtol
532 if ((unsigned)(Stop
- Start
) >= sizeof(S
))
534 strncpy(S
,Start
,Stop
-Start
);
539 signed long Result
= strtol(S
,&End
,10);
540 if (errno
== ERANGE
||
541 Result
< std::numeric_limits
<int>::min() || Result
> std::numeric_limits
<int>::max()) {
543 _error
->Error(_("Cannot convert %s to integer: out of range"), S
);
550 // TagSection::FindULL - Find an unsigned long long integer /*{{{*/
551 // ---------------------------------------------------------------------
553 unsigned long long pkgTagSection::FindULL(const char *Tag
, unsigned long long const &Default
) const
557 if (Find(Tag
,Start
,Stop
) == false)
560 // Copy it into a temp buffer so we can use strtoull
562 if ((unsigned)(Stop
- Start
) >= sizeof(S
))
564 strncpy(S
,Start
,Stop
-Start
);
568 unsigned long long Result
= strtoull(S
,&End
,10);
574 // TagSection::FindB - Find boolean value /*{{{*/
575 // ---------------------------------------------------------------------
577 bool pkgTagSection::FindB(const char *Tag
, bool const &Default
) const
579 const char *Start
, *Stop
;
580 if (Find(Tag
, Start
, Stop
) == false)
582 return StringToBool(string(Start
, Stop
));
585 // TagSection::FindFlag - Locate a yes/no type flag /*{{{*/
586 // ---------------------------------------------------------------------
587 /* The bits marked in Flag are masked on/off in Flags */
588 bool pkgTagSection::FindFlag(const char * const Tag
, uint8_t &Flags
,
589 uint8_t const Flag
) const
593 if (Find(Tag
,Start
,Stop
) == false)
595 return FindFlag(Flags
, Flag
, Start
, Stop
);
597 bool pkgTagSection::FindFlag(uint8_t &Flags
, uint8_t const Flag
,
598 char const* const Start
, char const* const Stop
)
600 switch (StringToBool(string(Start
, Stop
)))
611 _error
->Warning("Unknown flag value: %s",string(Start
,Stop
).c_str());
616 bool pkgTagSection::FindFlag(const char *Tag
,unsigned long &Flags
,
617 unsigned long Flag
) const
621 if (Find(Tag
,Start
,Stop
) == false)
623 return FindFlag(Flags
, Flag
, Start
, Stop
);
625 bool pkgTagSection::FindFlag(unsigned long &Flags
, unsigned long Flag
,
626 char const* Start
, char const* Stop
)
628 switch (StringToBool(string(Start
, Stop
)))
639 _error
->Warning("Unknown flag value: %s",string(Start
,Stop
).c_str());
645 void pkgTagSection::Get(const char *&Start
,const char *&Stop
,unsigned int I
) const
647 Start
= Section
+ d
->Tags
[I
].StartTag
;
648 Stop
= Section
+ d
->Tags
[I
+1].StartTag
;
650 APT_PURE
unsigned int pkgTagSection::Count() const { /*{{{*/
651 if (d
->Tags
.empty() == true)
653 // the last element is just marking the end and isn't a real one
654 return d
->Tags
.size() - 1;
657 // TagSection::Write - Ordered (re)writing of fields /*{{{*/
658 pkgTagSection::Tag
pkgTagSection::Tag::Remove(std::string
const &Name
)
660 return Tag(REMOVE
, Name
, "");
662 pkgTagSection::Tag
pkgTagSection::Tag::Rename(std::string
const &OldName
, std::string
const &NewName
)
664 return Tag(RENAME
, OldName
, NewName
);
666 pkgTagSection::Tag
pkgTagSection::Tag::Rewrite(std::string
const &Name
, std::string
const &Data
)
668 if (Data
.empty() == true)
669 return Tag(REMOVE
, Name
, "");
671 return Tag(REWRITE
, Name
, Data
);
673 static bool WriteTag(FileFd
&File
, std::string Tag
, std::string
const &Value
)
675 if (Value
.empty() || isspace_ascii(Value
[0]) != 0)
681 return File
.Write(Tag
.c_str(), Tag
.length());
683 static bool RewriteTags(FileFd
&File
, pkgTagSection
const * const This
, char const * const Tag
,
684 std::vector
<pkgTagSection::Tag
>::const_iterator
&R
,
685 std::vector
<pkgTagSection::Tag
>::const_iterator
const &REnd
)
687 size_t const TagLen
= strlen(Tag
);
688 for (; R
!= REnd
; ++R
)
691 if (R
->Name
.length() == TagLen
&& strncasecmp(R
->Name
.c_str(), Tag
, R
->Name
.length()) == 0)
693 if (R
->Action
!= pkgTagSection::Tag::REWRITE
)
697 else if(R
->Action
== pkgTagSection::Tag::RENAME
&& R
->Data
.length() == TagLen
&&
698 strncasecmp(R
->Data
.c_str(), Tag
, R
->Data
.length()) == 0)
699 data
= This
->FindRawS(R
->Name
.c_str());
703 return WriteTag(File
, Tag
, data
);
707 bool pkgTagSection::Write(FileFd
&File
, char const * const * const Order
, std::vector
<Tag
> const &Rewrite
) const
709 // first pass: Write everything we have an order for
712 for (unsigned int I
= 0; Order
[I
] != 0; ++I
)
714 std::vector
<Tag
>::const_iterator R
= Rewrite
.begin();
715 if (RewriteTags(File
, this, Order
[I
], R
, Rewrite
.end()) == false)
717 if (R
!= Rewrite
.end())
720 if (Exists(Order
[I
]) == false)
723 if (WriteTag(File
, Order
[I
], FindRawS(Order
[I
])) == false)
727 // second pass: See if we have tags which aren't ordered
728 if (d
->Tags
.empty() == false)
730 for (std::vector
<pkgTagSectionPrivate::TagData
>::const_iterator T
= d
->Tags
.begin(); T
!= d
->Tags
.end() - 1; ++T
)
732 char const * const fieldname
= Section
+ T
->StartTag
;
733 size_t fieldnamelen
= T
->EndTag
- T
->StartTag
;
737 for (; Order
[I
] != 0; ++I
)
739 if (fieldnamelen
== strlen(Order
[I
]) && strncasecmp(fieldname
, Order
[I
], fieldnamelen
) == 0)
746 std::string
const name(fieldname
, fieldnamelen
);
747 std::vector
<Tag
>::const_iterator R
= Rewrite
.begin();
748 if (RewriteTags(File
, this, name
.c_str(), R
, Rewrite
.end()) == false)
750 if (R
!= Rewrite
.end())
753 if (WriteTag(File
, name
, FindRawS(name
.c_str())) == false)
757 // last pass: see if there are any rewrites remaining we haven't done yet
758 for (std::vector
<Tag
>::const_iterator R
= Rewrite
.begin(); R
!= Rewrite
.end(); ++R
)
760 if (R
->Action
== Tag::REMOVE
)
762 std::string
const name
= ((R
->Action
== Tag::RENAME
) ? R
->Data
: R
->Name
);
763 if (Exists(name
.c_str()))
768 for (; Order
[I
] != 0; ++I
)
770 if (strncasecmp(name
.c_str(), Order
[I
], name
.length()) == 0 && name
.length() == strlen(Order
[I
]))
777 if (WriteTag(File
, name
, ((R
->Action
== Tag::RENAME
) ? FindRawS(R
->Name
.c_str()) : R
->Data
)) == false)
784 void pkgUserTagSection::TrimRecord(bool /*BeforeRecord*/, const char* &End
)/*{{{*/
786 for (; Stop
< End
&& (Stop
[0] == '\n' || Stop
[0] == '\r' || Stop
[0] == '#'); Stop
++)
788 Stop
= (const char*) memchr(Stop
,'\n',End
-Stop
);
792 #include "tagfile-order.c"
794 // TFRewrite - Rewrite a control record /*{{{*/
795 // ---------------------------------------------------------------------
796 /* This writes the control record to stdout rewriting it as necessary. The
797 override map item specificies the rewriting rules to follow. This also
798 takes the time to sort the feild list. */
799 APT_IGNORE_DEPRECATED_PUSH
800 bool TFRewrite(FILE *Output
,pkgTagSection
const &Tags
,const char *Order
[],
801 TFRewriteData
*Rewrite
)
803 unsigned char Visited
[256]; // Bit 1 is Order, Bit 2 is Rewrite
804 for (unsigned I
= 0; I
!= 256; I
++)
807 // Set new tag up as necessary.
808 for (unsigned int J
= 0; Rewrite
!= 0 && Rewrite
[J
].Tag
!= 0; J
++)
810 if (Rewrite
[J
].NewTag
== 0)
811 Rewrite
[J
].NewTag
= Rewrite
[J
].Tag
;
814 // Write all all of the tags, in order.
817 for (unsigned int I
= 0; Order
[I
] != 0; I
++)
819 bool Rewritten
= false;
821 // See if this is a field that needs to be rewritten
822 for (unsigned int J
= 0; Rewrite
!= 0 && Rewrite
[J
].Tag
!= 0; J
++)
824 if (strcasecmp(Rewrite
[J
].Tag
,Order
[I
]) == 0)
827 if (Rewrite
[J
].Rewrite
!= 0 && Rewrite
[J
].Rewrite
[0] != 0)
829 if (isspace_ascii(Rewrite
[J
].Rewrite
[0]))
830 fprintf(Output
,"%s:%s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
832 fprintf(Output
,"%s: %s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
839 // See if it is in the fragment
841 if (Tags
.Find(Order
[I
],Pos
) == false)
845 if (Rewritten
== true)
848 /* Write out this element, taking a moment to rewrite the tag
849 in case of changes of case. */
852 Tags
.Get(Start
,Stop
,Pos
);
854 if (fputs(Order
[I
],Output
) < 0)
855 return _error
->Errno("fputs","IO Error to output");
856 Start
+= strlen(Order
[I
]);
857 if (fwrite(Start
,Stop
- Start
,1,Output
) != 1)
858 return _error
->Errno("fwrite","IO Error to output");
859 if (Stop
[-1] != '\n')
860 fprintf(Output
,"\n");
864 // Now write all the old tags that were missed.
865 for (unsigned int I
= 0; I
!= Tags
.Count(); I
++)
867 if ((Visited
[I
] & 1) == 1)
872 Tags
.Get(Start
,Stop
,I
);
873 const char *End
= Start
;
874 for (; End
< Stop
&& *End
!= ':'; End
++);
876 // See if this is a field that needs to be rewritten
877 bool Rewritten
= false;
878 for (unsigned int J
= 0; Rewrite
!= 0 && Rewrite
[J
].Tag
!= 0; J
++)
880 if (stringcasecmp(Start
,End
,Rewrite
[J
].Tag
) == 0)
883 if (Rewrite
[J
].Rewrite
!= 0 && Rewrite
[J
].Rewrite
[0] != 0)
885 if (isspace_ascii(Rewrite
[J
].Rewrite
[0]))
886 fprintf(Output
,"%s:%s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
888 fprintf(Output
,"%s: %s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
896 if (Rewritten
== true)
899 // Write out this element
900 if (fwrite(Start
,Stop
- Start
,1,Output
) != 1)
901 return _error
->Errno("fwrite","IO Error to output");
902 if (Stop
[-1] != '\n')
903 fprintf(Output
,"\n");
906 // Now write all the rewrites that were missed
907 for (unsigned int J
= 0; Rewrite
!= 0 && Rewrite
[J
].Tag
!= 0; J
++)
909 if ((Visited
[J
] & 2) == 2)
912 if (Rewrite
[J
].Rewrite
!= 0 && Rewrite
[J
].Rewrite
[0] != 0)
914 if (isspace_ascii(Rewrite
[J
].Rewrite
[0]))
915 fprintf(Output
,"%s:%s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
917 fprintf(Output
,"%s: %s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
923 APT_IGNORE_DEPRECATED_POP
926 pkgTagSection::~pkgTagSection() { delete d
; }