X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/6360cbb001dc73a11c39e752aaf1fcd5fbf6504f..4e1c86a6c0cf9a6e51ec4f9b9ad9271547fa036d:/apt-pkg/contrib/strutl.cc diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index b54758632..ca096d736 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -15,14 +15,15 @@ ##################################################################### */ /*}}}*/ // Includes /*{{{*/ +#include + #include #include #include -#include - #include #include +#include #include #include #include @@ -31,7 +32,7 @@ #include #include -#include "config.h" +#include using namespace std; /*}}}*/ @@ -179,14 +180,14 @@ bool ParseQuoteWord(const char *&String,string &Res) { if (*C == '"') { - for (C++; *C != 0 && *C != '"'; C++); - if (*C == 0) + C = strchr(C + 1, '"'); + if (C == NULL) return false; } if (*C == '[') { - for (C++; *C != 0 && *C != ']'; C++); - if (*C == 0) + C = strchr(C + 1, ']'); + if (C == NULL) return false; } } @@ -271,7 +272,7 @@ bool ParseCWord(const char *&String,string &Res) string QuoteString(const string &Str, const char *Bad) { string Res; - for (string::const_iterator I = Str.begin(); I != Str.end(); I++) + for (string::const_iterator I = Str.begin(); I != Str.end(); ++I) { if (strchr(Bad,*I) != 0 || isprint(*I) == 0 || *I == 0x25 || // percent '%' char @@ -298,7 +299,7 @@ string DeQuoteString(string::const_iterator const &begin, string::const_iterator const &end) { string Res; - for (string::const_iterator I = begin; I != end; I++) + for (string::const_iterator I = begin; I != end; ++I) { if (*I == '%' && I + 2 < end && isxdigit(I[1]) && isxdigit(I[2])) @@ -340,13 +341,13 @@ string SizeToStr(double Size) { if (ASize < 100 && I != 0) { - sprintf(S,"%'.1f%c",ASize,Ext[I]); + sprintf(S,"%'.1f %c",ASize,Ext[I]); break; } if (ASize < 10000) { - sprintf(S,"%'.0f%c",ASize,Ext[I]); + sprintf(S,"%'.0f %c",ASize,Ext[I]); break; } ASize /= 1000.0; @@ -574,7 +575,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) @@ -583,7 +584,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; } @@ -592,7 +593,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) @@ -601,7 +602,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; } @@ -609,7 +610,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) @@ -618,7 +619,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; } @@ -632,7 +633,7 @@ string LookupTag(const string &Message,const char *Tag,const char *Default) { // Look for a matching tag. int Length = strlen(Tag); - for (string::const_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) @@ -640,14 +641,14 @@ string LookupTag(const string &Message,const char *Tag,const char *Default) // Find the end of line and strip the leading/trailing spaces string::const_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--); + 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); } - for (; *I != '\n' && I < Message.end(); I++); + for (; *I != '\n' && I < Message.end(); ++I); } // Failed to find a match @@ -692,14 +693,16 @@ int StringToBool(const string &Text,int Default) year 2000 complient and timezone neutral */ string TimeRFC1123(time_t Date) { - struct tm Conv = *gmtime(&Date); - char Buf[300]; + struct tm Conv; + if (gmtime_r(&Date, &Conv) == NULL) + return ""; + 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], + snprintf(Buf, sizeof(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; @@ -797,28 +800,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.. @@ -827,34 +830,70 @@ 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 /*}}}*/ +// 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; + setlocale (LC_ALL,"C"); + bool const invalid = + // Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 + (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); + setlocale (LC_ALL,""); + if (invalid == true) + 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 @@ -866,24 +905,23 @@ bool StrToTime(const 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++); - + const char *I = strchr(Val.c_str(), ' '); + // Handle RFC 1123 time Month[0] = 0; - if (sscanf(I," %d %3s %d %d:%d:%d GMT",&Tm.tm_mday,Month,&Tm.tm_year, + if (sscanf(I," %2d %3s %4d %2d:%2d:%2d 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, + if (sscanf(I," %2d-%3s-%3d %2d:%2d:%2d 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, + if (sscanf(I," %3s %2d %2d:%2d:%2d %4d",Month,&Tm.tm_mday, &Tm.tm_hour,&Tm.tm_min,&Tm.tm_sec,&Tm.tm_year) != 6) { // 'ftp' time @@ -932,6 +970,51 @@ bool StrToNum(const char *Str,unsigned long &Res,unsigned Len,unsigned Base) 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 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 = strtoull(S,&End,Base); + if (End == S) + return false; + + return true; +} + /*}}}*/ + +// Base256ToNum - Convert a fixed length binary to a number /*{{{*/ +// --------------------------------------------------------------------- +/* This is used in decoding the 256bit encoded fixed length fields in + tar files */ +bool Base256ToNum(const char *Str,unsigned long &Res,unsigned int Len) +{ + if ((Str[0] & 0x80) == 0) + return false; + else + { + Res = Str[0] & 0x7F; + for(unsigned int i = 1; i < Len; ++i) + Res = (Res<<8) + Str[i]; + return true; + } +} + /*}}}*/ // HexDigit - Convert a hex character into an integer /*{{{*/ // --------------------------------------------------------------------- /* Helper for Hex2Num */ @@ -1008,6 +1091,24 @@ bool TokSplitString(char Tok,char *Input,char **List, return true; } /*}}}*/ +// 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 have an iteratable vector */ +vector VectorizeString(string const &haystack, char const &split) +{ + string::const_iterator start = haystack.begin(); + string::const_iterator end = start; + vector exploded; + do { + for (; end != haystack.end() && *end != split; ++end); + exploded.push_back(string(start, end)); + start = end + 1; + } while (end != haystack.end() && (++end) != haystack.end()); + return exploded; +} + /*}}}*/ // RegexChoice - Simple regex list/list matcher /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -1068,34 +1169,50 @@ unsigned long RegexChoice(RxChoiceList *Rxs,const char **ListBegin, return Hits; } /*}}}*/ -// ioprintf - C format string outputter to C++ iostreams /*{{{*/ +// {str,io}printf - C format string outputter to C++ strings/iostreams /*{{{*/ // --------------------------------------------------------------------- /* This is used to make the internationalization strings easier to translate and to allow reordering of parameters */ -void ioprintf(ostream &out,const char *format,...) +static bool iovprintf(ostream &out, const char *format, + va_list &args, ssize_t &size) { + char *S = (char*)malloc(size); + ssize_t const n = vsnprintf(S, size, format, args); + if (n > -1 && n < size) { + out << S; + free(S); + return true; + } else { + if (n > -1) + size = n + 1; + else + size *= 2; + } + free(S); + return false; +} +void ioprintf(ostream &out,const char *format,...) { va_list args; - va_start(args,format); - - // sprintf the description - char S[4096]; - vsnprintf(S,sizeof(S),format,args); - out << S; + ssize_t size = 400; + while (true) { + va_start(args,format); + if (iovprintf(out, format, args, size) == true) + return; + va_end(args); + } } - /*}}}*/ -// strprintf - C format string outputter to C++ strings /*{{{*/ -// --------------------------------------------------------------------- -/* This is used to make the internationalization strings easier to translate - and to allow reordering of parameters */ -void strprintf(string &out,const char *format,...) +void strprintf(string &out,const char *format,...) { va_list args; - va_start(args,format); - - // sprintf the description - char S[4096]; - vsnprintf(S,sizeof(S),format,args); - out = string(S); + ssize_t size = 400; + std::ostringstream outstr; + while (true) { + va_start(args,format); + if (iovprintf(outstr, format, args, size) == true) + break; + va_end(args); + } + out = outstr.str(); } /*}}}*/ // safe_snprintf - Safer snprintf /*{{{*/ @@ -1107,7 +1224,7 @@ void strprintf(string &out,const char *format,...) char *safe_snprintf(char *Buffer,char *End,const char *Format,...) { va_list args; - unsigned long Did; + int Did; va_start(args,Format); @@ -1120,13 +1237,25 @@ char *safe_snprintf(char *Buffer,char *End,const char *Format,...) return Buffer + Did; } /*}}}*/ +// StripEpoch - Remove the version "epoch" from a version string /*{{{*/ +// --------------------------------------------------------------------- +string StripEpoch(const string &VerStr) +{ + size_t i = VerStr.find(":"); + if (i == string::npos) + return VerStr; + return VerStr.substr(i+1); +} // 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; } @@ -1139,7 +1268,7 @@ int tolower_ascii(int c) 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++) + for (string::const_iterator Cur = List.begin(); Cur <= List.end(); ++Cur) { if (Cur < List.end() && *Cur != ',') continue; @@ -1155,7 +1284,68 @@ bool CheckDomainList(const string &Host,const string &List) return false; } /*}}}*/ +// DeEscapeString - unescape (\0XX and \xXX) from a string /*{{{*/ +// --------------------------------------------------------------------- +/* */ +string DeEscapeString(const string &input) +{ + char tmp[3]; + string::const_iterator it, escape_start; + string output, octal, hex; + for (it = input.begin(); it != input.end(); ++it) + { + // just copy non-escape chars + if (*it != '\\') + { + output += *it; + continue; + } + + // deal with double escape + if (*it == '\\' && + (it + 1 < input.end()) && it[1] == '\\') + { + // copy + output += *it; + // advance iterator one step further + ++it; + continue; + } + + // ensure we have a char to read + if (it + 1 == input.end()) + continue; + // read it + ++it; + switch (*it) + { + case '0': + if (it + 2 <= input.end()) { + tmp[0] = it[1]; + tmp[1] = it[2]; + tmp[2] = 0; + output += (char)strtol(tmp, 0, 8); + it += 2; + } + break; + case 'x': + if (it + 2 <= input.end()) { + tmp[0] = it[1]; + tmp[1] = it[2]; + tmp[2] = 0; + output += (char)strtol(tmp, 0, 16); + it += 2; + } + break; + default: + // FIXME: raise exception here? + break; + } + } + return output; +} + /*}}}*/ // URI::CopyFrom - Copy from an object /*{{{*/ // --------------------------------------------------------------------- /* This parses the URI into all of its components */ @@ -1164,7 +1354,7 @@ void URI::CopyFrom(const string &U) string::const_iterator I = U.begin(); // Locate the first colon, this separates the scheme - for (; I < U.end() && *I != ':' ; I++); + for (; I < U.end() && *I != ':' ; ++I); string::const_iterator FirstColon = I; /* Determine if this is a host type URI with a leading double // @@ -1176,7 +1366,7 @@ void URI::CopyFrom(const string &U) /* 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++) + for (; SingleSlash < U.end() && (*SingleSlash != '/' || InBracket == true); ++SingleSlash) { if (*SingleSlash == '[') InBracket = true; @@ -1209,11 +1399,11 @@ void URI::CopyFrom(const string &U) I = FirstColon + 1; if (I > SingleSlash) I = SingleSlash; - for (; I < SingleSlash && *I != ':'; I++); + for (; I < SingleSlash && *I != ':'; ++I); string::const_iterator SecondColon = I; // Search for the @ after the colon - for (; I < SingleSlash && *I != '@'; I++); + for (; I < SingleSlash && *I != '@'; ++I); string::const_iterator At = I; // Now write the host and user/pass