From 3389a051da42b4fabb5690d4430875d16abbeca2 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 28 Jul 2003 22:58:01 +0000 Subject: [PATCH] Add gnulib vasnprintf(). --- glib/gnulib/Makefile.am | 24 ++ glib/gnulib/README | 38 ++ glib/gnulib/asnprintf.c | 40 ++ glib/gnulib/g-gnulib.h | 45 ++ glib/gnulib/printf-args.c | 121 ++++++ glib/gnulib/printf-args.h | 134 ++++++ glib/gnulib/printf-parse.c | 479 +++++++++++++++++++++ glib/gnulib/printf-parse.h | 74 ++++ glib/gnulib/printf.c | 154 +++++++ glib/gnulib/printf.h | 56 +++ glib/gnulib/vasnprintf.c | 1000 ++++++++++++++++++++++++++++++++++++++++++++ glib/gnulib/vasnprintf.h | 61 +++ 12 files changed, 2226 insertions(+) create mode 100644 glib/gnulib/Makefile.am create mode 100644 glib/gnulib/README create mode 100644 glib/gnulib/asnprintf.c create mode 100644 glib/gnulib/g-gnulib.h create mode 100644 glib/gnulib/printf-args.c create mode 100644 glib/gnulib/printf-args.h create mode 100644 glib/gnulib/printf-parse.c create mode 100644 glib/gnulib/printf-parse.h create mode 100644 glib/gnulib/printf.c create mode 100644 glib/gnulib/printf.h create mode 100644 glib/gnulib/vasnprintf.c create mode 100644 glib/gnulib/vasnprintf.h diff --git a/glib/gnulib/Makefile.am b/glib/gnulib/Makefile.am new file mode 100644 index 0000000..f34534a --- /dev/null +++ b/glib/gnulib/Makefile.am @@ -0,0 +1,24 @@ +## Process this file with automake to produce Makefile.in + +noinst_LTLIBRARIES = libgnulib.la + +libgnulib_la_SOURCES = \ + asnprintf.c \ + printf-args.c \ + printf-args.h \ + printf-parse.c \ + printf-parse.h \ + vasnprintf.c \ + vasnprintf.h \ + printf.c \ + printf.h \ + g-gnulib.h + + + + + + + + + diff --git a/glib/gnulib/README b/glib/gnulib/README new file mode 100644 index 0000000..cd07d86 --- /dev/null +++ b/glib/gnulib/README @@ -0,0 +1,38 @@ +The files + + asnprintf.c + printf-args.c + printf-args.h + printf-parse.c + printf-parse.h + vasnprintf.c + vasnprintf.h + +are taken from the vasnprintf module of the GNUlib package, which can +be found at: + + http://www.gnu.org/software/gnulib/ + +They have been modified to include g-gnulib.h. vasnprintf.c has also been modified to +include support for long long printing if the system printf doesn't. This code is protected +by #ifndef HAVE_LON_LONG_FORMAT. + +The files + + printf.h + printf.c + g-gnulib.h + +have been written by me. printf.[hc] contain implementations of the +remaining functions in the printf family based on +vasnprintf. g-gnulib.h is included by all source files in order to +move all exported functions to the _g_gnulib namespace, replace malloc +by g_malloc and make sure that snprintf is only used if it implements +C99 return value semantics. + +Matthias Clasen +July 28, 2003 + + + + diff --git a/glib/gnulib/asnprintf.c b/glib/gnulib/asnprintf.c new file mode 100644 index 0000000..765d98c --- /dev/null +++ b/glib/gnulib/asnprintf.c @@ -0,0 +1,40 @@ +/* Formatted output to strings. + Copyright (C) 1999, 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "g-gnulib.h" + +/* Specification. */ +#include "vasnprintf.h" + +#include + +char * +asnprintf (char *resultbuf, size_t *lengthp, const char *format, ...) +{ + va_list args; + char *result; + + va_start (args, format); + result = vasnprintf (resultbuf, lengthp, format, args); + va_end (args); + return result; +} diff --git a/glib/gnulib/g-gnulib.h b/glib/gnulib/g-gnulib.h new file mode 100644 index 0000000..8fec93d --- /dev/null +++ b/glib/gnulib/g-gnulib.h @@ -0,0 +1,45 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 2003 Matthias Clasen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef __G_GNULIB_H__ + +#include +#include +#include "glib/glib.h" + +/* Private namespace for gnulib functions */ +#define asnprintf _g_gnulib_asnprintf +#define vasnprintf _g_gnulib_vasnprintf +#define printf_parse _g_gnulib_printf_parse +#define printf_fetchargs _g_gnulib_printf_fetchargs + +/* Use GLib memory allocation */ +#define malloc g_malloc +#define realloc g_realloc +#define free g_free + +/* Ensure only C99 snprintf gets used */ +#ifdef HAVE_C99_SNPRINTF +#define HAVE_SNPRINTF 1 +#else +#define HAVE_SNPRINTF 0 +#endif + + +#endif /* __G_GNULIB_H__ */ + diff --git a/glib/gnulib/printf-args.c b/glib/gnulib/printf-args.c new file mode 100644 index 0000000..364a5d7 --- /dev/null +++ b/glib/gnulib/printf-args.c @@ -0,0 +1,121 @@ +/* Decomposed printf argument list. + Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "g-gnulib.h" + +/* Specification. */ +#include "printf-args.h" + +#ifdef STATIC +STATIC +#endif +int +printf_fetchargs (va_list args, arguments *a) +{ + unsigned int i; + argument *ap; + + for (i = 0, ap = &a->arg[0]; i < a->count; i++, ap++) + switch (ap->type) + { + case TYPE_SCHAR: + ap->a.a_schar = va_arg (args, /*signed char*/ int); + break; + case TYPE_UCHAR: + ap->a.a_uchar = va_arg (args, /*unsigned char*/ int); + break; + case TYPE_SHORT: + ap->a.a_short = va_arg (args, /*short*/ int); + break; + case TYPE_USHORT: + ap->a.a_ushort = va_arg (args, /*unsigned short*/ int); + break; + case TYPE_INT: + ap->a.a_int = va_arg (args, int); + break; + case TYPE_UINT: + ap->a.a_uint = va_arg (args, unsigned int); + break; + case TYPE_LONGINT: + ap->a.a_longint = va_arg (args, long int); + break; + case TYPE_ULONGINT: + ap->a.a_ulongint = va_arg (args, unsigned long int); + break; +#ifdef HAVE_LONG_LONG + case TYPE_LONGLONGINT: + ap->a.a_longlongint = va_arg (args, long long int); + break; + case TYPE_ULONGLONGINT: + ap->a.a_ulonglongint = va_arg (args, unsigned long long int); + break; +#endif + case TYPE_DOUBLE: + ap->a.a_double = va_arg (args, double); + break; +#ifdef HAVE_LONG_DOUBLE + case TYPE_LONGDOUBLE: + ap->a.a_longdouble = va_arg (args, long double); + break; +#endif + case TYPE_CHAR: + ap->a.a_char = va_arg (args, int); + break; +#ifdef HAVE_WINT_T + case TYPE_WIDE_CHAR: + ap->a.a_wide_char = va_arg (args, wint_t); + break; +#endif + case TYPE_STRING: + ap->a.a_string = va_arg (args, const char *); + break; +#ifdef HAVE_WCHAR_T + case TYPE_WIDE_STRING: + ap->a.a_wide_string = va_arg (args, const wchar_t *); + break; +#endif + case TYPE_POINTER: + ap->a.a_pointer = va_arg (args, void *); + break; + case TYPE_COUNT_SCHAR_POINTER: + ap->a.a_count_schar_pointer = va_arg (args, signed char *); + break; + case TYPE_COUNT_SHORT_POINTER: + ap->a.a_count_short_pointer = va_arg (args, short *); + break; + case TYPE_COUNT_INT_POINTER: + ap->a.a_count_int_pointer = va_arg (args, int *); + break; + case TYPE_COUNT_LONGINT_POINTER: + ap->a.a_count_longint_pointer = va_arg (args, long int *); + break; +#ifdef HAVE_LONG_LONG + case TYPE_COUNT_LONGLONGINT_POINTER: + ap->a.a_count_longlongint_pointer = va_arg (args, long long int *); + break; +#endif + default: + /* Unknown type. */ + return -1; + } + return 0; +} diff --git a/glib/gnulib/printf-args.h b/glib/gnulib/printf-args.h new file mode 100644 index 0000000..35114a8 --- /dev/null +++ b/glib/gnulib/printf-args.h @@ -0,0 +1,134 @@ +/* Decomposed printf argument list. + Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _PRINTF_ARGS_H +#define _PRINTF_ARGS_H + +/* Get wchar_t. */ +#ifdef HAVE_WCHAR_T +# include +#endif + +/* Get wint_t. */ +#ifdef HAVE_WINT_T +# include +#endif + +/* Get va_list. */ +#include + + +/* Argument types */ +typedef enum +{ + TYPE_NONE, + TYPE_SCHAR, + TYPE_UCHAR, + TYPE_SHORT, + TYPE_USHORT, + TYPE_INT, + TYPE_UINT, + TYPE_LONGINT, + TYPE_ULONGINT, +#ifdef HAVE_LONG_LONG + TYPE_LONGLONGINT, + TYPE_ULONGLONGINT, +#endif + TYPE_DOUBLE, +#ifdef HAVE_LONG_DOUBLE + TYPE_LONGDOUBLE, +#endif + TYPE_CHAR, +#ifdef HAVE_WINT_T + TYPE_WIDE_CHAR, +#endif + TYPE_STRING, +#ifdef HAVE_WCHAR_T + TYPE_WIDE_STRING, +#endif + TYPE_POINTER, + TYPE_COUNT_SCHAR_POINTER, + TYPE_COUNT_SHORT_POINTER, + TYPE_COUNT_INT_POINTER, + TYPE_COUNT_LONGINT_POINTER +#ifdef HAVE_LONG_LONG +, TYPE_COUNT_LONGLONGINT_POINTER +#endif +} arg_type; + +/* Polymorphic argument */ +typedef struct +{ + arg_type type; + union + { + signed char a_schar; + unsigned char a_uchar; + short a_short; + unsigned short a_ushort; + int a_int; + unsigned int a_uint; + long int a_longint; + unsigned long int a_ulongint; +#ifdef HAVE_LONG_LONG + long long int a_longlongint; + unsigned long long int a_ulonglongint; +#endif + float a_float; + double a_double; +#ifdef HAVE_LONG_DOUBLE + long double a_longdouble; +#endif + int a_char; +#ifdef HAVE_WINT_T + wint_t a_wide_char; +#endif + const char* a_string; +#ifdef HAVE_WCHAR_T + const wchar_t* a_wide_string; +#endif + void* a_pointer; + signed char * a_count_schar_pointer; + short * a_count_short_pointer; + int * a_count_int_pointer; + long int * a_count_longint_pointer; +#ifdef HAVE_LONG_LONG + long long int * a_count_longlongint_pointer; +#endif + } + a; +} +argument; + +typedef struct +{ + unsigned int count; + argument *arg; +} +arguments; + + +/* Fetch the arguments, putting them into a. */ +#ifdef STATIC +STATIC +#else +extern +#endif +int printf_fetchargs (va_list args, arguments *a); + +#endif /* _PRINTF_ARGS_H */ diff --git a/glib/gnulib/printf-parse.c b/glib/gnulib/printf-parse.c new file mode 100644 index 0000000..e511fc1 --- /dev/null +++ b/glib/gnulib/printf-parse.c @@ -0,0 +1,479 @@ +/* Formatted output to strings. + Copyright (C) 1999-2000, 2002-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "g-gnulib.h" + +/* Specification. */ +#include "printf-parse.h" + +/* Get size_t, NULL. */ +#include + +/* Get intmax_t. */ +#if HAVE_STDINT_H_WITH_UINTMAX +# include +#endif +#if HAVE_INTTYPES_H_WITH_UINTMAX +# include +#endif + +/* malloc(), realloc(), free(). */ +#include + +#ifdef STATIC +STATIC +#endif +int +printf_parse (const char *format, char_directives *d, arguments *a) +{ + const char *cp = format; /* pointer into format */ + int arg_posn = 0; /* number of regular arguments consumed */ + unsigned int d_allocated; /* allocated elements of d->dir */ + unsigned int a_allocated; /* allocated elements of a->arg */ + unsigned int max_width_length = 0; + unsigned int max_precision_length = 0; + + d->count = 0; + d_allocated = 1; + d->dir = malloc (d_allocated * sizeof (char_directive)); + if (d->dir == NULL) + /* Out of memory. */ + return -1; + + a->count = 0; + a_allocated = 0; + a->arg = NULL; + +#define REGISTER_ARG(_index_,_type_) \ + { \ + unsigned int n = (_index_); \ + if (n >= a_allocated) \ + { \ + argument *memory; \ + a_allocated = 2 * a_allocated; \ + if (a_allocated <= n) \ + a_allocated = n + 1; \ + memory = (a->arg \ + ? realloc (a->arg, a_allocated * sizeof (argument)) \ + : malloc (a_allocated * sizeof (argument))); \ + if (memory == NULL) \ + /* Out of memory. */ \ + goto error; \ + a->arg = memory; \ + } \ + while (a->count <= n) \ + a->arg[a->count++].type = TYPE_NONE; \ + if (a->arg[n].type == TYPE_NONE) \ + a->arg[n].type = (_type_); \ + else if (a->arg[n].type != (_type_)) \ + /* Ambiguous type for positional argument. */ \ + goto error; \ + } + + while (*cp != '\0') + { + char c = *cp++; + if (c == '%') + { + int arg_index = -1; + char_directive *dp = &d->dir[d->count];/* pointer to next directive */ + + /* Initialize the next directive. */ + dp->dir_start = cp - 1; + dp->flags = 0; + dp->width_start = NULL; + dp->width_end = NULL; + dp->width_arg_index = -1; + dp->precision_start = NULL; + dp->precision_end = NULL; + dp->precision_arg_index = -1; + dp->arg_index = -1; + + /* Test for positional argument. */ + if (*cp >= '0' && *cp <= '9') + { + const char *np; + + for (np = cp; *np >= '0' && *np <= '9'; np++) + ; + if (*np == '$') + { + unsigned int n = 0; + + for (np = cp; *np >= '0' && *np <= '9'; np++) + n = 10 * n + (*np - '0'); + if (n == 0) + /* Positional argument 0. */ + goto error; + arg_index = n - 1; + cp = np + 1; + } + } + + /* Read the flags. */ + for (;;) + { + if (*cp == '\'') + { + dp->flags |= FLAG_GROUP; + cp++; + } + else if (*cp == '-') + { + dp->flags |= FLAG_LEFT; + cp++; + } + else if (*cp == '+') + { + dp->flags |= FLAG_SHOWSIGN; + cp++; + } + else if (*cp == ' ') + { + dp->flags |= FLAG_SPACE; + cp++; + } + else if (*cp == '#') + { + dp->flags |= FLAG_ALT; + cp++; + } + else if (*cp == '0') + { + dp->flags |= FLAG_ZERO; + cp++; + } + else + break; + } + + /* Parse the field width. */ + if (*cp == '*') + { + dp->width_start = cp; + cp++; + dp->width_end = cp; + if (max_width_length < 1) + max_width_length = 1; + + /* Test for positional argument. */ + if (*cp >= '0' && *cp <= '9') + { + const char *np; + + for (np = cp; *np >= '0' && *np <= '9'; np++) + ; + if (*np == '$') + { + unsigned int n = 0; + + for (np = cp; *np >= '0' && *np <= '9'; np++) + n = 10 * n + (*np - '0'); + if (n == 0) + /* Positional argument 0. */ + goto error; + dp->width_arg_index = n - 1; + cp = np + 1; + } + } + if (dp->width_arg_index < 0) + dp->width_arg_index = arg_posn++; + REGISTER_ARG (dp->width_arg_index, TYPE_INT); + } + else if (*cp >= '0' && *cp <= '9') + { + unsigned int width_length; + + dp->width_start = cp; + for (; *cp >= '0' && *cp <= '9'; cp++) + ; + dp->width_end = cp; + width_length = dp->width_end - dp->width_start; + if (max_width_length < width_length) + max_width_length = width_length; + } + + /* Parse the precision. */ + if (*cp == '.') + { + cp++; + if (*cp == '*') + { + dp->precision_start = cp - 1; + cp++; + dp->precision_end = cp; + if (max_precision_length < 2) + max_precision_length = 2; + + /* Test for positional argument. */ + if (*cp >= '0' && *cp <= '9') + { + const char *np; + + for (np = cp; *np >= '0' && *np <= '9'; np++) + ; + if (*np == '$') + { + unsigned int n = 0; + + for (np = cp; *np >= '0' && *np <= '9'; np++) + n = 10 * n + (*np - '0'); + if (n == 0) + /* Positional argument 0. */ + goto error; + dp->precision_arg_index = n - 1; + cp = np + 1; + } + } + if (dp->precision_arg_index < 0) + dp->precision_arg_index = arg_posn++; + REGISTER_ARG (dp->precision_arg_index, TYPE_INT); + } + else + { + unsigned int precision_length; + + dp->precision_start = cp - 1; + for (; *cp >= '0' && *cp <= '9'; cp++) + ; + dp->precision_end = cp; + precision_length = dp->precision_end - dp->precision_start; + if (max_precision_length < precision_length) + max_precision_length = precision_length; + } + } + + { + arg_type type; + + /* Parse argument type/size specifiers. */ + { + int flags = 0; + + for (;;) + { + if (*cp == 'h') + { + flags |= (1 << (flags & 1)); + cp++; + } + else if (*cp == 'L') + { + flags |= 4; + cp++; + } + else if (*cp == 'l') + { + flags += 8; + cp++; + } +#ifdef HAVE_INTMAX_T + else if (*cp == 'j') + { + if (sizeof (intmax_t) > sizeof (long)) + { + /* intmax_t = long long */ + flags += 16; + } + else if (sizeof (intmax_t) > sizeof (int)) + { + /* intmax_t = long */ + flags += 8; + } + cp++; + } +#endif + else if (*cp == 'z' || *cp == 'Z') + { + /* 'z' is standardized in ISO C 99, but glibc uses 'Z' + because the warning facility in gcc-2.95.2 understands + only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784). */ + if (sizeof (size_t) > sizeof (long)) + { + /* size_t = long long */ + flags += 16; + } + else if (sizeof (size_t) > sizeof (int)) + { + /* size_t = long */ + flags += 8; + } + cp++; + } + else if (*cp == 't') + { + if (sizeof (ptrdiff_t) > sizeof (long)) + { + /* ptrdiff_t = long long */ + flags += 16; + } + else if (sizeof (ptrdiff_t) > sizeof (int)) + { + /* ptrdiff_t = long */ + flags += 8; + } + cp++; + } + else + break; + } + + /* Read the conversion character. */ + c = *cp++; + switch (c) + { + case 'd': case 'i': +#ifdef HAVE_LONG_LONG + if (flags >= 16 || (flags & 4)) + type = TYPE_LONGLONGINT; + else +#endif + if (flags >= 8) + type = TYPE_LONGINT; + else if (flags & 2) + type = TYPE_SCHAR; + else if (flags & 1) + type = TYPE_SHORT; + else + type = TYPE_INT; + break; + case 'o': case 'u': case 'x': case 'X': +#ifdef HAVE_LONG_LONG + if (flags >= 16 || (flags & 4)) + type = TYPE_ULONGLONGINT; + else +#endif + if (flags >= 8) + type = TYPE_ULONGINT; + else if (flags & 2) + type = TYPE_UCHAR; + else if (flags & 1) + type = TYPE_USHORT; + else + type = TYPE_UINT; + break; + case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': + case 'a': case 'A': +#ifdef HAVE_LONG_DOUBLE + if (flags >= 16 || (flags & 4)) + type = TYPE_LONGDOUBLE; + else +#endif + type = TYPE_DOUBLE; + break; + case 'c': + if (flags >= 8) +#ifdef HAVE_WINT_T + type = TYPE_WIDE_CHAR; +#else + goto error; +#endif + else + type = TYPE_CHAR; + break; +#ifdef HAVE_WINT_T + case 'C': + type = TYPE_WIDE_CHAR; + c = 'c'; + break; +#endif + case 's': + if (flags >= 8) +#ifdef HAVE_WCHAR_T + type = TYPE_WIDE_STRING; +#else + goto error; +#endif + else + type = TYPE_STRING; + break; +#ifdef HAVE_WCHAR_T + case 'S': + type = TYPE_WIDE_STRING; + c = 's'; + break; +#endif + case 'p': + type = TYPE_POINTER; + break; + case 'n': +#ifdef HAVE_LONG_LONG + if (flags >= 16 || (flags & 4)) + type = TYPE_COUNT_LONGLONGINT_POINTER; + else +#endif + if (flags >= 8) + type = TYPE_COUNT_LONGINT_POINTER; + else if (flags & 2) + type = TYPE_COUNT_SCHAR_POINTER; + else if (flags & 1) + type = TYPE_COUNT_SHORT_POINTER; + else + type = TYPE_COUNT_INT_POINTER; + break; + case '%': + type = TYPE_NONE; + break; + default: + /* Unknown conversion character. */ + goto error; + } + } + + if (type != TYPE_NONE) + { + dp->arg_index = arg_index; + if (dp->arg_index < 0) + dp->arg_index = arg_posn++; + REGISTER_ARG (dp->arg_index, type); + } + dp->conversion = c; + dp->dir_end = cp; + } + + d->count++; + if (d->count >= d_allocated) + { + char_directive *memory; + + d_allocated = 2 * d_allocated; + memory = realloc (d->dir, d_allocated * sizeof (char_directive)); + if (memory == NULL) + /* Out of memory. */ + goto error; + d->dir = memory; + } + } + } + d->dir[d->count].dir_start = cp; + + d->max_width_length = max_width_length; + d->max_precision_length = max_precision_length; + return 0; + +error: + if (a->arg) + free (a->arg); + if (d->dir) + free (d->dir); + return -1; +} diff --git a/glib/gnulib/printf-parse.h b/glib/gnulib/printf-parse.h new file mode 100644 index 0000000..ab41478 --- /dev/null +++ b/glib/gnulib/printf-parse.h @@ -0,0 +1,74 @@ +/* Parse printf format string. + Copyright (C) 1999, 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _PRINTF_PARSE_H +#define _PRINTF_PARSE_H + +#include "printf-args.h" + +/* Private namespace for gnulib functions */ +#define printf_parse _g_gnulib_printf_parse + +/* Flags */ +#define FLAG_GROUP 1 /* ' flag */ +#define FLAG_LEFT 2 /* - flag */ +#define FLAG_SHOWSIGN 4 /* + flag */ +#define FLAG_SPACE 8 /* space flag */ +#define FLAG_ALT 16 /* # flag */ +#define FLAG_ZERO 32 + +/* A parsed directive. */ +typedef struct +{ + const char* dir_start; + const char* dir_end; + int flags; + const char* width_start; + const char* width_end; + int width_arg_index; + const char* precision_start; + const char* precision_end; + int precision_arg_index; + char conversion; /* d i o u x X f e E g G c s p n U % but not C S */ + int arg_index; +} +char_directive; + +/* A parsed format string. */ +typedef struct +{ + unsigned int count; + char_directive *dir; + unsigned int max_width_length; + unsigned int max_precision_length; +} +char_directives; + + +/* Parses the format string. Fills in the number N of directives, and fills + in directives[0], ..., directives[N-1], and sets directives[N].dir_start + to the end of the format string. Also fills in the arg_type fields of the + arguments and the needed count of arguments. */ +#ifdef STATIC +STATIC +#else +extern +#endif +int printf_parse (const char *format, char_directives *d, arguments *a); + +#endif /* _PRINTF_PARSE_H */ diff --git a/glib/gnulib/printf.c b/glib/gnulib/printf.c new file mode 100644 index 0000000..18d29dd --- /dev/null +++ b/glib/gnulib/printf.c @@ -0,0 +1,154 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 2003 Matthias Clasen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 2003. See the AUTHORS + * file for a list of people on the GLib Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif +#include +#include +#include +#include "g-gnulib.h" +#include "vasnprintf.h" +#include "printf.h" + +int _g_gnulib_printf (char const *format, ...) +{ + va_list args; + int retval; + + va_start (args, format); + retval = _g_gnulib_vprintf (format, args); + va_end (args); + + return retval; +} + +int _g_gnulib_fprintf (FILE *file, char const *format, ...) +{ + va_list args; + int retval; + + va_start (args, format); + retval = _g_gnulib_vfprintf (file, format, args); + va_end (args); + + return retval; +} + +int _g_gnulib_sprintf (char *string, char const *format, ...) +{ + va_list args; + int retval; + + va_start (args, format); + retval = _g_gnulib_vsprintf (string, format, args); + va_end (args); + + return retval; +} + +int _g_gnulib_snprintf (char *string, size_t n, char const *format, ...) +{ + va_list args; + int retval; + + va_start (args, format); + retval = _g_gnulib_vsnprintf (string, n, format, args); + va_end (args); + + return retval; +} + +int _g_gnulib_vprintf (char const *format, va_list args) +{ + return _g_gnulib_vfprintf (stdout, format, args); +} + +int _g_gnulib_vfprintf (FILE *file, char const *format, va_list args) +{ + char *result; + size_t length; + + result = vasnprintf (NULL, &length, format, args); + if (result == NULL) + return -1; + + fwrite (result, 1, length + 1, file); + free (result); + + return length; +} + +int _g_gnulib_vsprintf (char *string, char const *format, va_list args) +{ + char *result; + size_t length; + + result = vasnprintf (NULL, &length, format, args); + if (result == NULL) + return -1; + + memcpy (string, result, length + 1); + free (result); + + return length; +} + +int _g_gnulib_vsnprintf (char *string, size_t n, char const *format, va_list args) +{ + char *result; + size_t length; + + result = vasnprintf (NULL, &length, format, args); + if (result == NULL) + return -1; + + if (n > 0) + { + memcpy (string, result, MIN(length + 1, n)); + string[n - 1] = 0; + } + + free (result); + + return length; +} + +int _g_gnulib_vasprintf (char **result, char const *format, va_list args) +{ + size_t length; + + *result = vasnprintf (NULL, &length, format, args); + if (*result == NULL) + return -1; + + return length; +} + + + + + diff --git a/glib/gnulib/printf.h b/glib/gnulib/printf.h new file mode 100644 index 0000000..e15b02b --- /dev/null +++ b/glib/gnulib/printf.h @@ -0,0 +1,56 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 2003 Matthias Clasen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef __GNULIB_PRINTF_H__ +#define __GNULIB_PRINTF_H__ + +#include + +int _g_gnulib_printf (char const *format, + ...); +int _g_gnulib_fprintf (FILE *file, + char const *format, + ...); +int _g_gnulib_sprintf (char *string, + char const *format, + ...); +int _g_gnulib_snprintf (char *string, + size_t n, + char const *format, + ...); +int _g_gnulib_vprintf (char const *format, + va_list args); +int _g_gnulib_vfprintf (FILE *file, + char const *format, + va_list args); +int _g_gnulib_vsprintf (char *string, + char const *format, + va_list args); +int _g_gnulib_vsnprintf (char *string, + size_t n, + char const *format, + va_list args); +int _g_gnulib_vasprintf (char **result, + char const *format, + va_list args); + + +#endif /* __GNULIB_PRINTF_H__ */ + + + diff --git a/glib/gnulib/vasnprintf.c b/glib/gnulib/vasnprintf.c new file mode 100644 index 0000000..e00bdb1 --- /dev/null +++ b/glib/gnulib/vasnprintf.c @@ -0,0 +1,1000 @@ +/* vsprintf with automatic memory allocation. + Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +/* Tell glibc's to provide a prototype for snprintf(). + This must come before because may include + , and once has been included, it's too late. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif +#include + +#include "g-gnulib.h" + +/* Specification. */ +#include "vasnprintf.h" + +#include /* snprintf(), sprintf() */ +#include /* abort(), malloc(), realloc(), free() */ +#include /* memcpy(), strlen() */ +#include /* errno */ +#include /* CHAR_BIT */ +#include /* DBL_MAX_EXP, LDBL_MAX_EXP */ +#include "printf-parse.h" + +/* For those losing systems which don't have 'alloca' we have to add + some additional code emulating it. */ +#ifdef HAVE_ALLOCA +# define freea(p) /* nothing */ +#else +# define alloca(n) malloc (n) +# define freea(p) free (p) +#endif + +#ifndef HAVE_LONG_LONG_FORMAT +static int +print_long_long (char *buf, + int len, + int width, + int precision, + unsigned long flags, + char conversion, + unsigned long long number) +{ + int negative = FALSE; + char buffer[128]; + char *bufferend; + char *pointer; + int base; + static const char *upper = "0123456789ABCDEFX"; + static const char *lower = "0123456789abcdefx"; + const char *digits; + int i; + char *p; + int count; + +#define EMIT(c) \ + if (p - buf == len - 1) \ + { \ + *p++ = '\0'; \ + return len; \ + } \ + else \ + *p++ = c; + + p = buf; + + switch (conversion) + { + case 'o': + base = 8; + digits = lower; + negative = FALSE; + break; + case 'x': + base = 16; + digits = lower; + negative = FALSE; + break; + case 'X': + base = 16; + digits = upper; + negative = FALSE; + break; + default: + base = 10; + digits = lower; + negative = (long long)number < 0; + if (negative) + number = -((long long)number); + break; + } + + /* Build number */ + pointer = bufferend = &buffer[sizeof(buffer) - 1]; + *pointer-- = '\0'; + for (i = 1; i < (int)sizeof(buffer); i++) + { + *pointer-- = digits[number % base]; + number /= base; + if (number == 0) + break; + } + + /* Adjust width */ + width -= (bufferend - pointer) - 1; + + /* Adjust precision */ + if (precision != -1) + { + precision -= (bufferend - pointer) - 1; + if (precision < 0) + precision = 0; + flags |= FLAG_ZERO; + } + + /* Adjust width further */ + if (negative || (flags & FLAG_SHOWSIGN) || (flags & FLAG_SPACE)) + width--; + if (flags & FLAG_ALT) + { + switch (base) + { + case 16: + width -= 2; + break; + case 8: + width--; + break; + default: + break; + } + } + + /* Output prefixes spaces if needed */ + if (! ((flags & FLAG_LEFT) || + ((flags & FLAG_ZERO) && (precision == -1)))) + { + count = (precision == -1) ? 0 : precision; + while (width-- > count) + *p++ = ' '; + } + + /* width has been adjusted for signs and alternatives */ + if (negative) + { + EMIT ('-'); + } + else if (flags & FLAG_SHOWSIGN) + { + EMIT('+'); + } + else if (flags & FLAG_SPACE) + { + EMIT(' '); + } + + if (flags & FLAG_ALT) + { + switch (base) + { + case 8: + EMIT('0'); + break; + case 16: + EMIT('0'); + EMIT(digits[16]); + break; + default: + break; + } /* switch base */ + } + + /* Output prefixed zero padding if needed */ + if (flags & FLAG_ZERO) + { + if (precision == -1) + precision = width; + while (precision-- > 0) + { + EMIT('0'); + width--; + } + } + + /* Output the number itself */ + while (*(++pointer)) + { + EMIT(*pointer); + } + + /* Output trailing spaces if needed */ + if (flags & FLAG_LEFT) + { + while (width-- > 0) + EMIT(' '); + } + + EMIT('\0'); + + return p - buf - 1; +} +#endif + +char * +vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) +{ + char_directives d; + arguments a; + + if (printf_parse (format, &d, &a) < 0) + { + errno = EINVAL; + return NULL; + } + +#define CLEANUP() \ + free (d.dir); \ + if (a.arg) \ + free (a.arg); + + if (printf_fetchargs (args, &a) < 0) + { + CLEANUP (); + errno = EINVAL; + return NULL; + } + + { + char *buf = + (char *) alloca (7 + d.max_width_length + d.max_precision_length + 6); + const char *cp; + unsigned int i; + char_directive *dp; + /* Output string accumulator. */ + char *result; + size_t allocated; + size_t length; + + if (resultbuf != NULL) + { + result = resultbuf; + allocated = *lengthp; + } + else + { + result = NULL; + allocated = 0; + } + length = 0; + /* Invariants: + result is either == resultbuf or == NULL or malloc-allocated. + If length > 0, then result != NULL. */ + +#define ENSURE_ALLOCATION(needed) \ + if ((needed) > allocated) \ + { \ + char *memory; \ + \ + allocated = (allocated > 0 ? 2 * allocated : 12); \ + if ((needed) > allocated) \ + allocated = (needed); \ + if (result == resultbuf || result == NULL) \ + memory = (char *) malloc (allocated); \ + else \ + memory = (char *) realloc (result, allocated); \ + \ + if (memory == NULL) \ + { \ + if (!(result == resultbuf || result == NULL)) \ + free (result); \ + freea (buf); \ + CLEANUP (); \ + errno = ENOMEM; \ + return NULL; \ + } \ + if (result == resultbuf && length > 0) \ + memcpy (memory, result, length); \ + result = memory; \ + } + + for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++) + { + if (cp != dp->dir_start) + { + size_t n = dp->dir_start - cp; + + ENSURE_ALLOCATION (length + n); + memcpy (result + length, cp, n); + length += n; + } + if (i == d.count) + break; + + /* Execute a single directive. */ + if (dp->conversion == '%') + { + if (!(dp->arg_index < 0)) + abort (); + ENSURE_ALLOCATION (length + 1); + result[length] = '%'; + length += 1; + } + else + { + if (!(dp->arg_index >= 0)) + abort (); + + if (dp->conversion == 'n') + { + switch (a.arg[dp->arg_index].type) + { + case TYPE_COUNT_SCHAR_POINTER: + *a.arg[dp->arg_index].a.a_count_schar_pointer = length; + break; + case TYPE_COUNT_SHORT_POINTER: + *a.arg[dp->arg_index].a.a_count_short_pointer = length; + break; + case TYPE_COUNT_INT_POINTER: + *a.arg[dp->arg_index].a.a_count_int_pointer = length; + break; + case TYPE_COUNT_LONGINT_POINTER: + *a.arg[dp->arg_index].a.a_count_longint_pointer = length; + break; +#ifdef HAVE_LONG_LONG + case TYPE_COUNT_LONGLONGINT_POINTER: + *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length; + break; +#endif + default: + abort (); + } + } + else + { + arg_type type = a.arg[dp->arg_index].type; + char *p; + unsigned int prefix_count; + int prefixes[2]; +#if !HAVE_SNPRINTF + unsigned int tmp_length; + char tmpbuf[700]; + char *tmp; + + /* Allocate a temporary buffer of sufficient size for calling + sprintf. */ + { + unsigned int width; + unsigned int precision; + + width = 0; + if (dp->width_start != dp->width_end) + { + if (dp->width_arg_index >= 0) + { + int arg; + + if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) + abort (); + arg = a.arg[dp->width_arg_index].a.a_int; + width = (arg < 0 ? -arg : arg); + } + else + { + const char *digitp = dp->width_start; + + do + width = width * 10 + (*digitp++ - '0'); + while (digitp != dp->width_end); + } + } + + precision = 6; + if (dp->precision_start != dp->precision_end) + { + if (dp->precision_arg_index >= 0) + { + int arg; + + if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) + abort (); + arg = a.arg[dp->precision_arg_index].a.a_int; + precision = (arg < 0 ? 0 : arg); + } + else + { + const char *digitp = dp->precision_start + 1; + + precision = 0; + do + precision = precision * 10 + (*digitp++ - '0'); + while (digitp != dp->precision_end); + } + } + + switch (dp->conversion) + { + case 'd': case 'i': case 'u': +# ifdef HAVE_LONG_LONG + if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) + tmp_length = + (unsigned int) (sizeof (unsigned long long) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + * 2 /* estimate for FLAG_GROUP */ + ) + + 1 /* turn floor into ceil */ + + 1; /* account for leading sign */ + else +# endif + if (type == TYPE_LONGINT || type == TYPE_ULONGINT) + tmp_length = + (unsigned int) (sizeof (unsigned long) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + * 2 /* estimate for FLAG_GROUP */ + ) + + 1 /* turn floor into ceil */ + + 1; /* account for leading sign */ + else + tmp_length = + (unsigned int) (sizeof (unsigned int) * CHAR_BIT + * 0.30103 /* binary -> decimal */ + * 2 /* estimate for FLAG_GROUP */ + ) + + 1 /* turn floor into ceil */ + + 1; /* account for leading sign */ + break; + + case 'o': +# ifdef HAVE_LONG_LONG + if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) + tmp_length = + (unsigned int) (sizeof (unsigned long long) * CHAR_BIT + * 0.333334 /* binary -> octal */ + ) + + 1 /* turn floor into ceil */ + + 1; /* account for leading sign */ + else +# endif + if (type == TYPE_LONGINT || type == TYPE_ULONGINT) + tmp_length = + (unsigned int) (sizeof (unsigned long) * CHAR_BIT + * 0.333334 /* binary -> octal */ + ) + + 1 /* turn floor into ceil */ + + 1; /* account for leading sign */ + else + tmp_length = + (unsigned int) (sizeof (unsigned int) * CHAR_BIT + * 0.333334 /* binary -> octal */ + ) + + 1 /* turn floor into ceil */ + + 1; /* account for leading sign */ + break; + + case 'x': case 'X': +# ifdef HAVE_LONG_LONG + if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) + tmp_length = + (unsigned int) (sizeof (unsigned long long) * CHAR_BIT + * 0.25 /* binary -> hexadecimal */ + ) + + 1 /* turn floor into ceil */ + + 2; /* account for leading sign or alternate form */ + else +# endif + if (type == TYPE_LONGINT || type == TYPE_ULONGINT) + tmp_length = + (unsigned int) (sizeof (unsigned long) * CHAR_BIT + * 0.25 /* binary -> hexadecimal */ + ) + + 1 /* turn floor into ceil */ + + 2; /* account for leading sign or alternate form */ + else + tmp_length = + (unsigned int) (sizeof (unsigned int) * CHAR_BIT + * 0.25 /* binary -> hexadecimal */ + ) + + 1 /* turn floor into ceil */ + + 2; /* account for leading sign or alternate form */ + break; + + case 'f': case 'F': +# ifdef HAVE_LONG_DOUBLE + if (type == TYPE_LONGDOUBLE) + tmp_length = + (unsigned int) (LDBL_MAX_EXP + * 0.30103 /* binary -> decimal */ + * 2 /* estimate for FLAG_GROUP */ + ) + + 1 /* turn floor into ceil */ + + precision + + 10; /* sign, decimal point etc. */ + else +# endif + tmp_length = + (unsigned int) (DBL_MAX_EXP + * 0.30103 /* binary -> decimal */ + * 2 /* estimate for FLAG_GROUP */ + ) + + 1 /* turn floor into ceil */ + + precision + + 10; /* sign, decimal point etc. */ + break; + + case 'e': case 'E': case 'g': case 'G': + case 'a': case 'A': + tmp_length = + precision + + 12; /* sign, decimal point, exponent etc. */ + break; + + case 'c': +# ifdef HAVE_WINT_T + if (type == TYPE_WIDE_CHAR) + tmp_length = MB_CUR_MAX; + else +# endif + tmp_length = 1; + break; + + case 's': +# ifdef HAVE_WCHAR_T + if (type == TYPE_WIDE_STRING) + tmp_length = + wcslen (a.arg[dp->arg_index].a.a_wide_string) + * MB_CUR_MAX; + else +# endif + tmp_length = strlen (a.arg[dp->arg_index].a.a_string); + break; + + case 'p': + tmp_length = + (unsigned int) (sizeof (void *) * CHAR_BIT + * 0.25 /* binary -> hexadecimal */ + ) + + 1 /* turn floor into ceil */ + + 2; /* account for leading 0x */ + break; + + default: + abort (); + } + + if (tmp_length < width) + tmp_length = width; + + tmp_length++; /* account for trailing NUL */ + } + + if (tmp_length <= sizeof (tmpbuf)) + tmp = tmpbuf; + else + { + tmp = (char *) malloc (tmp_length); + if (tmp == NULL) + { + /* Out of memory. */ + if (!(result == resultbuf || result == NULL)) + free (result); + freea (buf); + CLEANUP (); + errno = ENOMEM; + return NULL; + } + } +#endif + + /* Construct the format string for calling snprintf or + sprintf. */ + p = buf; + *p++ = '%'; + if (dp->flags & FLAG_GROUP) + *p++ = '\''; + if (dp->flags & FLAG_LEFT) + *p++ = '-'; + if (dp->flags & FLAG_SHOWSIGN) + *p++ = '+'; + if (dp->flags & FLAG_SPACE) + *p++ = ' '; + if (dp->flags & FLAG_ALT) + *p++ = '#'; + if (dp->flags & FLAG_ZERO) + *p++ = '0'; + if (dp->width_start != dp->width_end) + { + size_t n = dp->width_end - dp->width_start; + memcpy (p, dp->width_start, n); + p += n; + } + if (dp->precision_start != dp->precision_end) + { + size_t n = dp->precision_end - dp->precision_start; + memcpy (p, dp->precision_start, n); + p += n; + } + + switch (type) + { +#ifdef HAVE_LONG_LONG + case TYPE_LONGLONGINT: + case TYPE_ULONGLONGINT: + *p++ = 'l'; + /*FALLTHROUGH*/ +#endif + case TYPE_LONGINT: + case TYPE_ULONGINT: +#ifdef HAVE_WINT_T + case TYPE_WIDE_CHAR: +#endif +#ifdef HAVE_WCHAR_T + case TYPE_WIDE_STRING: +#endif + *p++ = 'l'; + break; +#ifdef HAVE_LONG_DOUBLE + case TYPE_LONGDOUBLE: + *p++ = 'L'; + break; +#endif + default: + break; + } + *p = dp->conversion; +#if HAVE_SNPRINTF + p[1] = '%'; + p[2] = 'n'; + p[3] = '\0'; +#else + p[1] = '\0'; +#endif + + /* Construct the arguments for calling snprintf or sprintf. */ + prefix_count = 0; + if (dp->width_arg_index >= 0) + { + if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) + abort (); + prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int; + } + if (dp->precision_arg_index >= 0) + { + if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) + abort (); + prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int; + } + +#if HAVE_SNPRINTF + /* Prepare checking whether snprintf returns the count + via %n. */ + ENSURE_ALLOCATION (length + 1); + result[length] = '\0'; +#endif + + for (;;) + { + size_t maxlen; + int count; + int retcount; + + maxlen = allocated - length; + count = -1; + retcount = 0; + +#if HAVE_SNPRINTF +#define SNPRINTF_BUF(arg) \ + switch (prefix_count) \ + { \ + case 0: \ + retcount = snprintf (result + length, maxlen, buf, \ + arg, &count); \ + break; \ + case 1: \ + retcount = snprintf (result + length, maxlen, buf, \ + prefixes[0], arg, &count); \ + break; \ + case 2: \ + retcount = snprintf (result + length, maxlen, buf, \ + prefixes[0], prefixes[1], arg, \ + &count); \ + break; \ + default: \ + abort (); \ + } +#else +#define SNPRINTF_BUF(arg) \ + switch (prefix_count) \ + { \ + case 0: \ + count = sprintf (tmp, buf, arg); \ + break; \ + case 1: \ + count = sprintf (tmp, buf, prefixes[0], arg); \ + break; \ + case 2: \ + count = sprintf (tmp, buf, prefixes[0], prefixes[1],\ + arg); \ + break; \ + default: \ + abort (); \ + } +#endif + + switch (type) + { + case TYPE_SCHAR: + { + int arg = a.arg[dp->arg_index].a.a_schar; + SNPRINTF_BUF (arg); + } + break; + case TYPE_UCHAR: + { + unsigned int arg = a.arg[dp->arg_index].a.a_uchar; + SNPRINTF_BUF (arg); + } + break; + case TYPE_SHORT: + { + int arg = a.arg[dp->arg_index].a.a_short; + SNPRINTF_BUF (arg); + } + break; + case TYPE_USHORT: + { + unsigned int arg = a.arg[dp->arg_index].a.a_ushort; + SNPRINTF_BUF (arg); + } + break; + case TYPE_INT: + { + int arg = a.arg[dp->arg_index].a.a_int; + SNPRINTF_BUF (arg); + } + break; + case TYPE_UINT: + { + unsigned int arg = a.arg[dp->arg_index].a.a_uint; + SNPRINTF_BUF (arg); + } + break; + case TYPE_LONGINT: + { + long int arg = a.arg[dp->arg_index].a.a_longint; + SNPRINTF_BUF (arg); + } + break; + case TYPE_ULONGINT: + { + unsigned long int arg = a.arg[dp->arg_index].a.a_ulongint; + SNPRINTF_BUF (arg); + } + break; +#ifdef HAVE_LONG_LONG +#ifndef HAVE_LONG_LONG_FORMAT + case TYPE_LONGLONGINT: + case TYPE_ULONGLONGINT: + { + unsigned long long int arg = a.arg[dp->arg_index].a.a_ulonglongint; + int width; + int precision; + + width = 0; + if (dp->width_start != dp->width_end) + { + if (dp->width_arg_index >= 0) + { + int arg; + + if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) + abort (); + arg = a.arg[dp->width_arg_index].a.a_int; + width = (arg < 0 ? -arg : arg); + } + else + { + const char *digitp = dp->width_start; + + do + width = width * 10 + (*digitp++ - '0'); + while (digitp != dp->width_end); + } + } + + precision = -1; + if (dp->precision_start != dp->precision_end) + { + if (dp->precision_arg_index >= 0) + { + int arg; + + if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) + abort (); + arg = a.arg[dp->precision_arg_index].a.a_int; + precision = (arg < 0 ? 0 : arg); + } + else + { + const char *digitp = dp->precision_start + 1; + + precision = 0; + do + precision = precision * 10 + (*digitp++ - '0'); + while (digitp != dp->precision_end); + } + } + + count = print_long_long (result + length, maxlen, + width, precision, + dp->flags, + dp->conversion, + arg); + } + break; +#else + case TYPE_LONGLONGINT: + { + long long int arg = a.arg[dp->arg_index].a.a_longlongint; + SNPRINTF_BUF (arg); + } + break; + case TYPE_ULONGLONGINT: + { + unsigned long long int arg = a.arg[dp->arg_index].a.a_ulonglongint; + SNPRINTF_BUF (arg); + } + break; +#endif +#endif + case TYPE_DOUBLE: + { + double arg = a.arg[dp->arg_index].a.a_double; + SNPRINTF_BUF (arg); + } + break; +#ifdef HAVE_LONG_DOUBLE + case TYPE_LONGDOUBLE: + { + long double arg = a.arg[dp->arg_index].a.a_longdouble; + SNPRINTF_BUF (arg); + } + break; +#endif + case TYPE_CHAR: + { + int arg = a.arg[dp->arg_index].a.a_char; + SNPRINTF_BUF (arg); + } + break; +#ifdef HAVE_WINT_T + case TYPE_WIDE_CHAR: + { + wint_t arg = a.arg[dp->arg_index].a.a_wide_char; + SNPRINTF_BUF (arg); + } + break; +#endif + case TYPE_STRING: + { + const char *arg = a.arg[dp->arg_index].a.a_string; + SNPRINTF_BUF (arg); + } + break; +#ifdef HAVE_WCHAR_T + case TYPE_WIDE_STRING: + { + const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string; + SNPRINTF_BUF (arg); + } + break; +#endif + case TYPE_POINTER: + { + void *arg = a.arg[dp->arg_index].a.a_pointer; + SNPRINTF_BUF (arg); + } + break; + default: + abort (); + } + +#if HAVE_SNPRINTF + /* Portability: Not all implementations of snprintf() + are ISO C 99 compliant. Determine the number of + bytes that snprintf() has produced or would have + produced. */ + if (count >= 0) + { + /* Verify that snprintf() has NUL-terminated its + result. */ + if (count < maxlen && result[length + count] != '\0') + abort (); + /* Portability hack. */ + if (retcount > count) + count = retcount; + } + else + { + /* snprintf() doesn't understand the '%n' + directive. */ + if (p[1] != '\0') + { + /* Don't use the '%n' directive; instead, look + at the snprintf() return value. */ + p[1] = '\0'; + continue; + } + count = retcount; + } +#endif + + /* Attempt to handle failure. */ + if (count < 0) + { + if (!(result == resultbuf || result == NULL)) + free (result); + freea (buf); + CLEANUP (); + errno = EINVAL; + return NULL; + } + +#if !HAVE_SNPRINTF + if (count >= tmp_length) + /* tmp_length was incorrectly calculated - fix the + code above! */ + abort (); +#endif + + /* Make room for the result. */ + if (count >= maxlen) + { + /* Need at least count bytes. But allocate + proportionally, to avoid looping eternally if + snprintf() reports a too small count. */ + size_t n = length + count; + + if (n < 2 * allocated) + n = 2 * allocated; + + ENSURE_ALLOCATION (n); +#if HAVE_SNPRINTF + continue; +#endif + } + +#if HAVE_SNPRINTF + /* The snprintf() result did fit. */ +#else + /* Append the sprintf() result. */ + memcpy (result + length, tmp, count); + if (tmp != tmpbuf) + free (tmp); +#endif + + length += count; + break; + } + } + } + } + + /* Add the final NUL. */ + ENSURE_ALLOCATION (length + 1); + result[length] = '\0'; + + if (result != resultbuf && length + 1 < allocated) + { + /* Shrink the allocated memory if possible. */ + char *memory; + + memory = (char *) realloc (result, length + 1); + if (memory != NULL) + result = memory; + } + + freea (buf); + CLEANUP (); + *lengthp = length; + return result; + } +} diff --git a/glib/gnulib/vasnprintf.h b/glib/gnulib/vasnprintf.h new file mode 100644 index 0000000..65f1bc1 --- /dev/null +++ b/glib/gnulib/vasnprintf.h @@ -0,0 +1,61 @@ +/* vsprintf with automatic memory allocation. + Copyright (C) 2002-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _VASNPRINTF_H +#define _VASNPRINTF_H + +/* Get va_list. */ +#include + +/* Get size_t. */ +#include + +#ifndef __attribute__ +/* This feature is available in gcc versions 2.5 and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__ +# define __attribute__(Spec) /* empty */ +# endif +/* The __-protected variants of `format' and `printf' attributes + are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) +# define __format__ format +# define __printf__ printf +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Write formatted output to a string dynamically allocated with malloc(). + You can pass a preallocated buffer for the result in RESULTBUF and its + size in *LENGTHP; otherwise you pass RESULTBUF = NULL. + If successful, return the address of the string (this may be = RESULTBUF + if no dynamic memory allocation was necessary) and set *LENGTHP to the + number of resulting bytes, excluding the trailing NUL. Upon error, set + errno and return NULL. */ +extern char * asnprintf (char *resultbuf, size_t *lengthp, const char *format, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); +extern char * vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) + __attribute__ ((__format__ (__printf__, 3, 0))); + +#ifdef __cplusplus +} +#endif + +#endif /* _VASNPRINTF_H */ -- 2.7.4