2 static char *RCSid
= "$Id$";
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.
27 /* Stupid MSC can't compile own headers without warning at least in VC 5.0 */
28 # pragma warning(disable: 4115 4201 4214)
34 # pragma warning(default: 4115 4201 4214)
40 /*#include <limits.h> */
45 /* #include <ctype.h> */
55 # define fork() vfork()
56 # ifdef posix_do_command
57 # undef posix_do_command
59 # define posix_do_command __regina_vms_do_command
62 #if defined(__WINS__) || defined(__EPOC32__)
63 # define REGINA_MAX_BUFFER_LENGTH 256
65 # define REGINA_MAX_BUFFER_LENGTH 4096
79 #if defined(_POSIX_PIPE_BUF) && !defined(PIPE_BUF)
80 # define PIPE_BUF _POSIX_PIPE_BUF
83 typedef struct { /* shl_tsd: static variables of this module (thread-safe) */
89 unsigned char IObuf
[4096]; /* write cache */
91 } shl_tsd_t
; /* thread-specific but only needed by this module. see
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
)
103 if (TSD
->shl_tsd
!= NULL
)
106 if ((st
= TSD
->shl_tsd
= MallocTSD(sizeof(shl_tsd_t
))) == NULL
)
108 memset(st
,0,sizeof(shl_tsd_t
)); /* correct for all values */
112 const streng
*stem_access( tsd_t
*TSD
, environpart
*e
, int pos
,
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
;
127 #ifndef NON_ANSI_BEFORE_NOV_2001
128 return( get_it_anyway_compound( TSD
, e
->currname
) ) ;
130 return( getdirvalue_compound( TSD
, e
->currname
) ) ;
133 setdirvalue_compound( TSD
, e
->currname
, Str_dupTSD( value
) ) ;
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.
147 e
->FileRedirected
= 0;
148 e
->tempname
= NULL
; /* none as default, might become char* RedirTempFile */
150 e
->hdls
[0] = e
->hdls
[1] = -1 ;
155 switch (e
->flags
.awt
) {
158 * For a STREAM input/output redirection, set the file reopen
159 * flag, and reopen the file.
162 if (e
->flags
.isinput
)
164 else if (e
->flags
.append
)
168 e
->file
= addr_reopen_file( TSD
, get_it_anyway( TSD
, e
->name
), code
) ;
173 * For a STEM input/output redirection, check that existing state of
174 * the stem if appropriate and initialise the 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 */
199 e
->base
->value
[0] = '0' ;
201 stem_access( TSD
, e
, 0, e
->base
) ;
206 if (Str_len(e
->name
) == 0)
208 if (e
->flags
.isinput
)
214 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "LIFO isn't implemented yet" ) ;
218 if (Str_len(e
->name
) == 0)
220 if (e
->flags
.isinput
)
226 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "FIFO isn't implemented yet" ) ;
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
243 e
->maxnum
= 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
)
264 shl_tsd_t
*st
= TSD
->shl_tsd
;
266 if ((buf
== NULL
) || (size
== 0)) /* force flush buffers */
269 rc
= __regina_write(hdl
, st
->IObuf
, st
->IOBused
, async_info
);
273 rc
= __regina_write(hdl
, NULL
, 0, async_info
);
275 __regina_write(hdl
, NULL
, 0, async_info
);
282 if (todo
> sizeof(st
->IObuf
) - st
->IOBused
)
283 todo
= sizeof(st
->IObuf
) - st
->IOBused
;
286 memcpy(st
->IObuf
+ st
->IOBused
, buf
, todo
);
291 if (st
->IOBused
< sizeof(st
->IObuf
))
295 rc
= __regina_write(hdl
, st
->IObuf
, st
->IOBused
, async_info
);
299 break; /* something done sucessfully */
302 if (rc
== (int) st
->IOBused
)
306 memmove(st
->IObuf
, st
->IObuf
+ rc
, st
->IOBused
- rc
);
310 buf
= (const char *) buf
+ 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
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.
330 if ((string
== NULL
) || (*string
== NULL
))
333 total
= Str_len( *string
) ;
337 done
= write_buffered(TSD
, hdl
, (*string
)->value
, total
, async_info
);
340 if (done
== 0) /* no error set? */
341 done
= ENOSPC
; /* good assumption */
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
);
356 assert((unsigned)done
==total
);
357 Free_stringTSD(*string
);
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
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
;
382 done
= __regina_read( hdl
, buf
, sizeof(buf
), async_info
) ;
386 return( -1 ); /* EOF */
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
)
398 s
= Str_makeTSD( done
) ;
403 total
= Str_max( s
) ;
404 if (len
+ done
> total
)
406 s
= Str_makeTSD( len
+ done
) ;
408 memcpy( s
->value
, (*string
)->value
, len
) ;
409 Free_stringTSD( *string
) ;
412 memcpy( s
->value
+ len
, buf
, done
) ;
418 void cleanup_envirpart(const tsd_t
*TSD
, environpart
*ep
)
419 /* Closes the associated file handles of ep and deletes a temporary file
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
);
430 if (ep
->hdls
[1] != -1)
432 __regina_close(ep
->hdls
[1], (ep
->FileRedirected
) ? NULL
: st
->AsyncInfo
);
437 unlink(ep
->tempname
);
438 FreeTSD(ep
->tempname
);
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
);
457 delete_async_info(st
->AsyncInfo
);
458 st
->AsyncInfo
= NULL
;
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
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
) ) ;
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
) ) ;
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
) ) ;
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.
586 switch (env
->input
.type
)
589 if (stack_empty( TSD
))
592 c
= popline( TSD
, NULL
, NULL
, 0 ) ;
596 if (env
->input
.file
== NULL
)
599 c
= addr_io_file( TSD
, env
->input
.file
, NULL
) ;
605 if (!env
->input
.SameAsOutput
)
607 if (env
->input
.currnum
> env
->input
.maxnum
)
609 c
= stem_access( TSD
, &env
->input
, env
->input
.currnum
++, NULL
) ;
614 c
= get_input_queue( TSD
) ;
621 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "Illegal feeder in fetch_food()" ) ;
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;
632 Free_stringTSD( (streng
*) c
) ;
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.
649 string
= Str_makeTSD( length
+ 1 ) ; /* We need a terminating 0 in some */
651 memcpy( string
->value
, data
, length
) ;
652 string
->len
= length
;
653 string
->value
[length
] = '\0' ;
656 type
= env
->error
.type
;
658 type
= env
->output
.type
;
663 tmp_stack(TSD
, string
, 0 ) ;
664 return; /* consumes the new string */
668 tmp_stack(TSD
, string
, 1 ) ;
669 return; /* consumes the new string */
675 addr_io_file( TSD
, env
->error
.file
, string
) ;
679 if (env
->output
.file
)
680 addr_io_file( TSD
, env
->output
.file
, string
) ;
685 if (is_error
&& !env
->error
.SameAsOutput
)
686 put_stem( TSD
, &env
->error
, string
) ;
688 put_stem( TSD
, &env
->output
, string
) ;
689 return; /* consumes the new string */
692 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "Illegal crop in drop_crop_line()" ) ;
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.
714 int len
=0, max
, found
, termlen
=0 ;
718 if (s
== NULL
) /* might happen on a first call */
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
) ;
741 else if (ccr
== clf
+ 1)
747 else /* '\r' found, but we must know if it terminates */
750 if ((len
< max
) || EOFreached
)
757 else if (clf
) /* simple line feed */
760 if ((len
< max
) || EOFreached
)
776 drop_crop_line( TSD
, env
, ptr
, (unsigned) len
, is_error
) ;
780 memcpy( s
->value
, s
->value
+ len
, max
) ;
786 int posix_do_command( tsd_t
*TSD
, const streng
*command
, int io_flags
, environment
*env
)
790 streng
*istring
= NULL
, *ostring
= NULL
, *estring
= NULL
;
792 shl_tsd_t
*st
= TSD
->shl_tsd
;
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
);
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
) ;
837 if (!env
->output
.FileRedirected
)
839 out
= env
->output
.hdls
[0];
840 unblock_handle( &out
, st
->AsyncInfo
) ;
844 if (!env
->error
.FileRedirected
)
846 err
= env
->error
.hdls
[0];
847 unblock_handle( &err
, st
->AsyncInfo
) ;
853 regina_signal( SIGPIPE
, SIG_IGN
) ;
856 while ((in
!= -1) || (out
!= -1) || (err
!= -1))
858 reset_async_info(st
->AsyncInfo
);
863 istring
= fetch_food( TSD
, env
) ;
866 rc
= write_buffered(TSD
, in
, NULL
, 0, st
->AsyncInfo
);
868 add_async_waiter(st
->AsyncInfo
, in
, 0);
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
) ;
888 add_async_waiter(st
->AsyncInfo
, in
, 0);
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.
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) */
913 rc
= reap( TSD
, &ostring
, out
, st
->AsyncInfo
);
917 add_async_waiter(st
->AsyncInfo
, out
, 1);
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) */
933 rc
= reap( TSD
, &estring
, err
, st
->AsyncInfo
);
937 add_async_waiter(st
->AsyncInfo
, err
, 1);
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 */
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
);
979 regina_signal( SIGPIPE
, SIG_DFL
) ;
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) {
988 drop_crop( TSD
, env
, &ostring
, 0, 0 ) ;
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
) ;