OSDN Git Service

2005-07-07 Thomas Quinot <quinot@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 Ada Core Technologies, Inc.            *
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 #else
53 #include <sys/wait.h>
54 #endif
55
56 /* This file provides the low level functionalities needed to implement Expect
57    capabilities in GNAT.Expect.
58    Implementations for unix and windows systems is provided.
59    Dummy stubs are also provided for other systems. */
60
61 #ifdef _AIX
62 /* Work around the fact that gcc/cpp does not define "__unix__" under AiX.  */
63 #define __unix__
64 #endif
65
66 #ifdef __APPLE__
67 /* Work around the fact that gcc/cpp does not define "__unix__" on Darwin.  */
68 #define __unix__
69 #endif
70
71 #ifdef _WIN32
72
73 #include <windows.h>
74 #include <process.h>
75
76 void
77 __gnat_kill (int pid, int sig)
78 {
79   HANDLE process_handle;
80
81   if (sig == 9)
82     {
83       process_handle = OpenProcess (PROCESS_TERMINATE, FALSE, pid);
84       if (process_handle != NULL)
85         {
86           TerminateProcess (process_handle, 0);
87           CloseHandle (process_handle);
88         }
89     }
90 }
91
92 int
93 __gnat_waitpid (int pid)
94 {
95   HANDLE process_handle;
96   DWORD exitcode = 1;
97   DWORD res;
98
99   process_handle = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, pid);
100
101   if (process_handle != NULL)
102     {
103       res = WaitForSingleObject (process_handle, INFINITE);
104       GetExitCodeProcess (process_handle, &exitcode);
105       CloseHandle (process_handle);
106     }
107
108   return (int) exitcode;
109 }
110
111 int
112 __gnat_expect_fork (void)
113 {
114   return 0;
115 }
116
117 void
118 __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
119 {
120   *pid = (int) spawnve (_P_NOWAIT, cmd, argv, NULL);
121 }
122
123 int
124 __gnat_pipe (int *fd)
125 {
126   HANDLE read, write;
127
128   CreatePipe (&read, &write, NULL, 0);
129   fd[0]=_open_osfhandle ((long)read, 0);
130   fd[1]=_open_osfhandle ((long)write, 0);
131   return 0;  /* always success */
132 }
133
134 int
135 __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set)
136 {
137 #define MAX_DELAY 100
138
139   int i, delay, infinite = 0;
140   DWORD avail;
141   HANDLE handles[num_fd];
142
143   for (i = 0; i < num_fd; i++)
144     is_set[i] = 0;
145
146   for (i = 0; i < num_fd; i++)
147     handles[i] = (HANDLE) _get_osfhandle (fd [i]);
148
149   /* Start with small delays, and then increase them, to avoid polling too
150      much when waiting a long time */
151   delay = 5;
152
153   if (timeout < 0)
154     infinite = 1;
155
156   while (1)
157     {
158       for (i = 0; i < num_fd; i++)
159         {
160           if (!PeekNamedPipe (handles [i], NULL, 0, NULL, &avail, NULL))
161             return -1;
162
163           if (avail > 0)
164             {
165               is_set[i] = 1;
166               return 1;
167             }
168         }
169
170       if (!infinite && timeout <= 0)
171         return 0;
172
173       Sleep (delay);
174       timeout -= delay;
175
176       if (delay < MAX_DELAY)
177         delay += 10;
178     }
179 }
180
181 #elif defined (VMS)
182 #include <unistd.h>
183 #include <stdio.h>
184 #include <unixio.h>
185 #include <stdlib.h>
186 #include <string.h>
187 #include <vms/descrip.h>
188 #include <stdio.h>
189 #include <vms/stsdef.h>
190 #include <vms/iodef.h>
191
192 int
193 __gnat_waitpid (int pid)
194 {
195   int status = 0;
196
197   waitpid (pid, &status, 0);
198   status = WEXITSTATUS (status);
199
200   return status;
201 }
202
203 int
204 __gnat_pipe (int *fd)
205 {
206   return pipe (fd);
207 }
208
209 int
210 __gnat_expect_fork (void)
211 {
212   return -1;
213 }
214
215 void
216 __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
217 {
218   *pid = (int) getpid ();
219   /* Since cmd is fully qualified, it is incorrect to call execvp */
220   execv (cmd, argv);
221   _exit (1);
222 }
223
224 int
225 __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set)
226 {
227   int i, num, ready = 0;
228   unsigned int status;
229   int mbxchans [num_fd];
230   struct dsc$descriptor_s mbxname;
231   struct io_status_block {
232     short int condition;
233     short int count;
234     int dev;
235   } iosb;
236   char buf [256];
237
238   for (i = 0; i < num_fd; i++)
239     is_set[i] = 0;
240
241   for (i = 0; i < num_fd; i++)
242     {
243
244       /* Get name of the mailbox used in the pipe */
245       getname (fd [i], buf);
246
247       /* Assign a channel to the mailbox */
248       if (strlen (buf) > 0)
249         {
250           mbxname.dsc$w_length = strlen (buf);
251           mbxname.dsc$b_dtype = DSC$K_DTYPE_T;
252           mbxname.dsc$b_class = DSC$K_CLASS_S;
253           mbxname.dsc$a_pointer = buf;
254
255           status = SYS$ASSIGN (&mbxname, &mbxchans[i], 0, 0, 0);
256
257           if ((status & 1) != 1)
258             {
259               ready = -1;
260               return ready;
261             }
262         }
263     }
264
265   num = timeout / 100;
266
267   while (1)
268     {
269       for (i = 0; i < num_fd; i++)
270         {
271           if (mbxchans[i] > 0)
272             {
273
274               /* Peek in the mailbox to see if there's data */
275               status = SYS$QIOW
276                 (0, mbxchans[i], IO$_SENSEMODE|IO$M_READERCHECK,
277                  &iosb, 0, 0, 0, 0, 0, 0, 0, 0);
278
279               if ((status & 1) != 1)
280                 {
281                   ready = -1;
282                   goto deassign;
283                 }
284
285               if (iosb.count > 0)
286                 {
287                   is_set[i] = 1;
288                   ready = 1;
289                   goto deassign;
290                 }
291             }
292         }
293
294       if (timeout > 0 && num == 0)
295         {
296           ready = 0;
297           goto deassign;
298         }
299
300       usleep (100000);
301       num--;
302     }
303
304  deassign:
305
306   /* Deassign channels assigned above */
307   for (i = 0; i < num_fd; i++)
308     {
309       if (mbxchans[i] > 0)
310         status = SYS$DASSGN (mbxchans[i]);
311     }
312
313   return ready;
314 }
315
316 #elif defined (__unix__)
317
318 #ifdef __hpux__
319 #include <sys/ptyio.h>
320 #endif
321
322 #include <sys/time.h>
323
324 #ifndef NO_FD_SET
325 #define SELECT_MASK fd_set
326 #else /* !NO_FD_SET */
327 #ifndef _AIX
328 typedef long fd_mask;
329 #endif /* _AIX */
330 #ifdef _IBMR2
331 #define SELECT_MASK void
332 #else /* !_IBMR2 */
333 #define SELECT_MASK int
334 #endif /* !_IBMR2 */
335 #endif /* !NO_FD_SET */
336
337 void
338 __gnat_kill (int pid, int sig)
339 {
340   kill (pid, sig);
341 }
342
343 int
344 __gnat_waitpid (int pid)
345 {
346   int status = 0;
347
348   waitpid (pid, &status, 0);
349   status = WEXITSTATUS (status);
350
351   return status;
352 }
353
354 int
355 __gnat_pipe (int *fd)
356 {
357   return pipe (fd);
358 }
359
360 int
361 __gnat_expect_fork (void)
362 {
363   return fork ();
364 }
365
366 void
367 __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
368 {
369   *pid = (int) getpid ();
370   /* Since cmd is fully qualified, it is incorrect to call execvp */
371   execv (cmd, argv);
372   _exit (1);
373 }
374
375 int
376 __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set)
377 {
378   struct timeval tv;
379   SELECT_MASK rset;
380   SELECT_MASK eset;
381
382   int max_fd = 0;
383   int ready;
384   int i;
385   int received;
386
387   tv.tv_sec  = timeout / 1000;
388   tv.tv_usec = (timeout % 1000) * 1000;
389
390   do {
391     FD_ZERO (&rset);
392     FD_ZERO (&eset);
393
394     for (i = 0; i < num_fd; i++)
395       {
396         FD_SET (fd[i], &rset);
397         FD_SET (fd[i], &eset);
398
399         if (fd[i] > max_fd)
400           max_fd = fd[i];
401       }
402
403     ready =
404       select (max_fd + 1, &rset, NULL, &eset, timeout == -1 ? NULL : &tv);
405
406     if (ready > 0)
407       {
408         received = 0;
409
410         for (i = 0; i < num_fd; i++)
411           {
412             if (FD_ISSET (fd[i], &rset))
413               {
414                 is_set[i] = 1;
415                 received = 1;
416               }
417             else
418               is_set[i] = 0;
419           }
420
421 #ifdef __hpux__
422         for (i = 0; i < num_fd; i++)
423           {
424             if (FD_ISSET (fd[i], &eset))
425               {
426                 struct request_info ei;
427
428                 /* Only query and reset error state if no file descriptor
429                    is ready to be read, otherwise we will be signalling a
430                    died process too early */
431
432                 if (!received)
433                   {
434                     ioctl (fd[i], TIOCREQCHECK, &ei);
435
436                     if (ei.request == TIOCCLOSE)
437                       {
438                         ioctl (fd[i], TIOCREQSET, &ei);
439                         return -1;
440                       }
441
442                     ioctl (fd[i], TIOCREQSET, &ei);
443                   }
444                 ready--;
445               }
446           }
447 #endif
448       }
449   } while (timeout == -1 && ready == 0);
450
451   return ready;
452 }
453
454 #else
455
456 void
457 __gnat_kill (int pid, int sig)
458 {
459 }
460
461 int
462 __gnat_waitpid (int pid, int sig)
463 {
464   return 0;
465 }
466
467 int
468 __gnat_pipe (int *fd)
469 {
470   return -1;
471 }
472
473 int
474 __gnat_expect_fork (void)
475 {
476   return -1;
477 }
478
479 void
480 __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
481 {
482   *pid = 0;
483 }
484
485 int
486 __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set)
487 {
488   return -1;
489 }
490 #endif