]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/contrib/strutl.cc
Join with aliencode
[apt.git] / apt-pkg / contrib / strutl.cc
index fb5f6683c96e1a817aba5d7f6c37acf84408d6b1..c1a1cb4dbdd24a2514a391207a8d539db4f78102 100644 (file)
@@ -1,12 +1,12 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: strutl.cc,v 1.27 1999/07/26 17:46:08 jgg Exp $
+// $Id: strutl.cc,v 1.35 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
 
 /* ######################################################################
 
-   String Util - Some usefull string functions.
+   String Util - Some useful string functions.
 
 
-   These have been collected from here and there to do all sorts of usefull
-   things to strings. They are usefull in file parsers, URI handlers and
+   These have been collected from here and there to do all sorts of useful
+   things to strings. They are useful in file parsers, URI handlers and
    especially in APT methods.   
    
    This source is placed in the Public Domain, do with it what you will
    especially in APT methods.   
    
    This source is placed in the Public Domain, do with it what you will
 
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/fileutl.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>
 #include <unistd.h>
 #include <ctype.h>
 #include <string.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <regex.h>
 #include <errno.h>
 #include <errno.h>
+#include <stdarg.h>
                                                                        /*}}}*/
 
 // strstrip - Remove white space from the front and back of a string   /*{{{*/
                                                                        /*}}}*/
 
 // strstrip - Remove white space from the front and back of a string   /*{{{*/
@@ -87,7 +92,8 @@ char *_strtabexpand(char *String,size_t Len)
 // ---------------------------------------------------------------------
 /* This grabs a single word, converts any % escaped characters to their
    proper values and advances the pointer. Double quotes are understood
 // ---------------------------------------------------------------------
 /* This grabs a single word, converts any % escaped characters to their
    proper values and advances the pointer. Double quotes are understood
-   and striped out as well. This is for URI/URL parsing. */
+   and striped out as well. This is for URI/URL parsing. It also can 
+   understand [] brackets.*/
 bool ParseQuoteWord(const char *&String,string &Res)
 {
    // Skip leading whitespace
 bool ParseQuoteWord(const char *&String,string &Res)
 {
    // Skip leading whitespace
@@ -101,7 +107,13 @@ bool ParseQuoteWord(const char *&String,string &Res)
    {
       if (*C == '"')
       {
    {
       if (*C == '"')
       {
-        for (C++;*C != 0 && *C != '"'; C++);
+        for (C++; *C != 0 && *C != '"'; C++);
+        if (*C == 0)
+           return false;
+      }
+      if (*C == '[')
+      {
+        for (C++; *C != 0 && *C != ']'; C++);
         if (*C == 0)
            return false;
       }
         if (*C == 0)
            return false;
       }
@@ -140,9 +152,9 @@ bool ParseQuoteWord(const char *&String,string &Res)
                                                                        /*}}}*/
 // ParseCWord - Parses a string like a C "" expression                 /*{{{*/
 // ---------------------------------------------------------------------
                                                                        /*}}}*/
 // ParseCWord - Parses a string like a C "" expression                 /*{{{*/
 // ---------------------------------------------------------------------
-/* This expects a series of space seperated strings enclosed in ""'s. 
+/* This expects a series of space separated strings enclosed in ""'s. 
    It concatenates the ""'s into a single string. */
    It concatenates the ""'s into a single string. */
-bool ParseCWord(const char *String,string &Res)
+bool ParseCWord(const char *&String,string &Res)
 {
    // Skip leading whitespace
    const char *C = String;
 {
    // Skip leading whitespace
    const char *C = String;
@@ -173,9 +185,10 @@ bool ParseCWord(const char *String,string &Res)
       if (isspace(*C) == 0)
         return false;
       *Buf++ = ' ';
       if (isspace(*C) == 0)
         return false;
       *Buf++ = ' ';
-   }   
+   }
    *Buf = 0;
    Res = Buffer;
    *Buf = 0;
    Res = Buffer;
+   String = C;
    return true;
 }
                                                                        /*}}}*/
    return true;
 }
                                                                        /*}}}*/
@@ -318,6 +331,13 @@ string SubstVar(string Str,string Subst,string Contents)
    
    return Temp + string(Str,OldPos);
 }
    
    return Temp + string(Str,OldPos);
 }
+
+string SubstVar(string Str,const struct SubstVar *Vars)
+{
+   for (; Vars->Subst != 0; Vars++)
+      Str = SubstVar(Str,Vars->Subst,*Vars->Contents);
+   return Str;
+}
                                                                        /*}}}*/
 // URItoFileName - Convert the uri into a unique file name             /*{{{*/
 // ---------------------------------------------------------------------
                                                                        /*}}}*/
 // URItoFileName - Convert the uri into a unique file name             /*{{{*/
 // ---------------------------------------------------------------------
@@ -326,11 +346,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)
 {
    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";
    // "\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 == '/') 
    string::iterator J = URI.begin();
    for (; J != URI.end(); J++)
       if (*J == '/') 
@@ -538,9 +561,11 @@ bool ReadMessages(int Fd, vector<string> &List)
         return false;
       
       // No data
         return false;
       
       // No data
-      if (Res <= 0)
+      if (Res < 0 && errno == EAGAIN)
         return true;
         return true;
-
+      if (Res < 0)
+        return false;
+                             
       End += Res;
       
       // Look for the end of the message
       End += Res;
       
       // Look for the end of the message
@@ -630,7 +655,8 @@ static time_t timegm(struct tm *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
 /* 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;
 bool StrToTime(string Val,time_t &Result)
 {
    struct tm Tm;
@@ -641,6 +667,7 @@ bool StrToTime(string Val,time_t &Result)
    for (;*I != 0  && *I != ' '; I++);
    
    // Handle RFC 1123 time
    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)
    {
    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)
    {
@@ -653,12 +680,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)
         // 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_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
    Tm.tm_year -= 1900;
    
    // Convert to local time and then to GMT
@@ -693,6 +727,158 @@ bool StrToNum(const char *Str,unsigned long &Res,unsigned Len,unsigned Base)
    return true;
 }
                                                                        /*}}}*/
    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;
+}
+                                                                       /*}}}*/
+// TokSplitString - Split a string up by a given token                 /*{{{*/
+// ---------------------------------------------------------------------
+/* This is intended to be a faster splitter, it does not use dynamic
+   memories. Input is changed to insert nulls at each token location. */
+bool TokSplitString(char Tok,char *Input,char **List,
+                   unsigned long ListMax)
+{
+   // Strip any leading spaces
+   char *Start = Input;
+   char *Stop = Start + strlen(Start);
+   for (; *Start != 0 && isspace(*Start) != 0; Start++);
+
+   unsigned long Count = 0;
+   char *Pos = Start;
+   while (Pos != Stop)
+   {
+      // Skip to the next Token
+      for (; Pos != Stop && *Pos != Tok; Pos++);
+      
+      // Back remove spaces
+      char *End = Pos;
+      for (; End > Start && (End[-1] == Tok || isspace(End[-1]) != 0); End--);
+      *End = 0;
+      
+      List[Count++] = Start;
+      if (Count >= ListMax)
+      {
+        List[Count-1] = 0;
+        return false;
+      }
+      
+      // Advance pos
+      for (; Pos != Stop && (*Pos == Tok || isspace(*Pos) != 0 || *Pos == 0); Pos++);
+      Start = Pos;
+   }
+   
+   List[Count] = 0;
+   return true;
+}
+                                                                       /*}}}*/
+// RegexChoice - Simple regex list/list matcher                                /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+unsigned long RegexChoice(RxChoiceList *Rxs,const char **ListBegin,
+                     const char **ListEnd)
+{
+   for (RxChoiceList *R = Rxs; R->Str != 0; R++)
+      R->Hit = false;
+
+   unsigned long Hits = 0;
+   for (; ListBegin != ListEnd; ListBegin++)
+   {
+      // Check if the name is a regex
+      const char *I;
+      bool Regex = true;
+      for (I = *ListBegin; *I != 0; I++)
+        if (*I == '.' || *I == '?' || *I == '*' || *I == '|')
+           break;
+      if (*I == 0)
+        Regex = false;
+        
+      // Compile the regex pattern
+      regex_t Pattern;
+      if (Regex == true)
+        if (regcomp(&Pattern,*ListBegin,REG_EXTENDED | REG_ICASE |
+                    REG_NOSUB) != 0)
+           Regex = false;
+        
+      // Search the list
+      bool Done = false;
+      for (RxChoiceList *R = Rxs; R->Str != 0; R++)
+      {
+        if (R->Str[0] == 0)
+           continue;
+        
+        if (strcasecmp(R->Str,*ListBegin) != 0)
+        {
+           if (Regex == false)
+              continue;
+           if (regexec(&Pattern,R->Str,0,0,0) != 0)
+              continue;
+        }
+        Done = true;
+        
+        if (R->Hit == false)
+           Hits++;
+        
+        R->Hit = true;
+      }
+      
+      if (Regex == true)
+        regfree(&Pattern);
+      
+      if (Done == false)
+        _error->Warning(_("Selection %s not found"),*ListBegin);
+   }
+   
+   return Hits;
+}
+                                                                       /*}}}*/
+// ioprintf - C format string outputter to C++ iostreams               /*{{{*/
+// ---------------------------------------------------------------------
+/* This is used to make the internationalization strinc easier to translate
+ and to allow reordering of parameters */
+void ioprintf(ostream &out,const char *format,...) 
+{
+   va_list args;
+   va_start(args,format);
+   
+   // sprintf the description
+   char S[400];
+   vsnprintf(S,sizeof(S),format,args);
+   out << S;
+}
+                                                                       /*}}}*/
 
 // URI::CopyFrom - Copy from an object                                 /*{{{*/
 // ---------------------------------------------------------------------
 
 // URI::CopyFrom - Copy from an object                                 /*{{{*/
 // ---------------------------------------------------------------------
@@ -701,7 +887,7 @@ void URI::CopyFrom(string U)
 {
    string::const_iterator I = U.begin();
 
 {
    string::const_iterator I = U.begin();
 
-   // Locate the first colon, this seperates the scheme
+   // Locate the first colon, this separates the scheme
    for (; I < U.end() && *I != ':' ; I++);
    string::const_iterator FirstColon = I;
 
    for (; I < U.end() && *I != ':' ; I++);
    string::const_iterator FirstColon = I;
 
@@ -710,7 +896,18 @@ void URI::CopyFrom(string U)
    string::const_iterator SingleSlash = I;
    if (I + 3 < U.end() && I[1] == '/' && I[2] == '/')
       SingleSlash += 3;
    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();
 
    if (SingleSlash > U.end())
       SingleSlash = U.end();
 
@@ -757,10 +954,39 @@ void URI::CopyFrom(string U)
         Password = string(U,SecondColon - U.begin() + 1,At - SecondColon - 1);
    }   
    
         Password = string(U,SecondColon - U.begin() + 1,At - SecondColon - 1);
    }   
    
+   // 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(':');
    // 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());
       return;
    
    Port = atoi(string(Host,Pos+1).c_str());
@@ -772,18 +998,31 @@ void URI::CopyFrom(string U)
 /* */
 URI::operator string()
 {
 /* */
 URI::operator string()
 {
-   string Res = Access + ':';
+   string Res;
+   
+   if (Access.empty() == false)
+      Res = Access + ':';
+   
    if (Host.empty() == false)
    if (Host.empty() == false)
-   {
-      Res += "//";
+   {    
+      if (Access.empty() == false)
+        Res += "//";
+          
       if (User.empty() == false)
       {
       if (User.empty() == false)
       {
-        Res += "//" + User;
+        Res +=  User;
         if (Password.empty() == false)
            Res += ":" + Password;
         Res += "@";
       }
         if (Password.empty() == false)
            Res += ":" + Password;
         Res += "@";
       }
-      Res += Host;
+      
+      // Add RFC 2732 escaping characters
+      if (Access.empty() == false &&
+         (Host.find('/') != string::npos || Host.find(':') != string::npos))
+        Res += '[' + Host + ']';
+      else
+        Res += Host;
+      
       if (Port != 0)
       {
         char S[30];
       if (Port != 0)
       {
         char S[30];
@@ -803,3 +1042,16 @@ URI::operator string()
    return Res;
 }
                                                                        /*}}}*/
    return Res;
 }
                                                                        /*}}}*/
+// URI::SiteOnly - Return the schema and site for the URI              /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string URI::SiteOnly(string URI)
+{
+   ::URI U(URI);
+   U.User = string();
+   U.Password = string();
+   U.Path = string();
+   U.Port = 0;
+   return U;
+}
+                                                                       /*}}}*/