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
, nconv
;
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(string Str
,const char *Bad
)
248 for (string::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(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(string Str
,string Subst
,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(string URI
)
396 // Nuke 'sensitive' items
399 U
.Password
= string();
402 // "\x00-\x20{}|\\\\^\\[\\]<>\"\x7F-\xFF";
403 URI
= QuoteString(U
,"\\|{}[]<>\"^~=!@#$%^&*");
404 string::iterator J
= URI
.begin();
405 for (; J
!= URI
.end(); J
++)
411 // Base64Encode - Base64 Encoding routine for short strings /*{{{*/
412 // ---------------------------------------------------------------------
413 /* This routine performs a base64 transformation on a string. It was ripped
414 from wget and then patched and bug fixed.
416 This spec can be found in rfc2045 */
417 string
Base64Encode(string S
)
420 static char tbl
[64] = {'A','B','C','D','E','F','G','H',
421 'I','J','K','L','M','N','O','P',
422 'Q','R','S','T','U','V','W','X',
423 'Y','Z','a','b','c','d','e','f',
424 'g','h','i','j','k','l','m','n',
425 'o','p','q','r','s','t','u','v',
426 'w','x','y','z','0','1','2','3',
427 '4','5','6','7','8','9','+','/'};
429 // Pre-allocate some space
431 Final
.reserve((4*S
.length() + 2)/3 + 2);
433 /* Transform the 3x8 bits to 4x6 bits, as required by
435 for (string::const_iterator I
= S
.begin(); I
< S
.end(); I
+= 3)
437 char Bits
[3] = {0,0,0};
444 Final
+= tbl
[Bits
[0] >> 2];
445 Final
+= tbl
[((Bits
[0] & 3) << 4) + (Bits
[1] >> 4)];
447 if (I
+ 1 >= S
.end())
450 Final
+= tbl
[((Bits
[1] & 0xf) << 2) + (Bits
[2] >> 6)];
452 if (I
+ 2 >= S
.end())
455 Final
+= tbl
[Bits
[2] & 0x3f];
458 /* Apply the padding elements, this tells how many bytes the remote
459 end should discard */
460 if (S
.length() % 3 == 2)
462 if (S
.length() % 3 == 1)
468 // stringcmp - Arbitary string compare /*{{{*/
469 // ---------------------------------------------------------------------
470 /* This safely compares two non-null terminated strings of arbitary
472 int stringcmp(const char *A
,const char *AEnd
,const char *B
,const char *BEnd
)
474 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
478 if (A
== AEnd
&& B
== BEnd
)
490 int stringcmp(string::const_iterator A
,string::const_iterator AEnd
,
491 const char *B
,const char *BEnd
)
493 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
497 if (A
== AEnd
&& B
== BEnd
)
507 int stringcmp(string::const_iterator A
,string::const_iterator AEnd
,
508 string::const_iterator B
,string::const_iterator BEnd
)
510 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
514 if (A
== AEnd
&& B
== BEnd
)
526 // stringcasecmp - Arbitary case insensitive string compare /*{{{*/
527 // ---------------------------------------------------------------------
529 int stringcasecmp(const char *A
,const char *AEnd
,const char *B
,const char *BEnd
)
531 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
532 if (toupper(*A
) != toupper(*B
))
535 if (A
== AEnd
&& B
== BEnd
)
541 if (toupper(*A
) < toupper(*B
))
546 int stringcasecmp(string::const_iterator A
,string::const_iterator AEnd
,
547 const char *B
,const char *BEnd
)
549 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
550 if (toupper(*A
) != toupper(*B
))
553 if (A
== AEnd
&& B
== BEnd
)
559 if (toupper(*A
) < toupper(*B
))
563 int stringcasecmp(string::const_iterator A
,string::const_iterator AEnd
,
564 string::const_iterator B
,string::const_iterator BEnd
)
566 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
567 if (toupper(*A
) != toupper(*B
))
570 if (A
== AEnd
&& B
== BEnd
)
576 if (toupper(*A
) < toupper(*B
))
582 // LookupTag - Lookup the value of a tag in a taged string /*{{{*/
583 // ---------------------------------------------------------------------
584 /* The format is like those used in package files and the method
585 communication system */
586 string
LookupTag(string Message
,const char *Tag
,const char *Default
)
588 // Look for a matching tag.
589 int Length
= strlen(Tag
);
590 for (string::iterator I
= Message
.begin(); I
+ Length
< Message
.end(); I
++)
593 if (I
[Length
] == ':' && stringcasecmp(I
,I
+Length
,Tag
) == 0)
595 // Find the end of line and strip the leading/trailing spaces
598 for (; isspace(*I
) != 0 && I
< Message
.end(); I
++);
599 for (J
= I
; *J
!= '\n' && J
< Message
.end(); J
++);
600 for (; J
> I
&& isspace(J
[-1]) != 0; J
--);
605 for (; *I
!= '\n' && I
< Message
.end(); I
++);
608 // Failed to find a match
614 // StringToBool - Converts a string into a boolean /*{{{*/
615 // ---------------------------------------------------------------------
616 /* This inspects the string to see if it is true or if it is false and
617 then returns the result. Several varients on true/false are checked. */
618 int StringToBool(string Text
,int Default
)
621 int Res
= strtol(Text
.c_str(),&End
,0);
622 if (End
!= Text
.c_str() && Res
>= 0 && Res
<= 1)
625 // Check for positives
626 if (strcasecmp(Text
.c_str(),"no") == 0 ||
627 strcasecmp(Text
.c_str(),"false") == 0 ||
628 strcasecmp(Text
.c_str(),"without") == 0 ||
629 strcasecmp(Text
.c_str(),"off") == 0 ||
630 strcasecmp(Text
.c_str(),"disable") == 0)
633 // Check for negatives
634 if (strcasecmp(Text
.c_str(),"yes") == 0 ||
635 strcasecmp(Text
.c_str(),"true") == 0 ||
636 strcasecmp(Text
.c_str(),"with") == 0 ||
637 strcasecmp(Text
.c_str(),"on") == 0 ||
638 strcasecmp(Text
.c_str(),"enable") == 0)
644 // TimeRFC1123 - Convert a time_t into RFC1123 format /*{{{*/
645 // ---------------------------------------------------------------------
646 /* This converts a time_t into a string time representation that is
647 year 2000 complient and timezone neutral */
648 string
TimeRFC1123(time_t Date
)
650 struct tm Conv
= *gmtime(&Date
);
653 const char *Day
[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
654 const char *Month
[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul",
655 "Aug","Sep","Oct","Nov","Dec"};
657 sprintf(Buf
,"%s, %02i %s %i %02i:%02i:%02i GMT",Day
[Conv
.tm_wday
],
658 Conv
.tm_mday
,Month
[Conv
.tm_mon
],Conv
.tm_year
+1900,Conv
.tm_hour
,
659 Conv
.tm_min
,Conv
.tm_sec
);
663 // ReadMessages - Read messages from the FD /*{{{*/
664 // ---------------------------------------------------------------------
665 /* This pulls full messages from the input FD into the message buffer.
666 It assumes that messages will not pause during transit so no
667 fancy buffering is used. */
668 bool ReadMessages(int Fd
, vector
<string
> &List
)
675 int Res
= read(Fd
,End
,sizeof(Buffer
) - (End
-Buffer
));
676 if (Res
< 0 && errno
== EINTR
)
679 // Process is dead, this is kind of bad..
684 if (Res
< 0 && errno
== EAGAIN
)
691 // Look for the end of the message
692 for (char *I
= Buffer
; I
+ 1 < End
; I
++)
694 if (I
[0] != '\n' || I
[1] != '\n')
697 // Pull the message out
698 string
Message(Buffer
,I
-Buffer
);
701 for (; I
< End
&& *I
== '\n'; I
++);
703 memmove(Buffer
,I
,End
-Buffer
);
706 List
.push_back(Message
);
711 if (WaitFd(Fd
) == false)
716 // MonthConv - Converts a month string into a number /*{{{*/
717 // ---------------------------------------------------------------------
718 /* This was lifted from the boa webserver which lifted it from 'wn-v1.07'
719 Made it a bit more robust with a few touppers though. */
720 static int MonthConv(char *Month
)
722 switch (toupper(*Month
))
725 return toupper(Month
[1]) == 'P'?3:7;
731 if (toupper(Month
[1]) == 'A')
733 return toupper(Month
[2]) == 'N'?5:6;
735 return toupper(Month
[2]) == 'R'?2:4;
743 // Pretend it is January..
749 // timegm - Internal timegm function if gnu is not available /*{{{*/
750 // ---------------------------------------------------------------------
751 /* Ripped this evil little function from wget - I prefer the use of
752 GNU timegm if possible as this technique will have interesting problems
753 with leap seconds, timezones and other.
755 Converts struct tm to time_t, assuming the data in tm is UTC rather
756 than local timezone (mktime assumes the latter).
758 Contributed by Roger Beeman <beeman@cisco.com>, with the help of
759 Mark Baushke <mdb@cisco.com> and the rest of the Gurus at CISCO. */
761 /* Turned it into an autoconf check, because GNU is not the only thing which
762 can provide timegm. -- 2002-09-22, Joel Baker */
764 #ifndef HAVE_TIMEGM // Now with autoconf!
765 static time_t timegm(struct tm
*t
)
772 tb
= mktime (gmtime (&tl
));
773 return (tl
<= tb
? (tl
+ (tl
- tb
)) : (tl
- (tb
- tl
)));
777 // StrToTime - Converts a string into a time_t /*{{{*/
778 // ---------------------------------------------------------------------
779 /* This handles all 3 populare time formats including RFC 1123, RFC 1036
780 and the C library asctime format. It requires the GNU library function
781 'timegm' to convert a struct tm in UTC to a time_t. For some bizzar
782 reason the C library does not provide any such function :< This also
783 handles the weird, but unambiguous FTP time format*/
784 bool StrToTime(string Val
,time_t &Result
)
788 const char *I
= Val
.c_str();
790 // Skip the day of the week
791 for (;*I
!= 0 && *I
!= ' '; I
++);
793 // Handle RFC 1123 time
795 if (sscanf(I
," %d %3s %d %d:%d:%d GMT",&Tm
.tm_mday
,Month
,&Tm
.tm_year
,
796 &Tm
.tm_hour
,&Tm
.tm_min
,&Tm
.tm_sec
) != 6)
798 // Handle RFC 1036 time
799 if (sscanf(I
," %d-%3s-%d %d:%d:%d GMT",&Tm
.tm_mday
,Month
,
800 &Tm
.tm_year
,&Tm
.tm_hour
,&Tm
.tm_min
,&Tm
.tm_sec
) == 6)
805 if (sscanf(I
," %3s %d %d:%d:%d %d",Month
,&Tm
.tm_mday
,
806 &Tm
.tm_hour
,&Tm
.tm_min
,&Tm
.tm_sec
,&Tm
.tm_year
) != 6)
809 if (sscanf(Val
.c_str(),"%4d%2d%2d%2d%2d%2d",&Tm
.tm_year
,&Tm
.tm_mon
,
810 &Tm
.tm_mday
,&Tm
.tm_hour
,&Tm
.tm_min
,&Tm
.tm_sec
) != 6)
819 Tm
.tm_mon
= MonthConv(Month
);
822 // Convert to local time and then to GMT
823 Result
= timegm(&Tm
);
827 // StrToNum - Convert a fixed length string to a number /*{{{*/
828 // ---------------------------------------------------------------------
829 /* This is used in decoding the crazy fixed length string headers in
831 bool StrToNum(const char *Str
,unsigned long &Res
,unsigned Len
,unsigned Base
)
834 if (Len
>= sizeof(S
))
839 // All spaces is a zero
842 for (I
= 0; S
[I
] == ' '; I
++);
847 Res
= strtoul(S
,&End
,Base
);
854 // HexDigit - Convert a hex character into an integer /*{{{*/
855 // ---------------------------------------------------------------------
856 /* Helper for Hex2Num */
857 static int HexDigit(int c
)
859 if (c
>= '0' && c
<= '9')
861 if (c
>= 'a' && c
<= 'f')
863 if (c
>= 'A' && c
<= 'F')
868 // Hex2Num - Convert a long hex number into a buffer /*{{{*/
869 // ---------------------------------------------------------------------
870 /* The length of the buffer must be exactly 1/2 the length of the string. */
871 bool Hex2Num(string Str
,unsigned char *Num
,unsigned int Length
)
873 if (Str
.length() != Length
*2)
876 // Convert each digit. We store it in the same order as the string
878 for (string::const_iterator I
= Str
.begin(); I
!= Str
.end();J
++, I
+= 2)
880 if (isxdigit(*I
) == 0 || isxdigit(I
[1]) == 0)
883 Num
[J
] = HexDigit(I
[0]) << 4;
884 Num
[J
] += HexDigit(I
[1]);
890 // TokSplitString - Split a string up by a given token /*{{{*/
891 // ---------------------------------------------------------------------
892 /* This is intended to be a faster splitter, it does not use dynamic
893 memories. Input is changed to insert nulls at each token location. */
894 bool TokSplitString(char Tok
,char *Input
,char **List
,
895 unsigned long ListMax
)
897 // Strip any leading spaces
899 char *Stop
= Start
+ strlen(Start
);
900 for (; *Start
!= 0 && isspace(*Start
) != 0; Start
++);
902 unsigned long Count
= 0;
906 // Skip to the next Token
907 for (; Pos
!= Stop
&& *Pos
!= Tok
; Pos
++);
909 // Back remove spaces
911 for (; End
> Start
&& (End
[-1] == Tok
|| isspace(End
[-1]) != 0); End
--);
914 List
[Count
++] = Start
;
915 if (Count
>= ListMax
)
922 for (; Pos
!= Stop
&& (*Pos
== Tok
|| isspace(*Pos
) != 0 || *Pos
== 0); Pos
++);
930 // RegexChoice - Simple regex list/list matcher /*{{{*/
931 // ---------------------------------------------------------------------
933 unsigned long RegexChoice(RxChoiceList
*Rxs
,const char **ListBegin
,
934 const char **ListEnd
)
936 for (RxChoiceList
*R
= Rxs
; R
->Str
!= 0; R
++)
939 unsigned long Hits
= 0;
940 for (; ListBegin
!= ListEnd
; ListBegin
++)
942 // Check if the name is a regex
945 for (I
= *ListBegin
; *I
!= 0; I
++)
946 if (*I
== '.' || *I
== '?' || *I
== '*' || *I
== '|')
951 // Compile the regex pattern
954 if (regcomp(&Pattern
,*ListBegin
,REG_EXTENDED
| REG_ICASE
|
960 for (RxChoiceList
*R
= Rxs
; R
->Str
!= 0; R
++)
965 if (strcasecmp(R
->Str
,*ListBegin
) != 0)
969 if (regexec(&Pattern
,R
->Str
,0,0,0) != 0)
984 _error
->Warning(_("Selection %s not found"),*ListBegin
);
990 // ioprintf - C format string outputter to C++ iostreams /*{{{*/
991 // ---------------------------------------------------------------------
992 /* This is used to make the internationalization strings easier to translate
993 and to allow reordering of parameters */
994 void ioprintf(ostream
&out
,const char *format
,...)
997 va_start(args
,format
);
999 // sprintf the description
1001 vsnprintf(S
,sizeof(S
),format
,args
);
1005 // safe_snprintf - Safer snprintf /*{{{*/
1006 // ---------------------------------------------------------------------
1007 /* This is a snprintf that will never (ever) go past 'End' and returns a
1008 pointer to the end of the new string. The returned string is always null
1009 terminated unless Buffer == end. This is a better alterantive to using
1010 consecutive snprintfs. */
1011 char *safe_snprintf(char *Buffer
,char *End
,const char *Format
,...)
1016 va_start(args
,Format
);
1021 Did
= vsnprintf(Buffer
,End
- Buffer
,Format
,args
);
1022 if (Did
< 0 || Buffer
+ Did
> End
)
1024 return Buffer
+ Did
;
1028 // CheckDomainList - See if Host is in a , seperate list /*{{{*/
1029 // ---------------------------------------------------------------------
1030 /* The domain list is a comma seperate list of domains that are suffix
1031 matched against the argument */
1032 bool CheckDomainList(string Host
,string List
)
1034 string::const_iterator Start
= List
.begin();
1035 for (string::const_iterator Cur
= List
.begin(); Cur
<= List
.end(); Cur
++)
1037 if (Cur
< List
.end() && *Cur
!= ',')
1040 // Match the end of the string..
1041 if ((Host
.size() >= (unsigned)(Cur
- Start
)) &&
1043 stringcasecmp(Host
.end() - (Cur
- Start
),Host
.end(),Start
,Cur
) == 0)
1052 // URI::CopyFrom - Copy from an object /*{{{*/
1053 // ---------------------------------------------------------------------
1054 /* This parses the URI into all of its components */
1055 void URI::CopyFrom(string U
)
1057 string::const_iterator I
= U
.begin();
1059 // Locate the first colon, this separates the scheme
1060 for (; I
< U
.end() && *I
!= ':' ; I
++);
1061 string::const_iterator FirstColon
= I
;
1063 /* Determine if this is a host type URI with a leading double //
1064 and then search for the first single / */
1065 string::const_iterator SingleSlash
= I
;
1066 if (I
+ 3 < U
.end() && I
[1] == '/' && I
[2] == '/')
1069 /* Find the / indicating the end of the hostname, ignoring /'s in the
1071 bool InBracket
= false;
1072 for (; SingleSlash
< U
.end() && (*SingleSlash
!= '/' || InBracket
== true); SingleSlash
++)
1074 if (*SingleSlash
== '[')
1076 if (InBracket
== true && *SingleSlash
== ']')
1080 if (SingleSlash
> U
.end())
1081 SingleSlash
= U
.end();
1083 // We can now write the access and path specifiers
1084 Access
= string(U
,0,FirstColon
- U
.begin());
1085 if (SingleSlash
!= U
.end())
1086 Path
= string(U
,SingleSlash
- U
.begin());
1087 if (Path
.empty() == true)
1090 // Now we attempt to locate a user:pass@host fragment
1091 if (FirstColon
+ 2 <= U
.end() && FirstColon
[1] == '/' && FirstColon
[2] == '/')
1095 if (FirstColon
>= U
.end())
1098 if (FirstColon
> SingleSlash
)
1099 FirstColon
= SingleSlash
;
1101 // Find the colon...
1103 if (I
> SingleSlash
)
1105 for (; I
< SingleSlash
&& *I
!= ':'; I
++);
1106 string::const_iterator SecondColon
= I
;
1108 // Search for the @ after the colon
1109 for (; I
< SingleSlash
&& *I
!= '@'; I
++);
1110 string::const_iterator At
= I
;
1112 // Now write the host and user/pass
1113 if (At
== SingleSlash
)
1115 if (FirstColon
< SingleSlash
)
1116 Host
= string(U
,FirstColon
- U
.begin(),SingleSlash
- FirstColon
);
1120 Host
= string(U
,At
- U
.begin() + 1,SingleSlash
- At
- 1);
1121 User
= string(U
,FirstColon
- U
.begin(),SecondColon
- FirstColon
);
1122 if (SecondColon
< At
)
1123 Password
= string(U
,SecondColon
- U
.begin() + 1,At
- SecondColon
- 1);
1126 // Now we parse the RFC 2732 [] hostnames.
1127 unsigned long PortEnd
= 0;
1129 for (unsigned I
= 0; I
!= Host
.length();)
1138 if (InBracket
== true && Host
[I
] == ']')
1149 if (InBracket
== true)
1155 // Now we parse off a port number from the hostname
1157 string::size_type Pos
= Host
.rfind(':');
1158 if (Pos
== string::npos
|| Pos
< PortEnd
)
1161 Port
= atoi(string(Host
,Pos
+1).c_str());
1162 Host
= string(Host
,0,Pos
);
1165 // URI::operator string - Convert the URI to a string /*{{{*/
1166 // ---------------------------------------------------------------------
1168 URI::operator string()
1172 if (Access
.empty() == false)
1175 if (Host
.empty() == false)
1177 if (Access
.empty() == false)
1180 if (User
.empty() == false)
1183 if (Password
.empty() == false)
1184 Res
+= ":" + Password
;
1188 // Add RFC 2732 escaping characters
1189 if (Access
.empty() == false &&
1190 (Host
.find('/') != string::npos
|| Host
.find(':') != string::npos
))
1191 Res
+= '[' + Host
+ ']';
1198 sprintf(S
,":%u",Port
);
1203 if (Path
.empty() == false)
1214 // URI::SiteOnly - Return the schema and site for the URI /*{{{*/
1215 // ---------------------------------------------------------------------
1217 string
URI::SiteOnly(string URI
)
1221 U
.Password
= string();