printf: add our own printf implementation for debug logging

We will add support for our own printf modifiers, so we can
get nice debug log output on all operating systems irrespective
of the specific libc version used.

https://bugzilla.gnome.org/show_bug.cgi?id=613081
This commit is contained in:
Tim-Philipp Müller 2013-03-30 15:13:32 +00:00 committed by Tim-Philipp Müller
parent f45c84db02
commit 8fc876f09f
14 changed files with 2230 additions and 2 deletions

View file

@ -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

View file

@ -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)

18
gst/printf/Makefile.am Normal file
View file

@ -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

58
gst/printf/README Normal file
View file

@ -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.

40
gst/printf/asnprintf.c Normal file
View file

@ -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;
}

48
gst/printf/gst-printf.h Normal file
View file

@ -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__ */

132
gst/printf/printf-args.c Normal file
View file

@ -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;
}

142
gst/printf/printf-args.h Normal file
View file

@ -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 */

449
gst/printf/printf-parse.c Normal file
View file

@ -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;
}

74
gst/printf/printf-parse.h Normal file
View file

@ -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 */

157
gst/printf/printf.c Normal file
View file

@ -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;
}

62
gst/printf/printf.h Normal file
View file

@ -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__ */

980
gst/printf/vasnprintf.c Normal file
View file

@ -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;
}
}

61
gst/printf/vasnprintf.h Normal file
View file

@ -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 */