From: Bruno Haible Date: Tue, 12 Jun 2001 12:44:54 +0000 (+0000) Subject: New library functions for msgcat, msgconv, msgen, msggrep, msgsed. X-Git-Tag: v0.11~673 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bc0e9e372fe046e28235851e2243a5e7d332a45e;p=thirdparty%2Fgettext.git New library functions for msgcat, msgconv, msgen, msggrep, msgsed. --- diff --git a/ChangeLog b/ChangeLog index 44ede11fe..8489fa3fb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2001-06-10 Bruno Haible + + * configure.in: Check for ssize_t, pid_t, posix_spawn, select. + Call AC_FUNC_VFORK, gt_UNION_WAIT. + 2001-06-08 Bruno Haible * ltmain.sh: Upgrade to libtool-1.4. diff --git a/configure.in b/configure.in index fea05f247..ee7c87c30 100644 --- a/configure.in +++ b/configure.in @@ -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) diff --git a/lib/ChangeLog b/lib/ChangeLog index 4b8af78e2..016cff597 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,22 @@ +2001-06-10 Bruno Haible + + * 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 * progname.h (set_program_name): New declaration. diff --git a/lib/Makefile.am b/lib/Makefile.am index 06f59c651..84ac17f57 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -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 index 000000000..b2ab40a37 --- /dev/null +++ b/lib/findprog.c @@ -0,0 +1,111 @@ +/* Locating a program in PATH. + Copyright (C) 2001 Free Software Foundation, Inc. + Written by Bruno Haible , 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 +#include + +#ifdef HAVE_UNISTD_H +# include +#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 index 000000000..3a0d13526 --- /dev/null +++ b/lib/findprog.h @@ -0,0 +1,24 @@ +/* Locating a program in PATH. + Copyright (C) 2001 Free Software Foundation, Inc. + Written by Bruno Haible , 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 index 000000000..13eae22dc --- /dev/null +++ b/lib/full-write.c @@ -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 +#endif + +#include + +#if HAVE_UNISTD_H +# include +#endif + +#include +#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 index 000000000..d7070a2f0 --- /dev/null +++ b/lib/full-write.h @@ -0,0 +1,27 @@ +/* write() wrapper. + Copyright (C) 2001 Free Software Foundation, Inc. + Written by Bruno Haible , 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 +#if HAVE_UNISTD_H +# include +#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 index 000000000..fe207778e --- /dev/null +++ b/lib/pipe-bidi.c @@ -0,0 +1,150 @@ +/* Creation of subprocesses, communicating via pipes. + Copyright (C) 2001 Free Software Foundation, Inc. + Written by Bruno Haible , 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 +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifdef HAVE_POSIX_SPAWN +# include +#else +# ifdef HAVE_VFORK_H +# include +# 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 index 000000000..ba63f3da2 --- /dev/null +++ b/lib/pipe-in.c @@ -0,0 +1,161 @@ +/* Creation of subprocesses, communicating via pipes. + Copyright (C) 2001 Free Software Foundation, Inc. + Written by Bruno Haible , 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 +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifdef HAVE_POSIX_SPAWN +# include +#else +# ifdef HAVE_VFORK_H +# include +# 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 index 000000000..3621dacd2 --- /dev/null +++ b/lib/pipe-out.c @@ -0,0 +1,161 @@ +/* Creation of subprocesses, communicating via pipes. + Copyright (C) 2001 Free Software Foundation, Inc. + Written by Bruno Haible , 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 +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifdef HAVE_POSIX_SPAWN +# include +#else +# ifdef HAVE_VFORK_H +# include +# 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 index 000000000..cb45cfb59 --- /dev/null +++ b/lib/pipe.h @@ -0,0 +1,58 @@ +/* Creation of subprocesses, communicating via pipes. + Copyright (C) 2001 Free Software Foundation, Inc. + Written by Bruno Haible , 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 index 000000000..d362e48b6 --- /dev/null +++ b/lib/safe-read.c @@ -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 +#endif + +#include + +#if HAVE_UNISTD_H +# include +#endif + +#include +#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 index 000000000..1b111a66f --- /dev/null +++ b/lib/safe-read.h @@ -0,0 +1,28 @@ +/* read() wrapper. + Copyright (C) 2001 Free Software Foundation, Inc. + Written by Bruno Haible , 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 +#if HAVE_UNISTD_H +# include +#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 index 000000000..89399425a --- /dev/null +++ b/lib/wait-process.c @@ -0,0 +1,119 @@ +/* Waiting for a subprocess to finish. + Copyright (C) 2001 Free Software Foundation, Inc. + Written by Bruno Haible , 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 +#include + +#include + +#include +/* 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 index 000000000..23dd0ecf0 --- /dev/null +++ b/lib/wait-process.h @@ -0,0 +1,26 @@ +/* Waiting for a subprocess to finish. + Copyright (C) 2001 Free Software Foundation, Inc. + Written by Bruno Haible , 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 */ diff --git a/m4/ChangeLog b/m4/ChangeLog index b8ccaccb6..073537dea 100644 --- a/m4/ChangeLog +++ b/m4/ChangeLog @@ -1,3 +1,9 @@ +2001-06-10 Bruno Haible + + * ssize_t.m4: New file. + * unionwait.m4: New file. + * Makefile.am (EXTRA_DIST): Add them. + 2001-06-08 Bruno Haible * libtool.m4: Upgrade to libtool-1.4. diff --git a/m4/Makefile.am b/m4/Makefile.am index e10aa2c46..ed70d6097 100644 --- a/m4/Makefile.am +++ b/m4/Makefile.am @@ -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 index 000000000..3c7503890 --- /dev/null +++ b/m4/ssize_t.m4 @@ -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 +#if HAVE_UNISTD_H +#include +#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 index 000000000..03694bf6c --- /dev/null +++ b/m4/unionwait.m4 @@ -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 +#include ], + [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 defines the 'union wait' type.]) +fi +AC_MSG_RESULT($gt_cv_union_wait) +]) diff --git a/po/ChangeLog b/po/ChangeLog index ab202780d..532af9f77 100644 --- a/po/ChangeLog +++ b/po/ChangeLog @@ -1,3 +1,8 @@ +2001-06-10 Bruno Haible + + * POTFILES.in: Add lib/pipe-bidi.c, lib/pipe-in.c, lib/pipe-out.c, + lib/wait-process.c. + 2001-06-08 Bruno Haible * ko.po: Update from Changwoo Ryu . diff --git a/po/POTFILES.in b/po/POTFILES.in index cbb18c6e3..51dbcd52c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -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