        .Title  Pipes
;+++
; Pipes Etc...
;       An attempt to allow redirection, multiple commands and
;       piping on one line.  This is very incomplete and definitely
;       a hack.  This was written to test out some minor changes to
;       DCLcomplete and not really meant as a production program.
;
;       This code is copyright Ramon Curiel 1994.  Non-commercial
;       distribution is allowed, but contributions to my hacking
;       fund are always welcome.
;       
;       To use this program do the following
;
; Compiling/linking:
;       $ MACRO PIPE
;       $ LINK PIPE
;       Note:   If you are using a version of VMS prior to V5.5
;               you will need to change the subroutine complete
;               see complete subroutine for details.
;
; Installing:
;       $ PIPE :== $pipedevice:[pipedir]PIPE.EXE
;       $ RUN DCLCOMPLETE
;;
;
; Known Problems:
;       In order for this to work the last command for any subprocess
;       needs to send an EOF or the $STO/I=0 will be interpreted as 
;       part of the input stream of the next piped command...
;       This will require a ^Y and then manually stopping subprocesses.
;       Oh, well...it almost works :-) Example of problem:
;
;         $ WRT :== $WRITE SYS$OUTPUT
;         $ PIPE WRT "Hello" ; WRT "There" | TYPE SYS$INPUT
;         Hello
;         There
;         sto/i=0
;
; at which point things hang.  Ctrl/Y gets it out, but it leaves a stray
; process to be killed off.
;
;
; Note:
;       This is a demonstration program on what you might do with
;       dclcomplete...Quoting Don Stokes  "You can hold me
;       responsible if it makes you feel better, but if you think
;       I'm going to guarantee this crap, you've got another thing
;       coming.... 8-)"
;
;       "Questions, bug reports, money, bug fixes, kudos, money,
;       offers, money etc to"
;
; Author:
;       Ramon M. Curiel, Jr.
;       SRI International
;       333 Ravenswood Ave.
;       Menlo Park, Ca. 94025
;
;       phone:  (415)859-6073
;       Fax:    (415)859-3668
;       EMail:  ray@sri.com
;
; Date:
;        7-Jul-94
; Modification History:
; HG001         Hunter Goatley                   5-AUG-1994 01:05
;       Add .IFs for pre-VMS V5.5 code.
;
; RMC003        Ramon M. Curiel                 14-Jul-94
;       Allow input redirection as well as output.  This requires
;       a change to how we do redirection.  Add routines 
;       Check_Do_Redirect and Write_To_MBX (should be Channel).
;
; RMC002        Ramon M. Curiel                 12-Jul-94
;       Change how we do redirection and fix problem in Multi_Cmds
;       introduced by changing call to Complete.
;
; RMC001        Ramon M. Curiel                 11-Jul-94
;       Fix Complete routine to correctly stop the next process in
;       the chain.  Use RMS to open the MBX and close it to signal
;       EOF.  Then "$Sto/I=0" the next process.
;
;---
        $DVIDEF
        $FABDEF                         ;FILE ACCESS BLOCK DEFINITIONS
        $IODEF                  ;       $QIO function codes
        $PSLDEF
        $QUIDEF

.IF DEFINED QUI$_AUTOSTART_ON           ;This symbol was added to VMS V5.5
VMS55 = 1
.ENDC

.IF DEFINED VMS55
        $CMBDEF
.ENDC

Arg1 = 4 * 1
Arg2 = 4 * 2
Arg3 = 4 * 3
Arg4 = 4 * 4
Arg5 = 4 * 5
Arg6 = 4 * 6
Arg7 = 4 * 7
Arg8 = 4 * 8
Arg9 = 4 * 9
ArgA = 4 * 10
ArgB = 4 * 11
ArgC = 4 * 12
ArgD = 4 * 13
ArgE = 4 * 14
ArgF = 4 * 15
EFN_Last = 20
;
;Local Vars for Pipe_it
;
                PTmp = .
                     . = 0
SProc:          .long   0               ;Count of SUBIds...
EFN:            .long   0
PID:            .BLKQ   16              ;Process PID
InChan:         .BLKW   16              ;MBX Input Chan
OutChan:        .BlkW   16              ;MBX Output chan
;
; Items below are reusable
Flags:          .Long   0
PItmLst:        .blkb   6*12            ;room for 6 Items...
InNam:          .Blkb   64              ;InMBX Name
OutNam:         .blkb   64              ;OutMBx Name

                PLocal = .
                        . = PTmp

        .PSECT  $PLIT$,LONG,RD,NOWRT,NOEXE

Login:  .ascii  /sys$system:loginout.exe/
L_Sz  = . - login
c1:     .ascii  /Pipe: /
c1_sz = . - c1



Asgn_O: .ascii  "DEFINE/USER SYS$OUTPUT "
Asg_O_Sz = . - Asgn_O
Asgn_I: .ascii  "DEFINE/USER SYS$INPUT "
ASG_I_SZ = . - ASGN_I

;;;Debug = 1                    ;Debugging switch
        .If defined DEBUG
debug1: .ascid  /called Write_To_MBX/
debug2: .ascid  /called Check_Do_Redirect/
debug3: .ascid  /called Redirect_Execute/
debug4: .ascid  /called multiple_cmds/
debug5: .ascid  /called pipe_it/
debug6: .ascid  /called complete/
debug7: .ascid  /Called Lib$Spawn/
        .Endc
;
; OWN STORAGE:
;
        .PSECT  $OWN$,LONG,RD,WRT,NOEXE


        .PSECT  $CODE$,LONG,RD,NOWRT,EXE

;+++
; Write_To_MBX
;       write a string to a channel
; Input:
;       Arg1    - Address of channel to MBX
;       Arg2    - String to write
; Output:
;       return status of QIO
;---
        .Entry  Write_To_MBX,-
                ^M<r2,r3,r4,r5>
        .If defined debug
        pushaq  debug1
        calls   #1,G^Lib$Put_Output
        .endc
        movl    #lib$_invarg,r0
        cmpb    (ap),#2                 ;need to Args
        bneq    100$
        movaq   -(sp),r2                ;iosb
        movl    arg1(ap),r3             ;channel
        movl    Arg2(ap),r4             ;string

        $QioW_S Chan=(r3),Func=#IO$_WriteVBlk,-
                iosb=(R2),-             ;reuse iosb 
                p1=@4(r4),p2=(r4),p4=#^X01010000
        blbc    r0,100$
        movl    (r2),r0
100$:   Ret

;+++
; Check for Input/output redirect and then write...
; Input:
;       Arg1    - Channel
;       Arg2    - String to check
; ----
        .Entry  Check_Do_Redirect,-
                ^M<r2,r3,r4,r5,r6,r7,r8,r9>
        .If defined debug
        pushaq  debug2
        calls   #1,G^Lib$Put_Output
        .endc
        cmpb    (ap),#2
        blss    100$
        movaq   -(Sp),r6
        movq    @Arg2(Ap),(r6)  ;Store it here for now
        Tstw    (r6)
        beql    100$
;;;     pushl   r6
;;;     Calls   #1,G^Lib$Put_Output
        movaq   -(sp),r7
        moval   -(sp),4(r7)
        clrl    (r7)
        movl    #^a/ <  /,@4(r7)
        matchc  #3,@4(r7),-
                (r6),@4(r6)
        beql    200$            ;nope then call w/o redirect
        movl    #^A/ >  /,@4(r7)
        matchc  #3,@4(r7),-
                (r6),@4(r6)
        beql    150$            ;nope then call w/o redirect
        Callg   (ap),G^Write_To_MBX
100$:   Ret
150$:
        ADDW3   #ASG_O_SZ,-
                R2,(R7)         ;GET SIZE OF COMMAND
        SUBL2   (R7),SP         ;ALLOCATE BUFFER
        MOVL    SP,4(R7)        ;SAVE IT
        MOVQ    R2,R8           ;SAVE FILENAME
        MOVC3   #ASG_O_SZ,-
                ASGN_O,-
                @4(R7)          ;FILL BUFFER WITH DEF/USER
        brb     210$
200$:
        ADDW3   #ASG_I_SZ,-
                R2,(R7)         ;GET SIZE OF COMMAND
        SUBL2   (R7),SP         ;ALLOCATE BUFFER
        MOVL    SP,4(R7)        ;SAVE IT
        MOVQ    R2,R8           ;SAVE FILENAME
        MOVC3   #ASG_I_SZ,-
                ASGN_I,-
                @4(R7)          ;FILL BUFFER WITH DEF/USER
210$:   MOVC3   R8,(R9),(R3)    ;ADD FILE TO END
        subw2   r8,(r6)         ;Strip output device
        subw2   #3,(r6)         ;strip " > "
        movl    Arg1(Ap),r8
        pushl   r7
        pushl   r8
        Calls   #2,Check_Do_Redirect
        BLBC    R0,100$
        pushl   r6
        pushl   r8
        Calls   #2,Check_Do_Redirect
        brb     100$

;+++
; Redirect and Execute:
;       This routine checks for redirection and changes the
;       output channel (Arg3) to the file specified...
; Input:
;       Arg1    - Command to Execute
;       Arg2    - Input channel
;       Arg3    - Output channel
;       Arg4    - Flags
;       Arg5    - Process name
;       Arg6    - process id
;       Arg7    - completetion status
;       Arg8    - Event flag num
;       Arg9    - AST Address
;       Arg10   - AST Argument
;---    Arg11   - prompt...
;---    Arg12   - CLI
;
;---
        .Entry  Redirect_Execute,-
                ^M<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>
        .If defined debug
        pushaq  debug3
        calls   #1,G^Lib$Put_Output
        .endc
        cmpb    (Ap),#3
        blss    100$            ;assume Args okay but don't search
;;;;    pushl   Arg1(ap)
;;;;    calls   #1,G^Lib$Put_Output
        movl    Arg1(Ap),r6     ;Store it here for now
        beql    101$
        Tstw    (r6)
        beql    101$
        movaq   -(sp),r7
        moval   -(sp),4(r7)
        movl    #^a/ >  /,@4(r7)
        matchc  #3,@4(r7),-
                (r6),@4(r6)
        beql    200$            ;nope then call w/o redirect
        movl    #^A/ <  /,@4(r7)
        matchc  #3,@4(r7),-
                (r6),@4(r6)
        beql    200$            ;nope then call w/o redirect
        
        .If defined debug
        pushaq  debug7
        calls   #1,G^Lib$Put_Output
        .endc
100$:   callg   (ap),G^Lib$Spawn
101$:   Ret
200$:
        movl    Arg2(Ap),r9     ;do We have input device?
        bneq    210$
        $CreMBX_S -
                Chan=inchan(r11)[r10],- ;
                promsk=#^XFF0F          ;
205$:   blbc    r0,101$                 ;Return with Error
        movaq   -(sp),r9
        movl    #64,(r9)
        movab   InNam(r11),4(r9)        ;
        pushl   r9
        pushaw  InChan(r11)[r10]
        Calls   #2,GetName
210$:   pushl   ArgA(ap)
        pushl   Arg9(ap)
        pushl   Arg8(ap)
        pushl   Arg7(ap)
        pushl   Arg6(ap)
        pushl   Arg5(ap)
        pushl   Arg4(ap)
        pushl   Arg3(Ap)        ;new output file/device
        pushl   r9              ;old input device
        pushl   #0              ;send commands on another channel
        .If defined debug
        pushaq  debug7
        calls   #1,G^Lib$Put_Output
        .endc
        calls   #10,G^Lib$Spawn
        BLBC    R0,205$         ;RETURN AN ERROR
        movaw   InChan(r11)[r10],r8

        pushl   r6
        pushl   r8
        Calls   #2,G^Check_Do_Redirect

290$:   tstl    Arg2(Ap)
        bneq    300$
        pushr   #^m<r0,r1>
        movl    #0,(r9)
        movl    r8,4(r9)
        pushl   r9
        calls   #1,Complete
        popr    #^m<r0,r1>
        blbc    r0,400$
300$:   Ret
400$:   $exit_S R0

;====
; Multiple_Commands:
;       Check for multiple commands
; Input:
;       Arg1    - Command to Execute
;       Arg2    - Input channel
;       Arg3    - Output channel
;       Arg4    - Flags
;       Arg5    - Process name
;       Arg6    - process id
;       Arg7    - completetion status
;       Arg8    - Event flag num
;       Arg9    - AST Address
;       Arg10   - AST Argument
;       -Arg11  - prompt...
;       -Arg12  - CLI
; Implicit Input:
;       r11,r10 unchanged...
;

        .Entry  Multi_CMDS,-
                ^M<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>
        .If defined debug
        pushaq  debug4
        calls   #1,G^Lib$Put_Output
        .endc
        cmpb    (Ap),#3
        blss    100$            ;assume args okay but don't search
;;;     movaq   -(sp),r6
;;;     movq    @Arg1(Ap),(r6)  ;Store it here for now
        movl    Arg1(ap),r6
        movaq   -(sp),r7
        movaq   -(sp),r8
        moval   -(sp),4(r8)
        movl    #^a/ ;  /,@4(r8)
        movzwl  #3,(r8)         ;initialize descriptor
        matchc  (r8),@4(r8),-
                (r6),@4(r6)
        tstl    r0
        beql    200$            ;nope then call w/o redirect
100$:   callg   (ap),G^Redirect_Execute
101$:   Ret
200$:
        movq    r2,(r7)         ;output device (file)
        subw2   (r7),(r6)       ;Strip output device
        subw2   #3,(r6)         ;strip " > "
        movl    Arg2(Ap),r9     ;do We have input device?
        bneq    210$
        $CreMBX_S -
                Chan=inchan(r11)[r10],- ;
                promsk=#^XFF0F          ;
        blbc    r0,101$                 ;Return with Error
        movaq   -(sp),r9
        movl    #64,(r9)
        movab   InNam(r11),4(r9)        ;
        pushl   r9
        pushaw  InChan(r11)[r10]
        Calls   #2,GetName
210$:   pushl   ArgA(ap)
        pushl   Arg9(ap)
        pushl   Arg8(ap)
        pushl   Arg7(ap)
        pushl   Arg6(ap)
        pushl   Arg5(ap)
        pushl   Arg4(ap)
        pushl   Arg3(ap)        ;output file/device
        pushl   r9              ;old input device
        pushl   r6              ;shortened string...
        calls   #10,G^Redirect_Execute
        blbc    r0,101$
        movaq   -(Sp),r6        ;get new descriptor
        movw    inchan(r11)[r10],-
                r5
300$:
        movq    (r7),(r6)       ;copy input line
        matchc  (r8),@4(r8),-
                (r6),@4(r6)
                                ;don't really need to check
        movl    r2,(r7)         ;output device (file)
        beql    310$            ;all done
        movl    r3,4(r7)        ;point to next
        subw2   (r7),(r6)       ;Strip output device
        subw2   #3,(r6)         ;strip " ; "
310$:
        movzwl  (r6),r2
        beql    399$
        pushl   r6
        pushaw  inchan(r11)[r10]
        Calls   #2,Check_Do_Redirect
        BLBC    R0,315$
        tstw    (r7)
        bneq    300$            ;do next command
315$:   tstl    Arg2(ap)        ;input device
        bneq    399$            ;okay skip
320$:
        movl    #0,(r7)
        movaw   inchan(r11)[r10],-
                4(r7)
        pushl   r7
        calls   #1,Complete
399$:   movl    #SS$_Normal,r0  ;I think...
        brw     101$

        
;+++
; Pipe_It:
;       Routine to create subprocesses to execute commands
;       with output and maybe input to a mailbox
; Input:
;       Arg1(ap)        - Work Area
;       Arg2(ap)        - Command to execute
;       Arg3(ap)        - MBX for input to Arg2...
; output:
;       ????
;---
        .Entry  Pipe_It,-
                ^M<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>
        .If defined debug
        pushaq  debug5
        calls   #1,G^Lib$Put_Output
        .endc
        movl    Arg1(Ap),r11            ;Get address of working buffer
        movl    (r11),r10               ;r10 is the index
        incl    (r11)                   ;increment the count
        movaq   -(Sp),r9                        ;Allocate descriptor
        movaq   -(Sp),r8                        ;allocate longword for
        movl    Arg3(Ap),r6
        movl    #^a/    /,(r8)
        movb    #^a/|/,1(r8)            ;space list_char space
        movq    @Arg2(Ap),(r9)          ;get ready
;;;     pushl   r9
;;;     calls   #1,G^Lib$Put_output
        MatchC  #3,(r8),-                       ;Check for
                (r9),-                          ; Redirect Chars in
                @4(r9)                          ; Input Buffer
        tstl    r0
        beql    20$                             ;Yes all Done
        tstl    r6                              ;anything there?
;;;     beql    10$                             ;nope - shouldn't be here
        clrl    r5
        brw     31$
10$:    Movl    #SS$_Normal,r0          ;All Done nothing to do...
11$:    RET
20$:    movl    r2,r0
        beql    10$
        addl2   #3,r0
        subw2   r0,(r9)                         ;get length of first command
        movq    r2,(r8)                         ;Second command in R8 now

        $CreMBX_S -
                Chan=outchan(r11)[r10],-        ;
                promsk=#^XFF0F          ;
        blbc    r0,11$                  ;Return with Error
        pushaw  outchan(r11)[r10]       ;Go Fire up the next command
        pushl   r8                      ;
        pushl   r11
        Calls   #3,Pipe_It              ;
        blbs    r0,30$
25$:    pushr   #^M<r0,r1>
        $Dassgn_S Chan=outchan(r11)[r10]
        popr    #^M<r0,r1>
        brb     11$                     ;return Error

30$:    movaq   -(sp),r5
        movl    #64,(r5)
        movab   OutNam(r11),4(r5)       ;
        pushl   r5
        pushaw  OutChan(r11)[r10]
        Calls   #2,GetName
        blbc    r0,25$
31$:
        clrl    r7
        tstl    r6
        beql    40$
35$:    movw    (r6),InChan(r11)[r10]   ;
        movaq   -(sp),r7
        movl    #64,(r7)
        movab   InNam(r11),4(r7)        ;
        pushl   r7
        pushaw  InChan(r11)[r10]
        Calls   #2,GetName
40$:    movl    #10,r3
;;;;    movzwl  outchan(r11)[r10],r1
;;;;    PUSHL   R1                      ;Ast Param
        movaq   PID(r11)[r10],r1
        movaw   outchan(r11)[r10],4(r1) ;use high longword for channel
        movl    r10,(r1)                ;save index here
        pushl   r1
        PUSHAB  complete                ;AST Adr
70$:    pushab  Flags(r11)              ;EFN
72$:    PUSHL   #0                      ;final status
        pushl   #0                      ;unless of course we're first
        PUSHL   #0                      ;Proces name
        movl    #1,(r8)
        pushl   r8                      ;NoWait
        pushl   r5                      ;Output Device MBX
        pushl   r7                      ;input
        pushl   r9
        calls   r3,G^Multi_CMDS
80$:    blbc    r0,200$
100$:
        Decb    Flags(r11)              ;Decrement
        Ret
200$:
        pushr   #^m<r0>                 ;save status
        TSTW    OUTCHAN(R11)[r10]
        BEQL    210$
        $Dassgn_S -
                Chan=OutChan(r11)[r10]
210$:
        TSTW    INCHAN(r11)[R10]
        BEQL    220$
        $Dassgn_S -
                Chan=INChan(r11)[r10]
220$:   popr    #^m<r0>                 ;restore status
        brb     100$

Complete:
;+++
; Subprocess completion routine.  We come here when we are finished
; processing in a subprocess.  The input of the next process must
; be terminated and then we send a "$Sto/i=0" to the next process.
; Except for the last process (the first command) we must open the
; mbx as a file and then close it to signal eof.  The next line will
; be treated correctly...
; Input:
;       Arg1    - Quadword
;               L0 is a copy of r10 (index count into block)
;                  used as flag to determine if we should kill...
;               L1 is address of channel to MBX.
; Output:
;       Channel is closed and the process down the line is stop/id=0.
;
; For Versions of VMS prior to 5.5 see changes to be made at
;       label 410$.
;---
        .WORD   ^m<R2,r3,R4,r5,r6,r7>
        .If defined debug
        pushaq  debug6
        calls   #1,G^Lib$Put_Output
        .endc

        movab   -FAB$K_BLN(sp),r7
        MOVL    R7,SP                   ;ALLOCATE THE SPACE
        MOVC5   #0,(SP),#0,#FAB$K_BLN,(SP) ;ZERO FAB AND RAB
        ASSUME  FAB$B_BLN EQ FAB$B_BID+1
        MOVW    #FAB$K_BLN@8!FAB$C_BID,- ;SET BLOCK LENGTH AND ID FIELDS
                FAB$B_BID(R7)
        BISB    #FAB$M_PUT,FAB$B_FAC(R7);GET ACCESS ONLY
        MOVL    Arg1(Ap),r2
        bneq    401$
400$:   brw     420$
401$:


        Tstw    @4(r2)
        beql    400$                    ;nothing to do...
        movaq   -(sp),r6
        moval   -(sp),r5
        MOVAQ   -(SP),R4
        MOVaq   -(Sp),R3
        subl2   #64,sp
        movl    sp,4(r4)
        movl    #64,(r4)
        pushl   r4
        pushl   4(r2)
        calls   #2,GetName
;;;     pushl   r4
;;;     calls   #1,G^Lib$Put_Output     ;tell us which channel
        $Dassgn_S chan=@4(r2)           ;close the channel we're using
        movq    #^A"$sto/i=0",(r3)
        movb    (r4),FAB$B_FNS(r7)
        movl    4(r4),FAB$L_FNA(r7)

        movl    (r2),r6
        beql    410$
405$:
;;;;    pushaq  debug
;;;;    calls   #1,G^lib$put_Output
        $open   (r7)
        blbc    r0,420$                 ;device is gone all done...
        $close  (r7)
        blbc    r0,450$

410$:
;
; comment out next line for versions of VMS prior to V5.5
.IF DEFINED VMS55
        pushl   #CMB$M_WriteOnly        ;going to open a channel for write
.ENDC
        pushl   #0                      ;no mbx
        pushl   #0                      ;no acc mode
        pushl   r5                      ;address of channel
        pushl   r4                      ;device name
;
; Change next line to calls #4,G^Sys$Assign for VMS prior to V5.5
.IF DEFINED VMS55
        calls   #5,G^sys$Assign         ;assign the channel
.IFF
        calls   #4,G^sys$Assign         ;assign the channel
.ENDC
        $Qiow_S Chan=(r5),Func=#IO$_WriteVBlk,-
                iosb=(R4),-
                p1=(r3),p2=#8,p4=#^X01010000
        $Dassgn_S chan=(r5)
420$:
        Ret
450$:   $Exit_S R0

GetName:
;++
; Routine to return name of a device  given an open channel
; to the device
; Input:
;       arg1    - Address of open channel
;       arg2    - Descriptor to return device name in.
; Output:
;       arg2    - descriptor of device name...
;---
        .word   ^M<r2,r3,r4,r5,r6,r7,r8>
        subl2   #<2*3*4>,sp
        movl    sp,r6
        movl    r6,r2
        movaq   -(sp),r5                ;iosb
        movl    Arg1(Ap),r7
        movl    Arg2(Ap),r8
        movw    (r8),(r2)+              ;Output device buffer length
        movw    #DVI$_devnam,(r2)+      ;Unit Number is all we need
        movl    4(r8),(r2)+             ;Store here
        clrq    (r2)+                   ;Zero the list and end it
        $GetDVIW_S -                    ;Need to Get the name
                Chan=(r7),-             ;for later use...
                ItmLst=(r6),-
                Iosb=(r5)               ;r2 has location of IOSB
        blbc    r0,100$                 ;Report Errors...
        movl    (r5),r0
9$:     blbc    r0,100$                 ;Check 
        movl    4(r8),r4
        movzwl  (r8),r1

10$:    decl    r1
        beql    20$
        cmpb    #32,(r4)[r1]
        beql    10$
20$:
        movl    r1,(r8)                 ;length
;;;     pushl   r8
;;;     Calls   #1,G^Lib$Put_Output
        movl    #SS$_Normal,r0
100$:   Ret

GetChan:
        .word   ^M<r2,r3,r4,r5,r6,r7,r8>
        subl2   #<2*3*4>,sp
        movl    sp,r6
        movl    r6,r2
        movaq   -(sp),r5                ;iosb
        movl    Arg1(Ap),r7
        movl    Arg2(Ap),r8
        movw    #4,(r2)+                ;Output device buffer length
        movw    #DVI$_refcnt,(r2)+      ;Unit Number is all we need
        movl    r8,(r2)+                ;Store here
        clrq    (r2)+                   ;Zero the list and end it
        $GetDVIW_S -                    ;Need to Get the name
                Chan=(r7),-             ;for later use...
                ItmLst=(r6),-
                Iosb=(r5)               ;r2 has location of IOSB
        blbc    r0,100$                 ;Report Errors...
        movl    (r5),r0
100$:   Ret



Clean_Up:
        .Word   ^m<r2>
        Ret


Pipe:
        .word   0
        subl2   #PLocal,sp
        movl    sp,r10
        movc5   #0,(r10),#0,-
                #<Plocal-1>,(r10)               ;init area...
        movl    #EFN_Last,Flags(r10)            ;Event Flags for use
        subl2   #512,Sp
        movl    sp,r5
        movaq   -(Sp),r6
        movzwl  #512,(r6)
        movl    r5,4(r6)
        movaq   -(sp),r7
        movzwl  #c1_sz,(r7)
        movab   c1,4(r7)
        pushl   r6
        pushl   r7
        pushl   r6
        Calls   #3,G^Lib$Get_Foreign
        blbc    r0,10$
;;      pushl   r6
;;      Calls   #1,G^Lib$Put_Output
        pushl   #0
        PUSHl   r6
        pushl   r10
        calls   #3,Pipe_it
        blbc    r0,10$
        $WaitFR_S EFN=#EFN_Last
10$:    Ret
        .End    Pipe
