Update.
[kopensolaris-gnu/glibc.git] / posix / wordexp.c
index 9f7d485..52869fe 100644 (file)
@@ -1,45 +1,62 @@
-/* Copyright (C) 1992 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
+/* Copyright (C) 1992, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
 
-The GNU C Library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
 
-The GNU C Library 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
-Library General Public License for more details.
+   The GNU C Library 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
+   Library General Public License for more details.
 
-You should have received a copy of the GNU Library General Public
-License along with the GNU C Library; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA.  */
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
 
-#include <ansidecl.h>
 #include <sys/types.h>
 #include <wordexp.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <sys/wait.h>
+#include <signal.h>
+
+
+/* We do word expansion with a pipe to the shell.
+   The shell command `sh [-P] [-u] -w "words ..."' expands words.
+   If -P, command substitution is an error.
+   If -u, reference to an undefined variable is an error.
+   The shell writes on its stdout:
+       %u\0    Number of words.
+       %u\0    Number of bytes in all words together (not counting \0s).
+       word1\0
+       word2\0
+       ...
+       wordN\0
+   */
+
+#define        SHELL_PATH      "/bin/sh"
+#define        SHELL_NAME      "sh"
+
 
 int
-DEFUN(wordexp, (string, pwordexp, flags),
-      CONST char *string AND wordexp_t *pwordexp AND int flags)
+wordexp (string, pwordexp, flags)
+     const char *string;
+     wordexp_t *pwordexp;
+     int flags;
 {
   int error;
   pid_t pid;
   int d[2];
   int status;
 
-  struct word
-    {
-      struct word *next;
-      char *word;
-    } *words;
-  size_t nwords, wordc, i;
   FILE *f;
+  size_t wordc, start, buflen;
+  char *buf;
 
+  /* Create the pipe through which we will communicate to the shell.  */
   if (pipe (d) < 0)
     return -1;
 
@@ -51,49 +68,48 @@ DEFUN(wordexp, (string, pwordexp, flags),
     {
       /* Child.  Run the shell.  */
 
-      CONST char fmt[]
-       = "for word in %s; do echo -n \"$word\"; echo -e \\\\000; done";
-      char flags[] = "-Puc", *f = &flags[1];
-      char *buffer = (char *) __alloca (fmt - 2 + strlen (string));
-      if (flags & WRDE_NOCMD)
-       *f++ = 'P';
-      if (flags & WRDE_UNDEF)
-       *f++ = 'u';
-      *f++ = 'c';
-      *f = '\0';
-      sprintf (buffer, fmt, string);
+      const char *argv[5];
+
       close (d[STDIN_FILENO]);
       dup2 (d[STDOUT_FILENO], STDOUT_FILENO);
       if (!(flags & WRDE_SHOWERR))
        close (STDERR_FILENO);
-      execl (SHELL_PATH, SHELL_NAME, flags, buffer, (char *) NULL);
-      _exit (WRDE_ABEND);
+
+      i = 0;
+      argv[i++] = SHELL_NAME;
+      if (flags & WRDE_NOCMD)
+       argv[i++] = "-P";
+      if (flags & WRDE_UNDEF)
+       argv[i++] = "-u";
+      argv[i++] = "-w";
+      argv[i++] = string;
+      argv[i++] = NULL;
+
+      execv (SHELL_PATH, argv);
+      _exit (WRDE_NOSPACE);
     }
 
   /* Parent.  */
 
-  words = NULL;
-  nwords = 0;
-  lose = WRDE_NOSPACE;
+  buf = NULL;
+  error = WRDE_NOSPACE;
 
   close (d[STDOUT_FILENO]);
   f = fdopen (d[STDIN_FILENO]);
   if (f == NULL)
     goto lose;
 
-  while (!feof (f))
-    {
-      struct word *new = (struct word *) __alloca (sizeof (struct word));
-      size_t len = 0;
-      new->word = NULL;
-      if (__getdelim (&new->word, &len, '\0', f) == -1)
-       goto lose;
-      new->next = words;
-      words = new;
-      ++nwords;
-    }
+  /* Read the number of words and number of bytes from the shell.  */
+  if (fscanf (f, "%u", &wordc) != 1 || getc (f) != '\0' ||
+      fscanf (f, "%u", &buflen) != 1 || getc (f) != '\0')
+    goto lose;
 
-  if (waitpid (pid, &status, 0) != pid)
+  /* Read the words from the shell, and wait for it to return.  */
+  buflen += wordc;
+  buf = malloc (buflen);
+  if (buf == NULL ||
+      fread (buf, buflen, 1, f) != 1 ||
+      waitpid (pid, &status, 0) != pid)
     goto lose;
 
   if (WIFEXITED (status))
@@ -107,14 +123,17 @@ DEFUN(wordexp, (string, pwordexp, flags),
   else
     goto lose;
 
-  wordc = nwords + 1;
+  /* Pack the structure.  */
+
+  start = 0;
   if (flags & WRDE_DOOFFS)
-    words += pwordexp->we_offs;
+    start += pwordexp->we_offs;
   if (flags & WRDE_APPEND)
-    wordc += pwordexp->we_wordc;
+    start += pwordexp->we_wordc;
+  wordc = start + wordc + 1;
 
   if (flags & WRDE_APPEND)
-    wordv = (char **) realloc ((PTR) pwordexp->we_wordv,
+    wordv = (char **) realloc ((void *) pwordexp->we_wordv,
                               wordc * sizeof (char *));
   else
     wordv = (char **) malloc (wordc * sizeof (char *));
@@ -125,15 +144,19 @@ DEFUN(wordexp, (string, pwordexp, flags),
     for (i = 0; i < pwordexp->we_offs; ++i)
       wordv[i] = NULL;
 
-  i = wordc;
-  while (words != NULL)
+  for (i = start; i < wordc; ++i)
     {
-      wordv[--i] = words->word;
-      words = words->next;
+      pwordexp->we_wordv[i] = buf;
+      buf = strchr (buf, '\0') + 1;
     }
+  wordv[i] = NULL;
 
   if (flags & WRDE_REUSE)
-    wordfree (pwordexp);
+    {
+      free (pwordexp->we_wordv[0]);
+      if (!(flags & WRDE_APPEND))
+       free (pwordexp->we_wordv);
+    }
 
   pwordexp->we_wordc = wordc;
   pwordexp->we_wordv = wordv;
@@ -145,12 +168,18 @@ DEFUN(wordexp, (string, pwordexp, flags),
     int save;
     save = errno;
     (void) kill (pid, SIGKILL);
-    while (words != NULL)
-      {
-       free (words->word);
-       words = words->next;
-      }
+    free (buf);
+    (void) waitpid (pid, (int *) NULL, 0);
     errno = save;
     return error;
   }
 }
+
+
+void
+DEFUN(wordexp, (pwordexp), wordexp_t *pwordexp)
+{
+  /* All the other elts point into the first.  */
+  free (pwordexp->we_wordv[0]);
+  free (pwordexp->we_wordv);
+}