1 // -*- mode: cpp; mode: fold -*-
3 // $Id: strutl.cc,v 1.37 2001/02/23 06:08:57 jgg 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>
37 // strstrip - Remove white space from the front and back of a string /*{{{*/
38 // ---------------------------------------------------------------------
39 /* This is handy to use when parsing a file. It also removes \n's left
40 over from fgets and company */
41 char *_strstrip(char *String
)
43 for (;*String
!= 0 && (*String
== ' ' || *String
== '\t'); String
++);
48 char *End
= String
+ strlen(String
) - 1;
49 for (;End
!= String
- 1 && (*End
== ' ' || *End
== '\t' || *End
== '\n' ||
50 *End
== '\r'); End
--);
56 // strtabexpand - Converts tabs into 8 spaces /*{{{*/
57 // ---------------------------------------------------------------------
59 char *_strtabexpand(char *String
,size_t Len
)
61 for (char *I
= String
; I
!= I
+ Len
&& *I
!= 0; I
++)
65 if (I
+ 8 > String
+ Len
)
71 /* Assume the start of the string is 0 and find the next 8 char
77 Len
= 8 - ((String
- I
) % 8);
85 memmove(I
+ Len
,I
+ 1,strlen(I
) + 1);
86 for (char *J
= I
; J
+ Len
!= I
; *I
= ' ', I
++);
91 // ParseQuoteWord - Parse a single word out of a string /*{{{*/
92 // ---------------------------------------------------------------------
93 /* This grabs a single word, converts any % escaped characters to their
94 proper values and advances the pointer. Double quotes are understood
95 and striped out as well. This is for URI/URL parsing. It also can
96 understand [] brackets.*/
97 bool ParseQuoteWord(const char *&String
,string
&Res
)
99 // Skip leading whitespace
100 const char *C
= String
;
101 for (;*C
!= 0 && *C
== ' '; C
++);
105 // Jump to the next word
106 for (;*C
!= 0 && isspace(*C
) == 0; C
++)
110 for (C
++; *C
!= 0 && *C
!= '"'; C
++);
116 for (C
++; *C
!= 0 && *C
!= ']'; C
++);
122 // Now de-quote characters
125 const char *Start
= String
;
127 for (I
= Buffer
; I
< Buffer
+ sizeof(Buffer
) && Start
!= C
; I
++)
129 if (*Start
== '%' && Start
+ 2 < C
)
134 *I
= (char)strtol(Tmp
,0,16);
147 // Skip ending white space
148 for (;*C
!= 0 && isspace(*C
) != 0; C
++);
153 // ParseCWord - Parses a string like a C "" expression /*{{{*/
154 // ---------------------------------------------------------------------
155 /* This expects a series of space separated strings enclosed in ""'s.
156 It concatenates the ""'s into a single string. */
157 bool ParseCWord(const char *&String
,string
&Res
)
159 // Skip leading whitespace
160 const char *C
= String
;
161 for (;*C
!= 0 && *C
== ' '; C
++);
167 if (strlen(String
) >= sizeof(Buffer
))
174 for (C
++; *C
!= 0 && *C
!= '"'; C
++)
183 if (C
!= String
&& isspace(*C
) != 0 && isspace(C
[-1]) != 0)
185 if (isspace(*C
) == 0)
195 // QuoteString - Convert a string into quoted from /*{{{*/
196 // ---------------------------------------------------------------------
198 string
QuoteString(string Str
,const char *Bad
)
201 for (string::iterator I
= Str
.begin(); I
!= Str
.end(); I
++)
203 if (strchr(Bad
,*I
) != 0 || isprint(*I
) == 0 ||
204 *I
<= 0x20 || *I
>= 0x7F)
207 sprintf(Buf
,"%%%02x",(int)*I
);
216 // DeQuoteString - Convert a string from quoted from /*{{{*/
217 // ---------------------------------------------------------------------
218 /* This undoes QuoteString */
219 string
DeQuoteString(string Str
)
222 for (string::iterator I
= Str
.begin(); I
!= Str
.end(); I
++)
224 if (*I
== '%' && I
+ 2 < Str
.end())
230 Res
+= (char)strtol(Tmp
,0,16);
241 // SizeToStr - Convert a long into a human readable size /*{{{*/
242 // ---------------------------------------------------------------------
243 /* A max of 4 digits are shown before conversion to the next highest unit.
244 The max length of the string will be 5 chars unless the size is > 10
246 string
SizeToStr(double Size
)
255 /* bytes, KiloBytes, MegaBytes, GigaBytes, TeraBytes, PetaBytes,
256 ExaBytes, ZettaBytes, YottaBytes */
257 char Ext
[] = {'\0','k','M','G','T','P','E','Z','Y'};
261 if (ASize
< 100 && I
!= 0)
263 sprintf(S
,"%.1f%c",ASize
,Ext
[I
]);
269 sprintf(S
,"%.0f%c",ASize
,Ext
[I
]);
279 // TimeToStr - Convert the time into a string /*{{{*/
280 // ---------------------------------------------------------------------
281 /* Converts a number of seconds to a hms format */
282 string
TimeToStr(unsigned long Sec
)
290 sprintf(S
,"%lid %lih%lim%lis",Sec
/60/60/24,(Sec
/60/60) % 24,(Sec
/60) % 60,Sec
% 60);
296 sprintf(S
,"%lih%lim%lis",Sec
/60/60,(Sec
/60) % 60,Sec
% 60);
302 sprintf(S
,"%lim%lis",Sec
/60,Sec
% 60);
306 sprintf(S
,"%lis",Sec
);
313 // SubstVar - Substitute a string for another string /*{{{*/
314 // ---------------------------------------------------------------------
315 /* This replaces all occurances of Subst with Contents in Str. */
316 string
SubstVar(string Str
,string Subst
,string Contents
)
318 string::size_type Pos
= 0;
319 string::size_type OldPos
= 0;
322 while (OldPos
< Str
.length() &&
323 (Pos
= Str
.find(Subst
,OldPos
)) != string::npos
)
325 Temp
+= string(Str
,OldPos
,Pos
) + Contents
;
326 OldPos
= Pos
+ Subst
.length();
332 return Temp
+ string(Str
,OldPos
);
335 string
SubstVar(string Str
,const struct SubstVar
*Vars
)
337 for (; Vars
->Subst
!= 0; Vars
++)
338 Str
= SubstVar(Str
,Vars
->Subst
,*Vars
->Contents
);
342 // URItoFileName - Convert the uri into a unique file name /*{{{*/
343 // ---------------------------------------------------------------------
344 /* This converts a URI into a safe filename. It quotes all unsafe characters
345 and converts / to _ and removes the scheme identifier. The resulting
346 file name should be unique and never occur again for a different file */
347 string
URItoFileName(string URI
)
349 // Nuke 'sensitive' items
352 U
.Password
= string();
355 // "\x00-\x20{}|\\\\^\\[\\]<>\"\x7F-\xFF";
356 URI
= QuoteString(U
,"\\|{}[]<>\"^~_=!@#$%^&*");
357 string::iterator J
= URI
.begin();
358 for (; J
!= URI
.end(); J
++)
364 // Base64Encode - Base64 Encoding routine for short strings /*{{{*/
365 // ---------------------------------------------------------------------
366 /* This routine performs a base64 transformation on a string. It was ripped
367 from wget and then patched and bug fixed.
369 This spec can be found in rfc2045 */
370 string
Base64Encode(string S
)
373 static char tbl
[64] = {'A','B','C','D','E','F','G','H',
374 'I','J','K','L','M','N','O','P',
375 'Q','R','S','T','U','V','W','X',
376 'Y','Z','a','b','c','d','e','f',
377 'g','h','i','j','k','l','m','n',
378 'o','p','q','r','s','t','u','v',
379 'w','x','y','z','0','1','2','3',
380 '4','5','6','7','8','9','+','/'};
382 // Pre-allocate some space
384 Final
.reserve((4*S
.length() + 2)/3 + 2);
386 /* Transform the 3x8 bits to 4x6 bits, as required by
388 for (string::const_iterator I
= S
.begin(); I
< S
.end(); I
+= 3)
390 char Bits
[3] = {0,0,0};
397 Final
+= tbl
[Bits
[0] >> 2];
398 Final
+= tbl
[((Bits
[0] & 3) << 4) + (Bits
[1] >> 4)];
400 if (I
+ 1 >= S
.end())
403 Final
+= tbl
[((Bits
[1] & 0xf) << 2) + (Bits
[2] >> 6)];
405 if (I
+ 2 >= S
.end())
408 Final
+= tbl
[Bits
[2] & 0x3f];
411 /* Apply the padding elements, this tells how many bytes the remote
412 end should discard */
413 if (S
.length() % 3 == 2)
415 if (S
.length() % 3 == 1)
421 // stringcmp - Arbitary string compare /*{{{*/
422 // ---------------------------------------------------------------------
423 /* This safely compares two non-null terminated strings of arbitary
425 int stringcmp(const char *A
,const char *AEnd
,const char *B
,const char *BEnd
)
427 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
431 if (A
== AEnd
&& B
== BEnd
)
442 // stringcasecmp - Arbitary case insensitive string compare /*{{{*/
443 // ---------------------------------------------------------------------
445 int stringcasecmp(const char *A
,const char *AEnd
,const char *B
,const char *BEnd
)
447 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
448 if (toupper(*A
) != toupper(*B
))
451 if (A
== AEnd
&& B
== BEnd
)
457 if (toupper(*A
) < toupper(*B
))
462 // LookupTag - Lookup the value of a tag in a taged string /*{{{*/
463 // ---------------------------------------------------------------------
464 /* The format is like those used in package files and the method
465 communication system */
466 string
LookupTag(string Message
,const char *Tag
,const char *Default
)
468 // Look for a matching tag.
469 int Length
= strlen(Tag
);
470 for (string::iterator I
= Message
.begin(); I
+ Length
< Message
.end(); I
++)
473 if (I
[Length
] == ':' && stringcasecmp(I
,I
+Length
,Tag
) == 0)
475 // Find the end of line and strip the leading/trailing spaces
478 for (; isspace(*I
) != 0 && I
< Message
.end(); I
++);
479 for (J
= I
; *J
!= '\n' && J
< Message
.end(); J
++);
480 for (; J
> I
&& isspace(J
[-1]) != 0; J
--);
482 return string(I
,J
-I
);
485 for (; *I
!= '\n' && I
< Message
.end(); I
++);
488 // Failed to find a match
494 // StringToBool - Converts a string into a boolean /*{{{*/
495 // ---------------------------------------------------------------------
496 /* This inspects the string to see if it is true or if it is false and
497 then returns the result. Several varients on true/false are checked. */
498 int StringToBool(string Text
,int Default
= -1)
501 int Res
= strtol(Text
.c_str(),&End
,0);
502 if (End
!= Text
.c_str() && Res
>= 0 && Res
<= 1)
505 // Check for positives
506 if (strcasecmp(Text
.c_str(),"no") == 0 ||
507 strcasecmp(Text
.c_str(),"false") == 0 ||
508 strcasecmp(Text
.c_str(),"without") == 0 ||
509 strcasecmp(Text
.c_str(),"off") == 0 ||
510 strcasecmp(Text
.c_str(),"disable") == 0)
513 // Check for negatives
514 if (strcasecmp(Text
.c_str(),"yes") == 0 ||
515 strcasecmp(Text
.c_str(),"true") == 0 ||
516 strcasecmp(Text
.c_str(),"with") == 0 ||
517 strcasecmp(Text
.c_str(),"on") == 0 ||
518 strcasecmp(Text
.c_str(),"enable") == 0)
524 // TimeRFC1123 - Convert a time_t into RFC1123 format /*{{{*/
525 // ---------------------------------------------------------------------
526 /* This converts a time_t into a string time representation that is
527 year 2000 complient and timezone neutral */
528 string
TimeRFC1123(time_t Date
)
530 struct tm Conv
= *gmtime(&Date
);
533 const char *Day
[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
534 const char *Month
[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul",
535 "Aug","Sep","Oct","Nov","Dec"};
537 sprintf(Buf
,"%s, %02i %s %i %02i:%02i:%02i GMT",Day
[Conv
.tm_wday
],
538 Conv
.tm_mday
,Month
[Conv
.tm_mon
],Conv
.tm_year
+1900,Conv
.tm_hour
,
539 Conv
.tm_min
,Conv
.tm_sec
);
543 // ReadMessages - Read messages from the FD /*{{{*/
544 // ---------------------------------------------------------------------
545 /* This pulls full messages from the input FD into the message buffer.
546 It assumes that messages will not pause during transit so no
547 fancy buffering is used. */
548 bool ReadMessages(int Fd
, vector
<string
> &List
)
555 int Res
= read(Fd
,End
,sizeof(Buffer
) - (End
-Buffer
));
556 if (Res
< 0 && errno
== EINTR
)
559 // Process is dead, this is kind of bad..
564 if (Res
< 0 && errno
== EAGAIN
)
571 // Look for the end of the message
572 for (char *I
= Buffer
; I
+ 1 < End
; I
++)
574 if (I
[0] != '\n' || I
[1] != '\n')
577 // Pull the message out
578 string
Message(Buffer
,0,I
-Buffer
);
581 for (; I
< End
&& *I
== '\n'; I
++);
583 memmove(Buffer
,I
,End
-Buffer
);
586 List
.push_back(Message
);
591 if (WaitFd(Fd
) == false)
596 // MonthConv - Converts a month string into a number /*{{{*/
597 // ---------------------------------------------------------------------
598 /* This was lifted from the boa webserver which lifted it from 'wn-v1.07'
599 Made it a bit more robust with a few touppers though. */
600 static int MonthConv(char *Month
)
602 switch (toupper(*Month
))
605 return toupper(Month
[1]) == 'P'?3:7;
611 if (toupper(Month
[1]) == 'A')
613 return toupper(Month
[2]) == 'N'?5:6;
615 return toupper(Month
[2]) == 'R'?2:4;
623 // Pretend it is January..
629 // timegm - Internal timegm function if gnu is not available /*{{{*/
630 // ---------------------------------------------------------------------
631 /* Ripped this evil little function from wget - I prefer the use of
632 GNU timegm if possible as this technique will have interesting problems
633 with leap seconds, timezones and other.
635 Converts struct tm to time_t, assuming the data in tm is UTC rather
636 than local timezone (mktime assumes the latter).
638 Contributed by Roger Beeman <beeman@cisco.com>, with the help of
639 Mark Baushke <mdb@cisco.com> and the rest of the Gurus at CISCO. */
640 #ifndef __USE_MISC // glib sets this
641 static time_t timegm(struct tm
*t
)
648 tb
= mktime (gmtime (&tl
));
649 return (tl
<= tb
? (tl
+ (tl
- tb
)) : (tl
- (tb
- tl
)));
653 // StrToTime - Converts a string into a time_t /*{{{*/
654 // ---------------------------------------------------------------------
655 /* This handles all 3 populare time formats including RFC 1123, RFC 1036
656 and the C library asctime format. It requires the GNU library function
657 'timegm' to convert a struct tm in UTC to a time_t. For some bizzar
658 reason the C library does not provide any such function :< This also
659 handles the weird, but unambiguous FTP time format*/
660 bool StrToTime(string Val
,time_t &Result
)
664 const char *I
= Val
.c_str();
666 // Skip the day of the week
667 for (;*I
!= 0 && *I
!= ' '; I
++);
669 // Handle RFC 1123 time
671 if (sscanf(I
," %d %3s %d %d:%d:%d GMT",&Tm
.tm_mday
,Month
,&Tm
.tm_year
,
672 &Tm
.tm_hour
,&Tm
.tm_min
,&Tm
.tm_sec
) != 6)
674 // Handle RFC 1036 time
675 if (sscanf(I
," %d-%3s-%d %d:%d:%d GMT",&Tm
.tm_mday
,Month
,
676 &Tm
.tm_year
,&Tm
.tm_hour
,&Tm
.tm_min
,&Tm
.tm_sec
) == 6)
681 if (sscanf(I
," %3s %d %d:%d:%d %d",Month
,&Tm
.tm_mday
,
682 &Tm
.tm_hour
,&Tm
.tm_min
,&Tm
.tm_sec
,&Tm
.tm_year
) != 6)
685 if (sscanf(Val
.c_str(),"%4d%2d%2d%2d%2d%2d",&Tm
.tm_year
,&Tm
.tm_mon
,
686 &Tm
.tm_mday
,&Tm
.tm_hour
,&Tm
.tm_min
,&Tm
.tm_sec
) != 6)
695 Tm
.tm_mon
= MonthConv(Month
);
698 // Convert to local time and then to GMT
699 Result
= timegm(&Tm
);
703 // StrToNum - Convert a fixed length string to a number /*{{{*/
704 // ---------------------------------------------------------------------
705 /* This is used in decoding the crazy fixed length string headers in
707 bool StrToNum(const char *Str
,unsigned long &Res
,unsigned Len
,unsigned Base
)
710 if (Len
>= sizeof(S
))
715 // All spaces is a zero
718 for (I
= 0; S
[I
] == ' '; I
++);
723 Res
= strtoul(S
,&End
,Base
);
730 // HexDigit - Convert a hex character into an integer /*{{{*/
731 // ---------------------------------------------------------------------
732 /* Helper for Hex2Num */
733 static int HexDigit(int c
)
735 if (c
>= '0' && c
<= '9')
737 if (c
>= 'a' && c
<= 'f')
739 if (c
>= 'A' && c
<= 'F')
744 // Hex2Num - Convert a long hex number into a buffer /*{{{*/
745 // ---------------------------------------------------------------------
746 /* The length of the buffer must be exactly 1/2 the length of the string. */
747 bool Hex2Num(const char *Start
,const char *End
,unsigned char *Num
,
750 if (End
- Start
!= (signed)(Length
*2))
753 // Convert each digit. We store it in the same order as the string
755 for (const char *I
= Start
; I
< End
;J
++, I
+= 2)
757 if (isxdigit(*I
) == 0 || isxdigit(I
[1]) == 0)
760 Num
[J
] = HexDigit(I
[0]) << 4;
761 Num
[J
] += HexDigit(I
[1]);
767 // TokSplitString - Split a string up by a given token /*{{{*/
768 // ---------------------------------------------------------------------
769 /* This is intended to be a faster splitter, it does not use dynamic
770 memories. Input is changed to insert nulls at each token location. */
771 bool TokSplitString(char Tok
,char *Input
,char **List
,
772 unsigned long ListMax
)
774 // Strip any leading spaces
776 char *Stop
= Start
+ strlen(Start
);
777 for (; *Start
!= 0 && isspace(*Start
) != 0; Start
++);
779 unsigned long Count
= 0;
783 // Skip to the next Token
784 for (; Pos
!= Stop
&& *Pos
!= Tok
; Pos
++);
786 // Back remove spaces
788 for (; End
> Start
&& (End
[-1] == Tok
|| isspace(End
[-1]) != 0); End
--);
791 List
[Count
++] = Start
;
792 if (Count
>= ListMax
)
799 for (; Pos
!= Stop
&& (*Pos
== Tok
|| isspace(*Pos
) != 0 || *Pos
== 0); Pos
++);
807 // RegexChoice - Simple regex list/list matcher /*{{{*/
808 // ---------------------------------------------------------------------
810 unsigned long RegexChoice(RxChoiceList
*Rxs
,const char **ListBegin
,
811 const char **ListEnd
)
813 for (RxChoiceList
*R
= Rxs
; R
->Str
!= 0; R
++)
816 unsigned long Hits
= 0;
817 for (; ListBegin
!= ListEnd
; ListBegin
++)
819 // Check if the name is a regex
822 for (I
= *ListBegin
; *I
!= 0; I
++)
823 if (*I
== '.' || *I
== '?' || *I
== '*' || *I
== '|')
828 // Compile the regex pattern
831 if (regcomp(&Pattern
,*ListBegin
,REG_EXTENDED
| REG_ICASE
|
837 for (RxChoiceList
*R
= Rxs
; R
->Str
!= 0; R
++)
842 if (strcasecmp(R
->Str
,*ListBegin
) != 0)
846 if (regexec(&Pattern
,R
->Str
,0,0,0) != 0)
861 _error
->Warning(_("Selection %s not found"),*ListBegin
);
867 // ioprintf - C format string outputter to C++ iostreams /*{{{*/
868 // ---------------------------------------------------------------------
869 /* This is used to make the internationalization strinc easier to translate
870 and to allow reordering of parameters */
871 void ioprintf(ostream
&out
,const char *format
,...)
874 va_start(args
,format
);
876 // sprintf the description
878 vsnprintf(S
,sizeof(S
),format
,args
);
883 // CheckDomainList - See if Host is in a , seperate list /*{{{*/
884 // ---------------------------------------------------------------------
885 /* The domain list is a comma seperate list of domains that are suffix
886 matched against the argument */
887 bool CheckDomainList(string Host
,string List
)
889 const char *Start
= List
.begin();
890 for (const char *Cur
= List
.begin(); Cur
<= List
.end() ; Cur
++)
892 if (Cur
< List
.end() && *Cur
!= ',')
895 // Match the end of the string..
896 if ((Host
.size() >= (unsigned)(Cur
- List
.begin())) &&
898 stringcasecmp(Host
.end() - (Cur
- Start
),Host
.end(),Start
,Cur
) == 0)
907 // URI::CopyFrom - Copy from an object /*{{{*/
908 // ---------------------------------------------------------------------
909 /* This parses the URI into all of its components */
910 void URI::CopyFrom(string U
)
912 string::const_iterator I
= U
.begin();
914 // Locate the first colon, this separates the scheme
915 for (; I
< U
.end() && *I
!= ':' ; I
++);
916 string::const_iterator FirstColon
= I
;
918 /* Determine if this is a host type URI with a leading double //
919 and then search for the first single / */
920 string::const_iterator SingleSlash
= I
;
921 if (I
+ 3 < U
.end() && I
[1] == '/' && I
[2] == '/')
924 /* Find the / indicating the end of the hostname, ignoring /'s in the
926 bool InBracket
= false;
927 for (; SingleSlash
< U
.end() && (*SingleSlash
!= '/' || InBracket
== true); SingleSlash
++)
929 if (*SingleSlash
== '[')
931 if (InBracket
== true && *SingleSlash
== ']')
935 if (SingleSlash
> U
.end())
936 SingleSlash
= U
.end();
938 // We can now write the access and path specifiers
939 Access
= string(U
,0,FirstColon
- U
.begin());
940 if (SingleSlash
!= U
.end())
941 Path
= string(U
,SingleSlash
- U
.begin());
942 if (Path
.empty() == true)
945 // Now we attempt to locate a user:pass@host fragment
946 if (FirstColon
[1] == '/' && FirstColon
[2] == '/')
950 if (FirstColon
>= U
.end())
953 if (FirstColon
> SingleSlash
)
954 FirstColon
= SingleSlash
;
960 for (; I
< SingleSlash
&& *I
!= ':'; I
++);
961 string::const_iterator SecondColon
= I
;
963 // Search for the @ after the colon
964 for (; I
< SingleSlash
&& *I
!= '@'; I
++);
965 string::const_iterator At
= I
;
967 // Now write the host and user/pass
968 if (At
== SingleSlash
)
970 if (FirstColon
< SingleSlash
)
971 Host
= string(U
,FirstColon
- U
.begin(),SingleSlash
- FirstColon
);
975 Host
= string(U
,At
- U
.begin() + 1,SingleSlash
- At
- 1);
976 User
= string(U
,FirstColon
- U
.begin(),SecondColon
- FirstColon
);
977 if (SecondColon
< At
)
978 Password
= string(U
,SecondColon
- U
.begin() + 1,At
- SecondColon
- 1);
981 // Now we parse the RFC 2732 [] hostnames.
982 unsigned long PortEnd
= 0;
984 for (unsigned I
= 0; I
!= Host
.length();)
993 if (InBracket
== true && Host
[I
] == ']')
1004 if (InBracket
== true)
1010 // Now we parse off a port number from the hostname
1012 string::size_type Pos
= Host
.rfind(':');
1013 if (Pos
== string::npos
|| Pos
< PortEnd
)
1016 Port
= atoi(string(Host
,Pos
+1).c_str());
1017 Host
= string(Host
,0,Pos
);
1020 // URI::operator string - Convert the URI to a string /*{{{*/
1021 // ---------------------------------------------------------------------
1023 URI::operator string()
1027 if (Access
.empty() == false)
1030 if (Host
.empty() == false)
1032 if (Access
.empty() == false)
1035 if (User
.empty() == false)
1038 if (Password
.empty() == false)
1039 Res
+= ":" + Password
;
1043 // Add RFC 2732 escaping characters
1044 if (Access
.empty() == false &&
1045 (Host
.find('/') != string::npos
|| Host
.find(':') != string::npos
))
1046 Res
+= '[' + Host
+ ']';
1053 sprintf(S
,":%u",Port
);
1058 if (Path
.empty() == false)
1069 // URI::SiteOnly - Return the schema and site for the URI /*{{{*/
1070 // ---------------------------------------------------------------------
1072 string
URI::SiteOnly(string URI
)
1076 U
.Password
= string();