OSDN Git Service

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