]> git.saurik.com Git - apt.git/blame - apt-pkg/contrib/strutl.cc
C9x types
[apt.git] / apt-pkg / contrib / strutl.cc
CommitLineData
6c139d6e
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
54cf15cb 3// $Id: strutl.cc,v 1.30 1999/10/17 07:30:23 jgg Exp $
6c139d6e
AL
4/* ######################################################################
5
6 String Util - Some usefull string functions.
7
24231681
AL
8 These have been collected from here and there to do all sorts of usefull
9 things to strings. They are usefull in file parsers, URI handlers and
10 especially in APT methods.
6c139d6e
AL
11
12 This source is placed in the Public Domain, do with it what you will
24231681 13 It was originally written by Jason Gunthorpe <jgg@gpu.srv.ualberta.ca>
6c139d6e
AL
14
15 ##################################################################### */
16 /*}}}*/
17// Includes /*{{{*/
492f957a 18#ifdef __GNUG__
cdcc6d34 19#pragma implementation "apt-pkg/strutl.h"
492f957a
AL
20#endif
21
cdcc6d34 22#include <apt-pkg/strutl.h>
7049d16d 23#include <apt-pkg/fileutl.h>
0a8a80e5 24
6c139d6e
AL
25#include <ctype.h>
26#include <string.h>
27#include <stdio.h>
2b154e53 28#include <unistd.h>
b0db36b1 29#include <errno.h>
6c139d6e
AL
30 /*}}}*/
31
32// strstrip - Remove white space from the front and back of a string /*{{{*/
33// ---------------------------------------------------------------------
34/* This is handy to use when parsing a file. It also removes \n's left
35 over from fgets and company */
36char *_strstrip(char *String)
37{
38 for (;*String != 0 && (*String == ' ' || *String == '\t'); String++);
39
40 if (*String == 0)
41 return String;
42
43 char *End = String + strlen(String) - 1;
44 for (;End != String - 1 && (*End == ' ' || *End == '\t' || *End == '\n' ||
45 *End == '\r'); End--);
46 End++;
47 *End = 0;
48 return String;
49};
50 /*}}}*/
51// strtabexpand - Converts tabs into 8 spaces /*{{{*/
52// ---------------------------------------------------------------------
53/* */
54char *_strtabexpand(char *String,size_t Len)
55{
56 for (char *I = String; I != I + Len && *I != 0; I++)
57 {
58 if (*I != '\t')
59 continue;
60 if (I + 8 > String + Len)
61 {
62 *I = 0;
63 return String;
64 }
65
66 /* Assume the start of the string is 0 and find the next 8 char
67 division */
68 int Len;
69 if (String == I)
70 Len = 1;
71 else
72 Len = 8 - ((String - I) % 8);
73 Len -= 2;
74 if (Len <= 0)
75 {
76 *I = ' ';
77 continue;
78 }
79
80 memmove(I + Len,I + 1,strlen(I) + 1);
81 for (char *J = I; J + Len != I; *I = ' ', I++);
82 }
83 return String;
84}
85 /*}}}*/
86// ParseQuoteWord - Parse a single word out of a string /*{{{*/
87// ---------------------------------------------------------------------
88/* This grabs a single word, converts any % escaped characters to their
89 proper values and advances the pointer. Double quotes are understood
08e8f724 90 and striped out as well. This is for URI/URL parsing. */
6c139d6e
AL
91bool ParseQuoteWord(const char *&String,string &Res)
92{
93 // Skip leading whitespace
94 const char *C = String;
95 for (;*C != 0 && *C == ' '; C++);
96 if (*C == 0)
97 return false;
98
99 // Jump to the next word
36f610f1 100 for (;*C != 0 && isspace(*C) == 0; C++)
6c139d6e
AL
101 {
102 if (*C == '"')
103 {
104 for (C++;*C != 0 && *C != '"'; C++);
105 if (*C == 0)
106 return false;
107 }
108 }
109
110 // Now de-quote characters
111 char Buffer[1024];
112 char Tmp[3];
113 const char *Start = String;
114 char *I;
115 for (I = Buffer; I < Buffer + sizeof(Buffer) && Start != C; I++)
116 {
117 if (*Start == '%' && Start + 2 < C)
118 {
119 Tmp[0] = Start[1];
120 Tmp[1] = Start[2];
1bc849af 121 Tmp[2] = 0;
6c139d6e
AL
122 *I = (char)strtol(Tmp,0,16);
123 Start += 3;
124 continue;
125 }
126 if (*Start != '"')
127 *I = *Start;
128 else
129 I--;
130 Start++;
131 }
132 *I = 0;
133 Res = Buffer;
134
135 // Skip ending white space
36f610f1 136 for (;*C != 0 && isspace(*C) != 0; C++);
6c139d6e
AL
137 String = C;
138 return true;
139}
140 /*}}}*/
08e8f724
AL
141// ParseCWord - Parses a string like a C "" expression /*{{{*/
142// ---------------------------------------------------------------------
143/* This expects a series of space seperated strings enclosed in ""'s.
144 It concatenates the ""'s into a single string. */
145bool ParseCWord(const char *String,string &Res)
146{
147 // Skip leading whitespace
148 const char *C = String;
149 for (;*C != 0 && *C == ' '; C++);
150 if (*C == 0)
151 return false;
152
153 char Buffer[1024];
154 char *Buf = Buffer;
155 if (strlen(String) >= sizeof(Buffer))
156 return false;
157
158 for (; *C != 0; C++)
159 {
160 if (*C == '"')
161 {
162 for (C++; *C != 0 && *C != '"'; C++)
163 *Buf++ = *C;
164
165 if (*C == 0)
166 return false;
167
168 continue;
169 }
170
171 if (C != String && isspace(*C) != 0 && isspace(C[-1]) != 0)
172 continue;
173 if (isspace(*C) == 0)
174 return false;
175 *Buf++ = ' ';
176 }
177 *Buf = 0;
178 Res = Buffer;
179 return true;
180}
181 /*}}}*/
6d5dd02a 182// QuoteString - Convert a string into quoted from /*{{{*/
1bc849af 183// ---------------------------------------------------------------------
6d5dd02a
AL
184/* */
185string QuoteString(string Str,const char *Bad)
1bc849af
AL
186{
187 string Res;
188 for (string::iterator I = Str.begin(); I != Str.end(); I++)
189 {
6d5dd02a
AL
190 if (strchr(Bad,*I) != 0 || isprint(*I) == 0 ||
191 *I <= 0x20 || *I >= 0x7F)
1bc849af 192 {
6d5dd02a
AL
193 char Buf[10];
194 sprintf(Buf,"%%%02x",(int)*I);
195 Res += Buf;
1bc849af
AL
196 }
197 else
198 Res += *I;
199 }
200 return Res;
201}
202 /*}}}*/
6d5dd02a 203// DeQuoteString - Convert a string from quoted from /*{{{*/
6c139d6e 204// ---------------------------------------------------------------------
6d5dd02a
AL
205/* This undoes QuoteString */
206string DeQuoteString(string Str)
6c139d6e
AL
207{
208 string Res;
209 for (string::iterator I = Str.begin(); I != Str.end(); I++)
210 {
6d5dd02a 211 if (*I == '%' && I + 2 < Str.end())
6c139d6e 212 {
6d5dd02a
AL
213 char Tmp[3];
214 Tmp[0] = I[1];
215 Tmp[1] = I[2];
216 Tmp[2] = 0;
217 Res += (char)strtol(Tmp,0,16);
218 I += 2;
219 continue;
6c139d6e
AL
220 }
221 else
222 Res += *I;
223 }
6d5dd02a 224 return Res;
6c139d6e 225}
6d5dd02a
AL
226
227 /*}}}*/
6c139d6e
AL
228// SizeToStr - Convert a long into a human readable size /*{{{*/
229// ---------------------------------------------------------------------
24231681
AL
230/* A max of 4 digits are shown before conversion to the next highest unit.
231 The max length of the string will be 5 chars unless the size is > 10
6c139d6e
AL
232 YottaBytes (E24) */
233string SizeToStr(double Size)
234{
235 char S[300];
236 double ASize;
237 if (Size >= 0)
238 ASize = Size;
239 else
240 ASize = -1*Size;
241
242 /* bytes, KiloBytes, MegaBytes, GigaBytes, TeraBytes, PetaBytes,
243 ExaBytes, ZettaBytes, YottaBytes */
7f25bdff 244 char Ext[] = {'\0','k','M','G','T','P','E','Z','Y'};
6c139d6e
AL
245 int I = 0;
246 while (I <= 8)
247 {
248 if (ASize < 100 && I != 0)
249 {
250 sprintf(S,"%.1f%c",ASize,Ext[I]);
251 break;
252 }
253
254 if (ASize < 10000)
255 {
256 sprintf(S,"%.0f%c",ASize,Ext[I]);
257 break;
258 }
259 ASize /= 1000.0;
260 I++;
261 }
262
263 return S;
264}
265 /*}}}*/
266// TimeToStr - Convert the time into a string /*{{{*/
267// ---------------------------------------------------------------------
268/* Converts a number of seconds to a hms format */
269string TimeToStr(unsigned long Sec)
270{
271 char S[300];
272
273 while (1)
274 {
275 if (Sec > 60*60*24)
276 {
277 sprintf(S,"%lid %lih%lim%lis",Sec/60/60/24,(Sec/60/60) % 24,(Sec/60) % 60,Sec % 60);
278 break;
279 }
280
281 if (Sec > 60*60)
282 {
283 sprintf(S,"%lih%lim%lis",Sec/60/60,(Sec/60) % 60,Sec % 60);
284 break;
285 }
286
287 if (Sec > 60)
288 {
289 sprintf(S,"%lim%lis",Sec/60,Sec % 60);
290 break;
291 }
292
293 sprintf(S,"%lis",Sec);
294 break;
295 }
296
297 return S;
298}
299 /*}}}*/
300// SubstVar - Substitute a string for another string /*{{{*/
301// ---------------------------------------------------------------------
302/* This replaces all occurances of Subst with Contents in Str. */
303string SubstVar(string Str,string Subst,string Contents)
304{
8efa2a3b 305 string::size_type Pos = 0;
6c139d6e
AL
306 string::size_type OldPos = 0;
307 string Temp;
308
309 while (OldPos < Str.length() &&
310 (Pos = Str.find(Subst,OldPos)) != string::npos)
311 {
312 Temp += string(Str,OldPos,Pos) + Contents;
313 OldPos = Pos + Subst.length();
314 }
315
316 if (OldPos == 0)
317 return Str;
318
319 return Temp + string(Str,OldPos);
320}
321 /*}}}*/
ad00ae81
AL
322// URItoFileName - Convert the uri into a unique file name /*{{{*/
323// ---------------------------------------------------------------------
324/* This converts a URI into a safe filename. It quotes all unsafe characters
325 and converts / to _ and removes the scheme identifier. The resulting
326 file name should be unique and never occur again for a different file */
327string URItoFileName(string URI)
328{
54cf15cb
AL
329 // Nuke 'sensitive' items
330 ::URI U(URI);
331 U.User = string();
332 U.Password = string();
333 U.Access = "";
334
ad00ae81 335 // "\x00-\x20{}|\\\\^\\[\\]<>\"\x7F-\xFF";
54cf15cb 336 URI = QuoteString(U,"\\|{}[]<>\"^~_=!@#$%^&*");
ad00ae81
AL
337 string::iterator J = URI.begin();
338 for (; J != URI.end(); J++)
339 if (*J == '/')
340 *J = '_';
341 return URI;
342}
343 /*}}}*/
6c139d6e
AL
344// Base64Encode - Base64 Encoding routine for short strings /*{{{*/
345// ---------------------------------------------------------------------
346/* This routine performs a base64 transformation on a string. It was ripped
347 from wget and then patched and bug fixed.
348
349 This spec can be found in rfc2045 */
350string Base64Encode(string S)
351{
352 // Conversion table.
353 static char tbl[64] = {'A','B','C','D','E','F','G','H',
354 'I','J','K','L','M','N','O','P',
355 'Q','R','S','T','U','V','W','X',
356 'Y','Z','a','b','c','d','e','f',
357 'g','h','i','j','k','l','m','n',
358 'o','p','q','r','s','t','u','v',
359 'w','x','y','z','0','1','2','3',
360 '4','5','6','7','8','9','+','/'};
361
362 // Pre-allocate some space
363 string Final;
364 Final.reserve((4*S.length() + 2)/3 + 2);
365
366 /* Transform the 3x8 bits to 4x6 bits, as required by
367 base64. */
368 for (string::const_iterator I = S.begin(); I < S.end(); I += 3)
369 {
370 char Bits[3] = {0,0,0};
371 Bits[0] = I[0];
372 if (I + 1 < S.end())
373 Bits[1] = I[1];
374 if (I + 2 < S.end())
375 Bits[2] = I[2];
376
377 Final += tbl[Bits[0] >> 2];
378 Final += tbl[((Bits[0] & 3) << 4) + (Bits[1] >> 4)];
379
380 if (I + 1 >= S.end())
381 break;
382
383 Final += tbl[((Bits[1] & 0xf) << 2) + (Bits[2] >> 6)];
384
385 if (I + 2 >= S.end())
386 break;
387
388 Final += tbl[Bits[2] & 0x3f];
389 }
390
391 /* Apply the padding elements, this tells how many bytes the remote
392 end should discard */
393 if (S.length() % 3 == 2)
394 Final += '=';
395 if (S.length() % 3 == 1)
396 Final += "==";
397
398 return Final;
399}
400 /*}}}*/
401// stringcmp - Arbitary string compare /*{{{*/
402// ---------------------------------------------------------------------
403/* This safely compares two non-null terminated strings of arbitary
404 length */
405int stringcmp(const char *A,const char *AEnd,const char *B,const char *BEnd)
406{
407 for (; A != AEnd && B != BEnd; A++, B++)
408 if (*A != *B)
409 break;
410
411 if (A == AEnd && B == BEnd)
412 return 0;
413 if (A == AEnd)
414 return 1;
415 if (B == BEnd)
416 return -1;
417 if (*A < *B)
418 return -1;
419 return 1;
420}
421 /*}}}*/
422// stringcasecmp - Arbitary case insensitive string compare /*{{{*/
423// ---------------------------------------------------------------------
424/* */
425int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd)
426{
427 for (; A != AEnd && B != BEnd; A++, B++)
428 if (toupper(*A) != toupper(*B))
429 break;
3b5421b4 430
6c139d6e
AL
431 if (A == AEnd && B == BEnd)
432 return 0;
433 if (A == AEnd)
434 return 1;
435 if (B == BEnd)
436 return -1;
437 if (toupper(*A) < toupper(*B))
438 return -1;
439 return 1;
440}
441 /*}}}*/
3b5421b4
AL
442// LookupTag - Lookup the value of a tag in a taged string /*{{{*/
443// ---------------------------------------------------------------------
444/* The format is like those used in package files and the method
445 communication system */
446string LookupTag(string Message,const char *Tag,const char *Default)
447{
448 // Look for a matching tag.
449 int Length = strlen(Tag);
450 for (string::iterator I = Message.begin(); I + Length < Message.end(); I++)
451 {
452 // Found the tag
453 if (I[Length] == ':' && stringcasecmp(I,I+Length,Tag) == 0)
454 {
455 // Find the end of line and strip the leading/trailing spaces
456 string::iterator J;
457 I += Length + 1;
458 for (; isspace(*I) != 0 && I < Message.end(); I++);
459 for (J = I; *J != '\n' && J < Message.end(); J++);
460 for (; J > I && isspace(J[-1]) != 0; J--);
461
462 return string(I,J-I);
463 }
464
465 for (; *I != '\n' && I < Message.end(); I++);
466 }
467
468 // Failed to find a match
469 if (Default == 0)
470 return string();
471 return Default;
472}
473 /*}}}*/
474// StringToBool - Converts a string into a boolean /*{{{*/
475// ---------------------------------------------------------------------
476/* This inspects the string to see if it is true or if it is false and
477 then returns the result. Several varients on true/false are checked. */
478int StringToBool(string Text,int Default = -1)
479{
480 char *End;
481 int Res = strtol(Text.c_str(),&End,0);
482 if (End != Text.c_str() && Res >= 0 && Res <= 1)
483 return Res;
484
485 // Check for positives
486 if (strcasecmp(Text.c_str(),"no") == 0 ||
487 strcasecmp(Text.c_str(),"false") == 0 ||
488 strcasecmp(Text.c_str(),"without") == 0 ||
7f25bdff 489 strcasecmp(Text.c_str(),"off") == 0 ||
3b5421b4
AL
490 strcasecmp(Text.c_str(),"disable") == 0)
491 return 0;
492
493 // Check for negatives
494 if (strcasecmp(Text.c_str(),"yes") == 0 ||
495 strcasecmp(Text.c_str(),"true") == 0 ||
496 strcasecmp(Text.c_str(),"with") == 0 ||
7f25bdff 497 strcasecmp(Text.c_str(),"on") == 0 ||
3b5421b4
AL
498 strcasecmp(Text.c_str(),"enable") == 0)
499 return 1;
500
501 return Default;
502}
503 /*}}}*/
0a8a80e5
AL
504// TimeRFC1123 - Convert a time_t into RFC1123 format /*{{{*/
505// ---------------------------------------------------------------------
506/* This converts a time_t into a string time representation that is
507 year 2000 complient and timezone neutral */
508string TimeRFC1123(time_t Date)
509{
510 struct tm Conv = *gmtime(&Date);
511 char Buf[300];
512
513 const char *Day[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
514 const char *Month[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul",
515 "Aug","Sep","Oct","Nov","Dec"};
516
517 sprintf(Buf,"%s, %02i %s %i %02i:%02i:%02i GMT",Day[Conv.tm_wday],
518 Conv.tm_mday,Month[Conv.tm_mon],Conv.tm_year+1900,Conv.tm_hour,
519 Conv.tm_min,Conv.tm_sec);
520 return Buf;
521}
522 /*}}}*/
523// ReadMessages - Read messages from the FD /*{{{*/
524// ---------------------------------------------------------------------
525/* This pulls full messages from the input FD into the message buffer.
526 It assumes that messages will not pause during transit so no
527 fancy buffering is used. */
528bool ReadMessages(int Fd, vector<string> &List)
529{
530 char Buffer[4000];
531 char *End = Buffer;
532
533 while (1)
534 {
535 int Res = read(Fd,End,sizeof(Buffer) - (End-Buffer));
b0db36b1
AL
536 if (Res < 0 && errno == EINTR)
537 continue;
0a8a80e5
AL
538
539 // Process is dead, this is kind of bad..
540 if (Res == 0)
541 return false;
542
543 // No data
544 if (Res <= 0)
545 return true;
546
547 End += Res;
548
549 // Look for the end of the message
c88edf1d 550 for (char *I = Buffer; I + 1 < End; I++)
0a8a80e5
AL
551 {
552 if (I[0] != '\n' || I[1] != '\n')
553 continue;
554
555 // Pull the message out
556 string Message(Buffer,0,I-Buffer);
557
558 // Fix up the buffer
559 for (; I < End && *I == '\n'; I++);
560 End -= I-Buffer;
561 memmove(Buffer,I,End-Buffer);
562 I = Buffer;
563
564 List.push_back(Message);
565 }
566 if (End == Buffer)
567 return true;
568
569 if (WaitFd(Fd) == false)
570 return false;
571 }
572}
573 /*}}}*/
24231681
AL
574// MonthConv - Converts a month string into a number /*{{{*/
575// ---------------------------------------------------------------------
576/* This was lifted from the boa webserver which lifted it from 'wn-v1.07'
577 Made it a bit more robust with a few touppers though. */
578static int MonthConv(char *Month)
579{
580 switch (toupper(*Month))
581 {
582 case 'A':
583 return toupper(Month[1]) == 'P'?3:7;
584 case 'D':
585 return 11;
586 case 'F':
587 return 1;
588 case 'J':
589 if (toupper(Month[1]) == 'A')
590 return 0;
591 return toupper(Month[2]) == 'N'?5:6;
592 case 'M':
593 return toupper(Month[2]) == 'R'?2:4;
594 case 'N':
595 return 10;
596 case 'O':
597 return 9;
598 case 'S':
599 return 8;
600
601 // Pretend it is January..
602 default:
603 return 0;
604 }
605}
606 /*}}}*/
6d5dd02a
AL
607// timegm - Internal timegm function if gnu is not available /*{{{*/
608// ---------------------------------------------------------------------
609/* Ripped this evil little function from wget - I prefer the use of
610 GNU timegm if possible as this technique will have interesting problems
611 with leap seconds, timezones and other.
612
613 Converts struct tm to time_t, assuming the data in tm is UTC rather
614 than local timezone (mktime assumes the latter).
615
616 Contributed by Roger Beeman <beeman@cisco.com>, with the help of
617 Mark Baushke <mdb@cisco.com> and the rest of the Gurus at CISCO. */
618#ifndef __USE_MISC // glib sets this
619static time_t timegm(struct tm *t)
620{
621 time_t tl, tb;
622
623 tl = mktime (t);
624 if (tl == -1)
625 return -1;
626 tb = mktime (gmtime (&tl));
627 return (tl <= tb ? (tl + (tl - tb)) : (tl - (tb - tl)));
628}
629#endif
630 /*}}}*/
24231681
AL
631// StrToTime - Converts a string into a time_t /*{{{*/
632// ---------------------------------------------------------------------
633/* This handles all 3 populare time formats including RFC 1123, RFC 1036
634 and the C library asctime format. It requires the GNU library function
635 'timegm' to convert a struct tm in UTC to a time_t. For some bizzar
636 reason the C library does not provide any such function :<*/
637bool StrToTime(string Val,time_t &Result)
638{
639 struct tm Tm;
640 char Month[10];
641 const char *I = Val.c_str();
642
643 // Skip the day of the week
644 for (;*I != 0 && *I != ' '; I++);
645
646 // Handle RFC 1123 time
647 if (sscanf(I," %d %3s %d %d:%d:%d GMT",&Tm.tm_mday,Month,&Tm.tm_year,
648 &Tm.tm_hour,&Tm.tm_min,&Tm.tm_sec) != 6)
649 {
650 // Handle RFC 1036 time
651 if (sscanf(I," %d-%3s-%d %d:%d:%d GMT",&Tm.tm_mday,Month,
652 &Tm.tm_year,&Tm.tm_hour,&Tm.tm_min,&Tm.tm_sec) == 6)
653 Tm.tm_year += 1900;
654 else
655 {
656 // asctime format
657 if (sscanf(I," %3s %d %d:%d:%d %d",Month,&Tm.tm_mday,
658 &Tm.tm_hour,&Tm.tm_min,&Tm.tm_sec,&Tm.tm_year) != 6)
659 return false;
660 }
661 }
662
663 Tm.tm_isdst = 0;
664 Tm.tm_mon = MonthConv(Month);
665 Tm.tm_year -= 1900;
666
667 // Convert to local time and then to GMT
668 Result = timegm(&Tm);
669 return true;
670}
671 /*}}}*/
ddc1d8d0
AL
672// StrToNum - Convert a fixed length string to a number /*{{{*/
673// ---------------------------------------------------------------------
674/* This is used in decoding the crazy fixed length string headers in
675 tar and ar files. */
676bool StrToNum(const char *Str,unsigned long &Res,unsigned Len,unsigned Base)
677{
678 char S[30];
679 if (Len >= sizeof(S))
680 return false;
681 memcpy(S,Str,Len);
682 S[Len] = 0;
683
684 // All spaces is a zero
685 Res = 0;
686 unsigned I;
687 for (I = 0; S[I] == ' '; I++);
688 if (S[I] == 0)
689 return true;
690
691 char *End;
692 Res = strtoul(S,&End,Base);
693 if (End == S)
694 return false;
695
696 return true;
697}
698 /*}}}*/
6e52073f
AL
699// HexDigit - Convert a hex character into an integer /*{{{*/
700// ---------------------------------------------------------------------
701/* Helper for Hex2Num */
702static int HexDigit(int c)
703{
704 if (c >= '0' && c <= '9')
705 return c - '0';
706 if (c >= 'a' && c <= 'f')
707 return c - 'a' + 10;
708 if (c >= 'A' && c <= 'F')
709 return c - 'A' + 10;
710 return 0;
711}
712 /*}}}*/
713// Hex2Num - Convert a long hex number into a buffer /*{{{*/
714// ---------------------------------------------------------------------
715/* The length of the buffer must be exactly 1/2 the length of the string. */
716bool Hex2Num(const char *Start,const char *End,unsigned char *Num,
717 unsigned int Length)
718{
bf3abeed 719 if (End - Start != (signed)(Length*2))
6e52073f
AL
720 return false;
721
722 // Convert each digit. We store it in the same order as the string
723 int J = 0;
724 for (const char *I = Start; I < End;J++, I += 2)
725 {
726 if (isxdigit(*I) == 0 || isxdigit(I[1]) == 0)
727 return false;
728
729 Num[J] = HexDigit(I[0]) << 4;
730 Num[J] += HexDigit(I[1]);
731 }
732
733 return true;
734}
735 /*}}}*/
93bf083d 736
be4401bf 737// URI::CopyFrom - Copy from an object /*{{{*/
93bf083d
AL
738// ---------------------------------------------------------------------
739/* This parses the URI into all of its components */
be4401bf 740void URI::CopyFrom(string U)
93bf083d
AL
741{
742 string::const_iterator I = U.begin();
743
744 // Locate the first colon, this seperates the scheme
745 for (; I < U.end() && *I != ':' ; I++);
746 string::const_iterator FirstColon = I;
747
bfd22fc0
AL
748 /* Determine if this is a host type URI with a leading double //
749 and then search for the first single / */
93bf083d
AL
750 string::const_iterator SingleSlash = I;
751 if (I + 3 < U.end() && I[1] == '/' && I[2] == '/')
bfd22fc0
AL
752 SingleSlash += 3;
753 for (; SingleSlash < U.end() && *SingleSlash != '/'; SingleSlash++);
754 if (SingleSlash > U.end())
f46e7681 755 SingleSlash = U.end();
93bf083d
AL
756
757 // We can now write the access and path specifiers
758 Access = string(U,0,FirstColon - U.begin());
759 if (SingleSlash != U.end())
92e889c8
AL
760 Path = string(U,SingleSlash - U.begin());
761 if (Path.empty() == true)
762 Path = "/";
763
93bf083d 764 // Now we attempt to locate a user:pass@host fragment
542ec555 765 if (FirstColon[1] == '/' && FirstColon[2] == '/')
f46e7681
AL
766 FirstColon += 3;
767 else
768 FirstColon += 1;
93bf083d
AL
769 if (FirstColon >= U.end())
770 return;
771
772 if (FirstColon > SingleSlash)
773 FirstColon = SingleSlash;
774
3856756b
AL
775 // Find the colon...
776 I = FirstColon + 1;
1d38d0e9
AL
777 if (I > SingleSlash)
778 I = SingleSlash;
3856756b
AL
779 for (; I < SingleSlash && *I != ':'; I++);
780 string::const_iterator SecondColon = I;
781
782 // Search for the @ after the colon
93bf083d
AL
783 for (; I < SingleSlash && *I != '@'; I++);
784 string::const_iterator At = I;
785
93bf083d
AL
786 // Now write the host and user/pass
787 if (At == SingleSlash)
788 {
789 if (FirstColon < SingleSlash)
790 Host = string(U,FirstColon - U.begin(),SingleSlash - FirstColon);
791 }
792 else
793 {
794 Host = string(U,At - U.begin() + 1,SingleSlash - At - 1);
795 User = string(U,FirstColon - U.begin(),SecondColon - FirstColon);
796 if (SecondColon < At)
797 Password = string(U,SecondColon - U.begin() + 1,At - SecondColon - 1);
798 }
799
1d38d0e9 800 // Now we parse off a port number from the hostname
93bf083d
AL
801 Port = 0;
802 string::size_type Pos = Host.rfind(':');
803 if (Pos == string::npos)
804 return;
805
806 Port = atoi(string(Host,Pos+1).c_str());
807 Host = string(Host,0,Pos);
808}
809 /*}}}*/
810// URI::operator string - Convert the URI to a string /*{{{*/
811// ---------------------------------------------------------------------
812/* */
813URI::operator string()
814{
54cf15cb
AL
815 string Res;
816
817 if (Access.empty() == false)
818 Res = Access + ':';
819
93bf083d
AL
820 if (Host.empty() == false)
821 {
54cf15cb
AL
822 if (Access.empty() == false)
823 Res += "//";
824
93bf083d
AL
825 if (User.empty() == false)
826 {
54cf15cb 827 Res += User;
93bf083d
AL
828 if (Password.empty() == false)
829 Res += ":" + Password;
830 Res += "@";
831 }
54cf15cb 832
93bf083d 833 Res += Host;
492f957a
AL
834 if (Port != 0)
835 {
836 char S[30];
837 sprintf(S,":%u",Port);
838 Res += S;
839 }
93bf083d
AL
840 }
841
842 if (Path.empty() == false)
492f957a
AL
843 {
844 if (Path[0] != '/')
845 Res += "/" + Path;
846 else
847 Res += Path;
848 }
93bf083d
AL
849
850 return Res;
851}
852 /*}}}*/