[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: C locale *printf functions ?
From: |
Ben Pfaff |
Subject: |
Re: C locale *printf functions ? |
Date: |
Mon, 10 Dec 2012 10:34:07 -0800 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/23.4 (gnu/linux) |
Right, I'll work on those.
What is vsnformat?
John Darrington <address@hidden> writes:
> I gave it a rudimentary test and it seems to do what I want.
> I will also need other related functions, though, Eg xasprintf,
> vsnformat, etc.
>
> J'
>
> On Thu, Dec 06, 2012 at 10:59:44PM -0800, Ben Pfaff wrote:
> John Darrington <address@hidden> writes:
>
> > Gnulib has a number of c-* variants of string processing functions,
> > eg c-strtod, c-strcasecmp etc But notably absent are any locale
> > independent printf routines. We could use some in PSPP.
>
> Here's some initial work on that. It only defines c_snprintf()
> so far. The test passes for me.
>
> Comments are welcome, from anyone.
>
> ---
> lib/c-snprintf.c | 74
> ++++++++++++++++++++++++++++++++++++++++++++
> lib/c-snprintf.h | 46 ++++++++++++++++++++++++++++
> lib/c-vasnprintf.c | 43 ++++++++++++++++++++++++++
> lib/c-vasnprintf.h | 76
> ++++++++++++++++++++++++++++++++++++++++++++++
> modules/c-snprintf | 23 ++++++++++++++
> modules/c-snprintf-tests | 17 +++++++++++
> modules/c-vasnprintf | 55 +++++++++++++++++++++++++++++++++
> tests/test-c-snprintf.c | 58 +++++++++++++++++++++++++++++++++++
> tests/test-c-snprintf.sh | 15 +++++++++
> 9 files changed, 407 insertions(+)
> create mode 100644 lib/c-snprintf.c
> create mode 100644 lib/c-snprintf.h
> create mode 100644 lib/c-vasnprintf.c
> create mode 100644 lib/c-vasnprintf.h
> create mode 100644 modules/c-snprintf
> create mode 100644 modules/c-snprintf-tests
> create mode 100644 modules/c-vasnprintf
> create mode 100644 tests/test-c-snprintf.c
> create mode 100755 tests/test-c-snprintf.sh
>
> diff --git a/lib/c-snprintf.c b/lib/c-snprintf.c
> new file mode 100644
> index 0000000..2dadbfc
> --- /dev/null
> +++ b/lib/c-snprintf.c
> @@ -0,0 +1,74 @@
> +/* Formatted output to strings in C locale.
> + Copyright (C) 2004, 2006-2012 Free Software Foundation, Inc.
> + Written by Simon Josefsson, Paul Eggert, and Ben Pfaff.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3, 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 General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> along
> + with this program; if not, see <http://www.gnu.org/licenses/>. */
> +
> +#include <config.h>
> +
> +/* Specification. */
> +#include <stdio.h>
> +
> +#include <errno.h>
> +#include <limits.h>
> +#include <stdarg.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#include "c-vasnprintf.h"
> +
> +/* Print formatted output to string STR. Similar to sprintf, but
> + additional length SIZE limit how much is written into STR. Returns
> + string length of formatted string (which may be larger than SIZE).
> + STR may be NULL, in which case nothing will be written. On error,
> + return a negative value.
> +
> + Formatting takes place in the C locale, that is, the decimal point
> + used in floating-point formatting directives is always '.'. */
> +int
> +c_snprintf (char *str, size_t size, const char *format, ...)
> +{
> + char *output;
> + size_t len;
> + size_t lenbuf = size;
> + va_list args;
> +
> + va_start (args, format);
> + output = c_vasnprintf (str, &lenbuf, format, args);
> + len = lenbuf;
> + va_end (args);
> +
> + if (!output)
> + return -1;
> +
> + if (output != str)
> + {
> + if (size)
> + {
> + size_t pruned_len = (len < size ? len : size - 1);
> + memcpy (str, output, pruned_len);
> + str[pruned_len] = '\0';
> + }
> +
> + free (output);
> + }
> +
> + if (INT_MAX < len)
> + {
> + errno = EOVERFLOW;
> + return -1;
> + }
> +
> + return len;
> +}
> diff --git a/lib/c-snprintf.h b/lib/c-snprintf.h
> new file mode 100644
> index 0000000..3192a2d
> --- /dev/null
> +++ b/lib/c-snprintf.h
> @@ -0,0 +1,46 @@
> +/* vsprintf with automatic memory allocation in C locale.
> + Copyright (C) 2002-2004, 2007-2012 Free Software Foundation, Inc.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3, 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 General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> along
> + with this program; if not, see <http://www.gnu.org/licenses/>. */
> +
> +#ifndef _C_SNPRINTF_H
> +#define _C_SNPRINTF_H
> +
> +/* Get size_t. */
> +#include <stddef.h>
> +
> +/* The __attribute__ feature is available in gcc versions 2.5 and later.
> + The __-protected variants of the attributes 'format' and 'printf' are
> + accepted by gcc versions 2.6.4 (effectively 2.7) and later.
> + We enable _GL_ATTRIBUTE_FORMAT only if these are supported too,
> because
> + gnulib and libintl do '#define printf __printf__' when they override
> + the 'printf' function. */
> +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
> +# define _GL_ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec))
> +#else
> +# define _GL_ATTRIBUTE_FORMAT(spec) /* empty */
> +#endif
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +int c_snprintf (char *str, size_t size, const char *format, ...)
> + _GL_ATTRIBUTE_FORMAT ((__printf__, 3, 4));
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif /* _C_SNPRINTF_H */
> diff --git a/lib/c-vasnprintf.c b/lib/c-vasnprintf.c
> new file mode 100644
> index 0000000..af6ca08
> --- /dev/null
> +++ b/lib/c-vasnprintf.c
> @@ -0,0 +1,43 @@
> +/* Formatted output to strings in C locale.
> + Copyright (C) 2009-2012 Free Software Foundation, Inc.
> +
> + This program is free software: you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, 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 General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see
> <http://www.gnu.org/licenses/>. */
> +
> +#include <config.h>
> +
> +#include <string.h>
> +
> +#include "printf-parse.h"
> +
> +#define VASNPRINTF c_vasnprintf
> +#define FCHAR_T char
> +#define DCHAR_T char
> +#define DIRECTIVE char_directive
> +#define DIRECTIVES char_directives
> +#define PRINTF_PARSE printf_parse
> +#define DCHAR_CPY memcpy
> +#define DCHAR_SET memset
> +#define DCHAR_IS_TCHAR 1
> +#define TCHAR_T char
> +
> +#define NEED_PRINTF_DOUBLE 1
> +#define NEED_PRINTF_LONG_DOUBLE 1
> +#define decimal_point_char_defined 1
> +static char
> +decimal_point_char (void)
> +{
> + return '.';
> +}
> +
> +#include "vasnprintf.c"
> diff --git a/lib/c-vasnprintf.h b/lib/c-vasnprintf.h
> new file mode 100644
> index 0000000..8fc1724
> --- /dev/null
> +++ b/lib/c-vasnprintf.h
> @@ -0,0 +1,76 @@
> +/* vsprintf with automatic memory allocation in C locale.
> + Copyright (C) 2002-2004, 2007-2012 Free Software Foundation, Inc.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3, 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 General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> along
> + with this program; if not, see <http://www.gnu.org/licenses/>. */
> +
> +#ifndef _C_VASNPRINTF_H
> +#define _C_VASNPRINTF_H
> +
> +/* Get va_list. */
> +#include <stdarg.h>
> +
> +/* Get size_t. */
> +#include <stddef.h>
> +
> +/* The __attribute__ feature is available in gcc versions 2.5 and later.
> + The __-protected variants of the attributes 'format' and 'printf' are
> + accepted by gcc versions 2.6.4 (effectively 2.7) and later.
> + We enable _GL_ATTRIBUTE_FORMAT only if these are supported too,
> because
> + gnulib and libintl do '#define printf __printf__' when they override
> + the 'printf' function. */
> +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
> +# define _GL_ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec))
> +#else
> +# define _GL_ATTRIBUTE_FORMAT(spec) /* empty */
> +#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.
> +
> + When dynamic memory allocation occurs, the preallocated buffer is
> left
> + alone (with possibly modified contents). This makes it possible to
> use
> + a statically allocated or stack-allocated buffer, like this:
> +
> + char buf[100];
> + size_t len = sizeof (buf);
> + char *output = vasnprintf (buf, &len, format, args);
> + if (output == NULL)
> + ... error handling ...;
> + else
> + {
> + ... use the output string ...;
> + if (output != buf)
> + free (output);
> + }
> +
> + Formatting takes place in the C locale, that is, the decimal point
> used in
> + floating-point formatting directives is always '.'.
> + */
> +extern char *c_vasnprintf (char *resultbuf, size_t *lengthp, const char
> *format, va_list args)
> + _GL_ATTRIBUTE_FORMAT ((__printf__, 3, 0));
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif /* _C_VASNPRINTF_H */
> diff --git a/modules/c-snprintf b/modules/c-snprintf
> new file mode 100644
> index 0000000..edebe2b
> --- /dev/null
> +++ b/modules/c-snprintf
> @@ -0,0 +1,23 @@
> +Description:
> +c_snprintf(): print formatted output to a fixed length string in C
> locale
> +
> +Files:
> +lib/c-snprintf.h
> +lib/c-snprintf.c
> +
> +Depends-on:
> +c-vasnprintf
> +
> +configure.ac:
> +
> +Makefile.am:
> +lib_SOURCES += c-snprintf.c
> +
> +Include:
> +"c-snprintf.h"
> +
> +License:
> +GPL
> +
> +Maintainer:
> +Ben Pfaff
> diff --git a/modules/c-snprintf-tests b/modules/c-snprintf-tests
> new file mode 100644
> index 0000000..86d6a14
> --- /dev/null
> +++ b/modules/c-snprintf-tests
> @@ -0,0 +1,17 @@
> +Files:
> +tests/test-c-snprintf.c
> +tests/test-c-snprintf.sh
> +m4/locale-fr.m4
> +tests/macros.h
> +
> +Depends-on:
> +setlocale
> +snprintf
> +
> +configure.ac:
> +gt_LOCALE_FR
> +
> +Makefile.am:
> +TESTS += test-c-snprintf.sh
> +check_PROGRAMS += test-c-snprintf
> +TESTS_ENVIRONMENT += LOCALE_FR='@LOCALE_FR@'
> diff --git a/modules/c-vasnprintf b/modules/c-vasnprintf
> new file mode 100644
> index 0000000..cd94193
> --- /dev/null
> +++ b/modules/c-vasnprintf
> @@ -0,0 +1,55 @@
> +Description:
> +Formatted output to strings in C locale.
> +
> +Files:
> +lib/c-vasnprintf.h
> +lib/c-vasnprintf.c
> +lib/float+.h
> +lib/printf-args.h
> +lib/printf-args.c
> +lib/printf-parse.h
> +lib/printf-parse.c
> +lib/vasnprintf.h
> +lib/vasnprintf.c
> +m4/wchar_t.m4
> +m4/wint_t.m4
> +m4/longlong.m4
> +m4/intmax_t.m4
> +m4/stdint_h.m4
> +m4/inttypes_h.m4
> +m4/vasnprintf.m4
> +m4/printf.m4
> +m4/math_h.m4
> +m4/exponentd.m4
> +
> +Depends-on:
> +isnand-nolibm
> +isnanl-nolibm
> +frexpl-nolibm
> +printf-frexp
> +printf-frexpl
> +signbit
> +fpucw
> +nocrash
> +printf-safe
> +alloca-opt
> +xsize
> +errno
> +memchr
> +multiarch
> +verify
> +
> +configure.ac:
> +gl_PREREQ_VASNPRINTF_WITH_EXTRAS
> +
> +Makefile.am:
> +lib_SOURCES += c-vasnprintf.c
> +
> +Include:
> +"c-vasnprintf.h"
> +
> +License:
> +GPL
> +
> +Maintainer:
> +Ben Pfaff
> diff --git a/tests/test-c-snprintf.c b/tests/test-c-snprintf.c
> new file mode 100644
> index 0000000..9da5443
> --- /dev/null
> +++ b/tests/test-c-snprintf.c
> @@ -0,0 +1,58 @@
> +/* Test of snprintf() function.
> + Copyright (C) 2011-2012 Free Software Foundation, Inc.
> +
> + This program is free software: you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, 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 General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see
> <http://www.gnu.org/licenses/>. */
> +
> +#include <config.h>
> +
> +#include "c-snprintf.h"
> +
> +#include <locale.h>
> +#include <stdio.h>
> +#include <string.h>
> +
> +#include "macros.h"
> +
> +int
> +main (int argc, char *argv[])
> +{
> + /* configure should already have checked that the locale is
> supported. */
> + if (setlocale (LC_ALL, "") == NULL)
> + return 1;
> +
> + /* Test behaviour of snprintf() as a "control group".
> + (We should be running in a locale where ',' is the decimal point.)
> */
> + {
> + char s[16];
> +
> + snprintf (s, sizeof s, "%#.0f", 1.0);
> + if (!strcmp (s, "1."))
> + {
> + /* Skip the test, since we're not in a useful locale for
> testing. */
> + return 77;
> + }
> + ASSERT (!strcmp (s, "1,"));
> + }
> +
> + /* Test behaviour of c_snprintf().
> + It should always use '.' as the decimal point. */
> + {
> + char s[16];
> +
> + c_snprintf (s, sizeof s, "%#.0f", 1.0);
> + ASSERT (!strcmp (s, "1."));
> + }
> +
> + return 0;
> +}
> diff --git a/tests/test-c-snprintf.sh b/tests/test-c-snprintf.sh
> new file mode 100755
> index 0000000..83051fc
> --- /dev/null
> +++ b/tests/test-c-snprintf.sh
> @@ -0,0 +1,15 @@
> +#!/bin/sh
> +
> +# Test in an ISO-8859-1 or ISO-8859-15 locale.
> +: ${LOCALE_FR=fr_FR}
> +if test $LOCALE_FR = none; then
> + if test -f /usr/bin/localedef; then
> + echo "Skipping test: no traditional french locale is installed"
> + else
> + echo "Skipping test: no traditional french locale is supported"
> + fi
> + exit 77
> +fi
> +
> +LC_ALL=$LOCALE_FR \
> +./test-c-snprintf${EXEEXT} 1
> --
> 1.7.10.4