summaryrefslogtreecommitdiff
path: root/apt-pkg
diff options
context:
space:
mode:
Diffstat (limited to 'apt-pkg')
-rw-r--r--apt-pkg/contrib/configuration.cc164
-rw-r--r--apt-pkg/contrib/strutl.cc44
-rw-r--r--apt-pkg/depcache.cc36
3 files changed, 185 insertions, 59 deletions
diff --git a/apt-pkg/contrib/configuration.cc b/apt-pkg/contrib/configuration.cc
index da57c2054..7326b84ea 100644
--- a/apt-pkg/contrib/configuration.cc
+++ b/apt-pkg/contrib/configuration.cc
@@ -495,8 +495,7 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional,
ifstream F(FName.c_str(),ios::in);
if (!F != 0)
return _error->Errno("ifstream::ifstream",_("Opening configuration file %s"),FName.c_str());
-
- char Buffer[1024];
+
string LineBuffer;
string Stack[100];
unsigned int StackPos = 0;
@@ -508,23 +507,63 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional,
bool InComment = false;
while (F.eof() == false)
{
- F.getline(Buffer,sizeof(Buffer));
+ // The raw input line.
+ std::string Input;
+ // The input line with comments stripped.
+ std::string Fragment;
+
+ // Grab the next line of F and place it in Input.
+ do
+ {
+ char *Buffer = new char[1024];
+
+ F.clear();
+ F.getline(Buffer,sizeof(Buffer) / 2);
+
+ Input += Buffer;
+ }
+ while (F.fail() && !F.eof());
+
+ // Expand tabs in the input line and remove leading and trailing
+ // whitespace.
+ {
+ const int BufferSize = Input.size() * 8 + 1;
+ char *Buffer = new char[BufferSize];
+ try
+ {
+ memcpy(Buffer, Input.c_str(), Input.size() + 1);
+
+ _strtabexpand(Buffer, BufferSize);
+ _strstrip(Buffer);
+ Input = Buffer;
+ }
+ catch(...)
+ {
+ delete[] Buffer;
+ throw;
+ }
+ delete[] Buffer;
+ }
CurLine++;
- // This should be made to work instead, but this is better than looping
- if (F.fail() && !F.eof())
- return _error->Error(_("Line %d too long (max %lu)"), CurLine, sizeof(Buffer));
- _strtabexpand(Buffer,sizeof(Buffer));
- _strstrip(Buffer);
+ // Now strip comments; if the whole line is contained in a
+ // comment, skip this line.
+
+ // The first meaningful character in the current fragment; will
+ // be adjusted below as we remove bytes from the front.
+ std::string::const_iterator Start = Input.begin();
+ // The last meaningful character in the current fragment.
+ std::string::const_iterator End = Input.end();
// Multi line comment
if (InComment == true)
{
- for (const char *I = Buffer; *I != 0; I++)
+ for (std::string::const_iterator I = Start;
+ I != End; ++I)
{
- if (*I == '*' && I[1] == '/')
+ if (*I == '*' && I + 1 != End && I[1] == '/')
{
- memmove(Buffer,I+2,strlen(I+2) + 1);
+ Start = I + 2;
InComment = false;
break;
}
@@ -535,57 +574,66 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional,
// Discard single line comments
bool InQuote = false;
- for (char *I = Buffer; *I != 0; I++)
+ for (std::string::const_iterator I = Start;
+ I != End; ++I)
{
if (*I == '"')
InQuote = !InQuote;
if (InQuote == true)
continue;
- if (*I == '/' && I[1] == '/')
+ if (*I == '/' && I + 1 != End && I[1] == '/')
{
- *I = 0;
+ End = I;
break;
}
}
- // Look for multi line comments
+ // Look for multi line comments and build up the
+ // fragment.
+ Fragment.reserve(End - Start);
InQuote = false;
- for (char *I = Buffer; *I != 0; I++)
+ for (std::string::const_iterator I = Start;
+ I != End; ++I)
{
if (*I == '"')
InQuote = !InQuote;
if (InQuote == true)
- continue;
-
- if (*I == '/' && I[1] == '*')
+ Fragment.push_back(*I);
+ else if (*I == '/' && I + 1 != End && I[1] == '*')
{
InComment = true;
- for (char *J = Buffer; *J != 0; J++)
+ for (std::string::const_iterator J = I;
+ J != End; ++J)
{
- if (*J == '*' && J[1] == '/')
+ if (*J == '*' && J + 1 != End && J[1] == '/')
{
- memmove(I,J+2,strlen(J+2) + 1);
+ // Pretend we just finished walking over the
+ // comment, and don't add anything to the output
+ // fragment.
+ I = J + 1;
InComment = false;
break;
}
}
if (InComment == true)
- {
- *I = 0;
- break;
- }
+ break;
}
+ else
+ Fragment.push_back(*I);
}
-
- // Blank
- if (Buffer[0] == 0)
+
+ // Skip blank lines.
+ if (Fragment.empty())
continue;
- // We now have a valid line fragment
+ // The line has actual content; interpret what it means.
InQuote = false;
- for (char *I = Buffer; *I != 0;)
+ Start = Fragment.begin();
+ End = Fragment.end();
+ for (std::string::const_iterator I = Start;
+ I != End; ++I)
{
if (*I == '"')
InQuote = !InQuote;
@@ -593,18 +641,21 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional,
if (InQuote == false && (*I == '{' || *I == ';' || *I == '}'))
{
// Put the last fragment into the buffer
- char *Start = Buffer;
- char *Stop = I;
- for (; Start != I && isspace(*Start) != 0; Start++);
- for (; Stop != Start && isspace(Stop[-1]) != 0; Stop--);
- if (LineBuffer.empty() == false && Stop - Start != 0)
+ std::string::const_iterator NonWhitespaceStart = Start;
+ std::string::const_iterator NonWhitespaceStop = I;
+ for (; NonWhitespaceStart != I && isspace(*NonWhitespaceStart) != 0; NonWhitespaceStart++)
+ ;
+ for (; NonWhitespaceStop != NonWhitespaceStart && isspace(NonWhitespaceStop[-1]) != 0; NonWhitespaceStop--)
+ ;
+ if (LineBuffer.empty() == false && NonWhitespaceStop - NonWhitespaceStart != 0)
LineBuffer += ' ';
- LineBuffer += string(Start,Stop - Start);
-
- // Remove the fragment
+ LineBuffer += string(NonWhitespaceStart, NonWhitespaceStop);
+
+ // Drop this from the input string, saving the character
+ // that terminated the construct we just closed. (i.e., a
+ // brace or a semicolon)
char TermChar = *I;
- memmove(Buffer,I + 1,strlen(I + 1) + 1);
- I = Buffer;
+ Start = I + 1;
// Syntax Error
if (TermChar == '{' && LineBuffer.empty() == true)
@@ -726,15 +777,32 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional,
}
}
- else
- I++;
}
- // Store the fragment
- const char *Stripd = _strstrip(Buffer);
- if (*Stripd != 0 && LineBuffer.empty() == false)
- LineBuffer += " ";
- LineBuffer += Stripd;
+ // Store the remaining text, if any, in the current line buffer.
+
+ // NB: could change this to use string-based operations; I'm
+ // using strstrip now to ensure backwards compatibility.
+ // -- dburrows 2008-04-01
+ {
+ char *Buffer = new char[End - Start + 1];
+ try
+ {
+ std::copy(Start, End, Buffer);
+ Buffer[End - Start] = '\0';
+
+ const char *Stripd = _strstrip(Buffer);
+ if (*Stripd != 0 && LineBuffer.empty() == false)
+ LineBuffer += " ";
+ LineBuffer += Stripd;
+ }
+ catch(...)
+ {
+ delete[] Buffer;
+ throw;
+ }
+ delete[] Buffer;
+ }
}
if (LineBuffer.empty() == false)
diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc
index a04c266ba..eacc7077a 100644
--- a/apt-pkg/contrib/strutl.cc
+++ b/apt-pkg/contrib/strutl.cc
@@ -658,11 +658,24 @@ string TimeRFC1123(time_t Date)
// ---------------------------------------------------------------------
/* This pulls full messages from the input FD into the message buffer.
It assumes that messages will not pause during transit so no
- fancy buffering is used. */
+ fancy buffering is used.
+
+ In particular: this reads blocks from the input until it believes
+ that it's run out of input text. Each block is terminated by a
+ double newline ('\n' followed by '\n'). As noted below, there is a
+ bug in this code: it assumes that all the blocks have been read if
+ it doesn't see additional text in the buffer after the last one is
+ parsed, which will cause it to lose blocks if the last block
+ coincides with the end of the buffer.
+ */
bool ReadMessages(int Fd, vector<string> &List)
{
char Buffer[64000];
char *End = Buffer;
+ // Represents any left-over from the previous iteration of the
+ // parse loop. (i.e., if a message is split across the end
+ // of the buffer, it goes here)
+ string PartialMessage;
while (1)
{
@@ -690,6 +703,7 @@ bool ReadMessages(int Fd, vector<string> &List)
// Pull the message out
string Message(Buffer,I-Buffer);
+ PartialMessage += Message;
// Fix up the buffer
for (; I < End && *I == '\n'; I++);
@@ -697,10 +711,32 @@ bool ReadMessages(int Fd, vector<string> &List)
memmove(Buffer,I,End-Buffer);
I = Buffer;
- List.push_back(Message);
+ List.push_back(PartialMessage);
+ PartialMessage.clear();
}
- if (End == Buffer)
- return true;
+ if (End != Buffer)
+ {
+ // If there's text left in the buffer, store it
+ // in PartialMessage and throw the rest of the buffer
+ // away. This allows us to handle messages that
+ // are longer than the static buffer size.
+ PartialMessage += string(Buffer, End);
+ End = Buffer;
+ }
+ else
+ {
+ // BUG ALERT: if a message block happens to end at a
+ // multiple of 64000 characters, this will cause it to
+ // terminate early, leading to a badly formed block and
+ // probably crashing the method. However, this is the only
+ // way we have to find the end of the message block. I have
+ // an idea of how to fix this, but it will require changes
+ // to the protocol (essentially to mark the beginning and
+ // end of the block).
+ //
+ // -- dburrows 2008-04-02
+ return true;
+ }
if (WaitFd(Fd) == false)
return false;
diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc
index c21872449..ee9f0da05 100644
--- a/apt-pkg/depcache.cc
+++ b/apt-pkg/depcache.cc
@@ -895,24 +895,41 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
if (IsImportantDep(Start) == false)
continue;
- /* check if any ImportantDep() (but not Critial) where added
- * since we installed the package
+ /* Check if any ImportantDep() (but not Critical) were added
+ * since we installed the package. Also check for deps that
+ * were satisfied in the past: for instance, if a version
+ * restriction in a Recommends was tightened, upgrading the
+ * package should follow that Recommends rather than causing the
+ * dependency to be removed. (bug #470115)
*/
bool isNewImportantDep = false;
+ bool isPreviouslySatisfiedImportantDep = false;
if(!ForceImportantDeps && !Start.IsCritical())
{
bool found=false;
VerIterator instVer = Pkg.CurrentVer();
if(!instVer.end())
{
- for (DepIterator D = instVer.DependsList(); D.end() != true; D++)
- {
+ for (DepIterator D = instVer.DependsList(); D.end() != true; D++)
+ {
//FIXME: deal better with or-groups(?)
DepIterator LocalStart = D;
if(IsImportantDep(D) && Start.TargetPkg() == D.TargetPkg())
- found=true;
- }
+ {
+ if(!isPreviouslySatisfiedImportantDep)
+ {
+ DepIterator D2 = D;
+ while((D2->CompareOp & Dep::Or) != 0)
+ ++D2;
+
+ isPreviouslySatisfiedImportantDep =
+ (((*this)[D2] & DepGNow) != 0);
+ }
+
+ found=true;
+ }
+ }
// this is a new dep if it was not found to be already
// a important dep of the installed pacakge
isNewImportantDep = !found;
@@ -922,10 +939,15 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
if(_config->FindB("Debug::pkgDepCache::AutoInstall",false) == true)
std::clog << "new important dependency: "
<< Start.TargetPkg().Name() << std::endl;
+ if(isPreviouslySatisfiedImportantDep)
+ if(_config->FindB("Debug::pkgDepCache::AutoInstall", false) == true)
+ std::clog << "previously satisfied important dependency on "
+ << Start.TargetPkg().Name() << std::endl;
// skip important deps if the package is already installed
if (Pkg->CurrentVer != 0 && Start.IsCritical() == false
- && !isNewImportantDep && !ForceImportantDeps)
+ && !isNewImportantDep && !isPreviouslySatisfiedImportantDep
+ && !ForceImportantDeps)
continue;
/* If we are in an or group locate the first or that can