strfuncs.c revision d2f5aacd3d549c3d39dae41b6522d585244b016d
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen/*
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen strfuncs.c : String manipulation functions (note: LGPL, because the )
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen Copyright (C) 2001-2002 Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen printf_string_upper_bound() code is taken from GLIB:
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen Modified by the GLib Team and others 1997-1999.
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen This library is free software; you can redistribute it and/or
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen modify it under the terms of the GNU Library General Public
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen License as published by the Free Software Foundation; either
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen version 2 of the License, or (at your option) any later version.
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen This library is distributed in the hope that it will be useful,
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen but WITHOUT ANY WARRANTY; without even the implied warranty of
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen Library General Public License for more details.
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen You should have received a copy of the GNU Library General Public
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen License along with this library; if not, write to the
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen Free Software Foundation, Inc., 59 Temple Place - Suite 330,
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen Boston, MA 02111-1307, USA.
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen*/
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#include "lib.h"
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#include "strfuncs.h"
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#include <stdio.h>
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#include <limits.h>
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#include <ctype.h>
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#define STRCONCAT_BUFSIZE 512
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainentypedef void *(*ALLOC_FUNC)(Pool, size_t);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainenstatic void *tp_malloc(Pool pool __attr_unused__, size_t size)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen{
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen return t_malloc(size);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen}
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainentypedef union _GDoubleIEEE754 GDoubleIEEE754;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#define G_IEEE754_DOUBLE_BIAS (1023)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen/* multiply with base2 exponent to get base10 exponent (nomal numbers) */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#define G_LOG_2_BASE_10 (0.30102999566398119521)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#if G_BYTE_ORDER == G_LITTLE_ENDIAN
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainenunion _GDoubleIEEE754
bbd51f171bb2f4abd437910c720579a4eaf65c85Sergey Kitov{
bbd51f171bb2f4abd437910c720579a4eaf65c85Sergey Kitov double v_double;
bbd51f171bb2f4abd437910c720579a4eaf65c85Sergey Kitov struct {
bbd51f171bb2f4abd437910c720579a4eaf65c85Sergey Kitov unsigned int mantissa_low : 32;
bbd51f171bb2f4abd437910c720579a4eaf65c85Sergey Kitov unsigned int mantissa_high : 20;
bbd51f171bb2f4abd437910c720579a4eaf65c85Sergey Kitov unsigned int biased_exponent : 11;
bbd51f171bb2f4abd437910c720579a4eaf65c85Sergey Kitov unsigned int sign : 1;
bbd51f171bb2f4abd437910c720579a4eaf65c85Sergey Kitov } mpn;
bbd51f171bb2f4abd437910c720579a4eaf65c85Sergey Kitov};
bbd51f171bb2f4abd437910c720579a4eaf65c85Sergey Kitov#elif G_BYTE_ORDER == G_BIG_ENDIAN
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainenunion _GDoubleIEEE754
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen{
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen double v_double;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen struct {
bbd51f171bb2f4abd437910c720579a4eaf65c85Sergey Kitov unsigned int sign : 1;
bbd51f171bb2f4abd437910c720579a4eaf65c85Sergey Kitov unsigned int biased_exponent : 11;
bbd51f171bb2f4abd437910c720579a4eaf65c85Sergey Kitov unsigned int mantissa_high : 20;
bbd51f171bb2f4abd437910c720579a4eaf65c85Sergey Kitov unsigned int mantissa_low : 32;
bbd51f171bb2f4abd437910c720579a4eaf65c85Sergey Kitov } mpn;
bbd51f171bb2f4abd437910c720579a4eaf65c85Sergey Kitov};
bbd51f171bb2f4abd437910c720579a4eaf65c85Sergey Kitov#else /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
bbd51f171bb2f4abd437910c720579a4eaf65c85Sergey Kitov#error unknown ENDIAN type
bbd51f171bb2f4abd437910c720579a4eaf65c85Sergey Kitov#endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
bbd51f171bb2f4abd437910c720579a4eaf65c85Sergey Kitov
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainentypedef struct
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen{
3abc26e06e053228d283503a8583657dfca0f2e0Timo Sirainen unsigned int min_width;
3abc26e06e053228d283503a8583657dfca0f2e0Timo Sirainen unsigned int precision;
3abc26e06e053228d283503a8583657dfca0f2e0Timo Sirainen int alternate_format, zero_padding, adjust_left, locale_grouping;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen int add_space, add_sign, possible_sign, seen_precision;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen int mod_half, mod_long, mod_extra_long;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen} PrintfArgSpec;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#if (SIZEOF_LONG > 4) || (SIZEOF_VOID_P > 4)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen# define HONOUR_LONGS 1
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#else
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen# define HONOUR_LONGS 0
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#endif
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainensize_t printf_string_upper_bound(const char *format, va_list args)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen{
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen size_t len = 1;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen if (!format)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen return len;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen while (*format)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen {
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen register char c = *format++;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen if (c != '%')
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen len += 1;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen else /* (c == '%') */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen {
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen PrintfArgSpec spec;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen int seen_l = FALSE, conv_done = FALSE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen unsigned int conv_len = 0;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen const char *spec_start = format;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen memset(&spec, 0, sizeof(spec));
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen do
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen {
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen c = *format++;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen switch (c)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen {
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen GDoubleIEEE754 u_double;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen unsigned int v_uint;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen int v_int;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen const char *v_string;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* beware of positional parameters
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case '$':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen i_warning (GNUC_PRETTY_FUNCTION
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen "(): unable to handle positional parameters (%%n$)");
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen len += 1024; /* try adding some safety padding */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* parse flags
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case '#':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.alternate_format = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case '0':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.zero_padding = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case '-':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.adjust_left = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case ' ':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.add_space = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case '+':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.add_sign = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case '\'':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.locale_grouping = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* parse output size specifications
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case '.':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.seen_precision = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case '1':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case '2':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case '3':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case '4':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case '5':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case '6':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case '7':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case '8':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case '9':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen v_uint = c - '0';
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen c = *format;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen while (c >= '0' && c <= '9')
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen {
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen format++;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen v_uint = v_uint * 10 + (c - '0');
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen c = *format;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen }
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen if (spec.seen_precision)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.precision = I_MAX (spec.precision, v_uint);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen else
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.min_width = I_MAX (spec.min_width, v_uint);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case '*':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen v_int = va_arg (args, int);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen if (spec.seen_precision)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen {
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* forget about negative precision */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen if (v_int >= 0)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.precision = I_MAX ((int)spec.precision, v_int);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen }
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen else
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen {
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen if (v_int < 0)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen {
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen v_int = - v_int;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.adjust_left = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen }
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.min_width = I_MAX ((int)spec.min_width, v_int);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen }
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* parse type modifiers
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'h':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.mod_half = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'l':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen if (!seen_l)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen {
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.mod_long = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen seen_l = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen }
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* else, fall through */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'L':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'q':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.mod_long = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.mod_extra_long = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'z':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'Z':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#if GLIB_SIZEOF_SIZE_T > 4
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.mod_long = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.mod_extra_long = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#endif /* GLIB_SIZEOF_SIZE_T > 4 */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 't':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#if GLIB_SIZEOF_PTRDIFF_T > 4
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.mod_long = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.mod_extra_long = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#endif /* GLIB_SIZEOF_PTRDIFF_T > 4 */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'j':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#if GLIB_SIZEOF_INTMAX_T > 4
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.mod_long = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.mod_extra_long = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#endif /* GLIB_SIZEOF_INTMAX_T > 4 */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* parse output conversions
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case '%':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_len += 1;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'O':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'D':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'I':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'U':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* some C libraries feature long variants for these as well? */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.mod_long = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* fall through */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'o':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_len += 2;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* fall through */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'd':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'i':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_len += 1; /* sign */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* fall through */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'u':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_len += 4;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* fall through */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'x':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'X':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.possible_sign = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_len += 10;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen if (spec.mod_long && HONOUR_LONGS)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_len *= 2;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen if (spec.mod_extra_long)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_len *= 2;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen if (spec.mod_extra_long)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen {
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#ifdef G_HAVE_GINT64
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen (void) va_arg (args, gint64);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#else
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen (void) va_arg (args, long);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#endif
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen }
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen else if (spec.mod_long)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen (void) va_arg (args, long);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen else
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen (void) va_arg (args, int);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'A':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'a':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* 0x */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_len += 2;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* fall through */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'g':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'G':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'e':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'E':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'f':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.possible_sign = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* n . dddddddddddddddddddddddd E +- eeee */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_len += 1 + 1 + I_MAX (24, spec.precision) + 1 + 1 + 4;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen if (spec.mod_extra_long)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen i_warning (GNUC_PRETTY_FUNCTION
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen "(): unable to handle long double, collecting double only");
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#ifdef HAVE_LONG_DOUBLE
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#error need to implement special handling for long double
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#endif
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen u_double.v_double = va_arg (args, double);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* %f can expand up to all significant digits before '.' (308) */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen if (c == 'f' &&
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen u_double.mpn.biased_exponent > 0 && u_double.mpn.biased_exponent < 2047)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen {
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen int exp = u_double.mpn.biased_exponent;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen exp -= G_IEEE754_DOUBLE_BIAS;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen exp = exp * G_LOG_2_BASE_10 + 1;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_len += exp;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen }
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* some printf() implementations require extra padding for rounding */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_len += 2;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* we can't really handle locale specific grouping here */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen if (spec.locale_grouping)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_len *= 2;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'C':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.mod_long = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* fall through */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'c':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_len += spec.mod_long ? MB_LEN_MAX : 1;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen (void) va_arg (args, int);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'S':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.mod_long = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* fall through */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 's':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen v_string = va_arg (args, char*);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen if (!v_string)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_len += 8; /* hold "(null)" */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen else if (spec.seen_precision)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_len += spec.precision;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen else
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_len += strlen (v_string);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_done = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen if (spec.mod_long)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen {
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen i_warning (GNUC_PRETTY_FUNCTION
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen "(): unable to handle wide char strings");
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen len += 1024; /* try adding some safety padding */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen }
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'P': /* do we actually need this? */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* fall through */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'p':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen spec.alternate_format = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_len += 10;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen if (HONOUR_LONGS)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_len *= 2;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* fall through */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'n':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_done = TRUE;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen (void) va_arg (args, void*);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case 'm':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* there's not much we can do to be clever */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen v_string = strerror (errno);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen v_uint = v_string ? strlen (v_string) : 0;
dee1520b5166708bd8dd4230c279c950bf01029aTimo Sirainen conv_len += I_MAX (256, v_uint);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* handle invalid cases
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen case '\000':
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* no conversion specification, bad bad */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_len += format - spec_start;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen default:
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen i_warning (GNUC_PRETTY_FUNCTION
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen "(): unable to handle `%c' while parsing format",
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen c);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen break;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen }
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_done |= conv_len > 0;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen }
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen while (!conv_done);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* handle width specifications */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_len = I_MAX (conv_len, I_MAX (spec.precision, spec.min_width));
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* handle flags */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen conv_len += spec.alternate_format ? 2 : 0;
dee1520b5166708bd8dd4230c279c950bf01029aTimo Sirainen conv_len += (spec.add_space || spec.add_sign || spec.possible_sign);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* finally done */
dee1520b5166708bd8dd4230c279c950bf01029aTimo Sirainen len += conv_len;
dee1520b5166708bd8dd4230c279c950bf01029aTimo Sirainen } /* else (c == '%') */
dee1520b5166708bd8dd4230c279c950bf01029aTimo Sirainen } /* while (*format) */
dee1520b5166708bd8dd4230c279c950bf01029aTimo Sirainen
dee1520b5166708bd8dd4230c279c950bf01029aTimo Sirainen return len;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen}
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainenstatic const char *fix_format_real(const char *fmt, const char *p)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen{
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen const char *errstr;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen char *buf;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen size_t pos, alloc, errlen;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen errstr = strerror(errno);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen errlen = strlen(errstr);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen pos = (size_t) (p-fmt);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen i_assert(pos < SSIZE_T_MAX);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen alloc = pos + errlen + 128;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen buf = t_buffer_get(alloc);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen memcpy(buf, fmt, pos);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen while (*p != '\0') {
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen if (*p == '%' && p[1] == 'm') {
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen if (pos+errlen+1 > alloc) {
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen alloc += errlen+1 + 128;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen buf = t_buffer_get(alloc);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen }
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen memcpy(buf+pos, errstr, errlen);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen pos += errlen;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen p += 2;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen } else {
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen /* p + \0 */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen if (pos+2 > alloc) {
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen alloc += 128;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen buf = t_buffer_get(alloc);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen }
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen buf[pos++] = *p;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen p++;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen }
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen }
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen buf[pos++] = '\0';
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen t_buffer_alloc(pos);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen return buf;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen}
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen/* replace %m with strerror() */
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainenstatic const char *fix_format(const char *fmt)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen{
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen const char *p;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen for (p = fmt; *p != '\0'; p++) {
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen if (*p == '%' && p[1] == 'm')
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen return fix_format_real(fmt, p);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen }
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen return fmt;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen}
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainenint i_snprintf(char *str, size_t max_chars, const char *format, ...)
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen{
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen#ifdef HAVE_VSNPRINTF
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen va_list args;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen int ret;
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen i_assert(str != NULL);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen i_assert(max_chars < SSIZE_T_MAX);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen i_assert(format != NULL);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen va_start(args, format);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen ret = vsnprintf(str, max_chars, fix_format(format), args);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen va_end(args);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen if (ret < 0) {
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen str[max_chars-1] = '\0';
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen ret = strlen(str);
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen }
654c60f1741fd195878d74a30df90bf130649d64Timo Sirainen
return ret;
#else
char *buf;
va_list args;
int len;
i_assert(str != NULL);
i_assert(max_chars < SSIZE_T_MAX);
i_assert(format != NULL);
va_start(args, format);
format = fix_format(format);
buf = t_buffer_get(printf_string_upper_bound(format, args));
va_end(args);
len = vsprintf(buf, format, args);
if (len >= (int)max_chars)
len = max_chars-1;
memcpy(str, buf, len);
str[len] = '\0';
return len;
#endif
}
#define STRDUP_CORE(alloc_func, str) STMT_START { \
void *mem; \
size_t len; \
\
for (len = 0; (str)[len] != '\0'; ) \
len++; \
len++; \
mem = alloc_func; \
memcpy(mem, str, sizeof(str[0])*len); \
return mem; \
} STMT_END
char *p_strdup(Pool pool, const char *str)
{
if (str == NULL)
return NULL;
STRDUP_CORE(p_malloc(pool, len), str);
}
const char *t_strdup(const char *str)
{
if (str == NULL)
return NULL;
STRDUP_CORE(t_malloc(len), str);
}
char *t_strdup_noconst(const char *str)
{
if (str == NULL)
return NULL;
STRDUP_CORE(t_malloc(len), str);
}
int *p_intarrdup(Pool pool, const int *arr)
{
if (arr == NULL)
return NULL;
STRDUP_CORE(p_malloc(pool, sizeof(int) * len), arr);
}
const int *t_intarrdup(const int *arr)
{
if (arr == NULL)
return NULL;
STRDUP_CORE(t_malloc(sizeof(int) * len), arr);
}
#define STRDUP_EMPTY_CORE(alloc_func, str) STMT_START { \
if ((str) == NULL || (str)[0] == '\0') \
return NULL; \
\
STRDUP_CORE(alloc_func, str); \
} STMT_END
char *p_strdup_empty(Pool pool, const char *str)
{
STRDUP_EMPTY_CORE(p_malloc(pool, len), str);
}
const char *t_strdup_empty(const char *str)
{
STRDUP_EMPTY_CORE(t_malloc(len), str);
}
char *p_strdup_until(Pool pool, const char *start, const char *end)
{
size_t size;
char *mem;
i_assert(start <= end);
size = (size_t) (end-start);
i_assert(size < SSIZE_T_MAX);
mem = p_malloc(pool, size + 1);
memcpy(mem, start, size);
return mem;
}
const char *t_strdup_until(const char *start, const char *end)
{
size_t size;
char *mem;
i_assert(start <= end);
size = (size_t) (end-start);
i_assert(size < SSIZE_T_MAX);
mem = t_malloc(size + 1);
memcpy(mem, start, size);
mem[size] = '\0';
return mem;
}
static inline char *strndup_core(const char *str, size_t max_chars,
ALLOC_FUNC alloc, Pool pool)
{
char *mem;
size_t len;
i_assert(max_chars < SSIZE_T_MAX);
if (str == NULL)
return NULL;
len = 0;
while (str[len] != '\0' && len < max_chars)
len++;
mem = alloc(pool, len+1);
memcpy(mem, str, len);
mem[len] = '\0';
return mem;
}
char *p_strndup(Pool pool, const char *str, size_t max_chars)
{
return strndup_core(str, max_chars, pool->malloc, pool);
}
const char *t_strndup(const char *str, size_t max_chars)
{
return strndup_core(str, max_chars, tp_malloc, NULL);
}
char *p_strdup_printf(Pool pool, const char *format, ...)
{
va_list args;
char *ret;
va_start(args, format);
ret = p_strdup_vprintf(pool, format, args);
va_end(args);
return ret;
}
const char *t_strdup_printf(const char *format, ...)
{
va_list args;
const char *ret;
va_start(args, format);
ret = t_strdup_vprintf(format, args);
va_end(args);
return ret;
}
static inline char *
strdup_vprintf_core(const char *format, va_list args,
ALLOC_FUNC alloc_func, Pool pool)
{
va_list temp_args;
char *ret;
if (format == NULL)
return NULL;
format = fix_format(format);
VA_COPY(temp_args, args);
ret = alloc_func(pool, printf_string_upper_bound(format, args));
vsprintf(ret, format, args);
va_end(temp_args);
return ret;
}
char *p_strdup_vprintf(Pool pool, const char *format, va_list args)
{
return strdup_vprintf_core(format, args, pool->malloc, pool);
}
const char *t_strdup_vprintf(const char *format, va_list args)
{
return strdup_vprintf_core(format, args, tp_malloc, NULL);
}
void p_strdup_replace(Pool pool, char **dest, const char *str)
{
p_free(pool, *dest);
*dest = p_strdup(pool, str);
}
const char *temp_strconcat(const char *str1, va_list args,
size_t *ret_len)
{
const char *str;
char *temp;
size_t full_len, len, bufsize;
if (str1 == NULL)
return NULL;
/* put str1 to buffer */
len = strlen(str1);
bufsize = len <= STRCONCAT_BUFSIZE ? STRCONCAT_BUFSIZE :
nearest_power(len+1);
temp = t_buffer_get(bufsize);
memcpy(temp, str1, len);
full_len = len;
/* put rest of the strings to buffer */
while ((str = va_arg(args, char *)) != NULL) {
len = strlen(str);
if (len == 0)
continue;
if (bufsize < full_len+len+1) {
bufsize = nearest_power(bufsize+len+1);
temp = t_buffer_reget(temp, bufsize);
}
memcpy(temp+full_len, str, len);
full_len += len;
}
temp[full_len] = '\0';
*ret_len = full_len+1;
return temp;
}
char *p_strconcat(Pool pool, const char *str1, ...)
{
va_list args;
const char *temp;
char *ret;
size_t len;
va_start(args, str1);
temp = temp_strconcat(str1, args, &len);
if (temp == NULL)
ret = NULL;
else {
ret = p_malloc(pool, len);
memcpy(ret, temp, len);
}
va_end(args);
return ret;
}
const char *t_strconcat(const char *str1, ...)
{
va_list args;
const char *ret;
size_t len;
va_start(args, str1);
ret = temp_strconcat(str1, args, &len);
if (ret != NULL)
t_buffer_alloc(len);
va_end(args);
return ret;
}
const char *t_strcut(const char *str, char cutchar)
{
const char *p;
for (p = str; *p != '\0'; p++) {
if (*p == cutchar)
return t_strdup_until(str, p);
}
return str;
}
int is_numeric(const char *str, char end_char)
{
if (*str == '\0' || *str == end_char)
return FALSE;
while (*str != '\0' && *str != end_char) {
if (!i_isdigit(*str))
return FALSE;
str++;
}
return TRUE;
}
char *str_ucase(char *str)
{
char *p;
for (p = str; *p != '\0'; p++)
*p = i_toupper(*p);
return str;
}
char *str_lcase(char *str)
{
char *p;
for (p = str; *p != '\0'; p++)
*p = i_tolower(*p);
return str;
}
char *i_strtoken(char **str, char delim)
{
char *ret;
if (*str == NULL || **str == '\0')
return NULL;
ret = *str;
while (**str != '\0') {
if (**str == delim) {
**str = '\0';
(*str)++;
break;
}
(*str)++;
}
return ret;
}
void string_remove_escapes(char *str)
{
char *dest;
for (dest = str; *str != '\0'; str++) {
if (*str != '\\' || str[1] == '\0')
*dest++ = *str;
}
*dest = '\0';
}
int strarray_length(char *const array[])
{
int len;
len = 0;
while (*array) {
len++;
array++;
}
return len;
}
int strarray_find(char *const array[], const char *item)
{
int index;
i_assert(item != NULL);
for (index = 0; *array != NULL; index++, array++) {
if (strcasecmp(*array, item) == 0)
return index;
}
return -1;
}
char *const *t_strsplit(const char *data, const char *separators)
{
char **array;
char *str;
size_t alloc_len, len;
i_assert(*separators != '\0');
len = strlen(data)+1;
str = t_malloc(len);
memcpy(str, data, len);
alloc_len = 20;
array = t_buffer_get(sizeof(const char *) * alloc_len);
array[0] = str; len = 1;
while (*str != '\0') {
if (strchr(separators, *str) != NULL) {
/* separator found */
if (len+1 >= alloc_len) {
alloc_len *= 2;
array = t_buffer_reget(array,
sizeof(const char *) *
alloc_len);
}
*str = '\0';
array[len++] = str+1;
}
str++;
}
array[len] = NULL;
t_buffer_alloc(sizeof(const char *) * (len+1));
return (char *const *) array;
}
const char *t_strjoin_replace(char *const args[], char separator,
int replacearg, const char *replacedata)
{
const char *arg;
char *data;
size_t alloc_len, arg_len, full_len;
int i;
if (args[0] == NULL)
return NULL;
alloc_len = 512; full_len = 0;
data = t_buffer_get(alloc_len);
for (i = 0; args[i] != NULL; i++) {
arg = i == replacearg ? replacedata : args[i];
arg_len = strlen(arg);
if (full_len + arg_len+1 >= alloc_len) {
alloc_len = nearest_power(full_len + arg_len+1);
data = t_buffer_reget(data, alloc_len);
}
memcpy(data+full_len, arg, arg_len);
full_len += arg_len;
data[full_len++] = separator;
}
data[full_len-1] = '\0';
t_buffer_alloc(full_len);
return data;
}
static size_t dec2str_recurse(char *buffer, size_t pos, size_t size,
largest_t number)
{
if (number == 0)
return 0;
pos = dec2str_recurse(buffer, pos, size-1, number / 10);
if (pos < size)
buffer[pos] = '0' + (number % 10);
return pos + 1;
}
void dec2str(char *buffer, size_t size, largest_t number)
{
size_t pos;
if (size == 0)
return;
pos = dec2str_recurse(buffer, 0, size, number);
if (pos == 0 && size > 1) {
/* we wrote nothing, because number is 0 */
buffer[0] = '0';
pos++;
}
buffer[pos < size ? pos : size-1] = '\0';
}