Formerly ../posix/wordexp.c.~2~
authorroland <roland>
Mon, 16 Mar 1992 12:08:28 +0000 (12:08 +0000)
committerroland <roland>
Mon, 16 Mar 1992 12:08:28 +0000 (12:08 +0000)
posix/wordexp.c

index 9f7d485..4bee3df 100644 (file)
@@ -22,6 +22,25 @@ Cambridge, MA 02139, USA.  */
 #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),
@@ -32,14 +51,11 @@ DEFUN(wordexp, (string, pwordexp, flags),
   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,29 +67,30 @@ 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;
+  buf = NULL;
   lose = WRDE_NOSPACE;
 
   close (d[STDOUT_FILENO]);
@@ -81,19 +98,17 @@ DEFUN(wordexp, (string, pwordexp, flags),
   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,11 +122,14 @@ 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,
@@ -125,15 +143,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 +167,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);
+}