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
)
386 if (*Stop
== '\n' && Stop
[1] != ' ')
390 lastTagData
.StartValue
= Stop
- Section
;
393 Stop
= (const char *)memchr(Stop
,'\n',End
- Stop
);
398 for (; Stop
+1 < End
&& Stop
[1] == '\r'; Stop
++)
402 // Double newline marks the end of the record
403 if (Stop
+1 < End
&& Stop
[1] == '\n')
405 if (lastTagData
.EndTag
!= 0)
407 if (AlphaIndexes
[lastTagHash
] != 0)
408 lastTagData
.NextInBucket
= AlphaIndexes
[lastTagHash
];
409 APT_IGNORE_DEPRECATED(AlphaIndexes
[lastTagHash
] = TagCount
;)
410 d
->Tags
.push_back(lastTagData
);
413 pkgTagSectionPrivate::TagData
const td(Stop
- Section
);
414 d
->Tags
.push_back(td
);
415 TrimRecord(false,End
);
425 // TagSection::TrimRecord - Trim off any garbage before/after a record /*{{{*/
426 // ---------------------------------------------------------------------
427 /* There should be exactly 2 newline at the end of the record, no more. */
428 void pkgTagSection::TrimRecord(bool BeforeRecord
, const char*& End
)
430 if (BeforeRecord
== true)
432 for (; Stop
< End
&& (Stop
[0] == '\n' || Stop
[0] == '\r'); Stop
++);
435 // TagSection::Trim - Trim off any trailing garbage /*{{{*/
436 // ---------------------------------------------------------------------
437 /* There should be exactly 1 newline at the end of the buffer, no more. */
438 void pkgTagSection::Trim()
440 for (; Stop
> Section
+ 2 && (Stop
[-2] == '\n' || Stop
[-2] == '\r'); Stop
--);
443 // TagSection::Exists - return True if a tag exists /*{{{*/
444 bool pkgTagSection::Exists(const char* const Tag
) const
447 return Find(Tag
, tmp
);
450 // TagSection::Find - Locate a tag /*{{{*/
451 // ---------------------------------------------------------------------
452 /* This searches the section for a tag that matches the given string. */
453 bool pkgTagSection::Find(const char *Tag
,unsigned int &Pos
) const
455 size_t const Length
= strlen(Tag
);
456 unsigned int Bucket
= AlphaIndexes
[AlphaHash(Tag
, Length
)];
460 for (; Bucket
!= 0; Bucket
= d
->Tags
[Bucket
- 1].NextInBucket
)
462 if ((d
->Tags
[Bucket
- 1].EndTag
- d
->Tags
[Bucket
- 1].StartTag
) != Length
)
465 char const * const St
= Section
+ d
->Tags
[Bucket
- 1].StartTag
;
466 if (strncasecmp(Tag
,St
,Length
) != 0)
476 bool pkgTagSection::Find(const char *Tag
,const char *&Start
,
477 const char *&End
) const
480 if (Find(Tag
, Pos
) == false)
483 Start
= Section
+ d
->Tags
[Pos
].StartValue
;
484 // Strip off the gunk from the end
485 End
= Section
+ d
->Tags
[Pos
+ 1].StartTag
;
486 if (unlikely(Start
> End
))
487 return _error
->Error("Internal parsing error");
489 for (; isspace_ascii(End
[-1]) != 0 && End
> Start
; --End
);
494 // TagSection::FindS - Find a string /*{{{*/
495 string
pkgTagSection::FindS(const char *Tag
) const
499 if (Find(Tag
,Start
,End
) == false)
501 return string(Start
,End
);
504 // TagSection::FindRawS - Find a string /*{{{*/
505 string
pkgTagSection::FindRawS(const char *Tag
) const
508 if (Find(Tag
, Pos
) == false)
511 char const *Start
= (char const *) memchr(Section
+ d
->Tags
[Pos
].EndTag
, ':', d
->Tags
[Pos
].StartValue
- d
->Tags
[Pos
].EndTag
);
513 char const *End
= Section
+ d
->Tags
[Pos
+ 1].StartTag
;
514 if (unlikely(Start
> End
))
517 for (; isspace_ascii(End
[-1]) != 0 && End
> Start
; --End
);
519 return std::string(Start
, End
- Start
);
522 // TagSection::FindI - Find an integer /*{{{*/
523 // ---------------------------------------------------------------------
525 signed int pkgTagSection::FindI(const char *Tag
,signed long Default
) const
529 if (Find(Tag
,Start
,Stop
) == false)
532 // Copy it into a temp buffer so we can use strtol
534 if ((unsigned)(Stop
- Start
) >= sizeof(S
))
536 strncpy(S
,Start
,Stop
-Start
);
541 signed long Result
= strtol(S
,&End
,10);
542 if (errno
== ERANGE
||
543 Result
< std::numeric_limits
<int>::min() || Result
> std::numeric_limits
<int>::max()) {
545 _error
->Error(_("Cannot convert %s to integer: out of range"), S
);
552 // TagSection::FindULL - Find an unsigned long long integer /*{{{*/
553 // ---------------------------------------------------------------------
555 unsigned long long pkgTagSection::FindULL(const char *Tag
, unsigned long long const &Default
) const
559 if (Find(Tag
,Start
,Stop
) == false)
562 // Copy it into a temp buffer so we can use strtoull
564 if ((unsigned)(Stop
- Start
) >= sizeof(S
))
566 strncpy(S
,Start
,Stop
-Start
);
570 unsigned long long Result
= strtoull(S
,&End
,10);
576 // TagSection::FindB - Find boolean value /*{{{*/
577 // ---------------------------------------------------------------------
579 bool pkgTagSection::FindB(const char *Tag
, bool const &Default
) const
581 const char *Start
, *Stop
;
582 if (Find(Tag
, Start
, Stop
) == false)
584 return StringToBool(string(Start
, Stop
));
587 // TagSection::FindFlag - Locate a yes/no type flag /*{{{*/
588 // ---------------------------------------------------------------------
589 /* The bits marked in Flag are masked on/off in Flags */
590 bool pkgTagSection::FindFlag(const char * const Tag
, uint8_t &Flags
,
591 uint8_t const Flag
) const
595 if (Find(Tag
,Start
,Stop
) == false)
597 return FindFlag(Flags
, Flag
, Start
, Stop
);
599 bool pkgTagSection::FindFlag(uint8_t &Flags
, uint8_t const Flag
,
600 char const* const Start
, char const* const Stop
)
602 switch (StringToBool(string(Start
, Stop
)))
613 _error
->Warning("Unknown flag value: %s",string(Start
,Stop
).c_str());
618 bool pkgTagSection::FindFlag(const char *Tag
,unsigned long &Flags
,
619 unsigned long Flag
) const
623 if (Find(Tag
,Start
,Stop
) == false)
625 return FindFlag(Flags
, Flag
, Start
, Stop
);
627 bool pkgTagSection::FindFlag(unsigned long &Flags
, unsigned long Flag
,
628 char const* Start
, char const* Stop
)
630 switch (StringToBool(string(Start
, Stop
)))
641 _error
->Warning("Unknown flag value: %s",string(Start
,Stop
).c_str());
647 void pkgTagSection::Get(const char *&Start
,const char *&Stop
,unsigned int I
) const
649 Start
= Section
+ d
->Tags
[I
].StartTag
;
650 Stop
= Section
+ d
->Tags
[I
+1].StartTag
;
652 APT_PURE
unsigned int pkgTagSection::Count() const { /*{{{*/
653 if (d
->Tags
.empty() == true)
655 // the last element is just marking the end and isn't a real one
656 return d
->Tags
.size() - 1;
659 // TagSection::Write - Ordered (re)writing of fields /*{{{*/
660 pkgTagSection::Tag
pkgTagSection::Tag::Remove(std::string
const &Name
)
662 return Tag(REMOVE
, Name
, "");
664 pkgTagSection::Tag
pkgTagSection::Tag::Rename(std::string
const &OldName
, std::string
const &NewName
)
666 return Tag(RENAME
, OldName
, NewName
);
668 pkgTagSection::Tag
pkgTagSection::Tag::Rewrite(std::string
const &Name
, std::string
const &Data
)
670 if (Data
.empty() == true)
671 return Tag(REMOVE
, Name
, "");
673 return Tag(REWRITE
, Name
, Data
);
675 static bool WriteTag(FileFd
&File
, std::string Tag
, std::string
const &Value
)
677 if (Value
.empty() || isspace_ascii(Value
[0]) != 0)
683 return File
.Write(Tag
.c_str(), Tag
.length());
685 static bool RewriteTags(FileFd
&File
, pkgTagSection
const * const This
, char const * const Tag
,
686 std::vector
<pkgTagSection::Tag
>::const_iterator
&R
,
687 std::vector
<pkgTagSection::Tag
>::const_iterator
const &REnd
)
689 size_t const TagLen
= strlen(Tag
);
690 for (; R
!= REnd
; ++R
)
693 if (R
->Name
.length() == TagLen
&& strncasecmp(R
->Name
.c_str(), Tag
, R
->Name
.length()) == 0)
695 if (R
->Action
!= pkgTagSection::Tag::REWRITE
)
699 else if(R
->Action
== pkgTagSection::Tag::RENAME
&& R
->Data
.length() == TagLen
&&
700 strncasecmp(R
->Data
.c_str(), Tag
, R
->Data
.length()) == 0)
701 data
= This
->FindRawS(R
->Name
.c_str());
705 return WriteTag(File
, Tag
, data
);
709 bool pkgTagSection::Write(FileFd
&File
, char const * const * const Order
, std::vector
<Tag
> const &Rewrite
) const
711 // first pass: Write everything we have an order for
714 for (unsigned int I
= 0; Order
[I
] != 0; ++I
)
716 std::vector
<Tag
>::const_iterator R
= Rewrite
.begin();
717 if (RewriteTags(File
, this, Order
[I
], R
, Rewrite
.end()) == false)
719 if (R
!= Rewrite
.end())
722 if (Exists(Order
[I
]) == false)
725 if (WriteTag(File
, Order
[I
], FindRawS(Order
[I
])) == false)
729 // second pass: See if we have tags which aren't ordered
730 if (d
->Tags
.empty() == false)
732 for (std::vector
<pkgTagSectionPrivate::TagData
>::const_iterator T
= d
->Tags
.begin(); T
!= d
->Tags
.end() - 1; ++T
)
734 char const * const fieldname
= Section
+ T
->StartTag
;
735 size_t fieldnamelen
= T
->EndTag
- T
->StartTag
;
739 for (; Order
[I
] != 0; ++I
)
741 if (fieldnamelen
== strlen(Order
[I
]) && strncasecmp(fieldname
, Order
[I
], fieldnamelen
) == 0)
748 std::string
const name(fieldname
, fieldnamelen
);
749 std::vector
<Tag
>::const_iterator R
= Rewrite
.begin();
750 if (RewriteTags(File
, this, name
.c_str(), R
, Rewrite
.end()) == false)
752 if (R
!= Rewrite
.end())
755 if (WriteTag(File
, name
, FindRawS(name
.c_str())) == false)
759 // last pass: see if there are any rewrites remaining we haven't done yet
760 for (std::vector
<Tag
>::const_iterator R
= Rewrite
.begin(); R
!= Rewrite
.end(); ++R
)
762 if (R
->Action
== Tag::REMOVE
)
764 std::string
const name
= ((R
->Action
== Tag::RENAME
) ? R
->Data
: R
->Name
);
765 if (Exists(name
.c_str()))
770 for (; Order
[I
] != 0; ++I
)
772 if (strncasecmp(name
.c_str(), Order
[I
], name
.length()) == 0 && name
.length() == strlen(Order
[I
]))
779 if (WriteTag(File
, name
, ((R
->Action
== Tag::RENAME
) ? FindRawS(R
->Name
.c_str()) : R
->Data
)) == false)
786 void pkgUserTagSection::TrimRecord(bool /*BeforeRecord*/, const char* &End
)/*{{{*/
788 for (; Stop
< End
&& (Stop
[0] == '\n' || Stop
[0] == '\r' || Stop
[0] == '#'); Stop
++)
790 Stop
= (const char*) memchr(Stop
,'\n',End
-Stop
);
794 #include "tagfile-order.c"
796 // TFRewrite - Rewrite a control record /*{{{*/
797 // ---------------------------------------------------------------------
798 /* This writes the control record to stdout rewriting it as necessary. The
799 override map item specificies the rewriting rules to follow. This also
800 takes the time to sort the feild list. */
801 APT_IGNORE_DEPRECATED_PUSH
802 bool TFRewrite(FILE *Output
,pkgTagSection
const &Tags
,const char *Order
[],
803 TFRewriteData
*Rewrite
)
805 unsigned char Visited
[256]; // Bit 1 is Order, Bit 2 is Rewrite
806 for (unsigned I
= 0; I
!= 256; I
++)
809 // Set new tag up as necessary.
810 for (unsigned int J
= 0; Rewrite
!= 0 && Rewrite
[J
].Tag
!= 0; J
++)
812 if (Rewrite
[J
].NewTag
== 0)
813 Rewrite
[J
].NewTag
= Rewrite
[J
].Tag
;
816 // Write all all of the tags, in order.
819 for (unsigned int I
= 0; Order
[I
] != 0; I
++)
821 bool Rewritten
= false;
823 // See if this is a field that needs to be rewritten
824 for (unsigned int J
= 0; Rewrite
!= 0 && Rewrite
[J
].Tag
!= 0; J
++)
826 if (strcasecmp(Rewrite
[J
].Tag
,Order
[I
]) == 0)
829 if (Rewrite
[J
].Rewrite
!= 0 && Rewrite
[J
].Rewrite
[0] != 0)
831 if (isspace_ascii(Rewrite
[J
].Rewrite
[0]))
832 fprintf(Output
,"%s:%s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
834 fprintf(Output
,"%s: %s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
841 // See if it is in the fragment
843 if (Tags
.Find(Order
[I
],Pos
) == false)
847 if (Rewritten
== true)
850 /* Write out this element, taking a moment to rewrite the tag
851 in case of changes of case. */
854 Tags
.Get(Start
,Stop
,Pos
);
856 if (fputs(Order
[I
],Output
) < 0)
857 return _error
->Errno("fputs","IO Error to output");
858 Start
+= strlen(Order
[I
]);
859 if (fwrite(Start
,Stop
- Start
,1,Output
) != 1)
860 return _error
->Errno("fwrite","IO Error to output");
861 if (Stop
[-1] != '\n')
862 fprintf(Output
,"\n");
866 // Now write all the old tags that were missed.
867 for (unsigned int I
= 0; I
!= Tags
.Count(); I
++)
869 if ((Visited
[I
] & 1) == 1)
874 Tags
.Get(Start
,Stop
,I
);
875 const char *End
= Start
;
876 for (; End
< Stop
&& *End
!= ':'; End
++);
878 // See if this is a field that needs to be rewritten
879 bool Rewritten
= false;
880 for (unsigned int J
= 0; Rewrite
!= 0 && Rewrite
[J
].Tag
!= 0; J
++)
882 if (stringcasecmp(Start
,End
,Rewrite
[J
].Tag
) == 0)
885 if (Rewrite
[J
].Rewrite
!= 0 && Rewrite
[J
].Rewrite
[0] != 0)
887 if (isspace_ascii(Rewrite
[J
].Rewrite
[0]))
888 fprintf(Output
,"%s:%s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
890 fprintf(Output
,"%s: %s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
898 if (Rewritten
== true)
901 // Write out this element
902 if (fwrite(Start
,Stop
- Start
,1,Output
) != 1)
903 return _error
->Errno("fwrite","IO Error to output");
904 if (Stop
[-1] != '\n')
905 fprintf(Output
,"\n");
908 // Now write all the rewrites that were missed
909 for (unsigned int J
= 0; Rewrite
!= 0 && Rewrite
[J
].Tag
!= 0; J
++)
911 if ((Visited
[J
] & 2) == 2)
914 if (Rewrite
[J
].Rewrite
!= 0 && Rewrite
[J
].Rewrite
[0] != 0)
916 if (isspace_ascii(Rewrite
[J
].Rewrite
[0]))
917 fprintf(Output
,"%s:%s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
919 fprintf(Output
,"%s: %s\n",Rewrite
[J
].NewTag
,Rewrite
[J
].Rewrite
);
925 APT_IGNORE_DEPRECATED_POP
928 pkgTagSection::~pkgTagSection() { delete d
; }