Right, I'll work on those. What is vsnformat?
John Darrington <j...@darrington.wattle.id.au> 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 <j...@darrington.wattle.id.au> 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