[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#319377: libapt-pkg: patches for speedup



Package: apt
Version: 0.6.38
Tags: patch
Severity: wishlist

Hi,

I profiled aptitude a bit and found out that most of its slowness(*)
is due to apt (which shouldn't be that much of a surprise, aptitude
being mostly only a frontend for apt). Here's a patch that speeds up
some things quite a bit, especially with some optimizations to
aptitude too (which I will submit separately soon).

Not all of the optimizations are that elegant, but in those cases they
are really in some quite critical pieces of code, from aptitude's
point of view.

Unfortunately the patch breaks binary compatibility, but I have
figured out that's quite normal for apt updates. Source compatibility
I believe I did not break.

I have only tested the patches enough (several days on one computer)
to figure out they work for me; of course it's best to read them and
think hard about if the code still does the same thing as before.

	Sami

(*) Just moving the cursor in aptitude takes seconds on my old Pentium
laptop.
--- apt-0.6.38.sli.0/apt-pkg/contrib/configuration.cc
+++ apt-0.6.38.sli.0/apt-pkg/contrib/configuration.cc
@@ -110,7 +110,7 @@
       return 0;
    
    I = new Item;
-   I->Tag = string(S,Len);
+   I->Tag.assign(S,Len);
    I->Next = *Last;
    I->Parent = Head;
    *Last = I;
@@ -161,7 +161,7 @@
    if (Itm == 0 || Itm->Value.empty() == true)
    {
       if (Default == 0)
-	 return string();
+	 return "";
       else
 	 return Default;
    }
@@ -180,7 +180,7 @@
    if (Itm == 0 || Itm->Value.empty() == true)
    {
       if (Default == 0)
-	 return string();
+	 return "";
       else
 	 return Default;
    }
@@ -294,7 +294,7 @@
 // Configuration::CndSet - Conditinal Set a value			/*{{{*/
 // ---------------------------------------------------------------------
 /* This will not overwrite */
-void Configuration::CndSet(const char *Name,string Value)
+void Configuration::CndSet(const char *Name,const string &Value)
 {
    Item *Itm = Lookup(Name,true);
    if (Itm == 0)
@@ -306,7 +306,7 @@
 // Configuration::Set - Set a value					/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-void Configuration::Set(const char *Name,string Value)
+void Configuration::Set(const char *Name,const string &Value)
 {
    Item *Itm = Lookup(Name,true);
    if (Itm == 0)
@@ -330,13 +330,13 @@
 // Configuration::Clear - Clear an entire tree				/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-void Configuration::Clear(string Name)
+void Configuration::Clear(const string &Name)
 {
    Item *Top = Lookup(Name.c_str(),false);
    if (Top == 0)
       return;
    
-   Top->Value = string();
+   Top->Value.clear();
    Item *Stop = Top;
    Top = Top->Child;
    Stop->Child = 0;
@@ -444,7 +444,7 @@
    sections like 'zone "foo.org" { .. };' This causes each section to be
    added in with a tag like "zone::foo.org" instead of being split 
    tag/value. AsSectional enables Sectional parsing.*/
-bool ReadConfigFile(Configuration &Conf,string FName,bool AsSectional,
+bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional,
 		    unsigned Depth)
 {   
    // Open the stream for reading
@@ -670,13 +670,13 @@
 	    }
 	    
 	    // Empty the buffer
-	    LineBuffer = string();
+	    LineBuffer.clear();
 	    
 	    // Move up a tag, but only if there is no bit to parse
 	    if (TermChar == '}')
 	    {
 	       if (StackPos == 0)
-		  ParentTag = string();
+		  ParentTag.clear();
 	       else
 		  ParentTag = Stack[--StackPos];
 	    }
@@ -701,7 +701,7 @@
 // ReadConfigDir - Read a directory of config files			/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool ReadConfigDir(Configuration &Conf,string Dir,bool AsSectional,
+bool ReadConfigDir(Configuration &Conf,const string &Dir,bool AsSectional,
 		    unsigned Depth)
 {   
    DIR *D = opendir(Dir.c_str());
--- apt-0.6.38.sli.0/apt-pkg/contrib/configuration.h
+++ apt-0.6.38.sli.0/apt-pkg/contrib/configuration.h
@@ -69,25 +69,25 @@
    public:
 
    string Find(const char *Name,const char *Default = 0) const;
-   string Find(string Name,const char *Default = 0) const {return Find(Name.c_str(),Default);};
+   string Find(const string &Name,const char *Default = 0) const {return Find(Name.c_str(),Default);};
    string FindFile(const char *Name,const char *Default = 0) const;
    string FindDir(const char *Name,const char *Default = 0) const;
    int FindI(const char *Name,int Default = 0) const;
-   int FindI(string Name,int Default = 0) const {return FindI(Name.c_str(),Default);};
+   int FindI(const string &Name,int Default = 0) const {return FindI(Name.c_str(),Default);};
    bool FindB(const char *Name,bool Default = false) const;
-   bool FindB(string Name,bool Default = false) const {return FindB(Name.c_str(),Default);};
+   bool FindB(const string &Name,bool Default = false) const {return FindB(Name.c_str(),Default);};
    string FindAny(const char *Name,const char *Default = 0) const;
 	      
-   inline void Set(string Name,string Value) {Set(Name.c_str(),Value);};
-   void CndSet(const char *Name,string Value);
-   void Set(const char *Name,string Value);
+   inline void Set(const string &Name,const string &Value) {Set(Name.c_str(),Value);};
+   void CndSet(const char *Name,const string &Value);
+   void Set(const char *Name,const string &Value);
    void Set(const char *Name,int Value);   
    
-   inline bool Exists(string Name) const {return Exists(Name.c_str());};
+   inline bool Exists(const string &Name) const {return Exists(Name.c_str());};
    bool Exists(const char *Name) const;
    bool ExistsAny(const char *Name) const;
 
-   void Clear(string Name);
+   void Clear(const string &Name);
    
    inline const Item *Tree(const char *Name) const {return Lookup(Name);};
 
@@ -101,10 +101,10 @@
 
 extern Configuration *_config;
 
-bool ReadConfigFile(Configuration &Conf,string FName,bool AsSectional = false,
+bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional = false,
 		    unsigned Depth = 0);
 
-bool ReadConfigDir(Configuration &Conf,string Dir,bool AsSectional = false,
+bool ReadConfigDir(Configuration &Conf,const string &Dir,bool AsSectional = false,
 		    unsigned Depth = 0);
 
 #endif
--- apt-0.6.38.sli.0/apt-pkg/contrib/mmap.h
+++ apt-0.6.38.sli.0/apt-pkg/contrib/mmap.h
@@ -94,7 +94,7 @@
    unsigned long RawAllocate(unsigned long Size,unsigned long Aln = 0);
    unsigned long Allocate(unsigned long ItemSize);
    unsigned long WriteString(const char *String,unsigned long Len = (unsigned long)-1);
-   inline unsigned long WriteString(string S) {return WriteString(S.c_str(),S.length());};
+   inline unsigned long WriteString(const string &S) {return WriteString(S.c_str(),S.length());};
    void UsePools(Pool &P,unsigned int Count) {Pools = &P; PoolCount = Count;};
    
    DynamicMMap(FileFd &F,unsigned long Flags,unsigned long WorkSpace = 2*1024*1024);
--- apt-0.6.38.sli.0/apt-pkg/contrib/progress.cc
+++ apt-0.6.38.sli.0/apt-pkg/contrib/progress.cc
@@ -50,7 +50,7 @@
 // ---------------------------------------------------------------------
 /* */
 void OpProgress::OverallProgress(unsigned long Current, unsigned long Total,
-	  			 unsigned long Size,string Op)
+	  			 unsigned long Size,const string &Op)
 {
    this->Current = Current;
    this->Total = Total;
@@ -67,7 +67,7 @@
 // OpProgress::SubProgress - Set the sub progress state			/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-void OpProgress::SubProgress(unsigned long SubTotal,string Op)
+void OpProgress::SubProgress(unsigned long SubTotal,const string &Op)
 {
    this->SubTotal = SubTotal;
    SubOp = Op;
--- apt-0.6.38.sli.0/apt-pkg/contrib/progress.h
+++ apt-0.6.38.sli.0/apt-pkg/contrib/progress.h
@@ -59,9 +59,9 @@
    
    void Progress(unsigned long Current);
    void SubProgress(unsigned long SubTotal);
-   void SubProgress(unsigned long SubTotal,string Op);
+   void SubProgress(unsigned long SubTotal,const string &Op);
    void OverallProgress(unsigned long Current,unsigned long Total,
-			unsigned long Size,string Op);
+			unsigned long Size,const string &Op);
    virtual void Done() {};
    
    OpProgress();
--- apt-0.6.38.sli.0/apt-pkg/contrib/strutl.cc
+++ apt-0.6.38.sli.0/apt-pkg/contrib/strutl.cc
@@ -32,12 +32,49 @@
 #include <regex.h>
 #include <errno.h>
 #include <stdarg.h>
+#include <algorithm>
+#include <sstream>
 
 #include "config.h"
 
 using namespace std;
 									/*}}}*/
 
+static bool URICharsToQuote[256];
+// "\x00-\x20{}|\\\\^\\[\\]<>\"\x7F-\xFF";
+static const char *URIBadChars = "\\|{}[]<>\"^~_=!@#$%^&*";
+
+namespace strutl_private {
+    bool isspace_tbl[256];
+    char tolower_tbl[256];
+    bool init_done=0;
+}
+
+// strutl_init - Initialize everything in the module that needs to be	/*{{{*/
+// ---------------------------------------------------------------------
+void __attribute__ ((constructor)) strutl_init(void)
+{
+    if (strutl_private::init_done)
+	return;
+
+    strutl_private::init_done=1;
+
+    for (int I=0; I<256; I++)
+    {
+	strutl_private::isspace_tbl[I] = isspace(I);
+	strutl_private::tolower_tbl[I] = tolower(I);
+    }
+
+    for (int I=0; I<256; I++)
+	if (I <= 0x20 || I >= 0x7F || isprint(I) == 0 ||
+	    strchr(URIBadChars,I) != 0)
+	    URICharsToQuote[I]=1;
+	else
+	    URICharsToQuote[I]=0;
+};
+									/*}}}*/
+
+
 // strstrip - Remove white space from the front and back of a string	/*{{{*/
 // ---------------------------------------------------------------------
 /* This is handy to use when parsing a file. It also removes \n's left 
@@ -199,28 +236,48 @@
 // QuoteString - Convert a string into quoted from			/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-string QuoteString(string Str,const char *Bad)
+string QuoteString(const string &Str,const char *Bad)
 {
-   string Res;
-   for (string::iterator I = Str.begin(); I != Str.end(); I++)
+   vector<char> Res;
+   Res.reserve(Str.length()*3/2);
+   for (string::const_iterator I = Str.begin(); I != Str.end(); I++)
    {
-      if (strchr(Bad,*I) != 0 || isprint(*I) == 0 || 
-	  *I <= 0x20 || *I >= 0x7F)
+   if (strchr(Bad,*I) != 0 || isprint(*I) == 0 ||
+          *I <= 0x20 || *I >= 0x7F)
       {
 	 char Buf[10];
 	 sprintf(Buf,"%%%02x",(int)*I);
-	 Res += Buf;
+	 copy(Buf,Buf+3,back_insert_iterator<vector<char> >(Res));
       }
       else
-	 Res += *I;
+	 Res.push_back(*I);
    }
-   return Res;
+   return string(Res.begin(),Res.end());
 }
 									/*}}}*/
+// QuoteURI - Quote characters that may not appear in URIs		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string QuoteURI(const string &Str)
+{
+    char Res[Str.length()*3+1];
+    int Wpos=0;
+    for (string::const_iterator I = Str.begin(); I != Str.end(); I++)
+    {
+	if (URICharsToQuote[static_cast<unsigned char>(*I)])
+	    Wpos += sprintf(Res+Wpos,"%%%02x",(int)*I);
+	else
+	    Res[Wpos++] = *I;
+    }
+    Res[Wpos]=0;
+    return Res;
+}
+
+/*}}}*/
 // DeQuoteString - Convert a string from quoted from                    /*{{{*/
 // ---------------------------------------------------------------------
 /* This undoes QuoteString */
-string DeQuoteString(string Str)
+string DeQuoteString(const string &Str)
 {
    string Res;
    for (string::const_iterator I = Str.begin(); I != Str.end(); I++)
@@ -317,7 +374,7 @@
 // SubstVar - Substitute a string for another string			/*{{{*/
 // ---------------------------------------------------------------------
 /* This replaces all occurances of Subst with Contents in Str. */
-string SubstVar(string Str,string Subst,string Contents)
+string SubstVar(const string &Str,const string &Subst,const string &Contents)
 {
    string::size_type Pos = 0;
    string::size_type OldPos = 0;
@@ -348,21 +405,17 @@
 /* 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 URItoFileName(const string &URI)
 {
    // Nuke 'sensitive' items
    ::URI U(URI);
-   U.User = string();
-   U.Password = string();
-   U.Access = "";
+   U.User.clear();
+   U.Password.clear();
+   U.Access.clear();
    
-   // "\x00-\x20{}|\\\\^\\[\\]<>\"\x7F-\xFF";
-   URI = QuoteString(U,"\\|{}[]<>\"^~_=!@#$%^&*");
-   string::iterator J = URI.begin();
-   for (; J != URI.end(); J++)
-      if (*J == '/') 
-	 *J = '_';
-   return URI;
+   string NewURI = QuoteURI(U);
+   replace(NewURI.begin(),NewURI.end(),'/','_');
+   return NewURI;
 }
 									/*}}}*/
 // Base64Encode - Base64 Encoding routine for short strings		/*{{{*/
@@ -371,7 +424,7 @@
    from wget and then patched and bug fixed.
  
    This spec can be found in rfc2045 */
-string Base64Encode(string S)
+string Base64Encode(const string &S)
 {
    // Conversion table.
    static char tbl[64] = {'A','B','C','D','E','F','G','H',
@@ -486,7 +539,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))
+      if (fast_tolower(*A) != fast_tolower(*B))
 	 break;
 
    if (A == AEnd && B == BEnd)
@@ -495,7 +548,7 @@
       return 1;
    if (B == BEnd)
       return -1;
-   if (toupper(*A) < toupper(*B))
+   if (fast_tolower(*A) < fast_tolower(*B))
       return -1;
    return 1;
 }
@@ -504,7 +557,7 @@
 		  const char *B,const char *BEnd)
 {
    for (; A != AEnd && B != BEnd; A++, B++)
-      if (toupper(*A) != toupper(*B))
+      if (fast_tolower(*A) != fast_tolower(*B))
 	 break;
 
    if (A == AEnd && B == BEnd)
@@ -513,7 +566,7 @@
       return 1;
    if (B == BEnd)
       return -1;
-   if (toupper(*A) < toupper(*B))
+   if (fast_tolower(*A) < fast_tolower(*B))
       return -1;
    return 1;
 }
@@ -521,7 +574,7 @@
 		  string::const_iterator B,string::const_iterator BEnd)
 {
    for (; A != AEnd && B != BEnd; A++, B++)
-      if (toupper(*A) != toupper(*B))
+      if (fast_tolower(*A) != fast_tolower(*B))
 	 break;
 
    if (A == AEnd && B == BEnd)
@@ -530,7 +583,7 @@
       return 1;
    if (B == BEnd)
       return -1;
-   if (toupper(*A) < toupper(*B))
+   if (fast_tolower(*A) < fast_tolower(*B))
       return -1;
    return 1;
 }
@@ -540,21 +593,21 @@
 // ---------------------------------------------------------------------
 /* The format is like those used in package files and the method 
    communication system */
-string LookupTag(string Message,const char *Tag,const char *Default)
+string LookupTag(const 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++)
+   for (string::const_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;
+	 string::const_iterator J;
 	 I += Length + 1;
-	 for (; isspace(*I) != 0 && I < Message.end(); I++);
+	 for (; fast_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 (; J > I && fast_isspace(J[-1]) != 0; J--);
 	 
 	 return string(I,J);
       }
@@ -572,7 +625,7 @@
 // ---------------------------------------------------------------------
 /* 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)
+int StringToBool(const string &Text,int Default)
 {
    char *End;
    int Res = strtol(Text.c_str(),&End,0);   
@@ -738,7 +791,7 @@
    '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 :< This also
    handles the weird, but unambiguous FTP time format*/
-bool StrToTime(string Val,time_t &Result)
+bool StrToTime(const string &Val,time_t &Result)
 {
    struct tm Tm;
    char Month[10];
@@ -825,7 +878,7 @@
 // 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(string Str,unsigned char *Num,unsigned int Length)
+bool Hex2Num(const string &Str,unsigned char *Num,unsigned int Length)
 {
    if (Str.length() != Length*2)
       return false;
@@ -986,7 +1039,7 @@
 // ---------------------------------------------------------------------
 /* The domain list is a comma seperate list of domains that are suffix
    matched against the argument */
-bool CheckDomainList(string Host,string List)
+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++)
@@ -1009,7 +1062,7 @@
 // URI::CopyFrom - Copy from an object					/*{{{*/
 // ---------------------------------------------------------------------
 /* This parses the URI into all of its components */
-void URI::CopyFrom(string U)
+void URI::CopyFrom(const string &U)
 {
    string::const_iterator I = U.begin();
 
@@ -1038,9 +1091,9 @@
       SingleSlash = U.end();
 
    // We can now write the access and path specifiers
-   Access = string(U,0,FirstColon - U.begin());
+   Access.assign(U.begin(),FirstColon);
    if (SingleSlash != U.end())
-      Path = string(U,SingleSlash - U.begin());
+      Path.assign(SingleSlash,U.end());
    if (Path.empty() == true)
       Path = "/";
 
@@ -1070,14 +1123,14 @@
    if (At == SingleSlash)
    {
       if (FirstColon < SingleSlash)
-	 Host = string(U,FirstColon - U.begin(),SingleSlash - FirstColon);
+	 Host.assign(FirstColon,SingleSlash);
    }
    else
    {
-      Host = string(U,At - U.begin() + 1,SingleSlash - At - 1);
-      User = string(U,FirstColon - U.begin(),SecondColon - FirstColon);
+      Host.assign(At+1,SingleSlash);
+      User.assign(FirstColon,SecondColon);
       if (SecondColon < At)
-	 Password = string(U,SecondColon - U.begin() + 1,At - SecondColon - 1);
+	 Password.assign(SecondColon+1,At);
    }   
    
    // Now we parse the RFC 2732 [] hostnames.
@@ -1105,7 +1158,7 @@
    // Tsk, weird.
    if (InBracket == true)
    {
-      Host = string();
+      Host.erase();
       return;
    }
    
@@ -1116,7 +1169,7 @@
       return;
    
    Port = atoi(string(Host,Pos+1).c_str());
-   Host = string(Host,0,Pos);
+   Host.assign(Host,0,Pos);
 }
 									/*}}}*/
 // URI::operator string - Convert the URI to a string			/*{{{*/
@@ -1124,54 +1177,70 @@
 /* */
 URI::operator string()
 {
-   string Res;
+   vector<char> Res;
    
    if (Access.empty() == false)
-      Res = Access + ':';
+   {
+       Res.insert(Res.end(),Access.begin(),Access.end());
+       Res.push_back(':');
+   }
    
    if (Host.empty() == false)
    {	 
       if (Access.empty() == false)
-	 Res += "//";
+      {
+	  Res.push_back('/');
+	  Res.push_back('/');
+      }
           
       if (User.empty() == false)
       {
-	 Res +=  User;
+	 Res.insert(Res.end(),User.begin(),User.end());
 	 if (Password.empty() == false)
-	    Res += ":" + Password;
-	 Res += "@";
+	 {
+	     Res.push_back(':');
+	     Res.insert(Res.end(),Password.begin(),Password.end());
+	 }
+	 Res.push_back('@');
       }
       
       // Add RFC 2732 escaping characters
       if (Access.empty() == false &&
 	  (Host.find('/') != string::npos || Host.find(':') != string::npos))
-	 Res += '[' + Host + ']';
+      {
+	  Res.push_back('[');
+	  Res.insert(Res.end(),Host.begin(),Host.end());
+	  Res.push_back(']');
+      }
       else
-	 Res += Host;
+	  Res.insert(Res.end(),Host.begin(),Host.end());
       
       if (Port != 0)
       {
 	 char S[30];
 	 sprintf(S,":%u",Port);
-	 Res += S;
+	 Res.insert(Res.end(),S,S+strlen(S));
       }	 
    }
    
    if (Path.empty() == false)
    {
       if (Path[0] != '/')
-	 Res += "/" + Path;
+      {
+	  Res.push_back('/');
+	  Res.insert(Res.end(),Path.begin(),Path.end());
+      }
       else
-	 Res += Path;
+	 Res.insert(Res.end(),Path.begin(),Path.end());
    }
    
-   return Res;
+   return string(Res.begin(),Res.end());
 }
 									/*}}}*/
 // URI::SiteOnly - Return the schema and site for the URI		/*{{{*/
 // ---------------------------------------------------------------------
 /* */
-string URI::SiteOnly(string URI)
+string URI::SiteOnly(const string &URI)
 {
    ::URI U(URI);
    U.User = string();
--- apt-0.6.38.sli.0/apt-pkg/contrib/strutl.h
+++ apt-0.6.38.sli.0/apt-pkg/contrib/strutl.h
@@ -38,41 +38,60 @@
 #define APT_FORMAT2
 #define APT_FORMAT3
 #endif    
-    
+
+namespace strutl_private {
+    extern bool isspace_tbl[256];
+    extern char tolower_tbl[256];
+}
+
+static inline bool fast_isspace(char c)
+{
+    return strutl_private::isspace_tbl[(unsigned char)(c)];
+}
+
+static inline char fast_tolower(char c)
+{
+    return strutl_private::tolower_tbl[(unsigned char)(c)];
+}
+
+void strutl_init(void);
 char *_strstrip(char *String);
 char *_strtabexpand(char *String,size_t Len);
 bool ParseQuoteWord(const char *&String,string &Res);
 bool ParseCWord(const char *&String,string &Res);
-string QuoteString(string Str,const char *Bad);
-string DeQuoteString(string Str);
+string QuoteString(const string &Str,const char *Bad);
+string QuoteURI(const string &Str);
+string DeQuoteString(const string &Str);
 string SizeToStr(double Bytes);
 string TimeToStr(unsigned long Sec);
-string Base64Encode(string Str);
-string URItoFileName(string URI);
+string Base64Encode(const string &Str);
+string URItoFileName(const string &URI);
 string TimeRFC1123(time_t Date);
-bool StrToTime(string Val,time_t &Result);
-string LookupTag(string Message,const char *Tag,const char *Default = 0);
-int StringToBool(string Text,int Default = -1);
+bool StrToTime(const string &Val,time_t &Result);
+string LookupTag(const string &Message,const char *Tag,const char *Default = 0);
+int StringToBool(const string &Text,int Default = -1);
 bool ReadMessages(int Fd, vector<string> &List);
 bool StrToNum(const char *Str,unsigned long &Res,unsigned Len,unsigned Base = 0);
-bool Hex2Num(string Str,unsigned char *Num,unsigned int Length);
+bool Hex2Num(const string &Str,unsigned char *Num,unsigned int Length);
 bool TokSplitString(char Tok,char *Input,char **List,
 		    unsigned long ListMax);
 void ioprintf(ostream &out,const char *format,...) APT_FORMAT2;
 char *safe_snprintf(char *Buffer,char *End,const char *Format,...) APT_FORMAT3;
-bool CheckDomainList(string Host,string List);
+bool CheckDomainList(const string &Host,const string &List);
 
 #define APT_MKSTRCMP(name,func) \
+inline int name(const char *A,const char *B) {return func(A,A+strlen(A),B,B+strlen(B));}; \
 inline int name(const char *A,const char *AEnd,const char *B) {return func(A,AEnd,B,B+strlen(B));}; \
-inline int name(string A,const char *B) {return func(A.c_str(),A.c_str()+A.length(),B,B+strlen(B));}; \
-inline int name(string A,string B) {return func(A.c_str(),A.c_str()+A.length(),B.c_str(),B.c_str()+B.length());}; \
-inline int name(string A,const char *B,const char *BEnd) {return func(A.c_str(),A.c_str()+A.length(),B,BEnd);}; 
+inline int name(const string &A,const char *B) {return func(A.c_str(),A.c_str()+A.length(),B,B+strlen(B));}; \
+inline int name(const string &A,const string &B) {return func(A.c_str(),A.c_str()+A.length(),B.c_str(),B.c_str()+B.length());}; \
+inline int name(const string &A,const char *B,const char *BEnd) {return func(A.c_str(),A.c_str()+A.length(),B,BEnd);}; 
 
 #define APT_MKSTRCMP2(name,func) \
+inline int name(const char *A,const char *B) {return func(A,A+strlen(A),B,B+strlen(B));}; \
 inline int name(const char *A,const char *AEnd,const char *B) {return func(A,AEnd,B,B+strlen(B));}; \
-inline int name(string A,const char *B) {return func(A.begin(),A.end(),B,B+strlen(B));}; \
-inline int name(string A,string B) {return func(A.begin(),A.end(),B.begin(),B.end());}; \
-inline int name(string A,const char *B,const char *BEnd) {return func(A.begin(),A.end(),B,BEnd);}; 
+inline int name(const string &A,const char *B) {return func(A.begin(),A.end(),B,B+strlen(B));}; \
+inline int name(const string &A,const string &B) {return func(A.begin(),A.end(),B.begin(),B.end());}; \
+inline int name(const string &A,const char *B,const char *BEnd) {return func(A.begin(),A.end(),B,BEnd);}; 
 
 int stringcmp(const char *A,const char *AEnd,const char *B,const char *BEnd);
 int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd);
@@ -101,7 +120,7 @@
 
 class URI
 {
-   void CopyFrom(string From);
+   void CopyFrom(const string &From);
 		 
    public:
    
@@ -113,11 +132,11 @@
    unsigned int Port;
    
    operator string();
-   inline void operator =(string From) {CopyFrom(From);};
+   inline void operator =(const string &From) {CopyFrom(From);};
    inline bool empty() {return Access.empty();};
-   static string SiteOnly(string URI);
+   static string SiteOnly(const string &URI);
    
-   URI(string Path) {CopyFrom(Path);};
+   URI(const string &Path) {CopyFrom(Path);};
    URI() : Port(0) {};
 };
 
@@ -127,7 +146,7 @@
    const string *Contents;
 };
 string SubstVar(string Str,const struct SubstVar *Vars);
-string SubstVar(string Str,string Subst,string Contents);
+string SubstVar(const string &Str,const string &Subst,const string &Contents);
 
 struct RxChoiceList
 {
--- apt-0.6.38.sli.0/apt-pkg/deb/debindexfile.cc
+++ apt-0.6.38.sli.0/apt-pkg/deb/debindexfile.cc
@@ -221,20 +221,34 @@
 }
 string debPackagesIndex::IndexURI(const char *Type) const
 {
-   string Res;
-   if (Dist[Dist.size() - 1] == '/')
-   {
-      if (Dist != "/")
-	 Res = URI + Dist;
-      else 
-	 Res = URI;
-   }
-   else
-      Res = URI + "dists/" + Dist + '/' + Section +
-      "/binary-" + _config->Find("APT::Architecture") + '/';
+    vector<char> Res;
+    Res.reserve(150);
+    if (Dist[Dist.size() - 1] == '/')
+    {
+	if (Dist != "/")
+	{
+	    Res.insert(Res.end(),URI.begin(),URI.end());
+	    Res.insert(Res.end(),Dist.begin(),Dist.end());
+	}
+	else 
+	    Res.assign(URI.begin(),URI.end());
+    }
+    else
+    {
+	static const char *Dists="dists/", *Binary="/binary-";
+	const string Arch(_config->Find("APT::Architecture"));
+	Res.assign(URI.begin(),URI.end());
+	Res.insert(Res.end(),Dists,Dists+6);
+	Res.insert(Res.end(),Dist.begin(),Dist.end());
+	Res.push_back('/');
+	Res.insert(Res.end(),Section.begin(),Section.end());
+	Res.insert(Res.end(),Binary,Binary+8);
+	Res.insert(Res.end(),Arch.begin(),Arch.end());
+	Res.push_back('/');
+    }
    
-   Res += Type;
-   return Res;
+    Res.insert(Res.end(),Type,Type+strlen(Type));
+    return string(Res.begin(),Res.end());
 }
 									/*}}}*/
 // PackagesIndex::Exists - Check if the index is available		/*{{{*/
--- apt-0.6.38.sli.0/apt-pkg/deb/deblistparser.cc
+++ apt-0.6.38.sli.0/apt-pkg/deb/deblistparser.cc
@@ -166,8 +166,8 @@
       char *I = S;
       for (; Start != End; Start++)
       {
-	 if (isspace(*Start) == 0)
-	    *I++ = tolower(*Start);
+	 if (fast_isspace(*Start) == 0)
+	    *I++ = fast_tolower(*Start);
 	 if (*Start == '<' && Start[1] != '<' && Start[1] != '=')
 	    *I++ = '=';
 	 if (*Start == '>' && Start[1] != '>' && Start[1] != '=')
@@ -337,11 +337,11 @@
 					unsigned int &Op, bool ParseArchFlags)
 {
    // Strip off leading space
-   for (;Start != Stop && isspace(*Start) != 0; Start++);
+   for (;Start != Stop && fast_isspace(*Start) != 0; Start++);
    
    // Parse off the package name
    const char *I = Start;
-   for (;I != Stop && isspace(*I) == 0 && *I != '(' && *I != ')' &&
+   for (;I != Stop && fast_isspace(*I) == 0 && *I != '(' && *I != ')' &&
 	*I != ',' && *I != '|'; I++);
    
    // Malformed, no '('
@@ -355,19 +355,19 @@
    Package.assign(Start,I - Start);
    
    // Skip white space to the '('
-   for (;I != Stop && isspace(*I) != 0 ; I++);
+   for (;I != Stop && fast_isspace(*I) != 0 ; I++);
    
    // Parse a version
    if (I != Stop && *I == '(')
    {
       // Skip the '('
-      for (I++; I != Stop && isspace(*I) != 0 ; I++);
+      for (I++; I != Stop && fast_isspace(*I) != 0 ; I++);
       if (I + 3 >= Stop)
 	 return 0;
       I = ConvertRelation(I,Op);
       
       // Skip whitespace
-      for (;I != Stop && isspace(*I) != 0; I++);
+      for (;I != Stop && fast_isspace(*I) != 0; I++);
       Start = I;
       for (;I != Stop && *I != ')'; I++);
       if (I == Stop || Start == I)
@@ -375,19 +375,19 @@
       
       // Skip trailing whitespace
       const char *End = I;
-      for (; End > Start && isspace(End[-1]); End--);
+      for (; End > Start && fast_isspace(End[-1]); End--);
       
-      Ver = string(Start,End-Start);
+      Ver.assign(Start,End-Start);
       I++;
    }
    else
    {
-      Ver = string();
+      Ver.clear();
       Op = pkgCache::Dep::NoOp;
    }
    
    // Skip whitespace
-   for (;I != Stop && isspace(*I) != 0; I++);
+   for (;I != Stop && fast_isspace(*I) != 0; I++);
 
    if (ParseArchFlags == true)
    {
@@ -407,7 +407,7 @@
          while (I != Stop) 
 	 {
             // look for whitespace or ending ']'
-	    while (End != Stop && !isspace(*End) && *End != ']') 
+	    while (End != Stop && !fast_isspace(*End) && *End != ']') 
 	       End++;
 	 
 	    if (End == Stop) 
@@ -428,7 +428,7 @@
 	    }
 	    
 	    I = End;
-	    for (;I != Stop && isspace(*I) != 0; I++);
+	    for (;I != Stop && fast_isspace(*I) != 0; I++);
          }
 
 	 if (NegArch)
@@ -439,7 +439,7 @@
       }
       
       // Skip whitespace
-      for (;I != Stop && isspace(*I) != 0; I++);
+      for (;I != Stop && fast_isspace(*I) != 0; I++);
    }
 
    if (I != Stop && *I == '|')
@@ -448,7 +448,7 @@
    if (I == Stop || *I == ',' || *I == '|')
    {
       if (I != Stop)
-	 for (I++; I != Stop && isspace(*I) != 0; I++);
+	 for (I++; I != Stop && fast_isspace(*I) != 0; I++);
       return I;
    }
    
--- apt-0.6.38.sli.0/apt-pkg/deb/debversion.cc
+++ apt-0.6.38.sli.0/apt-pkg/deb/debversion.cc
@@ -33,15 +33,29 @@
 }
 									/*}}}*/
 
+#define isdigit(x) ((x)>='0' && (x)<='9')
+#define isalpha(x) (((x)>='a' && (x)<='z') || ((x)>='A' && (x)<='Z'))
+
 // debVS::CmpFragment - Compare versions			        /*{{{*/
 // ---------------------------------------------------------------------
 /* This compares a fragment of the version. This is a slightly adapted 
    version of what dpkg uses. */
-#define order(x) ((x) == '~' ? -1    \
-		: isdigit((x)) ? 0   \
-		: !(x) ? 0           \
-		: isalpha((x)) ? (x) \
-		: (x) + 256)
+#define order2(x) ((x) == '~' ? -1    \
+		 : isdigit((x)) ? 0   \
+		 : !(x) ? 0           \
+		 : isalpha((x)) ? (x) \
+		 : (x) + 256)
+
+static int ordertab[256];
+
+#define order(x) ordertab[(unsigned int)(x)]
+
+static void __attribute__ ((constructor)) make_ordertab()
+{
+    for (int I=0; I<256; I++)
+	ordertab[I]=order2(I);
+}
+
 int debVersioningSystem::CmpFragment(const char *A,const char *AEnd,
 				     const char *B,const char *BEnd)
 {
@@ -133,11 +147,11 @@
    // Strip off the epoch and compare it 
    const char *lhs = A;
    const char *rhs = B;
-   for (;lhs != AEnd && *lhs != ':'; lhs++);
-   for (;rhs != BEnd && *rhs != ':'; rhs++);
-   if (lhs == AEnd)
+   lhs=static_cast<const char *>(memchr(lhs,':',AEnd-lhs));
+   rhs=static_cast<const char *>(memchr(rhs,':',BEnd-rhs));
+   if (lhs == 0)
       lhs = A;
-   if (rhs == BEnd)
+   if (rhs == 0)
       rhs = B;
    
    // Compare the epoch
@@ -154,12 +168,12 @@
    // Find the last - 
    const char *dlhs = AEnd-1;
    const char *drhs = BEnd-1;
-   for (;dlhs > lhs && *dlhs != '-'; dlhs--);
-   for (;drhs > rhs && *drhs != '-'; drhs--);
+   dlhs = static_cast<const char *>(memrchr(lhs, '-', dlhs-lhs));
+   drhs = static_cast<const char *>(memrchr(rhs, '-', drhs-rhs));
 
-   if (dlhs == lhs)
+   if (dlhs == 0)
       dlhs = AEnd;
-   if (drhs == rhs)
+   if (drhs == 0)
       drhs = BEnd;
    
    // Compare the main version
--- apt-0.6.38.sli.0/apt-pkg/init.cc
+++ apt-0.6.38.sli.0/apt-pkg/init.cc
@@ -11,6 +11,7 @@
 #include <apt-pkg/init.h>
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/error.h>
+#include <apt-pkg/strutl.h>
 
 #include <apti18n.h>
 #include <config.h>
@@ -33,7 +34,9 @@
    is prepended, this allows a fair degree of flexability. */
 bool pkgInitConfig(Configuration &Cnf)
 {
+   strutl_init();
+
    // General APT things
    if (strcmp(COMMON_OS,"linux") == 0 ||
        strcmp(COMMON_OS,"unknown") == 0)
--- apt-0.6.38.sli.0/apt-pkg/pkgcache.cc
+++ apt-0.6.38.sli.0/apt-pkg/pkgcache.cc
@@ -153,11 +153,11 @@
 /* This is used to generate the hash entries for the HashTable. With my
    package list from bo this function gets 94% table usage on a 512 item
    table (480 used items) */
-unsigned long pkgCache::sHash(string Str) const
+unsigned long pkgCache::sHash(const string &Str) const
 {
    unsigned long Hash = 0;
    for (string::const_iterator I = Str.begin(); I != Str.end(); I++)
-      Hash = 5*Hash + tolower(*I);
+      Hash = 5*Hash + fast_tolower(*I);
    return Hash % _count(HeaderP->HashTable);
 }
 
@@ -165,7 +165,7 @@
 {
    unsigned long Hash = 0;
    for (const char *I = Str; *I != 0; I++)
-      Hash = 5*Hash + tolower(*I);
+      Hash = 5*Hash + fast_tolower(*I);
    return Hash % _count(HeaderP->HashTable);
 }
 
@@ -173,7 +173,7 @@
 // Cache::FindPkg - Locate a package by name				/*{{{*/
 // ---------------------------------------------------------------------
 /* Returns 0 on error, pointer to the package otherwise */
-pkgCache::PkgIterator pkgCache::FindPkg(string Name)
+pkgCache::PkgIterator pkgCache::FindPkg(const string &Name)
 {
    // Look at the hash bucket
    Package *Pkg = PkgP + HeaderP->HashTable[Hash(Name)];
--- apt-0.6.38.sli.0/apt-pkg/pkgcache.h
+++ apt-0.6.38.sli.0/apt-pkg/pkgcache.h
@@ -89,7 +89,7 @@
    string CacheFile;
    MMap &Map;
 
-   unsigned long sHash(string S) const;
+   unsigned long sHash(const string &S) const;
    unsigned long sHash(const char *S) const;
    
    public:
@@ -111,14 +111,14 @@
    inline void *DataEnd() {return ((unsigned char *)Map.Data()) + Map.Size();};
       
    // String hashing function (512 range)
-   inline unsigned long Hash(string S) const {return sHash(S);};
+   inline unsigned long Hash(const string &S) const {return sHash(S);};
    inline unsigned long Hash(const char *S) const {return sHash(S);};
 
    // Usefull transformation things
    const char *Priority(unsigned char Priority);
    
    // Accessors
-   PkgIterator FindPkg(string Name);
+   PkgIterator FindPkg(const string &Name);
    Header &Head() {return *HeaderP;};
    inline PkgIterator PkgBegin();
    inline PkgIterator PkgEnd();
--- apt-0.6.38.sli.0/apt-pkg/pkgcachegen.cc
+++ apt-0.6.38.sli.0/apt-pkg/pkgcachegen.cc
@@ -266,7 +266,7 @@
 // CacheGenerator::NewPackage - Add a new package			/*{{{*/
 // ---------------------------------------------------------------------
 /* This creates a new package structure and adds it to the hash table */
-bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,string Name)
+bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name)
 {
    Pkg = Cache.FindPkg(Name);
    if (Pkg.end() == false)
@@ -330,7 +330,7 @@
 // ---------------------------------------------------------------------
 /* This puts a version structure in the linked list */
 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver,
-					    string VerStr,
+					    const string &VerStr,
 					    unsigned long Next)
 {
    // Get a structure
@@ -354,8 +354,8 @@
 /* This creates a dependency element in the tree. It is linked to the
    version and to the package that it is pointing to. */
 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
-					       string PackageName,
-					       string Version,
+					       const string &PackageName,
+					       const string &Version,
 					       unsigned int Op,
 					       unsigned int Type)
 {
@@ -419,8 +419,8 @@
 // ---------------------------------------------------------------------
 /* */
 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver,
-					        string PackageName,
-						string Version)
+					        const string &PackageName,
+						const string &Version)
 {
    pkgCache &Cache = Owner->Cache;
 
@@ -459,7 +459,7 @@
 // ---------------------------------------------------------------------
 /* This is used to select which file is to be associated with all newly
    added versions. The caller is responsible for setting the IMS fields. */
-bool pkgCacheGenerator::SelectFile(string File,string Site,
+bool pkgCacheGenerator::SelectFile(const string &File,const string &Site,
 				   const pkgIndexFile &Index,
 				   unsigned long Flags)
 {
@@ -543,7 +543,7 @@
 /* This just verifies that each file in the list of index files exists,
    has matching attributes with the cache and the cache does not have
    any extra files. */
-static bool CheckValidity(string CacheFile, FileIterator Start, 
+static bool CheckValidity(const string &CacheFile, FileIterator Start, 
                           FileIterator End,MMap **OutMap = 0)
 {
    // No file, certainly invalid
--- apt-0.6.38.sli.0/apt-pkg/pkgcachegen.h
+++ apt-0.6.38.sli.0/apt-pkg/pkgcachegen.h
@@ -53,17 +53,17 @@
    // Flag file dependencies
    bool FoundFileDeps;
    
-   bool NewPackage(pkgCache::PkgIterator &Pkg,string Pkg);
+   bool NewPackage(pkgCache::PkgIterator &Pkg,const string &Pkg);
    bool NewFileVer(pkgCache::VerIterator &Ver,ListParser &List);
-   unsigned long NewVersion(pkgCache::VerIterator &Ver,string VerStr,unsigned long Next);
+   unsigned long NewVersion(pkgCache::VerIterator &Ver,const string &VerStr,unsigned long Next);
 
    public:
 
    unsigned long WriteUniqString(const char *S,unsigned int Size);
-   inline unsigned long WriteUniqString(string S) {return WriteUniqString(S.c_str(),S.length());};
+   inline unsigned long WriteUniqString(const string &S) {return WriteUniqString(S.c_str(),S.length());};
 
    void DropProgress() {Progress = 0;};
-   bool SelectFile(string File,string Site,pkgIndexFile const &Index,
+   bool SelectFile(const string &File,const string &Site,pkgIndexFile const &Index,
 		   unsigned long Flags = 0);
    bool MergeList(ListParser &List,pkgCache::VerIterator *Ver = 0);
    inline pkgCache &GetCache() {return Cache;};
@@ -92,14 +92,14 @@
       
    protected:
 
-   inline unsigned long WriteUniqString(string S) {return Owner->WriteUniqString(S);};
+   inline unsigned long WriteUniqString(const string &S) {return Owner->WriteUniqString(S);};
    inline unsigned long WriteUniqString(const char *S,unsigned int Size) {return Owner->WriteUniqString(S,Size);};
-   inline unsigned long WriteString(string S) {return Owner->Map.WriteString(S);};
+   inline unsigned long WriteString(const string &S) {return Owner->Map.WriteString(S);};
    inline unsigned long WriteString(const char *S,unsigned int Size) {return Owner->Map.WriteString(S,Size);};
-   bool NewDepends(pkgCache::VerIterator Ver,string Package,
-		   string Version,unsigned int Op,
+   bool NewDepends(pkgCache::VerIterator Ver,const string &Package,
+		   const string &Version,unsigned int Op,
 		   unsigned int Type);
-   bool NewProvides(pkgCache::VerIterator Ver,string Package,string Version);
+   bool NewProvides(pkgCache::VerIterator Ver,const string &Package,const string &Version);
    
    public:
    
--- apt-0.6.38.sli.0/apt-pkg/tagfile.cc
+++ apt-0.6.38.sli.0/apt-pkg/tagfile.cc
@@ -188,7 +188,7 @@
    while (TagCount+1 < sizeof(Indexes)/sizeof(Indexes[0]) && Stop < End)
    {
       // Start a new index and add it to the hash
-      if (isspace(Stop[0]) == 0)
+      if (Stop[0] != ' ')
       {
 	 Indexes[TagCount++] = Stop - Section;
 	 AlphaIndexes[AlphaHash(Stop,End)] = TagCount;
@@ -199,7 +199,8 @@
       if (Stop == 0)
 	 return false;
       
-      for (; Stop+1 < End && Stop[1] == '\r'; Stop++);
+      if (Stop+1 < End && Stop[1] == '\r')
+	  Stop++;
 
       // Double newline marks the end of the record
       if (Stop+1 < End && Stop[1] == '\n')
@@ -239,12 +240,12 @@
    {
       const char *St;
       St = Section + Indexes[I];
-      if (strncasecmp(Tag,St,Length) != 0)
+      if (strncmp(Tag,St,Length) != 0)
 	 continue;
 
       // Make sure the colon is in the right place
       const char *C = St + Length;
-      for (; isspace(*C) != 0; C++);
+      for (; fast_isspace(*C) != 0; C++);
       if (*C != ':')
 	 continue;
       Pos = I;
@@ -272,12 +273,12 @@
    {
       const char *St;
       St = Section + Indexes[I];
-      if (strncasecmp(Tag,St,Length) != 0)
+      if (strncmp(Tag,St,Length) != 0)
 	 continue;
       
       // Make sure the colon is in the right place
       const char *C = St + Length;
-      for (; isspace(*C) != 0; C++);
+      for (; *C == ' '; C++);
       if (*C != ':')
 	 continue;
 
@@ -287,8 +288,8 @@
       if (Start >= End)
 	 return _error->Error("Internal parsing error");
       
-      for (; (isspace(*Start) != 0 || *Start == ':') && Start < End; Start++);
-      for (; isspace(End[-1]) != 0 && End > Start; End--);
+      for (; Start < End && (fast_isspace(*Start) ||  *Start == ':'); Start++);
+      for (; End > Start && fast_isspace(End[-1]); End--);
       
       return true;
    }
@@ -449,7 +450,7 @@
 	    Visited[J] |= 2;
 	    if (Rewrite[J].Rewrite != 0 && Rewrite[J].Rewrite[0] != 0)
 	    {
-	       if (isspace(Rewrite[J].Rewrite[0]))
+	       if (fast_isspace(Rewrite[J].Rewrite[0]))
 		  fprintf(Output,"%s:%s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
 	       else
 		  fprintf(Output,"%s: %s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
@@ -505,7 +506,7 @@
 	    Visited[J] |= 2;
 	    if (Rewrite[J].Rewrite != 0 && Rewrite[J].Rewrite[0] != 0)
 	    {
-	       if (isspace(Rewrite[J].Rewrite[0]))
+	       if (fast_isspace(Rewrite[J].Rewrite[0]))
 		  fprintf(Output,"%s:%s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
 	       else
 		  fprintf(Output,"%s: %s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
@@ -534,7 +535,7 @@
       
       if (Rewrite[J].Rewrite != 0 && Rewrite[J].Rewrite[0] != 0)
       {
-	 if (isspace(Rewrite[J].Rewrite[0]))
+	 if (fast_isspace(Rewrite[J].Rewrite[0]))
 	    fprintf(Output,"%s:%s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);
 	 else
 	    fprintf(Output,"%s: %s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite);

Attachment: signature.asc
Description: Digital signature


Reply to: