2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
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.
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
)
25 void WvFastString::setsize(size_t i
)
33 WvFastString::WvFastString()
39 WvFastString::WvFastString(const WvFastString
&s
)
45 WvFastString::WvFastString(const WvString
&s
)
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!
59 WvFastString::WvFastString(const char *_str
)
65 void WvString::copy_constructor(const WvFastString
&s
)
67 unlink(); // WvFastString has already been created by now
71 link(&nullbuf
, s
.str
);
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
);
88 WvString::WvString(const char *_str
)
90 unlink(); // WvFastString has already been created by now
95 // This function returns the NULL of a reversed string representation
96 // for unsigned integers
98 inline static char *wv_uitoar(char *begin
, T i
)
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;
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
)
141 bool negative
= false;
147 char *end
= wv_uitoar(begin
, i
);
157 inline static void wv_strrev(char *begin
, char *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
)
181 wv_strrev(str
, wv_itoar(str
, i
));
185 WvFastString::WvFastString(unsigned short i
)
188 wv_strrev(str
, wv_uitoar(str
, i
));
192 WvFastString::WvFastString(int i
)
195 wv_strrev(str
, wv_itoar(str
, i
));
199 WvFastString::WvFastString(unsigned int i
)
202 wv_strrev(str
, wv_uitoar(str
, i
));
206 WvFastString::WvFastString(long i
)
209 wv_strrev(str
, wv_itoar(str
, i
));
213 WvFastString::WvFastString(unsigned long i
)
216 wv_strrev(str
, wv_uitoar(str
, i
));
220 WvFastString::WvFastString(long long i
)
223 wv_strrev(str
, wv_itoar(str
, i
));
227 WvFastString::WvFastString(unsigned long long i
)
230 wv_strrev(str
, wv_uitoar(str
, i
));
234 WvFastString::WvFastString(double i
)
237 sprintf(str
, "%g", i
);
241 WvFastString::~WvFastString()
247 void WvFastString::unlink()
249 if (buf
&& ! --buf
->links
)
257 void WvFastString::link(WvStringBuf
*_buf
, const char *_str
)
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);
276 WvString
&WvString::append(WvStringParm s
)
281 *this = WvString("%s%s", *this, s
);
290 size_t WvFastString::len() const
292 return str
? strlen(str
) : 0;
296 void WvFastString::newbuf(size_t size
)
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
);
313 link(newb
, newb
->data
);
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
333 link(s2
.buf
, s2
.str
);
339 WvString
&WvString::operator= (int i
)
343 sprintf(str
, "%d", i
);
348 WvString
&WvString::operator= (const WvFastString
&s2
)
350 if (s2
.str
== str
&& (!s2
.buf
|| s2
.buf
== buf
))
351 return *this; // no change
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.
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
);
369 // assigning from a non-copied string - copy data if needed.
371 link(&nullbuf
, s2
.str
);
376 // just a normal string link
378 link(s2
.buf
, s2
.str
);
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];
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
== '%');
451 zeropad
= (*cptr
== '0');
453 justify
= atoi(cptr
);
455 for (; *cptr
&& *cptr
!='.' && *cptr
!='%' && *cptr
!='$'
456 && !isalpha(*cptr
); cptr
++)
458 if (!*cptr
) return cptr
;
461 maxlen
= atoi(cptr
+1);
465 for (; *cptr
&& *cptr
!='%' && *cptr
!='$' && !isalpha(*cptr
); cptr
++)
467 if (!*cptr
) return cptr
;
470 argnum
= atoi(cptr
+1);
474 for (; *cptr
&& *cptr
!='%' && !isalpha(*cptr
); 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
;
505 int total
= 0, aplen
, ladd
, justify
, maxlen
, argnum
;
508 // count the number of bytes we'll need
518 // otherwise, iptr is at a percent expression
520 iptr
= pparse(iptr
, zeropad
, justify
, maxlen
, argnum
);
521 if (*iptr
== '%') // literal percent
528 assert(*iptr
== 's' || *iptr
== 'c');
532 argP
= (argnum
> 0 ) ? (argv
+ argnum
-1): argptr
;
533 if (!*argP
|| !(**argP
).cstr())
536 arg
= (**argP
).cstr();
537 ladd
= _max(abs(justify
), strlen(arg
));
538 if (maxlen
&& maxlen
< ladd
)
555 output
.setsize(total
+ 1);
557 // actually render the final string
569 // otherwise, iptr is at a "percent expression"
571 iptr
= pparse(iptr
, zeropad
, justify
, maxlen
, argnum
);
579 argP
= (argnum
> 0 ) ? (argv
+ argnum
-1): argptr
;
580 if (!*argP
|| !(**argP
).cstr())
583 arg
= (**argP
).cstr();
585 if (maxlen
&& maxlen
< aplen
)
591 memset(optr
, '0', justify
-aplen
);
593 memset(optr
, ' ', justify
-aplen
);
594 optr
+= justify
-aplen
;
597 strncpy(optr
, arg
, aplen
);
600 if (justify
< 0 && -justify
> aplen
)
603 memset(optr
, '0', -justify
-aplen
);
605 memset(optr
, ' ', -justify
-aplen
);
606 optr
+= -justify
- aplen
;
616 argP
= (argnum
> 0 ) ? (argv
+ argnum
-1): argptr
++;
617 if (!*argP
|| !(**argP
))
621 *optr
++ = (char)atoi(arg
);