summaryrefslogtreecommitdiffabout
path: root/lib
authorSergey Poznyakoff <gray@gnu.org.ua>2005-02-23 15:09:34 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2005-02-23 15:09:34 (GMT)
commit2db5c7115e5b37734993603c0381aab7e62c4be9 (patch) (side-by-side diff)
tree1be931195d1bf1c22bf9a5ca53b9cad9263be6bb /lib
parent96aac32803af5414ffeec13a16205d7c456df19d (diff)
downloadmailutils-2db5c7115e5b37734993603c0381aab7e62c4be9.tar.gz
mailutils-2db5c7115e5b37734993603c0381aab7e62c4be9.tar.bz2
Updated by gnulib-sync
Diffstat (limited to 'lib') (more/less context) (ignore whitespace changes)
-rw-r--r--lib/setenv.c334
-rw-r--r--lib/snprintf.c886
-rw-r--r--lib/snprintf.h223
-rw-r--r--lib/vasprintf.c208
-rw-r--r--lib/xalloc.h94
-rw-r--r--lib/xmalloc.c238
-rw-r--r--lib/xstrtol.c163
-rw-r--r--lib/xstrtol.h55
8 files changed, 680 insertions, 1521 deletions
diff --git a/lib/setenv.c b/lib/setenv.c
index ba965fa..320469b 100644
--- a/lib/setenv.c
+++ b/lib/setenv.c
@@ -1,130 +1,276 @@
-/* Copyright (C) 1992, 1995, 1996, 1997, 2001 Free Software Foundation, Inc.
- This file based on setenv.c in the GNU C Library.
+/* Copyright (C) 1992,1995-1999,2000-2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
- The GNU C Library 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 of the
- License, or (at your option) any later version.
+ 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 2, or (at your option)
+ any later version.
- The GNU C Library is distributed in the hope that it will be useful,
+ 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.
+ 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 Library General Public
- License along with the GNU C Library; see the file COPYING.LIB. If not,
- write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ You should have received a copy of the GNU 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. */
#if HAVE_CONFIG_H
# include <config.h>
#endif
+#include <alloca.h>
#include <errno.h>
-
-#if HAVE_STDLIB_H
-# include <stdlib.h>
-#else
-#include <sys/types.h> /* For `size_t' */
-#include <stdio.h> /* For `NULL' */
-#endif
-#if HAVE_STRING_H
-# include <string.h>
+#ifndef __set_errno
+# define __set_errno(ev) ((errno) = (ev))
#endif
-#if HAVE_UNISTD_H
+
+#include <stdlib.h>
+#include <string.h>
+#if _LIBC || HAVE_UNISTD_H
# include <unistd.h>
#endif
-#define __environ environ
+#if !_LIBC
+# include "allocsa.h"
+#endif
+
+#if !_LIBC
+# define __environ environ
+# ifndef HAVE_ENVIRON_DECL
extern char **environ;
+# endif
+#endif
+
+#if _LIBC
+/* This lock protects against simultaneous modifications of `environ'. */
+# include <bits/libc-lock.h>
+__libc_lock_define_initialized (static, envlock)
+# define LOCK __libc_lock_lock (envlock)
+# define UNLOCK __libc_lock_unlock (envlock)
+#else
+# define LOCK
+# define UNLOCK
+#endif
+
+/* In the GNU C library we must keep the namespace clean. */
+#ifdef _LIBC
+# define setenv __setenv
+# define clearenv __clearenv
+# define tfind __tfind
+# define tsearch __tsearch
+#endif
+
+/* In the GNU C library implementation we try to be more clever and
+ allow arbitrarily many changes of the environment given that the used
+ values are from a small set. Outside glibc this will eat up all
+ memory after a while. */
+#if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \
+ && defined __GNUC__)
+# define USE_TSEARCH 1
+# include <search.h>
+typedef int (*compar_fn_t) (const void *, const void *);
+
+/* This is a pointer to the root of the search tree with the known
+ values. */
+static void *known_values;
-/* LOCK and UNLOCK are defined as no-ops. This makes the libiberty
- * implementation MT-Unsafe. */
-#define LOCK
-#define UNLOCK
+# define KNOWN_VALUE(Str) \
+ ({ \
+ void *value = tfind (Str, &known_values, (compar_fn_t) strcmp); \
+ value != NULL ? *(char **) value : NULL; \
+ })
+# define STORE_VALUE(Str) \
+ tsearch (Str, &known_values, (compar_fn_t) strcmp)
+
+#else
+# undef USE_TSEARCH
+
+# define KNOWN_VALUE(Str) NULL
+# define STORE_VALUE(Str) do { } while (0)
+
+#endif
-/* Below this point, it's verbatim code from the glibc-2.0 implementation */
/* If this variable is not a null pointer we allocated the current
environment. */
static char **last_environ;
+/* This function is used by `setenv' and `putenv'. The difference between
+ the two functions is that for the former must create a new string which
+ is then placed in the environment, while the argument of `putenv'
+ must be used directly. This is all complicated by the fact that we try
+ to reuse values once generated for a `setenv' call since we can never
+ free the strings. */
int
-setenv (name, value, replace)
- const char *name;
- const char *value;
- int replace;
+__add_to_environ (const char *name, const char *value, const char *combined,
+ int replace)
{
register char **ep;
register size_t size;
const size_t namelen = strlen (name);
- const size_t vallen = strlen (value) + 1;
+ const size_t vallen = value != NULL ? strlen (value) + 1 : 0;
LOCK;
+ /* We have to get the pointer now that we have the lock and not earlier
+ since another thread might have created a new environment. */
+ ep = __environ;
+
size = 0;
- if (__environ != NULL)
- for (ep = __environ; *ep != NULL; ++ep)
- if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
- break;
- else
- ++size;
+ if (ep != NULL)
+ {
+ for (; *ep != NULL; ++ep)
+ if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
+ break;
+ else
+ ++size;
+ }
- if (__environ == NULL || *ep == NULL)
+ if (ep == NULL || *ep == NULL)
{
char **new_environ;
- if (__environ == last_environ && __environ != NULL)
- /* We allocated this space; we can extend it. */
- new_environ = (char **) realloc (last_environ,
- (size + 2) * sizeof (char *));
- else
- new_environ = (char **) malloc ((size + 2) * sizeof (char *));
+#ifdef USE_TSEARCH
+ char *new_value;
+#endif
+ /* We allocated this space; we can extend it. */
+ new_environ =
+ (char **) (last_environ == NULL
+ ? malloc ((size + 2) * sizeof (char *))
+ : realloc (last_environ, (size + 2) * sizeof (char *)));
if (new_environ == NULL)
{
UNLOCK;
return -1;
}
- new_environ[size] = malloc (namelen + 1 + vallen);
- if (new_environ[size] == NULL)
+ /* If the whole entry is given add it. */
+ if (combined != NULL)
+ /* We must not add the string to the search tree since it belongs
+ to the user. */
+ new_environ[size] = (char *) combined;
+ else
{
- free ((char *) new_environ);
- errno = ENOMEM;
- UNLOCK;
- return -1;
+ /* See whether the value is already known. */
+#ifdef USE_TSEARCH
+# ifdef _LIBC
+ new_value = (char *) alloca (namelen + 1 + vallen);
+ __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
+ value, vallen);
+# else
+ new_value = (char *) allocsa (namelen + 1 + vallen);
+ if (new_value == NULL)
+ {
+ __set_errno (ENOMEM);
+ UNLOCK;
+ return -1;
+ }
+ memcpy (new_value, name, namelen);
+ new_value[namelen] = '=';
+ memcpy (&new_value[namelen + 1], value, vallen);
+# endif
+
+ new_environ[size] = KNOWN_VALUE (new_value);
+ if (new_environ[size] == NULL)
+#endif
+ {
+ new_environ[size] = (char *) malloc (namelen + 1 + vallen);
+ if (new_environ[size] == NULL)
+ {
+#if defined USE_TSEARCH && !defined _LIBC
+ freesa (new_value);
+#endif
+ __set_errno (ENOMEM);
+ UNLOCK;
+ return -1;
+ }
+
+#ifdef USE_TSEARCH
+ memcpy (new_environ[size], new_value, namelen + 1 + vallen);
+#else
+ memcpy (new_environ[size], name, namelen);
+ new_environ[size][namelen] = '=';
+ memcpy (&new_environ[size][namelen + 1], value, vallen);
+#endif
+ /* And save the value now. We cannot do this when we remove
+ the string since then we cannot decide whether it is a
+ user string or not. */
+ STORE_VALUE (new_environ[size]);
+ }
+#if defined USE_TSEARCH && !defined _LIBC
+ freesa (new_value);
+#endif
}
if (__environ != last_environ)
memcpy ((char *) new_environ, (char *) __environ,
size * sizeof (char *));
- memcpy (new_environ[size], name, namelen);
- new_environ[size][namelen] = '=';
- memcpy (&new_environ[size][namelen + 1], value, vallen);
-
new_environ[size + 1] = NULL;
last_environ = __environ = new_environ;
}
else if (replace)
{
- size_t len = strlen (*ep);
- if (len + 1 < namelen + 1 + vallen)
+ char *np;
+
+ /* Use the user string if given. */
+ if (combined != NULL)
+ np = (char *) combined;
+ else
{
- /* The existing string is too short; malloc a new one. */
- char *new = malloc (namelen + 1 + vallen);
- if (new == NULL)
+#ifdef USE_TSEARCH
+ char *new_value;
+# ifdef _LIBC
+ new_value = alloca (namelen + 1 + vallen);
+ __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
+ value, vallen);
+# else
+ new_value = allocsa (namelen + 1 + vallen);
+ if (new_value == NULL)
{
+ __set_errno (ENOMEM);
UNLOCK;
return -1;
}
- *ep = new;
+ memcpy (new_value, name, namelen);
+ new_value[namelen] = '=';
+ memcpy (&new_value[namelen + 1], value, vallen);
+# endif
+
+ np = KNOWN_VALUE (new_value);
+ if (np == NULL)
+#endif
+ {
+ np = malloc (namelen + 1 + vallen);
+ if (np == NULL)
+ {
+#if defined USE_TSEARCH && !defined _LIBC
+ freesa (new_value);
+#endif
+ __set_errno (ENOMEM);
+ UNLOCK;
+ return -1;
+ }
+
+#ifdef USE_TSEARCH
+ memcpy (np, new_value, namelen + 1 + vallen);
+#else
+ memcpy (np, name, namelen);
+ np[namelen] = '=';
+ memcpy (&np[namelen + 1], value, vallen);
+#endif
+ /* And remember the value. */
+ STORE_VALUE (np);
+ }
+#if defined USE_TSEARCH && !defined _LIBC
+ freesa (new_value);
+#endif
}
- memcpy (*ep, name, namelen);
- (*ep)[namelen] = '=';
- memcpy (&(*ep)[namelen + 1], value, vallen);
+
+ *ep = np;
}
UNLOCK;
@@ -132,25 +278,51 @@ setenv (name, value, replace)
return 0;
}
-void
-unsetenv (name)
- const char *name;
+int
+setenv (const char *name, const char *value, int replace)
{
- const size_t len = strlen (name);
- char **ep;
+ return __add_to_environ (name, value, NULL, replace);
+}
+/* The `clearenv' was planned to be added to POSIX.1 but probably
+ never made it. Nevertheless the POSIX.9 standard (POSIX bindings
+ for Fortran 77) requires this function. */
+int
+clearenv (void)
+{
LOCK;
- for (ep = __environ; *ep; ++ep)
- if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
- {
- /* Found it. Remove this pointer by moving later ones back. */
- char **dp = ep;
- do
- dp[0] = dp[1];
- while (*dp++);
- /* Continue the loop in case NAME appears again. */
- }
+ if (__environ == last_environ && __environ != NULL)
+ {
+ /* We allocated this environment so we can free it. */
+ free (__environ);
+ last_environ = NULL;
+ }
+
+ /* Clear the environment pointer removes the whole environment. */
+ __environ = NULL;
UNLOCK;
+
+ return 0;
+}
+
+#ifdef _LIBC
+static void
+free_mem (void)
+{
+ /* Remove all traces. */
+ clearenv ();
+
+ /* Now remove the search tree. */
+ __tdestroy (known_values, free);
+ known_values = NULL;
}
+text_set_element (__libc_subfreeres, free_mem);
+
+
+# undef setenv
+# undef clearenv
+weak_alias (__setenv, setenv)
+weak_alias (__clearenv, clearenv)
+#endif
diff --git a/lib/snprintf.c b/lib/snprintf.c
index 57ffb6c..9a4edc1 100644
--- a/lib/snprintf.c
+++ b/lib/snprintf.c
@@ -1,868 +1,60 @@
-
-/*
- Unix snprintf implementation.
- Version 1.3
+/* Formatted output to strings.
+ Copyright (C) 2004 Free Software Foundation, Inc.
+ Written by Simon Josefsson.
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 of the License, or
- (at your option) any later version.
+ it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Revision History:
-
- 1.3:
- * add #include <config.h> ifdef HAVE_CONFIG_H
- * cosmetic change, when exponent is 0 print xxxE+00
- instead of xxxE-00
- 1.2:
- * put the program under LGPL.
- 1.1:
- * added changes from Miles Bader
- * corrected a bug with %f
- * added support for %#g
- * added more comments :-)
- 1.0:
- * supporting must ANSI syntaxic_sugars
- 0.0:
- * suppot %s %c %d
-
- THANKS(for the patches and ideas):
- Miles Bader
- Cyrille Rustom
- Jacek Slabocewiz
- Mike Parker(mouse)
-
-*/
-
-#include "snprintf.h"
-
-/*
- * Find the nth power of 10
- */
-PRIVATE double
-#ifdef __STDC__
-pow_10(int n)
-#else
-pow_10(n)
-int n;
-#endif
-{
- int i;
- double P;
-
- if (n < 0)
- for (i = 1, P = 1., n = -n ; i <= n ; i++) {P *= .1;}
- else
- for (i = 1, P = 1. ; i <= n ; i++) {P *= 10.0;}
- return P;
-}
-
-/*
- * Find the integral part of the log in base 10
- * Note: this not a real log10()
- I just need and approximation(integerpart) of x in:
- 10^x ~= r
- * log_10(200) = 2;
- * log_10(250) = 2;
- */
-PRIVATE int
-#ifdef __STDC__
-log_10(double r)
-#else
-log_10(r)
-double r;
-#endif
-{
- int i = 0;
- double result = 1.;
-
- if (r < 0.)
- r = -r;
-
- if (r < 1.) {
- while (result >= r) {result *= .1; i++;}
- return (-i);
- } else {
- while (result <= r) {result *= 10.; i++;}
- return (i - 1);
- }
-}
-
-/*
- * This function return the fraction part of a double
- * and set in ip the integral part.
- * In many ways it resemble the modf() found on most Un*x
- */
-PRIVATE double
-#ifdef __STDC__
-integral(double real, double * ip)
-#else
-integral(real, ip)
-double real;
-double * ip;
-#endif
-{
- int j;
- double i, s, p;
- double real_integral = 0.;
-
-/* take care of the obvious */
-/* equal to zero ? */
- if (real == 0.) {
- *ip = 0.;
- return (0.);
- }
-
-/* negative number ? */
- if (real < 0.)
- real = -real;
-
-/* a fraction ? */
- if ( real < 1.) {
- *ip = 0.;
- return real;
- }
-/* the real work :-) */
- for (j = log_10(real); j >= 0; j--) {
- p = pow_10(j);
- s = (real - real_integral)/p;
- i = 0.;
- while (i + 1. <= s) {i++;}
- real_integral += i*p;
- }
- *ip = real_integral;
- return (real - real_integral);
-}
-
-#define PRECISION 1.e-6
-/*
- * return an ascii representation of the integral part of the number
- * and set fract to be an ascii representation of the fraction part
- * the container for the fraction and the integral part or staticly
- * declare with fix size
- */
-PRIVATE char *
-#ifdef __STDC__
-numtoa(double number, int base, int precision, char ** fract)
-#else
-numtoa(number, base, precision, fract)
-double number;
-int base;
-int precision;
-char ** fract;
-#endif
-{
- register int i, j;
- double ip, fp; /* integer and fraction part */
- double fraction;
- int digits = MAX_INT - 1;
- static char integral_part[MAX_INT];
- static char fraction_part[MAX_FRACT];
- double sign;
- int ch;
-
-/* taking care of the obvious case: 0.0 */
- if (number == 0.) {
- integral_part[0] = '0';
- integral_part[1] = '\0';
- fraction_part[0] = '0';
- fraction_part[1] = '\0';
- return integral_part;
- }
-
-/* for negative numbers */
- if ((sign = number) < 0.) {
- number = -number;
- digits--; /* sign consume one digit */
- }
-
- fraction = integral(number, &ip);
- number = ip;
-/* do the integral part */
- if ( ip == 0.) {
- integral_part[0] = '0';
- i = 1;
- } else {
- for ( i = 0; i < digits && number != 0.; ++i) {
- number /= base;
- fp = integral(number, &ip);
- ch = (int)((fp + PRECISION)*base); /* force to round */
- integral_part[i] = (ch <= 9) ? ch + '0' : ch + 'a' - 10;
- if (! isxdigit(integral_part[i])) /* bail out overflow !! */
- break;
- number = ip;
- }
- }
-
-/* Oh No !! out of bound, ho well fill it up ! */
- if (number != 0.)
- for (i = 0; i < digits; ++i)
- integral_part[i] = '9';
+ GNU General Public License for more details.
-/* put the sign ? */
- if (sign < 0.)
- integral_part[i++] = '-';
+ You should have received a copy of the GNU 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. */
- integral_part[i] = '\0';
-
-/* reverse every thing */
- for ( i--, j = 0; j < i; j++, i--)
- SWAP_INT(integral_part[i], integral_part[j]);
-
-/* the fractionnal part */
- for (i=0, fp=fraction; precision > 0 && i < MAX_FRACT ; i++, precision-- ) {
- fraction_part[i] = (int)((fp + PRECISION)*10. + '0');
- if (! isdigit(fraction_part[i])) /* underflow ? */
- break;
- fp = (fp*10.0) - (double)(long)((fp + PRECISION)*10.);
- }
- fraction_part[i] = '\0';
-
- if (fract != (char **)0)
- *fract = fraction_part;
-
- return integral_part;
-
-}
-
-/* for %d and friends, it puts in holder
- * the representation with the right padding
- */
-PRIVATE void
-#ifdef __STDC__
-decimal(struct DATA *p, double d)
-#else
-decimal(p, d)
-struct DATA *p;
-double d;
+#ifdef HAVE_CONFIG_H
+# include <config.h>
#endif
-{
- char *tmp;
- tmp = itoa(d);
- p->width -= strlen(tmp);
- PAD_RIGHT(p);
- PUT_PLUS(d, p);
- PUT_SPACE(d, p);
- while (*tmp) { /* the integral */
- PUT_CHAR(*tmp, p);
- tmp++;
- }
- PAD_LEFT(p);
-}
-
-/* for %o octal representation */
-PRIVATE void
-#ifdef __STDC__
-octal(struct DATA *p, double d)
-#else
-octal(p, d)
-struct DATA *p;
-double d;
-#endif
-{
- char *tmp;
-
- tmp = otoa(d);
- p->width -= strlen(tmp);
- PAD_RIGHT(p);
- if (p->square == FOUND) /* had prefix '0' for octal */
- PUT_CHAR('0', p);
- while (*tmp) { /* octal */
- PUT_CHAR(*tmp, p);
- tmp++;
- }
- PAD_LEFT(p);
-}
-
-/* for %x %X hexadecimal representation */
-PRIVATE void
-#ifdef __STDC__
-hexa(struct DATA *p, double d)
-#else
-hexa(p, d)
-struct DATA *p;
-double d;
-#endif
-{
- char *tmp;
-
- tmp = htoa(d);
- p->width -= strlen(tmp);
- PAD_RIGHT(p);
- if (p->square == FOUND) { /* prefix '0x' for hexa */
- PUT_CHAR('0', p); PUT_CHAR(*p->pf, p);
- }
- while (*tmp) { /* hexa */
- PUT_CHAR((*p->pf == 'X' ? toupper(*tmp) : *tmp), p);
- tmp++;
- }
- PAD_LEFT(p);
-}
-
-/* %s strings */
-PRIVATE void
-#ifdef __STDC__
-strings(struct DATA *p, char *tmp)
-#else
-strings(p, tmp)
-struct DATA *p;
-char *tmp;
-#endif
-{
- int i;
-
- i = strlen(tmp);
- if (p->precision != NOT_FOUND) /* the smallest number */
- i = (i < p->precision ? i : p->precision);
- p->width -= i;
- PAD_RIGHT(p);
- while (i-- > 0) { /* put the sting */
- PUT_CHAR(*tmp, p);
- tmp++;
- }
- PAD_LEFT(p);
-}
-
-/* %f or %g floating point representation */
-PRIVATE void
-#ifdef __STDC__
-floating(struct DATA *p, double d)
-#else
-floating(p, d)
-struct DATA *p;
-double d;
-#endif
-{
- char *tmp, *tmp2;
- int i;
-
- DEF_PREC(p);
- d = ROUND(d, p);
- tmp = dtoa(d, p->precision, &tmp2);
- /* calculate the padding. 1 for the dot */
- p->width = p->width -
- ((d > 0. && p->justify == RIGHT) ? 1:0) -
- ((p->space == FOUND) ? 1:0) -
- strlen(tmp) - p->precision - 1;
- PAD_RIGHT(p);
- PUT_PLUS(d, p);
- PUT_SPACE(d, p);
- while (*tmp) { /* the integral */
- PUT_CHAR(*tmp, p);
- tmp++;
- }
- if (p->precision != 0 || p->square == FOUND)
- PUT_CHAR('.', p); /* put the '.' */
- if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */
- for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
- tmp2[i] = '\0';
- for (; *tmp2; tmp2++)
- PUT_CHAR(*tmp2, p); /* the fraction */
-
- PAD_LEFT(p);
-}
-
-/* %e %E %g exponent representation */
-PRIVATE void
-#ifdef __STDC__
-exponent(struct DATA *p, double d)
-#else
-exponent(p, d)
-struct DATA *p;
-double d;
-#endif
-{
- char *tmp, *tmp2;
- int j, i;
-
- DEF_PREC(p);
- j = log_10(d);
- d = d / pow_10(j); /* get the Mantissa */
- d = ROUND(d, p);
- tmp = dtoa(d, p->precision, &tmp2);
- /* 1 for unit, 1 for the '.', 1 for 'e|E',
- * 1 for '+|-', 3 for 'exp' */
- /* calculate how much padding need */
- p->width = p->width -
- ((d > 0. && p->justify == RIGHT) ? 1:0) -
- ((p->space == FOUND) ? 1:0) - p->precision - 7;
- PAD_RIGHT(p);
- PUT_PLUS(d, p);
- PUT_SPACE(d, p);
- while (*tmp) {/* the integral */
- PUT_CHAR(*tmp, p);
- tmp++;
- }
- if (p->precision != 0 || p->square == FOUND)
- PUT_CHAR('.', p); /* the '.' */
- if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */
- for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
- tmp2[i] = '\0';
- for (; *tmp2; tmp2++)
- PUT_CHAR(*tmp2, p); /* the fraction */
-
- if (*p->pf == 'g' || *p->pf == 'e') { /* the exponent put the 'e|E' */
- PUT_CHAR('e', p);
- } else
- PUT_CHAR('E', p);
- if (j >= 0) { /* the sign of the exp */
- PUT_CHAR('+', p);
- } else {
- PUT_CHAR('-', p);
- j = -j;
- }
- tmp = itoa((double)j);
- if (j < 9) { /* need to pad the exponent with 0 '000' */
- PUT_CHAR('0', p); PUT_CHAR('0', p);
- } else if (j < 99)
- PUT_CHAR('0', p);
- while (*tmp) { /* the exponent */
- PUT_CHAR(*tmp, p);
- tmp++;
- }
- PAD_LEFT(p);
-}
-
-/* initialize the conversion specifiers */
-PRIVATE void
-#ifdef __STDC__
-conv_flag(char * s, struct DATA * p)
-#else
-conv_flag(s, p)
-char * s;
-struct DATA * p;
-#endif
-{
- char number[MAX_FIELD/2];
- int i;
-
- /* reset the flags. */
- p->precision = p->width = NOT_FOUND;
- p->star_w = p->star_p = NOT_FOUND;
- p->square = p->space = NOT_FOUND;
- p->a_long = p->justify = NOT_FOUND;
- p->a_longlong = NOT_FOUND;
- p->pad = ' ';
-
- for(;s && *s ;s++) {
- switch(*s) {
- case ' ': p->space = FOUND; break;
- case '#': p->square = FOUND; break;
- case '*': if (p->width == NOT_FOUND)
- p->width = p->star_w = FOUND;
- else
- p->precision = p->star_p = FOUND;
- break;
- case '+': p->justify = RIGHT; break;
- case '-': p->justify = LEFT; break;
- case '.': if (p->width == NOT_FOUND)
- p->width = 0;
- break;
- case '0': p->pad = '0'; break;
- case '1': case '2': case '3':
- case '4': case '5': case '6':
- case '7': case '8': case '9': /* gob all the digits */
- for (i = 0; isdigit(*s); i++, s++)
- if (i < MAX_FIELD/2 - 1)
- number[i] = *s;
- number[i] = '\0';
- if (p->width == NOT_FOUND)
- p->width = atoi(number);
- else
- p->precision = atoi(number);
- s--; /* went to far go back */
- break;
- }
- }
-}
-
-PUBLIC int
-#ifdef __STDC__
-vsnprintf(char *string, size_t length, const char * format, va_list args)
-#else
-vsnprintf(string, length, format, args)
-char *string;
-size_t length;
-char * format;
-va_list args;
-#endif
-{
- struct DATA data;
- char conv_field[MAX_FIELD];
- double d; /* temporary holder */
- int state;
- int i;
-
- data.length = length - 1; /* leave room for '\0' */
- data.holder = string;
- data.pf = format;
- data.counter = 0;
-
-
-/* sanity check, the string must be > 1 */
- if (length < 1)
- return -1;
-
-
- for (; *data.pf && (data.counter < data.length); data.pf++) {
- if ( *data.pf == '%' ) { /* we got a magic % cookie */
- conv_flag((char *)0, &data); /* initialise format flags */
- for (state = 1; *data.pf && state;) {
- switch (*(++data.pf)) {
- case '\0': /* a NULL here ? ? bail out */
- *data.holder = '\0';
- return data.counter;
- break;
- case 'f': /* float, double */
- STAR_ARGS(&data);
- if (data.a_long == FOUND)
- d = va_arg(args, LONG_DOUBLE);
- else
- d = va_arg(args, double);
- floating(&data, d);
- state = 0;
- break;
- case 'g':
- case 'G':
- STAR_ARGS(&data);
- DEF_PREC(&data);
- if (data.a_long == FOUND)
- d = va_arg(args, LONG_DOUBLE);
- else
- d = va_arg(args, double);
- i = log_10(d);
- /*
- * for '%g|%G' ANSI: use f if exponent
- * is in the range or [-4,p] exclusively
- * else use %e|%E
- */
- if (-4 < i && i < data.precision)
- floating(&data, d);
- else
- exponent(&data, d);
- state = 0;
- break;
- case 'e':
- case 'E': /* Exponent double */
- STAR_ARGS(&data);
- if (data.a_long == FOUND)
- d = va_arg(args, LONG_DOUBLE);
- else
- d = va_arg(args, double);
- exponent(&data, d);
- state = 0;
- break;
- case 'u': /* unsigned decimal */
- STAR_ARGS(&data);
- if (data.a_longlong == FOUND)
- d = va_arg(args, unsigned LONG_LONG);
- else if (data.a_long == FOUND)
- d = va_arg(args, unsigned long);
- else
- d = va_arg(args, unsigned int);
- decimal(&data, d);
- state = 0;
- break;
- case 'd': /* decimal */
- STAR_ARGS(&data);
- if (data.a_longlong == FOUND)
- d = va_arg(args, LONG_LONG);
- else if (data.a_long == FOUND)
- d = va_arg(args, long);
- else
- d = va_arg(args, int);
- decimal(&data, d);
- state = 0;
- break;
- case 'o': /* octal */
- STAR_ARGS(&data);
- if (data.a_longlong == FOUND)
- d = va_arg(args, LONG_LONG);
- else if (data.a_long == FOUND)
- d = va_arg(args, long);
- else
- d = va_arg(args, int);
- octal(&data, d);
- state = 0;
- break;
- case 'x':
- case 'X': /* hexadecimal */
- STAR_ARGS(&data);
- if (data.a_longlong == FOUND)
- d = va_arg(args, LONG_LONG);
- else if (data.a_long == FOUND)
- d = va_arg(args, long);
- else
- d = va_arg(args, int);
- hexa(&data, d);
- state = 0;
- break;
- case 'c': /* character */
- d = va_arg(args, int);
- PUT_CHAR(d, &data);
- state = 0;
- break;
- case 's': /* string */
- STAR_ARGS(&data);
- strings(&data, va_arg(args, char *));
- state = 0;
- break;
- case 'n':
- *(va_arg(args, int *)) = data.counter; /* what's the count ? */
- state = 0;
- break;
- case 'q':
- data.a_longlong = FOUND;
- break;
- case 'L':
- case 'l':
- if (data.a_long == FOUND)
- data.a_longlong = FOUND;
- else
- data.a_long = FOUND;
- break;
- case 'h':
- break;
- case '%': /* nothing just % */
- PUT_CHAR('%', &data);
- state = 0;
- break;
- case '#': case ' ': case '+': case '*':
- case '-': case '.': case '0': case '1':
- case '2': case '3': case '4': case '5':
- case '6': case '7': case '8': case '9':
- /* initialize width and precision */
- for (i = 0; isflag(*data.pf); i++, data.pf++)
- if (i < MAX_FIELD - 1)
- conv_field[i] = *data.pf;
- conv_field[i] = '\0';
- conv_flag(conv_field, &data);
- data.pf--; /* went to far go back */
- break;
- default:
- /* is this an error ? maybe bail out */
- state = 0;
- break;
- } /* end switch */
- } /* end of for state */
- } else { /* not % */
- PUT_CHAR(*data.pf, &data); /* add the char the string */
- }
- }
-
- *data.holder = '\0'; /* the end ye ! */
+#include "snprintf.h"
- return data.counter;
-}
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
-#ifndef HAVE_SNPRINTF
+#include "minmax.h"
+#include "vasnprintf.h"
-PUBLIC int
-#if __STDC__
-snprintf(char *string, size_t length, const char * format, ...)
-#else
-snprintf(string, length, format, va_alist)
-char *string;
-size_t length;
-char * format;
-va_dcl
-#endif
+/* 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. */
+int
+snprintf (char *str, size_t size, const char *format, ...)
{
- int rval;
+ char *output;
+ size_t len;
va_list args;
-#if __STDC__
- va_start(args, format);
-#else
- va_start(args);
-#endif
-
- rval = vsnprintf (string, length, format, args);
-
- va_end(args);
-
- return rval;
-}
-
-#endif /* HAVE_SNPRINTF */
-
-
-#ifdef DRIVER
-
-#include <stdio.h>
-
-/* set of small tests for snprintf() */
-int main()
-{
- char holder[100];
- int i;
+ va_start (args, format);
+ len = size;
+ output = vasnprintf (str, &len, format, args);
+ va_end (args);
-/*
- printf("Suite of test for snprintf:\n");
- printf("a_format\n");
- printf("printf() format\n");
- printf("snprintf() format\n\n");
-*/
-/* Checking the field widths */
-
- printf("/%%d/, 336\n");
- snprintf(holder, sizeof holder, "/%d/\n", 336);
- printf("/%d/\n", 336);
- printf("%s\n", holder);
-
- printf("/%%2d/, 336\n");
- snprintf(holder, sizeof holder, "/%2d/\n", 336);
- printf("/%2d/\n", 336);
- printf("%s\n", holder);
-
- printf("/%%10d/, 336\n");
- snprintf(holder, sizeof holder, "/%10d/\n", 336);
- printf("/%10d/\n", 336);
- printf("%s\n", holder);
-
- printf("/%%-10d/, 336\n");
- snprintf(holder, sizeof holder, "/%-10d/\n", 336);
- printf("/%-10d/\n", 336);
- printf("%s\n", holder);
-
-/* long long */
-
- printf("/%%lld/, 336\n");
- snprintf(holder, sizeof holder, "/%lld/\n", (LONG_LONG)336);
- printf("/%lld/\n", (LONG_LONG)336);
- printf("%s\n", holder);
-
- printf("/%%2qd/, 336\n");
- snprintf(holder, sizeof holder, "/%2qd/\n", (LONG_LONG)336);
- printf("/%2qd/\n", (LONG_LONG)336);
- printf("%s\n", holder);
-
-/* floating points */
-
- printf("/%%f/, 1234.56\n");
- snprintf(holder, sizeof holder, "/%f/\n", 1234.56);
- printf("/%f/\n", 1234.56);
- printf("%s\n", holder);
-
- printf("/%%e/, 1234.56\n");
- snprintf(holder, sizeof holder, "/%e/\n", 1234.56);
- printf("/%e/\n", 1234.56);
- printf("%s\n", holder);
-
- printf("/%%4.2f/, 1234.56\n");
- snprintf(holder, sizeof holder, "/%4.2f/\n", 1234.56);
- printf("/%4.2f/\n", 1234.56);
- printf("%s\n", holder);
-
- printf("/%%3.1f/, 1234.56\n");
- snprintf(holder, sizeof holder, "/%3.1f/\n", 1234.56);
- printf("/%3.1f/\n", 1234.56);
- printf("%s\n", holder);
-
- printf("/%%10.3f/, 1234.56\n");
- snprintf(holder, sizeof holder, "/%10.3f/\n", 1234.56);
- printf("/%10.3f/\n", 1234.56);
- printf("%s\n", holder);
-
- printf("/%%10.3e/, 1234.56\n");
- snprintf(holder, sizeof holder, "/%10.3e/\n", 1234.56);
- printf("/%10.3e/\n", 1234.56);
- printf("%s\n", holder);
-
- printf("/%%+4.2f/, 1234.56\n");
- snprintf(holder, sizeof holder, "/%+4.2f/\n", 1234.56);
- printf("/%+4.2f/\n", 1234.56);
- printf("%s\n", holder);
-
- printf("/%%010.2f/, 1234.56\n");
- snprintf(holder, sizeof holder, "/%010.2f/\n", 1234.56);
- printf("/%010.2f/\n", 1234.56);
- printf("%s\n", holder);
-
-#define BLURB "Outstanding acting !"
-/* strings precisions */
-
- printf("/%%2s/, \"%s\"\n", BLURB);
- snprintf(holder, sizeof holder, "/%2s/\n", BLURB);
- printf("/%2s/\n", BLURB);
- printf("%s\n", holder);
-
- printf("/%%22s/ %s\n", BLURB);
- snprintf(holder, sizeof holder, "/%22s/\n", BLURB);
- printf("/%22s/\n", BLURB);
- printf("%s\n", holder);
-
- printf("/%%22.5s/ %s\n", BLURB);
- snprintf(holder, sizeof holder, "/%22.5s/\n", BLURB);
- printf("/%22.5s/\n", BLURB);
- printf("%s\n", holder);
-
- printf("/%%-22.5s/ %s\n", BLURB);
- snprintf(holder, sizeof holder, "/%-22.5s/\n", BLURB);
- printf("/%-22.5s/\n", BLURB);
- printf("%s\n", holder);
-
-/* see some flags */
-
- printf("%%x %%X %%#x, 31, 31, 31\n");
- snprintf(holder, sizeof holder, "%x %X %#x\n", 31, 31, 31);
- printf("%x %X %#x\n", 31, 31, 31);
- printf("%s\n", holder);
-
- printf("**%%d**%% d**%% d**, 42, 42, -42\n");
- snprintf(holder, sizeof holder, "**%d**% d**% d**\n", 42, 42, -42);
- printf("**%d**% d**% d**\n", 42, 42, -42);
- printf("%s\n", holder);
-
-/* other flags */
-
- printf("/%%g/, 31.4\n");
- snprintf(holder, sizeof holder, "/%g/\n", 31.4);
- printf("/%g/\n", 31.4);
- printf("%s\n", holder);
-
- printf("/%%.6g/, 31.4\n");
- snprintf(holder, sizeof holder, "/%.6g/\n", 31.4);
- printf("/%.6g/\n", 31.4);
- printf("%s\n", holder);
-
- printf("/%%.1G/, 31.4\n");
- snprintf(holder, sizeof holder, "/%.1G/\n", 31.4);
- printf("/%.1G/\n", 31.4);
- printf("%s\n", holder);
-
- printf("abc%%n\n");
- printf("abc%n", &i); printf("%d\n", i);
- snprintf(holder, sizeof holder, "abc%n", &i);
- printf("%s", holder); printf("%d\n\n", i);
-
- printf("%%*.*s --> 10.10\n");
- snprintf(holder, sizeof holder, "%*.*s\n", 10, 10, BLURB);
- printf("%*.*s\n", 10, 10, BLURB);
- printf("%s\n", holder);
+ if (!output)
+ return -1;
- printf("%%%%%%%%\n");
- snprintf(holder, sizeof holder, "%%%%\n");
- printf("%%%%\n");
- printf("%s\n", holder);
+ if (str != NULL)
+ if (len > size - 1) /* equivalent to: (size > 0 && len >= size) */
+ str[size - 1] = '\0';
-#define BIG "Hello this is a too big string for the buffer"
-/* printf("A buffer to small of 10, trying to put this:\n");*/
- printf("<%%>, %s\n", BIG);
- i = snprintf(holder, 10, "%s\n", BIG);
- printf("<%s>\n", BIG);
- printf("<%s>\n", holder);
+ if (output != str)
+ free (output);
- return 0;
+ return len;
}
-#endif
diff --git a/lib/snprintf.h b/lib/snprintf.h
index 7a8ad40..a72f74d 100644
--- a/lib/snprintf.h
+++ b/lib/snprintf.h
@@ -1,218 +1,29 @@
-/*
- Unix snprintf implementation.
- Version 1.3
+/* Formatted output to strings.
+ Copyright (C) 2004 Free Software Foundation, Inc.
+ Written by Simon Josefsson.
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 of the License, or
- (at your option) any later version.
+ it under the terms of the GNU 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.
+ GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ You should have received a copy of the GNU 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. */
- Revision History:
- see header of snprintf.c.
+#ifndef SNPRINTF_H
+#define SNPRINTF_H
-format:
- int snprintf(holder, sizeof_holder, format, ...)
+/* Get snprintf declaration, if available. */
+#include <stdio.h>
-Return values:
- (sizeof_holder - 1)
-
-
- THANKS(for the patches and ideas):
- Miles Bader
- Cyrille Rustom
- Jacek Slabocewiz
- Mike Parker(mouse)
-
-Alain Magloire: alainm@rcsm.ee.mcgill.ca
-*/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#if __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-
-#include <stdlib.h> /* for atoi() */
-#include <ctype.h>
-
-
-/*
- * For the FLOATING POINT FORMAT :
- * the challenge was finding a way to
- * manipulate the Real numbers without having
- * to resort to mathematical function(it
- * would require to link with -lm) and not
- * going down to the bit pattern(not portable)
- *
- * so a number, a real is:
-
- real = integral + fraction
-
- integral = ... + a(2)*10^2 + a(1)*10^1 + a(0)*10^0
- fraction = b(1)*10^-1 + b(2)*10^-2 + ...
-
- where:
- 0 <= a(i) => 9
- 0 <= b(i) => 9
-
- from then it was simple math
- */
-
-/*
- * size of the buffer for the integral part
- * and the fraction part
- */
-#define MAX_INT 99 + 1 /* 1 for the null */
-#define MAX_FRACT 29 + 1
-
-/*
- * If the compiler supports (long long)
- */
-#ifndef LONG_LONG
-# define LONG_LONG long long
-/*# define LONG_LONG int64_t*/
-#endif
-
-/*
- * If the compiler supports (long double)
- */
-#ifndef LONG_DOUBLE
-# define LONG_DOUBLE long double
-/*# define LONG_DOUBLE double*/
+#if defined HAVE_DECL_SNPRINTF && !HAVE_DECL_SNPRINTF
+int snprintf (char *str, size_t size, const char *format, ...);
#endif
-/*
- * numtoa() uses PRIVATE buffers to store the results,
- * So this function is not reentrant
- */
-#define itoa(n) numtoa(n, 10, 0, (char **)0)
-#define otoa(n) numtoa(n, 8, 0, (char **)0)
-#define htoa(n) numtoa(n, 16, 0, (char **)0)
-#define dtoa(n, p, f) numtoa(n, 10, p, f)
-
-#define SWAP_INT(a,b) {int t; t = (a); (a) = (b); (b) = t;}
-
-/* this struct holds everything we need */
-struct DATA {
- int length;
- char *holder;
- int counter;
-#ifdef __STDC__
- const char *pf;
-#else
- char *pf;
-#endif
-/* FLAGS */
- int width, precision;
- int justify; char pad;
- int square, space, star_w, star_p, a_long, a_longlong;
-};
-
-#define PRIVATE static
-#define PUBLIC
-/* signature of the functions */
-#ifdef __STDC__
-/* the floating point stuff */
- PRIVATE double pow_10(int);
- PRIVATE int log_10(double);
- PRIVATE double integral(double, double *);
- PRIVATE char * numtoa(double, int, int, char **);
-
-/* for the format */
- PRIVATE void conv_flag(char *, struct DATA *);
- PRIVATE void floating(struct DATA *, double);
- PRIVATE void exponent(struct DATA *, double);
- PRIVATE void decimal(struct DATA *, double);
- PRIVATE void octal(struct DATA *, double);
- PRIVATE void hexa(struct DATA *, double);
- PRIVATE void strings(struct DATA *, char *);
-
-#else
-/* the floating point stuff */
- PRIVATE double pow_10();
- PRIVATE int log_10();
- PRIVATE double integral();
- PRIVATE char * numtoa();
-
-/* for the format */
- PRIVATE void conv_flag();
- PRIVATE void floating();
- PRIVATE void exponent();
- PRIVATE void decimal();
- PRIVATE void octal();
- PRIVATE void hexa();
- PRIVATE void strings();
-#endif
-
-/* those are defines specific to snprintf to hopefully
- * make the code clearer :-)
- */
-#define RIGHT 1
-#define LEFT 0
-#define NOT_FOUND -1
-#define FOUND 1
-#define MAX_FIELD 15
-
-/* the conversion flags */
-#define isflag(c) ((c) == '#' || (c) == ' ' || \
- (c) == '*' || (c) == '+' || \
- (c) == '-' || (c) == '.' || \
- isdigit(c))
-
-/* round off to the precision */
-#define ROUND(d, p) \
- (d < 0.) ? \
- d - pow_10(-(p)->precision) * 0.5 : \
- d + pow_10(-(p)->precision) * 0.5
-
-/* set default precision */
-#define DEF_PREC(p) \
- if ((p)->precision == NOT_FOUND) \
- (p)->precision = 6
-
-/* put a char */
-#define PUT_CHAR(c, p) \
- if ((p)->counter < (p)->length) { \
- *(p)->holder++ = (c); \
- (p)->counter++; \
- }
-
-#define PUT_PLUS(d, p) \
- if ((d) > 0. && (p)->justify == RIGHT) \
- PUT_CHAR('+', p)
-
-#define PUT_SPACE(d, p) \
- if ((p)->space == FOUND && (d) > 0.) \
- PUT_CHAR(' ', p)
-
-/* pad right */
-#define PAD_RIGHT(p) \
- if ((p)->width > 0 && (p)->justify != LEFT) \
- for (; (p)->width > 0; (p)->width--) \
- PUT_CHAR((p)->pad, p)
-
-/* pad left */
-#define PAD_LEFT(p) \
- if ((p)->width > 0 && (p)->justify == LEFT) \
- for (; (p)->width > 0; (p)->width--) \
- PUT_CHAR((p)->pad, p)
-
-/* if width and prec. in the args */
-#define STAR_ARGS(p) \
- if ((p)->star_w == FOUND) \
- (p)->width = va_arg(args, int); \
- if ((p)->star_p == FOUND) \
- (p)->precision = va_arg(args, int)
+#endif /* SNPRINTF_H */
diff --git a/lib/vasprintf.c b/lib/vasprintf.c
index 3b6aa38..ba94c64 100644
--- a/lib/vasprintf.c
+++ b/lib/vasprintf.c
@@ -1,194 +1,42 @@
-/* Like vsprintf but provides a pointer to malloc'd storage, which must
- be freed by the caller.
- Copyright (C) 1994 Free Software Foundation, Inc.
+/* Formatted output to strings.
+ Copyright (C) 1999, 2002-2004 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 2, or (at your option)
-any later version.
+ 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 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 General Public License for more details.
+ 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, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ You should have received a copy of the GNU 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 <stdio.h>
-#include <string.h>
+/* Specification. */
+#include "vasprintf.h"
-#if __STDC__
-# include <stdarg.h>
-#else
-# include <varargs.h>
-#endif
-
-#ifdef TEST
-int global_total_width;
-#endif
-
-unsigned long strtoul ();
-char *malloc ();
-
-static int
-int_vasprintf (result, format, args)
- char **result;
- const char *format;
- va_list *args;
-{
- const char *p = format;
- /* Add one to make sure that it is never zero, which might cause malloc
- to return NULL. */
- int total_width = strlen (format) + 1;
- va_list ap;
-
- memcpy (&ap, args, sizeof (va_list));
-
- while (*p != '\0')
- {
- if (*p++ == '%')
- {
- while (strchr ("-+ #0", *p))
- ++p;
- if (*p == '*')
- {
- ++p;
- total_width += abs (va_arg (ap, int));
- }
- else
- total_width += strtoul (p, &p, 10);
- if (*p == '.')
- {
- ++p;
- if (*p == '*')
- {
- ++p;
- total_width += abs (va_arg (ap, int));
- }
- else
- total_width += strtoul (p, &p, 10);
- }
- while (strchr ("hlL", *p))
- ++p;
- /* Should be big enough for any format specifier except %s. */
- total_width += 30;
- switch (*p)
- {
- case 'd':
- case 'i':
- case 'o':
- case 'u':
- case 'x':
- case 'X':
- case 'c':
- (void) va_arg (ap, int);
- break;
- case 'f':
- case 'e':
- case 'E':
- case 'g':
- case 'G':
- (void) va_arg (ap, double);
- break;
- case 's':
- total_width += strlen (va_arg (ap, char *));
- break;
- case 'p':
- case 'n':
- (void) va_arg (ap, char *);
- break;
- }
- }
- }
-#ifdef TEST
- global_total_width = total_width;
-#endif
- *result = malloc (total_width);
- if (*result != NULL)
- return vsprintf (*result, format, *args);
- else
- return 0;
-}
-
-int
-vasprintf (result, format, args)
- char **result;
- const char *format;
- va_list args;
-{
- return int_vasprintf (result, format, &args);
-}
-
-int
-asprintf
-#if __STDC__
- (char **result, const char *format, ...)
-#else
- (result, va_alist)
- char **result;
- va_dcl
-#endif
-{
- va_list args;
- int done;
-
-#if __STDC__
- va_start (args, format);
-#else
- char *format;
- va_start (args);
- format = va_arg (args, char *);
-#endif
- done = vasprintf (result, format, args);
- va_end (args);
+#include <stdlib.h>
- return done;
-}
-
-#ifdef TEST
-void
-checkit
-#if __STDC__
- (const char* format, ...)
-#else
- (va_alist)
- va_dcl
-#endif
-{
- va_list args;
- char *result;
-
-#if __STDC__
- va_start (args, format);
-#else
- char *format;
- va_start (args);
- format = va_arg (args, char *);
-#endif
- vasprintf (&result, format, args);
- va_end (args);
- if (strlen (result) < global_total_width)
- printf ("PASS: ");
- else
- printf ("FAIL: ");
- printf ("%d %s\n", global_total_width, result);
-}
+#include "vasnprintf.h"
int
-main ()
+vasprintf (char **resultp, const char *format, va_list args)
{
- checkit ("%d", 0x12345678);
- checkit ("%200d", 5);
- checkit ("%.300d", 6);
- checkit ("%100.150d", 7);
- checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
-777777777777777777333333333333366666666666622222222222777777777777733333");
- checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx");
+ size_t length;
+ char *result = vasnprintf (NULL, &length, format, args);
+ if (result == NULL)
+ return -1;
+
+ *resultp = result;
+ /* Return the number of resulting bytes, excluding the trailing NUL.
+ If it wouldn't fit in an 'int', vasnprintf() would have returned NULL
+ and set errno to EOVERFLOW. */
+ return length;
}
-#endif /* TEST */
diff --git a/lib/xalloc.h b/lib/xalloc.h
index 8668e19..8d0fcf0 100644
--- a/lib/xalloc.h
+++ b/lib/xalloc.h
@@ -1,5 +1,7 @@
/* xalloc.h -- malloc with out-of-memory checking
- Copyright (C) 1990-1998, 1999 Free Software Foundation, Inc.
+
+ Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000, 2003, 2004 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
@@ -18,14 +20,14 @@
#ifndef XALLOC_H_
# define XALLOC_H_
-# ifndef PARAMS
-# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
-# define PARAMS(Args) Args
-# else
-# define PARAMS(Args) ()
-# endif
+# include <stddef.h>
+
+
+# ifdef __cplusplus
+extern "C" {
# endif
+
# ifndef __attribute__
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__
# define __attribute__(x)
@@ -36,52 +38,42 @@
# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
# endif
-/* Exit value when the requested amount of memory is not available.
- It is initialized to EXIT_FAILURE, but the caller may set it to
- some other value. */
-extern int xalloc_exit_failure;
-
-/* If this pointer is non-zero, run the specified function upon each
- allocation failure. It is initialized to zero. */
-extern void (*xalloc_fail_func) PARAMS ((void));
-
-/* If XALLOC_FAIL_FUNC is undefined or a function that returns, this
- message must be non-NULL. It is translated via gettext.
- The default value is "Memory exhausted". */
-extern char *const xalloc_msg_memory_exhausted;
-
-/* This function is always triggered when memory is exhausted. It is
- in charge of honoring the three previous items. This is the
+/* This function is always triggered when memory is exhausted.
+ It must be defined by the application, either explicitly
+ or by using gnulib's xalloc-die module. This is the
function to call when one wants the program to die because of a
memory allocation failure. */
-extern void xalloc_die PARAMS ((void)) ATTRIBUTE_NORETURN;
-
-void *xmalloc PARAMS ((size_t n));
-void *xcalloc PARAMS ((size_t n, size_t s));
-void *xrealloc PARAMS ((void *p, size_t n));
-char *xstrdup PARAMS ((const char *str));
-
-# define XMALLOC(Type, N_items) ((Type *) xmalloc (sizeof (Type) * (N_items)))
-# define XCALLOC(Type, N_items) ((Type *) xcalloc (sizeof (Type), (N_items)))
-# define XREALLOC(Ptr, Type, N_items) \
- ((Type *) xrealloc ((void *) (Ptr), sizeof (Type) * (N_items)))
-
-/* Declare and alloc memory for VAR of type TYPE. */
-# define NEW(Type, Var) Type *(Var) = XMALLOC (Type, 1)
-
-/* Free VAR only if non NULL. */
-# define XFREE(Var) \
- do { \
- if (Var) \
- free (Var); \
- } while (0)
-
-/* Return a pointer to a malloc'ed copy of the array SRC of NUM elements. */
-# define CCLONE(Src, Num) \
- (memcpy (xmalloc (sizeof (*Src) * (Num)), (Src), sizeof (*Src) * (Num)))
-
-/* Return a malloc'ed copy of SRC. */
-# define CLONE(Src) CCLONE (Src, 1)
+extern void xalloc_die (void) ATTRIBUTE_NORETURN;
+
+void *xmalloc (size_t s);
+void *xnmalloc (size_t n, size_t s);
+void *xzalloc (size_t s);
+void *xcalloc (size_t n, size_t s);
+void *xrealloc (void *p, size_t s);
+void *xnrealloc (void *p, size_t n, size_t s);
+void *x2realloc (void *p, size_t *pn);
+void *x2nrealloc (void *p, size_t *pn, size_t s);
+void *xmemdup (void const *p, size_t s);
+char *xstrdup (char const *str);
+
+/* Return 1 if an array of N objects, each of size S, cannot exist due
+ to size arithmetic overflow. S must be positive and N must be
+ nonnegative. This is a macro, not an inline function, so that it
+ works correctly even when SIZE_MAX < N.
+
+ By gnulib convention, SIZE_MAX represents overflow in size
+ calculations, so the conservative dividend to use here is
+ SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value.
+ However, malloc (SIZE_MAX) fails on all known hosts where
+ sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for
+ exactly-SIZE_MAX allocations on such hosts; this avoids a test and
+ branch when S is known to be 1. */
+# define xalloc_oversized(n, s) \
+ ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n))
+
+# ifdef __cplusplus
+}
+# endif
#endif /* !XALLOC_H_ */
diff --git a/lib/xmalloc.c b/lib/xmalloc.c
index a71dc35..13c2490 100644
--- a/lib/xmalloc.c
+++ b/lib/xmalloc.c
@@ -1,5 +1,7 @@
/* xmalloc.c -- malloc with out of memory checking
- Copyright (C) 1990-1997, 98, 99 Free Software Foundation, Inc.
+
+ Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000, 2002, 2003, 2004 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
@@ -19,64 +21,31 @@
# include <config.h>
#endif
-#include <sys/types.h>
-
-#include <mailutils/error.h>
-
-#if STDC_HEADERS
-# include <stdlib.h>
-#else
-void *calloc ();
-void *malloc ();
-void *realloc ();
-void free ();
-#endif
-
-#if ENABLE_NLS
-# include <libintl.h>
-# define _(Text) gettext (Text)
-#else
-# define textdomain(Domain)
-# define _(Text) Text
-#endif
-#define N_(Text) Text
-
-#include "error.h"
#include "xalloc.h"
-#ifndef EXIT_FAILURE
-# define EXIT_FAILURE 1
-#endif
-
-#ifndef HAVE_MALLOC
-# error "you must run the autoconf test for a properly working malloc -- see malloc.m4"
-#endif
+#include <stdlib.h>
+#include <string.h>
-#ifndef HAVE_REALLOC
-# error "you must run the autoconf test for a properly working realloc -- see realloc.m4"
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
#endif
-/* Exit value when the requested amount of memory is not available.
- The caller may set it to some other value. */
-int xalloc_exit_failure = EXIT_FAILURE;
-
-/* If non NULL, call this function when memory is exhausted. */
-void (*xalloc_fail_func) PARAMS ((void)) = 0;
+/* Allocate an array of N objects, each with S bytes of memory,
+ dynamically, with error checking. S must be nonzero. */
-/* If XALLOC_FAIL_FUNC is NULL, or does return, display this message
- before exiting when memory is exhausted. Goes through gettext. */
-char *const xalloc_msg_memory_exhausted = N_("Memory exhausted");
+static inline void *
+xnmalloc_inline (size_t n, size_t s)
+{
+ void *p;
+ if (xalloc_oversized (n, s) || (! (p = malloc (n * s)) && n != 0))
+ xalloc_die ();
+ return p;
+}
-void
-xalloc_die (void)
+void *
+xnmalloc (size_t n, size_t s)
{
- if (xalloc_fail_func)
- (*xalloc_fail_func) ();
- mu_error ("%s", _(xalloc_msg_memory_exhausted));
- /* The `noreturn' cannot be given to error, since it may return if
- its first argument is 0. To help compilers understand the
- xalloc_die does terminate, call exit. */
- exit (xalloc_exit_failure);
+ return xnmalloc_inline (n, s);
}
/* Allocate N bytes of memory dynamically, with error checking. */
@@ -84,36 +53,177 @@ xalloc_die (void)
void *
xmalloc (size_t n)
{
- void *p;
+ return xnmalloc_inline (n, 1);
+}
+
+/* Change the size of an allocated block of memory P to an array of N
+ objects each of S bytes, with error checking. S must be nonzero. */
- p = malloc (n);
- if (p == 0)
+static inline void *
+xnrealloc_inline (void *p, size_t n, size_t s)
+{
+ if (xalloc_oversized (n, s) || (! (p = realloc (p, n * s)) && n != 0))
xalloc_die ();
return p;
}
+void *
+xnrealloc (void *p, size_t n, size_t s)
+{
+ return xnrealloc_inline (p, n, s);
+}
+
/* Change the size of an allocated block of memory P to N bytes,
- with error checking.
- If P is NULL, run xmalloc. */
+ with error checking. */
void *
xrealloc (void *p, size_t n)
{
- p = realloc (p, n);
- if (p == 0)
- xalloc_die ();
- return p;
+ return xnrealloc_inline (p, n, 1);
}
-/* Allocate memory for N elements of S bytes, with error checking. */
+
+/* If P is null, allocate a block of at least *PN such objects;
+ otherwise, reallocate P so that it contains more than *PN objects
+ each of S bytes. *PN must be nonzero unless P is null, and S must
+ be nonzero. Set *PN to the new number of objects, and return the
+ pointer to the new block. *PN is never set to zero, and the
+ returned pointer is never null.
+
+ Repeated reallocations are guaranteed to make progress, either by
+ allocating an initial block with a nonzero size, or by allocating a
+ larger block.
+
+ In the following implementation, nonzero sizes are doubled so that
+ repeated reallocations have O(N log N) overall cost rather than
+ O(N**2) cost, but the specification for this function does not
+ guarantee that sizes are doubled.
+
+ Here is an example of use:
+
+ int *p = NULL;
+ size_t used = 0;
+ size_t allocated = 0;
+
+ void
+ append_int (int value)
+ {
+ if (used == allocated)
+ p = x2nrealloc (p, &allocated, sizeof *p);
+ p[used++] = value;
+ }
+
+ This causes x2nrealloc to allocate a block of some nonzero size the
+ first time it is called.
+
+ To have finer-grained control over the initial size, set *PN to a
+ nonzero value before calling this function with P == NULL. For
+ example:
+
+ int *p = NULL;
+ size_t used = 0;
+ size_t allocated = 0;
+ size_t allocated1 = 1000;
+
+ void
+ append_int (int value)
+ {
+ if (used == allocated)
+ {
+ p = x2nrealloc (p, &allocated1, sizeof *p);
+ allocated = allocated1;
+ }
+ p[used++] = value;
+ }
+
+ */
+
+static inline void *
+x2nrealloc_inline (void *p, size_t *pn, size_t s)
+{
+ size_t n = *pn;
+
+ if (! p)
+ {
+ if (! n)
+ {
+ /* The approximate size to use for initial small allocation
+ requests, when the invoking code specifies an old size of
+ zero. 64 bytes is the largest "small" request for the
+ GNU C library malloc. */
+ enum { DEFAULT_MXFAST = 64 };
+
+ n = DEFAULT_MXFAST / s;
+ n += !n;
+ }
+ }
+ else
+ {
+ if (SIZE_MAX / 2 / s < n)
+ xalloc_die ();
+ n *= 2;
+ }
+
+ *pn = n;
+ return xrealloc (p, n * s);
+}
+
+void *
+x2nrealloc (void *p, size_t *pn, size_t s)
+{
+ return x2nrealloc_inline (p, pn, s);
+}
+
+/* If P is null, allocate a block of at least *PN bytes; otherwise,
+ reallocate P so that it contains more than *PN bytes. *PN must be
+ nonzero unless P is null. Set *PN to the new block's size, and
+ return the pointer to the new block. *PN is never set to zero, and
+ the returned pointer is never null. */
+
+void *
+x2realloc (void *p, size_t *pn)
+{
+ return x2nrealloc_inline (p, pn, 1);
+}
+
+/* Allocate S bytes of zeroed memory dynamically, with error checking.
+ There's no need for xnzalloc (N, S), since it would be equivalent
+ to xcalloc (N, S). */
+
+void *
+xzalloc (size_t s)
+{
+ return memset (xmalloc (s), 0, s);
+}
+
+/* Allocate zeroed memory for N elements of S bytes, with error
+ checking. S must be nonzero. */
void *
xcalloc (size_t n, size_t s)
{
void *p;
-
- p = calloc (n, s);
- if (p == 0)
+ /* Test for overflow, since some calloc implementations don't have
+ proper overflow checks. */
+ if (xalloc_oversized (n, s) || (! (p = calloc (n, s)) && n != 0))
xalloc_die ();
return p;
}
+
+/* Clone an object P of size S, with error checking. There's no need
+ for xnmemdup (P, N, S), since xmemdup (P, N * S) works without any
+ need for an arithmetic overflow check. */
+
+void *
+xmemdup (void const *p, size_t s)
+{
+ return memcpy (xmalloc (s), p, s);
+}
+
+/* Clone STRING. */
+
+char *
+xstrdup (char const *string)
+{
+ return xmemdup (string, strlen (string) + 1);
+}
diff --git a/lib/xstrtol.c b/lib/xstrtol.c
index e7b2061..906e4a1 100644
--- a/lib/xstrtol.c
+++ b/lib/xstrtol.c
@@ -1,5 +1,7 @@
/* A more useful interface to strtol.
- Copyright 1995, 1996, 1998, 1999 Free Software Foundation, Inc.
+
+ Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2003, 2004 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
@@ -25,48 +27,32 @@
# define __strtol strtol
# define __strtol_t long int
# define __xstrtol xstrtol
+# define STRTOL_T_MINIMUM LONG_MIN
+# define STRTOL_T_MAXIMUM LONG_MAX
#endif
/* Some pre-ANSI implementations (e.g. SunOS 4)
need stderr defined if assertion checking is enabled. */
#include <stdio.h>
-#if STDC_HEADERS
-# include <stdlib.h>
-#endif
-
-#if HAVE_STRING_H
-# include <string.h>
-#else
-# include <strings.h>
-# ifndef strchr
-# define strchr index
-# endif
-#endif
-
#include <assert.h>
#include <ctype.h>
-
#include <errno.h>
-#ifndef errno
-extern int errno;
-#endif
-
-#if HAVE_LIMITS_H
-# include <limits.h>
-#endif
-
-#ifndef CHAR_BIT
-# define CHAR_BIT 8
-#endif
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
/* The extra casts work around common compiler bugs. */
#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
-/* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
- It is necessary at least when t == time_t. */
#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \
- ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0))
-#define TYPE_MAXIMUM(t) (~ (t) 0 - TYPE_MINIMUM (t))
+ ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) \
+ : (t) 0))
+#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t)))
+
+#ifndef STRTOL_T_MINIMUM
+# define STRTOL_T_MINIMUM TYPE_MINIMUM (__strtol_t)
+# define STRTOL_T_MAXIMUM TYPE_MAXIMUM (__strtol_t)
+#endif
#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
# define IN_CTYPE_DOMAIN(c) 1
@@ -78,36 +64,38 @@ extern int errno;
#include "xstrtol.h"
-#ifndef strtol
-long int strtol ();
+#if !HAVE_DECL_STRTOIMAX && !defined strtoimax
+intmax_t strtoimax ();
#endif
-#ifndef strtoul
-unsigned long int strtoul ();
-#endif
-
-#ifndef strtoumax
+#if !HAVE_DECL_STRTOUMAX && !defined strtoumax
uintmax_t strtoumax ();
#endif
-static int
+static strtol_error
bkm_scale (__strtol_t *x, int scale_factor)
{
- __strtol_t product = *x * scale_factor;
- if (*x != product / scale_factor)
- return 1;
- *x = product;
- return 0;
+ if (TYPE_SIGNED (__strtol_t) && *x < STRTOL_T_MINIMUM / scale_factor)
+ {
+ *x = STRTOL_T_MINIMUM;
+ return LONGINT_OVERFLOW;
+ }
+ if (STRTOL_T_MAXIMUM / scale_factor < *x)
+ {
+ *x = STRTOL_T_MAXIMUM;
+ return LONGINT_OVERFLOW;
+ }
+ *x *= scale_factor;
+ return LONGINT_OK;
}
-static int
+static strtol_error
bkm_scale_by_power (__strtol_t *x, int base, int power)
{
+ strtol_error err = LONGINT_OK;
while (power--)
- if (bkm_scale (x, base))
- return 1;
-
- return 0;
+ err |= bkm_scale (x, base);
+ return err;
}
/* FIXME: comment. */
@@ -119,6 +107,7 @@ __xstrtol (const char *s, char **ptr, int strtol_base,
char *t_ptr;
char **p;
__strtol_t tmp;
+ strtol_error err = LONGINT_OK;
assert (0 <= strtol_base && strtol_base <= 36);
@@ -127,18 +116,31 @@ __xstrtol (const char *s, char **ptr, int strtol_base,
if (! TYPE_SIGNED (__strtol_t))
{
const char *q = s;
- while (ISSPACE ((unsigned char) *q))
- ++q;
- if (*q == '-')
+ unsigned char ch = *q;
+ while (ISSPACE (ch))
+ ch = *++q;
+ if (ch == '-')
return LONGINT_INVALID;
}
errno = 0;
tmp = __strtol (s, p, strtol_base);
- if (errno != 0)
- return LONGINT_OVERFLOW;
+
if (*p == s)
- return LONGINT_INVALID;
+ {
+ /* If there is no number but there is a valid suffix, assume the
+ number is 1. The string is invalid otherwise. */
+ if (valid_suffixes && **p && strchr (valid_suffixes, **p))
+ tmp = 1;
+ else
+ return LONGINT_INVALID;
+ }
+ else if (errno != 0)
+ {
+ if (errno != ERANGE)
+ return LONGINT_INVALID;
+ err = LONGINT_OVERFLOW;
+ }
/* Let valid_suffixes == NULL mean `allow any suffix'. */
/* FIXME: update all callers except the ones that allow suffixes
@@ -146,34 +148,39 @@ __xstrtol (const char *s, char **ptr, int strtol_base,
if (!valid_suffixes)
{
*val = tmp;
- return LONGINT_OK;
+ return err;
}
if (**p != '\0')
{
int base = 1024;
int suffixes = 1;
- int overflow;
+ strtol_error overflow;
if (!strchr (valid_suffixes, **p))
{
*val = tmp;
- return LONGINT_INVALID_SUFFIX_CHAR;
+ return err | LONGINT_INVALID_SUFFIX_CHAR;
}
if (strchr (valid_suffixes, '0'))
{
/* The ``valid suffix'' '0' is a special flag meaning that
an optional second suffix is allowed, which can change
- the base, e.g. "100MD" for 100 megabytes decimal. */
+ the base. A suffix "B" (e.g. "100MB") stands for a power
+ of 1000, whereas a suffix "iB" (e.g. "100MiB") stands for
+ a power of 1024. If no suffix (e.g. "100M"), assume
+ power-of-1024. */
switch (p[0][1])
{
- case 'B':
- suffixes++;
+ case 'i':
+ if (p[0][2] == 'B')
+ suffixes += 2;
break;
- case 'D':
+ case 'B':
+ case 'D': /* 'D' is obsolescent */
base = 1000;
suffixes++;
break;
@@ -194,28 +201,31 @@ __xstrtol (const char *s, char **ptr, int strtol_base,
overflow = 0;
break;
- case 'E': /* Exa */
+ case 'E': /* exa or exbi */
overflow = bkm_scale_by_power (&tmp, base, 6);
break;
- case 'G': /* Giga */
+ case 'G': /* giga or gibi */
+ case 'g': /* 'g' is undocumented; for compatibility only */
overflow = bkm_scale_by_power (&tmp, base, 3);
break;
case 'k': /* kilo */
+ case 'K': /* kibi */
overflow = bkm_scale_by_power (&tmp, base, 1);
break;
- case 'M': /* Mega */
- case 'm': /* 'm' is undocumented; for backward compatibility only */
+ case 'M': /* mega or mebi */
+ case 'm': /* 'm' is undocumented; for compatibility only */
overflow = bkm_scale_by_power (&tmp, base, 2);
break;
- case 'P': /* Peta */
+ case 'P': /* peta or pebi */
overflow = bkm_scale_by_power (&tmp, base, 5);
break;
- case 'T': /* Tera */
+ case 'T': /* tera or tebi */
+ case 't': /* 't' is undocumented; for compatibility only */
overflow = bkm_scale_by_power (&tmp, base, 4);
break;
@@ -223,28 +233,27 @@ __xstrtol (const char *s, char **ptr, int strtol_base,
overflow = bkm_scale (&tmp, 2);
break;
- case 'Y': /* Yotta */
+ case 'Y': /* yotta or 2**80 */
overflow = bkm_scale_by_power (&tmp, base, 8);
break;
- case 'Z': /* Zetta */
+ case 'Z': /* zetta or 2**70 */
overflow = bkm_scale_by_power (&tmp, base, 7);
break;
default:
*val = tmp;
- return LONGINT_INVALID_SUFFIX_CHAR;
- break;
+ return err | LONGINT_INVALID_SUFFIX_CHAR;
}
- if (overflow)
- return LONGINT_OVERFLOW;
-
- (*p) += suffixes;
+ err |= overflow;
+ *p += suffixes;
+ if (**p)
+ err |= LONGINT_INVALID_SUFFIX_CHAR;
}
*val = tmp;
- return LONGINT_OK;
+ return err;
}
#ifdef TESTING_XSTRTO
@@ -255,7 +264,7 @@ __xstrtol (const char *s, char **ptr, int strtol_base,
char *program_name;
int
-main (int argc, char** argv)
+main (int argc, char **argv)
{
strtol_error s_err;
int i;
diff --git a/lib/xstrtol.h b/lib/xstrtol.h
index 7a9a024..0d6b984 100644
--- a/lib/xstrtol.h
+++ b/lib/xstrtol.h
@@ -1,32 +1,56 @@
+/* A more useful interface to strtol.
+
+ Copyright (C) 1995, 1996, 1998, 1999, 2001, 2002, 2003, 2004 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 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 General Public License for more details.
+
+ You should have received a copy of the GNU 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 XSTRTOL_H_
# define XSTRTOL_H_ 1
+# include "exitfail.h"
+
# if HAVE_INTTYPES_H
-# include <inttypes.h> /* for uintmax_t */
+# include <inttypes.h>
# endif
-
-# ifndef PARAMS
-# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
-# define PARAMS(Args) Args
-# else
-# define PARAMS(Args) ()
-# endif
+# if HAVE_STDINT_H
+# include <stdint.h>
# endif
# ifndef _STRTOL_ERROR
enum strtol_error
{
- LONGINT_OK, LONGINT_INVALID, LONGINT_INVALID_SUFFIX_CHAR, LONGINT_OVERFLOW
+ LONGINT_OK = 0,
+
+ /* These two values can be ORed together, to indicate that both
+ errors occurred. */
+ LONGINT_OVERFLOW = 1,
+ LONGINT_INVALID_SUFFIX_CHAR = 2,
+
+ LONGINT_INVALID_SUFFIX_CHAR_WITH_OVERFLOW = (LONGINT_INVALID_SUFFIX_CHAR
+ | LONGINT_OVERFLOW),
+ LONGINT_INVALID = 4
};
typedef enum strtol_error strtol_error;
# endif
# define _DECLARE_XSTRTOL(name, type) \
- strtol_error \
- name PARAMS ((const char *s, char **ptr, int base, \
- type *val, const char *valid_suffixes));
+ strtol_error name (const char *, char **, int, type *, const char *);
_DECLARE_XSTRTOL (xstrtol, long int)
_DECLARE_XSTRTOL (xstrtoul, unsigned long int)
+_DECLARE_XSTRTOL (xstrtoimax, intmax_t)
_DECLARE_XSTRTOL (xstrtoumax, uintmax_t)
# define _STRTOL_ERROR(Exit_code, Str, Argument_type_string, Err) \
@@ -34,7 +58,7 @@ _DECLARE_XSTRTOL (xstrtoumax, uintmax_t)
{ \
switch ((Err)) \
{ \
- case LONGINT_OK: \
+ default: \
abort (); \
\
case LONGINT_INVALID: \
@@ -43,7 +67,8 @@ _DECLARE_XSTRTOL (xstrtoumax, uintmax_t)
break; \
\
case LONGINT_INVALID_SUFFIX_CHAR: \
- error ((Exit_code), 0, "invalid character following %s `%s'", \
+ case LONGINT_INVALID_SUFFIX_CHAR | LONGINT_OVERFLOW: \
+ error ((Exit_code), 0, "invalid character following %s in `%s'", \
(Argument_type_string), (Str)); \
break; \
\
@@ -56,7 +81,7 @@ _DECLARE_XSTRTOL (xstrtoumax, uintmax_t)
while (0)
# define STRTOL_FATAL_ERROR(Str, Argument_type_string, Err) \
- _STRTOL_ERROR (2, Str, Argument_type_string, Err)
+ _STRTOL_ERROR (exit_failure, Str, Argument_type_string, Err)
# define STRTOL_FAIL_WARN(Str, Argument_type_string, Err) \
_STRTOL_ERROR (0, Str, Argument_type_string, Err)

Return to:

Send suggestions and report system problems to the System administrator.