diff --git a/arscan.c b/arscan.c
index f4978486..ba8987e6 100644
--- a/arscan.c
+++ b/arscan.c
@@ -375,6 +375,8 @@ struct ar_hdr
#ifndef AR_HDR_SIZE
# define AR_HDR_SIZE (sizeof (struct ar_hdr))
#endif
+
+#include "output.h"
/* Takes three arguments ARCHIVE, FUNCTION and ARG.
@@ -891,7 +893,7 @@ ar_member_touch (const char *arname, const char *memname)
EINTRLOOP (o, lseek (fd, pos, 0));
if (o < 0)
goto lose;
- EINTRLOOP (r, write (fd, &ar_hdr, AR_HDR_SIZE));
+ r = output_write (fd, &ar_hdr, AR_HDR_SIZE);
if (r != AR_HDR_SIZE)
goto lose;
/* The file's mtime is the time we we want. */
@@ -913,7 +915,7 @@ ar_member_touch (const char *arname, const char *memname)
EINTRLOOP (o, lseek (fd, pos, 0));
if (o < 0)
goto lose;
- EINTRLOOP (r, write (fd, &ar_hdr, AR_HDR_SIZE));
+ r = output_write (fd, &ar_hdr, AR_HDR_SIZE);
if (r != AR_HDR_SIZE)
goto lose;
close (fd);
diff --git a/config.ami.template b/config.ami.template
index 4c5bb78b..8235f06b 100644
--- a/config.ami.template
+++ b/config.ami.template
@@ -335,3 +335,6 @@ this program. If not, see . */
/* Build host information. */
#define MAKE_HOST "Amiga"
+
+/* Define to `int' if does not define. */
+#define ssize_t int
diff --git a/config.h.W32.template b/config.h.W32.template
index 117ea4ab..ce070679 100644
--- a/config.h.W32.template
+++ b/config.h.W32.template
@@ -484,6 +484,9 @@ char *ttyname (int);
#endif
#endif
+/* Define to `int' if does not define. */
+#define ssize_t int
+
/* Define to 'int' if doesn't define. */
#define uid_t int
diff --git a/configh.dos.template b/configh.dos.template
index c43e6442..50d86ccf 100644
--- a/configh.dos.template
+++ b/configh.dos.template
@@ -111,3 +111,6 @@ this program. If not, see . */
/* Grok DOS paths (drive specs and backslash path element separators) */
#define HAVE_DOS_PATHS
+
+/* Define to `int' if does not define. */
+#define ssize_t int
diff --git a/job.h b/job.h
index 48cce764..9bea9a72 100644
--- a/job.h
+++ b/job.h
@@ -62,9 +62,6 @@ char **construct_command_argv (char *line, char **restp, struct file *file,
#ifdef VMS
int child_execute_job (struct child *child, char *argv);
#else
-# define FD_STDIN (fileno (stdin))
-# define FD_STDOUT (fileno (stdout))
-# define FD_STDERR (fileno (stderr))
int child_execute_job (struct output *out, int good_stdin, char **argv, char **envp);
#endif
diff --git a/makeint.h b/makeint.h
index 9fb2dd83..53a895e3 100644
--- a/makeint.h
+++ b/makeint.h
@@ -484,6 +484,7 @@ void error (const floc *flocp, size_t length, const char *fmt, ...)
__attribute__ ((__format__ (__printf__, 3, 4)));
void fatal (const floc *flocp, size_t length, const char *fmt, ...)
__attribute__ ((noreturn, __format__ (__printf__, 3, 4)));
+void out_of_memory () __attribute__((noreturn));
/* When adding macros to this list be sure to update the value of
XGETTEXT_OPTIONS in the po/Makevars file. */
@@ -501,8 +502,6 @@ void fatal (const floc *flocp, size_t length, const char *fmt, ...)
#define ONS(_t,_a,_f,_n,_s) _t((_a), INTSTR_LENGTH + strlen (_s), \
(_f), (_n), (_s))
-#define OUT_OF_MEM() O (fatal, NILF, _("virtual memory exhausted"))
-
void die (int) __attribute__ ((noreturn));
void pfatal_with_name (const char *) __attribute__ ((noreturn));
void perror_with_name (const char *, const char *);
diff --git a/misc.c b/misc.c
index e7ab8092..c9e88b61 100644
--- a/misc.c
+++ b/misc.c
@@ -220,7 +220,7 @@ xmalloc (unsigned int size)
/* Make sure we don't allocate 0, for pre-ISO implementations. */
void *result = malloc (size ? size : 1);
if (result == 0)
- OUT_OF_MEM();
+ out_of_memory ();
return result;
}
@@ -231,7 +231,7 @@ xcalloc (unsigned int size)
/* Make sure we don't allocate 0, for pre-ISO implementations. */
void *result = calloc (size ? size : 1, 1);
if (result == 0)
- OUT_OF_MEM();
+ out_of_memory ();
return result;
}
@@ -246,7 +246,7 @@ xrealloc (void *ptr, unsigned int size)
size = 1;
result = ptr ? realloc (ptr, size) : malloc (size);
if (result == 0)
- OUT_OF_MEM();
+ out_of_memory ();
return result;
}
@@ -263,7 +263,7 @@ xstrdup (const char *ptr)
#endif
if (result == 0)
- OUT_OF_MEM();
+ out_of_memory ();
#ifdef HAVE_STRDUP
return result;
@@ -282,7 +282,7 @@ xstrndup (const char *str, unsigned int length)
#ifdef HAVE_STRNDUP
result = strndup (str, length);
if (result == 0)
- OUT_OF_MEM();
+ out_of_memory ();
#else
result = xmalloc (length + 1);
if (length > 0)
diff --git a/output.c b/output.c
index b6ba3cfc..4945433d 100644
--- a/output.c
+++ b/output.c
@@ -61,6 +61,26 @@ unsigned int stdio_traced = 0;
# define MODE_T int
#endif
+/* Write a BUFFER of size LEN to file descriptor FD.
+ Handle EINTR and other short writes. If we get an error, ignore it. */
+int
+output_write (int fd, const void *buffer, size_t len)
+{
+ const char *msg = buffer;
+ while (1)
+ {
+ ssize_t r;
+
+ EINTRLOOP (r, write (fd, msg, len));
+
+ if (r < 0 || (size_t)r == len)
+ return r;
+
+ len -= r;
+ msg += r;
+ }
+}
+
/* Write a string to the current STDOUT or STDERR. */
static void
_outputs (struct output *out, int is_err, const char *msg)
@@ -76,16 +96,8 @@ _outputs (struct output *out, int is_err, const char *msg)
int fd = is_err ? out->err : out->out;
int len = strlen (msg);
int r;
-
EINTRLOOP (r, lseek (fd, 0, SEEK_END));
- while (1)
- {
- EINTRLOOP (r, write (fd, msg, len));
- if (r == len || r <= 0)
- break;
- len -= r;
- msg += r;
- }
+ output_write (fd, msg, len);
}
}
@@ -745,3 +757,15 @@ pfatal_with_name (const char *name)
/* NOTREACHED */
}
+
+/* Print a message about out of memory (not using more heap) and exit.
+ Our goal here is to be sure we don't try to allocate more memory, which
+ means we don't want to use string translations or normal cleanup. */
+
+void
+out_of_memory ()
+{
+ output_write (FD_STDOUT, program, strlen (program));
+ output_write (FD_STDOUT, STRING_SIZE_TUPLE (": *** virtual memory exhausted\n"));
+ exit (MAKE_FAILURE);
+}
diff --git a/output.h b/output.h
index bcd98051..b398cdd0 100644
--- a/output.h
+++ b/output.h
@@ -24,6 +24,10 @@ struct output
extern struct output *output_context;
extern unsigned int stdio_traced;
+#define FD_STDIN (fileno (stdin))
+#define FD_STDOUT (fileno (stdout))
+#define FD_STDERR (fileno (stderr))
+
#define OUTPUT_SET(_new) do{ output_context = (_new)->syncout ? (_new) : NULL; }while(0)
#define OUTPUT_UNSET() do{ output_context = NULL; }while(0)
@@ -32,6 +36,10 @@ extern unsigned int stdio_traced;
FILE *output_tmpfile (char **, const char *);
+/* Write a buffer directly to the given file descriptor.
+ This handles errors etc. */
+int output_write (int fd, const void *buffer, size_t len);
+
/* Initialize and close a child output structure: if NULL do this program's
output (this should only be done once). */
void output_init (struct output *out);
diff --git a/read.c b/read.c
index 3e399848..0ca456c0 100644
--- a/read.c
+++ b/read.c
@@ -3276,7 +3276,7 @@ parse_file_seq (char **stringp, unsigned int size, int stopmap,
switch (glob (name, GLOB_NOSORT|GLOB_ALTDIRFUNC, NULL, &gl))
{
case GLOB_NOSPACE:
- OUT_OF_MEM();
+ out_of_memory ();
case 0:
/* Success. */