From 6dc60370a750334cb701386cfa4ef9719db9078a Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Tue, 30 Mar 2010 12:38:38 +0200 Subject: replace every call to toupper with one to our own tolower_ascii This sounds like a premature optimization and since Mr. Knuth we all know that they are the root of all evil - but, and here it starts to be interesting: As the tolower_ascii method is by far the most called method we have (~60 Mio. times) and as we compare only strings containing ascii characters (package names, configuration options) using our own method reduces execution time of APT by 4% plus it avoids that the locale settings can influence us. --- apt-pkg/contrib/strutl.cc | 49 +++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 23 deletions(-) (limited to 'apt-pkg/contrib/strutl.cc') diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index 1b9922a31..ab47cdede 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -566,7 +566,7 @@ int stringcmp(string::const_iterator A,string::const_iterator AEnd, 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 (tolower_ascii(*A) != tolower_ascii(*B)) break; if (A == AEnd && B == BEnd) @@ -575,7 +575,7 @@ int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd) return 1; if (B == BEnd) return -1; - if (toupper(*A) < toupper(*B)) + if (tolower_ascii(*A) < tolower_ascii(*B)) return -1; return 1; } @@ -584,7 +584,7 @@ int stringcasecmp(string::const_iterator A,string::const_iterator AEnd, const char *B,const char *BEnd) { for (; A != AEnd && B != BEnd; A++, B++) - if (toupper(*A) != toupper(*B)) + if (tolower_ascii(*A) != tolower_ascii(*B)) break; if (A == AEnd && B == BEnd) @@ -593,7 +593,7 @@ int stringcasecmp(string::const_iterator A,string::const_iterator AEnd, return 1; if (B == BEnd) return -1; - if (toupper(*A) < toupper(*B)) + if (tolower_ascii(*A) < tolower_ascii(*B)) return -1; return 1; } @@ -601,7 +601,7 @@ int stringcasecmp(string::const_iterator A,string::const_iterator AEnd, string::const_iterator B,string::const_iterator BEnd) { for (; A != AEnd && B != BEnd; A++, B++) - if (toupper(*A) != toupper(*B)) + if (tolower_ascii(*A) != tolower_ascii(*B)) break; if (A == AEnd && B == BEnd) @@ -610,7 +610,7 @@ int stringcasecmp(string::const_iterator A,string::const_iterator AEnd, return 1; if (B == BEnd) return -1; - if (toupper(*A) < toupper(*B)) + if (tolower_ascii(*A) < tolower_ascii(*B)) return -1; return 1; } @@ -789,28 +789,28 @@ bool ReadMessages(int Fd, vector &List) // 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. */ + Made it a bit more robust with a few tolower_ascii though. */ static int MonthConv(char *Month) { - switch (toupper(*Month)) + switch (tolower_ascii(*Month)) { - case 'A': - return toupper(Month[1]) == 'P'?3:7; - case 'D': + case 'a': + return tolower_ascii(Month[1]) == 'p'?3:7; + case 'd': return 11; - case 'F': + case 'f': return 1; - case 'J': - if (toupper(Month[1]) == 'A') + case 'j': + if (tolower_ascii(Month[1]) == 'a') return 0; - return toupper(Month[2]) == 'N'?5:6; - case 'M': - return toupper(Month[2]) == 'R'?2:4; - case 'N': + return tolower_ascii(Month[2]) == 'n'?5:6; + case 'm': + return tolower_ascii(Month[2]) == 'r'?2:4; + case 'n': return 10; - case 'O': + case 'o': return 9; - case 'S': + case 's': return 8; // Pretend it is January.. @@ -1133,10 +1133,13 @@ char *safe_snprintf(char *Buffer,char *End,const char *Format,...) // tolower_ascii - tolower() function that ignores the locale /*{{{*/ // --------------------------------------------------------------------- -/* */ -int tolower_ascii(int c) +/* This little function is the most called method we have and tries + therefore to do the absolut minimum - and is noteable faster than + standard tolower/toupper and as a bonus avoids problems with different + locales - we only operate on ascii chars anyway. */ +int tolower_ascii(int const c) { - if (c >= 'A' and c <= 'Z') + if (c >= 'A' && c <= 'Z') return c + 32; return c; } -- cgit v1.2.3 From 3f42500d6b9eb318c46cacafdcfd6beb707ef9e9 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Tue, 30 Mar 2010 14:25:57 +0200 Subject: rename ExplodeString to VectorizeString --- apt-pkg/contrib/strutl.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'apt-pkg/contrib/strutl.cc') diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index ab47cdede..7eb986ac0 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -1000,12 +1000,12 @@ bool TokSplitString(char Tok,char *Input,char **List, return true; } /*}}}*/ -// ExplodeString - Split a string up into a vector /*{{{*/ +// VectorizeString - Split a string up into a vector of strings /*{{{*/ // --------------------------------------------------------------------- /* This can be used to split a given string up into a vector, so the propose is the same as in the method above and this one is a bit slower - also, but the advantage is that we an iteratable vector */ -vector ExplodeString(string const &haystack, char const &split) + also, but the advantage is that we have an iteratable vector */ +vector VectorizeString(string const &haystack, char const &split) { string::const_iterator start = haystack.begin(); string::const_iterator end = start; -- cgit v1.2.3 From 436d7eab92bb8f9cc6498acfbf2055e717be6fd0 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Wed, 31 Mar 2010 17:19:10 +0200 Subject: Userinfo is urlencoded in URIs (RFC 3986) Thanks to Jean-Baptiste Lallement for spotting and fixing it! * apt-pkg/contrib/strutl.cc: - always escape '%' (LP: #130289) (Closes: #500560) - unescape '%' sequence only if followed by 2 hex digit - username/password are urlencoded in proxy string (RFC 3986) --- apt-pkg/contrib/strutl.cc | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'apt-pkg/contrib/strutl.cc') diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index 7eb986ac0..c7d63ce8a 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -198,7 +198,8 @@ bool ParseQuoteWord(const char *&String,string &Res) char *I; for (I = Buffer; I < Buffer + sizeof(Buffer) && Start != C; I++) { - if (*Start == '%' && Start + 2 < C) + if (*Start == '%' && Start + 2 < C && + isxdigit(Start[1]) && isxdigit(Start[2])) { Tmp[0] = Start[1]; Tmp[1] = Start[2]; @@ -273,7 +274,8 @@ string QuoteString(const string &Str, const char *Bad) for (string::const_iterator I = Str.begin(); I != Str.end(); I++) { if (strchr(Bad,*I) != 0 || isprint(*I) == 0 || - *I <= 0x20 || *I >= 0x7F) + *I == 0x25 || // percent '%' char + *I <= 0x20 || *I >= 0x7F) // control chars { char Buf[10]; sprintf(Buf,"%%%02x",(int)*I); @@ -289,11 +291,17 @@ string QuoteString(const string &Str, const char *Bad) // --------------------------------------------------------------------- /* This undoes QuoteString */ string DeQuoteString(const string &Str) +{ + return DeQuoteString(Str.begin(),Str.end()); +} +string DeQuoteString(string::const_iterator const &begin, + string::const_iterator const &end) { string Res; - for (string::const_iterator I = Str.begin(); I != Str.end(); I++) + for (string::const_iterator I = begin; I != end; I++) { - if (*I == '%' && I + 2 < Str.end()) + if (*I == '%' && I + 2 < end && + isxdigit(I[1]) && isxdigit(I[2])) { char Tmp[3]; Tmp[0] = I[1]; @@ -1238,9 +1246,10 @@ void URI::CopyFrom(const string &U) else { Host.assign(At+1,SingleSlash); - User.assign(FirstColon,SecondColon); + // username and password must be encoded (RFC 3986) + User.assign(DeQuoteString(FirstColon,SecondColon)); if (SecondColon < At) - Password.assign(SecondColon+1,At); + Password.assign(DeQuoteString(SecondColon+1,At)); } // Now we parse the RFC 2732 [] hostnames. -- cgit v1.2.3 From cd8cf88f0e64e222e9fdcbf86e6cbbe09306040e Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Tue, 8 Jun 2010 22:46:42 +0200 Subject: * apt-pkg/contrib/strutl.cc: - split StrToTime() into HTTP1.1 and FTP date parser methods and use strptime() instead of some selfmade scanf mangling --- apt-pkg/contrib/strutl.cc | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'apt-pkg/contrib/strutl.cc') diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index c7d63ce8a..96e8143ec 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -855,6 +855,42 @@ static time_t timegm(struct tm *t) } #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; + // Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 + if (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) + 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 -- cgit v1.2.3 From 550891457ff63db01b57d9057a5fe447a165e10c Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Wed, 9 Jun 2010 00:27:22 +0200 Subject: use the portable timegm shown in his manpage instead of a strange looking code copycat from wget --- apt-pkg/contrib/strutl.cc | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) (limited to 'apt-pkg/contrib/strutl.cc') diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index 96e8143ec..160450366 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -827,31 +827,27 @@ 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 , with the help of - Mark Baushke 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 /*}}}*/ -- cgit v1.2.3 From 24d7b6267ef3e475a153d4e2c4bcb30e1d14e671 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Wed, 9 Jun 2010 18:23:23 +0200 Subject: be sure that the RFC1123StrToTime method is run in a LANG=C environment --- apt-pkg/contrib/strutl.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'apt-pkg/contrib/strutl.cc') diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index 160450366..ace74cb37 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -861,12 +861,16 @@ static time_t timegm(struct tm *t) 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 - if (strptime(str, "%a, %d %b %Y %H:%M:%S %Z", &Tm) == NULL && + (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) + strptime(str, "%a %b %d %H:%M:%S %Y", &Tm) == NULL); + setlocale (LC_ALL,""); + if (invalid == true) return false; time = timegm(&Tm); -- cgit v1.2.3