pike.git / src / string_builder.c

version» Context lines:

pike.git/src/string_builder.c:1: - /* - || This file is part of Pike. For copyright information see COPYRIGHT. - || Pike is distributed under GPL, LGPL and MPL. See the file COPYING - || for more information. - */ +     - #include "global.h" - #include "stralloc.h" - #include "string_builder.h" - #include "pike_macros.h" - #include "buffer.h" - #include "pike_macros.h" - #include "pike_memory.h" - #include "pike_error.h" - #include "gc.h" - #include "bignum.h" - #include "interpret.h" - #include "operators.h" - #include "pike_float.h" - #include "pike_types.h" - #include "block_allocator.h" - #include "whitespace.h" - #include "stuff.h" -  - #include <errno.h> -  - 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); - } +    Newline at end of file removed.