1 // -*- mode: cpp; mode: fold -*-
3 // $Id: strutl.cc,v 1.48 2003/07/18 14:15:11 mdz Exp $
4 /* ######################################################################
6 String Util - Some useful string functions.
8 These have been collected from here and there to do all sorts of useful
9 things to strings. They are useful in file parsers, URI handlers and
10 especially in APT methods.
12 This source is placed in the Public Domain, do with it what you will
13 It was originally written by Jason Gunthorpe <jgg@gpu.srv.ualberta.ca>
15 ##################################################################### */
19 #pragma implementation "apt-pkg/strutl.h"
22 #include <apt-pkg/strutl.h>
23 #include <apt-pkg/fileutl.h>
24 #include <apt-pkg/error.h>
42 // UTF8ToCodeset - Convert some UTF-8 string for some codeset /*{{{*/
43 // ---------------------------------------------------------------------
44 /* This is handy to use before display some information for enduser */
45 bool UTF8ToCodeset(const char *codeset
, const string
&orig
, string
*dest
)
49 char *inptr
, *outbuf
, *outptr
;
50 size_t insize
, outsize
;
52 cd
= iconv_open(codeset
, "UTF-8");
53 if (cd
== (iconv_t
)(-1)) {
54 // Something went wrong
56 _error
->Error("conversion from 'UTF-8' to '%s' not available",
61 // Clean the destination string
67 insize
= outsize
= orig
.size();
69 inptr
= (char *)inbuf
;
70 outbuf
= new char[insize
+1];
73 iconv(cd
, &inptr
, &insize
, &outptr
, &outsize
);
84 // strstrip - Remove white space from the front and back of a string /*{{{*/
85 // ---------------------------------------------------------------------
86 /* This is handy to use when parsing a file. It also removes \n's left
87 over from fgets and company */
88 char *_strstrip(char *String
)
90 for (;*String
!= 0 && (*String
== ' ' || *String
== '\t'); String
++);
95 char *End
= String
+ strlen(String
) - 1;
96 for (;End
!= String
- 1 && (*End
== ' ' || *End
== '\t' || *End
== '\n' ||
97 *End
== '\r'); End
--);
103 // strtabexpand - Converts tabs into 8 spaces /*{{{*/
104 // ---------------------------------------------------------------------
106 char *_strtabexpand(char *String
,size_t Len
)
108 for (char *I
= String
; I
!= I
+ Len
&& *I
!= 0; I
++)
112 if (I
+ 8 > String
+ Len
)
118 /* Assume the start of the string is 0 and find the next 8 char
124 Len
= 8 - ((String
- I
) % 8);
132 memmove(I
+ Len
,I
+ 1,strlen(I
) + 1);
133 for (char *J
= I
; J
+ Len
!= I
; *I
= ' ', I
++);
138 // ParseQuoteWord - Parse a single word out of a string /*{{{*/
139 // ---------------------------------------------------------------------
140 /* This grabs a single word, converts any % escaped characters to their
141 proper values and advances the pointer. Double quotes are understood
142 and striped out as well. This is for URI/URL parsing. It also can
143 understand [] brackets.*/
144 bool ParseQuoteWord(const char *&String
,string
&Res
)
146 // Skip leading whitespace
147 const char *C
= String
;
148 for (;*C
!= 0 && *C
== ' '; C
++);
152 // Jump to the next word
153 for (;*C
!= 0 && isspace(*C
) == 0; C
++)
157 for (C
++; *C
!= 0 && *C
!= '"'; C
++);
163 for (C
++; *C
!= 0 && *C
!= ']'; C
++);
169 // Now de-quote characters
172 const char *Start
= String
;
174 for (I
= Buffer
; I
< Buffer
+ sizeof(Buffer
) && Start
!= C
; I
++)
176 if (*Start
== '%' && Start
+ 2 < C
)
181 *I
= (char)strtol(Tmp
,0,16);
194 // Skip ending white space
195 for (;*C
!= 0 && isspace(*C
) != 0; C
++);
200 // ParseCWord - Parses a string like a C "" expression /*{{{*/
201 // ---------------------------------------------------------------------
202 /* This expects a series of space separated strings enclosed in ""'s.
203 It concatenates the ""'s into a single string. */
204 bool ParseCWord(const char *&String
,string
&Res
)
206 // Skip leading whitespace
207 const char *C
= String
;
208 for (;*C
!= 0 && *C
== ' '; C
++);
214 if (strlen(String
) >= sizeof(Buffer
))
221 for (C
++; *C
!= 0 && *C
!= '"'; C
++)
230 if (C
!= String
&& isspace(*C
) != 0 && isspace(C
[-1]) != 0)
232 if (isspace(*C
) == 0)
242 // QuoteString - Convert a string into quoted from /*{{{*/
243 // ---------------------------------------------------------------------
245 string
QuoteString(const string
&Str
, const char *Bad
)
248 for (string::const_iterator I
= Str
.begin(); I
!= Str
.end(); I
++)
250 if (strchr(Bad
,*I
) != 0 || isprint(*I
) == 0 ||
251 *I
<= 0x20 || *I
>= 0x7F)
254 sprintf(Buf
,"%%%02x",(int)*I
);
263 // DeQuoteString - Convert a string from quoted from /*{{{*/
264 // ---------------------------------------------------------------------
265 /* This undoes QuoteString */
266 string
DeQuoteString(const string
&Str
)
269 for (string::const_iterator I
= Str
.begin(); I
!= Str
.end(); I
++)
271 if (*I
== '%' && I
+ 2 < Str
.end())
277 Res
+= (char)strtol(Tmp
,0,16);
288 // SizeToStr - Convert a long into a human readable size /*{{{*/
289 // ---------------------------------------------------------------------
290 /* A max of 4 digits are shown before conversion to the next highest unit.
291 The max length of the string will be 5 chars unless the size is > 10
293 string
SizeToStr(double Size
)
302 /* bytes, KiloBytes, MegaBytes, GigaBytes, TeraBytes, PetaBytes,
303 ExaBytes, ZettaBytes, YottaBytes */
304 char Ext
[] = {'\0','k','M','G','T','P','E','Z','Y'};
308 if (ASize
< 100 && I
!= 0)
310 sprintf(S
,"%.1f%c",ASize
,Ext
[I
]);
316 sprintf(S
,"%.0f%c",ASize
,Ext
[I
]);
326 // TimeToStr - Convert the time into a string /*{{{*/
327 // ---------------------------------------------------------------------
328 /* Converts a number of seconds to a hms format */
329 string
TimeToStr(unsigned long Sec
)
337 sprintf(S
,"%lid %lih%lim%lis",Sec
/60/60/24,(Sec
/60/60) % 24,(Sec
/60) % 60,Sec
% 60);
343 sprintf(S
,"%lih%lim%lis",Sec
/60/60,(Sec
/60) % 60,Sec
% 60);
349 sprintf(S
,"%lim%lis",Sec
/60,Sec
% 60);
353 sprintf(S
,"%lis",Sec
);
360 // SubstVar - Substitute a string for another string /*{{{*/
361 // ---------------------------------------------------------------------
362 /* This replaces all occurances of Subst with Contents in Str. */
363 string
SubstVar(const string
&Str
,const string
&Subst
,const string
&Contents
)
365 string::size_type Pos
= 0;
366 string::size_type OldPos
= 0;
369 while (OldPos
< Str
.length() &&
370 (Pos
= Str
.find(Subst
,OldPos
)) != string::npos
)
372 Temp
+= string(Str
,OldPos
,Pos
) + Contents
;
373 OldPos
= Pos
+ Subst
.length();
379 return Temp
+ string(Str
,OldPos
);
382 string
SubstVar(string Str
,const struct SubstVar
*Vars
)
384 for (; Vars
->Subst
!= 0; Vars
++)
385 Str
= SubstVar(Str
,Vars
->Subst
,*Vars
->Contents
);
389 // URItoFileName - Convert the uri into a unique file name /*{{{*/
390 // ---------------------------------------------------------------------
391 /* This converts a URI into a safe filename. It quotes all unsafe characters
392 and converts / to _ and removes the scheme identifier. The resulting
393 file name should be unique and never occur again for a different file */
394 string
URItoFileName(const string
&URI
)
396 // Nuke 'sensitive' items
402 // "\x00-\x20{}|\\\\^\\[\\]<>\"\x7F-\xFF";
403 string NewURI
= QuoteString(U
,"\\|{}[]<>\"^~_=!@#$%^&*");
404 replace(NewURI
.begin(),NewURI
.end(),'/','_');
408 // Base64Encode - Base64 Encoding routine for short strings /*{{{*/
409 // ---------------------------------------------------------------------
410 /* This routine performs a base64 transformation on a string. It was ripped
411 from wget and then patched and bug fixed.
413 This spec can be found in rfc2045 */
414 string
Base64Encode(const string
&S
)
417 static char tbl
[64] = {'A','B','C','D','E','F','G','H',
418 'I','J','K','L','M','N','O','P',
419 'Q','R','S','T','U','V','W','X',
420 'Y','Z','a','b','c','d','e','f',
421 'g','h','i','j','k','l','m','n',
422 'o','p','q','r','s','t','u','v',
423 'w','x','y','z','0','1','2','3',
424 '4','5','6','7','8','9','+','/'};
426 // Pre-allocate some space
428 Final
.reserve((4*S
.length() + 2)/3 + 2);
430 /* Transform the 3x8 bits to 4x6 bits, as required by
432 for (string::const_iterator I
= S
.begin(); I
< S
.end(); I
+= 3)
434 char Bits
[3] = {0,0,0};
441 Final
+= tbl
[Bits
[0] >> 2];
442 Final
+= tbl
[((Bits
[0] & 3) << 4) + (Bits
[1] >> 4)];
444 if (I
+ 1 >= S
.end())
447 Final
+= tbl
[((Bits
[1] & 0xf) << 2) + (Bits
[2] >> 6)];
449 if (I
+ 2 >= S
.end())
452 Final
+= tbl
[Bits
[2] & 0x3f];
455 /* Apply the padding elements, this tells how many bytes the remote
456 end should discard */
457 if (S
.length() % 3 == 2)
459 if (S
.length() % 3 == 1)
465 // stringcmp - Arbitary string compare /*{{{*/
466 // ---------------------------------------------------------------------
467 /* This safely compares two non-null terminated strings of arbitary
469 int stringcmp(const char *A
,const char *AEnd
,const char *B
,const char *BEnd
)
471 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
475 if (A
== AEnd
&& B
== BEnd
)
487 int stringcmp(string::const_iterator A
,string::const_iterator AEnd
,
488 const char *B
,const char *BEnd
)
490 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
494 if (A
== AEnd
&& B
== BEnd
)
504 int stringcmp(string::const_iterator A
,string::const_iterator AEnd
,
505 string::const_iterator B
,string::const_iterator BEnd
)
507 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
511 if (A
== AEnd
&& B
== BEnd
)
523 // stringcasecmp - Arbitary case insensitive string compare /*{{{*/
524 // ---------------------------------------------------------------------
526 int stringcasecmp(const char *A
,const char *AEnd
,const char *B
,const char *BEnd
)
528 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
529 if (toupper(*A
) != toupper(*B
))
532 if (A
== AEnd
&& B
== BEnd
)
538 if (toupper(*A
) < toupper(*B
))
543 int stringcasecmp(string::const_iterator A
,string::const_iterator AEnd
,
544 const char *B
,const char *BEnd
)
546 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
547 if (toupper(*A
) != toupper(*B
))
550 if (A
== AEnd
&& B
== BEnd
)
556 if (toupper(*A
) < toupper(*B
))
560 int stringcasecmp(string::const_iterator A
,string::const_iterator AEnd
,
561 string::const_iterator B
,string::const_iterator BEnd
)
563 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
564 if (toupper(*A
) != toupper(*B
))
567 if (A
== AEnd
&& B
== BEnd
)
573 if (toupper(*A
) < toupper(*B
))
579 // LookupTag - Lookup the value of a tag in a taged string /*{{{*/
580 // ---------------------------------------------------------------------
581 /* The format is like those used in package files and the method
582 communication system */
583 string
LookupTag(const string
&Message
,const char *Tag
,const char *Default
)
585 // Look for a matching tag.
586 int Length
= strlen(Tag
);
587 for (string::const_iterator I
= Message
.begin(); I
+ Length
< Message
.end(); I
++)
590 if (I
[Length
] == ':' && stringcasecmp(I
,I
+Length
,Tag
) == 0)
592 // Find the end of line and strip the leading/trailing spaces
593 string::const_iterator J
;
595 for (; isspace(*I
) != 0 && I
< Message
.end(); I
++);
596 for (J
= I
; *J
!= '\n' && J
< Message
.end(); J
++);
597 for (; J
> I
&& isspace(J
[-1]) != 0; J
--);
602 for (; *I
!= '\n' && I
< Message
.end(); I
++);
605 // Failed to find a match
611 // StringToBool - Converts a string into a boolean /*{{{*/
612 // ---------------------------------------------------------------------
613 /* This inspects the string to see if it is true or if it is false and
614 then returns the result. Several varients on true/false are checked. */
615 int StringToBool(const string
&Text
,int Default
)
618 int Res
= strtol(Text
.c_str(),&End
,0);
619 if (End
!= Text
.c_str() && Res
>= 0 && Res
<= 1)
622 // Check for positives
623 if (strcasecmp(Text
.c_str(),"no") == 0 ||
624 strcasecmp(Text
.c_str(),"false") == 0 ||
625 strcasecmp(Text
.c_str(),"without") == 0 ||
626 strcasecmp(Text
.c_str(),"off") == 0 ||
627 strcasecmp(Text
.c_str(),"disable") == 0)
630 // Check for negatives
631 if (strcasecmp(Text
.c_str(),"yes") == 0 ||
632 strcasecmp(Text
.c_str(),"true") == 0 ||
633 strcasecmp(Text
.c_str(),"with") == 0 ||
634 strcasecmp(Text
.c_str(),"on") == 0 ||
635 strcasecmp(Text
.c_str(),"enable") == 0)
641 // TimeRFC1123 - Convert a time_t into RFC1123 format /*{{{*/
642 // ---------------------------------------------------------------------
643 /* This converts a time_t into a string time representation that is
644 year 2000 complient and timezone neutral */
645 string
TimeRFC1123(time_t Date
)
647 struct tm Conv
= *gmtime(&Date
);
650 const char *Day
[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
651 const char *Month
[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul",
652 "Aug","Sep","Oct","Nov","Dec"};
654 sprintf(Buf
,"%s, %02i %s %i %02i:%02i:%02i GMT",Day
[Conv
.tm_wday
],
655 Conv
.tm_mday
,Month
[Conv
.tm_mon
],Conv
.tm_year
+1900,Conv
.tm_hour
,
656 Conv
.tm_min
,Conv
.tm_sec
);
660 // ReadMessages - Read messages from the FD /*{{{*/
661 // ---------------------------------------------------------------------
662 /* This pulls full messages from the input FD into the message buffer.
663 It assumes that messages will not pause during transit so no
664 fancy buffering is used. */
665 bool ReadMessages(int Fd
, vector
<string
> &List
)
672 int Res
= read(Fd
,End
,sizeof(Buffer
) - (End
-Buffer
));
673 if (Res
< 0 && errno
== EINTR
)
676 // Process is dead, this is kind of bad..
681 if (Res
< 0 && errno
== EAGAIN
)
688 // Look for the end of the message
689 for (char *I
= Buffer
; I
+ 1 < End
; I
++)
691 if (I
[0] != '\n' || I
[1] != '\n')
694 // Pull the message out
695 string
Message(Buffer
,I
-Buffer
);
698 for (; I
< End
&& *I
== '\n'; I
++);
700 memmove(Buffer
,I
,End
-Buffer
);
703 List
.push_back(Message
);
708 if (WaitFd(Fd
) == false)
713 // MonthConv - Converts a month string into a number /*{{{*/
714 // ---------------------------------------------------------------------
715 /* This was lifted from the boa webserver which lifted it from 'wn-v1.07'
716 Made it a bit more robust with a few touppers though. */
717 static int MonthConv(char *Month
)
719 switch (toupper(*Month
))
722 return toupper(Month
[1]) == 'P'?3:7;
728 if (toupper(Month
[1]) == 'A')
730 return toupper(Month
[2]) == 'N'?5:6;
732 return toupper(Month
[2]) == 'R'?2:4;
740 // Pretend it is January..
746 // timegm - Internal timegm function if gnu is not available /*{{{*/
747 // ---------------------------------------------------------------------
748 /* Ripped this evil little function from wget - I prefer the use of
749 GNU timegm if possible as this technique will have interesting problems
750 with leap seconds, timezones and other.
752 Converts struct tm to time_t, assuming the data in tm is UTC rather
753 than local timezone (mktime assumes the latter).
755 Contributed by Roger Beeman <beeman@cisco.com>, with the help of
756 Mark Baushke <mdb@cisco.com> and the rest of the Gurus at CISCO. */
758 /* Turned it into an autoconf check, because GNU is not the only thing which
759 can provide timegm. -- 2002-09-22, Joel Baker */
761 #ifndef HAVE_TIMEGM // Now with autoconf!
762 static time_t timegm(struct tm
*t
)
769 tb
= mktime (gmtime (&tl
));
770 return (tl
<= tb
? (tl
+ (tl
- tb
)) : (tl
- (tb
- tl
)));
774 // StrToTime - Converts a string into a time_t /*{{{*/
775 // ---------------------------------------------------------------------
776 /* This handles all 3 populare time formats including RFC 1123, RFC 1036
777 and the C library asctime format. It requires the GNU library function
778 'timegm' to convert a struct tm in UTC to a time_t. For some bizzar
779 reason the C library does not provide any such function :< This also
780 handles the weird, but unambiguous FTP time format*/
781 bool StrToTime(const string
&Val
,time_t &Result
)
785 const char *I
= Val
.c_str();
787 // Skip the day of the week
788 for (;*I
!= 0 && *I
!= ' '; I
++);
790 // Handle RFC 1123 time
792 if (sscanf(I
," %d %3s %d %d:%d:%d GMT",&Tm
.tm_mday
,Month
,&Tm
.tm_year
,
793 &Tm
.tm_hour
,&Tm
.tm_min
,&Tm
.tm_sec
) != 6)
795 // Handle RFC 1036 time
796 if (sscanf(I
," %d-%3s-%d %d:%d:%d GMT",&Tm
.tm_mday
,Month
,
797 &Tm
.tm_year
,&Tm
.tm_hour
,&Tm
.tm_min
,&Tm
.tm_sec
) == 6)
802 if (sscanf(I
," %3s %d %d:%d:%d %d",Month
,&Tm
.tm_mday
,
803 &Tm
.tm_hour
,&Tm
.tm_min
,&Tm
.tm_sec
,&Tm
.tm_year
) != 6)
806 if (sscanf(Val
.c_str(),"%4d%2d%2d%2d%2d%2d",&Tm
.tm_year
,&Tm
.tm_mon
,
807 &Tm
.tm_mday
,&Tm
.tm_hour
,&Tm
.tm_min
,&Tm
.tm_sec
) != 6)
816 Tm
.tm_mon
= MonthConv(Month
);
819 // Convert to local time and then to GMT
820 Result
= timegm(&Tm
);
824 // StrToNum - Convert a fixed length string to a number /*{{{*/
825 // ---------------------------------------------------------------------
826 /* This is used in decoding the crazy fixed length string headers in
828 bool StrToNum(const char *Str
,unsigned long &Res
,unsigned Len
,unsigned Base
)
831 if (Len
>= sizeof(S
))
836 // All spaces is a zero
839 for (I
= 0; S
[I
] == ' '; I
++);
844 Res
= strtoul(S
,&End
,Base
);
851 // HexDigit - Convert a hex character into an integer /*{{{*/
852 // ---------------------------------------------------------------------
853 /* Helper for Hex2Num */
854 static int HexDigit(int c
)
856 if (c
>= '0' && c
<= '9')
858 if (c
>= 'a' && c
<= 'f')
860 if (c
>= 'A' && c
<= 'F')
865 // Hex2Num - Convert a long hex number into a buffer /*{{{*/
866 // ---------------------------------------------------------------------
867 /* The length of the buffer must be exactly 1/2 the length of the string. */
868 bool Hex2Num(const string
&Str
,unsigned char *Num
,unsigned int Length
)
870 if (Str
.length() != Length
*2)
873 // Convert each digit. We store it in the same order as the string
875 for (string::const_iterator I
= Str
.begin(); I
!= Str
.end();J
++, I
+= 2)
877 if (isxdigit(*I
) == 0 || isxdigit(I
[1]) == 0)
880 Num
[J
] = HexDigit(I
[0]) << 4;
881 Num
[J
] += HexDigit(I
[1]);
887 // TokSplitString - Split a string up by a given token /*{{{*/
888 // ---------------------------------------------------------------------
889 /* This is intended to be a faster splitter, it does not use dynamic
890 memories. Input is changed to insert nulls at each token location. */
891 bool TokSplitString(char Tok
,char *Input
,char **List
,
892 unsigned long ListMax
)
894 // Strip any leading spaces
896 char *Stop
= Start
+ strlen(Start
);
897 for (; *Start
!= 0 && isspace(*Start
) != 0; Start
++);
899 unsigned long Count
= 0;
903 // Skip to the next Token
904 for (; Pos
!= Stop
&& *Pos
!= Tok
; Pos
++);
906 // Back remove spaces
908 for (; End
> Start
&& (End
[-1] == Tok
|| isspace(End
[-1]) != 0); End
--);
911 List
[Count
++] = Start
;
912 if (Count
>= ListMax
)
919 for (; Pos
!= Stop
&& (*Pos
== Tok
|| isspace(*Pos
) != 0 || *Pos
== 0); Pos
++);
927 // RegexChoice - Simple regex list/list matcher /*{{{*/
928 // ---------------------------------------------------------------------
930 unsigned long RegexChoice(RxChoiceList
*Rxs
,const char **ListBegin
,
931 const char **ListEnd
)
933 for (RxChoiceList
*R
= Rxs
; R
->Str
!= 0; R
++)
936 unsigned long Hits
= 0;
937 for (; ListBegin
!= ListEnd
; ListBegin
++)
939 // Check if the name is a regex
942 for (I
= *ListBegin
; *I
!= 0; I
++)
943 if (*I
== '.' || *I
== '?' || *I
== '*' || *I
== '|')
948 // Compile the regex pattern
951 if (regcomp(&Pattern
,*ListBegin
,REG_EXTENDED
| REG_ICASE
|
957 for (RxChoiceList
*R
= Rxs
; R
->Str
!= 0; R
++)
962 if (strcasecmp(R
->Str
,*ListBegin
) != 0)
966 if (regexec(&Pattern
,R
->Str
,0,0,0) != 0)
981 _error
->Warning(_("Selection %s not found"),*ListBegin
);
987 // ioprintf - C format string outputter to C++ iostreams /*{{{*/
988 // ---------------------------------------------------------------------
989 /* This is used to make the internationalization strings easier to translate
990 and to allow reordering of parameters */
991 void ioprintf(ostream
&out
,const char *format
,...)
994 va_start(args
,format
);
996 // sprintf the description
998 vsnprintf(S
,sizeof(S
),format
,args
);
1002 // safe_snprintf - Safer snprintf /*{{{*/
1003 // ---------------------------------------------------------------------
1004 /* This is a snprintf that will never (ever) go past 'End' and returns a
1005 pointer to the end of the new string. The returned string is always null
1006 terminated unless Buffer == end. This is a better alterantive to using
1007 consecutive snprintfs. */
1008 char *safe_snprintf(char *Buffer
,char *End
,const char *Format
,...)
1013 va_start(args
,Format
);
1018 Did
= vsnprintf(Buffer
,End
- Buffer
,Format
,args
);
1019 if (Did
< 0 || Buffer
+ Did
> End
)
1021 return Buffer
+ Did
;
1025 // CheckDomainList - See if Host is in a , seperate list /*{{{*/
1026 // ---------------------------------------------------------------------
1027 /* The domain list is a comma seperate list of domains that are suffix
1028 matched against the argument */
1029 bool CheckDomainList(const string
&Host
,const string
&List
)
1031 string::const_iterator Start
= List
.begin();
1032 for (string::const_iterator Cur
= List
.begin(); Cur
<= List
.end(); Cur
++)
1034 if (Cur
< List
.end() && *Cur
!= ',')
1037 // Match the end of the string..
1038 if ((Host
.size() >= (unsigned)(Cur
- Start
)) &&
1040 stringcasecmp(Host
.end() - (Cur
- Start
),Host
.end(),Start
,Cur
) == 0)
1049 // URI::CopyFrom - Copy from an object /*{{{*/
1050 // ---------------------------------------------------------------------
1051 /* This parses the URI into all of its components */
1052 void URI::CopyFrom(const string
&U
)
1054 string::const_iterator I
= U
.begin();
1056 // Locate the first colon, this separates the scheme
1057 for (; I
< U
.end() && *I
!= ':' ; I
++);
1058 string::const_iterator FirstColon
= I
;
1060 /* Determine if this is a host type URI with a leading double //
1061 and then search for the first single / */
1062 string::const_iterator SingleSlash
= I
;
1063 if (I
+ 3 < U
.end() && I
[1] == '/' && I
[2] == '/')
1066 /* Find the / indicating the end of the hostname, ignoring /'s in the
1068 bool InBracket
= false;
1069 for (; SingleSlash
< U
.end() && (*SingleSlash
!= '/' || InBracket
== true); SingleSlash
++)
1071 if (*SingleSlash
== '[')
1073 if (InBracket
== true && *SingleSlash
== ']')
1077 if (SingleSlash
> U
.end())
1078 SingleSlash
= U
.end();
1080 // We can now write the access and path specifiers
1081 Access
.assign(U
.begin(),FirstColon
);
1082 if (SingleSlash
!= U
.end())
1083 Path
.assign(SingleSlash
,U
.end());
1084 if (Path
.empty() == true)
1087 // Now we attempt to locate a user:pass@host fragment
1088 if (FirstColon
+ 2 <= U
.end() && FirstColon
[1] == '/' && FirstColon
[2] == '/')
1092 if (FirstColon
>= U
.end())
1095 if (FirstColon
> SingleSlash
)
1096 FirstColon
= SingleSlash
;
1098 // Find the colon...
1100 if (I
> SingleSlash
)
1102 for (; I
< SingleSlash
&& *I
!= ':'; I
++);
1103 string::const_iterator SecondColon
= I
;
1105 // Search for the @ after the colon
1106 for (; I
< SingleSlash
&& *I
!= '@'; I
++);
1107 string::const_iterator At
= I
;
1109 // Now write the host and user/pass
1110 if (At
== SingleSlash
)
1112 if (FirstColon
< SingleSlash
)
1113 Host
.assign(FirstColon
,SingleSlash
);
1117 Host
.assign(At
+1,SingleSlash
);
1118 User
.assign(FirstColon
,SecondColon
);
1119 if (SecondColon
< At
)
1120 Password
.assign(SecondColon
+1,At
);
1123 // Now we parse the RFC 2732 [] hostnames.
1124 unsigned long PortEnd
= 0;
1126 for (unsigned I
= 0; I
!= Host
.length();)
1135 if (InBracket
== true && Host
[I
] == ']')
1146 if (InBracket
== true)
1152 // Now we parse off a port number from the hostname
1154 string::size_type Pos
= Host
.rfind(':');
1155 if (Pos
== string::npos
|| Pos
< PortEnd
)
1158 Port
= atoi(string(Host
,Pos
+1).c_str());
1159 Host
.assign(Host
,0,Pos
);
1162 // URI::operator string - Convert the URI to a string /*{{{*/
1163 // ---------------------------------------------------------------------
1165 URI::operator string()
1169 if (Access
.empty() == false)
1172 if (Host
.empty() == false)
1174 if (Access
.empty() == false)
1177 if (User
.empty() == false)
1180 if (Password
.empty() == false)
1181 Res
+= ":" + Password
;
1185 // Add RFC 2732 escaping characters
1186 if (Access
.empty() == false &&
1187 (Host
.find('/') != string::npos
|| Host
.find(':') != string::npos
))
1188 Res
+= '[' + Host
+ ']';
1195 sprintf(S
,":%u",Port
);
1200 if (Path
.empty() == false)
1211 // URI::SiteOnly - Return the schema and site for the URI /*{{{*/
1212 // ---------------------------------------------------------------------
1214 string
URI::SiteOnly(const string
&URI
)