Sync
[ntk/apt.git] / apt-pkg / contrib / strutl.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: strutl.cc,v 1.1 1998/07/07 04:17:16 jgg Exp $
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 */
26 char *_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 /* */
44 char *_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
80 and striped out as well. */
81 bool 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 /*}}}*/
131 // QuoteString - Convert a string into quoted from /*{{{*/
132 // ---------------------------------------------------------------------
133 /* */
134 string QuoteString(string Str,const char *Bad)
135 {
136 string Res;
137 for (string::iterator I = Str.begin(); I != Str.end(); I++)
138 {
139 if (strchr(Bad,*I) != 0 || isprint(*I) == 0 ||
140 *I <= 0x20 || *I >= 0x7F)
141 {
142 char Buf[10];
143 sprintf(Buf,"%%%02x",(int)*I);
144 Res += Buf;
145 }
146 else
147 Res += *I;
148 }
149 return Res;
150 }
151 /*}}}*/
152 // SizeToStr - Convert a long into a human readable size /*{{{*/
153 // ---------------------------------------------------------------------
154 /* A max of 4 digits are shown before conversion to the next highest unit. The
155 max length of the string will be 5 chars unless the size is > 10
156 YottaBytes (E24) */
157 string SizeToStr(double Size)
158 {
159 char S[300];
160 double ASize;
161 if (Size >= 0)
162 ASize = Size;
163 else
164 ASize = -1*Size;
165
166 /* bytes, KiloBytes, MegaBytes, GigaBytes, TeraBytes, PetaBytes,
167 ExaBytes, ZettaBytes, YottaBytes */
168 char Ext[] = {'b','k','M','G','T','P','E','Z','Y'};
169 int I = 0;
170 while (I <= 8)
171 {
172 if (ASize < 100 && I != 0)
173 {
174 sprintf(S,"%.1f%c",ASize,Ext[I]);
175 break;
176 }
177
178 if (ASize < 10000)
179 {
180 sprintf(S,"%.0f%c",ASize,Ext[I]);
181 break;
182 }
183 ASize /= 1000.0;
184 I++;
185 }
186
187 return S;
188 }
189 /*}}}*/
190 // TimeToStr - Convert the time into a string /*{{{*/
191 // ---------------------------------------------------------------------
192 /* Converts a number of seconds to a hms format */
193 string TimeToStr(unsigned long Sec)
194 {
195 char S[300];
196
197 while (1)
198 {
199 if (Sec > 60*60*24)
200 {
201 sprintf(S,"%lid %lih%lim%lis",Sec/60/60/24,(Sec/60/60) % 24,(Sec/60) % 60,Sec % 60);
202 break;
203 }
204
205 if (Sec > 60*60)
206 {
207 sprintf(S,"%lih%lim%lis",Sec/60/60,(Sec/60) % 60,Sec % 60);
208 break;
209 }
210
211 if (Sec > 60)
212 {
213 sprintf(S,"%lim%lis",Sec/60,Sec % 60);
214 break;
215 }
216
217 sprintf(S,"%lis",Sec);
218 break;
219 }
220
221 return S;
222 }
223 /*}}}*/
224 // SubstVar - Substitute a string for another string /*{{{*/
225 // ---------------------------------------------------------------------
226 /* This replaces all occurances of Subst with Contents in Str. */
227 string SubstVar(string Str,string Subst,string Contents)
228 {
229 string::size_type Pos;
230 string::size_type OldPos = 0;
231 string Temp;
232
233 while (OldPos < Str.length() &&
234 (Pos = Str.find(Subst,OldPos)) != string::npos)
235 {
236 Temp += string(Str,OldPos,Pos) + Contents;
237 OldPos = Pos + Subst.length();
238 }
239
240 if (OldPos == 0)
241 return Str;
242
243 return Temp + string(Str,OldPos);
244 }
245 /*}}}*/
246 // Base64Encode - Base64 Encoding routine for short strings /*{{{*/
247 // ---------------------------------------------------------------------
248 /* This routine performs a base64 transformation on a string. It was ripped
249 from wget and then patched and bug fixed.
250
251 This spec can be found in rfc2045 */
252 string Base64Encode(string S)
253 {
254 // Conversion table.
255 static char tbl[64] = {'A','B','C','D','E','F','G','H',
256 'I','J','K','L','M','N','O','P',
257 'Q','R','S','T','U','V','W','X',
258 'Y','Z','a','b','c','d','e','f',
259 'g','h','i','j','k','l','m','n',
260 'o','p','q','r','s','t','u','v',
261 'w','x','y','z','0','1','2','3',
262 '4','5','6','7','8','9','+','/'};
263
264 // Pre-allocate some space
265 string Final;
266 Final.reserve((4*S.length() + 2)/3 + 2);
267
268 /* Transform the 3x8 bits to 4x6 bits, as required by
269 base64. */
270 for (string::const_iterator I = S.begin(); I < S.end(); I += 3)
271 {
272 char Bits[3] = {0,0,0};
273 Bits[0] = I[0];
274 if (I + 1 < S.end())
275 Bits[1] = I[1];
276 if (I + 2 < S.end())
277 Bits[2] = I[2];
278
279 Final += tbl[Bits[0] >> 2];
280 Final += tbl[((Bits[0] & 3) << 4) + (Bits[1] >> 4)];
281
282 if (I + 1 >= S.end())
283 break;
284
285 Final += tbl[((Bits[1] & 0xf) << 2) + (Bits[2] >> 6)];
286
287 if (I + 2 >= S.end())
288 break;
289
290 Final += tbl[Bits[2] & 0x3f];
291 }
292
293 /* Apply the padding elements, this tells how many bytes the remote
294 end should discard */
295 if (S.length() % 3 == 2)
296 Final += '=';
297 if (S.length() % 3 == 1)
298 Final += "==";
299
300 return Final;
301 }
302 /*}}}*/
303 // stringcmp - Arbitary string compare /*{{{*/
304 // ---------------------------------------------------------------------
305 /* This safely compares two non-null terminated strings of arbitary
306 length */
307 int stringcmp(const char *A,const char *AEnd,const char *B,const char *BEnd)
308 {
309 for (; A != AEnd && B != BEnd; A++, B++)
310 if (*A != *B)
311 break;
312
313 if (A == AEnd && B == BEnd)
314 return 0;
315 if (A == AEnd)
316 return 1;
317 if (B == BEnd)
318 return -1;
319 if (*A < *B)
320 return -1;
321 return 1;
322 }
323 /*}}}*/
324 // stringcasecmp - Arbitary case insensitive string compare /*{{{*/
325 // ---------------------------------------------------------------------
326 /* */
327 int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd)
328 {
329 for (; A != AEnd && B != BEnd; A++, B++)
330 if (toupper(*A) != toupper(*B))
331 break;
332
333 if (A == AEnd && B == BEnd)
334 return 0;
335 if (A == AEnd)
336 return 1;
337 if (B == BEnd)
338 return -1;
339 if (toupper(*A) < toupper(*B))
340 return -1;
341 return 1;
342 }
343 /*}}}*/