]> git.saurik.com Git - apt.git/blame_incremental - apt-pkg/tagfile.cc
remove the compatibility markers for 4.13 abi
[apt.git] / apt-pkg / tagfile.cc
... / ...
CommitLineData
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
3// $Id: tagfile.cc,v 1.37.2.2 2003/12/31 16:02:30 mdz Exp $
4/* ######################################################################
5
6 Fast scanner for RFC-822 type header information
7
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.
10
11 ##################################################################### */
12 /*}}}*/
13// Include Files /*{{{*/
14#include<config.h>
15
16#include <apt-pkg/tagfile.h>
17#include <apt-pkg/error.h>
18#include <apt-pkg/strutl.h>
19#include <apt-pkg/fileutl.h>
20
21#include <string>
22#include <stdio.h>
23#include <ctype.h>
24#include <stdlib.h>
25#include <string.h>
26
27#include <apti18n.h>
28 /*}}}*/
29
30using std::string;
31
32class pkgTagFilePrivate
33{
34public:
35 void Reset(FileFd * const pFd, unsigned long long const pSize)
36 {
37 if (Buffer != NULL)
38 free(Buffer);
39 Buffer = NULL;
40 Fd = pFd;
41 Start = NULL;
42 End = NULL;
43 Done = false;
44 iOffset = 0;
45 Size = pSize;
46 }
47
48 pkgTagFilePrivate(FileFd * const pFd, unsigned long long const Size) : Buffer(NULL)
49 {
50 Reset(pFd, Size);
51 }
52 FileFd * Fd;
53 char *Buffer;
54 char *Start;
55 char *End;
56 bool Done;
57 unsigned long long iOffset;
58 unsigned long long Size;
59
60 ~pkgTagFilePrivate()
61 {
62 if (Buffer != NULL)
63 free(Buffer);
64 }
65};
66
67class pkgTagSectionPrivate
68{
69public:
70 pkgTagSectionPrivate()
71 {
72 }
73 struct TagData {
74 unsigned int StartTag;
75 unsigned int EndTag;
76 unsigned int StartValue;
77 unsigned int NextInBucket;
78
79 explicit TagData(unsigned int const StartTag) : StartTag(StartTag), EndTag(0), StartValue(0), NextInBucket(0) {}
80 };
81 std::vector<TagData> Tags;
82};
83
84static unsigned long AlphaHash(const char *Text, size_t Length) /*{{{*/
85{
86 /* This very simple hash function for the last 8 letters gives
87 very good performance on the debian package files */
88 if (Length > 8)
89 {
90 Text += (Length - 8);
91 Length = 8;
92 }
93 unsigned long Res = 0;
94 for (size_t i = 0; i < Length; ++i)
95 Res = ((unsigned long)(Text[i]) & 0xDF) ^ (Res << 1);
96 return Res & 0xFF;
97}
98 /*}}}*/
99
100// TagFile::pkgTagFile - Constructor /*{{{*/
101// ---------------------------------------------------------------------
102/* */
103pkgTagFile::pkgTagFile(FileFd * const pFd,unsigned long long const Size)
104 : d(new pkgTagFilePrivate(pFd, Size + 4))
105{
106 Init(pFd, Size);
107}
108void pkgTagFile::Init(FileFd * const pFd,unsigned long long Size)
109{
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 */
114 Size += 4;
115 d->Reset(pFd, Size);
116
117 if (d->Fd->IsOpen() == false)
118 d->Start = d->End = d->Buffer = 0;
119 else
120 d->Buffer = (char*)malloc(sizeof(char) * Size);
121
122 if (d->Buffer == NULL)
123 d->Done = true;
124 else
125 d->Done = false;
126
127 d->Start = d->End = d->Buffer;
128 d->iOffset = 0;
129 if (d->Done == false)
130 Fill();
131}
132 /*}}}*/
133// TagFile::~pkgTagFile - Destructor /*{{{*/
134// ---------------------------------------------------------------------
135/* */
136pkgTagFile::~pkgTagFile()
137{
138 delete d;
139}
140 /*}}}*/
141// TagFile::Offset - Return the current offset in the buffer /*{{{*/
142APT_PURE unsigned long pkgTagFile::Offset()
143{
144 return d->iOffset;
145}
146 /*}}}*/
147// TagFile::Resize - Resize the internal buffer /*{{{*/
148// ---------------------------------------------------------------------
149/* Resize the internal buffer (double it in size). Fail if a maximum size
150 * size is reached.
151 */
152bool pkgTagFile::Resize()
153{
154 // fail is the buffer grows too big
155 if(d->Size > 1024*1024+1)
156 return false;
157
158 return Resize(d->Size * 2);
159}
160bool pkgTagFile::Resize(unsigned long long const newSize)
161{
162 unsigned long long const EndSize = d->End - d->Start;
163
164 // get new buffer and use it
165 char* newBuffer = (char*)realloc(d->Buffer, sizeof(char) * newSize);
166 if (newBuffer == NULL)
167 return false;
168 d->Buffer = newBuffer;
169 d->Size = newSize;
170
171 // update the start/end pointers to the new buffer
172 d->Start = d->Buffer;
173 d->End = d->Start + EndSize;
174 return true;
175}
176 /*}}}*/
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.
182 */
183bool pkgTagFile::Step(pkgTagSection &Tag)
184{
185 if(Tag.Scan(d->Start,d->End - d->Start) == false)
186 {
187 do
188 {
189 if (Fill() == false)
190 return false;
191
192 if(Tag.Scan(d->Start,d->End - d->Start, false))
193 break;
194
195 if (Resize() == false)
196 return _error->Error(_("Unable to parse package file %s (%d)"),
197 d->Fd->Name().c_str(), 1);
198
199 } while (Tag.Scan(d->Start,d->End - d->Start, false) == false);
200 }
201
202 d->Start += Tag.size();
203 d->iOffset += Tag.size();
204
205 Tag.Trim();
206 return true;
207}
208 /*}}}*/
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 */
213bool pkgTagFile::Fill()
214{
215 unsigned long long EndSize = d->End - d->Start;
216 unsigned long long Actual = 0;
217
218 memmove(d->Buffer,d->Start,EndSize);
219 d->Start = d->Buffer;
220 d->End = d->Buffer + EndSize;
221
222 if (d->Done == false)
223 {
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)
227 return false;
228 if (Actual != dataSize)
229 d->Done = true;
230 d->End += Actual;
231 }
232
233 if (d->Done == true)
234 {
235 if (EndSize <= 3 && Actual == 0)
236 return false;
237 if (d->Size - (d->End - d->Buffer) < 4)
238 return true;
239
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--)
243 if (*E == '\n')
244 LineCount++;
245 if (LineCount < 2)
246 {
247 if ((unsigned)(d->End - d->Buffer) >= d->Size)
248 Resize(d->Size + 3);
249 for (; LineCount < 2; LineCount++)
250 *d->End++ = '\n';
251 }
252
253 return true;
254 }
255
256 return true;
257}
258 /*}}}*/
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
262 that is there */
263bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long long Offset)
264{
265 // We are within a buffer space of the next hit..
266 if (Offset >= d->iOffset && d->iOffset + (d->End - d->Start) > Offset)
267 {
268 unsigned long long Dist = Offset - d->iOffset;
269 d->Start += Dist;
270 d->iOffset += Dist;
271 // if we have seen the end, don't ask for more
272 if (d->Done == true)
273 return Tag.Scan(d->Start, d->End - d->Start);
274 else
275 return Step(Tag);
276 }
277
278 // Reposition and reload..
279 d->iOffset = Offset;
280 d->Done = false;
281 if (d->Fd->Seek(Offset) == false)
282 return false;
283 d->End = d->Start = d->Buffer;
284
285 if (Fill() == false)
286 return false;
287
288 if (Tag.Scan(d->Start, d->End - d->Start) == true)
289 return true;
290
291 // This appends a double new line (for the real eof handling)
292 if (Fill() == false)
293 return false;
294
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);
297
298 return true;
299}
300 /*}}}*/
301// pkgTagSection::pkgTagSection - Constructor /*{{{*/
302// ---------------------------------------------------------------------
303/* */
304APT_IGNORE_DEPRECATED_PUSH
305pkgTagSection::pkgTagSection()
306 : Section(0), d(new pkgTagSectionPrivate()), Stop(0)
307{
308 memset(&AlphaIndexes, 0, sizeof(AlphaIndexes));
309}
310APT_IGNORE_DEPRECATED_POP
311 /*}}}*/
312// TagSection::Scan - Scan for the end of the header information /*{{{*/
313bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength, bool const Restart)
314{
315 Section = Start;
316 const char *End = Start + MaxLength;
317
318 if (Restart == false && d->Tags.empty() == false)
319 {
320 Stop = Section + d->Tags.back().StartTag;
321 if (End <= Stop)
322 return false;
323 Stop = (const char *)memchr(Stop,'\n',End - Stop);
324 if (Stop == NULL)
325 return false;
326 ++Stop;
327 }
328 else
329 {
330 Stop = Section;
331 if (d->Tags.empty() == false)
332 {
333 memset(&AlphaIndexes, 0, sizeof(AlphaIndexes));
334 d->Tags.clear();
335 }
336 d->Tags.reserve(0x100);
337 }
338 unsigned int TagCount = d->Tags.size();
339
340 if (Stop == 0)
341 return false;
342
343 pkgTagSectionPrivate::TagData lastTagData(0);
344 lastTagData.EndTag = 0;
345 unsigned long lastTagHash = 0;
346 while (Stop < End)
347 {
348 TrimRecord(true,End);
349
350 // this can happen when TrimRecord trims away the entire Record
351 // (e.g. because it just contains comments)
352 if(Stop == End)
353 return true;
354
355 // Start a new index and add it to the hash
356 if (isspace(Stop[0]) == 0)
357 {
358 // store the last found tag
359 if (lastTagData.EndTag != 0)
360 {
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);
367 }
368
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);
373 if (Colon == NULL)
374 return false;
375 // find the end of the tag (which might or might not be the colon)
376 char const * EndTag = Colon;
377 --EndTag;
378 for (; EndTag > Stop && isspace(*EndTag) != 0; --EndTag)
379 ;
380 ++EndTag;
381 lastTagData.EndTag = EndTag - Section;
382 lastTagHash = AlphaHash(Stop, EndTag - Stop);
383 // find the beginning of the value
384 Stop = Colon + 1;
385 for (; isspace(*Stop) != 0; ++Stop);
386 if (Stop >= End)
387 return false;
388 lastTagData.StartValue = Stop - Section;
389 }
390
391 Stop = (const char *)memchr(Stop,'\n',End - Stop);
392
393 if (Stop == 0)
394 return false;
395
396 for (; Stop+1 < End && Stop[1] == '\r'; Stop++)
397 /* nothing */
398 ;
399
400 // Double newline marks the end of the record
401 if (Stop+1 < End && Stop[1] == '\n')
402 {
403 if (lastTagData.EndTag != 0)
404 {
405 if (AlphaIndexes[lastTagHash] != 0)
406 lastTagData.NextInBucket = AlphaIndexes[lastTagHash];
407 APT_IGNORE_DEPRECATED(AlphaIndexes[lastTagHash] = TagCount;)
408 d->Tags.push_back(lastTagData);
409 }
410
411 pkgTagSectionPrivate::TagData const td(Stop - Section);
412 d->Tags.push_back(td);
413 TrimRecord(false,End);
414 return true;
415 }
416
417 Stop++;
418 }
419
420 return false;
421}
422 /*}}}*/
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. */
426void pkgTagSection::TrimRecord(bool BeforeRecord, const char*& End)
427{
428 if (BeforeRecord == true)
429 return;
430 for (; Stop < End && (Stop[0] == '\n' || Stop[0] == '\r'); Stop++);
431}
432 /*}}}*/
433// TagSection::Trim - Trim off any trailing garbage /*{{{*/
434// ---------------------------------------------------------------------
435/* There should be exactly 1 newline at the end of the buffer, no more. */
436void pkgTagSection::Trim()
437{
438 for (; Stop > Section + 2 && (Stop[-2] == '\n' || Stop[-2] == '\r'); Stop--);
439}
440 /*}}}*/
441// TagSection::Exists - return True if a tag exists /*{{{*/
442bool pkgTagSection::Exists(const char* const Tag) const
443{
444 unsigned int tmp;
445 return Find(Tag, tmp);
446}
447 /*}}}*/
448// TagSection::Find - Locate a tag /*{{{*/
449// ---------------------------------------------------------------------
450/* This searches the section for a tag that matches the given string. */
451bool pkgTagSection::Find(const char *Tag,unsigned int &Pos) const
452{
453 size_t const Length = strlen(Tag);
454 unsigned int Bucket = AlphaIndexes[AlphaHash(Tag, Length)];
455 if (Bucket == 0)
456 return false;
457
458 for (; Bucket != 0; Bucket = d->Tags[Bucket - 1].NextInBucket)
459 {
460 if ((d->Tags[Bucket - 1].EndTag - d->Tags[Bucket - 1].StartTag) != Length)
461 continue;
462
463 char const * const St = Section + d->Tags[Bucket - 1].StartTag;
464 if (strncasecmp(Tag,St,Length) != 0)
465 continue;
466
467 Pos = Bucket - 1;
468 return true;
469 }
470
471 Pos = 0;
472 return false;
473}
474bool pkgTagSection::Find(const char *Tag,const char *&Start,
475 const char *&End) const
476{
477 unsigned int Pos;
478 if (Find(Tag, Pos) == false)
479 return false;
480
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");
486
487 for (; isspace(End[-1]) != 0 && End > Start; --End);
488
489 return true;
490}
491 /*}}}*/
492// TagSection::FindS - Find a string /*{{{*/
493string pkgTagSection::FindS(const char *Tag) const
494{
495 const char *Start;
496 const char *End;
497 if (Find(Tag,Start,End) == false)
498 return string();
499 return string(Start,End);
500}
501 /*}}}*/
502// TagSection::FindRawS - Find a string /*{{{*/
503string pkgTagSection::FindRawS(const char *Tag) const
504{
505 unsigned int Pos;
506 if (Find(Tag, Pos) == false)
507 return "";
508
509 char const *Start = (char const *) memchr(Section + d->Tags[Pos].EndTag, ':', d->Tags[Pos].StartValue - d->Tags[Pos].EndTag);
510 ++Start;
511 char const *End = Section + d->Tags[Pos + 1].StartTag;
512 if (unlikely(Start > End))
513 return "";
514
515 for (; isspace(End[-1]) != 0 && End > Start; --End);
516
517 return std::string(Start, End - Start);
518}
519 /*}}}*/
520// TagSection::FindI - Find an integer /*{{{*/
521// ---------------------------------------------------------------------
522/* */
523signed int pkgTagSection::FindI(const char *Tag,signed long Default) const
524{
525 const char *Start;
526 const char *Stop;
527 if (Find(Tag,Start,Stop) == false)
528 return Default;
529
530 // Copy it into a temp buffer so we can use strtol
531 char S[300];
532 if ((unsigned)(Stop - Start) >= sizeof(S))
533 return Default;
534 strncpy(S,Start,Stop-Start);
535 S[Stop - Start] = 0;
536
537 char *End;
538 signed long Result = strtol(S,&End,10);
539 if (S == End)
540 return Default;
541 return Result;
542}
543 /*}}}*/
544// TagSection::FindULL - Find an unsigned long long integer /*{{{*/
545// ---------------------------------------------------------------------
546/* */
547unsigned long long pkgTagSection::FindULL(const char *Tag, unsigned long long const &Default) const
548{
549 const char *Start;
550 const char *Stop;
551 if (Find(Tag,Start,Stop) == false)
552 return Default;
553
554 // Copy it into a temp buffer so we can use strtoull
555 char S[100];
556 if ((unsigned)(Stop - Start) >= sizeof(S))
557 return Default;
558 strncpy(S,Start,Stop-Start);
559 S[Stop - Start] = 0;
560
561 char *End;
562 unsigned long long Result = strtoull(S,&End,10);
563 if (S == End)
564 return Default;
565 return Result;
566}
567 /*}}}*/
568// TagSection::FindB - Find boolean value /*{{{*/
569// ---------------------------------------------------------------------
570/* */
571bool pkgTagSection::FindB(const char *Tag, bool const &Default) const
572{
573 const char *Start, *Stop;
574 if (Find(Tag, Start, Stop) == false)
575 return Default;
576 return StringToBool(string(Start, Stop));
577}
578 /*}}}*/
579// TagSection::FindFlag - Locate a yes/no type flag /*{{{*/
580// ---------------------------------------------------------------------
581/* The bits marked in Flag are masked on/off in Flags */
582bool pkgTagSection::FindFlag(const char *Tag,unsigned long &Flags,
583 unsigned long Flag) const
584{
585 const char *Start;
586 const char *Stop;
587 if (Find(Tag,Start,Stop) == false)
588 return true;
589 return FindFlag(Flags, Flag, Start, Stop);
590}
591bool pkgTagSection::FindFlag(unsigned long &Flags, unsigned long Flag,
592 char const* Start, char const* Stop)
593{
594 switch (StringToBool(string(Start, Stop)))
595 {
596 case 0:
597 Flags &= ~Flag;
598 return true;
599
600 case 1:
601 Flags |= Flag;
602 return true;
603
604 default:
605 _error->Warning("Unknown flag value: %s",string(Start,Stop).c_str());
606 return true;
607 }
608 return true;
609}
610 /*}}}*/
611void pkgTagSection::Get(const char *&Start,const char *&Stop,unsigned int I) const
612{
613 Start = Section + d->Tags[I].StartTag;
614 Stop = Section + d->Tags[I+1].StartTag;
615}
616APT_PURE unsigned int pkgTagSection::Count() const { /*{{{*/
617 if (d->Tags.empty() == true)
618 return 0;
619 // the last element is just marking the end and isn't a real one
620 return d->Tags.size() - 1;
621}
622 /*}}}*/
623// TagSection::Write - Ordered (re)writing of fields /*{{{*/
624pkgTagSection::Tag pkgTagSection::Tag::Remove(std::string const &Name)
625{
626 return Tag(REMOVE, Name, "");
627}
628pkgTagSection::Tag pkgTagSection::Tag::Rename(std::string const &OldName, std::string const &NewName)
629{
630 return Tag(RENAME, OldName, NewName);
631}
632pkgTagSection::Tag pkgTagSection::Tag::Rewrite(std::string const &Name, std::string const &Data)
633{
634 if (Data.empty() == true)
635 return Tag(REMOVE, Name, "");
636 else
637 return Tag(REWRITE, Name, Data);
638}
639static bool WriteTag(FileFd &File, std::string Tag, std::string const &Value)
640{
641 if (Value.empty() || isspace(Value[0]) != 0)
642 Tag.append(":");
643 else
644 Tag.append(": ");
645 Tag.append(Value);
646 Tag.append("\n");
647 return File.Write(Tag.c_str(), Tag.length());
648}
649static bool RewriteTags(FileFd &File, pkgTagSection const * const This, char const * const Tag,
650 std::vector<pkgTagSection::Tag>::const_iterator &R,
651 std::vector<pkgTagSection::Tag>::const_iterator const &REnd)
652{
653 size_t const TagLen = strlen(Tag);
654 for (; R != REnd; ++R)
655 {
656 std::string data;
657 if (R->Name.length() == TagLen && strncasecmp(R->Name.c_str(), Tag, R->Name.length()) == 0)
658 {
659 if (R->Action != pkgTagSection::Tag::REWRITE)
660 break;
661 data = R->Data;
662 }
663 else if(R->Action == pkgTagSection::Tag::RENAME && R->Data.length() == TagLen &&
664 strncasecmp(R->Data.c_str(), Tag, R->Data.length()) == 0)
665 data = This->FindRawS(R->Name.c_str());
666 else
667 continue;
668
669 return WriteTag(File, Tag, data);
670 }
671 return true;
672}
673bool pkgTagSection::Write(FileFd &File, char const * const * const Order, std::vector<Tag> const &Rewrite) const
674{
675 // first pass: Write everything we have an order for
676 if (Order != NULL)
677 {
678 for (unsigned int I = 0; Order[I] != 0; ++I)
679 {
680 std::vector<Tag>::const_iterator R = Rewrite.begin();
681 if (RewriteTags(File, this, Order[I], R, Rewrite.end()) == false)
682 return false;
683 if (R != Rewrite.end())
684 continue;
685
686 if (Exists(Order[I]) == false)
687 continue;
688
689 if (WriteTag(File, Order[I], FindRawS(Order[I])) == false)
690 return false;
691 }
692 }
693 // second pass: See if we have tags which aren't ordered
694 if (d->Tags.empty() == false)
695 {
696 for (std::vector<pkgTagSectionPrivate::TagData>::const_iterator T = d->Tags.begin(); T != d->Tags.end() - 1; ++T)
697 {
698 char const * const fieldname = Section + T->StartTag;
699 size_t fieldnamelen = T->EndTag - T->StartTag;
700 if (Order != NULL)
701 {
702 unsigned int I = 0;
703 for (; Order[I] != 0; ++I)
704 {
705 if (fieldnamelen == strlen(Order[I]) && strncasecmp(fieldname, Order[I], fieldnamelen) == 0)
706 break;
707 }
708 if (Order[I] != 0)
709 continue;
710 }
711
712 std::string const name(fieldname, fieldnamelen);
713 std::vector<Tag>::const_iterator R = Rewrite.begin();
714 if (RewriteTags(File, this, name.c_str(), R, Rewrite.end()) == false)
715 return false;
716 if (R != Rewrite.end())
717 continue;
718
719 if (WriteTag(File, name, FindRawS(name.c_str())) == false)
720 return false;
721 }
722 }
723 // last pass: see if there are any rewrites remaining we haven't done yet
724 for (std::vector<Tag>::const_iterator R = Rewrite.begin(); R != Rewrite.end(); ++R)
725 {
726 if (R->Action == Tag::REMOVE)
727 continue;
728 std::string const name = ((R->Action == Tag::RENAME) ? R->Data : R->Name);
729 if (Exists(name.c_str()))
730 continue;
731 if (Order != NULL)
732 {
733 unsigned int I = 0;
734 for (; Order[I] != 0; ++I)
735 {
736 if (strncasecmp(name.c_str(), Order[I], name.length()) == 0 && name.length() == strlen(Order[I]))
737 break;
738 }
739 if (Order[I] != 0)
740 continue;
741 }
742
743 if (WriteTag(File, name, ((R->Action == Tag::RENAME) ? FindRawS(R->Name.c_str()) : R->Data)) == false)
744 return false;
745 }
746 return true;
747}
748 /*}}}*/
749
750void pkgUserTagSection::TrimRecord(bool /*BeforeRecord*/, const char* &End)/*{{{*/
751{
752 for (; Stop < End && (Stop[0] == '\n' || Stop[0] == '\r' || Stop[0] == '#'); Stop++)
753 if (Stop[0] == '#')
754 Stop = (const char*) memchr(Stop,'\n',End-Stop);
755}
756 /*}}}*/
757
758#include "tagfile-order.c"
759
760// TFRewrite - Rewrite a control record /*{{{*/
761// ---------------------------------------------------------------------
762/* This writes the control record to stdout rewriting it as necessary. The
763 override map item specificies the rewriting rules to follow. This also
764 takes the time to sort the feild list. */
765APT_IGNORE_DEPRECATED_PUSH
766bool TFRewrite(FILE *Output,pkgTagSection const &Tags,const char *Order[],
767 TFRewriteData *Rewrite)
768{
769 unsigned char Visited[256]; // Bit 1 is Order, Bit 2 is Rewrite
770 for (unsigned I = 0; I != 256; I++)
771 Visited[I] = 0;
772
773 // Set new tag up as necessary.
774 for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++)
775 {
776 if (Rewrite[J].NewTag == 0)
777 Rewrite[J].NewTag = Rewrite[J].Tag;
778 }
779
780 // Write all all of the tags, in order.
781 if (Order != NULL)
782 {
783 for (unsigned int I = 0; Order[I] != 0; I++)
784 {
785 bool Rewritten = false;
786
787 // See if this is a field that needs to be rewritten
788 for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++)
789 {
790 if (strcasecmp(Rewrite[J].Tag,Order[I]) == 0)
791 {
792 Visited[J] |= 2;
793 if (Rewrite[J].Rewrite != 0 && Rewrite[J].Rewrite[0] != 0)
794 {
795 if (isspace(Rewrite[J].Rewrite[0]))
796 fprintf(Output,"%s:%s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
797 else
798 fprintf(Output,"%s: %s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
799 }
800 Rewritten = true;
801 break;
802 }
803 }
804
805 // See if it is in the fragment
806 unsigned Pos;
807 if (Tags.Find(Order[I],Pos) == false)
808 continue;
809 Visited[Pos] |= 1;
810
811 if (Rewritten == true)
812 continue;
813
814 /* Write out this element, taking a moment to rewrite the tag
815 in case of changes of case. */
816 const char *Start;
817 const char *Stop;
818 Tags.Get(Start,Stop,Pos);
819
820 if (fputs(Order[I],Output) < 0)
821 return _error->Errno("fputs","IO Error to output");
822 Start += strlen(Order[I]);
823 if (fwrite(Start,Stop - Start,1,Output) != 1)
824 return _error->Errno("fwrite","IO Error to output");
825 if (Stop[-1] != '\n')
826 fprintf(Output,"\n");
827 }
828 }
829
830 // Now write all the old tags that were missed.
831 for (unsigned int I = 0; I != Tags.Count(); I++)
832 {
833 if ((Visited[I] & 1) == 1)
834 continue;
835
836 const char *Start;
837 const char *Stop;
838 Tags.Get(Start,Stop,I);
839 const char *End = Start;
840 for (; End < Stop && *End != ':'; End++);
841
842 // See if this is a field that needs to be rewritten
843 bool Rewritten = false;
844 for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++)
845 {
846 if (stringcasecmp(Start,End,Rewrite[J].Tag) == 0)
847 {
848 Visited[J] |= 2;
849 if (Rewrite[J].Rewrite != 0 && Rewrite[J].Rewrite[0] != 0)
850 {
851 if (isspace(Rewrite[J].Rewrite[0]))
852 fprintf(Output,"%s:%s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
853 else
854 fprintf(Output,"%s: %s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
855 }
856
857 Rewritten = true;
858 break;
859 }
860 }
861
862 if (Rewritten == true)
863 continue;
864
865 // Write out this element
866 if (fwrite(Start,Stop - Start,1,Output) != 1)
867 return _error->Errno("fwrite","IO Error to output");
868 if (Stop[-1] != '\n')
869 fprintf(Output,"\n");
870 }
871
872 // Now write all the rewrites that were missed
873 for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++)
874 {
875 if ((Visited[J] & 2) == 2)
876 continue;
877
878 if (Rewrite[J].Rewrite != 0 && Rewrite[J].Rewrite[0] != 0)
879 {
880 if (isspace(Rewrite[J].Rewrite[0]))
881 fprintf(Output,"%s:%s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
882 else
883 fprintf(Output,"%s: %s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
884 }
885 }
886
887 return true;
888}
889APT_IGNORE_DEPRECATED_POP
890 /*}}}*/
891
892pkgTagSection::~pkgTagSection() { delete d; }