OSDN Git Service

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