]>
git.saurik.com Git - apt.git/blob - apt-pkg/contrib/strutl.cc
04a3c7bb7c3deab5414c5642af75cbe744c6deb9
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: strutl.cc,v 1.6 1998/10/22 04:56:48 jgg Exp $
4 /* ######################################################################
6 String Util - Some usefull string functions.
8 strstrip - Remove whitespace from the front and end of a line.
10 This source is placed in the Public Domain, do with it what you will
11 It was originally written by Jason Gunthorpe <jgg@gpu.srv.ualberta.ca>
13 ##################################################################### */
17 #include <apt-pkg/fileutl.h>
25 // strstrip - Remove white space from the front and back of a string /*{{{*/
26 // ---------------------------------------------------------------------
27 /* This is handy to use when parsing a file. It also removes \n's left
28 over from fgets and company */
29 char *_strstrip(char *String
)
31 for (;*String
!= 0 && (*String
== ' ' || *String
== '\t'); String
++);
36 char *End
= String
+ strlen(String
) - 1;
37 for (;End
!= String
- 1 && (*End
== ' ' || *End
== '\t' || *End
== '\n' ||
38 *End
== '\r'); End
--);
44 // strtabexpand - Converts tabs into 8 spaces /*{{{*/
45 // ---------------------------------------------------------------------
47 char *_strtabexpand(char *String
,size_t Len
)
49 for (char *I
= String
; I
!= I
+ Len
&& *I
!= 0; I
++)
53 if (I
+ 8 > String
+ Len
)
59 /* Assume the start of the string is 0 and find the next 8 char
65 Len
= 8 - ((String
- I
) % 8);
73 memmove(I
+ Len
,I
+ 1,strlen(I
) + 1);
74 for (char *J
= I
; J
+ Len
!= I
; *I
= ' ', I
++);
79 // ParseQuoteWord - Parse a single word out of a string /*{{{*/
80 // ---------------------------------------------------------------------
81 /* This grabs a single word, converts any % escaped characters to their
82 proper values and advances the pointer. Double quotes are understood
83 and striped out as well. This is for URI/URL parsing. */
84 bool ParseQuoteWord(const char *&String
,string
&Res
)
86 // Skip leading whitespace
87 const char *C
= String
;
88 for (;*C
!= 0 && *C
== ' '; C
++);
92 // Jump to the next word
93 for (;*C
!= 0 && *C
!= ' '; C
++)
97 for (C
++;*C
!= 0 && *C
!= '"'; C
++);
103 // Now de-quote characters
106 const char *Start
= String
;
108 for (I
= Buffer
; I
< Buffer
+ sizeof(Buffer
) && Start
!= C
; I
++)
110 if (*Start
== '%' && Start
+ 2 < C
)
115 *I
= (char)strtol(Tmp
,0,16);
128 // Skip ending white space
129 for (;*C
!= 0 && *C
== ' '; C
++);
134 // ParseCWord - Parses a string like a C "" expression /*{{{*/
135 // ---------------------------------------------------------------------
136 /* This expects a series of space seperated strings enclosed in ""'s.
137 It concatenates the ""'s into a single string. */
138 bool ParseCWord(const char *String
,string
&Res
)
140 // Skip leading whitespace
141 const char *C
= String
;
142 for (;*C
!= 0 && *C
== ' '; C
++);
148 if (strlen(String
) >= sizeof(Buffer
))
155 for (C
++; *C
!= 0 && *C
!= '"'; C
++)
164 if (C
!= String
&& isspace(*C
) != 0 && isspace(C
[-1]) != 0)
166 if (isspace(*C
) == 0)
175 // QuoteString - Convert a string into quoted from /*{{{*/
176 // ---------------------------------------------------------------------
178 string
QuoteString(string Str
,const char *Bad
)
181 for (string::iterator I
= Str
.begin(); I
!= Str
.end(); I
++)
183 if (strchr(Bad
,*I
) != 0 || isprint(*I
) == 0 ||
184 *I
<= 0x20 || *I
>= 0x7F)
187 sprintf(Buf
,"%%%02x",(int)*I
);
196 // SizeToStr - Convert a long into a human readable size /*{{{*/
197 // ---------------------------------------------------------------------
198 /* A max of 4 digits are shown before conversion to the next highest unit. The
199 max length of the string will be 5 chars unless the size is > 10
201 string
SizeToStr(double Size
)
210 /* bytes, KiloBytes, MegaBytes, GigaBytes, TeraBytes, PetaBytes,
211 ExaBytes, ZettaBytes, YottaBytes */
212 char Ext
[] = {'b','k','M','G','T','P','E','Z','Y'};
216 if (ASize
< 100 && I
!= 0)
218 sprintf(S
,"%.1f%c",ASize
,Ext
[I
]);
224 sprintf(S
,"%.0f%c",ASize
,Ext
[I
]);
234 // TimeToStr - Convert the time into a string /*{{{*/
235 // ---------------------------------------------------------------------
236 /* Converts a number of seconds to a hms format */
237 string
TimeToStr(unsigned long Sec
)
245 sprintf(S
,"%lid %lih%lim%lis",Sec
/60/60/24,(Sec
/60/60) % 24,(Sec
/60) % 60,Sec
% 60);
251 sprintf(S
,"%lih%lim%lis",Sec
/60/60,(Sec
/60) % 60,Sec
% 60);
257 sprintf(S
,"%lim%lis",Sec
/60,Sec
% 60);
261 sprintf(S
,"%lis",Sec
);
268 // SubstVar - Substitute a string for another string /*{{{*/
269 // ---------------------------------------------------------------------
270 /* This replaces all occurances of Subst with Contents in Str. */
271 string
SubstVar(string Str
,string Subst
,string Contents
)
273 string::size_type Pos
= 0;
274 string::size_type OldPos
= 0;
277 while (OldPos
< Str
.length() &&
278 (Pos
= Str
.find(Subst
,OldPos
)) != string::npos
)
280 Temp
+= string(Str
,OldPos
,Pos
) + Contents
;
281 OldPos
= Pos
+ Subst
.length();
287 return Temp
+ string(Str
,OldPos
);
290 // URItoFileName - Convert the uri into a unique file name /*{{{*/
291 // ---------------------------------------------------------------------
292 /* This converts a URI into a safe filename. It quotes all unsafe characters
293 and converts / to _ and removes the scheme identifier. The resulting
294 file name should be unique and never occur again for a different file */
295 string
URItoFileName(string URI
)
297 string::const_iterator I
= URI
.begin() + URI
.find(':') + 1;
298 for (; I
< URI
.end() && *I
== '/'; I
++);
300 // "\x00-\x20{}|\\\\^\\[\\]<>\"\x7F-\xFF";
301 URI
= QuoteString(string(I
,URI
.end() - I
),"\\|{}[]<>\"^~_=!@#$%^&*");
302 string::iterator J
= URI
.begin();
303 for (; J
!= URI
.end(); J
++)
309 // URIAccess - Return the access method for the URI /*{{{*/
310 // ---------------------------------------------------------------------
312 string
URIAccess(string URI
)
314 string::size_type Pos
= URI
.find(':');
315 if (Pos
== string::npos
)
317 return string(URI
,0,Pos
);
320 // Base64Encode - Base64 Encoding routine for short strings /*{{{*/
321 // ---------------------------------------------------------------------
322 /* This routine performs a base64 transformation on a string. It was ripped
323 from wget and then patched and bug fixed.
325 This spec can be found in rfc2045 */
326 string
Base64Encode(string S
)
329 static char tbl
[64] = {'A','B','C','D','E','F','G','H',
330 'I','J','K','L','M','N','O','P',
331 'Q','R','S','T','U','V','W','X',
332 'Y','Z','a','b','c','d','e','f',
333 'g','h','i','j','k','l','m','n',
334 'o','p','q','r','s','t','u','v',
335 'w','x','y','z','0','1','2','3',
336 '4','5','6','7','8','9','+','/'};
338 // Pre-allocate some space
340 Final
.reserve((4*S
.length() + 2)/3 + 2);
342 /* Transform the 3x8 bits to 4x6 bits, as required by
344 for (string::const_iterator I
= S
.begin(); I
< S
.end(); I
+= 3)
346 char Bits
[3] = {0,0,0};
353 Final
+= tbl
[Bits
[0] >> 2];
354 Final
+= tbl
[((Bits
[0] & 3) << 4) + (Bits
[1] >> 4)];
356 if (I
+ 1 >= S
.end())
359 Final
+= tbl
[((Bits
[1] & 0xf) << 2) + (Bits
[2] >> 6)];
361 if (I
+ 2 >= S
.end())
364 Final
+= tbl
[Bits
[2] & 0x3f];
367 /* Apply the padding elements, this tells how many bytes the remote
368 end should discard */
369 if (S
.length() % 3 == 2)
371 if (S
.length() % 3 == 1)
377 // stringcmp - Arbitary string compare /*{{{*/
378 // ---------------------------------------------------------------------
379 /* This safely compares two non-null terminated strings of arbitary
381 int stringcmp(const char *A
,const char *AEnd
,const char *B
,const char *BEnd
)
383 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
387 if (A
== AEnd
&& B
== BEnd
)
398 // stringcasecmp - Arbitary case insensitive string compare /*{{{*/
399 // ---------------------------------------------------------------------
401 int stringcasecmp(const char *A
,const char *AEnd
,const char *B
,const char *BEnd
)
403 for (; A
!= AEnd
&& B
!= BEnd
; A
++, B
++)
404 if (toupper(*A
) != toupper(*B
))
407 if (A
== AEnd
&& B
== BEnd
)
413 if (toupper(*A
) < toupper(*B
))
418 // LookupTag - Lookup the value of a tag in a taged string /*{{{*/
419 // ---------------------------------------------------------------------
420 /* The format is like those used in package files and the method
421 communication system */
422 string
LookupTag(string Message
,const char *Tag
,const char *Default
)
424 // Look for a matching tag.
425 int Length
= strlen(Tag
);
426 for (string::iterator I
= Message
.begin(); I
+ Length
< Message
.end(); I
++)
429 if (I
[Length
] == ':' && stringcasecmp(I
,I
+Length
,Tag
) == 0)
431 // Find the end of line and strip the leading/trailing spaces
434 for (; isspace(*I
) != 0 && I
< Message
.end(); I
++);
435 for (J
= I
; *J
!= '\n' && J
< Message
.end(); J
++);
436 for (; J
> I
&& isspace(J
[-1]) != 0; J
--);
438 return string(I
,J
-I
);
441 for (; *I
!= '\n' && I
< Message
.end(); I
++);
444 // Failed to find a match
450 // StringToBool - Converts a string into a boolean /*{{{*/
451 // ---------------------------------------------------------------------
452 /* This inspects the string to see if it is true or if it is false and
453 then returns the result. Several varients on true/false are checked. */
454 int StringToBool(string Text
,int Default
= -1)
457 int Res
= strtol(Text
.c_str(),&End
,0);
458 if (End
!= Text
.c_str() && Res
>= 0 && Res
<= 1)
461 // Check for positives
462 if (strcasecmp(Text
.c_str(),"no") == 0 ||
463 strcasecmp(Text
.c_str(),"false") == 0 ||
464 strcasecmp(Text
.c_str(),"without") == 0 ||
465 strcasecmp(Text
.c_str(),"disable") == 0)
468 // Check for negatives
469 if (strcasecmp(Text
.c_str(),"yes") == 0 ||
470 strcasecmp(Text
.c_str(),"true") == 0 ||
471 strcasecmp(Text
.c_str(),"with") == 0 ||
472 strcasecmp(Text
.c_str(),"enable") == 0)
478 // TimeRFC1123 - Convert a time_t into RFC1123 format /*{{{*/
479 // ---------------------------------------------------------------------
480 /* This converts a time_t into a string time representation that is
481 year 2000 complient and timezone neutral */
482 string
TimeRFC1123(time_t Date
)
484 struct tm Conv
= *gmtime(&Date
);
487 const char *Day
[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
488 const char *Month
[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul",
489 "Aug","Sep","Oct","Nov","Dec"};
491 sprintf(Buf
,"%s, %02i %s %i %02i:%02i:%02i GMT",Day
[Conv
.tm_wday
],
492 Conv
.tm_mday
,Month
[Conv
.tm_mon
],Conv
.tm_year
+1900,Conv
.tm_hour
,
493 Conv
.tm_min
,Conv
.tm_sec
);
497 // ReadMessages - Read messages from the FD /*{{{*/
498 // ---------------------------------------------------------------------
499 /* This pulls full messages from the input FD into the message buffer.
500 It assumes that messages will not pause during transit so no
501 fancy buffering is used. */
502 bool ReadMessages(int Fd
, vector
<string
> &List
)
509 int Res
= read(Fd
,End
,sizeof(Buffer
) - (End
-Buffer
));
511 // Process is dead, this is kind of bad..
521 // Look for the end of the message
522 for (char *I
= Buffer
; I
< End
; I
++)
524 if (I
[0] != '\n' || I
[1] != '\n')
527 // Pull the message out
528 string
Message(Buffer
,0,I
-Buffer
);
531 for (; I
< End
&& *I
== '\n'; I
++);
533 memmove(Buffer
,I
,End
-Buffer
);
536 List
.push_back(Message
);
541 if (WaitFd(Fd
) == false)