Writing Sample:
Club Tech Programming TIps Newsletter

*********** Club Tech iSeries Programming Tips Newsletter ***********
An AS400 Network Publication              http://www.as400network.com
Home of NEWS/400 Magazine
Issue 41                                               March 29, 2001
 
Sponsored by Generic Software
ARCHIVE YOUR AS/400 REPORTS WITH SOQ FOR ONLY $599.
SAVE OUTPUT QUEUE (SOQ) not only archives spool files to any AS/400 
tape device, but it can also manage (move, copy, delete, convert) 
spool files by user name, job name, creation date, etc. For a 30-day 
FREE trial, Contact Generic Software, Inc., at (800) 698-5669 or visit 
http://www.genericsoftware.com/html/save_output_queue.htm .
 
******************************************************************
 
THIS WEEK:
> APIs by Example: Read/Write an IFS File Line in RPG IV
> APIs by Example: Read an IFS File Line in Cobol
> Data Area Editor Utility
> Poor Man's Cross-Reference
> Maximum Libraries in *LIBL to Change from 25 to 250
 
Featured Tip:
 
APIs BY EXAMPLE: READ/WRITE AN IFS FILE LINE IN RPG IV
This installment of "APIs by Example" offers sample RPG code showing 
how to read a text line from an IFS file until a line terminator is 
encountered, and also how to write a line to an IFS file.
 
The sample code consists of three RPG IV programs that create and read 
three text files in QOpenSys to show how the APIs work. Here are the 
programs:
 
CBX002A
Creates stream files /QOpenSys/access001.log and 
/QOpenSys/access002.log.
 
CBX002B
Creates file /QOpenSys/access00x.log, reads the access001.log and 
access002.log files, and appends them to access00x.log.
 
CBX002C
Reads access00x.log, then deletes the example stream files.
 
The sample RPG IV programs use seven C library functions, listed 
below:
 
Open stream file (fopen)
Opens or creates the specified stream file. The access level required 
is defined by the mode parameter and is followed by an optional 
keyword parameter specifying various file attributes.
http://publib.boulder.ibm.com/cgi-bin/bookmgr/bookmgr.cmd/BOOKS/qb3at500/1.2.48
 
Read stream (fgets)
Reads characters from current stream position for the number of bytes 
specified by the second parameter or until new-line character or end-
of-stream is encountered. The new-line character (x'25') is included 
in the retrieved string.
http://publib.boulder.ibm.com/cgi-bin/bookmgr/bookmgr.cmd/BOOKS/qb3at500/1.2.42
 
Write stream (fputs)
Appends the string parameter to the current stream position. The 
number of bytes written is returned.
http://publib.boulder.ibm.com/cgi-bin/bookmgr/bookmgr.cmd/BOOKS/qb3at500/1.2.51
 
Close stream (fclose)
Closes the stream pointed to by the FILE structure.
http://publib.boulder.ibm.com/cgi-bin/bookmgr/bookmgr.cmd/BOOKS/qb3at500/1.2.35
 
Delete stream file (remove)
Deletes the specified stream file.
http://publib.boulder.ibm.com/cgi-bin/bookmgr/bookmgr.cmd/BOOKS/qb3at500/1.2.136
 
Get error number (errno)
Retrieves the current value of the C runtime error number variable. 
The errno function simply returns a pointer to a 4-byte integer.
http://publib.boulder.ibm.com/cgi-bin/bookmgr/bookmgr.cmd/BOOKS/qb3at702/9.1.2
http://publib.boulder.ibm.com/cgi-bin/bookmgr/bookmgr.cmd/BOOKS/qb3at500/1.3.1
http://publib.boulder.ibm.com/cgi-bin/bookmgr/bookmgr.cmd/BOOKS/qb3at500/1.3.2
 
Map error number (strerror)
Converts the error number variable to an error message string.
http://publib.boulder.ibm.com/cgi-bin/bookmgr/bookmgr.cmd/BOOKS/qb3at500/1.2.184
 
Below is the sample RPG IV code.
 
** Program:      CBX002A
** Description:  Create files used by IFS file API example. 
** Compile:      CRTBNDRPG ...  DBGVIEW(*LIST)
**
**-- Control spec:  -----------------------------------------------**
H Option( *SrcStmt )  DftActGrp( *No )  BndDir( 'QC2LE' )
**-- Global variables:  -------------------------------------------**
D FILE_o          s               *
D String          s            512a
D rc              s             10i 0
D Idx             s              5u 0
**-- Global constants:  -------------------------------------------**
D FilNam_1        c                   '/QOpenSys/access001.log'
D FilNam_2        c                   '/QOpenSys/access002.log'
D LF              c                   x'25'
**-- IFS stream file functions:  ----------------------------------**
Dopen             Pr              *   ExtProc( '_C_IFS_fopen' )
D                                 *   Value  Options( *String )
D                                 *   Value  Options( *String )
**
Dfgets            Pr              *   ExtProc( '_C_IFS_fgets' )
D                                 *   Value
D                               10i 0 Value
D                                 *   Value
**
Dfputs            Pr            10i 0 ExtProc( '_C_IFS_fputs' )
D                                 *   Value  Options( *String )
D                                 *   Value
**
Dclose            Pr            10i 0 ExtProc( '_C_IFS_fclose' )
D                                 *   Value
**
**-- Mainline:  ------------------------------------------------------
---**
**
**-- create file, set codepage (pc):
C                   Eval      FILE_o     =  open( %TrimR( FilNam_1 )
C                                               : 'w, codepage=850'
C                                               )
**
C                   Eval      rc         =  close( FILE_o )
**
C                   Eval      FILE_o     =  open( %TrimR( FilNam_2 )
C                                               : 'w, codepage=850'
C                                               )
**
C                   Eval      rc         =  close( FILE_o )
**
**-- open files, implicit conversion to job codepage:
C                   Eval      FILE_o     =  open( %TrimR( FilNam_1 )
C                                               : 'w'
C                                               )
**
C                   If        FILE_o    <>  *Null
**
C                   For       Idx = 1  to 10
C                   Eval      rc         =  fputs( 'Stream 1 line: ' +
C                                                  %Char( Idx )      +
C                                                  LF
C                                                : FILE_o
C                                                )
C                   EndFor
**
C                   Eval      rc         =  close( FILE_o )
C                   EndIf
**
**-- open files, implicit conversion to job codepage:
C                   Eval      FILE_o     =  open( %TrimR( FilNam_2 )
C                                               : 'w'
C                                               )
**
C                   If        FILE_o    <>  *Null
**
C                   For       Idx = 1  to 10
C                   Eval      rc         =  fputs( 'Stream 2 line: ' +
C                                                  %Char( Idx )      +
C                                                  LF
C                                                : FILE_o
C                                                )
C                   EndFor
**
C                   Eval      rc         =  close( FILE_o )
C                   EndIf
**
C                   Eval      *InLr      =  *On
C                   Return
 

** Program:      CBX002B
** Description:  Read two files, and append them to a third new file. 
** Compile:      CRTBNDRPG ...  DBGVIEW(*LIST)
**
**
**-- Control spec:  ------------------------------------------------**
H Option( *SrcStmt )  DftActGrp( *No )  BndDir( 'QC2LE' )
**-- Global variables:  --------------------------------------------**
D FILE_i          s               *
D FILE_o          s               *
D ErrTxt          s            128a
D String          s            512a
D rc              s             10i 0
**-- Global constants:  --------------------------------------------**
D FilNam_1        c                   '/QOpenSys/access001.log'
D FilNam_2        c                   '/QOpenSys/access002.log'
D FilNam_o        c                   '/QOpenSys/access00x.log'
**-- Error identification:  ----------------------------------------**
D errno           Pr            10i 0
**
D strerror        Pr           128a   Varying
**-- IFS stream file functions:  -----------------------------------**
Dopen             Pr              *   ExtProc( '_C_IFS_fopen' )
D                                 *   Value  Options( *String )
D                                 *   Value  Options( *String )
**
Dfgets            Pr              *   ExtProc( '_C_IFS_fgets' )
D                                 *   Value
D                               10i 0 Value
D                                 *   Value
**
Dfputs            Pr            10i 0 ExtProc( '_C_IFS_fputs' )
D                                 *   Value  Options( *String )
D                                 *   Value
**
Dclose            Pr            10i 0 ExtProc( '_C_IFS_fclose' )
D                                 *   Value
**
**-- Mainline:  ----------------------------------------------------**
**
**-- create file, set codepage (pc):
C                   Eval      FILE_o     =  open( %TrimR( FilNam_o )
C                                               : 'w, codepage=850'
C                                               )
**
C                   Eval      rc         =  close( FILE_o )
**
**-- open files, implicit conversion to job codepage:
C                   Eval      FILE_o     =  open( %TrimR( FilNam_o )
C                                               : 'w'
C                                               )
**
C                   Eval      FILE_i     =  open( %TrimR( FilNam_1 )
C                                               : 'r'
C                                               )
**
C                   If        FILE_i     =  *Null
C                   Eval      ErrTxt     =  %Char( Errno ) + ': ' +
C                                           Strerror
C                   Else
**
C                   Dow       fgets( %Addr( String )
C                                  : %Size( String )
C                                  : FILE_i
C                                  )    <>  *Null
**-- copy file 1 to new file...
C                   Eval      rc         =  fputs( %Str( %Addr( String 
))
C                                                : FILE_o
C                                                )
C                   EndDo
**
C                   Eval      rc         =  close( FILE_i )
C                   EndIf
**
C                   Eval      FILE_i     =  open( %TrimR( FilNam_2 )
C                                               : 'r'
C                                               )
**
C                   If        FILE_i     =  *Null
C                   Eval      ErrTxt     =  %Char( Errno ) + ': ' +
C                                           Strerror
C                   Else
**
C                   Dow       fgets( %Addr( String )
C                                  : %Size( String )
C                                  : FILE_i
C                                  )    <>  *Null
**-- copy file 2 to new file...
C                   Eval      rc         =  fputs( %Str( %Addr( String 
))
C                                                : FILE_o
C                                                )
C                   EndDo
**
C                   Eval      rc         =  close( FILE_i )
C                   EndIf
C                   Eval      rc         =  close( FILE_o )
**
C                   Eval      *InLr      =  *On
C                   Return
**
**-- Get runtime error number:  ------------------------------------**
P Errno           B
D                 Pi            10i 0
D sys_errno       Pr              *    ExtProc( '__errno' )
**
D Error           s             10i 0  Based( pError )  NoOpt
**
C                   Eval      pError     =  sys_errno
C                   Return    Error
**
P Errno           E
**-- Get runtime error text:  --------------------------------------**
P Strerror        B
D                 Pi           128a    Varying
D sys_strerror    Pr              *    ExtProc( 'strerror' )
D                               10i 0  Value
**
C                   Return    %Str( sys_strerror( Errno ))
**
P Strerror        E
 
** Program:      CBX002C
** Description:  Read merged file and clean up IFS example files.
** Compile:      CRTBNDRPG ...  DBGVIEW(*LIST)
**
**-- Control spec:  ------------------------------------------------**
H Option( *SrcStmt )  DftActGrp( *No )  BndDir( 'QC2LE' )
**-- Global variables:  --------------------------------------------**
D FILE_i          s               *
D String          s            512a
D rc              s             10i 0
D Idx             s              5u 0
**-- Global constants:  --------------------------------------------**
D FilNam_o        c                   '/QOpenSys/access00x.log'
D FilNam_1        c                   '/QOpenSys/access001.log'
D FilNam_2        c                   '/QOpenSys/access002.log'
**-- IFS stream file functions:  -----------------------------------**
Dopen             Pr              *   ExtProc( '_C_IFS_fopen' )
D                                 *   Value  Options( *String )
D                                 *   Value  Options( *String )
**
Dfgets            Pr              *   ExtProc( '_C_IFS_fgets' )
D                                 *   Value
D                               10i 0 Value
D                                 *   Value
**
Dfputs            Pr            10i 0 ExtProc( '_C_IFS_fputs' )
D                                 *   Value  Options( *String )
D                                 *   Value
**
Dclose            Pr            10i 0 ExtProc( '_C_IFS_fclose' )
D                                 *   Value
**
Dremove           Pr            10i 0 ExtProc( '_C_IFS_remove' )
D                                 *   Value  Options( *String )
**
**-- Mainline:  ----------------------------------------------------**
**
C                   Eval      FILE_i     =  open( %TrimR( FilNam_o )
C                                               : 'r'
C                                               )
**
C                   Dow       fgets( %Addr( String )
C                                  : %Size( String )
C                                  : FILE_i
C                                  )    <>  *Null
C                   EndDo
**
C                   Eval      rc         =  close( FILE_i )
**
C                   Eval      rc         =  remove( %TrimR( FilNam_o 
))
C                   Eval      rc         =  remove( %TrimR( FilNam_1 
))
C                   Eval      rc         =  remove( %TrimR( FilNam_2 
))
**
C                   Eval      *InLr      =  *On
C                   Return
 
The above tip was written by Carsten Flensburg. For questions 
regarding this tip, contact Carsten at mailto:flensburg@novasol.dk.
 
Short Takes:
 
1. APIs BY EXAMPLE: READ AN IFS FILE LINE IN COBOL
Simon Coulter offers a Cobol example showing how to read lines from an 
IFS file at http://archive.midrange.com/cobol400-l/200010/msg00006.html .
 
2. DATA AREA EDITOR UTILITY
Lynne Noll has made available a utility to easily edit data areas. The 
utility determines the attributes of the specified data area, then 
loads the contents into the screen. You can then type over the 
contents and press Enter to make the changes permanent.
 
The utility can edit character, logical, and decimal data areas. It 
can't update character data areas containing embedded packed numbers 
or other unprintable characters, or numeric data areas with more than 
15 positions to the left of the decimal. If there are decimal 
positions to the right of the decimal, it can support up to 10 
positions to the left and 5 to the right of the decimal.
 
The utility consists of a CL program, ITUDTAC, an RPG IV program, a 
DSPF file, and a help file. You can download the utility from 
http://www.as400network.com/noderesources/code/clubtechcode/DataAreaEdit.zip .
 
3. POOR MAN'S CROSS-REFERENCE
In the February 28 issue, I suggested the use of commercial utilities 
to show a list of programs used by a particular file. Many readers 
suggested a quick-and-dirty method of providing that information. Most 
importantly, the method is free. 
 
While there is no single command that gives you a list of all programs 
used by a file, you can query the outfile from the Display Program 
References (DSPPGMREF) command to give you this information. Here are 
the steps:
 
a. Run the DSPPGMREF command specifying the name of your library, *ALL 
for the program name, and a file name to receive the output:
 
DSPPGMREF PGM(YourLib/*ALL) OUTPUT(*OUTFILE) OBJTYPE(*ALL)
OUTFILE(YourOutLib/YourOutFile)
 
If you have multiple libraries, run the command again and change the 
output member parameter from *REPLACE to *ADD.
 
b. Use Query/400 to select records where the WHFNAM field is equal to 
your file name:
 
SELECT DISTINCT WHLIB, WHPNAM, WHTEXT FROM
YourOutLib/YourOutFile
WHERE WHFNAM='YourFileName'
ORDER BY WHLIB, WHPNAM
 
The above technique works, but it has its limitations. It won't list 
files overridden with OVRDBF, it will show logicals but not the 
physical file used by the logical, and it misses join OPNQRYs and DFUs 
and programs hidden in library lists. That's why many programmers 
recommend using a commercial documentation package, because they tend 
to have far fewer limitations. Still, though, you can't beat the 
price!
 
Thanks to all who sent in this suggestion: Bob Abbott, Paul J. 
Crowley, Susan Deem, Ray Gernon, Nizar S. Hajjaj, Patrick Holthuizen, 
Julie Hills, Michael Lynch, and Ron Wolford. Whew!
 
4. MAXIMUM LIBRARIES IN *LIBL TO CHANGE FROM 25 TO 250
The V5 release of OS/400, due out in May, changes the maximum number 
of libraries in the user part of a library list (*LIBL) from 25 to 
250. This will alleviate some problems that arose from the previous 
limitations, but it may cause other problems with your existing code.
 
The new versions of the RTVJOBA (Retrieve Job Attribute) command and 
the QUSRJOBI (Retrieve Job Information), QWCRTVCA (Retrieve Current 
Attributes), QUSRSPLA (Retrieve Spool File Attributes), and QWDRJOBD 
(Retrieve Job Description) APIs can now return more data than in 
previous releases. Be sure that any applications you have that use one 
of these interfaces provides enough room for 250 libraries in the 
return value.
 
When you increase the size of a return variable, you can still safely 
call V4R5 and earlier releases of these interfaces because there is no 
harm in providing more space than needed. Just be sure that your own 
application logic correctly handles however many library entries are 
returned.
 
For more information, see:
http://www.ibm.com/eserver/iseries/developer/os400/lib_list.html
 
Thanks to Paul Conte for the above item
 
************************** ADVERTISING **************************:
NEW DOMINO GUIDE GOES BEYOND THEORY ON THE AS/400!
Domino R5 and the AS/400 is your concise guide to the multi-faceted 
world of Domino. From electronic mail to workflow-based computing, 
from database replication to document management, Domino R5 can do it 
all -- if you know how to harness its power. Domino R5 and the AS/400 
untangles the intricacies of Domino R5 with extensive information 
about Domino's mail server capabilities, its dial-up connectivity 
features, and Operations Navigator. To order this essential guide, go 
to http://as400network.com/str/books/uniquebook2.cfm?NextBook=181 .
  
**************** ABOUT AS400 NETWORK NEWSLETTERS ****************:
  
Club Tech iSeries Programming Tips Newsletter and Club Tech iSeries 
DB2 UDB & SQL/400 Newsletter are published on alternate Thursdays. 
Club Tech Networking Tips Newsletter and Club Tech iSeries Systems 
Management Newsletter are published on alternate Wednesdays. 
NEWSWire/400 brings you daily AS/400 industry news, tech tips, product 
news, and IBM announcements. Tech Observatory Newsletter is published 
every other Tuesday and pinpoints Internet resources for iSeries 400 
professionals. ChannelWire and Hot Blasts, published on alternate 
Fridays, contain the latest news for IBM software developers and 
resellers. All are *FREE OF CHARGE*!