about summary refs log tree commit diff
path: root/posix/wordexp.c
diff options
context:
space:
mode:
Diffstat (limited to 'posix/wordexp.c')
-rw-r--r--posix/wordexp.c184
1 files changed, 184 insertions, 0 deletions
diff --git a/posix/wordexp.c b/posix/wordexp.c
new file mode 100644
index 0000000000..1922e44642
--- /dev/null
+++ b/posix/wordexp.c
@@ -0,0 +1,184 @@
+/* Copyright (C) 1992 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 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.  */
+
+#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)
+{
+  int error;
+  pid_t pid;
+  int d[2];
+  int status;
+
+  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;
+
+  pid = fork ();
+  if (pid < 0)
+    return -1;
+
+  if (pid == 0)
+    {
+      /* Child.  Run the shell.  */
+
+      CONST char *argv[5];
+
+      close (d[STDIN_FILENO]);
+      dup2 (d[STDOUT_FILENO], STDOUT_FILENO);
+      if (!(flags & WRDE_SHOWERR))
+	close (STDERR_FILENO);
+
+      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.  */
+
+  buf = NULL;
+  error = WRDE_NOSPACE;
+
+  close (d[STDOUT_FILENO]);
+  f = fdopen (d[STDIN_FILENO]);
+  if (f == NULL)
+    goto lose;
+
+  /* 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;
+
+  /* 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))
+    {
+      if (WEXITSTATUS (status) != 0)
+	{
+	  error = WEXITSTATUS (status);
+	  goto lose;
+	}
+    }
+  else
+    goto lose;
+
+  /* Pack the structure.  */
+
+  start = 0;
+  if (flags & WRDE_DOOFFS)
+    start += pwordexp->we_offs;
+  if (flags & WRDE_APPEND)
+    start += pwordexp->we_wordc;
+  wordc = start + wordc + 1;
+
+  if (flags & WRDE_APPEND)
+    wordv = (char **) realloc ((PTR) pwordexp->we_wordv,
+			       wordc * sizeof (char *));
+  else
+    wordv = (char **) malloc (wordc * sizeof (char *));
+  if (wordv == NULL)
+    goto lose;
+
+  if (flags & WRDE_DOOFFS)
+    for (i = 0; i < pwordexp->we_offs; ++i)
+      wordv[i] = NULL;
+
+  for (i = start; i < wordc; ++i)
+    {
+      pwordexp->we_wordv[i] = buf;
+      buf = strchr (buf, '\0') + 1;
+    }
+  wordv[i] = NULL;
+
+  if (flags & WRDE_REUSE)
+    {
+      free (pwordexp->we_wordv[0]);
+      if (!(flags & WRDE_APPEND))
+	free (pwordexp->we_wordv);
+    }
+
+  pwordexp->we_wordc = wordc;
+  pwordexp->we_wordv = wordv;
+
+  return 0;
+
+ lose:
+  {
+    int save;
+    save = errno;
+    (void) kill (pid, SIGKILL);
+    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);
+}