##################################################################### */
/*}}}*/
// Includes /*{{{*/
+#include <config.h>
+
#include <apt-pkg/strutl.h>
#include <apt-pkg/fileutl.h>
#include <apt-pkg/error.h>
-#include <apti18n.h>
-
+#include <stddef.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string>
+#include <vector>
#include <ctype.h>
#include <string.h>
+#include <sstream>
#include <stdio.h>
#include <algorithm>
#include <unistd.h>
#include <stdarg.h>
#include <iconv.h>
-#include "config.h"
-
-using namespace std;
+#include <apti18n.h>
/*}}}*/
+using namespace std;
+// Strip - Remove white space from the front and back of a string /*{{{*/
+// ---------------------------------------------------------------------
+namespace APT {
+ namespace String {
+std::string Strip(const std::string &s)
+{
+ size_t start = s.find_first_not_of(" \t\n");
+ // only whitespace
+ if (start == string::npos)
+ return "";
+ size_t end = s.find_last_not_of(" \t\n");
+ return s.substr(start, end-start+1);
+}
+
+bool Endswith(const std::string &s, const std::string &end)
+{
+ if (end.size() > s.size())
+ return false;
+ return (s.substr(s.size() - end.size(), s.size()) == end);
+}
+
+}
+}
+ /*}}}*/
// UTF8ToCodeset - Convert some UTF-8 string for some codeset /*{{{*/
// ---------------------------------------------------------------------
/* This is handy to use before display some information for enduser */
{
iconv_t cd;
const char *inbuf;
- char *inptr, *outbuf, *outptr;
- size_t insize, outsize;
-
+ char *inptr, *outbuf;
+ size_t insize, bufsize;
+ dest->clear();
+
cd = iconv_open(codeset, "UTF-8");
if (cd == (iconv_t)(-1)) {
// Something went wrong
else
perror("iconv_open");
- // Clean the destination string
- *dest = "";
-
return false;
}
- insize = outsize = orig.size();
+ insize = bufsize = orig.size();
inbuf = orig.data();
inptr = (char *)inbuf;
- outbuf = new char[insize+1];
- outptr = outbuf;
+ outbuf = new char[bufsize];
+ size_t lastError = -1;
while (insize != 0)
{
+ char *outptr = outbuf;
+ size_t outsize = bufsize;
size_t const err = iconv(cd, &inptr, &insize, &outptr, &outsize);
+ dest->append(outbuf, outptr - outbuf);
if (err == (size_t)(-1))
{
- insize--;
- outsize++;
- inptr++;
- *outptr = '?';
- outptr++;
+ switch (errno)
+ {
+ case EILSEQ:
+ insize--;
+ inptr++;
+ // replace a series of unknown multibytes with a single "?"
+ if (lastError != insize) {
+ lastError = insize - 1;
+ dest->append("?");
+ }
+ break;
+ case EINVAL:
+ insize = 0;
+ break;
+ case E2BIG:
+ if (outptr == outbuf)
+ {
+ bufsize *= 2;
+ delete[] outbuf;
+ outbuf = new char[bufsize];
+ }
+ break;
+ }
}
}
- *outptr = '\0';
- *dest = outbuf;
delete[] outbuf;
iconv_close(cd);
if (*String == 0)
return String;
-
+ return _strrstrip(String);
+}
+ /*}}}*/
+// strrstrip - Remove white space from the back of a string /*{{{*/
+// ---------------------------------------------------------------------
+char *_strrstrip(char *String)
+{
char *End = String + strlen(String) - 1;
for (;End != String - 1 && (*End == ' ' || *End == '\t' || *End == '\n' ||
*End == '\r'); End--);
End++;
*End = 0;
return String;
-};
+}
/*}}}*/
// strtabexpand - Converts tabs into 8 spaces /*{{{*/
// ---------------------------------------------------------------------
{
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;
}
}
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];
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 <= 0x20 || *I >= 0x7F)
+ *I == 0x25 || // percent '%' char
+ *I <= 0x20 || *I >= 0x7F) // control chars
{
char Buf[10];
sprintf(Buf,"%%%02x",(int)*I);
// ---------------------------------------------------------------------
/* 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];
{
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;
/*}}}*/
// SubstVar - Substitute a string for another string /*{{{*/
// ---------------------------------------------------------------------
-/* This replaces all occurances of Subst with Contents in Str. */
+/* This replaces all occurrences of Subst with Contents in Str. */
string SubstVar(const string &Str,const string &Subst,const string &Contents)
{
string::size_type Pos = 0;
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)
return 1;
if (B == BEnd)
return -1;
- if (toupper(*A) < toupper(*B))
+ if (tolower_ascii(*A) < tolower_ascii(*B))
return -1;
return 1;
}
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)
return 1;
if (B == BEnd)
return -1;
- if (toupper(*A) < toupper(*B))
+ if (tolower_ascii(*A) < tolower_ascii(*B))
return -1;
return 1;
}
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)
return 1;
if (B == BEnd)
return -1;
- if (toupper(*A) < toupper(*B))
+ if (tolower_ascii(*A) < tolower_ascii(*B))
return -1;
return 1;
}
{
// 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)
// 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
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;
// Look for the end of the message
for (char *I = Buffer; I + 1 < End; I++)
{
- if (I[0] != '\n' || I[1] != '\n')
+ if (I[1] != '\n' ||
+ (I[0] != '\n' && strncmp(I, "\r\n\r\n", 4) != 0))
continue;
// Pull the message out
PartialMessage += Message;
// Fix up the buffer
- for (; I < End && *I == '\n'; I++);
+ for (; I < End && (*I == '\n' || *I == '\r'); ++I);
End -= I-Buffer;
memmove(Buffer,I,End-Buffer);
I = Buffer;
// 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..
}
}
/*}}}*/
-// 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 <beeman@cisco.com>, with the help of
- Mark Baushke <mdb@cisco.com> 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
+/* This handles all 3 popular 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 :< This also
{
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
Tm.tm_isdst = 0;
if (Month[0] != 0)
Tm.tm_mon = MonthConv(Month);
+ else
+ Tm.tm_mon = 0; // we don't have a month, so pick something
Tm.tm_year -= 1900;
// Convert to local time and then to GMT
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 */
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<string> ExplodeString(string const &haystack, char const &split) {
- string::const_iterator start = haystack.begin();
- string::const_iterator end = start;
- vector<string> exploded;
- do {
- for (; end != haystack.end() && *end != split; ++end);
- exploded.push_back(string(start, end));
- start = end;
- } while (end != haystack.end() && (++end) != haystack.end());
- return exploded;
+ also, but the advantage is that we have an iteratable vector */
+vector<string> VectorizeString(string const &haystack, char const &split)
+{
+ vector<string> exploded;
+ if (haystack.empty() == true)
+ return exploded;
+ string::const_iterator start = haystack.begin();
+ string::const_iterator end = start;
+ 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;
+}
+ /*}}}*/
+// StringSplit - split a string into a string vector by token /*{{{*/
+// ---------------------------------------------------------------------
+/* See header for details.
+ */
+vector<string> StringSplit(std::string const &s, std::string const &sep,
+ unsigned int maxsplit)
+{
+ vector<string> split;
+ size_t start, pos;
+
+ // no seperator given, this is bogus
+ if(sep.size() == 0)
+ return split;
+
+ start = pos = 0;
+ while (pos != string::npos)
+ {
+ pos = s.find(sep, start);
+ split.push_back(s.substr(start, pos-start));
+
+ // if maxsplit is reached, the remaining string is the last item
+ if(split.size() >= maxsplit)
+ {
+ split[split.size()-1] = s.substr(start);
+ break;
+ }
+ start = pos+sep.size();
+ }
+ return split;
}
/*}}}*/
// RegexChoice - Simple regex list/list matcher /*{{{*/
R->Hit = false;
unsigned long Hits = 0;
- for (; ListBegin != ListEnd; ListBegin++)
+ for (; ListBegin < ListEnd; ++ListBegin)
{
// Check if the name is a regex
const char *I;
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 /*{{{*/
char *safe_snprintf(char *Buffer,char *End,const char *Format,...)
{
va_list args;
- unsigned long Did;
-
- va_start(args,Format);
+ int Did;
if (End <= Buffer)
return End;
-
+ va_start(args,Format);
Did = vsnprintf(Buffer,End - Buffer,Format,args);
+ va_end(args);
+
if (Did < 0 || Buffer + Did > End)
return End;
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 notable 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;
}
/*}}}*/
-// CheckDomainList - See if Host is in a , seperate list /*{{{*/
+// CheckDomainList - See if Host is in a , separate list /*{{{*/
// ---------------------------------------------------------------------
-/* The domain list is a comma seperate list of domains that are suffix
+/* The domain list is a comma separate list of domains that are suffix
matched against the argument */
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;
return false;
}
/*}}}*/
+// strv_length - Return the length of a NULL-terminated string array /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+size_t strv_length(const char **str_array)
+{
+ size_t i;
+ for (i=0; str_array[i] != NULL; i++)
+ /* nothing */
+ ;
+ return i;
+}
+// DeEscapeString - unescape (\0XX and \xXX) from a string /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string DeEscapeString(const string &input)
+{
+ char tmp[3];
+ string::const_iterator it;
+ string output;
+ 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 */
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 //
/* 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;
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
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.
if (User.empty() == false)
{
- Res += User;
+ // FIXME: Technically userinfo is permitted even less
+ // characters than these, but this is not conveniently
+ // expressed with a blacklist.
+ Res += QuoteString(User, ":/?#[]@");
if (Password.empty() == false)
- Res += ":" + Password;
+ Res += ":" + QuoteString(Password, ":/?#[]@");
Res += "@";
}
U.User.clear();
U.Password.clear();
U.Path.clear();
- U.Port = 0;
+ return U;
+}
+ /*}}}*/
+// URI::NoUserPassword - Return the schema, site and path for the URI /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string URI::NoUserPassword(const string &URI)
+{
+ ::URI U(URI);
+ U.User.clear();
+ U.Password.clear();
return U;
}
/*}}}*/