/* 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 #include #include #include #include #include #include /* 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); }