Add a global object in wvx509.cc to prevent SSL errors from getting unloaded.
[wvstreams.git] / utils / wvstring.cc
blobf453c6861d083c768d64b3f10a92976027754fb5
1 /*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4 *
5 * Implementation of a simple and efficient printable-string class. Most
6 * of the class is actually inlined and can be found in wvstring.h.
7 */
8 #include "wvstring.h"
9 #include <ctype.h>
10 #include <assert.h>
12 WvStringBuf WvFastString::nullbuf = { 0, 1 };
13 const WvFastString WvFastString::null;
15 const WvString WvString::empty("");
18 // always a handy function
19 static inline int _max(int x, int y)
21 return x>y ? x : y;
25 void WvFastString::setsize(size_t i)
27 unlink();
28 newbuf(i);
33 WvFastString::WvFastString()
35 link(&nullbuf, NULL);
39 WvFastString::WvFastString(const WvFastString &s)
41 link(s.buf, s.str);
45 WvFastString::WvFastString(const WvString &s)
47 link(s.buf, s.str);
51 void WvFastString::construct(const char *_str)
53 // just copy the pointer - no need to allocate memory!
54 str = (char *)_str; // I promise not to change anything!
55 buf = NULL;
59 WvFastString::WvFastString(const char *_str)
61 construct(_str);
65 void WvString::copy_constructor(const WvFastString &s)
67 unlink(); // WvFastString has already been created by now
69 if (!s.buf)
71 link(&nullbuf, s.str);
72 unique();
74 else
75 link(s.buf, s.str); // already in a nice, safe WvStreamBuf
79 WvFastString WvFastString::offset(size_t i) const
81 WvFastString retval(*this);
82 size_t l = retval.len();
83 retval.str += (i < l ? i : l);
84 return retval;
88 WvString::WvString(const char *_str)
90 unlink(); // WvFastString has already been created by now
91 construct(_str);
95 // This function returns the NULL of a reversed string representation
96 // for unsigned integers
97 template <typename T>
98 inline static char *wv_uitoar(char *begin, T i)
100 if (!begin)
101 return NULL;
103 char *end = begin;
105 if (i == 0)
106 *end++ = '0';
107 else
109 while (i > 0)
111 switch (i % 10)
113 case 0: *end++ = '0'; break;
114 case 1: *end++ = '1'; break;
115 case 2: *end++ = '2'; break;
116 case 3: *end++ = '3'; break;
117 case 4: *end++ = '4'; break;
118 case 5: *end++ = '5'; break;
119 case 6: *end++ = '6'; break;
120 case 7: *end++ = '7'; break;
121 case 8: *end++ = '8'; break;
122 case 9: *end++ = '9'; break;
123 default: ;
125 i /= 10;
129 *end = '\0';
130 return end;
133 // This function returns the NULL of a reversed string representation
134 // for signed integers
135 template <typename T>
136 inline static char *wv_itoar(char *begin, T i)
138 if (!begin)
139 return NULL;
141 bool negative = false;
142 if (i < 0)
144 negative = true;
145 i = -i;
147 char *end = wv_uitoar(begin, i);
148 if (negative)
150 *end++ = '-';
151 *end = '\0';
153 return end;
157 inline static void wv_strrev(char *begin, char *end)
159 if (!begin && !end)
160 return;
162 --end;
164 while (begin < end)
166 *begin ^= *end;
167 *end ^= *begin;
168 *begin ^= *end;
169 ++begin;
170 --end;
176 // NOTE: make sure that 32 bytes is big enough for your longest int.
177 // This is true up to at least 64 bits.
178 WvFastString::WvFastString(short i)
180 newbuf(32);
181 wv_strrev(str, wv_itoar(str, i));
185 WvFastString::WvFastString(unsigned short i)
187 newbuf(32);
188 wv_strrev(str, wv_uitoar(str, i));
192 WvFastString::WvFastString(int i)
194 newbuf(32);
195 wv_strrev(str, wv_itoar(str, i));
199 WvFastString::WvFastString(unsigned int i)
201 newbuf(32);
202 wv_strrev(str, wv_uitoar(str, i));
206 WvFastString::WvFastString(long i)
208 newbuf(32);
209 wv_strrev(str, wv_itoar(str, i));
213 WvFastString::WvFastString(unsigned long i)
215 newbuf(32);
216 wv_strrev(str, wv_uitoar(str, i));
220 WvFastString::WvFastString(long long i)
222 newbuf(32);
223 wv_strrev(str, wv_itoar(str, i));
227 WvFastString::WvFastString(unsigned long long i)
229 newbuf(32);
230 wv_strrev(str, wv_uitoar(str, i));
234 WvFastString::WvFastString(double i)
236 newbuf(32);
237 sprintf(str, "%g", i);
241 WvFastString::~WvFastString()
243 unlink();
247 void WvFastString::unlink()
249 if (buf && ! --buf->links)
251 free(buf);
252 buf = NULL;
257 void WvFastString::link(WvStringBuf *_buf, const char *_str)
259 buf = _buf;
260 if (buf)
261 buf->links++;
262 str = (char *)_str; // I promise not to change it without asking!
266 WvStringBuf *WvFastString::alloc(size_t size)
268 WvStringBuf *abuf = (WvStringBuf *)malloc(
269 (WVSTRINGBUF_SIZE(buf) + size + WVSTRING_EXTRA) | 3);
270 abuf->links = 0;
271 abuf->size = size;
272 return abuf;
276 WvString &WvString::append(WvStringParm s)
278 if (s)
280 if (*this)
281 *this = WvString("%s%s", *this, s);
282 else
283 *this = s;
286 return *this;
290 size_t WvFastString::len() const
292 return str ? strlen(str) : 0;
296 void WvFastString::newbuf(size_t size)
298 buf = alloc(size);
299 buf->links = 1;
300 str = buf->data;
304 // If the string is linked to more than once, we need to make our own copy
305 // of it. If it was linked to only once, then it's already "unique".
306 WvString &WvString::unique()
308 if (!is_unique() && str)
310 WvStringBuf *newb = alloc(len() + 1);
311 memcpy(newb->data, str, newb->size);
312 unlink();
313 link(newb, newb->data);
316 return *this;
320 bool WvString::is_unique() const
322 return (buf->links <= 1);
326 WvFastString &WvFastString::operator= (const WvFastString &s2)
328 if (s2.buf == buf && s2.str == str)
329 return *this; // no change
330 else
332 unlink();
333 link(s2.buf, s2.str);
335 return *this;
339 WvString &WvString::operator= (int i)
341 unlink();
342 newbuf(32);
343 sprintf(str, "%d", i);
344 return *this;
348 WvString &WvString::operator= (const WvFastString &s2)
350 if (s2.str == str && (!s2.buf || s2.buf == buf))
351 return *this; // no change
352 else if (!s2.buf)
354 // We have a string, and we're about to free() it.
355 if (str && buf && buf->links == 1)
357 // Set buf->size, if we don't already know it.
358 if (buf->size == 0)
359 buf->size = strlen(str);
361 if (str < s2.str && s2.str <= (str + buf->size))
363 // If the two strings overlap, we'll just need to
364 // shift s2.str over to here.
365 memmove(buf->data, s2.str, buf->size);
366 return *this;
369 // assigning from a non-copied string - copy data if needed.
370 unlink();
371 link(&nullbuf, s2.str);
372 unique();
374 else
376 // just a normal string link
377 unlink();
378 link(s2.buf, s2.str);
380 return *this;
384 // string comparison
385 bool WvFastString::operator== (WvStringParm s2) const
387 return (str==s2.str) || (str && s2.str && !strcmp(str, s2.str));
391 bool WvFastString::operator!= (WvStringParm s2) const
393 return (str!=s2.str) && (!str || !s2.str || strcmp(str, s2.str));
397 bool WvFastString::operator< (WvStringParm s2) const
399 if (str == s2.str) return false;
400 if (str == 0) return true;
401 if (s2.str == 0) return false;
402 return strcmp(str, s2.str) < 0;
406 bool WvFastString::operator== (const char *s2) const
408 return (str==s2) || (str && s2 && !strcmp(str, s2));
412 bool WvFastString::operator!= (const char *s2) const
414 return (str!=s2) && (!str || !s2 || strcmp(str, s2));
418 bool WvFastString::operator< (const char *s2) const
420 if (str == s2) return false;
421 if (str == 0) return true;
422 if (s2 == 0) return false;
423 return strcmp(str, s2) < 0;
427 // not operator is 'true' if string is empty
428 bool WvFastString::operator! () const
430 return !str || !str[0];
434 /**
435 * parse a 'percent' operator from a format string. For example:
436 * cptr out: zeropad justify maxlen argnum return pointer
437 * "%s" false 0 0 0 "s"
438 * "%-15s" false -15 0 0 "s"
439 * "%15.5s" false 15 5 0 "s"
440 * "%015.5s" true 15 5 0 "s"
441 * "%15$2s" false 15 0 2 "s"
442 * and so on. On entry, cptr should _always_ point at a percent '%' char.
443 * argnum is the argument number.
445 static const char *pparse(const char *cptr, bool &zeropad,
446 int &justify, int &maxlen, int &argnum)
448 assert(*cptr == '%');
449 cptr++;
451 zeropad = (*cptr == '0');
453 justify = atoi(cptr);
455 for (; *cptr && *cptr!='.' && *cptr!='%' && *cptr!='$'
456 && !isalpha(*cptr); cptr++)
458 if (!*cptr) return cptr;
460 if (*cptr == '.')
461 maxlen = atoi(cptr+1);
462 else
463 maxlen = 0;
465 for (; *cptr && *cptr!='%' && *cptr!='$' && !isalpha(*cptr); cptr++)
467 if (!*cptr) return cptr;
469 if (*cptr == '$')
470 argnum = atoi(cptr+1);
471 else
472 argnum = 0;
474 for (; *cptr && *cptr!='%' && !isalpha(*cptr); cptr++)
477 return cptr;
482 * Accept a printf-like format specifier (but more limited) and an array
483 * of WvStrings, and render them into another WvString. For example:
484 * WvString x[] = {"foo", "blue", 1234};
485 * WvString ret = WvString::do_format("%s%10.2s%-10s", x);
487 * The 'ret' string will be: "foo bl1234 "
488 * Note that only '%s' is supported, though integers can be rendered
489 * automatically into WvStrings. %d, %f, etc are not allowed!
491 * This function is usually called from some other function which allocates
492 * the array automatically.
494 * %$ns (n > 0) is also supported for internationalization purposes. e.g.
495 * ("%$2s is arg2, and %$1s ia arg1", arg1, arg2)
497 void WvFastString::do_format(WvFastString &output, const char *format,
498 const WvFastString * const *argv)
500 static const char blank[] = "(nil)";
501 const WvFastString * const *argptr = argv;
502 const WvFastString * const *argP;
503 const char *iptr = format, *arg;
504 char *optr;
505 int total = 0, aplen, ladd, justify, maxlen, argnum;
506 bool zeropad;
508 // count the number of bytes we'll need
509 while (*iptr)
511 if (*iptr != '%')
513 total++;
514 iptr++;
515 continue;
518 // otherwise, iptr is at a percent expression
519 argnum=0;
520 iptr = pparse(iptr, zeropad, justify, maxlen, argnum);
521 if (*iptr == '%') // literal percent
523 total++;
524 iptr++;
525 continue;
528 assert(*iptr == 's' || *iptr == 'c');
530 if (*iptr == 's')
532 argP = (argnum > 0 ) ? (argv + argnum -1): argptr;
533 if (!*argP || !(**argP).cstr())
534 arg = blank;
535 else
536 arg = (**argP).cstr();
537 ladd = _max(abs(justify), strlen(arg));
538 if (maxlen && maxlen < ladd)
539 ladd = maxlen;
540 total += ladd;
541 if ( argnum <= 0 )
542 argptr++;
543 iptr++;
544 continue;
547 if (*iptr++ == 'c')
549 if (argnum <= 0)
550 argptr++;
551 total++;
555 output.setsize(total + 1);
557 // actually render the final string
558 iptr = format;
559 optr = output.str;
560 argptr = argv;
561 while (*iptr)
563 if (*iptr != '%')
565 *optr++ = *iptr++;
566 continue;
569 // otherwise, iptr is at a "percent expression"
570 argnum=0;
571 iptr = pparse(iptr, zeropad, justify, maxlen, argnum);
572 if (*iptr == '%')
574 *optr++ = *iptr++;
575 continue;
577 if (*iptr == 's')
579 argP = (argnum > 0 ) ? (argv + argnum -1): argptr;
580 if (!*argP || !(**argP).cstr())
581 arg = blank;
582 else
583 arg = (**argP).cstr();
584 aplen = strlen(arg);
585 if (maxlen && maxlen < aplen)
586 aplen = maxlen;
588 if (justify > aplen)
590 if (zeropad)
591 memset(optr, '0', justify-aplen);
592 else
593 memset(optr, ' ', justify-aplen);
594 optr += justify-aplen;
597 strncpy(optr, arg, aplen);
598 optr += aplen;
600 if (justify < 0 && -justify > aplen)
602 if (zeropad)
603 memset(optr, '0', -justify-aplen);
604 else
605 memset(optr, ' ', -justify-aplen);
606 optr += -justify - aplen;
609 if ( argnum <= 0 )
610 argptr++;
611 iptr++;
612 continue;
614 if (*iptr++ == 'c')
616 argP = (argnum > 0 ) ? (argv + argnum -1): argptr++;
617 if (!*argP || !(**argP))
618 arg = " ";
619 else
620 arg = (**argP);
621 *optr++ = (char)atoi(arg);
624 *optr = 0;