mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-14 20:14:17 +00:00
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:
parent
f45c84db02
commit
8fc876f09f
14 changed files with 2230 additions and 2 deletions
|
@ -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
|
||||
|
|
|
@ -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
18
gst/printf/Makefile.am
Normal 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
58
gst/printf/README
Normal 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
40
gst/printf/asnprintf.c
Normal 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
48
gst/printf/gst-printf.h
Normal 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
132
gst/printf/printf-args.c
Normal 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
142
gst/printf/printf-args.h
Normal 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
449
gst/printf/printf-parse.c
Normal 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
74
gst/printf/printf-parse.h
Normal 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
157
gst/printf/printf.c
Normal 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
62
gst/printf/printf.h
Normal 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
980
gst/printf/vasnprintf.c
Normal 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
61
gst/printf/vasnprintf.h
Normal 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 */
|
Loading…
Reference in a new issue