X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/8efa2a3ba4ae833415223a888e4561e57e4bf132..93bf083d699c60f1ac40297bfa6783fb0cb800d8:/apt-pkg/contrib/strutl.cc diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index 8c1f7005c..d6a7143e4 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -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 + It was originally written by Jason Gunthorpe ##################################################################### */ /*}}}*/ // Includes /*{{{*/ #include +#include + #include #include #include +#include /*}}}*/ // 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 &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; +} + /*}}}*/