bringing SDL 1.2.14 from vendor into the main branch
[AROS-Contrib.git] / regina / shell.c
blob09a306a078631bf7637eddbeb2edf55932a2869d
1 #ifndef lint
2 static char *RCSid = "$Id$";
3 #endif
5 /*
6 * The Regina Rexx Interpreter
7 * Copyright (C) 1992-1994 Anders Christensen <anders@pvv.unit.no>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the Free
21 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #if defined(WIN32)
25 # ifdef _MSC_VER
26 # if _MSC_VER >= 1100
27 /* Stupid MSC can't compile own headers without warning at least in VC 5.0 */
28 # pragma warning(disable: 4115 4201 4214)
29 # endif
30 # endif
31 # include <windows.h>
32 # ifdef _MSC_VER
33 # if _MSC_VER >= 1100
34 # pragma warning(default: 4115 4201 4214)
35 # endif
36 # endif
37 #endif
39 #include "rexx.h"
40 /*#include <limits.h> */
41 #include <stdio.h>
43 #include <string.h>
44 #include <signal.h>
45 /* #include <ctype.h> */
46 #include <errno.h>
47 #ifdef HAVE_ASSERT_H
48 # include <assert.h>
49 #endif
50 #ifdef HAVE_UNISTD_H
51 # include <unistd.h>
52 #endif
54 #if defined(VMS)
55 # define fork() vfork()
56 # ifdef posix_do_command
57 # undef posix_do_command
58 # endif
59 # define posix_do_command __regina_vms_do_command
60 #endif
62 #if defined(__WINS__) || defined(__EPOC32__)
63 # define REGINA_MAX_BUFFER_LENGTH 256
64 #else
65 # define REGINA_MAX_BUFFER_LENGTH 4096
66 #endif
68 #define STD_IO 0x00
69 #define simQUEUE 0x01
70 #define simLIFO 0x02
71 #define simFIFO 0x04
72 #define STREAM 0x08
73 #define STEM 0x10
74 #define STRING 0x20
75 #define QUEUE 0x40
76 #define LIFO 0x80
77 #define FIFO 0x100
79 #if defined(_POSIX_PIPE_BUF) && !defined(PIPE_BUF)
80 # define PIPE_BUF _POSIX_PIPE_BUF
81 #endif
83 typedef struct { /* shl_tsd: static variables of this module (thread-safe) */
84 char *cbuff ;
85 int child ;
86 int status ;
87 int running ;
88 void *AsyncInfo ;
89 unsigned char IObuf[4096]; /* write cache */
90 unsigned IOBused;
91 } shl_tsd_t; /* thread-specific but only needed by this module. see
92 * init_shell
95 /* init_shell initializes the module.
96 * Currently, we set up the thread specific data.
97 * The function returns 1 on success, 0 if memory is short.
99 int init_shell( tsd_t *TSD )
101 shl_tsd_t *st;
103 if (TSD->shl_tsd != NULL)
104 return(1);
106 if ((st = TSD->shl_tsd = MallocTSD(sizeof(shl_tsd_t))) == NULL)
107 return(0);
108 memset(st,0,sizeof(shl_tsd_t)); /* correct for all values */
109 return(1);
112 const streng *stem_access( tsd_t *TSD, environpart *e, int pos,
113 const streng *value)
114 /* puts e->name+"."+itoa(pos) to e->currname and accesses this variable.
115 * value is NULL to access the current value or non-NULL to set the new value.
116 * The return value is NULL if a new value is set or the old one.
119 int stemlen, leaflen ;
121 stemlen = Str_len( e->name ) ;
122 leaflen = sprintf( e->currname->value + stemlen, "%d", pos ) ;
124 e->currname->len = stemlen + leaflen ;
126 if (value == NULL)
127 #ifndef NON_ANSI_BEFORE_NOV_2001
128 return( get_it_anyway_compound( TSD, e->currname ) ) ;
129 #else
130 return( getdirvalue_compound( TSD, e->currname ) ) ;
131 #endif
133 setdirvalue_compound( TSD, e->currname, Str_dupTSD( value ) ) ;
134 return( NULL ) ;
137 void open_env_io( tsd_t *TSD, environpart *e )
138 /* Prepares the WITH-IO-redirection from envpart and sets *flag to either
139 * STREAM or STEM. Nothing happens if there isn't a redirection.
142 const streng *h ;
143 int error ;
144 char code ;
146 e->SameAsOutput = 0;
147 e->FileRedirected = 0;
148 e->tempname = NULL ; /* none as default, might become char* RedirTempFile */
149 e->type = STD_IO ;
150 e->hdls[0] = e->hdls[1] = -1 ;
152 if (e->name == NULL)
153 return ;
155 switch (e->flags.awt) {
156 case isSTREAM:
158 * For a STREAM input/output redirection, set the file reopen
159 * flag, and reopen the file.
161 e->type = STREAM ;
162 if (e->flags.isinput)
163 code = 'r' ;
164 else if (e->flags.append)
165 code = 'A' ;
166 else /* REPLACE */
167 code = 'R' ;
168 e->file = addr_reopen_file( TSD, get_it_anyway( TSD, e->name ), code ) ;
169 break;
171 case isSTEM:
173 * For a STEM input/output redirection, check that existing state of
174 * the stem if appropriate and initialise the stem
176 e->type = STEM ;
178 if (e->flags.isinput || e->flags.append)
181 * For a STEM input redirection, the stem must already exist and be
182 * a valid Rexx "array". This happens to an existing output stem in
183 * the append mode, too.
185 h = stem_access( TSD, e, 0, NULL ) ;
186 /* h must be a whole positive number */
187 e->maxnum = streng_to_int( TSD, h, &error ) ;
188 if (error || (e->maxnum < 0))
189 exiterror( ERR_INVALID_STEM_OPTION, /* needs stem.0 and */
190 1, /* (stem.0) as arguments */
191 tmpstr_of( TSD, e->currname ),
192 tmpstr_of( TSD, h ) ) ;
193 e->currnum = (e->flags.isinput) ? 1 : e->maxnum + 1;
195 else /* must be REPLACE */
197 e->maxnum = 0 ;
198 e->currnum = 1 ;
199 e->base->value[0] = '0' ;
200 e->base->len = 1 ;
201 stem_access( TSD, e, 0, e->base ) ;
203 break;
205 case isLIFO:
206 if (Str_len(e->name) == 0)
208 if (e->flags.isinput)
209 e->type = QUEUE;
210 else
211 e->type = LIFO;
212 break;
214 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "LIFO isn't implemented yet" ) ;
215 break;
217 case isFIFO:
218 if (Str_len(e->name) == 0)
220 if (e->flags.isinput)
221 e->type = QUEUE;
222 else
223 e->type = FIFO;
224 break;
226 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "FIFO isn't implemented yet" ) ;
227 break;
229 default:
230 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "Illegal address code in open_env_io()" ) ;
234 void put_stem( tsd_t *TSD, environpart *e, streng *str )
235 /* Adds one line to the stem specified in e. */
238 * FGC: 2 lines commented on 27.02.2002 17:08:46 FIXME
239 * const streng *h;
240 * int dummy;
243 e->maxnum = e->currnum ;
244 e->currnum++ ;
246 /* FGC: FIXME: Do we still need the following two lines?
247 * Needed by doscmd.c?
250 * FGC: 2 lines commented on 27.02.2002 17:08:46 FIXME
251 * h = stem_access( TSD, e, 0, NULL ) ;
252 * e->maxnum = e->currnum = streng_to_int( TSD, h, &dummy ) + 1 ;
254 e->base->len = sprintf( e->base->value, "%d", e->maxnum ) ;
255 stem_access( TSD, e, 0, e->base ) ;
256 stem_access( TSD, e, e->maxnum, str ) ;
259 static int write_buffered(const tsd_t *TSD, int hdl, const void *buf,
260 unsigned size, void *async_info)
262 int rc, done;
263 unsigned todo;
264 shl_tsd_t *st = TSD->shl_tsd;
266 if ((buf == NULL) || (size == 0)) /* force flush buffers */
268 if (st->IOBused)
269 rc = __regina_write(hdl, st->IObuf, st->IOBused, async_info);
270 else
271 rc = 0;
272 if (rc >= 0)
273 rc = __regina_write(hdl, NULL, 0, async_info);
274 else
275 __regina_write(hdl, NULL, 0, async_info);
276 return(rc);
279 done = 0;
280 while (size) {
281 todo = size;
282 if (todo > sizeof(st->IObuf) - st->IOBused)
283 todo = sizeof(st->IObuf) - st->IOBused;
284 if (todo > 0)
286 memcpy(st->IObuf + st->IOBused, buf, todo);
287 st->IOBused += todo;
290 done += todo;
291 if (st->IOBused < sizeof(st->IObuf))
292 return(done);
294 /* buffer full */
295 rc = __regina_write(hdl, st->IObuf, st->IOBused, async_info);
296 if (rc <= 0)
298 if (done)
299 break; /* something done sucessfully */
300 return(rc);
302 if (rc == (int) st->IOBused)
303 st->IOBused = 0;
304 else
306 memmove(st->IObuf, st->IObuf + rc, st->IOBused - rc);
307 st->IOBused -= rc;
310 buf = (const char *) buf + todo;
311 size -= todo;
314 return(done); /* something done sucessfully */
317 static int feed( const tsd_t *TSD, streng **string, int hdl, void *async_info )
318 /* Writes the content of *string into the file associated with hdl. The
319 * string is shortened and, after the final write, deleted and *string set
320 * to NULL.
321 * async_info is both a structure and a flag. If set, asynchronous IO shall
322 * be used, otherwise blocked IO has to be used.
323 * feed returns 0 on success or an errno value on error.
324 * A return value of EAGAIN is set if we have to wait.
327 unsigned total ;
328 int done ;
330 if ((string == NULL) || (*string == NULL))
331 return( 0 ) ;
333 total = Str_len( *string ) ;
334 if (total == 0)
335 return( 0 ) ;
337 done = write_buffered(TSD, hdl, (*string)->value, total, async_info);
338 if (done <= 0)
340 if (done == 0) /* no error set? */
341 done = ENOSPC ; /* good assumption */
342 else
343 done = -done;
344 if ((done != EAGAIN) && (done != EPIPE))
345 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, strerror(done) ) ;
346 return( done ) ; /* error */
349 if ((unsigned) done < total)
351 (*string)->len -= done ;
352 memmove((*string)->value, (*string)->value + done, (*string)->len);
354 else
356 assert((unsigned)done==total);
357 Free_stringTSD(*string);
358 *string = NULL;
360 return(0);
363 static int reap( const tsd_t *TSD, streng **string, int hdl, void *async_info )
364 /* Reads data from the file associated with hdl and returns it in *string.
365 * *string may be NULL or valid, in which case it is expanded.
366 * reap returns 0 on success or an errno value on error. The value -1 indicates
367 * EOF.
368 * async_info is both a structure and a flag. If set, asynchronous IO shall
369 * be used, otherwise blocked IO has to be used.
370 * A maximum chunk of REGINA_MAX_BUFFER_LENGTH (usually 4096) bytes is read in one operation.
371 * A return value of EAGAIN is set if we have to wait.
374 char buf[REGINA_MAX_BUFFER_LENGTH] ;
375 unsigned len, total ;
376 streng *s ;
377 int done ;
379 if (string == NULL)
380 return( 0 ) ;
382 done = __regina_read( hdl, buf, sizeof(buf), async_info ) ;
383 if (done <= 0)
385 if (done == 0)
386 return( -1 ); /* EOF */
387 else
388 done = -done;
389 /* FGC, FIXME: Not sure, this is the right processing. Setting RS, etc? */
390 if ( done != EAGAIN )
391 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, strerror(done) ) ;
392 return( done ) ; /* error */
395 if (( s = *string ) == NULL)
397 len = 0 ;
398 s = Str_makeTSD( done ) ;
400 else
402 len = Str_len( s ) ;
403 total = Str_max( s ) ;
404 if (len + done > total)
406 s = Str_makeTSD( len + done ) ;
407 s->len = len ;
408 memcpy( s->value, (*string)->value, len ) ;
409 Free_stringTSD( *string ) ;
412 memcpy( s->value + len, buf, done ) ;
413 s->len += done ;
414 *string = s ;
415 return( 0 ) ;
418 void cleanup_envirpart(const tsd_t *TSD, environpart *ep)
419 /* Closes the associated file handles of ep and deletes a temporary file
420 * if necessary.
423 shl_tsd_t *st = TSD->shl_tsd;
425 if (ep->hdls[0] != -1)
427 __regina_close(ep->hdls[0], (ep->FileRedirected) ? NULL : st->AsyncInfo);
428 ep->hdls[0] = -1;
430 if (ep->hdls[1] != -1)
432 __regina_close(ep->hdls[1], (ep->FileRedirected) ? NULL : st->AsyncInfo);
433 ep->hdls[1] = -1;
435 if (ep->tempname)
437 unlink(ep->tempname);
438 FreeTSD(ep->tempname);
439 ep->tempname = NULL;
443 static void cleanup( tsd_t *TSD, environment *env )
444 /* Closes all open handles in env and deletes temporary files. Already closed
445 * handles are marked by a value of -1.
446 * -1 is set to each handle after closing.
449 shl_tsd_t *st = TSD->shl_tsd;
451 cleanup_envirpart(TSD, &env->input);
452 cleanup_envirpart(TSD, &env->output);
453 cleanup_envirpart(TSD, &env->error);
454 purge_input_queue(TSD);
456 if (st->AsyncInfo)
457 delete_async_info(st->AsyncInfo);
458 st->AsyncInfo = NULL;
459 st->IOBused = 0;
462 static int setup_io( tsd_t *TSD, int io_flags, environment *env )
463 /* Sets up the IO-redirections based on the values in io_flags and env.
464 * Each environpart (env->input, env->output, env->error) is set up as follows:
465 * a) The enviroment-based streams and stems are set up if used or not.
466 * env->input.type (or output or error) is set to STREAM, STEM or STD_IO.
467 * b) The io_flags overwrite the different settings and may have
468 * values QUEUE, simLIFO, simFIFO.
469 * c) If a redirection takes place (type != STD_IO) a pipe() or temporary
470 * file is opened and used.
471 * This function returns 1 on success, 0 on error, in which case an error is
472 * already reported..
475 shl_tsd_t *st = TSD->shl_tsd;
477 cleanup( TSD, env ); /* Useful in case of an undetected previous error */
480 * Determine which ANSI redirections are in effect
482 open_env_io( TSD, &env->input ) ;
483 open_env_io( TSD, &env->output ) ;
484 open_env_io( TSD, &env->error ) ;
486 if ((env->output.type == STEM) && (env->error.type == STEM))
488 /* env->output.name and env->error.name must exist here
490 * We have to take special care if output and error are
491 * redirected to the same stem. We neither want to overwrite
492 * stem values twice nor want to read "stem.0" for every
493 * stem on every access to prevent it.
495 if (Str_ccmp(env->output.name, env->error.name) == 0)
497 env->error.SameAsOutput = 1;
498 if (env->error.maxnum == 0)
500 /* error may has the REPLACE option while output has not.
501 * Force a silent replace in this case.
503 env->output.maxnum = 0;
504 env->output.currnum = 1 ;
509 if (env->input.type == STEM)
511 /* Same procedure. To prevent overwriting variables while
512 * outputting to a stem wherefrom we have to read, buffer
513 * the input stem of the names do overlap.
516 if ((env->output.type == STEM) &&
517 (Str_ccmp(env->input.name, env->output.name) == 0))
518 env->input.SameAsOutput = 1;
520 if ((env->error.type == STEM) &&
521 (Str_ccmp(env->input.name, env->error.name) == 0))
522 env->input.SameAsOutput = 1;
524 if (env->input.SameAsOutput)
525 fill_input_queue(TSD, env->input.name, env->input.maxnum);
528 * Override any Regina redirections
530 if (io_flags & REDIR_INPUT)
531 env->input.type = QUEUE ;
532 if (io_flags & REDIR_OUTLIFO)
533 env->output.type = simLIFO ;
534 else if (io_flags & REDIR_OUTFIFO)
535 env->output.type = simFIFO ;
536 else if (io_flags & REDIR_OUTSTRING)
537 env->output.type = STRING ;
539 st->AsyncInfo = create_async_info(TSD);
541 if (env->input.type != STD_IO)
543 if (open_subprocess_connection(TSD, &env->input, st->AsyncInfo) != 0)
545 cleanup( TSD, env ) ;
546 exiterror( ERR_SYSTEM_FAILURE, 920, "creating redirection", "for input", strerror(errno) ) ;
547 return( 0 ) ;
550 if (env->output.type != STD_IO)
552 if (open_subprocess_connection(TSD, &env->output, st->AsyncInfo) != 0)
554 cleanup( TSD, env ) ;
555 exiterror( ERR_SYSTEM_FAILURE, 920, "creating redirection", "for output", strerror(errno) ) ;
556 return( 0 ) ;
559 else
560 fflush(stdout);
561 if (env->error.type != STD_IO)
563 if (open_subprocess_connection(TSD, &env->error, st->AsyncInfo) != 0)
565 cleanup( TSD, env ) ;
566 exiterror( ERR_SYSTEM_FAILURE, 920, "creating redirection", "for error", strerror(errno) ) ;
567 return( 0 ) ;
570 else
571 fflush(stderr);
573 return( 1 ) ;
576 static streng *fetch_food( tsd_t *TSD, environment *env )
577 /* returns one streng fetched either from a queue (env->input.type == QUEUE) or
578 * from a stem or stream.
579 * Returns NULL if there is no more input to feed the child process.
582 const streng *c ;
583 streng *retval ;
584 int delflag = 0 ;
586 switch (env->input.type)
588 case QUEUE:
589 if (stack_empty( TSD ))
590 return( NULL ) ;
591 delflag = 1 ;
592 c = popline( TSD, NULL, NULL, 0 ) ;
593 break;
595 case STREAM:
596 if (env->input.file == NULL)
597 return( NULL ) ;
598 delflag = 1 ;
599 c = addr_io_file( TSD, env->input.file, NULL ) ;
600 if (!c)
601 return( NULL ) ;
602 break;
604 case STEM:
605 if (!env->input.SameAsOutput)
607 if (env->input.currnum > env->input.maxnum)
608 return( NULL ) ;
609 c = stem_access( TSD, &env->input, env->input.currnum++, NULL ) ;
611 else
613 delflag = 1 ;
614 c = get_input_queue( TSD ) ;
616 if (!c)
617 return( NULL ) ;
618 break;
620 default:
621 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "Illegal feeder in fetch_food()" ) ;
622 return( NULL ) ;
623 break ;
626 /* Append a newline to the end of the line before returning */
627 retval = Str_makeTSD( c->len + 1 ) ;
628 memcpy(retval->value, c->value, c->len);
629 retval->value[c->len] = REGINA_EOL;
630 retval->len = c->len + 1;
631 if (delflag)
632 Free_stringTSD( (streng *) c ) ;
633 return( retval ) ;
636 static void drop_crop_line( tsd_t *TSD, environment *env, const char *data,
637 unsigned length, int is_error )
638 /* Called while reading the output of the child. The output is in data and
639 * contains length bytes without the line terminator.
640 * which may be empty or not yet completed. The exact destination is determined
641 * by env->x.type, where x is either output or error depending on is_error.
642 * type may have one of the values simLIFO, simFIFO, STRING, STREAM or STEM.
643 * is_error is set if the error redirection should happen.
646 streng *string ;
647 int type;
649 string = Str_makeTSD( length + 1 ) ; /* We need a terminating 0 in some */
650 /* cases */
651 memcpy( string->value, data, length ) ;
652 string->len = length ;
653 string->value[length] = '\0' ;
655 if (is_error)
656 type = env->error.type;
657 else
658 type = env->output.type;
660 switch (type)
662 case simLIFO:
663 tmp_stack(TSD, string, 0 ) ;
664 return; /* consumes the new string */
666 case simFIFO:
667 case STRING:
668 tmp_stack(TSD, string, 1 ) ;
669 return; /* consumes the new string */
671 case STREAM:
672 if (is_error)
674 if (env->error.file)
675 addr_io_file( TSD, env->error.file, string ) ;
677 else
679 if (env->output.file)
680 addr_io_file( TSD, env->output.file, string ) ;
682 break;
684 case STEM:
685 if (is_error && !env->error.SameAsOutput)
686 put_stem( TSD, &env->error, string ) ;
687 else
688 put_stem( TSD, &env->output, string ) ;
689 return; /* consumes the new string */
691 default:
692 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "Illegal crop in drop_crop_line()" ) ;
693 break ;
696 Free_stringTSD( string ) ;
699 static void drop_crop( tsd_t *TSD, environment *env, streng **string,
700 int EOFreached, int is_error)
701 /* Called while reading the output of the child. The output is in *string,
702 * which may be empty or not yet completed. The exact destination is determined
703 * by env->x.type, where x is either output or error depending on is_error.
704 * type may have one of the values simLIFO, simFIFO, STRING, STREAM or STEM.
705 * If EOFreached is set and some data is in *string, this data is interpreted
706 * as a completed line.
707 * Completed lines are cut of the string. The string itself isn't deleted.
708 * is_error is set if the error redirection should happen.
711 streng *s ;
712 char *ptr ;
713 char *ccr, *clf ;
714 int len=0, max, found, termlen=0 ;
717 s = *string;
718 if (s == NULL) /* might happen on a first call */
719 return;
721 ptr = s->value ;
722 max = Str_len( s ) ;
724 for (;;)
726 /* We have to find the line end. This is painful because we don't
727 * know the used line style. Allow '\r', '\n', "\r\n" ,and "\n\r".
729 /* memchr calling twice is much faster than a locally defined loop */
730 ccr = memchr( ptr, '\r', max ) ;
731 clf = memchr( ptr, '\n', max ) ;
732 found = 0 ;
733 if (ccr)
735 if (clf == ccr + 1)
737 len = ccr - ptr ;
738 termlen = 2 ;
739 found = 1 ;
741 else if (ccr == clf + 1)
743 len = clf - ptr ;
744 termlen = 2 ;
745 found = 1 ;
747 else /* '\r' found, but we must know if it terminates */
749 len = ccr - ptr ;
750 if ((len < max) || EOFreached)
752 termlen = 1 ;
753 found = 1 ;
757 else if (clf) /* simple line feed */
759 len = clf - ptr ;
760 if ((len < max) || EOFreached)
762 termlen = 1 ;
763 found = 1 ;
766 else if (EOFreached)
768 len = max ;
769 termlen = 0 ;
770 if (len)
771 found = 1;
773 if (!found)
774 break;
776 drop_crop_line( TSD, env, ptr, (unsigned) len, is_error ) ;
777 len += termlen ;
778 max -= len ;
780 memcpy( s->value, s->value + len, max ) ;
782 s->len = max ;
783 *string = s ;
786 int posix_do_command( tsd_t *TSD, const streng *command, int io_flags, environment *env )
788 int child, rc ;
789 int in, out, err;
790 streng *istring = NULL, *ostring = NULL, *estring = NULL ;
791 char *cmdline ;
792 shl_tsd_t *st = TSD->shl_tsd;
794 fflush( stdout ) ;
795 fflush( stderr ) ;
797 if (!setup_io(TSD, io_flags, env))
798 exiterror( ERR_SYSTEM_FAILURE, 0 ) ;
800 if (env->input.FileRedirected)
802 /* fill up the input file without closing the stream. */
804 while ((istring = fetch_food(TSD, env)) != NULL) {
805 if (feed(TSD, &istring, env->input.hdls[1], NULL) != 0)
806 break; /* shall not happen! */
808 /* seek positions of both fdin may have been destroyed */
809 restart_file(env->input.hdls[0]);
810 __regina_close(env->input.hdls[1], st->AsyncInfo );
811 env->input.hdls[1] = -1;
814 cmdline = str_ofTSD( command ) ;
815 child = fork_exec(TSD, env, cmdline, st->AsyncInfo);
816 FreeTSD( cmdline ) ;
817 if ((child == -1) || (child == -2))
819 cleanup( TSD, env ) ;
820 exiterror( ERR_SYSTEM_FAILURE, 1, strerror(errno) ) ;
823 /* Close the child part of the handles */
824 if (env->input.hdls[0] != -1) __regina_close(env->input.hdls[0], st->AsyncInfo ) ;
825 if (env->output.hdls[1] != -1) __regina_close(env->output.hdls[1], st->AsyncInfo ) ;
826 if (env->error.hdls[1] != -1) __regina_close(env->error.hdls[1], st->AsyncInfo ) ;
827 env->input.hdls[0] = env->output.hdls[1] = env->error.hdls[1] = -1;
829 /* Force our own handles to become nonblocked */
830 if (!env->input.FileRedirected)
832 in = env->input.hdls[1];
833 unblock_handle( &in, st->AsyncInfo ) ;
835 else
836 in = -1;
837 if (!env->output.FileRedirected)
839 out = env->output.hdls[0];
840 unblock_handle( &out, st->AsyncInfo ) ;
842 else
843 out = -1;
844 if (!env->error.FileRedirected)
846 err = env->error.hdls[0];
847 unblock_handle( &err, st->AsyncInfo ) ;
849 else
850 err = -1;
852 #ifdef SIGPIPE
853 regina_signal( SIGPIPE, SIG_IGN ) ;
854 #endif
856 while ((in != -1) || (out != -1) || (err != -1))
858 reset_async_info(st->AsyncInfo);
859 if (in != -1)
861 do {
862 if (!istring)
863 istring = fetch_food( TSD, env ) ;
864 if (!istring)
866 rc = write_buffered(TSD, in, NULL, 0, st->AsyncInfo);
867 if (rc == -EAGAIN)
868 add_async_waiter(st->AsyncInfo, in, 0);
869 else
871 if (rc < 0)
873 errno = -rc;
874 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, strerror(errno) ) ;
876 if (__regina_close(in, st->AsyncInfo))
877 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, strerror(errno) ) ;
878 env->input.hdls[1] = in = -1 ;
879 rc = -1 ; /* indicate a closed stream */
882 else /* nothing left in string, but more in the stack */
884 rc = feed( TSD, &istring, in, st->AsyncInfo ) ;
885 if (rc)
887 if (rc == EAGAIN)
888 add_async_waiter(st->AsyncInfo, in, 0);
889 else
891 __regina_close(in, st->AsyncInfo) ;
892 env->input.hdls[1] = in = -1 ;
895 else if (istring != NULL)
897 /* hasn't written all at once, therefore is blocked.
898 * do a little performance boost and don't try to write
899 * once more, perform the wait instead.
901 rc = -1;
902 add_async_waiter(st->AsyncInfo, in, 0);
905 } while (rc == 0); /* It is best for performance and no penalty for */
906 /* security to write as much as possible */
908 } /* if (in != -1) */
910 if (out != -1)
912 do {
913 rc = reap( TSD, &ostring, out, st->AsyncInfo );
914 if (rc)
916 if (rc == EAGAIN)
917 add_async_waiter(st->AsyncInfo, out, 1);
918 else
920 __regina_close(out, st->AsyncInfo) ;
921 env->output.hdls[0] = out = -1 ;
924 else if (ostring != NULL)
925 drop_crop( TSD, env, &ostring, 0, 0 ) ;
926 } while (rc == 0); /* It is best for performance and no penalty for */
927 /* security to write as much as possible */
928 } /* if (out != -1) */
930 if (err != -1)
932 do {
933 rc = reap( TSD, &estring, err, st->AsyncInfo );
934 if (rc)
936 if (rc == EAGAIN)
937 add_async_waiter(st->AsyncInfo, err, 1);
938 else
940 __regina_close(err, st->AsyncInfo) ;
941 env->error.hdls[0] = err = -1 ;
944 else if (estring != NULL)
945 drop_crop( TSD, env, &estring, 0, 1 ) ;
946 } while (rc == 0); /* It is best for performance and no penalty for */
947 /* security to write as much as possible */
948 } /* if (err != -1) */
950 wait_async_info(st->AsyncInfo); /* wait for any more IO */
951 } /* end of IO */
953 if (istring)
954 Free_stringTSD( istring );
956 if (ostring && Str_len(ostring))
958 drop_crop( TSD, env, &ostring, 1, 0 ) ;
959 Free_stringTSD( ostring );
962 if (estring && Str_len(estring))
964 drop_crop( TSD, env, &estring, 1, 1 ) ;
965 Free_stringTSD( estring );
968 if (env->input.type == QUEUE)
970 while (!stack_empty( TSD ))
972 Free_stringTSD( popline( TSD, NULL, NULL, 0 ) ) ;
976 rc = __regina_wait(child);
978 #ifdef SIGPIPE
979 regina_signal( SIGPIPE, SIG_DFL ) ;
980 #endif
982 if (env->output.FileRedirected)
984 /* The file position is usually at the end: */
985 restart_file(env->output.hdls[0]);
986 while (reap( TSD, &ostring, env->output.hdls[0], NULL ) == 0) {
987 if (ostring != NULL)
988 drop_crop( TSD, env, &ostring, 0, 0 ) ;
990 if (ostring != NULL)
991 drop_crop( TSD, env, &ostring, 1, 0 ) ;
993 /* use the automatted closing feature of cleanup */
995 if (env->error.FileRedirected)
997 /* The file position is usually at the end: */
998 restart_file(env->error.hdls[0]);
999 while (reap( TSD, &estring, env->error.hdls[0], NULL ) == 0) {
1000 if (estring != NULL)
1001 drop_crop( TSD, env, &estring, 0, 1 ) ;
1003 if (estring != NULL)
1004 drop_crop( TSD, env, &estring, 1, 1 ) ;
1005 /* use the automatted closing feature of cleanup */
1008 if ((env->output.type == simLIFO) || (env->output.type == simFIFO))
1009 flush_stack( TSD, env->output.type == simFIFO ) ;
1011 cleanup( TSD, env ) ;
1013 return rc ;