OSDN Git Service

* check.c, expr.c, resolve.c, trans-common.c,
[pf3gnuchains/gcc-fork.git] / libiberty / pex-msdos.c
1 /* Utilities to execute a program in a subprocess (possibly linked by pipes
2    with other subprocesses), and wait for it.  Generic MSDOS specialization.
3    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2005
4    Free Software Foundation, Inc.
5
6 This file is part of the libiberty library.
7 Libiberty is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 Libiberty is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public
18 License along with libiberty; see the file COPYING.LIB.  If not,
19 write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20 Boston, MA 02110-1301, USA.  */
21
22 #include "pex-common.h"
23
24 #include <stdio.h>
25 #include <errno.h>
26 #ifdef NEED_DECLARATION_ERRNO
27 extern int errno;
28 #endif
29 #ifdef HAVE_STRING_H
30 #include <string.h>
31 #endif
32 #ifdef HAVE_STDLIB_H
33 #include <stdlib.h>
34 #endif
35
36 #include "safe-ctype.h"
37 #include <process.h>
38
39 /* The structure we keep in obj->sysdep.  */
40
41 #define PEX_MSDOS_FILE_COUNT 3
42
43 #define PEX_MSDOS_FD_OFFSET 10
44
45 struct pex_msdos
46 {
47   /* An array of file names.  We refer to these using file descriptors
48      of 10 + array index.  */
49   const char *files[PEX_MSDOS_FILE_COUNT];
50   /* Exit statuses of programs which have been run.  */
51   int *statuses;
52 };
53
54 static int pex_msdos_open (struct pex_obj *, const char *, int);
55 static int pex_msdos_open (struct pex_obj *, const char *, int);
56 static int pex_msdos_fdindex (struct pex_msdos *, int);
57 static long pex_msdos_exec_child (struct pex_obj *, int, const char *,
58                                   char * const *, int, int, int,
59                                   const char **, int *);
60 static int pex_msdos_close (struct pex_obj *, int);
61 static int pex_msdos_wait (struct pex_obj *, long, int *, struct pex_time *,
62                            int, const char **, int *);
63 static void pex_msdos_cleanup (struct pex_obj *);
64
65 /* The list of functions we pass to the common routines.  */
66
67 const struct pex_funcs funcs =
68 {
69   pex_msdos_open,
70   pex_msdos_open,
71   pex_msdos_exec_child,
72   pex_msdos_close,
73   pex_msdos_wait,
74   NULL, /* pipe */
75   NULL, /* fdopenr */
76   NULL, /* fdopenw */
77   pex_msdos_cleanup
78 };
79
80 /* Return a newly initialized pex_obj structure.  */
81
82 struct pex_obj *
83 pex_init (int flags, const char *pname, const char *tempbase)
84 {
85   struct pex_obj *ret;
86   int i;
87
88   /* MSDOS does not support pipes.  */
89   flags &= ~ PEX_USE_PIPES;
90
91   ret = pex_init_common (flags, pname, tempbase, funcs);
92
93   ret->sysdep = XNEW (struct pex_msdos);
94   for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
95     ret->files[i] = NULL;
96   ret->statuses = NULL;
97
98   return ret;
99 }
100
101 /* Open a file.  FIXME: We ignore the binary argument, since we have
102    no way to handle it.  */
103
104 static int
105 pex_msdos_open (struct pex_obj *obj, const char *name,
106                 int binary ATTRIBUTE_UNUSED)
107 {
108   struct pex_msdos *ms;
109   int i;
110
111   ms = (struct pex_msdos *) obj->sysdep;
112
113   for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
114     {
115       if (ms->files[i] == NULL)
116         {
117           ms->files[i] = xstrdup (name);
118           return i + PEX_MSDOS_FD_OFFSET;
119         }
120     }
121
122   abort ();
123 }
124
125 /* Get the index into msdos->files associated with an open file
126    descriptor.  */
127
128 static int
129 pex_msdos_fdindex (struct pex_msdos *ms, int fd)
130 {
131   fd -= PEX_MSDOS_FD_OFFSET;
132   if (fd < 0 || fd >= PEX_MSDOS_FILE_COUNT || ms->files[fd] == NULL)
133     abort ();
134   return fd;
135 }
136
137
138 /* Close a file.  */
139
140 static int
141 pex_msdos_close (struct pex_obj *obj, int fd)
142 {
143   struct pex_msdos *ms;
144   int fdinex;
145
146   ms = (struct pex_msdos *) obj->sysdep;
147   fdindex = pe_msdos_fdindex (ms, fd);
148   free (ms->files[fdindex]);
149   ms->files[fdindex] = NULL;
150 }
151
152 /* Execute a child.  */
153
154 static long
155 pex_msdos_exec_child (struct pex_obj *obj, int flags, const char *executable,
156                       char * const * argv, int in, int out,
157                       int errdes ATTRIBUTE_UNUSED, const char **errmsg,
158                       int *err)
159 {
160   struct pex_msdos *ms;
161   char *temp_base;
162   int temp_base_allocated;
163   char *rf;
164   int inindex;
165   char *infile;
166   int outindex;
167   char *outfile;
168   char *scmd;
169   FILE *argfile;
170   int i;
171   int status;
172
173   ms = (struct pex_msdos *) obj->sysdep;
174
175   /* FIXME: I don't know how to redirect stderr, so we ignore ERRDES
176      and PEX_STDERR_TO_STDOUT.  */
177
178   temp_base = obj->temp_base;
179   if (temp_base != NULL)
180     temp_base_allocated = 0;
181   else
182     {
183       temp_base = choose_temp_base ();
184       temp_base_allocated = 1;
185     }
186
187   rf = concat (temp_base, ".gp", NULL);
188
189   if (temp_base_allocated)
190     free (temp_base);
191
192   if (in == STDIN_FILE_NO)
193     {
194       inindex = -1;
195       infile = "";
196     }
197   else
198     {
199       inindex = pex_msdos_fdindex (ms, in);
200       infile = ms->files[inindex];
201     }
202
203   if (out == STDOUT_FILE_NO)
204     {
205       outindex = -1;
206       outfile = "";
207     }
208   else
209     {
210       outindex = pex_msdos_fdindex (ms, out);
211       outfile = ms->files[outindex];
212     }
213
214   scmd = XNEWVEC (char, strlen (program)
215                   + ((flags & PEXECUTE_SEARCH) != 0 ? 4 : 0)
216                   + strlen (rf)
217                   + strlen (infile)
218                   + strlen (outfile)
219                   + 10);
220   sprintf (scmd, "%s%s @%s%s%s%s%s",
221            program,
222            (flags & PEXECUTE_SEARCH) != 0 ? ".exe" : "",
223            rf,
224            inindex != -1 ? " <" : "",
225            infile,
226            outindex != -1 ? " >" : "",
227            outfile);
228
229   argfile = fopen (rf, "w");
230   if (argfile == NULL)
231     {
232       *err = errno;
233       free (scmd);
234       free (rf);
235       *errmsg = "cannot open temporary command file";
236       return -1;
237     }
238
239   for (i = 1; argv[i] != NULL; ++i)
240     {
241       char *p;
242
243       for (p = argv[i]; *p != '\0'; ++p)
244         {
245           if (*p == '"' || *p == '\'' || *p == '\\' || ISSPACE (*p))
246             putc ('\\', argfile);
247           putc (*p, argfile);
248         }
249       putc ('\n', argfile);
250     }
251
252   fclose (argfile);
253
254   status = system (scmd);
255
256   if (status == -1)
257     {
258       *err = errno;
259       remove (rf);
260       free (scmd);
261       free (rf);
262       *errmsg = "system";
263       return -1;
264     }
265
266   remove (rf);
267   free (scmd);
268   free (rf);
269
270   /* Save the exit status for later.  When we are called, obj->count
271      is the number of children which have executed before this
272      one.  */
273   ms->statuses = XRESIZEVEC(int, ms->statuses, obj->count + 1);
274   ms->statuses[obj->count] = status;
275
276   return obj->count;
277 }
278
279 /* Wait for a child process to complete.  Actually the child process
280    has already completed, and we just need to return the exit
281    status.  */
282
283 static int
284 pex_msdos_wait (struct pex_obj *obj, long pid, int *status,
285                 struct pex_time *time, int done ATTRIBUTE_UNUSED,
286                 const char **errmsg ATTRIBUTE_UNUSED,
287                 int *err ATTRIBUTE_UNUSED)
288 {
289   struct pex_msdos *ms;
290
291   ms = (struct pex_msdos *) obj->sysdep;
292
293   if (time != NULL)
294     memset (time, 0, sizeof *time);
295
296   *status = ms->statuses[pid];
297
298   return 0;
299 }
300
301 /* Clean up the pex_msdos structure.  */
302
303 static void
304 pex_msdos_cleanup (struct pex_obj  *obj)
305 {
306   struct pex_msdos *ms;
307   int i;
308
309   ms = (struct pex_msdos *) obj->sysdep;
310   for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
311     if (msdos->files[i] != NULL)
312       free (msdos->files[i]);
313   if (msdos->statuses != NULL)
314     free (msdos->statuses);
315   free (msdos);
316   obj->sysdep = NULL;
317 }