diff options
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | gst/Makefile.am | 10 | ||||
-rw-r--r-- | gst/printf/Makefile.am | 18 | ||||
-rw-r--r-- | gst/printf/README | 58 | ||||
-rw-r--r-- | gst/printf/asnprintf.c | 40 | ||||
-rw-r--r-- | gst/printf/gst-printf.h | 48 | ||||
-rw-r--r-- | gst/printf/printf-args.c | 132 | ||||
-rw-r--r-- | gst/printf/printf-args.h | 142 | ||||
-rw-r--r-- | gst/printf/printf-parse.c | 449 | ||||
-rw-r--r-- | gst/printf/printf-parse.h | 74 | ||||
-rw-r--r-- | gst/printf/printf.c | 157 | ||||
-rw-r--r-- | gst/printf/printf.h | 62 | ||||
-rw-r--r-- | gst/printf/vasnprintf.c | 980 | ||||
-rw-r--r-- | gst/printf/vasnprintf.h | 61 |
14 files changed, 2230 insertions, 2 deletions
diff --git a/configure.ac b/configure.ac index 34b7448b0..23a2055e7 100644 --- a/configure.ac +++ b/configure.ac @@ -740,6 +740,7 @@ gst/Makefile gst/gstconfig.h gst/gstversion.h gst/parse/Makefile +gst/printf/Makefile libs/Makefile libs/gst/Makefile libs/gst/base/Makefile diff --git a/gst/Makefile.am b/gst/Makefile.am index eb51dc142..032226513 100644 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -26,9 +26,14 @@ else GST_PLUGIN_SRC = gstplugin.c endif -SUBDIRS = $(SUBDIRS_PARSE) +# FIXME: might not be needed if debug logging is disabled +SUBDIRS_PRINTF = printf +GST_PRINTF_LA = printf/libgstprintf.la -DIST_SUBDIRS = parse + +SUBDIRS = $(SUBDIRS_PARSE) $(SUBDIRS_PRINTF) + +DIST_SUBDIRS = parse printf # make variables for all generated source and header files to make the # distinction clear @@ -132,6 +137,7 @@ libgstreamer_@GST_API_VERSION@_la_CFLAGS = \ libgstreamer_@GST_API_VERSION@_la_LIBADD = \ $(GST_PARSE_LA) \ + $(GST_PRINTF_LA) \ $(GST_ALL_LIBS) \ $(WIN32_LIBS) \ $(LIBM) diff --git a/gst/printf/Makefile.am b/gst/printf/Makefile.am new file mode 100644 index 000000000..d3f407aea --- /dev/null +++ b/gst/printf/Makefile.am @@ -0,0 +1,18 @@ +AM_CPPFLAGS = $(GLIB_CFLAGS) + +noinst_LTLIBRARIES = libgstprintf.la + +libgstprintf_la_CFLAGS = +libgstprintf_la_SOURCES = \ + asnprintf.c \ + printf-args.c \ + printf-args.h \ + printf-parse.c \ + printf-parse.h \ + vasnprintf.c \ + vasnprintf.h \ + printf.c \ + printf.h \ + gst-printf.h + +EXTRA_DIST = README diff --git a/gst/printf/README b/gst/printf/README new file mode 100644 index 000000000..04ce64628 --- /dev/null +++ b/gst/printf/README @@ -0,0 +1,58 @@ +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/ + +All files 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_LONG_LONG_FORMAT. + +Code has been added to printf-args.[ch], printf-parse.c and vasnprintf.c +to support printing of __int64 values with the I64 format modifier. This +is protected by #ifdef HAVE_INT64_AND_I64. + +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 +November 1, 2003 + +----- + +GStreamer modifications + +This was imported from GLib's gnulib subdirectory. + +g-gnulib.h and _g_gnulib namespace has been changed to gst-printf.h and +__gst_printf namespace for GStreamer. Also #define HAVE_SNPRINTF 0 has +been changed to #undef HAVE_SNPRINTF, and HAVE_ALLOCA has been changed to +GLIB_HAVE_ALLOCA_H + +We will also add support for our custom printf format specifiers. + +Files have also been indented with gst-indent, so this is basically a +permanent fork and any patches will have to be merged manually. + +March 30, 2013. diff --git a/gst/printf/asnprintf.c b/gst/printf/asnprintf.c new file mode 100644 index 000000000..d606d38d3 --- /dev/null +++ b/gst/printf/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 <config.h> +#endif + +#include "gst-printf.h" + +/* Specification. */ +#include "vasnprintf.h" + +#include <stdarg.h> + +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/gst/printf/gst-printf.h b/gst/printf/gst-printf.h new file mode 100644 index 000000000..8860003fd --- /dev/null +++ b/gst/printf/gst-printf.h @@ -0,0 +1,48 @@ +/* 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 "config.h" +#include <stdlib.h> +#include <glib.h> + +/* Private namespace for gnulib functions */ +#define asnprintf __gst_asnprintf +#define vasnprintf __gst_vasnprintf +#define printf_parse __gst_printf_parse +#define printf_fetchargs __gst_printf_fetchargs + +/* Use GLib memory allocation */ +#undef malloc +#undef realloc +#undef free +#define malloc g_malloc +#define realloc g_realloc +#define free g_free + +/* Ensure only C99 snprintf gets used */ +#undef HAVE_SNPRINTF +#ifdef HAVE_C99_SNPRINTF +#define HAVE_SNPRINTF 1 +#else +#undef HAVE_SNPRINTF +#endif + + +#endif /* __G_GNULIB_H__ */ diff --git a/gst/printf/printf-args.c b/gst/printf/printf-args.c new file mode 100644 index 000000000..5ca693cc5 --- /dev/null +++ b/gst/printf/printf-args.c @@ -0,0 +1,132 @@ +/* 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 <config.h> +#endif + +#include "gst-printf.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 +#ifdef HAVE_INT64_AND_I64 + case TYPE_INT64: + ap->a.a_int64 = va_arg (args, __int64); + break; + case TYPE_UINT64: + ap->a.a_uint64 = va_arg (args, unsigned __int64); + 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: +#ifdef _WIN32 + ap->a.a_wide_char = va_arg (args, int); +#else + ap->a.a_wide_char = va_arg (args, wint_t); +#endif + 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/gst/printf/printf-args.h b/gst/printf/printf-args.h new file mode 100644 index 000000000..082567568 --- /dev/null +++ b/gst/printf/printf-args.h @@ -0,0 +1,142 @@ +/* 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 <stddef.h> +#endif + +/* Get wint_t. */ +#ifdef HAVE_WINT_T +# include <wchar.h> +#endif + +/* Get va_list. */ +#include <stdarg.h> + + +/* 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 +#ifdef HAVE_INT64_AND_I64 + TYPE_INT64, + TYPE_UINT64, +#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 +#ifdef HAVE_INT64_AND_I64 + __int64 a_int64; + unsigned __int64 a_uint64; +#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/gst/printf/printf-parse.c b/gst/printf/printf-parse.c new file mode 100644 index 000000000..933867b39 --- /dev/null +++ b/gst/printf/printf-parse.c @@ -0,0 +1,449 @@ +/* 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 <config.h> +#endif + +#include "gst-printf.h" + +/* Specification. */ +#include "printf-parse.h" + +/* Get size_t, NULL. */ +#include <stddef.h> + +/* Get intmax_t. */ +#if HAVE_STDINT_H_WITH_UINTMAX +# include <stdint.h> +#endif +#if HAVE_INTTYPES_H_WITH_UINTMAX +# include <inttypes.h> +#endif + +/* malloc(), realloc(), free(). */ +#include <stdlib.h> + +#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_INT64_AND_I64 + else if (cp[0] == 'I' && cp[1] == '6' && cp[2] == '4') { + flags = 64; + cp += 3; + } +#endif +#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_INT64_AND_I64 + if (flags == 64) + type = TYPE_INT64; + else +#endif +#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_INT64_AND_I64 + if (flags == 64) + type = TYPE_UINT64; + else +#endif +#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/gst/printf/printf-parse.h b/gst/printf/printf-parse.h new file mode 100644 index 000000000..a76cecf5d --- /dev/null +++ b/gst/printf/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 __gst_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/gst/printf/printf.c b/gst/printf/printf.c new file mode 100644 index 000000000..ea0b68089 --- /dev/null +++ b/gst/printf/printf.c @@ -0,0 +1,157 @@ +/* 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 <config.h> +#endif +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include "gst-printf.h" +#include "vasnprintf.h" +#include "printf.h" + +int +__gst_printf (char const *format, ...) +{ + va_list args; + int retval; + + va_start (args, format); + retval = __gst_vprintf (format, args); + va_end (args); + + return retval; +} + +int +__gst_fprintf (FILE * file, char const *format, ...) +{ + va_list args; + int retval; + + va_start (args, format); + retval = __gst_vfprintf (file, format, args); + va_end (args); + + return retval; +} + +int +__gst_sprintf (char *string, char const *format, ...) +{ + va_list args; + int retval; + + va_start (args, format); + retval = __gst_vsprintf (string, format, args); + va_end (args); + + return retval; +} + +int +__gst_snprintf (char *string, size_t n, char const *format, ...) +{ + va_list args; + int retval; + + va_start (args, format); + retval = __gst_vsnprintf (string, n, format, args); + va_end (args); + + return retval; +} + +int +__gst_vprintf (char const *format, va_list args) +{ + return __gst_vfprintf (stdout, format, args); +} + +int +__gst_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, file); + free (result); + + return length; +} + +int +__gst_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 +__gst_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 +__gst_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/gst/printf/printf.h b/gst/printf/printf.h new file mode 100644 index 000000000..f39cf5432 --- /dev/null +++ b/gst/printf/printf.h @@ -0,0 +1,62 @@ +/* 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 <stdarg.h> +#include <stdio.h> + +int __gst_printf (char const *format, + ...); + +int __gst_fprintf (FILE *file, + char const *format, + ...); + +int __gst_sprintf (char *string, + char const *format, + ...); + +int __gst_snprintf (char *string, + size_t n, + char const *format, + ...); + +int __gst_vprintf (char const *format, + va_list args); + +int __gst_vfprintf (FILE *file, + char const *format, + va_list args); + +int __gst_vsprintf (char *string, + char const *format, + va_list args); + +int __gst_vsnprintf (char *string, + size_t n, + char const *format, + va_list args); + +int __gst_vasprintf (char **result, + char const *format, + va_list args); + + +#endif /* __GNULIB_PRINTF_H__ */ diff --git a/gst/printf/vasnprintf.c b/gst/printf/vasnprintf.c new file mode 100644 index 000000000..ef6a9e13d --- /dev/null +++ b/gst/printf/vasnprintf.c @@ -0,0 +1,980 @@ +/* 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. */ + +#ifndef _WIN32 +/* Tell glibc's <stdio.h> to provide a prototype for snprintf(). + This must come before <config.h> because <config.h> may include + <features.h>, and once <features.h> has been included, it's too late. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +#endif + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "gst-printf.h" + +/* Specification. */ +#include "vasnprintf.h" + +#include <stdio.h> /* snprintf(), sprintf() */ +#include <stdlib.h> /* abort(), malloc(), realloc(), free() */ +#include <string.h> /* memcpy(), strlen() */ +#include <errno.h> /* errno */ +#include <limits.h> /* CHAR_BIT */ +#include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP */ +#include "printf-parse.h" + +#ifdef HAVE_WCHAR_T +# ifdef HAVE_WCSLEN +# define local_wcslen wcslen +# else + /* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid + a dependency towards this library, here is a local substitute. + Define this substitute only once, even if this file is included + twice in the same compilation unit. */ +# ifndef local_wcslen_defined +# define local_wcslen_defined 1 +static size_t +local_wcslen (const wchar_t * s) +{ + const wchar_t *ptr; + + for (ptr = s; *ptr != (wchar_t) 0; ptr++); + return ptr - s; +} +# endif +# endif +#endif + +/* For those losing systems which don't have 'alloca' we have to add + some additional code emulating it. */ +#ifdef GLIB_HAVE_ALLOCA_H +# 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; + while (digitp != dp->precision_end) + precision = precision * 10 + (*digitp++ - '0'); + } + } + + 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 +# ifdef HAVE_INT64_AND_I64 + if (type == TYPE_INT64 || type == TYPE_UINT64) + tmp_length = (unsigned int) (sizeof (unsigned __int64) * 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 = (a.arg[dp->arg_index].a.a_wide_string == NULL ? 6 /* wcslen(L"(null)") */ + : local_wcslen (a.arg[dp->arg_index].a.a_wide_string)) + * MB_CUR_MAX; + else +# endif + tmp_length = a.arg[dp->arg_index].a.a_string == NULL ? 6 /* strlen("(null)") */ + : 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_INT64_AND_I64 + case TYPE_INT64: + case TYPE_UINT64: + *p++ = 'I'; + *p++ = '6'; + *p++ = '4'; + break; +#endif +#ifdef HAVE_LONG_LONG + case TYPE_LONGLONGINT: + case TYPE_ULONGLONGINT: +#ifdef HAVE_INT64_AND_I64 /* The system (sn)printf uses %I64. Also assume + * that long long == __int64. + */ + *p++ = 'I'; + *p++ = '6'; + *p++ = '4'; + break; +#else + *p++ = 'l'; + /*FALLTHROUGH*/ +#endif +#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; +#if HAVE_SNPRINTF + int retcount; +#endif + + maxlen = allocated - length; + count = -1; + +#if HAVE_SNPRINTF + retcount = 0; + +#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_INT64_AND_I64 + case TYPE_INT64: + { + __int64 arg = a.arg[dp->arg_index].a.a_int64; + SNPRINTF_BUF (arg); + } + break; + case TYPE_UINT64: + { + unsigned __int64 arg = a.arg[dp->arg_index].a.a_uint64; + SNPRINTF_BUF (arg); + } + break; +#endif +#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); + } + } +#if HAVE_SNPRINTF + count = print_long_long (result + length, maxlen, + width, precision, dp->flags, dp->conversion, arg); +#else + count = print_long_long (tmp, tmp_length, + width, precision, dp->flags, dp->conversion, arg); +#endif + } + 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 == NULL + ? "(null)" : 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 == + NULL ? L"(null)" : 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/gst/printf/vasnprintf.h b/gst/printf/vasnprintf.h new file mode 100644 index 000000000..65f1bc13d --- /dev/null +++ b/gst/printf/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 <stdarg.h> + +/* Get size_t. */ +#include <stddef.h> + +#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 */ |