You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
710 lines
20 KiB
710 lines
20 KiB
/*++
|
|
|
|
Copyright (c) 1988-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
cop.c
|
|
|
|
Abstract:
|
|
|
|
Conditional/sequential command execution
|
|
|
|
--*/
|
|
|
|
#include "cmd.h"
|
|
|
|
extern int LastRetCode;
|
|
|
|
extern int ExtCtrlc; /* @@1 */
|
|
|
|
/* M000 ends */
|
|
|
|
unsigned PipeCnt ; /* M007 - Active pipe count */
|
|
struct pipedata *PdHead = NULL; /* M007 - 1st element of pipedata list */
|
|
struct pipedata *PdTail = NULL; /* M007 - Last element of pipedata list */
|
|
HANDLE PipePid ; /* M007 - Communication with ECWork */
|
|
|
|
|
|
|
|
/*** eComSep - execute a statement containing a command separator
|
|
*
|
|
* Purpose:
|
|
* Execute the left and right hand sides of a command separator
|
|
* operator.
|
|
*
|
|
* int eComSep(struct node *n)
|
|
*
|
|
* Args:
|
|
* n - parse tree node containing the command separator node
|
|
*
|
|
* Returns:
|
|
* Whatever the right hand side returns.
|
|
*
|
|
* Notes:
|
|
* Revised to always supply both args to Dispatch().
|
|
*/
|
|
|
|
int eComSep(n)
|
|
struct node *n ;
|
|
{
|
|
Dispatch(RIO_OTHER,n->lhs) ;
|
|
if (GotoFlag) {
|
|
return SUCCESS;
|
|
} else {
|
|
return(Dispatch(RIO_OTHER,n->rhs)) ;
|
|
}
|
|
}
|
|
|
|
|
|
/*** eOr - execute an OR operation
|
|
*
|
|
* Purpose:
|
|
* Execute the left hand side of an OR operator (||). If it succeeds,
|
|
* quit. Otherwise execute the right side of the operator.
|
|
*
|
|
* int eOr(struct node *n)
|
|
*
|
|
* Args:
|
|
* n - parse tree node containing the OR operator node
|
|
*
|
|
* Returns:
|
|
* If the left hand side succeeds, return SUCCESS. Otherwise, return
|
|
* whatever the right side returns.
|
|
*
|
|
* Notes:
|
|
* Revised to always supply both args to Dispatch().
|
|
*/
|
|
|
|
int eOr(n)
|
|
struct node *n ;
|
|
{
|
|
int i ; /* Retcode from L.H. side of OR */
|
|
if ((i = Dispatch(RIO_OTHER,n->lhs)) == SUCCESS)
|
|
return(SUCCESS) ;
|
|
else {
|
|
LastRetCode = i;
|
|
return(Dispatch(RIO_OTHER,n->rhs)) ;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** eAnd - execute an AND operation
|
|
*
|
|
* Purpose:
|
|
* Execute the left hand side of an AND operator (&&). If it fails,
|
|
* quit. Otherwise execute the right side of the operator.
|
|
*
|
|
* int eAnd(struct node *n)
|
|
*
|
|
* Args:
|
|
* n - parse tree node containing the AND operator node
|
|
*
|
|
* Returns:
|
|
* If the left hand side fails, return its return code. Otherwise, return
|
|
* whatever the right side returns.
|
|
*
|
|
* Notes:
|
|
* Revised to always supply both args to Dispatch().
|
|
*/
|
|
|
|
int eAnd(n)
|
|
struct node *n ;
|
|
{
|
|
int i ; /* Retcode from L.H. side of AND */
|
|
|
|
if ((i = Dispatch(RIO_OTHER,n->lhs)) != SUCCESS) {
|
|
return(i) ;
|
|
} else if (GotoFlag) {
|
|
return SUCCESS;
|
|
} else {
|
|
return(Dispatch(RIO_OTHER,n->rhs)) ;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/********************* START OF SPECIFICATION **************************/
|
|
/* */
|
|
/* SUBROUTINE NAME: ePipe */
|
|
/* */
|
|
/* DESCRIPTIVE NAME: Pipe Process */
|
|
/* */
|
|
/* FUNCTION: Execute the left side of the pipe and direct its output to*/
|
|
/* the right side of the pipe. */
|
|
/* */
|
|
/* NOTES: None */
|
|
/* */
|
|
/* */
|
|
/* ENTRY POINT: ePipe */
|
|
/* LINKAGE: NEAR */
|
|
/* */
|
|
/* INPUT: n - parse tree node containing the pipe operator */
|
|
/* */
|
|
/* OUTPUT: None */
|
|
/* */
|
|
/* EXIT-NORMAL: The return code of the right side process. */
|
|
/* */
|
|
/* EXIT-ERROR: Failure if no pipe redirection can take place. */
|
|
/* */
|
|
/* EFFECTS: */
|
|
/* */
|
|
/* struct pipedata { */
|
|
/* unsigned rh ; Pipe read handle */
|
|
/* unsigned wh ; Pipe write handle */
|
|
/* unsigned shr ; Handles where the normal... */
|
|
/* unsigned shw ; ...STDIN/OUT handles are saved */
|
|
/* unsigned lPID ; Pipe lh side PID */
|
|
/* unsigned rPID ; Pipe rh side PID */
|
|
/* unsigned lstart ; Start Information of lh side @@4*/
|
|
/* unsigned rstart ; Start Information of rh side @@4*/
|
|
/* struct pipedata *prvpds ; Ptr to previous pipedata struct */
|
|
/* struct pipedata *nxtpds ; Ptr to next pipedata struct */
|
|
/* } */
|
|
/* */
|
|
/* unsigned PipePID; Pipe Process ID */
|
|
/* */
|
|
/* unsigned start_type; Start Information */
|
|
/* */
|
|
/* */
|
|
/* INTERNAL REFERENCES: */
|
|
/* ROUTINES: */
|
|
/* PutStdErr - Print an error message */
|
|
/* Abort - Terminate program with abort */
|
|
/* SetList - Set Link List for pipedata structure */
|
|
/* Cdup - Duplicate supplied handle and save the new handle*/
|
|
/* Cdup2 - Duplicate supplied handle and save the new handle*/
|
|
/* Dispatch - Execute the program */
|
|
/* PipeErr - Handle pipe error */
|
|
/* Cclose - Close the specified handle */
|
|
/* PipeWait - Wait for the all pipe process completion */
|
|
/* */
|
|
/* EXTERNAL REFERENCES: */
|
|
/* ROUTINES: */
|
|
/* DOSMAKEPIPE - Make pipe */
|
|
/* */
|
|
/********************** END OF SPECIFICATION **************************/
|
|
/*** ePipe - Create a pipeline between two processes (M000)
|
|
*
|
|
* Purpose:
|
|
* Execute the left side of the pipe and direct its output to
|
|
* the right side of the pipe.
|
|
*
|
|
* int ePipe(struct node *n)
|
|
*
|
|
* Args:
|
|
* n - parse tree node containing the pipe operator
|
|
*
|
|
* Returns:
|
|
* The return code of the right side process or failure if no
|
|
* pipe redirection can take place.
|
|
*
|
|
* Notes:
|
|
* M007 - This function has been completely rewritten for real pipes.
|
|
*
|
|
*/
|
|
|
|
int ePipe(n)
|
|
struct node *n ;
|
|
{
|
|
struct pipedata *Pd ; /* Pipe struct pointer */
|
|
int k = 0 ; /* RH side return code */
|
|
struct node *l ; /* Copy of left side arg */
|
|
struct node *r ; /* Copy of right side arg */
|
|
extern unsigned start_type ; /* API type used to start */
|
|
TCHAR cflags ; /* */
|
|
|
|
l = n->lhs ; /* Equate locals to... */
|
|
r = n->rhs ; /* ...L & R operations */
|
|
|
|
DEBUG((OPGRP,PILVL,"PIPES:LH = %d, RH = %d ",l->type,r->type)) ;
|
|
|
|
if (!(Pd = (struct pipedata *)mkstr(sizeof(struct pipedata)))) {
|
|
|
|
DEBUG((OPGRP,PILVL,"PIPES:Couldn't alloc structure!")) ;
|
|
|
|
return(FAILURE) ;
|
|
};
|
|
|
|
|
|
//
|
|
// Create a pipe with a read handle and a write handle
|
|
//
|
|
|
|
if (_pipe((int *)Pd, 0, O_BINARY)) {
|
|
|
|
DEBUG((OPGRP,PILVL,"PIPES:pipe failed!")) ;
|
|
|
|
PutStdErr(ERROR_NOT_ENOUGH_MEMORY, NOARGS); /* M013 */
|
|
return(FAILURE) ;
|
|
Abort() ;
|
|
};
|
|
|
|
SetList(Pd->rh) ; /* M009 */
|
|
SetList(Pd->wh) ; /* M009 */
|
|
|
|
DEBUG((OPGRP,PILVL,"PIPES:Pipe built. Handles: rd = %d wt = %d ",Pd->rh, Pd->wh)) ;
|
|
DEBUG((OPGRP,PILVL,"PIPES:Pipe (pre-index) count = %d", PipeCnt)) ;
|
|
|
|
if (!PipeCnt++) { /* Already some pipes? */
|
|
PdHead = PdTail = Pd ; /* No, set head/tail ptrs */
|
|
Pd->prvpds = NULL ; /* No previous structure */
|
|
|
|
DEBUG((OPGRP,PILVL,"PIPES:This is first pipe.")) ;
|
|
|
|
} else {
|
|
|
|
DEBUG((OPGRP,PILVL,"PIPES:This is pipe %d.", PipeCnt)) ;
|
|
|
|
PdTail->nxtpds = Pd ;
|
|
Pd->prvpds = PdTail ;
|
|
Pd->nxtpds = NULL ;
|
|
PdTail = Pd ;
|
|
} ;
|
|
|
|
//
|
|
// Set up the redirection for the left-hand side; the writing side.
|
|
// We do this by saving the current stdout, duplicating the pipe-write
|
|
// handle onto stdout, and then invoking the left-hand side of the pipe.
|
|
// When we do this, the lefthand side will fill the pipe with data.
|
|
//
|
|
|
|
//
|
|
// Save stdout handle
|
|
//
|
|
|
|
if ((Pd->shw = Cdup(STDOUT)) == BADHANDLE) { /* Save STDOUT (M009) */
|
|
Pd->shw = BADHANDLE ; /* If err, go process it */
|
|
PipeErr() ; /* DOES NOT RETURN */
|
|
};
|
|
|
|
DEBUG((OPGRP,PILVL,"PIPES:STDOUT dup'd to %d.", Pd->shw)) ;
|
|
|
|
//
|
|
// Make stdout point to the write side of the pipe
|
|
//
|
|
|
|
if (Cdup2(Pd->wh, STDOUT) == BADHANDLE) /* Make wh STDOUT (M009) */
|
|
PipeErr() ; /* DOES NOT RETURN */
|
|
|
|
Cclose(Pd->wh) ; /* Close pipe hndl (M009) */
|
|
Pd->wh = 0 ; /* And zero the holder */
|
|
|
|
if (l->type <= CMDTYP) { /* @@5a */
|
|
/* @@5a */
|
|
FindAndFix( (struct cmdnode *) l, &cflags ) ; /* @@5a */
|
|
} /* @@5a */
|
|
|
|
DEBUG((OPGRP,PILVL,"PIPES:Write pipe now STDOUT")) ;
|
|
|
|
//
|
|
// Execute the left side of the pipe, fillng the pipe
|
|
//
|
|
|
|
k = Dispatch(RIO_PIPE,l) ;
|
|
|
|
|
|
//
|
|
// This closes the read handle in the left hand pipe. I don't know
|
|
// why we're doing this.
|
|
//
|
|
|
|
if (PipePid != NULL) {
|
|
DuplicateHandle( PipePid,
|
|
CRTTONT(Pd->rh),
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
FALSE,
|
|
DUPLICATE_CLOSE_SOURCE);
|
|
}
|
|
|
|
//
|
|
// Restore the saved stdout
|
|
//
|
|
|
|
if (Cdup2(Pd->shw, STDOUT) == BADHANDLE)
|
|
PipeErr( );
|
|
|
|
//
|
|
// Closed the saved handle
|
|
//
|
|
|
|
Cclose(Pd->shw) ; /* M009 */
|
|
Pd->shw = 0 ;
|
|
|
|
DEBUG((OPGRP,PILVL,"PIPES:STDOUT now handle 1 again.")) ;
|
|
|
|
if (k) {
|
|
ExtCtrlc = 2; /* @@1 */
|
|
Abort() ;
|
|
}
|
|
|
|
Pd->lPID = PipePid ;
|
|
Pd->lstart = start_type ; /* Save the start_type in pipedata struct */
|
|
PipePid = 0 ;
|
|
start_type = NONEPGM ; /* Reset the start_type D64 */
|
|
|
|
DEBUG((OPGRP,PILVL,"PIPES:Dispatch LH side succeeded - LPID = %d.",Pd->lPID)) ;
|
|
|
|
|
|
//
|
|
// Start on the right hand side of the pipe. Save the current stdin,
|
|
// copy the pipe read handle to stdin and then execute the right hand side
|
|
// of the pipe
|
|
//
|
|
|
|
//
|
|
// Save stdin
|
|
//
|
|
|
|
if ((Pd->shr = Cdup(STDIN)) == BADHANDLE) { /* Save STDIN (M009) */
|
|
Pd->shr = BADHANDLE ;
|
|
PipeErr() ; /* DOES NOT RETURN */
|
|
};
|
|
|
|
DEBUG((OPGRP,PILVL,"PIPES:STDIN dup'd to %d.", Pd->shr)) ;
|
|
|
|
//
|
|
// Point stdin at the pipe read handle
|
|
//
|
|
|
|
if (Cdup2(Pd->rh, STDIN) == BADHANDLE) /* Make rh STDIN (M009) */
|
|
PipeErr() ; /* DOES NOT RETURN */
|
|
|
|
Cclose(Pd->rh) ; /* Close pipe hndl (M009) */
|
|
Pd->rh = 0 ; /* And zero the holder */
|
|
|
|
if (r->type <= CMDTYP) { /* @@5a */
|
|
/* @@5a */
|
|
FindAndFix( (struct cmdnode *) r, &cflags) ; /* @@5a */
|
|
}; /* @@5a */
|
|
|
|
DEBUG((OPGRP,PILVL,"PIPES:Read pipe now STDIN")) ;
|
|
|
|
//
|
|
// Start off the right hand side of the pipe
|
|
//
|
|
|
|
k = Dispatch(RIO_PIPE,r) ;
|
|
|
|
//
|
|
// Restore the saved stdin
|
|
//
|
|
|
|
if (Cdup2(Pd->shr, STDIN) == BADHANDLE) /* M009 */
|
|
PipeErr() ; /* DOES NOT RETURN */
|
|
|
|
//
|
|
// Get rid of the saved stdin
|
|
//
|
|
|
|
Cclose(Pd->shr) ; /* M009 */
|
|
Pd->shr = 0 ;
|
|
|
|
DEBUG((OPGRP,PILVL,"PIPES:STDIN now handle 0 again.")) ;
|
|
|
|
if (k) {
|
|
ExtCtrlc = 2; /* @@1 */
|
|
Abort() ;
|
|
}
|
|
|
|
Pd->rPID = PipePid ;
|
|
Pd->rstart = start_type ; /* Save the start_type in pipedata struct */
|
|
PipePid = 0 ;
|
|
start_type = NONEPGM ; /* Reset the start_type D64 */
|
|
|
|
DEBUG((OPGRP,PILVL,"PIPES:Dispatch RH side succeeded - RPID = %d.",Pd->rPID)) ;
|
|
|
|
if (!(--PipeCnt)) { /* Additional pipes? */
|
|
|
|
DEBUG((OPGRP,PILVL,"PIPES:Returning from top level pipe. Cnt = %d", PipeCnt)) ;
|
|
|
|
return(PipeWait()) ; /* No, return CWAIT */
|
|
};
|
|
|
|
DEBUG((OPGRP,PILVL,"PIPES:Returning from pipe. Cnt = %d", PipeCnt)) ;
|
|
|
|
return(k) ; /* Else return exec ret */
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** PipeErr - Fixup and error out following pipe error
|
|
*
|
|
* Purpose:
|
|
* To provide single error out point for multiple error conditions.
|
|
*
|
|
* int PipeErr()
|
|
*
|
|
* Args:
|
|
* None.
|
|
*
|
|
* Returns:
|
|
* DOES NOT RETURN TO CALLER. Instead it causes an internal Abort().
|
|
*
|
|
*/
|
|
|
|
void PipeErr()
|
|
{
|
|
|
|
PutStdErr(MSG_PIPE_FAILURE, NOARGS) ; /* M013 */
|
|
Abort() ;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/********************* START OF SPECIFICATION **************************/
|
|
/* */
|
|
/* SUBROUTINE NAME: PipeWait */
|
|
/* */
|
|
/* DESCRIPTIVE NAME: Wait and Collect Retcode for All Pipe Completion */
|
|
/* */
|
|
/* FUNCTION: This routine calls WaitProc or WaitTermQProc for all */
|
|
/* pipelined processes until entire pipeline is finished. */
|
|
/* The return code of right most element is returned. */
|
|
/* */
|
|
/* NOTES: If the pipelined process is started by DosExecPgm, */
|
|
/* WaitProc is called. If the pipelined process is started */
|
|
/* by DosStartSession, WaitTermQProc is called. */
|
|
/* */
|
|
/* */
|
|
/* ENTRY POINT: PipeWait */
|
|
/* LINKAGE: NEAR */
|
|
/* */
|
|
/* INPUT: None */
|
|
/* */
|
|
/* OUTPUT: None */
|
|
/* */
|
|
/* EXIT-NORMAL: No error return code */
|
|
/* */
|
|
/* EXIT-ERROR: Error return code from either WaitTermQProc or WaitProc*/
|
|
/* */
|
|
/* */
|
|
/* EFFECTS: None. */
|
|
/* */
|
|
/* INTERNAL REFERENCES: */
|
|
/* ROUTINES: */
|
|
/* WaitProc - wait for the termination of the specified process, */
|
|
/* its child process, and related pipelined */
|
|
/* processes. */
|
|
/* */
|
|
/* WaitTermQProc - wait for the termination of the specified */
|
|
/* session and related pipelined session. */
|
|
/* */
|
|
/* EXTERNAL REFERENCES: */
|
|
/* ROUTINES: */
|
|
/* WINCHANGESWITCHENTRY - Change switch list entry */
|
|
/* */
|
|
/********************** END OF SPECIFICATION **************************/
|
|
/*** PipeWait - wait and collect retcode for all pipe completion (M007)
|
|
*
|
|
* Purpose:
|
|
* To do cwaits on all pipelined processes until entire pipeline
|
|
* is finished. The retcode of the rightmost element of the pipe
|
|
* is returned.
|
|
*
|
|
* int PipeWait()
|
|
*
|
|
* Args:
|
|
* None.
|
|
*
|
|
* Returns:
|
|
* Retcode of rightmost pipe process.
|
|
*
|
|
*/
|
|
|
|
PipeWait()
|
|
{
|
|
unsigned i = SUCCESS;
|
|
|
|
DEBUG((OPGRP,PILVL,"PIPEWAIT:Entered - PipeCnt = %d", PipeCnt)) ;
|
|
|
|
while (PdHead) {
|
|
if (PdHead->lPID) {
|
|
DEBUG((OPGRP, PILVL, "PIPEWAIT: lPID %d, lstart %d", PdHead->lPID, PdHead->lstart));
|
|
|
|
if ( PdHead->lstart == EXECPGM ) {
|
|
i = WaitProc(PdHead->lPID) ; /* M012 - Wait LH */
|
|
|
|
DEBUG((OPGRP,PILVL,"PIPEWAIT:CWAIT on LH - Ret = %d, SPID = %d", i, PdHead->lPID)) ;
|
|
}
|
|
}
|
|
if (PdHead->rPID) {
|
|
DEBUG((OPGRP, PILVL, "PIPEWAIT: rPID %d, rstart %d", PdHead->rPID, PdHead->rstart));
|
|
if ( PdHead->rstart == EXECPGM ) {
|
|
i = WaitProc(PdHead->rPID) ; /* M012 - Wait RH */
|
|
|
|
DEBUG((OPGRP,PILVL,"PIPEWAIT:CWAIT on RH - Ret = %d, PID = %d", i, PdHead->rPID)) ;
|
|
}
|
|
|
|
}
|
|
|
|
PdHead = PdHead->nxtpds ;
|
|
}
|
|
|
|
DEBUG((OPGRP,PILVL,"PIPEWAIT: complete, Retcode = %d", i)) ;
|
|
|
|
PdTail = NULL ; /* Cancel linked list... */
|
|
PipeCnt = 0 ; /* ...pipe count and pipe PID */
|
|
PipePid = 0 ;
|
|
LastRetCode = i;
|
|
return(i) ;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** BreakPipes - disconnect all active pipes (M000)
|
|
*
|
|
* Purpose:
|
|
* To remove the temporary pipe files and invalidate the pipedata
|
|
* structure when pipes are to be terminated, either through the
|
|
* completion of the pipe operation or SigTerm.
|
|
*
|
|
* This routine is called directly by the signal handler and must
|
|
* not generate any additional error conditions.
|
|
*
|
|
* void BreakPipes()
|
|
*
|
|
* Args:
|
|
* None.
|
|
*
|
|
* Returns:
|
|
* Nothing.
|
|
*
|
|
* Notes:
|
|
* M007 - This function has been completely rewritten for real pipes.
|
|
*
|
|
* *** W A R N I N G ! ***
|
|
* THIS ROUTINE IS CALLED AS A PART OF SIGNAL/ABORT RECOVERY AND
|
|
* THEREFORE MUST NOT BE ABLE TO TRIGGER ANOTHER ABORT CONDITION.
|
|
*
|
|
*/
|
|
|
|
void BreakPipes()
|
|
{
|
|
unsigned i ;
|
|
struct pipedata *pnode;
|
|
|
|
DEBUG((OPGRP,PILVL,"BRKPIPES:Entered - PipeCnt = %d", PipeCnt)) ;
|
|
|
|
/* The following two lines have been commented out */
|
|
/* because the NULL test on PdTail should be enough, */
|
|
/* and more importantly, even if PipeCnt is 0, you */
|
|
/* may still have been servicing a pipe in Pipewait */
|
|
|
|
/* if (!PipeCnt) */ /* If no active pipes... */
|
|
/* return ; */ /* ...don't do anything */
|
|
|
|
pnode = PdTail;
|
|
|
|
/* First, kill all of the processes */
|
|
while (pnode) {
|
|
if (pnode->lPID!=(HANDLE) NULL) {
|
|
/* M012 */
|
|
i = KillProc(pnode->lPID, FALSE) ; /* Kill LH */
|
|
|
|
DEBUG((OPGRP,PILVL,"BRKPIPES:LH (Pid %d) killed - Retcode = %d", PdTail->lPID, i)) ;
|
|
};
|
|
|
|
if (pnode->rPID!=(HANDLE) NULL) {
|
|
/* M012 */
|
|
i = KillProc(pnode->rPID, FALSE) ; /* Kill RH */
|
|
|
|
DEBUG((OPGRP,PILVL,"BRKPIPES:RH (Pid %d) killed - Retcode = %d", PdTail->rPID, i)) ;
|
|
};
|
|
pnode = pnode->prvpds ;
|
|
}
|
|
|
|
/* Wait for the processes to die, and clean up file handles */
|
|
while (PdTail) {
|
|
if (PdTail->lPID) {
|
|
if (PdTail->lstart == EXECPGM) {
|
|
i = WaitProc(PdTail->lPID);
|
|
// } else {
|
|
// WaitTermQProc(PdTail->lPID, &i) ;
|
|
}
|
|
};
|
|
|
|
if (PdTail->rPID) {
|
|
if (PdTail->rstart == EXECPGM) {
|
|
i = WaitProc(PdTail->rPID);
|
|
// } else {
|
|
// WaitTermQProc(PdTail->rPID, &i) ;
|
|
}
|
|
};
|
|
|
|
if (PdTail->rh) {
|
|
Cclose(PdTail->rh) ; /* M009 */
|
|
|
|
DEBUG((OPGRP,PILVL,"BRKPIPES:Pipe read handle closed")) ;
|
|
};
|
|
if (PdTail->wh) {
|
|
Cclose(PdTail->wh) ; /* M009 */
|
|
|
|
DEBUG((OPGRP,PILVL,"BRKPIPES:Pipe write handle closed")) ;
|
|
};
|
|
if (PdTail->shr) {
|
|
FlushFileBuffers(CRTTONT(PdTail->shr));
|
|
Cdup2(PdTail->shr, STDIN) ; /* M009 */
|
|
Cclose(PdTail->shr) ; /* M009 */
|
|
|
|
DEBUG((OPGRP,PILVL,"BRKPIPES:STDIN restored.")) ;
|
|
|
|
};
|
|
if (PdTail->shw) {
|
|
Cdup2(PdTail->shw, STDOUT) ; /* M009 */
|
|
Cclose(PdTail->shw) ; /* M009 */
|
|
|
|
DEBUG((OPGRP,PILVL,"BRKPIPES:STDOUT restored.")) ;
|
|
|
|
};
|
|
PdTail = PdTail->prvpds ;
|
|
} ;
|
|
|
|
PdHead = NULL ; /* Cancel linked list... */
|
|
PipeCnt = 0 ; /* ...pipe count and pipe PID */
|
|
PipePid = 0;
|
|
|
|
DEBUG((OPGRP,PILVL,"BRKPIPES:Action complete, returning")) ;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** eParen - execute a parenthesized statement group
|
|
*
|
|
* Purpose:
|
|
* Execute the group of statements enclosed by a statement grouping
|
|
* operator; parenthesis().
|
|
*
|
|
* int eParen(struct node *n)
|
|
*
|
|
* Args:
|
|
* n - parse tree node containing the PAREN operator node
|
|
*
|
|
* Returns:
|
|
* Whatever the statement group returns.
|
|
*
|
|
* Notes:
|
|
* M000 - Altered to always supply both args to Dispatch().
|
|
* M004 - Debug statements were added for SILTYP operator.
|
|
* ** WARNING **
|
|
* BOTH THE LEFT PAREN AND THE SILENT OPERATOR (@) USE eParen
|
|
* WHEN DISPATCHED. CHANGING ONE WILL AFFECT THE OTHER !!
|
|
*/
|
|
|
|
int eParen(n)
|
|
struct node *n ;
|
|
{
|
|
DEBUG((OPGRP,PNLVL,"ePAREN: Operator is %s", (n->type == PARTYP) ? "Paren" : "Silent")) ;
|
|
return(Dispatch(RIO_OTHER,n->lhs)) ;
|
|
}
|