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 ##################################################################### */
18 #include <apt-pkg/strutl.h>
19 #include <apt-pkg/fileutl.h>
20 #include <apt-pkg/error.h>
39 // UTF8ToCodeset - Convert some UTF-8 string for some codeset /*{{{*/
40 // ---------------------------------------------------------------------
41 /* This is handy to use before display some information for enduser */
42 bool UTF8ToCodeset(const char *codeset
, const string
&orig
, string
*dest
)
46 char *inptr
, *outbuf
, *outptr
;
47 size_t insize
, outsize
;
49 cd
= iconv_open(codeset
, "UTF-8");
50 if (cd
== (iconv_t
)(-1)) {
51 // Something went wrong
53 _error
->Error("conversion from 'UTF-8' to '%s' not available",
58 // Clean the destination string
64 insize
= outsize
= orig
.size();
66 inptr
= (char *)inbuf
;
67 outbuf
= new char[insize
+1];
72 size_t const err
= iconv(cd
, &inptr
, &insize
, &outptr
, &outsize
);
73 if (err
== (size_t)(-1))
92 // strstrip - Remove white space from the front and back of a string /*{{{*/
93 // ---------------------------------------------------------------------
94 /* This is handy to use when parsing a file. It also removes \n's left
95 over from fgets and company */
96 char *_strstrip(char *String
)
98 for (;*String
!= 0 && (*String
== ' ' || *String
== '\t'); String
++);
103 char *End
= String
+ strlen(String
) - 1;
104 for (;End
!= String
- 1 && (*End
== ' ' || *End
== '\t' || *End
== '\n' ||
105 *End
== '\r'); End
--);
111 // strtabexpand - Converts tabs into 8 spaces /*{{{*/
112 // ---------------------------------------------------------------------
114 char *_strtabexpand(char *String
,size_t Len
)
116 for (char *I
= String
; I
!= I
+ Len
&& *I
!= 0; I
++)
120 if (I
+ 8 > String
+ Len
)
126 /* Assume the start of the string is 0 and find the next 8 char
132 Len
= 8 - ((String
- I
) % 8);
140 memmove(I
+ Len
,I
+ 1,strlen(I
) + 1);
141 for (char *J
= I
; J
+ Len
!= I
; *I
= ' ', I
++);
146 // ParseQuoteWord - Parse a single word out of a string /*{{{*/
147 // ---------------------------------------------------------------------
148 /* This grabs a single word, converts any % escaped characters to their
149 proper values and advances the pointer. Double quotes are understood
150 and striped out as well. This is for URI/URL parsing. It also can
151 understand [] brackets.*/
152 bool ParseQuoteWord(const char *&String
,string
&Res
)
154 // Skip leading whitespace
155 const char *C
= String
;
156 for (;*C
!= 0 && *C
== ' '; C
++);
160 // Jump to the next word
161 for (;*C
!= 0 && isspace(*C
) == 0; C
++)
165 for (C
++; *C
!= 0 && *C
!= '"'; C
++);
171 for (C
++; *C
!= 0 && *C
!= ']'; C
++);
177 // Now de-quote characters
180 const char *Start
= String
;
182 for (I
= Buffer
; I
< Buffer
+ sizeof(Buffer
) && Start
!= C
; I
++)
184 if (*Start
== '%' && Start
+ 2 < C
)
189 *I
= (char)strtol(Tmp
,0,16);
202 // Skip ending white space
203 for (;*C
!= 0 && isspace(*C
) != 0; C
++);
208 // ParseCWord - Parses a string like a C "" expression /*{{{*/
209 // ---------------------------------------------------------------------
210 /* This expects a series of space separated strings enclosed in ""'s.
211 It concatenates the ""'s into a single string. */
212 bool ParseCWord(const char *&String
,string
&Res
)
214 // Skip leading whitespace
215 const char *C
= String
;
216 for (;*C
!= 0 && *C
== ' '; C
++);
222 if (strlen(String
) >= sizeof(Buffer
))
229 for (C
++; *C
!= 0 && *C
!= '"'; C
++)
238 if (C
!= String
&& isspace(*C
) != 0 && isspace(C
[-1]) != 0)
240 if (isspace(*C
) == 0)
250 // QuoteString - Convert a string into quoted from /*{{{*/
251 // ---------------------------------------------------------------------
253 string
QuoteString(const string
&Str
, const char *Bad
)
256 for (string::const_iterator I
= Str
.begin(); I
!= Str
.end(); I
++)
258 if (strchr(Bad
,*I
) != 0 || isprint(*I
) == 0 ||
259 *I
<= 0x20 || *I
>= 0x7F)
262 sprintf(Buf
,"%%%02x",(int)*I
);
271 // DeQuoteString - Convert a string from quoted from /*{{{*/
272 // ---------------------------------------------------------------------
273 /* This undoes QuoteString */
274 string
DeQuoteString(const string
&Str
)
277 for (string::const_iterator I
= Str
.begin(); I
!= Str
.end(); I
++)
279 if (*I
== '%' && I
+ 2 < Str
.end())
285 Res
+= (char)strtol(Tmp
,0,16);
296 // SizeToStr - Convert a long into a human readable size /*{{{*/
297 // ---------------------------------------------------------------------
298 /* A max of 4 digits are shown before conversion to the next highest unit.
299 The max length of the string will be 5 chars unless the size is > 10
301 string
SizeToStr(double Size
)
310 /* bytes, KiloBytes, MegaBytes, GigaBytes, TeraBytes, PetaBytes,
311 ExaBytes, ZettaBytes, YottaBytes */
312 char Ext
[] = {'\0','k','M','G','T','P','E','Z','Y'};
316 if (ASize
< 100 && I
!= 0)
318 sprintf(S
,"%'.1f%c",ASize
,Ext
[I
]);
324 sprintf(S
,"%'.0f%c",ASize
,Ext
[I
]);
334 // TimeToStr - Convert the time into a string /*{{{*/
335 // ---------------------------------------------------------------------
336 /* Converts a number of seconds to a hms format */
337 string
TimeToStr(unsigned long Sec
)
345 //d means days, h means hours, min means minutes, s means seconds
346 sprintf(S
,_("%lid %lih %limin %lis"),Sec
/60/60/24,(Sec
/60/60) % 24,(Sec
/60) % 60,Sec
% 60);
352 //h means hours, min means minutes, s means seconds
353 sprintf(S
,_("%lih %limin %lis"),Sec
/60/60,(Sec
/60) % 60,Sec
% 60);
359 //min means minutes, s means seconds
360 sprintf(S
,_("%limin %lis"),Sec
/60,Sec
% 60);
365 sprintf(S
,_("%lis"),Sec
);
372 // SubstVar - Substitute a string for another string /*{{{*/
373 // ---------------------------------------------------------------------
374 /* This replaces all occurances of Subst with Contents in Str. */
375 string
SubstVar(const string
&Str
,const string
&Subst
,const string
&Contents
)
377 string::size_type Pos
= 0;
378 string::size_type OldPos
= 0;
381 while (OldPos
< Str
.length() &&
382 (Pos
= Str
.find(Subst
,OldPos
)) != string::npos
)
384 Temp
+= string(Str
,OldPos
,Pos
) + Contents
;
385 OldPos
= Pos
+ Subst
.length();
391 return Temp
+ string(Str
,OldPos
);
394 string
SubstVar(string Str
,const struct SubstVar
*Vars
)
396 for (; Vars
->Subst
!= 0; Vars
++)
397 Str
= SubstVar(Str
,Vars
->Subst
,*Vars
->Contents
);
401 // OutputInDepth - return a string with separator multiplied with depth /*{{{*/
402 // ---------------------------------------------------------------------
403 /* Returns a string with the supplied separator depth + 1 times in it */
404 std::string
OutputInDepth(const unsigned long Depth
, const char* Separator
)
406 std::string output
= "";
407 for(unsigned long d
=Depth
+1; d
> 0; d
--)
408 output
.append(Separator
);
412 // URItoFileName - Convert the uri into a unique file name /*{{{*/
413 // ---------------------------------------------------------------------
414 /* This converts a URI into a safe filename. It quotes all unsafe characters
415 and converts / to _ and removes the scheme identifier. The resulting
416 file name should be unique and never occur again for a different file */
417 string
URItoFileName(const string
&URI
)
419 // Nuke 'sensitive' items
425 // "\x00-\x20{}|\\\\^\\[\\]<>\"\x7F-\xFF";
426 string NewURI
= QuoteString(U
,"\\|{}[]<>\"^~_=!@#$%^&*");
427 replace(NewURI
.begin(),NewURI
.end(),'/','_');
431 // Base64Encode - Base64 Encoding routine for short strings /*{{{*/
432 // ---------------------------------------------------------------------
433 /* This routine performs a base64 transformation on a string. It was ripped
434 from wget and then patched and bug fixed.
436 This spec can be found in rfc2045 */
437 string
Base64Encode(const string
&S
)
440 static char tbl
[64] = {'A','B','C','D','E','F','G','H',
441 'I','J','K','L','M','N','O','P',
442 'Q','R','S','T','U','V','W','X',
443 'Y','Z','a','b','c','d','e','f',
444 'g','h','i','j','k','l','m','n',
445 'o','p','q','r','s','t','u','v',
446 'w','x','y','z','0','1','2','3',
447 '4','5','6','7','8','9','+','/'};
449 // Pre-allocate some space
451 Final
.reserve((4*S
.length() + 2)/3 + 2);
453 /* Transform the 3x8 bits to 4x6 bits, as required by
455 for (string::const_iterator I
= S
.begin(); I
< S
.end(); I
+= 3)
457 char Bits
[3] = {0,0,0};
464 Final
+= tbl
[Bits
[0] >> 2];
465 Final
+= tbl
[((Bits
[0] & 3) << 4) + (Bits
[1] >> 4)];
467 if (I
+ 1 >= S
.end())
470 Final
+= tbl
[((Bits
[1] & 0xf) << 2) + (Bits
[2] >> 6)];
472 if (I
+ 2 >= S
.end())
475 Final
+= tbl
[Bits
[2] & 0x3f];
478 /* Apply the padding elements, this tells how many bytes the remote
479 end should discard */
480 if (S
.length() % 3 == 2)
482 if (S
.length() % 3 == 1)
488 // stringcmp - Arbitrary string compare /*{{{*/
489 // ---------------------------------------------------------------------
490 /* This safely compares two non-null terminated strings of arbitrary
492 int stringcmp(const char *A
,const char *AEnd
,const char *B
,const char *BEnd
)
494 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
498 if (A
== AEnd
&& B
== BEnd
)
510 int stringcmp(string::const_iterator A
,string::const_iterator AEnd
,
511 const char *B
,const char *BEnd
)
513 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
517 if (A
== AEnd
&& B
== BEnd
)
527 int stringcmp(string::const_iterator A
,string::const_iterator AEnd
,
528 string::const_iterator B
,string::const_iterator BEnd
)
530 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
534 if (A
== AEnd
&& B
== BEnd
)
546 // stringcasecmp - Arbitrary case insensitive string compare /*{{{*/
547 // ---------------------------------------------------------------------
549 int stringcasecmp(const char *A
,const char *AEnd
,const char *B
,const char *BEnd
)
551 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
552 if (toupper(*A
) != toupper(*B
))
555 if (A
== AEnd
&& B
== BEnd
)
561 if (toupper(*A
) < toupper(*B
))
566 int stringcasecmp(string::const_iterator A
,string::const_iterator AEnd
,
567 const char *B
,const char *BEnd
)
569 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
570 if (toupper(*A
) != toupper(*B
))
573 if (A
== AEnd
&& B
== BEnd
)
579 if (toupper(*A
) < toupper(*B
))
583 int stringcasecmp(string::const_iterator A
,string::const_iterator AEnd
,
584 string::const_iterator B
,string::const_iterator BEnd
)
586 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
587 if (toupper(*A
) != toupper(*B
))
590 if (A
== AEnd
&& B
== BEnd
)
596 if (toupper(*A
) < toupper(*B
))
602 // LookupTag - Lookup the value of a tag in a taged string /*{{{*/
603 // ---------------------------------------------------------------------
604 /* The format is like those used in package files and the method
605 communication system */
606 string
LookupTag(const string
&Message
,const char *Tag
,const char *Default
)
608 // Look for a matching tag.
609 int Length
= strlen(Tag
);
610 for (string::const_iterator I
= Message
.begin(); I
+ Length
< Message
.end(); I
++)
613 if (I
[Length
] == ':' && stringcasecmp(I
,I
+Length
,Tag
) == 0)
615 // Find the end of line and strip the leading/trailing spaces
616 string::const_iterator J
;
618 for (; isspace(*I
) != 0 && I
< Message
.end(); I
++);
619 for (J
= I
; *J
!= '\n' && J
< Message
.end(); J
++);
620 for (; J
> I
&& isspace(J
[-1]) != 0; J
--);
625 for (; *I
!= '\n' && I
< Message
.end(); I
++);
628 // Failed to find a match
634 // StringToBool - Converts a string into a boolean /*{{{*/
635 // ---------------------------------------------------------------------
636 /* This inspects the string to see if it is true or if it is false and
637 then returns the result. Several varients on true/false are checked. */
638 int StringToBool(const string
&Text
,int Default
)
641 int Res
= strtol(Text
.c_str(),&End
,0);
642 if (End
!= Text
.c_str() && Res
>= 0 && Res
<= 1)
645 // Check for positives
646 if (strcasecmp(Text
.c_str(),"no") == 0 ||
647 strcasecmp(Text
.c_str(),"false") == 0 ||
648 strcasecmp(Text
.c_str(),"without") == 0 ||
649 strcasecmp(Text
.c_str(),"off") == 0 ||
650 strcasecmp(Text
.c_str(),"disable") == 0)
653 // Check for negatives
654 if (strcasecmp(Text
.c_str(),"yes") == 0 ||
655 strcasecmp(Text
.c_str(),"true") == 0 ||
656 strcasecmp(Text
.c_str(),"with") == 0 ||
657 strcasecmp(Text
.c_str(),"on") == 0 ||
658 strcasecmp(Text
.c_str(),"enable") == 0)
664 // TimeRFC1123 - Convert a time_t into RFC1123 format /*{{{*/
665 // ---------------------------------------------------------------------
666 /* This converts a time_t into a string time representation that is
667 year 2000 complient and timezone neutral */
668 string
TimeRFC1123(time_t Date
)
670 struct tm Conv
= *gmtime(&Date
);
673 const char *Day
[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
674 const char *Month
[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul",
675 "Aug","Sep","Oct","Nov","Dec"};
677 sprintf(Buf
,"%s, %02i %s %i %02i:%02i:%02i GMT",Day
[Conv
.tm_wday
],
678 Conv
.tm_mday
,Month
[Conv
.tm_mon
],Conv
.tm_year
+1900,Conv
.tm_hour
,
679 Conv
.tm_min
,Conv
.tm_sec
);
683 // ReadMessages - Read messages from the FD /*{{{*/
684 // ---------------------------------------------------------------------
685 /* This pulls full messages from the input FD into the message buffer.
686 It assumes that messages will not pause during transit so no
687 fancy buffering is used.
689 In particular: this reads blocks from the input until it believes
690 that it's run out of input text. Each block is terminated by a
691 double newline ('\n' followed by '\n'). As noted below, there is a
692 bug in this code: it assumes that all the blocks have been read if
693 it doesn't see additional text in the buffer after the last one is
694 parsed, which will cause it to lose blocks if the last block
695 coincides with the end of the buffer.
697 bool ReadMessages(int Fd
, vector
<string
> &List
)
701 // Represents any left-over from the previous iteration of the
702 // parse loop. (i.e., if a message is split across the end
703 // of the buffer, it goes here)
704 string PartialMessage
;
708 int Res
= read(Fd
,End
,sizeof(Buffer
) - (End
-Buffer
));
709 if (Res
< 0 && errno
== EINTR
)
712 // Process is dead, this is kind of bad..
717 if (Res
< 0 && errno
== EAGAIN
)
724 // Look for the end of the message
725 for (char *I
= Buffer
; I
+ 1 < End
; I
++)
727 if (I
[0] != '\n' || I
[1] != '\n')
730 // Pull the message out
731 string
Message(Buffer
,I
-Buffer
);
732 PartialMessage
+= Message
;
735 for (; I
< End
&& *I
== '\n'; I
++);
737 memmove(Buffer
,I
,End
-Buffer
);
740 List
.push_back(PartialMessage
);
741 PartialMessage
.clear();
745 // If there's text left in the buffer, store it
746 // in PartialMessage and throw the rest of the buffer
747 // away. This allows us to handle messages that
748 // are longer than the static buffer size.
749 PartialMessage
+= string(Buffer
, End
);
754 // BUG ALERT: if a message block happens to end at a
755 // multiple of 64000 characters, this will cause it to
756 // terminate early, leading to a badly formed block and
757 // probably crashing the method. However, this is the only
758 // way we have to find the end of the message block. I have
759 // an idea of how to fix this, but it will require changes
760 // to the protocol (essentially to mark the beginning and
761 // end of the block).
763 // -- dburrows 2008-04-02
767 if (WaitFd(Fd
) == false)
772 // MonthConv - Converts a month string into a number /*{{{*/
773 // ---------------------------------------------------------------------
774 /* This was lifted from the boa webserver which lifted it from 'wn-v1.07'
775 Made it a bit more robust with a few touppers though. */
776 static int MonthConv(char *Month
)
778 switch (toupper(*Month
))
781 return toupper(Month
[1]) == 'P'?3:7;
787 if (toupper(Month
[1]) == 'A')
789 return toupper(Month
[2]) == 'N'?5:6;
791 return toupper(Month
[2]) == 'R'?2:4;
799 // Pretend it is January..
805 // timegm - Internal timegm function if gnu is not available /*{{{*/
806 // ---------------------------------------------------------------------
807 /* Ripped this evil little function from wget - I prefer the use of
808 GNU timegm if possible as this technique will have interesting problems
809 with leap seconds, timezones and other.
811 Converts struct tm to time_t, assuming the data in tm is UTC rather
812 than local timezone (mktime assumes the latter).
814 Contributed by Roger Beeman <beeman@cisco.com>, with the help of
815 Mark Baushke <mdb@cisco.com> and the rest of the Gurus at CISCO. */
817 /* Turned it into an autoconf check, because GNU is not the only thing which
818 can provide timegm. -- 2002-09-22, Joel Baker */
820 #ifndef HAVE_TIMEGM // Now with autoconf!
821 static time_t timegm(struct tm
*t
)
828 tb
= mktime (gmtime (&tl
));
829 return (tl
<= tb
? (tl
+ (tl
- tb
)) : (tl
- (tb
- tl
)));
833 // StrToTime - Converts a string into a time_t /*{{{*/
834 // ---------------------------------------------------------------------
835 /* This handles all 3 populare time formats including RFC 1123, RFC 1036
836 and the C library asctime format. It requires the GNU library function
837 'timegm' to convert a struct tm in UTC to a time_t. For some bizzar
838 reason the C library does not provide any such function :< This also
839 handles the weird, but unambiguous FTP time format*/
840 bool StrToTime(const string
&Val
,time_t &Result
)
844 const char *I
= Val
.c_str();
846 // Skip the day of the week
847 for (;*I
!= 0 && *I
!= ' '; I
++);
849 // Handle RFC 1123 time
851 if (sscanf(I
," %d %3s %d %d:%d:%d GMT",&Tm
.tm_mday
,Month
,&Tm
.tm_year
,
852 &Tm
.tm_hour
,&Tm
.tm_min
,&Tm
.tm_sec
) != 6)
854 // Handle RFC 1036 time
855 if (sscanf(I
," %d-%3s-%d %d:%d:%d GMT",&Tm
.tm_mday
,Month
,
856 &Tm
.tm_year
,&Tm
.tm_hour
,&Tm
.tm_min
,&Tm
.tm_sec
) == 6)
861 if (sscanf(I
," %3s %d %d:%d:%d %d",Month
,&Tm
.tm_mday
,
862 &Tm
.tm_hour
,&Tm
.tm_min
,&Tm
.tm_sec
,&Tm
.tm_year
) != 6)
865 if (sscanf(Val
.c_str(),"%4d%2d%2d%2d%2d%2d",&Tm
.tm_year
,&Tm
.tm_mon
,
866 &Tm
.tm_mday
,&Tm
.tm_hour
,&Tm
.tm_min
,&Tm
.tm_sec
) != 6)
875 Tm
.tm_mon
= MonthConv(Month
);
878 // Convert to local time and then to GMT
879 Result
= timegm(&Tm
);
883 // StrToNum - Convert a fixed length string to a number /*{{{*/
884 // ---------------------------------------------------------------------
885 /* This is used in decoding the crazy fixed length string headers in
887 bool StrToNum(const char *Str
,unsigned long &Res
,unsigned Len
,unsigned Base
)
890 if (Len
>= sizeof(S
))
895 // All spaces is a zero
898 for (I
= 0; S
[I
] == ' '; I
++);
903 Res
= strtoul(S
,&End
,Base
);
910 // HexDigit - Convert a hex character into an integer /*{{{*/
911 // ---------------------------------------------------------------------
912 /* Helper for Hex2Num */
913 static int HexDigit(int c
)
915 if (c
>= '0' && c
<= '9')
917 if (c
>= 'a' && c
<= 'f')
919 if (c
>= 'A' && c
<= 'F')
924 // Hex2Num - Convert a long hex number into a buffer /*{{{*/
925 // ---------------------------------------------------------------------
926 /* The length of the buffer must be exactly 1/2 the length of the string. */
927 bool Hex2Num(const string
&Str
,unsigned char *Num
,unsigned int Length
)
929 if (Str
.length() != Length
*2)
932 // Convert each digit. We store it in the same order as the string
934 for (string::const_iterator I
= Str
.begin(); I
!= Str
.end();J
++, I
+= 2)
936 if (isxdigit(*I
) == 0 || isxdigit(I
[1]) == 0)
939 Num
[J
] = HexDigit(I
[0]) << 4;
940 Num
[J
] += HexDigit(I
[1]);
946 // TokSplitString - Split a string up by a given token /*{{{*/
947 // ---------------------------------------------------------------------
948 /* This is intended to be a faster splitter, it does not use dynamic
949 memories. Input is changed to insert nulls at each token location. */
950 bool TokSplitString(char Tok
,char *Input
,char **List
,
951 unsigned long ListMax
)
953 // Strip any leading spaces
955 char *Stop
= Start
+ strlen(Start
);
956 for (; *Start
!= 0 && isspace(*Start
) != 0; Start
++);
958 unsigned long Count
= 0;
962 // Skip to the next Token
963 for (; Pos
!= Stop
&& *Pos
!= Tok
; Pos
++);
965 // Back remove spaces
967 for (; End
> Start
&& (End
[-1] == Tok
|| isspace(End
[-1]) != 0); End
--);
970 List
[Count
++] = Start
;
971 if (Count
>= ListMax
)
978 for (; Pos
!= Stop
&& (*Pos
== Tok
|| isspace(*Pos
) != 0 || *Pos
== 0); Pos
++);
986 // RegexChoice - Simple regex list/list matcher /*{{{*/
987 // ---------------------------------------------------------------------
989 unsigned long RegexChoice(RxChoiceList
*Rxs
,const char **ListBegin
,
990 const char **ListEnd
)
992 for (RxChoiceList
*R
= Rxs
; R
->Str
!= 0; R
++)
995 unsigned long Hits
= 0;
996 for (; ListBegin
!= ListEnd
; ListBegin
++)
998 // Check if the name is a regex
1001 for (I
= *ListBegin
; *I
!= 0; I
++)
1002 if (*I
== '.' || *I
== '?' || *I
== '*' || *I
== '|')
1007 // Compile the regex pattern
1010 if (regcomp(&Pattern
,*ListBegin
,REG_EXTENDED
| REG_ICASE
|
1016 for (RxChoiceList
*R
= Rxs
; R
->Str
!= 0; R
++)
1021 if (strcasecmp(R
->Str
,*ListBegin
) != 0)
1025 if (regexec(&Pattern
,R
->Str
,0,0,0) != 0)
1030 if (R
->Hit
== false)
1040 _error
->Warning(_("Selection %s not found"),*ListBegin
);
1046 // ioprintf - C format string outputter to C++ iostreams /*{{{*/
1047 // ---------------------------------------------------------------------
1048 /* This is used to make the internationalization strings easier to translate
1049 and to allow reordering of parameters */
1050 void ioprintf(ostream
&out
,const char *format
,...)
1053 va_start(args
,format
);
1055 // sprintf the description
1057 vsnprintf(S
,sizeof(S
),format
,args
);
1061 // strprintf - C format string outputter to C++ strings /*{{{*/
1062 // ---------------------------------------------------------------------
1063 /* This is used to make the internationalization strings easier to translate
1064 and to allow reordering of parameters */
1065 void strprintf(string
&out
,const char *format
,...)
1068 va_start(args
,format
);
1070 // sprintf the description
1072 vsnprintf(S
,sizeof(S
),format
,args
);
1076 // safe_snprintf - Safer snprintf /*{{{*/
1077 // ---------------------------------------------------------------------
1078 /* This is a snprintf that will never (ever) go past 'End' and returns a
1079 pointer to the end of the new string. The returned string is always null
1080 terminated unless Buffer == end. This is a better alterantive to using
1081 consecutive snprintfs. */
1082 char *safe_snprintf(char *Buffer
,char *End
,const char *Format
,...)
1087 va_start(args
,Format
);
1092 Did
= vsnprintf(Buffer
,End
- Buffer
,Format
,args
);
1093 if (Did
< 0 || Buffer
+ Did
> End
)
1095 return Buffer
+ Did
;
1099 // tolower_ascii - tolower() function that ignores the locale /*{{{*/
1100 // ---------------------------------------------------------------------
1102 int tolower_ascii(int c
)
1104 if (c
>= 'A' and c
<= 'Z')
1110 // CheckDomainList - See if Host is in a , seperate list /*{{{*/
1111 // ---------------------------------------------------------------------
1112 /* The domain list is a comma seperate list of domains that are suffix
1113 matched against the argument */
1114 bool CheckDomainList(const string
&Host
,const string
&List
)
1116 string::const_iterator Start
= List
.begin();
1117 for (string::const_iterator Cur
= List
.begin(); Cur
<= List
.end(); Cur
++)
1119 if (Cur
< List
.end() && *Cur
!= ',')
1122 // Match the end of the string..
1123 if ((Host
.size() >= (unsigned)(Cur
- Start
)) &&
1125 stringcasecmp(Host
.end() - (Cur
- Start
),Host
.end(),Start
,Cur
) == 0)
1134 // URI::CopyFrom - Copy from an object /*{{{*/
1135 // ---------------------------------------------------------------------
1136 /* This parses the URI into all of its components */
1137 void URI::CopyFrom(const string
&U
)
1139 string::const_iterator I
= U
.begin();
1141 // Locate the first colon, this separates the scheme
1142 for (; I
< U
.end() && *I
!= ':' ; I
++);
1143 string::const_iterator FirstColon
= I
;
1145 /* Determine if this is a host type URI with a leading double //
1146 and then search for the first single / */
1147 string::const_iterator SingleSlash
= I
;
1148 if (I
+ 3 < U
.end() && I
[1] == '/' && I
[2] == '/')
1151 /* Find the / indicating the end of the hostname, ignoring /'s in the
1153 bool InBracket
= false;
1154 for (; SingleSlash
< U
.end() && (*SingleSlash
!= '/' || InBracket
== true); SingleSlash
++)
1156 if (*SingleSlash
== '[')
1158 if (InBracket
== true && *SingleSlash
== ']')
1162 if (SingleSlash
> U
.end())
1163 SingleSlash
= U
.end();
1165 // We can now write the access and path specifiers
1166 Access
.assign(U
.begin(),FirstColon
);
1167 if (SingleSlash
!= U
.end())
1168 Path
.assign(SingleSlash
,U
.end());
1169 if (Path
.empty() == true)
1172 // Now we attempt to locate a user:pass@host fragment
1173 if (FirstColon
+ 2 <= U
.end() && FirstColon
[1] == '/' && FirstColon
[2] == '/')
1177 if (FirstColon
>= U
.end())
1180 if (FirstColon
> SingleSlash
)
1181 FirstColon
= SingleSlash
;
1183 // Find the colon...
1185 if (I
> SingleSlash
)
1187 for (; I
< SingleSlash
&& *I
!= ':'; I
++);
1188 string::const_iterator SecondColon
= I
;
1190 // Search for the @ after the colon
1191 for (; I
< SingleSlash
&& *I
!= '@'; I
++);
1192 string::const_iterator At
= I
;
1194 // Now write the host and user/pass
1195 if (At
== SingleSlash
)
1197 if (FirstColon
< SingleSlash
)
1198 Host
.assign(FirstColon
,SingleSlash
);
1202 Host
.assign(At
+1,SingleSlash
);
1203 User
.assign(FirstColon
,SecondColon
);
1204 if (SecondColon
< At
)
1205 Password
.assign(SecondColon
+1,At
);
1208 // Now we parse the RFC 2732 [] hostnames.
1209 unsigned long PortEnd
= 0;
1211 for (unsigned I
= 0; I
!= Host
.length();)
1220 if (InBracket
== true && Host
[I
] == ']')
1231 if (InBracket
== true)
1237 // Now we parse off a port number from the hostname
1239 string::size_type Pos
= Host
.rfind(':');
1240 if (Pos
== string::npos
|| Pos
< PortEnd
)
1243 Port
= atoi(string(Host
,Pos
+1).c_str());
1244 Host
.assign(Host
,0,Pos
);
1247 // URI::operator string - Convert the URI to a string /*{{{*/
1248 // ---------------------------------------------------------------------
1250 URI::operator string()
1254 if (Access
.empty() == false)
1257 if (Host
.empty() == false)
1259 if (Access
.empty() == false)
1262 if (User
.empty() == false)
1265 if (Password
.empty() == false)
1266 Res
+= ":" + Password
;
1270 // Add RFC 2732 escaping characters
1271 if (Access
.empty() == false &&
1272 (Host
.find('/') != string::npos
|| Host
.find(':') != string::npos
))
1273 Res
+= '[' + Host
+ ']';
1280 sprintf(S
,":%u",Port
);
1285 if (Path
.empty() == false)
1296 // URI::SiteOnly - Return the schema and site for the URI /*{{{*/
1297 // ---------------------------------------------------------------------
1299 string
URI::SiteOnly(const string
&URI
)