midrange.com code scratchpad
Name:
Testing the Qshell QzshSystem API
Scriptlanguage:
Plain Text
Tabwidth:
4
Date:
04/20/2009 07:26:39 am
IP:
Logged
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:
  1. Create the *SRVPGM:
  2.  
  3. CRTSRVPGM SRVPGM( mylib/QSHFD ) MODULE( QSHOPNFD QSHCLOFD )
  4.             EXPORT( *ALL ) BNDDIR( QC2LE )
  5.  
  6. QSHOPNFD *MODULE:
  7.  
  8. /* ------ Begin *MODULE ------ */
  9.  
  10. /* +
  11.    QSHOPNFD -- Open file descriptors for QzshSystem API                        +
  12.                                                                                +
  13.    Open file descriptors 0, 1 and 2. These correspond to stdin, stdout and     +
  14.    stderr. We use the APPEND openflag because we want to accumulate output to  +
  15.    see what happens.                                                           +
  16.                                                                                +
  17.    We also use perror to 'print' the errno error message text if an error is   +
  18.    returned from open().                                                       +
  19.                                                                                +
  20.    Note that perror prints to stderr. But also note that perror is a C library +
  21.    function -- stderr need not be "stderr".                                    +
  22. */
  23.  pgm      ( +
  24.             &pRtnCode    +
  25.           )
  26.  
  27.    dcl      &pRtnCode    *int
  28.  
  29.  
  30.    dcl      &RtnCode     *int
  31.    dcl      &CloOpt      *int
  32.  
  33.    dcl      &RC          *int
  34.  
  35.    dcl      &mode        *uint          value( 511 )
  36.  
  37.    dcl      &RDONLY      *int           value( 1 )
  38.    dcl      &WRONLY      *int           value( 2 )
  39.    dcl      &CREAT       *int           value( 8 )
  40.    dcl      &TRUNC       *int           value( 64 )
  41.    dcl      &APPEND      *int           value( 256 )
  42.  
  43.    dcl      &OpenFlags   *int
  44.  
  45.    dcl      &fname       *char  128
  46.  
  47.    dcl      &stdin       *char   32     value( '/dev/qsh-stdin-null' )
  48.    dcl      &stdout      *char   32     value( './stdout.txt' )
  49.    dcl      &stderr      *char   32     value( '/tmp/stderr' )
  50.  
  51.    dcl      &err         *char   20
  52.    dcl      &errtxt      *char   20     value( 'Error' )
  53.  
  54.    dcl      &x00         *char    1     value( x'00' )
  55.  
  56.  
  57.   /* Set RtnCode to zero by default...                                        */
  58.  
  59.    chgvar         &pRtnCode       ( 0 )
  60.  
  61.  
  62.   /* Run close() against fd from 0 thru 2...                                  */
  63.   /* Close Option will determine if errors will print...                      */
  64.  
  65.    chgvar         &CloOpt         ( -1 )
  66.  
  67.    callprc  QSHCLOFD ( &CloOpt &RtnCode )
  68.  
  69.  
  70.   /* First open() -- fd 0: stdin                                              */
  71.  
  72.    chgvar         &fname          ( &stdin *tcat &x00 )
  73.    chgvar         &OpenFlags      ( &RDONLY )
  74.  
  75.    callprc  'open'         ( &fname +
  76.                              ( &OpenFlags   *byval )  +
  77.                            ) +
  78.                      rtnval( &RC )
  79.    if ( &RC *ne 0 )  do
  80.       chgvar      &err            ( &errtxt *bcat '1' *tcat &x00 )
  81.       callprc  'perror'      &err
  82.       chgvar      &pRtnCode       ( -1 )
  83.    enddo
  84.  
  85.  
  86.   /* Second open() -- fd 1: stdout                                            */
  87.   /* OpenFlags sets file for output, but subsequent uses by API will APPEND   */
  88.   /* to the file so we can see accumulates output.                            */
  89.  
  90.    chgvar         &fname          ( &stdout *tcat &x00 )
  91.    chgvar         &OpenFlags      ( &WRONLY + &CREAT + &APPEND )
  92.  
  93.    callprc  'open'         ( &fname +
  94.                              ( &OpenFlags   *byval )  +
  95.                              &mode  +
  96.                            ) +
  97.                      rtnval( &RC )
  98.    if ( &RC *ne 1 )  do
  99.       chgvar      &err            ( &errtxt *bcat '2' *tcat &x00 )
  100.       callprc  'perror'      &err
  101.       chgvar      &pRtnCode       ( -1 )
  102.    enddo
  103.  
  104.  
  105.   /* Third open() -- fd 2: stderr                                             */
  106.  
  107.    chgvar         &fname          ( &stderr *tcat &x00 )
  108.  
  109.    callprc  'open'         ( &fname +
  110.                              ( &OpenFlags   *byval )  +
  111.                              &mode  +
  112.                            ) +
  113.                      rtnval( &RC )
  114.    if ( &RC *ne 2 )  do
  115.       chgvar      &err            ( &errtxt *bcat '3' *tcat &x00 )
  116.       callprc  'perror'      &err
  117.       chgvar      &pRtnCode       ( -1 )
  118.    enddo
  119.  
  120.  
  121.    return
  122.  
  123.  endpgm
  124.  
  125. /* ------ End *MODULE ------ */
  126.  
  127.  
  128. QSHCLOFD *MODULE:
  129.  
  130. /* ------ Begin *MODULE ------ */
  131.  
  132. /* +
  133.    QSHCLOFD -- Close file descriptors for QzshSystem API                       +
  134.                                                                                +
  135.    Close file descriptors 0, 1 and 2. These correspond to stdin, stdout and    +
  136.    stderr. We run close() initially to ensure that some existing descriptor    +
  137.    doesn't interfere with the usage by QzshSystem. When we're done with the    +
  138.    API, we'll close them because we're finished with them.                     +
  139.                                                                                +
  140.    We also use perror to 'print' the errno error message text if an error is   +
  141.    returned from close(). We expect errors because we don't intend to have any +
  142.    descriptors open when QSHCLOFD is first called. We control whether the      +
  143.    condition is an "error" by passing in a CloseOption value.                  +
  144.                                                                                +
  145.    Note that perror prints to stderr. But also note that perror is a C library +
  146.    function -- stderr need not be "stderr".                                    +
  147. */
  148.  pgm      ( +
  149.             &pCloOpt     +
  150.             &pRtnCode    +
  151.           )
  152.  
  153.    dcl      &pCloOpt     *int
  154.    dcl      &pRtnCode    *int
  155.  
  156.  
  157.    dcl      &fd          *int
  158.  
  159.    dcl      &fd_c        *char    4
  160.    dcl      &RC          *int
  161.  
  162.    dcl      &err         *char   20
  163.    dcl      &errtxt      *char   20     value( 'Error FD' )
  164.  
  165.    dcl      &x00         *char    1     value( x'00' )
  166.  
  167.  
  168.   /* Set RtnCode to zero by default...                                        */
  169.  
  170.    chgvar         &pRtnCode       ( 0 )
  171.  
  172.   /* Run close() against fd from 0 thru 2...                                  */
  173.  
  174.    dofor  &fd  from( 0 ) to( 2 )
  175.  
  176.       callprc  'close'  ( (&fd *byval) ) +
  177.                   rtnval( &RC )
  178.  
  179.     /* If RC matches CloOpt, print the "error"...                             */
  180.  
  181.       if ( &RC *eq &pCloOpt )  do
  182.          chgvar   &fd_c           ( &fd )
  183.          chgvar   &err            ( &errtxt *bcat &fd_c *tcat &x00 )
  184.          callprc 'perror'    &err
  185.       enddo
  186.  
  187.    enddo
  188.  
  189.  
  190.    return
  191.  
  192.  endpgm
  193.  
  194. /* ------ End *MODULE ------ */
  195.  
  196.  
  197. Create TSTQSHSYS:
  198.  
  199. CRTPGM PGM( mylib/TSTQSHSYS ) MODULE( TSTQSHSYS2 )
  200.          BNDSRVPGM( QSHFD ) BNDDIR( QC2LE )
  201.          ACTGRP( *NEW )
  202.  
  203.  
  204. TSTQSHSYS *PGM entry *MODULE:
  205.  
  206. /* ------ Begin *MODULE ------ */
  207.  
  208. /* +
  209.    TSTQSHSYS -- Test QzshSystem API                                            +
  210.                                                                                +
  211.    Testing QzshSystem API characteristics -- multiple calls to the API are     +
  212.    used to see how one might affect the other. The stdin, stdout & stderr fds  +
  213.    are opened at the beginning and used multiple times.                        +
  214.                                                                                +
  215.    The API is called first to list a non-existent directory; the error is      +
  216.    listed in stderr. The API then lists the CurrentDirectory and passes the    +
  217.    list to sort in descending order. The API then lists the home directory     +
  218.    with a marker comment at the beginning.                                     +
  219.                                                                                +
  220.    The stdout & stderr streams are opened APPEND. This allows the output from  +
  221.    the last two calls to be in the same stdout.                                +
  222.                                                                                +
  223.    Note that the three fds are reused for each of the three API calls.         +
  224.                                                                                +
  225.    The printf and perror C library functions are also called. The output from  +
  226.    those goes to stdout & stderr; but those are overridden to QPRINT print-    +
  227.    files. The stdout & stderr output from these does not interfere with the    +
  228.    QzshSystem API output.                                                      +
  229. */
  230.  pgm
  231.  
  232.  
  233.    dcl      &RC         *int
  234.    dcl      &RtnCode    *int           value( 0 )
  235.    dcl      &CloOpt     *int           value( -1 )
  236.  
  237.    dcl      &cmd        *char  256
  238.  
  239.    dcl      &endsts     *char   20     value( 'Last stdout output' )
  240.  
  241.    dcl      &err        *char   20
  242.    dcl      &errtxt     *char   20     value( 'Error' )
  243.  
  244.    dcl      &x00        *char    1     value( x'00' )
  245.    dcl      &NL         *char    1     value( x'15' )
  246.  
  247.  
  248.   /* Override stdout to print to a QPRINT print file within this ActGrp.      */
  249.   /* Override stderr to print to a QPRINT print file within this ActGrp.      */
  250.  
  251.    ovrprtf     STDOUT  tofile( QPRINT ) ovrscope( *ACTGRPDFN )
  252.    ovrprtf     STDERR  tofile( QPRINT ) ovrscope( *ACTGRPDFN )
  253.  
  254.  
  255.   /* Send a message to get a timestamp...                                     */
  256.  
  257.    sndpgmmsg   msg( 'Start timestamp...' ) topgmq( *EXT )
  258.  
  259.  
  260.   /* Open stdin, stdout and stderr -- for QzshSystem, not for perror, printf  */
  261.  
  262.    callprc  QSHOPNFD ( &RtnCode )
  263.  
  264.    if ( &RtnCode *lt 0 )  do
  265.       chgvar      &err            ( &errtxt *bcat '4' *tcat &x00 )
  266.       callprc  'perror'      &err
  267.    enddo
  268.  
  269.  
  270.   /* First run -- list a non-existent file, error should be in stderr...      */
  271.  
  272.    chgvar   &cmd      ( 'ls /home/x1y2z3/a9b8c7 | sort -r' *cat &x00 )
  273.  
  274.    callprc  'QzshSystem'     &cmd +
  275.              rtnval( &RC )
  276.    if ( &RC *lt 0 )  do
  277.       chgvar      &err            ( &errtxt *bcat '5' *tcat &x00 )
  278.       callprc  'perror'         &err
  279.    enddo
  280.  
  281.  
  282.   /* Second run -- list CurDir, pipe into sort to output to stdout...         */
  283.  
  284.    chgvar   &cmd      ( 'ls | sort -r' *cat &x00 )
  285.  
  286.    callprc  'QzshSystem'     &cmd +
  287.              rtnval( &RC )
  288.    if ( &RC *lt 0 )  do
  289.       chgvar      &err            ( &errtxt *bcat '6' *tcat &x00 )
  290.       callprc  'perror'         &err
  291.    enddo
  292.  
  293.  
  294.   /* Third run -- Mark with echo, then list /home to stdout (APPEND)          */
  295.  
  296.    chgvar   &cmd      ( 'echo "--- Next list: ---";ls /home' *cat &x00 )
  297.  
  298.    callprc  'QzshSystem'     &cmd +
  299.              rtnval( &RC )
  300.    if ( &RC *lt 0 )  do
  301.       chgvar      &err            ( &errtxt *bcat '7' *tcat &x00 )
  302.       callprc  'perror'         &err
  303.    enddo
  304.  
  305.  
  306.   /* We close fd 0, 1 & 2 because stdin, stdout & stderr are no longer used   */
  307.   /* by QzshSystem. Note that this doesn't affect our use of stdout...        */
  308.  
  309.    callprc  QSHCLOFD ( &CloOpt &RtnCode )
  310.  
  311.    if ( &RtnCode *lt 0 )  do
  312.       chgvar      &err            ( &errtxt *bcat '8' *tcat &x00 )
  313.       callprc  'perror'      &err
  314.    enddo
  315.  
  316.  
  317.   /* Print EndStatus message to stdout...                                     */
  318.  
  319.    chgvar         &endsts         ( &endsts *tcat &NL *cat &x00 )
  320.  
  321.    callprc     'printf'    ( +
  322.                              &endsts      +
  323.                            ) +
  324.                      rtnval( &RC )
  325.  
  326.  
  327.   /* Send a message to get a timestamp...                                     */
  328.  
  329.    sndpgmmsg   msg( 'End timestamp...' ) topgmq( *EXT )
  330.  
  331.  
  332.   /* Remove stdout printfile override...                                      */
  333.   /* Remove stderr printfile override...                                      */
  334.  
  335.    dltovr      STDOUT  lvl( *ACTGRPDFN )
  336.    dltovr      STDERR  lvl( *ACTGRPDFN )
  337.  
  338.  
  339.    return
  340.  
  341.  endpgm
  342.  
  343. /* ------ End *MODULE ------ */
  344.  
© 2004-2019 by midrange.com generated in 0.007s valid xhtml & css