OSDN Git Service

2005-11-14 Pascal Obry <obry@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / expect.c
1 /****************************************************************************
2  *                                                                          *
3  *                         GNAT COMPILER COMPONENTS                         *
4  *                                                                          *
5  *                               E X P E C T                                *
6  *                                                                          *
7  *                          C Implementation File                           *
8  *                                                                          *
9  *                     Copyright (C) 2001-2005, AdaCore                     *
10  *                                                                          *
11  * GNAT is free software;  you can  redistribute it  and/or modify it under *
12  * terms of the  GNU General Public License as published  by the Free Soft- *
13  * ware  Foundation;  either version 2,  or (at your option) any later ver- *
14  * sion.  GNAT is distributed in the hope that it will be useful, but WITH- *
15  * OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY *
16  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License *
17  * for  more details.  You should have  received  a copy of the GNU General *
18  * Public License  distributed with GNAT;  see file COPYING.  If not, write *
19  * to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, *
20  * Boston, MA 02110-1301, USA.                                              *
21  *                                                                          *
22  * As a  special  exception,  if you  link  this file  with other  files to *
23  * produce an executable,  this file does not by itself cause the resulting *
24  * executable to be covered by the GNU General Public License. This except- *
25  * ion does not  however invalidate  any other reasons  why the  executable *
26  * file might be covered by the  GNU Public License.                        *
27  *                                                                          *
28  * GNAT was originally developed  by the GNAT team at  New York University. *
29  * Extensive contributions were provided by Ada Core Technologies Inc.      *
30  *                                                                          *
31  ****************************************************************************/
32
33 #ifdef __alpha_vxworks
34 #include "vxWorks.h"
35 #endif
36
37 #ifdef IN_RTS
38 #define POSIX
39 #include "tconfig.h"
40 #include "tsystem.h"
41 #else
42 #include "config.h"
43 #include "system.h"
44 #endif
45
46 #include <sys/types.h>
47
48 #ifdef __MINGW32__
49 #if OLD_MINGW
50 #include <sys/wait.h>
51 #endif
52 #elif defined (__vxworks) && defined (__RTP__)
53 #include <wait.h>
54 #else
55 #include <sys/wait.h>
56 #endif
57
58 /* This file provides the low level functionalities needed to implement Expect
59    capabilities in GNAT.Expect.
60    Implementations for unix and windows systems is provided.
61    Dummy stubs are also provided for other systems. */
62
63 #ifdef _AIX
64 /* Work around the fact that gcc/cpp does not define "__unix__" under AiX.  */
65 #define __unix__
66 #endif
67
68 #ifdef __APPLE__
69 /* Work around the fact that gcc/cpp does not define "__unix__" on Darwin.  */
70 #define __unix__
71 #endif
72
73 #ifdef _WIN32
74
75 #include <windows.h>
76 #include <process.h>
77
78 void
79 __gnat_kill (int pid, int sig, int close)
80 {
81   if (sig == 9)
82     {
83       if ((HANDLE)pid != NULL)
84         {
85           TerminateProcess ((HANDLE)pid, 0);
86           if (close)
87             CloseHandle ((HANDLE)pid);
88         }
89     }
90 }
91
92 int
93 __gnat_waitpid (int pid)
94 {
95   DWORD exitcode = 1;
96   DWORD res;
97
98   if ((HANDLE)pid != NULL)
99     {
100       res = WaitForSingleObject ((HANDLE)pid, INFINITE);
101       GetExitCodeProcess ((HANDLE)pid, &exitcode);
102       CloseHandle ((HANDLE)pid);
103     }
104
105   return (int) exitcode;
106 }
107
108 int
109 __gnat_expect_fork (void)
110 {
111   return 0;
112 }
113
114 void
115 __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
116 {
117   *pid = (int) spawnve (_P_NOWAIT, cmd, argv, NULL);
118 }
119
120 int
121 __gnat_pipe (int *fd)
122 {
123   HANDLE read, write;
124
125   CreatePipe (&read, &write, NULL, 0);
126   fd[0]=_open_osfhandle ((long)read, 0);
127   fd[1]=_open_osfhandle ((long)write, 0);
128   return 0;  /* always success */
129 }
130
131 int
132 __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set)
133 {
134 #define MAX_DELAY 100
135
136   int i, delay, infinite = 0;
137   DWORD avail;
138   HANDLE handles[num_fd];
139
140   for (i = 0; i < num_fd; i++)
141     is_set[i] = 0;
142
143   for (i = 0; i < num_fd; i++)
144     handles[i] = (HANDLE) _get_osfhandle (fd [i]);
145
146   /* Start with small delays, and then increase them, to avoid polling too
147      much when waiting a long time */
148   delay = 5;
149
150   if (timeout < 0)
151     infinite = 1;
152
153   while (1)
154     {
155       for (i = 0; i < num_fd; i++)
156         {
157           if (!PeekNamedPipe (handles [i], NULL, 0, NULL, &avail, NULL))
158             return -1;
159
160           if (avail > 0)
161             {
162               is_set[i] = 1;
163               return 1;
164             }
165         }
166
167       if (!infinite && timeout <= 0)
168         return 0;
169
170       Sleep (delay);
171       timeout -= delay;
172
173       if (delay < MAX_DELAY)
174         delay += 10;
175     }
176 }
177
178 #elif defined (VMS)
179 #include <unistd.h>
180 #include <stdio.h>
181 #include <unixio.h>
182 #include <stdlib.h>
183 #include <string.h>
184 #include <vms/descrip.h>
185 #include <stdio.h>
186 #include <vms/stsdef.h>
187 #include <vms/iodef.h>
188
189 int
190 __gnat_waitpid (int pid)
191 {
192   int status = 0;
193
194   waitpid (pid, &status, 0);
195   status = WEXITSTATUS (status);
196
197   return status;
198 }
199
200 int
201 __gnat_pipe (int *fd)
202 {
203   return pipe (fd);
204 }
205
206 int
207 __gnat_expect_fork (void)
208 {
209   return -1;
210 }
211
212 void
213 __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
214 {
215   *pid = (int) getpid ();
216   /* Since cmd is fully qualified, it is incorrect to call execvp */
217   execv (cmd, argv);
218   _exit (1);
219 }
220
221 int
222 __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set)
223 {
224   int i, num, ready = 0;
225   unsigned int status;
226   int mbxchans [num_fd];
227   struct dsc$descriptor_s mbxname;
228   struct io_status_block {
229     short int condition;
230     short int count;
231     int dev;
232   } iosb;
233   char buf [256];
234
235   for (i = 0; i < num_fd; i++)
236     is_set[i] = 0;
237
238   for (i = 0; i < num_fd; i++)
239     {
240
241       /* Get name of the mailbox used in the pipe */
242       getname (fd [i], buf);
243
244       /* Assign a channel to the mailbox */
245       if (strlen (buf) > 0)
246         {
247           mbxname.dsc$w_length = strlen (buf);
248           mbxname.dsc$b_dtype = DSC$K_DTYPE_T;
249           mbxname.dsc$b_class = DSC$K_CLASS_S;
250           mbxname.dsc$a_pointer = buf;
251
252           status = SYS$ASSIGN (&mbxname, &mbxchans[i], 0, 0, 0);
253
254           if ((status & 1) != 1)
255             {
256               ready = -1;
257               return ready;
258             }
259         }
260     }
261
262   num = timeout / 100;
263
264   while (1)
265     {
266       for (i = 0; i < num_fd; i++)
267         {
268           if (mbxchans[i] > 0)
269             {
270
271               /* Peek in the mailbox to see if there's data */
272               status = SYS$QIOW
273                 (0, mbxchans[i], IO$_SENSEMODE|IO$M_READERCHECK,
274                  &iosb, 0, 0, 0, 0, 0, 0, 0, 0);
275
276               if ((status & 1) != 1)
277                 {
278                   ready = -1;
279                   goto deassign;
280                 }
281
282               if (iosb.count > 0)
283                 {
284                   is_set[i] = 1;
285                   ready = 1;
286                   goto deassign;
287                 }
288             }
289         }
290
291       if (timeout > 0 && num == 0)
292         {
293           ready = 0;
294           goto deassign;
295         }
296
297       usleep (100000);
298       num--;
299     }
300
301  deassign:
302
303   /* Deassign channels assigned above */
304   for (i = 0; i < num_fd; i++)
305     {
306       if (mbxchans[i] > 0)
307         status = SYS$DASSGN (mbxchans[i]);
308     }
309
310   return ready;
311 }
312
313 #elif defined (__unix__)
314
315 #ifdef __hpux__
316 #include <sys/ptyio.h>
317 #endif
318
319 #include <sys/time.h>
320
321 #ifndef NO_FD_SET
322 #define SELECT_MASK fd_set
323 #else /* !NO_FD_SET */
324 #ifndef _AIX
325 typedef long fd_mask;
326 #endif /* _AIX */
327 #ifdef _IBMR2
328 #define SELECT_MASK void
329 #else /* !_IBMR2 */
330 #define SELECT_MASK int
331 #endif /* !_IBMR2 */
332 #endif /* !NO_FD_SET */
333
334 void
335 __gnat_kill (int pid, int sig, int close)
336 {
337   kill (pid, sig);
338 }
339
340 int
341 __gnat_waitpid (int pid)
342 {
343   int status = 0;
344
345   waitpid (pid, &status, 0);
346   status = WEXITSTATUS (status);
347
348   return status;
349 }
350
351 int
352 __gnat_pipe (int *fd)
353 {
354   return pipe (fd);
355 }
356
357 int
358 __gnat_expect_fork (void)
359 {
360   return fork ();
361 }
362
363 void
364 __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
365 {
366   *pid = (int) getpid ();
367   /* Since cmd is fully qualified, it is incorrect to call execvp */
368   execv (cmd, argv);
369   _exit (1);
370 }
371
372 int
373 __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set)
374 {
375   struct timeval tv;
376   SELECT_MASK rset;
377   SELECT_MASK eset;
378
379   int max_fd = 0;
380   int ready;
381   int i;
382   int received;
383
384   tv.tv_sec  = timeout / 1000;
385   tv.tv_usec = (timeout % 1000) * 1000;
386
387   do {
388     FD_ZERO (&rset);
389     FD_ZERO (&eset);
390
391     for (i = 0; i < num_fd; i++)
392       {
393         FD_SET (fd[i], &rset);
394         FD_SET (fd[i], &eset);
395
396         if (fd[i] > max_fd)
397           max_fd = fd[i];
398       }
399
400     ready =
401       select (max_fd + 1, &rset, NULL, &eset, timeout == -1 ? NULL : &tv);
402
403     if (ready > 0)
404       {
405         received = 0;
406
407         for (i = 0; i < num_fd; i++)
408           {
409             if (FD_ISSET (fd[i], &rset))
410               {
411                 is_set[i] = 1;
412                 received = 1;
413               }
414             else
415               is_set[i] = 0;
416           }
417
418 #ifdef __hpux__
419         for (i = 0; i < num_fd; i++)
420           {
421             if (FD_ISSET (fd[i], &eset))
422               {
423                 struct request_info ei;
424
425                 /* Only query and reset error state if no file descriptor
426                    is ready to be read, otherwise we will be signalling a
427                    died process too early */
428
429                 if (!received)
430                   {
431                     ioctl (fd[i], TIOCREQCHECK, &ei);
432
433                     if (ei.request == TIOCCLOSE)
434                       {
435                         ioctl (fd[i], TIOCREQSET, &ei);
436                         return -1;
437                       }
438
439                     ioctl (fd[i], TIOCREQSET, &ei);
440                   }
441                 ready--;
442               }
443           }
444 #endif
445       }
446   } while (timeout == -1 && ready == 0);
447
448   return ready;
449 }
450
451 #else
452
453 void
454 __gnat_kill (int pid, int sig, int close)
455 {
456 }
457
458 int
459 __gnat_waitpid (int pid, int sig)
460 {
461   return 0;
462 }
463
464 int
465 __gnat_pipe (int *fd)
466 {
467   return -1;
468 }
469
470 int
471 __gnat_expect_fork (void)
472 {
473   return -1;
474 }
475
476 void
477 __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
478 {
479   *pid = 0;
480 }
481
482 int
483 __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set)
484 {
485   return -1;
486 }
487 #endif