Initial revision
[kopensolaris-gnu/glibc.git] / posix / wordexp.c
1 /* Copyright (C) 1992 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
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA.  */
18
19 #include <ansidecl.h>
20 #include <sys/types.h>
21 #include <wordexp.h>
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <sys/wait.h>
25
26 int
27 DEFUN(wordexp, (string, pwordexp, flags),
28       CONST char *string AND wordexp_t *pwordexp AND int flags)
29 {
30   int error;
31   pid_t pid;
32   int d[2];
33   int status;
34
35   struct word
36     {
37       struct word *next;
38       char *word;
39     } *words;
40   size_t nwords, wordc, i;
41   FILE *f;
42
43   if (pipe (d) < 0)
44     return -1;
45
46   pid = fork ();
47   if (pid < 0)
48     return -1;
49
50   if (pid == 0)
51     {
52       /* Child.  Run the shell.  */
53
54       CONST char fmt[]
55         = "for word in %s; do echo -n \"$word\"; echo -e \\\\000; done";
56       char flags[] = "-Puc", *f = &flags[1];
57       char *buffer = (char *) __alloca (fmt - 2 + strlen (string));
58       if (flags & WRDE_NOCMD)
59         *f++ = 'P';
60       if (flags & WRDE_UNDEF)
61         *f++ = 'u';
62       *f++ = 'c';
63       *f = '\0';
64       sprintf (buffer, fmt, string);
65       close (d[STDIN_FILENO]);
66       dup2 (d[STDOUT_FILENO], STDOUT_FILENO);
67       if (!(flags & WRDE_SHOWERR))
68         close (STDERR_FILENO);
69       execl (SHELL_PATH, SHELL_NAME, flags, buffer, (char *) NULL);
70       _exit (WRDE_ABEND);
71     }
72
73   /* Parent.  */
74
75   words = NULL;
76   nwords = 0;
77   lose = WRDE_NOSPACE;
78
79   close (d[STDOUT_FILENO]);
80   f = fdopen (d[STDIN_FILENO]);
81   if (f == NULL)
82     goto lose;
83
84   while (!feof (f))
85     {
86       struct word *new = (struct word *) __alloca (sizeof (struct word));
87       size_t len = 0;
88       new->word = NULL;
89       if (__getdelim (&new->word, &len, '\0', f) == -1)
90         goto lose;
91       new->next = words;
92       words = new;
93       ++nwords;
94     }
95
96   if (waitpid (pid, &status, 0) != pid)
97     goto lose;
98
99   if (WIFEXITED (status))
100     {
101       if (WEXITSTATUS (status) != 0)
102         {
103           error = WEXITSTATUS (status);
104           goto lose;
105         }
106     }
107   else
108     goto lose;
109
110   wordc = nwords + 1;
111   if (flags & WRDE_DOOFFS)
112     words += pwordexp->we_offs;
113   if (flags & WRDE_APPEND)
114     wordc += pwordexp->we_wordc;
115
116   if (flags & WRDE_APPEND)
117     wordv = (char **) realloc ((PTR) pwordexp->we_wordv,
118                                wordc * sizeof (char *));
119   else
120     wordv = (char **) malloc (wordc * sizeof (char *));
121   if (wordv == NULL)
122     goto lose;
123
124   if (flags & WRDE_DOOFFS)
125     for (i = 0; i < pwordexp->we_offs; ++i)
126       wordv[i] = NULL;
127
128   i = wordc;
129   while (words != NULL)
130     {
131       wordv[--i] = words->word;
132       words = words->next;
133     }
134
135   if (flags & WRDE_REUSE)
136     wordfree (pwordexp);
137
138   pwordexp->we_wordc = wordc;
139   pwordexp->we_wordv = wordv;
140
141   return 0;
142
143  lose:
144   {
145     int save;
146     save = errno;
147     (void) kill (pid, SIGKILL);
148     while (words != NULL)
149       {
150         free (words->word);
151         words = words->next;
152       }
153     errno = save;
154     return error;
155   }
156 }