File quoting.diff of Package sharutils

--- configure.ac
+++ configure.ac
@@ -99,6 +99,7 @@
 AM_GNU_GETTEXT
 AM_GNU_GETTEXT_VERSION([0.14.5])
 AM_WITH_DMALLOC
+gl_QUOTEARG
 
 # sharutils is somewhat special about internationalization in that it
 # always requires the GNU .mo files installed.
--- lib/Makefile.am
+++ lib/Makefile.am
@@ -26,12 +26,13 @@
 CLEANFILES = unlocked-io.h
 
 libshar_a_SOURCES = basename.c error.c getopt.c getopt1.c md5.c offtostr.c \
-whoami.c xgetcwd.c xmalloc.c xstrdup.c
+whoami.c xgetcwd.c xmalloc.c xstrdup.c quotearg.c xalloc-die.c exitfail.c
 
 libshar_a_LIBADD = $(ALLOCA) $(LIBOBJS)
 
 noinst_HEADERS = basename.h error.h exit.h getopt.h gettext.h inttostr.h \
-liballoca.h md5.h pathmax.h stpcpy.h system.h xalloc.h xgetcwd.h
+liballoca.h md5.h pathmax.h stpcpy.h system.h xalloc.h xgetcwd.h \
+quotearg.h exitfail.h
 
 AM_CPPFLAGS = -I.. -I$(srcdir) -I../intl
 DEFS = -DLIBDIR=\"$(libdir)\" @DEFS@
--- lib/exitfail.c
+++ lib/exitfail.c
@@ -0,0 +1,27 @@
+/* Failure exit status
+
+   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   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; see the file COPYING.
+   If not, write to the Free Software Foundation,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "exitfail.h"
+#include "exit.h"
+
+int volatile exit_failure = EXIT_FAILURE;
--- lib/exitfail.h
+++ lib/exitfail.h
@@ -0,0 +1,20 @@
+/* Failure exit status
+
+   Copyright (C) 2002 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; see the file COPYING.
+   If not, write to the Free Software Foundation,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+extern int volatile exit_failure;
--- lib/quotearg.c
+++ lib/quotearg.c
@@ -0,0 +1,673 @@
+/* quotearg.c - quote arguments for output
+
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Free Software
+   Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is 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.  */
+
+/* Written by Paul Eggert <eggert@twinsun.com> */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#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 "gettext.h"
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
+
+#if HAVE_WCHAR_H
+
+/* BSD/OS 4.1 wchar.h requires FILE and struct tm to be declared.  */
+# include <stdio.h>
+# include <time.h>
+
+# include <wchar.h>
+#endif
+
+#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
+# 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 iswprint
+# if HAVE_WCTYPE_H
+#  include <wctype.h>
+# endif
+# if !defined iswprint && !HAVE_ISWPRINT
+#  define iswprint(wc) 1
+# endif
+#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.  */
+  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 = xmalloc (sizeof *p);
+  *p = *(o ? o : &default_quoting_options);
+  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;
+  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:
+      {
+	/* 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.  */
+
+	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;
+		  }
+	      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;
+				}
+			  }
+
+			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 = xmalloc (bufsize);
+  quotearg_buffer (buf, bufsize, arg, argsize, o);
+  errno = e;
+  return buf;
+}
+
+/* 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;
+
+  /* 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;
+  unsigned int n0 = n;
+  struct slotvec
+    {
+      size_t size;
+      char *val;
+    };
+  static struct slotvec slotvec0 = {sizeof slot0, slot0};
+  static struct slotvec *slotvec = &slotvec0;
+
+  if (n < 0)
+    abort ();
+
+  if (nslots <= n0)
+    {
+      unsigned int n1 = n0 + 1;
+
+      if (xalloc_oversized (n1, sizeof *slotvec))
+	xalloc_die ();
+
+      if (slotvec == &slotvec0)
+	{
+	  slotvec = xmalloc (sizeof *slotvec);
+	  *slotvec = slotvec0;
+	}
+      slotvec = xrealloc (slotvec, n1 * sizeof *slotvec);
+      memset (slotvec + nslots, 0, (n1 - nslots) * sizeof *slotvec);
+      nslots = n1;
+    }
+
+  {
+    size_t size = slotvec[n].size;
+    char *val = slotvec[n].val;
+    size_t qsize = quotearg_buffer (val, size, arg, argsize, options);
+
+    if (size <= qsize)
+      {
+	slotvec[n].size = size = qsize + 1;
+	if (val != slot0)
+	  free (val);
+	slotvec[n].val = val = xmalloc (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, ':');
+}
--- lib/quotearg.h
+++ lib/quotearg.h
@@ -0,0 +1,137 @@
+/* quotearg.h - quote arguments for output
+
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Free Software
+   Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is 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.  */
+
+/* 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);
+
+#endif /* !QUOTEARG_H_ */
--- lib/xalloc-die.c
+++ lib/xalloc-die.c
@@ -0,0 +1,45 @@
+/* Report a memory allocation failure and exit.
+
+   Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2004 Free
+   Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   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.  */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "xalloc.h"
+
+#include <stdlib.h>
+
+#include "error.h"
+#include "exitfail.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
+
+void
+xalloc_die (void)
+{
+  error (exit_failure, 0, "%s", _("memory exhausted"));
+
+  /* The `noreturn' cannot be given to error, since it may return if
+     its first argument is 0.  To help compilers understand the
+     xalloc_die does not return, call abort.  Also, the abort is a
+     safety feature if exit_failure is 0 (which shouldn't happen).  */
+  abort ();
+}
--- lib/xalloc.h
+++ lib/xalloc.h
@@ -1,5 +1,7 @@
 /* xalloc.h -- malloc with out-of-memory checking
-   Copyright (C) 1990-1998, 1999, 2000 Free Software Foundation, Inc.
+
+   Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000, 2003, 2004 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -18,14 +20,14 @@
 #ifndef XALLOC_H_
 # define XALLOC_H_
 
-# ifndef PARAMS
-#  if defined PROTOTYPES || (defined __STDC__ && __STDC__)
-#   define PARAMS(Args) Args
-#  else
-#   define PARAMS(Args) ()
-#  endif
+# include <stddef.h>
+
+
+# ifdef __cplusplus
+extern "C" {
 # endif
 
+
 # ifndef __attribute__
 #  if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__
 #   define __attribute__(x)
@@ -36,52 +38,42 @@
 #  define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
 # endif
 
-/* Exit value when the requested amount of memory is not available.
-   It is initialized to EXIT_FAILURE, but the caller may set it to
-   some other value.  */
-extern int xalloc_exit_failure;
-
-/* If this pointer is non-zero, run the specified function upon each
-   allocation failure.  It is initialized to zero. */
-extern void (*xalloc_fail_func) PARAMS ((void));
-
-/* If XALLOC_FAIL_FUNC is undefined or a function that returns, this
-   message is output.  It is translated via gettext.
-   Its value is "memory exhausted".  */
-extern char const xalloc_msg_memory_exhausted[];
-
-/* This function is always triggered when memory is exhausted.  It is
-   in charge of honoring the three previous items.  This is the
+/* This function is always triggered when memory is exhausted.
+   It must be defined by the application, either explicitly
+   or by using gnulib's xalloc-die module.  This is the
    function to call when one wants the program to die because of a
    memory allocation failure.  */
-extern void xalloc_die PARAMS ((void)) ATTRIBUTE_NORETURN;
+extern void xalloc_die (void) ATTRIBUTE_NORETURN;
 
-void *xmalloc PARAMS ((size_t n));
-void *xcalloc PARAMS ((size_t n, size_t s));
-void *xrealloc PARAMS ((void *p, size_t n));
-char *xstrdup PARAMS ((const char *str));
-
-# define XMALLOC(Type, N_items) ((Type *) xmalloc (sizeof (Type) * (N_items)))
-# define XCALLOC(Type, N_items) ((Type *) xcalloc (sizeof (Type), (N_items)))
-# define XREALLOC(Ptr, Type, N_items) \
-  ((Type *) xrealloc ((void *) (Ptr), sizeof (Type) * (N_items)))
-
-/* Declare and alloc memory for VAR of type TYPE. */
-# define NEW(Type, Var)  Type *(Var) = XMALLOC (Type, 1)
-
-/* Free VAR only if non NULL. */
-# define XFREE(Var)	\
-   do {                 \
-      if (Var)          \
-        free (Var);     \
-   } while (0)
-
-/* Return a pointer to a malloc'ed copy of the array SRC of NUM elements. */
-# define CCLONE(Src, Num) \
-  (memcpy (xmalloc (sizeof (*Src) * (Num)), (Src), sizeof (*Src) * (Num)))
+void *xmalloc (size_t s);
+void *xnmalloc (size_t n, size_t s);
+void *xzalloc (size_t s);
+void *xcalloc (size_t n, size_t s);
+void *xrealloc (void *p, size_t s);
+void *xnrealloc (void *p, size_t n, size_t s);
+void *x2realloc (void *p, size_t *pn);
+void *x2nrealloc (void *p, size_t *pn, size_t s);
+void *xmemdup (void const *p, size_t s);
+char *xstrdup (char const *str);
+
+/* Return 1 if an array of N objects, each of size S, cannot exist due
+   to size arithmetic overflow.  S must be positive and N must be
+   nonnegative.  This is a macro, not an inline function, so that it
+   works correctly even when SIZE_MAX < N.
+
+   By gnulib convention, SIZE_MAX represents overflow in size
+   calculations, so the conservative dividend to use here is
+   SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value.
+   However, malloc (SIZE_MAX) fails on all known hosts where
+   sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for
+   exactly-SIZE_MAX allocations on such hosts; this avoids a test and
+   branch when S is known to be 1.  */
+# define xalloc_oversized(n, s) \
+    ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n))
 
-/* Return a malloc'ed copy of SRC. */
-# define CLONE(Src) CCLONE (Src, 1)
+# ifdef __cplusplus
+}
+# endif
 
 
 #endif /* !XALLOC_H_ */
--- lib/xmalloc.c
+++ lib/xmalloc.c
@@ -1,5 +1,7 @@
 /* xmalloc.c -- malloc with out of memory checking
-   Copyright (C) 1990-1999, 2000 Free Software Foundation, Inc.
+
+   Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000, 2002, 2003, 2004 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -19,62 +21,31 @@
 # include <config.h>
 #endif
 
-#include <sys/types.h>
-
-#if STDC_HEADERS
-# include <stdlib.h>
-#else
-void *calloc ();
-void *malloc ();
-void *realloc ();
-void free ();
-#endif
-
-#if ENABLE_NLS
-# include <libintl.h>
-# define _(Text) gettext (Text)
-#else
-# define textdomain(Domain)
-# define _(Text) Text
-#endif
-#define N_(Text) Text
-
-#include "error.h"
 #include "xalloc.h"
 
-#ifndef EXIT_FAILURE
-# define EXIT_FAILURE 1
-#endif
+#include <stdlib.h>
+#include <string.h>
 
-#ifndef HAVE_DONE_WORKING_MALLOC_CHECK
-"you must run the autoconf test for a properly working malloc -- see malloc.m4"
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
 #endif
 
-#ifndef HAVE_DONE_WORKING_REALLOC_CHECK
-"you must run the autoconf test for a properly working realloc --see realloc.m4"
-#endif
+/* Allocate an array of N objects, each with S bytes of memory,
+   dynamically, with error checking.  S must be nonzero.  */
 
-/* Exit value when the requested amount of memory is not available.
-   The caller may set it to some other value.  */
-int xalloc_exit_failure = EXIT_FAILURE;
-
-/* If non NULL, call this function when memory is exhausted. */
-void (*xalloc_fail_func) PARAMS ((void)) = 0;
-
-/* If XALLOC_FAIL_FUNC is NULL, or does return, display this message
-   before exiting when memory is exhausted.  Goes through gettext. */
-char const xalloc_msg_memory_exhausted[] = N_("memory exhausted");
-
-void
-xalloc_die (void)
-{
-  if (xalloc_fail_func)
-    (*xalloc_fail_func) ();
-  error (xalloc_exit_failure, 0, "%s", _(xalloc_msg_memory_exhausted));
-  /* The `noreturn' cannot be given to error, since it may return if
-     its first argument is 0.  To help compilers understand the
-     xalloc_die does terminate, call exit. */
-  exit (EXIT_FAILURE);
+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);
 }
 
 /* Allocate N bytes of memory dynamically, with error checking.  */
@@ -82,35 +53,169 @@
 void *
 xmalloc (size_t n)
 {
-  void *p;
+  return xnmalloc_inline (n, 1);
+}
 
-  p = malloc (n);
-  if (p == 0)
+/* 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))
     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)
 {
-  p = realloc (p, n);
-  if (p == 0)
-    xalloc_die ();
-  return p;
+  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);
 }
 
-/* Allocate memory for N elements of S bytes, with error checking.  */
+void *
+x2nrealloc (void *p, size_t *pn, size_t s)
+{
+  return x2nrealloc_inline (p, pn, s);
+}
+
+/* If P is null, allocate a block of at least *PN bytes; otherwise,
+   reallocate P so that it contains more than *PN bytes.  *PN must be
+   nonzero unless P is null.  Set *PN to the new block's size, and
+   return the pointer to the new block.  *PN is never set to zero, and
+   the returned pointer is never null.  */
+
+void *
+x2realloc (void *p, size_t *pn)
+{
+  return x2nrealloc_inline (p, pn, 1);
+}
+
+/* Allocate S bytes of zeroed memory dynamically, with error checking.
+   There's no need for xnzalloc (N, S), since it would be equivalent
+   to xcalloc (N, S).  */
+
+void *
+xzalloc (size_t s)
+{
+  return memset (xmalloc (s), 0, s);
+}
+
+/* Allocate zeroed memory for N elements of S bytes, with error
+   checking.  S must be nonzero.  */
 
 void *
 xcalloc (size_t n, size_t s)
 {
   void *p;
-
-  p = calloc (n, s);
-  if (p == 0)
+  /* Test for overflow, since some calloc implementations don't have
+     proper overflow checks.  */
+  if (xalloc_oversized (n, s) || (! (p = calloc (n, s)) && n != 0))
     xalloc_die ();
   return p;
 }
+
+/* Clone an object P of size S, with error checking.  There's no need
+   for xnclone (P, N, S), since xclone (P, N * S) works without any
+   need for an arithmetic overflow check.  */
+
+void *
+xclone (void const *p, size_t s)
+{
+  return memcpy (xmalloc (s), p, s);
+}
--- m4/quotearg.m4
+++ m4/quotearg.m4
@@ -0,0 +1,16 @@
+# quotearg.m4 serial 2
+dnl Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License.  As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+AC_DEFUN([gl_QUOTEARG],
+[
+  dnl Prerequisites of lib/quotearg.c.
+  AC_CHECK_HEADERS(wchar.h wctype.h)
+  AC_CHECK_FUNCS(iswprint mbsinit)
+  AC_TYPE_MBSTATE_T
+  AC_FUNC_MBRTOWC
+])
--- src/scripts.def
+++ src/scripts.def
@@ -159,7 +159,7 @@
   body = <<- _EOBody_
 	  if ${md5check}
 	  then (
-	       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} '%s: %s'
+	       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} %s: '%s'
 	       ) << %s
 	_EOBody_;
 };
--- src/scripts.x
+++ src/scripts.x
@@ -131,7 +131,7 @@
 #line 160 "scripts.def"
 "  if ${md5check}\n\
   then (\n\
-       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} '%s: %s'\n\
+       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} %s: '%s'\n\
        ) << %s\n";
 
 static const char query_answers_z[769] = 
--- src/shar.c
+++ src/shar.c
@@ -147,6 +147,7 @@
 #include "getopt.h"
 #include "inttostr.h"
 #include "md5.h"
+#include "quotearg.h"
 
 /* No Brown-Shirt mode.  */
 static int vanilla_operation_mode = 0;
@@ -698,6 +699,8 @@
 generate_mkdir (path)
      const char *path;
 {
+  char *quoted_path = quotearg_n_style (2, shell_always_quoting_style, path);
+
   /* If already generated code for this dir creation, don't do again.  */
 
   {
@@ -738,18 +741,18 @@
 
   /* Generate the text.  */
 
-  fprintf (output, "if test ! -d '%s'; then\n", path);
+  fprintf (output, "if test ! -d %s; then\n", quoted_path);
   if (!quiet_unshar_mode)
     {
       const char* did_pz =
-	N_("x - created directory `%s'\\''.");
+	N_("x - created directory `'%s\\''.");
       const char* not_pz =
-	N_("x - failed to create directory `%s'\\''.");
-      fprintf (output, "  mkdir '%s'\n", path);
-      echo_status ("test $? -eq 0", did_pz, not_pz, path, 1);
+	N_("x - failed to create directory `'%s\\''.");
+      fprintf (output, "  mkdir %s\n", quoted_path);
+      echo_status ("test $? -eq 0", did_pz, not_pz, quoted_path, 1);
     }
   else
-    fprintf (output, "  mkdir '%s' || exit 1\n", path);
+    fprintf (output, "  mkdir %s || exit 1\n", quoted_path);
   fputs ("fi\n", output);
 }
 
@@ -988,7 +991,7 @@
      failed.  */
 
   fputs (" :\n", output);
-  echo_status ("test $? -ne 0", N_("restore of %s failed"), NULL,
+  echo_status ("test $? -ne 0", N_("restore of '%s' failed"), NULL,
 	       restore_name, 0);
 
   fputs ("'\n${echo} '", output);
@@ -1052,6 +1055,7 @@
   const char *file_type;	/* text of binary */
   const char *file_type_remote;	/* text or binary, avoiding locale */
   struct tm *restore_time;
+  const char *quoted_local_name, *quoted_restore_name;
 
   /* Check to see that this is still a regular file and readable.  */
 
@@ -1066,6 +1070,11 @@
       return 1;
     }
 
+  quoted_local_name = quotearg_n_style (0, shell_always_quoting_style,
+					local_name);
+  quoted_restore_name = quotearg_n_style (1, shell_always_quoting_style,
+					  restore_name);
+
   /* If file_size_limit set, get the current output length.  */
 
   if (file_size_limit)
@@ -1079,7 +1088,7 @@
 	       ? struct_stat.st_size + struct_stat.st_size / 3
 	       : struct_stat.st_size)
 	      > remaining_size))
-        change_files (restore_name, remaining_size);
+        change_files (quoted_restore_name, remaining_size);
     }
   else
     remaining_size = 0;		/* give some value to the variable */
@@ -1188,23 +1197,24 @@
 	      /* Start writing the pipe with encodes.  */
 
 	      FILE *outptr;
+	      char *cmdline = alloca (strlen (quoted_local_name) + 100);
 
 	      if (compressed_file_mode)
 		{
-		  sprintf (buffer, "compress -b%d < '%s'",
-			   bits_per_compressed_byte, local_name);
-		  input = popen (buffer, "r");
+		  sprintf (cmdline, "compress -b%d < %s",
+			   bits_per_compressed_byte, quoted_local_name);
+		  input = popen (cmdline, "r");
 		}
 	      else if (gzipped_file_mode)
 		{
-		  sprintf (buffer, "gzip -%d < '%s'",
-			   gzip_compression_level, local_name);
-		  input = popen (buffer, "r");
+		  sprintf (cmdline, "gzip -%d < %s",
+			   gzip_compression_level, quoted_local_name);
+		  input = popen (cmdline, "r");
 		}
 	      else if (bzipped_file_mode)
 		{
-		  sprintf (buffer, "bzip2 < '%s'", local_name);
-		  input = popen (buffer, "r");
+		  sprintf (cmdline, "bzip2 < %s", quoted_local_name);
+		  input = popen (cmdline, "r");
 		}
 	      else
 		input = fopen (local_name, "rb");
@@ -1248,27 +1258,27 @@
 
   if (check_existing_mode)
     {
-      fprintf (output, "if test -f '%s' && test \"$first_param\" != -c; then\n",
-	       restore_name);
+      fprintf (output, "if test -f %s && test \"$first_param\" != -c; then\n",
+	       quoted_restore_name);
 
       if (query_user_mode)
 	{
           char* pzOverwriting = scribble;
           char* pzOverwrite;
 
-          sprintf (pzOverwriting, N_("overwriting %s"), restore_name);
+          sprintf (pzOverwriting, N_("overwriting '%s'"), quoted_restore_name);
           pzOverwrite = scribble + strlen(pzOverwriting) + 2;
-          sprintf (pzOverwrite, N_("overwrite %s"), restore_name);
+          sprintf (pzOverwrite, N_("overwrite '%s'"), quoted_restore_name);
 
           fprintf (output, query_user_z, pzOverwriting, pzOverwrite);
 
-          sprintf (pzOverwriting, N_("SKIPPING %s"), restore_name);
+          sprintf (pzOverwriting, N_("SKIPPING '%s'"), quoted_restore_name);
           fprintf (output, query_check_z, N_("extraction aborted"),
 		   pzOverwriting, pzOverwriting);
 	}
       else
-        echo_text (N_("SKIPPING %s (file already exists)"),
-                   restore_name, 0);
+        echo_text (N_("SKIPPING '%s' (file already exists)"),
+                   quoted_restore_name, 0);
 
       if (split_file_mode)
 	fputs ("  rm -f ${lock_dir}/new\nelse\n  > ${lock_dir}/new\n", output);
@@ -1281,8 +1291,8 @@
 
   if (!quiet_unshar_mode)
     {
-      sprintf (scribble, N_("x - extracting %s %s"),
-               restore_name, file_type_remote);
+      sprintf (scribble, N_("x - extracting '%s' %s"),
+               quoted_restore_name, file_type_remote);
       fprintf (output, echo_string_z, scribble);
     }
 
@@ -1291,8 +1301,8 @@
 
       /* Just touch the file, or empty it if it exists.  */
 
-      fprintf (output, "  > '%s' &&\n",
-	       restore_name);
+      fprintf (output, "  > %s &&\n",
+	       quoted_restore_name);
     }
   else
     {
@@ -1315,8 +1325,8 @@
 
 	  /* Just run it into the file.  */
 
-	  fprintf (output, "  sed 's/^%c//' << '%s' > '%s' &&\n",
-		   line_prefix, here_delimiter, restore_name);
+	  fprintf (output, "  sed 's/^%c//' << '%s' > %s &&\n",
+		   line_prefix, here_delimiter, quoted_restore_name);
 	}
 
       while (fgets (buffer, BUFSIZ, input))
@@ -1397,8 +1407,8 @@
 		 failed.  */
 
 	      fputs (" :\n", output);
-	      echo_status ("test $? -ne 0", N_("restore of %s failed\n"), NULL,
-			   restore_name, 0);
+	      echo_status ("test $? -ne 0", N_("restore of '%s' failed\n"), NULL,
+			   quoted_restore_name, 0);
 
 	      if (check_existing_mode)
 		fputs ("fi\n", output);
@@ -1521,24 +1531,24 @@
 	  if (!quiet_unshar_mode)
             echo_text (N_("uncompressing file %s"), restore_name, 1);
 
-	  fprintf (output, "  compress -d < ${lock_dir}/cmp > '%s' &&\n",
-		   restore_name);
+	  fprintf (output, "  compress -d < ${lock_dir}/cmp > %s &&\n",
+		   quoted_restore_name);
 	}
       else if (gzipped_file_mode)
 	{
 	  if (!quiet_unshar_mode)
             echo_text (N_("gunzipping file %s"), restore_name, 1);
 
-	  fprintf (output, "  gzip -d < ${lock_dir}/gzi > '%s' &&\n",
-		   restore_name);
+	  fprintf (output, "  gzip -d < ${lock_dir}/gzi > %s &&\n",
+		   quoted_restore_name);
 	}
       else if (bzipped_file_mode)
 	{
 	  if (!quiet_unshar_mode)
             echo_text (N_("bunzipping file %s"), restore_name, 1);
 
-	  fprintf (output, "  bzip2 -d < ${lock_dir}/bzi > '%s' &&\n",
-		   restore_name);
+	  fprintf (output, "  bzip2 -d < ${lock_dir}/bzi > %s &&\n",
+		   quoted_restore_name);
 	}
     }
 
@@ -1549,12 +1559,12 @@
 
       restore_time = localtime (&struct_stat.st_mtime);
       fprintf (output, "\
-  (set %02d %02d %02d %02d %02d %02d %02d '%s'; eval \"$shar_touch\") &&\n",
+  (set %02d %02d %02d %02d %02d %02d %02d %s; eval \"$shar_touch\") &&\n",
 	       (restore_time->tm_year + 1900) / 100,
 	       (restore_time->tm_year + 1900) % 100,
 	       restore_time->tm_mon + 1, restore_time->tm_mday,
 	       restore_time->tm_hour, restore_time->tm_min,
-	       restore_time->tm_sec, restore_name);
+	       restore_time->tm_sec, quoted_restore_name);
     }
 
   if (vanilla_operation_mode)
@@ -1563,8 +1573,8 @@
       /* Close the "&&" and report an error if any of the above
 	 failed.  */
       fputs (":\n", output);
-      echo_status ("test $? -ne 0", N_("restore of %s failed"), NULL,
-		   restore_name, 0);
+      echo_status ("test $? -ne 0", N_("restore of '%s' failed"), NULL,
+		   quoted_restore_name, 0);
     }
   else
     {
@@ -1574,13 +1584,13 @@
 
       /* Set the permissions as they were.  */
 
-      fprintf (output, "  chmod %04o '%s'\n",
-	       (unsigned) (struct_stat.st_mode & 0777), restore_name);
+      fprintf (output, "  chmod %04o %s\n",
+	       (unsigned) (struct_stat.st_mode & 0777), quoted_restore_name);
 
       /* Report an error if any of the above failed.  */
 
-      echo_status ("test $? -ne 0", N_("restore of %s failed"), NULL,
-		   restore_name, 0);
+      echo_status ("test $? -ne 0", N_("restore of '%s' failed"), NULL,
+		   quoted_restore_name, 0);
 
       if (md5_count_mode && (fp = fopen (local_name, "r")) != NULL
 	  && md5_stream (fp, md5buffer) == 0)
@@ -1589,7 +1599,7 @@
 	  size_t cnt;
 	  did_md5 = 1;
 
-	  fprintf (output, md5test_z, restore_name,
+	  fprintf (output, md5test_z, quoted_restore_name,
 		   N_("MD5 check failed"), here_delimiter);
 
 	  for (cnt = 0; cnt < 16; ++cnt)
@@ -1609,9 +1619,10 @@
 	  /* Validate the transferred file using simple `wc' command.  */
 
 	  FILE *pfp;
-	  char command[BUFSIZ];
+	  char *command = alloca (strlen (CHARACTER_COUNT_COMMAND)
+				  + strlen (quoted_local_name) + 2);
 
-	  sprintf (command, "LC_ALL=C wc -c < '%s'", local_name);
+	  sprintf (command, "%s %s", CHARACTER_COUNT_COMMAND, quoted_local_name);
 	  if (pfp = popen (command, "r"), pfp)
 	    {
 	      char wc[BUFSIZ];
@@ -1643,11 +1654,11 @@
               }
 
 	      fprintf (output,
-                       "test `LC_ALL=C wc -c < '%s'` -ne %s && \\\n  ${echo} ",
-                       restore_name, wc);
+                       "test `LC_ALL=C wc -c < %s` -ne %s && \\\n  ${echo} ",
+                       quoted_restore_name, wc);
               fprintf (output,
-                       N_("'restoration warning:  size of %s is not %s'\n"),
-                       restore_name, wc);
+                       N_("'restoration warning:  size of '%s' is not %s'\n"),
+                       quoted_restore_name, wc);
 	      pclose (pfp);
 	    }
 	}
--- tests/shar-1.ok
+++ tests/shar-1.ok
@@ -94,26 +94,26 @@
 fi
 # ============= shar-1.in ==============
 if test -f 'shar-1.in' && test "$first_param" != -c; then
-  ${echo} 'x -SKIPPING shar-1.in (file already exists)'
+  ${echo} 'x -SKIPPING ''shar-1.in'' (file already exists)'
 else
-${echo} 'x - extracting shar-1.in (text)'
+${echo} 'x - extracting ''shar-1.in'' (text)'
   sed 's/^X//' << 'SHAR_EOF' > 'shar-1.in' &&
 This is a test
 SHAR_EOF
   (set <date> 'shar-1.in'; eval "$shar_touch") &&
   chmod 0644 'shar-1.in'
 if test $? -ne 0
-then ${echo} 'restore of shar-1.in failed'
+then ${echo} 'restore of ''shar-1.in'' failed'
 fi
   if ${md5check}
   then (
-       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'shar-1.in: MD5 check failed'
+       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'shar-1.in': 'MD5 check failed'
        ) << SHAR_EOF
 ff22941336956098ae9a564289d1bf1b  shar-1.in
 SHAR_EOF
   else
 test `LC_ALL=C wc -c < 'shar-1.in'` -ne 15 && \
-  ${echo} 'restoration warning:  size of shar-1.in is not 15'
+  ${echo} 'restoration warning:  size of ''shar-1.in'' is not 15'
   fi
 fi
 if rm -fr ${lock_dir}