Description:
The API is called multiple times within an ILE CL program. The calls allow for additional CL coding between them, and they are connected by a single set of file descriptors. Additional C library functions show that stdout & stderr do not necessarily refer to the same objects that the API uses, even when concurrency happens.
Code consists of a QSHFD *SRVPGM and a TSTQSHSYS *PGM. The *SRVPGM has a QSHOPNFD *MODULE that opens fd 0, 1 & 2 for stdin, stdout & stderr, and a QSHCLOFD *MODULE to close those descriptors. The *PGM calls QSHOPNFD to open the descriptors, calls the QzshSystem API multiple times, and then calls QSHCLOFD to close the descriptors.
|
Code:
- Create the *SRVPGM:
-
- CRTSRVPGM SRVPGM( mylib/QSHFD ) MODULE( QSHOPNFD QSHCLOFD )
- EXPORT( *ALL ) BNDDIR( QC2LE )
-
- QSHOPNFD *MODULE:
-
- /* ------ Begin *MODULE ------ */
-
- /* +
- QSHOPNFD -- Open file descriptors for QzshSystem API +
- +
- Open file descriptors 0, 1 and 2. These correspond to stdin, stdout and +
- stderr. We use the APPEND openflag because we want to accumulate output to +
- see what happens. +
- +
- We also use perror to 'print' the errno error message text if an error is +
- returned from open(). +
- +
- Note that perror prints to stderr. But also note that perror is a C library +
- function -- stderr need not be "stderr". +
- */
- pgm ( +
- &pRtnCode +
- )
-
- dcl &pRtnCode *int
-
-
- dcl &RtnCode *int
- dcl &CloOpt *int
-
- dcl &RC *int
-
- dcl &mode *uint value( 511 )
-
- dcl &RDONLY *int value( 1 )
- dcl &WRONLY *int value( 2 )
- dcl &CREAT *int value( 8 )
- dcl &TRUNC *int value( 64 )
- dcl &APPEND *int value( 256 )
-
- dcl &OpenFlags *int
-
- dcl &fname *char 128
-
- dcl &stdin *char 32 value( '/dev/qsh-stdin-null' )
- dcl &stdout *char 32 value( './stdout.txt' )
- dcl &stderr *char 32 value( '/tmp/stderr' )
-
- dcl &err *char 20
- dcl &errtxt *char 20 value( 'Error' )
-
- dcl &x00 *char 1 value( x'00' )
-
-
- /* Set RtnCode to zero by default... */
-
- chgvar &pRtnCode ( 0 )
-
-
- /* Run close() against fd from 0 thru 2... */
- /* Close Option will determine if errors will print... */
-
- chgvar &CloOpt ( -1 )
-
- callprc QSHCLOFD ( &CloOpt &RtnCode )
-
-
- /* First open() -- fd 0: stdin */
-
- chgvar &fname ( &stdin *tcat &x00 )
- chgvar &OpenFlags ( &RDONLY )
-
- callprc 'open' ( &fname +
- ( &OpenFlags *byval ) +
- ) +
- rtnval( &RC )
- if ( &RC *ne 0 ) do
- chgvar &err ( &errtxt *bcat '1' *tcat &x00 )
- callprc 'perror' &err
- chgvar &pRtnCode ( -1 )
- enddo
-
-
- /* Second open() -- fd 1: stdout */
- /* OpenFlags sets file for output, but subsequent uses by API will APPEND */
- /* to the file so we can see accumulates output. */
-
- chgvar &fname ( &stdout *tcat &x00 )
- chgvar &OpenFlags ( &WRONLY + &CREAT + &APPEND )
-
- callprc 'open' ( &fname +
- ( &OpenFlags *byval ) +
- &mode +
- ) +
- rtnval( &RC )
- if ( &RC *ne 1 ) do
- chgvar &err ( &errtxt *bcat '2' *tcat &x00 )
- callprc 'perror' &err
- chgvar &pRtnCode ( -1 )
- enddo
-
-
- /* Third open() -- fd 2: stderr */
-
- chgvar &fname ( &stderr *tcat &x00 )
-
- callprc 'open' ( &fname +
- ( &OpenFlags *byval ) +
- &mode +
- ) +
- rtnval( &RC )
- if ( &RC *ne 2 ) do
- chgvar &err ( &errtxt *bcat '3' *tcat &x00 )
- callprc 'perror' &err
- chgvar &pRtnCode ( -1 )
- enddo
-
-
- return
-
- endpgm
-
- /* ------ End *MODULE ------ */
-
-
- QSHCLOFD *MODULE:
-
- /* ------ Begin *MODULE ------ */
-
- /* +
- QSHCLOFD -- Close file descriptors for QzshSystem API +
- +
- Close file descriptors 0, 1 and 2. These correspond to stdin, stdout and +
- stderr. We run close() initially to ensure that some existing descriptor +
- doesn't interfere with the usage by QzshSystem. When we're done with the +
- API, we'll close them because we're finished with them. +
- +
- We also use perror to 'print' the errno error message text if an error is +
- returned from close(). We expect errors because we don't intend to have any +
- descriptors open when QSHCLOFD is first called. We control whether the +
- condition is an "error" by passing in a CloseOption value. +
- +
- Note that perror prints to stderr. But also note that perror is a C library +
- function -- stderr need not be "stderr". +
- */
- pgm ( +
- &pCloOpt +
- &pRtnCode +
- )
-
- dcl &pCloOpt *int
- dcl &pRtnCode *int
-
-
- dcl &fd *int
-
- dcl &fd_c *char 4
- dcl &RC *int
-
- dcl &err *char 20
- dcl &errtxt *char 20 value( 'Error FD' )
-
- dcl &x00 *char 1 value( x'00' )
-
-
- /* Set RtnCode to zero by default... */
-
- chgvar &pRtnCode ( 0 )
-
- /* Run close() against fd from 0 thru 2... */
-
- dofor &fd from( 0 ) to( 2 )
-
- callprc 'close' ( (&fd *byval) ) +
- rtnval( &RC )
-
- /* If RC matches CloOpt, print the "error"... */
-
- if ( &RC *eq &pCloOpt ) do
- chgvar &fd_c ( &fd )
- chgvar &err ( &errtxt *bcat &fd_c *tcat &x00 )
- callprc 'perror' &err
- enddo
-
- enddo
-
-
- return
-
- endpgm
-
- /* ------ End *MODULE ------ */
-
-
- Create TSTQSHSYS:
-
- CRTPGM PGM( mylib/TSTQSHSYS ) MODULE( TSTQSHSYS2 )
- BNDSRVPGM( QSHFD ) BNDDIR( QC2LE )
- ACTGRP( *NEW )
-
-
- TSTQSHSYS *PGM entry *MODULE:
-
- /* ------ Begin *MODULE ------ */
-
- /* +
- TSTQSHSYS -- Test QzshSystem API +
- +
- Testing QzshSystem API characteristics -- multiple calls to the API are +
- used to see how one might affect the other. The stdin, stdout & stderr fds +
- are opened at the beginning and used multiple times. +
- +
- The API is called first to list a non-existent directory; the error is +
- listed in stderr. The API then lists the CurrentDirectory and passes the +
- list to sort in descending order. The API then lists the home directory +
- with a marker comment at the beginning. +
- +
- The stdout & stderr streams are opened APPEND. This allows the output from +
- the last two calls to be in the same stdout. +
- +
- Note that the three fds are reused for each of the three API calls. +
- +
- The printf and perror C library functions are also called. The output from +
- those goes to stdout & stderr; but those are overridden to QPRINT print- +
- files. The stdout & stderr output from these does not interfere with the +
- QzshSystem API output. +
- */
- pgm
-
-
- dcl &RC *int
- dcl &RtnCode *int value( 0 )
- dcl &CloOpt *int value( -1 )
-
- dcl &cmd *char 256
-
- dcl &endsts *char 20 value( 'Last stdout output' )
-
- dcl &err *char 20
- dcl &errtxt *char 20 value( 'Error' )
-
- dcl &x00 *char 1 value( x'00' )
- dcl &NL *char 1 value( x'15' )
-
-
- /* Override stdout to print to a QPRINT print file within this ActGrp. */
- /* Override stderr to print to a QPRINT print file within this ActGrp. */
-
- ovrprtf STDOUT tofile( QPRINT ) ovrscope( *ACTGRPDFN )
- ovrprtf STDERR tofile( QPRINT ) ovrscope( *ACTGRPDFN )
-
-
- /* Send a message to get a timestamp... */
-
- sndpgmmsg msg( 'Start timestamp...' ) topgmq( *EXT )
-
-
- /* Open stdin, stdout and stderr -- for QzshSystem, not for perror, printf */
-
- callprc QSHOPNFD ( &RtnCode )
-
- if ( &RtnCode *lt 0 ) do
- chgvar &err ( &errtxt *bcat '4' *tcat &x00 )
- callprc 'perror' &err
- enddo
-
-
- /* First run -- list a non-existent file, error should be in stderr... */
-
- chgvar &cmd ( 'ls /home/x1y2z3/a9b8c7 | sort -r' *cat &x00 )
-
- callprc 'QzshSystem' &cmd +
- rtnval( &RC )
- if ( &RC *lt 0 ) do
- chgvar &err ( &errtxt *bcat '5' *tcat &x00 )
- callprc 'perror' &err
- enddo
-
-
- /* Second run -- list CurDir, pipe into sort to output to stdout... */
-
- chgvar &cmd ( 'ls | sort -r' *cat &x00 )
-
- callprc 'QzshSystem' &cmd +
- rtnval( &RC )
- if ( &RC *lt 0 ) do
- chgvar &err ( &errtxt *bcat '6' *tcat &x00 )
- callprc 'perror' &err
- enddo
-
-
- /* Third run -- Mark with echo, then list /home to stdout (APPEND) */
-
- chgvar &cmd ( 'echo "--- Next list: ---";ls /home' *cat &x00 )
-
- callprc 'QzshSystem' &cmd +
- rtnval( &RC )
- if ( &RC *lt 0 ) do
- chgvar &err ( &errtxt *bcat '7' *tcat &x00 )
- callprc 'perror' &err
- enddo
-
-
- /* We close fd 0, 1 & 2 because stdin, stdout & stderr are no longer used */
- /* by QzshSystem. Note that this doesn't affect our use of stdout... */
-
- callprc QSHCLOFD ( &CloOpt &RtnCode )
-
- if ( &RtnCode *lt 0 ) do
- chgvar &err ( &errtxt *bcat '8' *tcat &x00 )
- callprc 'perror' &err
- enddo
-
-
- /* Print EndStatus message to stdout... */
-
- chgvar &endsts ( &endsts *tcat &NL *cat &x00 )
-
- callprc 'printf' ( +
- &endsts +
- ) +
- rtnval( &RC )
-
-
- /* Send a message to get a timestamp... */
-
- sndpgmmsg msg( 'End timestamp...' ) topgmq( *EXT )
-
-
- /* Remove stdout printfile override... */
- /* Remove stderr printfile override... */
-
- dltovr STDOUT lvl( *ACTGRPDFN )
- dltovr STDERR lvl( *ACTGRPDFN )
-
-
- return
-
- endpgm
-
- /* ------ End *MODULE ------ */
-
|
|