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>
43 // UTF8ToCodeset - Convert some UTF-8 string for some codeset /*{{{*/
44 // ---------------------------------------------------------------------
45 /* This is handy to use before display some information for enduser */
46 bool UTF8ToCodeset(const char *codeset
, const string
&orig
, string
*dest
)
50 char *inptr
, *outbuf
, *outptr
;
51 size_t insize
, outsize
;
53 cd
= iconv_open(codeset
, "UTF-8");
54 if (cd
== (iconv_t
)(-1)) {
55 // Something went wrong
57 _error
->Error("conversion from 'UTF-8' to '%s' not available",
62 // Clean the destination string
68 insize
= outsize
= orig
.size();
70 inptr
= (char *)inbuf
;
71 outbuf
= new char[insize
+1];
74 iconv(cd
, &inptr
, &insize
, &outptr
, &outsize
);
85 // strstrip - Remove white space from the front and back of a string /*{{{*/
86 // ---------------------------------------------------------------------
87 /* This is handy to use when parsing a file. It also removes \n's left
88 over from fgets and company */
89 char *_strstrip(char *String
)
91 for (;*String
!= 0 && (*String
== ' ' || *String
== '\t'); String
++);
96 char *End
= String
+ strlen(String
) - 1;
97 for (;End
!= String
- 1 && (*End
== ' ' || *End
== '\t' || *End
== '\n' ||
98 *End
== '\r'); End
--);
104 // strtabexpand - Converts tabs into 8 spaces /*{{{*/
105 // ---------------------------------------------------------------------
107 char *_strtabexpand(char *String
,size_t Len
)
109 for (char *I
= String
; I
!= I
+ Len
&& *I
!= 0; I
++)
113 if (I
+ 8 > String
+ Len
)
119 /* Assume the start of the string is 0 and find the next 8 char
125 Len
= 8 - ((String
- I
) % 8);
133 memmove(I
+ Len
,I
+ 1,strlen(I
) + 1);
134 for (char *J
= I
; J
+ Len
!= I
; *I
= ' ', I
++);
139 // ParseQuoteWord - Parse a single word out of a string /*{{{*/
140 // ---------------------------------------------------------------------
141 /* This grabs a single word, converts any % escaped characters to their
142 proper values and advances the pointer. Double quotes are understood
143 and striped out as well. This is for URI/URL parsing. It also can
144 understand [] brackets.*/
145 bool ParseQuoteWord(const char *&String
,string
&Res
)
147 // Skip leading whitespace
148 const char *C
= String
;
149 for (;*C
!= 0 && *C
== ' '; C
++);
153 // Jump to the next word
154 for (;*C
!= 0 && isspace(*C
) == 0; C
++)
158 for (C
++; *C
!= 0 && *C
!= '"'; C
++);
164 for (C
++; *C
!= 0 && *C
!= ']'; C
++);
170 // Now de-quote characters
173 const char *Start
= String
;
175 for (I
= Buffer
; I
< Buffer
+ sizeof(Buffer
) && Start
!= C
; I
++)
177 if (*Start
== '%' && Start
+ 2 < C
)
182 *I
= (char)strtol(Tmp
,0,16);
195 // Skip ending white space
196 for (;*C
!= 0 && isspace(*C
) != 0; C
++);
201 // ParseCWord - Parses a string like a C "" expression /*{{{*/
202 // ---------------------------------------------------------------------
203 /* This expects a series of space separated strings enclosed in ""'s.
204 It concatenates the ""'s into a single string. */
205 bool ParseCWord(const char *&String
,string
&Res
)
207 // Skip leading whitespace
208 const char *C
= String
;
209 for (;*C
!= 0 && *C
== ' '; C
++);
215 if (strlen(String
) >= sizeof(Buffer
))
222 for (C
++; *C
!= 0 && *C
!= '"'; C
++)
231 if (C
!= String
&& isspace(*C
) != 0 && isspace(C
[-1]) != 0)
233 if (isspace(*C
) == 0)
243 // QuoteString - Convert a string into quoted from /*{{{*/
244 // ---------------------------------------------------------------------
246 string
QuoteString(const string
&Str
, const char *Bad
)
249 for (string::const_iterator I
= Str
.begin(); I
!= Str
.end(); I
++)
251 if (strchr(Bad
,*I
) != 0 || isprint(*I
) == 0 ||
252 *I
<= 0x20 || *I
>= 0x7F)
255 sprintf(Buf
,"%%%02x",(int)*I
);
264 // DeQuoteString - Convert a string from quoted from /*{{{*/
265 // ---------------------------------------------------------------------
266 /* This undoes QuoteString */
267 string
DeQuoteString(const string
&Str
)
270 for (string::const_iterator I
= Str
.begin(); I
!= Str
.end(); I
++)
272 if (*I
== '%' && I
+ 2 < Str
.end())
278 Res
+= (char)strtol(Tmp
,0,16);
289 // SizeToStr - Convert a long into a human readable size /*{{{*/
290 // ---------------------------------------------------------------------
291 /* A max of 4 digits are shown before conversion to the next highest unit.
292 The max length of the string will be 5 chars unless the size is > 10
294 string
SizeToStr(double Size
)
303 /* bytes, KiloBytes, MegaBytes, GigaBytes, TeraBytes, PetaBytes,
304 ExaBytes, ZettaBytes, YottaBytes */
305 char Ext
[] = {'\0','k','M','G','T','P','E','Z','Y'};
309 if (ASize
< 100 && I
!= 0)
311 sprintf(S
,"%.1f%c",ASize
,Ext
[I
]);
317 sprintf(S
,"%.0f%c",ASize
,Ext
[I
]);
327 // TimeToStr - Convert the time into a string /*{{{*/
328 // ---------------------------------------------------------------------
329 /* Converts a number of seconds to a hms format */
330 string
TimeToStr(unsigned long Sec
)
338 sprintf(S
,"%lid %lih%lim%lis",Sec
/60/60/24,(Sec
/60/60) % 24,(Sec
/60) % 60,Sec
% 60);
344 sprintf(S
,"%lih%lim%lis",Sec
/60/60,(Sec
/60) % 60,Sec
% 60);
350 sprintf(S
,"%lim%lis",Sec
/60,Sec
% 60);
354 sprintf(S
,"%lis",Sec
);
361 // SubstVar - Substitute a string for another string /*{{{*/
362 // ---------------------------------------------------------------------
363 /* This replaces all occurances of Subst with Contents in Str. */
364 string
SubstVar(const string
&Str
,const string
&Subst
,const string
&Contents
)
366 string::size_type Pos
= 0;
367 string::size_type OldPos
= 0;
370 while (OldPos
< Str
.length() &&
371 (Pos
= Str
.find(Subst
,OldPos
)) != string::npos
)
373 Temp
+= string(Str
,OldPos
,Pos
) + Contents
;
374 OldPos
= Pos
+ Subst
.length();
380 return Temp
+ string(Str
,OldPos
);
383 string
SubstVar(string Str
,const struct SubstVar
*Vars
)
385 for (; Vars
->Subst
!= 0; Vars
++)
386 Str
= SubstVar(Str
,Vars
->Subst
,*Vars
->Contents
);
390 // URItoFileName - Convert the uri into a unique file name /*{{{*/
391 // ---------------------------------------------------------------------
392 /* This converts a URI into a safe filename. It quotes all unsafe characters
393 and converts / to _ and removes the scheme identifier. The resulting
394 file name should be unique and never occur again for a different file */
395 string
URItoFileName(const string
&URI
)
397 // Nuke 'sensitive' items
403 // "\x00-\x20{}|\\\\^\\[\\]<>\"\x7F-\xFF";
404 string NewURI
= QuoteString(U
,"\\|{}[]<>\"^~_=!@#$%^&*");
405 replace(NewURI
.begin(),NewURI
.end(),'/','_');
409 // Base64Encode - Base64 Encoding routine for short strings /*{{{*/
410 // ---------------------------------------------------------------------
411 /* This routine performs a base64 transformation on a string. It was ripped
412 from wget and then patched and bug fixed.
414 This spec can be found in rfc2045 */
415 string
Base64Encode(const string
&S
)
418 static char tbl
[64] = {'A','B','C','D','E','F','G','H',
419 'I','J','K','L','M','N','O','P',
420 'Q','R','S','T','U','V','W','X',
421 'Y','Z','a','b','c','d','e','f',
422 'g','h','i','j','k','l','m','n',
423 'o','p','q','r','s','t','u','v',
424 'w','x','y','z','0','1','2','3',
425 '4','5','6','7','8','9','+','/'};
427 // Pre-allocate some space
429 Final
.reserve((4*S
.length() + 2)/3 + 2);
431 /* Transform the 3x8 bits to 4x6 bits, as required by
433 for (string::const_iterator I
= S
.begin(); I
< S
.end(); I
+= 3)
435 char Bits
[3] = {0,0,0};
442 Final
+= tbl
[Bits
[0] >> 2];
443 Final
+= tbl
[((Bits
[0] & 3) << 4) + (Bits
[1] >> 4)];
445 if (I
+ 1 >= S
.end())
448 Final
+= tbl
[((Bits
[1] & 0xf) << 2) + (Bits
[2] >> 6)];
450 if (I
+ 2 >= S
.end())
453 Final
+= tbl
[Bits
[2] & 0x3f];
456 /* Apply the padding elements, this tells how many bytes the remote
457 end should discard */
458 if (S
.length() % 3 == 2)
460 if (S
.length() % 3 == 1)
466 // stringcmp - Arbitary string compare /*{{{*/
467 // ---------------------------------------------------------------------
468 /* This safely compares two non-null terminated strings of arbitary
470 int stringcmp(const char *A
,const char *AEnd
,const char *B
,const char *BEnd
)
472 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
476 if (A
== AEnd
&& B
== BEnd
)
488 int stringcmp(string::const_iterator A
,string::const_iterator AEnd
,
489 const char *B
,const char *BEnd
)
491 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
495 if (A
== AEnd
&& B
== BEnd
)
505 int stringcmp(string::const_iterator A
,string::const_iterator AEnd
,
506 string::const_iterator B
,string::const_iterator BEnd
)
508 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
512 if (A
== AEnd
&& B
== BEnd
)
524 // stringcasecmp - Arbitary case insensitive string compare /*{{{*/
525 // ---------------------------------------------------------------------
527 int stringcasecmp(const char *A
,const char *AEnd
,const char *B
,const char *BEnd
)
529 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
530 if (toupper(*A
) != toupper(*B
))
533 if (A
== AEnd
&& B
== BEnd
)
539 if (toupper(*A
) < toupper(*B
))
544 int stringcasecmp(string::const_iterator A
,string::const_iterator AEnd
,
545 const char *B
,const char *BEnd
)
547 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
548 if (toupper(*A
) != toupper(*B
))
551 if (A
== AEnd
&& B
== BEnd
)
557 if (toupper(*A
) < toupper(*B
))
561 int stringcasecmp(string::const_iterator A
,string::const_iterator AEnd
,
562 string::const_iterator B
,string::const_iterator BEnd
)
564 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
565 if (toupper(*A
) != toupper(*B
))
568 if (A
== AEnd
&& B
== BEnd
)
574 if (toupper(*A
) < toupper(*B
))
580 // LookupTag - Lookup the value of a tag in a taged string /*{{{*/
581 // ---------------------------------------------------------------------
582 /* The format is like those used in package files and the method
583 communication system */
584 string
LookupTag(const string
&Message
,const char *Tag
,const char *Default
)
586 // Look for a matching tag.
587 int Length
= strlen(Tag
);
588 for (string::const_iterator I
= Message
.begin(); I
+ Length
< Message
.end(); I
++)
591 if (I
[Length
] == ':' && stringcasecmp(I
,I
+Length
,Tag
) == 0)
593 // Find the end of line and strip the leading/trailing spaces
594 string::const_iterator J
;
596 for (; isspace(*I
) != 0 && I
< Message
.end(); I
++);
597 for (J
= I
; *J
!= '\n' && J
< Message
.end(); J
++);
598 for (; J
> I
&& isspace(J
[-1]) != 0; J
--);
603 for (; *I
!= '\n' && I
< Message
.end(); I
++);
606 // Failed to find a match
612 // StringToBool - Converts a string into a boolean /*{{{*/
613 // ---------------------------------------------------------------------
614 /* This inspects the string to see if it is true or if it is false and
615 then returns the result. Several varients on true/false are checked. */
616 int StringToBool(const string
&Text
,int Default
)
619 int Res
= strtol(Text
.c_str(),&End
,0);
620 if (End
!= Text
.c_str() && Res
>= 0 && Res
<= 1)
623 // Check for positives
624 if (strcasecmp(Text
.c_str(),"no") == 0 ||
625 strcasecmp(Text
.c_str(),"false") == 0 ||
626 strcasecmp(Text
.c_str(),"without") == 0 ||
627 strcasecmp(Text
.c_str(),"off") == 0 ||
628 strcasecmp(Text
.c_str(),"disable") == 0)
631 // Check for negatives
632 if (strcasecmp(Text
.c_str(),"yes") == 0 ||
633 strcasecmp(Text
.c_str(),"true") == 0 ||
634 strcasecmp(Text
.c_str(),"with") == 0 ||
635 strcasecmp(Text
.c_str(),"on") == 0 ||
636 strcasecmp(Text
.c_str(),"enable") == 0)
642 // TimeRFC1123 - Convert a time_t into RFC1123 format /*{{{*/
643 // ---------------------------------------------------------------------
644 /* This converts a time_t into a string time representation that is
645 year 2000 complient and timezone neutral */
646 string
TimeRFC1123(time_t Date
)
648 struct tm Conv
= *gmtime(&Date
);
651 const char *Day
[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
652 const char *Month
[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul",
653 "Aug","Sep","Oct","Nov","Dec"};
655 sprintf(Buf
,"%s, %02i %s %i %02i:%02i:%02i GMT",Day
[Conv
.tm_wday
],
656 Conv
.tm_mday
,Month
[Conv
.tm_mon
],Conv
.tm_year
+1900,Conv
.tm_hour
,
657 Conv
.tm_min
,Conv
.tm_sec
);
661 // ReadMessages - Read messages from the FD /*{{{*/
662 // ---------------------------------------------------------------------
663 /* This pulls full messages from the input FD into the message buffer.
664 It assumes that messages will not pause during transit so no
665 fancy buffering is used. */
666 bool ReadMessages(int Fd
, vector
<string
> &List
)
673 int Res
= read(Fd
,End
,sizeof(Buffer
) - (End
-Buffer
));
674 if (Res
< 0 && errno
== EINTR
)
677 // Process is dead, this is kind of bad..
682 if (Res
< 0 && errno
== EAGAIN
)
689 // Look for the end of the message
690 for (char *I
= Buffer
; I
+ 1 < End
; I
++)
692 if (I
[0] != '\n' || I
[1] != '\n')
695 // Pull the message out
696 string
Message(Buffer
,I
-Buffer
);
699 for (; I
< End
&& *I
== '\n'; I
++);
701 memmove(Buffer
,I
,End
-Buffer
);
704 List
.push_back(Message
);
709 if (WaitFd(Fd
) == false)
714 // MonthConv - Converts a month string into a number /*{{{*/
715 // ---------------------------------------------------------------------
716 /* This was lifted from the boa webserver which lifted it from 'wn-v1.07'
717 Made it a bit more robust with a few touppers though. */
718 static int MonthConv(char *Month
)
720 switch (toupper(*Month
))
723 return toupper(Month
[1]) == 'P'?3:7;
729 if (toupper(Month
[1]) == 'A')
731 return toupper(Month
[2]) == 'N'?5:6;
733 return toupper(Month
[2]) == 'R'?2:4;
741 // Pretend it is January..
747 // timegm - Internal timegm function if gnu is not available /*{{{*/
748 // ---------------------------------------------------------------------
749 /* Ripped this evil little function from wget - I prefer the use of
750 GNU timegm if possible as this technique will have interesting problems
751 with leap seconds, timezones and other.
753 Converts struct tm to time_t, assuming the data in tm is UTC rather
754 than local timezone (mktime assumes the latter).
756 Contributed by Roger Beeman <beeman@cisco.com>, with the help of
757 Mark Baushke <mdb@cisco.com> and the rest of the Gurus at CISCO. */
759 /* Turned it into an autoconf check, because GNU is not the only thing which
760 can provide timegm. -- 2002-09-22, Joel Baker */
762 #ifndef HAVE_TIMEGM // Now with autoconf!
763 static time_t timegm(struct tm
*t
)
770 tb
= mktime (gmtime (&tl
));
771 return (tl
<= tb
? (tl
+ (tl
- tb
)) : (tl
- (tb
- tl
)));
775 // StrToTime - Converts a string into a time_t /*{{{*/
776 // ---------------------------------------------------------------------
777 /* This handles all 3 populare time formats including RFC 1123, RFC 1036
778 and the C library asctime format. It requires the GNU library function
779 'timegm' to convert a struct tm in UTC to a time_t. For some bizzar
780 reason the C library does not provide any such function :< This also
781 handles the weird, but unambiguous FTP time format*/
782 bool StrToTime(const string
&Val
,time_t &Result
)
786 const char *I
= Val
.c_str();
788 // Skip the day of the week
789 for (;*I
!= 0 && *I
!= ' '; I
++);
791 // Handle RFC 1123 time
793 if (sscanf(I
," %d %3s %d %d:%d:%d GMT",&Tm
.tm_mday
,Month
,&Tm
.tm_year
,
794 &Tm
.tm_hour
,&Tm
.tm_min
,&Tm
.tm_sec
) != 6)
796 // Handle RFC 1036 time
797 if (sscanf(I
," %d-%3s-%d %d:%d:%d GMT",&Tm
.tm_mday
,Month
,
798 &Tm
.tm_year
,&Tm
.tm_hour
,&Tm
.tm_min
,&Tm
.tm_sec
) == 6)
803 if (sscanf(I
," %3s %d %d:%d:%d %d",Month
,&Tm
.tm_mday
,
804 &Tm
.tm_hour
,&Tm
.tm_min
,&Tm
.tm_sec
,&Tm
.tm_year
) != 6)
807 if (sscanf(Val
.c_str(),"%4d%2d%2d%2d%2d%2d",&Tm
.tm_year
,&Tm
.tm_mon
,
808 &Tm
.tm_mday
,&Tm
.tm_hour
,&Tm
.tm_min
,&Tm
.tm_sec
) != 6)
817 Tm
.tm_mon
= MonthConv(Month
);
820 // Convert to local time and then to GMT
821 Result
= timegm(&Tm
);
825 // StrToNum - Convert a fixed length string to a number /*{{{*/
826 // ---------------------------------------------------------------------
827 /* This is used in decoding the crazy fixed length string headers in
829 bool StrToNum(const char *Str
,unsigned long &Res
,unsigned Len
,unsigned Base
)
832 if (Len
>= sizeof(S
))
837 // All spaces is a zero
840 for (I
= 0; S
[I
] == ' '; I
++);
845 Res
= strtoul(S
,&End
,Base
);
852 // HexDigit - Convert a hex character into an integer /*{{{*/
853 // ---------------------------------------------------------------------
854 /* Helper for Hex2Num */
855 static int HexDigit(int c
)
857 if (c
>= '0' && c
<= '9')
859 if (c
>= 'a' && c
<= 'f')
861 if (c
>= 'A' && c
<= 'F')
866 // Hex2Num - Convert a long hex number into a buffer /*{{{*/
867 // ---------------------------------------------------------------------
868 /* The length of the buffer must be exactly 1/2 the length of the string. */
869 bool Hex2Num(const string
&Str
,unsigned char *Num
,unsigned int Length
)
871 if (Str
.length() != Length
*2)
874 // Convert each digit. We store it in the same order as the string
876 for (string::const_iterator I
= Str
.begin(); I
!= Str
.end();J
++, I
+= 2)
878 if (isxdigit(*I
) == 0 || isxdigit(I
[1]) == 0)
881 Num
[J
] = HexDigit(I
[0]) << 4;
882 Num
[J
] += HexDigit(I
[1]);
888 // TokSplitString - Split a string up by a given token /*{{{*/
889 // ---------------------------------------------------------------------
890 /* This is intended to be a faster splitter, it does not use dynamic
891 memories. Input is changed to insert nulls at each token location. */
892 bool TokSplitString(char Tok
,char *Input
,char **List
,
893 unsigned long ListMax
)
895 // Strip any leading spaces
897 char *Stop
= Start
+ strlen(Start
);
898 for (; *Start
!= 0 && isspace(*Start
) != 0; Start
++);
900 unsigned long Count
= 0;
904 // Skip to the next Token
905 for (; Pos
!= Stop
&& *Pos
!= Tok
; Pos
++);
907 // Back remove spaces
909 for (; End
> Start
&& (End
[-1] == Tok
|| isspace(End
[-1]) != 0); End
--);
912 List
[Count
++] = Start
;
913 if (Count
>= ListMax
)
920 for (; Pos
!= Stop
&& (*Pos
== Tok
|| isspace(*Pos
) != 0 || *Pos
== 0); Pos
++);
928 // RegexChoice - Simple regex list/list matcher /*{{{*/
929 // ---------------------------------------------------------------------
931 unsigned long RegexChoice(RxChoiceList
*Rxs
,const char **ListBegin
,
932 const char **ListEnd
)
934 for (RxChoiceList
*R
= Rxs
; R
->Str
!= 0; R
++)
937 unsigned long Hits
= 0;
938 for (; ListBegin
!= ListEnd
; ListBegin
++)
940 // Check if the name is a regex
943 for (I
= *ListBegin
; *I
!= 0; I
++)
944 if (*I
== '.' || *I
== '?' || *I
== '*' || *I
== '|')
949 // Compile the regex pattern
952 if (regcomp(&Pattern
,*ListBegin
,REG_EXTENDED
| REG_ICASE
|
958 for (RxChoiceList
*R
= Rxs
; R
->Str
!= 0; R
++)
963 if (strcasecmp(R
->Str
,*ListBegin
) != 0)
967 if (regexec(&Pattern
,R
->Str
,0,0,0) != 0)
982 _error
->Warning(_("Selection %s not found"),*ListBegin
);
988 // ioprintf - C format string outputter to C++ iostreams /*{{{*/
989 // ---------------------------------------------------------------------
990 /* This is used to make the internationalization strings easier to translate
991 and to allow reordering of parameters */
992 void ioprintf(ostream
&out
,const char *format
,...)
995 va_start(args
,format
);
997 // sprintf the description
999 vsnprintf(S
,sizeof(S
),format
,args
);
1003 // safe_snprintf - Safer snprintf /*{{{*/
1004 // ---------------------------------------------------------------------
1005 /* This is a snprintf that will never (ever) go past 'End' and returns a
1006 pointer to the end of the new string. The returned string is always null
1007 terminated unless Buffer == end. This is a better alterantive to using
1008 consecutive snprintfs. */
1009 char *safe_snprintf(char *Buffer
,char *End
,const char *Format
,...)
1014 va_start(args
,Format
);
1019 Did
= vsnprintf(Buffer
,End
- Buffer
,Format
,args
);
1020 if (Did
< 0 || Buffer
+ Did
> End
)
1022 return Buffer
+ Did
;
1026 // CheckDomainList - See if Host is in a , seperate list /*{{{*/
1027 // ---------------------------------------------------------------------
1028 /* The domain list is a comma seperate list of domains that are suffix
1029 matched against the argument */
1030 bool CheckDomainList(const string
&Host
,const string
&List
)
1032 string::const_iterator Start
= List
.begin();
1033 for (string::const_iterator Cur
= List
.begin(); Cur
<= List
.end(); Cur
++)
1035 if (Cur
< List
.end() && *Cur
!= ',')
1038 // Match the end of the string..
1039 if ((Host
.size() >= (unsigned)(Cur
- Start
)) &&
1041 stringcasecmp(Host
.end() - (Cur
- Start
),Host
.end(),Start
,Cur
) == 0)
1050 // URI::CopyFrom - Copy from an object /*{{{*/
1051 // ---------------------------------------------------------------------
1052 /* This parses the URI into all of its components */
1053 void URI::CopyFrom(const string
&U
)
1055 string::const_iterator I
= U
.begin();
1057 // Locate the first colon, this separates the scheme
1058 for (; I
< U
.end() && *I
!= ':' ; I
++);
1059 string::const_iterator FirstColon
= I
;
1061 /* Determine if this is a host type URI with a leading double //
1062 and then search for the first single / */
1063 string::const_iterator SingleSlash
= I
;
1064 if (I
+ 3 < U
.end() && I
[1] == '/' && I
[2] == '/')
1067 /* Find the / indicating the end of the hostname, ignoring /'s in the
1069 bool InBracket
= false;
1070 for (; SingleSlash
< U
.end() && (*SingleSlash
!= '/' || InBracket
== true); SingleSlash
++)
1072 if (*SingleSlash
== '[')
1074 if (InBracket
== true && *SingleSlash
== ']')
1078 if (SingleSlash
> U
.end())
1079 SingleSlash
= U
.end();
1081 // We can now write the access and path specifiers
1082 Access
.assign(U
.begin(),FirstColon
);
1083 if (SingleSlash
!= U
.end())
1084 Path
.assign(SingleSlash
,U
.end());
1085 if (Path
.empty() == true)
1088 // Now we attempt to locate a user:pass@host fragment
1089 if (FirstColon
+ 2 <= U
.end() && FirstColon
[1] == '/' && FirstColon
[2] == '/')
1093 if (FirstColon
>= U
.end())
1096 if (FirstColon
> SingleSlash
)
1097 FirstColon
= SingleSlash
;
1099 // Find the colon...
1101 if (I
> SingleSlash
)
1103 for (; I
< SingleSlash
&& *I
!= ':'; I
++);
1104 string::const_iterator SecondColon
= I
;
1106 // Search for the @ after the colon
1107 for (; I
< SingleSlash
&& *I
!= '@'; I
++);
1108 string::const_iterator At
= I
;
1110 // Now write the host and user/pass
1111 if (At
== SingleSlash
)
1113 if (FirstColon
< SingleSlash
)
1114 Host
.assign(FirstColon
,SingleSlash
);
1118 Host
.assign(At
+1,SingleSlash
);
1119 User
.assign(FirstColon
,SecondColon
);
1120 if (SecondColon
< At
)
1121 Password
.assign(SecondColon
+1,At
);
1124 // Now we parse the RFC 2732 [] hostnames.
1125 unsigned long PortEnd
= 0;
1127 for (unsigned I
= 0; I
!= Host
.length();)
1136 if (InBracket
== true && Host
[I
] == ']')
1147 if (InBracket
== true)
1153 // Now we parse off a port number from the hostname
1155 string::size_type Pos
= Host
.rfind(':');
1156 if (Pos
== string::npos
|| Pos
< PortEnd
)
1159 Port
= atoi(string(Host
,Pos
+1).c_str());
1160 Host
.assign(Host
,0,Pos
);
1163 // URI::operator string - Convert the URI to a string /*{{{*/
1164 // ---------------------------------------------------------------------
1166 URI::operator string()
1170 if (Access
.empty() == false)
1173 if (Host
.empty() == false)
1175 if (Access
.empty() == false)
1178 if (User
.empty() == false)
1181 if (Password
.empty() == false)
1182 Res
+= ":" + Password
;
1186 // Add RFC 2732 escaping characters
1187 if (Access
.empty() == false &&
1188 (Host
.find('/') != string::npos
|| Host
.find(':') != string::npos
))
1189 Res
+= '[' + Host
+ ']';
1196 sprintf(S
,":%u",Port
);
1201 if (Path
.empty() == false)
1212 // URI::SiteOnly - Return the schema and site for the URI /*{{{*/
1213 // ---------------------------------------------------------------------
1215 string
URI::SiteOnly(const string
&URI
)