52869fe1d39a156f69c9737751a69222db695d1a
[kopensolaris-gnu/glibc.git] / posix / wordexp.c
1 /* Copyright (C) 1992, 1997 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Library General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    License, or (at your option) any later version.
8
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13
14    You should have received a copy of the GNU Library General Public
15    License along with the GNU C Library; see the file COPYING.LIB.  If not,
16    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17    Boston, MA 02111-1307, USA.  */
18
19 #include <sys/types.h>
20 #include <wordexp.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <sys/wait.h>
24 #include <signal.h>
25
26
27 /* We do word expansion with a pipe to the shell.
28    The shell command `sh [-P] [-u] -w "words ..."' expands words.
29    If -P, command substitution is an error.
30    If -u, reference to an undefined variable is an error.
31    The shell writes on its stdout:
32         %u\0    Number of words.
33         %u\0    Number of bytes in all words together (not counting \0s).
34         word1\0
35         word2\0
36         ...
37         wordN\0
38    */
39
40 #define SHELL_PATH      "/bin/sh"
41 #define SHELL_NAME      "sh"
42
43
44 int
45 wordexp (string, pwordexp, flags)
46      const char *string;
47      wordexp_t *pwordexp;
48      int flags;
49 {
50   int error;
51   pid_t pid;
52   int d[2];
53   int status;
54
55   FILE *f;
56   size_t wordc, start, buflen;
57   char *buf;
58
59   /* Create the pipe through which we will communicate to the shell.  */
60   if (pipe (d) < 0)
61     return -1;
62
63   pid = fork ();
64   if (pid < 0)
65     return -1;
66
67   if (pid == 0)
68     {
69       /* Child.  Run the shell.  */
70
71       const char *argv[5];
72
73       close (d[STDIN_FILENO]);
74       dup2 (d[STDOUT_FILENO], STDOUT_FILENO);
75       if (!(flags & WRDE_SHOWERR))
76         close (STDERR_FILENO);
77
78       i = 0;
79       argv[i++] = SHELL_NAME;
80       if (flags & WRDE_NOCMD)
81         argv[i++] = "-P";
82       if (flags & WRDE_UNDEF)
83         argv[i++] = "-u";
84       argv[i++] = "-w";
85       argv[i++] = string;
86       argv[i++] = NULL;
87
88       execv (SHELL_PATH, argv);
89       _exit (WRDE_NOSPACE);
90     }
91
92   /* Parent.  */
93
94   buf = NULL;
95   error = WRDE_NOSPACE;
96
97   close (d[STDOUT_FILENO]);
98   f = fdopen (d[STDIN_FILENO]);
99   if (f == NULL)
100     goto lose;
101
102   /* Read the number of words and number of bytes from the shell.  */
103   if (fscanf (f, "%u", &wordc) != 1 || getc (f) != '\0' ||
104       fscanf (f, "%u", &buflen) != 1 || getc (f) != '\0')
105     goto lose;
106
107   /* Read the words from the shell, and wait for it to return.  */
108   buflen += wordc;
109   buf = malloc (buflen);
110   if (buf == NULL ||
111       fread (buf, buflen, 1, f) != 1 ||
112       waitpid (pid, &status, 0) != pid)
113     goto lose;
114
115   if (WIFEXITED (status))
116     {
117       if (WEXITSTATUS (status) != 0)
118         {
119           error = WEXITSTATUS (status);
120           goto lose;
121         }
122     }
123   else
124     goto lose;
125
126   /* Pack the structure.  */
127
128   start = 0;
129   if (flags & WRDE_DOOFFS)
130     start += pwordexp->we_offs;
131   if (flags & WRDE_APPEND)
132     start += pwordexp->we_wordc;
133   wordc = start + wordc + 1;
134
135   if (flags & WRDE_APPEND)
136     wordv = (char **) realloc ((void *) pwordexp->we_wordv,
137                                wordc * sizeof (char *));
138   else
139     wordv = (char **) malloc (wordc * sizeof (char *));
140   if (wordv == NULL)
141     goto lose;
142
143   if (flags & WRDE_DOOFFS)
144     for (i = 0; i < pwordexp->we_offs; ++i)
145       wordv[i] = NULL;
146
147   for (i = start; i < wordc; ++i)
148     {
149       pwordexp->we_wordv[i] = buf;
150       buf = strchr (buf, '\0') + 1;
151     }
152   wordv[i] = NULL;
153
154   if (flags & WRDE_REUSE)
155     {
156       free (pwordexp->we_wordv[0]);
157       if (!(flags & WRDE_APPEND))
158         free (pwordexp->we_wordv);
159     }
160
161   pwordexp->we_wordc = wordc;
162   pwordexp->we_wordv = wordv;
163
164   return 0;
165
166  lose:
167   {
168     int save;
169     save = errno;
170     (void) kill (pid, SIGKILL);
171     free (buf);
172     (void) waitpid (pid, (int *) NULL, 0);
173     errno = save;
174     return error;
175   }
176 }
177
178
179 void
180 DEFUN(wordexp, (pwordexp), wordexp_t *pwordexp)
181 {
182   /* All the other elts point into the first.  */
183   free (pwordexp->we_wordv[0]);
184   free (pwordexp->we_wordv);
185 }