Start on acquire stuff
[ntk/apt.git] / apt-pkg / contrib / strutl.cc
CommitLineData
6c139d6e
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
3b5421b4 3// $Id: strutl.cc,v 1.5 1998/10/20 02:39:30 jgg Exp $
6c139d6e
AL
4/* ######################################################################
5
6 String Util - Some usefull string functions.
7
8 strstrip - Remove whitespace from the front and end of a line.
9
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>
12
13 ##################################################################### */
14 /*}}}*/
15// Includes /*{{{*/
16#include <strutl.h>
17#include <ctype.h>
18#include <string.h>
19#include <stdio.h>
20 /*}}}*/
21
22// strstrip - Remove white space from the front and back of a string /*{{{*/
23// ---------------------------------------------------------------------
24/* This is handy to use when parsing a file. It also removes \n's left
25 over from fgets and company */
26char *_strstrip(char *String)
27{
28 for (;*String != 0 && (*String == ' ' || *String == '\t'); String++);
29
30 if (*String == 0)
31 return String;
32
33 char *End = String + strlen(String) - 1;
34 for (;End != String - 1 && (*End == ' ' || *End == '\t' || *End == '\n' ||
35 *End == '\r'); End--);
36 End++;
37 *End = 0;
38 return String;
39};
40 /*}}}*/
41// strtabexpand - Converts tabs into 8 spaces /*{{{*/
42// ---------------------------------------------------------------------
43/* */
44char *_strtabexpand(char *String,size_t Len)
45{
46 for (char *I = String; I != I + Len && *I != 0; I++)
47 {
48 if (*I != '\t')
49 continue;
50 if (I + 8 > String + Len)
51 {
52 *I = 0;
53 return String;
54 }
55
56 /* Assume the start of the string is 0 and find the next 8 char
57 division */
58 int Len;
59 if (String == I)
60 Len = 1;
61 else
62 Len = 8 - ((String - I) % 8);
63 Len -= 2;
64 if (Len <= 0)
65 {
66 *I = ' ';
67 continue;
68 }
69
70 memmove(I + Len,I + 1,strlen(I) + 1);
71 for (char *J = I; J + Len != I; *I = ' ', I++);
72 }
73 return String;
74}
75 /*}}}*/
76// ParseQuoteWord - Parse a single word out of a string /*{{{*/
77// ---------------------------------------------------------------------
78/* This grabs a single word, converts any % escaped characters to their
79 proper values and advances the pointer. Double quotes are understood
08e8f724 80 and striped out as well. This is for URI/URL parsing. */
6c139d6e
AL
81bool ParseQuoteWord(const char *&String,string &Res)
82{
83 // Skip leading whitespace
84 const char *C = String;
85 for (;*C != 0 && *C == ' '; C++);
86 if (*C == 0)
87 return false;
88
89 // Jump to the next word
90 for (;*C != 0 && *C != ' '; C++)
91 {
92 if (*C == '"')
93 {
94 for (C++;*C != 0 && *C != '"'; C++);
95 if (*C == 0)
96 return false;
97 }
98 }
99
100 // Now de-quote characters
101 char Buffer[1024];
102 char Tmp[3];
103 const char *Start = String;
104 char *I;
105 for (I = Buffer; I < Buffer + sizeof(Buffer) && Start != C; I++)
106 {
107 if (*Start == '%' && Start + 2 < C)
108 {
109 Tmp[0] = Start[1];
110 Tmp[1] = Start[2];
111 Tmp[3] = 0;
112 *I = (char)strtol(Tmp,0,16);
113 Start += 3;
114 continue;
115 }
116 if (*Start != '"')
117 *I = *Start;
118 else
119 I--;
120 Start++;
121 }
122 *I = 0;
123 Res = Buffer;
124
125 // Skip ending white space
126 for (;*C != 0 && *C == ' '; C++);
127 String = C;
128 return true;
129}
130 /*}}}*/
08e8f724
AL
131// ParseCWord - Parses a string like a C "" expression /*{{{*/
132// ---------------------------------------------------------------------
133/* This expects a series of space seperated strings enclosed in ""'s.
134 It concatenates the ""'s into a single string. */
135bool ParseCWord(const char *String,string &Res)
136{
137 // Skip leading whitespace
138 const char *C = String;
139 for (;*C != 0 && *C == ' '; C++);
140 if (*C == 0)
141 return false;
142
143 char Buffer[1024];
144 char *Buf = Buffer;
145 if (strlen(String) >= sizeof(Buffer))
146 return false;
147
148 for (; *C != 0; C++)
149 {
150 if (*C == '"')
151 {
152 for (C++; *C != 0 && *C != '"'; C++)
153 *Buf++ = *C;
154
155 if (*C == 0)
156 return false;
157
158 continue;
159 }
160
161 if (C != String && isspace(*C) != 0 && isspace(C[-1]) != 0)
162 continue;
163 if (isspace(*C) == 0)
164 return false;
165 *Buf++ = ' ';
166 }
167 *Buf = 0;
168 Res = Buffer;
169 return true;
170}
171 /*}}}*/
6c139d6e
AL
172// QuoteString - Convert a string into quoted from /*{{{*/
173// ---------------------------------------------------------------------
174/* */
175string QuoteString(string Str,const char *Bad)
176{
177 string Res;
178 for (string::iterator I = Str.begin(); I != Str.end(); I++)
179 {
180 if (strchr(Bad,*I) != 0 || isprint(*I) == 0 ||
181 *I <= 0x20 || *I >= 0x7F)
182 {
183 char Buf[10];
184 sprintf(Buf,"%%%02x",(int)*I);
185 Res += Buf;
186 }
187 else
188 Res += *I;
189 }
190 return Res;
191}
192 /*}}}*/
193// SizeToStr - Convert a long into a human readable size /*{{{*/
194// ---------------------------------------------------------------------
195/* A max of 4 digits are shown before conversion to the next highest unit. The
196 max length of the string will be 5 chars unless the size is > 10
197 YottaBytes (E24) */
198string SizeToStr(double Size)
199{
200 char S[300];
201 double ASize;
202 if (Size >= 0)
203 ASize = Size;
204 else
205 ASize = -1*Size;
206
207 /* bytes, KiloBytes, MegaBytes, GigaBytes, TeraBytes, PetaBytes,
208 ExaBytes, ZettaBytes, YottaBytes */
209 char Ext[] = {'b','k','M','G','T','P','E','Z','Y'};
210 int I = 0;
211 while (I <= 8)
212 {
213 if (ASize < 100 && I != 0)
214 {
215 sprintf(S,"%.1f%c",ASize,Ext[I]);
216 break;
217 }
218
219 if (ASize < 10000)
220 {
221 sprintf(S,"%.0f%c",ASize,Ext[I]);
222 break;
223 }
224 ASize /= 1000.0;
225 I++;
226 }
227
228 return S;
229}
230 /*}}}*/
231// TimeToStr - Convert the time into a string /*{{{*/
232// ---------------------------------------------------------------------
233/* Converts a number of seconds to a hms format */
234string TimeToStr(unsigned long Sec)
235{
236 char S[300];
237
238 while (1)
239 {
240 if (Sec > 60*60*24)
241 {
242 sprintf(S,"%lid %lih%lim%lis",Sec/60/60/24,(Sec/60/60) % 24,(Sec/60) % 60,Sec % 60);
243 break;
244 }
245
246 if (Sec > 60*60)
247 {
248 sprintf(S,"%lih%lim%lis",Sec/60/60,(Sec/60) % 60,Sec % 60);
249 break;
250 }
251
252 if (Sec > 60)
253 {
254 sprintf(S,"%lim%lis",Sec/60,Sec % 60);
255 break;
256 }
257
258 sprintf(S,"%lis",Sec);
259 break;
260 }
261
262 return S;
263}
264 /*}}}*/
265// SubstVar - Substitute a string for another string /*{{{*/
266// ---------------------------------------------------------------------
267/* This replaces all occurances of Subst with Contents in Str. */
268string SubstVar(string Str,string Subst,string Contents)
269{
8efa2a3b 270 string::size_type Pos = 0;
6c139d6e
AL
271 string::size_type OldPos = 0;
272 string Temp;
273
274 while (OldPos < Str.length() &&
275 (Pos = Str.find(Subst,OldPos)) != string::npos)
276 {
277 Temp += string(Str,OldPos,Pos) + Contents;
278 OldPos = Pos + Subst.length();
279 }
280
281 if (OldPos == 0)
282 return Str;
283
284 return Temp + string(Str,OldPos);
285}
286 /*}}}*/
ad00ae81
AL
287// URItoFileName - Convert the uri into a unique file name /*{{{*/
288// ---------------------------------------------------------------------
289/* This converts a URI into a safe filename. It quotes all unsafe characters
290 and converts / to _ and removes the scheme identifier. The resulting
291 file name should be unique and never occur again for a different file */
292string URItoFileName(string URI)
293{
294 string::const_iterator I = URI.begin() + URI.find(':') + 1;
295 for (; I < URI.end() && *I == '/'; I++);
296
297 // "\x00-\x20{}|\\\\^\\[\\]<>\"\x7F-\xFF";
298 URI = QuoteString(string(I,URI.end() - I),"\\|{}[]<>\"^~_=!@#$%^&*");
299 string::iterator J = URI.begin();
300 for (; J != URI.end(); J++)
301 if (*J == '/')
302 *J = '_';
303 return URI;
304}
305 /*}}}*/
3b5421b4
AL
306// URIAccess - Return the access method for the URI /*{{{*/
307// ---------------------------------------------------------------------
308/* */
309string URIAccess(string URI)
310{
311 string::size_type Pos = URI.find(':');
312 if (Pos == string::npos)
313 return string();
314 return string(URI,0,Pos);
315}
316 /*}}}*/
6c139d6e
AL
317// Base64Encode - Base64 Encoding routine for short strings /*{{{*/
318// ---------------------------------------------------------------------
319/* This routine performs a base64 transformation on a string. It was ripped
320 from wget and then patched and bug fixed.
321
322 This spec can be found in rfc2045 */
323string Base64Encode(string S)
324{
325 // Conversion table.
326 static char tbl[64] = {'A','B','C','D','E','F','G','H',
327 'I','J','K','L','M','N','O','P',
328 'Q','R','S','T','U','V','W','X',
329 'Y','Z','a','b','c','d','e','f',
330 'g','h','i','j','k','l','m','n',
331 'o','p','q','r','s','t','u','v',
332 'w','x','y','z','0','1','2','3',
333 '4','5','6','7','8','9','+','/'};
334
335 // Pre-allocate some space
336 string Final;
337 Final.reserve((4*S.length() + 2)/3 + 2);
338
339 /* Transform the 3x8 bits to 4x6 bits, as required by
340 base64. */
341 for (string::const_iterator I = S.begin(); I < S.end(); I += 3)
342 {
343 char Bits[3] = {0,0,0};
344 Bits[0] = I[0];
345 if (I + 1 < S.end())
346 Bits[1] = I[1];
347 if (I + 2 < S.end())
348 Bits[2] = I[2];
349
350 Final += tbl[Bits[0] >> 2];
351 Final += tbl[((Bits[0] & 3) << 4) + (Bits[1] >> 4)];
352
353 if (I + 1 >= S.end())
354 break;
355
356 Final += tbl[((Bits[1] & 0xf) << 2) + (Bits[2] >> 6)];
357
358 if (I + 2 >= S.end())
359 break;
360
361 Final += tbl[Bits[2] & 0x3f];
362 }
363
364 /* Apply the padding elements, this tells how many bytes the remote
365 end should discard */
366 if (S.length() % 3 == 2)
367 Final += '=';
368 if (S.length() % 3 == 1)
369 Final += "==";
370
371 return Final;
372}
373 /*}}}*/
374// stringcmp - Arbitary string compare /*{{{*/
375// ---------------------------------------------------------------------
376/* This safely compares two non-null terminated strings of arbitary
377 length */
378int stringcmp(const char *A,const char *AEnd,const char *B,const char *BEnd)
379{
380 for (; A != AEnd && B != BEnd; A++, B++)
381 if (*A != *B)
382 break;
383
384 if (A == AEnd && B == BEnd)
385 return 0;
386 if (A == AEnd)
387 return 1;
388 if (B == BEnd)
389 return -1;
390 if (*A < *B)
391 return -1;
392 return 1;
393}
394 /*}}}*/
395// stringcasecmp - Arbitary case insensitive string compare /*{{{*/
396// ---------------------------------------------------------------------
397/* */
398int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd)
399{
400 for (; A != AEnd && B != BEnd; A++, B++)
401 if (toupper(*A) != toupper(*B))
402 break;
3b5421b4 403
6c139d6e
AL
404 if (A == AEnd && B == BEnd)
405 return 0;
406 if (A == AEnd)
407 return 1;
408 if (B == BEnd)
409 return -1;
410 if (toupper(*A) < toupper(*B))
411 return -1;
412 return 1;
413}
414 /*}}}*/
3b5421b4
AL
415// LookupTag - Lookup the value of a tag in a taged string /*{{{*/
416// ---------------------------------------------------------------------
417/* The format is like those used in package files and the method
418 communication system */
419string LookupTag(string Message,const char *Tag,const char *Default)
420{
421 // Look for a matching tag.
422 int Length = strlen(Tag);
423 for (string::iterator I = Message.begin(); I + Length < Message.end(); I++)
424 {
425 // Found the tag
426 if (I[Length] == ':' && stringcasecmp(I,I+Length,Tag) == 0)
427 {
428 // Find the end of line and strip the leading/trailing spaces
429 string::iterator J;
430 I += Length + 1;
431 for (; isspace(*I) != 0 && I < Message.end(); I++);
432 for (J = I; *J != '\n' && J < Message.end(); J++);
433 for (; J > I && isspace(J[-1]) != 0; J--);
434
435 return string(I,J-I);
436 }
437
438 for (; *I != '\n' && I < Message.end(); I++);
439 }
440
441 // Failed to find a match
442 if (Default == 0)
443 return string();
444 return Default;
445}
446 /*}}}*/
447// StringToBool - Converts a string into a boolean /*{{{*/
448// ---------------------------------------------------------------------
449/* This inspects the string to see if it is true or if it is false and
450 then returns the result. Several varients on true/false are checked. */
451int StringToBool(string Text,int Default = -1)
452{
453 char *End;
454 int Res = strtol(Text.c_str(),&End,0);
455 if (End != Text.c_str() && Res >= 0 && Res <= 1)
456 return Res;
457
458 // Check for positives
459 if (strcasecmp(Text.c_str(),"no") == 0 ||
460 strcasecmp(Text.c_str(),"false") == 0 ||
461 strcasecmp(Text.c_str(),"without") == 0 ||
462 strcasecmp(Text.c_str(),"disable") == 0)
463 return 0;
464
465 // Check for negatives
466 if (strcasecmp(Text.c_str(),"yes") == 0 ||
467 strcasecmp(Text.c_str(),"true") == 0 ||
468 strcasecmp(Text.c_str(),"with") == 0 ||
469 strcasecmp(Text.c_str(),"enable") == 0)
470 return 1;
471
472 return Default;
473}
474 /*}}}*/