OSDN Git Service

2007-03-01 Paul Brook <paul@codesourcery.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   BOOL result;
118   STARTUPINFO SI;
119   PROCESS_INFORMATION PI;
120   SECURITY_ATTRIBUTES SA;
121   int csize = 1;
122   char *full_command;
123   int k;
124
125   /* compute the total command line length.  */
126   k = 0;
127   while (argv[k])
128     {
129       csize += strlen (argv[k]) + 1;
130       k++;
131     }
132
133   full_command = (char *) malloc (csize);
134   full_command[0] = '\0';
135
136   /* Startup info. */
137   SI.cb          = sizeof (STARTUPINFO);
138   SI.lpReserved  = NULL;
139   SI.lpReserved2 = NULL;
140   SI.lpDesktop   = NULL;
141   SI.cbReserved2 = 0;
142   SI.lpTitle     = NULL;
143   SI.dwFlags     = 0;
144   SI.wShowWindow = SW_HIDE;
145
146   /* Security attributes. */
147   SA.nLength = sizeof (SECURITY_ATTRIBUTES);
148   SA.bInheritHandle = TRUE;
149   SA.lpSecurityDescriptor = NULL;
150
151   k = 0;
152   while (argv[k])
153     {
154       strcat (full_command, argv[k]);
155       strcat (full_command, " ");
156       k++;
157     }
158
159   result = CreateProcess
160              (NULL, (char *) full_command, &SA, NULL, TRUE,
161               GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
162
163   free (full_command);
164
165   if (result == TRUE)
166     {
167       CloseHandle (PI.hThread);
168       *pid = (int) PI.hProcess;
169     }
170   else
171     *pid = -1;
172 }
173
174 int
175 __gnat_pipe (int *fd)
176 {
177   HANDLE read, write;
178
179   CreatePipe (&read, &write, NULL, 0);
180   fd[0]=_open_osfhandle ((long)read, 0);
181   fd[1]=_open_osfhandle ((long)write, 0);
182   return 0;  /* always success */
183 }
184
185 int
186 __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set)
187 {
188 #define MAX_DELAY 100
189
190   int i, delay, infinite = 0;
191   DWORD avail;
192   HANDLE handles[num_fd];
193
194   for (i = 0; i < num_fd; i++)
195     is_set[i] = 0;
196
197   for (i = 0; i < num_fd; i++)
198     handles[i] = (HANDLE) _get_osfhandle (fd [i]);
199
200   /* Start with small delays, and then increase them, to avoid polling too
201      much when waiting a long time */
202   delay = 5;
203
204   if (timeout < 0)
205     infinite = 1;
206
207   while (1)
208     {
209       for (i = 0; i < num_fd; i++)
210         {
211           if (!PeekNamedPipe (handles [i], NULL, 0, NULL, &avail, NULL))
212             return -1;
213
214           if (avail > 0)
215             {
216               is_set[i] = 1;
217               return 1;
218             }
219         }
220
221       if (!infinite && timeout <= 0)
222         return 0;
223
224       Sleep (delay);
225       timeout -= delay;
226
227       if (delay < MAX_DELAY)
228         delay += 10;
229     }
230 }
231
232 #elif defined (VMS)
233 #include <unistd.h>
234 #include <stdio.h>
235 #include <unixio.h>
236 #include <stdlib.h>
237 #include <string.h>
238 #include <vms/descrip.h>
239 #include <stdio.h>
240 #include <vms/stsdef.h>
241 #include <vms/iodef.h>
242
243 int
244 __gnat_waitpid (int pid)
245 {
246   int status = 0;
247
248   waitpid (pid, &status, 0);
249   status = WEXITSTATUS (status);
250
251   return status;
252 }
253
254 int
255 __gnat_pipe (int *fd)
256 {
257   return pipe (fd);
258 }
259
260 int
261 __gnat_expect_fork (void)
262 {
263   return -1;
264 }
265
266 void
267 __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
268 {
269   *pid = (int) getpid ();
270   /* Since cmd is fully qualified, it is incorrect to call execvp */
271   execv (cmd, argv);
272   _exit (1);
273 }
274
275 int
276 __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set)
277 {
278   int i, num, ready = 0;
279   unsigned int status;
280   int mbxchans [num_fd];
281   struct dsc$descriptor_s mbxname;
282   struct io_status_block {
283     short int condition;
284     short int count;
285     int dev;
286   } iosb;
287   char buf [256];
288
289   for (i = 0; i < num_fd; i++)
290     is_set[i] = 0;
291
292   for (i = 0; i < num_fd; i++)
293     {
294
295       /* Get name of the mailbox used in the pipe */
296       getname (fd [i], buf);
297
298       /* Assign a channel to the mailbox */
299       if (strlen (buf) > 0)
300         {
301           mbxname.dsc$w_length = strlen (buf);
302           mbxname.dsc$b_dtype = DSC$K_DTYPE_T;
303           mbxname.dsc$b_class = DSC$K_CLASS_S;
304           mbxname.dsc$a_pointer = buf;
305
306           status = SYS$ASSIGN (&mbxname, &mbxchans[i], 0, 0, 0);
307
308           if ((status & 1) != 1)
309             {
310               ready = -1;
311               return ready;
312             }
313         }
314     }
315
316   num = timeout / 100;
317
318   while (1)
319     {
320       for (i = 0; i < num_fd; i++)
321         {
322           if (mbxchans[i] > 0)
323             {
324
325               /* Peek in the mailbox to see if there's data */
326               status = SYS$QIOW
327                 (0, mbxchans[i], IO$_SENSEMODE|IO$M_READERCHECK,
328                  &iosb, 0, 0, 0, 0, 0, 0, 0, 0);
329
330               if ((status & 1) != 1)
331                 {
332                   ready = -1;
333                   goto deassign;
334                 }
335
336               if (iosb.count > 0)
337                 {
338                   is_set[i] = 1;
339                   ready = 1;
340                   goto deassign;
341                 }
342             }
343         }
344
345       if (timeout > 0 && num == 0)
346         {
347           ready = 0;
348           goto deassign;
349         }
350
351       usleep (100000);
352       num--;
353     }
354
355  deassign:
356
357   /* Deassign channels assigned above */
358   for (i = 0; i < num_fd; i++)
359     {
360       if (mbxchans[i] > 0)
361         status = SYS$DASSGN (mbxchans[i]);
362     }
363
364   return ready;
365 }
366
367 #elif defined (__unix__)
368
369 #ifdef __hpux__
370 #include <sys/ptyio.h>
371 #endif
372
373 #include <sys/time.h>
374
375 #ifndef NO_FD_SET
376 #define SELECT_MASK fd_set
377 #else /* !NO_FD_SET */
378 #ifndef _AIX
379 typedef long fd_mask;
380 #endif /* _AIX */
381 #ifdef _IBMR2
382 #define SELECT_MASK void
383 #else /* !_IBMR2 */
384 #define SELECT_MASK int
385 #endif /* !_IBMR2 */
386 #endif /* !NO_FD_SET */
387
388 void
389 __gnat_kill (int pid, int sig, int close)
390 {
391   kill (pid, sig);
392 }
393
394 int
395 __gnat_waitpid (int pid)
396 {
397   int status = 0;
398
399   waitpid (pid, &status, 0);
400   status = WEXITSTATUS (status);
401
402   return status;
403 }
404
405 int
406 __gnat_pipe (int *fd)
407 {
408   return pipe (fd);
409 }
410
411 int
412 __gnat_expect_fork (void)
413 {
414   return fork ();
415 }
416
417 void
418 __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
419 {
420   *pid = (int) getpid ();
421   /* Since cmd is fully qualified, it is incorrect to call execvp */
422   execv (cmd, argv);
423   _exit (1);
424 }
425
426 int
427 __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set)
428 {
429   struct timeval tv;
430   SELECT_MASK rset;
431   SELECT_MASK eset;
432
433   int max_fd = 0;
434   int ready;
435   int i;
436   int received;
437
438   tv.tv_sec  = timeout / 1000;
439   tv.tv_usec = (timeout % 1000) * 1000;
440
441   do {
442     FD_ZERO (&rset);
443     FD_ZERO (&eset);
444
445     for (i = 0; i < num_fd; i++)
446       {
447         FD_SET (fd[i], &rset);
448         FD_SET (fd[i], &eset);
449
450         if (fd[i] > max_fd)
451           max_fd = fd[i];
452       }
453
454     ready =
455       select (max_fd + 1, &rset, NULL, &eset, timeout == -1 ? NULL : &tv);
456
457     if (ready > 0)
458       {
459         received = 0;
460
461         for (i = 0; i < num_fd; i++)
462           {
463             if (FD_ISSET (fd[i], &rset))
464               {
465                 is_set[i] = 1;
466                 received = 1;
467               }
468             else
469               is_set[i] = 0;
470           }
471
472 #ifdef __hpux__
473         for (i = 0; i < num_fd; i++)
474           {
475             if (FD_ISSET (fd[i], &eset))
476               {
477                 struct request_info ei;
478
479                 /* Only query and reset error state if no file descriptor
480                    is ready to be read, otherwise we will be signalling a
481                    died process too early */
482
483                 if (!received)
484                   {
485                     ioctl (fd[i], TIOCREQCHECK, &ei);
486
487                     if (ei.request == TIOCCLOSE)
488                       {
489                         ioctl (fd[i], TIOCREQSET, &ei);
490                         return -1;
491                       }
492
493                     ioctl (fd[i], TIOCREQSET, &ei);
494                   }
495                 ready--;
496               }
497           }
498 #endif
499       }
500   } while (timeout == -1 && ready == 0);
501
502   return ready;
503 }
504
505 #else
506
507 void
508 __gnat_kill (int pid, int sig, int close)
509 {
510 }
511
512 int
513 __gnat_waitpid (int pid, int sig)
514 {
515   return 0;
516 }
517
518 int
519 __gnat_pipe (int *fd)
520 {
521   return -1;
522 }
523
524 int
525 __gnat_expect_fork (void)
526 {
527   return -1;
528 }
529
530 void
531 __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
532 {
533   *pid = 0;
534 }
535
536 int
537 __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set)
538 {
539   return -1;
540 }
541 #endif