diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/alloca_.h | 40 | ||||
-rw-r--r-- | lib/argp-ba.c | 2 | ||||
-rw-r--r-- | lib/argp-eexst.c | 4 | ||||
-rw-r--r-- | lib/argp-fmtstream.c | 51 | ||||
-rw-r--r-- | lib/argp-fmtstream.h | 28 | ||||
-rw-r--r-- | lib/argp-fs-xinl.c | 4 | ||||
-rw-r--r-- | lib/argp-help.c | 310 | ||||
-rw-r--r-- | lib/argp-namefrob.h | 20 | ||||
-rw-r--r-- | lib/argp-parse.c | 85 | ||||
-rw-r--r-- | lib/argp-pin.c | 28 | ||||
-rw-r--r-- | lib/argp-pv.c | 6 | ||||
-rw-r--r-- | lib/argp-pvh.c | 4 | ||||
-rw-r--r-- | lib/argp-xinl.c | 4 | ||||
-rw-r--r-- | lib/argp.h | 124 | ||||
-rw-r--r-- | lib/basename.c | 112 | ||||
-rw-r--r-- | lib/dirname.c | 136 | ||||
-rw-r--r-- | lib/dirname.h | 41 | ||||
-rw-r--r-- | lib/error.c | 140 | ||||
-rw-r--r-- | lib/error.h | 6 | ||||
-rw-r--r-- | lib/exitfail.c | 11 | ||||
-rw-r--r-- | lib/exitfail.h | 2 | ||||
-rw-r--r-- | lib/fatal.c | 27 | ||||
-rw-r--r-- | lib/full-write.c | 10 | ||||
-rw-r--r-- | lib/full-write.h | 2 | ||||
-rw-r--r-- | lib/getopt.c | 88 | ||||
-rw-r--r-- | lib/getopt1.c | 9 | ||||
-rw-r--r-- | lib/getopt_.h | 23 | ||||
-rw-r--r-- | lib/getopt_int.h | 2 | ||||
-rw-r--r-- | lib/gettext.h | 220 | ||||
-rw-r--r-- | lib/hash.c | 1048 | ||||
-rw-r--r-- | lib/hash.h | 88 | ||||
-rw-r--r-- | lib/intprops.h | 78 | ||||
-rw-r--r-- | lib/inttostr.c | 51 | ||||
-rw-r--r-- | lib/inttostr.h (renamed from lib/exit.h) | 28 | ||||
-rw-r--r-- | lib/mempcpy.c | 8 | ||||
-rw-r--r-- | lib/paxerror.c | 365 | ||||
-rw-r--r-- | lib/paxexit.c | 28 | ||||
-rw-r--r-- | lib/paxlib.h | 115 | ||||
-rw-r--r-- | lib/paxnames.c | 156 | ||||
-rw-r--r-- | lib/quote.c | 41 | ||||
-rw-r--r-- | lib/quote.h (renamed from lib/strchrnul.h) | 20 | ||||
-rw-r--r-- | lib/quotearg.c | 697 | ||||
-rw-r--r-- | lib/quotearg.h | 140 | ||||
-rw-r--r-- | lib/rmt-command.h (renamed from lib/localedir.h) | 0 | ||||
-rw-r--r-- | lib/rmt.h | 2 | ||||
-rw-r--r-- | lib/rtapelib.c | 14 | ||||
-rw-r--r-- | lib/safe-read.c | 14 | ||||
-rw-r--r-- | lib/safe-read.h | 14 | ||||
-rw-r--r-- | lib/safe-write.c | 2 | ||||
-rw-r--r-- | lib/safe-write.h | 2 | ||||
-rw-r--r-- | lib/savedir.c | 96 | ||||
-rw-r--r-- | lib/savedir.h | 7 | ||||
-rw-r--r-- | lib/strcase.h | 47 | ||||
-rw-r--r-- | lib/strchrnul.c | 8 | ||||
-rw-r--r-- | lib/stripslash.c | 36 | ||||
-rw-r--r-- | lib/strndup.c | 32 | ||||
-rw-r--r-- | lib/strnlen.c | 31 | ||||
-rw-r--r-- | lib/system-ioctl.h | 55 | ||||
-rw-r--r-- | lib/system.h | 99 | ||||
-rw-r--r-- | lib/umaxtostr.c | 3 | ||||
-rw-r--r-- | lib/unlocked-io.h | 206 | ||||
-rw-r--r-- | lib/utimens.c | 189 | ||||
-rw-r--r-- | lib/utimens.h | 3 | ||||
-rw-r--r-- | lib/xalloc-die.c | 9 | ||||
-rw-r--r-- | lib/xalloc.h | 202 | ||||
-rw-r--r-- | lib/xmalloc.c | 162 | ||||
-rw-r--r-- | lib/xstrndup.c (renamed from lib/mempcpy.h) | 47 | ||||
-rw-r--r-- | lib/xstrndup.h (renamed from lib/strndup.h) | 20 |
68 files changed, 4550 insertions, 1152 deletions
diff --git a/lib/alloca_.h b/lib/alloca_.h index 10995510e2520..af274b9e75387 100644 --- a/lib/alloca_.h +++ b/lib/alloca_.h @@ -1,6 +1,6 @@ /* Memory allocation on the stack. - Copyright (C) 1995, 1999, 2001, 2002, 2003, 2004 Free Software + Copyright (C) 1995, 1999, 2001-2004, 2006-2007 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it @@ -15,15 +15,13 @@ 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, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -/* When this file is included, it may be preceded only by preprocessor - declarations. Thanks to AIX. Therefore we include it right after - "config.h", not later. */ - -#ifndef _ALLOCA_H -# define _ALLOCA_H +/* Avoid using the symbol _ALLOCA_H here, as Bison assumes _ALLOCA_H + means there is a real alloca function. */ +#ifndef _GL_ALLOCA_H +#define _GL_ALLOCA_H /* alloca (N) returns a pointer to N bytes of memory allocated on the stack, which will last until the function returns. @@ -36,19 +34,21 @@ request, the program just crashes. */ -#ifdef __GNUC__ -# define alloca __builtin_alloca -#elif defined _AIX -# define alloca __alloca -#elif defined _MSC_VER -# include <malloc.h> -# define alloca _alloca -#else -# include <stddef.h> -# ifdef __cplusplus +#ifndef alloca +# ifdef __GNUC__ +# define alloca __builtin_alloca +# elif defined _AIX +# define alloca __alloca +# elif defined _MSC_VER +# include <malloc.h> +# define alloca _alloca +# else +# include <stddef.h> +# ifdef __cplusplus extern "C" -# endif +# endif void *alloca (size_t); +# endif #endif -#endif /* _ALLOCA_H */ +#endif /* _GL_ALLOCA_H */ diff --git a/lib/argp-ba.c b/lib/argp-ba.c index c4712284a9b83..8bb7309fdecd9 100644 --- a/lib/argp-ba.c +++ b/lib/argp-ba.c @@ -15,7 +15,7 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* If set by the user program, it should point to string that is the bug-reporting address for the program. It will be printed by argp_help if diff --git a/lib/argp-eexst.c b/lib/argp-eexst.c index d5cd28ceae26a..bcab1c0c17fa7 100644 --- a/lib/argp-eexst.c +++ b/lib/argp-eexst.c @@ -15,10 +15,10 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H -#include <config.h> +# include <config.h> #endif #include <sysexits.h> diff --git a/lib/argp-fmtstream.c b/lib/argp-fmtstream.c index c88c3db214713..0dd9256f570ad 100644 --- a/lib/argp-fmtstream.c +++ b/lib/argp-fmtstream.c @@ -1,5 +1,5 @@ /* Word-wrapping and line-truncating streams - Copyright (C) 1997,1998,1999,2001,2002,2003 Free Software Foundation, Inc. + Copyright (C) 1997-1999,2001,2002,2003,2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Miles Bader <miles@gnu.ai.mit.edu>. @@ -15,13 +15,13 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* This package emulates glibc `line_wrap_stream' semantics for systems that don't have that. */ #ifdef HAVE_CONFIG_H -#include <config.h> +# include <config.h> #endif #include <stdlib.h> @@ -101,11 +101,10 @@ __argp_fmtstream_free (argp_fmtstream_t fs) if (fs->p > fs->buf) { #ifdef USE_IN_LIBIO - if (_IO_fwide (fs->stream, 0) > 0) - __fwprintf (fs->stream, L"%.*s", (int) (fs->p - fs->buf), fs->buf); - else + __fxprintf (fs->stream, "%.*s", (int) (fs->p - fs->buf), fs->buf); +#else + fwrite_unlocked (fs->buf, 1, fs->p - fs->buf, fs->stream); #endif - fwrite_unlocked (fs->buf, 1, fs->p - fs->buf, fs->stream); } free (fs->buf); free (fs); @@ -247,9 +246,10 @@ __argp_fmtstream_update (argp_fmtstream_t fs) Oh well. Put it on an overlong line by itself. */ p = buf + (r + 1 - fs->point_col); /* Find the end of the long word. */ - do - ++p; - while (p < nl && !isblank (*p)); + if (p < nl) + do + ++p; + while (p < nl && !isblank (*p)); if (p == nl) { /* It already ends a line. No fussing required. */ @@ -290,17 +290,15 @@ __argp_fmtstream_update (argp_fmtstream_t fs) else /* Output the first line so we can use the space. */ { -#ifdef USE_IN_LIBIO - if (_IO_fwide (fs->stream, 0) > 0) - __fwprintf (fs->stream, L"%.*s\n", - (int) (nl - fs->buf), fs->buf); - else +#ifdef _LIBC + __fxprintf (fs->stream, "%.*s\n", + (int) (nl - fs->buf), fs->buf); +#else + if (nl > fs->buf) + fwrite_unlocked (fs->buf, 1, nl - fs->buf, fs->stream); + putc_unlocked ('\n', fs->stream); #endif - { - if (nl > fs->buf) - fwrite_unlocked (fs->buf, 1, nl - fs->buf, fs->stream); - putc_unlocked ('\n', fs->stream); - } + len += buf - fs->buf; nl = buf = fs->buf; } @@ -359,15 +357,12 @@ __argp_fmtstream_ensure (struct argp_fmtstream *fs, size_t amount) /* Flush FS's buffer. */ __argp_fmtstream_update (fs); -#ifdef USE_IN_LIBIO - if (_IO_fwide (fs->stream, 0) > 0) - { - __fwprintf (fs->stream, L"%.*s", (int) (fs->p - fs->buf), fs->buf); - wrote = fs->p - fs->buf; - } - else +#ifdef _LIBC + __fxprintf (fs->stream, "%.*s", (int) (fs->p - fs->buf), fs->buf); + wrote = fs->p - fs->buf; +#else + wrote = fwrite_unlocked (fs->buf, 1, fs->p - fs->buf, fs->stream); #endif - wrote = fwrite_unlocked (fs->buf, 1, fs->p - fs->buf, fs->stream); if (wrote == fs->p - fs->buf) { fs->p = fs->buf; diff --git a/lib/argp-fmtstream.h b/lib/argp-fmtstream.h index e71df104ce918..e045a723da4e3 100644 --- a/lib/argp-fmtstream.h +++ b/lib/argp-fmtstream.h @@ -1,5 +1,5 @@ /* Word-wrapping and line-truncating streams. - Copyright (C) 1997 Free Software Foundation, Inc. + Copyright (C) 1997, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Miles Bader <miles@gnu.ai.mit.edu>. @@ -15,7 +15,7 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* This package emulates glibc `line_wrap_stream' semantics for systems that don't have that. If the system does have it, it is just a wrapper for @@ -25,10 +25,6 @@ #ifndef _ARGP_FMTSTREAM_H #define _ARGP_FMTSTREAM_H -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - #include <stdio.h> #include <string.h> #include <unistd.h> @@ -93,10 +89,6 @@ typedef FILE *argp_fmtstream_t; #else /* !ARGP_FMTSTREAM_USE_LINEWRAP */ /* Guess we have to define our own version. */ - -#ifndef __const -#define __const const -#endif struct argp_fmtstream { @@ -137,22 +129,22 @@ extern void __argp_fmtstream_free (argp_fmtstream_t __fs); extern void argp_fmtstream_free (argp_fmtstream_t __fs); extern ssize_t __argp_fmtstream_printf (argp_fmtstream_t __fs, - __const char *__fmt, ...) + const char *__fmt, ...) __attribute__ ((__format__ (printf, 2, 3))); extern ssize_t argp_fmtstream_printf (argp_fmtstream_t __fs, - __const char *__fmt, ...) + const char *__fmt, ...) __attribute__ ((__format__ (printf, 2, 3))); extern int __argp_fmtstream_putc (argp_fmtstream_t __fs, int __ch); extern int argp_fmtstream_putc (argp_fmtstream_t __fs, int __ch); -extern int __argp_fmtstream_puts (argp_fmtstream_t __fs, __const char *__str); -extern int argp_fmtstream_puts (argp_fmtstream_t __fs, __const char *__str); +extern int __argp_fmtstream_puts (argp_fmtstream_t __fs, const char *__str); +extern int argp_fmtstream_puts (argp_fmtstream_t __fs, const char *__str); extern size_t __argp_fmtstream_write (argp_fmtstream_t __fs, - __const char *__str, size_t __len); + const char *__str, size_t __len); extern size_t argp_fmtstream_write (argp_fmtstream_t __fs, - __const char *__str, size_t __len); + const char *__str, size_t __len); /* Access macros for various bits of state. */ #define argp_fmtstream_lmargin(__fs) ((__fs)->lmargin) @@ -211,7 +203,7 @@ extern int __argp_fmtstream_ensure (argp_fmtstream_t __fs, size_t __amount); ARGP_FS_EI size_t __argp_fmtstream_write (argp_fmtstream_t __fs, - __const char *__str, size_t __len) + const char *__str, size_t __len) { if (__fs->p + __len <= __fs->end || __argp_fmtstream_ensure (__fs, __len)) { @@ -224,7 +216,7 @@ __argp_fmtstream_write (argp_fmtstream_t __fs, } ARGP_FS_EI int -__argp_fmtstream_puts (argp_fmtstream_t __fs, __const char *__str) +__argp_fmtstream_puts (argp_fmtstream_t __fs, const char *__str) { size_t __len = strlen (__str); if (__len) diff --git a/lib/argp-fs-xinl.c b/lib/argp-fs-xinl.c index a4d14a2e58c59..3b4c917e020de 100644 --- a/lib/argp-fs-xinl.c +++ b/lib/argp-fs-xinl.c @@ -15,10 +15,10 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H -#include <config.h> +# include <config.h> #endif #define ARGP_FS_EI diff --git a/lib/argp-help.c b/lib/argp-help.c index 6035764961865..396e73326f9d4 100644 --- a/lib/argp-help.c +++ b/lib/argp-help.c @@ -1,5 +1,5 @@ /* Hierarchial argument parsing help output - Copyright (C) 1995-2003, 2004 Free Software Foundation, Inc. + Copyright (C) 1995-2005, 2007 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Miles Bader <miles@gnu.ai.mit.edu>. @@ -15,14 +15,14 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _GNU_SOURCE # define _GNU_SOURCE 1 #endif #ifdef HAVE_CONFIG_H -#include <config.h> +# include <config.h> #endif #include <alloca.h> @@ -89,15 +89,15 @@ struct uparams int dup_args_note; /* Various output columns. */ - int short_opt_col; - int long_opt_col; - int doc_opt_col; - int opt_doc_col; - int header_col; - int usage_indent; - int rmargin; - - int valid; /* True when the values in here are valid. */ + int short_opt_col; /* column in which short options start */ + int long_opt_col; /* column in which long options start */ + int doc_opt_col; /* column in which doc options start */ + int opt_doc_col; /* column in which option text starts */ + int header_col; /* column in which group headers are printed */ + int usage_indent; /* indentation of wrapped usage lines */ + int rmargin; /* right margin used for wrapping */ + + int valid; /* True when the values in here are valid. */ }; /* This is a global variable, as user options are only ever read once. */ @@ -131,91 +131,126 @@ static const struct uparam_name uparam_names[] = { 0 } }; -/* Read user options from the environment, and fill in UPARAMS appropiately. */ +static void +validate_uparams (const struct argp_state *state, struct uparams *upptr) +{ + const struct uparam_name *up; + + for (up = uparam_names; up->name; up++) + { + if (up->is_bool + || up->uparams_offs == offsetof (struct uparams, rmargin)) + continue; + if (*(int *)((char *)upptr + up->uparams_offs) >= upptr->rmargin) + { + __argp_failure (state, 0, 0, + dgettext (state->root_argp->argp_domain, + "\ +ARGP_HELP_FMT: %s value is less than or equal to %s"), + "rmargin", up->name); + return; + } + } + uparams = *upptr; + uparams.valid = 1; +} + +/* Read user options from the environment, and fill in UPARAMS appropiately. */ static void fill_in_uparams (const struct argp_state *state) { const char *var = getenv ("ARGP_HELP_FMT"); - -#define SKIPWS(p) do { while (isspace (*p)) p++; } while (0); + struct uparams new_params = uparams; + +#define SKIPWS(p) do { while (isspace ((unsigned char) *p)) p++; } while (0); if (var) - /* Parse var. */ - while (*var) - { - SKIPWS (var); - - if (isalpha (*var)) - { - size_t var_len; - const struct uparam_name *un; - int unspec = 0, val = 0; - const char *arg = var; - - while (isalnum (*arg) || *arg == '-' || *arg == '_') - arg++; - var_len = arg - var; - - SKIPWS (arg); + { + /* Parse var. */ + while (*var) + { + SKIPWS (var); + + if (isalpha ((unsigned char) *var)) + { + size_t var_len; + const struct uparam_name *un; + int unspec = 0, val = 0; + const char *arg = var; - if (*arg == '\0' || *arg == ',') - unspec = 1; - else if (*arg == '=') - { + while (isalnum ((unsigned char) *arg) || *arg == '-' || *arg == '_') arg++; - SKIPWS (arg); - } - - if (unspec) - { - if (var[0] == 'n' && var[1] == 'o' && var[2] == '-') - { - val = 0; - var += 3; - var_len -= 3; - } - else - val = 1; - } - else if (isdigit (*arg)) - { - val = atoi (arg); - while (isdigit (*arg)) + var_len = arg - var; + + SKIPWS (arg); + + if (*arg == '\0' || *arg == ',') + unspec = 1; + else if (*arg == '=') + { arg++; - SKIPWS (arg); - } - - for (un = uparam_names; un->name; un++) - if (strlen (un->name) == var_len - && strncmp (var, un->name, var_len) == 0) + SKIPWS (arg); + } + + if (unspec) { - if (unspec && !un->is_bool) - __argp_failure (state, 0, 0, - dgettext (state->root_argp->argp_domain, "\ -%.*s: ARGP_HELP_FMT parameter requires a value"), - (int) var_len, var); + if (var[0] == 'n' && var[1] == 'o' && var[2] == '-') + { + val = 0; + var += 3; + var_len -= 3; + } else - *(int *)((char *)&uparams + un->uparams_offs) = val; - break; + val = 1; } - if (! un->name) - __argp_failure (state, 0, 0, - dgettext (state->root_argp->argp_domain, "\ + else if (isdigit ((unsigned char) *arg)) + { + val = atoi (arg); + while (isdigit ((unsigned char) *arg)) + arg++; + SKIPWS (arg); + } + + for (un = uparam_names; un->name; un++) + if (strlen (un->name) == var_len + && strncmp (var, un->name, var_len) == 0) + { + if (unspec && !un->is_bool) + __argp_failure (state, 0, 0, + dgettext (state->root_argp->argp_domain, + "\ +%.*s: ARGP_HELP_FMT parameter requires a value"), + (int) var_len, var); + else if (val < 0) + __argp_failure (state, 0, 0, + dgettext (state->root_argp->argp_domain, + "\ +%.*s: ARGP_HELP_FMT parameter must be positive"), + (int) var_len, var); + else + *(int *)((char *)&new_params + un->uparams_offs) = val; + break; + } + if (! un->name) + __argp_failure (state, 0, 0, + dgettext (state->root_argp->argp_domain, "\ %.*s: Unknown ARGP_HELP_FMT parameter"), - (int) var_len, var); + (int) var_len, var); - var = arg; - if (*var == ',') - var++; - } - else if (*var) - { - __argp_failure (state, 0, 0, - dgettext (state->root_argp->argp_domain, - "Garbage in ARGP_HELP_FMT: %s"), var); - break; - } - } + var = arg; + if (*var == ',') + var++; + } + else if (*var) + { + __argp_failure (state, 0, 0, + dgettext (state->root_argp->argp_domain, + "Garbage in ARGP_HELP_FMT: %s"), var); + break; + } + } + validate_uparams (state, &new_params); + } } /* Returns true if OPT hasn't been marked invisible. Visibility only affects @@ -340,6 +375,9 @@ struct hol_entry /* The argp from which this option came. */ const struct argp *argp; + + /* Position in the array */ + unsigned ord; }; /* A cluster of entries to reflect the argp tree structure. */ @@ -638,10 +676,12 @@ static int hol_cluster_cmp (const struct hol_cluster *cl1, const struct hol_cluster *cl2) { /* If one cluster is deeper than the other, use its ancestor at the same - level, so that finding the common ancestor is straightforward. */ - while (cl1->depth < cl2->depth) + level, so that finding the common ancestor is straightforward. + + clN->depth > 0 means that clN->parent != NULL (see hol_add_cluster) */ + while (cl1->depth > cl2->depth) cl1 = cl1->parent; - while (cl2->depth < cl1->depth) + while (cl2->depth > cl1->depth) cl2 = cl2->parent; /* Now reduce both clusters to their ancestors at the point where both have @@ -685,17 +725,19 @@ canon_doc_option (const char **name) else { /* Skip initial whitespace. */ - while (isspace (**name)) + while (isspace ((unsigned char) **name)) (*name)++; /* Decide whether this looks like an option (leading `-') or not. */ non_opt = (**name != '-'); /* Skip until part of name used for sorting. */ - while (**name && !isalnum (**name)) + while (**name && !isalnum ((unsigned char) **name)) (*name)++; } return non_opt; } +#define HOL_ENTRY_PTRCMP(a,b) ((a)->ord < (b)->ord ? -1 : 1) + /* Order ENTRY1 & ENTRY2 by the order which they should appear in a help listing. */ static int @@ -705,6 +747,7 @@ hol_entry_cmp (const struct hol_entry *entry1, /* The group numbers by which the entries should be ordered; if either is in a cluster, then this is just the group within the cluster. */ int group1 = entry1->group, group2 = entry2->group; + int rc; if (entry1->cluster != entry2->cluster) { @@ -721,7 +764,8 @@ hol_entry_cmp (const struct hol_entry *entry1, return group_cmp (hol_cluster_base (entry1->cluster)->group, group2, 1); else /* Both entries are in clusters, we can just compare the clusters. */ - return hol_cluster_cmp (entry1->cluster, entry2->cluster); + return (rc = hol_cluster_cmp (entry1->cluster, entry2->cluster)) ? + rc : HOL_ENTRY_PTRCMP(entry1, entry2); } else if (group1 == group2) /* The entries are both in the same cluster and group, so compare them @@ -745,7 +789,8 @@ hol_entry_cmp (const struct hol_entry *entry1, return doc1 - doc2; else if (!short1 && !short2 && long1 && long2) /* Only long options. */ - return __strcasecmp (long1, long2); + return (rc = __strcasecmp (long1, long2)) ? + rc : HOL_ENTRY_PTRCMP(entry1, entry2); else /* Compare short/short, long/short, short/long, using the first character of long options. Entries without *any* valid @@ -762,13 +807,15 @@ hol_entry_cmp (const struct hol_entry *entry1, #endif /* Compare ignoring case, except when the options are both the same letter, in which case lower-case always comes first. */ - return lower_cmp ? lower_cmp : first2 - first1; + return lower_cmp ? lower_cmp : + (rc = first2 - first1) ? + rc : HOL_ENTRY_PTRCMP(entry1, entry2); } } else /* Within the same cluster, but not the same group, so just compare groups. */ - return group_cmp (group1, group2, 0); + return group_cmp (group1, group2, HOL_ENTRY_PTRCMP(entry1, entry2)); } /* Version of hol_entry_cmp with correct signature for qsort. */ @@ -785,8 +832,14 @@ static void hol_sort (struct hol *hol) { if (hol->num_entries > 0) - qsort (hol->entries, hol->num_entries, sizeof (struct hol_entry), - hol_entry_qcmp); + { + unsigned i; + struct hol_entry *e; + for (i = 0, e = hol->entries; i < hol->num_entries; i++, e++) + e->ord = i; + qsort (hol->entries, hol->num_entries, sizeof (struct hol_entry), + hol_entry_qcmp); + } } /* Append MORE to HOL, destroying MORE in the process. Options in HOL shadow @@ -1055,7 +1108,13 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state, int old_wm = __argp_fmtstream_wmargin (stream); /* PEST is a state block holding some of our variables that we'd like to share with helper functions. */ - struct pentry_state pest = { entry, stream, hhstate, 1, state }; + struct pentry_state pest; + + pest.entry = entry; + pest.stream = stream; + pest.hhstate = hhstate; + pest.first = 1; + pest.state = state; if (! odoc (real)) for (opt = real, num = entry->num; num > 0; opt++, num--) @@ -1263,7 +1322,7 @@ usage_long_opt (const struct argp_option *opt, if (! arg) arg = real->arg; - if (! (flags & OPTION_NO_USAGE)) + if (! (flags & OPTION_NO_USAGE) && !odoc (opt)) { if (arg) { @@ -1434,46 +1493,51 @@ argp_doc (const struct argp *argp, const struct argp_state *state, { const char *text; const char *inp_text; + size_t inp_text_len = 0; + const char *trans_text; void *input = 0; int anything = 0; - size_t inp_text_limit = 0; - const char *doc = dgettext (argp->argp_domain, argp->doc); const struct argp_child *child = argp->children; - if (doc) + if (argp->doc) { - char *vt = strchr (doc, '\v'); - inp_text = post ? (vt ? vt + 1 : 0) : doc; - inp_text_limit = (!post && vt) ? (vt - doc) : 0; + char *vt = strchr (argp->doc, '\v'); + if (vt) + { + if (post) + inp_text = vt + 1; + else + { + inp_text_len = vt - argp->doc; + inp_text = __strndup (argp->doc, inp_text_len); + } + } + else + inp_text = post ? 0 : argp->doc; + trans_text = inp_text ? dgettext (argp->argp_domain, inp_text) : NULL; } else - inp_text = 0; + trans_text = inp_text = 0; if (argp->help_filter) /* We have to filter the doc strings. */ { - if (inp_text_limit) - /* Copy INP_TEXT so that it's nul-terminated. */ - inp_text = __strndup (inp_text, inp_text_limit); input = __argp_input (argp, state); text = (*argp->help_filter) (post ? ARGP_KEY_HELP_POST_DOC : ARGP_KEY_HELP_PRE_DOC, - inp_text, input); + trans_text, input); } else - text = (const char *) inp_text; + text = (const char *) trans_text; if (text) { if (pre_blank) __argp_fmtstream_putc (stream, '\n'); - if (text == inp_text && inp_text_limit) - __argp_fmtstream_write (stream, inp_text, inp_text_limit); - else - __argp_fmtstream_puts (stream, text); + __argp_fmtstream_puts (stream, text); if (__argp_fmtstream_point (stream) > __argp_fmtstream_lmargin (stream)) __argp_fmtstream_putc (stream, '\n'); @@ -1481,9 +1545,10 @@ argp_doc (const struct argp *argp, const struct argp_state *state, anything = 1; } - if (text && text != inp_text) + if (text && text != trans_text) free ((char *) text); /* Free TEXT returned from the help filter. */ - if (inp_text && inp_text_limit && argp->help_filter) + + if (inp_text && inp_text_len) free ((char *) inp_text); /* We copied INP_TEXT, so free it now. */ if (post && argp->help_filter) @@ -1663,7 +1728,10 @@ Try `%s --help' or `%s --usage' for more information.\n"), void __argp_help (const struct argp *argp, FILE *stream, unsigned flags, char *name) { - _help (argp, 0, stream, flags, name); + struct argp_state state; + memset (&state, 0, sizeof state); + state.root_argp = argp; + _help (argp, &state, stream, flags, name); } #ifdef weak_alias weak_alias (__argp_help, argp_help) @@ -1674,8 +1742,7 @@ char * __argp_short_program_name (void) { # if HAVE_DECL_PROGRAM_INVOCATION_NAME - char *name = strrchr (program_invocation_name, '/'); - return name ? name + 1 : program_invocation_name; + return __argp_base_name (program_invocation_name); # else /* FIXME: What now? Miles suggests that it is better to use NULL, but currently the value is passed on directly to fputs_unlocked, @@ -1739,7 +1806,8 @@ __argp_error (const struct argp_state *state, const char *fmt, ...) { char *buf; - __asprintf (&buf, fmt, ap); + if (__asprintf (&buf, fmt, ap) < 0) + buf = NULL; __fwprintf (stream, L"%s: %s\n", state ? state->name : __argp_short_program_name (), @@ -1817,7 +1885,8 @@ __argp_failure (const struct argp_state *state, int status, int errnum, { char *buf; - __asprintf (&buf, fmt, ap); + if (__asprintf (&buf, fmt, ap) < 0) + buf = NULL; __fwprintf (stream, L": %s", buf); @@ -1857,7 +1926,8 @@ __argp_failure (const struct argp_state *state, int status, int errnum, #endif #if !_LIBC if (! s && ! (s = strerror (errnum))) - s = "Unknown system error"; /* FIXME: translate this */ + s = dgettext (state->root_argp->argp_domain, + "Unknown system error"); #endif fputs (s, stream); } diff --git a/lib/argp-namefrob.h b/lib/argp-namefrob.h index 09cafd0835319..6fe99cd7aaf17 100644 --- a/lib/argp-namefrob.h +++ b/lib/argp-namefrob.h @@ -1,5 +1,5 @@ /* Name frobnication for compiling argp outside of glibc - Copyright (C) 1997, 2003 Free Software Foundation, Inc. + Copyright (C) 1997, 2003, 2007 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Miles Bader <miles@gnu.ai.mit.edu>. @@ -15,7 +15,7 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #if !_LIBC /* This code is written for inclusion in gnu-libc, and uses names in the @@ -76,11 +76,6 @@ #undef __argp_fmtstream_wmargin #define __argp_fmtstream_wmargin argp_fmtstream_wmargin -#include "mempcpy.h" -#include "strcase.h" -#include "strchrnul.h" -#include "strndup.h" - /* normal libc functions we call */ #undef __flockfile #define __flockfile flockfile @@ -141,14 +136,21 @@ # define putchar_unlocked(x) putchar (x) # endif -extern char *__argp_basename (char *name); - #endif /* !_LIBC */ #ifndef __set_errno #define __set_errno(e) (errno = (e)) #endif +#if defined GNULIB_ARGP_DISABLE_DIRNAME +# define __argp_base_name(arg) arg +#elif defined GNULIB_ARGP_EXTERN_BASENAME +extern char *__argp_base_name(const char *arg); +#else +# include "dirname.h" +# define __argp_base_name base_name +#endif + #if defined _LIBC || HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME # define __argp_short_program_name() (program_invocation_short_name) #else diff --git a/lib/argp-parse.c b/lib/argp-parse.c index 9195b87a7709d..a7de72902aae7 100644 --- a/lib/argp-parse.c +++ b/lib/argp-parse.c @@ -15,13 +15,14 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H -#include <config.h> +# include <config.h> #endif #include <alloca.h> +#include <stddef.h> #include <stdlib.h> #include <string.h> #include <unistd.h> @@ -37,11 +38,14 @@ #else # include "gettext.h" #endif -#define N_(msgid) (msgid) +#define N_(msgid) msgid #include "argp.h" #include "argp-namefrob.h" +#define alignof(type) offsetof (struct { char c; type x; }, x) +#define alignto(n, d) ((((n) + (d) - 1) / (d)) * (d)) + /* Getopt return values. */ #define KEY_END (-1) /* The end of the options. */ #define KEY_ARG 1 /* A non-option argument. */ @@ -75,11 +79,11 @@ static volatile int _argp_hang; static const struct argp_option argp_default_options[] = { - {"help", '?', 0, 0, N_("Give this help list"), -1}, - {"usage", OPT_USAGE, 0, 0, N_("Give a short usage message"), 0}, - {"program-name",OPT_PROGNAME,"NAME", OPTION_HIDDEN, N_("Set the program name"), 0}, - {"HANG", OPT_HANG, "SECS", OPTION_ARG_OPTIONAL | OPTION_HIDDEN, - N_("Hang for SECS seconds (default 3600)"), 0}, + {"help", '?', 0, 0, N_("give this help list"), -1}, + {"usage", OPT_USAGE, 0, 0, N_("give a short usage message"), 0}, + {"program-name",OPT_PROGNAME,N_("NAME"), OPTION_HIDDEN, N_("set the program name"), 0}, + {"HANG", OPT_HANG, N_("SECS"), OPTION_ARG_OPTIONAL | OPTION_HIDDEN, + N_("hang for SECS seconds (default 3600)"), 0}, {NULL, 0, 0, 0, NULL, 0} }; @@ -93,7 +97,7 @@ argp_default_parser (int key, char *arg, struct argp_state *state) break; case OPT_USAGE: __argp_state_help (state, state->out_stream, - ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK); + ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK); break; case OPT_PROGNAME: /* Set the program name. */ @@ -105,11 +109,7 @@ argp_default_parser (int key, char *arg, struct argp_state *state) to be that, so we have to be a bit careful here.] */ /* Update what we use for messages. */ - state->name = strrchr (arg, '/'); - if (state->name) - state->name++; - else - state->name = arg; + state->name = __argp_base_name (arg); #if defined _LIBC || HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME program_invocation_short_name = state->name; @@ -140,7 +140,7 @@ static const struct argp argp_default_argp = static const struct argp_option argp_version_options[] = { - {"version", 'V', 0, 0, N_("Print program version"), -1}, + {"version", 'V', 0, 0, N_("print program version"), -1}, {NULL, 0, 0, 0, NULL, 0} }; @@ -462,6 +462,11 @@ parser_init (struct parser *parser, const struct argp *argp, struct group *group; struct parser_sizes szs; struct _getopt_data opt_data = _GETOPT_DATA_INITIALIZER; + char *storage; + size_t glen, gsum; + size_t clen, csum; + size_t llen, lsum; + size_t slen, ssum; szs.short_len = (flags & ARGP_NO_ARGS) ? 0 : 1; szs.long_len = 0; @@ -472,22 +477,33 @@ parser_init (struct parser *parser, const struct argp *argp, calc_sizes (argp, &szs); /* Lengths of the various bits of storage used by PARSER. */ -#define GLEN (szs.num_groups + 1) * sizeof (struct group) -#define CLEN (szs.num_child_inputs * sizeof (void *)) -#define LLEN ((szs.long_len + 1) * sizeof (struct option)) -#define SLEN (szs.short_len + 1) - - parser->storage = malloc (GLEN + CLEN + LLEN + SLEN); + glen = (szs.num_groups + 1) * sizeof (struct group); + clen = szs.num_child_inputs * sizeof (void *); + llen = (szs.long_len + 1) * sizeof (struct option); + slen = szs.short_len + 1; + + /* Sums of previous lengths, properly aligned. There's no need to + align gsum, since struct group is aligned at least as strictly as + void * (since it contains a void * member). And there's no need + to align lsum, since struct option is aligned at least as + strictly as char. */ + gsum = glen; + csum = alignto (gsum + clen, alignof (struct option)); + lsum = csum + llen; + ssum = lsum + slen; + + parser->storage = malloc (ssum); if (! parser->storage) return ENOMEM; + storage = parser->storage; parser->groups = parser->storage; - parser->child_inputs = parser->storage + GLEN; - parser->long_opts = parser->storage + GLEN + CLEN; - parser->short_opts = parser->storage + GLEN + CLEN + LLEN; + parser->child_inputs = (void **) (storage + gsum); + parser->long_opts = (struct option *) (storage + csum); + parser->short_opts = storage + lsum; parser->opt_data = opt_data; - memset (parser->child_inputs, 0, szs.num_child_inputs * sizeof (void *)); + memset (parser->child_inputs, 0, clen); parser_convert (parser, argp, flags); memset (&parser->state, 0, sizeof (struct argp_state)); @@ -542,10 +558,7 @@ parser_init (struct parser *parser, const struct argp *argp, if (parser->state.argv == argv && argv[0]) /* There's an argv[0]; use it for messages. */ - { - char *short_name = strrchr (argv[0], '/'); - parser->state.name = short_name ? short_name + 1 : argv[0]; - } + parser->state.name = __argp_base_name (argv[0]); else parser->state.name = __argp_short_program_name (); @@ -864,6 +877,20 @@ __argp_parse (const struct argp *argp, int argc, char **argv, unsigned flags, to be parsed (which in some cases isn't actually an error). */ int arg_ebadkey = 0; +#ifndef _LIBC + if (!(flags & ARGP_PARSE_ARGV0)) + { +#ifdef HAVE_DECL_PROGRAM_INVOCATION_NAME + if (!program_invocation_name) + program_invocation_name = argv[0]; +#endif +#ifdef HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME + if (!program_invocation_short_name) + program_invocation_short_name = __argp_base_name (argv[0]); +#endif + } +#endif + if (! (flags & ARGP_NO_HELP)) /* Add our own options. */ { diff --git a/lib/argp-pin.c b/lib/argp-pin.c new file mode 100644 index 0000000000000..852c6d6d93885 --- /dev/null +++ b/lib/argp-pin.c @@ -0,0 +1,28 @@ +/* Full and short program names for argp module + Copyright (C) 2005 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#ifndef HAVE_PROGRAM_INVOCATION_SHORT_NAME +char *program_invocation_short_name = 0; +#endif +#ifndef HAVE_PROGRAM_INVOCATION_NAME +char *program_invocation_name = 0; +#endif + diff --git a/lib/argp-pv.c b/lib/argp-pv.c index f93a22eda8fb1..a11298bfabd86 100644 --- a/lib/argp-pv.c +++ b/lib/argp-pv.c @@ -1,5 +1,5 @@ /* Default definition for ARGP_PROGRAM_VERSION. - Copyright (C) 1996, 1997, 1999 Free Software Foundation, Inc. + Copyright (C) 1996, 1997, 1999, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Miles Bader <miles@gnu.ai.mit.edu>. @@ -15,10 +15,10 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* If set by the user program to a non-zero value, then a default option --version is added (unless the ARGP_NO_HELP flag is used), which will - print this this string followed by a newline and exit (unless the + print this string followed by a newline and exit (unless the ARGP_NO_EXIT flag is used). Overridden by ARGP_PROGRAM_VERSION_HOOK. */ const char *argp_program_version; diff --git a/lib/argp-pvh.c b/lib/argp-pvh.c index 5474251bb711d..6bf7c49b814a7 100644 --- a/lib/argp-pvh.c +++ b/lib/argp-pvh.c @@ -15,10 +15,10 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H -#include <config.h> +# include <config.h> #endif #include "argp.h" diff --git a/lib/argp-xinl.c b/lib/argp-xinl.c index 51d3e20c82376..a6afb1f739a3e 100644 --- a/lib/argp-xinl.c +++ b/lib/argp-xinl.c @@ -15,10 +15,10 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H -#include <config.h> +# include <config.h> #endif #if defined _LIBC || defined HAVE_FEATURES_H diff --git a/lib/argp.h b/lib/argp.h index 0c65a4cbd309e..1c4e06f8fe569 100644 --- a/lib/argp.h +++ b/lib/argp.h @@ -1,5 +1,5 @@ /* Hierarchial argument parsing, layered over getopt. - Copyright (C) 1995-1999,2003,2004 Free Software Foundation, Inc. + Copyright (C) 1995-1999,2003-2007 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Miles Bader <miles@gnu.ai.mit.edu>. @@ -15,7 +15,7 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _ARGP_H #define _ARGP_H @@ -23,14 +23,11 @@ #include <stdio.h> #include <ctype.h> #include <getopt.h> +#include <limits.h> #define __need_error_t #include <errno.h> -#ifndef __const -# define __const const -#endif - #ifndef __THROW # define __THROW #endif @@ -52,10 +49,12 @@ #endif /* GCC 2.95 and later have "__restrict"; C99 compilers have - "restrict", and "configure" may have defined "restrict". */ + "restrict", and "configure" may have defined "restrict". + Other compilers use __restrict, __restrict__, and _Restrict, and + 'configure' might #define 'restrict' to those words. */ #ifndef __restrict # if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__)) -# if defined restrict || 199901L <= __STDC_VERSION__ +# if 199901L <= __STDC_VERSION__ # define __restrict restrict # else # define __restrict @@ -81,7 +80,7 @@ struct argp_option { /* The long option name. For more than one name for the same option, you can use following options with the OPTION_ALIAS flag set. */ - __const char *name; + const char *name; /* What key is returned for this option. If > 0 and printable, then it's also accepted as a short option. */ @@ -89,7 +88,7 @@ struct argp_option /* If non-NULL, this is the name of the argument associated with this option, which is required unless the OPTION_ARG_OPTIONAL flag is set. */ - __const char *arg; + const char *arg; /* OPTION_ flags. */ int flags; @@ -97,8 +96,11 @@ struct argp_option /* The doc string for this option. If both NAME and KEY are 0, This string will be printed outdented from the normal option column, making it useful as a group header (it will be the first thing printed in its - group); in this usage, it's conventional to end the string with a `:'. */ - __const char *doc; + group); in this usage, it's conventional to end the string with a `:'. + + Write the initial value as N_("TEXT") if you want xgettext to collect + it into a POT file. */ + const char *doc; /* The group this option is in. In a long help message, options are sorted alphabetically within each group, and the groups presented in the order @@ -226,7 +228,7 @@ struct argp { /* An array of argp_option structures, terminated by an entry with both NAME and KEY having a value of 0. */ - __const struct argp_option *options; + const struct argp_option *options; /* What to do with an option from this structure. KEY is the key associated with the option, and ARG is any associated argument (NULL if @@ -242,12 +244,14 @@ struct argp contains newlines, the strings separated by them are considered alternative usage patterns, and printed on separate lines (lines after the first are prefix by ` or: ' instead of `Usage:'). */ - __const char *args_doc; + const char *args_doc; /* If non-NULL, a string containing extra text to be printed before and after the options in a long help message (separated by a vertical tab - `\v' character). */ - __const char *doc; + `\v' character). + Write the initial value as N_("BEFORE-TEXT") "\v" N_("AFTER-TEXT") if + you want xgettext to collect the two pieces of text into a POT file. */ + const char *doc; /* A vector of argp_children structures, terminated by a member with a 0 argp field, pointing to child argps should be parsed with this one. Any @@ -255,7 +259,7 @@ struct argp CHILDREN list. This field is useful if you use libraries that supply their own argp structure, which you want to use in conjunction with your own. */ - __const struct argp_child *children; + const struct argp_child *children; /* If non-zero, this should be a function to filter the output of help messages. KEY is either a key from an option, in which case TEXT is @@ -267,7 +271,7 @@ struct argp has been done, so if any of the replacement text also needs translation, that should be done by the filter function. INPUT is either the input supplied to argp_parse, or NULL, if argp_help was called directly. */ - char *(*help_filter) (int __key, __const char *__text, void *__input); + char *(*help_filter) (int __key, const char *__text, void *__input); /* If non-zero the strings used in the argp library are translated using the domain described by this string. Otherwise the currently installed @@ -291,7 +295,7 @@ struct argp struct argp_child { /* The child parser. */ - __const struct argp *argp; + const struct argp *argp; /* Flags for this child. */ int flags; @@ -300,7 +304,7 @@ struct argp_child child options. As a side-effect, a non-zero value forces the child options to be grouped together; to achieve this effect without actually printing a header string, use a value of "". */ - __const char *header; + const char *header; /* Where to group the child options relative to the other (`consolidated') options in the parent argp; the values are the same as the GROUP field @@ -316,7 +320,7 @@ struct argp_child struct argp_state { /* The top level ARGP being parsed. */ - __const struct argp *root_argp; + const struct argp *root_argp; /* The argument vector being parsed. May be modified. */ int argc; @@ -410,22 +414,36 @@ struct argp_state routine returned a non-zero value, it is returned; otherwise 0 is returned. This function may also call exit unless the ARGP_NO_HELP flag is set. INPUT is a pointer to a value to be passed in to the parser. */ -extern error_t argp_parse (__const struct argp *__restrict __argp, - int __argc, char **__restrict __argv, +extern error_t argp_parse (const struct argp *__restrict __argp, + int /*argc*/, char **__restrict /*argv*/, unsigned __flags, int *__restrict __arg_index, void *__restrict __input); -extern error_t __argp_parse (__const struct argp *__restrict __argp, - int __argc, char **__restrict __argv, +extern error_t __argp_parse (const struct argp *__restrict __argp, + int /*argc*/, char **__restrict /*argv*/, unsigned __flags, int *__restrict __arg_index, void *__restrict __input); /* Global variables. */ +/* GNULIB makes sure both program_invocation_name and + program_invocation_short_name are available */ +#ifdef GNULIB_PROGRAM_INVOCATION_NAME +extern char *program_invocation_name; +# undef HAVE_DECL_PROGRAM_INVOCATION_NAME +# define HAVE_DECL_PROGRAM_INVOCATION_NAME 1 +#endif + +#ifdef GNULIB_PROGRAM_INVOCATION_SHORT_NAME +extern char *program_invocation_short_name; +# undef HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME +# define HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME 1 +#endif + /* If defined or set by the user program to a non-zero value, then a default option --version is added (unless the ARGP_NO_HELP flag is used), which will print this string followed by a newline and exit (unless the ARGP_NO_EXIT flag is used). Overridden by ARGP_PROGRAM_VERSION_HOOK. */ -extern __const char *argp_program_version; +extern const char *argp_program_version; /* If defined or set by the user program to a non-zero value, then a default option --version is added (unless the ARGP_NO_HELP flag is used), which @@ -441,7 +459,7 @@ extern void (*argp_program_version_hook) (FILE *__restrict __stream, argp_help if the ARGP_HELP_BUG_ADDR flag is set (as it is by various standard help messages), embedded in a sentence that says something like `Report bugs to ADDR.'. */ -extern __const char *argp_program_bug_address; +extern const char *argp_program_bug_address; /* The exit status that argp will use when exiting due to a parsing error. If not defined or set by the user program, this defaults to EX_USAGE from @@ -479,10 +497,10 @@ extern error_t argp_err_exit_status; /* Output a usage message for ARGP to STREAM. FLAGS are from the set ARGP_HELP_*. */ -extern void argp_help (__const struct argp *__restrict __argp, +extern void argp_help (const struct argp *__restrict __argp, FILE *__restrict __stream, unsigned __flags, char *__restrict __name); -extern void __argp_help (__const struct argp *__restrict __argp, +extern void __argp_help (const struct argp *__restrict __argp, FILE *__restrict __stream, unsigned __flags, char *__name); @@ -496,25 +514,25 @@ extern void __argp_help (__const struct argp *__restrict __argp, /* Output, if appropriate, a usage message for STATE to STREAM. FLAGS are from the set ARGP_HELP_*. */ -extern void argp_state_help (__const struct argp_state *__restrict __state, +extern void argp_state_help (const struct argp_state *__restrict __state, FILE *__restrict __stream, unsigned int __flags); -extern void __argp_state_help (__const struct argp_state *__restrict __state, +extern void __argp_state_help (const struct argp_state *__restrict __state, FILE *__restrict __stream, unsigned int __flags); /* Possibly output the standard usage message for ARGP to stderr and exit. */ -extern void argp_usage (__const struct argp_state *__state); -extern void __argp_usage (__const struct argp_state *__state); +extern void argp_usage (const struct argp_state *__state); +extern void __argp_usage (const struct argp_state *__state); /* If appropriate, print the printf string FMT and following args, preceded by the program name and `:', to stderr, and followed by a `Try ... --help' message, then exit (1). */ -extern void argp_error (__const struct argp_state *__restrict __state, - __const char *__restrict __fmt, ...) +extern void argp_error (const struct argp_state *__restrict __state, + const char *__restrict __fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); -extern void __argp_error (__const struct argp_state *__restrict __state, - __const char *__restrict __fmt, ...) +extern void __argp_error (const struct argp_state *__restrict __state, + const char *__restrict __fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); /* Similar to the standard gnu error-reporting function error(), but will @@ -525,31 +543,31 @@ extern void __argp_error (__const struct argp_state *__restrict __state, difference between this function and argp_error is that the latter is for *parsing errors*, and the former is for other problems that occur during parsing but don't reflect a (syntactic) problem with the input. */ -extern void argp_failure (__const struct argp_state *__restrict __state, +extern void argp_failure (const struct argp_state *__restrict __state, int __status, int __errnum, - __const char *__restrict __fmt, ...) + const char *__restrict __fmt, ...) __attribute__ ((__format__ (__printf__, 4, 5))); -extern void __argp_failure (__const struct argp_state *__restrict __state, +extern void __argp_failure (const struct argp_state *__restrict __state, int __status, int __errnum, - __const char *__restrict __fmt, ...) + const char *__restrict __fmt, ...) __attribute__ ((__format__ (__printf__, 4, 5))); /* Returns true if the option OPT is a valid short option. */ -extern int _option_is_short (__const struct argp_option *__opt) __THROW; -extern int __option_is_short (__const struct argp_option *__opt) __THROW; +extern int _option_is_short (const struct argp_option *__opt) __THROW; +extern int __option_is_short (const struct argp_option *__opt) __THROW; /* Returns true if the option OPT is in fact the last (unused) entry in an options array. */ -extern int _option_is_end (__const struct argp_option *__opt) __THROW; -extern int __option_is_end (__const struct argp_option *__opt) __THROW; +extern int _option_is_end (const struct argp_option *__opt) __THROW; +extern int __option_is_end (const struct argp_option *__opt) __THROW; /* Return the input field for ARGP in the parser corresponding to STATE; used by the help routines. */ -extern void *_argp_input (__const struct argp *__restrict __argp, - __const struct argp_state *__restrict __state) +extern void *_argp_input (const struct argp *__restrict __argp, + const struct argp_state *__restrict __state) __THROW; -extern void *__argp_input (__const struct argp *__restrict __argp, - __const struct argp_state *__restrict __state) +extern void *__argp_input (const struct argp *__restrict __argp, + const struct argp_state *__restrict __state) __THROW; #ifdef __USE_EXTERN_INLINES @@ -566,25 +584,25 @@ extern void *__argp_input (__const struct argp *__restrict __argp, # endif ARGP_EI void -__NTH (__argp_usage (__const struct argp_state *__state)) +__argp_usage (const struct argp_state *__state) { __argp_state_help (__state, stderr, ARGP_HELP_STD_USAGE); } ARGP_EI int -__NTH (__option_is_short (__const struct argp_option *__opt)) +__NTH (__option_is_short (const struct argp_option *__opt)) { if (__opt->flags & OPTION_DOC) return 0; else { int __key = __opt->key; - return __key > 0 && isprint (__key); + return __key > 0 && __key <= UCHAR_MAX && isprint (__key); } } ARGP_EI int -__NTH (__option_is_end (__const struct argp_option *__opt)) +__NTH (__option_is_end (const struct argp_option *__opt)) { return !__opt->key && !__opt->name && !__opt->doc && !__opt->group; } diff --git a/lib/basename.c b/lib/basename.c index adb9f02ff0084..fbe17ff910c8e 100644 --- a/lib/basename.c +++ b/lib/basename.c @@ -1,6 +1,6 @@ -/* basename.c -- return the last element in a path +/* basename.c -- return the last element in a file name - Copyright (C) 1990, 1998, 1999, 2000, 2001, 2003, 2004 Free + Copyright (C) 1990, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify @@ -15,65 +15,115 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#if HAVE_CONFIG_H -# include <config.h> -#endif +#include <config.h> #include "dirname.h" -#include <string.h> -/* In general, we can't use the builtin `basename' function if available, - since it has different meanings in different environments. - In some environments the builtin `basename' modifies its argument. +#include <string.h> +#include "xalloc.h" +#include "xstrndup.h" - Return the address of the last file name component of NAME. If - NAME has no file name components because it is all slashes, return - NAME if it is empty, the address of its last slash otherwise. */ +/* Return the address of the last file name component of NAME. If + NAME has no relative file name components because it is a file + system root, return the empty string. */ char * -base_name (char const *name) +last_component (char const *name) { char const *base = name + FILE_SYSTEM_PREFIX_LEN (name); char const *p; + bool saw_slash = false; + + while (ISSLASH (*base)) + base++; for (p = base; *p; p++) { if (ISSLASH (*p)) + saw_slash = true; + else if (saw_slash) { - /* Treat multiple adjacent slashes like a single slash. */ - do p++; - while (ISSLASH (*p)); - - /* If the file name ends in slash, use the trailing slash as - the basename if no non-slashes have been found. */ - if (! *p) - { - if (ISSLASH (*base)) - base = p - 1; - break; - } - - /* *P is a non-slash preceded by a slash. */ base = p; + saw_slash = false; } } return (char *) base; } -/* Return the length of of the basename NAME. Typically NAME is the - value returned by base_name. Act like strlen (NAME), except omit - redundant trailing slashes. */ + +/* In general, we can't use the builtin `basename' function if available, + since it has different meanings in different environments. + In some environments the builtin `basename' modifies its argument. + + Return the last file name component of NAME, allocated with + xmalloc. On systems with drive letters, a leading "./" + distinguishes relative names that would otherwise look like a drive + letter. Unlike POSIX basename(), NAME cannot be NULL, + base_name("") returns "", and the first trailing slash is not + stripped. + + If lstat (NAME) would succeed, then { chdir (dir_name (NAME)); + lstat (base_name (NAME)); } will access the same file. Likewise, + if the sequence { chdir (dir_name (NAME)); + rename (base_name (NAME), "foo"); } succeeds, you have renamed NAME + to "foo" in the same directory NAME was in. */ + +char * +base_name (char const *name) +{ + char const *base = last_component (name); + size_t length; + + /* If there is no last component, then name is a file system root or the + empty string. */ + if (! *base) + return xstrndup (name, base_len (name)); + + /* Collapse a sequence of trailing slashes into one. */ + length = base_len (base); + if (ISSLASH (base[length])) + length++; + + /* On systems with drive letters, `a/b:c' must return `./b:c' rather + than `b:c' to avoid confusion with a drive letter. On systems + with pure POSIX semantics, this is not an issue. */ + if (FILE_SYSTEM_PREFIX_LEN (base)) + { + char *p = xmalloc (length + 3); + p[0] = '.'; + p[1] = '/'; + memcpy (p + 2, base, length); + p[length + 2] = '\0'; + return p; + } + + /* Finally, copy the basename. */ + return xstrndup (base, length); +} + +/* Return the length of the basename NAME. Typically NAME is the + value returned by base_name or last_component. Act like strlen + (NAME), except omit all trailing slashes. */ size_t base_len (char const *name) { size_t len; + size_t prefix_len = FILE_SYSTEM_PREFIX_LEN (name); for (len = strlen (name); 1 < len && ISSLASH (name[len - 1]); len--) continue; + if (DOUBLE_SLASH_IS_DISTINCT_ROOT && len == 1 + && ISSLASH (name[0]) && ISSLASH (name[1]) && ! name[2]) + return 2; + + if (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE && prefix_len + && len == prefix_len && ISSLASH (name[prefix_len])) + return prefix_len + 1; + return len; } diff --git a/lib/dirname.c b/lib/dirname.c index 7671a0d62e43c..16552c64d2a37 100644 --- a/lib/dirname.c +++ b/lib/dirname.c @@ -1,6 +1,6 @@ -/* dirname.c -- return all but the last element in a path +/* dirname.c -- return all but the last element in a file name - Copyright (C) 1990, 1998, 2000, 2001, 2003, 2004 Free Software + Copyright (C) 1990, 1998, 2000, 2001, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify @@ -15,107 +15,71 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#if HAVE_CONFIG_H -# include <config.h> -#endif +#include <config.h> #include "dirname.h" #include <string.h> #include "xalloc.h" -/* Return the length of `dirname (PATH)', or zero if PATH is - in the working directory. Works properly even if - there are trailing slashes (by effectively ignoring them). */ +/* Return the length of the prefix of FILE that will be used by + dir_name. If FILE is in the working directory, this returns zero + even though `dir_name (FILE)' will return ".". Works properly even + if there are trailing slashes (by effectively ignoring them). */ + size_t -dir_len (char const *path) +dir_len (char const *file) { - size_t prefix_length = FILE_SYSTEM_PREFIX_LEN (path); + size_t prefix_length = FILE_SYSTEM_PREFIX_LEN (file); size_t length; - /* Strip the basename and any redundant slashes before it. */ - for (length = base_name (path) - path; prefix_length < length; length--) - if (! ISSLASH (path[length - 1])) - return length; - - /* But don't strip the only slash from "/". */ - return prefix_length + ISSLASH (path[prefix_length]); -} - -/* Return the leading directories part of PATH, - allocated with xmalloc. - Works properly even if there are trailing slashes - (by effectively ignoring them). */ + /* Advance prefix_length beyond important leading slashes. */ + prefix_length += (prefix_length != 0 + ? (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE + && ISSLASH (file[prefix_length])) + : (ISSLASH (file[0]) + ? ((DOUBLE_SLASH_IS_DISTINCT_ROOT + && ISSLASH (file[1]) && ! ISSLASH (file[2]) + ? 2 : 1)) + : 0)); -char * -dir_name (char const *path) -{ - size_t length = dir_len (path); - bool append_dot = (length == FILE_SYSTEM_PREFIX_LEN (path)); - char *newpath = xmalloc (length + append_dot + 1); - memcpy (newpath, path, length); - if (append_dot) - newpath[length++] = '.'; - newpath[length] = 0; - return newpath; + /* Strip the basename and any redundant slashes before it. */ + for (length = last_component (file) - file; + prefix_length < length; length--) + if (! ISSLASH (file[length - 1])) + break; + return length; } -#ifdef TEST_DIRNAME -/* - -Run the test like this (expect no output): - gcc -DHAVE_CONFIG_H -DTEST_DIRNAME -I.. -O -Wall \ - basename.c dirname.c xmalloc.c error.c - sed -n '/^BEGIN-DATA$/,/^END-DATA$/p' dirname.c|grep -v DATA|./a.out - -If it's been built on a DOS or Windows platforms, run another test like -this (again, expect no output): - sed -n '/^BEGIN-DOS-DATA$/,/^END-DOS-DATA$/p' dirname.c|grep -v DATA|./a.out - -BEGIN-DATA -foo//// . -bar/foo//// bar -foo/ . -/ / -. . -a . -END-DATA -BEGIN-DOS-DATA -c:///// c:/ -c:/ c:/ -c:/. c:/ -c:foo c:. -c:foo/bar c:foo -END-DOS-DATA +/* In general, we can't use the builtin `dirname' function if available, + since it has different meanings in different environments. + In some environments the builtin `dirname' modifies its argument. -*/ + Return the leading directories part of FILE, allocated with xmalloc. + Works properly even if there are trailing slashes (by effectively + ignoring them). Unlike POSIX dirname(), FILE cannot be NULL. -# define MAX_BUFF_LEN 1024 -# include <stdio.h> + If lstat (FILE) would succeed, then { chdir (dir_name (FILE)); + lstat (base_name (FILE)); } will access the same file. Likewise, + if the sequence { chdir (dir_name (FILE)); + rename (base_name (FILE), "foo"); } succeeds, you have renamed FILE + to "foo" in the same directory FILE was in. */ -char *program_name; - -int -main (int argc, char *argv[]) +char * +dir_name (char const *file) { - char buff[MAX_BUFF_LEN + 1]; - - program_name = argv[0]; - - buff[MAX_BUFF_LEN] = 0; - while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0]) - { - char path[MAX_BUFF_LEN]; - char expected_result[MAX_BUFF_LEN]; - char const *result; - sscanf (buff, "%s %s", path, expected_result); - result = dir_name (path); - if (strcmp (result, expected_result)) - printf ("%s: got %s, expected %s\n", path, result, expected_result); - } - return 0; + size_t length = dir_len (file); + bool append_dot = (length == 0 + || (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE + && length == FILE_SYSTEM_PREFIX_LEN (file) + && file[2] != '\0' && ! ISSLASH (file[2]))); + char *dir = xmalloc (length + append_dot + 1); + memcpy (dir, file, length); + if (append_dot) + dir[length++] = '.'; + dir[length] = '\0'; + return dir; } -#endif diff --git a/lib/dirname.h b/lib/dirname.h index bc2400a7d0a8a..91e7ed33666f8 100644 --- a/lib/dirname.h +++ b/lib/dirname.h @@ -1,6 +1,6 @@ /* Take file names apart into directory and base names. - Copyright (C) 1998, 2001, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 1998, 2001, 2003-2006 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 @@ -14,7 +14,7 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef DIRNAME_H_ # define DIRNAME_H_ 1 @@ -31,17 +31,40 @@ # endif # ifndef FILE_SYSTEM_PREFIX_LEN -# define FILE_SYSTEM_PREFIX_LEN(Filename) 0 +# if FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX + /* This internal macro assumes ASCII, but all hosts that support drive + letters use ASCII. */ +# define _IS_DRIVE_LETTER(c) (((unsigned int) (c) | ('a' - 'A')) - 'a' \ + <= 'z' - 'a') +# define FILE_SYSTEM_PREFIX_LEN(Filename) \ + (_IS_DRIVE_LETTER ((Filename)[0]) && (Filename)[1] == ':' ? 2 : 0) +# else +# define FILE_SYSTEM_PREFIX_LEN(Filename) 0 +# endif # endif -# define IS_ABSOLUTE_FILE_NAME(F) ISSLASH ((F)[FILE_SYSTEM_PREFIX_LEN (F)]) +# ifndef FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE +# define FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE 0 +# endif + +# ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT +# define DOUBLE_SLASH_IS_DISTINCT_ROOT 0 +# endif + +# if FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE +# define IS_ABSOLUTE_FILE_NAME(F) ISSLASH ((F)[FILE_SYSTEM_PREFIX_LEN (F)]) +# else +# define IS_ABSOLUTE_FILE_NAME(F) \ + (ISSLASH ((F)[0]) || 0 < FILE_SYSTEM_PREFIX_LEN (F)) +# endif # define IS_RELATIVE_FILE_NAME(F) (! IS_ABSOLUTE_FILE_NAME (F)) -char *base_name (char const *path); -char *dir_name (char const *path); -size_t base_len (char const *path); -size_t dir_len (char const *path); +char *base_name (char const *file); +char *dir_name (char const *file); +size_t base_len (char const *file); +size_t dir_len (char const *file); +char *last_component (char const *file); -bool strip_trailing_slashes (char *path); +bool strip_trailing_slashes (char *file); #endif /* not DIRNAME_H_ */ diff --git a/lib/error.c b/lib/error.c index 9bb3e558cb8bc..cf86343320203 100644 --- a/lib/error.c +++ b/lib/error.c @@ -1,5 +1,5 @@ /* Error handler for noninteractive utilities - Copyright (C) 1990-1998, 2000-2002, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 1990-1998, 2000-2005, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. This program is free software; you can redistribute it and/or modify @@ -14,11 +14,11 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */ -#ifdef HAVE_CONFIG_H +#if !_LIBC # include <config.h> #endif @@ -29,13 +29,14 @@ #include <stdlib.h> #include <string.h> -#ifdef _LIBC -# include <libintl.h> -#else +#if !_LIBC && ENABLE_NLS # include "gettext.h" #endif #ifdef _LIBC +# include <libintl.h> +# include <stdbool.h> +# include <stdint.h> # include <wchar.h> # define mbsrtowcs __mbsrtowcs #endif @@ -61,6 +62,7 @@ unsigned int error_message_count; # define program_name program_invocation_name # include <errno.h> +# include <limits.h> # include <libio/libioP.h> /* In GNU libc we want do not want to use the common name `error' directly. @@ -90,23 +92,19 @@ extern void __error_at_line (int status, int errnum, const char *file_name, char *strerror_r (); # endif -# ifndef SIZE_MAX -# define SIZE_MAX ((size_t) -1) -# endif - /* The calling program should define program_name and set it to the name of the executing program. */ extern char *program_name; # if HAVE_STRERROR_R || defined strerror_r # define __strerror_r strerror_r -# endif +# endif /* HAVE_STRERROR_R || defined strerror_r */ #endif /* not _LIBC */ static void print_errno_message (int errnum) { - char const *s = NULL; + char const *s; #if defined HAVE_STRERROR_R || _LIBC char errbuf[1024]; @@ -115,23 +113,23 @@ print_errno_message (int errnum) # else if (__strerror_r (errnum, errbuf, sizeof errbuf) == 0) s = errbuf; + else + s = 0; # endif +#else + s = strerror (errnum); #endif #if !_LIBC - if (! s && ! (s = strerror (errnum))) + if (! s) s = _("Unknown system error"); #endif #if _LIBC - if (_IO_fwide (stderr, 0) > 0) - { - __fwprintf (stderr, L": %s", s); - return; - } -#endif - + __fxprintf (NULL, ": %s", s); +#else fprintf (stderr, ": %s", s); +#endif } static void @@ -142,26 +140,65 @@ error_tail (int status, int errnum, const char *message, va_list args) { # define ALLOCA_LIMIT 2000 size_t len = strlen (message) + 1; - const wchar_t *wmessage = L"out of memory"; - wchar_t *wbuf = (len < ALLOCA_LIMIT - ? alloca (len * sizeof *wbuf) - : len <= SIZE_MAX / sizeof *wbuf - ? malloc (len * sizeof *wbuf) - : NULL); - - if (wbuf) + wchar_t *wmessage = NULL; + mbstate_t st; + size_t res; + const char *tmp; + bool use_malloc = false; + + while (1) { - size_t res; - mbstate_t st; - const char *tmp = message; + if (__libc_use_alloca (len * sizeof (wchar_t))) + wmessage = (wchar_t *) alloca (len * sizeof (wchar_t)); + else + { + if (!use_malloc) + wmessage = NULL; + + wchar_t *p = (wchar_t *) realloc (wmessage, + len * sizeof (wchar_t)); + if (p == NULL) + { + free (wmessage); + fputws_unlocked (L"out of memory\n", stderr); + return; + } + wmessage = p; + use_malloc = true; + } + memset (&st, '\0', sizeof (st)); - res = mbsrtowcs (wbuf, &tmp, len, &st); - wmessage = res == (size_t) -1 ? L"???" : wbuf; + tmp = message; + + res = mbsrtowcs (wmessage, &tmp, len, &st); + if (res != len) + break; + + if (__builtin_expect (len >= SIZE_MAX / 2, 0)) + { + /* This really should not happen if everything is fine. */ + res = (size_t) -1; + break; + } + + len *= 2; + } + + if (res == (size_t) -1) + { + /* The string cannot be converted. */ + if (use_malloc) + { + free (wmessage); + use_malloc = false; + } + wmessage = (wchar_t *) L"???"; } __vfwprintf (stderr, wmessage, args); - if (! (len < ALLOCA_LIMIT)) - free (wbuf); + + if (use_malloc) + free (wmessage); } else #endif @@ -172,11 +209,10 @@ error_tail (int status, int errnum, const char *message, va_list args) if (errnum) print_errno_message (errnum); #if _LIBC - if (_IO_fwide (stderr, 0) > 0) - putwc (L'\n', stderr); - else + __fxprintf (NULL, "\n"); +#else + putc ('\n', stderr); #endif - putc ('\n', stderr); fflush (stderr); if (status) exit (status); @@ -209,11 +245,10 @@ error (int status, int errnum, const char *message, ...) else { #if _LIBC - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s: ", program_name); - else + __fxprintf (NULL, "%s: ", program_name); +#else + fprintf (stderr, "%s: ", program_name); #endif - fprintf (stderr, "%s: ", program_name); } va_start (args, message); @@ -269,22 +304,19 @@ error_at_line (int status, int errnum, const char *file_name, else { #if _LIBC - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s: ", program_name); - else + __fxprintf (NULL, "%s:", program_name); +#else + fprintf (stderr, "%s:", program_name); #endif - fprintf (stderr, "%s:", program_name); } - if (file_name != NULL) - { #if _LIBC - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s:%d: ", file_name, line_number); - else + __fxprintf (NULL, file_name != NULL ? "%s:%d: " : " ", + file_name, line_number); +#else + fprintf (stderr, file_name != NULL ? "%s:%d: " : " ", + file_name, line_number); #endif - fprintf (stderr, "%s:%d: ", file_name, line_number); - } va_start (args, message); error_tail (status, errnum, message, args); diff --git a/lib/error.h b/lib/error.h index 8ed63595f24f6..5a5f2476583db 100644 --- a/lib/error.h +++ b/lib/error.h @@ -1,5 +1,5 @@ /* Declaration for error-reporting function - Copyright (C) 1995, 1996, 1997, 2003 Free Software Foundation, Inc. + Copyright (C) 1995, 1996, 1997, 2003, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. This program is free software; you can redistribute it and/or modify @@ -14,14 +14,14 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _ERROR_H #define _ERROR_H 1 #ifndef __attribute__ /* This feature is available in gcc versions 2.5 and later. */ -# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__ # define __attribute__(Spec) /* empty */ # endif /* The __-protected variants of `format' and `printf' attributes diff --git a/lib/exitfail.c b/lib/exitfail.c index 2ae5f69555f46..373d325c5ad73 100644 --- a/lib/exitfail.c +++ b/lib/exitfail.c @@ -1,6 +1,6 @@ /* Failure exit status - Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2005, 2006, 2007 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 @@ -15,13 +15,12 @@ You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#if HAVE_CONFIG_H -# include <config.h> -#endif +#include <config.h> #include "exitfail.h" -#include "exit.h" + +#include <stdlib.h> int volatile exit_failure = EXIT_FAILURE; diff --git a/lib/exitfail.h b/lib/exitfail.h index cf5ab719586e2..e46cf9c166567 100644 --- a/lib/exitfail.h +++ b/lib/exitfail.h @@ -15,6 +15,6 @@ You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ extern int volatile exit_failure; diff --git a/lib/fatal.c b/lib/fatal.c new file mode 100644 index 0000000000000..bcce42c090aa8 --- /dev/null +++ b/lib/fatal.c @@ -0,0 +1,27 @@ +/* This file is part of GNU cpio. + Copyright (C) 2005 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301 USA. */ + +#include <system.h> +#include <paxlib.h> + +void +fatal_exit () +{ + exit (PAXEXIT_FAILURE); +} + diff --git a/lib/full-write.c b/lib/full-write.c index d119977e79d17..cc168720eae94 100644 --- a/lib/full-write.c +++ b/lib/full-write.c @@ -1,7 +1,7 @@ /* An interface to read and write that retries (if necessary) until complete. Copyright (C) 1993, 1994, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004 Free Software Foundation, Inc. + 2004, 2005, 2006 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 @@ -15,11 +15,9 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#if HAVE_CONFIG_H -# include <config.h> -#endif +#include <config.h> /* Specification. */ #ifdef FULL_READ @@ -62,7 +60,7 @@ size_t full_rw (int fd, const void *buf, size_t count) { size_t total = 0; - const char *ptr = buf; + const char *ptr = (const char *) buf; while (count > 0) { diff --git a/lib/full-write.h b/lib/full-write.h index 2637903ecda49..d20d2fe4abdf7 100644 --- a/lib/full-write.h +++ b/lib/full-write.h @@ -14,7 +14,7 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <stddef.h> diff --git a/lib/getopt.c b/lib/getopt.c index ef790b79e07af..3580ad825c647 100644 --- a/lib/getopt.c +++ b/lib/getopt.c @@ -2,7 +2,7 @@ NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to drepper@gnu.org before changing it! - Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001,2002,2003,2004 + Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001,2002,2003,2004,2006 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -18,32 +18,20 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. - Ditto for AIX 3.2 and <stdlib.h>. */ -#ifndef _NO_PROTO -# define _NO_PROTO -#endif - -#ifdef HAVE_CONFIG_H +#ifndef _LIBC # include <config.h> #endif -#include <stdio.h> - -/* This needs to come after some library #include - to get __GNU_LIBRARY__ defined. */ -#ifdef __GNU_LIBRARY__ -/* Don't include stdlib.h for non-GNU C libraries because some of them - contain conflicting prototypes for getopt. */ -# include <stdlib.h> -# include <unistd.h> -#endif /* GNU C library. */ +#include "getopt.h" +#include <stdio.h> +#include <stdlib.h> #include <string.h> +#include <unistd.h> -#ifdef VMS +#ifdef __VMS # include <unixlib.h> #endif @@ -76,7 +64,6 @@ GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ -#include "getopt.h" #include "getopt_int.h" /* For communication from `getopt' to the caller. @@ -118,16 +105,9 @@ int optopt = '?'; static struct _getopt_data getopt_data; -#ifndef __GNU_LIBRARY__ - -/* Avoid depending on library functions or files - whose names are inconsistent. */ - -#ifndef getenv +#if defined HAVE_DECL_GETENV && !HAVE_DECL_GETENV extern char *getenv (); #endif - -#endif /* not __GNU_LIBRARY__ */ #ifdef _LIBC /* Stored original parameters. @@ -556,10 +536,7 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); @@ -634,10 +611,7 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); @@ -674,10 +648,7 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); @@ -751,10 +722,7 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); @@ -817,10 +785,7 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); @@ -868,10 +833,7 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); @@ -940,10 +902,7 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); @@ -985,10 +944,7 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); @@ -1027,10 +983,7 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); @@ -1101,10 +1054,7 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); diff --git a/lib/getopt1.c b/lib/getopt1.c index a7472371fa20a..cc0746ea43cec 100644 --- a/lib/getopt1.c +++ b/lib/getopt1.c @@ -1,5 +1,5 @@ /* getopt_long and getopt_long_only entry points for GNU getopt. - Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98,2004 + Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98,2004,2006 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -15,15 +15,12 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - #ifdef _LIBC # include <getopt.h> #else +# include <config.h> # include "getopt.h" #endif #include "getopt_int.h" diff --git a/lib/getopt_.h b/lib/getopt_.h index 83ac8b12844b8..615ef9a3b6fe1 100644 --- a/lib/getopt_.h +++ b/lib/getopt_.h @@ -1,5 +1,5 @@ /* Declarations for getopt. - Copyright (C) 1989-1994,1996-1999,2001,2003,2004 + Copyright (C) 1989-1994,1996-1999,2001,2003,2004,2005,2006,2007 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -15,7 +15,7 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _GETOPT_H @@ -34,9 +34,7 @@ #if defined __GETOPT_PREFIX && !defined __need_getopt # include <stdlib.h> # include <stdio.h> -# if HAVE_UNISTD_H -# include <unistd.h> -# endif +# include <unistd.h> # undef __need_getopt # undef getopt # undef getopt_long @@ -67,14 +65,14 @@ but it caused redefinition warnings if both unistd.h and getopt.h were included, since unistd.h includes getopt.h having previously defined __need_getopt. - + The only place where __getopt_argv_const is used is in definitions of getopt_long and getopt_long_only below, but these are visible only if __need_getopt is not defined, so it is quite safe to rewrite the conditional as follows: */ #if !defined __need_getopt -# if defined __GETOPT_PREFIX +# if defined __GETOPT_PREFIX # define __getopt_argv_const /* empty */ # else # define __getopt_argv_const const @@ -103,7 +101,7 @@ # endif #endif -#ifdef __cplusplus +#ifdef __cplusplus extern "C" { #endif @@ -198,9 +196,10 @@ struct option scanning, explicitly telling `getopt' that there are no more options. - If OPTS begins with `--', then non-option arguments are treated as - arguments to the option '\0'. This behavior is specific to the GNU - `getopt'. */ + If OPTS begins with `-', then non-option arguments are treated as + arguments to the option '\1'. This behavior is specific to the GNU + `getopt'. If OPTS begins with `+', or POSIXLY_CORRECT is set in + the environment, then do not permute arguments. */ extern int getopt (int ___argc, char *const *___argv, const char *__shortopts) __THROW; @@ -217,7 +216,7 @@ extern int getopt_long_only (int ___argc, char *__getopt_argv_const *___argv, #endif -#ifdef __cplusplus +#ifdef __cplusplus } #endif diff --git a/lib/getopt_int.h b/lib/getopt_int.h index e5bc3f2fd5173..401579fd28982 100644 --- a/lib/getopt_int.h +++ b/lib/getopt_int.h @@ -15,7 +15,7 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _GETOPT_INT_H #define _GETOPT_INT_H 1 diff --git a/lib/gettext.h b/lib/gettext.h index 835732e01fe55..9d76ec9afccff 100644 --- a/lib/gettext.h +++ b/lib/gettext.h @@ -1,5 +1,5 @@ /* Convenience header for conditional use of GNU <libintl.h>. - Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2002, 2004-2006 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 @@ -13,7 +13,7 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _LIBGETTEXT_H #define _LIBGETTEXT_H 1 @@ -24,6 +24,18 @@ /* Get declarations of GNU message catalog functions. */ # include <libintl.h> +/* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by + the gettext() and ngettext() macros. This is an alternative to calling + textdomain(), and is useful for libraries. */ +# ifdef DEFAULT_TEXT_DOMAIN +# undef gettext +# define gettext(Msgid) \ + dgettext (DEFAULT_TEXT_DOMAIN, Msgid) +# undef ngettext +# define ngettext(Msgid1, Msgid2, N) \ + dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N) +# endif + #else /* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which @@ -36,23 +48,38 @@ # include <locale.h> #endif +/* Many header files from the libstdc++ coming with g++ 3.3 or newer include + <libintl.h>, which chokes if dcgettext is defined as a macro. So include + it now, to make later inclusions of <libintl.h> a NOP. */ +#if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3) +# include <cstdlib> +# if (__GLIBC__ >= 2) || _GLIBCXX_HAVE_LIBINTL_H +# include <libintl.h> +# endif +#endif + /* Disabled NLS. The casts to 'const char *' serve the purpose of producing warnings for invalid uses of the value returned from these functions. On pre-ANSI systems without 'const', the config.h file is supposed to contain "#define const". */ # define gettext(Msgid) ((const char *) (Msgid)) -# define dgettext(Domainname, Msgid) ((const char *) (Msgid)) -# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid)) +# define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid)) +# define dcgettext(Domainname, Msgid, Category) \ + ((void) (Category), dgettext (Domainname, Msgid)) # define ngettext(Msgid1, Msgid2, N) \ - ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) + ((N) == 1 \ + ? ((void) (Msgid2), (const char *) (Msgid1)) \ + : ((void) (Msgid1), (const char *) (Msgid2))) # define dngettext(Domainname, Msgid1, Msgid2, N) \ - ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) + ((void) (Domainname), ngettext (Msgid1, Msgid2, N)) # define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ - ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) + ((void) (Category), dngettext(Domainname, Msgid1, Msgid2, N)) # define textdomain(Domainname) ((const char *) (Domainname)) -# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) -# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset)) +# define bindtextdomain(Domainname, Dirname) \ + ((void) (Domainname), (const char *) (Dirname)) +# define bind_textdomain_codeset(Domainname, Codeset) \ + ((void) (Domainname), (const char *) (Codeset)) #endif @@ -65,4 +92,179 @@ initializer for static 'char[]' or 'const char[]' variables. */ #define gettext_noop(String) String +/* The separator between msgctxt and msgid in a .mo file. */ +#define GETTEXT_CONTEXT_GLUE "\004" + +/* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a + MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be + short and rarely need to change. + The letter 'p' stands for 'particular' or 'special'. */ +#ifdef DEFAULT_TEXT_DOMAIN +# define pgettext(Msgctxt, Msgid) \ + pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) +#else +# define pgettext(Msgctxt, Msgid) \ + pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) +#endif +#define dpgettext(Domainname, Msgctxt, Msgid) \ + pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) +#define dcpgettext(Domainname, Msgctxt, Msgid, Category) \ + pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category) +#ifdef DEFAULT_TEXT_DOMAIN +# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ + npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) +#else +# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ + npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) +#endif +#define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ + npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) +#define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \ + npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, Category) + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static const char * +pgettext_aux (const char *domain, + const char *msg_ctxt_id, const char *msgid, + int category) +{ + const char *translation = dcgettext (domain, msg_ctxt_id, category); + if (translation == msg_ctxt_id) + return msgid; + else + return translation; +} + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static const char * +npgettext_aux (const char *domain, + const char *msg_ctxt_id, const char *msgid, + const char *msgid_plural, unsigned long int n, + int category) +{ + const char *translation = + dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); + if (translation == msg_ctxt_id || translation == msgid_plural) + return (n == 1 ? msgid : msgid_plural); + else + return translation; +} + +/* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID + can be arbitrary expressions. But for string literals these macros are + less efficient than those above. */ + +#include <string.h> + +#define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS \ + (((__GNUC__ >= 3 || __GNUG__ >= 2) && !__STRICT_ANSI__) \ + /* || __STDC_VERSION__ >= 199901L */ ) + +#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS +#include <stdlib.h> +#endif + +#define pgettext_expr(Msgctxt, Msgid) \ + dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES) +#define dpgettext_expr(Domainname, Msgctxt, Msgid) \ + dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES) + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static const char * +dcpgettext_expr (const char *domain, + const char *msgctxt, const char *msgid, + int category) +{ + size_t msgctxt_len = strlen (msgctxt) + 1; + size_t msgid_len = strlen (msgid) + 1; + const char *translation; +#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS + char msg_ctxt_id[msgctxt_len + msgid_len]; +#else + char buf[1024]; + char *msg_ctxt_id = + (msgctxt_len + msgid_len <= sizeof (buf) + ? buf + : (char *) malloc (msgctxt_len + msgid_len)); + if (msg_ctxt_id != NULL) +#endif + { + memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); + msg_ctxt_id[msgctxt_len - 1] = '\004'; + memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); + translation = dcgettext (domain, msg_ctxt_id, category); +#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS + if (msg_ctxt_id != buf) + free (msg_ctxt_id); +#endif + if (translation != msg_ctxt_id) + return translation; + } + return msgid; +} + +#define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \ + dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) +#define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ + dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static const char * +dcnpgettext_expr (const char *domain, + const char *msgctxt, const char *msgid, + const char *msgid_plural, unsigned long int n, + int category) +{ + size_t msgctxt_len = strlen (msgctxt) + 1; + size_t msgid_len = strlen (msgid) + 1; + const char *translation; +#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS + char msg_ctxt_id[msgctxt_len + msgid_len]; +#else + char buf[1024]; + char *msg_ctxt_id = + (msgctxt_len + msgid_len <= sizeof (buf) + ? buf + : (char *) malloc (msgctxt_len + msgid_len)); + if (msg_ctxt_id != NULL) +#endif + { + memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); + msg_ctxt_id[msgctxt_len - 1] = '\004'; + memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); + translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); +#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS + if (msg_ctxt_id != buf) + free (msg_ctxt_id); +#endif + if (!(translation == msg_ctxt_id || translation == msgid_plural)) + return translation; + } + return (n == 1 ? msgid : msgid_plural); +} + #endif /* _LIBGETTEXT_H */ diff --git a/lib/hash.c b/lib/hash.c new file mode 100644 index 0000000000000..f4ab12f487de7 --- /dev/null +++ b/lib/hash.c @@ -0,0 +1,1048 @@ +/* hash - hashing table processing. + + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006 Free + Software Foundation, Inc. + + Written by Jim Meyering, 1992. + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* A generic hash table package. */ + +/* Define USE_OBSTACK to 1 if you want the allocator to use obstacks instead + of malloc. If you change USE_OBSTACK, you have to recompile! */ + +#include <config.h> + +#include "hash.h" +#include "xalloc.h" + +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> + +#if USE_OBSTACK +# include "obstack.h" +# ifndef obstack_chunk_alloc +# define obstack_chunk_alloc malloc +# endif +# ifndef obstack_chunk_free +# define obstack_chunk_free free +# endif +#endif + +#ifndef SIZE_MAX +# define SIZE_MAX ((size_t) -1) +#endif + +struct hash_table + { + /* The array of buckets starts at BUCKET and extends to BUCKET_LIMIT-1, + for a possibility of N_BUCKETS. Among those, N_BUCKETS_USED buckets + are not empty, there are N_ENTRIES active entries in the table. */ + struct hash_entry *bucket; + struct hash_entry const *bucket_limit; + size_t n_buckets; + size_t n_buckets_used; + size_t n_entries; + + /* Tuning arguments, kept in a physicaly separate structure. */ + const Hash_tuning *tuning; + + /* Three functions are given to `hash_initialize', see the documentation + block for this function. In a word, HASHER randomizes a user entry + into a number up from 0 up to some maximum minus 1; COMPARATOR returns + true if two user entries compare equally; and DATA_FREER is the cleanup + function for a user entry. */ + Hash_hasher hasher; + Hash_comparator comparator; + Hash_data_freer data_freer; + + /* A linked list of freed struct hash_entry structs. */ + struct hash_entry *free_entry_list; + +#if USE_OBSTACK + /* Whenever obstacks are used, it is possible to allocate all overflowed + entries into a single stack, so they all can be freed in a single + operation. It is not clear if the speedup is worth the trouble. */ + struct obstack entry_stack; +#endif + }; + +/* A hash table contains many internal entries, each holding a pointer to + some user provided data (also called a user entry). An entry indistinctly + refers to both the internal entry and its associated user entry. A user + entry contents may be hashed by a randomization function (the hashing + function, or just `hasher' for short) into a number (or `slot') between 0 + and the current table size. At each slot position in the hash table, + starts a linked chain of entries for which the user data all hash to this + slot. A bucket is the collection of all entries hashing to the same slot. + + A good `hasher' function will distribute entries rather evenly in buckets. + In the ideal case, the length of each bucket is roughly the number of + entries divided by the table size. Finding the slot for a data is usually + done in constant time by the `hasher', and the later finding of a precise + entry is linear in time with the size of the bucket. Consequently, a + larger hash table size (that is, a larger number of buckets) is prone to + yielding shorter chains, *given* the `hasher' function behaves properly. + + Long buckets slow down the lookup algorithm. One might use big hash table + sizes in hope to reduce the average length of buckets, but this might + become inordinate, as unused slots in the hash table take some space. The + best bet is to make sure you are using a good `hasher' function (beware + that those are not that easy to write! :-), and to use a table size + larger than the actual number of entries. */ + +/* If an insertion makes the ratio of nonempty buckets to table size larger + than the growth threshold (a number between 0.0 and 1.0), then increase + the table size by multiplying by the growth factor (a number greater than + 1.0). The growth threshold defaults to 0.8, and the growth factor + defaults to 1.414, meaning that the table will have doubled its size + every second time 80% of the buckets get used. */ +#define DEFAULT_GROWTH_THRESHOLD 0.8 +#define DEFAULT_GROWTH_FACTOR 1.414 + +/* If a deletion empties a bucket and causes the ratio of used buckets to + table size to become smaller than the shrink threshold (a number between + 0.0 and 1.0), then shrink the table by multiplying by the shrink factor (a + number greater than the shrink threshold but smaller than 1.0). The shrink + threshold and factor default to 0.0 and 1.0, meaning that the table never + shrinks. */ +#define DEFAULT_SHRINK_THRESHOLD 0.0 +#define DEFAULT_SHRINK_FACTOR 1.0 + +/* Use this to initialize or reset a TUNING structure to + some sensible values. */ +static const Hash_tuning default_tuning = + { + DEFAULT_SHRINK_THRESHOLD, + DEFAULT_SHRINK_FACTOR, + DEFAULT_GROWTH_THRESHOLD, + DEFAULT_GROWTH_FACTOR, + false + }; + +/* Information and lookup. */ + +/* The following few functions provide information about the overall hash + table organization: the number of entries, number of buckets and maximum + length of buckets. */ + +/* Return the number of buckets in the hash table. The table size, the total + number of buckets (used plus unused), or the maximum number of slots, are + the same quantity. */ + +size_t +hash_get_n_buckets (const Hash_table *table) +{ + return table->n_buckets; +} + +/* Return the number of slots in use (non-empty buckets). */ + +size_t +hash_get_n_buckets_used (const Hash_table *table) +{ + return table->n_buckets_used; +} + +/* Return the number of active entries. */ + +size_t +hash_get_n_entries (const Hash_table *table) +{ + return table->n_entries; +} + +/* Return the length of the longest chain (bucket). */ + +size_t +hash_get_max_bucket_length (const Hash_table *table) +{ + struct hash_entry const *bucket; + size_t max_bucket_length = 0; + + for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) + { + if (bucket->data) + { + struct hash_entry const *cursor = bucket; + size_t bucket_length = 1; + + while (cursor = cursor->next, cursor) + bucket_length++; + + if (bucket_length > max_bucket_length) + max_bucket_length = bucket_length; + } + } + + return max_bucket_length; +} + +/* Do a mild validation of a hash table, by traversing it and checking two + statistics. */ + +bool +hash_table_ok (const Hash_table *table) +{ + struct hash_entry const *bucket; + size_t n_buckets_used = 0; + size_t n_entries = 0; + + for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) + { + if (bucket->data) + { + struct hash_entry const *cursor = bucket; + + /* Count bucket head. */ + n_buckets_used++; + n_entries++; + + /* Count bucket overflow. */ + while (cursor = cursor->next, cursor) + n_entries++; + } + } + + if (n_buckets_used == table->n_buckets_used && n_entries == table->n_entries) + return true; + + return false; +} + +void +hash_print_statistics (const Hash_table *table, FILE *stream) +{ + size_t n_entries = hash_get_n_entries (table); + size_t n_buckets = hash_get_n_buckets (table); + size_t n_buckets_used = hash_get_n_buckets_used (table); + size_t max_bucket_length = hash_get_max_bucket_length (table); + + fprintf (stream, "# entries: %lu\n", (unsigned long int) n_entries); + fprintf (stream, "# buckets: %lu\n", (unsigned long int) n_buckets); + fprintf (stream, "# buckets used: %lu (%.2f%%)\n", + (unsigned long int) n_buckets_used, + (100.0 * n_buckets_used) / n_buckets); + fprintf (stream, "max bucket length: %lu\n", + (unsigned long int) max_bucket_length); +} + +/* If ENTRY matches an entry already in the hash table, return the + entry from the table. Otherwise, return NULL. */ + +void * +hash_lookup (const Hash_table *table, const void *entry) +{ + struct hash_entry const *bucket + = table->bucket + table->hasher (entry, table->n_buckets); + struct hash_entry const *cursor; + + if (! (bucket < table->bucket_limit)) + abort (); + + if (bucket->data == NULL) + return NULL; + + for (cursor = bucket; cursor; cursor = cursor->next) + if (table->comparator (entry, cursor->data)) + return cursor->data; + + return NULL; +} + +/* Walking. */ + +/* The functions in this page traverse the hash table and process the + contained entries. For the traversal to work properly, the hash table + should not be resized nor modified while any particular entry is being + processed. In particular, entries should not be added or removed. */ + +/* Return the first data in the table, or NULL if the table is empty. */ + +void * +hash_get_first (const Hash_table *table) +{ + struct hash_entry const *bucket; + + if (table->n_entries == 0) + return NULL; + + for (bucket = table->bucket; ; bucket++) + if (! (bucket < table->bucket_limit)) + abort (); + else if (bucket->data) + return bucket->data; +} + +/* Return the user data for the entry following ENTRY, where ENTRY has been + returned by a previous call to either `hash_get_first' or `hash_get_next'. + Return NULL if there are no more entries. */ + +void * +hash_get_next (const Hash_table *table, const void *entry) +{ + struct hash_entry const *bucket + = table->bucket + table->hasher (entry, table->n_buckets); + struct hash_entry const *cursor; + + if (! (bucket < table->bucket_limit)) + abort (); + + /* Find next entry in the same bucket. */ + for (cursor = bucket; cursor; cursor = cursor->next) + if (cursor->data == entry && cursor->next) + return cursor->next->data; + + /* Find first entry in any subsequent bucket. */ + while (++bucket < table->bucket_limit) + if (bucket->data) + return bucket->data; + + /* None found. */ + return NULL; +} + +/* Fill BUFFER with pointers to active user entries in the hash table, then + return the number of pointers copied. Do not copy more than BUFFER_SIZE + pointers. */ + +size_t +hash_get_entries (const Hash_table *table, void **buffer, + size_t buffer_size) +{ + size_t counter = 0; + struct hash_entry const *bucket; + struct hash_entry const *cursor; + + for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) + { + if (bucket->data) + { + for (cursor = bucket; cursor; cursor = cursor->next) + { + if (counter >= buffer_size) + return counter; + buffer[counter++] = cursor->data; + } + } + } + + return counter; +} + +/* Call a PROCESSOR function for each entry of a hash table, and return the + number of entries for which the processor function returned success. A + pointer to some PROCESSOR_DATA which will be made available to each call to + the processor function. The PROCESSOR accepts two arguments: the first is + the user entry being walked into, the second is the value of PROCESSOR_DATA + as received. The walking continue for as long as the PROCESSOR function + returns nonzero. When it returns zero, the walking is interrupted. */ + +size_t +hash_do_for_each (const Hash_table *table, Hash_processor processor, + void *processor_data) +{ + size_t counter = 0; + struct hash_entry const *bucket; + struct hash_entry const *cursor; + + for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) + { + if (bucket->data) + { + for (cursor = bucket; cursor; cursor = cursor->next) + { + if (!(*processor) (cursor->data, processor_data)) + return counter; + counter++; + } + } + } + + return counter; +} + +/* Allocation and clean-up. */ + +/* Return a hash index for a NUL-terminated STRING between 0 and N_BUCKETS-1. + This is a convenience routine for constructing other hashing functions. */ + +#if USE_DIFF_HASH + +/* About hashings, Paul Eggert writes to me (FP), on 1994-01-01: "Please see + B. J. McKenzie, R. Harries & T. Bell, Selecting a hashing algorithm, + Software--practice & experience 20, 2 (Feb 1990), 209-224. Good hash + algorithms tend to be domain-specific, so what's good for [diffutils'] io.c + may not be good for your application." */ + +size_t +hash_string (const char *string, size_t n_buckets) +{ +# define ROTATE_LEFT(Value, Shift) \ + ((Value) << (Shift) | (Value) >> ((sizeof (size_t) * CHAR_BIT) - (Shift))) +# define HASH_ONE_CHAR(Value, Byte) \ + ((Byte) + ROTATE_LEFT (Value, 7)) + + size_t value = 0; + unsigned char ch; + + for (; (ch = *string); string++) + value = HASH_ONE_CHAR (value, ch); + return value % n_buckets; + +# undef ROTATE_LEFT +# undef HASH_ONE_CHAR +} + +#else /* not USE_DIFF_HASH */ + +/* This one comes from `recode', and performs a bit better than the above as + per a few experiments. It is inspired from a hashing routine found in the + very old Cyber `snoop', itself written in typical Greg Mansfield style. + (By the way, what happened to this excellent man? Is he still alive?) */ + +size_t +hash_string (const char *string, size_t n_buckets) +{ + size_t value = 0; + unsigned char ch; + + for (; (ch = *string); string++) + value = (value * 31 + ch) % n_buckets; + return value; +} + +#endif /* not USE_DIFF_HASH */ + +/* Return true if CANDIDATE is a prime number. CANDIDATE should be an odd + number at least equal to 11. */ + +static bool +is_prime (size_t candidate) +{ + size_t divisor = 3; + size_t square = divisor * divisor; + + while (square < candidate && (candidate % divisor)) + { + divisor++; + square += 4 * divisor; + divisor++; + } + + return (candidate % divisor ? true : false); +} + +/* Round a given CANDIDATE number up to the nearest prime, and return that + prime. Primes lower than 10 are merely skipped. */ + +static size_t +next_prime (size_t candidate) +{ + /* Skip small primes. */ + if (candidate < 10) + candidate = 10; + + /* Make it definitely odd. */ + candidate |= 1; + + while (!is_prime (candidate)) + candidate += 2; + + return candidate; +} + +void +hash_reset_tuning (Hash_tuning *tuning) +{ + *tuning = default_tuning; +} + +/* For the given hash TABLE, check the user supplied tuning structure for + reasonable values, and return true if there is no gross error with it. + Otherwise, definitively reset the TUNING field to some acceptable default + in the hash table (that is, the user loses the right of further modifying + tuning arguments), and return false. */ + +static bool +check_tuning (Hash_table *table) +{ + const Hash_tuning *tuning = table->tuning; + + /* Be a bit stricter than mathematics would require, so that + rounding errors in size calculations do not cause allocations to + fail to grow or shrink as they should. The smallest allocation + is 11 (due to next_prime's algorithm), so an epsilon of 0.1 + should be good enough. */ + float epsilon = 0.1f; + + if (epsilon < tuning->growth_threshold + && tuning->growth_threshold < 1 - epsilon + && 1 + epsilon < tuning->growth_factor + && 0 <= tuning->shrink_threshold + && tuning->shrink_threshold + epsilon < tuning->shrink_factor + && tuning->shrink_factor <= 1 + && tuning->shrink_threshold + epsilon < tuning->growth_threshold) + return true; + + table->tuning = &default_tuning; + return false; +} + +/* Allocate and return a new hash table, or NULL upon failure. The initial + number of buckets is automatically selected so as to _guarantee_ that you + may insert at least CANDIDATE different user entries before any growth of + the hash table size occurs. So, if have a reasonably tight a-priori upper + bound on the number of entries you intend to insert in the hash table, you + may save some table memory and insertion time, by specifying it here. If + the IS_N_BUCKETS field of the TUNING structure is true, the CANDIDATE + argument has its meaning changed to the wanted number of buckets. + + TUNING points to a structure of user-supplied values, in case some fine + tuning is wanted over the default behavior of the hasher. If TUNING is + NULL, the default tuning parameters are used instead. + + The user-supplied HASHER function should be provided. It accepts two + arguments ENTRY and TABLE_SIZE. It computes, by hashing ENTRY contents, a + slot number for that entry which should be in the range 0..TABLE_SIZE-1. + This slot number is then returned. + + The user-supplied COMPARATOR function should be provided. It accepts two + arguments pointing to user data, it then returns true for a pair of entries + that compare equal, or false otherwise. This function is internally called + on entries which are already known to hash to the same bucket index. + + The user-supplied DATA_FREER function, when not NULL, may be later called + with the user data as an argument, just before the entry containing the + data gets freed. This happens from within `hash_free' or `hash_clear'. + You should specify this function only if you want these functions to free + all of your `data' data. This is typically the case when your data is + simply an auxiliary struct that you have malloc'd to aggregate several + values. */ + +Hash_table * +hash_initialize (size_t candidate, const Hash_tuning *tuning, + Hash_hasher hasher, Hash_comparator comparator, + Hash_data_freer data_freer) +{ + Hash_table *table; + + if (hasher == NULL || comparator == NULL) + return NULL; + + table = malloc (sizeof *table); + if (table == NULL) + return NULL; + + if (!tuning) + tuning = &default_tuning; + table->tuning = tuning; + if (!check_tuning (table)) + { + /* Fail if the tuning options are invalid. This is the only occasion + when the user gets some feedback about it. Once the table is created, + if the user provides invalid tuning options, we silently revert to + using the defaults, and ignore further request to change the tuning + options. */ + goto fail; + } + + if (!tuning->is_n_buckets) + { + float new_candidate = candidate / tuning->growth_threshold; + if (SIZE_MAX <= new_candidate) + goto fail; + candidate = new_candidate; + } + + if (xalloc_oversized (candidate, sizeof *table->bucket)) + goto fail; + table->n_buckets = next_prime (candidate); + if (xalloc_oversized (table->n_buckets, sizeof *table->bucket)) + goto fail; + + table->bucket = calloc (table->n_buckets, sizeof *table->bucket); + table->bucket_limit = table->bucket + table->n_buckets; + table->n_buckets_used = 0; + table->n_entries = 0; + + table->hasher = hasher; + table->comparator = comparator; + table->data_freer = data_freer; + + table->free_entry_list = NULL; +#if USE_OBSTACK + obstack_init (&table->entry_stack); +#endif + return table; + + fail: + free (table); + return NULL; +} + +/* Make all buckets empty, placing any chained entries on the free list. + Apply the user-specified function data_freer (if any) to the datas of any + affected entries. */ + +void +hash_clear (Hash_table *table) +{ + struct hash_entry *bucket; + + for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) + { + if (bucket->data) + { + struct hash_entry *cursor; + struct hash_entry *next; + + /* Free the bucket overflow. */ + for (cursor = bucket->next; cursor; cursor = next) + { + if (table->data_freer) + (*table->data_freer) (cursor->data); + cursor->data = NULL; + + next = cursor->next; + /* Relinking is done one entry at a time, as it is to be expected + that overflows are either rare or short. */ + cursor->next = table->free_entry_list; + table->free_entry_list = cursor; + } + + /* Free the bucket head. */ + if (table->data_freer) + (*table->data_freer) (bucket->data); + bucket->data = NULL; + bucket->next = NULL; + } + } + + table->n_buckets_used = 0; + table->n_entries = 0; +} + +/* Reclaim all storage associated with a hash table. If a data_freer + function has been supplied by the user when the hash table was created, + this function applies it to the data of each entry before freeing that + entry. */ + +void +hash_free (Hash_table *table) +{ + struct hash_entry *bucket; + struct hash_entry *cursor; + struct hash_entry *next; + + /* Call the user data_freer function. */ + if (table->data_freer && table->n_entries) + { + for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) + { + if (bucket->data) + { + for (cursor = bucket; cursor; cursor = cursor->next) + { + (*table->data_freer) (cursor->data); + } + } + } + } + +#if USE_OBSTACK + + obstack_free (&table->entry_stack, NULL); + +#else + + /* Free all bucket overflowed entries. */ + for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) + { + for (cursor = bucket->next; cursor; cursor = next) + { + next = cursor->next; + free (cursor); + } + } + + /* Also reclaim the internal list of previously freed entries. */ + for (cursor = table->free_entry_list; cursor; cursor = next) + { + next = cursor->next; + free (cursor); + } + +#endif + + /* Free the remainder of the hash table structure. */ + free (table->bucket); + free (table); +} + +/* Insertion and deletion. */ + +/* Get a new hash entry for a bucket overflow, possibly by reclying a + previously freed one. If this is not possible, allocate a new one. */ + +static struct hash_entry * +allocate_entry (Hash_table *table) +{ + struct hash_entry *new; + + if (table->free_entry_list) + { + new = table->free_entry_list; + table->free_entry_list = new->next; + } + else + { +#if USE_OBSTACK + new = obstack_alloc (&table->entry_stack, sizeof *new); +#else + new = malloc (sizeof *new); +#endif + } + + return new; +} + +/* Free a hash entry which was part of some bucket overflow, + saving it for later recycling. */ + +static void +free_entry (Hash_table *table, struct hash_entry *entry) +{ + entry->data = NULL; + entry->next = table->free_entry_list; + table->free_entry_list = entry; +} + +/* This private function is used to help with insertion and deletion. When + ENTRY matches an entry in the table, return a pointer to the corresponding + user data and set *BUCKET_HEAD to the head of the selected bucket. + Otherwise, return NULL. When DELETE is true and ENTRY matches an entry in + the table, unlink the matching entry. */ + +static void * +hash_find_entry (Hash_table *table, const void *entry, + struct hash_entry **bucket_head, bool delete) +{ + struct hash_entry *bucket + = table->bucket + table->hasher (entry, table->n_buckets); + struct hash_entry *cursor; + + if (! (bucket < table->bucket_limit)) + abort (); + + *bucket_head = bucket; + + /* Test for empty bucket. */ + if (bucket->data == NULL) + return NULL; + + /* See if the entry is the first in the bucket. */ + if ((*table->comparator) (entry, bucket->data)) + { + void *data = bucket->data; + + if (delete) + { + if (bucket->next) + { + struct hash_entry *next = bucket->next; + + /* Bump the first overflow entry into the bucket head, then save + the previous first overflow entry for later recycling. */ + *bucket = *next; + free_entry (table, next); + } + else + { + bucket->data = NULL; + } + } + + return data; + } + + /* Scan the bucket overflow. */ + for (cursor = bucket; cursor->next; cursor = cursor->next) + { + if ((*table->comparator) (entry, cursor->next->data)) + { + void *data = cursor->next->data; + + if (delete) + { + struct hash_entry *next = cursor->next; + + /* Unlink the entry to delete, then save the freed entry for later + recycling. */ + cursor->next = next->next; + free_entry (table, next); + } + + return data; + } + } + + /* No entry found. */ + return NULL; +} + +/* For an already existing hash table, change the number of buckets through + specifying CANDIDATE. The contents of the hash table are preserved. The + new number of buckets is automatically selected so as to _guarantee_ that + the table may receive at least CANDIDATE different user entries, including + those already in the table, before any other growth of the hash table size + occurs. If TUNING->IS_N_BUCKETS is true, then CANDIDATE specifies the + exact number of buckets desired. */ + +bool +hash_rehash (Hash_table *table, size_t candidate) +{ + Hash_table *new_table; + struct hash_entry *bucket; + struct hash_entry *cursor; + struct hash_entry *next; + + new_table = hash_initialize (candidate, table->tuning, table->hasher, + table->comparator, table->data_freer); + if (new_table == NULL) + return false; + + /* Merely reuse the extra old space into the new table. */ +#if USE_OBSTACK + obstack_free (&new_table->entry_stack, NULL); + new_table->entry_stack = table->entry_stack; +#endif + new_table->free_entry_list = table->free_entry_list; + + for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) + if (bucket->data) + for (cursor = bucket; cursor; cursor = next) + { + void *data = cursor->data; + struct hash_entry *new_bucket + = (new_table->bucket + + new_table->hasher (data, new_table->n_buckets)); + + if (! (new_bucket < new_table->bucket_limit)) + abort (); + + next = cursor->next; + + if (new_bucket->data) + { + if (cursor == bucket) + { + /* Allocate or recycle an entry, when moving from a bucket + header into a bucket overflow. */ + struct hash_entry *new_entry = allocate_entry (new_table); + + if (new_entry == NULL) + return false; + + new_entry->data = data; + new_entry->next = new_bucket->next; + new_bucket->next = new_entry; + } + else + { + /* Merely relink an existing entry, when moving from a + bucket overflow into a bucket overflow. */ + cursor->next = new_bucket->next; + new_bucket->next = cursor; + } + } + else + { + /* Free an existing entry, when moving from a bucket + overflow into a bucket header. Also take care of the + simple case of moving from a bucket header into a bucket + header. */ + new_bucket->data = data; + new_table->n_buckets_used++; + if (cursor != bucket) + free_entry (new_table, cursor); + } + } + + free (table->bucket); + table->bucket = new_table->bucket; + table->bucket_limit = new_table->bucket_limit; + table->n_buckets = new_table->n_buckets; + table->n_buckets_used = new_table->n_buckets_used; + table->free_entry_list = new_table->free_entry_list; + /* table->n_entries already holds its value. */ +#if USE_OBSTACK + table->entry_stack = new_table->entry_stack; +#endif + free (new_table); + + return true; +} + +/* If ENTRY matches an entry already in the hash table, return the pointer + to the entry from the table. Otherwise, insert ENTRY and return ENTRY. + Return NULL if the storage required for insertion cannot be allocated. */ + +void * +hash_insert (Hash_table *table, const void *entry) +{ + void *data; + struct hash_entry *bucket; + + /* The caller cannot insert a NULL entry. */ + if (! entry) + abort (); + + /* If there's a matching entry already in the table, return that. */ + if ((data = hash_find_entry (table, entry, &bucket, false)) != NULL) + return data; + + /* ENTRY is not matched, it should be inserted. */ + + if (bucket->data) + { + struct hash_entry *new_entry = allocate_entry (table); + + if (new_entry == NULL) + return NULL; + + /* Add ENTRY in the overflow of the bucket. */ + + new_entry->data = (void *) entry; + new_entry->next = bucket->next; + bucket->next = new_entry; + table->n_entries++; + return (void *) entry; + } + + /* Add ENTRY right in the bucket head. */ + + bucket->data = (void *) entry; + table->n_entries++; + table->n_buckets_used++; + + /* If the growth threshold of the buckets in use has been reached, increase + the table size and rehash. There's no point in checking the number of + entries: if the hashing function is ill-conditioned, rehashing is not + likely to improve it. */ + + if (table->n_buckets_used + > table->tuning->growth_threshold * table->n_buckets) + { + /* Check more fully, before starting real work. If tuning arguments + became invalid, the second check will rely on proper defaults. */ + check_tuning (table); + if (table->n_buckets_used + > table->tuning->growth_threshold * table->n_buckets) + { + const Hash_tuning *tuning = table->tuning; + float candidate = + (tuning->is_n_buckets + ? (table->n_buckets * tuning->growth_factor) + : (table->n_buckets * tuning->growth_factor + * tuning->growth_threshold)); + + if (SIZE_MAX <= candidate) + return NULL; + + /* If the rehash fails, arrange to return NULL. */ + if (!hash_rehash (table, candidate)) + entry = NULL; + } + } + + return (void *) entry; +} + +/* If ENTRY is already in the table, remove it and return the just-deleted + data (the user may want to deallocate its storage). If ENTRY is not in the + table, don't modify the table and return NULL. */ + +void * +hash_delete (Hash_table *table, const void *entry) +{ + void *data; + struct hash_entry *bucket; + + data = hash_find_entry (table, entry, &bucket, true); + if (!data) + return NULL; + + table->n_entries--; + if (!bucket->data) + { + table->n_buckets_used--; + + /* If the shrink threshold of the buckets in use has been reached, + rehash into a smaller table. */ + + if (table->n_buckets_used + < table->tuning->shrink_threshold * table->n_buckets) + { + /* Check more fully, before starting real work. If tuning arguments + became invalid, the second check will rely on proper defaults. */ + check_tuning (table); + if (table->n_buckets_used + < table->tuning->shrink_threshold * table->n_buckets) + { + const Hash_tuning *tuning = table->tuning; + size_t candidate = + (tuning->is_n_buckets + ? table->n_buckets * tuning->shrink_factor + : (table->n_buckets * tuning->shrink_factor + * tuning->growth_threshold)); + + hash_rehash (table, candidate); + } + } + } + + return data; +} + +/* Testing. */ + +#if TESTING + +void +hash_print (const Hash_table *table) +{ + struct hash_entry const *bucket; + + for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) + { + struct hash_entry *cursor; + + if (bucket) + printf ("%lu:\n", (unsigned long int) (bucket - table->bucket)); + + for (cursor = bucket; cursor; cursor = cursor->next) + { + char const *s = cursor->data; + /* FIXME */ + if (s) + printf (" %s\n", s); + } + } +} + +#endif /* TESTING */ diff --git a/lib/hash.h b/lib/hash.h new file mode 100644 index 0000000000000..ab63a863fd0c8 --- /dev/null +++ b/lib/hash.h @@ -0,0 +1,88 @@ +/* hash - hashing table processing. + Copyright (C) 1998, 1999, 2001, 2003 Free Software Foundation, Inc. + Written by Jim Meyering <meyering@ascend.com>, 1998. + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* A generic hash table package. */ + +/* Make sure USE_OBSTACK is defined to 1 if you want the allocator to use + obstacks instead of malloc, and recompile `hash.c' with same setting. */ + +#ifndef HASH_H_ +# define HASH_H_ + +# include <stdio.h> +# include <stdbool.h> + +typedef size_t (*Hash_hasher) (const void *, size_t); +typedef bool (*Hash_comparator) (const void *, const void *); +typedef void (*Hash_data_freer) (void *); +typedef bool (*Hash_processor) (void *, void *); + +struct hash_entry + { + void *data; + struct hash_entry *next; + }; + +struct hash_tuning + { + /* This structure is mainly used for `hash_initialize', see the block + documentation of `hash_reset_tuning' for more complete comments. */ + + float shrink_threshold; /* ratio of used buckets to trigger a shrink */ + float shrink_factor; /* ratio of new smaller size to original size */ + float growth_threshold; /* ratio of used buckets to trigger a growth */ + float growth_factor; /* ratio of new bigger size to original size */ + bool is_n_buckets; /* if CANDIDATE really means table size */ + }; + +typedef struct hash_tuning Hash_tuning; + +struct hash_table; + +typedef struct hash_table Hash_table; + +/* Information and lookup. */ +size_t hash_get_n_buckets (const Hash_table *); +size_t hash_get_n_buckets_used (const Hash_table *); +size_t hash_get_n_entries (const Hash_table *); +size_t hash_get_max_bucket_length (const Hash_table *); +bool hash_table_ok (const Hash_table *); +void hash_print_statistics (const Hash_table *, FILE *); +void *hash_lookup (const Hash_table *, const void *); + +/* Walking. */ +void *hash_get_first (const Hash_table *); +void *hash_get_next (const Hash_table *, const void *); +size_t hash_get_entries (const Hash_table *, void **, size_t); +size_t hash_do_for_each (const Hash_table *, Hash_processor, void *); + +/* Allocation and clean-up. */ +size_t hash_string (const char *, size_t); +void hash_reset_tuning (Hash_tuning *); +Hash_table *hash_initialize (size_t, const Hash_tuning *, + Hash_hasher, Hash_comparator, + Hash_data_freer); +void hash_clear (Hash_table *); +void hash_free (Hash_table *); + +/* Insertion and deletion. */ +bool hash_rehash (Hash_table *, size_t); +void *hash_insert (Hash_table *, const void *); +void *hash_delete (Hash_table *, const void *); + +#endif diff --git a/lib/intprops.h b/lib/intprops.h new file mode 100644 index 0000000000000..34f971cbaad8c --- /dev/null +++ b/lib/intprops.h @@ -0,0 +1,78 @@ +/* intprops.h -- properties of integer types + + Copyright (C) 2001, 2002, 2003, 2004, 2005 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Paul Eggert. */ + +#include <limits.h> + +/* The extra casts in the following macros work around compiler bugs, + e.g., in Cray C 5.0.3.0. */ + +/* True if the arithmetic type T is an integer type. bool counts as + an integer. */ +#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1) + +/* True if negative values of the signed integer type T use two's + complement, ones' complement, or signed magnitude representation, + respectively. Much GNU code assumes two's complement, but some + people like to be portable to all possible C hosts. */ +#define TYPE_TWOS_COMPLEMENT(t) ((t) ~ (t) 0 == (t) -1) +#define TYPE_ONES_COMPLEMENT(t) ((t) ~ (t) 0 == 0) +#define TYPE_SIGNED_MAGNITUDE(t) ((t) ~ (t) 0 < (t) -1) + +/* True if the arithmetic type T is signed. */ +#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) + +/* The maximum and minimum values for the integer type T. These + macros have undefined behavior if T is signed and has padding bits. + If this is a problem for you, please let us know how to fix it for + your host. */ +#define TYPE_MINIMUM(t) \ + ((t) (! TYPE_SIGNED (t) \ + ? (t) 0 \ + : TYPE_SIGNED_MAGNITUDE (t) \ + ? ~ (t) 0 \ + : ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))) +#define TYPE_MAXIMUM(t) \ + ((t) (! TYPE_SIGNED (t) \ + ? (t) -1 \ + : ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1)))) + +/* Return zero if T can be determined to be an unsigned type. + Otherwise, return 1. + When compiling with GCC, INT_STRLEN_BOUND uses this macro to obtain a + tighter bound. Otherwise, it overestimates the true bound by one byte + when applied to unsigned types of size 2, 4, 16, ... bytes. + The symbol signed_type_or_expr__ is private to this header file. */ +#if __GNUC__ >= 2 +# define signed_type_or_expr__(t) TYPE_SIGNED (__typeof__ (t)) +#else +# define signed_type_or_expr__(t) 1 +#endif + +/* Bound on length of the string representing an integer type or expression T. + Subtract 1 for the sign bit if T is signed; log10 (2.0) < 146/485; + add 1 for integer division truncation; add 1 more for a minus sign + if needed. */ +#define INT_STRLEN_BOUND(t) \ + ((sizeof (t) * CHAR_BIT - signed_type_or_expr__ (t)) * 146 / 485 \ + + signed_type_or_expr__ (t) + 1) + +/* Bound on buffer size needed to represent an integer type or expression T, + including the terminating null. */ +#define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1) diff --git a/lib/inttostr.c b/lib/inttostr.c new file mode 100644 index 0000000000000..246d658350730 --- /dev/null +++ b/lib/inttostr.c @@ -0,0 +1,51 @@ +/* inttostr.c -- convert integers to printable strings + + Copyright (C) 2001, 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Paul Eggert */ + +#include <config.h> + +#include "inttostr.h" + +/* Convert I to a printable string in BUF, which must be at least + INT_BUFSIZE_BOUND (INTTYPE) bytes long. Return the address of the + printable string, which need not start at BUF. */ + +char * +inttostr (inttype i, char *buf) +{ + char *p = buf + INT_STRLEN_BOUND (inttype); + *p = 0; + + if (i < 0) + { + do + *--p = '0' - i % 10; + while ((i /= 10) != 0); + + *--p = '-'; + } + else + { + do + *--p = '0' + i % 10; + while ((i /= 10) != 0); + } + + return p; +} diff --git a/lib/exit.h b/lib/inttostr.h index 4e8d465165465..31258cad35bc9 100644 --- a/lib/exit.h +++ b/lib/inttostr.h @@ -1,5 +1,7 @@ -/* exit() function. - Copyright (C) 1995, 2001 Free Software Foundation, Inc. +/* inttostr.h -- convert integers to printable strings + + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 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 @@ -13,20 +15,16 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef _EXIT_H -#define _EXIT_H +/* Written by Paul Eggert */ -/* Get exit() declaration. */ -#include <stdlib.h> +#include <stdint.h> +#include <sys/types.h> -/* Some systems do not define EXIT_*, even with STDC_HEADERS. */ -#ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 -#endif -#ifndef EXIT_FAILURE -# define EXIT_FAILURE 1 -#endif +#include "intprops.h" -#endif /* _EXIT_H */ +char *offtostr (off_t, char *); +char *imaxtostr (intmax_t, char *); +char *umaxtostr (uintmax_t, char *); +char *uinttostr (unsigned int, char *); diff --git a/lib/mempcpy.c b/lib/mempcpy.c index 3ac42af288a58..1c702c7f4cb7c 100644 --- a/lib/mempcpy.c +++ b/lib/mempcpy.c @@ -1,5 +1,5 @@ /* Copy memory area and return pointer after last written byte. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2007 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 @@ -13,11 +13,11 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -/* Specification. */ -#include "mempcpy.h" +#include <config.h> +/* Specification. */ #include <string.h> /* Copy N bytes of SRC to DEST, return pointer to bytes after the diff --git a/lib/paxerror.c b/lib/paxerror.c new file mode 100644 index 0000000000000..000d9e44981fd --- /dev/null +++ b/lib/paxerror.c @@ -0,0 +1,365 @@ +/* Miscellaneous error functions + + Copyright (C) 2005 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <system.h> +#include <paxlib.h> +#include <quote.h> +#include <quotearg.h> + +/* Decode MODE from its binary form in a stat structure, and encode it + into a 9-byte string STRING, terminated with a NUL. */ + +void +pax_decode_mode (mode_t mode, char *string) +{ + *string++ = mode & S_IRUSR ? 'r' : '-'; + *string++ = mode & S_IWUSR ? 'w' : '-'; + *string++ = (mode & S_ISUID + ? (mode & S_IXUSR ? 's' : 'S') + : (mode & S_IXUSR ? 'x' : '-')); + *string++ = mode & S_IRGRP ? 'r' : '-'; + *string++ = mode & S_IWGRP ? 'w' : '-'; + *string++ = (mode & S_ISGID + ? (mode & S_IXGRP ? 's' : 'S') + : (mode & S_IXGRP ? 'x' : '-')); + *string++ = mode & S_IROTH ? 'r' : '-'; + *string++ = mode & S_IWOTH ? 'w' : '-'; + *string++ = (mode & S_ISVTX + ? (mode & S_IXOTH ? 't' : 'T') + : (mode & S_IXOTH ? 'x' : '-')); + *string = '\0'; +} + +/* Report an error associated with the system call CALL and the + optional name NAME. */ +void +call_arg_error (char const *call, char const *name) +{ + int e = errno; + /* TRANSLATORS: %s after `Cannot' is a function name, e.g. `Cannot open'. + Directly translating this to another language will not work, first because + %s itself is not translated. + Translate it as `%s: Function %s failed'. */ + ERROR ((0, e, _("%s: Cannot %s"), quotearg_colon (name), call)); +} + +/* Report a fatal error associated with the system call CALL and + the optional file name NAME. */ +void +call_arg_fatal (char const *call, char const *name) +{ + int e = errno; + /* TRANSLATORS: %s after `Cannot' is a function name, e.g. `Cannot open'. + Directly translating this to another language will not work, first because + %s itself is not translated. + Translate it as `%s: Function %s failed'. */ + FATAL_ERROR ((0, e, _("%s: Cannot %s"), quotearg_colon (name), call)); +} + +/* Report a warning associated with the system call CALL and + the optional file name NAME. */ +void +call_arg_warn (char const *call, char const *name) +{ + int e = errno; + /* TRANSLATORS: %s after `Cannot' is a function name, e.g. `Cannot open'. + Directly translating this to another language will not work, first because + %s itself is not translated. + Translate it as `%s: Function %s failed'. */ + WARN ((0, e, _("%s: Warning: Cannot %s"), quotearg_colon (name), call)); +} + +void +chmod_error_details (char const *name, mode_t mode) +{ + int e = errno; + char buf[10]; + pax_decode_mode (mode, buf); + ERROR ((0, e, _("%s: Cannot change mode to %s"), + quotearg_colon (name), buf)); +} + +void +chown_error_details (char const *name, uid_t uid, gid_t gid) +{ + int e = errno; + ERROR ((0, e, _("%s: Cannot change ownership to uid %lu, gid %lu"), + quotearg_colon (name), (unsigned long) uid, (unsigned long) gid)); +} + +void +close_error (char const *name) +{ + call_arg_error ("close", name); +} + +void +close_warn (char const *name) +{ + call_arg_warn ("close", name); +} + +void +exec_fatal (char const *name) +{ + call_arg_fatal ("exec", name); +} + +void +link_error (char const *target, char const *source) +{ + int e = errno; + ERROR ((0, e, _("%s: Cannot hard link to %s"), + quotearg_colon (source), quote_n (1, target))); +} + +void +mkdir_error (char const *name) +{ + call_arg_error ("mkdir", name); +} + +void +mkfifo_error (char const *name) +{ + call_arg_error ("mkfifo", name); +} + +void +mknod_error (char const *name) +{ + call_arg_error ("mknod", name); +} + +void +open_error (char const *name) +{ + call_arg_error ("open", name); +} + +void +open_fatal (char const *name) +{ + call_arg_fatal ("open", name); +} + +void +open_warn (char const *name) +{ + call_arg_warn ("open", name); +} + +void +read_error (char const *name) +{ + call_arg_error ("read", name); +} + +void +read_error_details (char const *name, off_t offset, size_t size) +{ + char buf[UINTMAX_STRSIZE_BOUND]; + int e = errno; + ERROR ((0, e, + ngettext ("%s: Read error at byte %s, while reading %lu byte", + "%s: Read error at byte %s, while reading %lu bytes", + size), + quotearg_colon (name), STRINGIFY_BIGINT (offset, buf), + (unsigned long) size)); +} + +void +read_warn_details (char const *name, off_t offset, size_t size) +{ + char buf[UINTMAX_STRSIZE_BOUND]; + int e = errno; + WARN ((0, e, + ngettext ("%s: Warning: Read error at byte %s, while reading %lu byte", + "%s: Warning: Read error at byte %s, while reading %lu bytes", + size), + quotearg_colon (name), STRINGIFY_BIGINT (offset, buf), + (unsigned long) size)); +} + +void +read_fatal (char const *name) +{ + call_arg_fatal ("read", name); +} + +void +read_fatal_details (char const *name, off_t offset, size_t size) +{ + char buf[UINTMAX_STRSIZE_BOUND]; + int e = errno; + FATAL_ERROR ((0, e, + ngettext ("%s: Read error at byte %s, while reading %lu byte", + "%s: Read error at byte %s, while reading %lu bytes", + size), + quotearg_colon (name), STRINGIFY_BIGINT (offset, buf), + (unsigned long) size)); +} + +void +readlink_error (char const *name) +{ + call_arg_error ("readlink", name); +} + +void +readlink_warn (char const *name) +{ + call_arg_warn ("readlink", name); +} + +void +rmdir_error (char const *name) +{ + call_arg_error ("rmdir", name); +} + +void +savedir_error (char const *name) +{ + call_arg_error ("savedir", name); +} + +void +savedir_warn (char const *name) +{ + call_arg_warn ("savedir", name); +} + +void +seek_error (char const *name) +{ + call_arg_error ("seek", name); +} + +void +seek_error_details (char const *name, off_t offset) +{ + char buf[UINTMAX_STRSIZE_BOUND]; + int e = errno; + ERROR ((0, e, _("%s: Cannot seek to %s"), + quotearg_colon (name), + STRINGIFY_BIGINT (offset, buf))); +} + +void +seek_warn (char const *name) +{ + call_arg_warn ("seek", name); +} + +void +seek_warn_details (char const *name, off_t offset) +{ + char buf[UINTMAX_STRSIZE_BOUND]; + int e = errno; + WARN ((0, e, _("%s: Warning: Cannot seek to %s"), + quotearg_colon (name), + STRINGIFY_BIGINT (offset, buf))); +} + +void +symlink_error (char const *contents, char const *name) +{ + int e = errno; + ERROR ((0, e, _("%s: Cannot create symlink to %s"), + quotearg_colon (name), quote_n (1, contents))); +} + +void +stat_fatal (char const *name) +{ + call_arg_fatal ("stat", name); +} + +void +stat_error (char const *name) +{ + call_arg_error ("stat", name); +} + +void +stat_warn (char const *name) +{ + call_arg_warn ("stat", name); +} + +void +truncate_error (char const *name) +{ + call_arg_error ("truncate", name); +} + +void +truncate_warn (char const *name) +{ + call_arg_warn ("truncate", name); +} + +void +unlink_error (char const *name) +{ + call_arg_error ("unlink", name); +} + +void +utime_error (char const *name) +{ + call_arg_error ("utime", name); +} + +void +waitpid_error (char const *name) +{ + call_arg_error ("waitpid", name); +} + +void +write_error (char const *name) +{ + call_arg_error ("write", name); +} + +void +write_error_details (char const *name, size_t status, size_t size) +{ + if (status == 0) + write_error (name); + else + ERROR ((0, 0, + ngettext ("%s: Wrote only %lu of %lu byte", + "%s: Wrote only %lu of %lu bytes", + size), + name, (unsigned long int) status, (unsigned long int) size)); +} + +void +write_fatal (char const *name) +{ + call_arg_fatal ("write", name); +} + +void +chdir_fatal (char const *name) +{ + call_arg_fatal ("chdir", name); +} diff --git a/lib/paxexit.c b/lib/paxexit.c new file mode 100644 index 0000000000000..a511f79cf171a --- /dev/null +++ b/lib/paxexit.c @@ -0,0 +1,28 @@ +/* Miscellaneous error functions + + Copyright (C) 2005, 2006 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <system.h> +#include <paxlib.h> + +int exit_status = PAXEXIT_SUCCESS; + +void +pax_exit () +{ + exit (exit_status); +} diff --git a/lib/paxlib.h b/lib/paxlib.h new file mode 100644 index 0000000000000..381c4c7029984 --- /dev/null +++ b/lib/paxlib.h @@ -0,0 +1,115 @@ +/* This file is part of GNU paxutils + + Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003, + 2005 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef _paxlib_h_ +#define _paxlib_h_ + +#include <hash.h> +#include <inttostr.h> + +/* Error reporting functions and definitions */ + +/* Exit status for paxutils app. Let's try to keep this list as simple as + possible. tar -d option strongly invites a status different for unequal + comparison and other errors. */ +#define PAXEXIT_SUCCESS 0 +#define PAXEXIT_DIFFERS 1 +#define PAXEXIT_FAILURE 2 + +/* Both WARN and ERROR write a message on stderr and continue processing, + however ERROR manages so tar will exit unsuccessfully. FATAL_ERROR + writes a message on stderr and aborts immediately, with another message + line telling so. USAGE_ERROR works like FATAL_ERROR except that the + other message line suggests trying --help. All four macros accept a + single argument of the form ((0, errno, _("FORMAT"), Args...)). errno + is zero when the error is not being detected by the system. */ + +#define WARN(Args) \ + error Args +#define ERROR(Args) \ + (error Args, exit_status = PAXEXIT_FAILURE) +#define FATAL_ERROR(Args) \ + (error Args, fatal_exit ()) +#define USAGE_ERROR(Args) \ + (error Args, usage (PAXEXIT_FAILURE)) + +extern int exit_status; + +void pax_decode_mode (mode_t mode, char *string); +void call_arg_error (char const *call, char const *name); +void call_arg_fatal (char const *call, char const *name) __attribute__ ((noreturn)); +void call_arg_warn (char const *call, char const *name); +void chmod_error_details (char const *name, mode_t mode); +void chown_error_details (char const *name, uid_t uid, gid_t gid); + +void decode_mode (mode_t, char *); + +void chdir_fatal (char const *) __attribute__ ((noreturn)); +void chmod_error_details (char const *, mode_t); +void chown_error_details (char const *, uid_t, gid_t); +void close_error (char const *); +void close_warn (char const *); +void exec_fatal (char const *) __attribute__ ((noreturn)); +void link_error (char const *, char const *); +void mkdir_error (char const *); +void mkfifo_error (char const *); +void mknod_error (char const *); +void open_error (char const *); +void open_fatal (char const *) __attribute__ ((noreturn)); +void open_warn (char const *); +void read_error (char const *); +void read_error_details (char const *, off_t, size_t); +void read_fatal (char const *) __attribute__ ((noreturn)); +void read_fatal_details (char const *, off_t, size_t) __attribute__ ((noreturn)); +void read_warn_details (char const *, off_t, size_t); +void readlink_error (char const *); +void readlink_warn (char const *); +void rmdir_error (char const *); +void savedir_error (char const *); +void savedir_warn (char const *); +void seek_error (char const *); +void seek_error_details (char const *, off_t); +void seek_warn (char const *); +void seek_warn_details (char const *, off_t); +void stat_fatal (char const *); +void stat_error (char const *); +void stat_warn (char const *); +void symlink_error (char const *, char const *); +void truncate_error (char const *); +void truncate_warn (char const *); +void unlink_error (char const *); +void utime_error (char const *); +void waitpid_error (char const *); +void write_error (char const *); + +void pax_exit (void); +void fatal_exit (void) __attribute__ ((noreturn)); + +#define STRINGIFY_BIGINT(i, b) umaxtostr (i, b) + + +/* Name-related functions */ +bool hash_string_insert (Hash_table **table, char const *string); +bool hash_string_lookup (Hash_table const *table, char const *string); + +bool removed_prefixes_p (void); +char *safer_name_suffix (char const *file_name, bool link_target, bool absolute_names); + +#endif diff --git a/lib/paxnames.c b/lib/paxnames.c new file mode 100644 index 0000000000000..3ca8bfaa7f96c --- /dev/null +++ b/lib/paxnames.c @@ -0,0 +1,156 @@ +/* This file is part of GNU paxutils + Copyright (C) 2005 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <system.h> +#include <hash.h> +#include <paxlib.h> + + +/* Hash tables of strings. */ + +/* Calculate the hash of a string. */ +static size_t +hash_string_hasher (void const *name, size_t n_buckets) +{ + return hash_string (name, n_buckets); +} + +/* Compare two strings for equality. */ +static bool +hash_string_compare (void const *name1, void const *name2) +{ + return strcmp (name1, name2) == 0; +} + +/* Return zero if TABLE contains a copy of STRING; otherwise, insert a + copy of STRING to TABLE and return 1. */ +bool +hash_string_insert (Hash_table **table, char const *string) +{ + Hash_table *t = *table; + char *s = xstrdup (string); + char *e; + + if (! ((t + || (*table = t = hash_initialize (0, 0, hash_string_hasher, + hash_string_compare, 0))) + && (e = hash_insert (t, s)))) + xalloc_die (); + + if (e == s) + return 1; + else + { + free (s); + return 0; + } +} + +/* Return 1 if TABLE contains STRING. */ +bool +hash_string_lookup (Hash_table const *table, char const *string) +{ + return table && hash_lookup (table, string); +} + + +static Hash_table *prefix_table[2]; + +/* Return true if file names of some members in the archive were stripped off + their leading components. We could have used + return prefix_table[0] || prefix_table[1] + but the following seems to be safer: */ +bool +removed_prefixes_p (void) +{ + return (prefix_table[0] && hash_get_n_entries (prefix_table[0]) != 0) + || (prefix_table[1] && hash_get_n_entries (prefix_table[1]) != 0); +} + +/* Return a safer suffix of FILE_NAME, or "." if it has no safer + suffix. Check for fully specified file names and other atrocities. + Warn the user if we do not return NAME. If LINK_TARGET is 1, + FILE_NAME is the target of a hard link, not a member name. + If ABSOLUTE_NAMES is 0, strip filesystem prefix from the file name. */ + +char * +safer_name_suffix (char const *file_name, bool link_target, bool absolute_names) +{ + char const *p; + + if (absolute_names) + p = file_name; + else + { + /* Skip file system prefixes, leading file name components that contain + "..", and leading slashes. */ + + size_t prefix_len = FILE_SYSTEM_PREFIX_LEN (file_name); + + for (p = file_name + prefix_len; *p; ) + { + if (p[0] == '.' && p[1] == '.' && (ISSLASH (p[2]) || !p[2])) + prefix_len = p + 2 - file_name; + + do + { + char c = *p++; + if (ISSLASH (c)) + break; + } + while (*p); + } + + for (p = file_name + prefix_len; ISSLASH (*p); p++) + continue; + prefix_len = p - file_name; + + if (prefix_len) + { + char *prefix = alloca (prefix_len + 1); + memcpy (prefix, file_name, prefix_len); + prefix[prefix_len] = '\0'; + + if (hash_string_insert (&prefix_table[link_target], prefix)) + { + static char const *const diagnostic[] = + { + N_("Removing leading `%s' from member names"), + N_("Removing leading `%s' from hard link targets") + }; + WARN ((0, 0, _(diagnostic[link_target]), prefix)); + } + } + } + + if (! *p) + { + if (p == file_name) + { + static char const *const diagnostic[] = + { + N_("Substituting `.' for empty member name"), + N_("Substituting `.' for empty hard link target") + }; + WARN ((0, 0, "%s", _(diagnostic[link_target]))); + } + + p = "."; + } + + return (char *) p; +} diff --git a/lib/quote.c b/lib/quote.c new file mode 100644 index 0000000000000..119be72ae0abe --- /dev/null +++ b/lib/quote.c @@ -0,0 +1,41 @@ +/* quote.c - quote arguments for output + + Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005, 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Paul Eggert <eggert@twinsun.com> */ + +#include <config.h> + +#include "quotearg.h" +#include "quote.h" + +/* Return an unambiguous printable representation of NAME, + allocated in slot N, suitable for diagnostics. */ +char const * +quote_n (int n, char const *name) +{ + return quotearg_n_style (n, locale_quoting_style, name); +} + +/* Return an unambiguous printable representation of NAME, + suitable for diagnostics. */ +char const * +quote (char const *name) +{ + return quote_n (0, name); +} diff --git a/lib/strchrnul.h b/lib/quote.h index f7589e990b141..5400eadb65730 100644 --- a/lib/strchrnul.h +++ b/lib/quote.h @@ -1,5 +1,7 @@ -/* Searching in a string. - Copyright (C) 2003 Free Software Foundation, Inc. +/* quote.h - prototypes for quote.c + + Copyright (C) 1998, 1999, 2000, 2001, 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 @@ -13,16 +15,8 @@ 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_STRCHRNUL - -/* Get strchrnul() declaration. */ -#include <string.h> - -#else + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -/* Find the first occurrence of C in S or the final NUL byte. */ -extern char *strchrnul (const char *s, int c_in); -#endif +char const *quote_n (int n, char const *name); +char const *quote (char const *name); diff --git a/lib/quotearg.c b/lib/quotearg.c new file mode 100644 index 0000000000000..f7f326ac50174 --- /dev/null +++ b/lib/quotearg.c @@ -0,0 +1,697 @@ +/* quotearg.c - quote arguments for output + + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Paul Eggert <eggert@twinsun.com> */ + +#include <config.h> + +#include "quotearg.h" + +#include "xalloc.h" + +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <wchar.h> +#include <wctype.h> + +#include "gettext.h" +#define _(msgid) gettext (msgid) +#define N_(msgid) msgid + +#if !HAVE_MBRTOWC +/* Disable multibyte processing entirely. Since MB_CUR_MAX is 1, the + other macros are defined only for documentation and to satisfy C + syntax. */ +# undef MB_CUR_MAX +# define MB_CUR_MAX 1 +# undef mbstate_t +# define mbstate_t int +# define mbrtowc(pwc, s, n, ps) ((*(pwc) = *(s)) != 0) +# define iswprint(wc) isprint ((unsigned char) (wc)) +# undef HAVE_MBSINIT +#endif + +#if !defined mbsinit && !HAVE_MBSINIT +# define mbsinit(ps) 1 +#endif + +#ifndef SIZE_MAX +# define SIZE_MAX ((size_t) -1) +#endif + +#define INT_BITS (sizeof (int) * CHAR_BIT) + +struct quoting_options +{ + /* Basic quoting style. */ + enum quoting_style style; + + /* Quote the characters indicated by this bit vector even if the + quoting style would not normally require them to be quoted. */ + unsigned int quote_these_too[(UCHAR_MAX / INT_BITS) + 1]; +}; + +/* Names of quoting styles. */ +char const *const quoting_style_args[] = +{ + "literal", + "shell", + "shell-always", + "c", + "escape", + "locale", + "clocale", + 0 +}; + +/* Correspondences to quoting style names. */ +enum quoting_style const quoting_style_vals[] = +{ + literal_quoting_style, + shell_quoting_style, + shell_always_quoting_style, + c_quoting_style, + escape_quoting_style, + locale_quoting_style, + clocale_quoting_style +}; + +/* The default quoting options. */ +static struct quoting_options default_quoting_options; + +/* Allocate a new set of quoting options, with contents initially identical + to O if O is not null, or to the default if O is null. + It is the caller's responsibility to free the result. */ +struct quoting_options * +clone_quoting_options (struct quoting_options *o) +{ + int e = errno; + struct quoting_options *p = xmemdup (o ? o : &default_quoting_options, + sizeof *o); + errno = e; + return p; +} + +/* Get the value of O's quoting style. If O is null, use the default. */ +enum quoting_style +get_quoting_style (struct quoting_options *o) +{ + return (o ? o : &default_quoting_options)->style; +} + +/* In O (or in the default if O is null), + set the value of the quoting style to S. */ +void +set_quoting_style (struct quoting_options *o, enum quoting_style s) +{ + (o ? o : &default_quoting_options)->style = s; +} + +/* In O (or in the default if O is null), + set the value of the quoting options for character C to I. + Return the old value. Currently, the only values defined for I are + 0 (the default) and 1 (which means to quote the character even if + it would not otherwise be quoted). */ +int +set_char_quoting (struct quoting_options *o, char c, int i) +{ + unsigned char uc = c; + unsigned int *p = + (o ? o : &default_quoting_options)->quote_these_too + uc / INT_BITS; + int shift = uc % INT_BITS; + int r = (*p >> shift) & 1; + *p ^= ((i & 1) ^ r) << shift; + return r; +} + +/* MSGID approximates a quotation mark. Return its translation if it + has one; otherwise, return either it or "\"", depending on S. */ +static char const * +gettext_quote (char const *msgid, enum quoting_style s) +{ + char const *translation = _(msgid); + if (translation == msgid && s == clocale_quoting_style) + translation = "\""; + return translation; +} + +/* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of + argument ARG (of size ARGSIZE), using QUOTING_STYLE and the + non-quoting-style part of O to control quoting. + Terminate the output with a null character, and return the written + size of the output, not counting the terminating null. + If BUFFERSIZE is too small to store the output string, return the + value that would have been returned had BUFFERSIZE been large enough. + If ARGSIZE is SIZE_MAX, use the string length of the argument for ARGSIZE. + + This function acts like quotearg_buffer (BUFFER, BUFFERSIZE, ARG, + ARGSIZE, O), except it uses QUOTING_STYLE instead of the quoting + style specified by O, and O may not be null. */ + +static size_t +quotearg_buffer_restyled (char *buffer, size_t buffersize, + char const *arg, size_t argsize, + enum quoting_style quoting_style, + struct quoting_options const *o) +{ + size_t i; + size_t len = 0; + char const *quote_string = 0; + size_t quote_string_len = 0; + bool backslash_escapes = false; + bool unibyte_locale = MB_CUR_MAX == 1; + +#define STORE(c) \ + do \ + { \ + if (len < buffersize) \ + buffer[len] = (c); \ + len++; \ + } \ + while (0) + + switch (quoting_style) + { + case c_quoting_style: + STORE ('"'); + backslash_escapes = true; + quote_string = "\""; + quote_string_len = 1; + break; + + case escape_quoting_style: + backslash_escapes = true; + break; + + case locale_quoting_style: + case clocale_quoting_style: + { + /* TRANSLATORS: + Get translations for open and closing quotation marks. + + The message catalog should translate "`" to a left + quotation mark suitable for the locale, and similarly for + "'". If the catalog has no translation, + locale_quoting_style quotes `like this', and + clocale_quoting_style quotes "like this". + + For example, an American English Unicode locale should + translate "`" to U+201C (LEFT DOUBLE QUOTATION MARK), and + should translate "'" to U+201D (RIGHT DOUBLE QUOTATION + MARK). A British English Unicode locale should instead + translate these to U+2018 (LEFT SINGLE QUOTATION MARK) and + U+2019 (RIGHT SINGLE QUOTATION MARK), respectively. + + If you don't know what to put here, please see + <http://en.wikipedia.org/wiki/Quotation_mark#Glyphs> + and use glyphs suitable for your language. */ + + char const *left = gettext_quote (N_("`"), quoting_style); + char const *right = gettext_quote (N_("'"), quoting_style); + for (quote_string = left; *quote_string; quote_string++) + STORE (*quote_string); + backslash_escapes = true; + quote_string = right; + quote_string_len = strlen (quote_string); + } + break; + + case shell_always_quoting_style: + STORE ('\''); + quote_string = "'"; + quote_string_len = 1; + break; + + default: + break; + } + + for (i = 0; ! (argsize == SIZE_MAX ? arg[i] == '\0' : i == argsize); i++) + { + unsigned char c; + unsigned char esc; + + if (backslash_escapes + && quote_string_len + && i + quote_string_len <= argsize + && memcmp (arg + i, quote_string, quote_string_len) == 0) + STORE ('\\'); + + c = arg[i]; + switch (c) + { + case '\0': + if (backslash_escapes) + { + STORE ('\\'); + STORE ('0'); + STORE ('0'); + c = '0'; + } + break; + + case '?': + switch (quoting_style) + { + case shell_quoting_style: + goto use_shell_always_quoting_style; + + case c_quoting_style: + if (i + 2 < argsize && arg[i + 1] == '?') + switch (arg[i + 2]) + { + case '!': case '\'': + case '(': case ')': case '-': case '/': + case '<': case '=': case '>': + /* Escape the second '?' in what would otherwise be + a trigraph. */ + c = arg[i + 2]; + i += 2; + STORE ('?'); + STORE ('\\'); + STORE ('?'); + break; + + default: + break; + } + break; + + default: + break; + } + break; + + case '\a': esc = 'a'; goto c_escape; + case '\b': esc = 'b'; goto c_escape; + case '\f': esc = 'f'; goto c_escape; + case '\n': esc = 'n'; goto c_and_shell_escape; + case '\r': esc = 'r'; goto c_and_shell_escape; + case '\t': esc = 't'; goto c_and_shell_escape; + case '\v': esc = 'v'; goto c_escape; + case '\\': esc = c; goto c_and_shell_escape; + + c_and_shell_escape: + if (quoting_style == shell_quoting_style) + goto use_shell_always_quoting_style; + c_escape: + if (backslash_escapes) + { + c = esc; + goto store_escape; + } + break; + + case '{': case '}': /* sometimes special if isolated */ + if (! (argsize == SIZE_MAX ? arg[1] == '\0' : argsize == 1)) + break; + /* Fall through. */ + case '#': case '~': + if (i != 0) + break; + /* Fall through. */ + case ' ': + case '!': /* special in bash */ + case '"': case '$': case '&': + case '(': case ')': case '*': case ';': + case '<': + case '=': /* sometimes special in 0th or (with "set -k") later args */ + case '>': case '[': + case '^': /* special in old /bin/sh, e.g. SunOS 4.1.4 */ + case '`': case '|': + /* A shell special character. In theory, '$' and '`' could + be the first bytes of multibyte characters, which means + we should check them with mbrtowc, but in practice this + doesn't happen so it's not worth worrying about. */ + if (quoting_style == shell_quoting_style) + goto use_shell_always_quoting_style; + break; + + case '\'': + switch (quoting_style) + { + case shell_quoting_style: + goto use_shell_always_quoting_style; + + case shell_always_quoting_style: + STORE ('\''); + STORE ('\\'); + STORE ('\''); + break; + + default: + break; + } + 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': case ':': + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': + case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': + case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': + case 'Y': case 'Z': case ']': case '_': case 'a': case 'b': + case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': + case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': + case 'o': case 'p': case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': + /* These characters don't cause problems, no matter what the + quoting style is. They cannot start multibyte sequences. */ + break; + + default: + /* If we have a multibyte sequence, copy it until we reach + its end, find an error, or come back to the initial shift + state. For C-like styles, if the sequence has + unprintable characters, escape the whole sequence, since + we can't easily escape single characters within it. */ + { + /* Length of multibyte sequence found so far. */ + size_t m; + + bool printable; + + if (unibyte_locale) + { + m = 1; + printable = isprint (c) != 0; + } + else + { + mbstate_t mbstate; + memset (&mbstate, 0, sizeof mbstate); + + m = 0; + printable = true; + if (argsize == SIZE_MAX) + argsize = strlen (arg); + + do + { + wchar_t w; + size_t bytes = mbrtowc (&w, &arg[i + m], + argsize - (i + m), &mbstate); + if (bytes == 0) + break; + else if (bytes == (size_t) -1) + { + printable = false; + break; + } + else if (bytes == (size_t) -2) + { + printable = false; + while (i + m < argsize && arg[i + m]) + m++; + break; + } + else + { + /* Work around a bug with older shells that "see" a '\' + that is really the 2nd byte of a multibyte character. + In practice the problem is limited to ASCII + chars >= '@' that are shell special chars. */ + if ('[' == 0x5b && quoting_style == shell_quoting_style) + { + size_t j; + for (j = 1; j < bytes; j++) + switch (arg[i + m + j]) + { + case '[': case '\\': case '^': + case '`': case '|': + goto use_shell_always_quoting_style; + + default: + break; + } + } + + if (! iswprint (w)) + printable = false; + m += bytes; + } + } + while (! mbsinit (&mbstate)); + } + + if (1 < m || (backslash_escapes && ! printable)) + { + /* Output a multibyte sequence, or an escaped + unprintable unibyte character. */ + size_t ilim = i + m; + + for (;;) + { + if (backslash_escapes && ! printable) + { + STORE ('\\'); + STORE ('0' + (c >> 6)); + STORE ('0' + ((c >> 3) & 7)); + c = '0' + (c & 7); + } + if (ilim <= i + 1) + break; + STORE (c); + c = arg[++i]; + } + + goto store_c; + } + } + } + + if (! (backslash_escapes + && o->quote_these_too[c / INT_BITS] & (1 << (c % INT_BITS)))) + goto store_c; + + store_escape: + STORE ('\\'); + + store_c: + STORE (c); + } + + if (i == 0 && quoting_style == shell_quoting_style) + goto use_shell_always_quoting_style; + + if (quote_string) + for (; *quote_string; quote_string++) + STORE (*quote_string); + + if (len < buffersize) + buffer[len] = '\0'; + return len; + + use_shell_always_quoting_style: + return quotearg_buffer_restyled (buffer, buffersize, arg, argsize, + shell_always_quoting_style, o); +} + +/* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of + argument ARG (of size ARGSIZE), using O to control quoting. + If O is null, use the default. + Terminate the output with a null character, and return the written + size of the output, not counting the terminating null. + If BUFFERSIZE is too small to store the output string, return the + value that would have been returned had BUFFERSIZE been large enough. + If ARGSIZE is SIZE_MAX, use the string length of the argument for + ARGSIZE. */ +size_t +quotearg_buffer (char *buffer, size_t buffersize, + char const *arg, size_t argsize, + struct quoting_options const *o) +{ + struct quoting_options const *p = o ? o : &default_quoting_options; + int e = errno; + size_t r = quotearg_buffer_restyled (buffer, buffersize, arg, argsize, + p->style, p); + errno = e; + return r; +} + +/* Like quotearg_buffer (..., ARG, ARGSIZE, O), except return newly + allocated storage containing the quoted string. */ +char * +quotearg_alloc (char const *arg, size_t argsize, + struct quoting_options const *o) +{ + int e = errno; + size_t bufsize = quotearg_buffer (0, 0, arg, argsize, o) + 1; + char *buf = xcharalloc (bufsize); + quotearg_buffer (buf, bufsize, arg, argsize, o); + errno = e; + return buf; +} + +/* A storage slot with size and pointer to a value. */ +struct slotvec +{ + size_t size; + char *val; +}; + +/* Preallocate a slot 0 buffer, so that the caller can always quote + one small component of a "memory exhausted" message in slot 0. */ +static char slot0[256]; +static unsigned int nslots = 1; +static struct slotvec slotvec0 = {sizeof slot0, slot0}; +static struct slotvec *slotvec = &slotvec0; + +void +quotearg_free (void) +{ + struct slotvec *sv = slotvec; + unsigned int i; + for (i = 1; i < nslots; i++) + free (sv[i].val); + if (sv[0].val != slot0) + { + free (sv[0].val); + slotvec0.size = sizeof slot0; + slotvec0.val = slot0; + } + if (sv != &slotvec0) + { + free (sv); + slotvec = &slotvec0; + } + nslots = 1; +} + +/* Use storage slot N to return a quoted version of argument ARG. + ARG is of size ARGSIZE, but if that is SIZE_MAX, ARG is a + null-terminated string. + OPTIONS specifies the quoting options. + The returned value points to static storage that can be + reused by the next call to this function with the same value of N. + N must be nonnegative. N is deliberately declared with type "int" + to allow for future extensions (using negative values). */ +static char * +quotearg_n_options (int n, char const *arg, size_t argsize, + struct quoting_options const *options) +{ + int e = errno; + + unsigned int n0 = n; + struct slotvec *sv = slotvec; + + if (n < 0) + abort (); + + if (nslots <= n0) + { + /* FIXME: technically, the type of n1 should be `unsigned int', + but that evokes an unsuppressible warning from gcc-4.0.1 and + older. If gcc ever provides an option to suppress that warning, + revert to the original type, so that the test in xalloc_oversized + is once again performed only at compile time. */ + size_t n1 = n0 + 1; + bool preallocated = (sv == &slotvec0); + + if (xalloc_oversized (n1, sizeof *sv)) + xalloc_die (); + + slotvec = sv = xrealloc (preallocated ? NULL : sv, n1 * sizeof *sv); + if (preallocated) + *sv = slotvec0; + memset (sv + nslots, 0, (n1 - nslots) * sizeof *sv); + nslots = n1; + } + + { + size_t size = sv[n].size; + char *val = sv[n].val; + size_t qsize = quotearg_buffer (val, size, arg, argsize, options); + + if (size <= qsize) + { + sv[n].size = size = qsize + 1; + if (val != slot0) + free (val); + sv[n].val = val = xcharalloc (size); + quotearg_buffer (val, size, arg, argsize, options); + } + + errno = e; + return val; + } +} + +char * +quotearg_n (int n, char const *arg) +{ + return quotearg_n_options (n, arg, SIZE_MAX, &default_quoting_options); +} + +char * +quotearg (char const *arg) +{ + return quotearg_n (0, arg); +} + +/* Return quoting options for STYLE, with no extra quoting. */ +static struct quoting_options +quoting_options_from_style (enum quoting_style style) +{ + struct quoting_options o; + o.style = style; + memset (o.quote_these_too, 0, sizeof o.quote_these_too); + return o; +} + +char * +quotearg_n_style (int n, enum quoting_style s, char const *arg) +{ + struct quoting_options const o = quoting_options_from_style (s); + return quotearg_n_options (n, arg, SIZE_MAX, &o); +} + +char * +quotearg_n_style_mem (int n, enum quoting_style s, + char const *arg, size_t argsize) +{ + struct quoting_options const o = quoting_options_from_style (s); + return quotearg_n_options (n, arg, argsize, &o); +} + +char * +quotearg_style (enum quoting_style s, char const *arg) +{ + return quotearg_n_style (0, s, arg); +} + +char * +quotearg_char (char const *arg, char ch) +{ + struct quoting_options options; + options = default_quoting_options; + set_char_quoting (&options, ch, 1); + return quotearg_n_options (0, arg, SIZE_MAX, &options); +} + +char * +quotearg_colon (char const *arg) +{ + return quotearg_char (arg, ':'); +} diff --git a/lib/quotearg.h b/lib/quotearg.h new file mode 100644 index 0000000000000..4887df3b6d5d9 --- /dev/null +++ b/lib/quotearg.h @@ -0,0 +1,140 @@ +/* quotearg.h - quote arguments for output + + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Paul Eggert <eggert@twinsun.com> */ + +#ifndef QUOTEARG_H_ +# define QUOTEARG_H_ 1 + +# include <stddef.h> + +/* Basic quoting styles. */ +enum quoting_style + { + /* Output names as-is (ls --quoting-style=literal). */ + literal_quoting_style, + + /* Quote names for the shell if they contain shell metacharacters + or would cause ambiguous output (ls --quoting-style=shell). */ + shell_quoting_style, + + /* Quote names for the shell, even if they would normally not + require quoting (ls --quoting-style=shell-always). */ + shell_always_quoting_style, + + /* Quote names as for a C language string (ls --quoting-style=c). */ + c_quoting_style, + + /* Like c_quoting_style except omit the surrounding double-quote + characters (ls --quoting-style=escape). */ + escape_quoting_style, + + /* Like clocale_quoting_style, but quote `like this' instead of + "like this" in the default C locale (ls --quoting-style=locale). */ + locale_quoting_style, + + /* Like c_quoting_style except use quotation marks appropriate for + the locale (ls --quoting-style=clocale). */ + clocale_quoting_style + }; + +/* For now, --quoting-style=literal is the default, but this may change. */ +# ifndef DEFAULT_QUOTING_STYLE +# define DEFAULT_QUOTING_STYLE literal_quoting_style +# endif + +/* Names of quoting styles and their corresponding values. */ +extern char const *const quoting_style_args[]; +extern enum quoting_style const quoting_style_vals[]; + +struct quoting_options; + +/* The functions listed below set and use a hidden variable + that contains the default quoting style options. */ + +/* Allocate a new set of quoting options, with contents initially identical + to O if O is not null, or to the default if O is null. + It is the caller's responsibility to free the result. */ +struct quoting_options *clone_quoting_options (struct quoting_options *o); + +/* Get the value of O's quoting style. If O is null, use the default. */ +enum quoting_style get_quoting_style (struct quoting_options *o); + +/* In O (or in the default if O is null), + set the value of the quoting style to S. */ +void set_quoting_style (struct quoting_options *o, enum quoting_style s); + +/* In O (or in the default if O is null), + set the value of the quoting options for character C to I. + Return the old value. Currently, the only values defined for I are + 0 (the default) and 1 (which means to quote the character even if + it would not otherwise be quoted). */ +int set_char_quoting (struct quoting_options *o, char c, int i); + +/* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of + argument ARG (of size ARGSIZE), using O to control quoting. + If O is null, use the default. + Terminate the output with a null character, and return the written + size of the output, not counting the terminating null. + If BUFFERSIZE is too small to store the output string, return the + value that would have been returned had BUFFERSIZE been large enough. + If ARGSIZE is -1, use the string length of the argument for ARGSIZE. */ +size_t quotearg_buffer (char *buffer, size_t buffersize, + char const *arg, size_t argsize, + struct quoting_options const *o); + +/* Like quotearg_buffer, except return the result in a newly allocated + buffer. It is the caller's responsibility to free the result. */ +char *quotearg_alloc (char const *arg, size_t argsize, + struct quoting_options const *o); + +/* Use storage slot N to return a quoted version of the string ARG. + Use the default quoting options. + The returned value points to static storage that can be + reused by the next call to this function with the same value of N. + N must be nonnegative. */ +char *quotearg_n (int n, char const *arg); + +/* Equivalent to quotearg_n (0, ARG). */ +char *quotearg (char const *arg); + +/* Use style S and storage slot N to return a quoted version of the string ARG. + This is like quotearg_n (N, ARG), except that it uses S with no other + options to specify the quoting method. */ +char *quotearg_n_style (int n, enum quoting_style s, char const *arg); + +/* Use style S and storage slot N to return a quoted version of the + argument ARG of size ARGSIZE. This is like quotearg_n_style + (N, S, ARG), except it can quote null bytes. */ +char *quotearg_n_style_mem (int n, enum quoting_style s, + char const *arg, size_t argsize); + +/* Equivalent to quotearg_n_style (0, S, ARG). */ +char *quotearg_style (enum quoting_style s, char const *arg); + +/* Like quotearg (ARG), except also quote any instances of CH. */ +char *quotearg_char (char const *arg, char ch); + +/* Equivalent to quotearg_char (ARG, ':'). */ +char *quotearg_colon (char const *arg); + +/* Free any dynamically allocated memory. */ +void quotearg_free (void); + +#endif /* !QUOTEARG_H_ */ diff --git a/lib/localedir.h b/lib/rmt-command.h index 7460e6fc96278..7460e6fc96278 100644 --- a/lib/localedir.h +++ b/lib/rmt-command.h diff --git a/lib/rmt.h b/lib/rmt.h index 1fd2f29f9af4b..9f96cdb9b5f08 100644 --- a/lib/rmt.h +++ b/lib/rmt.h @@ -15,7 +15,7 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ extern char *rmt_command; extern char *rmt_dev_name__; diff --git a/lib/rtapelib.c b/lib/rtapelib.c index 0e499b638ca75..af19b04c5d43c 100644 --- a/lib/rtapelib.c +++ b/lib/rtapelib.c @@ -1,7 +1,7 @@ /* Functions for communicating with a remote tape drive. - Copyright 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2001, 2004 Free - Software Foundation, Inc. + Copyright (C) 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2001, 2004, + 2005, 2006 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 @@ -15,7 +15,7 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* The man page rmt(8) for /etc/rmt documents the remote mag tape protocol which rdump and rrestore use. Unfortunately, the man page is *WRONG*. @@ -33,6 +33,8 @@ code, courtesy of Dan Kegel. */ #include "system.h" +#include "system-ioctl.h" + #include <safe-read.h> #include <full-write.h> @@ -58,7 +60,7 @@ #endif #include <rmt.h> -#include <localedir.h> +#include <rmt-command.h> /* Exit status if exec errors. */ #define EXIT_ON_EXEC_ERROR 128 @@ -340,9 +342,7 @@ encode_oflag (char *buf, int oflag) #ifdef O_NOCTTY if (oflag & O_NOCTTY) strcat (buf, "|O_NOCTTY"); #endif -#ifdef O_NONBLOCK if (oflag & O_NONBLOCK) strcat (buf, "|O_NONBLOCK"); -#endif #ifdef O_RSYNC if (oflag & O_RSYNC) strcat (buf, "|O_RSYNC"); #endif @@ -358,7 +358,7 @@ encode_oflag (char *buf, int oflag) remote pipe number plus BIAS. REMOTE_SHELL may be overridden. On error, return -1. */ int -rmt_open__ (const char *file_name, int open_mode, int bias, +rmt_open__ (const char *file_name, int open_mode, int bias, const char *remote_shell) { int remote_pipe_number; /* pseudo, biased file descriptor */ diff --git a/lib/safe-read.c b/lib/safe-read.c index 6f8bd780ed01a..b7bf1d5cd60ef 100644 --- a/lib/safe-read.c +++ b/lib/safe-read.c @@ -1,7 +1,7 @@ /* An interface to read and write that retries after interrupts. - Copyright (C) 1993, 1994, 1998, 2002, 2003, 2004 Free Software - Foundation, Inc. + Copyright (C) 1993, 1994, 1998, 2002, 2003, 2004, 2005, 2006 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 @@ -15,11 +15,9 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#if HAVE_CONFIG_H -# include <config.h> -#endif +#include <config.h> /* Specification. */ #ifdef SAFE_WRITE @@ -30,9 +28,7 @@ /* Get ssize_t. */ #include <sys/types.h> -#if HAVE_UNISTD_H -# include <unistd.h> -#endif +#include <unistd.h> #include <errno.h> diff --git a/lib/safe-read.h b/lib/safe-read.h index cbe6e0bfd60cf..3451955ad4ff4 100644 --- a/lib/safe-read.h +++ b/lib/safe-read.h @@ -1,5 +1,5 @@ /* An interface to read() that retries after interrupts. - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2006 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 @@ -13,13 +13,23 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <stddef.h> +#ifdef __cplusplus +extern "C" { +#endif + + #define SAFE_READ_ERROR ((size_t) -1) /* Read up to COUNT bytes at BUF from descriptor FD, retrying if interrupted. Return the actual number of bytes read, zero for EOF, or SAFE_READ_ERROR upon error. */ extern size_t safe_read (int fd, void *buf, size_t count); + + +#ifdef __cplusplus +} +#endif diff --git a/lib/safe-write.c b/lib/safe-write.c index fbafa7cc6776b..4c375a6ca1905 100644 --- a/lib/safe-write.c +++ b/lib/safe-write.c @@ -13,7 +13,7 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #define SAFE_WRITE #include "safe-read.c" diff --git a/lib/safe-write.h b/lib/safe-write.h index ab1f45b4ab2b3..c194636209f7a 100644 --- a/lib/safe-write.h +++ b/lib/safe-write.h @@ -13,7 +13,7 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <stddef.h> diff --git a/lib/savedir.c b/lib/savedir.c index c92e62eadccdf..d930fb4af273a 100644 --- a/lib/savedir.c +++ b/lib/savedir.c @@ -1,7 +1,7 @@ /* savedir.c -- save the list of files in a directory in a string - Copyright 1990, 1997, 1998, 1999, 2000, 2001, 2003, 2004 Free - Software Foundation, Inc. + Copyright (C) 1990, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, + 2006 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 @@ -15,13 +15,11 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */ -#if HAVE_CONFIG_H -# include <config.h> -#endif +#include <config.h> #include "savedir.h" @@ -29,68 +27,62 @@ #include <errno.h> -#if HAVE_DIRENT_H -# include <dirent.h> -#else -# define dirent direct -# if HAVE_SYS_NDIR_H -# include <sys/ndir.h> -# endif -# if HAVE_SYS_DIR_H -# include <sys/dir.h> -# endif -# if HAVE_NDIR_H -# include <ndir.h> -# endif -#endif - -#ifdef CLOSEDIR_VOID -/* Fake a return value. */ -# define CLOSEDIR(d) (closedir (d), 0) -#else -# define CLOSEDIR(d) closedir (d) +#include <dirent.h> +#ifndef _D_EXACT_NAMLEN +# define _D_EXACT_NAMLEN(dp) strlen ((dp)->d_name) #endif #include <stddef.h> #include <stdlib.h> #include <string.h> +#include "openat.h" #include "xalloc.h" -/* Return a freshly allocated string containing the filenames - in directory DIR, separated by '\0' characters; - the end is marked by two '\0' characters in a row. - Return NULL (setting errno) if DIR cannot be opened, read, or closed. */ - #ifndef NAME_SIZE_DEFAULT # define NAME_SIZE_DEFAULT 512 #endif -char * -savedir (const char *dir) +/* The results of opendir() in this file are not used with dirfd and fchdir, + therefore save some unnecessary work in fchdir.c. */ +#undef opendir +#undef closedir + +/* Return a freshly allocated string containing the file names + in directory DIRP, separated by '\0' characters; + the end is marked by two '\0' characters in a row. + Return NULL (setting errno) if DIRP cannot be read or closed. + If DIRP is NULL, return NULL without affecting errno. */ + +static char * +savedirstream (DIR *dirp) { - DIR *dirp; - struct dirent *dp; char *name_space; size_t allocated = NAME_SIZE_DEFAULT; size_t used = 0; int save_errno; - dirp = opendir (dir); if (dirp == NULL) return NULL; name_space = xmalloc (allocated); - errno = 0; - while ((dp = readdir (dirp)) != NULL) + for (;;) { + struct dirent const *dp; + char const *entry; + + errno = 0; + dp = readdir (dirp); + if (! dp) + break; + /* Skip "", ".", and "..". "" is returned by at least one buggy implementation: Solaris 2.4 readdir on NFS file systems. */ - char const *entry = dp->d_name; + entry = dp->d_name; if (entry[entry[0] != '.' ? 0 : entry[1] != '.' ? 1 : 2] != '\0') { - size_t entry_size = strlen (entry) + 1; + size_t entry_size = _D_EXACT_NAMLEN (dp) + 1; if (used + entry_size < used) xalloc_die (); if (allocated <= used + entry_size) @@ -111,7 +103,7 @@ savedir (const char *dir) } name_space[used] = '\0'; save_errno = errno; - if (CLOSEDIR (dirp) != 0) + if (closedir (dirp) != 0) save_errno = errno; if (save_errno != 0) { @@ -121,3 +113,25 @@ savedir (const char *dir) } return name_space; } + +/* Return a freshly allocated string containing the file names + in directory DIR, separated by '\0' characters; + the end is marked by two '\0' characters in a row. + Return NULL (setting errno) if DIR cannot be opened, read, or closed. */ + +char * +savedir (char const *dir) +{ + return savedirstream (opendir (dir)); +} + +/* Return a freshly allocated string containing the file names + in directory FD, separated by '\0' characters; + the end is marked by two '\0' characters in a row. + Return NULL (setting errno) if FD cannot be read or closed. */ + +char * +fdsavedir (int fd) +{ + return savedirstream (fdopendir (fd)); +} diff --git a/lib/savedir.h b/lib/savedir.h index bd330852149ba..5b7bef97134e3 100644 --- a/lib/savedir.h +++ b/lib/savedir.h @@ -1,6 +1,6 @@ /* Save the list of files in a directory in a string. - Copyright 1997, 1999, 2001, 2003 Free Software Foundation, Inc. + Copyright (C) 1997, 1999, 2001, 2003, 2005 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 @@ -14,13 +14,14 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */ #if !defined SAVEDIR_H_ # define SAVEDIR_H_ -char *savedir (const char *dir); +char *savedir (char const *dir); +char *fdsavedir (int fd); #endif diff --git a/lib/strcase.h b/lib/strcase.h deleted file mode 100644 index 9461392f8d6ad..0000000000000 --- a/lib/strcase.h +++ /dev/null @@ -1,47 +0,0 @@ -/* Case-insensitive string comparison functions. - Copyright (C) 1995-1996, 2001, 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 - 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 _STRCASE_H -#define _STRCASE_H - -#include <stddef.h> - - -#ifdef __cplusplus -extern "C" { -#endif - - -/* Compare strings S1 and S2, ignoring case, returning less than, equal to or - greater than zero if S1 is lexicographically less than, equal to or greater - than S2. - Note: This function does not work correctly in multibyte locales. */ -extern int strcasecmp (const char *s1, const char *s2); - -/* Compare no more than N characters of strings S1 and S2, ignoring case, - returning less than, equal to or greater than zero if S1 is - lexicographically less than, equal to or greater than S2. - Note: This function can not work correctly in multibyte locales. */ -extern int strncasecmp (const char *s1, const char *s2, size_t n); - - -#ifdef __cplusplus -} -#endif - - -#endif /* _STRCASE_H */ diff --git a/lib/strchrnul.c b/lib/strchrnul.c index be85312c4611b..07014be17afb1 100644 --- a/lib/strchrnul.c +++ b/lib/strchrnul.c @@ -1,5 +1,5 @@ /* Searching in a string. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2007 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 @@ -13,10 +13,12 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <config.h> /* Specification. */ -#include "strchrnul.h" +#include <string.h> /* Find the first occurrence of C in S or the final NUL byte. */ char * diff --git a/lib/stripslash.c b/lib/stripslash.c index 9998e641ced7a..342d497c89930 100644 --- a/lib/stripslash.c +++ b/lib/stripslash.c @@ -1,5 +1,6 @@ /* stripslash.c -- remove redundant trailing slashes from a file name - Copyright (C) 1990, 2001, 2003, 2004 Free Software Foundation, Inc. + + Copyright (C) 1990, 2001, 2003-2006 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 @@ -13,27 +14,32 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#if HAVE_CONFIG_H -# include <config.h> -#endif +#include <config.h> #include "dirname.h" -/* Remove trailing slashes from PATH. - Return true if a trailing slash was removed. - This is useful when using filename completion from a shell that - adds a "/" after directory names (such as tcsh and bash), because - the Unix rename and rmdir system calls return an "Invalid argument" error - when given a path that ends in "/" (except for the root directory). */ +/* Remove trailing slashes from FILE. Return true if a trailing slash + was removed. This is useful when using file name completion from a + shell that adds a "/" after directory names (such as tcsh and + bash), because on symlinks to directories, several system calls + have different semantics according to whether a trailing slash is + present. */ bool -strip_trailing_slashes (char *path) +strip_trailing_slashes (char *file) { - char *base = base_name (path); - char *base_lim = base + base_len (base); - bool had_slash = (*base_lim != '\0'); + char *base = last_component (file); + char *base_lim; + bool had_slash; + + /* last_component returns "" for file system roots, but we need to turn + `///' into `/'. */ + if (! *base) + base = file; + base_lim = base + base_len (base); + had_slash = (*base_lim != '\0'); *base_lim = '\0'; return had_slash; } diff --git a/lib/strndup.c b/lib/strndup.c index f85627e879d2f..3a1b0eae2e069 100644 --- a/lib/strndup.c +++ b/lib/strndup.c @@ -1,7 +1,7 @@ -/* Copyright (C) 1996, 1997, 1998, 2000, 2003 Free Software Foundation, Inc. +/* A replacement function, for systems that lack strndup. - NOTE: The canonical source of this file is maintained with the GNU C Library. - Bugs can be reported to bug-glibc@prep.ai.mit.edu. + Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2005, 2006, 2007 + 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 @@ -15,31 +15,16 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif +#include <config.h> -#include <stdlib.h> #include <string.h> -#ifndef HAVE_DECL_STRNLEN -"this configure-time declaration test was not run" -#endif -#if !HAVE_DECL_STRNLEN -size_t strnlen (); -#endif - -#undef __strndup -#undef strndup - -#ifndef weak_alias -# define __strndup strndup -#endif +#include <stdlib.h> char * -__strndup (const char *s, size_t n) +strndup (char const *s, size_t n) { size_t len = strnlen (s, n); char *new = malloc (len + 1); @@ -50,6 +35,3 @@ __strndup (const char *s, size_t n) new[len] = '\0'; return memcpy (new, s, len); } -#ifdef weak_alias -weak_alias (__strndup, strndup) -#endif diff --git a/lib/strnlen.c b/lib/strnlen.c index c9f389845117d..d346d3272c29d 100644 --- a/lib/strnlen.c +++ b/lib/strnlen.c @@ -1,6 +1,6 @@ /* Find the length of STRING, but scan at most MAXLEN characters. - Copyright (C) 1996, 1997, 1998, 2000-2003 Free Software Foundation, Inc. - This file is part of the GNU C Library. + Copyright (C) 2005, 2006, 2007 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 General Public License as published by @@ -12,37 +12,20 @@ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#if HAVE_CONFIG_H -# include <config.h> -#endif -#undef strnlen +#include <config.h> #include <string.h> -#undef __strnlen -#undef strnlen - -#ifndef _LIBC -# define strnlen rpl_strnlen -#endif - -#ifndef weak_alias -# define __strnlen strnlen -#endif - /* Find the length of STRING, but scan at most MAXLEN characters. If no '\0' terminator is found in that many characters, return MAXLEN. */ size_t -__strnlen (const char *string, size_t maxlen) +strnlen (const char *string, size_t maxlen) { const char *end = memchr (string, '\0', maxlen); return end ? (size_t) (end - string) : maxlen; } -#ifdef weak_alias -weak_alias (__strnlen, strnlen) -#endif diff --git a/lib/system-ioctl.h b/lib/system-ioctl.h new file mode 100644 index 0000000000000..a61c5fdfb01ca --- /dev/null +++ b/lib/system-ioctl.h @@ -0,0 +1,55 @@ +/* System dependent definitions for GNU tar's use of ioctl macros. + + Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003, + 2004, 2005, 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* This is a real challenge to properly get MTIO* symbols :-(. ISC uses + <sys/gentape.h>. SCO and BSDi uses <sys/tape.h>; BSDi also requires + <sys/tprintf.h> and <sys/device.h> for defining tp_dev and tpr_t. It + seems that the rest use <sys/mtio.h>, which itself requires other files, + depending on systems. Pyramid defines _IOW in <sgtty.h>, for example. */ + +#if HAVE_SYS_GENTAPE_H +# include <sys/gentape.h> +#else +# if HAVE_SYS_TAPE_H +# if HAVE_SYS_DEVICE_H +# include <sys/device.h> +# endif +# if HAVE_SYS_PARAM_H +# include <sys/param.h> +# endif +# if HAVE_SYS_BUF_H +# include <sys/buf.h> +# endif +# if HAVE_SYS_TPRINTF_H +# include <sys/tprintf.h> +# endif +# include <sys/tape.h> +# else +# if HAVE_SYS_MTIO_H +# include <sys/ioctl.h> +# if HAVE_SGTTY_H +# include <sgtty.h> +# endif +# if HAVE_SYS_IO_TRIOCTL_H +# include <sys/io/trioctl.h> +# endif +# include <sys/mtio.h> +# endif +# endif +#endif diff --git a/lib/system.h b/lib/system.h index 0914195132075..7602263f13931 100644 --- a/lib/system.h +++ b/lib/system.h @@ -1,7 +1,7 @@ /* System dependent definitions for GNU tar. Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003, - 2004 Free Software Foundation, Inc. + 2004, 2005, 2006 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 @@ -15,8 +15,7 @@ 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. -*/ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #if HAVE_CONFIG_H # include <config.h> @@ -109,10 +108,19 @@ extern int errno; #ifndef O_TRUNC # define O_TRUNC 32 /* truncate file on open */ #endif - /* MS-DOG forever, with my love! */ -#ifndef O_BINARY + +#ifndef O_BINARY # define O_BINARY 0 #endif +#ifndef O_DIRECTORY +# define O_DIRECTORY 0 +#endif +#ifndef O_NOATIME +# define O_NOATIME 0 +#endif +#ifndef O_NONBLOCK +# define O_NONBLOCK 0 +#endif /* Declare file status routines and bits. */ @@ -252,9 +260,7 @@ extern int errno; #define MODE_ALL (S_ISUID | S_ISGID | S_ISVTX | MODE_RWX) /* Include <unistd.h> before any preprocessor test of _POSIX_VERSION. */ -#if HAVE_UNISTD_H -# include <unistd.h> -#endif +#include <unistd.h> #ifndef SEEK_SET # define SEEK_SET 0 @@ -282,6 +288,9 @@ extern int errno; #if MAJOR_IN_MKDEV # include <sys/mkdev.h> +# if !defined(makedev) && defined(mkdev) +# define makedev(a,b) mkdev((a),(b)) +# endif # define GOT_MAJOR #endif @@ -377,45 +386,12 @@ extern int errno; #endif #ifndef ST_NBLOCKSIZE -#define ST_NBLOCKSIZE 512 +# define ST_NBLOCKSIZE 512 #endif -/* This is a real challenge to properly get MTIO* symbols :-(. ISC uses - <sys/gentape.h>. SCO and BSDi uses <sys/tape.h>; BSDi also requires - <sys/tprintf.h> and <sys/device.h> for defining tp_dev and tpr_t. It - seems that the rest use <sys/mtio.h>, which itself requires other files, - depending on systems. Pyramid defines _IOW in <sgtty.h>, for example. */ - -#if HAVE_SYS_GENTAPE_H -# include <sys/gentape.h> -#else -# if HAVE_SYS_TAPE_H -# if HAVE_SYS_DEVICE_H -# include <sys/device.h> -# endif -# if HAVE_SYS_PARAM_H -# include <sys/param.h> -# endif -# if HAVE_SYS_BUF_H -# include <sys/buf.h> -# endif -# if HAVE_SYS_TPRINTF_H -# include <sys/tprintf.h> -# endif -# include <sys/tape.h> -# else -# if HAVE_SYS_MTIO_H -# include <sys/ioctl.h> -# if HAVE_SGTTY_H -# include <sgtty.h> -# endif -# if HAVE_SYS_IO_TRIOCTL_H -# include <sys/io/trioctl.h> -# endif -# include <sys/mtio.h> -# endif -# endif -#endif +#define ST_IS_SPARSE(st) \ + (ST_NBLOCKS (st) \ + < ((st).st_size / ST_NBLOCKSIZE + ((st).st_size % ST_NBLOCKSIZE != 0))) /* Declare standard functions. */ @@ -435,7 +411,6 @@ char *getenv (); #endif #if WITH_DMALLOC -# undef HAVE_DECL_VALLOC # define DMALLOC_FUNC_CHECK # include <dmalloc.h> #endif @@ -446,28 +421,11 @@ char *getenv (); # define MB_LEN_MAX 1 #endif -#if HAVE_INTTYPES_H -# include <inttypes.h> -#endif - -/* These macros work even on ones'-complement hosts (!). - The extra casts work around common compiler bugs. */ -#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) -#define TYPE_MINIMUM(t) (TYPE_SIGNED (t) \ - ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) \ - : (t) 0) -#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t))) +#include <inttypes.h> -/* Bound on length of the string representing an integer value of type t. - Subtract one for the sign bit if t is signed; - 302 / 1000 is log10 (2) rounded up; - add one for integer division truncation; - add one more for a minus sign if t is signed. */ -#define INT_STRLEN_BOUND(t) \ - ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 \ - + 1 + TYPE_SIGNED (t)) +#include <intprops.h> -#define UINTMAX_STRSIZE_BOUND (INT_STRLEN_BOUND (uintmax_t) + 1) +#define UINTMAX_STRSIZE_BOUND INT_BUFSIZE_BOUND (uintmax_t) /* Prototypes for external functions. */ @@ -479,16 +437,9 @@ char *getenv (); #endif #include <time.h> -#if defined(HAVE_SYS_TIME_H) && defined(TIME_WITH_SYS_TIME) +#ifdef TIME_WITH_SYS_TIME # include <sys/time.h> #endif -#if ! HAVE_DECL_TIME -time_t time (); -#endif - -#ifdef HAVE_UTIME_H -# include <utime.h> -#endif /* Library modules. */ diff --git a/lib/umaxtostr.c b/lib/umaxtostr.c new file mode 100644 index 0000000000000..4f49a7f8ddd94 --- /dev/null +++ b/lib/umaxtostr.c @@ -0,0 +1,3 @@ +#define inttostr umaxtostr +#define inttype uintmax_t +#include "inttostr.c" diff --git a/lib/unlocked-io.h b/lib/unlocked-io.h index 3ff42f279b86e..d00930361c26c 100644 --- a/lib/unlocked-io.h +++ b/lib/unlocked-io.h @@ -14,12 +14,12 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Written by Jim Meyering. */ #ifndef UNLOCKED_IO_H -#define UNLOCKED_IO_H 1 +# define UNLOCKED_IO_H 1 /* These are wrappers for functions/macros from the GNU C library, and from other C libraries supporting POSIX's optional thread-safe functions. @@ -32,106 +32,106 @@ the *_unlocked functions directly. On hosts that lack those functions, invoke the non-thread-safe versions instead. */ -#include <stdio.h> - -#if HAVE_DECL_CLEARERR_UNLOCKED -# undef clearerr -# define clearerr(x) clearerr_unlocked (x) -#else -# define clearerr_unlocked(x) clearerr (x) -#endif - -#if HAVE_DECL_FEOF_UNLOCKED -# undef feof -# define feof(x) feof_unlocked (x) -#else -# define feof_unlocked(x) feof (x) -#endif - -#if HAVE_DECL_FERROR_UNLOCKED -# undef ferror -# define ferror(x) ferror_unlocked (x) -#else -# define ferror_unlocked(x) ferror (x) -#endif - -#if HAVE_DECL_FFLUSH_UNLOCKED -# undef fflush -# define fflush(x) fflush_unlocked (x) -#else -# define fflush_unlocked(x) fflush (x) -#endif - -#if HAVE_DECL_FGETS_UNLOCKED -# undef fgets -# define fgets(x,y,z) fgets_unlocked (x,y,z) -#else -# define fgets_unlocked(x,y,z) fgets (x,y,z) -#endif - -#if HAVE_DECL_FPUTC_UNLOCKED -# undef fputc -# define fputc(x,y) fputc_unlocked (x,y) -#else -# define fputc_unlocked(x,y) fputc (x,y) -#endif - -#if HAVE_DECL_FPUTS_UNLOCKED -# undef fputs -# define fputs(x,y) fputs_unlocked (x,y) -#else -# define fputs_unlocked(x,y) fputs (x,y) -#endif - -#if HAVE_DECL_FREAD_UNLOCKED -# undef fread -# define fread(w,x,y,z) fread_unlocked (w,x,y,z) -#else -# define fread_unlocked(w,x,y,z) fread (w,x,y,z) -#endif - -#if HAVE_DECL_FWRITE_UNLOCKED -# undef fwrite -# define fwrite(w,x,y,z) fwrite_unlocked (w,x,y,z) -#else -# define fwrite_unlocked(w,x,y,z) fwrite (w,x,y,z) -#endif - -#if HAVE_DECL_GETC_UNLOCKED -# undef getc -# define getc(x) getc_unlocked (x) -#else -# define getc_unlocked(x) getc (x) -#endif - -#if HAVE_DECL_GETCHAR_UNLOCKED -# undef getchar -# define getchar() getchar_unlocked () -#else -# define getchar_unlocked() getchar () -#endif - -#if HAVE_DECL_PUTC_UNLOCKED -# undef putc -# define putc(x,y) putc_unlocked (x,y) -#else -# define putc_unlocked(x,y) putc (x,y) -#endif - -#if HAVE_DECL_PUTCHAR_UNLOCKED -# undef putchar -# define putchar(x) putchar_unlocked (x) -#else -# define putchar_unlocked(x) putchar (x) -#endif - -#undef flockfile -#define flockfile(x) ((void) 0) - -#undef ftrylockfile -#define ftrylockfile(x) 0 - -#undef funlockfile -#define funlockfile(x) ((void) 0) +# include <stdio.h> + +# if HAVE_DECL_CLEARERR_UNLOCKED +# undef clearerr +# define clearerr(x) clearerr_unlocked (x) +# else +# define clearerr_unlocked(x) clearerr (x) +# endif + +# if HAVE_DECL_FEOF_UNLOCKED +# undef feof +# define feof(x) feof_unlocked (x) +# else +# define feof_unlocked(x) feof (x) +# endif + +# if HAVE_DECL_FERROR_UNLOCKED +# undef ferror +# define ferror(x) ferror_unlocked (x) +# else +# define ferror_unlocked(x) ferror (x) +# endif + +# if HAVE_DECL_FFLUSH_UNLOCKED +# undef fflush +# define fflush(x) fflush_unlocked (x) +# else +# define fflush_unlocked(x) fflush (x) +# endif + +# if HAVE_DECL_FGETS_UNLOCKED +# undef fgets +# define fgets(x,y,z) fgets_unlocked (x,y,z) +# else +# define fgets_unlocked(x,y,z) fgets (x,y,z) +# endif + +# if HAVE_DECL_FPUTC_UNLOCKED +# undef fputc +# define fputc(x,y) fputc_unlocked (x,y) +# else +# define fputc_unlocked(x,y) fputc (x,y) +# endif + +# if HAVE_DECL_FPUTS_UNLOCKED +# undef fputs +# define fputs(x,y) fputs_unlocked (x,y) +# else +# define fputs_unlocked(x,y) fputs (x,y) +# endif + +# if HAVE_DECL_FREAD_UNLOCKED +# undef fread +# define fread(w,x,y,z) fread_unlocked (w,x,y,z) +# else +# define fread_unlocked(w,x,y,z) fread (w,x,y,z) +# endif + +# if HAVE_DECL_FWRITE_UNLOCKED +# undef fwrite +# define fwrite(w,x,y,z) fwrite_unlocked (w,x,y,z) +# else +# define fwrite_unlocked(w,x,y,z) fwrite (w,x,y,z) +# endif + +# if HAVE_DECL_GETC_UNLOCKED +# undef getc +# define getc(x) getc_unlocked (x) +# else +# define getc_unlocked(x) getc (x) +# endif + +# if HAVE_DECL_GETCHAR_UNLOCKED +# undef getchar +# define getchar() getchar_unlocked () +# else +# define getchar_unlocked() getchar () +# endif + +# if HAVE_DECL_PUTC_UNLOCKED +# undef putc +# define putc(x,y) putc_unlocked (x,y) +# else +# define putc_unlocked(x,y) putc (x,y) +# endif + +# if HAVE_DECL_PUTCHAR_UNLOCKED +# undef putchar +# define putchar(x) putchar_unlocked (x) +# else +# define putchar_unlocked(x) putchar (x) +# endif + +# undef flockfile +# define flockfile(x) ((void) 0) + +# undef ftrylockfile +# define ftrylockfile(x) 0 + +# undef funlockfile +# define funlockfile(x) ((void) 0) #endif /* UNLOCKED_IO_H */ diff --git a/lib/utimens.c b/lib/utimens.c new file mode 100644 index 0000000000000..7e3175a495160 --- /dev/null +++ b/lib/utimens.c @@ -0,0 +1,189 @@ +/* Set file access and modification times. + + Copyright (C) 2003, 2004, 2005, 2006, 2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Paul Eggert. */ + +/* derived from a function in touch.c */ + +#include <config.h> + +#include "utimens.h" + +#include <errno.h> +#include <fcntl.h> +#include <sys/time.h> +#include <unistd.h> + +#if HAVE_UTIME_H +# include <utime.h> +#endif + +/* Some systems (even some that do have <utime.h>) don't declare this + structure anywhere. */ +#ifndef HAVE_STRUCT_UTIMBUF +struct utimbuf +{ + long actime; + long modtime; +}; +#endif + +/* 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 + +#ifndef __attribute__ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ +# define __attribute__(x) +# endif +#endif + +#ifndef ATTRIBUTE_UNUSED +# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#endif + +/* Set the access and modification time stamps of FD (a.k.a. FILE) to be + TIMESPEC[0] and TIMESPEC[1], respectively. + FD must be either negative -- in which case it is ignored -- + or a file descriptor that is open on FILE. + If FD is nonnegative, then FILE can be NULL, which means + use just futimes (or equivalent) instead of utimes (or equivalent), + and fail if on an old system without futimes (or equivalent). + If TIMESPEC is null, set the time stamps to the current time. + Return 0 on success, -1 (setting errno) on failure. */ + +int +gl_futimens (int fd ATTRIBUTE_UNUSED, + char const *file, struct timespec const timespec[2]) +{ + /* Some Linux-based NFS clients are buggy, and mishandle time stamps + of files in NFS file systems in some cases. We have no + configure-time test for this, but please see + <http://bugs.gentoo.org/show_bug.cgi?id=132673> for references to + some of the problems with Linux 2.6.16. If this affects you, + compile with -DHAVE_BUGGY_NFS_TIME_STAMPS; this is reported to + help in some cases, albeit at a cost in performance. But you + really should upgrade your kernel to a fixed version, since the + problem affects many applications. */ + +#if HAVE_BUGGY_NFS_TIME_STAMPS + if (fd < 0) + sync (); + else + fsync (fd); +#endif + + /* There's currently no interface to set file timestamps with + nanosecond resolution, so do the best we can, discarding any + fractional part of the timestamp. */ +#if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES + struct timeval timeval[2]; + struct timeval const *t; + if (timespec) + { + timeval[0].tv_sec = timespec[0].tv_sec; + timeval[0].tv_usec = timespec[0].tv_nsec / 1000; + timeval[1].tv_sec = timespec[1].tv_sec; + timeval[1].tv_usec = timespec[1].tv_nsec / 1000; + t = timeval; + } + else + t = NULL; + + + if (fd < 0) + { +# if HAVE_FUTIMESAT + return futimesat (AT_FDCWD, file, t); +# endif + } + else + { + /* If futimesat or futimes fails here, don't try to speed things + up by returning right away. glibc can incorrectly fail with + errno == ENOENT if /proc isn't mounted. Also, Mandrake 10.0 + in high security mode doesn't allow ordinary users to read + /proc/self, so glibc incorrectly fails with errno == EACCES. + If errno == EIO, EPERM, or EROFS, it's probably safe to fail + right away, but these cases are rare enough that they're not + worth optimizing, and who knows what other messed-up systems + are out there? So play it safe and fall back on the code + below. */ +# if HAVE_FUTIMESAT + if (futimesat (fd, NULL, t) == 0) + return 0; +# elif HAVE_FUTIMES + if (futimes (fd, t) == 0) + return 0; +# endif + } +#endif + + if (!file) + { +#if ! (HAVE_FUTIMESAT || (HAVE_WORKING_UTIMES && HAVE_FUTIMES)) + errno = ENOSYS; +#endif + + /* Prefer EBADF to ENOSYS if both error numbers apply. */ + if (errno == ENOSYS) + { + int fd2 = dup (fd); + int dup_errno = errno; + if (0 <= fd2) + close (fd2); + errno = (fd2 < 0 && dup_errno == EBADF ? EBADF : ENOSYS); + } + + return -1; + } + +#if HAVE_WORKING_UTIMES + return utimes (file, t); +#else + { + struct utimbuf utimbuf; + struct utimbuf const *ut; + if (timespec) + { + utimbuf.actime = timespec[0].tv_sec; + utimbuf.modtime = timespec[1].tv_sec; + ut = &utimbuf; + } + else + ut = NULL; + + return utime (file, ut); + } +#endif +} + +/* Set the access and modification time stamps of FILE to be + TIMESPEC[0] and TIMESPEC[1], respectively. */ +int +utimens (char const *file, struct timespec const timespec[2]) +{ + return gl_futimens (-1, file, timespec); +} diff --git a/lib/utimens.h b/lib/utimens.h new file mode 100644 index 0000000000000..169521da73ac3 --- /dev/null +++ b/lib/utimens.h @@ -0,0 +1,3 @@ +#include <time.h> +int gl_futimens (int, char const *, struct timespec const [2]); +int utimens (char const *, struct timespec const [2]); diff --git a/lib/xalloc-die.c b/lib/xalloc-die.c index ca3a689fa5c4d..090f060df7840 100644 --- a/lib/xalloc-die.c +++ b/lib/xalloc-die.c @@ -1,6 +1,6 @@ /* Report a memory allocation failure and exit. - Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2004 Free + Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2006 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify @@ -15,11 +15,9 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#if HAVE_CONFIG_H -# include <config.h> -#endif +#include <config.h> #include "xalloc.h" @@ -30,7 +28,6 @@ #include "gettext.h" #define _(msgid) gettext (msgid) -#define N_(msgid) msgid void xalloc_die (void) diff --git a/lib/xalloc.h b/lib/xalloc.h index 8d0fcf0faeeda..0c6d8dcf508df 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, 2004 Free Software Foundation, Inc. + 1999, 2000, 2003, 2004, 2006, 2007 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 @@ -15,7 +15,7 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef XALLOC_H_ # define XALLOC_H_ @@ -46,13 +46,10 @@ extern "C" { 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); @@ -71,8 +68,203 @@ char *xstrdup (char const *str); # define xalloc_oversized(n, s) \ ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n)) + +/* In the following macros, T must be an elementary or structure/union or + typedef'ed type, or a pointer to such a type. To apply one of the + following macros to a function pointer or array type, you need to typedef + it first and use the typedef name. */ + +/* Allocate an object of type T dynamically, with error checking. */ +/* extern t *XMALLOC (typename t); */ +# define XMALLOC(t) ((t *) xmalloc (sizeof (t))) + +/* Allocate memory for N elements of type T, with error checking. */ +/* extern t *XNMALLOC (size_t n, typename t); */ +# define XNMALLOC(n, t) \ + ((t *) (sizeof (t) == 1 ? xmalloc (n) : xnmalloc (n, sizeof (t)))) + +/* Allocate an object of type T dynamically, with error checking, + and zero it. */ +/* extern t *XZALLOC (typename t); */ +# define XZALLOC(t) ((t *) xzalloc (sizeof (t))) + +/* Allocate memory for N elements of type T, with error checking, + and zero it. */ +/* extern t *XCALLOC (size_t n, typename t); */ +# define XCALLOC(n, t) \ + ((t *) (sizeof (t) == 1 ? xzalloc (n) : xcalloc (n, sizeof (t)))) + + +# if HAVE_INLINE +# define static_inline static inline +# else + void *xnmalloc (size_t n, size_t s); + void *xnrealloc (void *p, size_t n, size_t s); + void *x2nrealloc (void *p, size_t *pn, size_t s); + char *xcharalloc (size_t n); +# endif + +# ifdef static_inline + +/* Allocate an array of N objects, each with S bytes of memory, + dynamically, with error checking. S must be nonzero. */ + +static_inline void * +xnmalloc (size_t n, size_t s) +{ + if (xalloc_oversized (n, s)) + xalloc_die (); + return xmalloc (n * s); +} + +/* 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. */ + +static_inline void * +xnrealloc (void *p, size_t n, size_t s) +{ + if (xalloc_oversized (n, s)) + xalloc_die (); + return xrealloc (p, n * s); +} + +/* 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 increased by a + factor of approximately 1.5 so that repeated reallocations have + O(N) overall cost rather than O(N**2) cost, but the + specification for this function does not guarantee that rate. + + 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 (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 + { + /* Set N = ceil (1.5 * N) so that progress is made if N == 1. + Check for overflow, so that N * S stays in size_t range. + The check is slightly conservative, but an exact check isn't + worth the trouble. */ + if ((size_t) -1 / 3 * 2 / s <= n) + xalloc_die (); + n += (n + 1) / 2; + } + + *pn = n; + return xrealloc (p, n * s); +} + +/* Return a pointer to a new buffer of N bytes. This is like xmalloc, + except it returns char *. */ + +static_inline char * +xcharalloc (size_t n) +{ + return XNMALLOC (n, char); +} + +# endif + # ifdef __cplusplus } + +/* C++ does not allow conversions from void * to other pointer types + without a cast. Use templates to work around the problem when + possible. */ + +template <typename T> inline T * +xrealloc (T *p, size_t s) +{ + return (T *) xrealloc ((void *) p, s); +} + +template <typename T> inline T * +xnrealloc (T *p, size_t n, size_t s) +{ + return (T *) xnrealloc ((void *) p, n, s); +} + +template <typename T> inline T * +x2realloc (T *p, size_t *pn) +{ + return (T *) x2realloc ((void *) p, pn); +} + +template <typename T> inline T * +x2nrealloc (T *p, size_t *pn, size_t s) +{ + return (T *) x2nrealloc ((void *) p, pn, s); +} + +template <typename T> inline T * +xmemdup (T const *p, size_t s) +{ + return (T *) xmemdup ((void const *) p, s); +} + # endif diff --git a/lib/xmalloc.c b/lib/xmalloc.c index 13c2490267d45..318e0ddb5a701 100644 --- a/lib/xmalloc.c +++ b/lib/xmalloc.c @@ -1,7 +1,8 @@ /* xmalloc.c -- malloc with out of memory checking Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2002, 2003, 2004 Free Software Foundation, Inc. + 1999, 2000, 2002, 2003, 2004, 2005, 2006 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 @@ -15,13 +16,15 @@ 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. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#if HAVE_CONFIG_H -# include <config.h> -#endif +#include <config.h> +#if ! HAVE_INLINE +# define static_inline +#endif #include "xalloc.h" +#undef static_inline #include <stdlib.h> #include <string.h> @@ -30,148 +33,36 @@ # define SIZE_MAX ((size_t) -1) #endif -/* Allocate an array of N objects, each with S bytes of memory, - dynamically, with error checking. S must be nonzero. */ - -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 * -xnmalloc (size_t n, size_t s) -{ - return xnmalloc_inline (n, s); -} +/* 1 if calloc is known to be compatible with GNU calloc. This + matters if we are not also using the calloc module, which defines + HAVE_CALLOC and supports the GNU API even on non-GNU platforms. */ +#if defined HAVE_CALLOC || defined __GLIBC__ +enum { HAVE_GNU_CALLOC = 1 }; +#else +enum { HAVE_GNU_CALLOC = 0 }; +#endif /* Allocate N bytes of memory dynamically, with error checking. */ void * xmalloc (size_t n) { - 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. */ - -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)) + void *p = malloc (n); + if (!p && 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. */ void * xrealloc (void *p, size_t n) { - return xnrealloc_inline (p, n, 1); -} - - -/* 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); + p = realloc (p, n); + if (!p && n != 0) + xalloc_die (); + return p; } /* If P is null, allocate a block of at least *PN bytes; otherwise, @@ -183,7 +74,7 @@ x2nrealloc (void *p, size_t *pn, size_t s) void * x2realloc (void *p, size_t *pn) { - return x2nrealloc_inline (p, pn, 1); + return x2nrealloc (p, pn, 1); } /* Allocate S bytes of zeroed memory dynamically, with error checking. @@ -204,8 +95,11 @@ xcalloc (size_t n, size_t s) { void *p; /* Test for overflow, since some calloc implementations don't have - proper overflow checks. */ - if (xalloc_oversized (n, s) || (! (p = calloc (n, s)) && n != 0)) + proper overflow checks. But omit overflow and size-zero tests if + HAVE_GNU_CALLOC, since GNU calloc catches overflow and never + returns NULL if successful. */ + if ((! HAVE_GNU_CALLOC && xalloc_oversized (n, s)) + || (! (p = calloc (n, s)) && (HAVE_GNU_CALLOC || n != 0))) xalloc_die (); return p; } diff --git a/lib/mempcpy.h b/lib/xstrndup.c index 4cc7a50c46ac6..7ccefd798a022 100644 --- a/lib/mempcpy.h +++ b/lib/xstrndup.c @@ -1,5 +1,6 @@ -/* Copy memory area and return pointer after last written byte. - Copyright (C) 2003, 2004 Free Software Foundation, Inc. +/* Duplicate a bounded initial segment of a string, with out-of-memory + checking. + Copyright (C) 2003, 2006, 2007 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 @@ -13,24 +14,24 @@ 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 mempcpy - -# if HAVE_MEMPCPY - -/* Get mempcpy() declaration. */ -# include <string.h> - -# else - -/* Get size_t */ -# include <stddef.h> - -/* Copy N bytes of SRC to DEST, return pointer to bytes after the - last written byte. */ -extern void *mempcpy (void *dest, const void *src, size_t n); - -# endif - -#endif + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <config.h> + +/* Specification. */ +#include "xstrndup.h" + +#include <string.h> +#include "xalloc.h" + +/* Return a newly allocated copy of at most N bytes of STRING. + In other words, return a copy of the initial segment of length N of + STRING. */ +char * +xstrndup (const char *string, size_t n) +{ + char *s = strndup (string, n); + if (! s) + xalloc_die (); + return s; +} diff --git a/lib/strndup.h b/lib/xstrndup.h index 318e799839316..88354cfd43a3a 100644 --- a/lib/strndup.h +++ b/lib/xstrndup.h @@ -1,4 +1,5 @@ -/* Duplicate a size-bounded string. +/* Duplicate a bounded initial segment of a string, with out-of-memory + checking. Copyright (C) 2003 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify @@ -13,18 +14,11 @@ 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_STRNDUP - -/* Get strndup() declaration. */ -#include <string.h> - -#else + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <stddef.h> -/* Return a newly allocated copy of at most N bytes of STRING. */ -extern char *strndup (const char *string, size_t n); - -#endif +/* Return a newly allocated copy of at most N bytes of STRING. + In other words, return a copy of the initial segment of length N of + STRING. */ +extern char *xstrndup (const char *string, size_t n); |