]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/contrib/strutl.cc
More Fixes
[apt.git] / apt-pkg / contrib / strutl.cc
index b5086be04f5960276e74adb0d72e726c0ed83a86..9899694c668d670b9e6a54ca22182294be16ae69 100644 (file)
@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: strutl.cc,v 1.19 1999/02/01 08:11:57 jgg Exp $
+// $Id: strutl.cc,v 1.33 2000/01/14 06:26:37 jgg Exp $
 /* ######################################################################
 
    String Util - Some usefull string functions.
@@ -25,6 +25,8 @@
 #include <ctype.h>
 #include <string.h>
 #include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
                                                                        /*}}}*/
 
 // strstrip - Remove white space from the front and back of a string   /*{{{*/
@@ -95,7 +97,7 @@ bool ParseQuoteWord(const char *&String,string &Res)
       return false;
    
    // Jump to the next word
-   for (;*C != 0 && *C != ' '; C++)
+   for (;*C != 0 && isspace(*C) == 0; C++)
    {
       if (*C == '"')
       {
@@ -131,7 +133,7 @@ bool ParseQuoteWord(const char *&String,string &Res)
    Res = Buffer;
    
    // Skip ending white space
-   for (;*C != 0 && *C == ' '; C++);
+   for (;*C != 0 && isspace(*C) != 0; C++);
    String = C;
    return true;
 }
@@ -177,23 +179,20 @@ bool ParseCWord(const char *String,string &Res)
    return true;
 }
                                                                        /*}}}*/
-// DeQuoteString - Convert a string from quoted from                   /*{{{*/
+// QuoteString - Convert a string into quoted from                     /*{{{*/
 // ---------------------------------------------------------------------
-/* This undoes QuoteString */
-string DeQuoteString(string Str)
+/* */
+string QuoteString(string Str,const char *Bad)
 {
    string Res;
    for (string::iterator I = Str.begin(); I != Str.end(); I++)
    {
-      if (*I == '%' && I + 2 < Str.end())
+      if (strchr(Bad,*I) != 0 || isprint(*I) == 0 || 
+         *I <= 0x20 || *I >= 0x7F)
       {
-        char Tmp[3];
-        Tmp[0] = I[1];
-        Tmp[1] = I[2];
-        Tmp[2] = 0;
-        Res += (char)strtol(Tmp,0,16);
-        I += 2;
-        continue;
+        char Buf[10];
+        sprintf(Buf,"%%%02x",(int)*I);
+        Res += Buf;
       }
       else
         Res += *I;
@@ -201,27 +200,31 @@ string DeQuoteString(string Str)
    return Res;
 }
                                                                        /*}}}*/
-// QuoteString - Convert a string into quoted from                     /*{{{*/
+// DeQuoteString - Convert a string from quoted from                    /*{{{*/
 // ---------------------------------------------------------------------
-/* */
-string QuoteString(string Str,const char *Bad)
+/* This undoes QuoteString */
+string DeQuoteString(string Str)
 {
    string Res;
    for (string::iterator I = Str.begin(); I != Str.end(); I++)
    {
-      if (strchr(Bad,*I) != 0 || isprint(*I) == 0 || 
-         *I <= 0x20 || *I >= 0x7F)
+      if (*I == '%' && I + 2 < Str.end())
       {
-        char Buf[10];
-        sprintf(Buf,"%%%02x",(int)*I);
-        Res += Buf;
+        char Tmp[3];
+        Tmp[0] = I[1];
+        Tmp[1] = I[2];
+        Tmp[2] = 0;
+        Res += (char)strtol(Tmp,0,16);
+        I += 2;
+        continue;
       }
       else
         Res += *I;
    }
-   return Res;
+   return Res;   
 }
-                                                                       /*}}}*/
+
+                                                                        /*}}}*/
 // SizeToStr - Convert a long into a human readable size               /*{{{*/
 // ---------------------------------------------------------------------
 /* A max of 4 digits are shown before conversion to the next highest unit. 
@@ -323,11 +326,14 @@ string SubstVar(string Str,string Subst,string Contents)
    file name should be unique and never occur again for a different file */
 string URItoFileName(string URI)
 {
-   string::const_iterator I = URI.begin() + URI.find(':') + 1;
-   for (; I < URI.end() && *I == '/'; I++);
-
+   // Nuke 'sensitive' items
+   ::URI U(URI);
+   U.User = string();
+   U.Password = string();
+   U.Access = "";
+   
    // "\x00-\x20{}|\\\\^\\[\\]<>\"\x7F-\xFF";
-   URI = QuoteString(string(I,URI.end() - I),"\\|{}[]<>\"^~_=!@#$%^&*");
+   URI = QuoteString(U,"\\|{}[]<>\"^~_=!@#$%^&*");
    string::iterator J = URI.begin();
    for (; J != URI.end(); J++)
       if (*J == '/') 
@@ -527,6 +533,8 @@ bool ReadMessages(int Fd, vector<string> &List)
    while (1)
    {
       int Res = read(Fd,End,sizeof(Buffer) - (End-Buffer));
+      if (Res < 0 && errno == EINTR)
+        continue;
       
       // Process is dead, this is kind of bad..
       if (Res == 0)
@@ -596,12 +604,37 @@ static int MonthConv(char *Month)
    }   
 }
                                                                        /*}}}*/
+// timegm - Internal timegm function if gnu 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
+   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. */
+#ifndef __USE_MISC        // glib sets this
+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)));
+}
+#endif
+                                                                       /*}}}*/
 // StrToTime - Converts a string into a time_t                         /*{{{*/
 // ---------------------------------------------------------------------
 /* This handles all 3 populare time formats including RFC 1123, RFC 1036
    and the C library asctime format. It requires the GNU library function
    'timegm' to convert a struct tm in UTC to a time_t. For some bizzar
-   reason the C library does not provide any such function :<*/
+   reason the C library does not provide any such function :< This also
+   handles the weird, but unambiguous FTP time format*/
 bool StrToTime(string Val,time_t &Result)
 {
    struct tm Tm;
@@ -612,6 +645,7 @@ bool StrToTime(string Val,time_t &Result)
    for (;*I != 0  && *I != ' '; I++);
    
    // Handle RFC 1123 time
+   Month[0] = 0;
    if (sscanf(I," %d %3s %d %d:%d:%d GMT",&Tm.tm_mday,Month,&Tm.tm_year,
              &Tm.tm_hour,&Tm.tm_min,&Tm.tm_sec) != 6)
    {
@@ -624,12 +658,19 @@ bool StrToTime(string Val,time_t &Result)
         // asctime format
         if (sscanf(I," %3s %d %d:%d:%d %d",Month,&Tm.tm_mday,
                    &Tm.tm_hour,&Tm.tm_min,&Tm.tm_sec,&Tm.tm_year) != 6)
-           return false;
+        {
+           // 'ftp' time
+           if (sscanf(Val.c_str(),"%4d%2d%2d%2d%2d%2d",&Tm.tm_year,&Tm.tm_mon,
+                      &Tm.tm_mday,&Tm.tm_hour,&Tm.tm_min,&Tm.tm_sec) != 6)
+              return false;
+           Tm.tm_mon--;
+        }       
       }
    }
    
    Tm.tm_isdst = 0;
-   Tm.tm_mon = MonthConv(Month);
+   if (Month[0] != 0)
+      Tm.tm_mon = MonthConv(Month);
    Tm.tm_year -= 1900;
    
    // Convert to local time and then to GMT
@@ -637,6 +678,70 @@ bool StrToTime(string Val,time_t &Result)
    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 &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 = strtoul(S,&End,Base);
+   if (End == S)
+      return false;
+   
+   return true;
+}
+                                                                       /*}}}*/
+// HexDigit - Convert a hex character into an integer                  /*{{{*/
+// ---------------------------------------------------------------------
+/* Helper for Hex2Num */
+static int HexDigit(int c)
+{   
+   if (c >= '0' && c <= '9')
+      return c - '0';
+   if (c >= 'a' && c <= 'f')
+      return c - 'a' + 10;
+   if (c >= 'A' && c <= 'F')
+      return c - 'A' + 10;
+   return 0;
+}
+                                                                       /*}}}*/
+// Hex2Num - Convert a long hex number into a buffer                   /*{{{*/
+// ---------------------------------------------------------------------
+/* The length of the buffer must be exactly 1/2 the length of the string. */
+bool Hex2Num(const char *Start,const char *End,unsigned char *Num,
+            unsigned int Length)
+{
+   if (End - Start != (signed)(Length*2))
+      return false;
+   
+   // Convert each digit. We store it in the same order as the string
+   int J = 0;
+   for (const char *I = Start; I < End;J++, I += 2)
+   {
+      if (isxdigit(*I) == 0 || isxdigit(I[1]) == 0)
+        return false;
+      
+      Num[J] = HexDigit(I[0]) << 4;
+      Num[J] += HexDigit(I[1]);
+   }
+   
+   return true;
+}
+                                                                       /*}}}*/
 
 // URI::CopyFrom - Copy from an object                                 /*{{{*/
 // ---------------------------------------------------------------------
@@ -654,7 +759,18 @@ void URI::CopyFrom(string U)
    string::const_iterator SingleSlash = I;
    if (I + 3 < U.end() && I[1] == '/' && I[2] == '/')
       SingleSlash += 3;
-   for (; SingleSlash < U.end() && *SingleSlash != '/'; SingleSlash++);
+   
+   /* 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++)
+   {
+      if (*SingleSlash == '[')
+        InBracket = true;
+      if (InBracket == true && *SingleSlash == ']')
+        InBracket = false;
+   }
+   
    if (SingleSlash > U.end())
       SingleSlash = U.end();
 
@@ -676,16 +792,17 @@ void URI::CopyFrom(string U)
    if (FirstColon > SingleSlash)
       FirstColon = SingleSlash;
    
-   // Search for the @
-   I = FirstColon;
+   // Find the colon...
+   I = FirstColon + 1;
+   if (I > SingleSlash)
+      I = SingleSlash;
+   for (; I < SingleSlash && *I != ':'; I++);
+   string::const_iterator SecondColon = I;
+   
+   // Search for the @ after the colon
    for (; I < SingleSlash && *I != '@'; I++);
    string::const_iterator At = I;
    
-   // Colon in the @ section
-   I = FirstColon + 1;
-   for (; I < At && *I != ':'; I++);
-   string::const_iterator SecondColon = I;
-      
    // Now write the host and user/pass
    if (At == SingleSlash)
    {
@@ -700,10 +817,39 @@ void URI::CopyFrom(string U)
         Password = string(U,SecondColon - U.begin() + 1,At - SecondColon - 1);
    }   
    
-   // Now we parse off a pot number from the hostname
+   // Now we parse the RFC 2732 [] hostnames.
+   unsigned long PortEnd = 0;
+   InBracket = false;
+   for (unsigned I = 0; I != Host.length();)
+   {
+      if (Host[I] == '[')
+      {
+        InBracket = true;
+        Host.erase(I,1);
+        continue;
+      }
+      
+      if (InBracket == true && Host[I] == ']')
+      {
+        InBracket = false;
+        Host.erase(I,1);
+        PortEnd = I;
+        continue;
+      }
+      I++;
+   }
+   
+   // Tsk, weird.
+   if (InBracket == true)
+   {
+      Host = string();
+      return;
+   }
+   
+   // Now we parse off a port number from the hostname
    Port = 0;
    string::size_type Pos = Host.rfind(':');
-   if (Pos == string::npos)
+   if (Pos == string::npos || Pos < PortEnd)
       return;
    
    Port = atoi(string(Host,Pos+1).c_str());
@@ -715,17 +861,24 @@ void URI::CopyFrom(string U)
 /* */
 URI::operator string()
 {
-   string Res = Access + ':';
+   string Res;
+   
+   if (Access.empty() == false)
+      Res = Access + ':';
+   
    if (Host.empty() == false)
    {
-      Res += "//";
+      if (Access.empty() == false)
+        Res += "//";
+      
       if (User.empty() == false)
       {
-        Res += "//" + User;
+        Res +=  User;
         if (Password.empty() == false)
            Res += ":" + Password;
         Res += "@";
       }
+      
       Res += Host;
       if (Port != 0)
       {