123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854 |
- // -*- mode: cpp; mode: fold -*-
- // Description /*{{{*/
- // $Id: strutl.cc,v 1.4 1999/10/24 06:53:12 jgg Exp $
- /* ######################################################################
- String Util - Some usefull string functions.
- 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 <jgg@gpu.srv.ualberta.ca>
-
- ##################################################################### */
- /*}}}*/
- // Includes /*{{{*/
- #ifdef __GNUG__
- #pragma implementation "dsync/strutl.h"
- #endif
- #include <dsync/strutl.h>
- #include <dsync/fileutl.h>
- #include <ctype.h>
- #include <string.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <errno.h>
- /*}}}*/
- // 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
- over from fgets and company */
- char *_strstrip(char *String)
- {
- for (;*String != 0 && (*String == ' ' || *String == '\t'); String++);
- if (*String == 0)
- return 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 /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- char *_strtabexpand(char *String,size_t Len)
- {
- for (char *I = String; I != I + Len && *I != 0; I++)
- {
- if (*I != '\t')
- continue;
- if (I + 8 > String + Len)
- {
- *I = 0;
- return String;
- }
- /* Assume the start of the string is 0 and find the next 8 char
- division */
- int Len;
- if (String == I)
- Len = 1;
- else
- Len = 8 - ((String - I) % 8);
- Len -= 2;
- if (Len <= 0)
- {
- *I = ' ';
- continue;
- }
-
- memmove(I + Len,I + 1,strlen(I) + 1);
- for (char *J = I; J + Len != I; *I = ' ', I++);
- }
- return String;
- }
- /*}}}*/
- // ParseQuoteWord - Parse a single word out of a string /*{{{*/
- // ---------------------------------------------------------------------
- /* 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. This is for URI/URL parsing. */
- bool ParseQuoteWord(const char *&String,string &Res)
- {
- // Skip leading whitespace
- const char *C = String;
- for (;*C != 0 && *C == ' '; C++);
- if (*C == 0)
- return false;
-
- // Jump to the next word
- for (;*C != 0 && isspace(*C) == 0; C++)
- {
- if (*C == '"')
- {
- for (C++;*C != 0 && *C != '"'; C++);
- if (*C == 0)
- return false;
- }
- }
- // Now de-quote characters
- char Buffer[1024];
- char Tmp[3];
- const char *Start = String;
- char *I;
- for (I = Buffer; I < Buffer + sizeof(Buffer) && Start != C; I++)
- {
- if (*Start == '%' && Start + 2 < C)
- {
- Tmp[0] = Start[1];
- Tmp[1] = Start[2];
- Tmp[2] = 0;
- *I = (char)strtol(Tmp,0,16);
- Start += 3;
- continue;
- }
- if (*Start != '"')
- *I = *Start;
- else
- I--;
- Start++;
- }
- *I = 0;
- Res = Buffer;
-
- // Skip ending white space
- for (;*C != 0 && isspace(*C) != 0; C++);
- String = C;
- return true;
- }
- /*}}}*/
- // ParseCWord - Parses a string like a C "" expression /*{{{*/
- // ---------------------------------------------------------------------
- /* This expects a series of space separated 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 /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- string QuoteString(string Str,const char *Bad)
- {
- string Res;
- for (string::iterator I = Str.begin(); I != Str.end(); I++)
- {
- if (strchr(Bad,*I) != 0 || isprint(*I) == 0 ||
- *I <= 0x20 || *I >= 0x7F)
- {
- char Buf[10];
- sprintf(Buf,"%%%02x",(int)*I);
- Res += Buf;
- }
- else
- Res += *I;
- }
- return Res;
- }
- /*}}}*/
- // DeQuoteString - Convert a string from quoted from /*{{{*/
- // ---------------------------------------------------------------------
- /* This undoes QuoteString */
- string DeQuoteString(string Str)
- {
- string Res;
- for (string::iterator I = Str.begin(); I != Str.end(); I++)
- {
- if (*I == '%' && I + 2 < Str.end())
- {
- char Tmp[3];
- Tmp[0] = I[1];
- Tmp[1] = I[2];
- Tmp[2] = 0;
- Res += (char)strtol(Tmp,0,16);
- I += 2;
- continue;
- }
- else
- Res += *I;
- }
- return Res;
- }
- /*}}}*/
- // 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
- YottaBytes (E24) */
- string SizeToStr(double Size)
- {
- char S[300];
- double ASize;
- if (Size >= 0)
- ASize = Size;
- else
- ASize = -1*Size;
-
- /* bytes, KiloBytes, MegaBytes, GigaBytes, TeraBytes, PetaBytes,
- ExaBytes, ZettaBytes, YottaBytes */
- char Ext[] = {'\0','k','M','G','T','P','E','Z','Y'};
- int I = 0;
- while (I <= 8)
- {
- if (ASize < 100 && I != 0)
- {
- sprintf(S,"%.1f%c",ASize,Ext[I]);
- break;
- }
-
- if (ASize < 10000)
- {
- sprintf(S,"%.0f%c",ASize,Ext[I]);
- break;
- }
- ASize /= 1000.0;
- I++;
- }
-
- return S;
- }
- /*}}}*/
- // TimeToStr - Convert the time into a string /*{{{*/
- // ---------------------------------------------------------------------
- /* Converts a number of seconds to a hms format */
- string TimeToStr(unsigned long Sec)
- {
- char S[300];
-
- while (1)
- {
- if (Sec > 60*60*24)
- {
- sprintf(S,"%lid %lih%lim%lis",Sec/60/60/24,(Sec/60/60) % 24,(Sec/60) % 60,Sec % 60);
- break;
- }
-
- if (Sec > 60*60)
- {
- sprintf(S,"%lih%lim%lis",Sec/60/60,(Sec/60) % 60,Sec % 60);
- break;
- }
-
- if (Sec > 60)
- {
- sprintf(S,"%lim%lis",Sec/60,Sec % 60);
- break;
- }
-
- sprintf(S,"%lis",Sec);
- break;
- }
-
- return S;
- }
- /*}}}*/
- // 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::size_type Pos = 0;
- string::size_type OldPos = 0;
- string Temp;
-
- while (OldPos < Str.length() &&
- (Pos = Str.find(Subst,OldPos)) != string::npos)
- {
- Temp += string(Str,OldPos,Pos) + Contents;
- OldPos = Pos + Subst.length();
- }
-
- if (OldPos == 0)
- return Str;
-
- 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)
- {
- // Nuke 'sensitive' items
- ::URI U(URI);
- U.User = string();
- U.Password = string();
- U.Access = "";
-
- // "\x00-\x20{}|\\\\^\\[\\]<>\"\x7F-\xFF";
- URI = QuoteString(U,"\\|{}[]<>\"^~_=!@#$%^&*");
- 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
- from wget and then patched and bug fixed.
-
- This spec can be found in rfc2045 */
- string Base64Encode(string S)
- {
- // Conversion table.
- static char tbl[64] = {'A','B','C','D','E','F','G','H',
- 'I','J','K','L','M','N','O','P',
- 'Q','R','S','T','U','V','W','X',
- 'Y','Z','a','b','c','d','e','f',
- 'g','h','i','j','k','l','m','n',
- 'o','p','q','r','s','t','u','v',
- 'w','x','y','z','0','1','2','3',
- '4','5','6','7','8','9','+','/'};
-
- // Pre-allocate some space
- string Final;
- Final.reserve((4*S.length() + 2)/3 + 2);
- /* Transform the 3x8 bits to 4x6 bits, as required by
- base64. */
- for (string::const_iterator I = S.begin(); I < S.end(); I += 3)
- {
- char Bits[3] = {0,0,0};
- Bits[0] = I[0];
- if (I + 1 < S.end())
- Bits[1] = I[1];
- if (I + 2 < S.end())
- Bits[2] = I[2];
- Final += tbl[Bits[0] >> 2];
- Final += tbl[((Bits[0] & 3) << 4) + (Bits[1] >> 4)];
-
- if (I + 1 >= S.end())
- break;
-
- Final += tbl[((Bits[1] & 0xf) << 2) + (Bits[2] >> 6)];
-
- if (I + 2 >= S.end())
- break;
-
- Final += tbl[Bits[2] & 0x3f];
- }
- /* Apply the padding elements, this tells how many bytes the remote
- end should discard */
- if (S.length() % 3 == 2)
- Final += '=';
- if (S.length() % 3 == 1)
- Final += "==";
-
- return Final;
- }
- /*}}}*/
- // stringcmp - Arbitary string compare /*{{{*/
- // ---------------------------------------------------------------------
- /* This safely compares two non-null terminated strings of arbitary
- length */
- int stringcmp(const char *A,const char *AEnd,const char *B,const char *BEnd)
- {
- for (; A != AEnd && B != BEnd; A++, B++)
- if (*A != *B)
- break;
-
- if (A == AEnd && B == BEnd)
- return 0;
- if (A == AEnd)
- return 1;
- if (B == BEnd)
- return -1;
- if (*A < *B)
- return -1;
- return 1;
- }
- /*}}}*/
- // stringcasecmp - Arbitary case insensitive string compare /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- 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)
- return 1;
- if (B == BEnd)
- return -1;
- if (toupper(*A) < toupper(*B))
- return -1;
- 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
- const char *i = Message.c_str() + (I - Message.begin());
- 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)
- {
- 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(),"off") == 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(),"on") == 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<string> &List)
- {
- char Buffer[4000];
- char *End = Buffer;
-
- while (1)
- {
- int Res = read(Fd,End,sizeof(Buffer) - (End-Buffer));
- if (Res < 0 && errno == EINTR)
- continue;
-
- // 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;
- }
- }
- /*}}}*/
- // timegm - Internal timegm function if gnu 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
- 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. */
- #ifndef __USE_MISC // glib sets this
- 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)));
- }
- #endif
- /*}}}*/
- // 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;
- }
- /*}}}*/
- // 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 &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 = strtoul(S,&End,Base);
- if (End == S)
- return false;
-
- return true;
- }
- /*}}}*/
- // HexDigit - Convert a hex character into an integer /*{{{*/
- // ---------------------------------------------------------------------
- /* Helper for Hex2Num */
- static int HexDigit(int c)
- {
- if (c >= '0' && c <= '9')
- return c - '0';
- if (c >= 'a' && c <= 'f')
- return c - 'a' + 10;
- if (c >= 'A' && c <= 'F')
- return c - 'A' + 10;
- return 0;
- }
- /*}}}*/
- // 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(const char *Start,const char *End,unsigned char *Num,
- unsigned int Length)
- {
- if (End - Start != (signed)(Length*2))
- return false;
-
- // Convert each digit. We store it in the same order as the string
- int J = 0;
- for (const char *I = Start; I < End;J++, I += 2)
- {
- if (isxdigit(*I) == 0 || isxdigit(I[1]) == 0)
- return false;
-
- Num[J] = HexDigit(I[0]) << 4;
- Num[J] += HexDigit(I[1]);
- }
-
- return true;
- }
- /*}}}*/
- // URI::CopyFrom - Copy from an object /*{{{*/
- // ---------------------------------------------------------------------
- /* This parses the URI into all of its components */
- void URI::CopyFrom(string U)
- {
- string::const_iterator I = U.begin();
- // Locate the first colon, this separates 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 //
- and then search for the first single / */
- string::const_iterator SingleSlash = I;
- if (I + 3 < U.end() && I[1] == '/' && I[2] == '/')
- SingleSlash += 3;
- for (; SingleSlash < U.end() && *SingleSlash != '/'; SingleSlash++);
- if (SingleSlash > U.end())
- SingleSlash = U.end();
- // 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());
- if (Path.empty() == true)
- Path = "/";
- // Now we attempt to locate a user:pass@host fragment
- if (FirstColon[1] == '/' && FirstColon[2] == '/')
- FirstColon += 3;
- else
- FirstColon += 1;
- if (FirstColon >= U.end())
- return;
-
- if (FirstColon > SingleSlash)
- FirstColon = SingleSlash;
-
- // Find the colon...
- I = FirstColon + 1;
- if (I > SingleSlash)
- I = SingleSlash;
- for (; I < SingleSlash && *I != ':'; I++);
- string::const_iterator SecondColon = I;
-
- // Search for the @ after the colon
- for (; I < SingleSlash && *I != '@'; I++);
- string::const_iterator At = 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 port 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;
-
- if (Access.empty() == false)
- Res = Access + ':';
-
- if (Host.empty() == false)
- {
- if (Access.empty() == false)
- Res += "//";
-
- if (User.empty() == false)
- {
- Res += User;
- if (Password.empty() == false)
- Res += ":" + Password;
- Res += "@";
- }
-
- Res += Host;
- if (Port != 0)
- {
- char S[30];
- sprintf(S,":%u",Port);
- Res += S;
- }
- }
-
- if (Path.empty() == false)
- {
- if (Path[0] != '/')
- Res += "/" + Path;
- else
- Res += Path;
- }
-
- return Res;
- }
- /*}}}*/
|