]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/contrib/strutl.cc
Sync
[apt.git] / apt-pkg / contrib / strutl.cc
index 8c1f7005cf76533a3d7bf414b5a8f2d85292b7cd..d6a7143e45cd1c47794cc3f53cce1791d574c171 100644 (file)
@@ -1,22 +1,27 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: strutl.cc,v 1.2 1998/07/16 06:08:41 jgg Exp $
+// $Id: strutl.cc,v 1.9 1998/10/30 07:53:45 jgg Exp $
 /* ######################################################################
 
    String Util - Some usefull string functions.
 
-   strstrip - Remove whitespace from the front and end of a line.
+   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
+   especially in APT methods.   
    
    This source is placed in the Public Domain, do with it what you will
-   It was originally written by Jason Gunthorpe <jgg@gpu.srv.ualberta.ca>   
+   It was originally written by Jason Gunthorpe <jgg@gpu.srv.ualberta.ca>
    
    ##################################################################### */
                                                                        /*}}}*/
 // Includes                                                            /*{{{*/
 #include <strutl.h>
+#include <apt-pkg/fileutl.h>
+
 #include <ctype.h>
 #include <string.h>
 #include <stdio.h>
+#include <time.h>
                                                                        /*}}}*/
 
 // strstrip - Remove white space from the front and back of a string   /*{{{*/
@@ -77,7 +82,7 @@ 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
-   and striped out as well. */
+   and striped out as well. This is for URI/URL parsing. */
 bool ParseQuoteWord(const char *&String,string &Res)
 {
    // Skip leading whitespace
@@ -128,6 +133,47 @@ bool ParseQuoteWord(const char *&String,string &Res)
    return true;
 }
                                                                        /*}}}*/
+// ParseCWord - Parses a string like a C "" expression                 /*{{{*/
+// ---------------------------------------------------------------------
+/* This expects a series of space seperated strings enclosed in ""'s. 
+   It concatenates the ""'s into a single string. */
+bool ParseCWord(const char *String,string &Res)
+{
+   // Skip leading whitespace
+   const char *C = String;
+   for (;*C != 0 && *C == ' '; C++);
+   if (*C == 0)
+      return false;
+   
+   char Buffer[1024];
+   char *Buf = Buffer;
+   if (strlen(String) >= sizeof(Buffer))
+       return false;
+       
+   for (; *C != 0; C++)
+   {
+      if (*C == '"')
+      {
+        for (C++; *C != 0 && *C != '"'; C++)
+           *Buf++ = *C;
+        
+        if (*C == 0)
+           return false;
+        
+        continue;
+      }      
+      
+      if (C != String && isspace(*C) != 0 && isspace(C[-1]) != 0)
+        continue;
+      if (isspace(*C) == 0)
+        return false;
+      *Buf++ = ' ';
+   }   
+   *Buf = 0;
+   Res = Buffer;
+   return true;
+}
+                                                                       /*}}}*/
 // QuoteString - Convert a string into quoted from                     /*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -151,8 +197,8 @@ string QuoteString(string Str,const char *Bad)
                                                                        /*}}}*/
 // SizeToStr - Convert a long into a human readable size               /*{{{*/
 // ---------------------------------------------------------------------
-/* A max of 4 digits are shown before conversion to the next highest unit. The
-   max length of the string will be 5 chars unless the size is > 10 
+/* A max of 4 digits are shown before conversion to the next highest unit. 
+   The max length of the string will be 5 chars unless the size is > 10
    YottaBytes (E24) */
 string SizeToStr(double Size)
 {
@@ -243,6 +289,25 @@ string SubstVar(string Str,string Subst,string Contents)
    return Temp + string(Str,OldPos);
 }
                                                                        /*}}}*/
+// URItoFileName - Convert the uri into a unique file name             /*{{{*/
+// ---------------------------------------------------------------------
+/* This converts a URI into a safe filename. It quotes all unsafe characters
+   and converts / to _ and removes the scheme identifier. The resulting
+   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++);
+
+   // "\x00-\x20{}|\\\\^\\[\\]<>\"\x7F-\xFF";
+   URI = QuoteString(string(I,URI.end() - I),"\\|{}[]<>\"^~_=!@#$%^&*");
+   string::iterator J = URI.begin();
+   for (; J != URI.end(); J++)
+      if (*J == '/') 
+        *J = '_';
+   return URI;
+}
+                                                                       /*}}}*/
 // Base64Encode - Base64 Encoding routine for short strings            /*{{{*/
 // ---------------------------------------------------------------------
 /* This routine performs a base64 transformation on a string. It was ripped
@@ -329,7 +394,7 @@ int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd)
    for (; A != AEnd && B != BEnd; A++, B++)
       if (toupper(*A) != toupper(*B))
         break;
-   
+
    if (A == AEnd && B == BEnd)
       return 0;
    if (A == AEnd)
@@ -341,3 +406,306 @@ int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd)
    return 1;
 }
                                                                        /*}}}*/
+// LookupTag - Lookup the value of a tag in a taged string             /*{{{*/
+// ---------------------------------------------------------------------
+/* The format is like those used in package files and the method 
+   communication system */
+string LookupTag(string Message,const char *Tag,const char *Default)
+{
+   // Look for a matching tag.
+   int Length = strlen(Tag);
+   for (string::iterator I = Message.begin(); I + Length < Message.end(); I++)
+   {
+      // Found the tag
+      if (I[Length] == ':' && stringcasecmp(I,I+Length,Tag) == 0)
+      {
+        // Find the end of line and strip the leading/trailing spaces
+        string::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--);
+        
+        return string(I,J-I);
+      }
+      
+      for (; *I != '\n' && I < Message.end(); I++);
+   }   
+   
+   // Failed to find a match
+   if (Default == 0)
+      return string();
+   return Default;
+}
+                                                                       /*}}}*/
+// StringToBool - Converts a string into a boolean                     /*{{{*/
+// ---------------------------------------------------------------------
+/* This inspects the string to see if it is true or if it is false and
+   then returns the result. Several varients on true/false are checked. */
+int StringToBool(string Text,int Default = -1)
+{
+   char *End;
+   int Res = strtol(Text.c_str(),&End,0);   
+   if (End != Text.c_str() && Res >= 0 && Res <= 1)
+      return Res;
+   
+   // Check for positives
+   if (strcasecmp(Text.c_str(),"no") == 0 ||
+       strcasecmp(Text.c_str(),"false") == 0 ||
+       strcasecmp(Text.c_str(),"without") == 0 ||
+       strcasecmp(Text.c_str(),"disable") == 0)
+      return 0;
+   
+   // Check for negatives
+   if (strcasecmp(Text.c_str(),"yes") == 0 ||
+       strcasecmp(Text.c_str(),"true") == 0 ||
+       strcasecmp(Text.c_str(),"with") == 0 ||
+       strcasecmp(Text.c_str(),"enable") == 0)
+      return 1;
+   
+   return Default;
+}
+                                                                       /*}}}*/
+// TimeRFC1123 - Convert a time_t into RFC1123 format                  /*{{{*/
+// ---------------------------------------------------------------------
+/* This converts a time_t into a string time representation that is
+   year 2000 complient and timezone neutral */
+string TimeRFC1123(time_t Date)
+{
+   struct tm Conv = *gmtime(&Date);
+   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],
+          Conv.tm_mday,Month[Conv.tm_mon],Conv.tm_year+1900,Conv.tm_hour,
+          Conv.tm_min,Conv.tm_sec);
+   return Buf;
+}
+                                                                       /*}}}*/
+// ReadMessages - Read messages from the FD                            /*{{{*/
+// ---------------------------------------------------------------------
+/* 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. */
+bool ReadMessages(int Fd, vector<string> &List)
+{
+   char Buffer[4000];
+   char *End = Buffer;
+   
+   while (1)
+   {
+      int Res = read(Fd,End,sizeof(Buffer) - (End-Buffer));
+      
+      // Process is dead, this is kind of bad..
+      if (Res == 0)
+        return false;
+      
+      // No data
+      if (Res <= 0)
+        return true;
+
+      End += Res;
+      
+      // Look for the end of the message
+      for (char *I = Buffer; I + 1 < End; I++)
+      {
+        if (I[0] != '\n' || I[1] != '\n')
+           continue;
+        
+        // Pull the message out
+        string Message(Buffer,0,I-Buffer);
+
+        // Fix up the buffer
+        for (; I < End && *I == '\n'; I++);
+        End -= I-Buffer;        
+        memmove(Buffer,I,End-Buffer);
+        I = Buffer;
+        
+        List.push_back(Message);
+      }
+      if (End == Buffer)
+        return true;
+
+      if (WaitFd(Fd) == false)
+        return false;
+   }   
+}
+                                                                       /*}}}*/
+// MonthConv - Converts a month string into a number                   /*{{{*/
+// ---------------------------------------------------------------------
+/* This was lifted from the boa webserver which lifted it from 'wn-v1.07'
+   Made it a bit more robust with a few touppers though. */
+static int MonthConv(char *Month)
+{
+   switch (toupper(*Month)) 
+   {
+      case 'A':
+      return toupper(Month[1]) == 'P'?3:7;
+      case 'D':
+      return 11;
+      case 'F':
+      return 1;
+      case 'J':
+      if (toupper(Month[1]) == 'A')
+        return 0;
+      return toupper(Month[2]) == 'N'?5:6;
+      case 'M':
+      return toupper(Month[2]) == 'R'?2:4;
+      case 'N':
+      return 10;
+      case 'O':
+      return 9;
+      case 'S':
+      return 8;
+
+      // Pretend it is January..
+      default:
+      return 0;
+   }   
+}
+                                                                       /*}}}*/
+// 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 :<*/
+bool StrToTime(string Val,time_t &Result)
+{
+   struct tm Tm;
+   char Month[10];
+   const char *I = Val.c_str();
+   
+   // Skip the day of the week
+   for (;*I != 0  && *I != ' '; I++);
+   
+   // Handle RFC 1123 time
+   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)
+   {
+      // Handle RFC 1036 time
+      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)
+        Tm.tm_year += 1900;
+      else
+      {
+        // 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;
+      }
+   }
+   
+   Tm.tm_isdst = 0;
+   Tm.tm_mon = MonthConv(Month);
+   Tm.tm_year -= 1900;
+   
+   // Convert to local time and then to GMT
+   Result = timegm(&Tm);
+   return true;
+}
+                                                                       /*}}}*/
+
+// URI::URI - Constructor                                              /*{{{*/
+// ---------------------------------------------------------------------
+/* This parses the URI into all of its components */
+URI::URI(string U)
+{
+   string::const_iterator I = U.begin();
+
+   // Locate the first colon, this seperates the scheme
+   for (; I < U.end() && *I != ':' ; I++);
+   string::const_iterator FirstColon = I;
+
+   // Determine if this is a host type URI with a leading double //
+   string::const_iterator SingleSlash = I;
+   if (I + 3 < U.end() && I[1] == '/' && I[2] == '/')
+   {
+      // Locate the single / that starts the path
+      for (; I < U.end(); I++)
+      {
+        if (*I == '/' && I[1] == '/')
+           I += 2;
+        else 
+           if (*I == '/')
+              break;
+      }
+      if (I > U.end())
+        I = U.end();
+      SingleSlash = I;      
+   }
+
+   // We can now write the access and path specifiers
+   Access = string(U,0,FirstColon - U.begin());
+   if (SingleSlash != U.end())
+      Path = string(U,SingleSlash - U.begin() + 1);
+   
+   // Now we attempt to locate a user:pass@host fragment
+   FirstColon += 3;
+   if (FirstColon >= U.end())
+      return;
+   
+   if (FirstColon > SingleSlash)
+      FirstColon = SingleSlash;
+   
+   // Search for the @
+   I = FirstColon;
+   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)
+   {
+      if (FirstColon < SingleSlash)
+        Host = string(U,FirstColon - U.begin(),SingleSlash - FirstColon);
+   }
+   else
+   {
+      Host = string(U,At - U.begin() + 1,SingleSlash - At - 1);
+      User = string(U,FirstColon - U.begin(),SecondColon - FirstColon);
+      if (SecondColon < At)
+        Password = string(U,SecondColon - U.begin() + 1,At - SecondColon - 1);
+   }   
+   
+   // Now we parse off a pot number from the hostname
+   Port = 0;
+   string::size_type Pos = Host.rfind(':');
+   if (Pos == string::npos)
+      return;
+   
+   Port = atoi(string(Host,Pos+1).c_str());
+   Host = string(Host,0,Pos);
+}
+                                                                       /*}}}*/
+// URI::operator string - Convert the URI to a string                  /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+URI::operator string()
+{
+   string Res = Access + ':';
+   if (Host.empty() == false)
+   {
+      if (User.empty() == false)
+      {
+        Res += "//" + User;
+        if (Password.empty() == false)
+           Res += ":" + Password;
+        Res += "@";
+      }
+      Res += Host;
+   }
+   
+   if (Path.empty() == false)
+      Res += "/" + Path;
+   
+   return Res;
+}
+                                                                       /*}}}*/