]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/contrib/strutl.cc
merge with debian/experimental
[apt.git] / apt-pkg / contrib / strutl.cc
index c7d63ce8a58f069e55e05f920b5c003d9519f127..aaf44b7ff95fff6601300c06f6a1c0a4bc4b9ac5 100644 (file)
    ##################################################################### */
                                                                        /*}}}*/
 // Includes                                                            /*{{{*/
+#include <config.h>
+
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/error.h>
 
-#include <apti18n.h>
-    
 #include <ctype.h>
 #include <string.h>
 #include <stdio.h>
@@ -31,7 +31,7 @@
 #include <stdarg.h>
 #include <iconv.h>
 
-#include "config.h"
+#include <apti18n.h>
 
 using namespace std;
                                                                        /*}}}*/
@@ -271,7 +271,7 @@ bool ParseCWord(const char *&String,string &Res)
 string QuoteString(const string &Str, const char *Bad)
 {
    string Res;
-   for (string::const_iterator I = Str.begin(); I != Str.end(); I++)
+   for (string::const_iterator I = Str.begin(); I != Str.end(); ++I)
    {
       if (strchr(Bad,*I) != 0 || isprint(*I) == 0 || 
          *I == 0x25 || // percent '%' char
@@ -298,7 +298,7 @@ string DeQuoteString(string::const_iterator const &begin,
                        string::const_iterator const &end)
 {
    string Res;
-   for (string::const_iterator I = begin; I != end; I++)
+   for (string::const_iterator I = begin; I != end; ++I)
    {
       if (*I == '%' && I + 2 < end &&
          isxdigit(I[1]) && isxdigit(I[2]))
@@ -340,13 +340,13 @@ string SizeToStr(double Size)
    {
       if (ASize < 100 && I != 0)
       {
-         sprintf(S,"%'.1f%c",ASize,Ext[I]);
+         sprintf(S,"%'.1f %c",ASize,Ext[I]);
         break;
       }
       
       if (ASize < 10000)
       {
-         sprintf(S,"%'.0f%c",ASize,Ext[I]);
+         sprintf(S,"%'.0f %c",ASize,Ext[I]);
         break;
       }
       ASize /= 1000.0;
@@ -632,7 +632,7 @@ string LookupTag(const string &Message,const char *Tag,const char *Default)
 {
    // Look for a matching tag.
    int Length = strlen(Tag);
-   for (string::const_iterator I = Message.begin(); I + Length < Message.end(); I++)
+   for (string::const_iterator I = Message.begin(); I + Length < Message.end(); ++I)
    {
       // Found the tag
       if (I[Length] == ':' && stringcasecmp(I,I+Length,Tag) == 0)
@@ -640,14 +640,14 @@ string LookupTag(const string &Message,const char *Tag,const char *Default)
         // Find the end of line and strip the leading/trailing spaces
         string::const_iterator J;
         I += Length + 1;
-        for (; isspace(*I) != 0 && I < Message.end(); I++);
-        for (J = I; *J != '\n' && J < Message.end(); J++);
-        for (; J > I && isspace(J[-1]) != 0; J--);
+        for (; isspace(*I) != 0 && I < Message.end(); ++I);
+        for (J = I; *J != '\n' && J < Message.end(); ++J);
+        for (; J > I && isspace(J[-1]) != 0; --J);
         
         return string(I,J);
       }
       
-      for (; *I != '\n' && I < Message.end(); I++);
+      for (; *I != '\n' && I < Message.end(); ++I);
    }   
    
    // Failed to find a match
@@ -692,14 +692,16 @@ int StringToBool(const string &Text,int Default)
    year 2000 complient and timezone neutral */
 string TimeRFC1123(time_t Date)
 {
-   struct tm Conv = *gmtime(&Date);
-   char Buf[300];
+   struct tm Conv;
+   if (gmtime_r(&Date, &Conv) == NULL)
+      return "";
 
+   char Buf[300];
    const char *Day[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
    const char *Month[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul",
                           "Aug","Sep","Oct","Nov","Dec"};
 
-   sprintf(Buf,"%s, %02i %s %i %02i:%02i:%02i GMT",Day[Conv.tm_wday],
+   snprintf(Buf, sizeof(Buf), "%s, %02i %s %i %02i:%02i:%02i GMT",Day[Conv.tm_wday],
           Conv.tm_mday,Month[Conv.tm_mon],Conv.tm_year+1900,Conv.tm_hour,
           Conv.tm_min,Conv.tm_sec);
    return Buf;
@@ -827,34 +829,70 @@ static int MonthConv(char *Month)
    }   
 }
                                                                        /*}}}*/
-// timegm - Internal timegm function if gnu is not available           /*{{{*/
+// timegm - Internal timegm if the gnu version is not available                /*{{{*/
 // ---------------------------------------------------------------------
-/* Ripped this evil little function from wget - I prefer the use of 
-   GNU timegm if possible as this technique will have interesting problems
-   with leap seconds, timezones and other.
-   
-   Converts struct tm to time_t, assuming the data in tm is UTC rather
+/* Converts struct tm to time_t, assuming the data in tm is UTC rather
    than local timezone (mktime assumes the latter).
-   
-   Contributed by Roger Beeman <beeman@cisco.com>, with the help of
-   Mark Baushke <mdb@cisco.com> and the rest of the Gurus at CISCO. */
-
-/* Turned it into an autoconf check, because GNU is not the only thing which
-   can provide timegm. -- 2002-09-22, Joel Baker */
 
-#ifndef HAVE_TIMEGM // Now with autoconf!
+   This function is a nonstandard GNU extension that is also present on
+   the BSDs and maybe other systems. For others we follow the advice of
+   the manpage of timegm and use his portable replacement. */
+#ifndef HAVE_TIMEGM
 static time_t timegm(struct tm *t)
 {
-   time_t tl, tb;
-   
-   tl = mktime (t);
-   if (tl == -1)
-      return -1;
-   tb = mktime (gmtime (&tl));
-   return (tl <= tb ? (tl + (tl - tb)) : (tl - (tb - tl)));
+   char *tz = getenv("TZ");
+   setenv("TZ", "", 1);
+   tzset();
+   time_t ret = mktime(t);
+   if (tz)
+      setenv("TZ", tz, 1);
+   else
+      unsetenv("TZ");
+   tzset();
+   return ret;
 }
 #endif
                                                                        /*}}}*/
+// FullDateToTime - Converts a HTTP1.1 full date strings into a time_t /*{{{*/
+// ---------------------------------------------------------------------
+/* tries to parses a full date as specified in RFC2616 Section 3.3.1
+   with one exception: All timezones (%Z) are accepted but the protocol
+   says that it MUST be GMT, but this one is equal to UTC which we will
+   encounter from time to time (e.g. in Release files) so we accept all
+   here and just assume it is GMT (or UTC) later on */
+bool RFC1123StrToTime(const char* const str,time_t &time)
+{
+   struct tm Tm;
+   setlocale (LC_ALL,"C");
+   bool const invalid =
+   // Sun, 06 Nov 1994 08:49:37 GMT  ; RFC 822, updated by RFC 1123
+      (strptime(str, "%a, %d %b %Y %H:%M:%S %Z", &Tm) == NULL &&
+   // Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
+       strptime(str, "%A, %d-%b-%y %H:%M:%S %Z", &Tm) == NULL &&
+   // Sun Nov  6 08:49:37 1994       ; ANSI C's asctime() format
+       strptime(str, "%a %b %d %H:%M:%S %Y", &Tm) == NULL);
+   setlocale (LC_ALL,"");
+   if (invalid == true)
+      return false;
+
+   time = timegm(&Tm);
+   return true;
+}
+                                                                       /*}}}*/
+// FTPMDTMStrToTime - Converts a ftp modification date into a time_t   /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool FTPMDTMStrToTime(const char* const str,time_t &time)
+{
+   struct tm Tm;
+   // MDTM includes no whitespaces but recommend and ignored by strptime
+   if (strptime(str, "%Y %m %d %H %M %S", &Tm) == NULL)
+      return false;
+
+   time = timegm(&Tm);
+   return true;
+}
+                                                                       /*}}}*/
 // StrToTime - Converts a string into a time_t                         /*{{{*/
 // ---------------------------------------------------------------------
 /* This handles all 3 populare time formats including RFC 1123, RFC 1036
@@ -932,6 +970,51 @@ bool StrToNum(const char *Str,unsigned long &Res,unsigned Len,unsigned Base)
    return true;
 }
                                                                        /*}}}*/
+// StrToNum - Convert a fixed length string to a number                        /*{{{*/
+// ---------------------------------------------------------------------
+/* This is used in decoding the crazy fixed length string headers in 
+   tar and ar files. */
+bool StrToNum(const char *Str,unsigned long long &Res,unsigned Len,unsigned Base)
+{
+   char S[30];
+   if (Len >= sizeof(S))
+      return false;
+   memcpy(S,Str,Len);
+   S[Len] = 0;
+   
+   // All spaces is a zero
+   Res = 0;
+   unsigned I;
+   for (I = 0; S[I] == ' '; I++);
+   if (S[I] == 0)
+      return true;
+   
+   char *End;
+   Res = strtoull(S,&End,Base);
+   if (End == S)
+      return false;
+   
+   return true;
+}
+                                                                       /*}}}*/
+
+// Base256ToNum - Convert a fixed length binary to a number             /*{{{*/
+// ---------------------------------------------------------------------
+/* This is used in decoding the 256bit encoded fixed length fields in
+   tar files */
+bool Base256ToNum(const char *Str,unsigned long &Res,unsigned int Len)
+{
+   if ((Str[0] & 0x80) == 0)
+      return false;
+   else
+   {
+      Res = Str[0] & 0x7F;
+      for(unsigned int i = 1; i < Len; ++i)
+         Res = (Res<<8) + Str[i];
+      return true;
+   }
+}
+                                                                       /*}}}*/
 // HexDigit - Convert a hex character into an integer                  /*{{{*/
 // ---------------------------------------------------------------------
 /* Helper for Hex2Num */
@@ -1125,7 +1208,7 @@ void strprintf(string &out,const char *format,...)
 char *safe_snprintf(char *Buffer,char *End,const char *Format,...)
 {
    va_list args;
-   unsigned long Did;
+   int Did;
 
    va_start(args,Format);
 
@@ -1138,6 +1221,15 @@ char *safe_snprintf(char *Buffer,char *End,const char *Format,...)
    return Buffer + Did;
 }
                                                                        /*}}}*/
+// StripEpoch - Remove the version "epoch" from a version string       /*{{{*/
+// ---------------------------------------------------------------------
+string StripEpoch(const string &VerStr)
+{
+   size_t i = VerStr.find(":");
+   if (i == string::npos)
+      return VerStr;
+   return VerStr.substr(i+1);
+}
 
 // tolower_ascii - tolower() function that ignores the locale          /*{{{*/
 // ---------------------------------------------------------------------
@@ -1160,7 +1252,7 @@ int tolower_ascii(int const c)
 bool CheckDomainList(const string &Host,const string &List)
 {
    string::const_iterator Start = List.begin();
-   for (string::const_iterator Cur = List.begin(); Cur <= List.end(); Cur++)
+   for (string::const_iterator Cur = List.begin(); Cur <= List.end(); ++Cur)
    {
       if (Cur < List.end() && *Cur != ',')
         continue;
@@ -1176,7 +1268,68 @@ bool CheckDomainList(const string &Host,const string &List)
    return false;
 }
                                                                        /*}}}*/
+// DeEscapeString - unescape (\0XX and \xXX) from a string             /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string DeEscapeString(const string &input)
+{
+   char tmp[3];
+   string::const_iterator it, escape_start;
+   string output, octal, hex;
+   for (it = input.begin(); it != input.end(); ++it)
+   {
+      // just copy non-escape chars
+      if (*it != '\\')
+      {
+         output += *it;
+         continue;
+      }
 
+      // deal with double escape
+      if (*it == '\\' && 
+          (it + 1 < input.end()) &&  it[1] == '\\')
+      {
+         // copy
+         output += *it;
+         // advance iterator one step further
+         ++it;
+         continue;
+      }
+        
+      // ensure we have a char to read
+      if (it + 1 == input.end())
+         continue;
+
+      // read it
+      ++it;
+      switch (*it)
+      {
+         case '0':
+            if (it + 2 <= input.end()) {
+               tmp[0] = it[1];
+               tmp[1] = it[2];
+               tmp[2] = 0;
+               output += (char)strtol(tmp, 0, 8);
+               it += 2;
+            }
+            break;
+         case 'x':
+            if (it + 2 <= input.end()) {
+               tmp[0] = it[1];
+               tmp[1] = it[2];
+               tmp[2] = 0;
+               output += (char)strtol(tmp, 0, 16);
+               it += 2;
+            }
+            break;
+         default:
+            // FIXME: raise exception here?
+            break;
+      }
+   }
+   return output;
+}
+                                                                       /*}}}*/
 // URI::CopyFrom - Copy from an object                                 /*{{{*/
 // ---------------------------------------------------------------------
 /* This parses the URI into all of its components */
@@ -1185,7 +1338,7 @@ void URI::CopyFrom(const string &U)
    string::const_iterator I = U.begin();
 
    // Locate the first colon, this separates the scheme
-   for (; I < U.end() && *I != ':' ; I++);
+   for (; I < U.end() && *I != ':' ; ++I);
    string::const_iterator FirstColon = I;
 
    /* Determine if this is a host type URI with a leading double //
@@ -1197,7 +1350,7 @@ void URI::CopyFrom(const string &U)
    /* Find the / indicating the end of the hostname, ignoring /'s in the
       square brackets */
    bool InBracket = false;
-   for (; SingleSlash < U.end() && (*SingleSlash != '/' || InBracket == true); SingleSlash++)
+   for (; SingleSlash < U.end() && (*SingleSlash != '/' || InBracket == true); ++SingleSlash)
    {
       if (*SingleSlash == '[')
         InBracket = true;
@@ -1230,11 +1383,11 @@ void URI::CopyFrom(const string &U)
    I = FirstColon + 1;
    if (I > SingleSlash)
       I = SingleSlash;
-   for (; I < SingleSlash && *I != ':'; I++);
+   for (; I < SingleSlash && *I != ':'; ++I);
    string::const_iterator SecondColon = I;
    
    // Search for the @ after the colon
-   for (; I < SingleSlash && *I != '@'; I++);
+   for (; I < SingleSlash && *I != '@'; ++I);
    string::const_iterator At = I;
    
    // Now write the host and user/pass