summaryrefslogtreecommitdiff
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);
+}