diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2004-08-05 23:01:03 +0000 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2004-08-05 23:01:03 +0000 |
commit | d86254a25acd878c97af400f8ad1309ac6e307b3 (patch) | |
tree | c15293059bff93c15975ced98e23d97c13307d7e /lib | |
parent | 71ff7490f9162ef114c2b141b1a1305e6c20c439 (diff) | |
download | coreutils-d86254a25acd878c97af400f8ad1309ac6e307b3.tar.xz |
Sync from gnulib.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/.cppi-disable | 2 | ||||
-rw-r--r-- | lib/.cvsignore | 8 | ||||
-rw-r--r-- | lib/ChangeLog | 25 | ||||
-rw-r--r-- | lib/backupfile.h | 11 | ||||
-rw-r--r-- | lib/closeout.h | 10 | ||||
-rw-r--r-- | lib/dirname.h | 4 | ||||
-rw-r--r-- | lib/full-write.h | 13 | ||||
-rw-r--r-- | lib/gettime.c | 21 | ||||
-rw-r--r-- | lib/mbswidth.h | 10 | ||||
-rw-r--r-- | lib/obstack.h | 2 | ||||
-rw-r--r-- | lib/printf-parse.c | 141 | ||||
-rw-r--r-- | lib/printf-parse.h | 17 | ||||
-rw-r--r-- | lib/settime.c | 39 | ||||
-rw-r--r-- | lib/vasnprintf.c | 352 | ||||
-rw-r--r-- | lib/xalloc.h | 15 |
15 files changed, 477 insertions, 193 deletions
diff --git a/lib/.cppi-disable b/lib/.cppi-disable index 11a9ea9f2..afd50d090 100644 --- a/lib/.cppi-disable +++ b/lib/.cppi-disable @@ -2,7 +2,7 @@ alloca_.h allocsa.h error.h exit.h -fnmatch.h +fnmatch_.h fts.c fts_.h getndelim2.h diff --git a/lib/.cvsignore b/lib/.cvsignore index 615f8c8dc..807a9e8ad 100644 --- a/lib/.cvsignore +++ b/lib/.cvsignore @@ -4,12 +4,12 @@ alloca.h charset.alias getdate.c getdate.tab.c +fnmatch.h lstat.c +poll.h ref-add.sed ref-del.sed -safe-lstat.c -safe-lstat.h -safe-stat.c -safe-stat.h stat.c +stdbool.h +sysexit.h unlocked-io.h diff --git a/lib/ChangeLog b/lib/ChangeLog index 442792602..5cddfbdb6 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,28 @@ +2004-08-05 Paul Eggert <eggert@cs.ucla.edu> + + Merge with gnulib and deal with some minor cleanups resulting. + + * .cppi-disable: Change fnmatch.h to fnmatch_.h. + * .cvs-ignore: Add fnmatch.h, poll.h, stdbool.h, sysexit.h. + Remove safe-lstat.c, safe-lstat.h, safe-stat.c, safe-stat.h. + + * backupfile.h, closeout.h, full-write.h, mbswidth.h, xalloc.h: + Add extern "C" wrappers for C++. + + * dirname.h (IS_ABSOLUTE_FILE_NAME): Port to DOS. + + * gettime.c (gettime): Fall back on `time' if `gettimeofday' + doesn't work. + * settime.c: Include <unistd.h>, for stime (on Solaris 8, anyway). + (ENOSYS): Define if not defined. + (settime): Fall back on stime if it exists and settimeofday fails. + But don't bother with fallbacks if a method fails with errno == EPERM. + + * obstack.h: Add white space. + + * printf-parse.c, printf-parse.h, vasnprintf.c: Merge changes from + gnulib, but rewrite to avoid "xsize.h". + 2004-08-04 Paul Eggert <eggert@cs.ucla.edu> * mountlist.c (SIZE_MAX): Define after including files, to avoid diff --git a/lib/backupfile.h b/lib/backupfile.h index f330f51cd..346b60c3e 100644 --- a/lib/backupfile.h +++ b/lib/backupfile.h @@ -21,6 +21,11 @@ #ifndef BACKUPFILE_H_ # define BACKUPFILE_H_ +# ifdef __cplusplus +extern "C" { +# endif + + /* When to make backup files. */ enum backup_type { @@ -49,5 +54,11 @@ extern char const *simple_backup_suffix; char *find_backup_file_name (char const *, enum backup_type); enum backup_type get_version (char const *context, char const *arg); enum backup_type xget_version (char const *context, char const *arg); +void addext (char *, char const *, int); + + +# ifdef __cplusplus +} +# endif #endif /* ! BACKUPFILE_H_ */ diff --git a/lib/closeout.h b/lib/closeout.h index d27d7601e..1b715ee30 100644 --- a/lib/closeout.h +++ b/lib/closeout.h @@ -1,6 +1,6 @@ /* Close standard output. - Copyright (C) 1998, 2000, 2003 Free Software Foundation, Inc. + Copyright (C) 1998, 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 @@ -19,7 +19,15 @@ #ifndef CLOSEOUT_H # define CLOSEOUT_H 1 +# ifdef __cplusplus +extern "C" { +# endif + void close_stdout_set_file_name (const char *file); void close_stdout (void); +# ifdef __cplusplus +} +# endif + #endif diff --git a/lib/dirname.h b/lib/dirname.h index 91479ad9a..bc2400a7d 100644 --- a/lib/dirname.h +++ b/lib/dirname.h @@ -34,8 +34,8 @@ # define FILE_SYSTEM_PREFIX_LEN(Filename) 0 # endif -# define IS_ABSOLUTE_FILE_NAME(Name) (ISSLASH (*Name)) -# define IS_RELATIVE_FILE_NAME(Name) ( ! IS_ABSOLUTE_FILE_NAME (Name)) +# define IS_ABSOLUTE_FILE_NAME(F) ISSLASH ((F)[FILE_SYSTEM_PREFIX_LEN (F)]) +# define IS_RELATIVE_FILE_NAME(F) (! IS_ABSOLUTE_FILE_NAME (F)) char *base_name (char const *path); char *dir_name (char const *path); diff --git a/lib/full-write.h b/lib/full-write.h index 8cd2e8157..2637903ec 100644 --- a/lib/full-write.h +++ b/lib/full-write.h @@ -1,6 +1,6 @@ /* An interface to write() that writes all it is asked to write. - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002-2003 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,7 +18,18 @@ #include <stddef.h> + +#ifdef __cplusplus +extern "C" { +#endif + + /* Write COUNT bytes at BUF to descriptor FD, retrying if interrupted or if partial writes occur. Return the number of bytes successfully written, setting errno if that is less than COUNT. */ extern size_t full_write (int fd, const void *buf, size_t count); + + +#ifdef __cplusplus +} +#endif diff --git a/lib/gettime.c b/lib/gettime.c index 528060733..715d1916a 100644 --- a/lib/gettime.c +++ b/lib/gettime.c @@ -1,5 +1,5 @@ /* gettime -- get the system clock - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 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 @@ -33,14 +33,27 @@ gettime (struct timespec *ts) return 0; #endif +#if HAVE_GETTIMEOFDAY { struct timeval tv; - int r = gettimeofday (&tv, 0); - if (r == 0) + if (gettimeofday (&tv, 0) == 0) { ts->tv_sec = tv.tv_sec; ts->tv_nsec = tv.tv_usec * 1000; + return 0; } - return r; } +#endif + + { + time_t t = time (0); + if (t != (time_t) -1) + { + ts->tv_sec = t; + ts->tv_nsec = 0; + return 0; + } + } + + return -1; } diff --git a/lib/mbswidth.h b/lib/mbswidth.h index 6fec3f490..4fcdb2096 100644 --- a/lib/mbswidth.h +++ b/lib/mbswidth.h @@ -30,6 +30,11 @@ #endif +#ifdef __cplusplus +extern "C" { +#endif + + /* Optional flags to influence mbswidth/mbsnwidth behavior. */ /* If this bit is set, return -1 upon finding an invalid or incomplete @@ -49,3 +54,8 @@ extern int mbswidth (const char *string, int flags); /* Returns the number of screen columns needed for the NBYTES bytes starting at BUF. */ extern int mbsnwidth (const char *buf, size_t nbytes, int flags); + + +#ifdef __cplusplus +} +#endif diff --git a/lib/obstack.h b/lib/obstack.h index dec18aca8..d46b0544a 100644 --- a/lib/obstack.h +++ b/lib/obstack.h @@ -206,7 +206,7 @@ extern int obstack_exit_failure; Note that this might not be the final address of the object because a new chunk might be needed to hold the final size. */ -#define obstack_base(h) ((void *)(h)->object_base) +#define obstack_base(h) ((void *) (h)->object_base) /* Size for allocating ordinary chunks. */ diff --git a/lib/printf-parse.c b/lib/printf-parse.c index 51b08bbb0..4663a7269 100644 --- a/lib/printf-parse.c +++ b/lib/printf-parse.c @@ -1,5 +1,5 @@ /* Formatted output to strings. - Copyright (C) 1999-2000, 2002-2003 Free Software Foundation, Inc. + Copyright (C) 1999-2000, 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 @@ -20,7 +20,11 @@ #endif /* Specification. */ -#include "printf-parse.h" +#if WIDE_CHAR_VERSION +# include "wprintf-parse.h" +#else +# include "printf-parse.h" +#endif /* Get size_t, NULL. */ #include <stddef.h> @@ -36,22 +40,38 @@ /* malloc(), realloc(), free(). */ #include <stdlib.h> +#ifndef SIZE_MAX +# define SIZE_MAX ((size_t) -1) +#endif + +#if WIDE_CHAR_VERSION +# define PRINTF_PARSE wprintf_parse +# define CHAR_T wchar_t +# define DIRECTIVE wchar_t_directive +# define DIRECTIVES wchar_t_directives +#else +# define PRINTF_PARSE printf_parse +# define CHAR_T char +# define DIRECTIVE char_directive +# define DIRECTIVES char_directives +#endif + #ifdef STATIC STATIC #endif int -printf_parse (const char *format, char_directives *d, arguments *a) +PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) { - const char *cp = format; /* pointer into format */ - int arg_posn = 0; /* number of regular arguments consumed */ - unsigned int d_allocated; /* allocated elements of d->dir */ - unsigned int a_allocated; /* allocated elements of a->arg */ - unsigned int max_width_length = 0; - unsigned int max_precision_length = 0; + const CHAR_T *cp = format; /* pointer into format */ + size_t arg_posn = 0; /* number of regular arguments consumed */ + size_t d_allocated; /* allocated elements of d->dir */ + size_t a_allocated; /* allocated elements of a->arg */ + size_t max_width_length = 0; + size_t max_precision_length = 0; d->count = 0; d_allocated = 1; - d->dir = malloc (d_allocated * sizeof (char_directive)); + d->dir = malloc (d_allocated * sizeof (DIRECTIVE)); if (d->dir == NULL) /* Out of memory. */ return -1; @@ -62,16 +82,22 @@ printf_parse (const char *format, char_directives *d, arguments *a) #define REGISTER_ARG(_index_,_type_) \ { \ - unsigned int n = (_index_); \ + size_t n = (_index_); \ if (n >= a_allocated) \ { \ + size_t memory_size; \ argument *memory; \ - a_allocated = 2 * a_allocated; \ + \ + a_allocated *= 2; \ if (a_allocated <= n) \ a_allocated = n + 1; \ + if (SIZE_MAX / sizeof (argument) < a_allocated) \ + /* Overflow, would lead to out of memory. */ \ + goto error; \ + memory_size = a_allocated * sizeof (argument); \ memory = (a->arg \ - ? realloc (a->arg, a_allocated * sizeof (argument)) \ - : malloc (a_allocated * sizeof (argument))); \ + ? realloc (a->arg, memory_size) \ + : malloc (memory_size)); \ if (memory == NULL) \ /* Out of memory. */ \ goto error; \ @@ -88,36 +114,40 @@ printf_parse (const char *format, char_directives *d, arguments *a) while (*cp != '\0') { - char c = *cp++; + CHAR_T c = *cp++; if (c == '%') { - int arg_index = -1; - char_directive *dp = &d->dir[d->count];/* pointer to next directive */ + size_t arg_index = ARG_NONE; + DIRECTIVE *dp = &d->dir[d->count];/* pointer to next directive */ /* Initialize the next directive. */ dp->dir_start = cp - 1; dp->flags = 0; dp->width_start = NULL; dp->width_end = NULL; - dp->width_arg_index = -1; + dp->width_arg_index = ARG_NONE; dp->precision_start = NULL; dp->precision_end = NULL; - dp->precision_arg_index = -1; - dp->arg_index = -1; + dp->precision_arg_index = ARG_NONE; + dp->arg_index = ARG_NONE; /* Test for positional argument. */ if (*cp >= '0' && *cp <= '9') { - const char *np; + const CHAR_T *np; for (np = cp; *np >= '0' && *np <= '9'; np++) ; if (*np == '$') { - unsigned int n = 0; + size_t n = 0; for (np = cp; *np >= '0' && *np <= '9'; np++) - n = 10 * n + (*np - '0'); + if (n < SIZE_MAX / 10) + n = 10 * n + (*np - '0'); + else + /* n too large for memory. */ + goto error; if (n == 0) /* Positional argument 0. */ goto error; @@ -175,16 +205,20 @@ printf_parse (const char *format, char_directives *d, arguments *a) /* Test for positional argument. */ if (*cp >= '0' && *cp <= '9') { - const char *np; + const CHAR_T *np; for (np = cp; *np >= '0' && *np <= '9'; np++) ; if (*np == '$') { - unsigned int n = 0; + size_t n = 0; for (np = cp; *np >= '0' && *np <= '9'; np++) - n = 10 * n + (*np - '0'); + if (n < SIZE_MAX / 10) + n = 10 * n + (*np - '0'); + else + /* n too large for memory. */ + goto error; if (n == 0) /* Positional argument 0. */ goto error; @@ -192,13 +226,18 @@ printf_parse (const char *format, char_directives *d, arguments *a) cp = np + 1; } } - if (dp->width_arg_index < 0) - dp->width_arg_index = arg_posn++; + if (dp->width_arg_index == ARG_NONE) + { + dp->width_arg_index = arg_posn++; + if (dp->width_arg_index == ARG_NONE) + /* arg_posn wrapped around. */ + goto error; + } REGISTER_ARG (dp->width_arg_index, TYPE_INT); } else if (*cp >= '0' && *cp <= '9') { - unsigned int width_length; + size_t width_length; dp->width_start = cp; for (; *cp >= '0' && *cp <= '9'; cp++) @@ -224,16 +263,20 @@ printf_parse (const char *format, char_directives *d, arguments *a) /* Test for positional argument. */ if (*cp >= '0' && *cp <= '9') { - const char *np; + const CHAR_T *np; for (np = cp; *np >= '0' && *np <= '9'; np++) ; if (*np == '$') { - unsigned int n = 0; + size_t n = 0; for (np = cp; *np >= '0' && *np <= '9'; np++) - n = 10 * n + (*np - '0'); + if (n < SIZE_MAX / 10) + n = 10 * n + (*np - '0'); + else + /* n too large for memory. */ + goto error; if (n == 0) /* Positional argument 0. */ goto error; @@ -241,13 +284,18 @@ printf_parse (const char *format, char_directives *d, arguments *a) cp = np + 1; } } - if (dp->precision_arg_index < 0) - dp->precision_arg_index = arg_posn++; + if (dp->precision_arg_index == ARG_NONE) + { + dp->precision_arg_index = arg_posn++; + if (dp->precision_arg_index == ARG_NONE) + /* arg_posn wrapped around. */ + goto error; + } REGISTER_ARG (dp->precision_arg_index, TYPE_INT); } else { - unsigned int precision_length; + size_t precision_length; dp->precision_start = cp - 1; for (; *cp >= '0' && *cp <= '9'; cp++) @@ -439,8 +487,13 @@ printf_parse (const char *format, char_directives *d, arguments *a) if (type != TYPE_NONE) { dp->arg_index = arg_index; - if (dp->arg_index < 0) - dp->arg_index = arg_posn++; + if (dp->arg_index == ARG_NONE) + { + dp->arg_index = arg_posn++; + if (dp->arg_index == ARG_NONE) + /* arg_posn wrapped around. */ + goto error; + } REGISTER_ARG (dp->arg_index, type); } dp->conversion = c; @@ -450,10 +503,13 @@ printf_parse (const char *format, char_directives *d, arguments *a) d->count++; if (d->count >= d_allocated) { - char_directive *memory; + DIRECTIVE *memory; - d_allocated = 2 * d_allocated; - memory = realloc (d->dir, d_allocated * sizeof (char_directive)); + if (SIZE_MAX / (2 * sizeof (DIRECTIVE)) < d_allocated) + /* Overflow, would lead to out of memory. */ + goto error; + d_allocated *= 2; + memory = realloc (d->dir, d_allocated * sizeof (DIRECTIVE)); if (memory == NULL) /* Out of memory. */ goto error; @@ -474,3 +530,8 @@ error: free (d->dir); return -1; } + +#undef DIRECTIVES +#undef DIRECTIVE +#undef CHAR_T +#undef PRINTF_PARSE diff --git a/lib/printf-parse.h b/lib/printf-parse.h index 54b429f12..f3f458660 100644 --- a/lib/printf-parse.h +++ b/lib/printf-parse.h @@ -1,5 +1,5 @@ /* Parse printf format string. - Copyright (C) 1999, 2002 Free Software Foundation, Inc. + Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -29,6 +29,9 @@ #define FLAG_ALT 16 /* # flag */ #define FLAG_ZERO 32 +/* arg_index value indicating that no argument is consumed. */ +#define ARG_NONE (~(size_t)0) + /* A parsed directive. */ typedef struct { @@ -37,22 +40,22 @@ typedef struct int flags; const char* width_start; const char* width_end; - int width_arg_index; + size_t width_arg_index; const char* precision_start; const char* precision_end; - int precision_arg_index; + size_t precision_arg_index; char conversion; /* d i o u x X f e E g G c s p n U % but not C S */ - int arg_index; + size_t arg_index; } char_directive; /* A parsed format string. */ typedef struct { - unsigned int count; + size_t count; char_directive *dir; - unsigned int max_width_length; - unsigned int max_precision_length; + size_t max_width_length; + size_t max_precision_length; } char_directives; diff --git a/lib/settime.c b/lib/settime.c index 277c80583..e989a6db6 100644 --- a/lib/settime.c +++ b/lib/settime.c @@ -1,5 +1,5 @@ /* settime -- set the system clock - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 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 @@ -23,21 +23,52 @@ #include "timespec.h" +#if HAVE_UNISTD_H +# include <unistd.h> +#endif + +#include <errno.h> + +/* Some systems don't have ENOSYS. */ +#ifndef ENOSYS +# ifdef ENOTSUP +# define ENOSYS ENOTSUP +# else +/* Some systems don't have ENOTSUP either. */ +# define ENOSYS EINVAL +# endif +#endif + /* Set the system time. */ int settime (struct timespec const *ts) { #if defined CLOCK_REALTIME && HAVE_CLOCK_SETTIME - if (clock_settime (CLOCK_REALTIME, ts) == 0) - return 0; + { + int r = clock_settime (CLOCK_REALTIME, ts); + if (r == 0 || errno == EPERM) + return r; + } #endif +#if HAVE_SETTIMEOFDAY { struct timeval tv; + int r; tv.tv_sec = ts->tv_sec; tv.tv_usec = ts->tv_nsec / 1000; - return settimeofday (&tv, 0); + r = settimeofday (&tv, 0); + if (r == 0 || errno == EPERM) + return r; } +#endif + +#if HAVE_STIME + return stime (&ts->tv_sec); +#endif + + errno = ENOSYS; + return -1; } diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c index f416c1240..e24e4cd86 100644 --- a/lib/vasnprintf.c +++ b/lib/vasnprintf.c @@ -1,5 +1,5 @@ /* vsprintf with automatic memory allocation. - Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc. + 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 @@ -25,10 +25,16 @@ #ifdef HAVE_CONFIG_H # include <config.h> #endif -#include <alloca.h> +#ifndef IN_LIBINTL +# include <alloca.h> +#endif /* Specification. */ -#include "vasnprintf.h" +#if WIDE_CHAR_VERSION +# include "vasnwprintf.h" +#else +# include "vasnprintf.h" +#endif #include <stdio.h> /* snprintf(), sprintf() */ #include <stdlib.h> /* abort(), malloc(), realloc(), free() */ @@ -36,15 +42,14 @@ #include <errno.h> /* errno */ #include <limits.h> /* CHAR_BIT */ #include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP */ -#include "printf-parse.h" - -/* For those losing systems which don't have 'alloca' we have to add - some additional code emulating it. */ -#ifdef HAVE_ALLOCA -# define freea(p) /* nothing */ +#if WIDE_CHAR_VERSION +# include "wprintf-parse.h" #else -# define alloca(n) malloc (n) -# define freea(p) free (p) +# include "printf-parse.h" +#endif + +#ifndef SIZE_MAX +# define SIZE_MAX ((size_t) -1) #endif #ifdef HAVE_WCHAR_T @@ -52,7 +57,11 @@ # define local_wcslen wcslen # else /* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid - a dependency towards this library, here is a local substitute. */ + a dependency towards this library, here is a local substitute. + Define this substitute only once, even if this file is included + twice in the same compilation unit. */ +# ifndef local_wcslen_defined +# define local_wcslen_defined 1 static size_t local_wcslen (const wchar_t *s) { @@ -62,16 +71,48 @@ local_wcslen (const wchar_t *s) ; return ptr - s; } +# endif # endif #endif -char * -vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) +#if WIDE_CHAR_VERSION +# define VASNPRINTF vasnwprintf +# define CHAR_T wchar_t +# define DIRECTIVE wchar_t_directive +# define DIRECTIVES wchar_t_directives +# define PRINTF_PARSE wprintf_parse +# define USE_SNPRINTF 1 +# if HAVE_DECL__SNWPRINTF + /* On Windows, the function swprintf() has a different signature than + on Unix; we use the _snwprintf() function instead. */ +# define SNPRINTF _snwprintf +# else + /* Unix. */ +# define SNPRINTF swprintf +# endif +#else +# define VASNPRINTF vasnprintf +# define CHAR_T char +# define DIRECTIVE char_directive +# define DIRECTIVES char_directives +# define PRINTF_PARSE printf_parse +# define USE_SNPRINTF (HAVE_DECL__SNPRINTF || HAVE_SNPRINTF) +# if HAVE_DECL__SNPRINTF + /* Windows. */ +# define SNPRINTF _snprintf +# else + /* Unix. */ +# define SNPRINTF snprintf +# endif +#endif + +CHAR_T * +VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args) { - char_directives d; + DIRECTIVES d; arguments a; - if (printf_parse (format, &d, &a) < 0) + if (PRINTF_PARSE (format, &d, &a) < 0) { errno = EINVAL; return NULL; @@ -90,16 +131,37 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) } { - char *buf = - (char *) alloca (7 + d.max_width_length + d.max_precision_length + 6); - const char *cp; - unsigned int i; - char_directive *dp; + size_t buf_neededlength; + CHAR_T *buf; + CHAR_T *buf_malloced; + const CHAR_T *cp; + size_t i; + DIRECTIVE *dp; /* Output string accumulator. */ - char *result; + CHAR_T *result; size_t allocated; size_t length; + /* Allocate a small buffer that will hold a directive passed to + sprintf or snprintf. */ + buf_neededlength = 7 + d.max_width_length + d.max_precision_length + 6; +#if HAVE_ALLOCA + if (buf_neededlength < 4000 / sizeof (CHAR_T)) + { + buf = (CHAR_T *) alloca (buf_neededlength * sizeof (CHAR_T)); + buf_malloced = NULL; + } + else +#endif + { + if (SIZE_MAX / sizeof (CHAR_T) < buf_neededlength) + goto out_of_memory_1; + buf = (CHAR_T *) malloc (buf_neededlength * sizeof (CHAR_T)); + if (buf == NULL) + goto out_of_memory_1; + buf_malloced = buf; + } + if (resultbuf != NULL) { result = resultbuf; @@ -115,32 +177,35 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) result is either == resultbuf or == NULL or malloc-allocated. If length > 0, then result != NULL. */ -#define ENSURE_ALLOCATION(needed) \ - if ((needed) > allocated) \ - { \ - char *memory; \ - \ - allocated = (allocated > 0 ? 2 * allocated : 12); \ - if ((needed) > allocated) \ - allocated = (needed); \ - if (result == resultbuf || result == NULL) \ - memory = (char *) malloc (allocated); \ - else \ - memory = (char *) realloc (result, allocated); \ - \ - if (memory == NULL) \ - { \ - if (!(result == resultbuf || result == NULL)) \ - free (result); \ - freea (buf); \ - CLEANUP (); \ - errno = ENOMEM; \ - return NULL; \ - } \ - if (result == resultbuf && length > 0) \ - memcpy (memory, result, length); \ - result = memory; \ - } + /* Ensures that allocated >= length + extra. Aborts through a jump to + out_of_memory if size is too big. */ +#define ENSURE_ALLOCATION(extra) \ + { \ + size_t needed = length + (extra); \ + if (needed < length) \ + goto out_of_memory; \ + if (needed > allocated) \ + { \ + size_t memory_size; \ + CHAR_T *memory; \ + \ + allocated = (allocated > 0 ? 2 * allocated : 12); \ + if (needed > allocated) \ + allocated = needed; \ + if (SIZE_MAX / sizeof (CHAR_T) < allocated) \ + goto out_of_memory; \ + memory_size = allocated * sizeof (CHAR_T); \ + if (result == resultbuf || result == NULL) \ + memory = (CHAR_T *) malloc (memory_size); \ + else \ + memory = (CHAR_T *) realloc (result, memory_size); \ + if (memory == NULL) \ + goto out_of_memory; \ + if (result == resultbuf && length > 0) \ + memcpy (memory, result, length * sizeof (CHAR_T)); \ + result = memory; \ + } \ + } for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++) { @@ -148,8 +213,8 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) { size_t n = dp->dir_start - cp; - ENSURE_ALLOCATION (length + n); - memcpy (result + length, cp, n); + ENSURE_ALLOCATION (n); + memcpy (result + length, cp, n * sizeof (CHAR_T)); length += n; } if (i == d.count) @@ -158,15 +223,15 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) /* Execute a single directive. */ if (dp->conversion == '%') { - if (!(dp->arg_index < 0)) + if (!(dp->arg_index == ARG_NONE)) abort (); - ENSURE_ALLOCATION (length + 1); + ENSURE_ALLOCATION (1); result[length] = '%'; length += 1; } else { - if (!(dp->arg_index >= 0)) + if (!(dp->arg_index != ARG_NONE)) abort (); if (dp->conversion == 'n') @@ -197,38 +262,42 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) else { arg_type type = a.arg[dp->arg_index].type; - char *p; + CHAR_T *p; unsigned int prefix_count; int prefixes[2]; -#if !HAVE_SNPRINTF - unsigned int tmp_length; - char tmpbuf[700]; - char *tmp; +#if !USE_SNPRINTF + size_t tmp_length; + CHAR_T tmpbuf[700]; + CHAR_T *tmp; /* Allocate a temporary buffer of sufficient size for calling sprintf. */ { - unsigned int width; - unsigned int precision; + size_t width; + size_t precision; width = 0; if (dp->width_start != dp->width_end) { - if (dp->width_arg_index >= 0) + if (dp->width_arg_index != ARG_NONE) { int arg; if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) abort (); arg = a.arg[dp->width_arg_index].a.a_int; - width = (arg < 0 ? -arg : arg); + width = (arg < 0 ? (unsigned int) (-arg) : arg); } else { - const char *digitp = dp->width_start; + const CHAR_T *digitp = dp->width_start; do - width = width * 10 + (*digitp++ - '0'); + { + if (SIZE_MAX / 10 <= width) + goto out_of_memory; + width = width * 10 + (*digitp++ - '0'); + } while (digitp != dp->width_end); } } @@ -236,7 +305,7 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) precision = 6; if (dp->precision_start != dp->precision_end) { - if (dp->precision_arg_index >= 0) + if (dp->precision_arg_index != ARG_NONE) { int arg; @@ -247,12 +316,16 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) } else { - const char *digitp = dp->precision_start + 1; + const CHAR_T *digitp = dp->precision_start + 1; precision = 0; - do - precision = precision * 10 + (*digitp++ - '0'); - while (digitp != dp->precision_end); + while (digitp != dp->precision_end) + { + size_t p1 = 10 * precision + (*digitp++ - '0'); + precision = ((SIZE_MAX / 10 < precision + || p1 < precision) + ? SIZE_MAX : p1); + } } } @@ -352,7 +425,6 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) * 2 /* estimate for FLAG_GROUP */ ) + 1 /* turn floor into ceil */ - + precision + 10; /* sign, decimal point etc. */ else # endif @@ -362,19 +434,23 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) * 2 /* estimate for FLAG_GROUP */ ) + 1 /* turn floor into ceil */ - + precision + 10; /* sign, decimal point etc. */ + tmp_length += precision; + if (tmp_length < precision) + goto out_of_memory; break; case 'e': case 'E': case 'g': case 'G': case 'a': case 'A': tmp_length = - precision - + 12; /* sign, decimal point, exponent etc. */ + 12; /* sign, decimal point, exponent etc. */ + tmp_length += precision; + if (tmp_length < precision) + goto out_of_memory; break; case 'c': -# ifdef HAVE_WINT_T +# if defined HAVE_WINT_T && !WIDE_CHAR_VERSION if (type == TYPE_WIDE_CHAR) tmp_length = MB_CUR_MAX; else @@ -385,9 +461,16 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) case 's': # ifdef HAVE_WCHAR_T if (type == TYPE_WIDE_STRING) - tmp_length = - local_wcslen (a.arg[dp->arg_index].a.a_wide_string) - * MB_CUR_MAX; + { + tmp_length = + local_wcslen (a.arg[dp->arg_index].a.a_wide_string); + +# if !WIDE_CHAR_VERSION + if (SIZE_MAX / MB_CUR_MAX < tmp_length) + goto out_of_memory; + tmp_length *= MB_CUR_MAX; +# endif + } else # endif tmp_length = strlen (a.arg[dp->arg_index].a.a_string); @@ -410,23 +493,21 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) tmp_length = width; tmp_length++; /* account for trailing NUL */ + if (!tmp_length) + goto out_of_memory; } - if (tmp_length <= sizeof (tmpbuf)) + if (tmp_length <= sizeof (tmpbuf) / sizeof (CHAR_T)) tmp = tmpbuf; else { - tmp = (char *) malloc (tmp_length); + if (SIZE_MAX / sizeof (CHAR_T) < tmp_length) + /* Overflow, would lead to out of memory. */ + goto out_of_memory; + tmp = (CHAR_T *) malloc (tmp_length * sizeof (CHAR_T)); if (tmp == NULL) - { - /* Out of memory. */ - if (!(result == resultbuf || result == NULL)) - free (result); - freea (buf); - CLEANUP (); - errno = ENOMEM; - return NULL; - } + /* Out of memory. */ + goto out_of_memory; } #endif @@ -449,13 +530,13 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) if (dp->width_start != dp->width_end) { size_t n = dp->width_end - dp->width_start; - memcpy (p, dp->width_start, n); + memcpy (p, dp->width_start, n * sizeof (CHAR_T)); p += n; } if (dp->precision_start != dp->precision_end) { size_t n = dp->precision_end - dp->precision_start; - memcpy (p, dp->precision_start, n); + memcpy (p, dp->precision_start, n * sizeof (CHAR_T)); p += n; } @@ -486,7 +567,7 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) break; } *p = dp->conversion; -#if HAVE_SNPRINTF +#if USE_SNPRINTF p[1] = '%'; p[2] = 'n'; p[3] = '\0'; @@ -496,23 +577,23 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) /* Construct the arguments for calling snprintf or sprintf. */ prefix_count = 0; - if (dp->width_arg_index >= 0) + if (dp->width_arg_index != ARG_NONE) { if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) abort (); prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int; } - if (dp->precision_arg_index >= 0) + if (dp->precision_arg_index != ARG_NONE) { if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) abort (); prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int; } -#if HAVE_SNPRINTF +#if USE_SNPRINTF /* Prepare checking whether snprintf returns the count via %n. */ - ENSURE_ALLOCATION (length + 1); + ENSURE_ALLOCATION (1); result[length] = '\0'; #endif @@ -526,20 +607,20 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) count = -1; retcount = 0; -#if HAVE_SNPRINTF +#if USE_SNPRINTF # define SNPRINTF_BUF(arg) \ switch (prefix_count) \ { \ case 0: \ - retcount = snprintf (result + length, maxlen, buf, \ + retcount = SNPRINTF (result + length, maxlen, buf, \ arg, &count); \ break; \ case 1: \ - retcount = snprintf (result + length, maxlen, buf, \ + retcount = SNPRINTF (result + length, maxlen, buf, \ prefixes[0], arg, &count); \ break; \ case 2: \ - retcount = snprintf (result + length, maxlen, buf, \ + retcount = SNPRINTF (result + length, maxlen, buf, \ prefixes[0], prefixes[1], arg, \ &count); \ break; \ @@ -681,7 +762,7 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) abort (); } -#if HAVE_SNPRINTF +#if USE_SNPRINTF /* Portability: Not all implementations of snprintf() are ISO C 99 compliant. Determine the number of bytes that snprintf() has produced or would have @@ -707,23 +788,24 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) p[1] = '\0'; continue; } - else if (retcount < 0) + else { - /* The system's snprintf is sorely deficient: - it doesn't recognize the `%n' directive, and it - returns -1 (rather than the length that would - have been required) when the buffer is too small. - This is the case at with least HPUX 10.20. - Double the memory allocation. */ - size_t n = allocated; - if (n < 2 * allocated) + /* Look at the snprintf() return value. */ + if (retcount < 0) { - n = 2 * allocated; - ENSURE_ALLOCATION (n); + /* HP-UX 10.20 snprintf() is doubly deficient: + It doesn't understand the '%n' directive, + *and* it returns -1 (rather than the length + that would have been required) when the + buffer is too small. */ + size_t bigger_need = + (allocated > 12 ? allocated : 12); + ENSURE_ALLOCATION (bigger_need); continue; } + else + count = retcount; } - count = retcount; } #endif @@ -732,13 +814,14 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) { if (!(result == resultbuf || result == NULL)) free (result); - freea (buf); + if (buf_malloced != NULL) + free (buf_malloced); CLEANUP (); errno = EINVAL; return NULL; } -#if !HAVE_SNPRINTF +#if !USE_SNPRINTF if (count >= tmp_length) /* tmp_length was incorrectly calculated - fix the code above! */ @@ -751,22 +834,18 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) /* Need at least count bytes. But allocate proportionally, to avoid looping eternally if snprintf() reports a too small count. */ - size_t n = length + count; - - if (n < 2 * allocated) - n = 2 * allocated; - - ENSURE_ALLOCATION (n); -#if HAVE_SNPRINTF + ENSURE_ALLOCATION (count < allocated + ? allocated : count); +#if USE_SNPRINTF continue; #endif } -#if HAVE_SNPRINTF +#if USE_SNPRINTF /* The snprintf() result did fit. */ #else /* Append the sprintf() result. */ - memcpy (result + length, tmp, count); + memcpy (result + length, tmp, count * sizeof (CHAR_T)); if (tmp != tmpbuf) free (tmp); #endif @@ -779,22 +858,41 @@ vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) } /* Add the final NUL. */ - ENSURE_ALLOCATION (length + 1); + ENSURE_ALLOCATION (1); result[length] = '\0'; if (result != resultbuf && length + 1 < allocated) { /* Shrink the allocated memory if possible. */ - char *memory; + CHAR_T *memory; - memory = (char *) realloc (result, length + 1); + memory = (CHAR_T *) realloc (result, (length + 1) * sizeof (CHAR_T)); if (memory != NULL) result = memory; } - freea (buf); + if (buf_malloced != NULL) + free (buf_malloced); CLEANUP (); *lengthp = length; return result; + + out_of_memory: + if (!(result == resultbuf || result == NULL)) + free (result); + if (buf_malloced != NULL) + free (buf_malloced); + out_of_memory_1: + CLEANUP (); + errno = ENOMEM; + return NULL; } } + +#undef SNPRINTF +#undef USE_SNPRINTF +#undef PRINTF_PARSE +#undef DIRECTIVES +#undef DIRECTIVE +#undef CHAR_T +#undef VASNPRINTF diff --git a/lib/xalloc.h b/lib/xalloc.h index 4b6585811..5985892c9 100644 --- a/lib/xalloc.h +++ b/lib/xalloc.h @@ -1,7 +1,7 @@ /* xalloc.h -- malloc with out-of-memory checking Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2003 Free Software Foundation, Inc. + 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 @@ -22,6 +22,12 @@ # include <stddef.h> + +# ifdef __cplusplus +extern "C" { +# endif + + # ifndef __attribute__ # if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ # define __attribute__(x) @@ -32,6 +38,7 @@ # define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) # endif + /* If this pointer is non-zero, run the specified function upon each allocation failure. It is initialized to zero. */ extern void (*xalloc_fail_func) (void); @@ -84,4 +91,10 @@ char *xstrdup (const char *str); # define XREALLOC(p, type, n) xnrealloc (p, n, sizeof (type)) # define XFREE(p) free (p) + +# ifdef __cplusplus +} +# endif + + #endif /* !XALLOC_H_ */ |