]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
New library functions for msgcat, msgconv, msgen, msggrep, msgsed.
authorBruno Haible <bruno@clisp.org>
Tue, 12 Jun 2001 12:44:54 +0000 (12:44 +0000)
committerBruno Haible <bruno@clisp.org>
Tue, 12 Jun 2001 12:44:54 +0000 (12:44 +0000)
22 files changed:
ChangeLog
configure.in
lib/ChangeLog
lib/Makefile.am
lib/findprog.c [new file with mode: 0644]
lib/findprog.h [new file with mode: 0644]
lib/full-write.c [new file with mode: 0644]
lib/full-write.h [new file with mode: 0644]
lib/pipe-bidi.c [new file with mode: 0644]
lib/pipe-in.c [new file with mode: 0644]
lib/pipe-out.c [new file with mode: 0644]
lib/pipe.h [new file with mode: 0644]
lib/safe-read.c [new file with mode: 0644]
lib/safe-read.h [new file with mode: 0644]
lib/wait-process.c [new file with mode: 0644]
lib/wait-process.h [new file with mode: 0644]
m4/ChangeLog
m4/Makefile.am
m4/ssize_t.m4 [new file with mode: 0644]
m4/unionwait.m4 [new file with mode: 0644]
po/ChangeLog
po/POTFILES.in

index 44ede11fe5c4b7f2996c41b40c19eac0c2756e41..8489fa3fbf888bdf4590def217620d7baf183435 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2001-06-10  Bruno Haible  <haible@clisp.cons.org>
+
+       * configure.in: Check for ssize_t, pid_t, posix_spawn, select.
+       Call AC_FUNC_VFORK, gt_UNION_WAIT.
+
 2001-06-08  Bruno Haible  <haible@clisp.cons.org>
 
        * ltmain.sh: Upgrade to libtool-1.4.
index fea05f247ff33c46153c215dda715653eefa2033..ee7c87c3075377b3c69ac4c3ca44099a798df218 100644 (file)
@@ -1,6 +1,6 @@
 dnl Process this file with autoconf to produce a configure script.
 AC_PREREQ(2.13)
-AC_REVISION($Revision: 1.29 $)
+AC_REVISION($Revision: 1.30 $)
 AC_INIT(src/msgfmt.c)
 AM_INIT_AUTOMAKE(gettext, 0.10.38)
 RELEASE_DATE=2001-05-23      dnl in "date +%Y-%m-%d" format
@@ -45,11 +45,13 @@ AC_TYPE_OFF_T
 AC_TYPE_SIZE_T
 AM_TYPE_PTRDIFF_T
 jm_AC_TYPE_UINTMAX_T
+gt_TYPE_SSIZE_T
+AC_TYPE_PID_T
 
 dnl Checks for library functions.
 AC_FUNC_ALLOCA
 AC_FUNC_VPRINTF
-AC_CHECK_FUNCS([getcwd mblen memcpy strchr strerror uname])
+AC_CHECK_FUNCS([getcwd mblen memcpy posix_spawn select strchr strerror uname])
 AC_REPLACE_FUNCS([memmove memset stpcpy stpncpy strcspn \
 strcasecmp strncasecmp strstr strtoul vasprintf])
 AM_FUNC_GETLINE
@@ -57,6 +59,8 @@ if test $am_cv_func_working_getline != yes; then
   AC_CHECK_FUNCS(getdelim)
 fi
 jm_PREREQ_MBSWIDTH
+AC_FUNC_VFORK
+gt_UNION_WAIT
 
 AC_CHECK_FUNC(parse_printf_format, gt_cv_func_parse_printf_format=yes,
   gt_cv_func_parse_printf_format=no)
index 4b8af78e27a8c1745574ad569478f027c987461d..016cff597effb38a080fff317c2c901445a24fc4 100644 (file)
@@ -1,3 +1,22 @@
+2001-06-10  Bruno Haible  <haible@clisp.cons.org>
+
+       * findprog.h: New file.
+       * findprog.c: New file.
+       * full-write.h: New file.
+       * full-write.c: New file.
+       * pipe.h: New file.
+       * pipe-bidi.c: New file.
+       * pipe-in.c: New file.
+       * pipe-out.c: New file.
+       * safe-read.h: New file.
+       * safe-read.c: New file.
+       * wait-process.h: New file.
+       * wait-process.c: New file.
+       * Makefile.am (libnlsut_a_SOURCES): Add findprog.c, full-write.c,
+       pipe-bidi.c, pipe-in.c, pipe-out.c, safe-read.c, wait-process.c.
+       (noinst_HEADERS): Add findprog.h, full-write.h, pipe.h, safe-read.h,
+       wait-process.h.
+
 2001-05-15  Bruno Haible  <haible@clisp.cons.org>
 
        * progname.h (set_program_name): New declaration.
index 06f59c6516cdec09baa544f60154c52690b38387..84ac17f57499d18cdc4344bb9e8ac29698aea5d9 100644 (file)
@@ -26,15 +26,17 @@ printf-prs.c ref-add.sin ref-del.sin stpcpy.c stpncpy.c strcasecmp.c \
 strcspn.c strncasecmp.c strstr.c strtol.c strtoul.c vasprintf.c \
 gen-lbrkprop.c 3level.h
 
-libnlsut_a_SOURCES = basename.c c-ctype.c concatpath.c fstrcmp.c \
-getopt.c getopt1.c hash.c linebreak.c localcharset.c mbswidth.c obstack.c \
-progname.c xerror.c xgetcwd.c xmalloc.c xstrdup.c
+libnlsut_a_SOURCES = basename.c c-ctype.c concatpath.c findprog.c fstrcmp.c \
+full-write.c getopt.c getopt1.c hash.c linebreak.c localcharset.c mbswidth.c \
+obstack.c pipe-bidi.c pipe-in.c pipe-out.c progname.c safe-read.c \
+wait-process.c xerror.c xgetcwd.c xmalloc.c xstrdup.c
 
 libnlsut_a_LIBADD = @ALLOCA@ @LIBOBJS@
 
-noinst_HEADERS = c-ctype.h error.h fstrcmp.h getline.h getopt.h hash.h \
-lbrkprop.h linebreak.h mbswidth.h obstack.h pathmax.h printf-parse.h printf.h \
-progname.h system.h xerror.h
+noinst_HEADERS = c-ctype.h error.h findprog.h fstrcmp.h full-write.h \
+getline.h getopt.h hash.h lbrkprop.h linebreak.h mbswidth.h obstack.h \
+pathmax.h pipe.h printf-parse.h printf.h progname.h safe-read.h system.h \
+wait-process.h xerror.h
 
 DEFS = -DLIBDIR=\"$(libdir)\" @DEFS@
 INCLUDES = -I. -I$(srcdir) -I.. -I../intl
diff --git a/lib/findprog.c b/lib/findprog.c
new file mode 100644 (file)
index 0000000..b2ab40a
--- /dev/null
@@ -0,0 +1,111 @@
+/* Locating a program in PATH.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
+
+   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.  */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "findprog.h"
+#include "system.h"
+
+
+const char *
+find_in_path (progname)
+     const char *progname;
+{
+#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
+  /* Win32, OS/2, DOS */
+  /* The searching rules with .COM, .EXE, .BAT, .CMD etc. suffixes are
+     too complicated.  Leave it to the OS.  */
+  return progname;
+#else
+  /* Unix */
+  char *path;
+  char *dir;
+  char *cp;
+
+  if (strchr (progname, '/') != NULL)
+    /* If progname contains a slash, it is either absolute or relative to
+       the current directory.  PATH is not used.  */
+    return progname;
+
+  path = getenv ("PATH");
+  if (path == NULL || *path == '\0')
+    /* If PATH is not set, the default search path is implementation
+       dependent.  */
+    return progname;
+
+  /* Make a copy, to prepare for destructive modifications.  */
+  path = xstrdup (path);
+  for (dir = path; ; dir = cp + 1)
+    {
+      int last;
+      char *progpathname;
+
+      /* Extract next directory in PATH.  */
+      for (cp = dir; *cp != '\0' && *cp != ':'; cp++);
+      last = (*cp == '\0');
+      *cp = '\0';
+
+      /* Empty PATH components designate the current directory.  */
+      if (dir == cp)
+       dir = ".";
+
+      /* Concatenate dir and progname.  */
+      progpathname = concatenated_pathname (dir, progname, NULL);
+
+      /* This program is usually not installed setuid or setgid, therefore
+        it is ok to call access() despite its design flaw.  */
+      if (access (progpathname, X_OK) == 0)
+       {
+         /* Found!  */
+         if (strcmp (progpathname, progname) == 0)
+           {
+             free (progpathname);
+
+             /* Add the "./" prefix for real, that concatenated_pathname()
+                optimized away.  */
+             progpathname = xmalloc (2 + strlen (progname) + 1);
+             progpathname[0] = '.';
+             progpathname[1] = '/';
+             memcpy (progpathname + 2, progname, strlen (progname) + 1);
+           }
+
+         free (path);
+         return progpathname;
+       }
+
+      free (progpathname);
+
+      if (last)
+       break;
+    }
+
+  /* Not found in PATH.  An error will be signalled at the first call.  */
+  free (path);
+  return progname;
+#endif
+}
diff --git a/lib/findprog.h b/lib/findprog.h
new file mode 100644 (file)
index 0000000..3a0d135
--- /dev/null
@@ -0,0 +1,24 @@
+/* Locating a program in PATH.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
+
+   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.  */
+
+/* Look up a program in the PATH.
+   Attempt to determine the pathname that would be called by execlp/execvp
+   of PROGNAME.  If successful, return a pathname containing a slash
+   (either absolute or relative to the current directory).  Otherwise,
+   return PROGNAME unmodified.  */
+extern const char *find_in_path PARAMS ((const char *progname));
diff --git a/lib/full-write.c b/lib/full-write.c
new file mode 100644 (file)
index 0000000..13eae22
--- /dev/null
@@ -0,0 +1,71 @@
+/* full-write.c -- an interface to write that retries after interrupts
+   Copyright (C) 1993-1994, 1997-1998, 2000, 2001 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.
+
+   Copied largely from GNU C's cccp.c.
+   */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+#include "full-write.h"
+
+/* Write LEN bytes at PTR to descriptor DESC, retrying if interrupted.
+   Return LEN upon success, write's (negative) error code otherwise.  */
+
+ssize_t
+full_write (desc, ptr, len)
+     int desc;
+     const char *ptr;
+     size_t len;
+{
+  int total_written;
+
+  total_written = 0;
+  while (len > 0)
+    {
+      ssize_t written = write (desc, ptr, len);
+      /* write on an old Slackware Linux 1.2.13 returns zero when
+        I try to write more data than there is room on a floppy disk.
+        This puts dd into an infinite loop.  Reproduce with
+        dd if=/dev/zero of=/dev/fd0.  If you have this problem,
+        consider upgrading to a newer kernel.  */
+      if (written < 0)
+       {
+#ifdef EINTR
+         if (errno == EINTR)
+           continue;
+#endif
+         return written;
+       }
+      total_written += written;
+      ptr += written;
+      len -= written;
+    }
+  return total_written;
+}
diff --git a/lib/full-write.h b/lib/full-write.h
new file mode 100644 (file)
index 0000000..d7070a2
--- /dev/null
@@ -0,0 +1,27 @@
+/* write() wrapper.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
+
+   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.  */
+
+/* Get ssize_t.  */
+#include <sys/types.h>
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+/* Write LEN bytes at PTR to descriptor DESC, retrying if interrupted.
+   Return LEN upon success, write's (negative) error code otherwise.  */
+extern ssize_t full_write PARAMS ((int desc, const char *ptr, size_t len));
diff --git a/lib/pipe-bidi.c b/lib/pipe-bidi.c
new file mode 100644 (file)
index 0000000..fe20777
--- /dev/null
@@ -0,0 +1,150 @@
+/* Creation of subprocesses, communicating via pipes.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
+
+   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.  */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_POSIX_SPAWN
+# include <spawn.h>
+#else
+# ifdef HAVE_VFORK_H
+#  include <vfork.h>
+# endif
+#endif
+
+#include "error.h"
+#include "libgettext.h"
+
+#ifndef STDIN_FILENO
+# define STDIN_FILENO 0
+#endif
+#ifndef STDOUT_FILENO
+# define STDOUT_FILENO 1
+#endif
+
+#define _(str) gettext (str)
+
+
+#ifdef EINTR
+
+/* EINTR handling for close().
+   These functions can return -1/EINTR even though we don't have any
+   signal handlers set up, namely when we get interrupted via SIGSTOP.  */
+
+static inline int
+nonintr_close (fd)
+     int fd;
+{
+  int retval;
+
+  do
+    retval = close (fd);
+  while (retval < 0 && errno == EINTR);
+
+  return retval;
+}
+#define close nonintr_close
+
+#endif
+
+
+/* Open a bidirectional pipe.
+ *
+ *           write       system                read
+ *    parent  ->   fd[1]   ->   STDIN_FILENO    ->   child
+ *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child
+ *           read        system                write
+ *
+ */
+pid_t
+create_pipe_bidi (progname, prog_path, prog_argv, fd)
+     const char *progname;
+     const char *prog_path;
+     char **prog_argv;
+     int fd[2];
+{
+  int ifd[2];
+  int ofd[2];
+#if HAVE_POSIX_SPAWN
+  posix_spawn_file_actions_t actions;
+  int err;
+  pid_t child;
+#else
+  int child;
+#endif
+
+  if (pipe (ifd) < 0)
+    error (EXIT_FAILURE, errno, _("cannot create pipe"));
+  if (pipe (ofd) < 0)
+    error (EXIT_FAILURE, errno, _("cannot create pipe"));
+/* Data flow diagram:
+ *
+ *           write        system         read
+ *    parent  ->   ofd[1]   ->   ofd[0]   ->   child
+ *    parent  <-   ifd[0]   <-   ifd[1]   <-   child
+ *           read         system         write
+ *
+ */
+
+#if HAVE_POSIX_SPAWN
+  if ((err = posix_spawn_file_actions_init (&actions)) != 0
+      || (err = posix_spawn_file_actions_adddup2 (&actions,
+                                                 ofd[0], STDIN_FILENO)) != 0
+      || (err = posix_spawn_file_actions_adddup2 (&actions,
+                                                 ifd[1], STDOUT_FILENO)) != 0
+      || (err = posix_spawn_file_actions_addclose (&actions, ofd[0])) != 0
+      || (err = posix_spawn_file_actions_addclose (&actions, ifd[1])) != 0
+      || (err = posix_spawn_file_actions_addclose (&actions, ofd[1])) != 0
+      || (err = posix_spawn_file_actions_addclose (&actions, ifd[0])) != 0
+      || (err = posix_spawnp (&child, prog_path, &actions, NULL, prog_argv,
+                             environ)) != 0)
+    error (EXIT_FAILURE, err, _("%s subprocess failed"), progname);
+  posix_spawn_file_actions_destroy (&actions);
+#else
+  /* Use vfork() instead of fork() for efficiency.  */
+  if ((child = vfork ()) == 0)
+    {
+      /* Child process code.  */
+      if (dup2 (ofd[0], STDIN_FILENO) >= 0
+         && dup2 (ifd[1], STDOUT_FILENO) >= 0
+         && close (ofd[0]) >= 0
+         && close (ifd[1]) >= 0
+         && close (ofd[1]) >= 0
+         && close (ifd[0]) >= 0)
+       execvp (prog_path, prog_argv);
+      _exit (-1);
+    }
+  if (child == -1)
+    error (EXIT_FAILURE, errno, _("%s subprocess failed"), prog_argv);
+#endif
+  close (ofd[0]);
+  close (ifd[1]);
+
+  fd[0] = ifd[0];
+  fd[1] = ofd[1];
+  return child;
+}
diff --git a/lib/pipe-in.c b/lib/pipe-in.c
new file mode 100644 (file)
index 0000000..ba63f3d
--- /dev/null
@@ -0,0 +1,161 @@
+/* Creation of subprocesses, communicating via pipes.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
+
+   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.  */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_POSIX_SPAWN
+# include <spawn.h>
+#else
+# ifdef HAVE_VFORK_H
+#  include <vfork.h>
+# endif
+#endif
+
+#include "error.h"
+#include "libgettext.h"
+
+#ifndef STDIN_FILENO
+# define STDIN_FILENO 0
+#endif
+#ifndef STDOUT_FILENO
+# define STDOUT_FILENO 1
+#endif
+
+#define _(str) gettext (str)
+
+
+#ifdef EINTR
+
+/* EINTR handling for close(), open().
+   These functions can return -1/EINTR even though we don't have any
+   signal handlers set up, namely when we get interrupted via SIGSTOP.  */
+
+static inline int
+nonintr_close (fd)
+     int fd;
+{
+  int retval;
+
+  do
+    retval = close (fd);
+  while (retval < 0 && errno == EINTR);
+
+  return retval;
+}
+#define close nonintr_close
+
+static inline int
+nonintr_open (pathname, oflag, mode)
+     const char *pathname;
+     int oflag;
+     mode_t mode;
+{
+  int retval;
+
+  do
+    retval = open (pathname, oflag, mode);
+  while (retval < 0 && errno == EINTR);
+
+  return retval;
+}
+#define open nonintr_open
+
+#endif
+
+
+/* Open a pipe for input from a child process.
+ * The child's stdin comes to a file.
+ *
+ *           read        system                write
+ *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child
+ *
+ */
+pid_t
+create_pipe_in (progname, prog_path, prog_argv, prog_stdin, fd)
+     const char *progname;
+     const char *prog_path;
+     char **prog_argv;
+     const char *prog_stdin;
+     int fd[1];
+{
+  int ifd[2];
+#if HAVE_POSIX_SPAWN
+  posix_spawn_file_actions_t actions;
+  int err;
+  pid_t child;
+#else
+  int child;
+#endif
+
+  if (pipe (ifd) < 0)
+    error (EXIT_FAILURE, errno, _("cannot create pipe"));
+/* Data flow diagram:
+ *
+ *           read        system         write
+ *    parent  <-  ifd[0]   <-   ifd[1]   <-   child
+ */
+
+#if HAVE_POSIX_SPAWN
+  if ((err = posix_spawn_file_actions_init (&actions)) != 0
+      || (err = posix_spawn_file_actions_adddup2 (&actions,
+                                                 ifd[1], STDOUT_FILENO)) != 0
+      || (err = posix_spawn_file_actions_addclose (&actions, ifd[1])) != 0
+      || (err = posix_spawn_file_actions_addclose (&actions, ifd[0])) != 0
+      || (err = posix_spawn_file_actions_addopen (&actions, STDIN_FILENO,
+                                                 prog_stdin, O_RDONLY,
+                                                 0)) != 0
+      || (err = posix_spawnp (&child, prog_path, &actions, NULL, prog_argv,
+                             environ)) != 0)
+    error (EXIT_FAILURE, err, _("%s subprocess failed"), progname);
+  posix_spawn_file_actions_destroy (&actions);
+#else
+  /* Use vfork() instead of fork() for efficiency.  */
+  if ((child = vfork ()) == 0)
+    {
+      /* Child process code.  */
+      int stdinfd;
+
+      if (dup2 (ifd[1], STDOUT_FILENO) >= 0
+         && close (ifd[1]) >= 0
+         && close (ifd[0]) >= 0
+         && (stdinfd = open (prog_stdin, O_RDONLY, 0)) >= 0
+         && (stdinfd == STDIN_FILENO
+             || (dup2 (stdinfd, STDIN_FILENO) >= 0
+                 && close (stdinfd) >= 0)))
+       execvp (prog_path, prog_argv);
+      _exit (-1);
+    }
+  if (child == -1)
+    error (EXIT_FAILURE, errno, _("%s subprocess failed"), progname);
+#endif
+  close (ifd[1]);
+
+  fd[0] = ifd[0];
+  return child;
+}
diff --git a/lib/pipe-out.c b/lib/pipe-out.c
new file mode 100644 (file)
index 0000000..3621dac
--- /dev/null
@@ -0,0 +1,161 @@
+/* Creation of subprocesses, communicating via pipes.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
+
+   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.  */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_POSIX_SPAWN
+# include <spawn.h>
+#else
+# ifdef HAVE_VFORK_H
+#  include <vfork.h>
+# endif
+#endif
+
+#include "error.h"
+#include "libgettext.h"
+
+#ifndef STDIN_FILENO
+# define STDIN_FILENO 0
+#endif
+#ifndef STDOUT_FILENO
+# define STDOUT_FILENO 1
+#endif
+
+#define _(str) gettext (str)
+
+
+#ifdef EINTR
+
+/* EINTR handling for close(), open().
+   These functions can return -1/EINTR even though we don't have any
+   signal handlers set up, namely when we get interrupted via SIGSTOP.  */
+
+static inline int
+nonintr_close (fd)
+     int fd;
+{
+  int retval;
+
+  do
+    retval = close (fd);
+  while (retval < 0 && errno == EINTR);
+
+  return retval;
+}
+#define close nonintr_close
+
+static inline int
+nonintr_open (pathname, oflag, mode)
+     const char *pathname;
+     int oflag;
+     mode_t mode;
+{
+  int retval;
+
+  do
+    retval = open (pathname, oflag, mode);
+  while (retval < 0 && errno == EINTR);
+
+  return retval;
+}
+#define open nonintr_open
+
+#endif
+
+
+/* Open a pipe for output to a child process.
+ * The child's stdout goes to a file.
+ *
+ *           write       system                read
+ *    parent  ->   fd[0]   ->   STDIN_FILENO    ->   child
+ *
+ */
+pid_t
+create_pipe_out (progname, prog_path, prog_argv, prog_stdout, fd)
+     const char *progname;
+     const char *prog_path;
+     char **prog_argv;
+     const char *prog_stdout;
+     int fd[1];
+{
+  int ofd[2];
+#if HAVE_POSIX_SPAWN
+  posix_spawn_file_actions_t actions;
+  int err;
+  pid_t child;
+#else
+  int child;
+#endif
+
+  if (pipe (ofd) < 0)
+    error (EXIT_FAILURE, errno, _("cannot create pipe"));
+/* Data flow diagram:
+ *
+ *           write        system         read
+ *    parent  ->   ofd[1]   ->   ofd[0]   ->   child
+ */
+
+#if HAVE_POSIX_SPAWN
+  if ((err = posix_spawn_file_actions_init (&actions)) != 0
+      || (err = posix_spawn_file_actions_adddup2 (&actions,
+                                                 ofd[0], STDIN_FILENO)) != 0
+      || (err = posix_spawn_file_actions_addclose (&actions, ofd[0])) != 0
+      || (err = posix_spawn_file_actions_addclose (&actions, ofd[1])) != 0
+      || (err = posix_spawn_file_actions_addopen (&actions, STDOUT_FILENO,
+                                                 prog_stdout, O_WRONLY,
+                                                 0)) != 0
+      || (err = posix_spawnp (&child, prog_path, &actions, NULL, prog_argv,
+                             environ)) != 0)
+    error (EXIT_FAILURE, err, _("%s subprocess failed"), progname);
+  posix_spawn_file_actions_destroy (&actions);
+#else
+  /* Use vfork() instead of fork() for efficiency.  */
+  if ((child = vfork ()) == 0)
+    {
+      /* Child process code.  */
+      int stdoutfd;
+
+      if (dup2 (ofd[0], STDIN_FILENO) >= 0
+         && close (ofd[0]) >= 0
+         && close (ofd[1]) >= 0
+         && (stdoutfd = open (prog_stdout, O_WRONLY, 0)) >= 0
+         && (stdoutfd == STDOUT_FILENO
+             || (dup2 (stdoutfd, STDOUT_FILENO) >= 0
+                 && close (stdoutfd) >= 0)))
+       execvp (prog_path, prog_argv);
+      _exit (-1);
+    }
+  if (child == -1)
+    error (EXIT_FAILURE, errno, _("%s subprocess failed"), progname);
+#endif
+  close (ofd[0]);
+
+  fd[0] = ofd[1];
+  return child;
+}
diff --git a/lib/pipe.h b/lib/pipe.h
new file mode 100644 (file)
index 0000000..cb45cfb
--- /dev/null
@@ -0,0 +1,58 @@
+/* Creation of subprocesses, communicating via pipes.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
+
+   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 _PIPE_H
+#define _PIPE_H
+
+/* Open a pipe for output to a child process.
+ * The child's stdout goes to a file.
+ *
+ *           write       system                read
+ *    parent  ->   fd[0]   ->   STDIN_FILENO    ->   child
+ *
+ */
+extern pid_t create_pipe_out PARAMS ((const char *progname,
+                                     const char *prog_path, char **prog_argv,
+                                     const char *prog_stdout,
+                                     int fd[1]));
+
+/* Open a pipe for input from a child process.
+ * The child's stdin comes to a file.
+ *
+ *           read        system                write
+ *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child
+ *
+ */
+extern pid_t create_pipe_in PARAMS ((const char *progname,
+                                    const char *prog_path, char **prog_argv,
+                                    const char *prog_stdin,
+                                    int fd[1]));
+
+/* Open a bidirectional pipe.
+ *
+ *           write       system                read
+ *    parent  ->   fd[1]   ->   STDIN_FILENO    ->   child
+ *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child
+ *           read        system                write
+ *
+ */
+extern pid_t create_pipe_bidi PARAMS ((const char *progname,
+                                      const char *prog_path, char **prog_argv,
+                                      int fd[2]));
+
+#endif /* _PIPE_H */
diff --git a/lib/safe-read.c b/lib/safe-read.c
new file mode 100644 (file)
index 0000000..d362e48
--- /dev/null
@@ -0,0 +1,62 @@
+/* safe-read.c -- an interface to read that retries after interrupts
+   Copyright (C) 1993-1994, 1998, 2001 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 <sys/types.h>
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+#include "safe-read.h"
+
+/* Read LEN bytes at PTR from descriptor DESC, retrying if interrupted.
+   Return the actual number of bytes read, zero for EOF, or negative
+   for an error.  */
+
+ssize_t
+safe_read (desc, ptr, len)
+     int desc;
+     void *ptr;
+     size_t len;
+{
+  ssize_t n_chars;
+
+  if (len <= 0)
+    return len;
+
+#ifdef EINTR
+  do
+    {
+      n_chars = read (desc, ptr, len);
+    }
+  while (n_chars < 0 && errno == EINTR);
+#else
+  n_chars = read (desc, ptr, len);
+#endif
+
+  return n_chars;
+}
diff --git a/lib/safe-read.h b/lib/safe-read.h
new file mode 100644 (file)
index 0000000..1b111a6
--- /dev/null
@@ -0,0 +1,28 @@
+/* read() wrapper.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
+
+   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.  */
+
+/* Get ssize_t.  */
+#include <sys/types.h>
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+/* Read LEN bytes at PTR from descriptor DESC, retrying if interrupted.
+   Return the actual number of bytes read, zero for EOF, or negative
+   for an error.  */
+extern ssize_t safe_read PARAMS ((int desc, void *ptr, size_t len));
diff --git a/lib/wait-process.c b/lib/wait-process.c
new file mode 100644 (file)
index 0000000..8939942
--- /dev/null
@@ -0,0 +1,119 @@
+/* Waiting for a subprocess to finish.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
+
+   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.  */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+
+#include <sys/wait.h>
+/* On Linux, WEXITSTATUS are bits 15..8 and WTERMSIG are bits 7..0, while
+   BeOS uses the contrary.  Therefore we use the abstract macros.  */
+#if HAVE_UNION_WAIT
+# define WAIT_T union wait
+# ifndef WTERMSIG
+#  define WTERMSIG(x) ((x).w_termsig)
+# endif
+# ifndef WCOREDUMP
+#  define WCOREDUMP(x) ((x).w_coredump)
+# endif
+# ifndef WEXITSTATUS
+#  define WEXITSTATUS(x) ((x).w_retcode)
+# endif
+# ifndef WIFSIGNALED
+#  define WIFSIGNALED(x) (WTERMSIG(x) != 0)
+# endif
+# ifndef WIFEXITED
+#  define WIFEXITED(x) (WTERMSIG(x) == 0)
+# endif
+# ifndef WIFSTOPPED
+#  define WIFSTOPPED(x) (WTERMSIG(x) == 0x7f)
+# endif
+#else
+# define WAIT_T int
+# ifndef WTERMSIG
+#  define WTERMSIG(x) ((x) & 0x7f)
+# endif
+# ifndef WCOREDUMP
+#  define WCOREDUMP(x) ((x) & 0x80)
+# endif
+# ifndef WEXITSTATUS
+#  define WEXITSTATUS(x) (((x) >> 8) & 0xff)
+# endif
+# ifndef WIFSIGNALED
+#  define WIFSIGNALED(x) (WTERMSIG (x) != 0)
+# endif
+# ifndef WIFEXITED
+#  define WIFEXITED(x) (WTERMSIG (x) == 0)
+# endif
+# ifndef WIFSTOPPED
+#  define WIFSTOPPED(x) (WTERMSIG(x) == 0x7f)
+# endif
+#endif
+
+#include "wait-process.h"
+#include "error.h"
+#include "libgettext.h"
+
+#define _(str) gettext (str)
+
+
+int
+wait_subprocess (child, progname)
+     pid_t child;
+     const char *progname;
+{
+  /* waitpid() is just as portable as wait() nowadays.  */
+  WAIT_T status;
+
+  *(int *) &status = 0;
+  for (;;)
+    {
+      int result = waitpid (child, &status, 0);
+
+      if (result != child)
+       {
+#ifdef EINTR
+         if (errno == EINTR)
+           continue;
+#endif
+#if 0 /* defined ECHILD */
+         if (errno == ECHILD)
+           {
+             /* Child process nonexistent?! Assume it terminated
+                successfully.  */
+             *(int *) &status = 0;
+             break;
+           }
+#endif
+         error (EXIT_FAILURE, errno, _("%s subprocess"), progname);
+       }
+
+      if (!WIFSTOPPED (status))
+       break;
+    }
+
+  if (WCOREDUMP (status) || WTERMSIG (status) != 0)
+    error (EXIT_FAILURE, 0, _("%s subprocess got fatal signal"), progname);
+  return WEXITSTATUS (status);
+}
diff --git a/lib/wait-process.h b/lib/wait-process.h
new file mode 100644 (file)
index 0000000..23dd0ec
--- /dev/null
@@ -0,0 +1,26 @@
+/* Waiting for a subprocess to finish.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
+
+   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 _WAIT_PROCESS_H
+#define _WAIT_PROCESS_H
+
+/* Wait for a subprocess to finish.  Exit if it didn't terminate
+   correctly.  Otherwise return its exit code.  */
+extern int wait_subprocess PARAMS ((pid_t child, const char *progname));
+
+#endif /* _WAIT_PROCESS_H */
index b8ccaccb6cd8ea1b3d2a83054e4b1bd438ba2ef5..073537dea2d821e3bb6bef92686d00a07a9e295c 100644 (file)
@@ -1,3 +1,9 @@
+2001-06-10  Bruno Haible  <haible@clisp.cons.org>
+
+       * ssize_t.m4: New file.
+       * unionwait.m4: New file.
+       * Makefile.am (EXTRA_DIST): Add them.
+
 2001-06-08  Bruno Haible  <haible@clisp.cons.org>
 
        * libtool.m4: Upgrade to libtool-1.4.
index e10aa2c46ca41ebf8f7d84016ffaa8c3c99f0493..ed70d60972e4f26360e7c2aadcf0705102f84a49 100644 (file)
@@ -9,4 +9,5 @@ aclocal_DATA = codeset.m4 gettext.m4 glibc21.m4 iconv.m4 isc-posix.m4 lcmessage.
 EXTRA_DIST = README \
 c-bs-a.m4 codeset.m4 getline.m4 gettext.m4 glibc21.m4 iconv.m4 \
 inttypes_h.m4 isc-posix.m4 lcmessage.m4 libtool.m4 mbrtowc.m4 mbstate_t.m4 \
-mbswidth.m4 progtest.m4 setlocale.m4 signed.m4 uintmax_t.m4 ulonglong.m4
+mbswidth.m4 progtest.m4 setlocale.m4 signed.m4 ssize_t.m4 uintmax_t.m4 \
+ulonglong.m4 unionwait.m4
diff --git a/m4/ssize_t.m4 b/m4/ssize_t.m4
new file mode 100644 (file)
index 0000000..3c75038
--- /dev/null
@@ -0,0 +1,20 @@
+# serial 1
+
+dnl From Bruno Haible.
+dnl Test whether ssize_t is defined.
+dnl Prerequisite: AC_CHECK_HEADERS(unistd.h)
+
+AC_DEFUN([gt_TYPE_SSIZE_T],
+[
+  AC_CACHE_CHECK([for ssize_t], gt_cv_ssize_t,
+    [AC_TRY_COMPILE([
+#include <sys/types.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif], [int x = sizeof (ssize_t *) + sizeof (ssize_t);],
+       gt_cv_ssize_t=yes, gt_cv_ssize_t=no)])
+  if test $gt_cv_ssize_t = no; then
+    AC_DEFINE(ssize_t, int,
+              [Define as a signed type of the same size as size_t.])
+  fi
+])
diff --git a/m4/unionwait.m4 b/m4/unionwait.m4
new file mode 100644 (file)
index 0000000..03694bf
--- /dev/null
@@ -0,0 +1,32 @@
+dnl Taken from GNU make 3.79.1.
+
+AC_DEFUN([gt_UNION_WAIT],
+[
+AC_CHECK_FUNCS(waitpid)
+AC_MSG_CHECKING(for union wait)
+AC_CACHE_VAL(gt_cv_union_wait, [dnl
+AC_TRY_LINK([#include <sys/types.h>
+#include <sys/wait.h>],
+           [union wait status; int pid; pid = wait (&status);
+#ifdef WEXITSTATUS
+/* Some POSIXoid systems have both the new-style macros and the old
+   union wait type, and they do not work together.  If union wait
+   conflicts with WEXITSTATUS et al, we don't want to use it at all.  */
+if (WEXITSTATUS (status) != 0) pid = -1;
+#ifdef WTERMSIG
+/* If we have WEXITSTATUS and WTERMSIG, just use them on ints.  */
+-- blow chunks here --
+#endif
+#endif
+#ifdef HAVE_WAITPID
+/* Make sure union wait works with waitpid.  */
+pid = waitpid (-1, &status, 0);
+#endif
+],
+           [gt_cv_union_wait=yes], [gt_cv_union_wait=no])])
+if test "$gt_cv_union_wait" = yes; then
+  AC_DEFINE(HAVE_UNION_WAIT, 1,
+            [Define if <sys/wait.h> defines the 'union wait' type.])
+fi
+AC_MSG_RESULT($gt_cv_union_wait)
+])
index ab202780d722f8dbc920721689ea5de8f318ae42..532af9f77c3acb78351c3ec433d2e2e9ee0a53a3 100644 (file)
@@ -1,3 +1,8 @@
+2001-06-10  Bruno Haible  <haible@clisp.cons.org>
+
+       * POTFILES.in: Add lib/pipe-bidi.c, lib/pipe-in.c, lib/pipe-out.c,
+       lib/wait-process.c.
+
 2001-06-08  Bruno Haible  <haible@clisp.cons.org>
 
        * ko.po: Update from Changwoo Ryu <cwryu@debian.org>.
index cbb18c6e343a34b4309f17840276276b4a124716..51dbcd52cce6529814a6a5858df367a0b6655590 100644 (file)
@@ -8,6 +8,10 @@
 lib/error.c
 lib/getopt.c
 lib/obstack.c
+lib/pipe-bidi.c
+lib/pipe-in.c
+lib/pipe-out.c
+lib/wait-process.c
 lib/xerror.c
 lib/xmalloc.c