pike.git/
src/
stralloc.c
Branch:
Tag:
Non-build tags
All tags
No tags
2017-01-26
2017-01-26 15:20:41 by Henrik Grubbström (Grubba) <grubba@grubba.org>
2a3bfaf0e44b4b256e18f9a2d4e339d50c6d981d (
1008
lines) (+
2
/-
1006
)
[
Show
|
Annotate
]
Branch:
8.1
Break out string_builder from stralloc.
[ch]
to string_builder.
[ch]
.
More cleanuo of stralloc.
[ch]
.
51:
static unsigned INT32 num_strings=0; PMOD_EXPORT struct pike_string *empty_pike_string = 0;
-
struct substring_pike_string {
-
struct pike_string str;
-
struct pike_string *parent;
-
};
-
+
/*** Main string hash function ***/ #define StrHash(s,len) low_do_hash(s,len,0) #define low_do_hash(STR,LEN,SHIFT) low_hashmem( (STR), (LEN)<<(SHIFT), hash_prefix_len<<(SHIFT), hashkey ) #define do_hash(STR) low_do_hash(STR->str,STR->len,STR->size_shift)
-
static inline int string_is_block_allocated(const struct pike_string * s) {
-
return (s->alloc_type == STRING_ALLOC_BA);
-
}
-
-
static inline int PIKE_UNUSED_ATTRIBUTE string_is_malloced(const struct pike_string * s) {
-
return (s->alloc_type == STRING_ALLOC_MALLOC);
-
}
-
-
static inline int string_is_static(const struct pike_string * s) {
-
return s->alloc_type == STRING_ALLOC_STATIC;
-
}
-
-
static inline int string_is_substring(const struct pike_string * s) {
-
return s->alloc_type == STRING_ALLOC_SUBSTRING;
-
}
-
-
static struct pike_string *substring_content_string(const struct pike_string *s)
-
{
-
return ((struct substring_pike_string*)s)->parent;
-
}
-
-
static inline int string_may_modify(const struct pike_string * s)
-
{
-
return !string_is_static(s) && !string_is_substring(s)
-
&& s->refs == 1;
-
}
-
-
static inline int string_may_modify_len(const struct pike_string * s)
-
{
-
return s->refs == 1;
-
}
-
-
+
/* Returns true if str could contain n. */ PMOD_EXPORT int string_range_contains( struct pike_string *str, int n ) {
239:
if( max ) *max = s_max; }
-
static inline int find_magnitude1(const p_wchar1 *s, ptrdiff_t len)
-
{
-
const p_wchar1 *e=s+len;
-
while(s<e)
-
if(*s++>=256)
-
return 1;
-
return 0;
-
}
-
-
static inline int find_magnitude2(const p_wchar2 *s, ptrdiff_t len)
-
{
-
const p_wchar2 *e=s+len;
-
while(s<e)
-
{
-
if((unsigned INT32)*s>=256)
-
{
-
do
-
{
-
if((unsigned INT32)*s++>=65536)
-
return 2;
-
}while(s<e);
-
return 1;
-
}
-
s++;
-
}
-
return 0;
-
}
-
-
static inline enum size_shift min_magnitude(const unsigned c)
-
{
-
return LIKELY(c<256) ? 0 : LIKELY(c<65536) ? 1 : 2;
-
}
-
+
void low_set_index(struct pike_string *s, ptrdiff_t pos, int value) { #ifdef PIKE_DEBUG
1074:
/*** Free strings ***/
-
static
void unlink_pike_string(struct pike_string *s)
+
void unlink_pike_string(struct pike_string *s)
{ size_t h=HMODULO(s->hval); struct pike_string *tmp=base_table[h], *p=NULL;
2335:
return next; }
-
PMOD_EXPORT void init_string_builder_alloc(struct string_builder *s, ptrdiff_t length, int mag)
-
{
-
s->s=begin_wide_shared_string(length,mag);
-
s->malloced=length;
-
s->known_shift=0;
-
s->s->len=0;
-
low_set_index (s->s, 0, 0);
-
}
+
-
PMOD_EXPORT void init_string_builder(struct string_builder *s, int mag)
-
{
-
init_string_builder_alloc(s, 256, mag);
-
}
-
-
PMOD_EXPORT void init_string_builder_copy(struct string_builder *to,
-
const struct string_builder *from)
-
{
-
to->malloced = from->malloced;
-
to->s = begin_wide_shared_string (from->malloced, from->s->size_shift);
-
to->s->len = from->s->len;
-
memcpy (to->s->str, from->s->str, (from->s->len + 1) << from->s->size_shift);
-
to->known_shift = from->known_shift;
-
}
-
-
/* str becomes invalid if successful (i.e. nonzero returned),
-
* otherwise nothing happens. */
-
PMOD_EXPORT int init_string_builder_with_string (struct string_builder *s,
-
struct pike_string *str)
-
{
-
if (string_may_modify(str)) {
-
/* Unlink the string and use it as buffer directly. */
-
unlink_pike_string (str);
-
str->flags = STRING_NOT_SHARED;
-
s->s = str;
-
s->malloced = str->len;
-
s->known_shift = str->size_shift;
-
return 1;
-
}
-
return 0;
-
}
-
-
PMOD_EXPORT void string_build_mkspace(struct string_builder *s,
-
ptrdiff_t chars, int mag)
-
/* Doesn't touch or sanity check s->known_shift. */
-
{
-
if(mag > s->s->size_shift)
-
{
-
struct pike_string *n;
-
ptrdiff_t l = s->s->len + chars;
-
if (l < s->malloced)
-
l = s->malloced;
-
n=begin_wide_shared_string(l,mag);
-
pike_string_cpy(MKPCHARP_STR(n),s->s);
-
n->len=s->s->len;
-
s->s->len = s->malloced; /* Restore the real length */
-
s->malloced=l;
-
free_string(s->s);
-
s->s=n;
-
}
-
else if(s->s->len+chars > s->malloced)
-
{
-
ptrdiff_t newlen = MAXIMUM(s->malloced*2,
-
s->s->len + chars);
-
ptrdiff_t oldlen = s->s->len;
-
-
s->s->len = s->malloced; /* Restore the real length */
-
s->s = realloc_unlinked_string(s->s, newlen);
-
s->s->len = oldlen;
-
s->malloced = newlen;
-
}
-
}
-
-
PMOD_EXPORT void *string_builder_allocate(struct string_builder *s, ptrdiff_t chars, int mag)
-
{
-
void *ret;
-
string_build_mkspace(s, chars, mag);
-
if(chars<0) s->known_shift=0;
-
ret = s->s->str + (s->s->len<<s->s->size_shift);
-
s->s->len += chars;
-
return ret;
-
}
-
-
PMOD_EXPORT void string_builder_putchar(struct string_builder *s, int ch)
-
{
-
ptrdiff_t i;
-
enum size_shift mag = min_magnitude(ch);
-
-
string_build_mkspace(s, 1, mag);
-
if (mag > s->known_shift) {
-
s->known_shift = mag;
-
}
-
i = s->s->len++;
-
low_set_index(s->s,i,ch);
-
}
-
-
PMOD_EXPORT void string_builder_putchars(struct string_builder *s, int ch,
-
ptrdiff_t count)
-
{
-
ptrdiff_t len = s->s->len;
-
enum size_shift mag = min_magnitude(ch);
-
-
/* This is not really expected to happen. But since we are doing
-
* memset here, a negative argument should be avoided. */
-
if (count < 0)
-
Pike_fatal("Non-positive count in call to string_builder_putchars().\n");
-
if (!count) return;
-
-
string_build_mkspace(s, count, mag);
-
if (mag > s->known_shift) {
-
s->known_shift = mag;
-
}
-
-
switch (s->s->size_shift) {
-
case 0:
-
memset (STR0 (s->s) + s->s->len, ch, count);
-
break;
-
case 1: {
-
int i;
-
for (i = 0; i < count; i++)
-
(STR1 (s->s) + s->s->len)[i] = ch;
-
break;
-
}
-
case 2: {
-
int i;
-
for (i = 0; i < count; i++)
-
(STR2 (s->s) + s->s->len)[i] = ch;
-
break;
-
}
-
}
-
-
s->s->len += count;
-
}
-
-
-
PMOD_EXPORT void string_builder_binary_strcat0(struct string_builder *s,
-
const p_wchar0 *str, ptrdiff_t len)
-
{
-
string_build_mkspace(s,len,0);
-
switch(s->s->size_shift)
-
{
-
case 0: convert_0_to_0(STR0(s->s)+s->s->len,str,len); break;
-
case 1: convert_0_to_1(STR1(s->s)+s->s->len,str,len); break;
-
case 2: convert_0_to_2(STR2(s->s)+s->s->len,str,len); break;
-
}
-
s->s->len+=len;
-
}
-
-
PMOD_EXPORT void string_builder_binary_strcat1(struct string_builder *s,
-
const p_wchar1 *str, ptrdiff_t len)
-
{
-
if (s->s->size_shift == 0) {
-
if (find_magnitude1 (str, len) == 0) {
-
string_build_mkspace (s, len, 0);
-
convert_1_to_0 (STR0(s->s) + s->s->len, str, len);
-
s->s->len += len;
-
return;
-
}
-
s->known_shift = 1;
-
}
-
-
string_build_mkspace (s, len, 1);
-
if (s->s->size_shift == 1)
-
convert_1_to_1 (STR1(s->s)+s->s->len, str, len);
-
else {
-
#ifdef PIKE_DEBUG
-
if (s->s->size_shift != 2)
-
Pike_fatal ("I aint got no clue 'bout nothing, dude. (%d)\n",
-
s->s->size_shift);
-
#endif
-
convert_1_to_2 (STR2(s->s)+s->s->len, str, len);
-
}
-
s->s->len += len;
-
}
-
-
PMOD_EXPORT void string_builder_binary_strcat2(struct string_builder *s,
-
const p_wchar2 *str, ptrdiff_t len)
-
{
-
if (s->s->size_shift < 2) {
-
enum size_shift shift = find_magnitude2 (str, len);
-
-
if (shift > s->s->size_shift) {
-
string_build_mkspace (s, len, shift);
-
if (shift == 1)
-
convert_2_to_1 (STR1(s->s) + s->s->len, str, len);
-
else {
-
#ifdef PIKE_DEBUG
-
if (shift != 2) Pike_fatal ("Uhh.. Like, what? (%d)\n", shift);
-
#endif
-
convert_2_to_2 (STR2(s->s) + s->s->len, str, len);
-
}
-
s->known_shift = shift;
-
}
-
-
else {
-
string_build_mkspace (s, len, 0);
-
if (s->s->size_shift == 0)
-
convert_2_to_0 (STR0(s->s) + s->s->len, str, len);
-
else {
-
#ifdef PIKE_DEBUG
-
if (s->s->size_shift != 1)
-
Pike_fatal ("This is soo way bogus, man. (%d)\n", s->s->size_shift);
-
#endif
-
convert_2_to_1 (STR1(s->s) + s->s->len, str, len);
-
}
-
}
-
}
-
-
else {
-
string_build_mkspace (s, len, 2);
-
convert_2_to_2 (STR2(s->s) + s->s->len, str, len);
-
}
-
-
s->s->len += len;
-
}
-
-
PMOD_EXPORT void string_builder_append(struct string_builder *s,
-
const PCHARP from,
-
ptrdiff_t len)
-
{
-
enum size_shift shift = from.shift;
-
if (shift > s->s->size_shift) {
-
if (shift == 1) {
-
shift = find_magnitude1((p_wchar1 *)from.ptr, len);
-
} else {
-
shift = find_magnitude2((p_wchar2 *)from.ptr, len);
-
}
-
if (shift > s->known_shift)
-
s->known_shift = shift;
-
}
-
string_build_mkspace(s, len, shift);
-
generic_memcpy(MKPCHARP_STR_OFF(s->s,s->s->len), from, len);
-
s->s->len+=len;
-
}
-
-
PMOD_EXPORT void string_builder_fill(struct string_builder *s,
-
ptrdiff_t howmany,
-
const PCHARP from,
-
ptrdiff_t len,
-
ptrdiff_t offset)
-
{
-
ptrdiff_t tmp;
-
enum size_shift shift;
-
-
#ifdef PIKE_DEBUG
-
if(len<=0)
-
Pike_fatal("Cannot fill with zero length strings!\n");
-
#endif
-
if(howmany<=0) return;
-
-
if(!s->s->size_shift &&
-
len == 1 &&
-
(!from.shift || !min_magnitude(EXTRACT_PCHARP(from))))
-
{
-
memset(string_builder_allocate(s,howmany,0),
-
EXTRACT_PCHARP(from),
-
howmany);
-
return;
-
}
-
-
if ((shift = from.shift) > s->s->size_shift) {
-
/* Check if we really need the extra magnitude. */
-
/* FIXME: What about offset? */
-
if (shift == 1) {
-
shift = find_magnitude1((p_wchar1 *)from.ptr, len);
-
} else {
-
shift = find_magnitude2((p_wchar2 *)from.ptr, len);
-
}
-
}
-
-
string_build_mkspace(s, howmany, shift);
-
tmp = MINIMUM(howmany, len - offset);
-
-
generic_memcpy(MKPCHARP_STR_OFF(s->s,s->s->len),
-
ADD_PCHARP(from,offset),
-
tmp);
-
s->s->len+=tmp;
-
howmany-=tmp;
-
if(howmany > 0)
-
{
-
PCHARP to;
-
tmp=MINIMUM(howmany, len);
-
to=MKPCHARP_STR_OFF(s->s,s->s->len);
-
generic_memcpy(to,from, tmp);
-
s->s->len+=tmp;
-
howmany-=tmp;
-
-
while(howmany > 0)
-
{
-
tmp = MINIMUM(len, howmany);
-
memcpy(s->s->str + (s->s->len << s->s->size_shift),
-
to.ptr,
-
tmp << s->s->size_shift);
-
len+=tmp;
-
howmany-=tmp;
-
s->s->len+=tmp;
-
}
-
}
-
}
-
-
/* Append a NUL-terminated UTF16 string possibly containing surrogates. */
-
PMOD_EXPORT void string_builder_utf16_strcat(struct string_builder *s,
-
const p_wchar1 *utf16str)
-
{
-
p_wchar1 uc;
-
while ((uc = *(utf16str++))) {
-
if ((uc & 0xf800) == 0xd800) {
-
/* Surrogate. */
-
p_wchar2 wchar = uc & 0x03ff;
-
if (!(uc & 0x0400)) {
-
/* High order 10 bits. */
-
wchar <<= 10;
-
}
-
uc = *(utf16str++);
-
if (uc & 0x0400) {
-
/* Low order 10 bits. */
-
wchar |= (uc & 0x3ff);
-
} else {
-
/* High order 10 bits. */
-
wchar |= (uc & 0x3ff) << 10;
-
}
-
string_builder_putchar(s, wchar + 0x00010000);
-
} else {
-
string_builder_putchar(s, uc);
-
}
-
}
-
}
-
-
PMOD_EXPORT void string_builder_strcat(struct string_builder *s, const char *str)
-
{
-
string_builder_binary_strcat(s,str,strlen(str));
-
}
-
-
PMOD_EXPORT void string_builder_shared_strcat(struct string_builder *s,
-
const struct pike_string *str)
-
{
-
string_build_mkspace(s,str->len,str->size_shift);
-
-
pike_string_cpy(MKPCHARP_STR_OFF(s->s,s->s->len), str);
-
s->known_shift=MAXIMUM(s->known_shift,str->size_shift);
-
s->s->len+=str->len;
-
}
-
-
PMOD_EXPORT ptrdiff_t string_builder_quote_string(struct string_builder *buf,
-
const struct pike_string *str,
-
ptrdiff_t i,
-
ptrdiff_t max_len,
-
int flags)
-
{
-
ptrdiff_t old_len = buf->s->len;
-
int inhibit_whitespace = (flags & QUOTE_NORMALIZE_WS);
-
-
for (; i < str->len; i++) {
-
p_wchar2 ch = index_shared_string(str, i);
-
if (ch < 0 || ch > 0xffff) {
-
/* Huge character. */
-
string_builder_binary_strcat(buf, "\\U", 2);
-
string_builder_append_integer(buf, (unsigned INT32)ch, 16, APPEND_ZERO_PAD, 8, 8);
-
inhibit_whitespace = 0;
-
} else if (ch > 0xff) {
-
/* Unicode character. */
-
string_builder_binary_strcat(buf, "\\u", 2);
-
string_builder_append_integer(buf, ch, 16, APPEND_ZERO_PAD, 4, 4);
-
inhibit_whitespace = 0;
-
} else if (ch & 0x60) {
-
/* Printable character or DEL. */
-
if (ch == '\177' || ch == ' ') {
-
/* DEL or SP */
-
goto ctrl_char;
-
}
-
-
inhibit_whitespace = 0;
-
-
if ((ch == '"') || (ch == '\\')) {
-
string_builder_putchar(buf, '\\');
-
}
-
string_builder_putchar(buf, ch);
-
} else {
-
p_wchar2 next_ch;
-
ctrl_char:
-
/* Control character or whitespace. */
-
if (flags & QUOTE_NORMALIZE_WS) {
-
/* Normalize all sequences of whitespace to a single SP. */
-
if (!inhibit_whitespace) {
-
string_builder_putchar(buf, ' ');
-
inhibit_whitespace = 1;
-
}
-
goto next;
-
}
-
string_builder_putchar(buf, '\\');
-
if ((ch > 6) && (ch < 14)) {
-
string_builder_putchar(buf, "0123456abtnvfr"[ch]);
-
if ((ch == 10) && (flags & QUOTE_BREAK_AT_LF)) {
-
if (buf->s->len > max_len) {
-
/* Too bad; no place for the lf. */
-
buf->s->len = old_len;
-
return i;
-
}
-
return i+1;
-
}
-
goto next;
-
}
-
if (ch == 27) {
-
string_builder_putchar(buf, 'e');
-
goto next;
-
}
-
/* Check if we can use an octal escape. */
-
if ((i+1 < str->len) &&
-
((next_ch = index_shared_string(str, i+1)) >= '0') &&
-
(next_ch <= '7')) {
-
/* No. */
-
if (flags & QUOTE_NO_STRING_CONCAT) {
-
string_builder_putchar(buf, 'u');
-
string_builder_append_integer(buf, ch, 16, APPEND_ZERO_PAD, 4, 4);
-
} else {
-
string_builder_append_integer(buf, ch, 8, 0, 1, 1);
-
string_builder_binary_strcat(buf, "\"\"", 2);
-
}
-
goto next;
-
}
-
string_builder_append_integer(buf, ch, 8, 0, 1, 1);
-
}
-
next:
-
if (buf->s->len > max_len) {
-
buf->s->len = old_len;
-
inhibit_whitespace = 0;
-
break;
-
}
-
old_len = buf->s->len;
-
}
-
if (inhibit_whitespace && (inhibit_whitespace != QUOTE_NORMALIZE_WS)) {
-
/* Get rid of the SP at the end of the buffer. */
-
buf->s->len--;
-
}
-
return i;
-
}
-
-
PMOD_EXPORT void string_builder_append_integer(struct string_builder *s,
-
INT64 val,
-
unsigned int base,
-
int flags,
-
size_t min_width,
-
size_t precision)
-
{
-
unsigned INT64 tmp;
-
size_t len = 1;
-
const char *numbers = "0123456789abcdef";
-
if ((base < 2) || (base > 16)) {
-
Pike_fatal("string_builder_append_int(): Unsupported base %u.\n", base);
-
}
-
if (flags & APPEND_UPPER_CASE) {
-
numbers = "0123456789ABCDEF";
-
}
-
if ((flags & APPEND_SIGNED) && (val < 0)) {
-
string_builder_putchar(s, '-');
-
val = -val;
-
} else if (flags & APPEND_POSITIVE) {
-
string_builder_putchar(s, '+');
-
}
-
if ((flags & APPEND_ZERO_PAD) && (precision < min_width)) {
-
precision = min_width;
-
}
-
-
tmp = val;
-
if (base & (base - 1)) {
-
size_t cnt;
-
/* Calculate the output length.
-
* Use do-while to ensure that zero isn't output as an empty string.
-
*/
-
len = 0;
-
do {
-
len++;
-
tmp /= base;
-
} while (tmp);
-
-
/* Precision is minimum number of digits. */
-
if (len < precision) len = precision;
-
-
/* Perform padding. */
-
if (!(flags & APPEND_LEFT)) {
-
if (len < min_width) {
-
string_builder_fill(s, min_width - len, MKPCHARP(" ", 0),
-
4, 0);
-
}
-
min_width = 0;
-
}
-
-
cnt = len;
-
-
tmp = val;
-
switch(s->s->size_shift) {
-
case 0:
-
{
-
p_wchar0 *p = string_builder_allocate(s, len, 0);
-
do {
-
p[--cnt] = numbers[tmp%base];
-
tmp /= base;
-
} while (cnt);
-
}
-
break;
-
case 1:
-
{
-
p_wchar1 *p = string_builder_allocate(s, len, 0);
-
do {
-
p[--cnt] = numbers[tmp%base];
-
tmp /= base;
-
} while (cnt);
-
}
-
break;
-
case 2:
-
{
-
p_wchar2 *p = string_builder_allocate(s, len, 0);
-
do {
-
p[--cnt] = numbers[tmp%base];
-
tmp /= base;
-
} while (cnt);
-
}
-
break;
-
}
-
} else {
-
/* base is a power of two, so we can do without
-
* the division and modulo operations.
-
*/
-
int delta;
-
size_t shift;
-
unsigned int mask;
-
-
for(delta = 1; (base>>delta) > 1; delta++)
-
;
-
-
mask = (1<<delta)-1; /* Usually base-1. */
-
-
/* Precision is minimum number of digits. */
-
if (precision) shift = (len = precision) * delta;
-
else shift = delta;
-
-
/* Calculate actual number of digits and initial shift. */
-
for (; shift < SIZEOF_INT64 * 8 && tmp >> shift; shift += delta, len++)
-
;
-
-
if ((len < min_width) && !(flags & APPEND_LEFT)) {
-
/* Perform padding.
-
* Note that APPEND_ZERO_PAD can not be active here, since
-
* len is at least min_width in that case.
-
*/
-
string_builder_fill(s, min_width - len, MKPCHARP(" ", 0),
-
4, 0);
-
min_width = 0;
-
}
-
-
while(shift) {
-
shift -= delta;
-
string_builder_putchar(s, numbers[(tmp>>shift) & mask]);
-
}
-
}
-
if (len < min_width) {
-
/* Perform padding.
-
* Note that APPEND_ZERO_PAD can not be active here, since
-
* len is at least min_width in that case.
-
* Note that APPEND_LEFT is always active here, since
-
* min_width isn't zero.
-
*/
-
string_builder_fill(s, min_width - len, MKPCHARP(" ", 0),
-
4, 0);
-
}
-
}
-
-
/* Kludge around brokeness of gcc/x86_64 */
-
#ifdef VA_LIST_IS_STATE_PTR
-
#define VA_LIST_PTR va_list
-
#define VA_LIST_ADDR(X) (X)
-
#define VA_LIST_DEREF(X) (X)
-
#else
-
#define VA_LIST_PTR va_list *
-
#define VA_LIST_ADDR(X) (&(X))
-
#define VA_LIST_DEREF(X) (*(X))
-
#endif
-
-
static INT64 pike_va_int(VA_LIST_PTR args, int flags)
-
{
-
switch (flags & (APPEND_WIDTH_MASK|APPEND_SIGNED)) {
-
case APPEND_WIDTH_HALF:
-
return va_arg(VA_LIST_DEREF(args), unsigned int) & 0xffff;
-
case APPEND_WIDTH_HALF|APPEND_SIGNED:
-
return (short)va_arg(VA_LIST_DEREF(args), int);
-
case 0:
-
return va_arg(VA_LIST_DEREF(args), unsigned int);
-
case APPEND_SIGNED:
-
return va_arg(VA_LIST_DEREF(args), int);
-
case APPEND_WIDTH_LONG:
-
return va_arg(VA_LIST_DEREF(args), unsigned long);
-
case APPEND_WIDTH_LONG|APPEND_SIGNED:
-
return va_arg(VA_LIST_DEREF(args), long);
-
case APPEND_WIDTH_LONG_LONG:
-
return va_arg(VA_LIST_DEREF(args), UINT64);
-
case APPEND_WIDTH_LONG_LONG|APPEND_SIGNED:
-
return va_arg(VA_LIST_DEREF(args), INT64);
-
}
-
Pike_fatal("string_builder_append_integerv(): Unsupported flags: 0x%04x\n",
-
flags);
-
UNREACHABLE(return 0);
-
}
-
-
/* Standard formats supported by string_builder_{v,}sprintf():
-
*
-
* '%' Insert %.
-
* 'a' Insert double.
-
* 'c' Insert character.
-
* 'd' Insert decimal integer.
-
* 'e' Insert double.
-
* 'f' Insert double.
-
* 'g' Insert double.
-
* 'o' Insert octal integer.
-
* 's' Insert string.
-
* 'u' Insert unsigned decimal integer.
-
* 'x' Insert lower-case hexadecimal integer.
-
* 'E' Insert double.
-
* 'G' Insert double.
-
* 'X' Insert upper-case hexadecimal integer.
-
*
-
* Format modifiers supported by string_builder_{v,}sprintf():
-
*
-
* '+' Explicit sign for non-negative numeric values.
-
* '-' Align left.
-
* '0' Zero pad.
-
* '0'..'9' Field width.
-
* '.' Precision field width follows.
-
* 'h' Half-width input.
-
* 'l' Long(-er) input.
-
* 't' Pointer-width input (ptrdiff_t).
-
* 'w' Wide input (same as 'l', but only for strings).
-
* 'z' Pointer-width input (size_t).
-
*
-
* Extended formats supported by string_builder_{v,}sprintf():
-
*
-
* 'b' Insert binary integer.
-
* 'O' Insert description of svalue.
-
* 'S' Insert pike_string.
-
* 'T' Insert pike_type.
-
*/
-
-
/* Values used internally in string_builder_vsprintf() */
-
#define STATE_MIN_WIDTH 1
-
#define STATE_PRECISION 2
-
-
PMOD_EXPORT void string_builder_vsprintf(struct string_builder *s,
-
const char *fmt,
-
va_list args)
-
{
-
while (*fmt) {
-
if (*fmt == '%') {
-
int flags = 0;
-
size_t min_width = 0;
-
size_t precision = 0;
-
int state = 0;
-
-
fmt++;
-
while (1) {
-
switch (*(fmt++)) {
-
case '%':
-
string_builder_putchar(s, '%');
-
break;
-
-
case '+':
-
flags |= APPEND_POSITIVE;
-
continue;
-
case '-':
-
flags |= APPEND_LEFT;
-
continue;
-
-
case '0':
-
if (!state) {
-
flags |= APPEND_ZERO_PAD;
-
}
-
/* FALL_THROUGH */
-
case '1': case '2': case '3':
-
case '4': case '5': case '6':
-
case '7': case '8': case '9':
-
if (state == STATE_PRECISION) {
-
precision = precision * 10 + fmt[-1] - '0';
-
} else {
-
state = STATE_MIN_WIDTH;
-
min_width = min_width * 10 + fmt[-1] - '0';
-
}
-
continue;
-
-
case '*':
-
if (state == STATE_PRECISION) {
-
precision = va_arg(args, int);
-
} else {
-
state = STATE_MIN_WIDTH;
-
min_width = va_arg(args, int);
-
}
-
continue;
-
-
case '.':
-
state = STATE_PRECISION;
-
continue;
-
-
case 'h':
-
flags |= APPEND_WIDTH_HALF;
-
continue;
-
-
case 'w': /* Same as l, but old-style, and only for %s. */
-
case 'l':
-
if (flags & APPEND_WIDTH_LONG) {
-
flags |= APPEND_WIDTH_LONG_LONG;
-
} else {
-
flags |= APPEND_WIDTH_LONG;
-
}
-
continue;
-
-
case 't': /* ptrdiff_t */
-
case 'z': /* size_t */
-
flags = (flags & ~APPEND_WIDTH_MASK) | APPEND_WIDTH_PTR;
-
continue;
-
-
case 'T': /* struct pike_type */
-
/* FIXME: Doesn't care about field or integer widths yet. */
-
low_describe_type(s, va_arg(args, struct pike_type *));
-
break;
-
-
case 'O':
-
{
-
/* FIXME: Doesn't care about field or integer widths yet. */
-
struct byte_buffer buf = BUFFER_INIT();
-
describe_svalue(&buf, va_arg(args, struct svalue *), 0, NULL);
-
string_builder_binary_strcat(s, buffer_ptr(&buf), buffer_content_length(&buf));
-
buffer_free(&buf);
-
}
-
break;
-
case 'S':
-
/* Note: On some platforms this is an alias for %ls, so if you
-
* want to output wchar_t strings, use %ls instead!
-
*/
-
{
-
struct pike_string *str = va_arg(args, struct pike_string *);
-
size_t len = str->len;
-
if (precision && (precision < len)) len = precision;
-
if (min_width > len) {
-
if (flags & APPEND_LEFT) {
-
string_builder_append(s, MKPCHARP_STR(str), len);
-
string_builder_fill(s, min_width - len, MKPCHARP(" ", 0),
-
4, 0);
-
} else {
-
string_builder_fill(s, min_width - len, MKPCHARP(" ", 0),
-
4, 0);
-
string_builder_append(s, MKPCHARP_STR(str), len);
-
}
-
} else {
-
string_builder_append(s, MKPCHARP_STR(str), len);
-
}
-
}
-
break;
-
case 's':
-
if (flags & APPEND_WIDTH_LONG) {
-
/* Wide string: %ws, %ls or %lls
-
*/
-
PCHARP str;
-
size_t len;
-
if ((flags & APPEND_WIDTH_LONG)== APPEND_WIDTH_LONG) {
-
str = MKPCHARP(va_arg(args, p_wchar1 *), 1);
-
} else {
-
str = MKPCHARP(va_arg(args, p_wchar2 *), 2);
-
}
-
len = pcharp_strlen(str);
-
if (precision && precision < len) len = precision;
-
if (min_width > len) {
-
if (flags & APPEND_LEFT) {
-
string_builder_append(s, str, len);
-
string_builder_fill(s, min_width - len, MKPCHARP(" ", 0),
-
4, 0);
-
} else {
-
string_builder_fill(s, min_width - len, MKPCHARP(" ", 0),
-
4, 0);
-
string_builder_append(s, str, len);
-
}
-
} else {
-
string_builder_append(s, str, len);
-
}
-
} else {
-
const char *str = va_arg(args, char *);
-
size_t len = strlen(str);
-
if (precision && precision < len) len = precision;
-
if (min_width > len) {
-
if (flags & APPEND_LEFT) {
-
string_builder_binary_strcat(s, str, len);
-
string_builder_fill(s, min_width - len, MKPCHARP(" ", 0),
-
4, 0);
-
} else {
-
string_builder_fill(s, min_width - len, MKPCHARP(" ", 0),
-
4, 0);
-
string_builder_binary_strcat(s, str, len);
-
}
-
} else {
-
string_builder_binary_strcat(s, str, len);
-
}
-
}
-
break;
-
case 'c':
-
/* FIXME: Doesn't care about field or integer widths yet. */
-
string_builder_putchar(s, va_arg(args, int));
-
break;
-
case 'b':
-
string_builder_append_integer(s, pike_va_int(VA_LIST_ADDR(args), flags), 2,
-
flags, min_width, precision);
-
break;
-
case 'o':
-
string_builder_append_integer(s, pike_va_int(VA_LIST_ADDR(args), flags), 8,
-
flags, min_width, precision);
-
break;
-
case 'x':
-
string_builder_append_integer(s, pike_va_int(VA_LIST_ADDR(args), flags), 16,
-
flags, min_width, precision);
-
break;
-
case 'X':
-
string_builder_append_integer(s, pike_va_int(VA_LIST_ADDR(args), flags), 16,
-
flags | APPEND_UPPER_CASE,
-
min_width, precision);
-
break;
-
case 'u':
-
string_builder_append_integer(s, pike_va_int(VA_LIST_ADDR(args), flags), 10,
-
flags, min_width, precision);
-
break;
-
case 'd':
-
flags |= APPEND_SIGNED;
-
string_builder_append_integer(s, pike_va_int(VA_LIST_ADDR(args), flags), 10,
-
flags, min_width, precision);
-
break;
-
-
/* %f used in modules/Image/colors.c. */
-
case 'a':
-
case 'e':
-
case 'E':
-
case 'f':
-
case 'g':
-
case 'G':
-
{
-
double val = va_arg(args, double);
-
size_t bytes;
-
char nfmt[] = { '%', fmt[-1], 0 };
-
-
if (PIKE_ISNAN(val)) {
-
/* NaN */
-
string_builder_strcat(s, "nan");
-
break;
-
}
-
if (val < 0.0) {
-
string_builder_putchar(s, '-');
-
val = -val;
-
} else if (flags & APPEND_POSITIVE) {
-
string_builder_putchar(s, '+');
-
}
-
if (PIKE_ISINF(val)) {
-
/* Infinity */
-
string_builder_strcat(s, "inf");
-
break;
-
}
-
/* FIXME: Field lengths and precision. */
-
if ((bytes = snprintf(NULL, 0, nfmt, val))) {
-
p_wchar0 *p = string_builder_allocate(s, bytes, 0);
-
size_t check = snprintf((char*)p, bytes+1, nfmt, val);
-
if (check != bytes) {
-
Pike_fatal("string_builder_vsprintf(): snprintf(\"%s\", %f) "
-
"is not trustworthy: "
-
"%"PRINTSIZET"u != %"PRINTSIZET"u\n",
-
nfmt, val, bytes, check);
-
}
-
if (s->s->size_shift) {
-
/* We need to widen the string we just wrote. */
-
if (s->s->size_shift == 1) {
-
p_wchar1 *p1 = (p_wchar1 *)p;
-
while (bytes--) {
-
p1[bytes] = p[bytes];
-
}
-
} else {
-
p_wchar2 *p2 = (p_wchar2 *)p;
-
while (bytes--) {
-
p2[bytes] = p[bytes];
-
}
-
}
-
}
-
}
-
}
-
break;
-
-
default:
-
Pike_fatal("string_builder_vsprintf(): Invalid formatting method: "
-
"\"%%%c\" 0x%x.\n", (fmt[-1] & 0xff), fmt[-1]);
-
}
-
break;
-
}
-
} else {
-
const char *start = fmt;
-
while (*fmt && (*fmt != '%'))
-
fmt++;
-
string_builder_binary_strcat(s, start, fmt-start);
-
}
-
}
-
}
-
-
-
PMOD_EXPORT void string_builder_sprintf(struct string_builder *s,
-
const char *fmt, ...)
-
{
-
va_list args;
-
va_start(args, fmt);
-
string_builder_vsprintf(s, fmt, args);
-
va_end(args);
-
}
-
-
-
PMOD_EXPORT void reset_string_builder(struct string_builder *s)
-
{
-
s->known_shift=0;
-
s->s->len=0;
-
}
-
-
PMOD_EXPORT void free_string_builder(struct string_builder *s)
-
{
-
s->s->len = s->malloced;
-
free_string(s->s);
-
}
-
-
PMOD_EXPORT struct pike_string *finish_string_builder(struct string_builder *s)
-
{
-
ptrdiff_t len = s->s->len;
-
if (len != s->malloced) {
-
s->s->len = s->malloced; /* Restore the allocated length. */
-
s->s = realloc_unlinked_string(s->s, len);
-
}
-
if(s->known_shift == s->s->size_shift)
-
return low_end_shared_string(s->s);
-
return end_shared_string(s->s);
-
}
-
+
PMOD_EXPORT PCHARP MEMCHR_PCHARP(const PCHARP ptr, int chr, ptrdiff_t len) { switch(ptr.shift)